Add support for creating chats and direct chats
This commit is contained in:
parent
4833b9027f
commit
037953be34
|
@ -26,12 +26,12 @@ import 'dart:core';
|
||||||
import 'responses/ErrorResponse.dart';
|
import 'responses/ErrorResponse.dart';
|
||||||
import 'Connection.dart';
|
import 'Connection.dart';
|
||||||
import 'Store.dart';
|
import 'Store.dart';
|
||||||
|
import 'User.dart';
|
||||||
|
|
||||||
/// Represents a Matrix client to communicate with a
|
/// Represents a Matrix client to communicate with a
|
||||||
/// [Matrix](https://matrix.org) homeserver and is the entry point for this
|
/// [Matrix](https://matrix.org) homeserver and is the entry point for this
|
||||||
/// SDK.
|
/// SDK.
|
||||||
class Client {
|
class Client {
|
||||||
|
|
||||||
/// Handles the connection for this client.
|
/// Handles the connection for this client.
|
||||||
Connection connection;
|
Connection connection;
|
||||||
|
|
||||||
|
@ -41,8 +41,7 @@ class Client {
|
||||||
Client(this.clientName) {
|
Client(this.clientName) {
|
||||||
connection = Connection(this);
|
connection = Connection(this);
|
||||||
|
|
||||||
if (this.clientName != "testclient")
|
if (this.clientName != "testclient") store = Store(this);
|
||||||
store = Store(this);
|
|
||||||
connection.onLoginStateChanged.stream.listen((loginState) {
|
connection.onLoginStateChanged.stream.listen((loginState) {
|
||||||
print("LoginState: ${loginState.toString()}");
|
print("LoginState: ${loginState.toString()}");
|
||||||
});
|
});
|
||||||
|
@ -86,7 +85,7 @@ class Client {
|
||||||
homeserver = serverUrl;
|
homeserver = serverUrl;
|
||||||
|
|
||||||
final versionResp =
|
final versionResp =
|
||||||
await connection.jsonRequest(type: "GET", action: "/client/versions");
|
await connection.jsonRequest(type: "GET", action: "/client/versions");
|
||||||
if (versionResp is ErrorResponse) {
|
if (versionResp is ErrorResponse) {
|
||||||
connection.onError.add(ErrorResponse(errcode: "NO_RESPONSE", error: ""));
|
connection.onError.add(ErrorResponse(errcode: "NO_RESPONSE", error: ""));
|
||||||
return false;
|
return false;
|
||||||
|
@ -118,7 +117,7 @@ class Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
final loginResp =
|
final loginResp =
|
||||||
await connection.jsonRequest(type: "GET", action: "/client/r0/login");
|
await connection.jsonRequest(type: "GET", action: "/client/r0/login");
|
||||||
if (loginResp is ErrorResponse) {
|
if (loginResp is ErrorResponse) {
|
||||||
connection.onError.add(loginResp);
|
connection.onError.add(loginResp);
|
||||||
return false;
|
return false;
|
||||||
|
@ -142,9 +141,8 @@ class Client {
|
||||||
/// Handles the login and allows the client to call all APIs which require
|
/// Handles the login and allows the client to call all APIs which require
|
||||||
/// authentication. Returns false if the login was not successful.
|
/// authentication. Returns false if the login was not successful.
|
||||||
Future<bool> login(String username, String password) async {
|
Future<bool> login(String username, String password) async {
|
||||||
|
final loginResp = await connection
|
||||||
final loginResp =
|
.jsonRequest(type: "POST", action: "/client/r0/login", data: {
|
||||||
await connection.jsonRequest(type: "POST", action: "/client/r0/login", data: {
|
|
||||||
"type": "m.login.password",
|
"type": "m.login.password",
|
||||||
"user": username,
|
"user": username,
|
||||||
"identifier": {
|
"identifier": {
|
||||||
|
@ -180,11 +178,24 @@ class Client {
|
||||||
/// Sends a logout command to the homeserver and clears all local data,
|
/// Sends a logout command to the homeserver and clears all local data,
|
||||||
/// including all persistent data from the store.
|
/// including all persistent data from the store.
|
||||||
Future<void> logout() async {
|
Future<void> logout() async {
|
||||||
final dynamic resp =
|
final dynamic resp = await connection.jsonRequest(
|
||||||
await connection.jsonRequest(type: "POST", action: "/client/r0/logout/all");
|
type: "POST", action: "/client/r0/logout/all");
|
||||||
if (resp == null) return;
|
if (resp == null) return;
|
||||||
|
|
||||||
await connection.clear();
|
await connection.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new group chat and invites the given Users and returns the new
|
||||||
|
/// created room ID.
|
||||||
|
Future<String> createGroup(List<User> users) async {
|
||||||
|
List<String> inviteIDs = [];
|
||||||
|
for (int i = 0; i < users.length; i++) inviteIDs.add(users[i].id);
|
||||||
|
|
||||||
|
Map<String, dynamic> resp = await connection.jsonRequest(
|
||||||
|
type: "POST",
|
||||||
|
action: "/client/r0/createRoom",
|
||||||
|
data: {"invite": inviteIDs, "preset": "private_chat"});
|
||||||
|
|
||||||
|
return resp["room_id"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ import 'Connection.dart';
|
||||||
/// Responsible to store all data persistent and to query objects from the
|
/// Responsible to store all data persistent and to query objects from the
|
||||||
/// database.
|
/// database.
|
||||||
class Store {
|
class Store {
|
||||||
|
|
||||||
final Client client;
|
final Client client;
|
||||||
|
|
||||||
Store(this.client) {
|
Store(this.client) {
|
||||||
|
@ -50,25 +49,24 @@ class Store {
|
||||||
/// SDK instead of writing direct queries to the database.
|
/// SDK instead of writing direct queries to the database.
|
||||||
Database get db => _db;
|
Database get db => _db;
|
||||||
|
|
||||||
_init() async{
|
_init() async {
|
||||||
var databasePath = await getDatabasesPath();
|
var databasePath = await getDatabasesPath();
|
||||||
String path = p.join(databasePath, "FluffyMatrix.db");
|
String path = p.join(databasePath, "FluffyMatrix.db");
|
||||||
_db = await openDatabase(path, version: 4,
|
_db = await openDatabase(path, version: 4,
|
||||||
onCreate: (Database db, int version) async {
|
onCreate: (Database db, int version) async {
|
||||||
await createTables(db);
|
await createTables(db);
|
||||||
},
|
}, onUpgrade: (Database db, int oldVersion, int newVersion) async {
|
||||||
onUpgrade: (Database db, int oldVersion, int newVersion) async{
|
print("Migrate databse from version $oldVersion to $newVersion");
|
||||||
print("Migrate databse from version $oldVersion to $newVersion");
|
if (oldVersion != newVersion) {
|
||||||
if (oldVersion != newVersion) {
|
await db.execute("DROP TABLE IF EXISTS Rooms");
|
||||||
await db.execute("DROP TABLE IF EXISTS Rooms");
|
await db.execute("DROP TABLE IF EXISTS Participants");
|
||||||
await db.execute("DROP TABLE IF EXISTS Participants");
|
await db.execute("DROP TABLE IF EXISTS User");
|
||||||
await db.execute("DROP TABLE IF EXISTS User");
|
await db.execute("DROP TABLE IF EXISTS Events");
|
||||||
await db.execute("DROP TABLE IF EXISTS Events");
|
db.rawUpdate("UPDATE Clients SET prev_batch='' WHERE client=?",
|
||||||
db.rawUpdate("UPDATE Clients SET prev_batch='' WHERE client=?",
|
[client.clientName]);
|
||||||
[client.clientName]);
|
createTables(db);
|
||||||
createTables(db);
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
List<Map> list = await _db
|
List<Map> list = await _db
|
||||||
.rawQuery("SELECT * FROM Clients WHERE client=?", [client.clientName]);
|
.rawQuery("SELECT * FROM Clients WHERE client=?", [client.clientName]);
|
||||||
|
@ -82,28 +80,30 @@ class Store {
|
||||||
newDeviceName: clientList["device_name"],
|
newDeviceName: clientList["device_name"],
|
||||||
newLazyLoadMembers: clientList["lazy_load_members"] == 1,
|
newLazyLoadMembers: clientList["lazy_load_members"] == 1,
|
||||||
newMatrixVersions: clientList["matrix_versions"].toString().split(","),
|
newMatrixVersions: clientList["matrix_versions"].toString().split(","),
|
||||||
newPrevBatch: clientList["prev_batch"].toString().isEmpty ? null : clientList["prev_batch"],
|
newPrevBatch: clientList["prev_batch"].toString().isEmpty
|
||||||
|
? null
|
||||||
|
: clientList["prev_batch"],
|
||||||
);
|
);
|
||||||
print("Restore client credentials of ${client.userID}");
|
print("Restore client credentials of ${client.userID}");
|
||||||
} else
|
} else
|
||||||
client.connection.onLoginStateChanged.add(LoginState.loggedOut);
|
client.connection.onLoginStateChanged.add(LoginState.loggedOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> createTables(Database db) async {
|
||||||
Future<void> createTables(Database db) async{
|
|
||||||
await db.execute(ClientsScheme);
|
await db.execute(ClientsScheme);
|
||||||
await db.execute(RoomsScheme);
|
await db.execute(RoomsScheme);
|
||||||
await db.execute(UserScheme);
|
await db.execute(UserScheme);
|
||||||
await db.execute(EventsScheme);
|
await db.execute(EventsScheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> queryPrevBatch() async{
|
Future<String> queryPrevBatch() async {
|
||||||
List<Map> list = await txn.rawQuery("SELECT prev_batch FROM Clients WHERE client=?", [client.clientName]);
|
List<Map> list = await txn.rawQuery(
|
||||||
|
"SELECT prev_batch FROM Clients WHERE client=?", [client.clientName]);
|
||||||
return list[0]["prev_batch"];
|
return list[0]["prev_batch"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Will be automatically called when the client is logged in successfully.
|
/// Will be automatically called when the client is logged in successfully.
|
||||||
Future<void> storeClient() async{
|
Future<void> storeClient() async {
|
||||||
await _db
|
await _db
|
||||||
.rawInsert('INSERT OR IGNORE INTO Clients VALUES(?,?,?,?,?,?,?,?,?)', [
|
.rawInsert('INSERT OR IGNORE INTO Clients VALUES(?,?,?,?,?,?,?,?,?)', [
|
||||||
client.clientName,
|
client.clientName,
|
||||||
|
@ -120,8 +120,9 @@ class Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clears all tables from the database.
|
/// Clears all tables from the database.
|
||||||
Future<void> clear() async{
|
Future<void> clear() async {
|
||||||
await _db.rawDelete("DELETE FROM Clients WHERE client=?", [client.clientName]);
|
await _db
|
||||||
|
.rawDelete("DELETE FROM Clients WHERE client=?", [client.clientName]);
|
||||||
await _db.rawDelete("DELETE FROM Rooms");
|
await _db.rawDelete("DELETE FROM Rooms");
|
||||||
await _db.rawDelete("DELETE FROM User");
|
await _db.rawDelete("DELETE FROM User");
|
||||||
await _db.rawDelete("DELETE FROM Events");
|
await _db.rawDelete("DELETE FROM Events");
|
||||||
|
@ -130,7 +131,7 @@ class Store {
|
||||||
|
|
||||||
Transaction txn;
|
Transaction txn;
|
||||||
|
|
||||||
Future<void> transaction(Future<void> queries()) async{
|
Future<void> transaction(Future<void> queries()) async {
|
||||||
return client.store.db.transaction((txnObj) async {
|
return client.store.db.transaction((txnObj) async {
|
||||||
txn = txnObj;
|
txn = txnObj;
|
||||||
await queries();
|
await queries();
|
||||||
|
@ -148,7 +149,7 @@ class Store {
|
||||||
/// [transaction].
|
/// [transaction].
|
||||||
Future<void> storeRoomUpdate(RoomUpdate roomUpdate) {
|
Future<void> storeRoomUpdate(RoomUpdate roomUpdate) {
|
||||||
// Insert the chat into the database if not exists
|
// Insert the chat into the database if not exists
|
||||||
txn.rawInsert(
|
txn.rawInsert(
|
||||||
"INSERT OR IGNORE INTO Rooms " +
|
"INSERT OR IGNORE INTO Rooms " +
|
||||||
"VALUES(?, ?, '', 0, 0, '', '', '', 0, '', '', '', '', '', '', '', '', 0, 50, 50, 0, 50, 50, 0, 50, 100, 50, 50, 50, 100) ",
|
"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]);
|
||||||
|
@ -194,7 +195,7 @@ class Store {
|
||||||
|
|
||||||
// Save the event in the database
|
// Save the event in the database
|
||||||
|
|
||||||
txn.rawInsert(
|
txn.rawInsert(
|
||||||
"INSERT OR REPLACE INTO Events VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", [
|
"INSERT OR REPLACE INTO Events VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", [
|
||||||
eventContent["event_id"],
|
eventContent["event_id"],
|
||||||
chat_id,
|
chat_id,
|
||||||
|
@ -211,6 +212,17 @@ class Store {
|
||||||
if (type == "history") return null;
|
if (type == "history") return null;
|
||||||
|
|
||||||
switch (eventUpdate.eventType) {
|
switch (eventUpdate.eventType) {
|
||||||
|
case "m.direct":
|
||||||
|
if (eventUpdate.content["content"] is Map<String, List<String>>) {
|
||||||
|
Map<String, List<String>> directMap = eventUpdate.content["content"];
|
||||||
|
directMap.forEach((String key, List<String> value) {
|
||||||
|
if (value.length > 0)
|
||||||
|
txn.rawUpdate(
|
||||||
|
"UPDATE Rooms SET direct_chat_matrix_id=? WHERE id=?",
|
||||||
|
[key, value[0]]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "m.receipt":
|
case "m.receipt":
|
||||||
if (eventContent["user"] == client.userID) {
|
if (eventContent["user"] == client.userID) {
|
||||||
txn.rawUpdate("UPDATE Rooms SET unread=? WHERE id=?",
|
txn.rawUpdate("UPDATE Rooms SET unread=? WHERE id=?",
|
||||||
|
@ -222,56 +234,56 @@ class Store {
|
||||||
[eventContent["ts"], chat_id]);
|
[eventContent["ts"], chat_id]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// This event means, that the name of a room has been changed, so
|
// This event means, that the name of a room has been changed, so
|
||||||
// it has to be changed in the database.
|
// it has to be changed in the database.
|
||||||
case "m.room.name":
|
case "m.room.name":
|
||||||
txn.rawUpdate("UPDATE Rooms SET topic=? WHERE id=?",
|
txn.rawUpdate("UPDATE Rooms SET topic=? WHERE id=?",
|
||||||
[eventContent["content"]["name"], chat_id]);
|
[eventContent["content"]["name"], chat_id]);
|
||||||
break;
|
break;
|
||||||
// This event means, that the topic of a room has been changed, so
|
// This event means, that the topic of a room has been changed, so
|
||||||
// it has to be changed in the database
|
// it has to be changed in the database
|
||||||
case "m.room.topic":
|
case "m.room.topic":
|
||||||
txn.rawUpdate("UPDATE Rooms SET description=? WHERE id=?",
|
txn.rawUpdate("UPDATE Rooms SET description=? WHERE id=?",
|
||||||
[eventContent["content"]["topic"], chat_id]);
|
[eventContent["content"]["topic"], chat_id]);
|
||||||
break;
|
break;
|
||||||
// This event means, that the topic of a room has been changed, so
|
// This event means, that the topic of a room has been changed, so
|
||||||
// it has to be changed in the database
|
// it has to be changed in the database
|
||||||
case "m.room.history_visibility":
|
case "m.room.history_visibility":
|
||||||
txn.rawUpdate("UPDATE Rooms SET history_visibility=? WHERE id=?",
|
txn.rawUpdate("UPDATE Rooms SET history_visibility=? WHERE id=?",
|
||||||
[eventContent["content"]["history_visibility"], chat_id]);
|
[eventContent["content"]["history_visibility"], chat_id]);
|
||||||
break;
|
break;
|
||||||
// This event means, that the topic of a room has been changed, so
|
// This event means, that the topic of a room has been changed, so
|
||||||
// it has to be changed in the database
|
// it has to be changed in the database
|
||||||
case "m.room.redaction":
|
case "m.room.redaction":
|
||||||
txn.rawDelete(
|
txn.rawDelete(
|
||||||
"DELETE FROM Events WHERE id=?", [eventContent["redacts"]]);
|
"DELETE FROM Events WHERE id=?", [eventContent["redacts"]]);
|
||||||
break;
|
break;
|
||||||
// This event means, that the topic of a room has been changed, so
|
// This event means, that the topic of a room has been changed, so
|
||||||
// it has to be changed in the database
|
// it has to be changed in the database
|
||||||
case "m.room.guest_access":
|
case "m.room.guest_access":
|
||||||
txn.rawUpdate("UPDATE Rooms SET guest_access=? WHERE id=?",
|
txn.rawUpdate("UPDATE Rooms SET guest_access=? WHERE id=?",
|
||||||
[eventContent["content"]["guest_access"], chat_id]);
|
[eventContent["content"]["guest_access"], chat_id]);
|
||||||
break;
|
break;
|
||||||
// This event means, that the topic of a room has been changed, so
|
// This event means, that the topic of a room has been changed, so
|
||||||
// it has to be changed in the database
|
// it has to be changed in the database
|
||||||
case "m.room.join_rules":
|
case "m.room.join_rules":
|
||||||
txn.rawUpdate("UPDATE Rooms SET join_rules=? WHERE id=?",
|
txn.rawUpdate("UPDATE Rooms SET join_rules=? WHERE id=?",
|
||||||
[eventContent["content"]["join_rule"], chat_id]);
|
[eventContent["content"]["join_rule"], chat_id]);
|
||||||
break;
|
break;
|
||||||
// This event means, that the avatar of a room has been changed, so
|
// This event means, that the avatar of a room has been changed, so
|
||||||
// it has to be changed in the database
|
// it has to be changed in the database
|
||||||
case "m.room.avatar":
|
case "m.room.avatar":
|
||||||
txn.rawUpdate("UPDATE Rooms SET avatar_url=? WHERE id=?",
|
txn.rawUpdate("UPDATE Rooms SET avatar_url=? WHERE id=?",
|
||||||
[eventContent["content"]["url"], chat_id]);
|
[eventContent["content"]["url"], chat_id]);
|
||||||
break;
|
break;
|
||||||
// This event means, that the aliases of a room has been changed, so
|
// This event means, that the aliases of a room has been changed, so
|
||||||
// it has to be changed in the database
|
// it has to be changed in the database
|
||||||
case "m.fully_read":
|
case "m.fully_read":
|
||||||
txn.rawUpdate("UPDATE Rooms SET fully_read=? WHERE id=?",
|
txn.rawUpdate("UPDATE Rooms SET fully_read=? WHERE id=?",
|
||||||
[eventContent["content"]["event_id"], chat_id]);
|
[eventContent["content"]["event_id"], chat_id]);
|
||||||
break;
|
break;
|
||||||
// This event means, that someone joined the room, has left the room
|
// This event means, that someone joined the room, has left the room
|
||||||
// or has changed his nickname
|
// or has changed his nickname
|
||||||
case "m.room.member":
|
case "m.room.member":
|
||||||
String membership = eventContent["content"]["membership"];
|
String membership = eventContent["content"]["membership"];
|
||||||
String state_key = eventContent["state_key"];
|
String state_key = eventContent["state_key"];
|
||||||
|
@ -285,7 +297,7 @@ class Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update membership table
|
// Update membership table
|
||||||
txn.rawInsert("INSERT OR IGNORE INTO User VALUES(?,?,?,?,?,0)", [
|
txn.rawInsert("INSERT OR IGNORE INTO User VALUES(?,?,?,?,?,0)", [
|
||||||
chat_id,
|
chat_id,
|
||||||
state_key,
|
state_key,
|
||||||
insertDisplayname,
|
insertDisplayname,
|
||||||
|
@ -309,7 +321,7 @@ class Store {
|
||||||
queryArgs.add(chat_id);
|
queryArgs.add(chat_id);
|
||||||
txn.rawUpdate(queryStr, queryArgs);
|
txn.rawUpdate(queryStr, queryArgs);
|
||||||
break;
|
break;
|
||||||
// This event changes the permissions of the users and the power levels
|
// This event changes the permissions of the users and the power levels
|
||||||
case "m.room.power_levels":
|
case "m.room.power_levels":
|
||||||
String query = "UPDATE Rooms SET ";
|
String query = "UPDATE Rooms SET ";
|
||||||
if (eventContent["content"]["ban"] is num)
|
if (eventContent["content"]["ban"] is num)
|
||||||
|
@ -336,12 +348,12 @@ class Store {
|
||||||
query += ", power_event_avatar=" +
|
query += ", power_event_avatar=" +
|
||||||
eventContent["content"]["events"]["m.room.avatar"].toString();
|
eventContent["content"]["events"]["m.room.avatar"].toString();
|
||||||
if (eventContent["content"]["events"]["m.room.history_visibility"]
|
if (eventContent["content"]["events"]["m.room.history_visibility"]
|
||||||
is num)
|
is num)
|
||||||
query += ", power_event_history_visibility=" +
|
query += ", power_event_history_visibility=" +
|
||||||
eventContent["content"]["events"]["m.room.history_visibility"]
|
eventContent["content"]["events"]["m.room.history_visibility"]
|
||||||
.toString();
|
.toString();
|
||||||
if (eventContent["content"]["events"]["m.room.canonical_alias"]
|
if (eventContent["content"]["events"]["m.room.canonical_alias"]
|
||||||
is num)
|
is num)
|
||||||
query += ", power_event_canonical_alias=" +
|
query += ", power_event_canonical_alias=" +
|
||||||
eventContent["content"]["events"]["m.room.canonical_alias"]
|
eventContent["content"]["events"]["m.room.canonical_alias"]
|
||||||
.toString();
|
.toString();
|
||||||
|
@ -369,7 +381,7 @@ class Store {
|
||||||
txn.rawUpdate(
|
txn.rawUpdate(
|
||||||
"UPDATE User SET power_level=? WHERE matrix_id=? AND chat_id=?",
|
"UPDATE User SET power_level=? WHERE matrix_id=? AND chat_id=?",
|
||||||
[power_level, user, chat_id]);
|
[power_level, user, chat_id]);
|
||||||
txn.rawInsert(
|
txn.rawInsert(
|
||||||
"INSERT OR IGNORE INTO User VALUES(?, ?, '', '', ?, ?)",
|
"INSERT OR IGNORE INTO User VALUES(?, ?, '', '', ?, ?)",
|
||||||
[chat_id, user, "unknown", power_level]);
|
[chat_id, user, "unknown", power_level]);
|
||||||
});
|
});
|
||||||
|
@ -379,8 +391,7 @@ class Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a User object by a given Matrix ID and a Room.
|
/// Returns a User object by a given Matrix ID and a Room.
|
||||||
Future<User> getUser(
|
Future<User> getUser({String matrixID, Room room}) async {
|
||||||
{String matrixID, Room room}) async {
|
|
||||||
List<Map<String, dynamic>> res = await db.rawQuery(
|
List<Map<String, dynamic>> res = await db.rawQuery(
|
||||||
"SELECT * FROM User WHERE matrix_id=? AND chat_id=?",
|
"SELECT * FROM User WHERE matrix_id=? AND chat_id=?",
|
||||||
[matrixID, room.id]);
|
[matrixID, room.id]);
|
||||||
|
@ -394,7 +405,8 @@ class Store {
|
||||||
"SELECT * FROM User WHERE matrix_id!=? GROUP BY matrix_id ORDER BY displayname",
|
"SELECT * FROM User WHERE matrix_id!=? GROUP BY matrix_id ORDER BY displayname",
|
||||||
[client.userID]);
|
[client.userID]);
|
||||||
List<User> userList = [];
|
List<User> userList = [];
|
||||||
for (int i = 0; i < res.length; i++) userList.add(User.fromJson(res[i], null));
|
for (int i = 0; i < res.length; i++)
|
||||||
|
userList.add(User.fromJson(res[i], null));
|
||||||
return userList;
|
return userList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +429,7 @@ class Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of events for the given room and sets all participants.
|
/// Returns a list of events for the given room and sets all participants.
|
||||||
Future<List<Event>> getEventList(Room room) async{
|
Future<List<Event>> getEventList(Room room) async {
|
||||||
List<Map<String, dynamic>> eventRes = await db.rawQuery(
|
List<Map<String, dynamic>> eventRes = await db.rawQuery(
|
||||||
"SELECT * " +
|
"SELECT * " +
|
||||||
" FROM Events events, User user " +
|
" FROM Events events, User user " +
|
||||||
|
@ -435,18 +447,22 @@ class Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all rooms, the client is participating. Excludes left rooms.
|
/// Returns all rooms, the client is participating. Excludes left rooms.
|
||||||
Future<List<Room>> getRoomList({bool onlyLeft = false, bool onlyDirect = false, bool onlyGroups=false}) async {
|
Future<List<Room>> getRoomList(
|
||||||
|
{bool onlyLeft = false,
|
||||||
|
bool onlyDirect = false,
|
||||||
|
bool onlyGroups = false}) async {
|
||||||
if (onlyDirect && onlyGroups) return [];
|
if (onlyDirect && onlyGroups) return [];
|
||||||
List<Map<String, dynamic>> res = await db.rawQuery(
|
List<Map<String, dynamic>> res = await db.rawQuery("SELECT * " +
|
||||||
"SELECT * " +
|
" FROM Rooms rooms LEFT JOIN Events events " +
|
||||||
" FROM Rooms rooms LEFT JOIN Events events " +
|
" ON rooms.id=events.chat_id " +
|
||||||
" ON rooms.id=events.chat_id " +
|
" WHERE rooms.id!='' " +
|
||||||
" WHERE rooms.id!='' " +
|
" AND rooms.membership" +
|
||||||
" AND rooms.membership" + (onlyLeft ? "=" : "!=") +"'left' " +
|
(onlyLeft ? "=" : "!=") +
|
||||||
(onlyDirect ? " AND rooms.direct_chat_matrix_id!= '' " : "") +
|
"'left' " +
|
||||||
(onlyGroups ? " AND rooms.direct_chat_matrix_id= '' " : "") +
|
(onlyDirect ? " AND rooms.direct_chat_matrix_id!= '' " : "") +
|
||||||
" GROUP BY rooms.id " +
|
(onlyGroups ? " AND rooms.direct_chat_matrix_id= '' " : "") +
|
||||||
" ORDER BY origin_server_ts DESC ");
|
" GROUP BY rooms.id " +
|
||||||
|
" ORDER BY origin_server_ts DESC ");
|
||||||
List<Room> roomList = [];
|
List<Room> roomList = [];
|
||||||
for (num i = 0; i < res.length; i++) {
|
for (num i = 0; i < res.length; i++) {
|
||||||
try {
|
try {
|
||||||
|
@ -459,18 +475,16 @@ class Store {
|
||||||
return roomList;
|
return roomList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Returns a room without events and participants.
|
/// Returns a room without events and participants.
|
||||||
Future<Room> getRoomById(String id) async {
|
Future<Room> getRoomById(String id) async {
|
||||||
List<Map<String, dynamic>> res =
|
List<Map<String, dynamic>> res =
|
||||||
await db.rawQuery("SELECT * FROM Rooms WHERE id=?", [id]);
|
await db.rawQuery("SELECT * FROM Rooms WHERE id=?", [id]);
|
||||||
if (res.length != 1) return null;
|
if (res.length != 1) return null;
|
||||||
return Room.getRoomFromTableRow(res[0], client);
|
return Room.getRoomFromTableRow(res[0], client);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates and returns an avatar for a direct chat by a given [roomID].
|
/// Calculates and returns an avatar for a direct chat by a given [roomID].
|
||||||
Future<String> getAvatarFromSingleChat(
|
Future<String> getAvatarFromSingleChat(String roomID) async {
|
||||||
String roomID) async {
|
|
||||||
String avatarStr = "";
|
String avatarStr = "";
|
||||||
List<Map<String, dynamic>> res = await db.rawQuery(
|
List<Map<String, dynamic>> res = await db.rawQuery(
|
||||||
"SELECT avatar_url FROM User " +
|
"SELECT avatar_url FROM User " +
|
||||||
|
@ -485,8 +499,7 @@ class Store {
|
||||||
/// Calculates a chat name for a groupchat without a name. The chat name will
|
/// Calculates a chat name for a groupchat without a name. The chat name will
|
||||||
/// be the name of all users (excluding the user of this client) divided by
|
/// be the name of all users (excluding the user of this client) divided by
|
||||||
/// ','.
|
/// ','.
|
||||||
Future<String> getChatNameFromMemberNames(
|
Future<String> getChatNameFromMemberNames(String roomID) async {
|
||||||
String roomID) async {
|
|
||||||
String displayname = 'Empty chat';
|
String displayname = 'Empty chat';
|
||||||
List<Map<String, dynamic>> rs = await db.rawQuery(
|
List<Map<String, dynamic>> rs = await db.rawQuery(
|
||||||
"SELECT User.displayname, User.matrix_id, User.membership FROM User " +
|
"SELECT User.displayname, User.matrix_id, User.membership FROM User " +
|
||||||
|
@ -509,6 +522,15 @@ class Store {
|
||||||
return displayname;
|
return displayname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the (first) room ID from the store which is a private chat with
|
||||||
|
/// the user [userID]. Returns null if there is none.
|
||||||
|
Future<String> getDirectChatRoomID(String userID) async {
|
||||||
|
List<Map<String, dynamic>> res = await db.rawQuery(
|
||||||
|
"SELECT id FROM Rooms WHERE direct_chat_matrix_id=?", [userID]);
|
||||||
|
if (res.length != 1) return null;
|
||||||
|
return res[0]["id"];
|
||||||
|
}
|
||||||
|
|
||||||
/// The database sheme for the Client class.
|
/// The database sheme for the Client class.
|
||||||
static final String ClientsScheme = 'CREATE TABLE IF NOT EXISTS Clients(' +
|
static final String ClientsScheme = 'CREATE TABLE IF NOT EXISTS Clients(' +
|
||||||
'client TEXT PRIMARY KEY, ' +
|
'client TEXT PRIMARY KEY, ' +
|
||||||
|
@ -584,4 +606,4 @@ class Store {
|
||||||
'membership TEXT, ' + // The status of the membership. Must be one of [join, invite, ban, leave]
|
'membership TEXT, ' + // The status of the membership. Must be one of [join, invite, ban, leave]
|
||||||
'power_level INTEGER, ' + // The power level of this user. Must be in [0,..,100]
|
'power_level INTEGER, ' + // The power level of this user. Must be in [0,..,100]
|
||||||
'UNIQUE(chat_id, matrix_id))';
|
'UNIQUE(chat_id, matrix_id))';
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,4 +104,21 @@ class User {
|
||||||
dynamic res = await room.unban(id);
|
dynamic res = await room.unban(id);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an existing direct chat with this user or creates a new one.
|
||||||
|
Future<String> startDirectChat() async {
|
||||||
|
// Try to find an existing direct chat
|
||||||
|
String roomID = await room.client?.store.getDirectChatRoomID(id);
|
||||||
|
if (roomID != null) return roomID;
|
||||||
|
|
||||||
|
// Start a new direct chat
|
||||||
|
Map<String,dynamic> resp = await room.client.connection.jsonRequest(type: "POST", action: "/client/r0/createRoom", data: {
|
||||||
|
"invite": [ id ],
|
||||||
|
"is_direct": true,
|
||||||
|
"preset": "trusted_private_chat"
|
||||||
|
});
|
||||||
|
|
||||||
|
return resp["room_id"];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue