From 98bb93e657334ac03c602c4d217907501a55121b Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 6 Aug 2019 09:47:09 +0000 Subject: [PATCH] [Room] Add support for RoomSummary --- lib/src/Client.dart | 2 +- lib/src/Connection.dart | 7 ++++++ lib/src/Room.dart | 43 +++++++++++++++++++++++------------- lib/src/RoomList.dart | 19 +++++++++------- lib/src/Store.dart | 39 +++++++++++++++++++++++--------- lib/src/sync/RoomUpdate.dart | 18 +++++++++++++++ test/FakeMatrixApi.dart | 9 +++++++- test/Room_test.dart | 21 +++++++++++++++++- 8 files changed, 121 insertions(+), 37 deletions(-) diff --git a/lib/src/Client.dart b/lib/src/Client.dart index 9b12501..28dcb07 100644 --- a/lib/src/Client.dart +++ b/lib/src/Client.dart @@ -107,7 +107,7 @@ class Client { } for (int i = 0; i < versions.length; i++) { - if (versions[i] == "r0.4.0") + if (versions[i] == "r0.5.0") break; else if (i == versions.length - 1) { connection.onError.add(ErrorResponse(errcode: "NO_SUPPORT", error: "")); diff --git a/lib/src/Connection.dart b/lib/src/Connection.dart index 479daaa..68cdecf 100644 --- a/lib/src/Connection.dart +++ b/lib/src/Connection.dart @@ -343,6 +343,12 @@ class Connection { prev_batch = room["timeline"]["prev_batch"]; } + RoomSummary summary; + + if (room["summary"] is Map) { + summary = RoomSummary.fromJson(room["summary"]); + } + RoomUpdate update = RoomUpdate( id: id, membership: membership, @@ -350,6 +356,7 @@ class Connection { highlight_count: highlight_count, limitedTimeline: limitedTimeline, prev_batch: prev_batch, + summary: summary, ); client.store?.storeRoomUpdate(update); onRoomUpdate.add(update); diff --git a/lib/src/Room.dart b/lib/src/Room.dart index a43d3f6..0f265c5 100644 --- a/lib/src/Room.dart +++ b/lib/src/Room.dart @@ -43,9 +43,6 @@ class Room { /// The name of the room if set by a participant. String name; - /// Whether this room has a name or the name is generated by member names. - bool hasName = false; - /// The topic of the room if set by a participant. String topic; @@ -89,6 +86,10 @@ class Room { /// The needed power levels for all actions. Map powerLevels = {}; + List mHeroes; + int mJoinedMemberCount; + int mInvitedMemberCount; + Event lastEvent; /// Your current client instance. @@ -107,7 +108,6 @@ class Room { this.id, this.membership, this.name, - this.hasName = false, this.topic, this.avatar, this.notificationCount, @@ -125,8 +125,28 @@ class Room { this.powerLevels, this.lastEvent, this.client, + this.mHeroes, + this.mInvitedMemberCount, + this.mJoinedMemberCount, }); + /// Calculates the displayname. First checks if there is a name, then checks for a canonical alias and + /// then generates a name from the heroes. + String get displayname { + if (name != null && !name.isEmpty) return name; + if (canonicalAlias != null && + !canonicalAlias.isEmpty && + canonicalAlias.length > 3) + return canonicalAlias.substring(1, canonicalAlias.length).split(":")[0]; + if (mHeroes.length > 0) { + String displayname = ""; + for (int i = 0; i < mHeroes.length; i++) + displayname += User(mHeroes[i]).calcDisplayname() + ", "; + return displayname.substring(0, displayname.length - 2); + } + return "Empty chat"; + } + /// The last message sent to this room. String get lastMessage { if (lastEvent != null) @@ -378,23 +398,13 @@ class Room { /// Returns a Room from a json String which comes normally from the store. static Future getRoomFromTableRow( Map row, Client matrix) async { - bool newHasName = false; - String name = row["topic"]; - if (name == "" && !row["canonical_alias"].isEmpty) - name = row["canonical_alias"]; - else if (name == "") - name = await matrix.store?.getChatNameFromMemberNames(row["id"]) ?? ""; - else - newHasName = true; - String avatarUrl = row["avatar_url"]; if (avatarUrl == "") avatarUrl = await matrix.store?.getAvatarFromSingleChat(row["id"]) ?? ""; return Room( id: row["id"], - name: name, - hasName: newHasName, + name: row["topic"], membership: Membership.values .firstWhere((e) => e.toString() == 'Membership.' + row["membership"]), topic: row["description"], @@ -411,6 +421,9 @@ class Room { historyVisibility: row["history_visibility"], joinRules: row["join_rules"], canonicalAlias: row["canonical_alias"], + mInvitedMemberCount: row["invited_member_count"], + mJoinedMemberCount: row["joined_member_count"], + mHeroes: row["heroes"]?.split(",") ?? [], powerLevels: { "power_events_default": row["power_events_default"], "power_state_default": row["power_state_default"], diff --git a/lib/src/RoomList.dart b/lib/src/RoomList.dart index 61461e6..c3d1f2d 100644 --- a/lib/src/RoomList.dart +++ b/lib/src/RoomList.dart @@ -92,7 +92,9 @@ class RoomList { prev_batch: chatUpdate.prev_batch, highlightCount: chatUpdate.highlight_count, notificationCount: chatUpdate.notification_count, - hasName: false, + mHeroes: chatUpdate.summary?.mHeroes, + mJoinedMemberCount: chatUpdate.summary?.mJoinedMemberCount, + mInvitedMemberCount: chatUpdate.summary?.mInvitedMemberCount, ); rooms.insert(position, newRoom); if (onInsert != null) onInsert(position); @@ -110,6 +112,14 @@ class RoomList { rooms[j].highlightCount != chatUpdate.highlight_count)) { rooms[j].notificationCount = chatUpdate.notification_count; rooms[j].highlightCount = chatUpdate.highlight_count; + if (chatUpdate.summary != null) { + if (chatUpdate.summary.mHeroes != null) + rooms[j].mHeroes = chatUpdate.summary.mHeroes; + if (chatUpdate.summary.mJoinedMemberCount != null) + rooms[j].mJoinedMemberCount = chatUpdate.summary.mJoinedMemberCount; + if (chatUpdate.summary.mInvitedMemberCount != null) + rooms[j].mInvitedMemberCount = chatUpdate.summary.mInvitedMemberCount; + } } sortAndUpdate(); } @@ -156,8 +166,6 @@ class RoomList { // Update the room avatar rooms[j].avatar = MxContent(eventUpdate.content["content"]["url"]); } - if (eventUpdate.eventType == "m.room.member" && !rooms[j].hasName) - updateMemberName(j); sortAndUpdate(); } @@ -166,11 +174,6 @@ class RoomList { b.timeCreated.toTimeStamp().compareTo(a.timeCreated.toTimeStamp())); if (onUpdate != null) onUpdate(); } - - void updateMemberName(int position) async { - rooms[position].name = - await client.store.getChatNameFromMemberNames(rooms[position].id); - } } typedef onRoomListUpdateCallback = void Function(); diff --git a/lib/src/Store.dart b/lib/src/Store.dart index 0e79109..80bb54e 100644 --- a/lib/src/Store.dart +++ b/lib/src/Store.dart @@ -55,7 +55,7 @@ class Store { _init() async { var databasePath = await getDatabasesPath(); String path = p.join(databasePath, "FluffyMatrix.db"); - _db = await openDatabase(path, version: 10, + _db = await openDatabase(path, version: 11, onCreate: (Database db, int version) async { await createTables(db); }, onUpgrade: (Database db, int oldVersion, int newVersion) async { @@ -164,18 +164,32 @@ class Store { // Insert the chat into the database if not exists txn.rawInsert( "INSERT OR IGNORE INTO Rooms " + - "VALUES(?, ?, '', 0, 0, '', '', '', 0, '', '', '', '', '', '', '', '', 0, 50, 50, 0, 50, 50, 0, 50, 100, 50, 50, 50, 100) ", + "VALUES(?, ?, '', 0, 0, 0, 0, '', '', '', '', 0, '', '', '', '', '', '', '', '', 0, 50, 50, 0, 50, 50, 0, 50, 100, 50, 50, 50, 100) ", [roomUpdate.id, roomUpdate.membership.toString().split('.').last]); - // Update the notification counts and the limited timeline boolean - txn.rawUpdate( - "UPDATE Rooms SET highlight_count=?, notification_count=?, membership=? WHERE id=? ", - [ - roomUpdate.highlight_count, - roomUpdate.notification_count, - roomUpdate.membership.toString().split('.').last, - roomUpdate.id - ]); + // Update the notification counts and the limited timeline boolean and the summary + String updateQuery = + "UPDATE Rooms SET highlight_count=?, notification_count=?, membership=?"; + List updateArgs = [ + roomUpdate.highlight_count, + roomUpdate.notification_count, + roomUpdate.membership.toString().split('.').last + ]; + if (roomUpdate.summary?.mJoinedMemberCount != null) { + updateQuery += ", joined_member_count=?"; + updateArgs.add(roomUpdate.summary.mJoinedMemberCount); + } + if (roomUpdate.summary?.mInvitedMemberCount != null) { + updateQuery += ", invited_member_count=?"; + updateArgs.add(roomUpdate.summary.mInvitedMemberCount); + } + if (roomUpdate.summary?.mHeroes != null) { + updateQuery += ", heroes=?"; + updateArgs.add(roomUpdate.summary.mHeroes.join(",")); + } + updateQuery += " WHERE id=?"; + updateArgs.add(roomUpdate.id); + txn.rawUpdate(updateQuery, updateArgs); // Is the timeline limited? Then all previous messages should be // removed from the database! @@ -691,6 +705,9 @@ class Store { 'topic TEXT, ' + 'highlight_count INTEGER, ' + 'notification_count INTEGER, ' + + 'joined_member_count INTEGER, ' + + 'invited_member_count INTEGER, ' + + 'heroes TEXT, ' + 'prev_batch TEXT, ' + 'avatar_url TEXT, ' + 'draft TEXT, ' + diff --git a/lib/src/sync/RoomUpdate.dart b/lib/src/sync/RoomUpdate.dart index 2f8abcb..ba8efdd 100644 --- a/lib/src/sync/RoomUpdate.dart +++ b/lib/src/sync/RoomUpdate.dart @@ -46,6 +46,8 @@ class RoomUpdate { /// Represents the current position of the client in the room history. final String prev_batch; + final RoomSummary summary; + RoomUpdate({ this.id, this.membership, @@ -53,5 +55,21 @@ class RoomUpdate { this.highlight_count, this.limitedTimeline, this.prev_batch, + this.summary, }); } + +class RoomSummary { + List mHeroes; + int mJoinedMemberCount; + int mInvitedMemberCount; + + RoomSummary( + {this.mHeroes, this.mJoinedMemberCount, this.mInvitedMemberCount}); + + RoomSummary.fromJson(Map json) { + mHeroes = json['m.heroes']?.cast(); + mJoinedMemberCount = json['m.joined_member_count']; + mInvitedMemberCount = json['m.invited_member_count']; + } +} diff --git a/test/FakeMatrixApi.dart b/test/FakeMatrixApi.dart index 58a9380..5f3e8a9 100644 --- a/test/FakeMatrixApi.dart +++ b/test/FakeMatrixApi.dart @@ -138,7 +138,14 @@ class FakeMatrixApi extends MockClient { ] }, "/client/versions": (var req) => { - "versions": ["r0.0.1", "r0.1.0", "r0.2.0", "r0.3.0", "r0.4.0"], + "versions": [ + "r0.0.1", + "r0.1.0", + "r0.2.0", + "r0.3.0", + "r0.4.0", + "r0.5.0" + ], "unstable_features": {"m.lazy_load_members": true}, }, "/client/r0/login": (var req) => { diff --git a/test/Room_test.dart b/test/Room_test.dart index ac50fd1..b70be7f 100644 --- a/test/Room_test.dart +++ b/test/Room_test.dart @@ -68,8 +68,13 @@ void main() { final String formatted_body = "Hello World"; final String contentJson = '{"msgtype":"$msgtype","body":"$body","formatted_body":"$formatted_body"}'; + final List heroes = [ + "@alice:matrix.org", + "@bob:example.com", + "@charley:example.org" + ]; - final Map jsonObj = { + Map jsonObj = { "id": id, "membership": membership.toString().split('.').last, "topic": name, @@ -101,6 +106,9 @@ void main() { "power_event_name": 0, "power_event_power_levels": 0, "content_json": contentJson, + "joined_member_count": notificationCount, + "invited_member_count": notificationCount, + "heroes": heroes.join(","), }; room = await Room.getRoomFromTableRow(jsonObj, matrix); @@ -108,6 +116,7 @@ void main() { expect(room.id, id); expect(room.membership, membership); expect(room.name, name); + expect(room.displayname, name); expect(room.topic, topic); expect(room.avatar.mxc, ""); expect(room.notificationCount, notificationCount); @@ -127,6 +136,16 @@ void main() { room.powerLevels.forEach((String key, int value) { expect(value, 0); }); + expect(room.mJoinedMemberCount, notificationCount); + expect(room.mInvitedMemberCount, notificationCount); + expect(room.mHeroes, heroes); + + jsonObj["topic"] = ""; + room = await Room.getRoomFromTableRow(jsonObj, matrix); + expect(room.displayname, "testroom"); + jsonObj["canonical_alias"] = ""; + room = await Room.getRoomFromTableRow(jsonObj, matrix); + expect(room.displayname, "alice, bob, charley"); }); test("sendReadReceipt", () async {