diff --git a/lib/src/room.dart b/lib/src/room.dart index 538d591c..b69cf0b1 100644 --- a/lib/src/room.dart +++ b/lib/src/room.dart @@ -506,10 +506,14 @@ class Room { /// Returns true if this room is unread bool get isUnread => notificationCount > 0 || markedUnread; - /// Sets an unread flag manually for this room. Similar to the setUnreadMarker - /// this changes the local account data model before syncing it to make sure - /// this works if there is no connection to the homeserver. - Future setUnread(bool unread) async { + @Deprecated('Use [markUnread] instead') + Future setUnread(bool unread) => markUnread(unread); + + /// Sets an unread flag manually for this room. This changes the local account + /// data model before syncing it to make sure + /// this works if there is no connection to the homeserver. This does **not** + /// set a read marker! + Future markUnread(bool unread) async { final content = MarkedUnread(unread).toJson(); await _handleFakeSync(SyncUpdate(nextBatch: '') ..rooms = (RoomsUpdate() @@ -527,13 +531,6 @@ class Room { EventType.markedUnread, content, ); - final lastEvent = this.lastEvent; - if (!unread && lastEvent != null) { - await setReadMarker( - lastEvent.eventId, - mRead: lastEvent.eventId, - ); - } } /// Returns true if this room has a m.favourite tag. diff --git a/lib/src/timeline.dart b/lib/src/timeline.dart index 47cead5e..5969d5e2 100644 --- a/lib/src/timeline.dart +++ b/lib/src/timeline.dart @@ -18,6 +18,8 @@ import 'dart:async'; +import 'package:collection/src/iterable_extensions.dart'; + import '../matrix.dart'; import 'event.dart'; import 'event_status.dart'; @@ -185,6 +187,14 @@ class Timeline { } } + /// Set the read marker to the last synced event in this timeline. + Future setReadMarker([String? eventId]) async { + eventId ??= + events.firstWhereOrNull((event) => event.status.isSynced)?.eventId; + if (eventId == null) return; + return room.setReadMarker(eventId, mRead: eventId); + } + int _findEvent({String? event_id, String? unsigned_txid}) { // we want to find any existing event where either the passed event_id or the passed unsigned_txid // matches either the event_id or transaction_id of the existing event. diff --git a/test/fake_matrix_api.dart b/test/fake_matrix_api.dart index bdb023e2..e8564e21 100644 --- a/test/fake_matrix_api.dart +++ b/test/fake_matrix_api.dart @@ -1779,6 +1779,7 @@ class FakeMatrixApi extends MockClient { '/client/r0/rooms/!localpart%3Aexample.com/receipt/m.read/%241234%3Aexample.com': (var req) => {}, '/client/r0/rooms/!localpart%3Aexample.com/read_markers': (var req) => {}, + '/client/r0/rooms/!1234%3Aexample.com/read_markers': (var req) => {}, '/client/r0/user/${Uri.encodeComponent('@othertest:fakeServer.notExisting')}/filter': (var req) => {'filter_id': '1234'}, '/client/r0/user/${Uri.encodeComponent('@test:fakeServer.notExisting')}/filter': diff --git a/test/room_test.dart b/test/room_test.dart index 494748eb..b68f08de 100644 --- a/test/room_test.dart +++ b/test/room_test.dart @@ -743,15 +743,15 @@ void main() { }); test('Test marked unread room', () async { - await room.setUnread(true); - await room.setUnread(false); - expect(room.isUnread, false); + await room.markUnread(true); + await room.markUnread(false); + expect(room.markedUnread, false); room.roomAccountData['com.famedly.marked_unread'] = BasicRoomEvent.fromJson({ 'content': {'unread': true}, 'type': 'com.famedly.marked_unread' }); - expect(room.isUnread, true); + expect(room.markedUnread, true); }); test('joinRules', () async { diff --git a/test/timeline_test.dart b/test/timeline_test.dart index 032da3b3..8c996069 100644 --- a/test/timeline_test.dart +++ b/test/timeline_test.dart @@ -386,6 +386,24 @@ void main() { expect(timeline.events[0].status, EventStatus.error); expect(timeline.events.length, 1); }); + test('setReadMarker', () async { + client.onEvent.add(EventUpdate( + type: EventUpdateType.timeline, + roomID: roomID, + content: { + 'type': 'm.room.message', + 'content': {'msgtype': 'm.text', 'body': 'Testcase'}, + 'sender': '@alice:example.com', + 'status': EventStatus.synced.intValue, + 'event_id': 'will-work', + 'origin_server_ts': DateTime.now().millisecondsSinceEpoch, + }, + )); + await Future.delayed(Duration(milliseconds: 50)); + room.notificationCount = 1; + await timeline.setReadMarker(); + expect(room.notificationCount, 0); + }); test('sending an event and the http request finishes first, 0 -> 1 -> 2', () async { timeline.events.clear();