From 2a3e3462ac14993b54ff16150b2cd74b5325068e Mon Sep 17 00:00:00 2001 From: Terence ZAFINDRATAFA <31937920+Te-Z@users.noreply.github.com> Date: Tue, 9 Apr 2024 16:59:41 +0200 Subject: [PATCH] TW-1675: status of user is not correct (#1684) --- docs/adr/0021-listen-to-presence-status.md | 64 ++++++++++++++++++++++ lib/pages/chat/chat_view.dart | 3 +- lib/utils/room_status_extension.dart | 2 +- pubspec.lock | 2 +- 4 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 docs/adr/0021-listen-to-presence-status.md diff --git a/docs/adr/0021-listen-to-presence-status.md b/docs/adr/0021-listen-to-presence-status.md new file mode 100644 index 0000000000..ca5c2da4aa --- /dev/null +++ b/docs/adr/0021-listen-to-presence-status.md @@ -0,0 +1,64 @@ +# 21. Listen to presence status + +Date: 2024-04-08 + +## Status + +Accepted + +## Context + +The status of presence of a user on a direct chat was not stable. By this we mean that it changes multiple times in a small timeline (few seconds). +This was because the UI was listening to `onPresenceChanged`'s stream which is updated in a for loop where there can be multiple items. So if there was 6 items in this loop, the status was updated 6 times. + +```dart + /// Callback will be called on presence updates. + final CachedStreamController onPresenceChanged = + CachedStreamController(); + + for (final newPresence in sync.presence ?? []) { + final cachedPresence = CachedPresence.fromMatrixEvent(newPresence); + presences[newPresence.senderId] = cachedPresence; + // ignore: deprecated_member_use_from_same_package + onPresence.add(newPresence); + onPresenceChanged.add(cachedPresence); + } +``` + +## Decision + +To avoid this problem we created a new stream which purpose is to get the status of presence the closest of current time: `onlatestPresenceChanged` . That's the one who should be listened by the UI. + +Here `lastActivePresence` is updated for each items in `sync.presence` list if it is `null` or if the current item's timestamp is after the one in `lastActivePresence`. Then when the loop is over and we are sure to have the right value, we can update `onLatestPresenceChange` with the right value and this way update the UI. + +```dart + /// Callback will be called on presence updates. + final CachedStreamController onPresenceChanged = + CachedStreamController(); + + /// Callback will be called on presence update and return latest value. + final CachedStreamController onlatestPresenceChanged = + CachedStreamController(); + + CachedPresence? lastActivePresence; + + for (final newPresence in sync.presence ?? []) { + final cachedPresence = CachedPresence.fromMatrixEvent(newPresence); + presences[newPresence.senderId] = cachedPresence; + // ignore: deprecated_member_use_from_same_package + onPresence.add(newPresence); + onPresenceChanged.add(cachedPresence); + + if (lastActivePresence == null || + (cachedPresence.lastActiveTimestamp != null && + lastActivePresence.lastActiveTimestamp != null && + cachedPresence.lastActiveTimestamp! + .isAfter(lastActivePresence.lastActiveTimestamp!))) { + lastActivePresence = cachedPresence; + } + } + + if (lastActivePresence != null) { + onlatestPresenceChanged.add(lastActivePresence); + } +``` \ No newline at end of file diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index a933534014..8828d91855 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -127,7 +127,8 @@ class ChatView extends StatelessWidget with MessageContentMixin { sendController: controller.sendController, connectivityResultStream: controller .networkConnectionService - .getStreamInstance(), + .connectivity + .onConnectivityChanged, actions: _appBarActions(context), onPushDetails: controller.onPushDetails, roomName: controller.roomName, diff --git a/lib/utils/room_status_extension.dart b/lib/utils/room_status_extension.dart index cc4229d164..c0eb53c25e 100644 --- a/lib/utils/room_status_extension.dart +++ b/lib/utils/room_status_extension.dart @@ -12,7 +12,7 @@ extension RoomStatusExtension on Room { client.presences[directChatMatrixID]; Stream get directChatPresenceStream => - client.onPresenceChanged.stream; + client.onlatestPresenceChanged.stream; String getLocalizedStatus(BuildContext context, {CachedPresence? presence}) { if (isDirectChat) { diff --git a/pubspec.lock b/pubspec.lock index 7b04240a69..8a8529f2ef 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1607,7 +1607,7 @@ packages: description: path: "." ref: "twake-supported-0.22.6" - resolved-ref: "8f821c1cab2506d13c2266cc8759ffd2b2818770" + resolved-ref: "699db764273c113e9d508a1f2d148067aabc8101" url: "git@github.com:linagora/matrix-dart-sdk.git" source: git version: "0.22.6"