feat(chat-options): add pending messages option

This commit is contained in:
Kiril Tijsma 2025-03-11 10:26:42 +01:00
parent 9d7ca39f49
commit 6fbe1e67d2
8 changed files with 72 additions and 26 deletions

View file

@ -73,6 +73,12 @@ abstract class ChatRepositoryInterface {
required MessageModel firstMessage, required MessageModel firstMessage,
}); });
/// Function that provides the next message id
Future<String> getNextMessageId({
required String userId,
required String chatId,
});
/// Send a message with the given parameters. /// Send a message with the given parameters.
/// [chatId] is the chat id. /// [chatId] is the chat id.
/// [senderId] is the sender id. /// [senderId] is the sender id.

View file

@ -208,6 +208,13 @@ class LocalChatRepository implements ChatRepositoryInterface {
return Stream.value(message); return Stream.value(message);
} }
@override
Future<String> getNextMessageId({
required String userId,
required String chatId,
}) async =>
"$chatId-$userId-${DateTime.now()}";
@override @override
Future<void> sendMessage({ Future<void> sendMessage({
required String chatId, required String chatId,

View file

@ -25,9 +25,9 @@ class ChatService {
PendingMessageRepositoryInterface? pendingMessageRepository, PendingMessageRepositoryInterface? pendingMessageRepository,
UserRepositoryInterface? userRepository, UserRepositoryInterface? userRepository,
}) : chatRepository = chatRepository ?? LocalChatRepository(), }) : chatRepository = chatRepository ?? LocalChatRepository(),
userRepository = userRepository ?? LocalUserRepository(),
pendingMessageRepository = pendingMessageRepository =
pendingMessageRepository ?? LocalPendingMessageRepository(), pendingMessageRepository ?? LocalPendingMessageRepository();
userRepository = userRepository ?? LocalUserRepository();
/// The user ID of the person currently looking at the chat /// The user ID of the person currently looking at the chat
final String userId; final String userId;
@ -200,12 +200,15 @@ class ChatService {
Future<void> sendMessage({ Future<void> sendMessage({
required String chatId, required String chatId,
required String senderId, required String senderId,
required String messageId, String? presetMessageId,
String? text, String? text,
String? messageType, String? messageType,
String? imageUrl, String? imageUrl,
Uint8List? imageData, Uint8List? imageData,
}) async { }) async {
var messageId = presetMessageId ??
await chatRepository.getNextMessageId(userId: userId, chatId: chatId);
await pendingMessageRepository.createMessage( await pendingMessageRepository.createMessage(
chatId: chatId, chatId: chatId,
senderId: senderId, senderId: senderId,
@ -239,6 +242,32 @@ class ChatService {
); );
} }
/// Method for sending an image and a message at the same time.
Future<void> sendImageMessage({
required String chatId,
required String userId,
required Uint8List data,
}) async {
var messageId = await chatRepository.getNextMessageId(
userId: userId,
chatId: chatId,
);
var path = await uploadImage(
path: "chats/$messageId",
image: data,
chatId: chatId,
);
await sendMessage(
presetMessageId: messageId,
chatId: chatId,
senderId: userId,
imageUrl: path,
imageData: data,
);
}
/// Delete the chat with the given parameters. /// Delete the chat with the given parameters.
/// [chatId] is the chat id. /// [chatId] is the chat id.
Future<void> deleteChat({ Future<void> deleteChat({

View file

@ -140,6 +140,13 @@ class FirebaseChatRepository implements ChatRepositoryInterface {
} }
} }
@override
Future<String> getNextMessageId({
required String userId,
required String chatId,
}) async =>
"$chatId-$userId-${DateTime.now()}";
@override @override
Future<void> sendMessage({ Future<void> sendMessage({
required String chatId, required String chatId,

View file

@ -29,12 +29,19 @@ class ChatOptions {
this.timeIndicatorOptions = const ChatTimeIndicatorOptions(), this.timeIndicatorOptions = const ChatTimeIndicatorOptions(),
ChatRepositoryInterface? chatRepository, ChatRepositoryInterface? chatRepository,
UserRepositoryInterface? userRepository, UserRepositoryInterface? userRepository,
PendingMessageRepositoryInterface? pendingMessagesRepository,
}) : chatRepository = chatRepository ?? LocalChatRepository(), }) : chatRepository = chatRepository ?? LocalChatRepository(),
userRepository = userRepository ?? LocalUserRepository(); userRepository = userRepository ?? LocalUserRepository(),
pendingMessagesRepository =
pendingMessagesRepository ?? LocalPendingMessageRepository();
/// The implementation for communication with persistance layer for chats /// The implementation for communication with persistance layer for chats
final ChatRepositoryInterface chatRepository; final ChatRepositoryInterface chatRepository;
/// The implementation for communication with persistance layer
/// for pending messages
final PendingMessageRepositoryInterface pendingMessagesRepository;
/// The implementation for communication with persistance layer for users /// The implementation for communication with persistance layer for users
final UserRepositoryInterface userRepository; final UserRepositoryInterface userRepository;

View file

@ -83,6 +83,7 @@ class _FlutterChatEntryWidgetState extends State<FlutterChatEntryWidget> {
userId: widget.userId, userId: widget.userId,
chatRepository: widget.options?.chatRepository, chatRepository: widget.options?.chatRepository,
userRepository: widget.options?.userRepository, userRepository: widget.options?.userRepository,
pendingMessageRepository: widget.options?.pendingMessagesRepository,
); );
} }

View file

@ -94,6 +94,7 @@ abstract class _BaseChatNavigatorUserstory extends HookWidget {
userId: userId, userId: userId,
chatRepository: options.chatRepository, chatRepository: options.chatRepository,
userRepository: options.userRepository, userRepository: options.userRepository,
pendingMessageRepository: options.pendingMessagesRepository,
), ),
[userId, options], [userId, options],
); );

View file

@ -50,28 +50,16 @@ MaterialPageRoute chatDetailRoute({
chatId: chatId, chatId: chatId,
onExit: onExit, onExit: onExit,
onReadChat: (chat) async => chatService.markAsRead(chatId: chat.id), onReadChat: (chat) async => chatService.markAsRead(chatId: chat.id),
onUploadImage: (data) async { onUploadImage: (data) async => chatService.sendImageMessage(
var path = await chatService.uploadImage( chatId: chatId,
path: "chats/$chatId-$userId-${DateTime.now()}", userId: userId,
image: data, data: data,
chatId: chatId, ),
); onMessageSubmit: (text) async => chatService.sendMessage(
await chatService.sendMessage( chatId: chatId,
messageId: "$chatId-$userId-${DateTime.now()}", senderId: userId,
chatId: chatId, text: text,
senderId: userId, ),
imageUrl: path,
imageData: data,
);
},
onMessageSubmit: (text) async {
await chatService.sendMessage(
messageId: "$chatId-$userId-${DateTime.now()}",
chatId: chatId,
senderId: userId,
text: text,
);
},
onPressChatTitle: (chat) async { onPressChatTitle: (chat) async {
if (chat.isGroupChat) { if (chat.isGroupChat) {
await _routeToScreen( await _routeToScreen(