Merge branch 'maintance' into 'master'

Maintance fixes

See merge request famedly/famedlysdk!28
This commit is contained in:
Christian 2019-07-12 09:26:07 +00:00
commit 457350e82b
14 changed files with 188 additions and 130 deletions

View file

@ -23,13 +23,14 @@
import 'dart:async';
import 'dart:core';
import 'requests/SetPushersRequest.dart';
import 'responses/ErrorResponse.dart';
import 'Connection.dart';
import 'RoomList.dart';
import 'Room.dart';
import 'RoomList.dart';
import 'Store.dart';
import 'User.dart';
import 'requests/SetPushersRequest.dart';
import 'responses/ErrorResponse.dart';
import 'responses/PushrulesResponse.dart';
/// Represents a Matrix client to communicate with a
@ -91,8 +92,8 @@ class Client {
Future<bool> checkServer(serverUrl) async {
homeserver = serverUrl;
final versionResp =
await connection.jsonRequest(type: "GET", action: "/client/versions");
final versionResp = await connection.jsonRequest(
type: HTTPType.GET, action: "/client/versions");
if (versionResp is ErrorResponse) {
connection.onError.add(ErrorResponse(errcode: "NO_RESPONSE", error: ""));
return false;
@ -123,8 +124,8 @@ class Client {
: false;
}
final loginResp =
await connection.jsonRequest(type: "GET", action: "/client/r0/login");
final loginResp = await connection.jsonRequest(
type: HTTPType.GET, action: "/client/r0/login");
if (loginResp is ErrorResponse) {
connection.onError.add(loginResp);
return false;
@ -149,7 +150,7 @@ class Client {
/// authentication. Returns false if the login was not successful.
Future<bool> login(String username, String password) async {
final loginResp = await connection
.jsonRequest(type: "POST", action: "/client/r0/login", data: {
.jsonRequest(type: HTTPType.POST, action: "/client/r0/login", data: {
"type": "m.login.password",
"user": username,
"identifier": {
@ -186,7 +187,7 @@ class Client {
/// including all persistent data from the store.
Future<void> logout() async {
final dynamic resp = await connection.jsonRequest(
type: "POST", action: "/client/r0/logout/all");
type: HTTPType.POST, action: "/client/r0/logout/all");
if (resp is ErrorResponse) connection.onError.add(resp);
await connection.clear();
@ -213,6 +214,11 @@ class Client {
rooms: rooms);
}
Future<dynamic> joinRoomById(String id) async {
return await connection.jsonRequest(
type: HTTPType.POST, action: "/client/r0/join/$id");
}
/// Creates a new group chat and invites the given Users and returns the new
/// created room ID.
Future<String> createGroup(List<User> users) async {
@ -220,7 +226,7 @@ class Client {
for (int i = 0; i < users.length; i++) inviteIDs.add(users[i].id);
final dynamic resp = await connection.jsonRequest(
type: "POST",
type: HTTPType.POST,
action: "/client/r0/createRoom",
data: {"invite": inviteIDs, "preset": "private_chat"});
@ -236,7 +242,7 @@ class Client {
/// These are needed for notifications on Android
Future<PushrulesResponse> getPushrules() async {
final dynamic resp = await connection.jsonRequest(
type: "GET",
type: HTTPType.GET,
action: "/client/r0/pushrules",
);
@ -251,7 +257,7 @@ class Client {
/// This endpoint allows the creation, modification and deletion of pushers for this user ID.
Future setPushers(SetPushersRequest data) async {
final dynamic resp = await connection.jsonRequest(
type: "POST",
type: HTTPType.POST,
action: "/client/r0/pushers/set",
data: data,
);

View file

@ -24,13 +24,18 @@
import 'dart:async';
import 'dart:convert';
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'Client.dart';
import 'User.dart';
import 'responses/ErrorResponse.dart';
import 'sync/EventUpdate.dart';
import 'sync/UserUpdate.dart';
import 'sync/RoomUpdate.dart';
import 'Client.dart';
import 'sync/UserUpdate.dart';
enum HTTPType { GET, POST, PUT, DELETE }
/// Represents a Matrix connection to communicate with a
/// [Matrix](https://matrix.org) homeserver.
@ -41,10 +46,12 @@ class Connection {
WidgetsBinding.instance
?.addObserver(_LifecycleEventHandler(resumeCallBack: () {
_sync();
return;
}));
}
String get _syncFilters => '{"room":{"state":{"lazy_load_members":true}}}';
String get _firstSyncFilters =>
'{"room":{"include_leave":true,"state":{"lazy_load_members":true}}}';
@ -103,7 +110,7 @@ class Connection {
///
/// ```
/// final resp = await matrix
/// .jsonRequest(type: "POST", action: "/client/r0/login", data: {
/// .jsonRequest(type: HTTPType.POST, action: "/client/r0/login", data: {
/// "type": "m.login.password",
/// "user": "test",
/// "password": "1234",
@ -164,7 +171,7 @@ class Connection {
///
/// ```
/// final resp = await jsonRequest(
/// type: "PUT",
/// type: HTTPType.PUT,
/// action: "/r0/rooms/!fjd823j:example.com/send/m.room.message/$txnId",
/// data: {
/// "msgtype": "m.text",
@ -174,7 +181,7 @@ class Connection {
/// ```
///
Future<dynamic> jsonRequest(
{String type, String action, dynamic data = "", int timeout}) async {
{HTTPType type, String action, dynamic data = "", int timeout}) async {
if (client.isLogged() == false && client.homeserver == null)
throw ("No homeserver specified.");
if (timeout == null) timeout = syncTimeoutSec + 5;
@ -188,11 +195,13 @@ class Connection {
if (client.isLogged())
headers["Authorization"] = "Bearer ${client.accessToken}";
if (client.debug) print("[REQUEST $type] Action: $action, Data: $data");
if (client.debug)
print(
"[REQUEST ${type.toString().split('.').last}] Action: $action, Data: $data");
http.Response resp;
try {
switch (type) {
switch (type.toString().split('.').last) {
case "GET":
resp = await httpClient
.get(url, headers: headers)
@ -257,7 +266,7 @@ class Connection {
action += "&timeout=30000";
action += "&since=${client.prevBatch}";
}
_syncRequest = jsonRequest(type: "GET", action: action);
_syncRequest = jsonRequest(type: HTTPType.GET, action: action);
final int hash = _syncRequest.hashCode;
final syncResp = await _syncRequest;
if (hash != _syncRequest.hashCode) return;
@ -270,6 +279,7 @@ class Connection {
await client.store.transaction(() {
_handleSync(syncResp);
client.store.storePrevBatch(syncResp);
return;
});
else
await _handleSync(syncResp);
@ -287,11 +297,11 @@ class Connection {
void _handleSync(dynamic sync) {
if (sync["rooms"] is Map<String, dynamic>) {
if (sync["rooms"]["join"] is Map<String, dynamic>)
_handleRooms(sync["rooms"]["join"], "join");
_handleRooms(sync["rooms"]["join"], Membership.join);
if (sync["rooms"]["invite"] is Map<String, dynamic>)
_handleRooms(sync["rooms"]["invite"], "invite");
_handleRooms(sync["rooms"]["invite"], Membership.invite);
if (sync["rooms"]["leave"] is Map<String, dynamic>)
_handleRooms(sync["rooms"]["leave"], "leave");
_handleRooms(sync["rooms"]["leave"], Membership.leave);
}
if (sync["presence"] is Map<String, dynamic> &&
sync["presence"]["events"] is List<dynamic>) {
@ -308,7 +318,7 @@ class Connection {
onSync.add(sync);
}
void _handleRooms(Map<String, dynamic> rooms, String membership) {
void _handleRooms(Map<String, dynamic> rooms, Membership membership) {
rooms.forEach((String id, dynamic room) async {
// calculate the notification counts, the limitedTimeline and prevbatch
num highlight_count = 0;

View file

@ -22,11 +22,13 @@
*/
import 'dart:convert';
import 'package:famedlysdk/src/Client.dart';
import 'package:famedlysdk/src/sync/EventUpdate.dart';
import 'package:famedlysdk/src/utils/ChatTime.dart';
import 'package:famedlysdk/src/Client.dart';
import './User.dart';
import './Room.dart';
import './User.dart';
/// A single Matrix event, e.g. a message in a chat.
class Event {
@ -106,6 +108,9 @@ class Event {
case "m.room.message":
switch (content["msgtype"] ?? "m.text") {
case "m.text":
if (content.containsKey("m.relates_to")) {
return EventTypes.Reply;
}
return EventTypes.Text;
case "m.notice":
return EventTypes.Notice;
@ -135,7 +140,9 @@ class Event {
try {
content = json.decode(jsonObj["content_json"]);
} catch (e) {
print("jsonObj decode of event content failed: ${e.toString()}");
if (room.client.debug) {
print("jsonObj decode of event content failed: ${e.toString()}");
}
content = {};
}
else if (content == null) content = {};
@ -198,6 +205,7 @@ enum EventTypes {
Audio,
File,
Location,
Reply,
RoomAliases,
RoomCanonicalAlias,
RoomCreate,

View file

@ -22,12 +22,14 @@
*/
import 'package:famedlysdk/src/Client.dart';
import 'package:famedlysdk/src/utils/ChatTime.dart';
import 'package:famedlysdk/src/utils/MxContent.dart';
import 'package:famedlysdk/src/Event.dart';
import 'package:famedlysdk/src/responses/ErrorResponse.dart';
import 'package:famedlysdk/src/sync/EventUpdate.dart';
import 'package:famedlysdk/src/Event.dart';
import 'package:famedlysdk/src/utils/ChatTime.dart';
import 'package:famedlysdk/src/utils/MxContent.dart';
import './User.dart';
import 'Connection.dart';
import 'Timeline.dart';
/// Represents a Matrix room.
@ -36,7 +38,7 @@ class Room {
final String id;
/// Membership status of the user for this room.
String membership;
Membership membership;
/// The name of the room if set by a participant.
String name;
@ -96,7 +98,7 @@ class Room {
Client get matrix => this.client;
@Deprecated("Rooms.status is deprecated! Use Rooms.membership instead!")
String get status => this.membership;
String get status => this.membership.toString().split('.').last;
Room({
this.id,
@ -140,7 +142,7 @@ class Room {
/// Call the Matrix API to change the name of this room.
Future<dynamic> setName(String newName) async {
dynamic res = await client.connection.jsonRequest(
type: "PUT",
type: HTTPType.PUT,
action: "/client/r0/rooms/${id}/send/m.room.name/${new DateTime.now()}",
data: {"name": newName});
if (res is ErrorResponse) client.connection.onError.add(res);
@ -150,7 +152,7 @@ class Room {
/// Call the Matrix API to change the topic of this room.
Future<dynamic> setDescription(String newName) async {
dynamic res = await client.connection.jsonRequest(
type: "PUT",
type: HTTPType.PUT,
action:
"/client/r0/rooms/${id}/send/m.room.topic/${new DateTime.now()}",
data: {"topic": newName});
@ -162,7 +164,7 @@ class Room {
Future<dynamic> sendText(String message, {String txid = null}) async {
if (txid == null) txid = "txid${DateTime.now().millisecondsSinceEpoch}";
final dynamic res = await client.connection.jsonRequest(
type: "PUT",
type: HTTPType.PUT,
action: "/client/r0/rooms/${id}/send/m.room.message/$txid",
data: {"msgtype": "m.text", "body": message});
if (res is ErrorResponse) client.connection.onError.add(res);
@ -197,6 +199,7 @@ class Room {
client.connection.onEvent.add(eventUpdate);
await client.store?.transaction(() {
client.store.storeEventUpdate(eventUpdate);
return;
});
// Send the text and on success, store and display a *sent* event.
@ -208,6 +211,7 @@ class Room {
client.connection.onEvent.add(eventUpdate);
await client.store?.transaction(() {
client.store.storeEventUpdate(eventUpdate);
return;
});
} else {
eventUpdate.content["status"] = 1;
@ -215,6 +219,7 @@ class Room {
client.connection.onEvent.add(eventUpdate);
await client.store?.transaction(() {
client.store.storeEventUpdate(eventUpdate);
return;
});
return res["event_id"];
}
@ -223,8 +228,8 @@ class Room {
/// Call the Matrix API to leave this room.
Future<dynamic> leave() async {
dynamic res = await client.connection
.jsonRequest(type: "POST", action: "/client/r0/rooms/${id}/leave");
dynamic res = await client.connection.jsonRequest(
type: HTTPType.POST, action: "/client/r0/rooms/${id}/leave");
if (res is ErrorResponse) client.connection.onError.add(res);
return res;
}
@ -232,8 +237,8 @@ class Room {
/// Call the Matrix API to forget this room if you already left it.
Future<dynamic> forget() async {
client.store.forgetRoom(id);
dynamic res = await client.connection
.jsonRequest(type: "POST", action: "/client/r0/rooms/${id}/forget");
dynamic res = await client.connection.jsonRequest(
type: HTTPType.POST, action: "/client/r0/rooms/${id}/forget");
if (res is ErrorResponse) client.connection.onError.add(res);
return res;
}
@ -241,7 +246,7 @@ class Room {
/// Call the Matrix API to kick a user from this room.
Future<dynamic> kick(String userID) async {
dynamic res = await client.connection.jsonRequest(
type: "POST",
type: HTTPType.POST,
action: "/client/r0/rooms/${id}/kick",
data: {"user_id": userID});
if (res is ErrorResponse) client.connection.onError.add(res);
@ -251,7 +256,7 @@ class Room {
/// Call the Matrix API to ban a user from this room.
Future<dynamic> ban(String userID) async {
dynamic res = await client.connection.jsonRequest(
type: "POST",
type: HTTPType.POST,
action: "/client/r0/rooms/${id}/ban",
data: {"user_id": userID});
if (res is ErrorResponse) client.connection.onError.add(res);
@ -261,7 +266,7 @@ class Room {
/// Call the Matrix API to unban a banned user from this room.
Future<dynamic> unban(String userID) async {
dynamic res = await client.connection.jsonRequest(
type: "POST",
type: HTTPType.POST,
action: "/client/r0/rooms/${id}/unban",
data: {"user_id": userID});
if (res is ErrorResponse) client.connection.onError.add(res);
@ -274,7 +279,7 @@ class Room {
powerMap[userID] = power;
dynamic res = await client.connection.jsonRequest(
type: "PUT",
type: HTTPType.PUT,
action: "/client/r0/rooms/$id/state/m.room.power_levels/",
data: {"users": powerMap});
if (res is ErrorResponse) client.connection.onError.add(res);
@ -284,7 +289,7 @@ class Room {
/// Call the Matrix API to invite a user to this room.
Future<dynamic> invite(String userID) async {
dynamic res = await client.connection.jsonRequest(
type: "POST",
type: HTTPType.POST,
action: "/client/r0/rooms/${id}/invite",
data: {"user_id": userID});
if (res is ErrorResponse) client.connection.onError.add(res);
@ -294,7 +299,7 @@ class Room {
/// Request more previous events from the server.
Future<void> requestHistory({int historyCount = 100}) async {
final dynamic resp = await client.connection.jsonRequest(
type: "GET",
type: HTTPType.GET,
action:
"/client/r0/rooms/$id/messages?from=${prev_batch}&dir=b&limit=$historyCount");
@ -321,6 +326,7 @@ class Room {
client.store.txn.rawUpdate(
"UPDATE Rooms SET prev_batch=? WHERE id=?", [resp["end"], id]);
}
return;
});
if (client.store == null) {
for (int i = 0; i < history.length; i++) {
@ -347,7 +353,7 @@ class Room {
directChats[userID] = [id];
final resp = await client.connection.jsonRequest(
type: "PUT",
type: HTTPType.PUT,
action: "/client/r0/user/${client.userID}/account_data/m.direct",
data: directChats);
return resp;
@ -356,7 +362,7 @@ class Room {
/// Sends *m.fully_read* and *m.read* for the given event ID.
Future<dynamic> sendReadReceipt(String eventID) async {
final dynamic resp = client.connection.jsonRequest(
type: "POST",
type: HTTPType.POST,
action: "/client/r0/rooms/$id/read_markers",
data: {
"m.fully_read": eventID,
@ -379,7 +385,8 @@ class Room {
return Room(
id: row["id"],
name: name,
membership: row["membership"],
membership: Membership.values
.firstWhere((e) => e.toString() == 'Membership.' + row["membership"]),
topic: row["description"],
avatar: MxContent(avatarUrl),
notificationCount: row["notification_count"],
@ -455,18 +462,21 @@ class Room {
Future<List<User>> requestParticipants() async {
List<User> participants = [];
dynamic res = await client.connection
.jsonRequest(type: "GET", action: "/client/r0/rooms/${id}/members");
dynamic res = await client.connection.jsonRequest(
type: HTTPType.GET, action: "/client/r0/rooms/${id}/members");
if (res is ErrorResponse || !(res["chunk"] is List<dynamic>))
return participants;
for (num i = 0; i < res["chunk"].length; i++) {
User newUser = User(res["chunk"][i]["state_key"],
displayName: res["chunk"][i]["content"]["displayname"] ?? "",
membership: res["chunk"][i]["content"]["membership"] ?? "",
membership: Membership.values.firstWhere((e) =>
e.toString() ==
'Membership.' + res["chunk"][i]["content"]["membership"] ??
""),
avatarUrl: MxContent(res["chunk"][i]["content"]["avatar_url"] ?? ""),
room: this);
if (newUser.membership != "leave") participants.add(newUser);
if (newUser.membership != Membership.leave) participants.add(newUser);
}
return participants;
@ -480,7 +490,7 @@ class Room {
if (storeEvent != null) return storeEvent;
}
final dynamic resp = await client.connection.jsonRequest(
type: "GET", action: "/client/r0/rooms/$id/event/$eventID");
type: HTTPType.GET, action: "/client/r0/rooms/$id/event/$eventID");
if (resp is ErrorResponse) return null;
return Event.fromJson(resp, this);
}

View file

@ -23,14 +23,15 @@
import 'dart:async';
import 'dart:core';
import 'Client.dart';
import 'Event.dart';
import 'Room.dart';
import 'User.dart';
import 'utils/ChatTime.dart';
import 'utils/MxContent.dart';
import 'sync/EventUpdate.dart';
import 'sync/RoomUpdate.dart';
import 'utils/ChatTime.dart';
import 'utils/MxContent.dart';
/// Represents a list of rooms for this client, which will automatically update
/// itself and call the [onUpdate], [onInsert] and [onDelete] callbacks. To get
@ -78,11 +79,11 @@ class RoomList {
if (rooms[j].id == chatUpdate.id) break;
}
final bool found = (j < rooms.length - 1 && rooms[j].id == chatUpdate.id);
final bool isLeftRoom = chatUpdate.membership == "leave";
final bool isLeftRoom = chatUpdate.membership == Membership.leave;
// Does the chat already exist in the list rooms?
if (!found && ((!onlyLeft && !isLeftRoom) || (onlyLeft && isLeftRoom))) {
num position = chatUpdate.membership == "invite" ? 0 : j;
num position = chatUpdate.membership == Membership.invite ? 0 : j;
// Add the new chat to the list
Room newRoom = Room(
id: chatUpdate.id,
@ -102,7 +103,7 @@ class RoomList {
}
// Update notification and highlight count
else if (found &&
chatUpdate.membership != "leave" &&
chatUpdate.membership != Membership.leave &&
(rooms[j].notificationCount != chatUpdate.notification_count ||
rooms[j].highlightCount != chatUpdate.highlight_count)) {
rooms[j].notificationCount = chatUpdate.notification_count;

View file

@ -24,16 +24,18 @@
import 'dart:async';
import 'dart:convert';
import 'dart:core';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart' as p;
import 'sync/EventUpdate.dart';
import 'sync/UserUpdate.dart';
import 'sync/RoomUpdate.dart';
import 'package:sqflite/sqflite.dart';
import 'Client.dart';
import 'User.dart';
import 'Room.dart';
import 'Event.dart';
import 'Connection.dart';
import 'Event.dart';
import 'Room.dart';
import 'User.dart';
import 'sync/EventUpdate.dart';
import 'sync/RoomUpdate.dart';
import 'sync/UserUpdate.dart';
/// Responsible to store all data persistent and to query objects from the
/// database.
@ -53,7 +55,7 @@ class Store {
_init() async {
var databasePath = await getDatabasesPath();
String path = p.join(databasePath, "FluffyMatrix.db");
_db = await openDatabase(path, version: 4,
_db = await openDatabase(path, version: 5,
onCreate: (Database db, int version) async {
await createTables(db);
}, onUpgrade: (Database db, int oldVersion, int newVersion) async {
@ -61,7 +63,7 @@ class Store {
if (oldVersion != newVersion) {
await db.execute("DROP TABLE IF EXISTS Rooms");
await db.execute("DROP TABLE IF EXISTS Participants");
await db.execute("DROP TABLE IF EXISTS User");
await db.execute("DROP TABLE IF EXISTS Users");
await db.execute("DROP TABLE IF EXISTS Events");
db.rawUpdate("UPDATE Clients SET prev_batch='' WHERE client=?",
[client.clientName]);
@ -127,7 +129,7 @@ class Store {
await _db
.rawDelete("DELETE FROM Clients WHERE client=?", [client.clientName]);
await _db.rawDelete("DELETE FROM Rooms");
await _db.rawDelete("DELETE FROM User");
await _db.rawDelete("DELETE FROM Users");
await _db.rawDelete("DELETE FROM Events");
return;
}
@ -162,7 +164,7 @@ class Store {
txn.rawInsert(
"INSERT OR IGNORE INTO Rooms " +
"VALUES(?, ?, '', 0, 0, '', '', '', 0, '', '', '', '', '', '', '', '', 0, 50, 50, 0, 50, 50, 0, 50, 100, 50, 50, 50, 100) ",
[roomUpdate.id, roomUpdate.membership]);
[roomUpdate.id, roomUpdate.membership.toString().split('.').last]);
// Update the notification counts and the limited timeline boolean
txn.rawUpdate(
@ -170,7 +172,7 @@ class Store {
[
roomUpdate.highlight_count,
roomUpdate.notification_count,
roomUpdate.membership,
roomUpdate.membership.toString().split('.').last,
roomUpdate.id
]);
@ -329,14 +331,14 @@ class Store {
}
// Update membership table
txn.rawInsert("INSERT OR IGNORE INTO User VALUES(?,?,?,?,?,0)", [
txn.rawInsert("INSERT OR IGNORE INTO Users VALUES(?,?,?,?,?,0)", [
chat_id,
state_key,
insertDisplayname,
insertAvatarUrl,
membership
]);
String queryStr = "UPDATE User SET membership=?";
String queryStr = "UPDATE Users SET membership=?";
List<String> queryArgs = [membership];
if (eventContent["content"]["displayname"] is String) {
@ -411,10 +413,10 @@ class Store {
.forEach((String user, dynamic value) async {
num power_level = eventContent["content"]["users"][user];
txn.rawUpdate(
"UPDATE User SET power_level=? WHERE matrix_id=? AND chat_id=?",
"UPDATE Users SET power_level=? WHERE matrix_id=? AND chat_id=?",
[power_level, user, chat_id]);
txn.rawInsert(
"INSERT OR IGNORE INTO User VALUES(?, ?, '', '', ?, ?)",
"INSERT OR IGNORE INTO Users VALUES(?, ?, '', '', ?, ?)",
[chat_id, user, "unknown", power_level]);
});
}
@ -426,7 +428,7 @@ class Store {
/// Returns a User object by a given Matrix ID and a Room.
Future<User> getUser({String matrixID, Room room}) async {
List<Map<String, dynamic>> res = await db.rawQuery(
"SELECT * FROM User WHERE matrix_id=? AND chat_id=?",
"SELECT * FROM Users WHERE matrix_id=? AND chat_id=?",
[matrixID, room.id]);
if (res.length != 1) return null;
return User.fromJson(res[0], room);
@ -435,7 +437,7 @@ class Store {
/// Loads all Users in the database to provide a contact list.
Future<List<User>> loadContacts() async {
List<Map<String, dynamic>> res = await db.rawQuery(
"SELECT * FROM User WHERE matrix_id!=? GROUP BY matrix_id ORDER BY displayname",
"SELECT * FROM Users WHERE matrix_id!=? GROUP BY matrix_id ORDER BY displayname",
[client.userID]);
List<User> userList = [];
for (int i = 0; i < res.length; i++)
@ -447,7 +449,7 @@ class Store {
Future<List<User>> loadParticipants(Room room) async {
List<Map<String, dynamic>> res = await db.rawQuery(
"SELECT * " +
" FROM User " +
" FROM Users " +
" WHERE chat_id=? " +
" AND membership='join'",
[room.id]);
@ -464,7 +466,7 @@ class Store {
/// Returns a list of events for the given room and sets all participants.
Future<List<Event>> getEventList(Room room) async {
List<Map<String, dynamic>> memberRes = await db.rawQuery(
"SELECT * " + " FROM User " + " WHERE User.chat_id=?", [room.id]);
"SELECT * " + " FROM Users " + " WHERE Users.chat_id=?", [room.id]);
Map<String, User> userMap = {};
for (num i = 0; i < memberRes.length; i++)
userMap[memberRes[i]["matrix_id"]] = User.fromJson(memberRes[i], room);
@ -528,10 +530,10 @@ class Store {
Future<String> getAvatarFromSingleChat(String roomID) async {
String avatarStr = "";
List<Map<String, dynamic>> res = await db.rawQuery(
"SELECT avatar_url FROM User " +
" WHERE User.chat_id=? " +
" AND (User.membership='join' OR User.membership='invite') " +
" AND User.matrix_id!=? ",
"SELECT avatar_url FROM Users " +
" WHERE Users.chat_id=? " +
" AND (Users.membership='join' OR Users.membership='invite') " +
" AND Users.matrix_id!=? ",
[roomID, client.userID]);
if (res.length == 1) avatarStr = res[0]["avatar_url"];
return avatarStr;
@ -543,10 +545,10 @@ class Store {
Future<String> getChatNameFromMemberNames(String roomID) async {
String displayname = 'Empty chat';
List<Map<String, dynamic>> rs = await db.rawQuery(
"SELECT User.displayname, User.matrix_id, User.membership FROM User " +
" WHERE User.chat_id=? " +
" AND (User.membership='join' OR User.membership='invite') " +
" AND User.matrix_id!=? ",
"SELECT Users.displayname, Users.matrix_id, Users.membership FROM Users " +
" WHERE Users.chat_id=? " +
" AND (Users.membership='join' OR Users.membership='invite') " +
" AND Users.matrix_id!=? ",
[roomID, client.userID]);
if (rs.length > 0) {
displayname = "";
@ -576,7 +578,7 @@ class Store {
/// the room or the own user wasn't found.
Future<int> getPowerLevel(String roomID) async {
List<Map<String, dynamic>> res = await db.rawQuery(
"SELECT power_level FROM User WHERE matrix_id=? AND chat_id=?",
"SELECT power_level FROM Users WHERE matrix_id=? AND chat_id=?",
[roomID, client.userID]);
if (res.length != 1) return null;
return res[0]["power_level"];
@ -585,7 +587,7 @@ class Store {
/// Returns the power levels from all users for the given [roomID].
Future<Map<String, int>> getPowerLevels(String roomID) async {
List<Map<String, dynamic>> res = await db.rawQuery(
"SELECT matrix_id, power_level FROM User WHERE chat_id=?",
"SELECT matrix_id, power_level FROM Users WHERE chat_id=?",
[roomID, client.userID]);
Map<String, int> powerMap = {};
for (int i = 0; i < res.length; i++)
@ -686,7 +688,7 @@ class Store {
'UNIQUE(id))';
/// The database sheme for the User class.
static final String UserScheme = 'CREATE TABLE IF NOT EXISTS User(' +
static final String UserScheme = 'CREATE TABLE IF NOT EXISTS Users(' +
'chat_id TEXT, ' + // The chat id of this membership
'matrix_id TEXT, ' + // The matrix id of this user
'displayname TEXT, ' +

View file

@ -22,6 +22,7 @@
*/
import 'dart:async';
import 'Event.dart';
import 'Room.dart';
import 'User.dart';
@ -94,7 +95,9 @@ class Timeline {
}
sortAndUpdate();
} catch (e) {
print("[WARNING] (_handleEventUpdate) ${e.toString()}");
if (room.client.debug) {
print("[WARNING] (_handleEventUpdate) ${e.toString()}");
}
}
}

View file

@ -21,9 +21,13 @@
* along with famedlysdk. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:famedlysdk/src/Room.dart';
import 'package:famedlysdk/src/responses/ErrorResponse.dart';
import 'package:famedlysdk/src/utils/MxContent.dart';
import 'package:famedlysdk/src/Room.dart';
import 'Connection.dart';
enum Membership { join, invite, leave, ban }
/// Represents a Matrix User which may be a participant in a Matrix Room.
class User {
@ -38,7 +42,7 @@ class User {
/// invite
/// leave
/// ban
String membership;
Membership membership;
/// The avatar if the user has one.
MxContent avatarUrl;
@ -53,7 +57,7 @@ class User {
final Room room;
@Deprecated("Use membership instead!")
String get status => membership;
String get status => membership.toString().split('.').last;
@Deprecated("Use ID instead!")
String get mxid => id;
@ -81,7 +85,12 @@ class User {
return User(json['matrix_id'] ?? json['sender'],
displayName: json['displayname'],
avatarUrl: MxContent(json['avatar_url']),
membership: json['membership'],
membership: Membership.values.firstWhere((e) {
if (json["membership"] != null) {
return e.toString() == 'Membership.' + json['membership'];
}
return false;
}, orElse: () => null),
powerLevel: json['power_level'],
room: room);
}
@ -132,12 +141,14 @@ class User {
if (roomID != null) return roomID;
// Start a new direct chat
final dynamic resp = await room.client.connection
.jsonRequest(type: "POST", action: "/client/r0/createRoom", data: {
"invite": [id],
"is_direct": true,
"preset": "trusted_private_chat"
});
final dynamic resp = await room.client.connection.jsonRequest(
type: HTTPType.POST,
action: "/client/r0/createRoom",
data: {
"invite": [id],
"is_direct": true,
"preset": "trusted_private_chat"
});
if (resp is ErrorResponse) {
room.client.connection.onError.add(resp);

View file

@ -21,6 +21,8 @@
* along with famedlysdk. If not, see <http://www.gnu.org/licenses/>.
*/
import '../User.dart';
/// Represents a new room or an update for an
/// already known room.
class RoomUpdate {
@ -28,7 +30,7 @@ class RoomUpdate {
final String id;
/// The current membership state of the user in this room.
final String membership;
final Membership membership;
/// Represents the number of unead notifications. This probably doesn't fit the number
/// of unread messages.

View file

@ -21,16 +21,18 @@
* along with famedlysdk. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:famedlysdk/src/responses/PushrulesResponse.dart';
import 'package:flutter_test/flutter_test.dart';
import 'dart:async';
import 'package:famedlysdk/src/Client.dart';
import 'package:famedlysdk/src/Connection.dart';
import 'package:famedlysdk/src/User.dart';
import 'package:famedlysdk/src/responses/ErrorResponse.dart';
import 'package:famedlysdk/src/responses/PushrulesResponse.dart';
import 'package:famedlysdk/src/sync/EventUpdate.dart';
import 'package:famedlysdk/src/sync/RoomUpdate.dart';
import 'package:famedlysdk/src/sync/UserUpdate.dart';
import 'package:famedlysdk/src/responses/ErrorResponse.dart';
import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'FakeMatrixApi.dart';
void main() {
@ -70,7 +72,7 @@ void main() {
expect(checkError.errcode, "NO_RESPONSE");
final resp = await matrix.connection
.jsonRequest(type: "POST", action: "/client/r0/login", data: {
.jsonRequest(type: HTTPType.POST, action: "/client/r0/login", data: {
"type": "m.login.password",
"user": "test",
"password": "1234",
@ -108,13 +110,13 @@ void main() {
test('Try to get ErrorResponse', () async {
final resp = await matrix.connection
.jsonRequest(type: "PUT", action: "/non/existing/path");
.jsonRequest(type: HTTPType.PUT, action: "/non/existing/path");
expect(resp is ErrorResponse, true);
});
test('Logout', () async {
final dynamic resp = await matrix.connection
.jsonRequest(type: "POST", action: "/client/r0/logout");
.jsonRequest(type: HTTPType.POST, action: "/client/r0/logout");
expect(resp is ErrorResponse, false);
Future<LoginState> loginStateFuture =
@ -143,21 +145,21 @@ void main() {
expect(roomUpdateList.length, 3);
expect(roomUpdateList[0].id == "!726s6s6q:example.com", true);
expect(roomUpdateList[0].membership == "join", true);
expect(roomUpdateList[0].membership == Membership.join, true);
expect(roomUpdateList[0].prev_batch == "t34-23535_0_0", true);
expect(roomUpdateList[0].limitedTimeline == true, true);
expect(roomUpdateList[0].notification_count == 2, true);
expect(roomUpdateList[0].highlight_count == 2, true);
expect(roomUpdateList[1].id == "!696r7674:example.com", true);
expect(roomUpdateList[1].membership == "invite", true);
expect(roomUpdateList[1].membership == Membership.invite, true);
expect(roomUpdateList[1].prev_batch == "", true);
expect(roomUpdateList[1].limitedTimeline == false, true);
expect(roomUpdateList[1].notification_count == 0, true);
expect(roomUpdateList[1].highlight_count == 0, true);
expect(roomUpdateList[2].id == "!5345234234:example.com", true);
expect(roomUpdateList[2].membership == "leave", true);
expect(roomUpdateList[2].membership == Membership.leave, true);
expect(roomUpdateList[2].prev_batch == "", true);
expect(roomUpdateList[2].limitedTimeline == false, true);
expect(roomUpdateList[2].notification_count == 0, true);
@ -250,7 +252,7 @@ void main() {
Future<LoginState> loginStateFuture =
matrix.connection.onLoginStateChanged.stream.first;
await matrix.connection
.jsonRequest(type: "DELETE", action: "/unknown/token");
.jsonRequest(type: HTTPType.DELETE, action: "/unknown/token");
LoginState state = await loginStateFuture;
expect(state, LoginState.loggedOut);

View file

@ -21,8 +21,9 @@
* along with famedlysdk. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:flutter_test/flutter_test.dart';
import 'package:famedlysdk/src/Event.dart';
import 'package:famedlysdk/src/User.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
/// All Tests related to the Event
@ -33,7 +34,7 @@ void main() {
final String senderID = "@alice:server.abc";
final String senderDisplayname = "Alice";
final String empty = "";
final String membership = "join";
final Membership membership = Membership.join;
final String type = "m.room.message";
final String msgtype = "m.text";
final String body = "Hello World";
@ -47,7 +48,7 @@ void main() {
"matrix_id": senderID,
"displayname": senderDisplayname,
"avatar_url": empty,
"membership": membership,
"membership": membership.toString().split('.').last,
"origin_server_ts": timestamp,
"state_key": empty,
"type": type,

View file

@ -21,12 +21,13 @@
* along with famedlysdk. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:flutter_test/flutter_test.dart';
import 'package:famedlysdk/src/Client.dart';
import 'package:famedlysdk/src/RoomList.dart';
import 'package:famedlysdk/src/User.dart';
import 'package:famedlysdk/src/sync/EventUpdate.dart';
import 'package:famedlysdk/src/sync/RoomUpdate.dart';
import 'package:famedlysdk/src/utils/ChatTime.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
/// All Tests related to the MxContent
@ -59,7 +60,7 @@ void main() {
client.connection.onRoomUpdate.add(RoomUpdate(
id: roomID,
membership: "join",
membership: Membership.join,
notification_count: 2,
highlight_count: 1,
limitedTimeline: false,
@ -74,7 +75,7 @@ void main() {
expect(roomList.rooms.length, 1);
expect(roomList.rooms[0].id, roomID);
expect(roomList.rooms[0].membership, "join");
expect(roomList.rooms[0].membership, Membership.join);
expect(roomList.rooms[0].notificationCount, 2);
expect(roomList.rooms[0].highlightCount, 1);
expect(roomList.rooms[0].prev_batch, "1234");
@ -104,7 +105,7 @@ void main() {
client.connection.onRoomUpdate.add(RoomUpdate(
id: "1",
membership: "join",
membership: Membership.join,
notification_count: 2,
highlight_count: 1,
limitedTimeline: false,
@ -112,7 +113,7 @@ void main() {
));
client.connection.onRoomUpdate.add(RoomUpdate(
id: "2",
membership: "join",
membership: Membership.join,
notification_count: 2,
highlight_count: 1,
limitedTimeline: false,
@ -193,7 +194,7 @@ void main() {
client.connection.onRoomUpdate.add(RoomUpdate(
id: "1",
membership: "join",
membership: Membership.join,
notification_count: 2,
highlight_count: 1,
limitedTimeline: false,
@ -201,7 +202,7 @@ void main() {
));
client.connection.onRoomUpdate.add(RoomUpdate(
id: "2",
membership: "leave",
membership: Membership.leave,
notification_count: 2,
highlight_count: 1,
limitedTimeline: false,

View file

@ -21,11 +21,12 @@
* along with famedlysdk. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:flutter_test/flutter_test.dart';
import 'package:famedlysdk/src/Room.dart';
import 'package:famedlysdk/src/Client.dart';
import 'package:famedlysdk/src/Event.dart';
import 'package:famedlysdk/src/Room.dart';
import 'package:famedlysdk/src/User.dart';
import 'package:flutter_test/flutter_test.dart';
import 'FakeMatrixApi.dart';
void main() {
@ -50,7 +51,7 @@ void main() {
test("Create from json", () async {
final String id = "!localpart:server.abc";
final String name = "My Room";
final String membership = "join";
final Membership membership = Membership.join;
final String topic = "This is my own room";
final int unread = DateTime.now().millisecondsSinceEpoch;
final int notificationCount = 2;
@ -69,7 +70,7 @@ void main() {
final Map<String, dynamic> jsonObj = {
"id": id,
"membership": membership,
"membership": membership.toString().split('.').last,
"topic": name,
"description": topic,
"avatar_url": "",
@ -137,7 +138,7 @@ void main() {
User user = participants[0];
expect(user.id, "@alice:example.org");
expect(user.displayName, "Alice Margatroid");
expect(user.membership, "join");
expect(user.membership, Membership.join);
expect(user.avatarUrl.mxc, "mxc://example.org/SEsfnsuifSDFSSEF");
expect(user.room.id, "!localpart:server.abc");
});

View file

@ -21,15 +21,15 @@
* along with famedlysdk. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:flutter_test/flutter_test.dart';
import 'package:famedlysdk/src/User.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
/// All Tests related to the Event
group("User", () {
test("Create from json", () async {
final String id = "@alice:server.abc";
final String membership = "join";
final Membership membership = Membership.join;
final String displayName = "Alice";
final String avatarUrl = "";
final int powerLevel = 50;
@ -38,7 +38,7 @@ void main() {
"matrix_id": id,
"displayname": displayName,
"avatar_url": avatarUrl,
"membership": membership,
"membership": membership.toString().split('.').last,
"power_level": powerLevel,
};