diff --git a/lib/src/Client.dart b/lib/src/Client.dart index f2422f4e..344eb800 100644 --- a/lib/src/Client.dart +++ b/lib/src/Client.dart @@ -98,9 +98,6 @@ class Client { /// A list of all rooms the user is participating or invited. RoomList roomList; - /// A list of all rooms the user is not participating anymore. - RoomList archive; - /// Key/Value store of account data. Map accountData = {}; @@ -262,27 +259,33 @@ class Client { /// Creates a new [RoomList] object. RoomList getRoomList( - {bool onlyLeft = false, - onRoomListUpdateCallback onUpdate, + {onRoomListUpdateCallback onUpdate, onRoomListInsertCallback onInsert, onRoomListRemoveCallback onRemove}) { - List rooms = onlyLeft ? archive.rooms : roomList.rooms; + List rooms = roomList.rooms; return RoomList( client: this, - onlyLeft: onlyLeft, + onlyLeft: false, onUpdate: onUpdate, onInsert: onInsert, onRemove: onRemove, rooms: rooms); } - /// Searches in the roomList and in the archive for a room with the given [id]. - Room getRoomById(String id) { - Room room = roomList.getRoomById(id); - if (room == null) room = archive.getRoomById(id); - return room; + Future get archive async { + RoomList archiveList = RoomList(client: this, rooms: [], onlyLeft: true); + String syncFilters = + '{"room":{"include_leave":true,"timeline":{"limit":1}}}'; + String action = "/client/r0/sync?filter=$syncFilters&timeout=0"; + final syncResp = + await connection.jsonRequest(type: HTTPType.GET, action: action); + if (!(syncResp is ErrorResponse)) await connection.handleSync(syncResp); + return archiveList; } + /// Searches in the roomList and in the archive for a room with the given [id]. + Room getRoomById(String id) => roomList.getRoomById(id); + Future joinRoomById(String id) async { return await connection.jsonRequest( type: HTTPType.POST, action: "/client/r0/join/$id"); diff --git a/lib/src/Connection.dart b/lib/src/Connection.dart index 273ab30a..d201b796 100644 --- a/lib/src/Connection.dart +++ b/lib/src/Connection.dart @@ -49,9 +49,6 @@ class Connection { static String syncFilters = '{"room":{"state":{"lazy_load_members":true}}}'; - static String firstSyncFilters = - '{"room":{"include_leave":true,"state":{"lazy_load_members":true}}}'; - /// Handles the connection to the Matrix Homeserver. You can change this to a /// MockClient for testing. http.Client httpClient = http.Client(); @@ -145,11 +142,9 @@ class Connection { client.prevBatch = newPrevBatch; List rooms = []; - List archivedRooms = []; if (client.store != null) { client.store.storeClient(); rooms = await client.store.getRoomList(onlyLeft: false); - archivedRooms = await client.store.getRoomList(onlyLeft: true); client.accountData = await client.store.getAccountData(); client.presences = await client.store.getPresences(); } @@ -162,14 +157,6 @@ class Connection { onRemove: null, rooms: rooms); - client.archive = RoomList( - client: client, - onlyLeft: true, - onUpdate: null, - onInsert: null, - onRemove: null, - rooms: archivedRooms); - _userEventSub ??= onUserEvent.stream.listen(client.handleUserUpdate); onLoginStateChanged.add(LoginState.logged); @@ -309,10 +296,9 @@ class Connection { Future _sync() async { if (client.isLogged() == false) return; - String action = "/client/r0/sync?filter=$firstSyncFilters"; + String action = "/client/r0/sync?filter=$syncFilters"; if (client.prevBatch != null) { - action = "/client/r0/sync?filter=$syncFilters"; action += "&timeout=30000"; action += "&since=${client.prevBatch}"; } @@ -327,12 +313,12 @@ class Connection { try { if (client.store != null) await client.store.transaction(() { - _handleSync(syncResp); + handleSync(syncResp); client.store.storePrevBatch(syncResp); return; }); else - await _handleSync(syncResp); + await handleSync(syncResp); if (client.prevBatch == null) client.connection.onFirstSync.add(true); client.prevBatch = syncResp["next_batch"]; } catch (e) { @@ -344,7 +330,7 @@ class Connection { if (hash == _syncRequest.hashCode) _sync(); } - void _handleSync(dynamic sync) { + void handleSync(dynamic sync) { if (sync["rooms"] is Map) { if (sync["rooms"]["join"] is Map) _handleRooms(sync["rooms"]["join"], Membership.join); diff --git a/lib/src/Room.dart b/lib/src/Room.dart index e71a05c4..c44fd85b 100644 --- a/lib/src/Room.dart +++ b/lib/src/Room.dart @@ -203,11 +203,25 @@ class Room { !canonicalAlias.isEmpty && canonicalAlias.length > 3) return canonicalAlias.substring(1, canonicalAlias.length).split(":")[0]; - if (mHeroes != null && mHeroes.length > 0 && mHeroes.any((h) => h.isNotEmpty)) { + List heroes = []; + if (mHeroes != null && + mHeroes.length > 0 && + mHeroes.any((h) => h.isNotEmpty)) { + heroes = mHeroes; + } else { + if (states["m.room.member"] is Map) { + for (var entry in states["m.room.member"].entries) { + RoomState state = entry.value; + if (state.type == EventTypes.RoomMember && + state.stateKey != client?.userID) heroes.add(state.stateKey); + } + } + } + if (heroes.length > 0) { String displayname = ""; - for (int i = 0; i < mHeroes.length; i++) { - if (mHeroes[i].isEmpty) continue; - displayname += User(mHeroes[i]).calcDisplayname() + ", "; + for (int i = 0; i < heroes.length; i++) { + if (heroes[i].isEmpty) continue; + displayname += User(heroes[i]).calcDisplayname() + ", "; } return displayname.substring(0, displayname.length - 2); } @@ -679,7 +693,6 @@ class Room { List getParticipants() { List userList = []; if (states["m.room.member"] is Map) { - print('Check members: ${states["m.room.member"].length}'); for (var entry in states["m.room.member"].entries) { RoomState state = entry.value; if (state.type == EventTypes.RoomMember) userList.add(state.asUser); diff --git a/test/Client_test.dart b/test/Client_test.dart index 22b6e0ea..13fbb66b 100644 --- a/test/Client_test.dart +++ b/test/Client_test.dart @@ -27,6 +27,7 @@ import 'package:famedlysdk/src/AccountData.dart'; import 'package:famedlysdk/src/Client.dart'; import 'package:famedlysdk/src/Connection.dart'; import 'package:famedlysdk/src/Presence.dart'; +import 'package:famedlysdk/src/RoomList.dart'; import 'package:famedlysdk/src/User.dart'; import 'package:famedlysdk/src/requests/SetPushersRequest.dart'; import 'package:famedlysdk/src/responses/ErrorResponse.dart'; @@ -207,7 +208,7 @@ void main() { List roomUpdateList = await roomUpdateListFuture; - expect(roomUpdateList.length, 3); + expect(roomUpdateList.length, 2); expect(roomUpdateList[0].id == "!726s6s6q:example.com", true); expect(roomUpdateList[0].membership == Membership.join, true); @@ -222,13 +223,6 @@ void main() { expect(roomUpdateList[1].limitedTimeline == false, true); expect(roomUpdateList[1].notification_count == 0, true); expect(roomUpdateList[1].highlight_count == 0, true); - - expect(roomUpdateList[2].id == "!5345234234:example.com", true); - expect(roomUpdateList[2].membership == Membership.leave, true); - expect(roomUpdateList[2].prev_batch == "", true); - expect(roomUpdateList[2].limitedTimeline == false, true); - expect(roomUpdateList[2].notification_count == 0, true); - expect(roomUpdateList[2].highlight_count == 0, true); }); test('Event Update Test', () async { @@ -364,6 +358,15 @@ void main() { expect(resp["room_id"], roomID); }); + test('get archive', () async { + RoomList archive = await matrix.archive; + + await new Future.delayed(new Duration(milliseconds: 50)); + expect(archive.rooms.length, 1); + expect(archive.rooms[0].id, "!5345234234:example.com"); + expect(archive.rooms[0].membership, Membership.leave); + }); + test('Logout when token is unknown', () async { Future loginStateFuture = matrix.connection.onLoginStateChanged.stream.first; diff --git a/test/FakeMatrixApi.dart b/test/FakeMatrixApi.dart index ead161f2..c0d1a785 100644 --- a/test/FakeMatrixApi.dart +++ b/test/FakeMatrixApi.dart @@ -62,6 +62,176 @@ class FakeMatrixApi extends MockClient { return Response(json.encode(res), 100); }); + static Map syncResponse = { + "next_batch": Random().nextDouble().toString(), + "presence": { + "events": [ + { + "sender": "@alice:example.com", + "type": "m.presence", + "content": {"presence": "online"} + } + ] + }, + "account_data": { + "events": [ + { + "type": "org.example.custom.config", + "content": {"custom_config_key": "custom_config_value"} + }, + { + "content": { + "@bob:example.com": [ + "!726s6s6q:example.com", + "!hgfedcba:example.com" + ] + }, + "type": "m.direct" + }, + ] + }, + "to_device": { + "events": [ + { + "sender": "@alice:example.com", + "type": "m.new_device", + "content": { + "device_id": "XYZABCDE", + "rooms": ["!726s6s6q:example.com"] + } + } + ] + }, + "rooms": { + "join": { + "!726s6s6q:example.com": { + "unread_notifications": { + "highlight_count": 2, + "notification_count": 2, + }, + "state": { + "events": [ + { + "sender": "@alice:example.com", + "type": "m.room.member", + "state_key": "@alice:example.com", + "content": {"membership": "join"}, + "origin_server_ts": 1417731086795, + "event_id": "66697273743031:example.com" + }, + { + "sender": "@alice:example.com", + "type": "m.room.canonical_alias", + "content": { + "alias": "#famedlyContactDiscovery:fakeServer.notExisting" + }, + "state_key": "", + "origin_server_ts": 1417731086796, + "event_id": "66697273743032:example.com" + } + ] + }, + "timeline": { + "events": [ + { + "sender": "@bob:example.com", + "type": "m.room.member", + "state_key": "@bob:example.com", + "content": {"membership": "join"}, + "prev_content": {"membership": "invite"}, + "origin_server_ts": 1417731086795, + "event_id": "7365636s6r6432:example.com" + }, + { + "sender": "@alice:example.com", + "type": "m.room.message", + "txn_id": "1234", + "content": {"body": "I am a fish", "msgtype": "m.text"}, + "origin_server_ts": 1417731086797, + "event_id": "74686972643033:example.com" + } + ], + "limited": true, + "prev_batch": "t34-23535_0_0" + }, + "ephemeral": { + "events": [ + { + "type": "m.typing", + "content": { + "user_ids": ["@alice:example.com"] + } + }, + { + "content": { + "7365636s6r6432:example.com": { + "m.read": { + "@alice:example.com": {"ts": 1436451550453} + } + } + }, + "room_id": "!726s6s6q:example.com", + "type": "m.receipt" + } + ] + }, + "account_data": { + "events": [ + { + "type": "m.tag", + "content": { + "tags": { + "work": {"order": 1} + } + } + }, + { + "type": "org.example.custom.room.config", + "content": {"custom_config_key": "custom_config_value"} + } + ] + } + } + }, + "invite": { + "!696r7674:example.com": { + "invite_state": { + "events": [ + { + "sender": "@alice:example.com", + "type": "m.room.name", + "state_key": "", + "content": {"name": "My Room Name"} + }, + { + "sender": "@alice:example.com", + "type": "m.room.member", + "state_key": "@bob:example.com", + "content": {"membership": "invite"} + } + ] + } + } + }, + } + }; + + static Map archiveSyncResponse = { + "next_batch": Random().nextDouble().toString(), + "presence": {"events": []}, + "account_data": {"events": []}, + "to_device": {"events": []}, + "rooms": { + "join": {}, + "invite": {}, + "leave": { + "!5345234234:example.com": { + "timeline": {"events": []} + }, + }, + } + }; + static final Map> api = { "GET": { "/client/r0/rooms/!localpart:server.abc/state/m.room.member/@getme:example.com": @@ -339,171 +509,10 @@ class FakeMatrixApi extends MockClient { ] } }, - "/client/r0/sync?filter=%7B%22room%22:%7B%22include_leave%22:true,%22state%22:%7B%22lazy_load_members%22:true%7D%7D%7D": - (var req) => { - "next_batch": Random().nextDouble().toString(), - "presence": { - "events": [ - { - "sender": "@alice:example.com", - "type": "m.presence", - "content": {"presence": "online"} - } - ] - }, - "account_data": { - "events": [ - { - "type": "org.example.custom.config", - "content": {"custom_config_key": "custom_config_value"} - }, - { - "content": { - "@bob:example.com": [ - "!726s6s6q:example.com", - "!hgfedcba:example.com" - ] - }, - "type": "m.direct" - }, - ] - }, - "to_device": { - "events": [ - { - "sender": "@alice:example.com", - "type": "m.new_device", - "content": { - "device_id": "XYZABCDE", - "rooms": ["!726s6s6q:example.com"] - } - } - ] - }, - "rooms": { - "join": { - "!726s6s6q:example.com": { - "unread_notifications": { - "highlight_count": 2, - "notification_count": 2, - }, - "state": { - "events": [ - { - "sender": "@alice:example.com", - "type": "m.room.member", - "state_key": "@alice:example.com", - "content": {"membership": "join"}, - "origin_server_ts": 1417731086795, - "event_id": "66697273743031:example.com" - }, - { - "sender": "@alice:example.com", - "type": "m.room.canonical_alias", - "content": { - "alias": - "#famedlyContactDiscovery:fakeServer.notExisting" - }, - "state_key": "", - "origin_server_ts": 1417731086796, - "event_id": "66697273743032:example.com" - } - ] - }, - "timeline": { - "events": [ - { - "sender": "@bob:example.com", - "type": "m.room.member", - "state_key": "@bob:example.com", - "content": {"membership": "join"}, - "prev_content": {"membership": "invite"}, - "origin_server_ts": 1417731086795, - "event_id": "7365636s6r6432:example.com" - }, - { - "sender": "@alice:example.com", - "type": "m.room.message", - "txn_id": "1234", - "content": { - "body": "I am a fish", - "msgtype": "m.text" - }, - "origin_server_ts": 1417731086797, - "event_id": "74686972643033:example.com" - } - ], - "limited": true, - "prev_batch": "t34-23535_0_0" - }, - "ephemeral": { - "events": [ - { - "type": "m.typing", - "content": { - "user_ids": ["@alice:example.com"] - } - }, - { - "content": { - "7365636s6r6432:example.com": { - "m.read": { - "@alice:example.com": {"ts": 1436451550453} - } - } - }, - "room_id": "!726s6s6q:example.com", - "type": "m.receipt" - } - ] - }, - "account_data": { - "events": [ - { - "type": "m.tag", - "content": { - "tags": { - "work": {"order": 1} - } - } - }, - { - "type": "org.example.custom.room.config", - "content": { - "custom_config_key": "custom_config_value" - } - } - ] - } - } - }, - "invite": { - "!696r7674:example.com": { - "invite_state": { - "events": [ - { - "sender": "@alice:example.com", - "type": "m.room.name", - "state_key": "", - "content": {"name": "My Room Name"} - }, - { - "sender": "@alice:example.com", - "type": "m.room.member", - "state_key": "@bob:example.com", - "content": {"membership": "invite"} - } - ] - } - } - }, - "leave": { - "!5345234234:example.com": { - "timeline": {"events": []} - }, - }, - } - }, + "/client/r0/sync?filter=%7B%22room%22:%7B%22include_leave%22:true,%22timeline%22:%7B%22limit%22:1%7D%7D%7D&timeout=0": + (var req) => archiveSyncResponse, + "/client/r0/sync?filter=%7B%22room%22:%7B%22state%22:%7B%22lazy_load_members%22:true%7D%7D%7D": + (var req) => syncResponse, }, "POST": { "/client/r0/login": (var req) => {