From 525991f24b64448094e236c32a60321d8b67a6db Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 16:36:50 +0530 Subject: [PATCH 1/8] feat : ChannelListHeader --- example/lib/group_chat_details_screen.dart | 3 +- example/lib/main.dart | 8 +- example/lib/new_chat_screen.dart | 3 +- lib/src/channel_list_header.dart | 158 ++++++++++++++++++ .../src/stream_neumorphic_button.dart | 4 +- lib/stream_chat_flutter.dart | 2 + 6 files changed, 165 insertions(+), 13 deletions(-) create mode 100644 lib/src/channel_list_header.dart rename example/lib/neumorphic_button.dart => lib/src/stream_neumorphic_button.dart (90%) diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index 6aff5711..5fca35b4 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -3,7 +3,6 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:uuid/uuid.dart'; import 'main.dart'; -import 'neumorphic_button.dart'; class GroupChatDetailsScreen extends StatefulWidget { final List selectedUsers; @@ -103,7 +102,7 @@ class _GroupChatDetailsScreenState extends State { ), ), actions: [ - NeumorphicButton( + StreamNeumorphicButton( child: IconButton( padding: const EdgeInsets.all(0), icon: Icon(StreamIcons.check), diff --git a/example/lib/main.dart b/example/lib/main.dart index a7d5e473..7592cfab 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -69,13 +69,7 @@ class ChannelListPage extends StatelessWidget { Widget build(BuildContext context) { final user = StreamChat.of(context).user; return Scaffold( - appBar: AppBar( - backgroundColor: Colors.white, - title: Text( - 'Stream Chat', - style: TextStyle(color: Colors.black), - ), - ), + appBar: ChannelListHeader(), drawer: _buildDrawer(context, user), drawerEdgeDragWidth: 50, body: ChannelsBloc( diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index 9ec2ca7e..deff2a3c 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -5,7 +5,6 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'chips_input_text_field.dart'; import 'main.dart'; -import 'neumorphic_button.dart'; import 'new_group_chat_screen.dart'; class NewChatScreen extends StatefulWidget { @@ -193,7 +192,7 @@ class _NewChatScreenState extends State { padding: const EdgeInsets.symmetric(vertical: 8), child: Row( children: [ - NeumorphicButton( + StreamNeumorphicButton( child: Icon( StreamIcons.group, color: Color(0xFF006CFF), diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart new file mode 100644 index 00000000..94266045 --- /dev/null +++ b/lib/src/channel_list_header.dart @@ -0,0 +1,158 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/stream_neumorphic_button.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'stream_chat.dart'; + +typedef TitleBuilder = Widget Function( + BuildContext context, + ConnectionStatus status, + Client client, +); + +class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { + const ChannelListHeader({ + Key key, + this.client, + this.titleBuilder, + }) : super(key: key); + + final Client client; + + final TitleBuilder titleBuilder; + + @override + Widget build(BuildContext context) { + final _client = client ?? StreamChat.of(context).client; + final user = _client.state.user; + return AppBar( + brightness: Theme.of(context).brightness, + elevation: 1, + backgroundColor: + StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color, + centerTitle: true, + leading: Center( + child: UserAvatar( + user: user, + onTap: (_) => Scaffold.of(context).openDrawer(), + constraints: BoxConstraints.tightFor( + height: 40, + width: 40, + ), + ), + ), + actions: [ + StreamNeumorphicButton( + child: IconButton( + icon: ValueListenableBuilder( + valueListenable: _client.wsConnectionStatus, + builder: (context, status, child) { + var color; + switch (status) { + case ConnectionStatus.connected: + color = Color(0xFF006CFF); + break; + case ConnectionStatus.connecting: + color = Colors.grey; + break; + case ConnectionStatus.disconnected: + color = Colors.grey; + break; + } + return Icon( + StreamIcons.pen_write, + color: color, + ); + }, + ), + onPressed: () {}, + ), + ) + ], + title: ValueListenableBuilder( + valueListenable: _client.wsConnectionStatus, + builder: (context, status, child) { + if (titleBuilder != null) { + return titleBuilder(context, status, _client); + } + switch (status) { + case ConnectionStatus.connected: + return _buildConnectedTitleState(); + case ConnectionStatus.connecting: + return _buildConnectingTitleState(); + case ConnectionStatus.disconnected: + return _buildDisconnectedTitleState(_client); + default: + return Offstage(); + } + }, + ), + ); + } + + Widget _buildConnectedTitleState() => Text( + 'Stream Chat', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ); + + Widget _buildConnectingTitleState() { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + height: 16, + width: 16, + child: Center( + child: CircularProgressIndicator(), + ), + ), + SizedBox(width: 10), + Text( + 'Searching for Network', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ) + ], + ); + } + + Widget _buildDisconnectedTitleState(Client client) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Offline...', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + TextButton( + onPressed: () => client.connect(), + child: Text( + 'Try Again', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF006CFF), + ), + ), + ), + ], + ); + } + + @override + Size get preferredSize => Size.fromHeight(kToolbarHeight); +} diff --git a/example/lib/neumorphic_button.dart b/lib/src/stream_neumorphic_button.dart similarity index 90% rename from example/lib/neumorphic_button.dart rename to lib/src/stream_neumorphic_button.dart index 69454fb2..bf3e8e97 100644 --- a/example/lib/neumorphic_button.dart +++ b/lib/src/stream_neumorphic_button.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -class NeumorphicButton extends StatelessWidget { +class StreamNeumorphicButton extends StatelessWidget { final Widget child; final Color backgroundColor; - const NeumorphicButton({ + const StreamNeumorphicButton({ Key key, @required this.child, this.backgroundColor = Colors.white, diff --git a/lib/stream_chat_flutter.dart b/lib/stream_chat_flutter.dart index 91ac68c8..1399bf08 100644 --- a/lib/stream_chat_flutter.dart +++ b/lib/stream_chat_flutter.dart @@ -33,3 +33,5 @@ export 'src/video_attachment.dart'; export 'src/users_bloc.dart'; export 'src/user_list_view.dart'; export 'src/user_item.dart'; +export 'src/stream_neumorphic_button.dart'; +export 'src/channel_list_header.dart'; From a30565e0e1784d031efc82ceda1c5242dacc6585 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 17:40:41 +0530 Subject: [PATCH 2/8] [ChannelListHeader] Refactor, Add support for trailing, leading widget taps. --- lib/src/channel_list_header.dart | 111 ++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 31 deletions(-) diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 94266045..147f9340 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -7,22 +7,57 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'stream_chat.dart'; -typedef TitleBuilder = Widget Function( +typedef _TitleBuilder = Widget Function( BuildContext context, ConnectionStatus status, Client client, ); +/// +/// It shows the current [Client] status. +/// +/// ```dart +/// class MyApp extends StatelessWidget { +/// final Client client; +/// +/// MyApp(this.client); +/// +/// @override +/// Widget build(BuildContext context) { +/// return MaterialApp( +/// home: StreamChat( +/// client: client, +/// child: Scaffold( +/// appBar: ChannelListHeader(), +/// ), +/// ), +/// ); +/// } +/// } +/// ``` +/// +/// Usually you would use this widget as an [AppBar] inside a [Scaffold]. +/// However you can also use it as a normal widget. +/// +/// The widget components render the ui based on the first ancestor of type [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property. +/// Modify it to change the widget appearance. class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { + /// Instantiates a ChannelListHeader const ChannelListHeader({ Key key, this.client, this.titleBuilder, + this.onUserAvatarTap, + this.onNewChatButtonTap, }) : super(key: key); final Client client; - final TitleBuilder titleBuilder; + final _TitleBuilder titleBuilder; + + final Function(User) onUserAvatarTap; + + final VoidCallback onNewChatButtonTap; @override Widget build(BuildContext context) { @@ -37,7 +72,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { leading: Center( child: UserAvatar( user: user, - onTap: (_) => Scaffold.of(context).openDrawer(), + onTap: onUserAvatarTap ?? (_) => Scaffold.of(context).openDrawer(), + borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( height: 40, width: 40, @@ -68,7 +104,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ); }, ), - onPressed: () {}, + onPressed: onNewChatButtonTap, ), ) ], @@ -80,11 +116,11 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { } switch (status) { case ConnectionStatus.connected: - return _buildConnectedTitleState(); + return _buildConnectedTitleState(context); case ConnectionStatus.connecting: - return _buildConnectingTitleState(); + return _buildConnectingTitleState(context); case ConnectionStatus.disconnected: - return _buildDisconnectedTitleState(_client); + return _buildDisconnectedTitleState(context, _client); default: return Offstage(); } @@ -93,16 +129,19 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ); } - Widget _buildConnectedTitleState() => Text( + Widget _buildConnectedTitleState(BuildContext context) => Text( 'Stream Chat', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black, - ), + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .title + .copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + ), ); - Widget _buildConnectingTitleState() { + Widget _buildConnectingTitleState(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -116,37 +155,47 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { SizedBox(width: 10), Text( 'Searching for Network', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - ) + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .title + .copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), ], ); } - Widget _buildDisconnectedTitleState(Client client) { + Widget _buildDisconnectedTitleState(BuildContext context, Client client) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Offline...', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black, - ), + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .title + .copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + ), ), TextButton( onPressed: () => client.connect(), child: Text( 'Try Again', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Color(0xFF006CFF), - ), + style: StreamChatTheme.of(context) + .channelTheme + .channelHeaderTheme + .title + .copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF006CFF), + ), ), ), ], From 942250d517971c28bbaed7eb4ac3d374e1b2b1f2 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 17:49:42 +0530 Subject: [PATCH 3/8] [ChannelListHeader] Add docComments --- lib/src/channel_list_header.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 147f9340..b44097c2 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -39,6 +39,9 @@ typedef _TitleBuilder = Widget Function( /// Usually you would use this widget as an [AppBar] inside a [Scaffold]. /// However you can also use it as a normal widget. /// +/// The widget by default uses the inherited [Client] to fetch information about the status. +/// However you can also pass your own [Client] if you don't have it in the widget tree. +/// /// The widget components render the ui based on the first ancestor of type [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property. /// Modify it to change the widget appearance. class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { @@ -51,12 +54,17 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { this.onNewChatButtonTap, }) : super(key: key); + /// Pass this if you don't have a [Client] in your widget tree. final Client client; + /// Use this to build your own title as per different [ConnectionStatus] final _TitleBuilder titleBuilder; + /// Callback to call when pressing the user avatar button. + /// By default it calls Scaffold.of(context).openDrawer() final Function(User) onUserAvatarTap; + /// Callback to call when pressing the new chat button. final VoidCallback onNewChatButtonTap; @override From f789975844b69f1aca1b96a46ccb735813268834 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Mon, 23 Nov 2020 17:51:37 +0530 Subject: [PATCH 4/8] Open new chat screen page when new chat button is pressed. --- example/lib/main.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 7592cfab..9bcf63b5 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -69,7 +69,15 @@ class ChannelListPage extends StatelessWidget { Widget build(BuildContext context) { final user = StreamChat.of(context).user; return Scaffold( - appBar: ChannelListHeader(), + appBar: ChannelListHeader( + onNewChatButtonTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => NewChatScreen(), + ), + ); + }, + ), drawer: _buildDrawer(context, user), drawerEdgeDragWidth: 50, body: ChannelsBloc( From d68c02066e51ebe3a3cb0220f9fa6651f835a316 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Mon, 23 Nov 2020 17:00:51 +0100 Subject: [PATCH 5/8] change reconnection logic --- lib/src/channel_list_header.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index b44097c2..0df8ea06 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -192,7 +192,10 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ), ), TextButton( - onPressed: () => client.connect(), + onPressed: () async { + await client.disconnect(); + return client.connect(); + }, child: Text( 'Try Again', style: StreamChatTheme.of(context) From f61d42bf3a61f926b2621bde1786e25355ce3dda Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Tue, 24 Nov 2020 12:44:34 +0530 Subject: [PATCH 6/8] [Channel List Header] Hide online status from user avatar --- lib/src/channel_list_header.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 0df8ea06..6a838265 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -80,6 +80,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { leading: Center( child: UserAvatar( user: user, + showOnlineStatus: false, onTap: onUserAvatarTap ?? (_) => Scaffold.of(context).openDrawer(), borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( From 5ec2b20a0d6b1658bfe98e2903e3cba6848218c5 Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Tue, 24 Nov 2020 14:55:37 +0530 Subject: [PATCH 7/8] [Channel List Header] Replace pen_write icon with correct svg icon. --- images/icon_pen-write.svg | 5 +++++ lib/src/channel_list_header.dart | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 images/icon_pen-write.svg diff --git a/images/icon_pen-write.svg b/images/icon_pen-write.svg new file mode 100644 index 00000000..b2711dad --- /dev/null +++ b/images/icon_pen-write.svg @@ -0,0 +1,5 @@ + + + diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 6a838265..7ae84eec 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_neumorphic_button.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; @@ -107,8 +108,11 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { color = Colors.grey; break; } - return Icon( - StreamIcons.pen_write, + return SvgPicture.asset( + 'images/icon_pen-write.svg', + package: 'stream_chat_flutter', + width: 24.0, + height: 24.0, color: color, ); }, From 92b88c505eac8de6165b19cadb0702cd59fb730b Mon Sep 17 00:00:00 2001 From: xsahil03x Date: Tue, 24 Nov 2020 15:33:48 +0530 Subject: [PATCH 8/8] Minor fix --- lib/src/channel_list_header.dart | 2 +- images/icon_pen-write.svg => svgs/icon_pen_write.svg | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename images/icon_pen-write.svg => svgs/icon_pen_write.svg (100%) diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 7ae84eec..0a01733b 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -109,7 +109,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { break; } return SvgPicture.asset( - 'images/icon_pen-write.svg', + 'svgs/icon_pen_write.svg', package: 'stream_chat_flutter', width: 24.0, height: 24.0, diff --git a/images/icon_pen-write.svg b/svgs/icon_pen_write.svg similarity index 100% rename from images/icon_pen-write.svg rename to svgs/icon_pen_write.svg