feat: show amount of unread messages

This commit is contained in:
Freek van de Ven 2023-10-27 16:16:42 +02:00
parent f6a2a26def
commit 5e41f3885f
6 changed files with 150 additions and 35 deletions

View file

@ -29,6 +29,24 @@ class FirebaseChatService implements ChatService {
_options = options ?? const FirebaseChatOptions();
}
StreamSubscription<DocumentSnapshot> _addUnreadChatSubscription(
String chatId,
String userId,
Function(int) onUnreadChatsUpdated,
) {
var snapshots = _db
.collection(_options.usersCollectionName)
.doc(userId)
.collection('chats')
.doc(chatId)
.snapshots();
return snapshots.listen((snapshot) {
var data = snapshot.data();
onUnreadChatsUpdated(data?['amount_unread_messages'] ?? 0);
});
}
StreamSubscription<QuerySnapshot> _addChatSubscription(
List<String> chatIds,
Function(List<ChatModel>) onReceivedChats,
@ -79,6 +97,8 @@ class FirebaseChatService implements ChatService {
);
}
}
ChatModel? chatModel;
if (chatData.personal) {
var otherUserId = List<String>.from(chatData.users).firstWhere(
(element) => element != currentUser?.id,
@ -86,8 +106,7 @@ class FirebaseChatService implements ChatService {
var otherUser = await _userService.getUser(otherUserId);
if (otherUser != null) {
chats.add(
PersonalChatModel(
chatModel = PersonalChatModel(
id: chatDoc.id,
user: otherUser,
lastMessage: messages.isNotEmpty ? messages.last : null,
@ -97,7 +116,6 @@ class FirebaseChatService implements ChatService {
: DateTime.fromMillisecondsSinceEpoch(
chatData.lastUsed!.millisecondsSinceEpoch,
),
),
);
}
} else {
@ -109,8 +127,7 @@ class FirebaseChatService implements ChatService {
users.add(user);
}
}
chats.add(
GroupChatModel(
chatModel = GroupChatModel(
id: chatDoc.id,
title: chatData.title ?? '',
imageUrl: chatData.imageUrl ?? '',
@ -122,9 +139,27 @@ class FirebaseChatService implements ChatService {
: DateTime.fromMillisecondsSinceEpoch(
chatData.lastUsed!.millisecondsSinceEpoch,
),
),
);
}
if (chatModel != null) {
_addUnreadChatSubscription(chatModel.id ?? '', currentUser?.id ?? '',
(unreadMessages) {
// the chatmodel should be updated to reflect the amount of unread messages
if (chatModel is PersonalChatModel) {
chatModel = (chatModel as PersonalChatModel)
.copyWith(unreadMessages: unreadMessages);
} else if (chatModel is GroupChatModel) {
chatModel = (chatModel as GroupChatModel)
.copyWith(unreadMessages: unreadMessages);
}
chats = chats
.map((chat) => chat.id == chatModel?.id ? chatModel! : chat)
.toList();
onReceivedChats(chats);
});
chats.add(chatModel!);
}
}
onReceivedChats(chats);
});

View file

@ -8,12 +8,14 @@ abstract class ChatModel {
ChatModel({
this.id,
this.messages = const [],
this.unreadMessages,
this.lastUsed,
this.lastMessage,
});
String? id;
List<ChatMessageModel>? messages;
int? unreadMessages;
DateTime? lastUsed;
ChatMessageModel? lastMessage;
}

View file

@ -13,9 +13,31 @@ class GroupChatModel extends ChatModel {
super.messages,
super.lastUsed,
super.lastMessage,
super.unreadMessages,
});
final String title;
final String imageUrl;
final List<ChatUserModel> users;
GroupChatModel copyWith({
String? id,
List<ChatMessageModel>? messages,
int? unreadMessages,
DateTime? lastUsed,
ChatMessageModel? lastMessage,
String? title,
String? imageUrl,
List<ChatUserModel>? users,
}) =>
GroupChatModel(
id: id ?? this.id,
messages: messages ?? this.messages,
unreadMessages: unreadMessages ?? this.unreadMessages,
lastUsed: lastUsed ?? this.lastUsed,
lastMessage: lastMessage ?? this.lastMessage,
title: title ?? this.title,
imageUrl: imageUrl ?? this.imageUrl,
users: users ?? this.users,
);
}

View file

@ -9,9 +9,27 @@ class PersonalChatModel extends ChatModel {
required this.user,
super.id,
super.messages,
super.unreadMessages,
super.lastUsed,
super.lastMessage,
});
final ChatUserModel user;
PersonalChatModel copyWith({
String? id,
List<ChatMessageModel>? messages,
int? unreadMessages,
DateTime? lastUsed,
ChatMessageModel? lastMessage,
ChatUserModel? user,
}) =>
PersonalChatModel(
id: id ?? this.id,
messages: messages ?? this.messages,
unreadMessages: unreadMessages ?? this.unreadMessages,
lastUsed: lastUsed ?? this.lastUsed,
lastMessage: lastMessage ?? this.lastMessage,
user: user ?? this.user,
);
}

View file

@ -7,12 +7,14 @@ import 'package:flutter/material.dart';
class ChatRow extends StatelessWidget {
const ChatRow({
required this.title,
this.unreadMessages = 0,
this.lastUsed,
this.subTitle,
this.avatar,
super.key,
});
final String title;
final int unreadMessages;
final Widget? avatar;
final String? subTitle;
final String? lastUsed;
@ -35,9 +37,11 @@ class ChatRow extends StatelessWidget {
title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
fontWeight: unreadMessages > 0
? FontWeight.w600
: FontWeight.w400,
),
),
if (subTitle != null)
@ -45,8 +49,11 @@ class ChatRow extends StatelessWidget {
padding: const EdgeInsets.only(top: 3.0),
child: Text(
subTitle!,
style: const TextStyle(
style: TextStyle(
fontSize: 16,
fontWeight: unreadMessages > 0
? FontWeight.w600
: FontWeight.w400,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
@ -56,6 +63,10 @@ class ChatRow extends StatelessWidget {
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
lastUsed ?? '',
style: const TextStyle(
@ -63,6 +74,29 @@ class ChatRow extends StatelessWidget {
fontSize: 14,
),
),
if (unreadMessages > 0) ...[
Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
shape: BoxShape.circle,
),
child: Center(
child: Text(
unreadMessages.toString(),
style: const TextStyle(
fontSize: 14,
),
),
),
),
),
],
],
),
],
);
}

View file

@ -99,6 +99,8 @@ class _ChatScreenState extends State<ChatScreen> {
child: widget.options.chatRowContainerBuilder(
(chat is PersonalChatModel)
? ChatRow(
unreadMessages:
chat.unreadMessages ?? 0,
avatar:
widget.options.userAvatarBuilder(
chat.user,
@ -122,6 +124,8 @@ class _ChatScreenState extends State<ChatScreen> {
)
: ChatRow(
title: (chat as GroupChatModel).title,
unreadMessages:
chat.unreadMessages ?? 0,
subTitle: chat.lastMessage != null
? chat.lastMessage
is ChatTextMessageModel