diff --git a/lib/matrix_api/model/tag.dart b/lib/matrix_api/model/tag.dart index fa27ea9..af6adad 100644 --- a/lib/matrix_api/model/tag.dart +++ b/lib/matrix_api/model/tag.dart @@ -20,7 +20,7 @@ class Tag { double order; Tag.fromJson(Map json) { - order = json['order']; + order = json['order']?.toDouble(); } Map toJson() { @@ -31,3 +31,12 @@ class Tag { return data; } } + +abstract class TagType { + static const String Favourite = 'm.favourite'; + static const String LowPriority = 'm.lowpriority'; + static const String ServerNotice = 'm.server_notice'; + static bool isValid(String tag) => tag.startsWith('m.') + ? [Favourite, LowPriority, ServerNotice].contains(tag) + : true; +} diff --git a/lib/src/client.dart b/lib/src/client.dart index bcfc3ff..62bee50 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -1074,8 +1074,10 @@ class Client { /// The compare function how the rooms should be sorted internally. By default /// rooms are sorted by timestamp of the last m.room.message event or the last /// event if there is no known message. - RoomSorter sortRoomsBy = (a, b) => b.timeCreated.millisecondsSinceEpoch - .compareTo(a.timeCreated.millisecondsSinceEpoch); + RoomSorter sortRoomsBy = (a, b) => (a.isFavourite != b.isFavourite) + ? (a.isFavourite ? -1 : 1) + : b.timeCreated.millisecondsSinceEpoch + .compareTo(a.timeCreated.millisecondsSinceEpoch); void _sortRooms() { if (prevBatch == null || _sortLock || rooms.length < 2) return; diff --git a/lib/src/room.dart b/lib/src/room.dart index 9450f22..eb55a8d 100644 --- a/lib/src/room.dart +++ b/lib/src/room.dart @@ -361,6 +361,40 @@ class Room { {'topic': newName}, ); + /// Add a tag to the room. + Future addTag(String tag, {double order}) => client.api.addRoomTag( + client.userID, + id, + tag, + order: order, + ); + + /// Removes a tag from the room. + Future removeTag(String tag) => client.api.removeRoomTag( + client.userID, + id, + tag, + ); + + /// Returns all tags for this room. + Map get tags { + if (roomAccountData['m.tag'] == null || + !(roomAccountData['m.tag'].content['tags'] is Map)) { + return {}; + } + final tags = (roomAccountData['m.tag'].content['tags'] as Map) + .map((k, v) => MapEntry(k, Tag.fromJson(v))); + tags.removeWhere((k, v) => !TagType.isValid(k)); + return tags; + } + + /// Returns true if this room has a m.favourite tag. + bool get isFavourite => tags[TagType.Favourite] != null; + + /// Sets the m.favourite tag for this room. + Future setFavourite(bool favourite) => + favourite ? addTag(TagType.Favourite) : removeTag(TagType.Favourite); + /// Call the Matrix API to change the pinned events of this room. Future setPinnedEvents(List pinnedEventIds) => client.api.sendState( diff --git a/test/fake_matrix_api.dart b/test/fake_matrix_api.dart index 4bde4c5..a609771 100644 --- a/test/fake_matrix_api.dart +++ b/test/fake_matrix_api.dart @@ -1791,6 +1791,8 @@ class FakeMatrixApi extends MockClient { (var reqI) => { 'event_id': '\$event${FakeMatrixApi.eventCounter++}', }, + '/client/r0/user/%40test%3AfakeServer.notExisting/rooms/%21localpart%3Aserver.abc/tags/m.favourite': + (var req) => {}, '/client/r0/user/%40alice%3Aexample.com/rooms/%21localpart%3Aexample.com/tags/testtag': (var req) => {}, '/client/r0/user/%40alice%3Aexample.com/account_data/test.account.data': @@ -1839,6 +1841,8 @@ class FakeMatrixApi extends MockClient { '/client/r0/pushrules/global/content/nocake': (var req) => {}, '/client/r0/pushrules/global/override/!localpart%3Aserver.abc': (var req) => {}, + '/client/r0/user/%40test%3AfakeServer.notExisting/rooms/%21localpart%3Aserver.abc/tags/m.favourite': + (var req) => {}, '/client/r0/user/%40alice%3Aexample.com/rooms/%21localpart%3Aexample.com/tags/testtag': (var req) => {}, }, diff --git a/test/room_test.dart b/test/room_test.dart index 3fc0398..a4ac925 100644 --- a/test/room_test.dart +++ b/test/room_test.dart @@ -409,6 +409,25 @@ void main() { await room.sendCallCandidates('1234', [], txid: '1234'); }); + test('Test tag methods', () async { + await room.addTag(TagType.Favourite, order: 0.1); + await room.removeTag(TagType.Favourite); + expect(room.isFavourite, false); + room.roomAccountData['m.tag'] = BasicRoomEvent.fromJson({ + 'content': { + 'tags': { + 'm.favourite': {'order': 0.1}, + 'm.wrong': {'order': 0.2}, + } + }, + 'type': 'm.tag' + }); + expect(room.tags.length, 1); + expect(room.tags[TagType.Favourite].order, 0.1); + expect(room.isFavourite, true); + await room.setFavourite(false); + }); + test('joinRules', () async { expect(room.canChangeJoinRules, false); expect(room.joinRules, JoinRules.public);