Merge branch 'sdk-refactor-harder-analyzer' into 'master'

[SDK] Make analyzer much more happy

See merge request famedly/famedlysdk!143
This commit is contained in:
Christian Pauly 2020-01-02 14:37:02 +00:00
commit 877ebe7f1f
9 changed files with 206 additions and 152 deletions

View file

@ -2,7 +2,7 @@ include: package:pedantic/analysis_options.yaml
linter: linter:
rules: rules:
#- camel_case_types - camel_case_types
analyzer: analyzer:
# exclude: # exclude:

View file

@ -30,6 +30,7 @@ import 'package:famedlysdk/src/Presence.dart';
import 'package:famedlysdk/src/StoreAPI.dart'; import 'package:famedlysdk/src/StoreAPI.dart';
import 'package:famedlysdk/src/sync/UserUpdate.dart'; import 'package:famedlysdk/src/sync/UserUpdate.dart';
import 'package:famedlysdk/src/utils/MatrixFile.dart'; import 'package:famedlysdk/src/utils/MatrixFile.dart';
import 'package:pedantic/pedantic.dart';
import 'Room.dart'; import 'Room.dart';
import 'Event.dart'; import 'Event.dart';
import 'User.dart'; import 'User.dart';
@ -161,8 +162,9 @@ class Client {
if (accountData["m.direct"] != null && if (accountData["m.direct"] != null &&
accountData["m.direct"].content[userId] is List<dynamic> && accountData["m.direct"].content[userId] is List<dynamic> &&
accountData["m.direct"].content[userId].length > 0) { accountData["m.direct"].content[userId].length > 0) {
if (getRoomById(accountData["m.direct"].content[userId][0]) != null) if (getRoomById(accountData["m.direct"].content[userId][0]) != null) {
return accountData["m.direct"].content[userId][0]; return accountData["m.direct"].content[userId][0];
}
(accountData["m.direct"].content[userId] as List<dynamic>) (accountData["m.direct"].content[userId] as List<dynamic>)
.remove(accountData["m.direct"].content[userId][0]); .remove(accountData["m.direct"].content[userId][0]);
this.jsonRequest( this.jsonRequest(
@ -171,11 +173,13 @@ class Client {
data: directChats); data: directChats);
return getDirectChatFromUserId(userId); return getDirectChatFromUserId(userId);
} }
for (int i = 0; i < this.rooms.length; i++) for (int i = 0; i < this.rooms.length; i++) {
if (this.rooms[i].membership == Membership.invite && if (this.rooms[i].membership == Membership.invite &&
this.rooms[i].states[userID]?.senderId == userId && this.rooms[i].states[userID]?.senderId == userId &&
this.rooms[i].states[userID].content["is_direct"] == true) this.rooms[i].states[userID].content["is_direct"] == true) {
return this.rooms[i].id; return this.rooms[i].id;
}
}
return null; return null;
} }
@ -192,9 +196,9 @@ class Client {
final List<String> versions = List<String>.from(versionResp["versions"]); final List<String> versions = List<String>.from(versionResp["versions"]);
for (int i = 0; i < versions.length; i++) { for (int i = 0; i < versions.length; i++) {
if (versions[i] == "r0.5.0") if (versions[i] == "r0.5.0") {
break; break;
else if (i == versions.length - 1) { } else if (i == versions.length - 1) {
return false; return false;
} }
} }
@ -216,9 +220,9 @@ class Client {
for (int i = 0; i < flows.length; i++) { for (int i = 0; i < flows.length; i++) {
if (flows[i].containsKey("type") && if (flows[i].containsKey("type") &&
flows[i]["type"] == "m.login.password") flows[i]["type"] == "m.login.password") {
break; break;
else if (i == flows.length - 1) { } else if (i == flows.length - 1) {
return false; return false;
} }
} }
@ -341,9 +345,9 @@ class Client {
List<User> contacts = []; List<User> contacts = [];
Room contactDiscoveryRoom = Room contactDiscoveryRoom =
this.getRoomByAlias("#famedlyContactDiscovery:${userID.split(":")[1]}"); this.getRoomByAlias("#famedlyContactDiscovery:${userID.split(":")[1]}");
if (contactDiscoveryRoom != null) if (contactDiscoveryRoom != null) {
contacts = await contactDiscoveryRoom.requestParticipants(); contacts = await contactDiscoveryRoom.requestParticipants();
else { } else {
Map<String, bool> userMap = {}; Map<String, bool> userMap = {};
for (int i = 0; i < this.rooms.length; i++) { for (int i = 0; i < this.rooms.length; i++) {
List<User> roomUsers = this.rooms[i].getParticipants(); List<User> roomUsers = this.rooms[i].getParticipants();
@ -366,8 +370,11 @@ class Client {
Future<String> createRoom( Future<String> createRoom(
{List<User> invite, Map<String, dynamic> params}) async { {List<User> invite, Map<String, dynamic> params}) async {
List<String> inviteIDs = []; List<String> inviteIDs = [];
if (params == null && invite != null) if (params == null && invite != null) {
for (int i = 0; i < invite.length; i++) inviteIDs.add(invite[i].id); for (int i = 0; i < invite.length; i++) {
inviteIDs.add(invite[i].id);
}
}
try { try {
final dynamic resp = await this.jsonRequest( final dynamic resp = await this.jsonRequest(
@ -440,31 +447,29 @@ class Client {
/// the app receives a new synchronization, this event is called for every signal /// the app receives a new synchronization, this event is called for every signal
/// to update the GUI. For example, for a new message, it is called: /// to update the GUI. For example, for a new message, it is called:
/// onRoomEvent( "m.room.message", "!chat_id:server.com", "timeline", {sender: "@bob:server.com", body: "Hello world"} ) /// onRoomEvent( "m.room.message", "!chat_id:server.com", "timeline", {sender: "@bob:server.com", body: "Hello world"} )
final StreamController<EventUpdate> onEvent = final StreamController<EventUpdate> onEvent = StreamController.broadcast();
new StreamController.broadcast();
/// Outside of the events there are updates for the global chat states which /// Outside of the events there are updates for the global chat states which
/// are handled by this signal: /// are handled by this signal:
final StreamController<RoomUpdate> onRoomUpdate = final StreamController<RoomUpdate> onRoomUpdate =
new StreamController.broadcast(); StreamController.broadcast();
/// Outside of rooms there are account updates like account_data or presences. /// Outside of rooms there are account updates like account_data or presences.
final StreamController<UserUpdate> onUserEvent = final StreamController<UserUpdate> onUserEvent = StreamController.broadcast();
new StreamController.broadcast();
/// Called when the login state e.g. user gets logged out. /// Called when the login state e.g. user gets logged out.
final StreamController<LoginState> onLoginStateChanged = final StreamController<LoginState> onLoginStateChanged =
new StreamController.broadcast(); StreamController.broadcast();
/// Synchronization erros are coming here. /// Synchronization erros are coming here.
final StreamController<MatrixException> onError = final StreamController<MatrixException> onError =
new StreamController.broadcast(); StreamController.broadcast();
/// This is called once, when the first sync has received. /// This is called once, when the first sync has received.
final StreamController<bool> onFirstSync = new StreamController.broadcast(); final StreamController<bool> onFirstSync = StreamController.broadcast();
/// When a new sync response is coming in, this gives the complete payload. /// When a new sync response is coming in, this gives the complete payload.
final StreamController<dynamic> onSync = new StreamController.broadcast(); final StreamController<dynamic> onSync = StreamController.broadcast();
/// Matrix synchronisation is done with https long polling. This needs a /// Matrix synchronisation is done with https long polling. This needs a
/// timeout which is usually 30 seconds. /// timeout which is usually 30 seconds.
@ -525,7 +530,7 @@ class Client {
this.prevBatch = newPrevBatch; this.prevBatch = newPrevBatch;
if (this.store != null) { if (this.store != null) {
this.store.storeClient(); await this.store.storeClient();
this._rooms = await this.store.getRoomList(onlyLeft: false); this._rooms = await this.store.getRoomList(onlyLeft: false);
this.accountData = await this.store.getAccountData(); this.accountData = await this.store.getAccountData();
this.presences = await this.store.getPresences(); this.presences = await this.store.getPresences();
@ -535,7 +540,7 @@ class Client {
onLoginStateChanged.add(LoginState.logged); onLoginStateChanged.add(LoginState.logged);
_sync(); return _sync();
} }
StreamSubscription _userEventSub; StreamSubscription _userEventSub;
@ -574,8 +579,9 @@ class Client {
dynamic data = "", dynamic data = "",
int timeout, int timeout,
String contentType = "application/json"}) async { String contentType = "application/json"}) async {
if (this.isLogged() == false && this.homeserver == null) if (this.isLogged() == false && this.homeserver == null) {
throw ("No homeserver specified."); throw ("No homeserver specified.");
}
if (timeout == null) timeout = syncTimeoutSec + 5; if (timeout == null) timeout = syncTimeoutSec + 5;
dynamic json; dynamic json;
if (data is Map) data.removeWhere((k, v) => v == null); if (data is Map) data.removeWhere((k, v) => v == null);
@ -585,14 +591,17 @@ class Client {
final url = "${this.homeserver}/_matrix${action}"; final url = "${this.homeserver}/_matrix${action}";
Map<String, String> headers = {}; Map<String, String> headers = {};
if (type == HTTPType.PUT || type == HTTPType.POST) if (type == HTTPType.PUT || type == HTTPType.POST) {
headers["Content-Type"] = contentType; headers["Content-Type"] = contentType;
if (this.isLogged()) }
if (this.isLogged()) {
headers["Authorization"] = "Bearer ${this.accessToken}"; headers["Authorization"] = "Bearer ${this.accessToken}";
}
if (this.debug) if (this.debug) {
print( print(
"[REQUEST ${type.toString().split('.').last}] Action: $action, Data: $data"); "[REQUEST ${type.toString().split('.').last}] Action: $action, Data: $data");
}
http.Response resp; http.Response resp;
Map<String, dynamic> jsonResp = {}; Map<String, dynamic> jsonResp = {};
@ -650,8 +659,9 @@ class Client {
/// and returns the mxc url as a string. /// and returns the mxc url as a string.
Future<String> upload(MatrixFile file) async { Future<String> upload(MatrixFile file) async {
dynamic fileBytes; dynamic fileBytes;
if (this.homeserver != "https://fakeServer.notExisting") if (this.homeserver != "https://fakeServer.notExisting") {
fileBytes = file.bytes; fileBytes = file.bytes;
}
String fileName = file.path.split("/").last.toLowerCase(); String fileName = file.path.split("/").last.toLowerCase();
String mimeType = mime(file.path); String mimeType = mime(file.path);
print("[UPLOADING] $fileName, type: $mimeType, size: ${fileBytes?.length}"); print("[UPLOADING] $fileName, type: $mimeType, size: ${fileBytes?.length}");
@ -679,17 +689,18 @@ class Client {
final int hash = _syncRequest.hashCode; final int hash = _syncRequest.hashCode;
final syncResp = await _syncRequest; final syncResp = await _syncRequest;
if (hash != _syncRequest.hashCode) return; if (hash != _syncRequest.hashCode) return;
if (this.store != null) if (this.store != null) {
await this.store.transaction(() { await this.store.transaction(() {
handleSync(syncResp); handleSync(syncResp);
this.store.storePrevBatch(syncResp); this.store.storePrevBatch(syncResp);
return; return;
}); });
else } else {
await handleSync(syncResp); await handleSync(syncResp);
}
if (this.prevBatch == null) this.onFirstSync.add(true); if (this.prevBatch == null) this.onFirstSync.add(true);
this.prevBatch = syncResp["next_batch"]; this.prevBatch = syncResp["next_batch"];
if (hash == _syncRequest.hashCode) _sync(); if (hash == _syncRequest.hashCode) unawaited(_sync());
} on MatrixException catch (exception) { } on MatrixException catch (exception) {
onError.add(exception); onError.add(exception);
await Future.delayed(Duration(seconds: syncErrorTimeoutSec), _sync); await Future.delayed(Duration(seconds: syncErrorTimeoutSec), _sync);
@ -700,13 +711,16 @@ class Client {
void handleSync(dynamic sync) { void handleSync(dynamic sync) {
if (sync["rooms"] is Map<String, dynamic>) { if (sync["rooms"] is Map<String, dynamic>) {
if (sync["rooms"]["join"] is Map<String, dynamic>) if (sync["rooms"]["join"] is Map<String, dynamic>) {
_handleRooms(sync["rooms"]["join"], Membership.join); _handleRooms(sync["rooms"]["join"], Membership.join);
if (sync["rooms"]["invite"] is Map<String, dynamic>) }
if (sync["rooms"]["invite"] is Map<String, dynamic>) {
_handleRooms(sync["rooms"]["invite"], Membership.invite); _handleRooms(sync["rooms"]["invite"], Membership.invite);
if (sync["rooms"]["leave"] is Map<String, dynamic>) }
if (sync["rooms"]["leave"] is Map<String, dynamic>) {
_handleRooms(sync["rooms"]["leave"], Membership.leave); _handleRooms(sync["rooms"]["leave"], Membership.leave);
} }
}
if (sync["presence"] is Map<String, dynamic> && if (sync["presence"] is Map<String, dynamic> &&
sync["presence"]["events"] is List<dynamic>) { sync["presence"]["events"] is List<dynamic>) {
_handleGlobalEvents(sync["presence"]["events"], "presence"); _handleGlobalEvents(sync["presence"]["events"], "presence");
@ -731,19 +745,23 @@ class Client {
bool limitedTimeline = false; bool limitedTimeline = false;
if (room["unread_notifications"] is Map<String, dynamic>) { if (room["unread_notifications"] is Map<String, dynamic>) {
if (room["unread_notifications"]["highlight_count"] is num) if (room["unread_notifications"]["highlight_count"] is num) {
highlight_count = room["unread_notifications"]["highlight_count"]; highlight_count = room["unread_notifications"]["highlight_count"];
if (room["unread_notifications"]["notification_count"] is num) }
if (room["unread_notifications"]["notification_count"] is num) {
notification_count = notification_count =
room["unread_notifications"]["notification_count"]; room["unread_notifications"]["notification_count"];
} }
}
if (room["timeline"] is Map<String, dynamic>) { if (room["timeline"] is Map<String, dynamic>) {
if (room["timeline"]["limited"] is bool) if (room["timeline"]["limited"] is bool) {
limitedTimeline = room["timeline"]["limited"]; limitedTimeline = room["timeline"]["limited"];
if (room["timeline"]["prev_batch"] is String) }
if (room["timeline"]["prev_batch"] is String) {
prev_batch = room["timeline"]["prev_batch"]; prev_batch = room["timeline"]["prev_batch"];
} }
}
RoomSummary summary; RoomSummary summary;
@ -761,29 +779,34 @@ class Client {
summary: summary, summary: summary,
); );
_updateRoomsByRoomUpdate(update); _updateRoomsByRoomUpdate(update);
this.store?.storeRoomUpdate(update); unawaited(this.store?.storeRoomUpdate(update));
onRoomUpdate.add(update); onRoomUpdate.add(update);
/// Handle now all room events and save them in the database /// Handle now all room events and save them in the database
if (room["state"] is Map<String, dynamic> && if (room["state"] is Map<String, dynamic> &&
room["state"]["events"] is List<dynamic>) room["state"]["events"] is List<dynamic>) {
_handleRoomEvents(id, room["state"]["events"], "state"); _handleRoomEvents(id, room["state"]["events"], "state");
}
if (room["invite_state"] is Map<String, dynamic> && if (room["invite_state"] is Map<String, dynamic> &&
room["invite_state"]["events"] is List<dynamic>) room["invite_state"]["events"] is List<dynamic>) {
_handleRoomEvents(id, room["invite_state"]["events"], "invite_state"); _handleRoomEvents(id, room["invite_state"]["events"], "invite_state");
}
if (room["timeline"] is Map<String, dynamic> && if (room["timeline"] is Map<String, dynamic> &&
room["timeline"]["events"] is List<dynamic>) room["timeline"]["events"] is List<dynamic>) {
_handleRoomEvents(id, room["timeline"]["events"], "timeline"); _handleRoomEvents(id, room["timeline"]["events"], "timeline");
}
if (room["ephemeral"] is Map<String, dynamic> && if (room["ephemeral"] is Map<String, dynamic> &&
room["ephemeral"]["events"] is List<dynamic>) room["ephemeral"]["events"] is List<dynamic>) {
_handleEphemerals(id, room["ephemeral"]["events"]); _handleEphemerals(id, room["ephemeral"]["events"]);
}
if (room["account_data"] is Map<String, dynamic> && if (room["account_data"] is Map<String, dynamic> &&
room["account_data"]["events"] is List<dynamic>) room["account_data"]["events"] is List<dynamic>) {
_handleRoomEvents(id, room["account_data"]["events"], "account_data"); _handleRoomEvents(id, room["account_data"]["events"], "account_data");
}
}); });
} }
@ -839,7 +862,7 @@ class Client {
} }
void _handleGlobalEvents(List<dynamic> events, String type) { void _handleGlobalEvents(List<dynamic> events, String type) {
for (int i = 0; i < events.length; i++) for (int i = 0; i < events.length; i++) {
if (events[i]["type"] is String && if (events[i]["type"] is String &&
events[i]["content"] is Map<String, dynamic>) { events[i]["content"] is Map<String, dynamic>) {
UserUpdate update = UserUpdate( UserUpdate update = UserUpdate(
@ -851,6 +874,7 @@ class Client {
onUserEvent.add(update); onUserEvent.add(update);
} }
} }
}
void _handleEvent(Map<String, dynamic> event, String roomID, String type) { void _handleEvent(Map<String, dynamic> event, String roomID, String type) {
if (event["type"] is String && event["content"] is Map<String, dynamic>) { if (event["type"] is String && event["content"] is Map<String, dynamic>) {
@ -908,16 +932,20 @@ class Client {
rooms[j].membership = chatUpdate.membership; rooms[j].membership = chatUpdate.membership;
rooms[j].notificationCount = chatUpdate.notification_count; rooms[j].notificationCount = chatUpdate.notification_count;
rooms[j].highlightCount = chatUpdate.highlight_count; rooms[j].highlightCount = chatUpdate.highlight_count;
if (chatUpdate.prev_batch != null) if (chatUpdate.prev_batch != null) {
rooms[j].prev_batch = chatUpdate.prev_batch; rooms[j].prev_batch = chatUpdate.prev_batch;
}
if (chatUpdate.summary != null) { if (chatUpdate.summary != null) {
if (chatUpdate.summary.mHeroes != null) if (chatUpdate.summary.mHeroes != null) {
rooms[j].mHeroes = chatUpdate.summary.mHeroes; rooms[j].mHeroes = chatUpdate.summary.mHeroes;
if (chatUpdate.summary.mJoinedMemberCount != null) }
if (chatUpdate.summary.mJoinedMemberCount != null) {
rooms[j].mJoinedMemberCount = chatUpdate.summary.mJoinedMemberCount; rooms[j].mJoinedMemberCount = chatUpdate.summary.mJoinedMemberCount;
if (chatUpdate.summary.mInvitedMemberCount != null) }
if (chatUpdate.summary.mInvitedMemberCount != null) {
rooms[j].mInvitedMemberCount = chatUpdate.summary.mInvitedMemberCount; rooms[j].mInvitedMemberCount = chatUpdate.summary.mInvitedMemberCount;
} }
}
if (rooms[j].onUpdate != null) rooms[j].onUpdate(); if (rooms[j].onUpdate != null) rooms[j].onUpdate();
} }
sortAndUpdate(); sortAndUpdate();

View file

@ -105,12 +105,13 @@ class Event {
this.room}); this.room});
static Map<String, dynamic> getMapFromPayload(dynamic payload) { static Map<String, dynamic> getMapFromPayload(dynamic payload) {
if (payload is String) if (payload is String) {
try { try {
return json.decode(payload); return json.decode(payload);
} catch (e) { } catch (e) {
return {}; return {};
} }
}
if (payload is Map<String, dynamic>) return payload; if (payload is Map<String, dynamic>) return payload;
return {}; return {};
} }
@ -141,18 +142,20 @@ class Event {
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>(); final Map<String, dynamic> data = Map<String, dynamic>();
if (this.stateKey != null) data['state_key'] = this.stateKey; if (this.stateKey != null) data['state_key'] = this.stateKey;
if (this.prevContent != null && this.prevContent.isNotEmpty) if (this.prevContent != null && this.prevContent.isNotEmpty) {
data['prev_content'] = this.prevContent; data['prev_content'] = this.prevContent;
}
data['content'] = this.content; data['content'] = this.content;
data['type'] = this.typeKey; data['type'] = this.typeKey;
data['event_id'] = this.eventId; data['event_id'] = this.eventId;
data['room_id'] = this.roomId; data['room_id'] = this.roomId;
data['sender'] = this.senderId; data['sender'] = this.senderId;
data['origin_server_ts'] = this.time.millisecondsSinceEpoch; data['origin_server_ts'] = this.time.millisecondsSinceEpoch;
if (this.unsigned != null && this.unsigned.isNotEmpty) if (this.unsigned != null && this.unsigned.isNotEmpty) {
data['unsigned'] = this.unsigned; data['unsigned'] = this.unsigned;
}
return data; return data;
} }
@ -245,9 +248,6 @@ class Event {
prevContent = null; prevContent = null;
List<String> contentKeyWhiteList = []; List<String> contentKeyWhiteList = [];
switch (type) { switch (type) {
case EventTypes.RoomMember:
contentKeyWhiteList.add("membership");
break;
case EventTypes.RoomMember: case EventTypes.RoomMember:
contentKeyWhiteList.add("membership"); contentKeyWhiteList.add("membership");
break; break;
@ -278,7 +278,7 @@ class Event {
} }
List<String> toRemoveList = []; List<String> toRemoveList = [];
for (var entry in content.entries) { for (var entry in content.entries) {
if (contentKeyWhiteList.indexOf(entry.key) == -1) { if (!contentKeyWhiteList.contains(entry.key)) {
toRemoveList.add(entry.key); toRemoveList.add(entry.key);
} }
} }
@ -304,10 +304,11 @@ class Event {
if (!(room.roomAccountData.containsKey("m.receipt"))) return []; if (!(room.roomAccountData.containsKey("m.receipt"))) return [];
List<Receipt> receiptsList = []; List<Receipt> receiptsList = [];
for (var entry in room.roomAccountData["m.receipt"].content.entries) { for (var entry in room.roomAccountData["m.receipt"].content.entries) {
if (entry.value["event_id"] == eventId) if (entry.value["event_id"] == eventId) {
receiptsList.add(Receipt(room.getUserByMXIDSync(entry.key), receiptsList.add(Receipt(room.getUserByMXIDSync(entry.key),
DateTime.fromMillisecondsSinceEpoch(entry.value["ts"]))); DateTime.fromMillisecondsSinceEpoch(entry.value["ts"])));
} }
}
return receiptsList; return receiptsList;
} }
@ -315,8 +316,9 @@ class Event {
/// from the database and the timelines. Returns false if not removed. /// from the database and the timelines. Returns false if not removed.
Future<bool> remove() async { Future<bool> remove() async {
if (status < 1) { if (status < 1) {
if (room.client.store != null) if (room.client.store != null) {
await room.client.store.removeEvent(eventId); await room.client.store.removeEvent(eventId);
}
room.client.onEvent.add(EventUpdate( room.client.onEvent.add(EventUpdate(
roomID: room.id, roomID: room.id,
@ -335,7 +337,7 @@ class Event {
/// Try to send this event again. Only works with events of status -1. /// Try to send this event again. Only works with events of status -1.
Future<String> sendAgain({String txid}) async { Future<String> sendAgain({String txid}) async {
if (status != -1) return null; if (status != -1) return null;
remove(); await remove();
final String eventID = await room.sendTextEvent(text, txid: txid); final String eventID = await room.sendTextEvent(text, txid: txid);
return eventID; return eventID;
} }

View file

@ -29,7 +29,6 @@ import 'package:famedlysdk/src/sync/RoomUpdate.dart';
import 'package:famedlysdk/src/utils/MatrixException.dart'; import 'package:famedlysdk/src/utils/MatrixException.dart';
import 'package:famedlysdk/src/utils/MatrixFile.dart'; import 'package:famedlysdk/src/utils/MatrixFile.dart';
import 'package:famedlysdk/src/utils/MxContent.dart'; import 'package:famedlysdk/src/utils/MxContent.dart';
//import 'package:image/image.dart';
import 'package:mime_type/mime_type.dart'; import 'package:mime_type/mime_type.dart';
import './User.dart'; import './User.dart';
@ -81,8 +80,9 @@ class Room {
/// Adds the [state] to this room and overwrites a state with the same /// Adds the [state] to this room and overwrites a state with the same
/// typeKey/stateKey key pair if there is one. /// typeKey/stateKey key pair if there is one.
void setState(Event state) { void setState(Event state) {
if (!states.states.containsKey(state.typeKey)) if (!states.states.containsKey(state.typeKey)) {
states.states[state.typeKey] = {}; states.states[state.typeKey] = {};
}
states.states[state.typeKey][state.stateKey ?? ""] = state; states.states[state.typeKey][state.stateKey ?? ""] = state;
} }
@ -106,10 +106,12 @@ class Room {
/// The avatar of the room if set by a participant. /// The avatar of the room if set by a participant.
MxContent get avatar { MxContent get avatar {
if (states["m.room.avatar"] != null) if (states["m.room.avatar"] != null) {
return MxContent(states["m.room.avatar"].content["url"]); return MxContent(states["m.room.avatar"].content["url"]);
if (mHeroes != null && mHeroes.length == 1 && states[mHeroes[0]] != null) }
if (mHeroes != null && mHeroes.length == 1 && states[mHeroes[0]] != null) {
return states[mHeroes[0]].asUser.avatarUrl; return states[mHeroes[0]].asUser.avatarUrl;
}
if (membership == Membership.invite && if (membership == Membership.invite &&
getState("m.room.member", client.userID) != null) { getState("m.room.member", client.userID) != null) {
return getState("m.room.member", client.userID).sender.avatarUrl; return getState("m.room.member", client.userID).sender.avatarUrl;
@ -125,16 +127,17 @@ class Room {
/// If this room is a direct chat, this is the matrix ID of the user. /// If this room is a direct chat, this is the matrix ID of the user.
/// Returns null otherwise. /// Returns null otherwise.
String get directChatMatrixID { String get directChatMatrixID {
String returnUserId = null; String returnUserId;
if (client.directChats is Map<String, dynamic>) { if (client.directChats is Map<String, dynamic>) {
client.directChats.forEach((String userId, dynamic roomIds) { client.directChats.forEach((String userId, dynamic roomIds) {
if (roomIds is List<dynamic>) { if (roomIds is List<dynamic>) {
for (int i = 0; i < roomIds.length; i++) for (int i = 0; i < roomIds.length; i++) {
if (roomIds[i] == this.id) { if (roomIds[i] == this.id) {
returnUserId = userId; returnUserId = userId;
break; break;
} }
} }
}
}); });
} }
return returnUserId; return returnUserId;
@ -149,7 +152,7 @@ class Room {
Event get lastEvent { Event get lastEvent {
DateTime lastTime = DateTime.fromMillisecondsSinceEpoch(0); DateTime lastTime = DateTime.fromMillisecondsSinceEpoch(0);
Event lastEvent = getState("m.room.message")?.timelineEvent; Event lastEvent = getState("m.room.message")?.timelineEvent;
if (lastEvent == null) if (lastEvent == null) {
states.forEach((final String key, final entry) { states.forEach((final String key, final entry) {
if (!entry.containsKey("")) return; if (!entry.containsKey("")) return;
final Event state = entry[""]; final Event state = entry[""];
@ -160,6 +163,7 @@ class Room {
lastEvent = state.timelineEvent; lastEvent = state.timelineEvent;
} }
}); });
}
return lastEvent; return lastEvent;
} }
@ -168,8 +172,9 @@ class Room {
if (!ephemerals.containsKey("m.typing")) return []; if (!ephemerals.containsKey("m.typing")) return [];
List<dynamic> typingMxid = ephemerals["m.typing"].content["user_ids"]; List<dynamic> typingMxid = ephemerals["m.typing"].content["user_ids"];
List<User> typingUsers = []; List<User> typingUsers = [];
for (int i = 0; i < typingMxid.length; i++) for (int i = 0; i < typingMxid.length; i++) {
typingUsers.add(getUserByMXIDSync(typingMxid[i])); typingUsers.add(getUserByMXIDSync(typingMxid[i]));
}
return typingUsers; return typingUsers;
} }
@ -199,12 +204,13 @@ class Room {
String get displayname { String get displayname {
if (name != null && name.isNotEmpty) return name; if (name != null && name.isNotEmpty) return name;
if (canonicalAlias != null && if (canonicalAlias != null &&
!canonicalAlias.isEmpty && canonicalAlias.isNotEmpty &&
canonicalAlias.length > 3) canonicalAlias.length > 3) {
return canonicalAlias.substring(1, canonicalAlias.length).split(":")[0]; return canonicalAlias.substring(1, canonicalAlias.length).split(":")[0];
}
List<String> heroes = []; List<String> heroes = [];
if (mHeroes != null && if (mHeroes != null &&
mHeroes.length > 0 && mHeroes.isNotEmpty &&
mHeroes.any((h) => h.isNotEmpty)) { mHeroes.any((h) => h.isNotEmpty)) {
heroes = mHeroes; heroes = mHeroes;
} else { } else {
@ -216,7 +222,7 @@ class Room {
} }
} }
} }
if (heroes.length > 0) { if (heroes.isNotEmpty) {
String displayname = ""; String displayname = "";
for (int i = 0; i < heroes.length; i++) { for (int i = 0; i < heroes.length; i++) {
if (heroes[i].isEmpty) continue; if (heroes[i].isEmpty) continue;
@ -233,17 +239,18 @@ class Room {
/// The last message sent to this room. /// The last message sent to this room.
String get lastMessage { String get lastMessage {
if (lastEvent != null) if (lastEvent != null) {
return lastEvent.getBody(); return lastEvent.getBody();
else } else {
return ""; return "";
} }
}
/// When the last message received. /// When the last message received.
DateTime get timeCreated { DateTime get timeCreated {
if (lastEvent != null) if (lastEvent != null) {
return lastEvent.time; return lastEvent.time;
else }
return DateTime.now(); return DateTime.now();
} }
@ -267,7 +274,7 @@ class Room {
} }
Future<String> _sendRawEventNow(Map<String, dynamic> content, Future<String> _sendRawEventNow(Map<String, dynamic> content,
{String txid = null}) async { {String txid}) async {
if (txid == null) txid = "txid${DateTime.now().millisecondsSinceEpoch}"; if (txid == null) txid = "txid${DateTime.now().millisecondsSinceEpoch}";
final Map<String, dynamic> res = await client.jsonRequest( final Map<String, dynamic> res = await client.jsonRequest(
type: HTTPType.PUT, type: HTTPType.PUT,
@ -276,13 +283,13 @@ class Room {
return res["event_id"]; return res["event_id"];
} }
Future<String> sendTextEvent(String message, {String txid = null}) => Future<String> sendTextEvent(String message, {String txid}) =>
sendEvent({"msgtype": "m.text", "body": message}, txid: txid); sendEvent({"msgtype": "m.text", "body": message}, txid: txid);
/// Sends a [file] to this room after uploading it. The [msgType] is optional /// Sends a [file] to this room after uploading it. The [msgType] is optional
/// and will be detected by the mimetype of the file. /// and will be detected by the mimetype of the file.
Future<String> sendFileEvent(MatrixFile file, Future<String> sendFileEvent(MatrixFile file,
{String msgType = "m.file", String txid = null}) async { {String msgType = "m.file", String txid}) async {
if (msgType == "m.image") return sendImageEvent(file); if (msgType == "m.image") return sendImageEvent(file);
if (msgType == "m.audio") return sendVideoEvent(file); if (msgType == "m.audio") return sendVideoEvent(file);
if (msgType == "m.video") return sendAudioEvent(file); if (msgType == "m.video") return sendAudioEvent(file);
@ -305,7 +312,7 @@ class Room {
} }
Future<String> sendAudioEvent(MatrixFile file, Future<String> sendAudioEvent(MatrixFile file,
{String txid = null, int width, int height}) async { {String txid, int width, int height}) async {
String fileName = file.path.split("/").last; String fileName = file.path.split("/").last;
final String uploadResp = await client.upload(file); final String uploadResp = await client.upload(file);
Map<String, dynamic> content = { Map<String, dynamic> content = {
@ -322,7 +329,7 @@ class Room {
} }
Future<String> sendImageEvent(MatrixFile file, Future<String> sendImageEvent(MatrixFile file,
{String txid = null, int width, int height}) async { {String txid, int width, int height}) async {
String fileName = file.path.split("/").last; String fileName = file.path.split("/").last;
final String uploadResp = await client.upload(file); final String uploadResp = await client.upload(file);
Map<String, dynamic> content = { Map<String, dynamic> content = {
@ -340,7 +347,7 @@ class Room {
} }
Future<String> sendVideoEvent(MatrixFile file, Future<String> sendVideoEvent(MatrixFile file,
{String txid = null, {String txid,
int videoWidth, int videoWidth,
int videoHeight, int videoHeight,
int duration, int duration,
@ -385,8 +392,7 @@ class Room {
return await sendEvent(content, txid: txid); return await sendEvent(content, txid: txid);
} }
Future<String> sendEvent(Map<String, dynamic> content, Future<String> sendEvent(Map<String, dynamic> content, {String txid}) async {
{String txid = null}) async {
final String type = "m.room.message"; final String type = "m.room.message";
// Create new transaction id // Create new transaction id
@ -394,8 +400,9 @@ class Room {
final int now = DateTime.now().millisecondsSinceEpoch; final int now = DateTime.now().millisecondsSinceEpoch;
if (txid == null) { if (txid == null) {
messageID = "msg$now"; messageID = "msg$now";
} else } else {
messageID = txid; messageID = txid;
}
// Display a *sending* event and store it. // Display a *sending* event and store it.
EventUpdate eventUpdate = EventUpdate eventUpdate =
@ -447,11 +454,12 @@ class Room {
type: HTTPType.POST, action: "/client/r0/rooms/${id}/join"); type: HTTPType.POST, action: "/client/r0/rooms/${id}/join");
if (states.containsKey(client.userID) && if (states.containsKey(client.userID) &&
states[client.userID].content["is_direct"] is bool && states[client.userID].content["is_direct"] is bool &&
states[client.userID].content["is_direct"]) states[client.userID].content["is_direct"]) {
addToDirectChat(states[client.userID].sender.id); await addToDirectChat(states[client.userID].sender.id);
}
} on MatrixException catch (exception) { } on MatrixException catch (exception) {
if (exception.errorMessage == "No known servers") { if (exception.errorMessage == "No known servers") {
client.store?.forgetRoom(id); await client.store?.forgetRoom(id);
client.onRoomUpdate.add( client.onRoomUpdate.add(
RoomUpdate( RoomUpdate(
id: id, id: id,
@ -475,7 +483,7 @@ class Room {
/// Call the Matrix API to forget this room if you already left it. /// Call the Matrix API to forget this room if you already left it.
Future<void> forget() async { Future<void> forget() async {
client.store.forgetRoom(id); await client.store?.forgetRoom(id);
await client.jsonRequest( await client.jsonRequest(
type: HTTPType.POST, action: "/client/r0/rooms/${id}/forget"); type: HTTPType.POST, action: "/client/r0/rooms/${id}/forget");
return; return;
@ -546,14 +554,14 @@ class Room {
if (onHistoryReceived != null) onHistoryReceived(); if (onHistoryReceived != null) onHistoryReceived();
prev_batch = resp["end"]; prev_batch = resp["end"];
client.store?.storeRoomPrevBatch(this); await client.store?.storeRoomPrevBatch(this);
if (!(resp["chunk"] is List<dynamic> && if (!(resp["chunk"] is List<dynamic> &&
resp["chunk"].length > 0 && resp["chunk"].length > 0 &&
resp["end"] is String)) return; resp["end"] is String)) return;
if (resp["state"] is List<dynamic>) { if (resp["state"] is List<dynamic>) {
client.store?.transaction(() { await client.store?.transaction(() {
for (int i = 0; i < resp["state"].length; i++) { for (int i = 0; i < resp["state"].length; i++) {
EventUpdate eventUpdate = EventUpdate( EventUpdate eventUpdate = EventUpdate(
type: "state", type: "state",
@ -580,7 +588,7 @@ class Room {
} }
List<dynamic> history = resp["chunk"]; List<dynamic> history = resp["chunk"];
client.store?.transaction(() { await client.store?.transaction(() {
for (int i = 0; i < history.length; i++) { for (int i = 0; i < history.length; i++) {
EventUpdate eventUpdate = EventUpdate( EventUpdate eventUpdate = EventUpdate(
type: "history", type: "history",
@ -620,12 +628,15 @@ class Room {
/// Sets this room as a direct chat for this user if not already. /// Sets this room as a direct chat for this user if not already.
Future<void> addToDirectChat(String userID) async { Future<void> addToDirectChat(String userID) async {
Map<String, dynamic> directChats = client.directChats; Map<String, dynamic> directChats = client.directChats;
if (directChats.containsKey(userID)) if (!directChats[userID].contains(id)) if (directChats.containsKey(userID)) {
if (!directChats[userID].contains(id)) {
directChats[userID].add(id); directChats[userID].add(id);
else } else {
return; // Is already in direct chats return;
else } // Is already in direct chats
} else {
directChats[userID] = [id]; directChats[userID] = [id];
}
await client.jsonRequest( await client.jsonRequest(
type: HTTPType.PUT, type: HTTPType.PUT,
@ -638,10 +649,11 @@ class Room {
Future<void> removeFromDirectChat() async { Future<void> removeFromDirectChat() async {
Map<String, dynamic> directChats = client.directChats; Map<String, dynamic> directChats = client.directChats;
if (directChats.containsKey(directChatMatrixID) && if (directChats.containsKey(directChatMatrixID) &&
directChats[directChatMatrixID].contains(id)) directChats[directChatMatrixID].contains(id)) {
directChats[directChatMatrixID].remove(id); directChats[directChatMatrixID].remove(id);
else } else {
return; // Nothing to do here return;
} // Nothing to do here
await client.jsonRequest( await client.jsonRequest(
type: HTTPType.PUT, type: HTTPType.PUT,
@ -653,8 +665,8 @@ class Room {
/// Sends *m.fully_read* and *m.read* for the given event ID. /// Sends *m.fully_read* and *m.read* for the given event ID.
Future<void> sendReadReceipt(String eventID) async { Future<void> sendReadReceipt(String eventID) async {
this.notificationCount = 0; this.notificationCount = 0;
client?.store?.resetNotificationCount(this.id); await client?.store?.resetNotificationCount(this.id);
client.jsonRequest( await client.jsonRequest(
type: HTTPType.POST, type: HTTPType.POST,
action: "/client/r0/rooms/$id/read_markers", action: "/client/r0/rooms/$id/read_markers",
data: { data: {
@ -712,11 +724,11 @@ class Room {
{onTimelineUpdateCallback onUpdate, {onTimelineUpdateCallback onUpdate,
onTimelineInsertCallback onInsert}) async { onTimelineInsertCallback onInsert}) async {
List<Event> events = []; List<Event> events = [];
if (client.store != null) if (client.store != null) {
events = await client.store.getEventList(this); events = await client.store.getEventList(this);
else { } else {
prev_batch = ""; prev_batch = "";
requestHistory(); await requestHistory();
} }
return Timeline( return Timeline(
room: this, room: this,
@ -772,9 +784,9 @@ class Room {
/// Returns the [User] object for the given [mxID] or requests it from /// Returns the [User] object for the given [mxID] or requests it from
/// the homeserver and returns a default [User] object while waiting. /// the homeserver and returns a default [User] object while waiting.
User getUserByMXIDSync(String mxID) { User getUserByMXIDSync(String mxID) {
if (states[mxID] != null) if (states[mxID] != null) {
return states[mxID].asUser; return states[mxID].asUser;
else { } else {
try { try {
requestUser(mxID); requestUser(mxID);
} catch (_) {} } catch (_) {}
@ -802,8 +814,8 @@ class Room {
avatarUrl: resp["avatar_url"], avatarUrl: resp["avatar_url"],
room: this); room: this);
states[mxID] = user; states[mxID] = user;
if (client.store != null) if (client.store != null) {
client.store.transaction(() { await client.store.transaction(() {
client.store.storeEventUpdate( client.store.storeEventUpdate(
EventUpdate( EventUpdate(
content: resp, content: resp,
@ -813,6 +825,7 @@ class Room {
); );
return; return;
}); });
}
if (onUpdate != null) onUpdate(); if (onUpdate != null) onUpdate();
_requestingMatrixIds.remove(mxID); _requestingMatrixIds.remove(mxID);
return user; return user;
@ -830,11 +843,13 @@ class Room {
int powerLevel = 0; int powerLevel = 0;
Event powerLevelState = states["m.room.power_levels"]; Event powerLevelState = states["m.room.power_levels"];
if (powerLevelState == null) return powerLevel; if (powerLevelState == null) return powerLevel;
if (powerLevelState.content["users_default"] is int) if (powerLevelState.content["users_default"] is int) {
powerLevel = powerLevelState.content["users_default"]; powerLevel = powerLevelState.content["users_default"];
}
if (powerLevelState.content["users"] is Map<String, dynamic> && if (powerLevelState.content["users"] is Map<String, dynamic> &&
powerLevelState.content["users"][userId] != null) powerLevelState.content["users"][userId] != null) {
powerLevel = powerLevelState.content["users"][userId]; powerLevel = powerLevelState.content["users"][userId];
}
return powerLevel; return powerLevel;
} }
@ -844,8 +859,9 @@ class Room {
/// Returns the power levels from all users for this room or null if not given. /// Returns the power levels from all users for this room or null if not given.
Map<String, int> get powerLevels { Map<String, int> get powerLevels {
Event powerLevelState = states["m.room.power_levels"]; Event powerLevelState = states["m.room.power_levels"];
if (powerLevelState.content["users"] is Map<String, int>) if (powerLevelState.content["users"] is Map<String, int>) {
return powerLevelState.content["users"]; return powerLevelState.content["users"];
}
return null; return null;
} }
@ -889,10 +905,11 @@ class Room {
bool canSendEvent(String eventType) { bool canSendEvent(String eventType) {
if (getState("m.room.power_levels") == null) return false; if (getState("m.room.power_levels") == null) return false;
if (getState("m.room.power_levels").content["events"] == null || if (getState("m.room.power_levels").content["events"] == null ||
getState("m.room.power_levels").content["events"][eventType] == null) getState("m.room.power_levels").content["events"][eventType] == null) {
return eventType == "m.room.message" return eventType == "m.room.message"
? canSendDefaultMessages ? canSendDefaultMessages
: canSendDefaultStates; : canSendDefaultStates;
}
return ownPowerLevel >= return ownPowerLevel >=
getState("m.room.power_levels").content["events"][eventType]; getState("m.room.power_levels").content["events"][eventType];
} }
@ -901,8 +918,9 @@ class Room {
/// the account_data. /// the account_data.
PushRuleState get pushRuleState { PushRuleState get pushRuleState {
if (!client.accountData.containsKey("m.push_rules") || if (!client.accountData.containsKey("m.push_rules") ||
!(client.accountData["m.push_rules"].content["global"] is Map)) !(client.accountData["m.push_rules"].content["global"] is Map)) {
return PushRuleState.notify; return PushRuleState.notify;
}
final Map<String, dynamic> globalPushRules = final Map<String, dynamic> globalPushRules =
client.accountData["m.push_rules"].content["global"]; client.accountData["m.push_rules"].content["global"];
if (globalPushRules == null) return PushRuleState.notify; if (globalPushRules == null) return PushRuleState.notify;
@ -943,16 +961,17 @@ class Room {
switch (newState) { switch (newState) {
// All push notifications should be sent to the user // All push notifications should be sent to the user
case PushRuleState.notify: case PushRuleState.notify:
if (pushRuleState == PushRuleState.dont_notify) if (pushRuleState == PushRuleState.dont_notify) {
resp = await client.jsonRequest( resp = await client.jsonRequest(
type: HTTPType.DELETE, type: HTTPType.DELETE,
action: "/client/r0/pushrules/global/override/$id", action: "/client/r0/pushrules/global/override/$id",
data: {}); data: {});
else if (pushRuleState == PushRuleState.mentions_only) } else if (pushRuleState == PushRuleState.mentions_only) {
resp = await client.jsonRequest( resp = await client.jsonRequest(
type: HTTPType.DELETE, type: HTTPType.DELETE,
action: "/client/r0/pushrules/global/room/$id", action: "/client/r0/pushrules/global/room/$id",
data: {}); data: {});
}
break; break;
// Only when someone mentions the user, a push notification should be sent // Only when someone mentions the user, a push notification should be sent
case PushRuleState.mentions_only: case PushRuleState.mentions_only:
@ -967,13 +986,14 @@ class Room {
data: { data: {
"actions": ["dont_notify"] "actions": ["dont_notify"]
}); });
} else if (pushRuleState == PushRuleState.notify) } else if (pushRuleState == PushRuleState.notify) {
resp = await client.jsonRequest( resp = await client.jsonRequest(
type: HTTPType.PUT, type: HTTPType.PUT,
action: "/client/r0/pushrules/global/room/$id", action: "/client/r0/pushrules/global/room/$id",
data: { data: {
"actions": ["dont_notify"] "actions": ["dont_notify"]
}); });
}
break; break;
// No push notification should be ever sent for this room. // No push notification should be ever sent for this room.
case PushRuleState.dont_notify: case PushRuleState.dont_notify:
@ -1004,8 +1024,9 @@ class Room {
final int now = DateTime.now().millisecondsSinceEpoch; final int now = DateTime.now().millisecondsSinceEpoch;
if (txid == null) { if (txid == null) {
messageID = "msg$now"; messageID = "msg$now";
} else } else {
messageID = txid; messageID = txid;
}
Map<String, dynamic> data = {}; Map<String, dynamic> data = {};
if (reason != null) data["reason"] = reason; if (reason != null) data["reason"] = reason;
final dynamic resp = await client.jsonRequest( final dynamic resp = await client.jsonRequest(

View file

@ -14,13 +14,14 @@ class StatesMap {
return states["m.room.member"][key]; return states["m.room.member"][key];
} }
if (!states.containsKey(key)) states[key] = {}; if (!states.containsKey(key)) states[key] = {};
if (states[key][""] is Event) if (states[key][""] is Event) {
return states[key][""]; return states[key][""];
else if (states[key].length == 0) } else if (states[key].isEmpty) {
return null; return null;
else } else {
return states[key]; return states[key];
} }
}
void operator []=(String key, Event val) { void operator []=(String key, Event val) {
//print("[Warning] This method will be depracated in the future!"); //print("[Warning] This method will be depracated in the future!");

View file

@ -303,7 +303,7 @@ packages:
source: hosted source: hosted
version: "1.6.4" version: "1.6.4"
pedantic: pedantic:
dependency: "direct dev" dependency: "direct main"
description: description:
name: pedantic name: pedantic
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"

View file

@ -100,7 +100,7 @@ void main() {
newDeviceID: resp["device_id"], newDeviceID: resp["device_id"],
newMatrixVersions: matrix.matrixVersions, newMatrixVersions: matrix.matrixVersions,
newLazyLoadMembers: matrix.lazyLoadMembers); newLazyLoadMembers: matrix.lazyLoadMembers);
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect(matrix.accessToken == resp["access_token"], true); expect(matrix.accessToken == resp["access_token"], true);
expect(matrix.deviceName == "Text Matrix Client", true); expect(matrix.deviceName == "Text Matrix Client", true);
@ -164,7 +164,7 @@ void main() {
} }
} }
}); });
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect( expect(
matrix.getRoomByAlias( matrix.getRoomByAlias(
@ -209,7 +209,7 @@ void main() {
}); });
test('Room Update Test', () async { test('Room Update Test', () async {
matrix.onRoomUpdate.close(); await matrix.onRoomUpdate.close();
List<RoomUpdate> roomUpdateList = await roomUpdateListFuture; List<RoomUpdate> roomUpdateList = await roomUpdateListFuture;
@ -231,7 +231,7 @@ void main() {
}); });
test('Event Update Test', () async { test('Event Update Test', () async {
matrix.onEvent.close(); await matrix.onEvent.close();
List<EventUpdate> eventUpdateList = await eventUpdateListFuture; List<EventUpdate> eventUpdateList = await eventUpdateListFuture;
@ -283,7 +283,7 @@ void main() {
}); });
test('User Update Test', () async { test('User Update Test', () async {
matrix.onUserEvent.close(); await matrix.onUserEvent.close();
List<UserUpdate> eventUpdateList = await userUpdateListFuture; List<UserUpdate> eventUpdateList = await userUpdateListFuture;
@ -358,7 +358,7 @@ void main() {
test('get archive', () async { test('get archive', () async {
List<Room> archive = await matrix.archive; List<Room> archive = await matrix.archive;
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect(archive.length, 2); expect(archive.length, 2);
expect(archive[0].id, "!5345234234:example.com"); expect(archive[0].id, "!5345234234:example.com");
expect(archive[0].membership, Membership.leave); expect(archive[0].membership, Membership.leave);

View file

@ -43,26 +43,28 @@ class FakeMatrixApi extends MockClient {
// Sync requests with timeout // Sync requests with timeout
if (data is Map<String, dynamic> && data["timeout"] is String) { if (data is Map<String, dynamic> && data["timeout"] is String) {
await new Future.delayed(Duration(seconds: 5)); await Future.delayed(Duration(seconds: 5));
} }
if (request.url.origin != "https://fakeserver.notexisting") if (request.url.origin != "https://fakeserver.notexisting") {
return Response( return Response(
"<html><head></head><body>Not found...</body></html>", 404); "<html><head></head><body>Not found...</body></html>", 404);
}
// Call API // Call API
if (api.containsKey(method) && api[method].containsKey(action)) if (api.containsKey(method) && api[method].containsKey(action)) {
res = api[method][action](data); res = api[method][action](data);
else if (method == "GET" && } else if (method == "GET" &&
action.contains("/client/r0/rooms/") && action.contains("/client/r0/rooms/") &&
action.contains("/state/m.room.member/")) { action.contains("/state/m.room.member/")) {
res = {"displayname": ""}; res = {"displayname": ""};
return Response(json.encode(res), 200); return Response(json.encode(res), 200);
} else } else {
res = { res = {
"errcode": "M_UNRECOGNIZED", "errcode": "M_UNRECOGNIZED",
"error": "Unrecognized request" "error": "Unrecognized request"
}; };
}
return Response(json.encode(res), 100); return Response(json.encode(res), 100);
}); });

View file

@ -82,7 +82,7 @@ void main() {
expect(timeline.sub != null, true); expect(timeline.sub != null, true);
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect(updateCount, 2); expect(updateCount, 2);
expect(insertList, [0, 0]); expect(insertList, [0, 0]);
@ -109,7 +109,7 @@ void main() {
"room_id": roomID, "room_id": roomID,
}, room); }, room);
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect(timeline.events[0].receipts.length, 1); expect(timeline.events[0].receipts.length, 1);
expect(timeline.events[0].receipts[0].user.id, "@alice:example.com"); expect(timeline.events[0].receipts[0].user.id, "@alice:example.com");
@ -127,7 +127,7 @@ void main() {
"origin_server_ts": testTimeStamp + 1000 "origin_server_ts": testTimeStamp + 1000
})); }));
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect(updateCount, 3); expect(updateCount, 3);
expect(insertList, [0, 0]); expect(insertList, [0, 0]);
@ -137,9 +137,9 @@ void main() {
}); });
test("Send message", () async { test("Send message", () async {
room.sendTextEvent("test", txid: "1234"); await room.sendTextEvent("test", txid: "1234");
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect(updateCount, 5); expect(updateCount, 5);
expect(insertList, [0, 0, 0]); expect(insertList, [0, 0, 0]);
@ -161,7 +161,7 @@ void main() {
"origin_server_ts": DateTime.now().millisecondsSinceEpoch "origin_server_ts": DateTime.now().millisecondsSinceEpoch
})); }));
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect(updateCount, 6); expect(updateCount, 6);
expect(insertList, [0, 0, 0]); expect(insertList, [0, 0, 0]);
@ -183,13 +183,13 @@ void main() {
"event_id": "abc", "event_id": "abc",
"origin_server_ts": testTimeStamp "origin_server_ts": testTimeStamp
})); }));
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
room.sendTextEvent("test", txid: "errortxid"); await room.sendTextEvent("test", txid: "errortxid");
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
room.sendTextEvent("test", txid: "errortxid2"); await room.sendTextEvent("test", txid: "errortxid2");
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
room.sendTextEvent("test", txid: "errortxid3"); await room.sendTextEvent("test", txid: "errortxid3");
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect(updateCount, 13); expect(updateCount, 13);
expect(insertList, [0, 0, 0, 0, 0, 0, 0]); expect(insertList, [0, 0, 0, 0, 0, 0, 0]);
@ -200,9 +200,9 @@ void main() {
}); });
test("Remove message", () async { test("Remove message", () async {
timeline.events[0].remove(); await timeline.events[0].remove();
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect(updateCount, 14); expect(updateCount, 14);
@ -212,9 +212,9 @@ void main() {
}); });
test("Resend message", () async { test("Resend message", () async {
timeline.events[0].sendAgain(txid: "1234"); await timeline.events[0].sendAgain(txid: "1234");
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect(updateCount, 17); expect(updateCount, 17);
@ -226,7 +226,7 @@ void main() {
test("Request history", () async { test("Request history", () async {
await room.requestHistory(); await room.requestHistory();
await new Future.delayed(new Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect(updateCount, 20); expect(updateCount, 20);
expect(timeline.events.length, 9); expect(timeline.events.length, 9);