Merge branch 'lists-enhance-new-list-types' into 'master'
[Lists] New list types Closes #10 See merge request famedly/famedlysdk!12
This commit is contained in:
commit
7c94bce7bb
|
@ -25,6 +25,8 @@ import 'dart:async';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
import 'responses/ErrorResponse.dart';
|
import 'responses/ErrorResponse.dart';
|
||||||
import 'Connection.dart';
|
import 'Connection.dart';
|
||||||
|
import 'RoomList.dart';
|
||||||
|
import 'Room.dart';
|
||||||
import 'Store.dart';
|
import 'Store.dart';
|
||||||
import 'User.dart';
|
import 'User.dart';
|
||||||
import 'responses/PushrulesResponse.dart';
|
import 'responses/PushrulesResponse.dart';
|
||||||
|
@ -189,6 +191,28 @@ class Client {
|
||||||
await connection.clear();
|
await connection.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Loads the Rooms from the [store] and creates a new [RoomList] object.
|
||||||
|
Future<RoomList> getRoomList(
|
||||||
|
{bool onlyLeft = false,
|
||||||
|
bool onlyDirect = false,
|
||||||
|
bool onlyGroups = false,
|
||||||
|
onUpdateCallback onUpdate,
|
||||||
|
onInsertCallback,
|
||||||
|
onInsert,
|
||||||
|
onRemoveCallback onRemove}) async {
|
||||||
|
List<Room> rooms = await store.getRoomList(
|
||||||
|
onlyLeft: onlyLeft, onlyGroups: onlyGroups, onlyDirect: onlyDirect);
|
||||||
|
return RoomList(
|
||||||
|
client: this,
|
||||||
|
onlyLeft: onlyLeft,
|
||||||
|
onlyDirect: onlyDirect,
|
||||||
|
onlyGroups: onlyGroups,
|
||||||
|
onUpdate: onUpdate,
|
||||||
|
onInsert: onInsert,
|
||||||
|
onRemove: onRemove,
|
||||||
|
rooms: rooms);
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new group chat and invites the given Users and returns the new
|
/// Creates a new group chat and invites the given Users and returns the new
|
||||||
/// created room ID.
|
/// created room ID.
|
||||||
Future<String> createGroup(List<User> users) async {
|
Future<String> createGroup(List<User> users) async {
|
||||||
|
|
|
@ -126,13 +126,16 @@ class Event {
|
||||||
|
|
||||||
/// Generate a new Event object from a json string, mostly a table row.
|
/// Generate a new Event object from a json string, mostly a table row.
|
||||||
static Event fromJson(Map<String, dynamic> jsonObj, Room room) {
|
static Event fromJson(Map<String, dynamic> jsonObj, Room room) {
|
||||||
Map<String, dynamic> content;
|
Map<String, dynamic> content = jsonObj["content"];
|
||||||
try {
|
|
||||||
content = json.decode(jsonObj["content_json"]);
|
if (content == null)
|
||||||
} catch (e) {
|
try {
|
||||||
print("jsonObj decode of event content failed: ${e.toString()}");
|
content = json.decode(jsonObj["content_json"]);
|
||||||
content = {};
|
} catch (e) {
|
||||||
}
|
print("jsonObj decode of event content failed: ${e.toString()}");
|
||||||
|
content = {};
|
||||||
|
}
|
||||||
|
|
||||||
return Event(
|
return Event(
|
||||||
jsonObj["id"],
|
jsonObj["id"],
|
||||||
User.fromJson(jsonObj, room),
|
User.fromJson(jsonObj, room),
|
||||||
|
|
|
@ -28,6 +28,7 @@ import 'package:famedlysdk/src/responses/ErrorResponse.dart';
|
||||||
import 'package:famedlysdk/src/sync/EventUpdate.dart';
|
import 'package:famedlysdk/src/sync/EventUpdate.dart';
|
||||||
import 'package:famedlysdk/src/Event.dart';
|
import 'package:famedlysdk/src/Event.dart';
|
||||||
import './User.dart';
|
import './User.dart';
|
||||||
|
import 'Timeline.dart';
|
||||||
|
|
||||||
/// Represents a Matrix room.
|
/// Represents a Matrix room.
|
||||||
class Room {
|
class Room {
|
||||||
|
@ -83,14 +84,7 @@ class Room {
|
||||||
/// The needed power levels for all actions.
|
/// The needed power levels for all actions.
|
||||||
Map<String, int> powerLevels = {};
|
Map<String, int> powerLevels = {};
|
||||||
|
|
||||||
/// The list of events in this room. If the room is created by the
|
Event lastEvent;
|
||||||
/// [getRoomList()] of the [Store], this will contain only the last event.
|
|
||||||
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.
|
/// Your current client instance.
|
||||||
final Client client;
|
final Client client;
|
||||||
|
@ -123,23 +117,22 @@ class Room {
|
||||||
this.historyVisibility,
|
this.historyVisibility,
|
||||||
this.joinRules,
|
this.joinRules,
|
||||||
this.powerLevels,
|
this.powerLevels,
|
||||||
this.events,
|
this.lastEvent,
|
||||||
this.participants,
|
|
||||||
this.client,
|
this.client,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The last message sent to this room.
|
/// The last message sent to this room.
|
||||||
String get lastMessage {
|
String get lastMessage {
|
||||||
if (events != null && events.length > 0)
|
if (lastEvent != null)
|
||||||
return events[0].getBody();
|
return lastEvent.getBody();
|
||||||
else
|
else
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When the last message received.
|
/// When the last message received.
|
||||||
ChatTime get timeCreated {
|
ChatTime get timeCreated {
|
||||||
if (events?.length > 0)
|
if (lastEvent != null)
|
||||||
return events[0].time;
|
return lastEvent.time;
|
||||||
else
|
else
|
||||||
return ChatTime.now();
|
return ChatTime.now();
|
||||||
}
|
}
|
||||||
|
@ -165,12 +158,6 @@ class Room {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Use the client.connection streams instead!")
|
|
||||||
Stream<List<Event>> get eventsStream {
|
|
||||||
return Stream<List<Event>>.fromIterable(Iterable<List<Event>>.generate(
|
|
||||||
this.events.length, (int index) => this.events)).asBroadcastStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call the Matrix API to send a simple text message.
|
/// Call the Matrix API to send a simple text message.
|
||||||
Future<dynamic> sendText(String message, {String txid = null}) async {
|
Future<dynamic> sendText(String message, {String txid = null}) async {
|
||||||
if (txid == null) txid = "txid${DateTime.now().millisecondsSinceEpoch}";
|
if (txid == null) txid = "txid${DateTime.now().millisecondsSinceEpoch}";
|
||||||
|
@ -394,9 +381,8 @@ class Room {
|
||||||
"power_event_name": row["power_event_name"],
|
"power_event_name": row["power_event_name"],
|
||||||
"power_event_power_levels": row["power_event_power_levels"],
|
"power_event_power_levels": row["power_event_power_levels"],
|
||||||
},
|
},
|
||||||
|
lastEvent: Event.fromJson(row, null),
|
||||||
client: matrix,
|
client: matrix,
|
||||||
events: [Event.fromJson(row, null)],
|
|
||||||
participants: [],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,26 +399,25 @@ class Room {
|
||||||
return room;
|
return room;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Timeline> getTimeline({onUpdate, onInsert}) async {
|
||||||
|
List<Event> events = await loadEvents();
|
||||||
|
return Timeline(
|
||||||
|
room: this,
|
||||||
|
events: events,
|
||||||
|
onUpdate: onUpdate,
|
||||||
|
onInsert: onInsert,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Load all events for a given room from the store. This includes all
|
/// 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.
|
/// senders of those events, who will be added to the participants list.
|
||||||
Future<List<Event>> loadEvents() async {
|
Future<List<Event>> loadEvents() async {
|
||||||
this.events = await client.store.getEventList(this);
|
return await client.store.getEventList(this);
|
||||||
|
|
||||||
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.
|
/// Load all participants for a given room from the store.
|
||||||
Future<List<User>> loadParticipants() async {
|
Future<List<User>> loadParticipants() async {
|
||||||
this.participants = await client.store.loadParticipants(this);
|
return await client.store.loadParticipants(this);
|
||||||
return this.participants;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request the full list of participants from the server. The local list
|
/// Request the full list of participants from the server. The local list
|
||||||
|
@ -454,8 +439,6 @@ class Room {
|
||||||
if (newUser.membership != "leave") participants.add(newUser);
|
if (newUser.membership != "leave") participants.add(newUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.participants = participants;
|
return participants;
|
||||||
|
|
||||||
return this.participants;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
165
lib/src/RoomList.dart
Normal file
165
lib/src/RoomList.dart
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Zender & Kurtz GbR.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Christian Pauly <krille@famedly.com>
|
||||||
|
* Marcel Radzio <mtrnord@famedly.com>
|
||||||
|
*
|
||||||
|
* This file is part of famedlysdk.
|
||||||
|
*
|
||||||
|
* famedlysdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* famedlysdk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with famedlysdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
/// Represents a list of rooms for this client, which will automatically update
|
||||||
|
/// itself and call the [onUpdate], [onInsert] and [onDelete] callbacks. To get
|
||||||
|
/// the initial room list, use the store or create a RoomList instance by using
|
||||||
|
/// [client.getRoomList].
|
||||||
|
class RoomList {
|
||||||
|
final Client client;
|
||||||
|
List<Room> rooms = [];
|
||||||
|
|
||||||
|
final bool onlyLeft;
|
||||||
|
final bool onlyDirect;
|
||||||
|
final bool onlyGroups;
|
||||||
|
|
||||||
|
/// Will be called, when the room list has changed. Can be used e.g. to update
|
||||||
|
/// the state of a StatefulWidget.
|
||||||
|
final onUpdateCallback onUpdate;
|
||||||
|
|
||||||
|
/// Will be called, when a new room is added to the list.
|
||||||
|
final onInsertCallback onInsert;
|
||||||
|
|
||||||
|
/// Will be called, when a room has been removed from the list.
|
||||||
|
final onRemoveCallback onRemove;
|
||||||
|
|
||||||
|
StreamSubscription<EventUpdate> eventSub;
|
||||||
|
StreamSubscription<RoomUpdate> roomSub;
|
||||||
|
|
||||||
|
RoomList(
|
||||||
|
{this.client,
|
||||||
|
this.rooms,
|
||||||
|
this.onUpdate,
|
||||||
|
this.onInsert,
|
||||||
|
this.onRemove,
|
||||||
|
this.onlyLeft = false,
|
||||||
|
this.onlyDirect = false,
|
||||||
|
this.onlyGroups = false}) {
|
||||||
|
eventSub ??= client.connection.onEvent.stream.listen(_handleEventUpdate);
|
||||||
|
roomSub ??= client.connection.onRoomUpdate.stream.listen(_handleRoomUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleRoomUpdate(RoomUpdate chatUpdate) async {
|
||||||
|
// Update the chat list item.
|
||||||
|
// Search the room in the rooms
|
||||||
|
num j = 0;
|
||||||
|
for (j = 0; j < rooms.length; j++) {
|
||||||
|
if (rooms[j].id == chatUpdate.id) break;
|
||||||
|
}
|
||||||
|
final bool found = (j < rooms.length - 1 && rooms[j].id == chatUpdate.id);
|
||||||
|
|
||||||
|
// Does the chat already exist in the list rooms?
|
||||||
|
if (!found && chatUpdate.membership != "leave") {
|
||||||
|
num position = chatUpdate.membership == "invite" ? 0 : j;
|
||||||
|
ChatTime timestamp =
|
||||||
|
chatUpdate.membership == "invite" ? ChatTime.now() : ChatTime(0);
|
||||||
|
// Add the new chat to the list
|
||||||
|
Room newRoom = Room(
|
||||||
|
id: chatUpdate.id,
|
||||||
|
name: "",
|
||||||
|
membership: chatUpdate.membership,
|
||||||
|
prev_batch: chatUpdate.prev_batch,
|
||||||
|
highlightCount: chatUpdate.highlight_count,
|
||||||
|
notificationCount: chatUpdate.notification_count);
|
||||||
|
rooms.insert(position, newRoom);
|
||||||
|
onInsert(position);
|
||||||
|
}
|
||||||
|
// If the membership is "leave" then remove the item and stop here
|
||||||
|
else if (found && chatUpdate.membership == "leave") {
|
||||||
|
final Room removed = rooms.removeAt(j);
|
||||||
|
onRemove(j);
|
||||||
|
}
|
||||||
|
// Update notification and highlight count
|
||||||
|
else if (found &&
|
||||||
|
chatUpdate.membership != "leave" &&
|
||||||
|
(rooms[j].notificationCount != chatUpdate.notification_count ||
|
||||||
|
rooms[j].highlightCount != chatUpdate.highlight_count)) {
|
||||||
|
rooms[j].notificationCount = chatUpdate.notification_count;
|
||||||
|
rooms[j].highlightCount = chatUpdate.highlight_count;
|
||||||
|
}
|
||||||
|
sortAndUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleEventUpdate(EventUpdate eventUpdate) {
|
||||||
|
// Is the event necessary for the chat list? If not, then return
|
||||||
|
if (!(eventUpdate.type == "timeline" ||
|
||||||
|
eventUpdate.eventType == "m.room.avatar" ||
|
||||||
|
eventUpdate.eventType == "m.room.name")) return;
|
||||||
|
|
||||||
|
// Search the room in the rooms
|
||||||
|
num j = 0;
|
||||||
|
for (j = 0; j < rooms.length; j++) {
|
||||||
|
if (rooms[j].id == eventUpdate.roomID) break;
|
||||||
|
}
|
||||||
|
final bool found = (j < rooms.length && rooms[j].id == eventUpdate.roomID);
|
||||||
|
if (!found) return;
|
||||||
|
|
||||||
|
// Is this an old timeline event? Then stop here...
|
||||||
|
/*if (eventUpdate.type == "timeline" &&
|
||||||
|
ChatTime(eventUpdate.content["origin_server_ts"]) <=
|
||||||
|
rooms[j].timeCreated) return;*/
|
||||||
|
|
||||||
|
if (eventUpdate.type == "timeline") {
|
||||||
|
// Update the last message preview
|
||||||
|
String body = eventUpdate.content["content"]["body"] ?? "";
|
||||||
|
rooms[j].lastEvent = Event(
|
||||||
|
eventUpdate.content["id"],
|
||||||
|
User(eventUpdate.content["sender"]),
|
||||||
|
ChatTime(eventUpdate.content["origin_server_ts"]),
|
||||||
|
room: rooms[j],
|
||||||
|
content: eventUpdate.content["content"],
|
||||||
|
environment: "timeline",
|
||||||
|
status: 2,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (eventUpdate.eventType == "m.room.name") {
|
||||||
|
// Update the room name
|
||||||
|
rooms[j].name = eventUpdate.content["content"]["name"];
|
||||||
|
} else if (eventUpdate.eventType == "m.room.avatar") {
|
||||||
|
// Update the room avatar
|
||||||
|
rooms[j].avatar = MxContent(eventUpdate.content["content"]["url"]);
|
||||||
|
}
|
||||||
|
sortAndUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
sortAndUpdate() {
|
||||||
|
rooms?.sort((a, b) =>
|
||||||
|
b.timeCreated.toTimeStamp().compareTo(a.timeCreated.toTimeStamp()));
|
||||||
|
onUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef onUpdateCallback = void Function();
|
||||||
|
typedef onInsertCallback = void Function(int insertID);
|
||||||
|
typedef onRemoveCallback = void Function(int insertID);
|
80
lib/src/Timeline.dart
Normal file
80
lib/src/Timeline.dart
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Zender & Kurtz GbR.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Christian Pauly <krille@famedly.com>
|
||||||
|
* Marcel Radzio <mtrnord@famedly.com>
|
||||||
|
*
|
||||||
|
* This file is part of famedlysdk.
|
||||||
|
*
|
||||||
|
* famedlysdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* famedlysdk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with famedlysdk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'Event.dart';
|
||||||
|
import 'Room.dart';
|
||||||
|
import 'User.dart';
|
||||||
|
import 'sync/EventUpdate.dart';
|
||||||
|
|
||||||
|
/// Represents the timeline of a room. The callbacks [onUpdate], [onDelete],
|
||||||
|
/// [onInsert] and [onResort] will be triggered automatically. The initial
|
||||||
|
/// event list will be retreived when created by the [room.getTimeline] method.
|
||||||
|
class Timeline {
|
||||||
|
final Room room;
|
||||||
|
List<Event> events = [];
|
||||||
|
|
||||||
|
final onUpdateCallback onUpdate;
|
||||||
|
final onInsertCallback onInsert;
|
||||||
|
|
||||||
|
StreamSubscription<EventUpdate> sub;
|
||||||
|
|
||||||
|
Timeline({this.room, this.events, this.onUpdate, this.onInsert}) {
|
||||||
|
sub ??= room.client.connection.onEvent.stream.listen(_handleEventUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleEventUpdate(EventUpdate eventUpdate) async {
|
||||||
|
try {
|
||||||
|
if (eventUpdate.roomID != room.id) return;
|
||||||
|
if (eventUpdate.type == "timeline" || eventUpdate.type == "history") {
|
||||||
|
if (!eventUpdate.content.containsKey("id"))
|
||||||
|
eventUpdate.content["id"] = eventUpdate.content["event_id"];
|
||||||
|
|
||||||
|
User user = await room.client.store
|
||||||
|
?.getUser(matrixID: eventUpdate.content["sender"], room: room);
|
||||||
|
if (user != null) {
|
||||||
|
eventUpdate.content["displayname"] = user.displayName;
|
||||||
|
eventUpdate.content["avatar_url"] = user.avatarUrl.mxc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Event newEvent = Event.fromJson(eventUpdate.content, room);
|
||||||
|
|
||||||
|
events.insert(0, newEvent);
|
||||||
|
onInsert(0);
|
||||||
|
}
|
||||||
|
sortAndUpdate();
|
||||||
|
} catch (e) {
|
||||||
|
print("[WARNING] ${e.toString()}");
|
||||||
|
sub.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortAndUpdate() {
|
||||||
|
events
|
||||||
|
?.sort((a, b) => b.time.toTimeStamp().compareTo(a.time.toTimeStamp()));
|
||||||
|
onUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef onUpdateCallback = void Function();
|
||||||
|
typedef onInsertCallback = void Function(int insertID);
|
|
@ -79,7 +79,7 @@ class User {
|
||||||
|
|
||||||
/// Creates a new User object from a json string like a row from the database.
|
/// Creates a new User object from a json string like a row from the database.
|
||||||
static User fromJson(Map<String, dynamic> json, Room room) {
|
static User fromJson(Map<String, dynamic> json, Room room) {
|
||||||
return User(json['matrix_id'],
|
return User(json['matrix_id'] ?? json['sender'],
|
||||||
displayName: json['displayname'],
|
displayName: json['displayname'],
|
||||||
avatarUrl: MxContent(json['avatar_url']),
|
avatarUrl: MxContent(json['avatar_url']),
|
||||||
membership: json['membership'],
|
membership: json['membership'],
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
/// already known event.
|
/// already known event.
|
||||||
class EventUpdate {
|
class EventUpdate {
|
||||||
/// Usually 'timeline', 'state' or whatever.
|
/// Usually 'timeline', 'state' or whatever.
|
||||||
final String eventType;
|
final String type;
|
||||||
|
|
||||||
/// Most events belong to a room. If not, this equals to eventType.
|
/// Most events belong to a room. If not, this equals to eventType.
|
||||||
final String roomID;
|
final String roomID;
|
||||||
|
@ -33,7 +33,7 @@ class EventUpdate {
|
||||||
/// See (Matrix Room Events)[https://matrix.org/docs/spec/client_server/r0.4.0.html#room-events]
|
/// See (Matrix Room Events)[https://matrix.org/docs/spec/client_server/r0.4.0.html#room-events]
|
||||||
/// and (Matrix Events)[https://matrix.org/docs/spec/client_server/r0.4.0.html#id89] for more
|
/// and (Matrix Events)[https://matrix.org/docs/spec/client_server/r0.4.0.html#id89] for more
|
||||||
/// informations.
|
/// informations.
|
||||||
final String type;
|
final String eventType;
|
||||||
|
|
||||||
// The json payload of the content of this event.
|
// The json payload of the content of this event.
|
||||||
final dynamic content;
|
final dynamic content;
|
||||||
|
|
175
test/RoomList_test.dart
Normal file
175
test/RoomList_test.dart
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Zender & Kurtz GbR.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Christian Pauly <krille@famedly.com>
|
||||||
|
* Marcel Radzio <mtrnord@famedly.com>
|
||||||
|
*
|
||||||
|
* This file is part of famedlysdk.
|
||||||
|
*
|
||||||
|
* famedlysdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* famedlysdk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* 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/Event.dart';
|
||||||
|
import 'package:famedlysdk/src/Room.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';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
/// All Tests related to the MxContent
|
||||||
|
group("RoomList", () {
|
||||||
|
final roomID = "!1:example.com";
|
||||||
|
|
||||||
|
test("Create and insert one room", () async {
|
||||||
|
final Client client = Client("testclient");
|
||||||
|
client.homeserver = "https://testserver.abc";
|
||||||
|
|
||||||
|
int updateCount = 0;
|
||||||
|
List<int> insertList = [];
|
||||||
|
List<int> removeList = [];
|
||||||
|
|
||||||
|
RoomList roomList = RoomList(
|
||||||
|
client: client,
|
||||||
|
rooms: [],
|
||||||
|
onUpdate: () {
|
||||||
|
updateCount++;
|
||||||
|
},
|
||||||
|
onInsert: (int insertID) {
|
||||||
|
insertList.add(insertID);
|
||||||
|
},
|
||||||
|
onRemove: (int removeID) {
|
||||||
|
insertList.add(removeID);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(roomList.eventSub != null, true);
|
||||||
|
expect(roomList.roomSub != null, true);
|
||||||
|
|
||||||
|
client.connection.onRoomUpdate.add(RoomUpdate(
|
||||||
|
id: roomID,
|
||||||
|
membership: "join",
|
||||||
|
notification_count: 2,
|
||||||
|
highlight_count: 1,
|
||||||
|
limitedTimeline: false,
|
||||||
|
prev_batch: "1234",
|
||||||
|
));
|
||||||
|
|
||||||
|
await new Future.delayed(new Duration(milliseconds: 50));
|
||||||
|
|
||||||
|
expect(updateCount, 1);
|
||||||
|
expect(insertList, [0]);
|
||||||
|
expect(removeList, []);
|
||||||
|
|
||||||
|
expect(roomList.rooms.length, 1);
|
||||||
|
expect(roomList.rooms[0].id, roomID);
|
||||||
|
expect(roomList.rooms[0].membership, "join");
|
||||||
|
expect(roomList.rooms[0].notificationCount, 2);
|
||||||
|
expect(roomList.rooms[0].highlightCount, 1);
|
||||||
|
expect(roomList.rooms[0].prev_batch, "1234");
|
||||||
|
expect(roomList.rooms[0].timeCreated, ChatTime.now());
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Restort", () async {
|
||||||
|
final Client client = Client("testclient");
|
||||||
|
client.homeserver = "https://testserver.abc";
|
||||||
|
|
||||||
|
int updateCount = 0;
|
||||||
|
List<int> insertList = [];
|
||||||
|
List<int> removeList = [];
|
||||||
|
|
||||||
|
RoomList roomList = RoomList(
|
||||||
|
client: client,
|
||||||
|
rooms: [],
|
||||||
|
onUpdate: () {
|
||||||
|
updateCount++;
|
||||||
|
},
|
||||||
|
onInsert: (int insertID) {
|
||||||
|
insertList.add(insertID);
|
||||||
|
},
|
||||||
|
onRemove: (int removeID) {
|
||||||
|
insertList.add(removeID);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.connection.onRoomUpdate.add(RoomUpdate(
|
||||||
|
id: "1",
|
||||||
|
membership: "join",
|
||||||
|
notification_count: 2,
|
||||||
|
highlight_count: 1,
|
||||||
|
limitedTimeline: false,
|
||||||
|
prev_batch: "1234",
|
||||||
|
));
|
||||||
|
client.connection.onRoomUpdate.add(RoomUpdate(
|
||||||
|
id: "2",
|
||||||
|
membership: "join",
|
||||||
|
notification_count: 2,
|
||||||
|
highlight_count: 1,
|
||||||
|
limitedTimeline: false,
|
||||||
|
prev_batch: "1234",
|
||||||
|
));
|
||||||
|
|
||||||
|
await new Future.delayed(new Duration(milliseconds: 50));
|
||||||
|
|
||||||
|
expect(roomList.eventSub != null, true);
|
||||||
|
expect(roomList.roomSub != null, true);
|
||||||
|
expect(roomList.rooms[0].id, "1");
|
||||||
|
expect(roomList.rooms[1].id, "2");
|
||||||
|
|
||||||
|
ChatTime now = ChatTime.now();
|
||||||
|
|
||||||
|
client.connection.onEvent.add(EventUpdate(
|
||||||
|
type: "timeline",
|
||||||
|
roomID: "1",
|
||||||
|
eventType: "m.room.message",
|
||||||
|
content: {
|
||||||
|
"type": "m.room.message",
|
||||||
|
"content": {"msgtype": "m.text", "body": "Testcase"},
|
||||||
|
"sender": "@alice:example.com",
|
||||||
|
"status": 2,
|
||||||
|
"id": "1",
|
||||||
|
"origin_server_ts": now.toTimeStamp() - 1000
|
||||||
|
}));
|
||||||
|
|
||||||
|
client.connection.onEvent.add(EventUpdate(
|
||||||
|
type: "timeline",
|
||||||
|
roomID: "2",
|
||||||
|
eventType: "m.room.message",
|
||||||
|
content: {
|
||||||
|
"type": "m.room.message",
|
||||||
|
"content": {"msgtype": "m.text", "body": "Testcase 2"},
|
||||||
|
"sender": "@alice:example.com",
|
||||||
|
"status": 2,
|
||||||
|
"id": "2",
|
||||||
|
"origin_server_ts": now.toTimeStamp()
|
||||||
|
}));
|
||||||
|
|
||||||
|
await new Future.delayed(new Duration(milliseconds: 50));
|
||||||
|
|
||||||
|
expect(updateCount, 4);
|
||||||
|
expect(insertList, [0, 1]);
|
||||||
|
expect(removeList, []);
|
||||||
|
|
||||||
|
expect(roomList.rooms.length, 2);
|
||||||
|
expect(
|
||||||
|
roomList.rooms[0].timeCreated > roomList.rooms[1].timeCreated, true);
|
||||||
|
expect(roomList.rooms[0].id, "2");
|
||||||
|
expect(roomList.rooms[1].id, "1");
|
||||||
|
expect(roomList.rooms[0].lastMessage, "Testcase 2");
|
||||||
|
expect(roomList.rooms[0].timeCreated, now);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
95
test/Timeline_test.dart
Normal file
95
test/Timeline_test.dart
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Zender & Kurtz GbR.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Christian Pauly <krille@famedly.com>
|
||||||
|
* Marcel Radzio <mtrnord@famedly.com>
|
||||||
|
*
|
||||||
|
* This file is part of famedlysdk.
|
||||||
|
*
|
||||||
|
* famedlysdk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* famedlysdk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* 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/Room.dart';
|
||||||
|
import 'package:famedlysdk/src/Timeline.dart';
|
||||||
|
import 'package:famedlysdk/src/sync/EventUpdate.dart';
|
||||||
|
import 'package:famedlysdk/src/utils/ChatTime.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
/// All Tests related to the MxContent
|
||||||
|
group("Timeline", () {
|
||||||
|
final String roomID = "!1234:example.com";
|
||||||
|
final testTimeStamp = ChatTime.now().toTimeStamp();
|
||||||
|
int updateCount = 0;
|
||||||
|
List<int> insertList = [];
|
||||||
|
|
||||||
|
test("Create", () async {
|
||||||
|
Client client = Client("testclient");
|
||||||
|
client.homeserver = "https://testserver.abc";
|
||||||
|
|
||||||
|
Room room = Room(id: roomID, client: client);
|
||||||
|
Timeline timeline = Timeline(
|
||||||
|
room: room,
|
||||||
|
events: [],
|
||||||
|
onUpdate: () {
|
||||||
|
updateCount++;
|
||||||
|
},
|
||||||
|
onInsert: (int insertID) {
|
||||||
|
insertList.add(insertID);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.connection.onEvent.add(EventUpdate(
|
||||||
|
type: "timeline",
|
||||||
|
roomID: roomID,
|
||||||
|
eventType: "m.room.message",
|
||||||
|
content: {
|
||||||
|
"type": "m.room.message",
|
||||||
|
"content": {"msgtype": "m.text", "body": "Testcase"},
|
||||||
|
"sender": "@alice:example.com",
|
||||||
|
"status": 2,
|
||||||
|
"id": "1",
|
||||||
|
"origin_server_ts": testTimeStamp
|
||||||
|
}));
|
||||||
|
|
||||||
|
client.connection.onEvent.add(EventUpdate(
|
||||||
|
type: "timeline",
|
||||||
|
roomID: roomID,
|
||||||
|
eventType: "m.room.message",
|
||||||
|
content: {
|
||||||
|
"type": "m.room.message",
|
||||||
|
"content": {"msgtype": "m.text", "body": "Testcase"},
|
||||||
|
"sender": "@alice:example.com",
|
||||||
|
"status": 2,
|
||||||
|
"id": "2",
|
||||||
|
"origin_server_ts": testTimeStamp - 1000
|
||||||
|
}));
|
||||||
|
|
||||||
|
expect(timeline.sub != null, true);
|
||||||
|
|
||||||
|
await new Future.delayed(new Duration(milliseconds: 50));
|
||||||
|
|
||||||
|
expect(updateCount, 2);
|
||||||
|
expect(insertList, [0, 0]);
|
||||||
|
expect(timeline.events.length, 2);
|
||||||
|
expect(timeline.events[0].id, "1");
|
||||||
|
expect(timeline.events[0].sender.id, "@alice:example.com");
|
||||||
|
expect(timeline.events[0].time.toTimeStamp(), testTimeStamp);
|
||||||
|
expect(timeline.events[0].environment, "m.room.message");
|
||||||
|
expect(timeline.events[0].getBody(), "Testcase");
|
||||||
|
expect(timeline.events[0].time > timeline.events[1].time, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in a new issue