diff --git a/lib/src/client.dart b/lib/src/client.dart index cd937449..3be0d26e 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -2665,8 +2665,27 @@ class Client extends MatrixApi { if (syncRoomUpdate is JoinedRoomUpdate) { final state = syncRoomUpdate.state; + // If we are receiving states when fetching history we need to check if + // we are not overwriting a newer state. + if (direction == Direction.b) { + await room.postLoad(); + state?.removeWhere((state) { + final existingState = + room.getState(state.type, state.stateKey ?? ''); + if (existingState == null) return false; + if (existingState is User) { + return existingState.originServerTs + ?.isAfter(state.originServerTs) ?? + true; + } + if (existingState is MatrixEvent) { + return existingState.originServerTs.isAfter(state.originServerTs); + } + return true; + }); + } + if (state != null && state.isNotEmpty) { - // TODO: This method seems to be comperatively slow for some updates await _handleRoomEvents( room, state, diff --git a/lib/src/event.dart b/lib/src/event.dart index d1498580..5974b27c 100644 --- a/lib/src/event.dart +++ b/lib/src/event.dart @@ -256,6 +256,7 @@ class Event extends MatrixEvent { typeKey: type, senderId: senderId, room: room, + originServerTs: originServerTs, ); String get messageType => type == EventTypes.Sticker diff --git a/lib/src/user.dart b/lib/src/user.dart index ef12b3ca..71ef5d0f 100644 --- a/lib/src/user.dart +++ b/lib/src/user.dart @@ -22,12 +22,14 @@ import 'package:matrix/matrix.dart'; class User extends StrippedStateEvent { final Room room; final Map? prevContent; + final DateTime? originServerTs; factory User( String id, { String? membership, String? displayName, String? avatarUrl, + DateTime? originServerTs, required Room room, }) { return User.fromState( @@ -40,6 +42,7 @@ class User extends StrippedStateEvent { }, typeKey: EventTypes.RoomMember, room: room, + originServerTs: originServerTs, ); } @@ -49,6 +52,7 @@ class User extends StrippedStateEvent { required String typeKey, required super.senderId, required this.room, + this.originServerTs, this.prevContent, }) : super( type: typeKey, @@ -254,5 +258,6 @@ extension FromStrippedStateEventExtension on StrippedStateEvent { typeKey: type, senderId: senderId, room: room, + originServerTs: null, ); } diff --git a/test/client_test.dart b/test/client_test.dart index 50bb4e9f..a6a17416 100644 --- a/test/client_test.dart +++ b/test/client_test.dart @@ -695,6 +695,35 @@ void main() { ); expect(room.lastEvent!.content['body'], '* floooof'); + // Older state event should not overwrite current state events + room.partial = false; + await matrix.handleSync( + SyncUpdate( + nextBatch: '', + rooms: RoomsUpdate( + join: { + room.id: JoinedRoomUpdate( + state: [ + MatrixEvent( + type: EventTypes.RoomMember, + content: {'displayname': 'Alice Catgirl'}, + senderId: '@alice:example.com', + eventId: 'oldEventId', + stateKey: '@alice:example.com', + originServerTs: + DateTime.now().subtract(const Duration(days: 365 * 30)), + ), + ], + ), + }, + ), + ), + direction: Direction.b, + ); + room.partial = true; + expect(room.getParticipants().first.id, '@alice:example.com'); + expect(room.getParticipants().first.displayName, 'Alice Margatroid'); + // accepts a consecutive edit await matrix.handleSync( SyncUpdate.fromJson({