From b1a945a5017f42edf90835b9d0efd4ba16ed7055 Mon Sep 17 00:00:00 2001 From: Nutcake Date: Fri, 5 May 2023 12:40:19 +0200 Subject: [PATCH] Change notifications to be only triggered by websocket stream --- lib/clients/messaging_client.dart | 69 +++++++++++++++++++++++++------ lib/widgets/friends_list.dart | 37 ++++++++--------- lib/widgets/messages_list.dart | 6 +-- 3 files changed, 78 insertions(+), 34 deletions(-) diff --git a/lib/clients/messaging_client.dart b/lib/clients/messaging_client.dart index d7ba827..607bbdc 100644 --- a/lib/clients/messaging_client.dart +++ b/lib/clients/messaging_client.dart @@ -42,10 +42,12 @@ class MessagingClient { final ApiClient _apiClient; final Map _friendsCache = {}; final Map _messageCache = {}; - final Map _updateListeners = {}; + final Map _messageUpdateListeners = {}; + final Map> _unreads = {}; final Logger _logger = Logger("NeosHub"); final Workmanager _workmanager = Workmanager(); final NotificationClient _notificationClient; + Function? _unreadsUpdateListener; WebSocket? _wsChannel; bool _isConnecting = false; @@ -66,6 +68,46 @@ class MessagingClient { } } + void updateAllUnreads(List messages) { + _unreads.clear(); + for (final msg in messages) { + if (msg.senderId != _apiClient.userId) { + final value = _unreads[msg.senderId]; + if (value == null) { + _unreads[msg.senderId] = [msg]; + } else { + value.add(msg); + } + } + } + } + + void addUnread(Message message) { + var messages = _unreads[message.senderId]; + if (messages == null) { + messages = [message]; + _unreads[message.senderId] = messages; + } else { + messages.add(message); + } + messages.sort(); + _notificationClient.showUnreadMessagesNotification(messages.reversed); + notifyUnreadListener(); + } + + void clearUnreadsForFriend(Friend friend) { + _unreads[friend.id]?.clear(); + notifyUnreadListener(); + } + + List getUnreadsForFriend(Friend friend) => _unreads[friend.id] ?? []; + + bool friendHasUnreads(Friend friend) => _unreads.containsKey(friend.id); + + bool messageIsUnread(Message message) { + return _unreads[message.senderId]?.any((element) => element.id == message.id) ?? false; + } + Friend? getAsFriend(String userId) => _friendsCache[userId]; Future getMessageCache(String userId) async { @@ -153,9 +195,13 @@ class MessagingClient { } } - void registerListener(String userId, Function function) => _updateListeners[userId] = function; - void unregisterListener(String userId) => _updateListeners.remove(userId); - void notifyListener(String userId) => _updateListeners[userId]?.call(); + void registerMessageListener(String userId, Function function) => _messageUpdateListeners[userId] = function; + void unregisterMessageListener(String userId) => _messageUpdateListeners.remove(userId); + void notifyMessageListener(String userId) => _messageUpdateListeners[userId]?.call(); + + void registerUnreadListener(Function function) => _unreadsUpdateListener = function; + void unregisterUnreadListener() => _unreadsUpdateListener = null; + void notifyUnreadListener() => _unreadsUpdateListener?.call(); void _handleEvent(event) { final body = jsonDecode((event.toString().replaceAll(eofChar, ""))); @@ -186,17 +232,17 @@ class MessagingClient { final message = Message.fromMap(msg, withState: MessageState.sent); final cache = await getMessageCache(message.recipientId); cache.addMessage(message); - notifyListener(message.recipientId); + notifyMessageListener(message.recipientId); break; case EventTarget.receiveMessage: final msg = args[0]; final message = Message.fromMap(msg); final cache = await getMessageCache(message.senderId); cache.addMessage(message); - if (!_updateListeners.containsKey(message.senderId)) { - _notificationClient.showUnreadMessagesNotification([message]); + if (!_messageUpdateListeners.containsKey(message.senderId)) { + addUnread(message); } - notifyListener(message.senderId); + notifyMessageListener(message.senderId); break; case EventTarget.messagesRead: final messageIds = args[0]["ids"] as List; @@ -205,7 +251,7 @@ class MessagingClient { for (var id in messageIds) { cache.setMessageState(id, MessageState.read); } - notifyListener(recipientId); + notifyMessageListener(recipientId); break; } } @@ -222,7 +268,7 @@ class MessagingClient { _sendData(data); final cache = await getMessageCache(message.recipientId); cache.messages.add(message); - notifyListener(message.recipientId); + notifyMessageListener(message.recipientId); } void markMessagesRead(MarkReadBatch batch) { @@ -260,13 +306,12 @@ class NotificationClient { ) ); - Future showUnreadMessagesNotification(List messages) async { + Future showUnreadMessagesNotification(Iterable messages) async { if (messages.isEmpty) return; final bySender = groupBy(messages, (p0) => p0.senderId); for (final entry in bySender.entries) { - final uname = entry.key.stripUid(); await _notifier.show( uname.hashCode, diff --git a/lib/widgets/friends_list.dart b/lib/widgets/friends_list.dart index ab47e10..1afc683 100644 --- a/lib/widgets/friends_list.dart +++ b/lib/widgets/friends_list.dart @@ -31,7 +31,6 @@ class FriendsList extends StatefulWidget { class _FriendsListState extends State { static const Duration _autoRefreshDuration = Duration(seconds: 90); static const Duration _refreshTimeoutDuration = Duration(seconds: 30); - final _unreads = >{}; Future>? _friendsFuture; ClientHolder? _clientHolder; Timer? _autoRefresh; @@ -51,6 +50,14 @@ class _FriendsListState extends State { final clientHolder = ClientHolder.of(context); if (_clientHolder != clientHolder) { _clientHolder = clientHolder; + final mClient = _clientHolder!.messagingClient; + mClient.registerUnreadListener(() { + if (context.mounted) { + setState(() {}); + } else { + mClient.unregisterUnreadListener(); + } + }); _refreshFriendsList(); } } @@ -59,22 +66,14 @@ class _FriendsListState extends State { if (_refreshTimeout?.isActive == true) return; _friendsFuture = FriendApi.getFriendsList(_clientHolder!.apiClient).then((Iterable value) async { final unreadMessages = await MessageApi.getUserMessages(_clientHolder!.apiClient, unreadOnly: true); - _unreads.clear(); - for (final msg in unreadMessages) { - if (msg.senderId != _clientHolder!.apiClient.userId) { - final value = _unreads[msg.senderId]; - if (value == null) { - _unreads[msg.senderId] = [msg]; - } else { - value.add(msg); - } - } - } + final mClient = _clientHolder?.messagingClient; + if (mClient == null) return []; + mClient.updateAllUnreads(unreadMessages.toList()); final friends = value.toList() ..sort((a, b) { - var aVal = _unreads.containsKey(a.id) ? -3 : 0; - var bVal = _unreads.containsKey(b.id) ? -3 : 0; + var aVal = mClient.friendHasUnreads(a) ? -3 : 0; + var bVal = mClient.friendHasUnreads(b) ? -3 : 0; aVal -= a.userStatus.lastStatusChange.compareTo(b.userStatus.lastStatusChange); aVal += a.userStatus.onlineStatus.compareTo(b.userStatus.onlineStatus) * 2; @@ -164,21 +163,21 @@ class _FriendsListState extends State { itemCount: friends.length, itemBuilder: (context, index) { final friend = friends[index]; - final unread = _unreads[friend.id] ?? []; + final unreads = _clientHolder?.messagingClient.getUnreadsForFriend(friend) ?? []; return FriendListTile( friend: friend, - unreads: unread.length, + unreads: unreads.length, onTap: () async { - if (unread.isNotEmpty) { + if (unreads.isNotEmpty) { final readBatch = MarkReadBatch( senderId: _clientHolder!.apiClient.userId, - ids: unread.map((e) => e.id).toList(), + ids: unreads.map((e) => e.id).toList(), readTime: DateTime.now(), ); _clientHolder!.messagingClient.markMessagesRead(readBatch); } setState(() { - unread.clear(); + unreads.clear(); }); }, ); diff --git a/lib/widgets/messages_list.dart b/lib/widgets/messages_list.dart index 8338278..2d452ed 100644 --- a/lib/widgets/messages_list.dart +++ b/lib/widgets/messages_list.dart @@ -51,18 +51,18 @@ class _MessagesListState extends State { .whenComplete(() => _messageCacheFutureComplete = true); final mClient = _clientHolder?.messagingClient; final id = widget.friend.id; - mClient?.registerListener(id, () { + mClient?.registerMessageListener(id, () { if (context.mounted) { setState(() {}); } else { - mClient.unregisterListener(id); + mClient.unregisterMessageListener(id); } }); } @override void dispose() { - _clientHolder?.messagingClient.unregisterListener(widget.friend.id); + _clientHolder?.messagingClient.unregisterMessageListener(widget.friend.id); _messageTextController.dispose(); _sessionListScrollController.dispose(); super.dispose();