From 2d45c3edee8008a749cc01a339b34b31fdc6b72a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 8 Apr 2021 16:54:50 +0200 Subject: [PATCH 01/48] add channel file and media display screens --- .../lib/channel_file_display_screen.dart | 180 +++++++++++++ .../lib/channel_media_display_screen.dart | 249 ++++++++++++++++++ .../stream_chat_v1/lib/chat_info_screen.dart | 2 + .../stream_chat_v1/lib/group_info_screen.dart | 2 + 4 files changed, 433 insertions(+) create mode 100644 packages/stream_chat_v1/lib/channel_file_display_screen.dart create mode 100644 packages/stream_chat_v1/lib/channel_media_display_screen.dart diff --git a/packages/stream_chat_v1/lib/channel_file_display_screen.dart b/packages/stream_chat_v1/lib/channel_file_display_screen.dart new file mode 100644 index 0000000..a3e1c67 --- /dev/null +++ b/packages/stream_chat_v1/lib/channel_file_display_screen.dart @@ -0,0 +1,180 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +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; + + /// The builder used when the file list is empty. + final WidgetBuilder emptyBuilder; + + const ChannelFileDisplayScreen({ + this.sortOptions, + this.paginationParams, + this.emptyBuilder, + }); + + @override + _ChannelFileDisplayScreenState createState() => + _ChannelFileDisplayScreenState(); +} + +class _ChannelFileDisplayScreenState extends State { + @override + void initState() { + super.initState(); + final messageSearchBloc = MessageSearchBloc.of(context); + messageSearchBloc.search( + filter: { + 'cid': { + r'$in': [StreamChannel.of(context).channel.cid] + } + }, + messageFilter: { + 'attachments.type': { + r'$in': ['file'], + }, + }, + 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( + 'Files', + 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.files( + size: 136.0, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + ), + SizedBox(height: 16.0), + Text( + 'No Files', + style: TextStyle( + fontSize: 14.0, + color: StreamChatTheme.of(context).colorTheme.black, + ), + ), + SizedBox(height: 8.0), + Text( + 'Files sent in this chat will appear here', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14.0, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + ), + ), + ], + ), + ); + } + + final 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': [StreamChannel.of(context).channel.cid] + } + }, + messageFilter: { + 'attachments.type': { + r'$in': ['file'] + }, + }, + sort: widget.sortOptions, + pagination: widget.paginationParams.copyWith( + offset: messageSearchBloc.messageResponses?.length ?? 0, + ), + ), + child: ListView.builder( + itemBuilder: (context, position) { + return Padding( + padding: const EdgeInsets.all(1.0), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: FileAttachment( + message: media.values.toList()[position], + attachment: media.keys.toList()[position], + ), + ), + ); + }, + itemCount: media.length, + ), + ); + }, + stream: messageSearchBloc.messagesStream, + ); + } +} diff --git a/packages/stream_chat_v1/lib/channel_media_display_screen.dart b/packages/stream_chat_v1/lib/channel_media_display_screen.dart new file mode 100644 index 0000000..a0ed072 --- /dev/null +++ b/packages/stream_chat_v1/lib/channel_media_display_screen.dart @@ -0,0 +1,249 @@ +import 'package:flutter/material.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; + + /// 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 + _ChannelMediaDisplayScreenState createState() => + _ChannelMediaDisplayScreenState(); +} + +class _ChannelMediaDisplayScreenState extends State { + Map controllerCache = {}; + + @override + void initState() { + super.initState(); + final messageSearchBloc = MessageSearchBloc.of(context); + messageSearchBloc.search( + filter: { + 'cid': { + r'$in': [StreamChannel.of(context).channel.cid], + } + }, + messageFilter: { + 'attachments.type': { + r'$in': ['image', 'video'] + }, + }, + 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( + 'Photos & Videos', + 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.pictures( + size: 136.0, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + ), + SizedBox(height: 16.0), + Text( + 'No Media', + style: TextStyle( + fontSize: 14.0, + color: StreamChatTheme.of(context).colorTheme.black, + ), + ), + SizedBox(height: 8.0), + Text( + 'Photos or video sent in this chat will \nappear here', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14.0, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + ), + ), + ], + ), + ); + } + + final media = <_AssetPackage>[]; + + for (var item in snapshot.data) { + item.message.attachments + .where((e) => + (e.type == 'image' || e.type == 'video') && + e.ogScrapeUrl == null) + .forEach((e) { + VideoPlayerController controller; + if (e.type == 'video') { + var cachedController = controllerCache[e.assetUrl]; + + if (cachedController == null) { + controller = VideoPlayerController.network(e.assetUrl); + controller.initialize(); + controllerCache[e.assetUrl] = controller; + } else { + controller = cachedController; + } + } + media.add(_AssetPackage(e, item.message, controller)); + }); + } + + return LazyLoadScrollView( + onEndOfPage: () => messageSearchBloc.search( + filter: { + 'cid': { + r'$in': [StreamChannel.of(context).channel.cid] + } + }, + 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.map((e) => e.attachment).toList(), + startIndex: position, + message: media[position].message, + sentAt: media[position].message.createdAt, + userName: media[position].message.user.name, + onShowMessage: widget.onShowMessage, + ), + ), + ), + ); + }, + child: media[position].attachment.type == 'image' + ? 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), + ), + ); + }, + itemCount: media.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); +} diff --git a/packages/stream_chat_v1/lib/chat_info_screen.dart b/packages/stream_chat_v1/lib/chat_info_screen.dart index 5c8441e..38fbb70 100644 --- a/packages/stream_chat_v1/lib/chat_info_screen.dart +++ b/packages/stream_chat_v1/lib/chat_info_screen.dart @@ -3,6 +3,8 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'channel_file_display_screen.dart'; +import 'channel_media_display_screen.dart'; import 'main.dart'; import 'routes/routes.dart'; diff --git a/packages/stream_chat_v1/lib/group_info_screen.dart b/packages/stream_chat_v1/lib/group_info_screen.dart index b76cc9b..efe1808 100644 --- a/packages/stream_chat_v1/lib/group_info_screen.dart +++ b/packages/stream_chat_v1/lib/group_info_screen.dart @@ -7,6 +7,8 @@ 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 'channel_file_display_screen.dart'; +import 'channel_media_display_screen.dart'; import 'chat_info_screen.dart'; import 'main.dart'; import 'routes/routes.dart'; From 0c597134fea7c6e429b2ba9c24db58ae2f0db978 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 3 May 2021 11:05:22 +0200 Subject: [PATCH 02/48] update fastlane configs --- packages/stream_chat_v1/ios/fastlane/Fastfile | 2 +- .../fastlane/beta_gym_export_options.plist | 2 +- .../stream_chat_v1/ios/fastlane/report.xml | 22 +++++-------------- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/packages/stream_chat_v1/ios/fastlane/Fastfile b/packages/stream_chat_v1/ios/fastlane/Fastfile index 4ddcc99..98d4536 100644 --- a/packages/stream_chat_v1/ios/fastlane/Fastfile +++ b/packages/stream_chat_v1/ios/fastlane/Fastfile @@ -62,7 +62,7 @@ platform :ios do settings_to_override = { :BUNDLE_IDENTIFIER => "io.getstream.flutter", - :PROVISIONING_PROFILE_SPECIFIER => "match AppStore io.getstream.flutter" + :PROVISIONING_PROFILE_SPECIFIER => "match AppStore io.getstream.flutter 1620032657" } gym( diff --git a/packages/stream_chat_v1/ios/fastlane/beta_gym_export_options.plist b/packages/stream_chat_v1/ios/fastlane/beta_gym_export_options.plist index e88559a..3721528 100644 --- a/packages/stream_chat_v1/ios/fastlane/beta_gym_export_options.plist +++ b/packages/stream_chat_v1/ios/fastlane/beta_gym_export_options.plist @@ -7,7 +7,7 @@ provisioningProfiles io.getstream.flutter - match AdHoc io.getstream.flutter + match AdHoc io.getstream.flutter 1620032657 \ No newline at end of file diff --git a/packages/stream_chat_v1/ios/fastlane/report.xml b/packages/stream_chat_v1/ios/fastlane/report.xml index 42d2518..268d605 100644 --- a/packages/stream_chat_v1/ios/fastlane/report.xml +++ b/packages/stream_chat_v1/ios/fastlane/report.xml @@ -5,39 +5,27 @@ - + - + - + - + - - - - - - - - - - - - - + From 9612bb178603d371a635e6d881f983d1874e40ca Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 3 May 2021 11:39:38 +0200 Subject: [PATCH 03/48] fix build --- packages/stream_chat_v1/ios/Gemfile.lock | 2 +- .../ios/Runner.xcodeproj/project.pbxproj | 6 +++--- .../stream_chat_v1/ios/fastlane/report.xml | 20 ++++++++++++++----- packages/stream_chat_v1/pubspec.yaml | 2 +- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/packages/stream_chat_v1/ios/Gemfile.lock b/packages/stream_chat_v1/ios/Gemfile.lock index dc0ee04..2fb0757 100644 --- a/packages/stream_chat_v1/ios/Gemfile.lock +++ b/packages/stream_chat_v1/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.2.3) + fastlane-plugin-firebase_app_distribution (0.2.7) gh_inspector (1.1.3) google-api-client (0.38.0) addressable (~> 2.5, >= 2.5.1) diff --git a/packages/stream_chat_v1/ios/Runner.xcodeproj/project.pbxproj b/packages/stream_chat_v1/ios/Runner.xcodeproj/project.pbxproj index 8cd3ed0..ccb925f 100644 --- a/packages/stream_chat_v1/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/stream_chat_v1/ios/Runner.xcodeproj/project.pbxproj @@ -447,7 +447,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter"; + PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter 1620032657"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -586,7 +586,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter"; + PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter 1620032657"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -620,7 +620,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = io.getstream.flutter; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter"; + PROVISIONING_PROFILE_SPECIFIER = "match AdHoc io.getstream.flutter 1620032657"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; diff --git a/packages/stream_chat_v1/ios/fastlane/report.xml b/packages/stream_chat_v1/ios/fastlane/report.xml index 268d605..55d4f11 100644 --- a/packages/stream_chat_v1/ios/fastlane/report.xml +++ b/packages/stream_chat_v1/ios/fastlane/report.xml @@ -5,27 +5,37 @@ - + - + - + - + - + + + + + + + + + + + diff --git a/packages/stream_chat_v1/pubspec.yaml b/packages/stream_chat_v1/pubspec.yaml index a45698a..35af177 100644 --- a/packages/stream_chat_v1/pubspec.yaml +++ b/packages/stream_chat_v1/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. publish_to: 'none' -version: 1.5.4 +version: 1.5.4+1 environment: sdk: ">=2.2.2 <3.0.0" From 6d1db8d4bfa381bd4abadf8acf437ba808045a50 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 12 May 2021 16:54:44 +0200 Subject: [PATCH 04/48] upgrade dependencies --- .../lib/channel_file_display_screen.dart | 36 ++++++++-------- .../lib/channel_media_display_screen.dart | 41 +++++++++---------- .../stream_chat_v1/lib/chat_info_screen.dart | 27 ++++++------ .../stream_chat_v1/lib/group_info_screen.dart | 27 +++++++----- packages/stream_chat_v1/lib/main.dart | 40 ++++++++---------- .../stream_chat_v1/lib/new_chat_screen.dart | 23 +++++------ .../lib/new_group_chat_screen.dart | 12 ++---- .../stream_chat_v1/lib/routes/app_routes.dart | 9 ++-- packages/stream_chat_v1/pubspec.yaml | 18 ++++---- packages/stream_chat_v1/test/widget_test.dart | 30 -------------- 10 files changed, 112 insertions(+), 151 deletions(-) delete mode 100644 packages/stream_chat_v1/test/widget_test.dart diff --git a/packages/stream_chat_v1/lib/channel_file_display_screen.dart b/packages/stream_chat_v1/lib/channel_file_display_screen.dart index a3e1c67..cbd5264 100644 --- a/packages/stream_chat_v1/lib/channel_file_display_screen.dart +++ b/packages/stream_chat_v1/lib/channel_file_display_screen.dart @@ -34,16 +34,14 @@ class _ChannelFileDisplayScreenState extends State { super.initState(); final messageSearchBloc = MessageSearchBloc.of(context); messageSearchBloc.search( - filter: { - 'cid': { - r'$in': [StreamChannel.of(context).channel.cid] - } - }, - messageFilter: { - 'attachments.type': { - r'$in': ['file'], - }, - }, + filter: Filter.in_( + 'cid', + [StreamChannel.of(context).channel.cid], + ), + messageFilter: Filter.in_( + 'attachments.type', + ['file'], + ), sort: widget.sortOptions, pagination: widget.paginationParams, ); @@ -142,16 +140,14 @@ class _ChannelFileDisplayScreenState extends State { return LazyLoadScrollView( onEndOfPage: () => messageSearchBloc.search( - filter: { - 'cid': { - r'$in': [StreamChannel.of(context).channel.cid] - } - }, - messageFilter: { - 'attachments.type': { - r'$in': ['file'] - }, - }, + filter: Filter.in_( + 'cid', + [StreamChannel.of(context).channel.cid], + ), + messageFilter: Filter.in_( + 'attachments.type', + ['file'], + ), sort: widget.sortOptions, pagination: widget.paginationParams.copyWith( offset: messageSearchBloc.messageResponses?.length ?? 0, diff --git a/packages/stream_chat_v1/lib/channel_media_display_screen.dart b/packages/stream_chat_v1/lib/channel_media_display_screen.dart index a0ed072..2bf0fb1 100644 --- a/packages/stream_chat_v1/lib/channel_media_display_screen.dart +++ b/packages/stream_chat_v1/lib/channel_media_display_screen.dart @@ -20,7 +20,10 @@ class ChannelMediaDisplayScreen extends StatefulWidget { final ShowMessageCallback onShowMessage; + final MessageTheme messageTheme; + const ChannelMediaDisplayScreen({ + @required this.messageTheme, this.sortOptions, this.paginationParams, this.emptyBuilder, @@ -40,16 +43,14 @@ class _ChannelMediaDisplayScreenState extends State { super.initState(); final messageSearchBloc = MessageSearchBloc.of(context); messageSearchBloc.search( - filter: { - 'cid': { - r'$in': [StreamChannel.of(context).channel.cid], - } - }, - messageFilter: { - 'attachments.type': { - r'$in': ['image', 'video'] - }, - }, + filter: Filter.in_( + 'cid', + [StreamChannel.of(context).channel.cid], + ), + messageFilter: Filter.in_( + 'attachments.type', + ['image', 'video'], + ), sort: widget.sortOptions, pagination: widget.paginationParams, ); @@ -165,16 +166,14 @@ class _ChannelMediaDisplayScreenState extends State { return LazyLoadScrollView( onEndOfPage: () => messageSearchBloc.search( - filter: { - 'cid': { - r'$in': [StreamChannel.of(context).channel.cid] - } - }, - messageFilter: { - 'attachments.type': { - r'$in': ['image', 'video'] - }, - }, + filter: Filter.in_( + 'cid', + [StreamChannel.of(context).channel.cid], + ), + messageFilter: Filter.in_( + 'attachments.type', + ['image', 'video'], + ), sort: widget.sortOptions, pagination: widget.paginationParams.copyWith( offset: messageSearchBloc.messageResponses?.length ?? 0, @@ -199,7 +198,6 @@ class _ChannelMediaDisplayScreenState extends State { media.map((e) => e.attachment).toList(), startIndex: position, message: media[position].message, - sentAt: media[position].message.createdAt, userName: media[position].message.user.name, onShowMessage: widget.onShowMessage, ), @@ -217,6 +215,7 @@ class _ChannelMediaDisplayScreenState extends State { MediaQuery.of(context).size.width * 0.8, MediaQuery.of(context).size.height * 0.3, ), + messageTheme: widget.messageTheme, ), ) : VideoPlayer(media[position].videoPlayer), diff --git a/packages/stream_chat_v1/lib/chat_info_screen.dart b/packages/stream_chat_v1/lib/chat_info_screen.dart index 38fbb70..99611c8 100644 --- a/packages/stream_chat_v1/lib/chat_info_screen.dart +++ b/packages/stream_chat_v1/lib/chat_info_screen.dart @@ -13,7 +13,13 @@ class ChatInfoScreen extends StatefulWidget { /// User in consideration final User user; - const ChatInfoScreen({Key key, this.user}) : super(key: key); + final MessageTheme messageTheme; + + const ChatInfoScreen({ + Key key, + @required this.messageTheme, + this.user, + }) : super(key: key); @override _ChatInfoScreenState createState() => _ChatInfoScreenState(); @@ -217,6 +223,7 @@ class _ChatInfoScreenState extends State { channel: channel, child: MessageSearchBloc( child: ChannelMediaDisplayScreen( + messageTheme: widget.messageTheme, sortOptions: [ SortOption( 'created_at', @@ -445,20 +452,10 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { ), body: StreamBuilder>( stream: chat.client.queryChannels( - filter: { - r'$and': [ - { - 'members': { - r'$in': [widget.otherUser.id], - }, - }, - { - 'members': { - r'$in': [widget.mainUser.id], - }, - } - ], - }, + filter: Filter.and([ + Filter.in_('members', [widget.otherUser.id]), + Filter.in_('members', [widget.mainUser.id]), + ]), ), builder: (context, snapshot) { if (!snapshot.hasData) { diff --git a/packages/stream_chat_v1/lib/group_info_screen.dart b/packages/stream_chat_v1/lib/group_info_screen.dart index efe1808..d84826c 100644 --- a/packages/stream_chat_v1/lib/group_info_screen.dart +++ b/packages/stream_chat_v1/lib/group_info_screen.dart @@ -14,6 +14,13 @@ import 'main.dart'; import 'routes/routes.dart'; class GroupInfoScreen extends StatefulWidget { + final MessageTheme messageTheme; + + const GroupInfoScreen({ + Key key, + @required this.messageTheme, + }) : super(key: key); + @override _GroupInfoScreenState createState() => _GroupInfoScreenState(); } @@ -502,6 +509,7 @@ class _GroupInfoScreenState extends State { channel: channel, child: MessageSearchBloc( child: ChannelMediaDisplayScreen( + messageTheme: widget.messageTheme, sortOptions: [ SortOption( 'created_at', @@ -657,18 +665,16 @@ class _GroupInfoScreenState extends State { pagination: PaginationParams( limit: 25, ), - filter: { - if (_searchController.text.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$nin': [ + filter: Filter.and( + [ + if (_searchController.text.isNotEmpty) + Filter.autoComplete('name', _userNameQuery), + Filter.notIn('id', [ StreamChat.of(context).user.id, ...channel.state.members.map((e) => e.userId), - ], - }, - }, + ]), + ], + ), sort: [ SortOption( 'name', @@ -848,6 +854,7 @@ class _GroupInfoScreenState extends State { builder: (context) => StreamChannel( channel: c, child: ChatInfoScreen( + messageTheme: widget.messageTheme, user: user, ), ), diff --git a/packages/stream_chat_v1/lib/main.dart b/packages/stream_chat_v1/lib/main.dart index 4e93955..4610d55 100644 --- a/packages/stream_chat_v1/lib/main.dart +++ b/packages/stream_chat_v1/lib/main.dart @@ -498,16 +498,12 @@ class UserMentionPage extends StatelessWidget { final user = StreamChat.of(context).user; return MessageSearchBloc( child: MessageSearchListView( - filters: { - 'members': { - r'$in': [user.id], - }, - }, - messageFilters: { - 'mentioned_users.id': { - r'$contains': user.id, - }, - }, + filters: Filter.in_('members', [user.id]), + messageFilters: Filter.custom( + operator: 'contains', + key: 'mentioned_users.id', + value: user.id, + ), sortOptions: [ SortOption( 'created_at', @@ -651,11 +647,7 @@ class _ChannelListPageState extends State { ? MessageSearchListView( showErrorTile: true, messageQuery: _channelQuery, - filters: { - 'members': { - r'$in': [user.id] - }, - }, + filters: Filter.in_('members', [user.id]), sortOptions: [ SortOption( 'created_at', @@ -720,11 +712,7 @@ class _ChannelListPageState extends State { Navigator.pushNamed(context, Routes.NEW_CHAT); }, swipeToAction: true, - filter: { - 'members': { - r'$in': [user.id], - }, - }, + filter: Filter.in_('members', [user.id]), options: { 'presence': true, }, @@ -741,6 +729,8 @@ class _ChannelListPageState extends State { builder: (context) => StreamChannel( channel: channel, child: ChatInfoScreen( + messageTheme: StreamChatTheme.of(context) + .ownMessageTheme, user: channel.state.members .where((m) => m.userId != @@ -757,7 +747,10 @@ class _ChannelListPageState extends State { MaterialPageRoute( builder: (context) => StreamChannel( channel: channel, - child: GroupInfoScreen(), + child: GroupInfoScreen( + messageTheme: StreamChatTheme.of(context) + .ownMessageTheme, + ), ), ), ); @@ -843,6 +836,7 @@ class _ChannelPageState extends State { MaterialPageRoute( builder: (context) => StreamChannel( child: ChatInfoScreen( + messageTheme: StreamChatTheme.of(context).ownMessageTheme, user: otherUser.user, ), channel: channel, @@ -859,7 +853,9 @@ class _ChannelPageState extends State { context, MaterialPageRoute( builder: (context) => StreamChannel( - child: GroupInfoScreen(), + child: GroupInfoScreen( + messageTheme: StreamChatTheme.of(context).ownMessageTheme, + ), channel: channel, ), ), diff --git a/packages/stream_chat_v1/lib/new_chat_screen.dart b/packages/stream_chat_v1/lib/new_chat_screen.dart index d4a6888..fac0ed0 100644 --- a/packages/stream_chat_v1/lib/new_chat_screen.dart +++ b/packages/stream_chat_v1/lib/new_chat_screen.dart @@ -70,13 +70,13 @@ class _NewChatScreenState extends State { 'state': false, 'watch': false, }, - filter: { - 'members': [ + filter: Filter.and([ + Filter.equal('members', [ ..._selectedUsers.map((e) => e.id), chatState.user.id, - ], - 'distinct': true, - }, + ]), + Filter.equal('distinct', true), + ]), messageLimit: 0, paginationParams: PaginationParams( limit: 1, @@ -308,15 +308,12 @@ class _NewChatScreenState extends State { pagination: PaginationParams( limit: 25, ), - filter: { + filter: Filter.and([ if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - }, - }, + Filter.autoComplete('name', _userNameQuery), + Filter.notEqual( + 'id', StreamChat.of(context).user.id), + ]), sort: [ SortOption( 'name', diff --git a/packages/stream_chat_v1/lib/new_group_chat_screen.dart b/packages/stream_chat_v1/lib/new_group_chat_screen.dart index 209d372..9944572 100644 --- a/packages/stream_chat_v1/lib/new_group_chat_screen.dart +++ b/packages/stream_chat_v1/lib/new_group_chat_screen.dart @@ -244,15 +244,11 @@ class _NewGroupChatScreenState extends State { pagination: PaginationParams( limit: 25, ), - filter: { + filter: Filter.and([ if (_userNameQuery.isNotEmpty) - 'name': { - r'$autocomplete': _userNameQuery, - }, - 'id': { - r'$ne': StreamChat.of(context).user.id, - } - }, + Filter.autoComplete('name', _userNameQuery), + Filter.notEqual('id', StreamChat.of(context).user.id), + ]), sort: [ SortOption( 'name', diff --git a/packages/stream_chat_v1/lib/routes/app_routes.dart b/packages/stream_chat_v1/lib/routes/app_routes.dart index c641b04..1be8bf7 100644 --- a/packages/stream_chat_v1/lib/routes/app_routes.dart +++ b/packages/stream_chat_v1/lib/routes/app_routes.dart @@ -74,16 +74,19 @@ class AppRoutes { case Routes.CHAT_INFO_SCREEN: return MaterialPageRoute( settings: const RouteSettings(name: Routes.CHAT_INFO_SCREEN), - builder: (_) { + builder: (context) { return ChatInfoScreen( user: args, + messageTheme: StreamChatTheme.of(context).ownMessageTheme, ); }); case Routes.GROUP_INFO_SCREEN: return MaterialPageRoute( settings: const RouteSettings(name: Routes.GROUP_INFO_SCREEN), - builder: (_) { - return GroupInfoScreen(); + builder: (context) { + return GroupInfoScreen( + messageTheme: StreamChatTheme.of(context).ownMessageTheme, + ); }); // Default case, should not reach here. default: diff --git a/packages/stream_chat_v1/pubspec.yaml b/packages/stream_chat_v1/pubspec.yaml index 35af177..464d235 100644 --- a/packages/stream_chat_v1/pubspec.yaml +++ b/packages/stream_chat_v1/pubspec.yaml @@ -7,7 +7,7 @@ environment: sdk: ">=2.2.2 <3.0.0" dependencies: - flutter_app_badger: ^1.1.2 + flutter_app_badger: ^1.2.0 flutter: sdk: flutter stream_chat_flutter: @@ -20,13 +20,13 @@ dependencies: url: https://github.com/GetStream/stream-chat-flutter.git ref: develop path: packages/stream_chat_persistence - flutter_local_notifications: ^2.0.2 - flutter_svg: ^0.19.3 - flutter_secure_storage: ^3.3.5 - yaml: ^2.2.1 - uuid: ^2.2.2 - streaming_shared_preferences: ^1.0.2 - lottie: ^0.7.0+1 + flutter_local_notifications: ^5.0.0+4 + flutter_svg: ^0.22.0 + flutter_secure_storage: ^4.2.0 + yaml: ^3.1.0 + uuid: ^3.0.4 + streaming_shared_preferences: ^2.0.0 + lottie: ^1.0.1 dependency_overrides: stream_chat: @@ -41,7 +41,7 @@ dependency_overrides: path: packages/stream_chat_flutter_core dev_dependencies: - flutter_launcher_icons: ^0.8.1 + flutter_launcher_icons: ^0.9.0 test: any flutter: diff --git a/packages/stream_chat_v1/test/widget_test.dart b/packages/stream_chat_v1/test/widget_test.dart deleted file mode 100644 index 2d257c0..0000000 --- a/packages/stream_chat_v1/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:stream_chat_v1/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 0303e18945569b7dba6c753d805914930acfa3d0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 12 May 2021 17:01:51 +0200 Subject: [PATCH 05/48] migrate sample app --- .../lib/advanced_options_page.dart | 14 +- .../lib/channel_file_display_screen.dart | 18 +-- .../lib/channel_media_display_screen.dart | 36 ++--- .../stream_chat_v1/lib/chat_info_screen.dart | 64 ++++---- .../lib/chips_input_text_field.dart | 20 +-- .../lib/group_chat_details_screen.dart | 16 +- .../stream_chat_v1/lib/group_info_screen.dart | 120 +++++++-------- packages/stream_chat_v1/lib/main.dart | 142 +++++++++--------- .../stream_chat_v1/lib/new_chat_screen.dart | 36 ++--- .../lib/new_group_chat_screen.dart | 16 +- .../lib/notifications_service.dart | 8 +- .../stream_chat_v1/lib/routes/app_routes.dart | 8 +- .../stream_chat_v1/lib/search_text_field.dart | 16 +- .../stream_chat_v1/lib/stream_version.dart | 4 +- packages/stream_chat_v1/pubspec.yaml | 3 +- 15 files changed, 261 insertions(+), 260 deletions(-) diff --git a/packages/stream_chat_v1/lib/advanced_options_page.dart b/packages/stream_chat_v1/lib/advanced_options_page.dart index a654f3d..b4a4326 100644 --- a/packages/stream_chat_v1/lib/advanced_options_page.dart +++ b/packages/stream_chat_v1/lib/advanced_options_page.dart @@ -17,13 +17,13 @@ class _AdvancedOptionsPageState extends State { final _formKey = GlobalKey(); final TextEditingController _apiKeyController = TextEditingController(); - String _apiKeyError; + String? _apiKeyError; final TextEditingController _userIdController = TextEditingController(); - String _userIdError; + String? _userIdError; final TextEditingController _userTokenController = TextEditingController(); - String _userTokenError; + String? _userTokenError; final TextEditingController _usernameController = TextEditingController(); @@ -73,7 +73,7 @@ class _AdvancedOptionsPageState extends State { } }, validator: (value) { - if (value.isEmpty) { + if (value!.isEmpty) { setState(() { _apiKeyError = 'Please enter the Chat API Key'.toUpperCase(); @@ -119,7 +119,7 @@ class _AdvancedOptionsPageState extends State { } }, validator: (value) { - if (value.isEmpty) { + if (value!.isEmpty) { setState(() { _userIdError = 'Please enter the User ID'.toUpperCase(); @@ -165,7 +165,7 @@ class _AdvancedOptionsPageState extends State { }, controller: _userTokenController, validator: (value) { - if (value.isEmpty) { + if (value!.isEmpty) { setState(() { _userTokenError = 'Please enter the user token'.toUpperCase(); @@ -243,7 +243,7 @@ class _AdvancedOptionsPageState extends State { if (loading) { return; } - if (_formKey.currentState.validate()) { + if (_formKey.currentState!.validate()) { final apiKey = _apiKeyController.text; final userId = _userIdController.text; final userToken = _userTokenController.text; diff --git a/packages/stream_chat_v1/lib/channel_file_display_screen.dart b/packages/stream_chat_v1/lib/channel_file_display_screen.dart index cbd5264..806f184 100644 --- a/packages/stream_chat_v1/lib/channel_file_display_screen.dart +++ b/packages/stream_chat_v1/lib/channel_file_display_screen.dart @@ -6,16 +6,16 @@ class ChannelFileDisplayScreen extends StatefulWidget { /// 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; + 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; + final PaginationParams? paginationParams; /// The builder used when the file list is empty. - final WidgetBuilder emptyBuilder; + final WidgetBuilder? emptyBuilder; const ChannelFileDisplayScreen({ this.sortOptions, @@ -36,7 +36,7 @@ class _ChannelFileDisplayScreenState extends State { messageSearchBloc.search( filter: Filter.in_( 'cid', - [StreamChannel.of(context).channel.cid], + [StreamChannel.of(context).channel.cid!], ), messageFilter: Filter.in_( 'attachments.type', @@ -93,9 +93,9 @@ class _ChannelFileDisplayScreenState extends State { ); } - if (snapshot.data.isEmpty) { + if (snapshot.data!.isEmpty) { if (widget.emptyBuilder != null) { - return widget.emptyBuilder(context); + return widget.emptyBuilder!(context); } return Center( child: Column( @@ -132,7 +132,7 @@ class _ChannelFileDisplayScreenState extends State { final media = {}; - for (var item in snapshot.data) { + for (var item in snapshot.data!) { item.message.attachments.where((e) => e.type == 'file').forEach((e) { media[e] = item.message; }); @@ -142,14 +142,14 @@ class _ChannelFileDisplayScreenState extends State { onEndOfPage: () => messageSearchBloc.search( filter: Filter.in_( 'cid', - [StreamChannel.of(context).channel.cid], + [StreamChannel.of(context).channel.cid!], ), messageFilter: Filter.in_( 'attachments.type', ['file'], ), sort: widget.sortOptions, - pagination: widget.paginationParams.copyWith( + pagination: widget.paginationParams!.copyWith( offset: messageSearchBloc.messageResponses?.length ?? 0, ), ), diff --git a/packages/stream_chat_v1/lib/channel_media_display_screen.dart b/packages/stream_chat_v1/lib/channel_media_display_screen.dart index 2bf0fb1..5c33622 100644 --- a/packages/stream_chat_v1/lib/channel_media_display_screen.dart +++ b/packages/stream_chat_v1/lib/channel_media_display_screen.dart @@ -7,23 +7,23 @@ class ChannelMediaDisplayScreen extends StatefulWidget { /// 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; + 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; + final PaginationParams? paginationParams; /// The builder used when the file list is empty. - final WidgetBuilder emptyBuilder; + final WidgetBuilder? emptyBuilder; - final ShowMessageCallback onShowMessage; + final ShowMessageCallback? onShowMessage; final MessageTheme messageTheme; const ChannelMediaDisplayScreen({ - @required this.messageTheme, + required this.messageTheme, this.sortOptions, this.paginationParams, this.emptyBuilder, @@ -36,7 +36,7 @@ class ChannelMediaDisplayScreen extends StatefulWidget { } class _ChannelMediaDisplayScreenState extends State { - Map controllerCache = {}; + Map controllerCache = {}; @override void initState() { @@ -45,7 +45,7 @@ class _ChannelMediaDisplayScreenState extends State { messageSearchBloc.search( filter: Filter.in_( 'cid', - [StreamChannel.of(context).channel.cid], + [StreamChannel.of(context).channel.cid!], ), messageFilter: Filter.in_( 'attachments.type', @@ -103,9 +103,9 @@ class _ChannelMediaDisplayScreenState extends State { ); } - if (snapshot.data.isEmpty) { + if (snapshot.data!.isEmpty) { if (widget.emptyBuilder != null) { - return widget.emptyBuilder(context); + return widget.emptyBuilder!(context); } return Center( child: Column( @@ -142,18 +142,18 @@ class _ChannelMediaDisplayScreenState extends State { final media = <_AssetPackage>[]; - for (var item in snapshot.data) { + for (var item in snapshot.data!) { item.message.attachments .where((e) => (e.type == 'image' || e.type == 'video') && e.ogScrapeUrl == null) .forEach((e) { - VideoPlayerController controller; + VideoPlayerController? controller; if (e.type == 'video') { var cachedController = controllerCache[e.assetUrl]; if (cachedController == null) { - controller = VideoPlayerController.network(e.assetUrl); + controller = VideoPlayerController.network(e.assetUrl!); controller.initialize(); controllerCache[e.assetUrl] = controller; } else { @@ -168,14 +168,14 @@ class _ChannelMediaDisplayScreenState extends State { onEndOfPage: () => messageSearchBloc.search( filter: Filter.in_( 'cid', - [StreamChannel.of(context).channel.cid], + [StreamChannel.of(context).channel.cid!], ), messageFilter: Filter.in_( 'attachments.type', ['image', 'video'], ), sort: widget.sortOptions, - pagination: widget.paginationParams.copyWith( + pagination: widget.paginationParams!.copyWith( offset: messageSearchBloc.messageResponses?.length ?? 0, ), ), @@ -198,7 +198,7 @@ class _ChannelMediaDisplayScreenState extends State { media.map((e) => e.attachment).toList(), startIndex: position, message: media[position].message, - userName: media[position].message.user.name, + userName: media[position].message.user!.name, onShowMessage: widget.onShowMessage, ), ), @@ -218,7 +218,7 @@ class _ChannelMediaDisplayScreenState extends State { messageTheme: widget.messageTheme, ), ) - : VideoPlayer(media[position].videoPlayer), + : VideoPlayer(media[position].videoPlayer!), ), ); }, @@ -234,7 +234,7 @@ class _ChannelMediaDisplayScreenState extends State { void dispose() { super.dispose(); for (var c in controllerCache.values) { - c.dispose(); + c!.dispose(); } } } @@ -242,7 +242,7 @@ class _ChannelMediaDisplayScreenState extends State { class _AssetPackage { Attachment attachment; Message message; - VideoPlayerController videoPlayer; + VideoPlayerController? videoPlayer; _AssetPackage(this.attachment, this.message, this.videoPlayer); } diff --git a/packages/stream_chat_v1/lib/chat_info_screen.dart b/packages/stream_chat_v1/lib/chat_info_screen.dart index 99611c8..8a09f43 100644 --- a/packages/stream_chat_v1/lib/chat_info_screen.dart +++ b/packages/stream_chat_v1/lib/chat_info_screen.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; @@ -11,13 +12,13 @@ import 'routes/routes.dart'; /// Detail screen for a 1:1 chat correspondence class ChatInfoScreen extends StatefulWidget { /// User in consideration - final User user; + final User? user; final MessageTheme messageTheme; const ChatInfoScreen({ - Key key, - @required this.messageTheme, + Key? key, + required this.messageTheme, this.user, }) : super(key: key); @@ -26,7 +27,7 @@ class ChatInfoScreen extends StatefulWidget { } class _ChatInfoScreenState extends State { - ValueNotifier mutedBool = ValueNotifier(false); + ValueNotifier mutedBool = ValueNotifier(false); @override void initState() { @@ -54,9 +55,8 @@ class _ChatInfoScreenState extends State { if ([ 'admin', 'owner', - ].contains(channel.state.members - .firstWhere((m) => m.userId == channel.client.state.user.id, - orElse: () => null) + ].contains(channel.state!.members + .firstWhereOrNull((m) => m.userId == channel.client.state.user!.id) ?.role)) _buildDeleteListTile(), ], @@ -76,7 +76,7 @@ class _ChatInfoScreenState extends State { Padding( padding: const EdgeInsets.all(16.0), child: UserAvatar( - user: widget.user, + user: widget.user!, constraints: BoxConstraints( maxWidth: 72.0, maxHeight: 72.0, @@ -86,19 +86,19 @@ class _ChatInfoScreenState extends State { ), ), Text( - widget.user.name, + 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}', + title: '@${widget.user!.id}', tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, trailing: Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text( - widget.user.name, + widget.user!.name, style: TextStyle( color: StreamChatTheme.of(context) .colorTheme @@ -161,15 +161,15 @@ class _ChatInfoScreenState extends State { ), trailing: snapshot.data == null ? CircularProgressIndicator() - : ValueListenableBuilder( + : ValueListenableBuilder( valueListenable: mutedBool, builder: (context, value, _) { return CupertinoSwitch( - value: value, + value: value!, onChanged: (val) { mutedBool.value = val; - if (snapshot.data) { + if (snapshot.data!) { channel.channel.unmute(); } else { channel.channel.mute(); @@ -394,7 +394,7 @@ class _ChatInfoScreenState extends State { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - if (widget.user.online) + if (widget.user!.online) Material( type: MaterialType.circle, child: Container( @@ -411,7 +411,7 @@ class _ChatInfoScreenState extends State { color: StreamChatTheme.of(context).colorTheme.white, ), alternativeWidget, - if (widget.user.online) + if (widget.user!.online) SizedBox( width: 24.0, ), @@ -421,8 +421,8 @@ class _ChatInfoScreenState extends State { } class _SharedGroupsScreen extends StatefulWidget { - final User mainUser; - final User otherUser; + final User? mainUser; + final User? otherUser; _SharedGroupsScreen(this.mainUser, this.otherUser); @@ -453,8 +453,8 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { body: StreamBuilder>( stream: chat.client.queryChannels( filter: Filter.and([ - Filter.in_('members', [widget.otherUser.id]), - Filter.in_('members', [widget.mainUser.id]), + Filter.in_('members', [widget.otherUser!.id]), + Filter.in_('members', [widget.mainUser!.id]), ]), ), builder: (context, snapshot) { @@ -464,7 +464,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { ); } - if (snapshot.data.isEmpty) { + if (snapshot.data!.isEmpty) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -498,11 +498,11 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { ); } - final channels = snapshot.data + final channels = snapshot.data! .where((c) => - c.state.members.any((m) => - m.userId != widget.mainUser.id && - m.userId != widget.otherUser.id) || + c.state!.members.any((m) => + m.userId != widget.mainUser!.id && + m.userId != widget.otherUser!.id) || !c.isDistinct) .toList(); @@ -522,24 +522,24 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { Widget _buildListTile(Channel channel) { var extraData = channel.extraData; - var members = channel.state.members; + 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; + String? title; if (extraData['name'] == null) { final otherMembers = members.where( - (member) => member.userId != StreamChat.of(context).user.id); + (member) => member.userId != StreamChat.of(context).user!.id); if (otherMembers.isNotEmpty) { final maxWidth = constraints.maxWidth; - final maxChars = maxWidth / textStyle.fontSize; + final maxChars = maxWidth / textStyle.fontSize!; var currentChars = 0; final currentMembers = []; otherMembers.forEach((element) { - final newLength = currentChars + element.user.name.length; + final newLength = currentChars + element.user!.name.length; if (newLength < maxChars) { currentChars = newLength; currentMembers.add(element); @@ -549,7 +549,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { final exceedingMembers = otherMembers.length - currentMembers.length; title = - '${currentMembers.map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; + '${currentMembers.map((e) => e.user!.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; } else { title = 'No title'; } @@ -572,7 +572,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { ), Expanded( child: Text( - title, + title!, style: textStyle, )), Padding( diff --git a/packages/stream_chat_v1/lib/chips_input_text_field.dart b/packages/stream_chat_v1/lib/chips_input_text_field.dart index 0fc0791..c36e4ae 100644 --- a/packages/stream_chat_v1/lib/chips_input_text_field.dart +++ b/packages/stream_chat_v1/lib/chips_input_text_field.dart @@ -6,18 +6,18 @@ 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 TextEditingController? controller; + final FocusNode? focusNode; + final ValueChanged? onInputChanged; final ChipBuilder chipBuilder; - final OnChipAdded onChipAdded; - final OnChipRemoved onChipRemoved; + final OnChipAdded? onChipAdded; + final OnChipRemoved? onChipRemoved; final String hint; const ChipsInputTextField({ - Key key, - @required this.chipBuilder, - @required this.controller, + Key? key, + required this.chipBuilder, + required this.controller, this.onInputChanged, this.focusNode, this.onChipAdded, @@ -35,7 +35,7 @@ class ChipInputTextFieldState extends State> { void addItem(T item) { setState(() => _chips.add(item)); - if (widget.onChipAdded != null) widget.onChipAdded(item); + if (widget.onChipAdded != null) widget.onChipAdded!(item); } void removeItem(T item) { @@ -43,7 +43,7 @@ class ChipInputTextFieldState extends State> { _chips.remove(item); if (_chips.isEmpty) resumeItemAddition(); }); - if (widget.onChipRemoved != null) widget.onChipRemoved(item); + if (widget.onChipRemoved != null) widget.onChipRemoved!(item); } void pauseItemAddition() { diff --git a/packages/stream_chat_v1/lib/group_chat_details_screen.dart b/packages/stream_chat_v1/lib/group_chat_details_screen.dart index afc9d12..1819fe8 100644 --- a/packages/stream_chat_v1/lib/group_chat_details_screen.dart +++ b/packages/stream_chat_v1/lib/group_chat_details_screen.dart @@ -6,11 +6,11 @@ import 'main.dart'; import 'routes/routes.dart'; class GroupChatDetailsScreen extends StatefulWidget { - final List selectedUsers; + final List? selectedUsers; const GroupChatDetailsScreen({ - Key key, - @required this.selectedUsers, + Key? key, + required this.selectedUsers, }) : super(key: key); @override @@ -20,14 +20,14 @@ class GroupChatDetailsScreen extends StatefulWidget { class _GroupChatDetailsScreenState extends State { final _selectedUsers = []; - TextEditingController _groupNameController; + TextEditingController? _groupNameController; bool _isGroupNameEmpty = true; int get _totalUsers => _selectedUsers.length; void _groupNameListener() { - final name = _groupNameController.text; + final name = _groupNameController!.text; if (mounted) { setState(() { _isGroupNameEmpty = name.isEmpty; @@ -38,7 +38,7 @@ class _GroupChatDetailsScreenState extends State { @override void initState() { super.initState(); - _selectedUsers.addAll(widget.selectedUsers); + _selectedUsers.addAll(widget.selectedUsers!); _groupNameController = TextEditingController() ..addListener(_groupNameListener); } @@ -124,13 +124,13 @@ class _GroupChatDetailsScreenState extends State { ? null : () async { try { - final groupName = _groupNameController.text; + final groupName = _groupNameController!.text; final client = StreamChat.of(context).client; final channel = client.channel('messaging', id: Uuid().v4(), extraData: { 'members': [ - client.state.user.id, + client.state.user!.id, ..._selectedUsers.map((e) => e.id), ], 'name': groupName, diff --git a/packages/stream_chat_v1/lib/group_info_screen.dart b/packages/stream_chat_v1/lib/group_info_screen.dart index d84826c..00e3966 100644 --- a/packages/stream_chat_v1/lib/group_info_screen.dart +++ b/packages/stream_chat_v1/lib/group_info_screen.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; @@ -17,8 +18,8 @@ class GroupInfoScreen extends StatefulWidget { final MessageTheme messageTheme; const GroupInfoScreen({ - Key key, - @required this.messageTheme, + Key? key, + required this.messageTheme, }) : super(key: key); @override @@ -26,29 +27,29 @@ class GroupInfoScreen extends StatefulWidget { } class _GroupInfoScreenState extends State { - TextEditingController _nameController; + TextEditingController? _nameController; - TextEditingController _searchController; + TextEditingController? _searchController; String _userNameQuery = ''; - Timer _debounce; - Function modalSetStateCallback; + Timer? _debounce; + Function? modalSetStateCallback; final FocusNode _focusNode = FocusNode(); bool listExpanded = false; - ValueNotifier mutedBool = ValueNotifier(false); + ValueNotifier mutedBool = ValueNotifier(false); void _userNameListener() { - if (_searchController.text == _userNameQuery) { + if (_searchController!.text == _userNameQuery) { return; } - if (_debounce?.isActive ?? false) _debounce.cancel(); + if (_debounce?.isActive ?? false) _debounce!.cancel(); _debounce = Timer(const Duration(milliseconds: 350), () { if (mounted && modalSetStateCallback != null) { - modalSetStateCallback(() { - _userNameQuery = _searchController.text; + modalSetStateCallback!(() { + _userNameQuery = _searchController!.text; }); } }); @@ -62,7 +63,7 @@ class _GroupInfoScreenState extends State { TextEditingValue(text: channel.channel.extraData['name'] ?? '')); _searchController = TextEditingController()..addListener(_userNameListener); - _nameController.addListener(() { + _nameController!.addListener(() { setState(() {}); }); mutedBool = ValueNotifier(StreamChannel.of(context).channel.isMuted); @@ -73,7 +74,7 @@ class _GroupInfoScreenState extends State { var channel = StreamChannel.of(context); return StreamBuilder>( - stream: channel.channel.state.membersStream, + stream: channel.channel.state!.membersStream, builder: (context, snapshot) { if (!snapshot.hasData) { return Container( @@ -82,9 +83,8 @@ class _GroupInfoScreenState extends State { ); } - var userMember = snapshot.data.firstWhere( - (e) => e.user.id == StreamChat.of(context).user.id, - orElse: () => null, + var userMember = snapshot.data!.firstWhereOrNull( + (e) => e.user!.id == StreamChat.of(context).user!.id, ); var isOwner = userMember?.role == 'owner'; @@ -118,9 +118,9 @@ class _GroupInfoScreenState extends State { _getChannelName( 2 * MediaQuery.of(context).size.width / 3, members: snapshot.data, - extraData: state.data.channel.extraData, + extraData: state.data!.channel!.extraData, maxFontSize: 16.0, - ), + )!, style: TextStyle( color: StreamChatTheme.of(context).colorTheme.black, fontSize: 16, @@ -133,7 +133,7 @@ class _GroupInfoScreenState extends State { height: 3.0, ), Text( - '${channel.channel.memberCount} Members, ${snapshot?.data?.where((e) => e.user.online)?.length ?? 0} Online', + '${channel.channel.memberCount} Members, ${snapshot.data?.where((e) => e.user!.online).length ?? 0} Online', style: TextStyle( color: StreamChatTheme.of(context) .colorTheme @@ -165,7 +165,7 @@ class _GroupInfoScreenState extends State { ), body: ListView( children: [ - _buildMembers(snapshot.data), + _buildMembers(snapshot.data!), Container( height: 8.0, color: StreamChatTheme.of(context).colorTheme.greyGainsboro, @@ -204,9 +204,8 @@ class _GroupInfoScreenState extends State { return Material( child: InkWell( onTap: () { - final userMember = groupMembers.firstWhere( - (e) => e.user.id == StreamChat.of(context).user.id, - orElse: () => null, + final userMember = groupMembers.firstWhereOrNull( + (e) => e.user!.id == StreamChat.of(context).user!.id, ); _showUserInfoModal(member.user, userMember?.role == 'owner'); }, @@ -220,7 +219,7 @@ class _GroupInfoScreenState extends State { padding: const EdgeInsets.symmetric( horizontal: 8.0, vertical: 12.0), child: UserAvatar( - user: member.user, + user: member.user!, constraints: BoxConstraints( maxHeight: 40.0, maxWidth: 40.0), ), @@ -231,14 +230,14 @@ class _GroupInfoScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - member.user.name, + member.user!.name, style: TextStyle(fontWeight: FontWeight.bold), ), SizedBox( height: 1.0, ), Text( - _getLastSeen(member.user), + _getLastSeen(member.user!), style: TextStyle( color: StreamChatTheme.of(context) .colorTheme @@ -378,7 +377,7 @@ class _GroupInfoScreenState extends State { ), ), if ((channelName == null) || - (channelName != _nameController.text.trim())) + (channelName != _nameController!.text.trim())) Row( mainAxisSize: MainAxisSize.min, children: [ @@ -386,12 +385,12 @@ class _GroupInfoScreenState extends State { child: StreamSvgIcon.closeSmall(), onTap: () { setState(() { - _nameController.text = _getChannelName( + _nameController!.text = _getChannelName( 2 * MediaQuery.of(context).size.width / 3, - members: channel.state.members, + members: channel.state!.members, extraData: channel.extraData, maxFontSize: 16.0, - ); + )!; _focusNode.unfocus(); }); }, @@ -406,10 +405,10 @@ class _GroupInfoScreenState extends State { ), onTap: () { StreamChannel.of(context).channel.update({ - 'name': _nameController.text.trim(), + 'name': _nameController!.text.trim(), }).catchError((err) { setState(() { - _nameController.text = channelName; + _nameController!.text = channelName; _focusNode.unfocus(); }); }); @@ -464,15 +463,15 @@ class _GroupInfoScreenState extends State { ), trailing: snapshot.data == null ? CircularProgressIndicator() - : ValueListenableBuilder( + : ValueListenableBuilder( valueListenable: mutedBool, builder: (context, value, _) { return CupertinoSwitch( - value: value, + value: value!, onChanged: (val) { mutedBool.value = val; - if (snapshot.data) { + if (snapshot.data!) { channel.channel.unmute(); } else { channel.channel.mute(); @@ -617,7 +616,7 @@ class _GroupInfoScreenState extends State { ); if (res == true) { final channel = StreamChannel.of(context).channel; - await channel.removeMembers([StreamChat.of(context).user.id]); + await channel.removeMembers([StreamChat.of(context).user!.id]); Navigator.pop(context); } }, @@ -655,7 +654,7 @@ class _GroupInfoScreenState extends State { child: UserListView( selectedUsers: {}, onUserTap: (user, _) async { - _searchController.clear(); + _searchController!.clear(); await channel.addMembers([user.id]); Navigator.pop(context); @@ -667,11 +666,12 @@ class _GroupInfoScreenState extends State { ), filter: Filter.and( [ - if (_searchController.text.isNotEmpty) + if (_searchController!.text.isNotEmpty) Filter.autoComplete('name', _userNameQuery), Filter.notIn('id', [ - StreamChat.of(context).user.id, - ...channel.state.members.map((e) => e.userId), + StreamChat.of(context).user!.id, + ...channel.state!.members.map(((e) => e.userId!) + as Object Function(Member)), ]), ], ), @@ -784,7 +784,7 @@ class _GroupInfoScreenState extends State { ); } - void _showUserInfoModal(User user, bool isUserAdmin) { + void _showUserInfoModal(User? user, bool isUserAdmin) { var channel = StreamChannel.of(context).channel; showModalBottomSheet( @@ -804,7 +804,7 @@ class _GroupInfoScreenState extends State { ), Center( child: Text( - user.name, + user!.name, style: TextStyle( fontSize: 16.0, fontWeight: FontWeight.bold, @@ -814,7 +814,7 @@ class _GroupInfoScreenState extends State { SizedBox( height: 5.0, ), - _buildConnectedTitleState(user), + _buildConnectedTitleState(user)!, Center( child: Padding( padding: const EdgeInsets.all(16.0), @@ -828,7 +828,7 @@ class _GroupInfoScreenState extends State { ), ), ), - if (StreamChat.of(context).user.id != user.id) + if (StreamChat.of(context).user!.id != user.id) _buildModalListTile( context, StreamSvgIcon.user( @@ -842,7 +842,7 @@ class _GroupInfoScreenState extends State { var c = client.channel('messaging', extraData: { 'members': [ user.id, - StreamChat.of(context).user.id, + StreamChat.of(context).user!.id, ], }); @@ -862,7 +862,7 @@ class _GroupInfoScreenState extends State { ); }, ), - if (StreamChat.of(context).user.id != user.id) + if (StreamChat.of(context).user!.id != user.id) _buildModalListTile( context, StreamSvgIcon.message( @@ -876,7 +876,7 @@ class _GroupInfoScreenState extends State { var c = client.channel('messaging', extraData: { 'members': [ user.id, - StreamChat.of(context).user.id, + StreamChat.of(context).user!.id, ], }); @@ -894,7 +894,7 @@ class _GroupInfoScreenState extends State { }, ), if (!channel.isDistinct && - StreamChat.of(context).user.id != user.id && + StreamChat.of(context).user!.id != user.id && isUserAdmin) _buildModalListTile( context, @@ -906,7 +906,7 @@ class _GroupInfoScreenState extends State { // TODO: Add make owner implementation (Remaining from backend) }), if (!channel.isDistinct && - StreamChat.of(context).user.id != user.id && + StreamChat.of(context).user!.id != user.id && isUserAdmin) _buildModalListTile( context, @@ -941,7 +941,7 @@ class _GroupInfoScreenState extends State { ); } - Widget _buildConnectedTitleState(User user) { + Widget? _buildConnectedTitleState(User? user) { var alternativeWidget; final otherMember = user; @@ -973,7 +973,7 @@ class _GroupInfoScreenState extends State { Widget _buildModalListTile( BuildContext context, Widget leading, String title, VoidCallback onTap, - {Color color}) { + {Color? color}) { color ??= StreamChatTheme.of(context).colorTheme.black; return Material( @@ -1010,24 +1010,24 @@ class _GroupInfoScreenState extends State { ); } - String _getChannelName( + String? _getChannelName( double width, { - List members, - Map extraData, - double maxFontSize, + List? members, + required Map extraData, + double? maxFontSize, }) { - String title; + String? title; var client = StreamChat.of(context); if (extraData['name'] == null) { final otherMembers = - members.where((member) => member.user.id != client.user.id); + members!.where((member) => member.user!.id != client.user!.id); if (otherMembers.isNotEmpty) { final maxWidth = width; - final maxChars = maxWidth / maxFontSize; + final maxChars = maxWidth / maxFontSize!; var currentChars = 0; final currentMembers = []; otherMembers.forEach((element) { - final newLength = currentChars + element.user.name.length; + final newLength = currentChars + element.user!.name.length; if (newLength < maxChars) { currentChars = newLength; currentMembers.add(element); @@ -1036,7 +1036,7 @@ class _GroupInfoScreenState extends State { final exceedingMembers = otherMembers.length - currentMembers.length; title = - '${currentMembers.map((e) => e.user.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; + '${currentMembers.map((e) => e.user!.name).join(', ')} ${exceedingMembers > 0 ? '+ $exceedingMembers' : ''}'; } else { title = 'No title'; } diff --git a/packages/stream_chat_v1/lib/main.dart b/packages/stream_chat_v1/lib/main.dart index 4610d55..8b982e4 100644 --- a/packages/stream_chat_v1/lib/main.dart +++ b/packages/stream_chat_v1/lib/main.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:collection/collection.dart' show IterableExtension; import 'package:example/chat_info_screen.dart'; import 'package:example/choose_user_page.dart'; import 'package:example/group_info_screen.dart'; @@ -38,15 +39,15 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State with TickerProviderStateMixin { - InitData _initData; + InitData? _initData; bool _animCompleted = false; - Animation _animation, _scaleAnimation; - AnimationController _animationController, _scaleAnimationController; - Animation _colorAnimation; - int timeOfStartMs; + Animation? _animation, _scaleAnimation; + AnimationController? _animationController, _scaleAnimationController; + Animation? _colorAnimation; + late int timeOfStartMs; Future _initConnection() async { - String apiKey, userId, token; + String? apiKey, userId, token; if (!kIsWeb) { final secureStorage = FlutterSecureStorage(); @@ -84,7 +85,7 @@ class _MyAppState extends State with TickerProviderStateMixin { begin: 1.0, end: 1.5, ).animate(CurvedAnimation( - parent: _scaleAnimationController, + parent: _scaleAnimationController!, curve: Curves.easeInOutBack, )); @@ -98,21 +99,21 @@ class _MyAppState extends State with TickerProviderStateMixin { begin: 0.0, end: 1000.0, ).animate(CurvedAnimation( - parent: _animationController, + parent: _animationController!, curve: Curves.easeInOut, )); _colorAnimation = ColorTween( begin: Color(0xff005FFF), end: Color(0xff005FFF), ).animate(CurvedAnimation( - parent: _animationController, + parent: _animationController!, curve: Curves.easeInOut, )); _colorAnimation = ColorTween( begin: Color(0xff005FFF), end: Colors.transparent, ).animate(CurvedAnimation( - parent: _animationController, + parent: _animationController!, curve: Curves.easeInOut, )); } @@ -132,22 +133,22 @@ class _MyAppState extends State with TickerProviderStateMixin { var now = DateTime.now().millisecondsSinceEpoch; if (now - timeOfStartMs > 1500) { - SchedulerBinding.instance.addPostFrameCallback((timeStamp) { - _scaleAnimationController.forward().whenComplete(() { - _animationController.forward(); + SchedulerBinding.instance!.addPostFrameCallback((timeStamp) { + _scaleAnimationController?.forward().whenComplete(() { + _animationController?.forward(); }); }); } else { Future.delayed(Duration(milliseconds: 1500)).then((value) { - _scaleAnimationController.forward().whenComplete(() { - _animationController.forward(); + _scaleAnimationController?.forward().whenComplete(() { + _animationController?.forward(); }); }); } if (!kIsWeb) { - _initData.client.state?.totalUnreadCountStream?.listen((count) { - if (count > 0) { + _initData!.client.state.totalUnreadCountStream.listen((count) { + if (count! > 0) { FlutterAppBadger.updateBadgeCount(count); } else { FlutterAppBadger.removeBadge(); @@ -156,7 +157,7 @@ class _MyAppState extends State with TickerProviderStateMixin { } }, ); - _animationController.addStatusListener((status) { + _animationController?.addStatusListener((status) { if (status == AnimationStatus.completed) { setState(() { _animCompleted = true; @@ -174,20 +175,20 @@ class _MyAppState extends State with TickerProviderStateMixin { alignment: Alignment.center, children: [ AnimatedBuilder( - animation: _scaleAnimation, + animation: _scaleAnimation!, builder: (context, _) { return Transform.scale( - scale: _scaleAnimation.value, + scale: _scaleAnimation!.value, child: AnimatedBuilder( - animation: _colorAnimation, + animation: _colorAnimation!, builder: (context, snapshot) { return Container( alignment: Alignment.center, constraints: BoxConstraints.expand(), color: _colorAnimation == null ? Color(0xff005FFF) - : _colorAnimation.value, - child: !_animationController.isAnimating + : _colorAnimation!.value, + child: !_animationController!.isAnimating ? Lottie.asset( 'assets/floating_boat.json', alignment: Alignment.center, @@ -199,16 +200,16 @@ class _MyAppState extends State with TickerProviderStateMixin { }, ), AnimatedBuilder( - animation: _animation, + animation: _animation!, builder: (context, snapshot) { return Transform.scale( - scale: _animation.value, + scale: _animation!.value, child: Container( width: 1.0, height: 1.0, decoration: BoxDecoration( color: Colors.white - .withOpacity(1 - _animationController.value), + .withOpacity(1 - _animationController!.value), shape: BoxShape.circle, ), ), @@ -227,19 +228,19 @@ class _MyAppState extends State with TickerProviderStateMixin { children: [ if (_initData != null) PreferenceBuilder( - preference: _initData.preferences.getInt( + preference: _initData!.preferences.getInt( 'theme', defaultValue: 0, ), builder: (context, snapshot) => MaterialApp( builder: (context, child) { return StreamChat( - client: _initData.client, - onBackgroundEventReceived: (e) => - showLocalNotification(e, _initData.client.state.user.id), + client: _initData!.client, + onBackgroundEventReceived: (e) => showLocalNotification( + e, _initData!.client.state.user!.id), child: Builder( builder: (context) => AnnotatedRegion( - child: child, + child: child!, value: SystemUiOverlayStyle( systemNavigationBarColor: StreamChatTheme.of(context).colorTheme.white, @@ -260,7 +261,7 @@ class _MyAppState extends State with TickerProviderStateMixin { 1: ThemeMode.light, }[snapshot], onGenerateRoute: AppRoutes.generateRoute, - initialRoute: _initData.client.state.user == null + initialRoute: _initData!.client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, ), @@ -319,7 +320,7 @@ class _HomePageState extends State { @override Widget build(BuildContext context) { - final user = StreamChat.of(context).user; + final user = StreamChat.of(context).user!; return Scaffold( backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: ChannelListHeader( @@ -495,7 +496,7 @@ class _HomePageState extends State { class UserMentionPage extends StatelessWidget { @override Widget build(BuildContext context) { - final user = StreamChat.of(context).user; + final user = StreamChat.of(context).user!; return MessageSearchBloc( child: MessageSearchListView( filters: Filter.in_('members', [user.id]), @@ -555,8 +556,8 @@ class UserMentionPage extends StatelessWidget { final client = StreamChat.of(context).client; final message = messageResponse.message; final channel = client.channel( - messageResponse.channel.type, - id: messageResponse.channel.id, + messageResponse.channel!.type, + id: messageResponse.channel!.id, ); if (channel.state == null) { await channel.watch(); @@ -581,20 +582,20 @@ class ChannelListPage extends StatefulWidget { } class _ChannelListPageState extends State { - TextEditingController _controller; + TextEditingController? _controller; String _channelQuery = ''; bool _isSearchActive = false; - Timer _debounce; + Timer? _debounce; void _channelQueryListener() { - if (_debounce?.isActive ?? false) _debounce.cancel(); + if (_debounce?.isActive ?? false) _debounce!.cancel(); _debounce = Timer(const Duration(milliseconds: 350), () { if (mounted) { setState(() { - _channelQuery = _controller.text; + _channelQuery = _controller!.text; _isSearchActive = _channelQuery.isNotEmpty; }); } @@ -620,7 +621,7 @@ class _ChannelListPageState extends State { return WillPopScope( onWillPop: () async { if (_isSearchActive) { - _controller.clear(); + _controller!.clear(); setState(() => _isSearchActive = false); return false; } @@ -647,7 +648,7 @@ class _ChannelListPageState extends State { ? MessageSearchListView( showErrorTile: true, messageQuery: _channelQuery, - filters: Filter.in_('members', [user.id]), + filters: Filter.in_('members', [user!.id]), sortOptions: [ SortOption( 'created_at', @@ -691,8 +692,8 @@ class _ChannelListPageState extends State { final client = StreamChat.of(context).client; final message = messageResponse.message; final channel = client.channel( - messageResponse.channel.type, - id: messageResponse.channel.id, + messageResponse.channel!.type, + id: messageResponse.channel!.id, ); if (channel.state == null) { await channel.watch(); @@ -712,7 +713,7 @@ class _ChannelListPageState extends State { Navigator.pushNamed(context, Routes.NEW_CHAT); }, swipeToAction: true, - filter: Filter.in_('members', [user.id]), + filter: Filter.in_('members', [user!.id]), options: { 'presence': true, }, @@ -731,10 +732,10 @@ class _ChannelListPageState extends State { child: ChatInfoScreen( messageTheme: StreamChatTheme.of(context) .ownMessageTheme, - user: channel.state.members + user: channel.state!.members .where((m) => m.userId != - channel.client.state.user.id) + channel.client.state.user!.id) .first .user, ), @@ -767,8 +768,8 @@ class _ChannelListPageState extends State { } class ChannelPageArgs { - final Channel channel; - final Message initialMessage; + final Channel? channel; + final Message? initialMessage; const ChannelPageArgs({ this.channel, @@ -777,12 +778,12 @@ class ChannelPageArgs { } class ChannelPage extends StatefulWidget { - final int initialScrollIndex; - final double initialAlignment; + final int? initialScrollIndex; + final double? initialAlignment; final bool highlightInitialMessage; const ChannelPage({ - Key key, + Key? key, this.initialScrollIndex, this.initialAlignment, this.highlightInitialMessage = false, @@ -793,8 +794,8 @@ class ChannelPage extends StatefulWidget { } class _ChannelPageState extends State { - Message _quotedMessage; - FocusNode _focusNode; + Message? _quotedMessage; + FocusNode? _focusNode; @override void initState() { @@ -804,14 +805,14 @@ class _ChannelPageState extends State { @override void dispose() { - _focusNode.dispose(); + _focusNode!.dispose(); super.dispose(); } void _reply(Message message) { setState(() => _quotedMessage = message); - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - _focusNode.requestFocus(); + WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { + _focusNode!.requestFocus(); }); } @@ -826,9 +827,8 @@ class _ChannelPageState extends State { 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, + final otherUser = channel.state!.members.firstWhereOrNull( + (element) => element.user!.id != currentUser!.id, ); if (otherUser != null) { final pop = await Navigator.push( @@ -932,7 +932,7 @@ class _ChannelPageState extends State { quotedMessage: _quotedMessage, onQuotedMessageCleared: () { setState(() => _quotedMessage = null); - _focusNode.unfocus(); + _focusNode!.unfocus(); }, ), ], @@ -942,12 +942,12 @@ class _ChannelPageState extends State { } class ThreadPage extends StatefulWidget { - final Message parent; - final int initialScrollIndex; - final double initialAlignment; + final Message? parent; + final int? initialScrollIndex; + final double? initialAlignment; ThreadPage({ - Key key, + Key? key, this.parent, this.initialScrollIndex, this.initialAlignment, @@ -958,7 +958,7 @@ class ThreadPage extends StatefulWidget { } class _ThreadPageState extends State { - Message _quotedMessage; + Message? _quotedMessage; FocusNode _focusNode = FocusNode(); @override @@ -969,7 +969,7 @@ class _ThreadPageState extends State { void _reply(Message message) { setState(() => _quotedMessage = message); - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { _focusNode.requestFocus(); }); } @@ -979,7 +979,7 @@ class _ThreadPageState extends State { return Scaffold( backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: ThreadHeader( - parent: widget.parent, + parent: widget.parent!, ), body: Column( children: [ @@ -992,7 +992,7 @@ class _ThreadPageState extends State { onReplyTap: _reply, ), ), - if (widget.parent.type != 'deleted') + if (widget.parent!.type != 'deleted') MessageInput( parentMessage: widget.parent, focusNode: _focusNode, @@ -1017,8 +1017,8 @@ class InitData { class HolePainter extends CustomPainter { HolePainter({ - @required this.color, - @required this.holeSize, + required this.color, + required this.holeSize, }); Color color; diff --git a/packages/stream_chat_v1/lib/new_chat_screen.dart b/packages/stream_chat_v1/lib/new_chat_screen.dart index fac0ed0..2213db4 100644 --- a/packages/stream_chat_v1/lib/new_chat_screen.dart +++ b/packages/stream_chat_v1/lib/new_chat_screen.dart @@ -16,9 +16,9 @@ class _NewChatScreenState extends State { final _chipInputTextFieldStateKey = GlobalKey>(); - TextEditingController _controller; + late TextEditingController _controller; - ChipInputTextFieldState get _chipInputTextFieldState => + ChipInputTextFieldState? get _chipInputTextFieldState => _chipInputTextFieldStateKey.currentState; String _userNameQuery = ''; @@ -30,14 +30,14 @@ class _NewChatScreenState extends State { bool _isSearchActive = false; - Channel channel; + Channel? channel; - Timer _debounce; + Timer? _debounce; bool _showUserList = true; void _userNameListener() { - if (_debounce?.isActive ?? false) _debounce.cancel(); + if (_debounce?.isActive ?? false) _debounce!.cancel(); _debounce = Timer(const Duration(milliseconds: 350), () { if (mounted) setState(() { @@ -73,7 +73,7 @@ class _NewChatScreenState extends State { filter: Filter.and([ Filter.equal('members', [ ..._selectedUsers.map((e) => e.id), - chatState.user.id, + chatState.user!.id, ]), Filter.equal('distinct', true), ]), @@ -86,14 +86,14 @@ class _NewChatScreenState extends State { final _channelExisted = res.length == 1; if (_channelExisted) { channel = res.first; - await channel.watch(); + await channel!.watch(); } else { channel = chatState.client.channel( 'messaging', extraData: { 'members': [ ..._selectedUsers.map((e) => e.id), - chatState.user.id, + chatState.user!.id, ], }, ); @@ -110,9 +110,9 @@ class _NewChatScreenState extends State { void dispose() { _searchFocusNode.dispose(); _messageInputFocusNode.dispose(); - _controller?.clear(); - _controller?.removeListener(_userNameListener); - _controller?.dispose(); + _controller.clear(); + _controller.removeListener(_userNameListener); + _controller.dispose(); super.dispose(); } @@ -158,7 +158,7 @@ class _NewChatScreenState extends State { message: statusString, child: StreamChannel( showLoading: false, - channel: channel, + channel: channel!, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -169,7 +169,7 @@ class _NewChatScreenState extends State { chipBuilder: (context, user) { return GestureDetector( onTap: () { - _chipInputTextFieldState.removeItem(user); + _chipInputTextFieldState?.removeItem(user); _searchFocusNode.requestFocus(); }, child: Stack( @@ -299,10 +299,10 @@ class _NewChatScreenState extends State { _controller.clear(); if (!_selectedUsers.contains(user)) { _chipInputTextFieldState - ..addItem(user) + ?..addItem(user) ..pauseItemAddition(); } else { - _chipInputTextFieldState.removeItem(user); + _chipInputTextFieldState!.removeItem(user); } }, pagination: PaginationParams( @@ -312,7 +312,7 @@ class _NewChatScreenState extends State { if (_userNameQuery.isNotEmpty) Filter.autoComplete('name', _userNameQuery), Filter.notEqual( - 'id', StreamChat.of(context).user.id), + 'id', StreamChat.of(context).user!.id), ]), sort: [ SortOption( @@ -367,7 +367,7 @@ class _NewChatScreenState extends State { ), ) : FutureBuilder( - future: channel.initialized, + future: channel!.initialized, builder: (context, snapshot) { if (snapshot.data == true) { return MessageListView(); @@ -391,7 +391,7 @@ class _NewChatScreenState extends State { MessageInput( focusNode: _messageInputFocusNode, preMessageSending: (message) async { - await channel.watch(); + await channel!.watch(); return message; }, onMessageSent: (m) { diff --git a/packages/stream_chat_v1/lib/new_group_chat_screen.dart b/packages/stream_chat_v1/lib/new_group_chat_screen.dart index 9944572..0db780e 100644 --- a/packages/stream_chat_v1/lib/new_group_chat_screen.dart +++ b/packages/stream_chat_v1/lib/new_group_chat_screen.dart @@ -12,7 +12,7 @@ class NewGroupChatScreen extends StatefulWidget { } class _NewGroupChatScreenState extends State { - TextEditingController _controller; + TextEditingController? _controller; String _userNameQuery = ''; @@ -20,14 +20,14 @@ class _NewGroupChatScreenState extends State { bool _isSearchActive = false; - Timer _debounce; + Timer? _debounce; void _userNameListener() { - if (_debounce?.isActive ?? false) _debounce.cancel(); + if (_debounce?.isActive ?? false) _debounce!.cancel(); _debounce = Timer(const Duration(milliseconds: 350), () { if (mounted) { setState(() { - _userNameQuery = _controller.text; + _userNameQuery = _controller!.text; _isSearchActive = _userNameQuery.isNotEmpty; }); } @@ -80,7 +80,7 @@ class _NewGroupChatScreenState extends State { setState(() { _selectedUsers ..clear() - ..addAll(updatedList); + ..addAll(updatedList as Iterable); }); } }, @@ -247,7 +247,7 @@ class _NewGroupChatScreenState extends State { filter: Filter.and([ if (_userNameQuery.isNotEmpty) Filter.autoComplete('name', _userNameQuery), - Filter.notEqual('id', StreamChat.of(context).user.id), + Filter.notEqual('id', StreamChat.of(context).user!.id), ]), sort: [ SortOption( @@ -311,8 +311,8 @@ class _HeaderDelegate extends SliverPersistentHeaderDelegate { final double height; const _HeaderDelegate({ - @required this.child, - @required this.height, + required this.child, + required this.height, }); @override diff --git a/packages/stream_chat_v1/lib/notifications_service.dart b/packages/stream_chat_v1/lib/notifications_service.dart index c72ac19..56f6ad7 100644 --- a/packages/stream_chat_v1/lib/notifications_service.dart +++ b/packages/stream_chat_v1/lib/notifications_service.dart @@ -7,7 +7,7 @@ void showLocalNotification(Event event, String currentUserId) async { EventType.messageNew, EventType.notificationMessageNew, ].contains(event.type) || - event.user.id == currentUserId) { + event.user!.id == currentUserId) { return; } if (event.message == null) return; @@ -21,9 +21,9 @@ void showLocalNotification(Event event, String currentUserId) async { ); await flutterLocalNotificationsPlugin.initialize(initializationSettings); await flutterLocalNotificationsPlugin.show( - event.message.id.hashCode, - event.message.user.name, - event.message.text, + event.message!.id.hashCode, + event.message!.user!.name, + event.message!.text, NotificationDetails( android: AndroidNotificationDetails( 'message channel', diff --git a/packages/stream_chat_v1/lib/routes/app_routes.dart b/packages/stream_chat_v1/lib/routes/app_routes.dart index 1be8bf7..a8ce583 100644 --- a/packages/stream_chat_v1/lib/routes/app_routes.dart +++ b/packages/stream_chat_v1/lib/routes/app_routes.dart @@ -12,7 +12,7 @@ import '../group_info_screen.dart'; class AppRoutes { /// Add entry for new route here - static Route generateRoute(RouteSettings settings) { + static Route? generateRoute(RouteSettings settings) { final args = settings.arguments; switch (settings.name) { case Routes.APP: @@ -44,7 +44,7 @@ class AppRoutes { builder: (_) { final arg = args as ChannelPageArgs; return StreamChannel( - channel: arg.channel, + channel: arg.channel!, initialMessageId: arg.initialMessage?.id, child: ChannelPage( highlightInitialMessage: arg.initialMessage != null, @@ -68,7 +68,7 @@ class AppRoutes { settings: const RouteSettings(name: Routes.NEW_GROUP_CHAT_DETAILS), builder: (_) { return GroupChatDetailsScreen( - selectedUsers: args, + selectedUsers: args as List?, ); }); case Routes.CHAT_INFO_SCREEN: @@ -76,7 +76,7 @@ class AppRoutes { settings: const RouteSettings(name: Routes.CHAT_INFO_SCREEN), builder: (context) { return ChatInfoScreen( - user: args, + user: args as User?, messageTheme: StreamChatTheme.of(context).ownMessageTheme, ); }); diff --git a/packages/stream_chat_v1/lib/search_text_field.dart b/packages/stream_chat_v1/lib/search_text_field.dart index 9628ddb..c3850c2 100644 --- a/packages/stream_chat_v1/lib/search_text_field.dart +++ b/packages/stream_chat_v1/lib/search_text_field.dart @@ -2,15 +2,15 @@ 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 TextEditingController? controller; + final ValueChanged? onChanged; final String hintText; - final VoidCallback onTap; + final VoidCallback? onTap; final bool showCloseButton; const SearchTextField({ - Key key, - @required this.controller, + Key? key, + required this.controller, this.onChanged, this.onTap, this.hintText = 'Search', @@ -76,11 +76,11 @@ class SearchTextField extends StatelessWidget { ), splashRadius: 24, onPressed: () { - if (controller.text.isNotEmpty) { + if (controller!.text.isNotEmpty) { Future.microtask( () => [ - controller.clear(), - if (onChanged != null) onChanged(''), + controller!.clear(), + if (onChanged != null) onChanged!(''), ], ); } diff --git a/packages/stream_chat_v1/lib/stream_version.dart b/packages/stream_chat_v1/lib/stream_version.dart index b3f926b..0458d75 100644 --- a/packages/stream_chat_v1/lib/stream_version.dart +++ b/packages/stream_chat_v1/lib/stream_version.dart @@ -5,7 +5,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class StreamVersion extends StatelessWidget { const StreamVersion({ - Key key, + Key? key, }) : super(key: key); @override @@ -20,7 +20,7 @@ class StreamVersion extends StatelessWidget { return SizedBox(); } - final pubspec = snapshot.data; + final pubspec = snapshot.data!; final yaml = loadYaml(pubspec); final streamChatDep = yaml['packages']['stream_chat_flutter']['version']; diff --git a/packages/stream_chat_v1/pubspec.yaml b/packages/stream_chat_v1/pubspec.yaml index 464d235..9f1f30d 100644 --- a/packages/stream_chat_v1/pubspec.yaml +++ b/packages/stream_chat_v1/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: 'none' version: 1.5.4+1 environment: - sdk: ">=2.2.2 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: flutter_app_badger: ^1.2.0 @@ -27,6 +27,7 @@ dependencies: uuid: ^3.0.4 streaming_shared_preferences: ^2.0.0 lottie: ^1.0.1 + collection: ^1.15.0-nullsafety.4 dependency_overrides: stream_chat: From 1ba92a8676aefc7308de74767f45b50f63de2fd9 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 17 May 2021 14:40:50 +0530 Subject: [PATCH 06/48] removed deprecated uses, fmt --- .../lib/data/local/image_picker_impl.dart | 3 +- .../lib/data/local/stream_api_local_impl.dart | 19 +++-- packages/chatty/lib/data/prod/auth_impl.dart | 6 +- .../chatty/lib/data/prod/stream_api_impl.dart | 18 +++-- .../lib/data/stream_api_repository.dart | 4 +- packages/chatty/lib/dependencies.dart | 9 ++- .../domain/usecases/create_group_usecase.dart | 3 +- .../usecases/profile_sign_in_usecase.dart | 6 +- packages/chatty/lib/main.dart | 3 +- packages/chatty/lib/navigator_utils.dart | 4 +- .../lib/ui/common/my_channel_preview.dart | 80 ++++++++++++++----- .../chatty/lib/ui/home/chat/chat_view.dart | 6 +- .../selection/friends_selection_cubit.dart | 16 ++-- .../selection/friends_selection_view.dart | 45 +++++++---- .../chat/selection/group_selection_view.dart | 13 ++- packages/chatty/lib/ui/home/home_view.dart | 10 ++- .../lib/ui/home/settings/settings_view.dart | 10 ++- .../profile_verify/profile_verify_view.dart | 10 ++- .../chatty/lib/ui/sign_in/sign_in_view.dart | 7 +- packages/imessage/lib/utils.dart | 1 - .../lib/advanced_options_page.dart | 24 ++++-- .../stream_chat_v1/lib/chat_info_screen.dart | 3 +- .../lib/group_chat_details_screen.dart | 2 +- .../stream_chat_v1/lib/stream_version.dart | 2 +- 24 files changed, 208 insertions(+), 96 deletions(-) diff --git a/packages/chatty/lib/data/local/image_picker_impl.dart b/packages/chatty/lib/data/local/image_picker_impl.dart index 21a1b15..90c63e0 100644 --- a/packages/chatty/lib/data/local/image_picker_impl.dart +++ b/packages/chatty/lib/data/local/image_picker_impl.dart @@ -6,7 +6,8 @@ class ImagePickerImpl extends ImagePickerRepository { @override Future pickImage() async { final picker = ImagePicker(); - final pickedFile = await picker.getImage(source: ImageSource.gallery, maxWidth: 400); + final pickedFile = + await picker.getImage(source: ImageSource.gallery, maxWidth: 400); return File(pickedFile.path); } } diff --git a/packages/chatty/lib/data/local/stream_api_local_impl.dart b/packages/chatty/lib/data/local/stream_api_local_impl.dart index f772a26..a2d2e35 100644 --- a/packages/chatty/lib/data/local/stream_api_local_impl.dart +++ b/packages/chatty/lib/data/local/stream_api_local_impl.dart @@ -46,7 +46,9 @@ class StreamApiLocalImpl extends StreamApiRepository { } @override - Future createGroupChat(String channelId, String name, List members, {String image}) async { + Future createGroupChat( + String channelId, String name, List members, + {String image}) async { final channel = _client.channel('messaging', id: channelId, extraData: { 'name': name, 'image': image, @@ -58,13 +60,14 @@ class StreamApiLocalImpl extends StreamApiRepository { @override Future createSimpleChat(String friendId) async { - final channel = - _client.channel('messaging', id: '${_client.state.user.id.hashCode}${friendId.hashCode}', extraData: { - 'members': [ - friendId, - _client.state.user.id, - ], - }); + final channel = _client.channel('messaging', + id: '${_client.state.user.id.hashCode}${friendId.hashCode}', + extraData: { + 'members': [ + friendId, + _client.state.user.id, + ], + }); await channel.watch(); return channel; } diff --git a/packages/chatty/lib/data/prod/auth_impl.dart b/packages/chatty/lib/data/prod/auth_impl.dart index 90547bb..71bb3c6 100644 --- a/packages/chatty/lib/data/prod/auth_impl.dart +++ b/packages/chatty/lib/data/prod/auth_impl.dart @@ -20,8 +20,10 @@ class AuthImpl extends AuthRepository { try { UserCredential userCredential; final GoogleSignInAccount googleUser = await GoogleSignIn().signIn(); - final GoogleSignInAuthentication googleAuth = await googleUser.authentication; - final GoogleAuthCredential googleAuthCredential = GoogleAuthProvider.credential( + final GoogleSignInAuthentication googleAuth = + await googleUser.authentication; + final GoogleAuthCredential googleAuthCredential = + GoogleAuthProvider.credential( accessToken: googleAuth.accessToken, idToken: googleAuth.idToken, ); diff --git a/packages/chatty/lib/data/prod/stream_api_impl.dart b/packages/chatty/lib/data/prod/stream_api_impl.dart index 1bcab14..a60cd1c 100644 --- a/packages/chatty/lib/data/prod/stream_api_impl.dart +++ b/packages/chatty/lib/data/prod/stream_api_impl.dart @@ -62,7 +62,8 @@ class StreamApiImpl extends StreamApiRepository { } @override - Future createGroupChat(String id, String name, List members, {String image}) async { + Future createGroupChat(String id, String name, List members, + {String image}) async { final channel = _client.channel('messaging', id: id, extraData: { 'name': name, 'image': image, @@ -74,13 +75,14 @@ class StreamApiImpl extends StreamApiRepository { @override Future createSimpleChat(String friendId) async { - final channel = - _client.channel('messaging', id: '${_client.state.user.id.hashCode}${friendId.hashCode}', extraData: { - 'members': [ - friendId, - _client.state.user.id, - ], - }); + final channel = _client.channel('messaging', + id: '${_client.state.user.id.hashCode}${friendId.hashCode}', + extraData: { + 'members': [ + friendId, + _client.state.user.id, + ], + }); await channel.watch(); return channel; } diff --git a/packages/chatty/lib/data/stream_api_repository.dart b/packages/chatty/lib/data/stream_api_repository.dart index 4ae31cb..3d5c215 100644 --- a/packages/chatty/lib/data/stream_api_repository.dart +++ b/packages/chatty/lib/data/stream_api_repository.dart @@ -6,7 +6,9 @@ abstract class StreamApiRepository { Future getToken(String userId); Future connectIfExist(String userId); Future connectUser(ChatUser user, String token); - Future createGroupChat(String channelId, String name, List members, {String image}); + Future createGroupChat( + String channelId, String name, List members, + {String image}); Future createSimpleChat(String friendId); Future logout(); } diff --git a/packages/chatty/lib/dependencies.dart b/packages/chatty/lib/dependencies.dart index f6d6414..d60194c 100644 --- a/packages/chatty/lib/dependencies.dart +++ b/packages/chatty/lib/dependencies.dart @@ -18,10 +18,13 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; List buildRepositories(StreamChatClient client) { //TODO: Here you can use your local implementations of your repositories return [ - RepositoryProvider(create: (_) => StreamApiImpl(client)), - RepositoryProvider(create: (_) => PersistentStorageImpl()), + RepositoryProvider( + create: (_) => StreamApiImpl(client)), + RepositoryProvider( + create: (_) => PersistentStorageImpl()), RepositoryProvider(create: (_) => AuthImpl()), - RepositoryProvider(create: (_) => UploadStorageImpl()), + RepositoryProvider( + create: (_) => UploadStorageImpl()), RepositoryProvider(create: (_) => ImagePickerImpl()), RepositoryProvider( create: (context) => ProfileSignInUseCase( diff --git a/packages/chatty/lib/domain/usecases/create_group_usecase.dart b/packages/chatty/lib/domain/usecases/create_group_usecase.dart index 82122a2..0e19d80 100644 --- a/packages/chatty/lib/domain/usecases/create_group_usecase.dart +++ b/packages/chatty/lib/domain/usecases/create_group_usecase.dart @@ -25,7 +25,8 @@ class CreateGroupUseCase { final channelId = Uuid().v4(); String image; if (input.imageFile != null) { - image = await _uploadStorageRepository.uploadPhoto(input.imageFile, 'channels/$channelId'); + image = await _uploadStorageRepository.uploadPhoto( + input.imageFile, 'channels/$channelId'); } final channel = await _streamApiRepository.createGroupChat( channelId, diff --git a/packages/chatty/lib/domain/usecases/profile_sign_in_usecase.dart b/packages/chatty/lib/domain/usecases/profile_sign_in_usecase.dart index 8450581..1c18918 100644 --- a/packages/chatty/lib/domain/usecases/profile_sign_in_usecase.dart +++ b/packages/chatty/lib/domain/usecases/profile_sign_in_usecase.dart @@ -27,8 +27,10 @@ class ProfileSignInUseCase { final token = await _streamApiRepository.getToken(auth.id); String image; if (input.imageFile != null) { - image = await _uploadStorageRepository.uploadPhoto(input.imageFile, 'users/${auth.id}'); + image = await _uploadStorageRepository.uploadPhoto( + input.imageFile, 'users/${auth.id}'); } - await _streamApiRepository.connectUser(ChatUser(name: input.name, id: auth.id, image: image), token); + await _streamApiRepository.connectUser( + ChatUser(name: input.name, id: auth.id, image: image), token); } } diff --git a/packages/chatty/lib/main.dart b/packages/chatty/lib/main.dart index 479c1c8..817010d 100644 --- a/packages/chatty/lib/main.dart +++ b/packages/chatty/lib/main.dart @@ -34,7 +34,8 @@ class MyApp extends StatelessWidget { return StreamChat( child: child, client: _streamChatClient, - streamChatThemeData: StreamChatThemeData.fromTheme(Theme.of(context)).copyWith( + streamChatThemeData: + StreamChatThemeData.fromTheme(Theme.of(context)).copyWith( ownMessageTheme: MessageTheme( messageBackgroundColor: Theme.of(context).accentColor, messageText: TextStyle(color: Colors.white), diff --git a/packages/chatty/lib/navigator_utils.dart b/packages/chatty/lib/navigator_utils.dart index 2d5c27f..731c4c1 100644 --- a/packages/chatty/lib/navigator_utils.dart +++ b/packages/chatty/lib/navigator_utils.dart @@ -18,5 +18,7 @@ Future pushAndReplaceToPage(BuildContext context, Widget widget) async { Future popAllAndPush(BuildContext context, Widget widget) async { await Navigator.pushAndRemoveUntil( - context, MaterialPageRoute(builder: (BuildContext context) => widget), ModalRoute.withName('/')); + context, + MaterialPageRoute(builder: (BuildContext context) => widget), + ModalRoute.withName('/')); } diff --git a/packages/chatty/lib/ui/common/my_channel_preview.dart b/packages/chatty/lib/ui/common/my_channel_preview.dart index b561e45..8886b47 100644 --- a/packages/chatty/lib/ui/common/my_channel_preview.dart +++ b/packages/chatty/lib/ui/common/my_channel_preview.dart @@ -90,7 +90,8 @@ class MyChannelPreview extends StatelessWidget { children: [ Flexible( child: ChannelName( - textStyle: StreamChatTheme.of(context).channelPreviewTheme.title, + textStyle: + StreamChatTheme.of(context).channelPreviewTheme.title, ), ), StreamBuilder>( @@ -99,7 +100,8 @@ class MyChannelPreview extends StatelessWidget { builder: (context, snapshot) { if (!snapshot.hasData || snapshot.data.isEmpty || - !snapshot.data.any((Member e) => e.user.id == channel.client.state.user.id)) { + !snapshot.data.any((Member e) => + e.user.id == channel.client.state.user.id)) { return SizedBox(); } return ChannelUnreadIndicator( @@ -118,15 +120,21 @@ class MyChannelPreview extends StatelessWidget { (m) => !m.isDeleted && m.shadowed != true, orElse: () => null, ); - if (lastMessage?.user?.id == StreamChat.of(context).user.id) { + if (lastMessage?.user?.id == + StreamChat.of(context).user.id) { return Padding( padding: const EdgeInsets.only(right: 4.0), child: SendingIndicator( message: lastMessage, - size: StreamChatTheme.of(context).channelPreviewTheme.indicatorIconSize, + size: StreamChatTheme.of(context) + .channelPreviewTheme + .indicatorIconSize, isMessageRead: channel.state.read - ?.where((element) => element.user.id != channel.client.state.user.id) - ?.where((element) => element.lastRead.isAfter(lastMessage.createdAt)) + ?.where((element) => + element.user.id != + channel.client.state.user.id) + ?.where((element) => element.lastRead + .isAfter(lastMessage.createdAt)) ?.isNotEmpty == true, ), @@ -158,7 +166,8 @@ class MyChannelPreview extends StatelessWidget { var startOfDay = DateTime(now.year, now.month, now.day); - if (lastMessageAt.millisecondsSinceEpoch >= startOfDay.millisecondsSinceEpoch) { + if (lastMessageAt.millisecondsSinceEpoch >= + startOfDay.millisecondsSinceEpoch) { stringDate = Jiffy(lastMessageAt.toLocal()).format('HH:mm'); } else if (lastMessageAt.millisecondsSinceEpoch >= startOfDay.subtract(Duration(days: 1)).millisecondsSinceEpoch) { @@ -187,8 +196,14 @@ class MyChannelPreview extends StatelessWidget { ), Text( ' Channel is muted', - style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( - color: StreamChatTheme.of(context).channelPreviewTheme.subtitle.color, + style: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle + .copyWith( + color: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle + .color, ), ), ], @@ -198,7 +213,8 @@ class MyChannelPreview extends StatelessWidget { channel: channel, alternativeWidget: _buildLastMessage(context), style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( - color: StreamChatTheme.of(context).channelPreviewTheme.subtitle.color, + color: + StreamChatTheme.of(context).channelPreviewTheme.subtitle.color, ), ); } @@ -208,7 +224,9 @@ class MyChannelPreview extends StatelessWidget { stream: channel.state.messagesStream, initialData: channel.state.messages, builder: (context, snapshot) { - final lastMessage = snapshot.data?.lastWhere((m) => m.shadowed != true && !m.isDeleted, orElse: () => null); + final lastMessage = snapshot.data?.lastWhere( + (m) => m.shadowed != true && !m.isDeleted, + orElse: () => null); if (lastMessage == null) { return SizedBox(); } @@ -224,7 +242,9 @@ class MyChannelPreview extends StatelessWidget { } else if (e.type == 'giphy') { return '[GIF]'; } - return e == lastMessage.attachments.last ? (e.title ?? 'File') : '${e.title ?? 'File'} , '; + return e == lastMessage.attachments.last + ? (e.title ?? 'File') + : '${e.title ?? 'File'} , '; }).where((e) => e != null), lastMessage.text ?? '', ]; @@ -238,11 +258,21 @@ class MyChannelPreview extends StatelessWidget { lastMessage.mentionedUsers, lastMessage.attachments, StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( - color: StreamChatTheme.of(context).channelPreviewTheme.subtitle.color, - fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) ? FontStyle.italic : FontStyle.normal), + 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, + color: StreamChatTheme.of(context) + .channelPreviewTheme + .subtitle + .color, + fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) + ? FontStyle.italic + : FontStyle.normal, fontWeight: FontWeight.bold), ), maxLines: 1, @@ -252,19 +282,27 @@ class MyChannelPreview extends StatelessWidget { ); } - TextSpan _getDisplayText(String text, List mentions, List attachments, TextStyle normalTextStyle, + TextSpan _getDisplayText( + String text, + List mentions, + List attachments, + TextStyle normalTextStyle, TextStyle mentionsTextStyle) { var textList = text.split(' '); var resList = []; for (var e in textList) { - if (mentions != null && mentions.isNotEmpty && 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 != null && attachments.isNotEmpty && - attachments.where((e) => e.title != null).any((element) => element.title == e)) { + attachments + .where((e) => e.title != null) + .any((element) => element.title == e)) { resList.add(TextSpan( text: '$e ', style: normalTextStyle.copyWith(fontStyle: FontStyle.italic), @@ -301,7 +339,9 @@ class ChannelUnreadIndicator extends StatelessWidget { return Material( borderRadius: BorderRadius.circular(8), - color: StreamChatTheme.of(context).channelPreviewTheme.unreadCounterColor, + color: StreamChatTheme.of(context) + .channelPreviewTheme + .unreadCounterColor, child: Padding( padding: const EdgeInsets.only( left: 5.0, diff --git a/packages/chatty/lib/ui/home/chat/chat_view.dart b/packages/chatty/lib/ui/home/chat/chat_view.dart index b9f4ea7..5267162 100644 --- a/packages/chatty/lib/ui/home/chat/chat_view.dart +++ b/packages/chatty/lib/ui/home/chat/chat_view.dart @@ -43,8 +43,10 @@ class ChatView extends StatelessWidget { name = channel.extraData['name']; image = channel.extraData['image']; } else { - final friend = - channel.state.members.where((element) => element.userId != currentUser.id).first.user; + final friend = channel.state.members + .where((element) => element.userId != currentUser.id) + .first + .user; name = friend.name; image = friend.extraData['image']; } diff --git a/packages/chatty/lib/ui/home/chat/selection/friends_selection_cubit.dart b/packages/chatty/lib/ui/home/chat/selection/friends_selection_cubit.dart index 3f35080..d43c222 100644 --- a/packages/chatty/lib/ui/home/chat/selection/friends_selection_cubit.dart +++ b/packages/chatty/lib/ui/home/chat/selection/friends_selection_cubit.dart @@ -13,21 +13,27 @@ class FriendsSelectionCubit extends Cubit> { FriendsSelectionCubit(this._streamApiRepository) : super([]); final StreamApiRepository _streamApiRepository; - List get selectedUsers => state.where((element) => element.selected).toList(); + List get selectedUsers => + state.where((element) => element.selected).toList(); Future init() async { - final chatUsers = (await _streamApiRepository.getChatUsers()).map((e) => ChatUserState(e)).toList(); + final chatUsers = (await _streamApiRepository.getChatUsers()) + .map((e) => ChatUserState(e)) + .toList(); emit(chatUsers); } void selectUser(ChatUserState chatUser) { - final index = state.indexWhere((element) => element.chatUser.id == chatUser.chatUser.id); - state[index] = ChatUserState(state[index].chatUser, selected: !chatUser.selected); + final index = state + .indexWhere((element) => element.chatUser.id == chatUser.chatUser.id); + state[index] = + ChatUserState(state[index].chatUser, selected: !chatUser.selected); emit(List.from(state)); } Future createFriendChannel(ChatUserState chatUserState) async { - return await _streamApiRepository.createSimpleChat(chatUserState.chatUser.id); + return await _streamApiRepository + .createSimpleChat(chatUserState.chatUser.id); } } diff --git a/packages/chatty/lib/ui/home/chat/selection/friends_selection_view.dart b/packages/chatty/lib/ui/home/chat/selection/friends_selection_view.dart index 4cafcef..d7c0d1f 100644 --- a/packages/chatty/lib/ui/home/chat/selection/friends_selection_view.dart +++ b/packages/chatty/lib/ui/home/chat/selection/friends_selection_view.dart @@ -7,8 +7,11 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class FriendsSelectionView extends StatelessWidget { - void _createFriendChannel(BuildContext context, ChatUserState chatUserState) async { - final channel = await context.read().createFriendChannel(chatUserState); + void _createFriendChannel( + BuildContext context, ChatUserState chatUserState) async { + final channel = await context + .read() + .createFriendChannel(chatUserState); pushAndReplaceToPage( context, Scaffold( @@ -26,19 +29,23 @@ class FriendsSelectionView extends StatelessWidget { final accentColor = Theme.of(context).accentColor; return MultiBlocProvider( providers: [ - BlocProvider(create: (context) => FriendsSelectionCubit(context.read())..init()), + BlocProvider( + create: (context) => FriendsSelectionCubit(context.read())..init()), BlocProvider(create: (_) => FriendsGroupCubit()), ], child: BlocBuilder(builder: (context, isGroup) { - return BlocBuilder>(builder: (context, snapshot) { - final selectedUsers = context.read().selectedUsers; + return BlocBuilder>( + builder: (context, snapshot) { + final selectedUsers = + context.read().selectedUsers; return Scaffold( floatingActionButton: isGroup && selectedUsers.isNotEmpty ? FloatingActionButton( child: Icon(Icons.arrow_right_alt_rounded), onPressed: () { - pushAndReplaceToPage(context, GroupSelectionView(selectedUsers)); + pushAndReplaceToPage( + context, GroupSelectionView(selectedUsers)); }) : null, backgroundColor: Theme.of(context).canvasColor, @@ -91,12 +98,14 @@ class FriendsSelectionView extends StatelessWidget { backgroundColor: accentColor, child: Icon(Icons.group_outlined), ), - title: Text('Create group', style: TextStyle(fontWeight: FontWeight.w700)), + title: Text('Create group', + style: TextStyle(fontWeight: FontWeight.w700)), subtitle: Text('Talk with 2 or more contacts'), ) else if (isGroup && selectedUsers.isEmpty) Padding( - padding: const EdgeInsets.only(top: 15.0, left: 20.0, bottom: 20), + padding: const EdgeInsets.only( + top: 15.0, left: 20.0, bottom: 20), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -123,7 +132,8 @@ class FriendsSelectionView extends StatelessWidget { itemBuilder: (context, index) { final chatUserState = selectedUsers[index]; return Padding( - padding: const EdgeInsets.symmetric(horizontal: 13.0), + padding: const EdgeInsets.symmetric( + horizontal: 13.0), child: Stack( clipBehavior: Clip.none, children: [ @@ -132,7 +142,8 @@ class FriendsSelectionView extends StatelessWidget { children: [ CircleAvatar( radius: 30, - backgroundImage: NetworkImage(chatUserState.chatUser.image), + backgroundImage: NetworkImage( + chatUserState.chatUser.image), ), Text(chatUserState.chatUser.name), ], @@ -141,11 +152,14 @@ class FriendsSelectionView extends StatelessWidget { bottom: 40, right: -4, child: InkWell( - onTap: () => context.read().selectUser(chatUserState), + onTap: () => context + .read() + .selectUser(chatUserState), child: CircleAvatar( radius: 9, backgroundColor: accentColor, - child: Icon(Icons.close_rounded, size: 12), + child: Icon(Icons.close_rounded, + size: 12), ), ), ), @@ -163,7 +177,8 @@ class FriendsSelectionView extends StatelessWidget { _createFriendChannel(context, chatUserState); }, leading: CircleAvatar( - backgroundImage: NetworkImage(chatUserState.chatUser.image), + backgroundImage: + NetworkImage(chatUserState.chatUser.image), ), title: Text(chatUserState.chatUser.name), trailing: isGroup @@ -171,7 +186,9 @@ class FriendsSelectionView extends StatelessWidget { value: chatUserState.selected, onChanged: (val) { print('select user for group'); - context.read().selectUser(chatUserState); + context + .read() + .selectUser(chatUserState); }, ) : null, diff --git a/packages/chatty/lib/ui/home/chat/selection/group_selection_view.dart b/packages/chatty/lib/ui/home/chat/selection/group_selection_view.dart index 7f336f9..70c100b 100644 --- a/packages/chatty/lib/ui/home/chat/selection/group_selection_view.dart +++ b/packages/chatty/lib/ui/home/chat/selection/group_selection_view.dart @@ -21,7 +21,8 @@ class GroupSelectionView extends StatelessWidget { context.read(), context.read(), ), - child: BlocConsumer(listener: (context, snapshot) { + child: BlocConsumer( + listener: (context, snapshot) { if (snapshot.channel != null) { pushAndReplaceToPage( context, @@ -76,9 +77,12 @@ class GroupSelectionView extends StatelessWidget { vertical: 20, ), child: TextField( - controller: context.read().nameTextController, + controller: + context.read().nameTextController, decoration: InputDecoration( - fillColor: Theme.of(context).bottomNavigationBarTheme.backgroundColor, + fillColor: Theme.of(context) + .bottomNavigationBarTheme + .backgroundColor, hintText: 'Name of the group', hintStyle: TextStyle( fontSize: 13, @@ -99,7 +103,8 @@ class GroupSelectionView extends StatelessWidget { children: [ CircleAvatar( radius: 30, - backgroundImage: NetworkImage(chatUserState.chatUser.image), + backgroundImage: + NetworkImage(chatUserState.chatUser.image), ), Text(chatUserState.chatUser.name), ], diff --git a/packages/chatty/lib/ui/home/home_view.dart b/packages/chatty/lib/ui/home/home_view.dart index 5199415..5d30d87 100644 --- a/packages/chatty/lib/ui/home/home_view.dart +++ b/packages/chatty/lib/ui/home/home_view.dart @@ -61,7 +61,9 @@ class HomeNavigationBar extends StatelessWidget { child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(25), - color: Theme.of(context).bottomNavigationBarTheme.backgroundColor, + color: Theme.of(context) + .bottomNavigationBarTheme + .backgroundColor, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, @@ -122,8 +124,10 @@ class _HomeNavItem extends StatelessWidget { @override Widget build(BuildContext context) { - final selectedColor = Theme.of(context).bottomNavigationBarTheme.selectedItemColor; - final unselectedColor = Theme.of(context).bottomNavigationBarTheme.unselectedItemColor; + final selectedColor = + Theme.of(context).bottomNavigationBarTheme.selectedItemColor; + final unselectedColor = + Theme.of(context).bottomNavigationBarTheme.unselectedItemColor; final color = selected ? selectedColor : unselectedColor; return GestureDetector( onTap: onTap, diff --git a/packages/chatty/lib/ui/home/settings/settings_view.dart b/packages/chatty/lib/ui/home/settings/settings_view.dart index 77ce96a..17020ff 100644 --- a/packages/chatty/lib/ui/home/settings/settings_view.dart +++ b/packages/chatty/lib/ui/home/settings/settings_view.dart @@ -16,7 +16,8 @@ class SettingsView extends StatelessWidget { return MultiBlocProvider( providers: [ BlocProvider( - create: (_) => SettingsSwitchCubit(context.read().isDark), + create: (_) => + SettingsSwitchCubit(context.read().isDark), ), BlocProvider( create: (_) => SettingsLogoutCubit(context.read()), @@ -75,11 +76,14 @@ class SettingsView extends StatelessWidget { ), ), Spacer(), - BlocBuilder(builder: (context, snapshot) { + BlocBuilder( + builder: (context, snapshot) { return Switch( value: snapshot, onChanged: (val) { - context.read().onChangeDarkMode(val); + context + .read() + .onChangeDarkMode(val); context.read().updateTheme(val); }, ); diff --git a/packages/chatty/lib/ui/profile_verify/profile_verify_view.dart b/packages/chatty/lib/ui/profile_verify/profile_verify_view.dart index 3a475c3..4000202 100644 --- a/packages/chatty/lib/ui/profile_verify/profile_verify_view.dart +++ b/packages/chatty/lib/ui/profile_verify/profile_verify_view.dart @@ -13,7 +13,8 @@ class ProfileVerifyView extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => ProfileVerifyCubit(context.read(), context.read()), - child: BlocConsumer(listener: (context, snapshot) { + child: BlocConsumer( + listener: (context, snapshot) { if (snapshot.success) { pushAndReplaceToPage(context, HomeView()); } @@ -59,9 +60,12 @@ class ProfileVerifyView extends StatelessWidget { vertical: 20, ), child: TextField( - controller: context.read().nameController, + controller: + context.read().nameController, decoration: InputDecoration( - fillColor: Theme.of(context).bottomNavigationBarTheme.backgroundColor, + fillColor: Theme.of(context) + .bottomNavigationBarTheme + .backgroundColor, hintText: 'Or just how people now you', hintStyle: TextStyle( fontSize: 13, diff --git a/packages/chatty/lib/ui/sign_in/sign_in_view.dart b/packages/chatty/lib/ui/sign_in/sign_in_view.dart index 41ff317..d8f2a9e 100644 --- a/packages/chatty/lib/ui/sign_in/sign_in_view.dart +++ b/packages/chatty/lib/ui/sign_in/sign_in_view.dart @@ -11,7 +11,8 @@ class SignInView extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => SignInCubit(context.read()), - child: BlocConsumer(listener: (context, snapshot) { + child: + BlocConsumer(listener: (context, snapshot) { if (snapshot == SignInState.none) { pushAndReplaceToPage(context, ProfileVerifyView()); } else { @@ -59,7 +60,9 @@ class SignInView extends StatelessWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), - color: Theme.of(context).bottomNavigationBarTheme.backgroundColor, + color: Theme.of(context) + .bottomNavigationBarTheme + .backgroundColor, child: InkWell( onTap: () { context.read().signIn(); diff --git a/packages/imessage/lib/utils.dart b/packages/imessage/lib/utils.dart index f78e450..4600512 100644 --- a/packages/imessage/lib/utils.dart +++ b/packages/imessage/lib/utils.dart @@ -49,7 +49,6 @@ class CupertinoCircleAvatar extends StatelessWidget { } } - class Divider extends StatelessWidget { const Divider({ Key key, diff --git a/packages/stream_chat_v1/lib/advanced_options_page.dart b/packages/stream_chat_v1/lib/advanced_options_page.dart index b4a4326..29fe270 100644 --- a/packages/stream_chat_v1/lib/advanced_options_page.dart +++ b/packages/stream_chat_v1/lib/advanced_options_page.dart @@ -221,14 +221,22 @@ class _AdvancedOptionsPageState extends State { ), ), 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), + ElevatedButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + Theme.of(context).brightness == Brightness.light + ? StreamChatTheme.of(context) + .colorTheme + .accentBlue + : Colors.white), + elevation: MaterialStateProperty.all(0), + padding: MaterialStateProperty.all( + const EdgeInsets.symmetric(vertical: 16)), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(26), + ), + ), ), child: Text( 'Login', diff --git a/packages/stream_chat_v1/lib/chat_info_screen.dart b/packages/stream_chat_v1/lib/chat_info_screen.dart index 8a09f43..2ba2839 100644 --- a/packages/stream_chat_v1/lib/chat_info_screen.dart +++ b/packages/stream_chat_v1/lib/chat_info_screen.dart @@ -56,7 +56,8 @@ class _ChatInfoScreenState extends State { 'admin', 'owner', ].contains(channel.state!.members - .firstWhereOrNull((m) => m.userId == channel.client.state.user!.id) + .firstWhereOrNull( + (m) => m.userId == channel.client.state.user!.id) ?.role)) _buildDeleteListTile(), ], diff --git a/packages/stream_chat_v1/lib/group_chat_details_screen.dart b/packages/stream_chat_v1/lib/group_chat_details_screen.dart index 1819fe8..a1a92b8 100644 --- a/packages/stream_chat_v1/lib/group_chat_details_screen.dart +++ b/packages/stream_chat_v1/lib/group_chat_details_screen.dart @@ -306,7 +306,7 @@ class _GroupChatDetailsScreenState extends State { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - FlatButton( + TextButton( child: Text( 'OK', style: StreamChatTheme.of(context) diff --git a/packages/stream_chat_v1/lib/stream_version.dart b/packages/stream_chat_v1/lib/stream_version.dart index 0458d75..7401813 100644 --- a/packages/stream_chat_v1/lib/stream_version.dart +++ b/packages/stream_chat_v1/lib/stream_version.dart @@ -26,7 +26,7 @@ class StreamVersion extends StatelessWidget { yaml['packages']['stream_chat_flutter']['version']; return Text( - 'Stream SDK v ${streamChatDep}', + 'Stream SDK v $streamChatDep', style: TextStyle( fontSize: 14, color: StreamChatTheme.of(context).colorTheme.greyGainsboro, From dc9aa9edbdcdb73024c41630f132ef95929d1b1a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 17 May 2021 13:56:28 +0200 Subject: [PATCH 07/48] fix new chat filter --- packages/stream_chat_v1/lib/new_chat_screen.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/stream_chat_v1/lib/new_chat_screen.dart b/packages/stream_chat_v1/lib/new_chat_screen.dart index 2213db4..d708b00 100644 --- a/packages/stream_chat_v1/lib/new_chat_screen.dart +++ b/packages/stream_chat_v1/lib/new_chat_screen.dart @@ -70,13 +70,13 @@ class _NewChatScreenState extends State { 'state': false, 'watch': false, }, - filter: Filter.and([ - Filter.equal('members', [ + filter: Filter.raw(value: { + 'members': [ ..._selectedUsers.map((e) => e.id), chatState.user!.id, - ]), - Filter.equal('distinct', true), - ]), + ], + 'distinct': true, + }), messageLimit: 0, paginationParams: PaginationParams( limit: 1, From 0e506c6df788b9c2046377896c2eb79b1a82779a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 17 May 2021 15:23:06 +0200 Subject: [PATCH 08/48] fix mentions filter --- packages/stream_chat_v1/lib/main.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_v1/lib/main.dart b/packages/stream_chat_v1/lib/main.dart index 8b982e4..ecd9957 100644 --- a/packages/stream_chat_v1/lib/main.dart +++ b/packages/stream_chat_v1/lib/main.dart @@ -58,7 +58,7 @@ class _MyAppState extends State with TickerProviderStateMixin { final client = StreamChatClient( apiKey ?? kDefaultStreamApiKey, - logLevel: Level.SEVERE, + logLevel: Level.INFO, )..chatPersistenceClient = chatPersistentClient; if (userId != null) { @@ -501,7 +501,7 @@ class UserMentionPage extends StatelessWidget { child: MessageSearchListView( filters: Filter.in_('members', [user.id]), messageFilters: Filter.custom( - operator: 'contains', + operator: r'$contains', key: 'mentioned_users.id', value: user.id, ), From 273b24bcd865a9bed5a4de380b159492b056583c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 17 May 2021 15:48:03 +0200 Subject: [PATCH 09/48] bump deps --- packages/imessage/lib/main.dart | 124 +++++++++++++++----------------- packages/imessage/pubspec.yaml | 10 +-- 2 files changed, 61 insertions(+), 73 deletions(-) diff --git a/packages/imessage/lib/main.dart b/packages/imessage/lib/main.dart index f235f41..b1b4fa1 100644 --- a/packages/imessage/lib/main.dart +++ b/packages/imessage/lib/main.dart @@ -1,18 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart' - show - Channel, - ChannelListController, - ChannelListCore, - ChannelsBloc, - LazyLoadScrollView, - Level, - PaginationParams, - SortOption, - StreamChatClient, - StreamChatCore, - User; + hide ChannelListView; import 'package:imessage/channel_list_view.dart'; @@ -61,61 +50,60 @@ class ChatLoader extends StatelessWidget { Widget build(BuildContext context) { final user = StreamChatCore.of(context).user; return CupertinoPageScaffold( - child: ChannelsBloc( - child: ChannelListCore( - channelListController: channelListController, - filter: { - 'members': { - r'$in': [user.id], - }, - 'type': { - r'$eq': 'messaging', - }, - }, - sort: [SortOption('last_message_at')], - pagination: PaginationParams( - limit: 20, - ), - 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: CupertinoActivityIndicator(), - ), - ); - }, - errorBuilder: (BuildContext context, dynamic error) { - return Center( - child: Text( - 'Oh no, something went wrong. Please check your config.'), - ); - }, - listBuilder: ( - BuildContext context, - List channels, - ) => - LazyLoadScrollView( - onEndOfPage: () async { - channelListController.paginateData(); - }, - child: CustomScrollView( - slivers: [ - CupertinoSliverRefreshControl(onRefresh: () async { - channelListController.loadData(); - }), - ChannelPageAppBar(), - SliverPadding( - sliver: ChannelListView(channels: channels), - padding: const EdgeInsets.only(top: 16), - ) - ], - ), - )))); + child: ChannelsBloc( + child: ChannelListCore( + channelListController: channelListController, + filter: Filter.and([ + Filter.in_('members', [user.id]), + Filter.equal('type', 'messaging'), + ]), + sort: [SortOption('last_message_at')], + pagination: PaginationParams( + limit: 20, + ), + 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: CupertinoActivityIndicator(), + ), + ); + }, + errorBuilder: (BuildContext context, dynamic error) { + return Center( + child: Text( + 'Oh no, something went wrong. Please check your config.'), + ); + }, + listBuilder: ( + BuildContext context, + List channels, + ) => + LazyLoadScrollView( + onEndOfPage: () async { + return channelListController.paginateData(); + }, + child: CustomScrollView( + slivers: [ + CupertinoSliverRefreshControl(onRefresh: () async { + return channelListController.loadData(); + }), + ChannelPageAppBar(), + SliverPadding( + sliver: ChannelListView(channels: channels), + padding: const EdgeInsets.only(top: 16), + ) + ], + ), + ), + ), + ), + ); } } diff --git a/packages/imessage/pubspec.yaml b/packages/imessage/pubspec.yaml index 62e7507..2156918 100644 --- a/packages/imessage/pubspec.yaml +++ b/packages/imessage/pubspec.yaml @@ -23,11 +23,11 @@ environment: dependencies: flutter: sdk: flutter - intl: ^0.16.1 - stream_chat_flutter: ^1.3.0-beta - animations: ^1.0.0+5 - collection: ^1.14.13 - cached_network_image: ^2.0.0-rc + intl: ^0.17.0 + stream_chat_flutter: ^2.0.0-nullsafety.3 + animations: ^2.0.0 + collection: ^1.15.0 + cached_network_image: ^3.0.0 # The following adds the Cupertino Icons font to your application. From 33622093e0adb72247b293c7a24c4564d6be779b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 17 May 2021 15:58:10 +0200 Subject: [PATCH 10/48] migrate app --- packages/imessage/lib/channel_image.dart | 4 +- packages/imessage/lib/channel_list_view.dart | 4 +- packages/imessage/lib/channel_name_text.dart | 6 +-- .../imessage/lib/channel_page_appbar.dart | 2 +- packages/imessage/lib/channel_preview.dart | 23 ++++----- packages/imessage/lib/cutom_painter.dart | 4 +- packages/imessage/lib/main.dart | 10 ++-- packages/imessage/lib/message_header.dart | 2 +- packages/imessage/lib/message_input.dart | 39 +++++++++------ packages/imessage/lib/message_list_view.dart | 10 ++-- packages/imessage/lib/message_page.dart | 2 +- packages/imessage/lib/message_widget.dart | 47 +++++++++---------- packages/imessage/lib/utils.dart | 20 ++++---- packages/imessage/pubspec.yaml | 2 +- 14 files changed, 93 insertions(+), 82 deletions(-) diff --git a/packages/imessage/lib/channel_image.dart b/packages/imessage/lib/channel_image.dart index 65b23ff..d7b6343 100644 --- a/packages/imessage/lib/channel_image.dart +++ b/packages/imessage/lib/channel_image.dart @@ -4,7 +4,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart' show Channel; import 'package:imessage/utils.dart'; class ChannelImage extends StatelessWidget { - const ChannelImage({Key key, @required this.channel, @required this.size}) + const ChannelImage({Key? key, required this.channel, required this.size}) : super(key: key); final Channel channel; @@ -14,7 +14,7 @@ class ChannelImage extends StatelessWidget { Widget build(BuildContext context) { final avatarUrl = channel.extraData.containsKey('image') && (channel.extraData['image'] as String).isNotEmpty - ? channel.extraData['image'] as String + ? channel.extraData['image'] as String? : 'https://4.bp.blogspot.com/-Jx21kNqFSTU/UXemtqPhZCI/AAAAAAAAh74/BMGSzpU6F48/s1600/funny-cat-pictures-047-001.jpg'; return CupertinoCircleAvatar( diff --git a/packages/imessage/lib/channel_list_view.dart b/packages/imessage/lib/channel_list_view.dart index 89c03b5..9421b6d 100644 --- a/packages/imessage/lib/channel_list_view.dart +++ b/packages/imessage/lib/channel_list_view.dart @@ -6,7 +6,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart' show Channel, StreamChannel; class ChannelListView extends StatelessWidget { - const ChannelListView({Key key, @required this.channels}) : super(key: key); + const ChannelListView({Key? key, required this.channels}) : super(key: key); final List channels; @override Widget build(BuildContext context) { @@ -36,10 +36,10 @@ class ChannelListView extends StatelessWidget { child, ) => SharedAxisTransition( - child: child, animation: animation, secondaryAnimation: secondaryAnimation, transitionType: SharedAxisTransitionType.horizontal, + child: child, ), ), ); diff --git a/packages/imessage/lib/channel_name_text.dart b/packages/imessage/lib/channel_name_text.dart index e2e8d2b..169bb9d 100644 --- a/packages/imessage/lib/channel_name_text.dart +++ b/packages/imessage/lib/channel_name_text.dart @@ -3,8 +3,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart' show Channel; class ChannelNameText extends StatelessWidget { const ChannelNameText({ - Key key, - @required this.channel, + Key? key, + required this.channel, this.size = 17, }) : super(key: key); @@ -14,7 +14,7 @@ class ChannelNameText extends StatelessWidget { @override Widget build(BuildContext context) { return Text( - channel.extraData['name'] as String ?? 'No name', + channel.extraData['name'] as String? ?? 'No name', style: TextStyle( fontSize: size, fontWeight: FontWeight.bold, diff --git a/packages/imessage/lib/channel_page_appbar.dart b/packages/imessage/lib/channel_page_appbar.dart index f991829..5f44995 100644 --- a/packages/imessage/lib/channel_page_appbar.dart +++ b/packages/imessage/lib/channel_page_appbar.dart @@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart'; class ChannelPageAppBar extends StatelessWidget { const ChannelPageAppBar({ - Key key, + Key? key, }) : super(key: key); @override diff --git a/packages/imessage/lib/channel_preview.dart b/packages/imessage/lib/channel_preview.dart index 8b8c039..98a16c4 100644 --- a/packages/imessage/lib/channel_preview.dart +++ b/packages/imessage/lib/channel_preview.dart @@ -11,19 +11,20 @@ class ChannelPreview extends StatelessWidget { final Channel channel; const ChannelPreview({ - Key key, - @required this.onTap, - @required this.channel, + Key? key, + required this.onTap, + required this.channel, }) : super(key: key); @override Widget build(BuildContext context) { - final lastMessage = - channel.state.messages.isNotEmpty ? channel.state.messages.last : null; + final lastMessage = channel.state!.messages.isNotEmpty + ? channel.state!.messages.last + : null; final prefix = lastMessage?.attachments != null ? lastMessage?.attachments //TODO: ugly - ?.map((e) { + .map((e) { if (e.type == 'image') { return '📷 '; } else if (e.type == 'video') { @@ -31,8 +32,8 @@ class ChannelPreview extends StatelessWidget { } return null; }) - ?.where((e) => e != null) - ?.join(' ') + .where((e) => e != null) + .join(' ') : ''; return GestureDetector( onTap: onTap, @@ -76,9 +77,9 @@ class ChannelPreview extends StatelessWidget { child: Row( children: [ Text( - isSameWeek(channel.lastMessageAt) - ? formatDateSameWeek(channel.lastMessageAt) - : formatDate(channel.lastMessageAt), + isSameWeek(channel.lastMessageAt!) + ? formatDateSameWeek(channel.lastMessageAt!) + : formatDate(channel.lastMessageAt!), style: TextStyle( fontSize: 15, color: CupertinoColors.systemGrey, diff --git a/packages/imessage/lib/cutom_painter.dart b/packages/imessage/lib/cutom_painter.dart index 4437fc3..0ed6213 100644 --- a/packages/imessage/lib/cutom_painter.dart +++ b/packages/imessage/lib/cutom_painter.dart @@ -2,10 +2,10 @@ import 'package:flutter/cupertino.dart'; class ChatBubble extends CustomPainter { final Color color; - final Alignment alignment; + final Alignment? alignment; ChatBubble({ - @required this.color, + required this.color, this.alignment, }); diff --git a/packages/imessage/lib/main.dart b/packages/imessage/lib/main.dart index b1b4fa1..fc7283d 100644 --- a/packages/imessage/lib/main.dart +++ b/packages/imessage/lib/main.dart @@ -26,7 +26,7 @@ Future main() async { class IMessage extends StatelessWidget { final StreamChatClient client; - IMessage({@required this.client}); + IMessage({required this.client}); @override Widget build(BuildContext context) { initializeDateFormatting('en_US', null); @@ -41,14 +41,14 @@ class IMessage extends StatelessWidget { class ChatLoader extends StatelessWidget { ChatLoader({ - Key key, + Key? key, }) : super(key: key); final channelListController = ChannelListController(); @override Widget build(BuildContext context) { - final user = StreamChatCore.of(context).user; + final user = StreamChatCore.of(context).user!; return CupertinoPageScaffold( child: ChannelsBloc( child: ChannelListCore( @@ -87,12 +87,12 @@ class ChatLoader extends StatelessWidget { ) => LazyLoadScrollView( onEndOfPage: () async { - return channelListController.paginateData(); + return channelListController.paginateData!(); }, child: CustomScrollView( slivers: [ CupertinoSliverRefreshControl(onRefresh: () async { - return channelListController.loadData(); + return channelListController.loadData!(); }), ChannelPageAppBar(), SliverPadding( diff --git a/packages/imessage/lib/message_header.dart b/packages/imessage/lib/message_header.dart index 31ae34b..e8ee94b 100644 --- a/packages/imessage/lib/message_header.dart +++ b/packages/imessage/lib/message_header.dart @@ -4,7 +4,7 @@ import 'package:imessage/utils.dart'; class MessageHeader extends StatelessWidget { final String rawTimeStamp; - const MessageHeader({Key key, @required this.rawTimeStamp}) : super(key: key); + const MessageHeader({Key? key, required this.rawTimeStamp}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/packages/imessage/lib/message_input.dart b/packages/imessage/lib/message_input.dart index 9d9d831..7836498 100644 --- a/packages/imessage/lib/message_input.dart +++ b/packages/imessage/lib/message_input.dart @@ -3,11 +3,11 @@ import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:image_picker/image_picker.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart' - show Attachment, AttachmentFile, Message, MultipartFile, StreamChannel; + show Attachment, AttachmentFile, Message, StreamChannel; class MessageInput extends StatefulWidget { const MessageInput({ - Key key, + Key? key, }) : super(key: key); @override @@ -16,7 +16,6 @@ class MessageInput extends StatefulWidget { class _MessageInputState extends State { final textController = TextEditingController(); - File _image; final picker = ImagePicker(); @override @@ -39,16 +38,25 @@ class _MessageInputState extends State { GestureDetector( onTap: () async { final pickedFile = - await picker.getImage(source: ImageSource.gallery); + await (picker.getImage(source: ImageSource.gallery)); + if (pickedFile == null) { + return; + } final bytes = await File(pickedFile.path).readAsBytes(); final channel = StreamChannel.of(context).channel; - final message = - Message(text: textController.value.text, attachments: [ - Attachment( - type: 'image', - file: AttachmentFile(bytes: bytes, path: pickedFile.path), - ), - ]); + final message = Message( + text: textController.value.text, + attachments: [ + Attachment( + type: 'image', + file: AttachmentFile( + bytes: bytes, + path: pickedFile.path, + size: bytes.length, + ), + ), + ], + ); await channel.sendMessage(message); }, child: Padding( @@ -68,10 +76,11 @@ class _MessageInputState extends State { }, placeholder: 'Text Message', prefix: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - "") //trick to add padding around placeholder iMessage text - ), + padding: const EdgeInsets.all(8.0), + child: Text( + '', + ), //trick to add padding around placeholder iMessage text + ), suffix: GestureDetector( onTap: () async { if (textController.value.text.isNotEmpty) { diff --git a/packages/imessage/lib/message_list_view.dart b/packages/imessage/lib/message_list_view.dart index e12572c..b76f506 100644 --- a/packages/imessage/lib/message_list_view.dart +++ b/packages/imessage/lib/message_list_view.dart @@ -7,12 +7,12 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart' show Message, StreamChatCore; class MessageListView extends StatelessWidget { - const MessageListView({Key key, this.messages}) : super(key: key); - final List messages; + const MessageListView({Key? key, this.messages}) : super(key: key); + final List? messages; @override Widget build(BuildContext context) { - final entries = groupBy(messages, + final entries = groupBy(messages!, (Message message) => message.createdAt.toString().substring(0, 10)) .entries .toList(); @@ -64,8 +64,8 @@ class MessageListView extends StatelessWidget { } bool isReceived(Message message, BuildContext context) { - final currentUserId = StreamChatCore.of(context).user.id; - return message.user.id == currentUserId; + final currentUserId = StreamChatCore.of(context).user!.id; + return message.user!.id == currentUserId; } bool isSameDay(Message message) => diff --git a/packages/imessage/lib/message_page.dart b/packages/imessage/lib/message_page.dart index 01b555e..f64eb66 100644 --- a/packages/imessage/lib/message_page.dart +++ b/packages/imessage/lib/message_page.dart @@ -53,7 +53,7 @@ class MessagePage extends StatelessWidget { }, messageListBuilder: (context, messages) => LazyLoadScrollView( onStartOfPage: () async { - messageListController.paginateData(); + await messageListController.paginateData!(); }, child: MessageListView( messages: messages, diff --git a/packages/imessage/lib/message_widget.dart b/packages/imessage/lib/message_widget.dart index 494e9d2..8fa6638 100644 --- a/packages/imessage/lib/message_widget.dart +++ b/packages/imessage/lib/message_widget.dart @@ -1,8 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/cupertino.dart'; import 'package:imessage/cutom_painter.dart'; -import 'package:stream_chat_flutter/stream_chat_flutter.dart' - show Message, AttachmentUploadStateBuilder; +import 'package:stream_chat_flutter/stream_chat_flutter.dart' show Message; class MessageWidget extends StatelessWidget { final Alignment alignment; @@ -11,16 +10,16 @@ class MessageWidget extends StatelessWidget { final Color messageColor; const MessageWidget( - {Key key, - @required this.alignment, - @required this.message, - @required this.color, - @required this.messageColor}) + {Key? key, + required this.alignment, + required this.message, + required this.color, + required this.messageColor}) : super(key: key); @override Widget build(BuildContext context) { - if (message.attachments?.isNotEmpty == true && + if (message.attachments.isNotEmpty == true && message.attachments.first.type == 'image') { return MessageImage( color: color, message: message, messageColor: messageColor); @@ -36,10 +35,10 @@ class MessageWidget extends StatelessWidget { class MessageImage extends StatelessWidget { const MessageImage({ - Key key, - @required this.color, - @required this.message, - @required this.messageColor, + Key? key, + required this.color, + required this.message, + required this.messageColor, }) : super(key: key); final Color color; @@ -61,23 +60,23 @@ class MessageImage extends StatelessWidget { children: [ if (message.attachments.first.file != null) Image.memory( - message.attachments.first.file.bytes, + message.attachments.first.file!.bytes!, fit: BoxFit.cover, ) else CachedNetworkImage( imageUrl: message.attachments.first.thumbUrl ?? message.attachments.first.imageUrl ?? - message.attachments.first.assetUrl, + message.attachments.first.assetUrl!, ), - if (message.attachments.first?.title != null) + if (message.attachments.first.title != null) Padding( padding: const EdgeInsets.all(8.0), - child: Text(message.attachments.first.title, + child: Text(message.attachments.first.title!, style: TextStyle(color: messageColor)), ), message.attachments.first.pretext != null - ? Text(message.attachments.first.pretext) + ? Text(message.attachments.first.pretext!) : Container() ], ), @@ -92,7 +91,7 @@ class MessageImage extends StatelessWidget { child: Container( color: color, child: CachedNetworkImage( - imageUrl: message.attachments.first.thumbUrl, + imageUrl: message.attachments.first.thumbUrl!, )), ); } @@ -101,11 +100,11 @@ class MessageImage extends StatelessWidget { class MessageText extends StatelessWidget { const MessageText({ - Key key, - @required this.alignment, - @required this.color, - @required this.message, - @required this.messageColor, + Key? key, + required this.alignment, + required this.color, + required this.message, + required this.messageColor, }) : super(key: key); final Alignment alignment; @@ -133,7 +132,7 @@ class MessageText extends StatelessWidget { child: Padding( padding: const EdgeInsets.all(4.0), child: Text( - message.text, + message.text!, style: TextStyle(color: messageColor), ), ), diff --git a/packages/imessage/lib/utils.dart b/packages/imessage/lib/utils.dart index 4600512..6487b35 100644 --- a/packages/imessage/lib/utils.dart +++ b/packages/imessage/lib/utils.dart @@ -26,24 +26,26 @@ bool isSameWeek(DateTime timestamp) => DateTime.now().difference(timestamp).inDays < 7; class CupertinoCircleAvatar extends StatelessWidget { - final String url; - final double size; - const CupertinoCircleAvatar({Key key, this.url, this.size}) : super(key: key); + final String? url; + final double? size; + const CupertinoCircleAvatar({Key? key, this.url, this.size}) + : super(key: key); @override Widget build(BuildContext context) { return ClipRRect( - borderRadius: BorderRadius.circular(size / 2), + borderRadius: BorderRadius.circular(size! / 2), child: CachedNetworkImage( - imageUrl: url, + imageUrl: url!, height: size, width: size, fit: BoxFit.cover, errorWidget: (context, url, error) { //TODO: this crash the app when getting 404 and in debug mode, see :https://github.com/Baseflow/flutter_cached_network_image/issues/504 return CachedNetworkImage( - imageUrl: - "https://4.bp.blogspot.com/-Jx21kNqFSTU/UXemtqPhZCI/AAAAAAAAh74/BMGSzpU6F48/s1600/funny-cat-pictures-047-001.jpg"); + imageUrl: + 'https://4.bp.blogspot.com/-Jx21kNqFSTU/UXemtqPhZCI/AAAAAAAAh74/BMGSzpU6F48/s1600/funny-cat-pictures-047-001.jp', + ); }), ); } @@ -51,18 +53,18 @@ class CupertinoCircleAvatar extends StatelessWidget { class Divider extends StatelessWidget { const Divider({ - Key key, + Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return Expanded( child: Align( + alignment: Alignment.bottomCenter, child: Container( height: 1, color: CupertinoColors.systemGrey5, ), - alignment: Alignment.bottomCenter, ), ); } diff --git a/packages/imessage/pubspec.yaml b/packages/imessage/pubspec.yaml index 2156918..9d05f4c 100644 --- a/packages/imessage/pubspec.yaml +++ b/packages/imessage/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: From bc655e0dc4fc4501495578a8e5e917506525b7ff Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 18 May 2021 17:15:37 +0200 Subject: [PATCH 11/48] migrate chatty --- .../contents.xcworkspacedata | 2 +- packages/chatty/lib/data/auth_repository.dart | 2 +- .../lib/data/image_picker_repository.dart | 2 +- .../lib/data/local/image_picker_impl.dart | 13 ++- .../lib/data/local/stream_api_local_impl.dart | 26 +++--- .../data/local/upload_storage_local_impl.dart | 2 +- packages/chatty/lib/data/prod/auth_impl.dart | 13 ++- .../data/prod/persistent_storage_impl.dart | 2 +- .../chatty/lib/data/prod/stream_api_impl.dart | 30 +++---- .../lib/data/prod/upload_storage_impl.dart | 4 +- .../lib/data/stream_api_repository.dart | 10 +-- .../lib/data/upload_storage_repository.dart | 2 +- .../chatty/lib/domain/models/chat_user.dart | 6 +- .../domain/usecases/create_group_usecase.dart | 8 +- .../usecases/profile_sign_in_usecase.dart | 18 +++- .../lib/ui/common/avatar_image_view.dart | 6 +- .../chatty/lib/ui/common/loading_view.dart | 4 +- .../lib/ui/common/my_channel_preview.dart | 90 +++++++++---------- .../chatty/lib/ui/home/chat/chat_view.dart | 37 ++++---- .../selection/friends_selection_view.dart | 8 +- .../chat/selection/group_selection_cubit.dart | 4 +- .../chat/selection/group_selection_view.dart | 10 +-- packages/chatty/lib/ui/home/home_view.dart | 12 +-- .../lib/ui/home/settings/settings_view.dart | 6 +- .../profile_verify/profile_verify_cubit.dart | 2 +- .../profile_verify/profile_verify_view.dart | 2 +- packages/chatty/pubspec.yaml | 19 ++-- 27 files changed, 181 insertions(+), 159 deletions(-) diff --git a/packages/chatty/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/chatty/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a1..919434a 100644 --- a/packages/chatty/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/packages/chatty/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/packages/chatty/lib/data/auth_repository.dart b/packages/chatty/lib/data/auth_repository.dart index 2ac77e8..db5849e 100644 --- a/packages/chatty/lib/data/auth_repository.dart +++ b/packages/chatty/lib/data/auth_repository.dart @@ -1,7 +1,7 @@ import 'package:stream_chatter/domain/models/auth_user.dart'; abstract class AuthRepository { - Future getAuthUser(); + Future getAuthUser(); Future signIn(); Future logout(); } diff --git a/packages/chatty/lib/data/image_picker_repository.dart b/packages/chatty/lib/data/image_picker_repository.dart index f5632f0..08d7ab8 100644 --- a/packages/chatty/lib/data/image_picker_repository.dart +++ b/packages/chatty/lib/data/image_picker_repository.dart @@ -1,5 +1,5 @@ import 'dart:io'; abstract class ImagePickerRepository { - Future pickImage(); + Future pickImage(); } diff --git a/packages/chatty/lib/data/local/image_picker_impl.dart b/packages/chatty/lib/data/local/image_picker_impl.dart index 90c63e0..2bd82dd 100644 --- a/packages/chatty/lib/data/local/image_picker_impl.dart +++ b/packages/chatty/lib/data/local/image_picker_impl.dart @@ -4,10 +4,17 @@ import 'package:stream_chatter/data/image_picker_repository.dart'; class ImagePickerImpl extends ImagePickerRepository { @override - Future pickImage() async { + Future pickImage() async { final picker = ImagePicker(); - final pickedFile = - await picker.getImage(source: ImageSource.gallery, maxWidth: 400); + final pickedFile = await picker.getImage( + source: ImageSource.gallery, + maxWidth: 400, + ); + + if (pickedFile == null) { + return null; + } + return File(pickedFile.path); } } diff --git a/packages/chatty/lib/data/local/stream_api_local_impl.dart b/packages/chatty/lib/data/local/stream_api_local_impl.dart index a2d2e35..8337c92 100644 --- a/packages/chatty/lib/data/local/stream_api_local_impl.dart +++ b/packages/chatty/lib/data/local/stream_api_local_impl.dart @@ -8,7 +8,7 @@ class StreamApiLocalImpl extends StreamApiRepository { final StreamChatClient _client; @override - Future connectUser(ChatUser user, String token) async { + Future connectUser(ChatUser user, String? token) async { Map extraData = {}; if (user.image != null) { extraData['image'] = user.image; @@ -18,7 +18,7 @@ class StreamApiLocalImpl extends StreamApiRepository { } await _client.disconnect(); await _client.connectUser( - User(id: user.id, extraData: extraData), + User(id: user.id!, extraData: extraData as Map), token, ); return user; @@ -28,12 +28,12 @@ class StreamApiLocalImpl extends StreamApiRepository { Future> getChatUsers() async { final result = await _client.queryUsers(); final chatUsers = result.users - .where((element) => element.id != _client.state.user.id) + .where((element) => element.id != _client.state.user!.id) .map( (e) => ChatUser( id: e.id, name: e.name, - image: e.extraData['image'], + image: e.extraData['image'] as String?, ), ) .toList(); @@ -47,25 +47,25 @@ class StreamApiLocalImpl extends StreamApiRepository { @override Future createGroupChat( - String channelId, String name, List members, - {String image}) async { + String channelId, String? name, List? members, + {String? image}) async { final channel = _client.channel('messaging', id: channelId, extraData: { - 'name': name, - 'image': image, - 'members': [_client.state.user.id, ...members], + 'name': name!, + 'image': image!, + 'members': [_client.state.user!.id, ...members!], }); await channel.watch(); return channel; } @override - Future createSimpleChat(String friendId) async { + Future createSimpleChat(String? friendId) async { final channel = _client.channel('messaging', - id: '${_client.state.user.id.hashCode}${friendId.hashCode}', + id: '${_client.state.user!.id.hashCode}${friendId.hashCode}', extraData: { 'members': [ friendId, - _client.state.user.id, + _client.state.user!.id, ], }); await channel.watch(); @@ -84,6 +84,6 @@ class StreamApiLocalImpl extends StreamApiRepository { User(id: userId), token, ); - return _client.state.user.name != null && _client.state.user.name != userId; + return _client.state.user!.name != null && _client.state.user!.name != userId; } } diff --git a/packages/chatty/lib/data/local/upload_storage_local_impl.dart b/packages/chatty/lib/data/local/upload_storage_local_impl.dart index 8a3b804..a1b0f63 100644 --- a/packages/chatty/lib/data/local/upload_storage_local_impl.dart +++ b/packages/chatty/lib/data/local/upload_storage_local_impl.dart @@ -4,7 +4,7 @@ import 'package:stream_chatter/data/upload_storage_repository.dart'; class UploadStorageLocalImpl extends UploadStorageRepository { @override - Future uploadPhoto(File file, String path) async { + Future uploadPhoto(File? file, String path) async { return 'https://lh3.googleusercontent.com/a-/AOh14GjhqGZ-V7tNXS1pOIp9vbBij4OS9JbzxXgxgy1t=s600-k-no-rp-mo'; } } diff --git a/packages/chatty/lib/data/prod/auth_impl.dart b/packages/chatty/lib/data/prod/auth_impl.dart index 71bb3c6..cc8e139 100644 --- a/packages/chatty/lib/data/prod/auth_impl.dart +++ b/packages/chatty/lib/data/prod/auth_impl.dart @@ -7,7 +7,7 @@ class AuthImpl extends AuthRepository { FirebaseAuth _auth = FirebaseAuth.instance; @override - Future getAuthUser() async { + Future getAuthUser() async { final user = _auth.currentUser; if (user != null) { return AuthUser(user.uid); @@ -19,16 +19,21 @@ class AuthImpl extends AuthRepository { Future signIn() async { try { UserCredential userCredential; - final GoogleSignInAccount googleUser = await GoogleSignIn().signIn(); + final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn(); + + if (googleUser == null) { + throw Exception('login error'); + } + final GoogleSignInAuthentication googleAuth = await googleUser.authentication; final GoogleAuthCredential googleAuthCredential = GoogleAuthProvider.credential( accessToken: googleAuth.accessToken, idToken: googleAuth.idToken, - ); + ) as GoogleAuthCredential; userCredential = await _auth.signInWithCredential(googleAuthCredential); - final user = userCredential.user; + final user = userCredential.user!; return AuthUser(user.uid); } catch (e) { print(e); diff --git a/packages/chatty/lib/data/prod/persistent_storage_impl.dart b/packages/chatty/lib/data/prod/persistent_storage_impl.dart index 5d247d5..d701846 100644 --- a/packages/chatty/lib/data/prod/persistent_storage_impl.dart +++ b/packages/chatty/lib/data/prod/persistent_storage_impl.dart @@ -13,6 +13,6 @@ class PersistentStorageImpl extends PersistentStorageRepository { @override Future updateDarkMode(bool isDarkMode) async { final preference = await SharedPreferences.getInstance(); - return await preference.setBool(_isDarkMode, isDarkMode); + await preference.setBool(_isDarkMode, isDarkMode); } } diff --git a/packages/chatty/lib/data/prod/stream_api_impl.dart b/packages/chatty/lib/data/prod/stream_api_impl.dart index a60cd1c..877e210 100644 --- a/packages/chatty/lib/data/prod/stream_api_impl.dart +++ b/packages/chatty/lib/data/prod/stream_api_impl.dart @@ -11,7 +11,7 @@ class StreamApiImpl extends StreamApiRepository { final StreamChatClient _client; @override - Future connectUser(ChatUser user, String token) async { + Future connectUser(ChatUser user, String? token) async { Map extraData = {}; if (user.image != null) { extraData['image'] = user.image; @@ -21,7 +21,7 @@ class StreamApiImpl extends StreamApiRepository { } await _client.disconnect(); await _client.connectUser( - User(id: user.id, extraData: extraData), + User(id: user.id!, extraData: extraData as Map), token, ); return user; @@ -31,12 +31,12 @@ class StreamApiImpl extends StreamApiRepository { Future> getChatUsers() async { final result = await _client.queryUsers(); final chatUsers = result.users - .where((element) => element.id != _client.state.user.id) + .where((element) => element.id != _client.state.user!.id) .map( (e) => ChatUser( id: e.id, name: e.name, - image: e.extraData['image'], + image: e.extraData['image'] as String?, ), ) .toList(); @@ -44,10 +44,10 @@ class StreamApiImpl extends StreamApiRepository { } @override - Future getToken(String userId) async { + Future getToken(String userId) async { //TODO: use your own implementation in Production final response = await http.post( - 'your_backend_url', + Uri.parse('your_backend_url'), body: jsonEncode({'id': userId}), headers: { 'Content-Type': 'application/json; charset=UTF-8', @@ -62,25 +62,25 @@ class StreamApiImpl extends StreamApiRepository { } @override - Future createGroupChat(String id, String name, List members, - {String image}) async { + Future createGroupChat(String id, String? name, List? members, + {String? image}) async { final channel = _client.channel('messaging', id: id, extraData: { - 'name': name, - 'image': image, - 'members': [_client.state.user.id, ...members], + 'name': name!, + 'image': image!, + 'members': [_client.state.user!.id, ...members!], }); await channel.watch(); return channel; } @override - Future createSimpleChat(String friendId) async { + Future createSimpleChat(String? friendId) async { final channel = _client.channel('messaging', - id: '${_client.state.user.id.hashCode}${friendId.hashCode}', + id: '${_client.state.user!.id.hashCode}${friendId.hashCode}', extraData: { 'members': [ friendId, - _client.state.user.id, + _client.state.user!.id, ], }); await channel.watch(); @@ -99,6 +99,6 @@ class StreamApiImpl extends StreamApiRepository { User(id: userId), token, ); - return _client.state.user.name != null && _client.state.user.name != userId; + return _client.state.user!.name != null && _client.state.user!.name != userId; } } diff --git a/packages/chatty/lib/data/prod/upload_storage_impl.dart b/packages/chatty/lib/data/prod/upload_storage_impl.dart index 37f6830..a476f43 100644 --- a/packages/chatty/lib/data/prod/upload_storage_impl.dart +++ b/packages/chatty/lib/data/prod/upload_storage_impl.dart @@ -4,9 +4,9 @@ import 'package:stream_chatter/data/upload_storage_repository.dart'; class UploadStorageImpl extends UploadStorageRepository { @override - Future uploadPhoto(File file, String path) async { + Future uploadPhoto(File? file, String path) async { final ref = firebase_storage.FirebaseStorage.instance.ref(path); - final uploadTask = ref.putFile(file); + final uploadTask = ref.putFile(file!); await uploadTask; return await ref.getDownloadURL(); } diff --git a/packages/chatty/lib/data/stream_api_repository.dart b/packages/chatty/lib/data/stream_api_repository.dart index 3d5c215..b722932 100644 --- a/packages/chatty/lib/data/stream_api_repository.dart +++ b/packages/chatty/lib/data/stream_api_repository.dart @@ -3,12 +3,12 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; abstract class StreamApiRepository { Future> getChatUsers(); - Future getToken(String userId); + Future getToken(String userId); Future connectIfExist(String userId); - Future connectUser(ChatUser user, String token); + Future connectUser(ChatUser user, String? token); Future createGroupChat( - String channelId, String name, List members, - {String image}); - Future createSimpleChat(String friendId); + String channelId, String? name, List? members, + {String? image}); + Future createSimpleChat(String? friendId); Future logout(); } diff --git a/packages/chatty/lib/data/upload_storage_repository.dart b/packages/chatty/lib/data/upload_storage_repository.dart index 6876138..88590ee 100644 --- a/packages/chatty/lib/data/upload_storage_repository.dart +++ b/packages/chatty/lib/data/upload_storage_repository.dart @@ -1,5 +1,5 @@ import 'dart:io'; abstract class UploadStorageRepository { - Future uploadPhoto(File file, String path); + Future uploadPhoto(File? file, String path); } diff --git a/packages/chatty/lib/domain/models/chat_user.dart b/packages/chatty/lib/domain/models/chat_user.dart index 05a0a61..9ad376b 100644 --- a/packages/chatty/lib/domain/models/chat_user.dart +++ b/packages/chatty/lib/domain/models/chat_user.dart @@ -1,6 +1,6 @@ class ChatUser { const ChatUser({this.name, this.image, this.id}); - final String name; - final String image; - final String id; + final String? name; + final String? image; + final String? id; } diff --git a/packages/chatty/lib/domain/usecases/create_group_usecase.dart b/packages/chatty/lib/domain/usecases/create_group_usecase.dart index 0e19d80..4b0dc78 100644 --- a/packages/chatty/lib/domain/usecases/create_group_usecase.dart +++ b/packages/chatty/lib/domain/usecases/create_group_usecase.dart @@ -7,9 +7,9 @@ import 'package:uuid/uuid.dart'; class CreateGroupInput { CreateGroupInput({this.imageFile, this.name, this.members}); - final File imageFile; - final String name; - final List members; + final File? imageFile; + final String? name; + final List? members; } class CreateGroupUseCase { @@ -23,7 +23,7 @@ class CreateGroupUseCase { Future createGroup(CreateGroupInput input) async { final channelId = Uuid().v4(); - String image; + String? image; if (input.imageFile != null) { image = await _uploadStorageRepository.uploadPhoto( input.imageFile, 'channels/$channelId'); diff --git a/packages/chatty/lib/domain/usecases/profile_sign_in_usecase.dart b/packages/chatty/lib/domain/usecases/profile_sign_in_usecase.dart index 1c18918..19969d6 100644 --- a/packages/chatty/lib/domain/usecases/profile_sign_in_usecase.dart +++ b/packages/chatty/lib/domain/usecases/profile_sign_in_usecase.dart @@ -5,10 +5,12 @@ import 'package:stream_chatter/data/stream_api_repository.dart'; import 'package:stream_chatter/data/upload_storage_repository.dart'; import 'package:stream_chatter/domain/models/chat_user.dart'; +import '../exceptions/auth_exception.dart'; + class ProfileInput { ProfileInput({this.imageFile, this.name}); - final File imageFile; - final String name; + final File? imageFile; + final String? name; } class ProfileSignInUseCase { @@ -24,13 +26,21 @@ class ProfileSignInUseCase { Future verify(ProfileInput input) async { final auth = await _authRepository.getAuthUser(); + if (auth == null) { + throw AuthException(AuthErrorCode.not_auth); + } final token = await _streamApiRepository.getToken(auth.id); - String image; + String? image; if (input.imageFile != null) { image = await _uploadStorageRepository.uploadPhoto( input.imageFile, 'users/${auth.id}'); } await _streamApiRepository.connectUser( - ChatUser(name: input.name, id: auth.id, image: image), token); + ChatUser( + name: input.name, + id: auth.id, + image: image, + ), + token); } } diff --git a/packages/chatty/lib/ui/common/avatar_image_view.dart b/packages/chatty/lib/ui/common/avatar_image_view.dart index 76ee22a..08a2fbf 100644 --- a/packages/chatty/lib/ui/common/avatar_image_view.dart +++ b/packages/chatty/lib/ui/common/avatar_image_view.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; class AvatarImageView extends StatelessWidget { - const AvatarImageView({Key key, this.onTap, this.child}) : super(key: key); - final Widget child; - final VoidCallback onTap; + const AvatarImageView({Key? key, this.onTap, this.child}) : super(key: key); + final Widget? child; + final VoidCallback? onTap; @override Widget build(BuildContext context) { diff --git a/packages/chatty/lib/ui/common/loading_view.dart b/packages/chatty/lib/ui/common/loading_view.dart index 9e1cded..6ff3f12 100644 --- a/packages/chatty/lib/ui/common/loading_view.dart +++ b/packages/chatty/lib/ui/common/loading_view.dart @@ -5,8 +5,8 @@ class LoadingView extends StatelessWidget { final Widget child; const LoadingView({ - Key key, - @required this.child, + Key? key, + required this.child, this.isLoading = false, }) : super(key: key); diff --git a/packages/chatty/lib/ui/common/my_channel_preview.dart b/packages/chatty/lib/ui/common/my_channel_preview.dart index 8886b47..cd2417f 100644 --- a/packages/chatty/lib/ui/common/my_channel_preview.dart +++ b/packages/chatty/lib/ui/common/my_channel_preview.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:jiffy/jiffy.dart'; @@ -30,22 +31,22 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// Modify it to change the widget appearance. class MyChannelPreview extends StatelessWidget { /// Function called when tapping this widget - final void Function(Channel) onTap; + final void Function(Channel)? onTap; /// Function called when long pressing this widget - final void Function(Channel) onLongPress; + final void Function(Channel)? onLongPress; /// Channel displayed final Channel channel; /// The function called when the image is tapped - final VoidCallback onImageTap; + final VoidCallback? onImageTap; - final String heroTag; + final String? heroTag; MyChannelPreview({ - @required this.channel, - Key key, + required this.channel, + Key? key, this.onTap, this.onLongPress, this.onImageTap, @@ -59,24 +60,24 @@ class MyChannelPreview extends StatelessWidget { initialData: channel.isMuted, builder: (context, snapshot) { return Opacity( - opacity: snapshot.data ? 0.5 : 1, + opacity: snapshot.data! ? 0.5 : 1, child: ListTile( contentPadding: const EdgeInsets.symmetric( horizontal: 8, ), onTap: () { if (onTap != null) { - onTap(channel); + onTap!(channel); } }, onLongPress: () { if (onLongPress != null) { - onLongPress(channel); + onLongPress!(channel); } }, leading: Material( child: Hero( - tag: heroTag, + tag: heroTag!, child: StreamChannel( channel: channel, child: ChannelImage( @@ -95,13 +96,13 @@ class MyChannelPreview extends StatelessWidget { ), ), StreamBuilder>( - stream: channel.state.membersStream, - initialData: channel.state.members, + 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)) { + snapshot.data!.isEmpty || + !snapshot.data!.any((Member e) => + e.user!.id == channel.client.state.user!.id)) { return SizedBox(); } return ChannelUnreadIndicator( @@ -116,26 +117,26 @@ class MyChannelPreview extends StatelessWidget { Flexible(child: _buildSubtitle(context)), Builder( builder: (context) { - final lastMessage = channel.state.messages.lastWhere( + final lastMessage = + channel.state!.messages.lastWhereOrNull( (m) => !m.isDeleted && m.shadowed != true, - orElse: () => null, ); if (lastMessage?.user?.id == - StreamChat.of(context).user.id) { + StreamChat.of(context).user!.id) { return Padding( padding: const EdgeInsets.only(right: 4.0), child: SendingIndicator( - message: lastMessage, + message: lastMessage!, size: StreamChatTheme.of(context) .channelPreviewTheme .indicatorIconSize, - isMessageRead: channel.state.read + isMessageRead: channel.state!.read ?.where((element) => element.user.id != - channel.client.state.user.id) - ?.where((element) => element.lastRead + channel.client.state.user!.id) + .where((element) => element.lastRead .isAfter(lastMessage.createdAt)) - ?.isNotEmpty == + .isNotEmpty == true, ), ); @@ -152,14 +153,14 @@ class MyChannelPreview extends StatelessWidget { } Widget _buildDate(BuildContext context) { - return StreamBuilder( + return StreamBuilder( stream: channel.lastMessageAtStream, initialData: channel.lastMessageAt, builder: (context, snapshot) { if (!snapshot.hasData) { return SizedBox(); } - final lastMessageAt = snapshot.data.toLocal(); + final lastMessageAt = snapshot.data!.toLocal(); String stringDate; final now = DateTime.now(); @@ -198,11 +199,11 @@ class MyChannelPreview extends StatelessWidget { ' Channel is muted', style: StreamChatTheme.of(context) .channelPreviewTheme - .subtitle + .subtitle! .copyWith( color: StreamChatTheme.of(context) .channelPreviewTheme - .subtitle + .subtitle! .color, ), ), @@ -212,21 +213,20 @@ class MyChannelPreview extends StatelessWidget { return TypingIndicator( channel: channel, alternativeWidget: _buildLastMessage(context), - style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( + style: StreamChatTheme.of(context).channelPreviewTheme.subtitle!.copyWith( color: - StreamChatTheme.of(context).channelPreviewTheme.subtitle.color, + StreamChatTheme.of(context).channelPreviewTheme.subtitle!.color, ), ); } Widget _buildLastMessage(BuildContext context) { - return StreamBuilder>( - stream: channel.state.messagesStream, - initialData: channel.state.messages, + return StreamBuilder?>( + stream: channel.state!.messagesStream, + initialData: channel.state!.messages, builder: (context, snapshot) { - final lastMessage = snapshot.data?.lastWhere( - (m) => m.shadowed != true && !m.isDeleted, - orElse: () => null); + final lastMessage = snapshot.data + ?.lastWhereOrNull((m) => m.shadowed != true && !m.isDeleted); if (lastMessage == null) { return SizedBox(); } @@ -254,21 +254,21 @@ class MyChannelPreview extends StatelessWidget { return Text.rich( _getDisplayText( - text, + text!, lastMessage.mentionedUsers, lastMessage.attachments, - StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( + StreamChatTheme.of(context).channelPreviewTheme.subtitle!.copyWith( color: StreamChatTheme.of(context) .channelPreviewTheme - .subtitle + .subtitle! .color, fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) ? FontStyle.italic : FontStyle.normal), - StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( + StreamChatTheme.of(context).channelPreviewTheme.subtitle!.copyWith( color: StreamChatTheme.of(context) .channelPreviewTheme - .subtitle + .subtitle! .color, fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) ? FontStyle.italic @@ -321,8 +321,8 @@ class MyChannelPreview extends StatelessWidget { class ChannelUnreadIndicator extends StatelessWidget { const ChannelUnreadIndicator({ - Key key, - @required this.channel, + Key? key, + required this.channel, }) : super(key: key); final Channel channel; @@ -330,8 +330,8 @@ class ChannelUnreadIndicator extends StatelessWidget { @override Widget build(BuildContext context) { return StreamBuilder( - stream: channel.state.unreadCountStream, - initialData: channel.state.unreadCount, + stream: channel.state!.unreadCountStream, + initialData: channel.state!.unreadCount, builder: (context, snapshot) { if (!snapshot.hasData || snapshot.data == 0) { return SizedBox(); @@ -351,7 +351,7 @@ class ChannelUnreadIndicator extends StatelessWidget { ), child: Center( child: Text( - '${snapshot.data > 99 ? '99+' : snapshot.data}', + '${snapshot.data! > 99 ? '99+' : snapshot.data}', style: TextStyle( fontSize: 11, color: Colors.white, diff --git a/packages/chatty/lib/ui/home/chat/chat_view.dart b/packages/chatty/lib/ui/home/chat/chat_view.dart index 5267162..0bed83a 100644 --- a/packages/chatty/lib/ui/home/chat/chat_view.dart +++ b/packages/chatty/lib/ui/home/chat/chat_view.dart @@ -23,11 +23,10 @@ class ChatView extends StatelessWidget { ), body: ChannelsBloc( child: ChannelListView( - filter: { - 'members': { - '\$in': [StreamChat.of(context).user?.id], - } - }, + filter: Filter.in_( + 'members', + [StreamChat.of(context).user!.id], + ), sort: [SortOption('last_message_at')], channelPreviewBuilder: (context, channel) { return Container( @@ -36,22 +35,22 @@ class ChatView extends StatelessWidget { channel: channel, heroTag: channel.id, onImageTap: () { - String name; - String image; + String? name; + String? image; final currentUser = StreamChat.of(context).client.state.user; if (channel.isGroup) { name = channel.extraData['name']; image = channel.extraData['image']; } else { - final friend = channel.state.members - .where((element) => element.userId != currentUser.id) + final friend = channel.state!.members + .where((element) => element.userId != currentUser!.id) .first - .user; + .user!; name = friend.name; - image = friend.extraData['image']; + image = friend.extraData['image'] as String?; } - return Navigator.of(context).push( + Navigator.of(context).push( PageRouteBuilder( barrierColor: Colors.black45, barrierDismissible: true, @@ -110,15 +109,15 @@ class ChannelPage extends StatelessWidget { class ChatDetailView extends StatelessWidget { const ChatDetailView({ - Key key, + Key? key, this.image, this.name, this.channelId, }) : super(key: key); - final String image; - final String name; - final String channelId; + final String? image; + final String? name; + final String? channelId; @override Widget build(BuildContext context) { @@ -135,10 +134,10 @@ class ChatDetailView extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Hero( - tag: channelId, + tag: channelId!, child: ClipOval( child: Image.network( - image, + image!, height: 180, width: 180, fit: BoxFit.cover, @@ -146,7 +145,7 @@ class ChatDetailView extends StatelessWidget { ), ), Text( - name, + name!, style: TextStyle( fontWeight: FontWeight.w700, fontSize: 22, diff --git a/packages/chatty/lib/ui/home/chat/selection/friends_selection_view.dart b/packages/chatty/lib/ui/home/chat/selection/friends_selection_view.dart index d7c0d1f..3fdb50b 100644 --- a/packages/chatty/lib/ui/home/chat/selection/friends_selection_view.dart +++ b/packages/chatty/lib/ui/home/chat/selection/friends_selection_view.dart @@ -143,9 +143,9 @@ class FriendsSelectionView extends StatelessWidget { CircleAvatar( radius: 30, backgroundImage: NetworkImage( - chatUserState.chatUser.image), + chatUserState.chatUser.image!), ), - Text(chatUserState.chatUser.name), + Text(chatUserState.chatUser.name!), ], ), Positioned( @@ -178,9 +178,9 @@ class FriendsSelectionView extends StatelessWidget { }, leading: CircleAvatar( backgroundImage: - NetworkImage(chatUserState.chatUser.image), + NetworkImage(chatUserState.chatUser.image!), ), - title: Text(chatUserState.chatUser.name), + title: Text(chatUserState.chatUser.name!), trailing: isGroup ? Checkbox( value: chatUserState.selected, diff --git a/packages/chatty/lib/ui/home/chat/selection/group_selection_cubit.dart b/packages/chatty/lib/ui/home/chat/selection/group_selection_cubit.dart index 79ac5eb..db72b1a 100644 --- a/packages/chatty/lib/ui/home/chat/selection/group_selection_cubit.dart +++ b/packages/chatty/lib/ui/home/chat/selection/group_selection_cubit.dart @@ -13,8 +13,8 @@ class GroupSelectionState { this.channel, this.isLoading = false, }); - final File file; - final Channel channel; + final File? file; + final Channel? channel; final bool isLoading; } diff --git a/packages/chatty/lib/ui/home/chat/selection/group_selection_view.dart b/packages/chatty/lib/ui/home/chat/selection/group_selection_view.dart index 70c100b..42f65e5 100644 --- a/packages/chatty/lib/ui/home/chat/selection/group_selection_view.dart +++ b/packages/chatty/lib/ui/home/chat/selection/group_selection_view.dart @@ -28,7 +28,7 @@ class GroupSelectionView extends StatelessWidget { context, Scaffold( body: StreamChannel( - channel: snapshot.channel, + channel: snapshot.channel!, child: ChannelPage(), ), ), @@ -60,9 +60,9 @@ class GroupSelectionView extends StatelessWidget { children: [ AvatarImageView( onTap: context.read().pickImage, - child: snapshot?.file != null + child: snapshot.file != null ? Image.file( - snapshot?.file, + snapshot.file!, fit: BoxFit.cover, ) : Icon( @@ -104,9 +104,9 @@ class GroupSelectionView extends StatelessWidget { CircleAvatar( radius: 30, backgroundImage: - NetworkImage(chatUserState.chatUser.image), + NetworkImage(chatUserState.chatUser.image!), ), - Text(chatUserState.chatUser.name), + Text(chatUserState.chatUser.name!), ], ), ); diff --git a/packages/chatty/lib/ui/home/home_view.dart b/packages/chatty/lib/ui/home/home_view.dart index 5d30d87..0492889 100644 --- a/packages/chatty/lib/ui/home/home_view.dart +++ b/packages/chatty/lib/ui/home/home_view.dart @@ -36,7 +36,7 @@ class HomeView extends StatelessWidget { class HomeNavigationBar extends StatelessWidget { const HomeNavigationBar({ - Key key, + Key? key, }) : super(key: key); @override @@ -110,16 +110,16 @@ class HomeNavigationBar extends StatelessWidget { class _HomeNavItem extends StatelessWidget { const _HomeNavItem({ - Key key, + Key? key, this.iconData, this.text, this.onTap, this.selected = false, }) : super(key: key); - final IconData iconData; - final String text; - final VoidCallback onTap; + final IconData? iconData; + final String? text; + final VoidCallback? onTap; final bool selected; @override @@ -135,7 +135,7 @@ class _HomeNavItem extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Icon(iconData, color: color), - Text(text, style: TextStyle(color: color)), + Text(text!, style: TextStyle(color: color)), ], ), ); diff --git a/packages/chatty/lib/ui/home/settings/settings_view.dart b/packages/chatty/lib/ui/home/settings/settings_view.dart index 17020ff..4347749 100644 --- a/packages/chatty/lib/ui/home/settings/settings_view.dart +++ b/packages/chatty/lib/ui/home/settings/settings_view.dart @@ -10,8 +10,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class SettingsView extends StatelessWidget { @override Widget build(BuildContext context) { - final user = StreamChat.of(context).client.state.user; - final image = user?.extraData['image']; + final user = StreamChat.of(context).client.state.user!; + final image = user.extraData['image']; final textColor = Theme.of(context).appBarTheme.color; return MultiBlocProvider( providers: [ @@ -48,7 +48,7 @@ class SettingsView extends StatelessWidget { onTap: () => null, child: image != null ? Image.network( - image, + image as String, fit: BoxFit.cover, ) : Icon( diff --git a/packages/chatty/lib/ui/profile_verify/profile_verify_cubit.dart b/packages/chatty/lib/ui/profile_verify/profile_verify_cubit.dart index 2593f36..0dd4824 100644 --- a/packages/chatty/lib/ui/profile_verify/profile_verify_cubit.dart +++ b/packages/chatty/lib/ui/profile_verify/profile_verify_cubit.dart @@ -11,7 +11,7 @@ class ProfileState { this.success = false, this.loading = false, }); - final File file; + final File? file; final bool success; final bool loading; } diff --git a/packages/chatty/lib/ui/profile_verify/profile_verify_view.dart b/packages/chatty/lib/ui/profile_verify/profile_verify_view.dart index 4000202..6b6c2bd 100644 --- a/packages/chatty/lib/ui/profile_verify/profile_verify_view.dart +++ b/packages/chatty/lib/ui/profile_verify/profile_verify_view.dart @@ -39,7 +39,7 @@ class ProfileVerifyView extends StatelessWidget { onTap: context.read().pickImage, child: snapshot.file != null ? Image.file( - snapshot.file, + snapshot.file!, fit: BoxFit.cover, ) : Icon( diff --git a/packages/chatty/pubspec.yaml b/packages/chatty/pubspec.yaml index 6327bfd..c0f4552 100644 --- a/packages/chatty/pubspec.yaml +++ b/packages/chatty/pubspec.yaml @@ -4,22 +4,23 @@ publish_to: 'none' version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: sdk: flutter - flutter_bloc: 6.1.2 - stream_chat_flutter: 1.3.0-beta - uuid: 2.2.2 + flutter_bloc: ^7.0.0 + stream_chat_flutter: ^2.0.0-nullsafety.3 + uuid: ^3.0.4 - firebase_core: 0.7.0 - google_sign_in: 4.5.9 - firebase_auth: 0.20.0+1 - firebase_storage: 7.0.0 - shared_preferences: 0.5.12+4 + firebase_core: ^1.2.0 + google_sign_in: ^5.0.3 + firebase_auth: ^1.2.0 + firebase_storage: ^8.1.0 + shared_preferences: ^2.0.5 http: any + collection: ^1.15.0-nullsafety.4 dev_dependencies: flutter_test: From 1ec08cef830c519605a10999a3f1948ffd5a06bb Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 20 May 2021 14:40:03 +0200 Subject: [PATCH 12/48] update chatty --- .../lib/data/local/stream_api_local_impl.dart | 2 +- .../chatty/lib/data/prod/stream_api_impl.dart | 2 +- .../lib/ui/common/my_channel_preview.dart | 42 +++++++++---------- .../chatty/lib/ui/sign_in/sign_in_cubit.dart | 6 +-- packages/chatty/lib/ui/themes.dart | 2 +- 5 files changed, 24 insertions(+), 30 deletions(-) diff --git a/packages/chatty/lib/data/local/stream_api_local_impl.dart b/packages/chatty/lib/data/local/stream_api_local_impl.dart index 8337c92..4a84e35 100644 --- a/packages/chatty/lib/data/local/stream_api_local_impl.dart +++ b/packages/chatty/lib/data/local/stream_api_local_impl.dart @@ -84,6 +84,6 @@ class StreamApiLocalImpl extends StreamApiRepository { User(id: userId), token, ); - return _client.state.user!.name != null && _client.state.user!.name != userId; + return _client.state.user!.name != userId; } } diff --git a/packages/chatty/lib/data/prod/stream_api_impl.dart b/packages/chatty/lib/data/prod/stream_api_impl.dart index 877e210..fa65e76 100644 --- a/packages/chatty/lib/data/prod/stream_api_impl.dart +++ b/packages/chatty/lib/data/prod/stream_api_impl.dart @@ -99,6 +99,6 @@ class StreamApiImpl extends StreamApiRepository { User(id: userId), token, ); - return _client.state.user!.name != null && _client.state.user!.name != userId; + return _client.state.user!.name != userId; } } diff --git a/packages/chatty/lib/ui/common/my_channel_preview.dart b/packages/chatty/lib/ui/common/my_channel_preview.dart index cd2417f..2e168b5 100644 --- a/packages/chatty/lib/ui/common/my_channel_preview.dart +++ b/packages/chatty/lib/ui/common/my_channel_preview.dart @@ -232,29 +232,27 @@ class MyChannelPreview extends StatelessWidget { } var text = lastMessage.text; - if (lastMessage.attachments != null) { - 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 e == lastMessage.attachments.last - ? (e.title ?? 'File') - : '${e.title ?? 'File'} , '; - }).where((e) => e != null), - lastMessage.text ?? '', - ]; + 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 e == lastMessage.attachments.last + ? (e.title ?? 'File') + : '${e.title ?? 'File'} , '; + }), + lastMessage.text ?? '', + ]; - text = parts.join(' '); - } + text = parts.join(' '); return Text.rich( _getDisplayText( - text!, + text, lastMessage.mentionedUsers, lastMessage.attachments, StreamChatTheme.of(context).channelPreviewTheme.subtitle!.copyWith( @@ -291,15 +289,13 @@ class MyChannelPreview extends StatelessWidget { var textList = text.split(' '); var resList = []; for (var e in textList) { - if (mentions != null && - mentions.isNotEmpty && + if (mentions.isNotEmpty && mentions.any((element) => '@${element.name}' == e)) { resList.add(TextSpan( text: '$e ', style: mentionsTextStyle, )); - } else if (attachments != null && - attachments.isNotEmpty && + } else if (attachments.isNotEmpty && attachments .where((e) => e.title != null) .any((element) => element.title == e)) { diff --git a/packages/chatty/lib/ui/sign_in/sign_in_cubit.dart b/packages/chatty/lib/ui/sign_in/sign_in_cubit.dart index 10d23b2..ee341f2 100644 --- a/packages/chatty/lib/ui/sign_in/sign_in_cubit.dart +++ b/packages/chatty/lib/ui/sign_in/sign_in_cubit.dart @@ -20,10 +20,8 @@ class SignInCubit extends Cubit { emit(SignInState.existing_user); } } catch (ex) { - final result = await _loginUseCase.signIn(); - if (result != null) { - emit(SignInState.none); - } + _loginUseCase.signIn(); + emit(SignInState.none); } } } diff --git a/packages/chatty/lib/ui/themes.dart b/packages/chatty/lib/ui/themes.dart index c99082d..ef9412b 100644 --- a/packages/chatty/lib/ui/themes.dart +++ b/packages/chatty/lib/ui/themes.dart @@ -44,7 +44,7 @@ class Themes { selectedItemColor: primaryColor, unselectedItemColor: Colors.grey[300], ), - textSelectionColor: Colors.white, + textSelectionTheme: TextSelectionThemeData(selectionColor: Colors.white), // switch active color toggleableActiveColor: primaryColor, canvasColor: backgroundDarkColor, From c9e72ebc9144ffe93ab0e587ffa6ea73f81409b5 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 20 May 2021 14:40:35 +0200 Subject: [PATCH 13/48] add modal before removing member and remove make owner (not yet in backend) --- .../stream_chat_v1/lib/group_info_screen.dart | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/packages/stream_chat_v1/lib/group_info_screen.dart b/packages/stream_chat_v1/lib/group_info_screen.dart index 00e3966..76938fb 100644 --- a/packages/stream_chat_v1/lib/group_info_screen.dart +++ b/packages/stream_chat_v1/lib/group_info_screen.dart @@ -670,8 +670,9 @@ class _GroupInfoScreenState extends State { Filter.autoComplete('name', _userNameQuery), Filter.notIn('id', [ StreamChat.of(context).user!.id, - ...channel.state!.members.map(((e) => e.userId!) - as Object Function(Member)), + ...channel.state!.members + .map(((e) => e.userId)) + .whereType(), ]), ], ), @@ -893,18 +894,18 @@ class _GroupInfoScreenState extends State { ); }, ), - 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.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) @@ -915,7 +916,17 @@ class _GroupInfoScreenState extends State { size: 24.0, ), 'Remove From Group', () async { - await channel.removeMembers([user.id]); + final res = await showConfirmationDialog( + context, + title: 'Remove member', + okText: 'REMOVE', + question: 'Are you sure you want to remove this member?', + cancelText: 'CANCEL', + ); + + if (res == true) { + await channel.removeMembers([user.id]); + } Navigator.pop(context); }, color: StreamChatTheme.of(context).colorTheme.accentRed), _buildModalListTile( From 66ea6ae875f20bb17504ebb465d7b34ccbf9f962 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 20 May 2021 15:33:01 +0200 Subject: [PATCH 14/48] fix modal adding safearea --- .../stream_chat_v1/lib/group_info_screen.dart | 274 +++++++++--------- 1 file changed, 140 insertions(+), 134 deletions(-) diff --git a/packages/stream_chat_v1/lib/group_info_screen.dart b/packages/stream_chat_v1/lib/group_info_screen.dart index 76938fb..3e964b2 100644 --- a/packages/stream_chat_v1/lib/group_info_screen.dart +++ b/packages/stream_chat_v1/lib/group_info_screen.dart @@ -787,158 +787,164 @@ class _GroupInfoScreenState extends State { void _showUserInfoModal(User? user, bool isUserAdmin) { var channel = StreamChannel.of(context).channel; + final color = StreamChatTheme.of(context).colorTheme.white; showModalBottomSheet( context: context, clipBehavior: Clip.antiAlias, isScrollControlled: true, + backgroundColor: color, 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, - ), + return SafeArea( + child: StreamChannel( + channel: channel, + child: Material( + color: color, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 24.0, ), - ), - 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, + Center( + child: Text( + user!.name, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, ), - 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( - messageTheme: widget.messageTheme, - user: user, - ), - ), + 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, ), - ); - }, - ), - if (StreamChat.of(context).user!.id != user.id) - _buildModalListTile( - context, - StreamSvgIcon.message( - color: StreamChatTheme.of(context).colorTheme.grey, - size: 24.0, + borderRadius: BorderRadius.circular(32.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( + if (StreamChat.of(context).user!.id != user.id) + _buildModalListTile( context, - StreamSvgIcon.userRemove( - color: StreamChatTheme.of(context).colorTheme.accentRed, + StreamSvgIcon.user( + color: StreamChatTheme.of(context).colorTheme.grey, size: 24.0, ), - 'Remove From Group', () async { - final res = await showConfirmationDialog( - context, - title: 'Remove member', - okText: 'REMOVE', - question: 'Are you sure you want to remove this member?', - cancelText: 'CANCEL', - ); + 'View info', + () async { + var client = StreamChat.of(context).client; - if (res == true) { - 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, + 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( + messageTheme: widget.messageTheme, + user: user, + ), + ), + ), + ); + }, ), - 'Cancel', () { - Navigator.pop(context); - }), - ], + 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 { + final res = await showConfirmationDialog( + context, + title: 'Remove member', + okText: 'REMOVE', + question: + 'Are you sure you want to remove this member?', + cancelText: 'CANCEL', + ); + + if (res == true) { + 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); + }), + ], + ), ), ), ); From 4978d457630fc98c42223ef456b042f2ce8d3b2e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 28 May 2021 20:17:59 +0530 Subject: [PATCH 15/48] 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 16/48] 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 17/48] 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 18/48] 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 19/48] 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 20/48] 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') From bd61de99db8fccb32af2a89b8e7b1a98939524e1 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 11 Jun 2021 16:06:01 +0200 Subject: [PATCH 21/48] Update pubspec.yaml --- packages/stream_chat_v1/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_v1/pubspec.yaml b/packages/stream_chat_v1/pubspec.yaml index 9f1f30d..6906283 100644 --- a/packages/stream_chat_v1/pubspec.yaml +++ b/packages/stream_chat_v1/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. publish_to: 'none' -version: 1.5.4+1 +version: 1.6.0 environment: sdk: '>=2.12.0 <3.0.0' From 40b880e09c3204667c305b9e543fd45257f3bf2b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 11:59:31 +0200 Subject: [PATCH 22/48] add web build with production config to nightly --- .github/workflows/build_nightly.yml | 14 ++++++++++++++ .../ios/Runner.xcodeproj/project.pbxproj | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index 44716c9..9310363 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -69,3 +69,17 @@ jobs: with: name: android-stream-chat-v1 path: packages/stream_chat_v1/build/app/outputs/apk/release/app-release.apk + build_and_deploy_web: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: subosito/flutter-action@v1.4.0 + with: + channel: 'stable' + - name: Copy production config + run: echo ${{ secrets.PRODUCTION_CONFIG }} > lib/app_config.dart + - run: flutter pub get + - run: pub global activate peanut + - run: flutter pub global run peanut:peanut + - run: git push origin --set-upstream gh-pages + diff --git a/packages/stream_chat_v1/ios/Runner.xcodeproj/project.pbxproj b/packages/stream_chat_v1/ios/Runner.xcodeproj/project.pbxproj index ccb925f..417fb0b 100644 --- a/packages/stream_chat_v1/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/stream_chat_v1/ios/Runner.xcodeproj/project.pbxproj @@ -245,8 +245,10 @@ "${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework", "${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework", "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", + "${BUILT_PRODUCTS_DIR}/Reachability/Reachability.framework", "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", + "${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework", "${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework", "${BUILT_PRODUCTS_DIR}/flutter_app_badger/flutter_app_badger.framework", "${BUILT_PRODUCTS_DIR}/flutter_keyboard_visibility/flutter_keyboard_visibility.framework", @@ -273,8 +275,10 @@ "${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}/Reachability.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_app_badger.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_keyboard_visibility.framework", From c3ca037c928fc8cb22510a6ef2524ec23dc631e4 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 12:03:13 +0200 Subject: [PATCH 23/48] fix build --- .github/workflows/build_nightly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index 9310363..0827e9e 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -76,9 +76,9 @@ jobs: - uses: subosito/flutter-action@v1.4.0 with: channel: 'stable' + - run: flutter pub get - name: Copy production config run: echo ${{ secrets.PRODUCTION_CONFIG }} > lib/app_config.dart - - run: flutter pub get - run: pub global activate peanut - run: flutter pub global run peanut:peanut - run: git push origin --set-upstream gh-pages From 9693e4ac90362378cf89133dbfd83a436015feee Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 12:06:36 +0200 Subject: [PATCH 24/48] fix build --- .github/workflows/build_nightly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index 0827e9e..207c929 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -78,7 +78,7 @@ jobs: channel: 'stable' - run: flutter pub get - name: Copy production config - run: echo ${{ secrets.PRODUCTION_CONFIG }} > lib/app_config.dart + run: echo "${{ secrets.PRODUCTION_CONFIG }}" > lib/app_config.dart - run: pub global activate peanut - run: flutter pub global run peanut:peanut - run: git push origin --set-upstream gh-pages From 0c2f5018babe03775456432d2484de2f4b8ee87b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 12:08:43 +0200 Subject: [PATCH 25/48] fix build --- .github/workflows/build_nightly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index 207c929..6f8c13b 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -79,7 +79,7 @@ jobs: - run: flutter pub get - name: Copy production config run: echo "${{ secrets.PRODUCTION_CONFIG }}" > lib/app_config.dart - - run: pub global activate peanut + - run: flutter pub global activate peanut - run: flutter pub global run peanut:peanut - run: git push origin --set-upstream gh-pages From 2e8c3d91cfc9b0721a84eee6e2a857875c6590b7 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 12:16:26 +0200 Subject: [PATCH 26/48] build canvas kit --- .github/workflows/build_nightly.yml | 2 +- packages/stream_chat_v1/pubspec.yaml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index 6f8c13b..2c0270f 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -80,6 +80,6 @@ jobs: - name: Copy production config run: echo "${{ secrets.PRODUCTION_CONFIG }}" > lib/app_config.dart - run: flutter pub global activate peanut - - run: flutter pub global run peanut:peanut + - run: flutter pub global run peanut:peanut --canvas-kit - run: git push origin --set-upstream gh-pages diff --git a/packages/stream_chat_v1/pubspec.yaml b/packages/stream_chat_v1/pubspec.yaml index 6906283..3e1f7ca 100644 --- a/packages/stream_chat_v1/pubspec.yaml +++ b/packages/stream_chat_v1/pubspec.yaml @@ -44,7 +44,8 @@ dependency_overrides: dev_dependencies: flutter_launcher_icons: ^0.9.0 test: any - + build_runner: ^2.0.4 + build_web_compilers: ^3.0.0 flutter: assets: - assets/ From 194dd3946ae12072763e28a2d8e6fcdf18d7dc84 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 12:21:13 +0200 Subject: [PATCH 27/48] fix build --- .github/workflows/build_nightly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index 2c0270f..8a9ea11 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -80,6 +80,6 @@ jobs: - name: Copy production config run: echo "${{ secrets.PRODUCTION_CONFIG }}" > lib/app_config.dart - run: flutter pub global activate peanut - - run: flutter pub global run peanut:peanut --canvas-kit + - run: flutter pub global run peanut:peanut --web-renderer=canvaskit - run: git push origin --set-upstream gh-pages From aad4cad312f301f37477f80856462baeb369992f Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 12:28:11 +0200 Subject: [PATCH 28/48] add github config --- .github/workflows/build_nightly.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index 8a9ea11..85ccb0b 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -73,6 +73,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + - name: config git + - run: | + git config --local user.email "$(git log --format='%ae' HEAD^!)" + git config --local user.name "$(git log --format='%an' HEAD^!)" - uses: subosito/flutter-action@v1.4.0 with: channel: 'stable' From 3cd64cd869cbf5a965f1885f50812db6284fec4a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 12:28:49 +0200 Subject: [PATCH 29/48] fix action --- .github/workflows/build_nightly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index 85ccb0b..d55a8db 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -74,7 +74,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: config git - - run: | + run: | git config --local user.email "$(git log --format='%ae' HEAD^!)" git config --local user.name "$(git log --format='%an' HEAD^!)" - uses: subosito/flutter-action@v1.4.0 From f5aa8d6ea215be440a24c87baaafb51061b76f8e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 12:32:40 +0200 Subject: [PATCH 30/48] fix action --- .github/workflows/build_nightly.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index d55a8db..2a98539 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -75,8 +75,8 @@ jobs: - uses: actions/checkout@v2 - name: config git run: | - git config --local user.email "$(git log --format='%ae' HEAD^!)" - git config --local user.name "$(git log --format='%an' HEAD^!)" + git config --global user.email "$(git log --format='%ae' HEAD^!)" + git config --global user.name "$(git log --format='%an' HEAD^!)" - uses: subosito/flutter-action@v1.4.0 with: channel: 'stable' From 1d3ce9168c4687184e0f8c69ddb10efa57856b25 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 12:37:04 +0200 Subject: [PATCH 31/48] fix action --- .github/workflows/build_nightly.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index 2a98539..7627662 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -77,6 +77,7 @@ jobs: run: | git config --global user.email "$(git log --format='%ae' HEAD^!)" git config --global user.name "$(git log --format='%an' HEAD^!)" + git fetch origin gh-pages - uses: subosito/flutter-action@v1.4.0 with: channel: 'stable' From 43b769cb576ffee0f5ee9d5076d03dc1c7f9d73b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 12:40:40 +0200 Subject: [PATCH 32/48] fix action --- .github/workflows/build_nightly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index 7627662..6a9ede3 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -77,7 +77,7 @@ jobs: run: | git config --global user.email "$(git log --format='%ae' HEAD^!)" git config --global user.name "$(git log --format='%an' HEAD^!)" - git fetch origin gh-pages + git fetch origin gh-pages:gh-pages - uses: subosito/flutter-action@v1.4.0 with: channel: 'stable' From ff7fce1dcccd8dccc920ad4fce1bed56c3d0b2e1 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 12:54:39 +0200 Subject: [PATCH 33/48] try different action --- .github/workflows/build_nightly.yml | 7 ++++--- packages/stream_chat_v1/pubspec.yaml | 2 -- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index 6a9ede3..30e698a 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -84,7 +84,8 @@ jobs: - run: flutter pub get - name: Copy production config run: echo "${{ secrets.PRODUCTION_CONFIG }}" > lib/app_config.dart - - run: flutter pub global activate peanut - - run: flutter pub global run peanut:peanut --web-renderer=canvaskit - - run: git push origin --set-upstream gh-pages + - uses: erickzanardo/flutter-gh-pages@v3 + with: + webRenderer: canvaskit + diff --git a/packages/stream_chat_v1/pubspec.yaml b/packages/stream_chat_v1/pubspec.yaml index 3e1f7ca..59ce306 100644 --- a/packages/stream_chat_v1/pubspec.yaml +++ b/packages/stream_chat_v1/pubspec.yaml @@ -44,8 +44,6 @@ dependency_overrides: dev_dependencies: flutter_launcher_icons: ^0.9.0 test: any - build_runner: ^2.0.4 - build_web_compilers: ^3.0.0 flutter: assets: - assets/ From 9cd88dc0ebc0cfa2c47fae679c450d6479c9ba58 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 18 Jun 2021 12:57:09 +0200 Subject: [PATCH 34/48] fix work dir --- .github/workflows/build_nightly.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build_nightly.yml b/.github/workflows/build_nightly.yml index 30e698a..011d2fa 100644 --- a/.github/workflows/build_nightly.yml +++ b/.github/workflows/build_nightly.yml @@ -87,5 +87,6 @@ jobs: - uses: erickzanardo/flutter-gh-pages@v3 with: webRenderer: canvaskit + workingDir: packages/stream_chat_v1 From 1ecc21ca5303c3f2475cf4beb77d1c996c35f0d9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 21 Jun 2021 20:34:34 +0200 Subject: [PATCH 35/48] align with main repo --- .../stream_chat_v1/lib/advanced_options_page.dart | 4 ++-- packages/stream_chat_v1/lib/chat_info_screen.dart | 6 +++--- packages/stream_chat_v1/lib/choose_user_page.dart | 2 +- packages/stream_chat_v1/lib/group_info_screen.dart | 11 ++++++----- packages/stream_chat_v1/lib/main.dart | 13 +++++-------- packages/stream_chat_v1/lib/new_chat_screen.dart | 6 ++---- packages/stream_chat_v1/pubspec.yaml | 8 ++++---- 7 files changed, 23 insertions(+), 27 deletions(-) diff --git a/packages/stream_chat_v1/lib/advanced_options_page.dart b/packages/stream_chat_v1/lib/advanced_options_page.dart index 29fe270..3882580 100644 --- a/packages/stream_chat_v1/lib/advanced_options_page.dart +++ b/packages/stream_chat_v1/lib/advanced_options_page.dart @@ -306,7 +306,7 @@ class _AdvancedOptionsPageState extends State { key: kStreamToken, value: userToken, ); - await client.disconnect(); + client.closeConnection(); } catch (e) { var errorText = 'Error connecting, retry'; if (e is Map) { @@ -317,7 +317,7 @@ class _AdvancedOptionsPageState extends State { _apiKeyError = errorText.toUpperCase(); }); loading = false; - await client.disconnect(); + client.closeConnection(); return; } loading = false; diff --git a/packages/stream_chat_v1/lib/chat_info_screen.dart b/packages/stream_chat_v1/lib/chat_info_screen.dart index eca16bb..0fbd4ea 100644 --- a/packages/stream_chat_v1/lib/chat_info_screen.dart +++ b/packages/stream_chat_v1/lib/chat_info_screen.dart @@ -6,8 +6,8 @@ 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 'pinned_messages_screen.dart'; import 'routes/routes.dart'; /// Detail screen for a 1:1 chat correspondence @@ -615,7 +615,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { title = 'No title'; } } else { - title = extraData['name']; + title = extraData['name'] as String; } return Column( @@ -633,7 +633,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { ), Expanded( child: Text( - title!, + title, style: textStyle, )), Padding( diff --git a/packages/stream_chat_v1/lib/choose_user_page.dart b/packages/stream_chat_v1/lib/choose_user_page.dart index a6dd5e1..7c882e3 100644 --- a/packages/stream_chat_v1/lib/choose_user_page.dart +++ b/packages/stream_chat_v1/lib/choose_user_page.dart @@ -90,7 +90,7 @@ class ChooseUserPage extends StatelessWidget { ); final client = StreamChat.of(context).client; - client.apiKey = kDefaultStreamApiKey; + // client.apiKey = kDefaultStreamApiKey; await client.connectUser( user, token, diff --git a/packages/stream_chat_v1/lib/group_info_screen.dart b/packages/stream_chat_v1/lib/group_info_screen.dart index 6c45757..5ec1ec2 100644 --- a/packages/stream_chat_v1/lib/group_info_screen.dart +++ b/packages/stream_chat_v1/lib/group_info_screen.dart @@ -10,9 +10,9 @@ 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 'pinned_messages_screen.dart'; import 'routes/routes.dart'; class GroupInfoScreen extends StatefulWidget { @@ -61,7 +61,9 @@ class _GroupInfoScreenState extends State { super.initState(); var channel = StreamChannel.of(context); _nameController = TextEditingController.fromValue( - TextEditingValue(text: channel.channel.extraData['name'] ?? '')); + TextEditingValue( + text: (channel.channel.extraData['name'] as String?) ?? ''), + ); _searchController = TextEditingController()..addListener(_userNameListener); _nameController!.addListener(() { @@ -333,7 +335,7 @@ class _GroupInfoScreenState extends State { Widget _buildNameTile() { var channel = StreamChannel.of(context).channel; - var channelName = channel.extraData['name'] ?? ''; + var channelName = (channel.extraData['name'] as String?) ?? ''; return Material( color: StreamChatTheme.of(context).colorTheme.whiteSnow, @@ -377,8 +379,7 @@ class _GroupInfoScreenState extends State { ), ), ), - if ((channelName == null) || - (channelName != _nameController!.text.trim())) + if (channelName != _nameController!.text.trim()) Row( mainAxisSize: MainAxisSize.min, children: [ diff --git a/packages/stream_chat_v1/lib/main.dart b/packages/stream_chat_v1/lib/main.dart index c4d16b1..b0a0327 100644 --- a/packages/stream_chat_v1/lib/main.dart +++ b/packages/stream_chat_v1/lib/main.dart @@ -61,7 +61,7 @@ class _MyAppState extends State with TickerProviderStateMixin { logLevel: Level.INFO, )..chatPersistenceClient = chatPersistentClient; - if (userId != null) { + if (userId != null && token != null) { await client.connectUser( User(id: userId), token, @@ -148,7 +148,7 @@ class _MyAppState extends State with TickerProviderStateMixin { if (!kIsWeb) { _initData!.client.state.totalUnreadCountStream.listen((count) { - if (count! > 0) { + if (count > 0) { FlutterAppBadger.updateBadgeCount(count); } else { FlutterAppBadger.removeBadge(); @@ -235,6 +235,7 @@ class _MyAppState extends State with TickerProviderStateMixin { builder: (context, snapshot) => MaterialApp( builder: (context, child) { return StreamChat( + backgroundKeepAlive: Duration(seconds: 5), client: _initData!.client, onBackgroundEventReceived: (e) => showLocalNotification( e, _initData!.client.state.user!.id), @@ -445,9 +446,7 @@ class _HomePageState extends State { await secureStorage.deleteAll(); } - StreamChat.of(context).client.disconnect( - clearUser: true, - ); + StreamChat.of(context).client.disconnectUser(); await Navigator.pushReplacementNamed( context, @@ -714,9 +713,7 @@ class _ChannelListPageState extends State { }, swipeToAction: true, filter: Filter.in_('members', [user!.id]), - options: { - 'presence': true, - }, + presence: true, pagination: PaginationParams( limit: 20, ), diff --git a/packages/stream_chat_v1/lib/new_chat_screen.dart b/packages/stream_chat_v1/lib/new_chat_screen.dart index d708b00..e70c492 100644 --- a/packages/stream_chat_v1/lib/new_chat_screen.dart +++ b/packages/stream_chat_v1/lib/new_chat_screen.dart @@ -66,10 +66,8 @@ class _NewChatScreenState extends State { final chatState = StreamChat.of(context); final res = await chatState.client.queryChannelsOnline( - options: { - 'state': false, - 'watch': false, - }, + state: false, + watch: false, filter: Filter.raw(value: { 'members': [ ..._selectedUsers.map((e) => e.id), diff --git a/packages/stream_chat_v1/pubspec.yaml b/packages/stream_chat_v1/pubspec.yaml index 59ce306..9c82d91 100644 --- a/packages/stream_chat_v1/pubspec.yaml +++ b/packages/stream_chat_v1/pubspec.yaml @@ -13,12 +13,12 @@ dependencies: stream_chat_flutter: git: url: https://github.com/GetStream/stream-chat-flutter.git - ref: develop + ref: ref/segregate-api-layer path: packages/stream_chat_flutter stream_chat_persistence: git: url: https://github.com/GetStream/stream-chat-flutter.git - ref: develop + ref: ref/segregate-api-layer path: packages/stream_chat_persistence flutter_local_notifications: ^5.0.0+4 flutter_svg: ^0.22.0 @@ -33,12 +33,12 @@ dependency_overrides: stream_chat: git: url: https://github.com/GetStream/stream-chat-flutter.git - ref: develop + ref: ref/segregate-api-layer path: packages/stream_chat stream_chat_flutter_core: git: url: https://github.com/GetStream/stream-chat-flutter.git - ref: develop + ref: ref/segregate-api-layer path: packages/stream_chat_flutter_core dev_dependencies: From 3638e364712e454235e8a4353e14d35afa4e506e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 21 Jun 2021 20:38:43 +0200 Subject: [PATCH 36/48] extract main.dart widgets --- .../stream_chat_v1/lib/channel_list_page.dart | 199 +++++ packages/stream_chat_v1/lib/channel_page.dart | 183 +++++ .../stream_chat_v1/lib/chat_info_screen.dart | 2 +- .../lib/group_chat_details_screen.dart | 2 +- .../stream_chat_v1/lib/group_info_screen.dart | 2 +- packages/stream_chat_v1/lib/home_page.dart | 241 ++++++ packages/stream_chat_v1/lib/main.dart | 738 ------------------ .../stream_chat_v1/lib/new_chat_screen.dart | 2 +- .../stream_chat_v1/lib/routes/app_routes.dart | 26 +- packages/stream_chat_v1/lib/thread_page.dart | 70 ++ .../lib/user_mentions_page.dart | 88 +++ 11 files changed, 800 insertions(+), 753 deletions(-) create mode 100644 packages/stream_chat_v1/lib/channel_list_page.dart create mode 100644 packages/stream_chat_v1/lib/channel_page.dart create mode 100644 packages/stream_chat_v1/lib/home_page.dart create mode 100644 packages/stream_chat_v1/lib/thread_page.dart create mode 100644 packages/stream_chat_v1/lib/user_mentions_page.dart diff --git a/packages/stream_chat_v1/lib/channel_list_page.dart b/packages/stream_chat_v1/lib/channel_list_page.dart new file mode 100644 index 0000000..c6529d5 --- /dev/null +++ b/packages/stream_chat_v1/lib/channel_list_page.dart @@ -0,0 +1,199 @@ +import 'dart:async'; + +import 'package:example/routes/routes.dart'; +import 'package:example/search_text_field.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'channel_page.dart'; +import 'chat_info_screen.dart'; +import 'group_info_screen.dart'; + +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( + showErrorTile: true, + messageQuery: _channelQuery, + filters: Filter.in_('members', [user!.id]), + sortOptions: [ + SortOption( + 'created_at', + direction: SortOption.ASC, + ), + ], + pullToRefresh: false, + paginationParams: PaginationParams(limit: 20), + 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 results...', + ), + ], + ), + ), + ), + ); + }, + ); + }, + 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: Filter.in_('members', [user!.id]), + presence: true, + pagination: PaginationParams( + limit: 20, + ), + channelWidget: ChannelPage(), + onViewInfoTap: (channel) { + Navigator.pop(context); + if (channel.memberCount == 2 && channel.isDistinct) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: ChatInfoScreen( + messageTheme: StreamChatTheme.of(context) + .ownMessageTheme, + user: channel.state!.members + .where((m) => + m.userId != + channel.client.state.user!.id) + .first + .user, + ), + ), + ), + ); + } else { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: GroupInfoScreen( + messageTheme: StreamChatTheme.of(context) + .ownMessageTheme, + ), + ), + ), + ); + } + }, + ), + ), + ), + ), + ), + ), + ); + } +} diff --git a/packages/stream_chat_v1/lib/channel_page.dart b/packages/stream_chat_v1/lib/channel_page.dart new file mode 100644 index 0000000..1ff592c --- /dev/null +++ b/packages/stream_chat_v1/lib/channel_page.dart @@ -0,0 +1,183 @@ +import 'package:collection/collection.dart'; +import 'package:example/routes/routes.dart'; +import 'package:example/thread_page.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'chat_info_screen.dart'; +import 'group_info_screen.dart'; + +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; + + 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.firstWhereOrNull( + (element) => element.user!.id != currentUser!.id, + ); + if (otherUser != null) { + final pop = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + child: ChatInfoScreen( + messageTheme: StreamChatTheme.of(context).ownMessageTheme, + user: otherUser.user, + ), + channel: channel, + ), + ), + ); + + if (pop == true) { + Navigator.pop(context); + } + } + } else { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + child: GroupInfoScreen( + messageTheme: StreamChatTheme.of(context).ownMessageTheme, + ), + channel: channel, + ), + ), + ); + } + }, + ), + 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, + ), + ); + }, + pinPermissions: ['owner', 'admin', 'member'], + ), + 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(); + }, + ), + ], + ), + ); + } +} diff --git a/packages/stream_chat_v1/lib/chat_info_screen.dart b/packages/stream_chat_v1/lib/chat_info_screen.dart index 0fbd4ea..6517ef3 100644 --- a/packages/stream_chat_v1/lib/chat_info_screen.dart +++ b/packages/stream_chat_v1/lib/chat_info_screen.dart @@ -6,7 +6,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'channel_file_display_screen.dart'; import 'channel_media_display_screen.dart'; -import 'main.dart'; +import 'channel_page.dart'; import 'pinned_messages_screen.dart'; import 'routes/routes.dart'; diff --git a/packages/stream_chat_v1/lib/group_chat_details_screen.dart b/packages/stream_chat_v1/lib/group_chat_details_screen.dart index a1a92b8..c59f744 100644 --- a/packages/stream_chat_v1/lib/group_chat_details_screen.dart +++ b/packages/stream_chat_v1/lib/group_chat_details_screen.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:uuid/uuid.dart'; -import 'main.dart'; +import 'channel_page.dart'; import 'routes/routes.dart'; class GroupChatDetailsScreen extends StatefulWidget { diff --git a/packages/stream_chat_v1/lib/group_info_screen.dart b/packages/stream_chat_v1/lib/group_info_screen.dart index 5ec1ec2..1d9572e 100644 --- a/packages/stream_chat_v1/lib/group_info_screen.dart +++ b/packages/stream_chat_v1/lib/group_info_screen.dart @@ -10,8 +10,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'channel_file_display_screen.dart'; import 'channel_media_display_screen.dart'; +import 'channel_page.dart'; import 'chat_info_screen.dart'; -import 'main.dart'; import 'pinned_messages_screen.dart'; import 'routes/routes.dart'; diff --git a/packages/stream_chat_v1/lib/home_page.dart b/packages/stream_chat_v1/lib/home_page.dart new file mode 100644 index 0000000..af5f68d --- /dev/null +++ b/packages/stream_chat_v1/lib/home_page.dart @@ -0,0 +1,241 @@ +import 'package:example/routes/routes.dart'; +import 'package:example/user_mentions_page.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 'package:streaming_shared_preferences/streaming_shared_preferences.dart'; + +import 'channel_list_page.dart'; + +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: LeftDrawer( + user: 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(), + UserMentionsPage(), + ], + ), + ); + } +} + +class LeftDrawer extends StatelessWidget { + const LeftDrawer({ + Key? key, + required this.user, + }) : super(key: key); + + final User user; + + @override + Widget build(BuildContext context) { + 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); + + if (!kIsWeb) { + final secureStorage = FlutterSecureStorage(); + await secureStorage.deleteAll(); + } + + StreamChat.of(context).client.disconnectUser(); + + await Navigator.pushNamedAndRemoveUntil( + context, + Routes.APP, + ModalRoute.withName(Routes.APP), + ); + }, + 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, + ); + }, + ), + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/packages/stream_chat_v1/lib/main.dart b/packages/stream_chat_v1/lib/main.dart index b0a0327..05af49c 100644 --- a/packages/stream_chat_v1/lib/main.dart +++ b/packages/stream_chat_v1/lib/main.dart @@ -1,9 +1,6 @@ import 'dart:async'; -import 'package:collection/collection.dart' show IterableExtension; -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'; @@ -20,7 +17,6 @@ import 'app_config.dart'; import 'notifications_service.dart'; import 'routes/app_routes.dart'; import 'routes/routes.dart'; -import 'search_text_field.dart'; final chatPersistentClient = StreamChatPersistenceClient( logLevel: Level.SEVERE, @@ -273,740 +269,6 @@ class _MyAppState extends State with TickerProviderStateMixin { } } -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); - - if (!kIsWeb) { - final secureStorage = FlutterSecureStorage(); - await secureStorage.deleteAll(); - } - - StreamChat.of(context).client.disconnectUser(); - - 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, - ); - }, - ), - ), - ), - ), - ], - ), - ), - ), - ), - ); - } -} - -class UserMentionPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - final user = StreamChat.of(context).user!; - return MessageSearchBloc( - child: MessageSearchListView( - filters: Filter.in_('members', [user.id]), - messageFilters: Filter.custom( - operator: r'$contains', - key: 'mentioned_users.id', - value: 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( - showErrorTile: true, - messageQuery: _channelQuery, - filters: Filter.in_('members', [user!.id]), - sortOptions: [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - pullToRefresh: false, - paginationParams: PaginationParams(limit: 20), - 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 results...', - ), - ], - ), - ), - ), - ); - }, - ); - }, - 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: Filter.in_('members', [user!.id]), - presence: true, - pagination: PaginationParams( - limit: 20, - ), - channelWidget: ChannelPage(), - onViewInfoTap: (channel) { - Navigator.pop(context); - if (channel.memberCount == 2 && channel.isDistinct) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: ChatInfoScreen( - messageTheme: StreamChatTheme.of(context) - .ownMessageTheme, - user: channel.state!.members - .where((m) => - m.userId != - channel.client.state.user!.id) - .first - .user, - ), - ), - ), - ); - } else { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: GroupInfoScreen( - messageTheme: StreamChatTheme.of(context) - .ownMessageTheme, - ), - ), - ), - ); - } - }, - ), - ), - ), - ), - ), - ), - ); - } -} - -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; - - 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.firstWhereOrNull( - (element) => element.user!.id != currentUser!.id, - ); - if (otherUser != null) { - final pop = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - child: ChatInfoScreen( - messageTheme: StreamChatTheme.of(context).ownMessageTheme, - user: otherUser.user, - ), - channel: channel, - ), - ), - ); - - if (pop == true) { - Navigator.pop(context); - } - } - } else { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - child: GroupInfoScreen( - messageTheme: StreamChatTheme.of(context).ownMessageTheme, - ), - channel: channel, - ), - ), - ); - } - }, - ), - 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, - ), - ); - }, - pinPermissions: ['owner', 'admin', 'member'], - ), - 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(); - }, - ), - ], - ), - ); - } -} - -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, - pinPermissions: ['owner', 'admin', 'member'], - ), - ), - if (widget.parent!.type != 'deleted') - MessageInput( - parentMessage: widget.parent, - focusNode: _focusNode, - quotedMessage: _quotedMessage, - onQuotedMessageCleared: () { - setState(() => _quotedMessage = null); - _focusNode.unfocus(); - }, - ), - ], - ), - ); - } -} - class InitData { final StreamChatClient client; final StreamingSharedPreferences preferences; diff --git a/packages/stream_chat_v1/lib/new_chat_screen.dart b/packages/stream_chat_v1/lib/new_chat_screen.dart index e70c492..1d7f024 100644 --- a/packages/stream_chat_v1/lib/new_chat_screen.dart +++ b/packages/stream_chat_v1/lib/new_chat_screen.dart @@ -3,8 +3,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'channel_page.dart'; import 'chips_input_text_field.dart'; -import 'main.dart'; import 'routes/routes.dart'; class NewChatScreen extends StatefulWidget { diff --git a/packages/stream_chat_v1/lib/routes/app_routes.dart b/packages/stream_chat_v1/lib/routes/app_routes.dart index a8ce583..4bc157e 100644 --- a/packages/stream_chat_v1/lib/routes/app_routes.dart +++ b/packages/stream_chat_v1/lib/routes/app_routes.dart @@ -1,14 +1,17 @@ -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 '../advanced_options_page.dart'; +import '../channel_page.dart'; import '../chat_info_screen.dart'; +import '../choose_user_page.dart'; +import '../group_chat_details_screen.dart'; import '../group_info_screen.dart'; +import '../home_page.dart'; +import '../main.dart'; +import '../new_chat_screen.dart'; +import '../new_group_chat_screen.dart'; +import 'routes.dart'; class AppRoutes { /// Add entry for new route here @@ -42,12 +45,13 @@ class AppRoutes { return MaterialPageRoute( settings: const RouteSettings(name: Routes.CHANNEL_PAGE), builder: (_) { - final arg = args as ChannelPageArgs; + final channelPageArgs = args as ChannelPageArgs; return StreamChannel( - channel: arg.channel!, - initialMessageId: arg.initialMessage?.id, + channel: channelPageArgs.channel!, + initialMessageId: channelPageArgs.initialMessage?.id, child: ChannelPage( - highlightInitialMessage: arg.initialMessage != null, + highlightInitialMessage: + channelPageArgs.initialMessage != null, ), ); }); diff --git a/packages/stream_chat_v1/lib/thread_page.dart b/packages/stream_chat_v1/lib/thread_page.dart new file mode 100644 index 0000000..b9799c7 --- /dev/null +++ b/packages/stream_chat_v1/lib/thread_page.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +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, + pinPermissions: ['owner', 'admin', 'member'], + ), + ), + if (widget.parent!.type != 'deleted') + MessageInput( + parentMessage: widget.parent, + focusNode: _focusNode, + quotedMessage: _quotedMessage, + onQuotedMessageCleared: () { + setState(() => _quotedMessage = null); + _focusNode.unfocus(); + }, + ), + ], + ), + ); + } +} diff --git a/packages/stream_chat_v1/lib/user_mentions_page.dart b/packages/stream_chat_v1/lib/user_mentions_page.dart new file mode 100644 index 0000000..837aa19 --- /dev/null +++ b/packages/stream_chat_v1/lib/user_mentions_page.dart @@ -0,0 +1,88 @@ +import 'package:example/routes/routes.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'channel_page.dart'; + +class UserMentionsPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final user = StreamChat.of(context).user!; + return MessageSearchBloc( + child: MessageSearchListView( + filters: Filter.in_('members', [user.id]), + messageFilters: Filter.custom( + operator: r'$contains', + key: 'mentioned_users.id', + value: 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, + ), + ); + }, + ), + ); + } +} From 6acaf964661712330753368bf1383f05a0ed6ae9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 22 Jun 2021 12:52:11 +0200 Subject: [PATCH 37/48] refactor home page --- .../lib/advanced_options_page.dart | 9 +- packages/stream_chat_v1/lib/channel_list.dart | 199 +++++++++ .../stream_chat_v1/lib/channel_list_page.dart | 416 +++++++++++------- .../lib/channel_media_display_screen.dart | 16 +- .../stream_chat_v1/lib/choose_user_page.dart | 10 +- packages/stream_chat_v1/lib/home_page.dart | 236 +--------- packages/stream_chat_v1/lib/main.dart | 240 ++-------- .../lib/pinned_messages_screen.dart | 16 +- .../stream_chat_v1/lib/routes/app_routes.dart | 12 +- .../stream_chat_v1/lib/routes/routes.dart | 1 + .../stream_chat_v1/lib/splash_screen.dart | 122 +++++ packages/stream_chat_v1/pubspec.yaml | 20 +- 12 files changed, 647 insertions(+), 650 deletions(-) create mode 100644 packages/stream_chat_v1/lib/channel_list.dart create mode 100644 packages/stream_chat_v1/lib/splash_screen.dart diff --git a/packages/stream_chat_v1/lib/advanced_options_page.dart b/packages/stream_chat_v1/lib/advanced_options_page.dart index 3882580..4a97c68 100644 --- a/packages/stream_chat_v1/lib/advanced_options_page.dart +++ b/packages/stream_chat_v1/lib/advanced_options_page.dart @@ -1,3 +1,4 @@ +import 'package:example/home_page.dart'; import 'package:example/routes/routes.dart'; import 'package:example/stream_version.dart'; import 'package:flutter/material.dart'; @@ -306,7 +307,6 @@ class _AdvancedOptionsPageState extends State { key: kStreamToken, value: userToken, ); - client.closeConnection(); } catch (e) { var errorText = 'Error connecting, retry'; if (e is Map) { @@ -317,15 +317,14 @@ class _AdvancedOptionsPageState extends State { _apiKeyError = errorText.toUpperCase(); }); loading = false; - client.closeConnection(); return; } loading = false; await Navigator.pushNamedAndRemoveUntil( context, - Routes.APP, - ModalRoute.withName(Routes.APP), - arguments: client, + Routes.HOME, + ModalRoute.withName(Routes.HOME), + arguments: HomePageArgs(client), ); } }, diff --git a/packages/stream_chat_v1/lib/channel_list.dart b/packages/stream_chat_v1/lib/channel_list.dart new file mode 100644 index 0000000..e88c9a1 --- /dev/null +++ b/packages/stream_chat_v1/lib/channel_list.dart @@ -0,0 +1,199 @@ +import 'dart:async'; + +import 'package:example/routes/routes.dart'; +import 'package:example/search_text_field.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'channel_page.dart'; +import 'chat_info_screen.dart'; +import 'group_info_screen.dart'; + +class ChannelList extends StatefulWidget { + @override + _ChannelList createState() => _ChannelList(); +} + +class _ChannelList 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( + showErrorTile: true, + messageQuery: _channelQuery, + filters: Filter.in_('members', [user!.id]), + sortOptions: [ + SortOption( + 'created_at', + direction: SortOption.ASC, + ), + ], + pullToRefresh: false, + paginationParams: PaginationParams(limit: 20), + 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 results...', + ), + ], + ), + ), + ), + ); + }, + ); + }, + 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: Filter.in_('members', [user!.id]), + presence: true, + pagination: PaginationParams( + limit: 20, + ), + channelWidget: ChannelPage(), + onViewInfoTap: (channel) { + Navigator.pop(context); + if (channel.memberCount == 2 && channel.isDistinct) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: ChatInfoScreen( + messageTheme: StreamChatTheme.of(context) + .ownMessageTheme, + user: channel.state!.members + .where((m) => + m.userId != + channel.client.state.user!.id) + .first + .user, + ), + ), + ), + ); + } else { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: GroupInfoScreen( + messageTheme: StreamChatTheme.of(context) + .ownMessageTheme, + ), + ), + ), + ); + } + }, + ), + ), + ), + ), + ), + ), + ); + } +} diff --git a/packages/stream_chat_v1/lib/channel_list_page.dart b/packages/stream_chat_v1/lib/channel_list_page.dart index c6529d5..baf6eca 100644 --- a/packages/stream_chat_v1/lib/channel_list_page.dart +++ b/packages/stream_chat_v1/lib/channel_list_page.dart @@ -1,195 +1,277 @@ import 'dart:async'; import 'package:example/routes/routes.dart'; -import 'package:example/search_text_field.dart'; +import 'package:example/user_mentions_page.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_app_badger/flutter_app_badger.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 'channel_page.dart'; -import 'chat_info_screen.dart'; -import 'group_info_screen.dart'; +import 'channel_list.dart'; class ChannelListPage extends StatefulWidget { + const ChannelListPage({ + Key? key, + }) : super(key: key); + @override _ChannelListPageState createState() => _ChannelListPageState(); } class _ChannelListPageState extends State { - TextEditingController? _controller; + 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( + 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 WillPopScope( - onWillPop: () async { - if (_isSearchActive) { - _controller!.clear(); - setState(() => _isSearchActive = false); - return false; + if (user == null) { + return Offstage(); + } + return Scaffold( + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + appBar: ChannelListHeader( + onNewChatButtonTap: () { + Navigator.pushNamed(context, Routes.NEW_CHAT); + }, + preNavigationCallback: () { + FocusScope.of(context).requestFocus(FocusNode()); + }, + ), + drawer: LeftDrawer( + user: 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: [ + ChannelList(), + UserMentionsPage(), + ], + ), + ); + } + + StreamSubscription? badgeListener; + + @override + void initState() { + if (!kIsWeb) { + badgeListener = StreamChat.of(context) + .client + .state + .totalUnreadCountStream + .listen((count) { + if (count > 0) { + FlutterAppBadger.updateBadgeCount(count); + } else { + FlutterAppBadger.removeBadge(); } - 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( - showErrorTile: true, - messageQuery: _channelQuery, - filters: Filter.in_('members', [user!.id]), - sortOptions: [ - SortOption( - 'created_at', - direction: SortOption.ASC, + }); + } + super.initState(); + } + + @override + void dispose() { + badgeListener?.cancel(); + super.dispose(); + } +} + +class LeftDrawer extends StatelessWidget { + const LeftDrawer({ + Key? key, + required this.user, + }) : super(key: key); + + final User user; + + @override + Widget build(BuildContext context) { + 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, ), - ], - pullToRefresh: false, - paginationParams: PaginationParams(limit: 20), - 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 results...', - ), - ], - ), - ), - ), - ); - }, - ); - }, - 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: Filter.in_('members', [user!.id]), - presence: true, - pagination: PaginationParams( - limit: 20, ), - channelWidget: ChannelPage(), - onViewInfoTap: (channel) { - Navigator.pop(context); - if (channel.memberCount == 2 && channel.isDistinct) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: ChatInfoScreen( - messageTheme: StreamChatTheme.of(context) - .ownMessageTheme, - user: channel.state!.members - .where((m) => - m.userId != - channel.client.state.user!.id) - .first - .user, - ), - ), - ), - ); - } else { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: GroupInfoScreen( - messageTheme: StreamChatTheme.of(context) - .ownMessageTheme, - ), - ), - ), - ); - } + ), + ], + ), + ), + 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); + + if (!kIsWeb) { + final secureStorage = FlutterSecureStorage(); + await secureStorage.deleteAll(); + } + + final client = StreamChat.of(context).client; + client.disconnectUser(); + await client.dispose(); + + await Navigator.of( + context, + rootNavigator: true, + ).pushNamedAndRemoveUntil( + Routes.CHOOSE_USER, + ModalRoute.withName(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, + ); }, ), - ), + ), + ), + ), + ], ), ), ), diff --git a/packages/stream_chat_v1/lib/channel_media_display_screen.dart b/packages/stream_chat_v1/lib/channel_media_display_screen.dart index 5c33622..15f8fd6 100644 --- a/packages/stream_chat_v1/lib/channel_media_display_screen.dart +++ b/packages/stream_chat_v1/lib/channel_media_display_screen.dart @@ -71,21 +71,7 @@ class _ChannelMediaDisplayScreenState extends State { 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, - ), - ), - ), - ), + leading: StreamBackButton(), backgroundColor: StreamChatTheme.of(context).colorTheme.white, ), body: _buildMediaGrid(), diff --git a/packages/stream_chat_v1/lib/choose_user_page.dart b/packages/stream_chat_v1/lib/choose_user_page.dart index 7c882e3..e7be235 100644 --- a/packages/stream_chat_v1/lib/choose_user_page.dart +++ b/packages/stream_chat_v1/lib/choose_user_page.dart @@ -1,4 +1,5 @@ import 'package:example/app_config.dart'; +import 'package:example/home_page.dart'; import 'package:example/stream_version.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -6,6 +7,7 @@ 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 'main.dart'; import 'routes/routes.dart'; const kStreamApiKey = 'STREAM_API_KEY'; @@ -89,8 +91,11 @@ class ChooseUserPage extends StatelessWidget { ), ); - final client = StreamChat.of(context).client; - // client.apiKey = kDefaultStreamApiKey; + final client = StreamChatClient( + kDefaultStreamApiKey, + logLevel: Level.INFO, + )..chatPersistenceClient = chatPersistentClient; + await client.connectUser( user, token, @@ -115,6 +120,7 @@ class ChooseUserPage extends StatelessWidget { context, Routes.HOME, ModalRoute.withName(Routes.HOME), + arguments: HomePageArgs(client), ); }, leading: UserAvatar( diff --git a/packages/stream_chat_v1/lib/home_page.dart b/packages/stream_chat_v1/lib/home_page.dart index af5f68d..7746729 100644 --- a/packages/stream_chat_v1/lib/home_page.dart +++ b/packages/stream_chat_v1/lib/home_page.dart @@ -1,240 +1,30 @@ +import 'package:example/routes/app_routes.dart'; import 'package:example/routes/routes.dart'; -import 'package:example/user_mentions_page.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 'package:streaming_shared_preferences/streaming_shared_preferences.dart'; -import 'channel_list_page.dart'; +class HomePageArgs { + final StreamChatClient chatClient; -class HomePage extends StatefulWidget { - @override - _HomePageState createState() => _HomePageState(); + HomePageArgs(this.chatClient); } -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: LeftDrawer( - user: 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(), - UserMentionsPage(), - ], - ), - ); - } -} - -class LeftDrawer extends StatelessWidget { - const LeftDrawer({ +class HomePage extends StatelessWidget { + HomePage({ Key? key, - required this.user, + required this.chatClient, }) : super(key: key); - final User user; + final StreamChatClient chatClient; @override Widget build(BuildContext context) { - 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); - - if (!kIsWeb) { - final secureStorage = FlutterSecureStorage(); - await secureStorage.deleteAll(); - } - - StreamChat.of(context).client.disconnectUser(); - - await Navigator.pushNamedAndRemoveUntil( - context, - Routes.APP, - ModalRoute.withName(Routes.APP), - ); - }, - 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, - ); - }, - ), - ), - ), - ), - ], - ), - ), - ), + return StreamChat( + client: chatClient, + child: Navigator( + onGenerateRoute: AppRoutes.generateRoute, + initialRoute: Routes.CHANNEL_LIST_PAGE, ), ); } diff --git a/packages/stream_chat_v1/lib/main.dart b/packages/stream_chat_v1/lib/main.dart index 05af49c..e53e8c0 100644 --- a/packages/stream_chat_v1/lib/main.dart +++ b/packages/stream_chat_v1/lib/main.dart @@ -1,20 +1,18 @@ import 'dart:async'; import 'package:example/choose_user_page.dart'; +import 'package:example/home_page.dart'; +import 'package:example/splash_screen.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:lottie/lottie.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 'app_config.dart'; -import 'notifications_service.dart'; import 'routes/app_routes.dart'; import 'routes/routes.dart'; @@ -24,8 +22,6 @@ final chatPersistentClient = StreamChatPersistenceClient( ); void main() async { - WidgetsFlutterBinding.ensureInitialized(); - runApp(MyApp()); } @@ -34,13 +30,9 @@ class MyApp extends StatefulWidget { _MyAppState createState() => _MyAppState(); } -class _MyAppState extends State with TickerProviderStateMixin { +class _MyAppState extends State + with SplashScreenStateMixin, TickerProviderStateMixin { InitData? _initData; - bool _animCompleted = false; - Animation? _animation, _scaleAnimation; - AnimationController? _animationController, _scaleAnimationController; - Animation? _colorAnimation; - late int timeOfStartMs; Future _initConnection() async { String? apiKey, userId, token; @@ -69,56 +61,9 @@ class _MyAppState extends State with TickerProviderStateMixin { return InitData(client, prefs); } - void _createAnimations() { - _scaleAnimationController = AnimationController( - vsync: this, - value: 0, - duration: Duration( - milliseconds: 500, - ), - ); - _scaleAnimation = Tween( - begin: 1.0, - end: 1.5, - ).animate(CurvedAnimation( - parent: _scaleAnimationController!, - curve: Curves.easeInOutBack, - )); - - _animationController = AnimationController( - vsync: this, - duration: Duration( - milliseconds: 1000, - ), - ); - _animation = Tween( - begin: 0.0, - end: 1000.0, - ).animate(CurvedAnimation( - parent: _animationController!, - curve: Curves.easeInOut, - )); - _colorAnimation = ColorTween( - begin: Color(0xff005FFF), - end: Color(0xff005FFF), - ).animate(CurvedAnimation( - parent: _animationController!, - curve: Curves.easeInOut, - )); - _colorAnimation = ColorTween( - begin: Color(0xff005FFF), - end: Colors.transparent, - ).animate(CurvedAnimation( - parent: _animationController!, - curve: Curves.easeInOut, - )); - } - @override void initState() { - timeOfStartMs = DateTime.now().millisecondsSinceEpoch; - - _createAnimations(); + final timeOfStartMs = DateTime.now().millisecondsSinceEpoch; _initConnection().then( (initData) { @@ -126,97 +71,23 @@ class _MyAppState extends State with TickerProviderStateMixin { _initData = initData; }); - var now = DateTime.now().millisecondsSinceEpoch; + final now = DateTime.now().millisecondsSinceEpoch; if (now - timeOfStartMs > 1500) { SchedulerBinding.instance!.addPostFrameCallback((timeStamp) { - _scaleAnimationController?.forward().whenComplete(() { - _animationController?.forward(); - }); + forwardAnimations(); }); } else { Future.delayed(Duration(milliseconds: 1500)).then((value) { - _scaleAnimationController?.forward().whenComplete(() { - _animationController?.forward(); - }); - }); - } - - if (!kIsWeb) { - _initData!.client.state.totalUnreadCountStream.listen((count) { - if (count > 0) { - FlutterAppBadger.updateBadgeCount(count); - } else { - FlutterAppBadger.removeBadge(); - } + forwardAnimations(); }); } }, ); - _animationController?.addStatusListener((status) { - if (status == AnimationStatus.completed) { - setState(() { - _animCompleted = true; - }); - } - }); super.initState(); } - Widget _buildAnimation() { - return MaterialApp( - home: Stack( - clipBehavior: Clip.none, - alignment: Alignment.center, - children: [ - AnimatedBuilder( - animation: _scaleAnimation!, - builder: (context, _) { - return Transform.scale( - scale: _scaleAnimation!.value, - child: AnimatedBuilder( - animation: _colorAnimation!, - builder: (context, snapshot) { - return Container( - alignment: Alignment.center, - constraints: BoxConstraints.expand(), - color: _colorAnimation == null - ? Color(0xff005FFF) - : _colorAnimation!.value, - child: !_animationController!.isAnimating - ? Lottie.asset( - 'assets/floating_boat.json', - alignment: Alignment.center, - ) - : SizedBox(), - ); - }), - ); - }, - ), - AnimatedBuilder( - animation: _animation!, - builder: (context, snapshot) { - return Transform.scale( - scale: _animation!.value, - child: Container( - width: 1.0, - height: 1.0, - decoration: BoxDecoration( - color: Colors.white - .withOpacity(1 - _animationController!.value), - shape: BoxShape.circle, - ), - ), - ); - }, - ), - ], - ), - ); - } - @override Widget build(BuildContext context) { return Stack( @@ -229,27 +100,6 @@ class _MyAppState extends State with TickerProviderStateMixin { defaultValue: 0, ), builder: (context, snapshot) => MaterialApp( - builder: (context, child) { - return StreamChat( - backgroundKeepAlive: Duration(seconds: 5), - client: _initData!.client, - onBackgroundEventReceived: (e) => showLocalNotification( - e, _initData!.client.state.user!.id), - 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, - ), - ), - ), - ); - }, theme: ThemeData.light(), darkTheme: ThemeData.dark(), themeMode: { @@ -257,13 +107,38 @@ class _MyAppState extends State with TickerProviderStateMixin { 0: ThemeMode.system, 1: ThemeMode.light, }[snapshot], + builder: (context, child) => StreamChatTheme( + data: StreamChatThemeData( + brightness: Theme.of(context).brightness, + ), + child: child!, + ), onGenerateRoute: AppRoutes.generateRoute, + onGenerateInitialRoutes: (initialRouteName) { + if (initialRouteName == Routes.HOME) { + return [ + AppRoutes.generateRoute( + RouteSettings( + name: Routes.HOME, + arguments: HomePageArgs(_initData!.client), + ), + )! + ]; + } + return [ + AppRoutes.generateRoute( + RouteSettings( + name: Routes.CHOOSE_USER, + ), + )! + ]; + }, initialRoute: _initData!.client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, ), ), - if (!_animCompleted) _buildAnimation(), + if (!animationCompleted) buildAnimation(), ], ); } @@ -275,50 +150,3 @@ class InitData { InitData(this.client, this.preferences); } - -class HolePainter extends CustomPainter { - HolePainter({ - required this.color, - required this.holeSize, - }); - - Color color; - double holeSize; - - @override - void paint(Canvas canvas, Size size) { - double radius = holeSize / 2; - Rect rect = Rect.fromLTWH(0, 0, size.width, size.height); - Rect outerCircleRect = Rect.fromCircle( - center: Offset(size.width / 2, size.height / 2), radius: radius); - Rect innerCircleRect = Rect.fromCircle( - center: Offset(size.width / 2, size.height / 2), radius: radius / 2); - - Path transparentHole = Path.combine( - PathOperation.difference, - Path()..addRect(rect), - Path() - ..addOval(outerCircleRect) - ..close(), - ); - - Path halfTransparentRing = Path.combine( - PathOperation.difference, - Path() - ..addOval(outerCircleRect) - ..close(), - Path() - ..addOval(innerCircleRect) - ..close(), - ); - - canvas.drawPath(transparentHole, Paint()..color = color); - canvas.drawPath( - halfTransparentRing, Paint()..color = color.withOpacity(0.5)); - } - - @override - bool shouldRepaint(CustomPainter oldDelegate) { - return true; - } -} diff --git a/packages/stream_chat_v1/lib/pinned_messages_screen.dart b/packages/stream_chat_v1/lib/pinned_messages_screen.dart index 82dd532..d8f756b 100644 --- a/packages/stream_chat_v1/lib/pinned_messages_screen.dart +++ b/packages/stream_chat_v1/lib/pinned_messages_screen.dart @@ -70,21 +70,7 @@ class _PinnedMessagesScreenState extends State { 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, - ), - ), - ), - ), + leading: StreamBackButton(), backgroundColor: StreamChatTheme.of(context).colorTheme.white, ), body: _buildMediaGrid(), diff --git a/packages/stream_chat_v1/lib/routes/app_routes.dart b/packages/stream_chat_v1/lib/routes/app_routes.dart index 4bc157e..145fa8e 100644 --- a/packages/stream_chat_v1/lib/routes/app_routes.dart +++ b/packages/stream_chat_v1/lib/routes/app_routes.dart @@ -1,3 +1,4 @@ +import 'package:example/channel_list_page.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -28,7 +29,10 @@ class AppRoutes { return MaterialPageRoute( settings: const RouteSettings(name: Routes.HOME), builder: (_) { - return HomePage(); + final homePageArgs = args as HomePageArgs; + return HomePage( + chatClient: homePageArgs.chatClient, + ); }); case Routes.CHOOSE_USER: return MaterialPageRoute( @@ -92,6 +96,12 @@ class AppRoutes { messageTheme: StreamChatTheme.of(context).ownMessageTheme, ); }); + case Routes.CHANNEL_LIST_PAGE: + return MaterialPageRoute( + settings: const RouteSettings(name: Routes.CHANNEL_LIST_PAGE), + builder: (context) { + return ChannelListPage(); + }); // Default case, should not reach here. default: return null; diff --git a/packages/stream_chat_v1/lib/routes/routes.dart b/packages/stream_chat_v1/lib/routes/routes.dart index 2280ca3..239bd28 100644 --- a/packages/stream_chat_v1/lib/routes/routes.dart +++ b/packages/stream_chat_v1/lib/routes/routes.dart @@ -10,4 +10,5 @@ class Routes { 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'; + static const String CHANNEL_LIST_PAGE = '/channel_list_page'; } diff --git a/packages/stream_chat_v1/lib/splash_screen.dart b/packages/stream_chat_v1/lib/splash_screen.dart new file mode 100644 index 0000000..2c89228 --- /dev/null +++ b/packages/stream_chat_v1/lib/splash_screen.dart @@ -0,0 +1,122 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:lottie/lottie.dart'; + +mixin SplashScreenStateMixin on State + implements TickerProvider { + late Animation animation, scaleAnimation; + late AnimationController _animationController, _scaleAnimationController; + late Animation colorAnimation; + bool animationCompleted = false; + + void _createAnimations() { + _scaleAnimationController = AnimationController( + vsync: this, + value: 0, + duration: Duration( + milliseconds: 500, + ), + ); + scaleAnimation = Tween( + begin: 1.0, + end: 1.5, + ).animate(CurvedAnimation( + parent: _scaleAnimationController, + curve: Curves.easeInOutBack, + )); + + _animationController = AnimationController( + vsync: this, + duration: Duration( + milliseconds: 1000, + ), + ); + animation = Tween( + begin: 0.0, + end: 1000.0, + ).animate(CurvedAnimation( + parent: _animationController, + curve: Curves.easeInOut, + )); + colorAnimation = ColorTween( + begin: Color(0xff005FFF), + end: Color(0xff005FFF), + ).animate(CurvedAnimation( + parent: _animationController, + curve: Curves.easeInOut, + )); + colorAnimation = ColorTween( + begin: Color(0xff005FFF), + end: Colors.transparent, + ).animate(CurvedAnimation( + parent: _animationController, + curve: Curves.easeInOut, + )); + } + + void forwardAnimations() { + _scaleAnimationController.forward().whenComplete(() { + _animationController.forward(); + }); + } + + Widget buildAnimation() => Stack( + clipBehavior: Clip.none, + alignment: Alignment.center, + children: [ + AnimatedBuilder( + animation: scaleAnimation, + builder: (context, _) { + return Transform.scale( + scale: scaleAnimation.value, + child: AnimatedBuilder( + animation: colorAnimation, + builder: (context, snapshot) { + return Container( + alignment: Alignment.center, + constraints: BoxConstraints.expand(), + color: colorAnimation.value, + child: !_animationController.isAnimating + ? Lottie.asset( + 'assets/floating_boat.json', + alignment: Alignment.center, + ) + : SizedBox(), + ); + }), + ); + }, + ), + AnimatedBuilder( + animation: animation, + builder: (context, snapshot) { + return Transform.scale( + scale: animation.value, + child: Container( + width: 1.0, + height: 1.0, + decoration: BoxDecoration( + color: Colors.white + .withOpacity(1 - _animationController.value), + shape: BoxShape.circle, + ), + ), + ); + }, + ), + ], + ); + + @override + void initState() { + _createAnimations(); + _animationController.addStatusListener((status) { + if (status == AnimationStatus.completed) { + setState(() { + animationCompleted = true; + }); + } + }); + super.initState(); + } +} diff --git a/packages/stream_chat_v1/pubspec.yaml b/packages/stream_chat_v1/pubspec.yaml index 9c82d91..8c0528b 100644 --- a/packages/stream_chat_v1/pubspec.yaml +++ b/packages/stream_chat_v1/pubspec.yaml @@ -11,15 +11,9 @@ dependencies: flutter: sdk: flutter stream_chat_flutter: - git: - url: https://github.com/GetStream/stream-chat-flutter.git - ref: ref/segregate-api-layer - path: packages/stream_chat_flutter + path: ../../../stream-chat-flutter/packages/stream_chat_flutter stream_chat_persistence: - git: - url: https://github.com/GetStream/stream-chat-flutter.git - ref: ref/segregate-api-layer - path: packages/stream_chat_persistence + path: ../../../stream-chat-flutter/packages/stream_chat_persistence flutter_local_notifications: ^5.0.0+4 flutter_svg: ^0.22.0 flutter_secure_storage: ^4.2.0 @@ -31,15 +25,9 @@ dependencies: dependency_overrides: stream_chat: - git: - url: https://github.com/GetStream/stream-chat-flutter.git - ref: ref/segregate-api-layer - path: packages/stream_chat + path: ../../../stream-chat-flutter/packages/stream_chat stream_chat_flutter_core: - git: - url: https://github.com/GetStream/stream-chat-flutter.git - ref: ref/segregate-api-layer - path: packages/stream_chat_flutter_core + path: ../../../stream-chat-flutter/packages/stream_chat_flutter_core dev_dependencies: flutter_launcher_icons: ^0.9.0 From fa12548f0d30c08c23cb3b6a9c2ab8dead08c66c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 22 Jun 2021 14:47:54 +0200 Subject: [PATCH 38/48] restore dependencies --- packages/stream_chat_v1/pubspec.yaml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/stream_chat_v1/pubspec.yaml b/packages/stream_chat_v1/pubspec.yaml index 8c0528b..59ce306 100644 --- a/packages/stream_chat_v1/pubspec.yaml +++ b/packages/stream_chat_v1/pubspec.yaml @@ -11,9 +11,15 @@ dependencies: flutter: sdk: flutter stream_chat_flutter: - path: ../../../stream-chat-flutter/packages/stream_chat_flutter + git: + url: https://github.com/GetStream/stream-chat-flutter.git + ref: develop + path: packages/stream_chat_flutter stream_chat_persistence: - path: ../../../stream-chat-flutter/packages/stream_chat_persistence + git: + url: https://github.com/GetStream/stream-chat-flutter.git + ref: develop + path: packages/stream_chat_persistence flutter_local_notifications: ^5.0.0+4 flutter_svg: ^0.22.0 flutter_secure_storage: ^4.2.0 @@ -25,9 +31,15 @@ dependencies: dependency_overrides: stream_chat: - path: ../../../stream-chat-flutter/packages/stream_chat + git: + url: https://github.com/GetStream/stream-chat-flutter.git + ref: develop + path: packages/stream_chat stream_chat_flutter_core: - path: ../../../stream-chat-flutter/packages/stream_chat_flutter_core + git: + url: https://github.com/GetStream/stream-chat-flutter.git + ref: develop + path: packages/stream_chat_flutter_core dev_dependencies: flutter_launcher_icons: ^0.9.0 From d93d93aeedfb64086f5e6246c9bbfc8ef7ce3b2d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 23 Jun 2021 19:23:02 +0200 Subject: [PATCH 39/48] fix android build --- .../android/gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_v1/android/gradle/wrapper/gradle-wrapper.properties b/packages/stream_chat_v1/android/gradle/wrapper/gradle-wrapper.properties index 4a4c204..c0a81d1 100644 --- a/packages/stream_chat_v1/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/stream_chat_v1/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-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip From 97914bfd15f565a4b9a39adedfe98db15e5e7276 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 29 Jun 2021 13:31:31 +0200 Subject: [PATCH 40/48] fix modals using nearest navigator --- packages/stream_chat_v1/lib/group_chat_details_screen.dart | 1 + packages/stream_chat_v1/lib/group_info_screen.dart | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/stream_chat_v1/lib/group_chat_details_screen.dart b/packages/stream_chat_v1/lib/group_chat_details_screen.dart index c59f744..f4b15ef 100644 --- a/packages/stream_chat_v1/lib/group_chat_details_screen.dart +++ b/packages/stream_chat_v1/lib/group_chat_details_screen.dart @@ -266,6 +266,7 @@ class _GroupChatDetailsScreenState extends State { void _showErrorAlert() { showModalBottomSheet( + useRootNavigator: false, backgroundColor: StreamChatTheme.of(context).colorTheme.white, context: context, shape: RoundedRectangleBorder( diff --git a/packages/stream_chat_v1/lib/group_info_screen.dart b/packages/stream_chat_v1/lib/group_info_screen.dart index 1d9572e..639175e 100644 --- a/packages/stream_chat_v1/lib/group_info_screen.dart +++ b/packages/stream_chat_v1/lib/group_info_screen.dart @@ -690,6 +690,7 @@ class _GroupInfoScreenState extends State { var channel = StreamChannel.of(context).channel; showDialog( + useRootNavigator: false, context: context, barrierColor: StreamChatTheme.of(context).colorTheme.overlay, builder: (context) { @@ -851,6 +852,7 @@ class _GroupInfoScreenState extends State { final color = StreamChatTheme.of(context).colorTheme.white; showModalBottomSheet( + useRootNavigator: false, context: context, clipBehavior: Clip.antiAlias, isScrollControlled: true, From 0a5f291a59368fd95b9947328ab0c451bbe4af8e Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 29 Jun 2021 13:31:49 +0200 Subject: [PATCH 41/48] bump version --- packages/stream_chat_v1/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_v1/pubspec.yaml b/packages/stream_chat_v1/pubspec.yaml index 59ce306..6d39645 100644 --- a/packages/stream_chat_v1/pubspec.yaml +++ b/packages/stream_chat_v1/pubspec.yaml @@ -1,7 +1,7 @@ name: example description: A new Flutter project. publish_to: 'none' -version: 1.6.0 +version: 1.6.1 environment: sdk: '>=2.12.0 <3.0.0' From 9cd670b6a7c061411cda952b12e17764e6084b97 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 29 Jun 2021 14:53:17 +0200 Subject: [PATCH 42/48] fix physical button navigation on android --- packages/stream_chat_v1/lib/home_page.dart | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat_v1/lib/home_page.dart b/packages/stream_chat_v1/lib/home_page.dart index 7746729..abe14f1 100644 --- a/packages/stream_chat_v1/lib/home_page.dart +++ b/packages/stream_chat_v1/lib/home_page.dart @@ -17,14 +17,22 @@ class HomePage extends StatelessWidget { }) : super(key: key); final StreamChatClient chatClient; + final GlobalKey _navigatorKey = GlobalKey(); @override Widget build(BuildContext context) { return StreamChat( client: chatClient, - child: Navigator( - onGenerateRoute: AppRoutes.generateRoute, - initialRoute: Routes.CHANNEL_LIST_PAGE, + child: WillPopScope( + onWillPop: () async { + final canPop = await _navigatorKey.currentState?.maybePop() ?? false; + return !canPop; + }, + child: Navigator( + key: _navigatorKey, + onGenerateRoute: AppRoutes.generateRoute, + initialRoute: Routes.CHANNEL_LIST_PAGE, + ), ), ); } From 52e19e9bc1b5b8665ced83298c45aeae1bcea0ad Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 1 Jul 2021 08:55:12 +0200 Subject: [PATCH 43/48] fix homepage --- packages/stream_chat_v1/lib/home_page.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_v1/lib/home_page.dart b/packages/stream_chat_v1/lib/home_page.dart index abe14f1..828230f 100644 --- a/packages/stream_chat_v1/lib/home_page.dart +++ b/packages/stream_chat_v1/lib/home_page.dart @@ -10,19 +10,25 @@ class HomePageArgs { HomePageArgs(this.chatClient); } -class HomePage extends StatelessWidget { +class HomePage extends StatefulWidget { HomePage({ Key? key, required this.chatClient, }) : super(key: key); final StreamChatClient chatClient; + + @override + _HomePageState createState() => _HomePageState(); +} + +class _HomePageState extends State { final GlobalKey _navigatorKey = GlobalKey(); @override Widget build(BuildContext context) { return StreamChat( - client: chatClient, + client: widget.chatClient, child: WillPopScope( onWillPop: () async { final canPop = await _navigatorKey.currentState?.maybePop() ?? false; From 253e6caa1c9cfef85308510ed099ff7000cff4d3 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 1 Jul 2021 09:28:01 +0200 Subject: [PATCH 44/48] update color names with develop ones --- .../lib/advanced_options_page.dart | 66 +++-- .../lib/channel_file_display_screen.dart | 15 +- packages/stream_chat_v1/lib/channel_list.dart | 246 +++++++++--------- .../stream_chat_v1/lib/channel_list_page.dart | 23 +- .../lib/channel_media_display_screen.dart | 13 +- packages/stream_chat_v1/lib/channel_page.dart | 9 +- .../stream_chat_v1/lib/chat_info_screen.dart | 100 +++---- .../lib/chips_input_text_field.dart | 10 +- .../stream_chat_v1/lib/choose_user_page.dart | 28 +- .../lib/group_chat_details_screen.dart | 42 +-- .../stream_chat_v1/lib/group_info_screen.dart | 155 ++++++----- packages/stream_chat_v1/lib/main.dart | 6 +- .../stream_chat_v1/lib/new_chat_screen.dart | 24 +- .../lib/new_group_chat_screen.dart | 25 +- .../lib/pinned_messages_screen.dart | 19 +- .../stream_chat_v1/lib/search_text_field.dart | 9 +- .../stream_chat_v1/lib/stream_version.dart | 2 +- packages/stream_chat_v1/lib/thread_page.dart | 2 +- .../lib/user_mentions_page.dart | 10 +- 19 files changed, 430 insertions(+), 374 deletions(-) diff --git a/packages/stream_chat_v1/lib/advanced_options_page.dart b/packages/stream_chat_v1/lib/advanced_options_page.dart index 4a97c68..3fd9a95 100644 --- a/packages/stream_chat_v1/lib/advanced_options_page.dart +++ b/packages/stream_chat_v1/lib/advanced_options_page.dart @@ -33,22 +33,20 @@ class _AdvancedOptionsPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + backgroundColor: StreamChatTheme.of(context).colorTheme.appBg, appBar: AppBar( - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, 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), + style: StreamChatTheme.of(context).textTheme.headlineBold.copyWith( + color: StreamChatTheme.of(context).colorTheme.textHighEmphasis), ), leading: IconButton( icon: StreamSvgIcon.left( - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context).colorTheme.textHighEmphasis, ), onPressed: () { Navigator.pop(context); @@ -85,7 +83,9 @@ class _AdvancedOptionsPageState extends State { }, style: TextStyle( fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis, ), decoration: InputDecoration( errorStyle: TextStyle(height: 0, fontSize: 0), @@ -93,15 +93,16 @@ class _AdvancedOptionsPageState extends State { fontSize: 14, fontWeight: FontWeight.bold, color: _apiKeyError != null - ? StreamChatTheme.of(context).colorTheme.accentRed - : StreamChatTheme.of(context).colorTheme.grey, + ? StreamChatTheme.of(context).colorTheme.accentError + : StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, + fillColor: StreamChatTheme.of(context).colorTheme.inputBg, filled: true, labelText: _apiKeyError != null ? 'CHAT API KEY: $_apiKeyError' @@ -131,7 +132,9 @@ class _AdvancedOptionsPageState extends State { }, style: TextStyle( fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis, ), textInputAction: TextInputAction.next, decoration: InputDecoration( @@ -140,15 +143,16 @@ class _AdvancedOptionsPageState extends State { fontWeight: FontWeight.bold, fontSize: 14, color: _userIdError != null - ? StreamChatTheme.of(context).colorTheme.accentRed - : StreamChatTheme.of(context).colorTheme.grey, + ? StreamChatTheme.of(context).colorTheme.accentError + : StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, + fillColor: StreamChatTheme.of(context).colorTheme.inputBg, filled: true, labelText: _userIdError != null ? 'USER ID: $_userIdError' @@ -177,7 +181,9 @@ class _AdvancedOptionsPageState extends State { }, style: TextStyle( fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis, ), textInputAction: TextInputAction.next, decoration: InputDecoration( @@ -186,15 +192,16 @@ class _AdvancedOptionsPageState extends State { fontWeight: FontWeight.bold, fontSize: 14, color: _userTokenError != null - ? StreamChatTheme.of(context).colorTheme.accentRed - : StreamChatTheme.of(context).colorTheme.grey, + ? StreamChatTheme.of(context).colorTheme.accentError + : StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, + fillColor: StreamChatTheme.of(context).colorTheme.inputBg, filled: true, labelText: _userTokenError != null ? 'USER TOKEN: $_userTokenError' @@ -209,14 +216,15 @@ class _AdvancedOptionsPageState extends State { labelStyle: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, + fillColor: StreamChatTheme.of(context).colorTheme.inputBg, filled: true, labelText: 'Username (optional)', ), @@ -228,7 +236,7 @@ class _AdvancedOptionsPageState extends State { Theme.of(context).brightness == Brightness.light ? StreamChatTheme.of(context) .colorTheme - .accentBlue + .accentPrimary : Colors.white), elevation: MaterialStateProperty.all(0), padding: MaterialStateProperty.all( @@ -244,7 +252,9 @@ class _AdvancedOptionsPageState extends State { style: TextStyle( fontSize: 16, color: Theme.of(context).brightness != Brightness.light - ? StreamChatTheme.of(context).colorTheme.accentBlue + ? StreamChatTheme.of(context) + .colorTheme + .accentPrimary : Colors.white, ), ), @@ -270,7 +280,7 @@ class _AdvancedOptionsPageState extends State { borderRadius: BorderRadius.circular(16), color: StreamChatTheme.of(context) .colorTheme - .white, + .barsBg, ), height: 100, width: 100, diff --git a/packages/stream_chat_v1/lib/channel_file_display_screen.dart b/packages/stream_chat_v1/lib/channel_file_display_screen.dart index 806f184..2cffbc8 100644 --- a/packages/stream_chat_v1/lib/channel_file_display_screen.dart +++ b/packages/stream_chat_v1/lib/channel_file_display_screen.dart @@ -50,7 +50,7 @@ class _ChannelFileDisplayScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, @@ -58,7 +58,7 @@ class _ChannelFileDisplayScreenState extends State { title: Text( 'Files', style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context).colorTheme.textHighEmphasis, fontSize: 16.0), ), leading: Center( @@ -70,13 +70,13 @@ class _ChannelFileDisplayScreenState extends State { width: 24.0, height: 24.0, child: StreamSvgIcon.left( - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context).colorTheme.textHighEmphasis, size: 24.0, ), ), ), ), - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, ), body: _buildMediaGrid(), ); @@ -103,14 +103,15 @@ class _ChannelFileDisplayScreenState extends State { children: [ StreamSvgIcon.files( size: 136.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + color: StreamChatTheme.of(context).colorTheme.disabled, ), SizedBox(height: 16.0), Text( 'No Files', style: TextStyle( fontSize: 14.0, - color: StreamChatTheme.of(context).colorTheme.black, + color: + StreamChatTheme.of(context).colorTheme.textHighEmphasis, ), ), SizedBox(height: 8.0), @@ -121,7 +122,7 @@ class _ChannelFileDisplayScreenState extends State { fontSize: 14.0, color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5), ), ), diff --git a/packages/stream_chat_v1/lib/channel_list.dart b/packages/stream_chat_v1/lib/channel_list.dart index e88c9a1..c31fabb 100644 --- a/packages/stream_chat_v1/lib/channel_list.dart +++ b/packages/stream_chat_v1/lib/channel_list.dart @@ -60,137 +60,137 @@ class _ChannelList extends State { } 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( - showErrorTile: true, - messageQuery: _channelQuery, - filters: Filter.in_('members', [user!.id]), - sortOptions: [ - SortOption( - 'created_at', - direction: SortOption.ASC, - ), - ], - pullToRefresh: false, - paginationParams: PaginationParams(limit: 20), - 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, - ), + 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 + ? MessageSearchBloc( + child: MessageSearchListView( + showErrorTile: true, + messageQuery: _channelQuery, + filters: Filter.in_('members', [user!.id]), + sortOptions: [ + SortOption( + 'created_at', + direction: SortOption.ASC, + ), + ], + pullToRefresh: false, + paginationParams: PaginationParams(limit: 20), + 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 results...', - ), - ], - ), + ), + Text( + 'No results...', + ), + ], ), ), - ); - }, - ); - }, - 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( + ), + ); + }, + ); + }, + 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, + ), + ); + }, + ), + ) + : ChannelsBloc( + child: ChannelListView( + onStartChatPressed: () { + Navigator.pushNamed(context, Routes.NEW_CHAT); + }, + swipeToAction: true, + filter: Filter.in_('members', [user!.id]), + presence: true, + pagination: PaginationParams( + limit: 20, + ), + channelWidget: ChannelPage(), + onViewInfoTap: (channel) { + Navigator.pop(context); + if (channel.memberCount == 2 && channel.isDistinct) { + Navigator.push( context, - Routes.CHANNEL_PAGE, - arguments: ChannelPageArgs( - channel: channel, - initialMessage: message, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: ChatInfoScreen( + messageTheme: StreamChatTheme.of(context) + .ownMessageTheme, + user: channel.state!.members + .where((m) => + m.userId != + channel.client.state.user!.id) + .first + .user, + ), + ), ), ); - }, - ) - : ChannelListView( - onStartChatPressed: () { - Navigator.pushNamed(context, Routes.NEW_CHAT); - }, - swipeToAction: true, - filter: Filter.in_('members', [user!.id]), - presence: true, - pagination: PaginationParams( - limit: 20, - ), - channelWidget: ChannelPage(), - onViewInfoTap: (channel) { - Navigator.pop(context); - if (channel.memberCount == 2 && channel.isDistinct) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: ChatInfoScreen( - messageTheme: StreamChatTheme.of(context) - .ownMessageTheme, - user: channel.state!.members - .where((m) => - m.userId != - channel.client.state.user!.id) - .first - .user, - ), + } else { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StreamChannel( + channel: channel, + child: GroupInfoScreen( + messageTheme: StreamChatTheme.of(context) + .ownMessageTheme, ), ), - ); - } else { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => StreamChannel( - channel: channel, - child: GroupInfoScreen( - messageTheme: StreamChatTheme.of(context) - .ownMessageTheme, - ), - ), - ), - ); - } - }, - ), - ), - ), + ), + ); + } + }, + ), + ), ), ), ), diff --git a/packages/stream_chat_v1/lib/channel_list_page.dart b/packages/stream_chat_v1/lib/channel_list_page.dart index baf6eca..5379062 100644 --- a/packages/stream_chat_v1/lib/channel_list_page.dart +++ b/packages/stream_chat_v1/lib/channel_list_page.dart @@ -33,7 +33,7 @@ class _ChannelListPageState extends State { children: [ StreamSvgIcon.message( color: _isSelected(0) - ? StreamChatTheme.of(context).colorTheme.black + ? StreamChatTheme.of(context).colorTheme.textHighEmphasis : Colors.grey, ), Positioned( @@ -51,7 +51,7 @@ class _ChannelListPageState extends State { children: [ StreamSvgIcon.mentions( color: _isSelected(1) - ? StreamChatTheme.of(context).colorTheme.black + ? StreamChatTheme.of(context).colorTheme.textHighEmphasis : Colors.grey, ), ], @@ -68,7 +68,7 @@ class _ChannelListPageState extends State { return Offstage(); } return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + backgroundColor: StreamChatTheme.of(context).colorTheme.appBg, appBar: ChannelListHeader( onNewChatButtonTap: () { Navigator.pushNamed(context, Routes.NEW_CHAT); @@ -82,14 +82,15 @@ class _ChannelListPageState extends State { ), drawerEdgeDragWidth: 50, bottomNavigationBar: BottomNavigationBar( - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, 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, + selectedItemColor: + StreamChatTheme.of(context).colorTheme.textHighEmphasis, unselectedItemColor: Colors.grey, onTap: (index) { setState(() => _currentIndex = index); @@ -144,7 +145,7 @@ class LeftDrawer extends StatelessWidget { Widget build(BuildContext context) { return Drawer( child: Container( - color: StreamChatTheme.of(context).colorTheme.white, + color: StreamChatTheme.of(context).colorTheme.barsBg, child: SafeArea( child: Padding( padding: EdgeInsets.only( @@ -181,7 +182,7 @@ class LeftDrawer extends StatelessWidget { leading: StreamSvgIcon.penWrite( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(.5), ), onTap: () { @@ -201,7 +202,7 @@ class LeftDrawer extends StatelessWidget { leading: StreamSvgIcon.contacts( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(.5), ), onTap: () { @@ -244,7 +245,7 @@ class LeftDrawer extends StatelessWidget { leading: StreamSvgIcon.user( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(.5), ), title: Text( @@ -257,7 +258,9 @@ class LeftDrawer extends StatelessWidget { icon: StreamSvgIcon.iconMoon( size: 24, ), - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, onPressed: () async { final sp = await StreamingSharedPreferences.instance; sp.setInt( diff --git a/packages/stream_chat_v1/lib/channel_media_display_screen.dart b/packages/stream_chat_v1/lib/channel_media_display_screen.dart index 15f8fd6..f2ad261 100644 --- a/packages/stream_chat_v1/lib/channel_media_display_screen.dart +++ b/packages/stream_chat_v1/lib/channel_media_display_screen.dart @@ -59,7 +59,7 @@ class _ChannelMediaDisplayScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, @@ -67,12 +67,12 @@ class _ChannelMediaDisplayScreenState extends State { title: Text( 'Photos & Videos', style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context).colorTheme.textHighEmphasis, fontSize: 16.0, ), ), leading: StreamBackButton(), - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, ), body: _buildMediaGrid(), ); @@ -99,14 +99,15 @@ class _ChannelMediaDisplayScreenState extends State { children: [ StreamSvgIcon.pictures( size: 136.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + color: StreamChatTheme.of(context).colorTheme.disabled, ), SizedBox(height: 16.0), Text( 'No Media', style: TextStyle( fontSize: 14.0, - color: StreamChatTheme.of(context).colorTheme.black, + color: + StreamChatTheme.of(context).colorTheme.textHighEmphasis, ), ), SizedBox(height: 8.0), @@ -117,7 +118,7 @@ class _ChannelMediaDisplayScreenState extends State { fontSize: 14.0, color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5), ), ), diff --git a/packages/stream_chat_v1/lib/channel_page.dart b/packages/stream_chat_v1/lib/channel_page.dart index 1ff592c..0bdb6b6 100644 --- a/packages/stream_chat_v1/lib/channel_page.dart +++ b/packages/stream_chat_v1/lib/channel_page.dart @@ -59,7 +59,7 @@ class _ChannelPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + backgroundColor: StreamChatTheme.of(context).colorTheme.appBg, appBar: ChannelHeader( showTypingIndicator: false, onImageTap: () async { @@ -148,7 +148,7 @@ class _ChannelPageState extends State { alignment: Alignment.centerLeft, color: StreamChatTheme.of(context) .colorTheme - .whiteSnow + .appBg .withOpacity(.9), child: TypingIndicator( alignment: Alignment.centerLeft, @@ -160,8 +160,9 @@ class _ChannelPageState extends State { .textTheme .footnote .copyWith( - color: - StreamChatTheme.of(context).colorTheme.grey), + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis), ), ), ), diff --git a/packages/stream_chat_v1/lib/chat_info_screen.dart b/packages/stream_chat_v1/lib/chat_info_screen.dart index 6517ef3..013851b 100644 --- a/packages/stream_chat_v1/lib/chat_info_screen.dart +++ b/packages/stream_chat_v1/lib/chat_info_screen.dart @@ -40,18 +40,18 @@ class _ChatInfoScreenState extends State { Widget build(BuildContext context) { final channel = StreamChannel.of(context).channel; return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + backgroundColor: StreamChatTheme.of(context).colorTheme.appBg, body: ListView( children: [ _buildUserHeader(), Container( height: 8.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + color: StreamChatTheme.of(context).colorTheme.disabled, ), _buildOptionListTiles(), Container( height: 8.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + color: StreamChatTheme.of(context).colorTheme.disabled, ), if ([ 'admin', @@ -68,7 +68,7 @@ class _ChatInfoScreenState extends State { Widget _buildUserHeader() { return Material( - color: StreamChatTheme.of(context).colorTheme.whiteSnow, + color: StreamChatTheme.of(context).colorTheme.appBg, child: SafeArea( child: Stack( children: [ @@ -96,7 +96,7 @@ class _ChatInfoScreenState extends State { SizedBox(height: 15.0), OptionListTile( title: '@${widget.user!.id}', - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + tileColor: StreamChatTheme.of(context).colorTheme.appBg, trailing: Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text( @@ -104,7 +104,7 @@ class _ChatInfoScreenState extends State { style: TextStyle( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5), fontSize: 16.0), ), @@ -134,7 +134,7 @@ class _ChatInfoScreenState extends State { // title: 'Notifications', // leading: StreamSvgIcon.Icon_notification( // size: 24.0, - // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + // color: StreamChatTheme.of(context).colorTheme.textHighEmphasis.withOpacity(0.5), // ), // trailing: CupertinoSwitch( // value: true, @@ -148,7 +148,7 @@ class _ChatInfoScreenState extends State { mutedBool.value = snapshot.data; return OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + tileColor: StreamChatTheme.of(context).colorTheme.appBg, title: 'Mute user', titleTextStyle: StreamChatTheme.of(context).textTheme.body, leading: Padding( @@ -157,7 +157,7 @@ class _ChatInfoScreenState extends State { size: 24.0, color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5), ), ), @@ -186,7 +186,7 @@ class _ChatInfoScreenState extends State { // title: 'Block User', // leading: StreamSvgIcon.Icon_user_delete( // size: 24.0, - // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + // color: StreamChatTheme.of(context).colorTheme.textHighEmphasis.withOpacity(0.5), // ), // trailing: CupertinoSwitch( // value: widget.user.banned, @@ -202,18 +202,20 @@ class _ChatInfoScreenState extends State { // ), OptionListTile( title: 'Pinned Messages', - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + tileColor: StreamChatTheme.of(context).colorTheme.appBg, titleTextStyle: StreamChatTheme.of(context).textTheme.body, leading: Padding( padding: const EdgeInsets.symmetric(horizontal: 22.0), child: StreamSvgIcon.pin( size: 24.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis + .withOpacity(0.5), ), ), trailing: StreamSvgIcon.right( - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, ), onTap: () { final channel = StreamChannel.of(context).channel; @@ -261,18 +263,20 @@ class _ChatInfoScreenState extends State { ), OptionListTile( title: 'Photos & Videos', - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + tileColor: StreamChatTheme.of(context).colorTheme.appBg, 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), + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis + .withOpacity(0.5), ), ), trailing: StreamSvgIcon.right( - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, ), onTap: () { final channel = StreamChannel.of(context).channel; @@ -320,18 +324,20 @@ class _ChatInfoScreenState extends State { ), OptionListTile( title: 'Files', - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + tileColor: StreamChatTheme.of(context).colorTheme.appBg, 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), + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis + .withOpacity(0.5), ), ), trailing: StreamSvgIcon.right( - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, ), onTap: () { final channel = StreamChannel.of(context).channel; @@ -359,18 +365,20 @@ class _ChatInfoScreenState extends State { ), OptionListTile( title: 'Shared groups', - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + tileColor: StreamChatTheme.of(context).colorTheme.appBg, 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), + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis + .withOpacity(0.5), ), ), trailing: StreamSvgIcon.right( - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, ), onTap: () { Navigator.push( @@ -387,21 +395,21 @@ class _ChatInfoScreenState extends State { Widget _buildDeleteListTile() { return OptionListTile( title: 'Delete Conversation', - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + tileColor: StreamChatTheme.of(context).colorTheme.appBg, titleTextStyle: StreamChatTheme.of(context).textTheme.body.copyWith( - color: StreamChatTheme.of(context).colorTheme.accentRed, + color: StreamChatTheme.of(context).colorTheme.accentError, ), leading: Padding( padding: const EdgeInsets.symmetric(horizontal: 22.0), child: StreamSvgIcon.delete( - color: StreamChatTheme.of(context).colorTheme.accentRed, + color: StreamChatTheme.of(context).colorTheme.accentError, size: 24.0, ), ), onTap: () { _showDeleteDialog(); }, - titleColor: StreamChatTheme.of(context).colorTheme.accentRed, + titleColor: StreamChatTheme.of(context).colorTheme.accentError, ); } @@ -413,7 +421,7 @@ class _ChatInfoScreenState extends State { question: 'Are you sure you want to delete this conversation?', cancelText: 'CANCEL', icon: StreamSvgIcon.delete( - color: StreamChatTheme.of(context).colorTheme.accentRed, + color: StreamChatTheme.of(context).colorTheme.accentError, ), ); var channel = StreamChannel.of(context).channel; @@ -437,7 +445,7 @@ class _ChatInfoScreenState extends State { style: TextStyle( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5)), ); } else { @@ -446,7 +454,7 @@ class _ChatInfoScreenState extends State { style: TextStyle( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5)), ); } @@ -466,10 +474,10 @@ class _ChatInfoScreenState extends State { ), child: Material( shape: CircleBorder(), - color: StreamChatTheme.of(context).colorTheme.accentGreen, + color: StreamChatTheme.of(context).colorTheme.accentInfo, ), ), - color: StreamChatTheme.of(context).colorTheme.white, + color: StreamChatTheme.of(context).colorTheme.barsBg, ), alternativeWidget, if (widget.user!.online) @@ -497,7 +505,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { var chat = StreamChat.of(context); return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + backgroundColor: StreamChatTheme.of(context).colorTheme.appBg, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, @@ -505,11 +513,11 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { title: Text( 'Shared Groups', style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context).colorTheme.textHighEmphasis, fontSize: 16.0), ), leading: StreamBackButton(), - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, ), body: StreamBuilder>( stream: chat.client.queryChannels( @@ -532,14 +540,16 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { children: [ StreamSvgIcon.message( size: 136.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + color: StreamChatTheme.of(context).colorTheme.disabled, ), SizedBox(height: 16.0), Text( 'No Shared Groups', style: TextStyle( fontSize: 14.0, - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis, ), ), SizedBox(height: 8.0), @@ -550,7 +560,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { fontSize: 14.0, color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5), ), ), @@ -643,7 +653,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { style: TextStyle( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5)), ), ) @@ -652,8 +662,10 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { ), Container( height: 1.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis + .withOpacity(.08), ), ], ); diff --git a/packages/stream_chat_v1/lib/chips_input_text_field.dart b/packages/stream_chat_v1/lib/chips_input_text_field.dart index c36e4ae..a67895e 100644 --- a/packages/stream_chat_v1/lib/chips_input_text_field.dart +++ b/packages/stream_chat_v1/lib/chips_input_text_field.dart @@ -66,7 +66,7 @@ class ChipInputTextFieldState extends State> { onTap: _pauseItemAddition ? resumeItemAddition : null, child: Material( elevation: 1, - color: StreamChatTheme.of(context).colorTheme.white, + color: StreamChatTheme.of(context).colorTheme.barsBg, child: Container( child: Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 16), @@ -82,7 +82,7 @@ class ChipInputTextFieldState extends State> { .copyWith( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(.5)), ), ), @@ -119,7 +119,7 @@ class ChipInputTextFieldState extends State> { .copyWith( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(.5)), ), ), @@ -134,14 +134,14 @@ class ChipInputTextFieldState extends State> { ? StreamSvgIcon.user( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5), size: 24, ) : StreamSvgIcon.userAdd( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5), size: 24, ), diff --git a/packages/stream_chat_v1/lib/choose_user_page.dart b/packages/stream_chat_v1/lib/choose_user_page.dart index e7be235..f50ae55 100644 --- a/packages/stream_chat_v1/lib/choose_user_page.dart +++ b/packages/stream_chat_v1/lib/choose_user_page.dart @@ -20,7 +20,7 @@ class ChooseUserPage extends StatelessWidget { final users = defaultUsers; return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + backgroundColor: StreamChatTheme.of(context).colorTheme.appBg, body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -34,7 +34,7 @@ class ChooseUserPage extends StatelessWidget { child: SvgPicture.asset( 'assets/logo.svg', height: 40, - color: StreamChatTheme.of(context).colorTheme.accentBlue, + color: StreamChatTheme.of(context).colorTheme.accentPrimary, ), ), ), @@ -56,7 +56,7 @@ class ChooseUserPage extends StatelessWidget { separatorBuilder: (context, i) { return Container( height: 1, - color: StreamChatTheme.of(context).colorTheme.greyWhisper, + color: StreamChatTheme.of(context).colorTheme.borders, ); }, itemCount: users.length + 1, @@ -80,7 +80,7 @@ class ChooseUserPage extends StatelessWidget { borderRadius: BorderRadius.circular(16), color: StreamChatTheme.of(context) .colorTheme - .white, + .barsBg, ), height: 100, width: 100, @@ -94,7 +94,7 @@ class ChooseUserPage extends StatelessWidget { final client = StreamChatClient( kDefaultStreamApiKey, logLevel: Level.INFO, - )..chatPersistenceClient = chatPersistentClient; + ); await client.connectUser( user, @@ -142,13 +142,13 @@ class ChooseUserPage extends StatelessWidget { .copyWith( color: StreamChatTheme.of(context) .colorTheme - .grey, + .textLowEmphasis, ), ), trailing: StreamSvgIcon.arrowRight( color: StreamChatTheme.of(context) .colorTheme - .accentBlue, + .accentPrimary, ), ); }), @@ -158,11 +158,12 @@ class ChooseUserPage extends StatelessWidget { }, leading: CircleAvatar( child: StreamSvgIcon.settings( - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis, ), - backgroundColor: StreamChatTheme.of(context) - .colorTheme - .greyWhisper, + backgroundColor: + StreamChatTheme.of(context).colorTheme.borders, ), title: Text( 'Advanced Options', @@ -174,8 +175,9 @@ class ChooseUserPage extends StatelessWidget { .textTheme .footnote .copyWith( - color: - StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, ), ), trailing: SvgPicture.asset( diff --git a/packages/stream_chat_v1/lib/group_chat_details_screen.dart b/packages/stream_chat_v1/lib/group_chat_details_screen.dart index f4b15ef..a2f51ed 100644 --- a/packages/stream_chat_v1/lib/group_chat_details_screen.dart +++ b/packages/stream_chat_v1/lib/group_chat_details_screen.dart @@ -59,16 +59,16 @@ class _GroupChatDetailsScreenState extends State { return false; }, child: Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + backgroundColor: StreamChatTheme.of(context).colorTheme.appBg, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, leading: const StreamBackButton(), title: Text( 'Name of Group Chat', style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context).colorTheme.textHighEmphasis, fontSize: 16, ), ), @@ -83,7 +83,9 @@ class _GroupChatDetailsScreenState extends State { 'NAME', style: TextStyle( fontSize: 12, - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, ), ), SizedBox(width: 16), @@ -101,7 +103,9 @@ class _GroupChatDetailsScreenState extends State { hintText: 'Choose a group chat name', hintStyle: TextStyle( fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, ), ), ), @@ -117,8 +121,8 @@ class _GroupChatDetailsScreenState extends State { icon: StreamSvgIcon.check( size: 24, color: _isGroupNameEmpty - ? StreamChatTheme.of(context).colorTheme.grey - : StreamChatTheme.of(context).colorTheme.accentBlue, + ? StreamChatTheme.of(context).colorTheme.textLowEmphasis + : StreamChatTheme.of(context).colorTheme.accentPrimary, ), onPressed: _isGroupNameEmpty ? null @@ -188,7 +192,9 @@ class _GroupChatDetailsScreenState extends State { child: Text( '$_totalUsers ${_totalUsers > 1 ? 'Members' : 'Member'}', style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, ), ), ), @@ -201,9 +207,7 @@ class _GroupChatDetailsScreenState extends State { itemCount: _selectedUsers.length + 1, separatorBuilder: (_, __) => Container( height: 1, - color: StreamChatTheme.of(context) - .colorTheme - .greyWhisper, + color: StreamChatTheme.of(context).colorTheme.borders, ), itemBuilder: (_, index) { if (index == _selectedUsers.length) { @@ -211,7 +215,7 @@ class _GroupChatDetailsScreenState extends State { height: 1, color: StreamChatTheme.of(context) .colorTheme - .greyWhisper, + .borders, ); } final user = _selectedUsers[index]; @@ -237,7 +241,7 @@ class _GroupChatDetailsScreenState extends State { Icons.clear_rounded, color: StreamChatTheme.of(context) .colorTheme - .black, + .textHighEmphasis, ), padding: const EdgeInsets.all(0), splashRadius: 24, @@ -267,7 +271,7 @@ class _GroupChatDetailsScreenState extends State { void _showErrorAlert() { showModalBottomSheet( useRootNavigator: false, - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( @@ -282,7 +286,7 @@ class _GroupChatDetailsScreenState extends State { height: 26.0, ), StreamSvgIcon.error( - color: StreamChatTheme.of(context).colorTheme.accentRed, + color: StreamChatTheme.of(context).colorTheme.accentError, size: 24.0, ), SizedBox( @@ -300,8 +304,10 @@ class _GroupChatDetailsScreenState extends State { height: 36.0, ), Container( - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis + .withOpacity(.08), height: 1.0, ), Row( @@ -316,7 +322,7 @@ class _GroupChatDetailsScreenState extends State { .copyWith( color: StreamChatTheme.of(context) .colorTheme - .accentBlue), + .accentPrimary), ), onPressed: () { Navigator.of(context).pop(); diff --git a/packages/stream_chat_v1/lib/group_info_screen.dart b/packages/stream_chat_v1/lib/group_info_screen.dart index 639175e..4193213 100644 --- a/packages/stream_chat_v1/lib/group_info_screen.dart +++ b/packages/stream_chat_v1/lib/group_info_screen.dart @@ -81,7 +81,7 @@ class _GroupInfoScreenState extends State { builder: (context, snapshot) { if (!snapshot.hasData) { return Container( - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + color: StreamChatTheme.of(context).colorTheme.disabled, child: Center(child: CircularProgressIndicator()), ); } @@ -92,12 +92,12 @@ class _GroupInfoScreenState extends State { var isOwner = userMember?.role == 'owner'; return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + backgroundColor: StreamChatTheme.of(context).colorTheme.appBg, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1.0, toolbarHeight: 56.0, - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, leading: StreamBackButton(), title: Column( children: [ @@ -108,8 +108,9 @@ class _GroupInfoScreenState extends State { return Text( 'Loading...', style: TextStyle( - color: - StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis, fontSize: 16, ), maxLines: 1, @@ -125,7 +126,9 @@ class _GroupInfoScreenState extends State { maxFontSize: 16.0, )!, style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis, fontSize: 16, ), maxLines: 1, @@ -140,7 +143,7 @@ class _GroupInfoScreenState extends State { style: TextStyle( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5), fontSize: 12.0, ), @@ -160,7 +163,7 @@ class _GroupInfoScreenState extends State { child: StreamSvgIcon.userAdd( color: StreamChatTheme.of(context) .colorTheme - .accentBlue), + .accentPrimary), ), ), ), @@ -171,7 +174,7 @@ class _GroupInfoScreenState extends State { _buildMembers(snapshot.data!), Container( height: 8.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + color: StreamChatTheme.of(context).colorTheme.disabled, ), if (isOwner) _buildNameTile(), _buildOptionListTiles(), @@ -244,7 +247,7 @@ class _GroupInfoScreenState extends State { style: TextStyle( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5)), ), ], @@ -257,7 +260,7 @@ class _GroupInfoScreenState extends State { style: TextStyle( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5)), ), ), @@ -267,13 +270,13 @@ class _GroupInfoScreenState extends State { height: 1.0, color: StreamChatTheme.of(context) .colorTheme - .greyGainsboro, + .disabled, ), ], ), ), ), - color: StreamChatTheme.of(context).colorTheme.whiteSnow, + color: StreamChatTheme.of(context).colorTheme.appBg, ); }, ), @@ -285,7 +288,7 @@ class _GroupInfoScreenState extends State { }); }, child: Material( - color: StreamChatTheme.of(context).colorTheme.whiteSnow, + color: StreamChatTheme.of(context).colorTheme.appBg, child: Container( height: 65.0, child: Column( @@ -297,8 +300,9 @@ class _GroupInfoScreenState extends State { padding: const EdgeInsets.symmetric( horizontal: 21.0, vertical: 12.0), child: StreamSvgIcon.down( - color: - StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, ), ), Expanded( @@ -311,7 +315,7 @@ class _GroupInfoScreenState extends State { style: TextStyle( color: StreamChatTheme.of(context) .colorTheme - .grey), + .textLowEmphasis), ), ], ), @@ -321,8 +325,7 @@ class _GroupInfoScreenState extends State { ), Container( height: 1.0, - color: - StreamChatTheme.of(context).colorTheme.greyGainsboro, + color: StreamChatTheme.of(context).colorTheme.disabled, ), ], ), @@ -338,7 +341,7 @@ class _GroupInfoScreenState extends State { var channelName = (channel.extraData['name'] as String?) ?? ''; return Material( - color: StreamChatTheme.of(context).colorTheme.whiteSnow, + color: StreamChatTheme.of(context).colorTheme.appBg, child: Container( height: 56.0, alignment: Alignment.center, @@ -351,7 +354,7 @@ class _GroupInfoScreenState extends State { style: StreamChatTheme.of(context).textTheme.footnote.copyWith( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5)), ), ), @@ -362,7 +365,8 @@ class _GroupInfoScreenState extends State { child: TextField( focusNode: _focusNode, controller: _nameController, - cursorColor: StreamChatTheme.of(context).colorTheme.black, + cursorColor: + StreamChatTheme.of(context).colorTheme.textHighEmphasis, decoration: InputDecoration.collapsed( hintText: 'Add a group name', hintStyle: StreamChatTheme.of(context) @@ -371,7 +375,7 @@ class _GroupInfoScreenState extends State { .copyWith( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5))), style: TextStyle( fontWeight: FontWeight.bold, @@ -401,8 +405,9 @@ class _GroupInfoScreenState extends State { padding: const EdgeInsets.only(right: 16.0, left: 8.0), child: InkWell( child: StreamSvgIcon.check( - color: - StreamChatTheme.of(context).colorTheme.accentBlue, + color: StreamChatTheme.of(context) + .colorTheme + .accentPrimary, size: 24.0, ), onTap: () { @@ -434,7 +439,7 @@ class _GroupInfoScreenState extends State { // title: 'Notifications', // leading: StreamSvgIcon.Icon_notification( // size: 24.0, - // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + // color: StreamChatTheme.of(context).colorTheme.textHighEmphasis.withOpacity(0.5), // ), // trailing: CupertinoSwitch( // value: true, @@ -448,9 +453,8 @@ class _GroupInfoScreenState extends State { mutedBool.value = snapshot.data; return OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - separatorColor: - StreamChatTheme.of(context).colorTheme.greyGainsboro, + tileColor: StreamChatTheme.of(context).colorTheme.appBg, + separatorColor: StreamChatTheme.of(context).colorTheme.disabled, title: 'Mute group', titleTextStyle: StreamChatTheme.of(context).textTheme.body, leading: Padding( @@ -459,7 +463,7 @@ class _GroupInfoScreenState extends State { size: 24.0, color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5), ), ), @@ -486,18 +490,20 @@ class _GroupInfoScreenState extends State { }), OptionListTile( title: 'Pinned Messages', - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + tileColor: StreamChatTheme.of(context).colorTheme.appBg, titleTextStyle: StreamChatTheme.of(context).textTheme.body, leading: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: StreamSvgIcon.pin( size: 24.0, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis + .withOpacity(0.5), ), ), trailing: StreamSvgIcon.right( - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, ), onTap: () { final channel = StreamChannel.of(context).channel; @@ -544,20 +550,22 @@ class _GroupInfoScreenState extends State { }, ), OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, + tileColor: StreamChatTheme.of(context).colorTheme.appBg, + separatorColor: StreamChatTheme.of(context).colorTheme.disabled, 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), + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis + .withOpacity(0.5), ), ), trailing: StreamSvgIcon.right( - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, ), onTap: () { var channel = StreamChannel.of(context).channel; @@ -604,20 +612,22 @@ class _GroupInfoScreenState extends State { }, ), OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - separatorColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, + tileColor: StreamChatTheme.of(context).colorTheme.appBg, + separatorColor: StreamChatTheme.of(context).colorTheme.disabled, 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), + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis + .withOpacity(0.5), ), ), trailing: StreamSvgIcon.right( - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, ), onTap: () { var channel = StreamChannel.of(context).channel; @@ -645,9 +655,8 @@ class _GroupInfoScreenState extends State { ), if (!channel.channel.isDistinct) OptionListTile( - tileColor: StreamChatTheme.of(context).colorTheme.whiteSnow, - separatorColor: - StreamChatTheme.of(context).colorTheme.greyGainsboro, + tileColor: StreamChatTheme.of(context).colorTheme.appBg, + separatorColor: StreamChatTheme.of(context).colorTheme.disabled, title: 'Leave Group', titleTextStyle: StreamChatTheme.of(context).textTheme.body, leading: Padding( @@ -656,7 +665,7 @@ class _GroupInfoScreenState extends State { size: 24.0, color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5), ), ), @@ -672,7 +681,7 @@ class _GroupInfoScreenState extends State { question: 'Are you sure you want to leave this conversation?', cancelText: 'CANCEL', icon: StreamSvgIcon.userRemove( - color: StreamChatTheme.of(context).colorTheme.accentRed, + color: StreamChatTheme.of(context).colorTheme.accentError, ), ); if (res == true) { @@ -762,7 +771,7 @@ class _GroupInfoScreenState extends State { size: 96, color: StreamChatTheme.of(context) .colorTheme - .grey, + .textLowEmphasis, ), ), Text( @@ -800,28 +809,28 @@ class _GroupInfoScreenState extends State { height: 36, child: TextField( controller: _searchController, - cursorColor: theme.colorTheme.black, + cursorColor: theme.colorTheme.textHighEmphasis, autofocus: true, decoration: InputDecoration( hintText: 'Search', hintStyle: theme.textTheme.body.copyWith( - color: theme.colorTheme.grey, + color: theme.colorTheme.textLowEmphasis, ), prefixIconConstraints: BoxConstraints.tight(Size(40, 24)), prefixIcon: StreamSvgIcon.search( - color: theme.colorTheme.black, + color: theme.colorTheme.textHighEmphasis, size: 24, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(24.0), borderSide: BorderSide( - color: theme.colorTheme.greyWhisper, + color: theme.colorTheme.borders, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(24.0), borderSide: BorderSide( - color: theme.colorTheme.greyWhisper, + color: theme.colorTheme.borders, )), contentPadding: const EdgeInsets.all(0), ), @@ -831,7 +840,7 @@ class _GroupInfoScreenState extends State { SizedBox(width: 16.0), IconButton( icon: StreamSvgIcon.closeSmall( - color: theme.colorTheme.grey, + color: theme.colorTheme.textLowEmphasis, ), constraints: BoxConstraints.tightFor( height: 24, @@ -849,7 +858,7 @@ class _GroupInfoScreenState extends State { void _showUserInfoModal(User? user, bool isUserAdmin) { var channel = StreamChannel.of(context).channel; - final color = StreamChatTheme.of(context).colorTheme.white; + final color = StreamChatTheme.of(context).colorTheme.barsBg; showModalBottomSheet( useRootNavigator: false, @@ -899,7 +908,9 @@ class _GroupInfoScreenState extends State { _buildModalListTile( context, StreamSvgIcon.user( - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, size: 24.0, ), 'View info', @@ -933,7 +944,9 @@ class _GroupInfoScreenState extends State { _buildModalListTile( context, StreamSvgIcon.message( - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, size: 24.0, ), 'Message', @@ -966,7 +979,7 @@ class _GroupInfoScreenState extends State { // _buildModalListTile( // context, // StreamSvgIcon.iconUserSettings( - // color: StreamChatTheme.of(context).colorTheme.grey, + // color: StreamChatTheme.of(context).colorTheme.textLowEmphasis, // size: 24.0, // ), // 'Make Owner', () { @@ -978,8 +991,8 @@ class _GroupInfoScreenState extends State { _buildModalListTile( context, StreamSvgIcon.userRemove( - color: - StreamChatTheme.of(context).colorTheme.accentRed, + color: StreamChatTheme.of(context) + .colorTheme.accentError, size: 24.0, ), 'Remove From Group', () async { @@ -996,11 +1009,15 @@ class _GroupInfoScreenState extends State { await channel.removeMembers([user.id]); } Navigator.pop(context); - }, color: StreamChatTheme.of(context).colorTheme.accentRed), + }, + color: StreamChatTheme.of(context) + .colorTheme.accentError), _buildModalListTile( context, StreamSvgIcon.closeSmall( - color: StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, size: 24.0, ), 'Cancel', () { @@ -1033,7 +1050,7 @@ class _GroupInfoScreenState extends State { style: TextStyle( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5)), ); } else { @@ -1042,7 +1059,7 @@ class _GroupInfoScreenState extends State { style: TextStyle( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5)), ); } @@ -1054,17 +1071,17 @@ class _GroupInfoScreenState extends State { Widget _buildModalListTile( BuildContext context, Widget leading, String title, VoidCallback onTap, {Color? color}) { - color ??= StreamChatTheme.of(context).colorTheme.black; + color ??= StreamChatTheme.of(context).colorTheme.textHighEmphasis; return Material( - color: StreamChatTheme.of(context).colorTheme.white, + color: StreamChatTheme.of(context).colorTheme.barsBg, child: InkWell( onTap: onTap, child: Column( children: [ Container( height: 1.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + color: StreamChatTheme.of(context).colorTheme.disabled, ), Container( height: 64.0, diff --git a/packages/stream_chat_v1/lib/main.dart b/packages/stream_chat_v1/lib/main.dart index e53e8c0..e17ef4a 100644 --- a/packages/stream_chat_v1/lib/main.dart +++ b/packages/stream_chat_v1/lib/main.dart @@ -18,7 +18,7 @@ import 'routes/routes.dart'; final chatPersistentClient = StreamChatPersistenceClient( logLevel: Level.SEVERE, - connectionMode: ConnectionMode.background, + connectionMode: ConnectionMode.regular, ); void main() async { @@ -46,8 +46,8 @@ class _MyAppState extends State final client = StreamChatClient( apiKey ?? kDefaultStreamApiKey, - logLevel: Level.INFO, - )..chatPersistenceClient = chatPersistentClient; + logLevel: Level.SEVERE, + ); if (userId != null && token != null) { await client.connectUser( diff --git a/packages/stream_chat_v1/lib/new_chat_screen.dart b/packages/stream_chat_v1/lib/new_chat_screen.dart index 1d7f024..41a1ded 100644 --- a/packages/stream_chat_v1/lib/new_chat_screen.dart +++ b/packages/stream_chat_v1/lib/new_chat_screen.dart @@ -117,18 +117,16 @@ class _NewChatScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + backgroundColor: StreamChatTheme.of(context).colorTheme.appBg, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 0, - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, leading: const StreamBackButton(), title: Text( 'New Chat', - style: StreamChatTheme.of(context) - .textTheme - .headlineBold - .copyWith(color: StreamChatTheme.of(context).colorTheme.black), + style: StreamChatTheme.of(context).textTheme.headlineBold.copyWith( + color: StreamChatTheme.of(context).colorTheme.textHighEmphasis), ), centerTitle: true, ), @@ -177,7 +175,7 @@ class _NewChatScreenState extends State { decoration: BoxDecoration( color: StreamChatTheme.of(context) .colorTheme - .greyGainsboro, + .disabled, borderRadius: BorderRadius.circular(12), ), padding: const EdgeInsets.only(left: 24), @@ -189,7 +187,7 @@ class _NewChatScreenState extends State { style: TextStyle( color: StreamChatTheme.of(context) .colorTheme - .black, + .textHighEmphasis, ), ), ), @@ -240,7 +238,7 @@ class _NewChatScreenState extends State { child: StreamSvgIcon.contacts( color: StreamChatTheme.of(context) .colorTheme - .accentBlue, + .accentPrimary, size: 24, ), ), @@ -279,7 +277,7 @@ class _NewChatScreenState extends State { .copyWith( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(.5))), ), ), @@ -350,7 +348,7 @@ class _NewChatScreenState extends State { color: StreamChatTheme .of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(.5)), ), ], @@ -378,7 +376,7 @@ class _NewChatScreenState extends State { fontSize: 12, color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(.5), ), ), @@ -396,7 +394,7 @@ class _NewChatScreenState extends State { Navigator.pushNamedAndRemoveUntil( context, Routes.CHANNEL_PAGE, - ModalRoute.withName(Routes.HOME), + ModalRoute.withName(Routes.CHANNEL_LIST_PAGE), arguments: ChannelPageArgs(channel: channel), ); }, diff --git a/packages/stream_chat_v1/lib/new_group_chat_screen.dart b/packages/stream_chat_v1/lib/new_group_chat_screen.dart index 0db780e..414606f 100644 --- a/packages/stream_chat_v1/lib/new_group_chat_screen.dart +++ b/packages/stream_chat_v1/lib/new_group_chat_screen.dart @@ -51,15 +51,15 @@ class _NewGroupChatScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + backgroundColor: StreamChatTheme.of(context).colorTheme.appBg, appBar: AppBar( elevation: 1, - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, leading: const StreamBackButton(), title: Text( 'Add Group Members', style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context).colorTheme.textHighEmphasis, fontSize: 16, ), ), @@ -68,7 +68,7 @@ class _NewGroupChatScreenState extends State { if (_selectedUsers.isNotEmpty) IconButton( icon: StreamSvgIcon.arrowRight( - color: StreamChatTheme.of(context).colorTheme.accentBlue, + color: StreamChatTheme.of(context).colorTheme.accentPrimary, ), onPressed: () async { final updatedList = await Navigator.pushNamed( @@ -159,18 +159,18 @@ class _NewGroupChatScreenState extends State { decoration: BoxDecoration( color: StreamChatTheme.of(context) .colorTheme - .white, + .appBg, shape: BoxShape.circle, border: Border.all( color: StreamChatTheme.of(context) .colorTheme - .whiteSnow, + .appBg, ), ), child: StreamSvgIcon.close( color: StreamChatTheme.of(context) .colorTheme - .black, + .textHighEmphasis, size: 24, ), ), @@ -212,8 +212,9 @@ class _NewGroupChatScreenState extends State { ? 'Matches for \"$_userNameQuery\"' : 'On the platform', style: TextStyle( - color: - StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, ), ), ), @@ -273,7 +274,7 @@ class _NewGroupChatScreenState extends State { size: 96, color: StreamChatTheme.of(context) .colorTheme - .grey, + .textLowEmphasis, ), ), Text( @@ -284,7 +285,7 @@ class _NewGroupChatScreenState extends State { .copyWith( color: StreamChatTheme.of(context) .colorTheme - .grey, + .textLowEmphasis, ), ), ], @@ -319,7 +320,7 @@ class _HeaderDelegate extends SliverPersistentHeaderDelegate { Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return Container( - color: StreamChatTheme.of(context).colorTheme.white, + color: StreamChatTheme.of(context).colorTheme.barsBg, child: child, ); } diff --git a/packages/stream_chat_v1/lib/pinned_messages_screen.dart b/packages/stream_chat_v1/lib/pinned_messages_screen.dart index d8f756b..11287bb 100644 --- a/packages/stream_chat_v1/lib/pinned_messages_screen.dart +++ b/packages/stream_chat_v1/lib/pinned_messages_screen.dart @@ -58,7 +58,7 @@ class _PinnedMessagesScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, @@ -66,12 +66,12 @@ class _PinnedMessagesScreenState extends State { title: Text( 'Pinned Messages', style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context).colorTheme.textHighEmphasis, fontSize: 16.0, ), ), leading: StreamBackButton(), - backgroundColor: StreamChatTheme.of(context).colorTheme.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg, ), body: _buildMediaGrid(), ); @@ -98,14 +98,15 @@ class _PinnedMessagesScreenState extends State { children: [ StreamSvgIcon.pin( size: 136.0, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + color: StreamChatTheme.of(context).colorTheme.disabled, ), SizedBox(height: 16.0), Text( 'No pinned items', style: TextStyle( fontSize: 17.0, - color: StreamChatTheme.of(context).colorTheme.black, + color: + StreamChatTheme.of(context).colorTheme.textHighEmphasis, fontWeight: FontWeight.bold, ), ), @@ -119,7 +120,7 @@ class _PinnedMessagesScreenState extends State { fontSize: 14.0, color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5), ), ), @@ -130,7 +131,7 @@ class _PinnedMessagesScreenState extends State { fontWeight: FontWeight.bold, color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(0.5), ), ), @@ -176,7 +177,9 @@ class _PinnedMessagesScreenState extends State { title: Text( user.name, style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.black, + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis, fontWeight: FontWeight.bold), ), subtitle: Text( diff --git a/packages/stream_chat_v1/lib/search_text_field.dart b/packages/stream_chat_v1/lib/search_text_field.dart index c3850c2..7641a7b 100644 --- a/packages/stream_chat_v1/lib/search_text_field.dart +++ b/packages/stream_chat_v1/lib/search_text_field.dart @@ -22,9 +22,9 @@ class SearchTextField extends StatelessWidget { return Container( height: 36, decoration: BoxDecoration( - color: StreamChatTheme.of(context).colorTheme.white, + color: StreamChatTheme.of(context).colorTheme.barsBg, border: Border.all( - color: StreamChatTheme.of(context).colorTheme.greyWhisper, + color: StreamChatTheme.of(context).colorTheme.borders, ), borderRadius: BorderRadius.circular(24), ), @@ -48,7 +48,8 @@ class SearchTextField extends StatelessWidget { right: 8, ), child: StreamSvgIcon.search( - color: StreamChatTheme.of(context).colorTheme.black, + color: + StreamChatTheme.of(context).colorTheme.textHighEmphasis, size: 24, ), ), @@ -56,7 +57,7 @@ class SearchTextField extends StatelessWidget { hintStyle: StreamChatTheme.of(context).textTheme.body.copyWith( color: StreamChatTheme.of(context) .colorTheme - .black + .textHighEmphasis .withOpacity(.5)), contentPadding: const EdgeInsets.all(0), border: OutlineInputBorder( diff --git a/packages/stream_chat_v1/lib/stream_version.dart b/packages/stream_chat_v1/lib/stream_version.dart index 7401813..89004f7 100644 --- a/packages/stream_chat_v1/lib/stream_version.dart +++ b/packages/stream_chat_v1/lib/stream_version.dart @@ -29,7 +29,7 @@ class StreamVersion extends StatelessWidget { 'Stream SDK v $streamChatDep', style: TextStyle( fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.greyGainsboro, + color: StreamChatTheme.of(context).colorTheme.disabled, ), ); }, diff --git a/packages/stream_chat_v1/lib/thread_page.dart b/packages/stream_chat_v1/lib/thread_page.dart index b9799c7..d1fbd3c 100644 --- a/packages/stream_chat_v1/lib/thread_page.dart +++ b/packages/stream_chat_v1/lib/thread_page.dart @@ -37,7 +37,7 @@ class _ThreadPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + backgroundColor: StreamChatTheme.of(context).colorTheme.appBg, appBar: ThreadHeader( parent: widget.parent!, ), diff --git a/packages/stream_chat_v1/lib/user_mentions_page.dart b/packages/stream_chat_v1/lib/user_mentions_page.dart index 837aa19..d02bd1c 100644 --- a/packages/stream_chat_v1/lib/user_mentions_page.dart +++ b/packages/stream_chat_v1/lib/user_mentions_page.dart @@ -40,9 +40,8 @@ class UserMentionsPage extends StatelessWidget { padding: const EdgeInsets.all(24), child: StreamSvgIcon.mentions( size: 96, - color: StreamChatTheme.of(context) - .colorTheme - .greyGainsboro, + color: + StreamChatTheme.of(context).colorTheme.disabled, ), ), Text( @@ -51,8 +50,9 @@ class UserMentionsPage extends StatelessWidget { .textTheme .body .copyWith( - color: - StreamChatTheme.of(context).colorTheme.grey, + color: StreamChatTheme.of(context) + .colorTheme + .textLowEmphasis, ), ), ], From be0ddfb1c2c68df3771e3a55a606e52e63e23cb3 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 6 Jul 2021 17:12:35 +0200 Subject: [PATCH 45/48] update fastlane --- packages/stream_chat_v1/ios/fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_v1/ios/fastlane/Fastfile b/packages/stream_chat_v1/ios/fastlane/Fastfile index 98d4536..2d46198 100644 --- a/packages/stream_chat_v1/ios/fastlane/Fastfile +++ b/packages/stream_chat_v1/ios/fastlane/Fastfile @@ -1,4 +1,4 @@ -fastlane_version "2.162.0" +fastlane_version "2.187.0" default_platform :ios before_all do From fe9666568c63e1212d732ab2d7d8cb259cbece4c Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 6 Jul 2021 18:04:39 +0200 Subject: [PATCH 46/48] update fastlane --- packages/stream_chat_v1/ios/Gemfile.lock | 141 ++++++++++++++--------- 1 file changed, 86 insertions(+), 55 deletions(-) diff --git a/packages/stream_chat_v1/ios/Gemfile.lock b/packages/stream_chat_v1/ios/Gemfile.lock index 2fb0757..477eef6 100644 --- a/packages/stream_chat_v1/ios/Gemfile.lock +++ b/packages/stream_chat_v1/ios/Gemfile.lock @@ -1,57 +1,73 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.2) - addressable (2.7.0) + CFPropertyList (3.0.3) + addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) + artifactory (3.0.15) atomos (0.1.3) - aws-eventstream (1.1.0) - aws-partitions (1.380.0) - aws-sdk-core (3.109.1) + aws-eventstream (1.1.1) + aws-partitions (1.473.0) + aws-sdk-core (3.115.0) 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-sdk-kms (1.44.0) + aws-sdk-core (~> 3, >= 3.112.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.83.0) - aws-sdk-core (~> 3, >= 3.109.0) + aws-sdk-s3 (1.96.1) + aws-sdk-core (~> 3, >= 3.112.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.1) - aws-sigv4 (1.2.2) + aws-sigv4 (1.2.3) aws-eventstream (~> 1, >= 1.0.2) - babosa (1.0.3) + babosa (1.0.4) claide (1.0.3) colored (1.2) colored2 (3.1.2) - commander-fastlane (4.4.6) - highline (~> 1.7.2) + commander (4.6.0) + highline (~> 2.0.0) declarative (0.0.20) - declarative-option (0.1.0) - digest-crc (0.6.1) - rake (~> 13.0) + digest-crc (0.6.3) + rake (>= 12.0.0, < 14.0.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) + emoji_regex (3.2.2) + excon (0.83.0) + faraday (1.5.0) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0.1) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.1) + faraday-patron (~> 1.0) multipart-post (>= 1.2, < 3) + ruby2_keywords (>= 0.0.4) faraday-cookie_jar (0.0.7) faraday (>= 0.8.0) http-cookie (~> 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.1.0) + faraday-patron (1.0.0) faraday_middleware (1.0.0) faraday (~> 1.0) - fastimage (2.2.0) - fastlane (2.162.0) + fastimage (2.2.4) + fastlane (2.187.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.3, < 3.0.0) + artifactory (~> 3.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) + commander (~> 4.6) dotenv (>= 2.1.1, < 3.0.0) emoji_regex (>= 0.1, < 4.0) excon (>= 0.71.0, < 1.0.0) @@ -60,18 +76,19 @@ GEM 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) + google-apis-androidpublisher_v3 (~> 0.1) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-storage (~> 1.31) + highline (~> 2.0) json (< 3.0.0) jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) multipart-post (~> 2.0.0) + naturally (~> 2.2) 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) @@ -82,61 +99,73 @@ GEM xcpretty-travis-formatter (>= 0.0.3) fastlane-plugin-firebase_app_distribution (0.2.7) gh_inspector (1.1.3) - google-api-client (0.38.0) + google-apis-androidpublisher_v3 (0.8.0) + google-apis-core (>= 0.4, < 2.a) + google-apis-core (0.4.0) addressable (~> 2.5, >= 2.5.1) - googleauth (~> 0.9) - httpclient (>= 2.8.1, < 3.0) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) mini_mime (~> 1.0) representable (~> 3.0) - retriable (>= 2.0, < 4.0) - signet (~> 0.12) - google-cloud-core (1.5.0) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.6.0) + google-apis-core (>= 0.4, < 2.a) + google-apis-playcustomapp_v1 (0.5.0) + google-apis-core (>= 0.4, < 2.a) + google-apis-storage_v1 (0.6.0) + google-apis-core (>= 0.4, < 2.a) + google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) - google-cloud-env (1.3.3) + google-cloud-env (1.5.0) faraday (>= 0.17.3, < 2.0) - google-cloud-errors (1.0.1) - google-cloud-storage (1.29.1) + google-cloud-errors (1.1.0) + google-cloud-storage (1.34.0) addressable (~> 2.5) digest-crc (~> 0.4) - google-api-client (~> 0.33) - google-cloud-core (~> 1.2) - googleauth (~> 0.9) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.1) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (0.13.1) + googleauth (0.16.2) 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) + highline (2.0.3) + http-cookie (1.0.4) domain_name (~> 0.5) httpclient (2.8.3) jmespath (1.4.0) - json (2.3.1) - jwt (2.2.2) + json (2.5.1) + jwt (2.2.3) memoist (0.16.2) - mini_magick (4.10.1) - mini_mime (1.0.2) + mini_magick (4.11.0) + mini_mime (1.1.0) multi_json (1.15.0) multipart-post (2.0.0) nanaimo (0.3.0) - naturally (2.2.0) + naturally (2.2.1) os (1.1.1) - plist (3.5.0) + plist (3.6.0) public_suffix (4.0.6) - rake (13.0.1) - representable (3.0.4) + rake (13.0.4) + representable (3.1.1) declarative (< 0.1.0) - declarative-option (< 0.2.0) + trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) + rexml (3.2.5) rouge (2.0.7) - rubyzip (2.3.0) + ruby2_keywords (0.0.4) + rubyzip (2.3.2) security (0.1.3) - signet (0.14.0) + signet (0.15.0) addressable (~> 2.3) faraday (>= 0.17.3, < 2.0) jwt (>= 1.5, < 3.0) @@ -144,10 +173,10 @@ GEM 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) + trailblazer-option (0.1.1) tty-cursor (0.7.1) tty-screen (0.8.1) tty-spinner (0.9.3) @@ -157,16 +186,18 @@ GEM unf_ext unf_ext (0.0.7.7) unicode-display_width (1.7.0) + webrick (1.7.0) word_wrap (1.0.0) - xcodeproj (1.18.0) + xcodeproj (1.20.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) + rexml (~> 3.2.4) xcpretty (0.3.0) rouge (~> 2.0.7) - xcpretty-travis-formatter (1.0.0) + xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) PLATFORMS From d855efcbb3a7b5e66d587e67bd7070a68c84c1c8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 6 Jul 2021 18:34:25 +0200 Subject: [PATCH 47/48] update fastlane --- packages/stream_chat_v1/ios/Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_v1/ios/Gemfile.lock b/packages/stream_chat_v1/ios/Gemfile.lock index 477eef6..06d690f 100644 --- a/packages/stream_chat_v1/ios/Gemfile.lock +++ b/packages/stream_chat_v1/ios/Gemfile.lock @@ -97,7 +97,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.2.7) + fastlane-plugin-firebase_app_distribution (0.2.9) gh_inspector (1.1.3) google-apis-androidpublisher_v3 (0.8.0) google-apis-core (>= 0.4, < 2.a) From df155c5415dd5645fd526eeca998423019d92922 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 19 Jul 2021 16:32:50 +0200 Subject: [PATCH 48/48] align with latest stable --- packages/stream_chat_v1/lib/channel_page.dart | 44 ++++++++++--------- .../stream_chat_v1/lib/chat_info_screen.dart | 2 +- .../stream_chat_v1/lib/choose_user_page.dart | 1 - packages/stream_chat_v1/lib/thread_page.dart | 6 ++- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/packages/stream_chat_v1/lib/channel_page.dart b/packages/stream_chat_v1/lib/channel_page.dart index 0bdb6b6..571a54d 100644 --- a/packages/stream_chat_v1/lib/channel_page.dart +++ b/packages/stream_chat_v1/lib/channel_page.dart @@ -113,31 +113,35 @@ class _ChannelPageState extends State { initialAlignment: widget.initialAlignment, highlightInitialMessage: widget.highlightInitialMessage, onMessageSwiped: _reply, - onReplyTap: _reply, + messageBuilder: (context, details, messages, defaultMessage) { + return defaultMessage.copyWith( + onReplyTap: _reply, + 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, + ), + ); + }, + ); + }, 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, - ), - ); - }, pinPermissions: ['owner', 'admin', 'member'], ), Positioned( diff --git a/packages/stream_chat_v1/lib/chat_info_screen.dart b/packages/stream_chat_v1/lib/chat_info_screen.dart index 013851b..6c6bb1e 100644 --- a/packages/stream_chat_v1/lib/chat_info_screen.dart +++ b/packages/stream_chat_v1/lib/chat_info_screen.dart @@ -635,7 +635,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { children: [ Padding( padding: const EdgeInsets.all(8.0), - child: ChannelImage( + child: ChannelAvatar( channel: channel, constraints: BoxConstraints(maxWidth: 40.0, maxHeight: 40.0), diff --git a/packages/stream_chat_v1/lib/choose_user_page.dart b/packages/stream_chat_v1/lib/choose_user_page.dart index f50ae55..e487acd 100644 --- a/packages/stream_chat_v1/lib/choose_user_page.dart +++ b/packages/stream_chat_v1/lib/choose_user_page.dart @@ -7,7 +7,6 @@ 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 'main.dart'; import 'routes/routes.dart'; const kStreamApiKey = 'STREAM_API_KEY'; diff --git a/packages/stream_chat_v1/lib/thread_page.dart b/packages/stream_chat_v1/lib/thread_page.dart index d1fbd3c..5d032f8 100644 --- a/packages/stream_chat_v1/lib/thread_page.dart +++ b/packages/stream_chat_v1/lib/thread_page.dart @@ -49,7 +49,11 @@ class _ThreadPageState extends State { initialScrollIndex: widget.initialScrollIndex, initialAlignment: widget.initialAlignment, onMessageSwiped: _reply, - onReplyTap: _reply, + messageBuilder: (context, details, messages, defaultMessage) { + return defaultMessage.copyWith( + onReplyTap: _reply, + ); + }, pinPermissions: ['owner', 'admin', 'member'], ), ),