feat: change ChatService and ChatScope to work the same as in flutter_availability

The userid should be managed inside of the service and it should come from the ChatOptions
This commit is contained in:
Freek van de Ven 2025-02-12 08:53:58 +01:00 committed by Bart Ribbers
parent 9af9bc8078
commit 52e3e570dd
6 changed files with 62 additions and 60 deletions

View file

@ -16,11 +16,15 @@ import "package:collection/collection.dart";
class ChatService {
/// Create a chat service with the given parameters.
ChatService({
required this.userId,
ChatRepositoryInterface? chatRepository,
UserRepositoryInterface? userRepository,
}) : chatRepository = chatRepository ?? LocalChatRepository(),
userRepository = userRepository ?? LocalUserRepository();
/// The user ID of the person currently looking at the chat
final String userId;
/// The chat repository
final ChatRepositoryInterface chatRepository;
@ -54,11 +58,9 @@ class ChatService {
);
}
/// Get the chats for the given [userId].
/// Get the chats for the user with the given [userId].
/// Returns a list of [ChatModel] stream.
Stream<List<ChatModel>?> getChats({
required String userId,
}) =>
Stream<List<ChatModel>?> getChats() =>
chatRepository.getChats(userId: userId);
/// Get the chat with the given [chatId].
@ -129,11 +131,9 @@ class ChatService {
/// Returns a list of [MessageModel] stream.
/// [pageSize] is the number of messages to be fetched.
/// [page] is the page number.
/// [userId] is the user id.
/// [chatId] is the chat id.
/// Returns a list of [MessageModel] stream.
Stream<List<MessageModel>?> getMessages({
required String userId,
required String chatId,
required int pageSize,
required int page,
@ -183,15 +183,14 @@ class ChatService {
/// Returns a list of [UserModel] stream.
Stream<List<UserModel>> getAllUsers() => userRepository.getAllUsers();
/// Get the unread messages count for the given [userId] and or [chatId].
/// [userId] is the user id.
/// Get the unread messages count for a user [chatId].
/// [chatId] is the chat id. If not provided, it will return the
/// total unread messages count.
/// Returns a [Stream] of [int].
Stream<int> getUnreadMessagesCount({
required String userId,
String? chatId,
}) =>
chatRepository.getUnreadMessagesCount(userId: userId);
chatRepository.getUnreadMessagesCount(userId: userId, chatId: chatId);
/// Upload an image with the given parameters.
/// [path] is the image path.
@ -211,7 +210,6 @@ class ChatService {
/// Returns a [Future] of [void].
Future<void> markAsRead({
required String chatId,
required String userId,
}) async {
var chat = await chatRepository.getChat(chatId: chatId).first;

View file

@ -7,7 +7,7 @@ import "package:flutter_chat/src/config/chat_translations.dart";
/// Use this class to configure the chat options.
class ChatOptions {
/// The chat options constructor
const ChatOptions({
ChatOptions({
this.dateformat,
this.groupChatEnabled = true,
this.enableLoadingIndicator = false,
@ -21,7 +21,16 @@ class ChatOptions {
this.chatAlignment,
this.onNoChats,
this.pageSize = 20,
});
ChatRepositoryInterface? chatRepository,
UserRepositoryInterface? userRepository,
}) : chatRepository = chatRepository ?? LocalChatRepository(),
userRepository = userRepository ?? LocalUserRepository();
/// The implementation for communication with persistance layer for chats
final ChatRepositoryInterface chatRepository;
/// The implementation for communication with persistance layer for users
final UserRepositoryInterface userRepository;
/// [dateformat] is a function that formats the date.
// ignore: avoid_positional_boolean_parameters

View file

@ -8,7 +8,6 @@ class FlutterChatEntryWidget extends StatefulWidget {
/// Constructs a [FlutterChatEntryWidget].
const FlutterChatEntryWidget({
required this.userId,
this.chatService,
this.options,
this.onTap,
this.widgetSize = 75,
@ -20,9 +19,6 @@ class FlutterChatEntryWidget extends StatefulWidget {
super.key,
});
/// The chat service associated with the widget.
final ChatService? chatService;
/// The user ID of the person currently looking at the chat
final String userId;
@ -56,12 +52,29 @@ class FlutterChatEntryWidget extends StatefulWidget {
/// State class for [FlutterChatEntryWidget].
class _FlutterChatEntryWidgetState extends State<FlutterChatEntryWidget> {
ChatService? chatService;
late ChatService chatService;
@override
void initState() {
super.initState();
chatService ??= widget.chatService ?? ChatService();
_initChatService();
}
@override
void didUpdateWidget(covariant FlutterChatEntryWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.userId != widget.userId ||
oldWidget.options != widget.options) {
_initChatService();
}
}
void _initChatService() {
chatService = ChatService(
userId: widget.userId,
chatRepository: widget.options?.chatRepository,
userRepository: widget.options?.userRepository,
);
}
@override
@ -72,13 +85,12 @@ class _FlutterChatEntryWidgetState extends State<FlutterChatEntryWidget> {
MaterialPageRoute(
builder: (context) => FlutterChatNavigatorUserstory(
userId: widget.userId,
chatService: chatService,
chatOptions: widget.options,
options: widget.options ?? ChatOptions(),
),
),
),
child: StreamBuilder<int>(
stream: chatService!.getUnreadMessagesCount(userId: widget.userId),
stream: chatService.getUnreadMessagesCount(),
builder: (BuildContext context, snapshot) => Stack(
alignment: Alignment.center,
children: [

View file

@ -25,19 +25,15 @@ class FlutterChatNavigatorUserstory extends StatefulWidget {
/// Constructs a [FlutterChatNavigatorUserstory].
const FlutterChatNavigatorUserstory({
required this.userId,
this.chatService,
this.chatOptions,
required this.options,
super.key,
});
/// The user ID of the person currently looking at the chat
final String userId;
/// The chat service associated with the widget.
final ChatService? chatService;
/// The chat options
final ChatOptions? chatOptions;
final ChatOptions options;
@override
State<FlutterChatNavigatorUserstory> createState() =>
@ -46,14 +42,18 @@ class FlutterChatNavigatorUserstory extends StatefulWidget {
class _FlutterChatNavigatorUserstoryState
extends State<FlutterChatNavigatorUserstory> {
late ChatService _service = widget.chatService ?? ChatService();
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.chatOptions ?? const ChatOptions(),
options: widget.options,
service: _service,
popHandler: _popHandler,
child: NavigatorPopHandler(
@ -67,7 +67,7 @@ class _FlutterChatNavigatorUserstoryState
builder: (context) => _NavigatorWrapper(
userId: widget.userId,
chatService: _service,
chatOptions: widget.chatOptions ?? const ChatOptions(),
chatOptions: widget.options,
),
),
),
@ -79,9 +79,13 @@ class _FlutterChatNavigatorUserstoryState
super.didUpdateWidget(oldWidget);
if (oldWidget.userId != widget.userId ||
oldWidget.chatOptions != widget.chatOptions) {
oldWidget.options != widget.options) {
setState(() {
_service = widget.chatService ?? ChatService();
_service = ChatService(
userId: widget.userId,
chatRepository: widget.options.chatRepository,
userRepository: widget.options.userRepository,
);
});
}
}
@ -102,7 +106,6 @@ class _NavigatorWrapper extends StatelessWidget {
Widget build(BuildContext context) => chatScreen(context);
Widget chatScreen(BuildContext context) => ChatScreen(
userId: userId,
chatService: chatService,
chatOptions: chatOptions,
onPressChat: (chat) => route(context, chatDetailScreen(context, chat)),
@ -115,8 +118,7 @@ class _NavigatorWrapper extends StatelessWidget {
Widget chatDetailScreen(BuildContext context, ChatModel chat) =>
ChatDetailScreen(
chat: chat,
onReadChat: (chat) async =>
chatService.markAsRead(chatId: chat.id, userId: userId),
onReadChat: (chat) async => chatService.markAsRead(chatId: chat.id),
onPressChatTitle: (chat) async {
if (chat.isGroupChat) {
return route(context, chatProfileScreen(context, null, chat));

View file

@ -204,7 +204,6 @@ class _BodyState extends State<_Body> {
var chatScope = ChatScope.of(context);
var options = chatScope.options;
var service = chatScope.service;
var userId = chatScope.userId;
void handleScroll(PointerMoveEvent event) {
if (!showIndicator &&
@ -233,7 +232,6 @@ class _BodyState extends State<_Body> {
alignment: options.chatAlignment ?? Alignment.bottomCenter,
child: StreamBuilder<List<MessageModel>?>(
stream: service.getMessages(
userId: userId,
chatId: widget.chat.id,
pageSize: pageSize,
page: page,

View file

@ -4,6 +4,7 @@ import "package:flutter_chat/src/config/chat_options.dart";
import "package:flutter_chat/src/config/chat_translations.dart";
import "package:flutter_chat/src/config/screen_types.dart";
import "package:flutter_chat/src/services/date_formatter.dart";
import "package:flutter_chat/src/util/scope.dart";
import "package:flutter_profile/flutter_profile.dart";
/// The chat screen
@ -11,7 +12,6 @@ import "package:flutter_profile/flutter_profile.dart";
class ChatScreen extends StatelessWidget {
/// Constructs a [ChatScreen]
const ChatScreen({
required this.userId,
required this.chatService,
required this.chatOptions,
required this.onPressChat,
@ -20,9 +20,6 @@ class ChatScreen extends StatelessWidget {
super.key,
});
/// The user ID of the person currently looking at the chat
final String userId;
/// The chat service
final ChatService chatService;
@ -43,12 +40,10 @@ class ChatScreen extends StatelessWidget {
if (chatOptions.builders.baseScreenBuilder == null) {
return Scaffold(
appBar: _AppBar(
userId: userId,
chatOptions: chatOptions,
chatService: chatService,
),
body: _Body(
userId: userId,
chatOptions: chatOptions,
chatService: chatService,
onPressChat: onPressChat,
@ -62,12 +57,10 @@ class ChatScreen extends StatelessWidget {
context,
mapScreenType,
_AppBar(
userId: userId,
chatOptions: chatOptions,
chatService: chatService,
),
_Body(
userId: userId,
chatOptions: chatOptions,
chatService: chatService,
onPressChat: onPressChat,
@ -80,12 +73,10 @@ class ChatScreen extends StatelessWidget {
class _AppBar extends StatelessWidget implements PreferredSizeWidget {
const _AppBar({
required this.userId,
required this.chatOptions,
required this.chatService,
});
final String userId;
final ChatOptions chatOptions;
final ChatService chatService;
@ -100,7 +91,7 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
),
actions: [
StreamBuilder<int>(
stream: chatService.getUnreadMessagesCount(userId: userId),
stream: chatService.getUnreadMessagesCount(),
builder: (BuildContext context, snapshot) => Align(
alignment: Alignment.centerRight,
child: Visibility(
@ -127,7 +118,6 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
class _Body extends StatefulWidget {
const _Body({
required this.userId,
required this.chatOptions,
required this.chatService,
required this.onPressChat,
@ -135,7 +125,6 @@ class _Body extends StatefulWidget {
this.onPressStartChat,
});
final String userId;
final ChatOptions chatOptions;
final ChatService chatService;
final Function(ChatModel chat) onPressChat;
@ -163,7 +152,7 @@ class _BodyState extends State<_Body> {
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 28),
children: [
StreamBuilder<List<ChatModel>?>(
stream: widget.chatService.getChats(userId: widget.userId),
stream: widget.chatService.getChats(),
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
(snapshot.data?.isEmpty ?? true) ||
@ -251,7 +240,6 @@ class _BodyState extends State<_Body> {
service: widget.chatService,
chat: chat,
chatOptions: widget.chatOptions,
userId: widget.userId,
onPressChat: widget.onPressChat,
),
)
@ -259,7 +247,6 @@ class _BodyState extends State<_Body> {
service: widget.chatService,
chat: chat,
chatOptions: widget.chatOptions,
userId: widget.userId,
onPressChat: widget.onPressChat,
),
),
@ -308,14 +295,12 @@ class _ChatItem extends StatelessWidget {
required this.chat,
required this.chatOptions,
required this.service,
required this.userId,
required this.onPressChat,
});
final ChatModel chat;
final ChatOptions chatOptions;
final ChatService service;
final String userId;
final Function(ChatModel chat) onPressChat;
@override
@ -335,7 +320,6 @@ class _ChatItem extends StatelessWidget {
options: chatOptions,
dateFormatter: dateFormatter,
chatService: service,
currentUserId: userId,
),
) ??
DecoratedBox(
@ -355,7 +339,6 @@ class _ChatItem extends StatelessWidget {
options: chatOptions,
dateFormatter: dateFormatter,
chatService: service,
currentUserId: userId,
),
),
),
@ -368,18 +351,18 @@ class _ChatListItem extends StatelessWidget {
required this.chat,
required this.options,
required this.dateFormatter,
required this.currentUserId,
required this.chatService,
});
final ChatModel chat;
final ChatOptions options;
final DateFormatter dateFormatter;
final String currentUserId;
final ChatService chatService;
@override
Widget build(BuildContext context) {
var scope = ChatScope.of(context);
var currentUserId = scope.userId;
var translations = options.translations;
if (chat.isGroupChat) {
return StreamBuilder<MessageModel?>(