Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 62 additions & 117 deletions lib/src/client.dart
Comment thread
krille-chan marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -411,12 +411,6 @@ class Client extends MatrixApi {
List<Room> get rooms => _rooms;
List<Room> _rooms = [];

/// Get a list of the archived rooms
///
/// Attention! Archived rooms are only returned if [loadArchive()] was called
/// beforehand! The state refers to the last retrieval via [loadArchive()]!
List<ArchivedRoom> get archivedRooms => _archivedRooms;

bool enableDehydratedDevices = false;

final String dehydratedDeviceDisplayName;
Expand Down Expand Up @@ -483,10 +477,9 @@ class Client extends MatrixApi {
}

/// Searches in the local cache for the given room and returns null if not
/// found. If you have loaded the [loadArchive()] before, it can also return
/// archived rooms.
/// found. This does not include archived rooms.
Room? getRoomById(String id) {
for (final room in <Room>[...rooms, ..._archivedRooms.map((e) => e.room)]) {
for (final room in rooms) {
if (room.id == id) return room;
}

Expand Down Expand Up @@ -1226,25 +1219,6 @@ class Client extends MatrixApi {
);
}

final List<ArchivedRoom> _archivedRooms = [];

/// Return an archive room containing the room and the timeline for a specific archived room.
ArchivedRoom? getArchiveRoomFromCache(String roomId) {
for (var i = 0; i < _archivedRooms.length; i++) {
final archive = _archivedRooms[i];
if (archive.room.id == roomId) return archive;
}
return null;
}

/// Remove all the archives stored in cache.
void clearArchivesFromCache() {
_archivedRooms.clear();
}

@Deprecated('Use [loadArchive()] instead.')
Future<List<Room>> get archive => loadArchive();

/// Fetch all the archived rooms from the server and return the list of the
/// room. If you want to have the Timelines bundled with it, use
/// loadArchiveWithTimeline instead.
Expand All @@ -1264,8 +1238,6 @@ class Client extends MatrixApi {
/// Fetch the archived rooms from the server and return them as a list of
/// [ArchivedRoom] objects containing the [Room] and the associated [Timeline].
Future<List<ArchivedRoom>> loadArchiveWithTimeline() async {
_archivedRooms.clear();

final filter = jsonEncode(
Filter(
room: RoomFilter(
Expand All @@ -1285,94 +1257,62 @@ class Client extends MatrixApi {
_archiveCacheBusterTimeout = (_archiveCacheBusterTimeout + 1) % 30;

final leave = syncResp.rooms?.leave;
final archivedRooms = <ArchivedRoom>[];
if (leave != null) {
for (final entry in leave.entries) {
await _storeArchivedRoom(entry.key, entry.value);
final room = Room(
id: entry.key,
prev_batch: entry.value.timeline?.prevBatch,
membership: Membership.leave,
client: this,
roomAccountData:
entry.value.accountData?.asMap().map(
(k, v) => MapEntry(v.type, v),
) ??
<String, BasicEvent>{},
);
entry.value.state?.forEach(room.setState);
final timeline = Timeline(
room: room,
chunk: TimelineChunk(
events:
entry.value.timeline?.events?.reversed
.toList() // we display the event in the other sence
.map((e) => Event.fromMatrixEvent(e, room))
.toList() ??
[],
prevBatch: entry.value.timeline?.prevBatch ?? '',
),
);
Comment thread
cursor[bot] marked this conversation as resolved.
for (var i = 0; i < timeline.events.length; i++) {
// Try to decrypt encrypted events but don't update the database.
if (room.encrypted && room.client.encryptionEnabled) {
if (timeline.events[i].type == EventTypes.Encrypted) {
await room.client.encryption!
.decryptRoomEvent(timeline.events[i])
.then((decrypted) => timeline.events[i] = decrypted);
}
}
}
room.lastEvent = timeline.events.firstWhereOrNull(
(event) => roomPreviewLastEvents.contains(event.type),
);

archivedRooms.add(ArchivedRoom(room: room, timeline: timeline));
Comment thread
krille-chan marked this conversation as resolved.
}
}

// Sort the archived rooms by last event originServerTs as this is the
// best indicator we have to sort them. For archived rooms where we don't
// have any, we move them to the bottom.
final beginningOfTime = DateTime.fromMillisecondsSinceEpoch(0);
_archivedRooms.sort(
archivedRooms.sort(
(b, a) => (a.room.lastEvent?.originServerTs ?? beginningOfTime).compareTo(
b.room.lastEvent?.originServerTs ?? beginningOfTime,
),
);

return _archivedRooms;
}

/// [_storeArchivedRoom]
/// @leftRoom we can pass a room which was left so that we don't loose states
Future<void> _storeArchivedRoom(
String id,
LeftRoomUpdate update, {
Room? leftRoom,
}) async {
final roomUpdate = update;
final archivedRoom =
leftRoom ??
Room(
id: id,
membership: Membership.leave,
client: this,
roomAccountData:
roomUpdate.accountData?.asMap().map(
(k, v) => MapEntry(v.type, v),
) ??
<String, BasicEvent>{},
);
// 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 seence
.map((e) => Event.fromMatrixEvent(e, archivedRoom))
.toList() ??
[],
),
);

archivedRoom.prev_batch = update.timeline?.prevBatch;

final stateEvents = roomUpdate.state;
if (stateEvents != null) {
await _handleRoomEvents(
archivedRoom,
stateEvents,
EventUpdateType.state,
store: false,
);
}

final timelineEvents = roomUpdate.timeline?.events;
if (timelineEvents != null) {
await _handleRoomEvents(
archivedRoom,
timelineEvents.toList(),
EventUpdateType.timeline,
store: false,
);
}

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(timeline.events[i])
.then((decrypted) => timeline.events[i] = decrypted);
}
}
}

_archivedRooms.add(ArchivedRoom(room: archivedRoom, timeline: timeline));
return archivedRooms;
}

@override
Expand Down Expand Up @@ -2861,12 +2801,15 @@ class Client extends MatrixApi {
room,
timelineEvents,
timelineUpdateType,
store: false,
store: syncFilter.room?.includeLeave == true,
);
}
final accountData = syncRoomUpdate.accountData;
if (accountData != null && accountData.isNotEmpty) {
for (final event in accountData) {
if (syncFilter.room?.includeLeave == true) {
await database.storeRoomAccountData(room.id, event);
}
room.roomAccountData[event.type] = event;
}
}
Expand All @@ -2876,7 +2819,7 @@ class Client extends MatrixApi {
room,
state,
EventUpdateType.state,
store: false,
store: syncFilter.room?.includeLeave == true,
);
}
}
Expand Down Expand Up @@ -3113,25 +3056,27 @@ class Client extends MatrixApi {
summary: chatUpdate.summary,
client: this,
)
: Room(id: roomId, membership: membership, client: this));
: Room(
id: roomId,
membership: membership,
prev_batch: chatUpdate is LeftRoomUpdate
? chatUpdate.timeline?.prevBatch
: null,
client: this,
));

