mirror of
https://github.com/Iconica-Development/flutter_chat.git
synced 2025-05-19 10:53:51 +02:00
feat: show amount of unread messages
This commit is contained in:
parent
f6a2a26def
commit
5e41f3885f
6 changed files with 150 additions and 35 deletions
|
@ -29,6 +29,24 @@ class FirebaseChatService implements ChatService {
|
||||||
_options = options ?? const FirebaseChatOptions();
|
_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(
|
StreamSubscription<QuerySnapshot> _addChatSubscription(
|
||||||
List<String> chatIds,
|
List<String> chatIds,
|
||||||
Function(List<ChatModel>) onReceivedChats,
|
Function(List<ChatModel>) onReceivedChats,
|
||||||
|
@ -79,6 +97,8 @@ class FirebaseChatService implements ChatService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ChatModel? chatModel;
|
||||||
|
|
||||||
if (chatData.personal) {
|
if (chatData.personal) {
|
||||||
var otherUserId = List<String>.from(chatData.users).firstWhere(
|
var otherUserId = List<String>.from(chatData.users).firstWhere(
|
||||||
(element) => element != currentUser?.id,
|
(element) => element != currentUser?.id,
|
||||||
|
@ -86,18 +106,16 @@ class FirebaseChatService implements ChatService {
|
||||||
var otherUser = await _userService.getUser(otherUserId);
|
var otherUser = await _userService.getUser(otherUserId);
|
||||||
|
|
||||||
if (otherUser != null) {
|
if (otherUser != null) {
|
||||||
chats.add(
|
chatModel = PersonalChatModel(
|
||||||
PersonalChatModel(
|
id: chatDoc.id,
|
||||||
id: chatDoc.id,
|
user: otherUser,
|
||||||
user: otherUser,
|
lastMessage: messages.isNotEmpty ? messages.last : null,
|
||||||
lastMessage: messages.isNotEmpty ? messages.last : null,
|
messages: messages,
|
||||||
messages: messages,
|
lastUsed: chatData.lastUsed == null
|
||||||
lastUsed: chatData.lastUsed == null
|
? null
|
||||||
? null
|
: DateTime.fromMillisecondsSinceEpoch(
|
||||||
: DateTime.fromMillisecondsSinceEpoch(
|
chatData.lastUsed!.millisecondsSinceEpoch,
|
||||||
chatData.lastUsed!.millisecondsSinceEpoch,
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,22 +127,39 @@ class FirebaseChatService implements ChatService {
|
||||||
users.add(user);
|
users.add(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chats.add(
|
chatModel = GroupChatModel(
|
||||||
GroupChatModel(
|
id: chatDoc.id,
|
||||||
id: chatDoc.id,
|
title: chatData.title ?? '',
|
||||||
title: chatData.title ?? '',
|
imageUrl: chatData.imageUrl ?? '',
|
||||||
imageUrl: chatData.imageUrl ?? '',
|
lastMessage: messages.isNotEmpty ? messages.last : null,
|
||||||
lastMessage: messages.isNotEmpty ? messages.last : null,
|
messages: messages,
|
||||||
messages: messages,
|
users: users,
|
||||||
users: users,
|
lastUsed: chatData.lastUsed == null
|
||||||
lastUsed: chatData.lastUsed == null
|
? null
|
||||||
? null
|
: DateTime.fromMillisecondsSinceEpoch(
|
||||||
: DateTime.fromMillisecondsSinceEpoch(
|
chatData.lastUsed!.millisecondsSinceEpoch,
|
||||||
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);
|
onReceivedChats(chats);
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,12 +8,14 @@ abstract class ChatModel {
|
||||||
ChatModel({
|
ChatModel({
|
||||||
this.id,
|
this.id,
|
||||||
this.messages = const [],
|
this.messages = const [],
|
||||||
|
this.unreadMessages,
|
||||||
this.lastUsed,
|
this.lastUsed,
|
||||||
this.lastMessage,
|
this.lastMessage,
|
||||||
});
|
});
|
||||||
|
|
||||||
String? id;
|
String? id;
|
||||||
List<ChatMessageModel>? messages;
|
List<ChatMessageModel>? messages;
|
||||||
|
int? unreadMessages;
|
||||||
DateTime? lastUsed;
|
DateTime? lastUsed;
|
||||||
ChatMessageModel? lastMessage;
|
ChatMessageModel? lastMessage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,31 @@ class GroupChatModel extends ChatModel {
|
||||||
super.messages,
|
super.messages,
|
||||||
super.lastUsed,
|
super.lastUsed,
|
||||||
super.lastMessage,
|
super.lastMessage,
|
||||||
|
super.unreadMessages,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
final String imageUrl;
|
final String imageUrl;
|
||||||
final List<ChatUserModel> users;
|
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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,27 @@ class PersonalChatModel extends ChatModel {
|
||||||
required this.user,
|
required this.user,
|
||||||
super.id,
|
super.id,
|
||||||
super.messages,
|
super.messages,
|
||||||
|
super.unreadMessages,
|
||||||
super.lastUsed,
|
super.lastUsed,
|
||||||
super.lastMessage,
|
super.lastMessage,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ChatUserModel user;
|
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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,14 @@ import 'package:flutter/material.dart';
|
||||||
class ChatRow extends StatelessWidget {
|
class ChatRow extends StatelessWidget {
|
||||||
const ChatRow({
|
const ChatRow({
|
||||||
required this.title,
|
required this.title,
|
||||||
|
this.unreadMessages = 0,
|
||||||
this.lastUsed,
|
this.lastUsed,
|
||||||
this.subTitle,
|
this.subTitle,
|
||||||
this.avatar,
|
this.avatar,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
final String title;
|
final String title;
|
||||||
|
final int unreadMessages;
|
||||||
final Widget? avatar;
|
final Widget? avatar;
|
||||||
final String? subTitle;
|
final String? subTitle;
|
||||||
final String? lastUsed;
|
final String? lastUsed;
|
||||||
|
@ -35,9 +37,11 @@ class ChatRow extends StatelessWidget {
|
||||||
title,
|
title,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: unreadMessages > 0
|
||||||
|
? FontWeight.w600
|
||||||
|
: FontWeight.w400,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (subTitle != null)
|
if (subTitle != null)
|
||||||
|
@ -45,8 +49,11 @@ class ChatRow extends StatelessWidget {
|
||||||
padding: const EdgeInsets.only(top: 3.0),
|
padding: const EdgeInsets.only(top: 3.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
subTitle!,
|
subTitle!,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
|
fontWeight: unreadMessages > 0
|
||||||
|
? FontWeight.w600
|
||||||
|
: FontWeight.w400,
|
||||||
),
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
|
@ -56,12 +63,39 @@ class ChatRow extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Column(
|
||||||
lastUsed ?? '',
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
style: const TextStyle(
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
color: Color(0xFFBBBBBB),
|
children: [
|
||||||
fontSize: 14,
|
Text(
|
||||||
),
|
lastUsed ?? '',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Color(0xFFBBBBBB),
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
@ -99,6 +99,8 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||||
child: widget.options.chatRowContainerBuilder(
|
child: widget.options.chatRowContainerBuilder(
|
||||||
(chat is PersonalChatModel)
|
(chat is PersonalChatModel)
|
||||||
? ChatRow(
|
? ChatRow(
|
||||||
|
unreadMessages:
|
||||||
|
chat.unreadMessages ?? 0,
|
||||||
avatar:
|
avatar:
|
||||||
widget.options.userAvatarBuilder(
|
widget.options.userAvatarBuilder(
|
||||||
chat.user,
|
chat.user,
|
||||||
|
@ -122,6 +124,8 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||||
)
|
)
|
||||||
: ChatRow(
|
: ChatRow(
|
||||||
title: (chat as GroupChatModel).title,
|
title: (chat as GroupChatModel).title,
|
||||||
|
unreadMessages:
|
||||||
|
chat.unreadMessages ?? 0,
|
||||||
subTitle: chat.lastMessage != null
|
subTitle: chat.lastMessage != null
|
||||||
? chat.lastMessage
|
? chat.lastMessage
|
||||||
is ChatTextMessageModel
|
is ChatTextMessageModel
|
||||||
|
|
Loading…
Reference in a new issue