Refactor Room class
This commit is contained in:
parent
ec72849a90
commit
efa2ed5379
|
@ -30,131 +30,220 @@ import './User.dart';
|
||||||
|
|
||||||
/// Represents a Matrix room.
|
/// Represents a Matrix room.
|
||||||
class Room {
|
class Room {
|
||||||
final String roomID;
|
/// The full qualified Matrix ID for the room in the format '!localid:server.abc'.
|
||||||
|
final String id;
|
||||||
|
|
||||||
|
/// Membership status of the user for this room.
|
||||||
|
String membership;
|
||||||
|
|
||||||
|
/// The name of the room if set by a participant.
|
||||||
String name;
|
String name;
|
||||||
String lastMessage;
|
|
||||||
MxContent avatar;
|
/// The topic of the room if set by a participant.
|
||||||
ChatTime timeCreated;
|
|
||||||
int notificationCount;
|
|
||||||
int highlightCount;
|
|
||||||
String topic;
|
String topic;
|
||||||
User user;
|
|
||||||
final Client matrix;
|
/// The avatar of the room if set by a participant.
|
||||||
|
MxContent avatar;
|
||||||
|
|
||||||
|
/// The count of unread notifications.
|
||||||
|
int notificationCount;
|
||||||
|
|
||||||
|
/// The count of highlighted notifications.
|
||||||
|
int highlightCount;
|
||||||
|
|
||||||
|
String prev_batch;
|
||||||
|
|
||||||
|
String draft;
|
||||||
|
|
||||||
|
/// Time when the user has last read the chat.
|
||||||
|
ChatTime unread;
|
||||||
|
|
||||||
|
/// ID of the fully read marker event.
|
||||||
|
String fullyRead;
|
||||||
|
|
||||||
|
/// The address in the format: #roomname:homeserver.org.
|
||||||
|
String canonicalAlias;
|
||||||
|
|
||||||
|
/// If this room is a direct chat, this is the matrix ID of the user
|
||||||
|
String directChatMatrixID;
|
||||||
|
|
||||||
|
/// Must be one of [all, mention]
|
||||||
|
String notificationSettings;
|
||||||
|
|
||||||
|
/// Are guest users allowed?
|
||||||
|
String guestAccess;
|
||||||
|
|
||||||
|
/// Who can see the history of this room?
|
||||||
|
String historyVisibility;
|
||||||
|
|
||||||
|
/// Who is allowed to join this room?
|
||||||
|
String joinRules;
|
||||||
|
|
||||||
|
/// The needed power levels for all actions.
|
||||||
|
Map<String,int> powerLevels = {};
|
||||||
|
|
||||||
|
/// The list of events in this room. If the room is created by the
|
||||||
|
/// [getRoomList()] of the [Store], this will contain only the last event.
|
||||||
List<Event> events = [];
|
List<Event> events = [];
|
||||||
|
|
||||||
|
/// The list of participants in this room. If the room is created by the
|
||||||
|
/// [getRoomList()] of the [Store], this will contain only the sender of the
|
||||||
|
/// last event.
|
||||||
|
List<User> participants = [];
|
||||||
|
|
||||||
|
/// Your current client instance.
|
||||||
|
final Client client;
|
||||||
|
|
||||||
|
@Deprecated("Rooms.roomID is deprecated! Use Rooms.id instead!")
|
||||||
|
String get roomID =>this.id;
|
||||||
|
|
||||||
|
@Deprecated("Rooms.matrix is deprecated! Use Rooms.client instead!")
|
||||||
|
Client get matrix => this.client;
|
||||||
|
|
||||||
|
@Deprecated("Rooms.status is deprecated! Use Rooms.membership instead!")
|
||||||
|
String get status => this.membership;
|
||||||
|
|
||||||
Room({
|
Room({
|
||||||
this.roomID,
|
this.id,
|
||||||
|
this.membership,
|
||||||
this.name,
|
this.name,
|
||||||
this.lastMessage,
|
this.topic,
|
||||||
this.avatar,
|
this.avatar,
|
||||||
this.timeCreated,
|
|
||||||
this.notificationCount,
|
this.notificationCount,
|
||||||
this.highlightCount,
|
this.highlightCount,
|
||||||
this.topic,
|
this.prev_batch,
|
||||||
this.user,
|
this.draft,
|
||||||
this.matrix,
|
this.unread,
|
||||||
|
this.fullyRead,
|
||||||
|
this.canonicalAlias,
|
||||||
|
this.directChatMatrixID,
|
||||||
|
this.notificationSettings,
|
||||||
|
this.guestAccess,
|
||||||
|
this.historyVisibility,
|
||||||
|
this.joinRules,
|
||||||
|
this.powerLevels,
|
||||||
this.events,
|
this.events,
|
||||||
|
this.participants,
|
||||||
|
this.client,
|
||||||
});
|
});
|
||||||
|
|
||||||
String get status {
|
/// The last message sent to this room.
|
||||||
if (this.user != null) {
|
String get lastMessage {
|
||||||
return this.user.status;
|
if (events.length > 0)
|
||||||
}
|
return events[0].getBody();
|
||||||
return this.topic;
|
else return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// When the last message received.
|
||||||
|
ChatTime get timeCreated {
|
||||||
|
if (events.length > 0)
|
||||||
|
return events[0].time;
|
||||||
|
else return ChatTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call the Matrix API to change the name of this room.
|
||||||
Future<dynamic> setName(String newName) async{
|
Future<dynamic> setName(String newName) async{
|
||||||
dynamic res = await matrix.connection.jsonRequest(
|
dynamic res = await client.connection.jsonRequest(
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
action:
|
action:
|
||||||
"/client/r0/rooms/${roomID}/send/m.room.name/${new DateTime.now()}",
|
"/client/r0/rooms/${id}/send/m.room.name/${new DateTime.now()}",
|
||||||
data: {"name": newName});
|
data: {"name": newName});
|
||||||
if (res is ErrorResponse) matrix.connection.onError.add(res);
|
if (res is ErrorResponse) client.connection.onError.add(res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call the Matrix API to change the topic of this room.
|
||||||
Future<dynamic> setDescription(String newName) async{
|
Future<dynamic> setDescription(String newName) async{
|
||||||
dynamic res = await matrix.connection.jsonRequest(
|
dynamic res = await client.connection.jsonRequest(
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
action:
|
action:
|
||||||
"/client/r0/rooms/${roomID}/send/m.room.topic/${new DateTime.now()}",
|
"/client/r0/rooms/${id}/send/m.room.topic/${new DateTime.now()}",
|
||||||
data: {"topic": newName});
|
data: {"topic": newName});
|
||||||
if (res is ErrorResponse) matrix.connection.onError.add(res);
|
if (res is ErrorResponse) client.connection.onError.add(res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Use the client.connection streams instead!")
|
||||||
Stream<List<Event>> get eventsStream {
|
Stream<List<Event>> get eventsStream {
|
||||||
return Stream<List<Event>>.fromIterable(Iterable<List<Event>>.generate(
|
return Stream<List<Event>>.fromIterable(Iterable<List<Event>>.generate(
|
||||||
this.events.length, (int index) => this.events)).asBroadcastStream();
|
this.events.length, (int index) => this.events)).asBroadcastStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call the Matrix API to send a simple text message.
|
||||||
Future<void> sendText(String message) async {
|
Future<void> sendText(String message) async {
|
||||||
dynamic res = await matrix.connection.jsonRequest(
|
dynamic res = await client.connection.jsonRequest(
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
action:
|
action:
|
||||||
"/client/r0/rooms/${roomID}/send/m.room.message/${new DateTime.now()}",
|
"/client/r0/rooms/${id}/send/m.room.message/${new DateTime.now()}",
|
||||||
data: {"msgtype": "m.text", "body": message});
|
data: {"msgtype": "m.text", "body": message});
|
||||||
if (res["errcode"] == "M_LIMIT_EXCEEDED") matrix.connection.onError.add(res["error"]);
|
if (res["errcode"] == "M_LIMIT_EXCEEDED") client.connection.onError.add(res["error"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call the Matrix API to leave this room.
|
||||||
Future<dynamic> leave() async {
|
Future<dynamic> leave() async {
|
||||||
dynamic res = await matrix.connection.jsonRequest(
|
dynamic res = await client.connection.jsonRequest(
|
||||||
type: "POST",
|
type: "POST",
|
||||||
action:
|
action:
|
||||||
"/client/r0/rooms/${roomID}/leave");
|
"/client/r0/rooms/${id}/leave");
|
||||||
if (res is ErrorResponse) matrix.connection.onError.add(res);
|
if (res is ErrorResponse) client.connection.onError.add(res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call the Matrix API to forget this room if you already left it.
|
||||||
Future<dynamic> forget() async {
|
Future<dynamic> forget() async {
|
||||||
dynamic res = await matrix.connection.jsonRequest(
|
dynamic res = await client.connection.jsonRequest(
|
||||||
type: "POST",
|
type: "POST",
|
||||||
action:
|
action:
|
||||||
"/client/r0/rooms/${roomID}/forget");
|
"/client/r0/rooms/${id}/forget");
|
||||||
if (res is ErrorResponse) matrix.connection.onError.add(res);
|
if (res is ErrorResponse) client.connection.onError.add(res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call the Matrix API to kick a user from this room.
|
||||||
Future<dynamic> kick(String userID) async {
|
Future<dynamic> kick(String userID) async {
|
||||||
dynamic res = await matrix.connection.jsonRequest(
|
dynamic res = await client.connection.jsonRequest(
|
||||||
type: "POST",
|
type: "POST",
|
||||||
action:
|
action:
|
||||||
"/client/r0/rooms/${roomID}/kick",
|
"/client/r0/rooms/${id}/kick",
|
||||||
data: {"user_id": userID});
|
data: {"user_id": userID});
|
||||||
if (res is ErrorResponse) matrix.connection.onError.add(res);
|
if (res is ErrorResponse) client.connection.onError.add(res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call the Matrix API to ban a user from this room.
|
||||||
Future<dynamic> ban(String userID) async {
|
Future<dynamic> ban(String userID) async {
|
||||||
dynamic res = await matrix.connection.jsonRequest(
|
dynamic res = await client.connection.jsonRequest(
|
||||||
type: "POST",
|
type: "POST",
|
||||||
action:
|
action:
|
||||||
"/client/r0/rooms/${roomID}/ban",
|
"/client/r0/rooms/${id}/ban",
|
||||||
data: {"user_id": userID});
|
data: {"user_id": userID});
|
||||||
if (res is ErrorResponse) matrix.connection.onError.add(res);
|
if (res is ErrorResponse) client.connection.onError.add(res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call the Matrix API to unban a banned user from this room.
|
||||||
Future<dynamic> unban(String userID) async {
|
Future<dynamic> unban(String userID) async {
|
||||||
dynamic res = await matrix.connection.jsonRequest(
|
dynamic res = await client.connection.jsonRequest(
|
||||||
type: "POST",
|
type: "POST",
|
||||||
action:
|
action:
|
||||||
"/client/r0/rooms/${roomID}/unban",
|
"/client/r0/rooms/${id}/unban",
|
||||||
data: {"user_id": userID});
|
data: {"user_id": userID});
|
||||||
if (res is ErrorResponse) matrix.connection.onError.add(res);
|
if (res is ErrorResponse) client.connection.onError.add(res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call the Matrix API to invite a user to this room.
|
||||||
Future<dynamic> invite(String userID) async {
|
Future<dynamic> invite(String userID) async {
|
||||||
dynamic res = await matrix.connection.jsonRequest(
|
dynamic res = await client.connection.jsonRequest(
|
||||||
type: "POST",
|
type: "POST",
|
||||||
action:
|
action:
|
||||||
"/client/r0/rooms/${roomID}/invite",
|
"/client/r0/rooms/${id}/invite",
|
||||||
data: {"user_id": userID});
|
data: {"user_id": userID});
|
||||||
if (res is ErrorResponse) matrix.connection.onError.add(res);
|
if (res is ErrorResponse) client.connection.onError.add(res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a Room from a json String which comes normally from the store.
|
||||||
static Future<Room> getRoomFromTableRow(
|
static Future<Room> getRoomFromTableRow(
|
||||||
Map<String, dynamic> row, Client matrix) async {
|
Map<String, dynamic> row, Client matrix) async {
|
||||||
String name = row["topic"];
|
String name = row["topic"];
|
||||||
|
@ -170,37 +259,60 @@ class Room {
|
||||||
avatarMxcUrl = await matrix.store.getAvatarFromSingleChat(row["id"]);
|
avatarMxcUrl = await matrix.store.getAvatarFromSingleChat(row["id"]);
|
||||||
|
|
||||||
return Room(
|
return Room(
|
||||||
roomID: row["id"],
|
id: row["id"],
|
||||||
name: name,
|
name: name,
|
||||||
lastMessage: content_body,
|
|
||||||
avatar: MxContent(avatarMxcUrl),
|
avatar: MxContent(avatarMxcUrl),
|
||||||
timeCreated: ChatTime(row["origin_server_ts"]),
|
|
||||||
notificationCount: row["notification_count"],
|
notificationCount: row["notification_count"],
|
||||||
highlightCount: row["highlight_count"],
|
highlightCount: row["highlight_count"],
|
||||||
topic: "",
|
topic: "",
|
||||||
matrix: matrix,
|
client: matrix,
|
||||||
events: [],
|
events: [],
|
||||||
|
participants: [],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Use client.store.getRoomById(String id) instead!")
|
||||||
static Future<Room> getRoomById(String id, Client matrix) async {
|
static Future<Room> getRoomById(String id, Client matrix) async {
|
||||||
List<Map<String, dynamic>> res =
|
Room room = await matrix.store.getRoomById(id);
|
||||||
await matrix.store.db.rawQuery("SELECT * FROM Rooms WHERE id=?", [id]);
|
|
||||||
if (res.length != 1) return null;
|
|
||||||
return getRoomFromTableRow(res[0], matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<Room> loadRoomEvents(String id, Client matrix) async {
|
|
||||||
Room room = await Room.getRoomById(id, matrix);
|
|
||||||
room.events = await Event.getEventList(matrix, id);
|
|
||||||
return room;
|
return room;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load a room from the store including all room events.
|
||||||
|
static Future<Room> loadRoomEvents(String id, Client matrix) async {
|
||||||
|
Room room = await matrix.store.getRoomById(id);
|
||||||
|
await room.loadEvents();
|
||||||
|
return room;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load all events for a given room from the store. This includes all
|
||||||
|
/// senders of those events, who will be added to the participants list.
|
||||||
|
Future<List<Event>> loadEvents() async {
|
||||||
|
this.events = await client.store.getEventList(id);
|
||||||
|
|
||||||
|
Map<String,bool> participantMap = {};
|
||||||
|
for (num i = 0; i < events.length; i++) {
|
||||||
|
if (!participantMap.containsKey(events[i].sender.mxid)) {
|
||||||
|
participants.add(events[i].sender);
|
||||||
|
participantMap[events[i].sender.mxid] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.events;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load all participants for a given room from the store.
|
||||||
|
Future<List<User>> loadParticipants() async {
|
||||||
|
this.participants = await client.store.loadParticipants(id);
|
||||||
|
return this.participants;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Request the full list of participants from the server. The local list
|
||||||
|
/// from the store is not complete if the client uses lazy loading.
|
||||||
Future<List<User>> requestParticipants(Client matrix) async {
|
Future<List<User>> requestParticipants(Client matrix) async {
|
||||||
List<User> participants = [];
|
List<User> participants = [];
|
||||||
|
|
||||||
dynamic res = await matrix.connection.jsonRequest(
|
dynamic res = await matrix.connection.jsonRequest(
|
||||||
type: "GET", action: "/client/r0/rooms/${roomID}/members");
|
type: "GET", action: "/client/r0/rooms/${id}/members");
|
||||||
if (res is ErrorResponse || !(res["chunk"] is List<dynamic>))
|
if (res is ErrorResponse || !(res["chunk"] is List<dynamic>))
|
||||||
return participants;
|
return participants;
|
||||||
|
|
||||||
|
@ -214,6 +326,8 @@ class Room {
|
||||||
if (newUser.status != "leave") participants.add(newUser);
|
if (newUser.status != "leave") participants.add(newUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
return participants;
|
this.participants = participants;
|
||||||
|
|
||||||
|
return this.participants;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import 'sync/RoomUpdate.dart';
|
||||||
import 'Client.dart';
|
import 'Client.dart';
|
||||||
import 'User.dart';
|
import 'User.dart';
|
||||||
import 'Room.dart';
|
import 'Room.dart';
|
||||||
|
import 'Event.dart';
|
||||||
import 'Connection.dart';
|
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
|
||||||
|
@ -414,6 +415,24 @@ class Store {
|
||||||
return participants;
|
return participants;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a list of events for the given room and sets all participants.
|
||||||
|
Future<List<Event>> getEventList(String roomID) async{
|
||||||
|
List<Map<String, dynamic>> eventRes = await db.rawQuery(
|
||||||
|
"SELECT * " +
|
||||||
|
" FROM Events events, Participants participants " +
|
||||||
|
" WHERE events.chat_id=?" +
|
||||||
|
" AND events.sender=participants.matrix_id " +
|
||||||
|
" GROUP BY events.id " +
|
||||||
|
" ORDER BY origin_server_ts DESC",
|
||||||
|
[roomID]);
|
||||||
|
|
||||||
|
List<Event> eventList = [];
|
||||||
|
|
||||||
|
for (num i = 0; i < eventRes.length; i++)
|
||||||
|
eventList.add(Event.fromJson(eventRes[i]));
|
||||||
|
return eventList;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns all rooms, the client is participating. Excludes left rooms.
|
/// Returns all rooms, the client is participating. Excludes left rooms.
|
||||||
Future<List<Room>> getRoomList() async {
|
Future<List<Room>> getRoomList() async {
|
||||||
List<Map<String, dynamic>> res = await db.rawQuery(
|
List<Map<String, dynamic>> res = await db.rawQuery(
|
||||||
|
@ -436,6 +455,15 @@ class Store {
|
||||||
return roomList;
|
return roomList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns a room without events and participants.
|
||||||
|
Future<Room> getRoomById(String id) async {
|
||||||
|
List<Map<String, dynamic>> res =
|
||||||
|
await db.rawQuery("SELECT * FROM Rooms WHERE id=?", [id]);
|
||||||
|
if (res.length != 1) return null;
|
||||||
|
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 {
|
||||||
|
|
Loading…
Reference in a new issue