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:
commit
877ebe7f1f
|
@ -2,7 +2,7 @@ include: package:pedantic/analysis_options.yaml
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
rules:
|
rules:
|
||||||
#- camel_case_types
|
- camel_case_types
|
||||||
|
|
||||||
analyzer:
|
analyzer:
|
||||||
# exclude:
|
# exclude:
|
||||||
|
|
|
@ -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,12 +711,15 @@ 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>) {
|
||||||
|
@ -731,18 +745,22 @@ 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(
|
||||||
|
@ -850,6 +873,7 @@ class Client {
|
||||||
this.store?.storeUserEventUpdate(update);
|
this.store?.storeUserEventUpdate(update);
|
||||||
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) {
|
||||||
|
@ -908,15 +932,19 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,9 +304,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,15 +127,16 @@ 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;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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,18 +239,19 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the Matrix API to change the name of this room. Returns the event ID of the
|
/// Call the Matrix API to change the name of this room. Returns the event ID of the
|
||||||
|
@ -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)) {
|
||||||
directChats[userID].add(id);
|
if (!directChats[userID].contains(id)) {
|
||||||
else
|
directChats[userID].add(id);
|
||||||
return; // Is already in direct chats
|
} else {
|
||||||
else
|
return;
|
||||||
|
} // 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(
|
||||||
|
|
|
@ -14,12 +14,13 @@ 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) {
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue