feat: remove chatService and chatOptions from widget parameters to use ChatScope instead

This commit is contained in:
Freek van de Ven 2025-02-12 22:38:02 +01:00 committed by Freek van de Ven
parent 97c259761c
commit cc52c78487
8 changed files with 128 additions and 211 deletions

View file

@ -3,7 +3,6 @@ import "dart:typed_data";
import "package:chat_repository_interface/chat_repository_interface.dart"; import "package:chat_repository_interface/chat_repository_interface.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_chat/src/config/chat_options.dart";
import "package:flutter_chat/src/config/screen_types.dart"; import "package:flutter_chat/src/config/screen_types.dart";
import "package:flutter_chat/src/screens/chat_detail/widgets/default_message_builder.dart"; import "package:flutter_chat/src/screens/chat_detail/widgets/default_message_builder.dart";
import "package:flutter_chat/src/screens/creation/widgets/image_picker.dart"; import "package:flutter_chat/src/screens/creation/widgets/image_picker.dart";
@ -91,7 +90,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context); var chatScope = ChatScope.of(context);
var chatOptions = chatScope.options; var options = chatScope.options;
var appBar = _AppBar( var appBar = _AppBar(
chatTitle: chatTitle, chatTitle: chatTitle,
onPressChatTitle: widget.onPressChatTitle, onPressChatTitle: widget.onPressChatTitle,
@ -113,14 +112,14 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
return () => chatScope.popHandler.remove(widget.onExit!); return () => chatScope.popHandler.remove(widget.onExit!);
}); });
if (chatOptions.builders.baseScreenBuilder == null) { if (options.builders.baseScreenBuilder == null) {
return Scaffold( return Scaffold(
appBar: appBar, appBar: appBar,
body: body, body: body,
); );
} }
return chatOptions.builders.baseScreenBuilder!.call( return options.builders.baseScreenBuilder!.call(
context, context,
widget.mapScreenType, widget.mapScreenType,
appBar, appBar,
@ -305,7 +304,6 @@ class _BodyState extends State<_Body> {
widget.onUploadImage, widget.onUploadImage,
), ),
onMessageSubmit: widget.onMessageSubmit, onMessageSubmit: widget.onMessageSubmit,
options: options,
), ),
], ],
), ),
@ -347,7 +345,6 @@ class _ChatBottom extends StatefulWidget {
const _ChatBottom({ const _ChatBottom({
required this.chat, required this.chat,
required this.onMessageSubmit, required this.onMessageSubmit,
required this.options,
this.onPressSelectImage, this.onPressSelectImage,
}); });
@ -360,8 +357,6 @@ class _ChatBottom extends StatefulWidget {
/// The chat model. /// The chat model.
final ChatModel chat; final ChatModel chat;
final ChatOptions options;
@override @override
State<_ChatBottom> createState() => _ChatBottomState(); State<_ChatBottom> createState() => _ChatBottomState();
} }
@ -373,6 +368,8 @@ class _ChatBottomState extends State<_ChatBottom> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context);
var options = chatScope.options;
var theme = Theme.of(context); var theme = Theme.of(context);
_textEditingController.addListener(() { _textEditingController.addListener(() {
@ -409,12 +406,12 @@ class _ChatBottomState extends State<_ChatBottom> {
onPressed: widget.onPressSelectImage, onPressed: widget.onPressSelectImage,
icon: Icon( icon: Icon(
Icons.image_outlined, Icons.image_outlined,
color: widget.options.iconEnabledColor, color: options.iconEnabledColor,
), ),
), ),
IconButton( IconButton(
disabledColor: widget.options.iconDisabledColor, disabledColor: options.iconDisabledColor,
color: widget.options.iconEnabledColor, color: options.iconEnabledColor,
onPressed: onClickSendMessage, onPressed: onClickSendMessage,
icon: const Icon( icon: const Icon(
Icons.send_rounded, Icons.send_rounded,
@ -446,7 +443,7 @@ class _ChatBottomState extends State<_ChatBottom> {
vertical: 0, vertical: 0,
horizontal: 30, horizontal: 30,
), ),
hintText: widget.options.translations.messagePlaceholder, hintText: options.translations.messagePlaceholder,
hintStyle: theme.textTheme.bodyMedium, hintStyle: theme.textTheme.bodyMedium,
fillColor: Colors.white, fillColor: Colors.white,
filled: true, filled: true,
@ -467,11 +464,11 @@ class _ChatBottomState extends State<_ChatBottom> {
), ),
child: SizedBox( child: SizedBox(
height: 45, height: 45,
child: widget.options.builders.messageInputBuilder?.call( child: options.builders.messageInputBuilder?.call(
context, context,
_textEditingController, _textEditingController,
messageSendButtons, messageSendButtons,
widget.options.translations, options.translations,
) ?? ) ??
defaultInputField, defaultInputField,
), ),

View file

@ -1,6 +1,5 @@
import "package:chat_repository_interface/chat_repository_interface.dart"; import "package:chat_repository_interface/chat_repository_interface.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_chat/src/config/chat_options.dart";
import "package:flutter_chat/src/config/screen_types.dart"; import "package:flutter_chat/src/config/screen_types.dart";
import "package:flutter_chat/src/util/scope.dart"; import "package:flutter_chat/src/util/scope.dart";
import "package:flutter_hooks/flutter_hooks.dart"; import "package:flutter_hooks/flutter_hooks.dart";
@ -39,8 +38,6 @@ class ChatProfileScreen extends HookWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context); var chatScope = ChatScope.of(context);
var options = chatScope.options; var options = chatScope.options;
var service = chatScope.service;
var userId = chatScope.userId;
useEffect(() { useEffect(() {
chatScope.popHandler.add(onExit); chatScope.popHandler.add(onExit);
@ -50,13 +47,9 @@ class ChatProfileScreen extends HookWidget {
var appBar = _AppBar( var appBar = _AppBar(
user: userModel, user: userModel,
chat: chatModel, chat: chatModel,
options: options,
); );
var body = _Body( var body = _Body(
currentUser: userId,
options: options,
service: service,
user: userModel, user: userModel,
chat: chatModel, chat: chatModel,
onTapUser: onTapUser, onTapUser: onTapUser,
@ -83,15 +76,15 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
const _AppBar({ const _AppBar({
required this.user, required this.user,
required this.chat, required this.chat,
required this.options,
}); });
final UserModel? user; final UserModel? user;
final ChatModel? chat; final ChatModel? chat;
final ChatOptions options;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context);
var options = chatScope.options;
var theme = Theme.of(context); var theme = Theme.of(context);
return AppBar( return AppBar(
iconTheme: theme.appBarTheme.iconTheme, iconTheme: theme.appBarTheme.iconTheme,
@ -111,25 +104,23 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
class _Body extends StatelessWidget { class _Body extends StatelessWidget {
const _Body({ const _Body({
required this.options,
required this.service,
required this.user, required this.user,
required this.chat, required this.chat,
required this.onPressStartChat, required this.onPressStartChat,
required this.onTapUser, required this.onTapUser,
required this.currentUser,
}); });
final ChatOptions options;
final ChatService service;
final UserModel? user; final UserModel? user;
final ChatModel? chat; final ChatModel? chat;
final Function(String)? onTapUser; final Function(String)? onTapUser;
final Function(String)? onPressStartChat; final Function(String)? onPressStartChat;
final String currentUser;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context);
var options = chatScope.options;
var service = chatScope.service;
var currentUser = chatScope.userId;
var theme = Theme.of(context); var theme = Theme.of(context);
var chatUserDisplay = Wrap( var chatUserDisplay = Wrap(

View file

@ -1,6 +1,5 @@
import "package:chat_repository_interface/chat_repository_interface.dart"; import "package:chat_repository_interface/chat_repository_interface.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_chat/src/config/chat_options.dart";
import "package:flutter_chat/src/config/chat_translations.dart"; import "package:flutter_chat/src/config/chat_translations.dart";
import "package:flutter_chat/src/config/screen_types.dart"; import "package:flutter_chat/src/config/screen_types.dart";
import "package:flutter_chat/src/services/date_formatter.dart"; import "package:flutter_chat/src/services/date_formatter.dart";
@ -36,7 +35,6 @@ class ChatScreen extends HookWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context); var chatScope = ChatScope.of(context);
var options = chatScope.options; var options = chatScope.options;
var service = chatScope.service;
useEffect(() { useEffect(() {
if (onExit == null) return null; if (onExit == null) return null;
@ -46,13 +44,8 @@ class ChatScreen extends HookWidget {
if (options.builders.baseScreenBuilder == null) { if (options.builders.baseScreenBuilder == null) {
return Scaffold( return Scaffold(
appBar: _AppBar( appBar: const _AppBar(),
chatOptions: options,
chatService: service,
),
body: _Body( body: _Body(
chatOptions: options,
chatService: service,
onPressChat: onPressChat, onPressChat: onPressChat,
onPressStartChat: onPressStartChat, onPressStartChat: onPressStartChat,
onDeleteChat: onDeleteChat, onDeleteChat: onDeleteChat,
@ -63,13 +56,8 @@ class ChatScreen extends HookWidget {
return options.builders.baseScreenBuilder!.call( return options.builders.baseScreenBuilder!.call(
context, context,
mapScreenType, mapScreenType,
_AppBar( const _AppBar(),
chatOptions: options,
chatService: service,
),
_Body( _Body(
chatOptions: options,
chatService: service,
onPressChat: onPressChat, onPressChat: onPressChat,
onPressStartChat: onPressStartChat, onPressStartChat: onPressStartChat,
onDeleteChat: onDeleteChat, onDeleteChat: onDeleteChat,
@ -79,17 +67,14 @@ class ChatScreen extends HookWidget {
} }
class _AppBar extends StatelessWidget implements PreferredSizeWidget { class _AppBar extends StatelessWidget implements PreferredSizeWidget {
const _AppBar({ const _AppBar();
required this.chatOptions,
required this.chatService,
});
final ChatOptions chatOptions;
final ChatService chatService;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var translations = chatOptions.translations; var chatScope = ChatScope.of(context);
var service = chatScope.service;
var options = chatScope.options;
var translations = options.translations;
var theme = Theme.of(context); var theme = Theme.of(context);
return AppBar( return AppBar(
@ -98,7 +83,7 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
), ),
actions: [ actions: [
StreamBuilder<int>( StreamBuilder<int>(
stream: chatService.getUnreadMessagesCount(), stream: service.getUnreadMessagesCount(),
builder: (BuildContext context, snapshot) => Align( builder: (BuildContext context, snapshot) => Align(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: Visibility( child: Visibility(
@ -125,15 +110,11 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
class _Body extends StatefulWidget { class _Body extends StatefulWidget {
const _Body({ const _Body({
required this.chatOptions,
required this.chatService,
required this.onPressChat, required this.onPressChat,
required this.onDeleteChat, required this.onDeleteChat,
this.onPressStartChat, this.onPressStartChat,
}); });
final ChatOptions chatOptions;
final ChatService chatService;
final Function(ChatModel chat) onPressChat; final Function(ChatModel chat) onPressChat;
final Function()? onPressStartChat; final Function()? onPressStartChat;
final Function(ChatModel) onDeleteChat; final Function(ChatModel) onDeleteChat;
@ -148,7 +129,10 @@ class _BodyState extends State<_Body> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var translations = widget.chatOptions.translations; var chatScope = ChatScope.of(context);
var options = chatScope.options;
var service = chatScope.service;
var translations = options.translations;
var theme = Theme.of(context); var theme = Theme.of(context);
return Column( return Column(
children: [ children: [
@ -159,17 +143,16 @@ class _BodyState extends State<_Body> {
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 28), padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 28),
children: [ children: [
StreamBuilder<List<ChatModel>?>( StreamBuilder<List<ChatModel>?>(
stream: widget.chatService.getChats(), stream: service.getChats(),
builder: (BuildContext context, snapshot) { builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.done && if (snapshot.connectionState == ConnectionState.done &&
(snapshot.data?.isEmpty ?? true) || (snapshot.data?.isEmpty ?? true) ||
(snapshot.data != null && snapshot.data!.isEmpty)) { (snapshot.data != null && snapshot.data!.isEmpty)) {
if (widget.chatOptions.onNoChats != null && if (options.onNoChats != null && !_hasCalledOnNoChats) {
!_hasCalledOnNoChats) {
_hasCalledOnNoChats = true; // Set the flag to true _hasCalledOnNoChats = true; // Set the flag to true
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
// ignore: avoid_dynamic_calls // ignore: avoid_dynamic_calls
await widget.chatOptions.onNoChats!.call(); await options.onNoChats!.call();
}); });
} }
return Center( return Center(
@ -195,8 +178,8 @@ class _BodyState extends State<_Body> {
builder: (context) => !chat.canBeDeleted builder: (context) => !chat.canBeDeleted
? Dismissible( ? Dismissible(
confirmDismiss: (_) async { confirmDismiss: (_) async {
await widget.chatOptions.builders await options
.deleteChatDialogBuilder .builders.deleteChatDialogBuilder
?.call(context, chat) ?? ?.call(context, chat) ??
_deleteDialog( _deleteDialog(
chat, chat,
@ -244,16 +227,12 @@ class _BodyState extends State<_Body> {
chat.id, chat.id,
), ),
child: _ChatItem( child: _ChatItem(
service: widget.chatService,
chat: chat, chat: chat,
chatOptions: widget.chatOptions,
onPressChat: widget.onPressChat, onPressChat: widget.onPressChat,
), ),
) )
: _ChatItem( : _ChatItem(
service: widget.chatService,
chat: chat, chat: chat,
chatOptions: widget.chatOptions,
onPressChat: widget.onPressChat, onPressChat: widget.onPressChat,
), ),
), ),
@ -267,7 +246,7 @@ class _BodyState extends State<_Body> {
), ),
), ),
if (widget.onPressStartChat != null) if (widget.onPressStartChat != null)
widget.chatOptions.builders.newChatButtonBuilder?.call( options.builders.newChatButtonBuilder?.call(
context, context,
widget.onPressStartChat!, widget.onPressStartChat!,
translations, translations,
@ -300,33 +279,29 @@ class _BodyState extends State<_Body> {
class _ChatItem extends StatelessWidget { class _ChatItem extends StatelessWidget {
const _ChatItem({ const _ChatItem({
required this.chat, required this.chat,
required this.chatOptions,
required this.service,
required this.onPressChat, required this.onPressChat,
}); });
final ChatModel chat; final ChatModel chat;
final ChatOptions chatOptions;
final ChatService service;
final Function(ChatModel chat) onPressChat; final Function(ChatModel chat) onPressChat;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context);
var options = chatScope.options;
var dateFormatter = DateFormatter( var dateFormatter = DateFormatter(
options: chatOptions, options: options,
); );
var theme = Theme.of(context); var theme = Theme.of(context);
return InkWell( return InkWell(
onTap: () { onTap: () {
onPressChat(chat); onPressChat(chat);
}, },
child: chatOptions.builders.chatRowContainerBuilder?.call( child: options.builders.chatRowContainerBuilder?.call(
context, context,
_ChatListItem( _ChatListItem(
chat: chat, chat: chat,
options: chatOptions,
dateFormatter: dateFormatter, dateFormatter: dateFormatter,
chatService: service,
), ),
) ?? ) ??
DecoratedBox( DecoratedBox(
@ -343,9 +318,7 @@ class _ChatItem extends StatelessWidget {
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: _ChatListItem( child: _ChatListItem(
chat: chat, chat: chat,
options: chatOptions,
dateFormatter: dateFormatter, dateFormatter: dateFormatter,
chatService: service,
), ),
), ),
), ),
@ -356,25 +329,23 @@ class _ChatItem extends StatelessWidget {
class _ChatListItem extends StatelessWidget { class _ChatListItem extends StatelessWidget {
const _ChatListItem({ const _ChatListItem({
required this.chat, required this.chat,
required this.options,
required this.dateFormatter, required this.dateFormatter,
required this.chatService,
}); });
final ChatModel chat; final ChatModel chat;
final ChatOptions options;
final DateFormatter dateFormatter; final DateFormatter dateFormatter;
final ChatService chatService;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var scope = ChatScope.of(context); var scope = ChatScope.of(context);
var service = scope.service;
var options = scope.options;
var currentUserId = scope.userId; var currentUserId = scope.userId;
var translations = options.translations; var translations = options.translations;
if (chat.isGroupChat) { if (chat.isGroupChat) {
return StreamBuilder<MessageModel?>( return StreamBuilder<MessageModel?>(
stream: chat.lastMessage != null stream: chat.lastMessage != null
? chatService.getMessage( ? service.getMessage(
chatId: chat.id, chatId: chat.id,
messageId: chat.lastMessage!, messageId: chat.lastMessage!,
) )
@ -432,7 +403,7 @@ class _ChatListItem extends StatelessWidget {
); );
return StreamBuilder<UserModel>( return StreamBuilder<UserModel>(
stream: chatService.getUser(userId: otherUser), stream: service.getUser(userId: otherUser),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center( return const Center(
@ -448,7 +419,7 @@ class _ChatListItem extends StatelessWidget {
return StreamBuilder<MessageModel?>( return StreamBuilder<MessageModel?>(
stream: chat.lastMessage != null stream: chat.lastMessage != null
? chatService.getMessage( ? service.getMessage(
chatId: chat.id, chatId: chat.id,
messageId: chat.lastMessage!, messageId: chat.lastMessage!,
) )

View file

@ -1,6 +1,5 @@
import "package:chat_repository_interface/chat_repository_interface.dart"; import "package:chat_repository_interface/chat_repository_interface.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_chat/src/config/chat_options.dart";
import "package:flutter_chat/src/config/screen_types.dart"; import "package:flutter_chat/src/config/screen_types.dart";
import "package:flutter_chat/src/screens/creation/widgets/search_field.dart"; import "package:flutter_chat/src/screens/creation/widgets/search_field.dart";
import "package:flutter_chat/src/screens/creation/widgets/search_icon.dart"; import "package:flutter_chat/src/screens/creation/widgets/search_icon.dart";
@ -41,8 +40,6 @@ class _NewChatScreenState extends State<NewChatScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context); var chatScope = ChatScope.of(context);
var options = chatScope.options; var options = chatScope.options;
var service = chatScope.service;
var userId = chatScope.userId;
useEffect(() { useEffect(() {
chatScope.popHandler.add(widget.onExit); chatScope.popHandler.add(widget.onExit);
@ -52,7 +49,6 @@ class _NewChatScreenState extends State<NewChatScreen> {
if (options.builders.baseScreenBuilder == null) { if (options.builders.baseScreenBuilder == null) {
return Scaffold( return Scaffold(
appBar: _AppBar( appBar: _AppBar(
chatOptions: options,
isSearching: _isSearching, isSearching: _isSearching,
onSearch: (query) { onSearch: (query) {
setState(() { setState(() {
@ -73,12 +69,9 @@ class _NewChatScreenState extends State<NewChatScreen> {
focusNode: _textFieldFocusNode, focusNode: _textFieldFocusNode,
), ),
body: _Body( body: _Body(
chatOptions: options,
chatService: service,
isSearching: _isSearching, isSearching: _isSearching,
onPressCreateGroupChat: widget.onPressCreateGroupChat, onPressCreateGroupChat: widget.onPressCreateGroupChat,
onPressCreateChat: widget.onPressCreateChat, onPressCreateChat: widget.onPressCreateChat,
userId: userId,
query: query, query: query,
), ),
); );
@ -88,7 +81,6 @@ class _NewChatScreenState extends State<NewChatScreen> {
context, context,
widget.mapScreenType, widget.mapScreenType,
_AppBar( _AppBar(
chatOptions: options,
isSearching: _isSearching, isSearching: _isSearching,
onSearch: (query) { onSearch: (query) {
setState(() { setState(() {
@ -109,12 +101,9 @@ class _NewChatScreenState extends State<NewChatScreen> {
focusNode: _textFieldFocusNode, focusNode: _textFieldFocusNode,
), ),
_Body( _Body(
chatOptions: options,
chatService: service,
isSearching: _isSearching, isSearching: _isSearching,
onPressCreateGroupChat: widget.onPressCreateGroupChat, onPressCreateGroupChat: widget.onPressCreateGroupChat,
onPressCreateChat: widget.onPressCreateChat, onPressCreateChat: widget.onPressCreateChat,
userId: userId,
query: query, query: query,
), ),
); );
@ -123,14 +112,12 @@ class _NewChatScreenState extends State<NewChatScreen> {
class _AppBar extends StatelessWidget implements PreferredSizeWidget { class _AppBar extends StatelessWidget implements PreferredSizeWidget {
const _AppBar({ const _AppBar({
required this.chatOptions,
required this.isSearching, required this.isSearching,
required this.onSearch, required this.onSearch,
required this.onPressedSearchIcon, required this.onPressedSearchIcon,
required this.focusNode, required this.focusNode,
}); });
final ChatOptions chatOptions;
final bool isSearching; final bool isSearching;
final Function(String) onSearch; final Function(String) onSearch;
final VoidCallback onPressedSearchIcon; final VoidCallback onPressedSearchIcon;
@ -138,17 +125,18 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context);
var options = chatScope.options;
var theme = Theme.of(context); var theme = Theme.of(context);
return AppBar( return AppBar(
iconTheme: theme.appBarTheme.iconTheme ?? iconTheme: theme.appBarTheme.iconTheme ??
const IconThemeData(color: Colors.white), const IconThemeData(color: Colors.white),
title: SearchField( title: SearchField(
chatOptions: chatOptions,
isSearching: isSearching, isSearching: isSearching,
onSearch: onSearch, onSearch: onSearch,
focusNode: focusNode, focusNode: focusNode,
text: chatOptions.translations.newChatTitle, text: options.translations.newChatTitle,
), ),
actions: [ actions: [
SearchIcon( SearchIcon(
@ -165,20 +153,14 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
class _Body extends StatelessWidget { class _Body extends StatelessWidget {
const _Body({ const _Body({
required this.chatOptions,
required this.chatService,
required this.isSearching, required this.isSearching,
required this.onPressCreateGroupChat, required this.onPressCreateGroupChat,
required this.onPressCreateChat, required this.onPressCreateChat,
required this.userId,
required this.query, required this.query,
}); });
final ChatOptions chatOptions;
final ChatService chatService;
final bool isSearching; final bool isSearching;
final String userId;
final String query; final String query;
final VoidCallback onPressCreateGroupChat; final VoidCallback onPressCreateGroupChat;
@ -186,12 +168,16 @@ class _Body extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var translations = chatOptions.translations; var chatScope = ChatScope.of(context);
var service = chatScope.service;
var options = chatScope.options;
var userId = chatScope.userId;
var translations = options.translations;
var theme = Theme.of(context); var theme = Theme.of(context);
return Column( return Column(
children: [ children: [
if (chatOptions.groupChatEnabled && !isSearching) ...[ if (options.groupChatEnabled && !isSearching) ...[
Padding( Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 32, left: 32,
@ -222,7 +208,7 @@ class _Body extends StatelessWidget {
Expanded( Expanded(
child: StreamBuilder<List<UserModel>>( child: StreamBuilder<List<UserModel>>(
// ignore: discarded_futures // ignore: discarded_futures
stream: chatService.getAllUsers(), stream: service.getAllUsers(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
@ -233,11 +219,10 @@ class _Body extends StatelessWidget {
users: snapshot.data!, users: snapshot.data!,
currentUser: userId, currentUser: userId,
query: query, query: query,
options: chatOptions,
onPressCreateChat: onPressCreateChat, onPressCreateChat: onPressCreateChat,
); );
} else { } else {
return chatOptions.builders.noUsersPlaceholderBuilder return options.builders.noUsersPlaceholderBuilder
?.call(context, translations) ?? ?.call(context, translations) ??
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 20), padding: const EdgeInsets.symmetric(vertical: 20),

View file

@ -2,7 +2,6 @@ import "dart:typed_data";
import "package:chat_repository_interface/chat_repository_interface.dart"; import "package:chat_repository_interface/chat_repository_interface.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_chat/src/config/chat_options.dart";
import "package:flutter_chat/src/config/screen_types.dart"; import "package:flutter_chat/src/config/screen_types.dart";
import "package:flutter_chat/src/screens/creation/widgets/image_picker.dart"; import "package:flutter_chat/src/screens/creation/widgets/image_picker.dart";
import "package:flutter_chat/src/util/scope.dart"; import "package:flutter_chat/src/util/scope.dart";
@ -47,11 +46,8 @@ class NewGroupChatOverview extends HookWidget {
if (options.builders.baseScreenBuilder == null) { if (options.builders.baseScreenBuilder == null) {
return Scaffold( return Scaffold(
appBar: _AppBar( appBar: const _AppBar(),
options: options,
),
body: _Body( body: _Body(
options: options,
users: users, users: users,
onComplete: onComplete, onComplete: onComplete,
), ),
@ -61,11 +57,8 @@ class NewGroupChatOverview extends HookWidget {
return options.builders.baseScreenBuilder!.call( return options.builders.baseScreenBuilder!.call(
context, context,
mapScreenType, mapScreenType,
_AppBar( const _AppBar(),
options: options,
),
_Body( _Body(
options: options,
users: users, users: users,
onComplete: onComplete, onComplete: onComplete,
), ),
@ -74,14 +67,12 @@ class NewGroupChatOverview extends HookWidget {
} }
class _AppBar extends StatelessWidget implements PreferredSizeWidget { class _AppBar extends StatelessWidget implements PreferredSizeWidget {
const _AppBar({ const _AppBar();
required this.options,
});
final ChatOptions options;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context);
var options = chatScope.options;
var theme = Theme.of(context); var theme = Theme.of(context);
return AppBar( return AppBar(
iconTheme: theme.appBarTheme.iconTheme ?? iconTheme: theme.appBarTheme.iconTheme ??
@ -99,12 +90,10 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
class _Body extends StatefulWidget { class _Body extends StatefulWidget {
const _Body({ const _Body({
required this.options,
required this.users, required this.users,
required this.onComplete, required this.onComplete,
}); });
final ChatOptions options;
final List<UserModel> users; final List<UserModel> users;
final Function( final Function(
List<UserModel> users, List<UserModel> users,
@ -147,8 +136,10 @@ class _BodyState extends State<_Body> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context);
var options = chatScope.options;
var theme = Theme.of(context); var theme = Theme.of(context);
var translations = widget.options.translations; var translations = options.translations;
return Stack( return Stack(
children: [ children: [
SingleChildScrollView( SingleChildScrollView(
@ -168,7 +159,7 @@ class _BodyState extends State<_Body> {
InkWell( InkWell(
onTap: () async => onPressSelectImage( onTap: () async => onPressSelectImage(
context, context,
widget.options, options,
(image) { (image) {
setState(() { setState(() {
this.image = image; this.image = image;
@ -322,7 +313,6 @@ class _BodyState extends State<_Body> {
...users.map( ...users.map(
(e) => _SelectedUser( (e) => _SelectedUser(
user: e, user: e,
options: widget.options,
onRemove: (user) { onRemove: (user) {
setState(() { setState(() {
users.remove(user); users.remove(user);
@ -387,47 +377,49 @@ class _BodyState extends State<_Body> {
class _SelectedUser extends StatelessWidget { class _SelectedUser extends StatelessWidget {
const _SelectedUser({ const _SelectedUser({
required this.user, required this.user,
required this.options,
required this.onRemove, required this.onRemove,
}); });
final UserModel user; final UserModel user;
final ChatOptions options;
final Function(UserModel) onRemove; final Function(UserModel) onRemove;
@override @override
Widget build(BuildContext context) => InkWell( Widget build(BuildContext context) {
onTap: () { var chatScope = ChatScope.of(context);
onRemove(user); var options = chatScope.options;
}, return InkWell(
child: Stack( onTap: () {
children: [ onRemove(user);
Padding( },
padding: const EdgeInsets.all(8), child: Stack(
child: options.builders.userAvatarBuilder?.call( children: [
context, Padding(
user, padding: const EdgeInsets.all(8),
40, child: options.builders.userAvatarBuilder?.call(
) ?? context,
Avatar( user,
boxfit: BoxFit.cover, 40,
user: User( ) ??
firstName: user.firstName, Avatar(
lastName: user.lastName, boxfit: BoxFit.cover,
imageUrl: user.imageUrl != "" ? user.imageUrl : null, user: User(
), firstName: user.firstName,
size: 40, lastName: user.lastName,
imageUrl: user.imageUrl != "" ? user.imageUrl : null,
), ),
size: 40,
),
),
Positioned.directional(
textDirection: Directionality.of(context),
end: 0,
child: const Icon(
Icons.cancel,
size: 20,
), ),
Positioned.directional( ),
textDirection: Directionality.of(context), ],
end: 0, ),
child: const Icon( );
Icons.cancel, }
size: 20,
),
),
],
),
);
} }

View file

@ -1,6 +1,5 @@
import "package:chat_repository_interface/chat_repository_interface.dart"; import "package:chat_repository_interface/chat_repository_interface.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_chat/src/config/chat_options.dart";
import "package:flutter_chat/src/config/screen_types.dart"; import "package:flutter_chat/src/config/screen_types.dart";
import "package:flutter_chat/src/screens/creation/widgets/search_field.dart"; import "package:flutter_chat/src/screens/creation/widgets/search_field.dart";
import "package:flutter_chat/src/screens/creation/widgets/search_icon.dart"; import "package:flutter_chat/src/screens/creation/widgets/search_icon.dart";
@ -38,18 +37,15 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context); var chatScope = ChatScope.of(context);
var chatOptions = chatScope.options; var options = chatScope.options;
var chatService = chatScope.service;
var userId = chatScope.userId;
useEffect(() { useEffect(() {
chatScope.popHandler.add(widget.onExit); chatScope.popHandler.add(widget.onExit);
return () => chatScope.popHandler.remove(widget.onExit); return () => chatScope.popHandler.remove(widget.onExit);
}); });
if (chatOptions.builders.baseScreenBuilder == null) { if (options.builders.baseScreenBuilder == null) {
return Scaffold( return Scaffold(
appBar: _AppBar( appBar: _AppBar(
chatOptions: chatOptions,
isSearching: _isSearching, isSearching: _isSearching,
onSearch: (query) { onSearch: (query) {
setState(() { setState(() {
@ -73,20 +69,16 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
onSelectedUser: handleUserTap, onSelectedUser: handleUserTap,
selectedUsers: selectedUsers, selectedUsers: selectedUsers,
onPressGroupChatOverview: widget.onContinue, onPressGroupChatOverview: widget.onContinue,
chatOptions: chatOptions,
chatService: chatService,
isSearching: _isSearching, isSearching: _isSearching,
userId: userId,
query: query, query: query,
), ),
); );
} }
return chatOptions.builders.baseScreenBuilder!.call( return options.builders.baseScreenBuilder!.call(
context, context,
widget.mapScreenType, widget.mapScreenType,
_AppBar( _AppBar(
chatOptions: chatOptions,
isSearching: _isSearching, isSearching: _isSearching,
onSearch: (query) { onSearch: (query) {
setState(() { setState(() {
@ -110,10 +102,7 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
onSelectedUser: handleUserTap, onSelectedUser: handleUserTap,
selectedUsers: selectedUsers, selectedUsers: selectedUsers,
onPressGroupChatOverview: widget.onContinue, onPressGroupChatOverview: widget.onContinue,
chatOptions: chatOptions,
chatService: chatService,
isSearching: _isSearching, isSearching: _isSearching,
userId: userId,
query: query, query: query,
), ),
); );
@ -134,14 +123,12 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
class _AppBar extends StatelessWidget implements PreferredSizeWidget { class _AppBar extends StatelessWidget implements PreferredSizeWidget {
const _AppBar({ const _AppBar({
required this.chatOptions,
required this.isSearching, required this.isSearching,
required this.onSearch, required this.onSearch,
required this.onPressedSearchIcon, required this.onPressedSearchIcon,
required this.focusNode, required this.focusNode,
}); });
final ChatOptions chatOptions;
final bool isSearching; final bool isSearching;
final Function(String) onSearch; final Function(String) onSearch;
final VoidCallback onPressedSearchIcon; final VoidCallback onPressedSearchIcon;
@ -149,17 +136,18 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context);
var options = chatScope.options;
var theme = Theme.of(context); var theme = Theme.of(context);
return AppBar( return AppBar(
iconTheme: theme.appBarTheme.iconTheme ?? iconTheme: theme.appBarTheme.iconTheme ??
const IconThemeData(color: Colors.white), const IconThemeData(color: Colors.white),
title: SearchField( title: SearchField(
chatOptions: chatOptions,
isSearching: isSearching, isSearching: isSearching,
onSearch: onSearch, onSearch: onSearch,
focusNode: focusNode, focusNode: focusNode,
text: chatOptions.translations.newGroupChatTitle, text: options.translations.newGroupChatTitle,
), ),
actions: [ actions: [
SearchIcon( SearchIcon(
@ -176,21 +164,15 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
class _Body extends StatelessWidget { class _Body extends StatelessWidget {
const _Body({ const _Body({
required this.chatOptions,
required this.chatService,
required this.isSearching, required this.isSearching,
required this.userId,
required this.query, required this.query,
required this.selectedUsers, required this.selectedUsers,
required this.onSelectedUser, required this.onSelectedUser,
required this.onPressGroupChatOverview, required this.onPressGroupChatOverview,
}); });
final ChatOptions chatOptions;
final ChatService chatService;
final bool isSearching; final bool isSearching;
final String userId;
final String query; final String query;
final List<UserModel> selectedUsers; final List<UserModel> selectedUsers;
@ -199,7 +181,11 @@ class _Body extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var translations = chatOptions.translations; var chatScope = ChatScope.of(context);
var service = chatScope.service;
var options = chatScope.options;
var userId = chatScope.userId;
var translations = options.translations;
var theme = Theme.of(context); var theme = Theme.of(context);
return Column( return Column(
@ -207,7 +193,7 @@ class _Body extends StatelessWidget {
Expanded( Expanded(
child: StreamBuilder<List<UserModel>>( child: StreamBuilder<List<UserModel>>(
// ignore: discarded_futures // ignore: discarded_futures
stream: chatService.getAllUsers(), stream: service.getAllUsers(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
@ -220,7 +206,6 @@ class _Body extends StatelessWidget {
users: snapshot.data!, users: snapshot.data!,
currentUser: userId, currentUser: userId,
query: query, query: query,
options: chatOptions,
onPressCreateChat: null, onPressCreateChat: null,
creatingGroup: true, creatingGroup: true,
selectedUsers: selectedUsers, selectedUsers: selectedUsers,
@ -229,12 +214,11 @@ class _Body extends StatelessWidget {
_NextButton( _NextButton(
selectedUsers: selectedUsers, selectedUsers: selectedUsers,
onPressGroupChatOverview: onPressGroupChatOverview, onPressGroupChatOverview: onPressGroupChatOverview,
chatOptions: chatOptions,
), ),
], ],
); );
} else { } else {
return chatOptions.builders.noUsersPlaceholderBuilder return options.builders.noUsersPlaceholderBuilder
?.call(context, translations) ?? ?.call(context, translations) ??
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 20), padding: const EdgeInsets.symmetric(vertical: 20),
@ -260,15 +244,15 @@ class _NextButton extends StatelessWidget {
const _NextButton({ const _NextButton({
required this.onPressGroupChatOverview, required this.onPressGroupChatOverview,
required this.selectedUsers, required this.selectedUsers,
required this.chatOptions,
}); });
final Function(List<UserModel>) onPressGroupChatOverview; final Function(List<UserModel>) onPressGroupChatOverview;
final List<UserModel> selectedUsers; final List<UserModel> selectedUsers;
final ChatOptions chatOptions;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context);
var options = chatScope.options;
var theme = Theme.of(context); var theme = Theme.of(context);
return Align( return Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
@ -287,7 +271,7 @@ class _NextButton extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
chatOptions.translations.next, options.translations.next,
style: theme.textTheme.displayLarge, style: theme.textTheme.displayLarge,
), ),
], ],

View file

@ -1,11 +1,10 @@
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_chat/src/config/chat_options.dart"; import "package:flutter_chat/src/util/scope.dart";
/// The search field widget /// The search field widget
class SearchField extends StatelessWidget { class SearchField extends StatelessWidget {
/// Constructs a [SearchField] /// Constructs a [SearchField]
const SearchField({ const SearchField({
required this.chatOptions,
required this.isSearching, required this.isSearching,
required this.onSearch, required this.onSearch,
required this.focusNode, required this.focusNode,
@ -13,9 +12,6 @@ class SearchField extends StatelessWidget {
super.key, super.key,
}); });
/// The chat options
final ChatOptions chatOptions;
/// Whether the search field is currently in use /// Whether the search field is currently in use
final bool isSearching; final bool isSearching;
@ -30,8 +26,10 @@ class SearchField extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context);
var options = chatScope.options;
var theme = Theme.of(context); var theme = Theme.of(context);
var translations = chatOptions.translations; var translations = options.translations;
if (isSearching) { if (isSearching) {
return TextField( return TextField(

View file

@ -1,6 +1,6 @@
import "package:chat_repository_interface/chat_repository_interface.dart"; import "package:chat_repository_interface/chat_repository_interface.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_chat/src/config/chat_options.dart"; import "package:flutter_chat/src/util/scope.dart";
import "package:flutter_profile/flutter_profile.dart"; import "package:flutter_profile/flutter_profile.dart";
/// The user list widget /// The user list widget
@ -10,7 +10,6 @@ class UserList extends StatefulWidget {
required this.users, required this.users,
required this.currentUser, required this.currentUser,
required this.query, required this.query,
required this.options,
required this.onPressCreateChat, required this.onPressCreateChat,
this.creatingGroup = false, this.creatingGroup = false,
this.selectedUsers = const [], this.selectedUsers = const [],
@ -27,9 +26,6 @@ class UserList extends StatefulWidget {
/// The current user /// The current user
final String currentUser; final String currentUser;
/// The chat options
final ChatOptions options;
/// Whether the user is creating a group /// Whether the user is creating a group
final bool creatingGroup; final bool creatingGroup;
@ -60,8 +56,11 @@ class _UserListState extends State<UserList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var chatScope = ChatScope.of(context);
var options = chatScope.options;
var theme = Theme.of(context); var theme = Theme.of(context);
var translations = widget.options.translations;
var translations = options.translations;
filteredUsers = widget.query.isNotEmpty filteredUsers = widget.query.isNotEmpty
? users ? users
.where( .where(
@ -88,11 +87,11 @@ class _UserListState extends State<UserList> {
return handlePersonalChatTap(user); return handlePersonalChatTap(user);
} }
}, },
child: widget.options.builders.chatRowContainerBuilder?.call( child: options.builders.chatRowContainerBuilder?.call(
context, context,
Row( Row(
children: [ children: [
widget.options.builders.userAvatarBuilder options.builders.userAvatarBuilder
?.call(context, user, 44) ?? ?.call(context, user, 44) ??
Avatar( Avatar(
boxfit: BoxFit.cover, boxfit: BoxFit.cover,
@ -140,7 +139,7 @@ class _UserListState extends State<UserList> {
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: Row( child: Row(
children: [ children: [
widget.options.builders.userAvatarBuilder options.builders.userAvatarBuilder
?.call(context, user, 44) ?? ?.call(context, user, 44) ??
Avatar( Avatar(
boxfit: BoxFit.cover, boxfit: BoxFit.cover,