From 9b3f9e4ef7284fbcca0d2ff8f51cdf7015778cdd Mon Sep 17 00:00:00 2001 From: Marcus Hoffmann Date: Sat, 21 Nov 2020 19:56:20 +0100 Subject: [PATCH] feature: allow marking rooms as unread --- lib/matrix_api/model/marked_unread.dart | 43 +++++++++++++++++++++++++ lib/src/room.dart | 28 ++++++++++++++-- test/fake_matrix_api.dart | 2 ++ test/room_test.dart | 22 ++++++++++--- 4 files changed, 87 insertions(+), 8 deletions(-) create mode 100644 lib/matrix_api/model/marked_unread.dart diff --git a/lib/matrix_api/model/marked_unread.dart b/lib/matrix_api/model/marked_unread.dart new file mode 100644 index 00000000..c3223c78 --- /dev/null +++ b/lib/matrix_api/model/marked_unread.dart @@ -0,0 +1,43 @@ +/* + * Famedly Matrix SDK + * Copyright (C) 2019, 2020 Famedly GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +mixin EventType { + static const String MarkedUnread = 'com.famedly.marked_unread'; +} + +class MarkedUnread { + bool unread; + + MarkedUnread(this.unread); + + MarkedUnread.fromJson(Map json) { + if (!(json['unread'] is bool)) { + unread = false; + } else { + unread = json['unread']; + } + } + + Map toJson() { + final data = {}; + if (unread != null) { + data['unread'] = unread; + } + return data; + } +} diff --git a/lib/src/room.dart b/lib/src/room.dart index 2b5f2ed4..b424e015 100644 --- a/lib/src/room.dart +++ b/lib/src/room.dart @@ -18,6 +18,7 @@ import 'dart:async'; +import 'package:famedlysdk/matrix_api/model/marked_unread.dart'; import 'package:famedlysdk/src/utils/tombstone_content.dart'; import 'package:html_unescape/html_unescape.dart'; import 'package:matrix_file_e2ee/matrix_file_e2ee.dart'; @@ -40,6 +41,7 @@ enum PushRuleState { notify, mentions_only, dont_notify } enum JoinRules { public, knock, invite, private } enum GuestAccess { can_join, forbidden } enum HistoryVisibility { invited, joined, shared, world_readable } + const String MessageSendingStatusKey = 'com.famedly.famedlysdk.message_sending_status'; @@ -176,7 +178,7 @@ class Room { ? states[EventTypes.RoomName].content['name'] : ''; - /// The pinned events for this room. If there are no this returns an empty + /// The pinned events for this room. If there are none this returns an empty /// list. List get pinnedEventIds => states[EventTypes.RoomPinnedEvents] != null ? (states[EventTypes.RoomPinnedEvents].content['pinned'] is List @@ -427,6 +429,24 @@ class Room { return tags; } + bool get markedUnread { + return MarkedUnread.fromJson( + roomAccountData[EventType.MarkedUnread]?.content ?? {}) + .unread; + } + + /// Returns true if this room is unread + bool get isUnread => notificationCount > 0 || markedUnread; + + Future setUnread(bool unread) async { + await client.setRoomAccountData( + client.userID, + id, + EventType.MarkedUnread, + MarkedUnread(unread).toJson(), + ); + } + /// Returns true if this room has a m.favourite tag. bool get isFavourite => tags[TagType.Favourite] != null; @@ -973,7 +993,8 @@ class Room { /// Returns a Room from a json String which comes normally from the store. If the /// state are also given, the method will await them. static Future getRoomFromTableRow( - DbRoom row, // either Map or DbRoom + // either Map or DbRoom + DbRoom row, Client matrix, { dynamic states, // DbRoomState, as iterator and optionally as future dynamic @@ -985,7 +1006,8 @@ class Room { .firstWhere((e) => e.toString() == 'Membership.' + row.membership), notificationCount: row.notificationCount, highlightCount: row.highlightCount, - notificationSettings: 'mention', // TODO: do proper things + // TODO: do proper things + notificationSettings: 'mention', prev_batch: row.prevBatch, mInvitedMemberCount: row.invitedMemberCount, mJoinedMemberCount: row.joinedMemberCount, diff --git a/test/fake_matrix_api.dart b/test/fake_matrix_api.dart index 156d86a6..edb3c49a 100644 --- a/test/fake_matrix_api.dart +++ b/test/fake_matrix_api.dart @@ -2040,6 +2040,8 @@ class FakeMatrixApi extends MockClient { (var req) => {}, '/client/r0/user/%40alice%3Aexample.com/rooms/1234/account_data/test.account.data': (var req) => {}, + '/client/r0/user/%40test%3AfakeServer.notExisting/rooms/!localpart%3Aserver.abc/account_data/com.famedly.marked_unread': + (var req) => {}, '/client/r0/user/%40test%3AfakeServer.notExisting/account_data/m.direct': (var req) => {}, '/client/r0/user/%40othertest%3AfakeServer.notExisting/account_data/m.direct': diff --git a/test/room_test.dart b/test/room_test.dart index b777b589..79679cf1 100644 --- a/test/room_test.dart +++ b/test/room_test.dart @@ -16,22 +16,22 @@ * along with this program. If not, see . */ +import 'dart:convert'; +import 'dart:typed_data'; + import 'package:famedlysdk/matrix_api.dart'; import 'package:famedlysdk/src/client.dart'; +import 'package:famedlysdk/src/database/database.dart' + show DbRoom, DbRoomState, DbRoomAccountData; import 'package:famedlysdk/src/event.dart'; import 'package:famedlysdk/src/room.dart'; import 'package:famedlysdk/src/user.dart'; import 'package:famedlysdk/src/utils/matrix_file.dart'; -import 'package:famedlysdk/src/database/database.dart' - show DbRoom, DbRoomState, DbRoomAccountData; import 'package:test/test.dart'; import 'fake_client.dart'; import 'fake_matrix_api.dart'; -import 'dart:convert'; -import 'dart:typed_data'; - void main() { Client matrix; Room room; @@ -552,6 +552,18 @@ void main() { await room.setFavourite(false); }); + test('Test marked unread room', () async { + await room.setUnread(true); + await room.setUnread(false); + expect(room.isUnread, false); + room.roomAccountData['com.famedly.marked_unread'] = + BasicRoomEvent.fromJson({ + 'content': {'unread': true}, + 'type': 'com.famedly.marked_unread' + }); + expect(room.isUnread, true); + }); + test('joinRules', () async { expect(room.canChangeJoinRules, false); expect(room.joinRules, JoinRules.public);