From 45b5d4eeea01c774386e9e2b07d741046139330b Mon Sep 17 00:00:00 2001 From: Freek van de Ven Date: Mon, 10 Feb 2025 08:25:50 +0100 Subject: [PATCH] feat: add ChatScope inherited widget for accessing the options, service and userId everywhere through the context --- CHANGELOG.md | 1 + packages/flutter_chat/lib/flutter_chat.dart | 10 ++-- .../src/flutter_chat_navigator_userstory.dart | 54 ++++++++++++------- .../lib/src/services/pop_handler.dart | 24 +++++++++ packages/flutter_chat/lib/src/util/scope.dart | 37 +++++++++++++ packages/flutter_chat/lib/src/util/utils.dart | 1 + 6 files changed, 105 insertions(+), 22 deletions(-) create mode 100644 packages/flutter_chat/lib/src/services/pop_handler.dart create mode 100644 packages/flutter_chat/lib/src/util/scope.dart create mode 100644 packages/flutter_chat/lib/src/util/utils.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index b30294c..5de7258 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Added messageType to the ChatMessageModel to allow for different type of messages, it is nullable to remain backwards compatible - Get the color for the imagepicker from the Theme's primaryColor - Added chatMessageBuilder to the userstory configuration to customize the chat messages +- Added ChatScope that can be used to get the ChatService and ChatTranslations from the context. If you use individual components instead of the userstory you need to wrap them with the ChatScope. The options and service will be removed from all the component constructors. ## 4.0.0 - Move to the new user story architecture diff --git a/packages/flutter_chat/lib/flutter_chat.dart b/packages/flutter_chat/lib/flutter_chat.dart index 6f8053e..59d24b6 100644 --- a/packages/flutter_chat/lib/flutter_chat.dart +++ b/packages/flutter_chat/lib/flutter_chat.dart @@ -1,7 +1,5 @@ -// ignore_for_file: prefer_double_quotes - // Core -export 'package:chat_repository_interface/chat_repository_interface.dart'; +export "package:chat_repository_interface/chat_repository_interface.dart"; // User story export "package:flutter_chat/src/flutter_chat_entry_widget.dart"; @@ -11,7 +9,7 @@ export "package:flutter_chat/src/flutter_chat_navigator_userstory.dart"; export "src/config/chat_builders.dart"; export "src/config/chat_options.dart"; export "src/config/chat_translations.dart"; -export 'src/config/screen_types.dart'; +export "src/config/screen_types.dart"; // Screens export "src/screens/chat_detail_screen.dart"; @@ -21,3 +19,7 @@ export "src/screens/creation/new_chat_screen.dart"; export "src/screens/creation/new_group_chat_overview.dart"; export "src/screens/creation/new_group_chat_screen.dart"; export "src/services/date_formatter.dart"; + +// Utils +export "src/util/scope.dart"; +export "src/util/utils.dart"; diff --git a/packages/flutter_chat/lib/src/flutter_chat_navigator_userstory.dart b/packages/flutter_chat/lib/src/flutter_chat_navigator_userstory.dart index 256a63a..2a3b02a 100644 --- a/packages/flutter_chat/lib/src/flutter_chat_navigator_userstory.dart +++ b/packages/flutter_chat/lib/src/flutter_chat_navigator_userstory.dart @@ -13,6 +13,8 @@ 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 @@ -44,29 +46,45 @@ class FlutterChatNavigatorUserstory extends StatefulWidget { class _FlutterChatNavigatorUserstoryState extends State { - late ChatService chatService; - late ChatOptions chatOptions; + late ChatService _service = widget.chatService ?? ChatService(); + + late final PopHandler _popHandler = PopHandler(); @override - void initState() { - chatService = widget.chatService ?? ChatService(); - chatOptions = widget.chatOptions ?? const ChatOptions(); - super.initState(); - } - - @override - Widget build(BuildContext context) => Navigator( - key: const ValueKey( - "chat_navigator", - ), - onGenerateRoute: (settings) => MaterialPageRoute( - builder: (context) => _NavigatorWrapper( - userId: widget.userId, - chatService: chatService, - chatOptions: chatOptions, + Widget build(BuildContext context) => ChatScope( + userId: widget.userId, + options: widget.chatOptions ?? const ChatOptions(), + 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.chatOptions ?? const ChatOptions(), + ), + ), ), ), ); + + @override + void didUpdateWidget(covariant FlutterChatNavigatorUserstory oldWidget) { + super.didUpdateWidget(oldWidget); + + if (oldWidget.userId != widget.userId || + oldWidget.chatOptions != widget.chatOptions) { + setState(() { + _service = widget.chatService ?? ChatService(); + }); + } + } } class _NavigatorWrapper extends StatelessWidget { diff --git a/packages/flutter_chat/lib/src/services/pop_handler.dart b/packages/flutter_chat/lib/src/services/pop_handler.dart new file mode 100644 index 0000000..348a28d --- /dev/null +++ b/packages/flutter_chat/lib/src/services/pop_handler.dart @@ -0,0 +1,24 @@ +import "package:flutter/material.dart"; + +/// +class PopHandler { + /// Constructor + PopHandler(); + + final List _handlers = []; + + /// Registers a new handler + void add(VoidCallback handler) { + _handlers.add(handler); + } + + /// Removes a handler + void remove(VoidCallback handler) { + _handlers.remove(handler); + } + + /// Handles the pop + void handlePop() { + _handlers.lastOrNull?.call(); + } +} diff --git a/packages/flutter_chat/lib/src/util/scope.dart b/packages/flutter_chat/lib/src/util/scope.dart new file mode 100644 index 0000000..e82dae4 --- /dev/null +++ b/packages/flutter_chat/lib/src/util/scope.dart @@ -0,0 +1,37 @@ +import "package:chat_repository_interface/chat_repository_interface.dart"; +import "package:flutter/widgets.dart"; +import "package:flutter_chat/src/config/chat_options.dart"; +import "package:flutter_chat/src/services/pop_handler.dart"; + +/// +class ChatScope extends InheritedWidget { + /// + const ChatScope({ + required this.userId, + required this.options, + required this.service, + required this.popHandler, + required super.child, + super.key, + }); + + /// + final String userId; + + /// + final ChatOptions options; + + /// + final ChatService service; + + /// + final PopHandler popHandler; + + @override + bool updateShouldNotify(ChatScope oldWidget) => + oldWidget.userId != userId || oldWidget.options != options; + + /// + static ChatScope of(BuildContext context) => + context.dependOnInheritedWidgetOfExactType()!; +} diff --git a/packages/flutter_chat/lib/src/util/utils.dart b/packages/flutter_chat/lib/src/util/utils.dart new file mode 100644 index 0000000..5312e4f --- /dev/null +++ b/packages/flutter_chat/lib/src/util/utils.dart @@ -0,0 +1 @@ +// add generic utils that are used in the package