From 372c185228816b7d677e94397167c5db529358b3 Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Fri, 21 Jun 2019 09:46:53 +0200 Subject: [PATCH 1/3] [License] Replace 'foobar' with 'famedlysdk' in all Files. --- lib/famedlysdk.dart | 4 +- lib/src/Client.dart | 2 +- lib/src/Connection.dart | 2 +- lib/src/Event.dart | 77 ++++--- lib/src/Room.dart | 2 +- lib/src/Store.dart | 2 +- lib/src/User.dart | 2 +- lib/src/responses/ErrorResponse.dart | 3 +- lib/src/sync/EventUpdate.dart | 3 +- lib/src/sync/RoomUpdate.dart | 3 +- lib/src/sync/UserUpdate.dart | 3 +- lib/src/utils/ChatTime.dart | 21 +- lib/src/utils/MxContent.dart | 2 +- test/ChatTime_test.dart | 21 +- test/Client_test.dart | 2 +- test/Event_test.dart | 2 +- test/FakeMatrixApi.dart | 325 ++++++++++++--------------- test/MxContent_test.dart | 16 +- test/Room_test.dart | 2 +- test/User_test.dart | 18 +- 20 files changed, 243 insertions(+), 269 deletions(-) diff --git a/lib/famedlysdk.dart b/lib/famedlysdk.dart index 145ffd51..453fc388 100644 --- a/lib/famedlysdk.dart +++ b/lib/famedlysdk.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ library famedlysdk; @@ -33,4 +33,4 @@ export 'package:famedlysdk/src/Connection.dart'; export 'package:famedlysdk/src/Event.dart'; export 'package:famedlysdk/src/Room.dart'; export 'package:famedlysdk/src/Store.dart'; -export 'package:famedlysdk/src/User.dart'; \ No newline at end of file +export 'package:famedlysdk/src/User.dart'; diff --git a/lib/src/Client.dart b/lib/src/Client.dart index 3ae68cb3..c83fad2e 100644 --- a/lib/src/Client.dart +++ b/lib/src/Client.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'dart:async'; diff --git a/lib/src/Connection.dart b/lib/src/Connection.dart index 77d3c25b..ede7d86a 100644 --- a/lib/src/Connection.dart +++ b/lib/src/Connection.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'dart:async'; diff --git a/lib/src/Event.dart b/lib/src/Event.dart index 373d3421..37851aed 100644 --- a/lib/src/Event.dart +++ b/lib/src/Event.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'dart:convert'; @@ -29,7 +29,6 @@ import './Room.dart'; /// A single Matrix event, e.g. a message in a chat. class Event { - /// The Matrix ID for this event in the format '$localpart:server.abc'. final String id; @@ -56,9 +55,12 @@ class Event { int status; /// The json payload of the content. The content highly depends on the type. - final Map content; + final Map content; - Event(this.id, this.sender, this.time,{ + Event( + this.id, + this.sender, + this.time, { this.room, this.stateKey, this.status = 2, @@ -73,7 +75,7 @@ class Event { String get formattedText => content["formatted_body"] ?? ""; /// Use this to get the body. - String getBody () { + String getBody() { if (text != "") return text; if (formattedText != "") return formattedText; return "*** Unable to parse Content ***"; @@ -82,36 +84,52 @@ class Event { /// Get the real type. EventTypes get type { switch (environment) { - case "m.room.avatar": return EventTypes.RoomAvatar; - case "m.room.name": return EventTypes.RoomName; - case "m.room.topic": return EventTypes.RoomTopic; - case "m.room.Aliases": return EventTypes.RoomAliases; - case "m.room.canonical_alias": return EventTypes.RoomCanonicalAlias; - case "m.room.create": return EventTypes.RoomCreate; - case "m.room.join_rules": return EventTypes.RoomJoinRules; - case "m.room.member": return EventTypes.RoomMember; - case "m.room.power_levels": return EventTypes.RoomPowerLevels; + case "m.room.avatar": + return EventTypes.RoomAvatar; + case "m.room.name": + return EventTypes.RoomName; + case "m.room.topic": + return EventTypes.RoomTopic; + case "m.room.Aliases": + return EventTypes.RoomAliases; + case "m.room.canonical_alias": + return EventTypes.RoomCanonicalAlias; + case "m.room.create": + return EventTypes.RoomCreate; + case "m.room.join_rules": + return EventTypes.RoomJoinRules; + case "m.room.member": + return EventTypes.RoomMember; + case "m.room.power_levels": + return EventTypes.RoomPowerLevels; case "m.room.message": - switch(content["msgtype"] ?? "m.text") { - case "m.text": return EventTypes.Text; - case "m.notice": return EventTypes.Notice; - case "m.emote": return EventTypes.Emote; - case "m.image": return EventTypes.Image; - case "m.video": return EventTypes.Video; - case "m.audio": return EventTypes.Audio; - case "m.file": return EventTypes.File; - case "m.location": return EventTypes.Location; + switch (content["msgtype"] ?? "m.text") { + case "m.text": + return EventTypes.Text; + case "m.notice": + return EventTypes.Notice; + case "m.emote": + return EventTypes.Emote; + case "m.image": + return EventTypes.Image; + case "m.video": + return EventTypes.Video; + case "m.audio": + return EventTypes.Audio; + case "m.file": + return EventTypes.File; + case "m.location": + return EventTypes.Location; } } - } /// Generate a new Event object from a json string, mostly a table row. static Event fromJson(Map jsonObj, Room room) { - Map content; + Map content; try { content = json.decode(jsonObj["content_json"]); - } catch(e) { + } catch (e) { print("jsonObj decode of event content failed: ${e.toString()}"); content = {}; } @@ -128,11 +146,10 @@ class Event { } @Deprecated("Use [client.store.getEventList(Room room)] instead!") - static Future> getEventList(Client matrix, Room room) async{ + static Future> getEventList(Client matrix, Room room) async { List eventList = await matrix.store.getEventList(room); return eventList; } - } enum EventTypes { @@ -155,9 +172,9 @@ enum EventTypes { RoomAvatar, } -final Map StatusTypes = { +final Map StatusTypes = { "ERROR": -1, "SENDING": 0, "SENT": 1, "RECEIVED": 2, -}; \ No newline at end of file +}; diff --git a/lib/src/Room.dart b/lib/src/Room.dart index a4ac9c82..0ff0420c 100644 --- a/lib/src/Room.dart +++ b/lib/src/Room.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'package:famedlysdk/src/Client.dart'; diff --git a/lib/src/Store.dart b/lib/src/Store.dart index 13f244a1..979294d5 100644 --- a/lib/src/Store.dart +++ b/lib/src/Store.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'dart:async'; diff --git a/lib/src/User.dart b/lib/src/User.dart index e14c1b93..aff91227 100644 --- a/lib/src/User.dart +++ b/lib/src/User.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'package:famedlysdk/src/responses/ErrorResponse.dart'; diff --git a/lib/src/responses/ErrorResponse.dart b/lib/src/responses/ErrorResponse.dart index 02ff30b9..ff674be6 100644 --- a/lib/src/responses/ErrorResponse.dart +++ b/lib/src/responses/ErrorResponse.dart @@ -18,14 +18,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'package:http/http.dart' as http; /// Represents a special response from the Homeserver for errors. class ErrorResponse { - /// The unique identifier for this error. String errcode; diff --git a/lib/src/sync/EventUpdate.dart b/lib/src/sync/EventUpdate.dart index 66307fab..41c40b00 100644 --- a/lib/src/sync/EventUpdate.dart +++ b/lib/src/sync/EventUpdate.dart @@ -18,13 +18,12 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ /// Represents a new event (e.g. a message in a room) or an update for an /// already known event. class EventUpdate { - /// Usually 'timeline', 'state' or whatever. final String eventType; diff --git a/lib/src/sync/RoomUpdate.dart b/lib/src/sync/RoomUpdate.dart index 58573eb8..1b1db37e 100644 --- a/lib/src/sync/RoomUpdate.dart +++ b/lib/src/sync/RoomUpdate.dart @@ -18,13 +18,12 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ /// Represents a new room or an update for an /// already known room. class RoomUpdate { - /// All rooms have an idea in the format: !uniqueid:server.abc final String id; diff --git a/lib/src/sync/UserUpdate.dart b/lib/src/sync/UserUpdate.dart index 89e101bc..f4d36a73 100644 --- a/lib/src/sync/UserUpdate.dart +++ b/lib/src/sync/UserUpdate.dart @@ -18,12 +18,11 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ /// Represents a new global event like presence or account_data. class UserUpdate { - /// Usually 'presence', 'account_data' or whatever. final String eventType; diff --git a/lib/src/utils/ChatTime.dart b/lib/src/utils/ChatTime.dart index bc962960..5b57e81b 100644 --- a/lib/src/utils/ChatTime.dart +++ b/lib/src/utils/ChatTime.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ // TODO: localize this! @@ -32,8 +32,7 @@ class ChatTime { /// Insert with a timestamp [ts] which represents the milliseconds since /// the Unix epoch. ChatTime(num ts) { - if (ts != null) - dateTime = DateTime.fromMillisecondsSinceEpoch(ts); + if (ts != null) dateTime = DateTime.fromMillisecondsSinceEpoch(ts); } /// Returns a ChatTime object which represents the current time. @@ -51,12 +50,16 @@ class ChatTime { bool sameDay = sameYear && now.month == dateTime.month && now.day == dateTime.day; - bool sameWeek = sameYear && !sameDay && now.millisecondsSinceEpoch - dateTime.millisecondsSinceEpoch < 1000*60*60*24*7; + bool sameWeek = sameYear && + !sameDay && + now.millisecondsSinceEpoch - dateTime.millisecondsSinceEpoch < + 1000 * 60 * 60 * 24 * 7; if (sameDay) { return toTimeString(); } else if (sameWeek) { - switch (dateTime.weekday) { // TODO: Needs localization + switch (dateTime.weekday) { + // TODO: Needs localization case 1: return "Montag"; case 2: @@ -102,8 +105,9 @@ class ChatTime { operator ==(dynamic other) { if (other is ChatTime) - return this.toTimeStamp() == other.toTimeStamp(); - else return false; + return this.toTimeStamp() == other.toTimeStamp(); + else + return false; } /// Two message events can belong to the same environment. That means that they @@ -114,7 +118,8 @@ class ChatTime { /// Checks if two ChatTimes are close enough to belong to the same /// environment. bool sameEnvironment(ChatTime prevTime) { - return toTimeStamp() - prevTime.toTimeStamp() < 1000*60*minutesBetweenEnvironments; + return toTimeStamp() - prevTime.toTimeStamp() < + 1000 * 60 * minutesBetweenEnvironments; } /// Returns a simple time String. diff --git a/lib/src/utils/MxContent.dart b/lib/src/utils/MxContent.dart index 335b962d..d7a0c237 100644 --- a/lib/src/utils/MxContent.dart +++ b/lib/src/utils/MxContent.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'package:famedlysdk/src/Client.dart'; diff --git a/test/ChatTime_test.dart b/test/ChatTime_test.dart index a1c9e5e9..cdfd5127 100644 --- a/test/ChatTime_test.dart +++ b/test/ChatTime_test.dart @@ -18,30 +18,29 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'package:flutter_test/flutter_test.dart'; import 'package:famedlysdk/src/utils/ChatTime.dart'; void main() { - - /// All Tests related to the ChatTime group("ChatTime", () { - test("Comparing", () async { - final int originServerTs = DateTime.now().millisecondsSinceEpoch - (ChatTime.minutesBetweenEnvironments-1)*1000*60; - final int oldOriginServerTs = DateTime.now().millisecondsSinceEpoch - (ChatTime.minutesBetweenEnvironments+1)*1000*60; + final int originServerTs = DateTime.now().millisecondsSinceEpoch - + (ChatTime.minutesBetweenEnvironments - 1) * 1000 * 60; + final int oldOriginServerTs = DateTime.now().millisecondsSinceEpoch - + (ChatTime.minutesBetweenEnvironments + 1) * 1000 * 60; final ChatTime chatTime = ChatTime(originServerTs); final ChatTime oldChatTime = ChatTime(oldOriginServerTs); final ChatTime nowTime = ChatTime.now(); expect(chatTime.toTimeStamp(), originServerTs); - expect(nowTime.toTimeStamp()>chatTime.toTimeStamp(),true); - expect(nowTime.sameEnvironment(chatTime),true); - expect(nowTime.sameEnvironment(oldChatTime),false); + expect(nowTime.toTimeStamp() > chatTime.toTimeStamp(), true); + expect(nowTime.sameEnvironment(chatTime), true); + expect(nowTime.sameEnvironment(oldChatTime), false); expect(chatTime > oldChatTime, true); expect(chatTime < oldChatTime, false); @@ -55,10 +54,10 @@ void main() { final int timestamp = DateTime.now().millisecondsSinceEpoch; final ChatTime chatTime = ChatTime(timestamp); //expect(chatTime.toTimeString(),"05:36"); // This depends on the time and your timezone ;) - expect(chatTime.toTimeString(),chatTime.toEventTimeString()); + expect(chatTime.toTimeString(), chatTime.toEventTimeString()); final ChatTime oldChatTime = ChatTime(156014498475); - expect(oldChatTime.toString(),"11.12.1974"); + expect(oldChatTime.toString(), "11.12.1974"); }); }); } diff --git a/test/Client_test.dart b/test/Client_test.dart index 1ba84888..f71aa35b 100644 --- a/test/Client_test.dart +++ b/test/Client_test.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'package:famedlysdk/src/responses/PushrulesResponse.dart'; diff --git a/test/Event_test.dart b/test/Event_test.dart index 959fd929..0eb9d7ce 100644 --- a/test/Event_test.dart +++ b/test/Event_test.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'package:flutter_test/flutter_test.dart'; diff --git a/test/FakeMatrixApi.dart b/test/FakeMatrixApi.dart index f27b0573..2b35ae89 100644 --- a/test/FakeMatrixApi.dart +++ b/test/FakeMatrixApi.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'package:http/testing.dart'; @@ -90,193 +90,150 @@ class FakeMatrixApi extends MockClient { ] }, "/client/r0/pushrules": (var req) => { - "global": { - "content": [ - { - "actions": [ - "notify", + "global": { + "content": [ { - "set_tweak": "sound", - "value": "default" - }, - { - "set_tweak": "highlight" + "actions": [ + "notify", + {"set_tweak": "sound", "value": "default"}, + {"set_tweak": "highlight"} + ], + "default": true, + "enabled": true, + "pattern": "alice", + "rule_id": ".m.rule.contains_user_name" } ], - "default": true, - "enabled": true, - "pattern": "alice", - "rule_id": ".m.rule.contains_user_name" + "override": [ + { + "actions": ["dont_notify"], + "conditions": [], + "default": true, + "enabled": false, + "rule_id": ".m.rule.master" + }, + { + "actions": ["dont_notify"], + "conditions": [ + { + "key": "content.msgtype", + "kind": "event_match", + "pattern": "m.notice" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.suppress_notices" + } + ], + "room": [], + "sender": [], + "underride": [ + { + "actions": [ + "notify", + {"set_tweak": "sound", "value": "ring"}, + {"set_tweak": "highlight", "value": false} + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.call.invite" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.call" + }, + { + "actions": [ + "notify", + {"set_tweak": "sound", "value": "default"}, + {"set_tweak": "highlight"} + ], + "conditions": [ + {"kind": "contains_display_name"} + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.contains_display_name" + }, + { + "actions": [ + "notify", + {"set_tweak": "sound", "value": "default"}, + {"set_tweak": "highlight", "value": false} + ], + "conditions": [ + {"is": "2", "kind": "room_member_count"} + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.room_one_to_one" + }, + { + "actions": [ + "notify", + {"set_tweak": "sound", "value": "default"}, + {"set_tweak": "highlight", "value": false} + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + }, + { + "key": "content.membership", + "kind": "event_match", + "pattern": "invite" + }, + { + "key": "state_key", + "kind": "event_match", + "pattern": "@alice:example.com" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.invite_for_me" + }, + { + "actions": [ + "notify", + {"set_tweak": "highlight", "value": false} + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.member_event" + }, + { + "actions": [ + "notify", + {"set_tweak": "highlight", "value": false} + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.message" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.message" + } + ] } - ], - "override": [ - { - "actions": [ - "dont_notify" - ], - "conditions": [], - "default": true, - "enabled": false, - "rule_id": ".m.rule.master" - }, - { - "actions": [ - "dont_notify" - ], - "conditions": [ - { - "key": "content.msgtype", - "kind": "event_match", - "pattern": "m.notice" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.suppress_notices" - } - ], - "room": [], - "sender": [], - "underride": [ - { - "actions": [ - "notify", - { - "set_tweak": "sound", - "value": "ring" - }, - { - "set_tweak": "highlight", - "value": false - } - ], - "conditions": [ - { - "key": "type", - "kind": "event_match", - "pattern": "m.call.invite" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.call" - }, - { - "actions": [ - "notify", - { - "set_tweak": "sound", - "value": "default" - }, - { - "set_tweak": "highlight" - } - ], - "conditions": [ - { - "kind": "contains_display_name" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.contains_display_name" - }, - { - "actions": [ - "notify", - { - "set_tweak": "sound", - "value": "default" - }, - { - "set_tweak": "highlight", - "value": false - } - ], - "conditions": [ - { - "is": "2", - "kind": "room_member_count" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.room_one_to_one" - }, - { - "actions": [ - "notify", - { - "set_tweak": "sound", - "value": "default" - }, - { - "set_tweak": "highlight", - "value": false - } - ], - "conditions": [ - { - "key": "type", - "kind": "event_match", - "pattern": "m.room.member" - }, - { - "key": "content.membership", - "kind": "event_match", - "pattern": "invite" - }, - { - "key": "state_key", - "kind": "event_match", - "pattern": "@alice:example.com" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.invite_for_me" - }, - { - "actions": [ - "notify", - { - "set_tweak": "highlight", - "value": false - } - ], - "conditions": [ - { - "key": "type", - "kind": "event_match", - "pattern": "m.room.member" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.member_event" - }, - { - "actions": [ - "notify", - { - "set_tweak": "highlight", - "value": false - } - ], - "conditions": [ - { - "key": "type", - "kind": "event_match", - "pattern": "m.room.message" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.message" - } - ] - } - }, + }, "/client/r0/sync": (var req) => { "next_batch": Random().nextDouble().toString(), "presence": { diff --git a/test/MxContent_test.dart b/test/MxContent_test.dart index 3b2dec4f..cfdc5ca2 100644 --- a/test/MxContent_test.dart +++ b/test/MxContent_test.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'package:flutter_test/flutter_test.dart'; @@ -26,20 +26,22 @@ import 'package:famedlysdk/src/Client.dart'; import 'package:famedlysdk/src/utils/MxContent.dart'; void main() { - - /// All Tests related to the MxContent group("MxContent", () { - test("Formatting", () async { Client client = Client("testclient"); client.homeserver = "https://testserver.abc"; final String mxc = "mxc://exampleserver.abc/abcdefghijklmn"; final MxContent content = MxContent(mxc); - expect(content.getDownloadLink(client),"${client.homeserver}/_matrix/media/r0/download/exampleserver.abc/abcdefghijklmn"); - expect(content.getThumbnail(client, width: 50, height: 50),"${client.homeserver}/_matrix/media/r0/thumbnail/exampleserver.abc/abcdefghijklmn?width=50&height=50&method=crop"); - expect(content.getThumbnail(client, width: 50, height: 50, method: ThumbnailMethod.scale),"${client.homeserver}/_matrix/media/r0/thumbnail/exampleserver.abc/abcdefghijklmn?width=50&height=50&method=scale"); + expect(content.getDownloadLink(client), + "${client.homeserver}/_matrix/media/r0/download/exampleserver.abc/abcdefghijklmn"); + expect(content.getThumbnail(client, width: 50, height: 50), + "${client.homeserver}/_matrix/media/r0/thumbnail/exampleserver.abc/abcdefghijklmn?width=50&height=50&method=crop"); + expect( + content.getThumbnail(client, + width: 50, height: 50, method: ThumbnailMethod.scale), + "${client.homeserver}/_matrix/media/r0/thumbnail/exampleserver.abc/abcdefghijklmn?width=50&height=50&method=scale"); }); }); } diff --git a/test/Room_test.dart b/test/Room_test.dart index 2ee48353..2b8557a6 100644 --- a/test/Room_test.dart +++ b/test/Room_test.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'package:flutter_test/flutter_test.dart'; diff --git a/test/User_test.dart b/test/User_test.dart index 9387dd5d..6991ff55 100644 --- a/test/User_test.dart +++ b/test/User_test.dart @@ -18,7 +18,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . + * along with famedlysdk. If not, see . */ import 'package:flutter_test/flutter_test.dart'; @@ -28,14 +28,13 @@ void main() { /// All Tests related to the Event group("User", () { test("Create from json", () async { - final String id = "@alice:server.abc"; final String membership = "join"; final String displayName = "Alice"; final String avatarUrl = ""; final int powerLevel = 50; - final Map jsonObj = { + final Map jsonObj = { "matrix_id": id, "displayname": displayName, "avatar_url": avatarUrl, @@ -45,13 +44,12 @@ void main() { User user = User.fromJson(jsonObj, null); - expect(user.id,id); - expect(user.membership,membership); - expect(user.displayName,displayName); - expect(user.avatarUrl.mxc,avatarUrl); - expect(user.powerLevel,powerLevel); - expect(user.calcDisplayname(),displayName); - + expect(user.id, id); + expect(user.membership, membership); + expect(user.displayName, displayName); + expect(user.avatarUrl.mxc, avatarUrl); + expect(user.powerLevel, powerLevel); + expect(user.calcDisplayname(), displayName); }); }); } From 1b1abf71902c9208e9891b04f0ca6c04d3b57ae9 Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Fri, 21 Jun 2019 12:18:54 +0200 Subject: [PATCH 2/3] [Lists] Add Timeline List type. --- lib/src/Event.dart | 17 +++++--- lib/src/Room.dart | 59 +++++++++---------------- lib/src/Timeline.dart | 75 ++++++++++++++++++++++++++++++++ lib/src/User.dart | 2 +- lib/src/sync/EventUpdate.dart | 4 +- test/Timeline_test.dart | 81 +++++++++++++++++++++++++++++++++++ 6 files changed, 190 insertions(+), 48 deletions(-) create mode 100644 lib/src/Timeline.dart create mode 100644 test/Timeline_test.dart diff --git a/lib/src/Event.dart b/lib/src/Event.dart index 37851aed..ad85437b 100644 --- a/lib/src/Event.dart +++ b/lib/src/Event.dart @@ -126,13 +126,16 @@ class Event { /// Generate a new Event object from a json string, mostly a table row. static Event fromJson(Map jsonObj, Room room) { - Map content; - try { - content = json.decode(jsonObj["content_json"]); - } catch (e) { - print("jsonObj decode of event content failed: ${e.toString()}"); - content = {}; - } + Map content = jsonObj["content"]; + + if (content == null) + try { + content = json.decode(jsonObj["content_json"]); + } catch (e) { + print("jsonObj decode of event content failed: ${e.toString()}"); + content = {}; + } + return Event( jsonObj["id"], User.fromJson(jsonObj, room), diff --git a/lib/src/Room.dart b/lib/src/Room.dart index 0ff0420c..c34b542b 100644 --- a/lib/src/Room.dart +++ b/lib/src/Room.dart @@ -28,6 +28,7 @@ import 'package:famedlysdk/src/responses/ErrorResponse.dart'; import 'package:famedlysdk/src/sync/EventUpdate.dart'; import 'package:famedlysdk/src/Event.dart'; import './User.dart'; +import 'Timeline.dart'; /// Represents a Matrix room. class Room { @@ -83,14 +84,7 @@ class Room { /// The needed power levels for all actions. Map powerLevels = {}; - /// The list of events in this room. If the room is created by the - /// [getRoomList()] of the [Store], this will contain only the last event. - List events = []; - - /// The list of participants in this room. If the room is created by the - /// [getRoomList()] of the [Store], this will contain only the sender of the - /// last event. - List participants = []; + Event lastEvent; /// Your current client instance. final Client client; @@ -123,23 +117,22 @@ class Room { this.historyVisibility, this.joinRules, this.powerLevels, - this.events, - this.participants, + this.lastEvent, this.client, }); /// The last message sent to this room. String get lastMessage { - if (events != null && events.length > 0) - return events[0].getBody(); + if (lastEvent != null) + return lastEvent.getBody(); else return ""; } /// When the last message received. ChatTime get timeCreated { - if (events?.length > 0) - return events[0].time; + if (lastEvent != null) + return lastEvent.time; else return ChatTime.now(); } @@ -165,12 +158,6 @@ class Room { return res; } - @Deprecated("Use the client.connection streams instead!") - Stream> get eventsStream { - return Stream>.fromIterable(Iterable>.generate( - this.events.length, (int index) => this.events)).asBroadcastStream(); - } - /// Call the Matrix API to send a simple text message. Future sendText(String message, {String txid = null}) async { if (txid == null) txid = "txid${DateTime.now().millisecondsSinceEpoch}"; @@ -394,9 +381,8 @@ class Room { "power_event_name": row["power_event_name"], "power_event_power_levels": row["power_event_power_levels"], }, + lastEvent: Event.fromJson(row, null), client: matrix, - events: [Event.fromJson(row, null)], - participants: [], ); } @@ -413,26 +399,25 @@ class Room { return room; } + Future getTimeline({onUpdate, onInsert}) async { + List events = await loadEvents(); + return Timeline( + room: this, + events: events, + onUpdate: onUpdate, + onInsert: onInsert, + ); + } + /// Load all events for a given room from the store. This includes all /// senders of those events, who will be added to the participants list. Future> loadEvents() async { - this.events = await client.store.getEventList(this); - - Map participantMap = {}; - for (num i = 0; i < events.length; i++) { - if (!participantMap.containsKey(events[i].sender.mxid)) { - participants.add(events[i].sender); - participantMap[events[i].sender.mxid] = true; - } - } - - return this.events; + return await client.store.getEventList(this); } /// Load all participants for a given room from the store. Future> loadParticipants() async { - this.participants = await client.store.loadParticipants(this); - return this.participants; + return await client.store.loadParticipants(this); } /// Request the full list of participants from the server. The local list @@ -454,8 +439,6 @@ class Room { if (newUser.membership != "leave") participants.add(newUser); } - this.participants = participants; - - return this.participants; + return participants; } } diff --git a/lib/src/Timeline.dart b/lib/src/Timeline.dart new file mode 100644 index 00000000..65dc665b --- /dev/null +++ b/lib/src/Timeline.dart @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019 Zender & Kurtz GbR. + * + * Authors: + * Christian Pauly + * Marcel Radzio + * + * This file is part of famedlysdk. + * + * famedlysdk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * famedlysdk 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with famedlysdk. If not, see . + */ + +import 'dart:async'; +import 'Event.dart'; +import 'Room.dart'; +import 'User.dart'; +import 'utils/ChatTime.dart'; +import 'sync/EventUpdate.dart'; + +/// Represents the timeline of a room. The callbacks [onUpdate], [onDelete], +/// [onInsert] and [onResort] will be triggered automatically. The initial +/// event list will be retreived when created by the [room.getTimeline] method. +class Timeline { + final Room room; + List events = []; + + final onUpdateCallback onUpdate; + final onInsertCallback onInsert; + + StreamSubscription sub; + + Timeline({this.room, this.events, this.onUpdate, this.onInsert}) { + sub ??= room.client.connection.onEvent.stream.listen(_handleEventUpdate); + } + + void _handleEventUpdate(EventUpdate eventUpdate) async { + try { + if (eventUpdate.roomID != room.id) return; + if (eventUpdate.type == "timeline" || eventUpdate.type == "history") { + if (!eventUpdate.content.containsKey("id")) + eventUpdate.content["id"] = eventUpdate.content["event_id"]; + + User user = await room.client.store + ?.getUser(matrixID: eventUpdate.content["sender"], room: room); + if (user != null) { + eventUpdate.content["displayname"] = user.displayName; + eventUpdate.content["avatar_url"] = user.avatarUrl.mxc; + } + + Event newEvent = Event.fromJson(eventUpdate.content, room); + + events.insert(0, newEvent); + onInsert(0); + } + onUpdate(); + } catch (e) { + print("[WARNING] ${e.toString()}"); + sub.cancel(); + } + } +} + +typedef onUpdateCallback = void Function(); +typedef onInsertCallback = void Function(int insertID); diff --git a/lib/src/User.dart b/lib/src/User.dart index aff91227..9836727f 100644 --- a/lib/src/User.dart +++ b/lib/src/User.dart @@ -79,7 +79,7 @@ class User { /// Creates a new User object from a json string like a row from the database. static User fromJson(Map json, Room room) { - return User(json['matrix_id'], + return User(json['matrix_id'] ?? json['sender'], displayName: json['displayname'], avatarUrl: MxContent(json['avatar_url']), membership: json['membership'], diff --git a/lib/src/sync/EventUpdate.dart b/lib/src/sync/EventUpdate.dart index 41c40b00..725a711d 100644 --- a/lib/src/sync/EventUpdate.dart +++ b/lib/src/sync/EventUpdate.dart @@ -25,7 +25,7 @@ /// already known event. class EventUpdate { /// Usually 'timeline', 'state' or whatever. - final String eventType; + final String type; /// Most events belong to a room. If not, this equals to eventType. final String roomID; @@ -33,7 +33,7 @@ class EventUpdate { /// See (Matrix Room Events)[https://matrix.org/docs/spec/client_server/r0.4.0.html#room-events] /// and (Matrix Events)[https://matrix.org/docs/spec/client_server/r0.4.0.html#id89] for more /// informations. - final String type; + final String eventType; // The json payload of the content of this event. final dynamic content; diff --git a/test/Timeline_test.dart b/test/Timeline_test.dart new file mode 100644 index 00000000..14f7c993 --- /dev/null +++ b/test/Timeline_test.dart @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019 Zender & Kurtz GbR. + * + * Authors: + * Christian Pauly + * Marcel Radzio + * + * This file is part of famedlysdk. + * + * famedlysdk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * famedlysdk 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with famedlysdk. If not, see . + */ + +import 'package:flutter_test/flutter_test.dart'; +import 'package:famedlysdk/src/Client.dart'; +import 'package:famedlysdk/src/Room.dart'; +import 'package:famedlysdk/src/Timeline.dart'; +import 'package:famedlysdk/src/sync/EventUpdate.dart'; +import 'package:famedlysdk/src/utils/ChatTime.dart'; + +void main() { + /// All Tests related to the MxContent + group("Timeline", () { + final String roomID = "!1234:example.com"; + final testTimeStamp = ChatTime.now().toTimeStamp(); + int updateCount = 0; + List insertList = []; + + test("Create", () async { + Client client = Client("testclient"); + client.homeserver = "https://testserver.abc"; + + Room room = Room(id: roomID, client: client); + Timeline timeline = Timeline( + room: room, + events: [], + onUpdate: () { + updateCount++; + }, + onInsert: (int insertID) { + insertList.add(insertID); + }); + + client.connection.onEvent.add(EventUpdate( + type: "timeline", + roomID: roomID, + eventType: "m.room.message", + content: { + "type": "m.room.message", + "content": {"msgtype": "m.text", "body": "Testcase"}, + "sender": "@alice:example.com", + "status": 2, + "id": "1", + "origin_server_ts": testTimeStamp + })); + + expect(timeline.sub != null, true); + + await new Future.delayed(new Duration(milliseconds: 50)); + + expect(updateCount, 1); + expect(insertList, [0]); + expect(timeline.events.length, 1); + expect(timeline.events[0].id, "1"); + expect(timeline.events[0].sender.id, "@alice:example.com"); + expect(timeline.events[0].time.toTimeStamp(), testTimeStamp); + expect(timeline.events[0].environment, "m.room.message"); + expect(timeline.events[0].getBody(), "Testcase"); + }); + }); +} From 66fce65dee250d8882f3217526ebd9be8055046e Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Fri, 21 Jun 2019 13:30:39 +0200 Subject: [PATCH 3/3] [Lists] Add RoomList List type. --- lib/src/Client.dart | 24 ++++++ lib/src/RoomList.dart | 165 +++++++++++++++++++++++++++++++++++++ lib/src/Timeline.dart | 9 ++- test/RoomList_test.dart | 175 ++++++++++++++++++++++++++++++++++++++++ test/Timeline_test.dart | 20 ++++- 5 files changed, 388 insertions(+), 5 deletions(-) create mode 100644 lib/src/RoomList.dart create mode 100644 test/RoomList_test.dart diff --git a/lib/src/Client.dart b/lib/src/Client.dart index c83fad2e..266e00f3 100644 --- a/lib/src/Client.dart +++ b/lib/src/Client.dart @@ -25,6 +25,8 @@ import 'dart:async'; import 'dart:core'; import 'responses/ErrorResponse.dart'; import 'Connection.dart'; +import 'RoomList.dart'; +import 'Room.dart'; import 'Store.dart'; import 'User.dart'; import 'responses/PushrulesResponse.dart'; @@ -189,6 +191,28 @@ class Client { await connection.clear(); } + /// Loads the Rooms from the [store] and creates a new [RoomList] object. + Future getRoomList( + {bool onlyLeft = false, + bool onlyDirect = false, + bool onlyGroups = false, + onUpdateCallback onUpdate, + onInsertCallback, + onInsert, + onRemoveCallback onRemove}) async { + List rooms = await store.getRoomList( + onlyLeft: onlyLeft, onlyGroups: onlyGroups, onlyDirect: onlyDirect); + return RoomList( + client: this, + onlyLeft: onlyLeft, + onlyDirect: onlyDirect, + onlyGroups: onlyGroups, + onUpdate: onUpdate, + onInsert: onInsert, + onRemove: onRemove, + rooms: rooms); + } + /// Creates a new group chat and invites the given Users and returns the new /// created room ID. Future createGroup(List users) async { diff --git a/lib/src/RoomList.dart b/lib/src/RoomList.dart new file mode 100644 index 00000000..0faeb9ff --- /dev/null +++ b/lib/src/RoomList.dart @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2019 Zender & Kurtz GbR. + * + * Authors: + * Christian Pauly + * Marcel Radzio + * + * This file is part of famedlysdk. + * + * famedlysdk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * famedlysdk 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with famedlysdk. If not, see . + */ + +import 'dart:async'; +import 'dart:core'; +import 'Client.dart'; +import 'Event.dart'; +import 'Room.dart'; +import 'User.dart'; +import 'utils/ChatTime.dart'; +import 'utils/MxContent.dart'; +import 'sync/EventUpdate.dart'; +import 'sync/RoomUpdate.dart'; + +/// Represents a list of rooms for this client, which will automatically update +/// itself and call the [onUpdate], [onInsert] and [onDelete] callbacks. To get +/// the initial room list, use the store or create a RoomList instance by using +/// [client.getRoomList]. +class RoomList { + final Client client; + List rooms = []; + + final bool onlyLeft; + final bool onlyDirect; + final bool onlyGroups; + + /// Will be called, when the room list has changed. Can be used e.g. to update + /// the state of a StatefulWidget. + final onUpdateCallback onUpdate; + + /// Will be called, when a new room is added to the list. + final onInsertCallback onInsert; + + /// Will be called, when a room has been removed from the list. + final onRemoveCallback onRemove; + + StreamSubscription eventSub; + StreamSubscription roomSub; + + RoomList( + {this.client, + this.rooms, + this.onUpdate, + this.onInsert, + this.onRemove, + this.onlyLeft = false, + this.onlyDirect = false, + this.onlyGroups = false}) { + eventSub ??= client.connection.onEvent.stream.listen(_handleEventUpdate); + roomSub ??= client.connection.onRoomUpdate.stream.listen(_handleRoomUpdate); + } + + void _handleRoomUpdate(RoomUpdate chatUpdate) async { + // Update the chat list item. + // Search the room in the rooms + num j = 0; + for (j = 0; j < rooms.length; j++) { + if (rooms[j].id == chatUpdate.id) break; + } + final bool found = (j < rooms.length - 1 && rooms[j].id == chatUpdate.id); + + // Does the chat already exist in the list rooms? + if (!found && chatUpdate.membership != "leave") { + num position = chatUpdate.membership == "invite" ? 0 : j; + ChatTime timestamp = + chatUpdate.membership == "invite" ? ChatTime.now() : ChatTime(0); + // Add the new chat to the list + Room newRoom = Room( + id: chatUpdate.id, + name: "", + membership: chatUpdate.membership, + prev_batch: chatUpdate.prev_batch, + highlightCount: chatUpdate.highlight_count, + notificationCount: chatUpdate.notification_count); + rooms.insert(position, newRoom); + onInsert(position); + } + // If the membership is "leave" then remove the item and stop here + else if (found && chatUpdate.membership == "leave") { + final Room removed = rooms.removeAt(j); + onRemove(j); + } + // Update notification and highlight count + else if (found && + chatUpdate.membership != "leave" && + (rooms[j].notificationCount != chatUpdate.notification_count || + rooms[j].highlightCount != chatUpdate.highlight_count)) { + rooms[j].notificationCount = chatUpdate.notification_count; + rooms[j].highlightCount = chatUpdate.highlight_count; + } + sortAndUpdate(); + } + + void _handleEventUpdate(EventUpdate eventUpdate) { + // Is the event necessary for the chat list? If not, then return + if (!(eventUpdate.type == "timeline" || + eventUpdate.eventType == "m.room.avatar" || + eventUpdate.eventType == "m.room.name")) return; + + // Search the room in the rooms + num j = 0; + for (j = 0; j < rooms.length; j++) { + if (rooms[j].id == eventUpdate.roomID) break; + } + final bool found = (j < rooms.length && rooms[j].id == eventUpdate.roomID); + if (!found) return; + + // Is this an old timeline event? Then stop here... + /*if (eventUpdate.type == "timeline" && + ChatTime(eventUpdate.content["origin_server_ts"]) <= + rooms[j].timeCreated) return;*/ + + if (eventUpdate.type == "timeline") { + // Update the last message preview + String body = eventUpdate.content["content"]["body"] ?? ""; + rooms[j].lastEvent = Event( + eventUpdate.content["id"], + User(eventUpdate.content["sender"]), + ChatTime(eventUpdate.content["origin_server_ts"]), + room: rooms[j], + content: eventUpdate.content["content"], + environment: "timeline", + status: 2, + ); + } + if (eventUpdate.eventType == "m.room.name") { + // Update the room name + rooms[j].name = eventUpdate.content["content"]["name"]; + } else if (eventUpdate.eventType == "m.room.avatar") { + // Update the room avatar + rooms[j].avatar = MxContent(eventUpdate.content["content"]["url"]); + } + sortAndUpdate(); + } + + sortAndUpdate() { + rooms?.sort((a, b) => + b.timeCreated.toTimeStamp().compareTo(a.timeCreated.toTimeStamp())); + onUpdate(); + } +} + +typedef onUpdateCallback = void Function(); +typedef onInsertCallback = void Function(int insertID); +typedef onRemoveCallback = void Function(int insertID); diff --git a/lib/src/Timeline.dart b/lib/src/Timeline.dart index 65dc665b..04a23b59 100644 --- a/lib/src/Timeline.dart +++ b/lib/src/Timeline.dart @@ -25,7 +25,6 @@ import 'dart:async'; import 'Event.dart'; import 'Room.dart'; import 'User.dart'; -import 'utils/ChatTime.dart'; import 'sync/EventUpdate.dart'; /// Represents the timeline of a room. The callbacks [onUpdate], [onDelete], @@ -63,12 +62,18 @@ class Timeline { events.insert(0, newEvent); onInsert(0); } - onUpdate(); + sortAndUpdate(); } catch (e) { print("[WARNING] ${e.toString()}"); sub.cancel(); } } + + sortAndUpdate() { + events + ?.sort((a, b) => b.time.toTimeStamp().compareTo(a.time.toTimeStamp())); + onUpdate(); + } } typedef onUpdateCallback = void Function(); diff --git a/test/RoomList_test.dart b/test/RoomList_test.dart new file mode 100644 index 00000000..abd1c4f8 --- /dev/null +++ b/test/RoomList_test.dart @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2019 Zender & Kurtz GbR. + * + * Authors: + * Christian Pauly + * Marcel Radzio + * + * This file is part of famedlysdk. + * + * famedlysdk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * famedlysdk 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with famedlysdk. If not, see . + */ + +import 'package:flutter_test/flutter_test.dart'; +import 'package:famedlysdk/src/Client.dart'; +import 'package:famedlysdk/src/Event.dart'; +import 'package:famedlysdk/src/Room.dart'; +import 'package:famedlysdk/src/RoomList.dart'; +import 'package:famedlysdk/src/User.dart'; +import 'package:famedlysdk/src/sync/EventUpdate.dart'; +import 'package:famedlysdk/src/sync/RoomUpdate.dart'; +import 'package:famedlysdk/src/utils/ChatTime.dart'; + +void main() { + /// All Tests related to the MxContent + group("RoomList", () { + final roomID = "!1:example.com"; + + test("Create and insert one room", () async { + final Client client = Client("testclient"); + client.homeserver = "https://testserver.abc"; + + int updateCount = 0; + List insertList = []; + List removeList = []; + + RoomList roomList = RoomList( + client: client, + rooms: [], + onUpdate: () { + updateCount++; + }, + onInsert: (int insertID) { + insertList.add(insertID); + }, + onRemove: (int removeID) { + insertList.add(removeID); + }); + + expect(roomList.eventSub != null, true); + expect(roomList.roomSub != null, true); + + client.connection.onRoomUpdate.add(RoomUpdate( + id: roomID, + membership: "join", + notification_count: 2, + highlight_count: 1, + limitedTimeline: false, + prev_batch: "1234", + )); + + await new Future.delayed(new Duration(milliseconds: 50)); + + expect(updateCount, 1); + expect(insertList, [0]); + expect(removeList, []); + + expect(roomList.rooms.length, 1); + expect(roomList.rooms[0].id, roomID); + expect(roomList.rooms[0].membership, "join"); + expect(roomList.rooms[0].notificationCount, 2); + expect(roomList.rooms[0].highlightCount, 1); + expect(roomList.rooms[0].prev_batch, "1234"); + expect(roomList.rooms[0].timeCreated, ChatTime.now()); + }); + + test("Restort", () async { + final Client client = Client("testclient"); + client.homeserver = "https://testserver.abc"; + + int updateCount = 0; + List insertList = []; + List removeList = []; + + RoomList roomList = RoomList( + client: client, + rooms: [], + onUpdate: () { + updateCount++; + }, + onInsert: (int insertID) { + insertList.add(insertID); + }, + onRemove: (int removeID) { + insertList.add(removeID); + }); + + client.connection.onRoomUpdate.add(RoomUpdate( + id: "1", + membership: "join", + notification_count: 2, + highlight_count: 1, + limitedTimeline: false, + prev_batch: "1234", + )); + client.connection.onRoomUpdate.add(RoomUpdate( + id: "2", + membership: "join", + notification_count: 2, + highlight_count: 1, + limitedTimeline: false, + prev_batch: "1234", + )); + + await new Future.delayed(new Duration(milliseconds: 50)); + + expect(roomList.eventSub != null, true); + expect(roomList.roomSub != null, true); + expect(roomList.rooms[0].id, "1"); + expect(roomList.rooms[1].id, "2"); + + ChatTime now = ChatTime.now(); + + client.connection.onEvent.add(EventUpdate( + type: "timeline", + roomID: "1", + eventType: "m.room.message", + content: { + "type": "m.room.message", + "content": {"msgtype": "m.text", "body": "Testcase"}, + "sender": "@alice:example.com", + "status": 2, + "id": "1", + "origin_server_ts": now.toTimeStamp() - 1000 + })); + + client.connection.onEvent.add(EventUpdate( + type: "timeline", + roomID: "2", + eventType: "m.room.message", + content: { + "type": "m.room.message", + "content": {"msgtype": "m.text", "body": "Testcase 2"}, + "sender": "@alice:example.com", + "status": 2, + "id": "2", + "origin_server_ts": now.toTimeStamp() + })); + + await new Future.delayed(new Duration(milliseconds: 50)); + + expect(updateCount, 4); + expect(insertList, [0, 1]); + expect(removeList, []); + + expect(roomList.rooms.length, 2); + expect( + roomList.rooms[0].timeCreated > roomList.rooms[1].timeCreated, true); + expect(roomList.rooms[0].id, "2"); + expect(roomList.rooms[1].id, "1"); + expect(roomList.rooms[0].lastMessage, "Testcase 2"); + expect(roomList.rooms[0].timeCreated, now); + }); + }); +} diff --git a/test/Timeline_test.dart b/test/Timeline_test.dart index 14f7c993..2576aca1 100644 --- a/test/Timeline_test.dart +++ b/test/Timeline_test.dart @@ -64,18 +64,32 @@ void main() { "origin_server_ts": testTimeStamp })); + client.connection.onEvent.add(EventUpdate( + type: "timeline", + roomID: roomID, + eventType: "m.room.message", + content: { + "type": "m.room.message", + "content": {"msgtype": "m.text", "body": "Testcase"}, + "sender": "@alice:example.com", + "status": 2, + "id": "2", + "origin_server_ts": testTimeStamp - 1000 + })); + expect(timeline.sub != null, true); await new Future.delayed(new Duration(milliseconds: 50)); - expect(updateCount, 1); - expect(insertList, [0]); - expect(timeline.events.length, 1); + expect(updateCount, 2); + expect(insertList, [0, 0]); + expect(timeline.events.length, 2); expect(timeline.events[0].id, "1"); expect(timeline.events[0].sender.id, "@alice:example.com"); expect(timeline.events[0].time.toTimeStamp(), testTimeStamp); expect(timeline.events[0].environment, "m.room.message"); expect(timeline.events[0].getBody(), "Testcase"); + expect(timeline.events[0].time > timeline.events[1].time, true); }); }); }