// Does the chat already exist in the list rooms?
if (!found && membership != Membership.leave) {
// Check if the room is not in the rooms in the invited list
if (_archivedRooms.isNotEmpty) {
_archivedRooms.removeWhere((archive) => archive.room.id == roomId);
}
final position = membership == Membership.invite ? 0 : rooms.length;
// Add the new chat to the list
rooms.insert(position, room);
}
// If the membership is "leave" then remove the item and stop here
else if (found && membership == Membership.leave) {
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);
else if (membership == Membership.leave) {
Comment thread
krille-chan marked this conversation as resolved.
if (syncFilter.room?.includeLeave == true && !found) {
rooms.add(room);
} else if (found) {
rooms.removeAt(roomIndex);
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
krille-chan marked this conversation as resolved.
}
}
// Update notification, highlight count and/or additional information
Expand Down
6 changes: 5 additions & 1 deletion lib/src/database/matrix_sdk_database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1264,7 +1264,8 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
Client client,
) async {
// Leave room if membership is leave
if (roomUpdate is LeftRoomUpdate) {
if (roomUpdate is LeftRoomUpdate &&
client.syncFilter.room?.includeLeave != true) {
Comment thread
cursor[bot] marked this conversation as resolved.
await forgetRoom(roomId);
return;
}
Expand Down Expand Up @@ -1294,6 +1295,9 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
: Room(
client: client,
id: roomId,
prev_batch: roomUpdate is LeftRoomUpdate
? roomUpdate.timeline?.prevBatch
: null,
membership: membership,
lastEvent: lastEvent,
).toJson(),
Expand Down
24 changes: 6 additions & 18 deletions lib/src/room.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1495,12 +1495,7 @@ class Room {
Future<void> forget() async {
await client.database.forgetRoom(id);
await client.forgetRoom(id);
// Update archived rooms, otherwise an archived room may still be in the
Comment thread
cursor[bot] marked this conversation as resolved.
// list after a forget room call
final roomIndex = client.archivedRooms.indexWhere((r) => r.room.id == id);
if (roomIndex != -1) {
client.archivedRooms.removeAt(roomIndex);
}
client.rooms.remove(this);
return;
}

Expand Down Expand Up @@ -1776,20 +1771,13 @@ class Room {
await client.database.transaction(() async {
events = await client.database.getEventList(this, limit: limit);
});
} else {
Comment thread
cursor[bot] marked this conversation as resolved.
final archive = client.getArchiveRoomFromCache(id);
events = archive?.timeline.events.toList() ?? [];
for (var i = 0; i < events.length; i++) {
// Try to decrypt encrypted events but don't update the database.
if (encrypted && client.encryptionEnabled) {
if (events[i].type == EventTypes.Encrypted) {
events[i] = await client.encryption!.decryptRoomEvent(events[i]);
}
}
}
}

var chunk = TimelineChunk(events: events);
var chunk = TimelineChunk(
events: events,
// Leave rooms paginate via getRoomEvents which uses chunk.prevBatch.
prevBatch: isArchived ? (prev_batch ?? '') : '',
);
// Load the timeline arround eventContextId if set
if (eventContextId != null) {
if (!events.any((Event event) => event.eventId == eventContextId)) {
Expand Down
6 changes: 5 additions & 1 deletion lib/src/timeline.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ class Timeline {
direction: Direction.b,
historyCount: historyCount,
filter: filter,
inMemoryOnly:
room.membership == Membership.leave &&
room.client.syncFilter.room?.includeLeave != true,
Comment thread
cursor[bot] marked this conversation as resolved.
);
isRequestingHistory = false;
}
Expand Down Expand Up @@ -136,6 +139,7 @@ class Timeline {
int historyCount = Room.defaultHistoryCount,
required Direction direction,
StateFilter? filter,
bool inMemoryOnly = false,
}) async {
onUpdate?.call();

Expand Down Expand Up @@ -184,7 +188,7 @@ class Timeline {
_fetchedAllDatabaseEvents = true;
Logs().i('No more events found in the store. Request from server...');

if (isFragmentedTimeline) {
if (isFragmentedTimeline || inMemoryOnly) {
await getRoomEvents(
historyCount: historyCount,
direction: direction,
Expand Down
27 changes: 0 additions & 27 deletions test/client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1730,11 +1730,6 @@ void main() {
reason:
'Count of invited+joined before loadArchive() rooms does not match',
);
expect(
client.archivedRooms.length,
0,
reason: 'Count of archived rooms before loadArchive() does not match',
);

await client.loadArchive();

Expand All @@ -1743,28 +1738,6 @@ void main() {
3,
reason: 'Count of invited+joined rooms does not match',
);
expect(
client.archivedRooms.length,
2,
reason: 'Count of archived rooms does not match',
);

expect(
client.archivedRooms.firstWhereOrNull(
(r) => r.room.id == '!5345234234:example.com',
) !=
null,
true,
reason: '!5345234234:example.com not found as archived room',
);
expect(
client.archivedRooms.firstWhereOrNull(
(r) => r.room.id == '!5345234235:example.com',
) !=
null,
true,
reason: '!5345234235:example.com not found as archived room',
);

await client.dispose();
});
Expand Down
Loading
Loading