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);