From 15604bf26456aa7fe4a6207824d0a050357e8e51 Mon Sep 17 00:00:00 2001 From: Freek van de Ven Date: Wed, 12 Feb 2025 10:30:54 +0100 Subject: [PATCH] feat: rework the existing navigator userstory to look more like flutter_availability userstory --- packages/flutter_chat/lib/flutter_chat.dart | 2 +- .../lib/src/flutter_chat_entry_widget.dart | 4 +- .../flutter_chat_navigator_userstories.dart | 86 ++++++++++ ...t_navigator_userstory.dart => routes.dart} | 155 ++++++------------ 4 files changed, 137 insertions(+), 110 deletions(-) create mode 100644 packages/flutter_chat/lib/src/flutter_chat_navigator_userstories.dart rename packages/flutter_chat/lib/src/{flutter_chat_navigator_userstory.dart => routes.dart} (61%) diff --git a/packages/flutter_chat/lib/flutter_chat.dart b/packages/flutter_chat/lib/flutter_chat.dart index 13b7d9b..dd081f9 100644 --- a/packages/flutter_chat/lib/flutter_chat.dart +++ b/packages/flutter_chat/lib/flutter_chat.dart @@ -3,7 +3,7 @@ export "package:chat_repository_interface/chat_repository_interface.dart"; // User story export "package:flutter_chat/src/flutter_chat_entry_widget.dart"; -export "package:flutter_chat/src/flutter_chat_navigator_userstory.dart"; +export "package:flutter_chat/src/flutter_chat_navigator_userstories.dart"; // Options export "src/config/chat_builders.dart"; diff --git a/packages/flutter_chat/lib/src/flutter_chat_entry_widget.dart b/packages/flutter_chat/lib/src/flutter_chat_entry_widget.dart index 08d5994..8f0dd8e 100644 --- a/packages/flutter_chat/lib/src/flutter_chat_entry_widget.dart +++ b/packages/flutter_chat/lib/src/flutter_chat_entry_widget.dart @@ -81,7 +81,7 @@ class _FlutterChatEntryWidgetState extends State { Widget build(BuildContext context) => InkWell( onTap: () async => widget.onTap?.call() ?? - Navigator.of(context).pushReplacement( + Navigator.of(context).push( MaterialPageRoute( builder: (context) => FlutterChatNavigatorUserstory( userId: widget.userId, @@ -122,7 +122,7 @@ class _FlutterChatEntryWidgetState extends State { ), child: Center( child: Text( - "${snapshot.data ?? 0}", + snapshot.data?.toString() ?? "0", style: widget.textStyle, ), ), diff --git a/packages/flutter_chat/lib/src/flutter_chat_navigator_userstories.dart b/packages/flutter_chat/lib/src/flutter_chat_navigator_userstories.dart new file mode 100644 index 0000000..7fe69ed --- /dev/null +++ b/packages/flutter_chat/lib/src/flutter_chat_navigator_userstories.dart @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: 2023 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +import "package:chat_repository_interface/chat_repository_interface.dart"; +import "package:flutter/material.dart"; +import "package:flutter_chat/src/config/chat_options.dart"; +import "package:flutter_chat/src/routes.dart"; +import "package:flutter_chat/src/services/pop_handler.dart"; +import "package:flutter_chat/src/util/scope.dart"; + +/// The flutter chat navigator userstory +/// [userId] is the id of the user +/// [chatService] is the chat service +/// [chatOptions] are the chat options +/// This widget is the entry point for the chat UI +class FlutterChatNavigatorUserstory extends StatefulWidget { + /// Constructs a [FlutterChatNavigatorUserstory]. + const FlutterChatNavigatorUserstory({ + required this.userId, + required this.options, + super.key, + }); + + /// The user ID of the person currently looking at the chat + final String userId; + + /// The chat options + final ChatOptions options; + + @override + State createState() => + _FlutterChatNavigatorUserstoryState(); +} + +class _FlutterChatNavigatorUserstoryState + extends State { + late ChatService _service = ChatService( + userId: widget.userId, + chatRepository: widget.options.chatRepository, + userRepository: widget.options.userRepository, + ); + + late final PopHandler _popHandler = PopHandler(); + + final GlobalKey _nestedNavigatorKey = + GlobalKey(); + + @override + Widget build(BuildContext context) => ChatScope( + userId: widget.userId, + options: widget.options, + service: _service, + popHandler: _popHandler, + child: NavigatorPopHandler( + // ignore: deprecated_member_use + onPop: () => _popHandler.handlePop(), + child: Navigator( + key: _nestedNavigatorKey, + onGenerateRoute: (settings) => MaterialPageRoute( + builder: (context) => NavigatorWrapper( + userId: widget.userId, + chatService: _service, + chatOptions: widget.options, + ), + ), + ), + ), + ); + + @override + void didUpdateWidget(covariant FlutterChatNavigatorUserstory oldWidget) { + super.didUpdateWidget(oldWidget); + + if (oldWidget.userId != widget.userId || + oldWidget.options != widget.options) { + setState(() { + _service = ChatService( + userId: widget.userId, + chatRepository: widget.options.chatRepository, + userRepository: widget.options.userRepository, + ); + }); + } + } +} diff --git a/packages/flutter_chat/lib/src/flutter_chat_navigator_userstory.dart b/packages/flutter_chat/lib/src/routes.dart similarity index 61% rename from packages/flutter_chat/lib/src/flutter_chat_navigator_userstory.dart rename to packages/flutter_chat/lib/src/routes.dart index c0fe01d..398cc6f 100644 --- a/packages/flutter_chat/lib/src/flutter_chat_navigator_userstory.dart +++ b/packages/flutter_chat/lib/src/routes.dart @@ -1,7 +1,3 @@ -// SPDX-FileCopyrightText: 2023 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - import "dart:async"; import "package:chat_repository_interface/chat_repository_interface.dart"; @@ -13,125 +9,66 @@ import "package:flutter_chat/src/screens/chat_screen.dart"; import "package:flutter_chat/src/screens/creation/new_chat_screen.dart"; import "package:flutter_chat/src/screens/creation/new_group_chat_overview.dart"; import "package:flutter_chat/src/screens/creation/new_group_chat_screen.dart"; -import "package:flutter_chat/src/services/pop_handler.dart"; -import "package:flutter_chat/src/util/scope.dart"; -/// The flutter chat navigator userstory -/// [userId] is the id of the user -/// [chatService] is the chat service -/// [chatOptions] are the chat options -/// This widget is the entry point for the chat UI -class FlutterChatNavigatorUserstory extends StatefulWidget { - /// Constructs a [FlutterChatNavigatorUserstory]. - const FlutterChatNavigatorUserstory({ - required this.userId, - required this.options, - super.key, - }); - - /// The user ID of the person currently looking at the chat - final String userId; - - /// The chat options - final ChatOptions options; - - @override - State createState() => - _FlutterChatNavigatorUserstoryState(); -} - -class _FlutterChatNavigatorUserstoryState - extends State { - late ChatService _service = ChatService( - userId: widget.userId, - chatRepository: widget.options.chatRepository, - userRepository: widget.options.userRepository, - ); - - late final PopHandler _popHandler = PopHandler(); - - @override - Widget build(BuildContext context) => ChatScope( - userId: widget.userId, - options: widget.options, - service: _service, - popHandler: _popHandler, - child: NavigatorPopHandler( - // ignore: deprecated_member_use - onPop: _popHandler.handlePop, - child: Navigator( - key: const ValueKey( - "chat_navigator", - ), - onGenerateRoute: (settings) => MaterialPageRoute( - builder: (context) => _NavigatorWrapper( - userId: widget.userId, - chatService: _service, - chatOptions: widget.options, - ), - ), - ), - ), - ); - - @override - void didUpdateWidget(covariant FlutterChatNavigatorUserstory oldWidget) { - super.didUpdateWidget(oldWidget); - - if (oldWidget.userId != widget.userId || - oldWidget.options != widget.options) { - setState(() { - _service = ChatService( - userId: widget.userId, - chatRepository: widget.options.chatRepository, - userRepository: widget.options.userRepository, - ); - }); - } - } -} - -class _NavigatorWrapper extends StatelessWidget { - const _NavigatorWrapper({ +/// The navigator wrapper +class NavigatorWrapper extends StatelessWidget { + /// Constructs a [NavigatorWrapper]. + const NavigatorWrapper({ required this.userId, required this.chatService, required this.chatOptions, + super.key, }); + /// The user ID of the person starting the chat userstory final String userId; + + /// The chat service containing the chat repository and user repository final ChatService chatService; + + /// The chat userstory configuration final ChatOptions chatOptions; @override Widget build(BuildContext context) => chatScreen(context); + /// The chat overview screen Widget chatScreen(BuildContext context) => ChatScreen( chatService: chatService, chatOptions: chatOptions, - onPressChat: (chat) => route(context, chatDetailScreen(context, chat)), + onPressChat: (chat) async => + _routeToScreen(context, chatDetailScreen(context, chat)), onDeleteChat: (chat) async { await chatService.deleteChat(chatId: chat.id); }, - onPressStartChat: () => route(context, newChatScreen(context)), + onPressStartChat: () async => + _routeToScreen(context, newChatScreen(context)), ); + /// The chat screen Widget chatDetailScreen(BuildContext context, ChatModel chat) => ChatDetailScreen( chat: chat, onReadChat: (chat) async => chatService.markAsRead(chatId: chat.id), onPressChatTitle: (chat) async { if (chat.isGroupChat) { - return route(context, chatProfileScreen(context, null, chat)); + return _routeToScreen( + context, + chatProfileScreen(context, null, chat), + ); } var otherUserId = chat.getOtherUser(userId); var otherUser = await chatService.getUser(userId: otherUserId).first; if (!context.mounted) return; - return route(context, chatProfileScreen(context, otherUser, null)); + return _routeToScreen( + context, + chatProfileScreen(context, otherUser, null), + ); }, - onPressUserProfile: (user) => - route(context, chatProfileScreen(context, user, null)), + onPressUserProfile: (user) async => + _routeToScreen(context, chatProfileScreen(context, user, null)), onUploadImage: (data) async { var path = await chatService.uploadImage( path: "chats/${chat.id}-$userId-${DateTime.now()}", @@ -155,6 +92,7 @@ class _NavigatorWrapper extends StatelessWidget { }, ); + /// The chat profile screen Widget chatProfileScreen( BuildContext context, UserModel? user, @@ -170,38 +108,41 @@ class _NavigatorWrapper extends StatelessWidget { var user = await chatService.getUser(userId: userId).first; if (!context.mounted) return; - route(context, chatProfileScreen(context, user, null)); + await _routeToScreen(context, chatProfileScreen(context, user, null)); }, onPressStartChat: (userId) async { - var chat = await createChat(userId); + var chat = await _createChat(userId); if (!context.mounted) return; - return route(context, chatDetailScreen(context, chat)); + return _routeToScreen(context, chatDetailScreen(context, chat)); }, ); + /// The new chat screen Widget newChatScreen(BuildContext context) => NewChatScreen( userId: userId, chatService: chatService, chatOptions: chatOptions, - onPressCreateGroupChat: () => - route(context, newGroupChatScreen(context)), + onPressCreateGroupChat: () async => + _routeToScreen(context, newGroupChatScreen(context)), onPressCreateChat: (user) async { - var chat = await createChat(user.id); + var chat = await _createChat(user.id); if (!context.mounted) return; - return route(context, chatDetailScreen(context, chat)); + return _routeToScreen(context, chatDetailScreen(context, chat)); }, ); + /// The new group chat screen Widget newGroupChatScreen(BuildContext context) => NewGroupChatScreen( userId: userId, chatService: chatService, chatOptions: chatOptions, - onContinue: (users) => - route(context, newGroupChatOverview(context, users)), + onContinue: (users) async => + _routeToScreen(context, newGroupChatOverview(context, users)), ); + /// The new group chat overview screen Widget newGroupChatOverview(BuildContext context, List users) => NewGroupChatOverview( options: chatOptions, @@ -214,7 +155,7 @@ class _NavigatorWrapper extends StatelessWidget { image: image, ); } - var chat = await createGroupChat( + var chat = await _createGroupChat( users, title, description, @@ -222,11 +163,12 @@ class _NavigatorWrapper extends StatelessWidget { ); if (!context.mounted) return; - return route(context, chatDetailScreen(context, chat)); + return _routeToScreen(context, chatDetailScreen(context, chat)); }, ); - Future createGroupChat( + /// Creates a group chat + Future _createGroupChat( List userModels, String title, String description, @@ -275,7 +217,8 @@ class _NavigatorWrapper extends StatelessWidget { return chat; } - Future createChat(String otherUserId) async { + /// Creates a chat + Future _createChat(String otherUserId) async { ChatModel? chat; try { @@ -311,11 +254,9 @@ class _NavigatorWrapper extends StatelessWidget { return chat; } - void route(BuildContext context, Widget screen) { - unawaited( + /// Routes to a new screen for the userstory + Future _routeToScreen(BuildContext context, Widget screen) async => Navigator.of(context).push( MaterialPageRoute(builder: (context) => screen), - ), - ); - } + ); }