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:
rules:
#- camel_case_types
- camel_case_types
analyzer:
# exclude:

View file

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

View file

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

View file

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

View file

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

View file

@ -100,7 +100,7 @@ void main() {
newDeviceID: resp["device_id"],
newMatrixVersions: matrix.matrixVersions,
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.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(
matrix.getRoomByAlias(
@ -209,7 +209,7 @@ void main() {
});
test('Room Update Test', () async {
matrix.onRoomUpdate.close();
await matrix.onRoomUpdate.close();
List<RoomUpdate> roomUpdateList = await roomUpdateListFuture;
@ -231,7 +231,7 @@ void main() {
});
test('Event Update Test', () async {
matrix.onEvent.close();
await matrix.onEvent.close();
List<EventUpdate> eventUpdateList = await eventUpdateListFuture;
@ -283,7 +283,7 @@ void main() {
});
test('User Update Test', () async {
matrix.onUserEvent.close();
await matrix.onUserEvent.close();
List<UserUpdate> eventUpdateList = await userUpdateListFuture;
@ -358,7 +358,7 @@ void main() {
test('get archive', () async {
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[0].id, "!5345234234:example.com");
expect(archive[0].membership, Membership.leave);

View file

@ -43,26 +43,28 @@ class FakeMatrixApi extends MockClient {
// Sync requests with timeout
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(
"<html><head></head><body>Not found...</body></html>", 404);
}
// Call API
if (api.containsKey(method) && api[method].containsKey(action))
if (api.containsKey(method) && api[method].containsKey(action)) {
res = api[method][action](data);
else if (method == "GET" &&
} else if (method == "GET" &&
action.contains("/client/r0/rooms/") &&
action.contains("/state/m.room.member/")) {
res = {"displayname": ""};
return Response(json.encode(res), 200);
} else
} else {
res = {
"errcode": "M_UNRECOGNIZED",
"error": "Unrecognized request"
};
}
return Response(json.encode(res), 100);
});

View file

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