diff --git a/lib/src/client.dart b/lib/src/client.dart index 2b03896a9..8910a6ed7 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -261,7 +261,7 @@ class Client extends MatrixApi { bool enableDehydratedDevices = false; - /// Wether read receipts are sent as public receipts by default or just as private receipts. + /// Whether read receipts are sent as public receipts by default or just as private receipts. bool receiptsPublicByDefault = true; /// Whether this client supports end-to-end encryption using olm. @@ -940,58 +940,74 @@ class Client extends MatrixApi { final leave = syncResp.rooms?.leave; if (leave != null) { for (final entry in leave.entries) { - final id = entry.key; - final room = entry.value; - final leftRoom = Room( + await _storeArchivedRoom(entry.key, entry.value); + } + } + return _archivedRooms; + } + + /// [_storeArchivedRoom] + /// @leftRoom we can pass a room which was left so that we don't loose states + Future _storeArchivedRoom( + String id, + LeftRoomUpdate update, { + Room? leftRoom, + }) async { + final roomUpdate = update; + final archivedRoom = leftRoom ?? + Room( id: id, membership: Membership.leave, client: this, - roomAccountData: - room.accountData?.asMap().map((k, v) => MapEntry(v.type, v)) ?? - {}, + roomAccountData: roomUpdate.accountData + ?.asMap() + .map((k, v) => MapEntry(v.type, v)) ?? + {}, ); + // Set membership of room to leave, in the case we got a left room passed, otherwise + // the left room would have still membership join, which would be wrong for the setState later + archivedRoom.membership = Membership.leave; + final timeline = Timeline( + room: archivedRoom, + chunk: TimelineChunk( + events: roomUpdate.timeline?.events?.reversed + .toList() // we display the event in the other sence + .map((e) => Event.fromMatrixEvent(e, archivedRoom)) + .toList() ?? + [])); + + archivedRoom.prev_batch = update.timeline?.prevBatch; + update.state?.forEach((event) { + archivedRoom.setState(Event.fromMatrixEvent( + event, + archivedRoom, + )); + }); - final timeline = Timeline( - room: leftRoom, - chunk: TimelineChunk( - events: room.timeline?.events?.reversed - .toList() // we display the event in the other sence - .map((e) => Event.fromMatrixEvent(e, leftRoom)) - .toList() ?? - [])); - - leftRoom.prev_batch = room.timeline?.prevBatch; - room.state?.forEach((event) { - leftRoom.setState(Event.fromMatrixEvent( - event, - leftRoom, - )); - }); - - room.timeline?.events?.forEach((event) { - leftRoom.setState(Event.fromMatrixEvent( - event, - leftRoom, - )); - }); + update.timeline?.events?.forEach((event) { + archivedRoom.setState(Event.fromMatrixEvent( + event, + archivedRoom, + )); + }); - for (var i = 0; i < timeline.events.length; i++) { - // Try to decrypt encrypted events but don't update the database. - if (leftRoom.encrypted && leftRoom.client.encryptionEnabled) { - if (timeline.events[i].type == EventTypes.Encrypted) { - timeline.events[i] = - await leftRoom.client.encryption!.decryptRoomEvent( - leftRoom.id, + for (var i = 0; i < timeline.events.length; i++) { + // Try to decrypt encrypted events but don't update the database. + if (archivedRoom.encrypted && archivedRoom.client.encryptionEnabled) { + if (timeline.events[i].type == EventTypes.Encrypted) { + await archivedRoom.client.encryption! + .decryptRoomEvent( + archivedRoom.id, timeline.events[i], + ) + .then( + (decrypted) => timeline.events[i] = decrypted, ); - } - } } - - _archivedRooms.add(ArchivedRoom(room: leftRoom, timeline: timeline)); } } - return _archivedRooms; + + _archivedRooms.add(ArchivedRoom(room: archivedRoom, timeline: timeline)); } /// Uploads a file and automatically caches it in the database, if it is small enough @@ -1892,7 +1908,7 @@ class Client extends MatrixApi { final syncRoomUpdate = entry.value; await database?.storeRoomUpdate(id, syncRoomUpdate, this); - final room = _updateRoomsByRoomUpdate(id, syncRoomUpdate); + final room = await _updateRoomsByRoomUpdate(id, syncRoomUpdate); final timelineUpdateType = direction != null ? (direction == Direction.b @@ -2132,7 +2148,8 @@ class Client extends MatrixApi { } } - Room _updateRoomsByRoomUpdate(String roomId, SyncRoomUpdate chatUpdate) { + Future _updateRoomsByRoomUpdate( + String roomId, SyncRoomUpdate chatUpdate) async { // Update the chat list item. // Search the room in the rooms final roomIndex = rooms.indexWhere((r) => r.id == roomId); @@ -2175,8 +2192,13 @@ class Client extends MatrixApi { room.stopStaleCallsChecker(room.id); rooms.removeAt(roomIndex); + + // in order to keep the archive in sync, add left room to archive + if (chatUpdate is LeftRoomUpdate) { + await _storeArchivedRoom(room.id, chatUpdate, leftRoom: room); + } } - // Update notification, highlight count and/or additional informations + // Update notification, highlight count and/or additional information else if (found && chatUpdate is JoinedRoomUpdate && (rooms[roomIndex].membership != membership || @@ -2206,7 +2228,7 @@ class Client extends MatrixApi { requestHistoryOnLimitedTimeline) { Logs().v( 'Limited timeline for ${rooms[roomIndex].id} request history now'); - runInRoot(rooms[roomIndex].requestHistory); + unawaited(runInRoot(rooms[roomIndex].requestHistory)); } } return room; diff --git a/lib/src/room.dart b/lib/src/room.dart index 861f41d20..d9327ab94 100644 --- a/lib/src/room.dart +++ b/lib/src/room.dart @@ -1187,6 +1187,12 @@ class Room { Future forget() async { await client.database?.forgetRoom(id); await client.forgetRoom(id); + // Update archived rooms, otherwise an archived room may still be in the + // list after a forget room call + final roomIndex = client.archivedRooms.indexWhere((r) => r.room.id == id); + if (roomIndex != -1) { + client.archivedRooms.removeAt(roomIndex); + } return; }