fix: Last event calculation

This commit is contained in:
Christian Pauly 2020-09-16 10:18:13 +02:00
parent d9c4472cac
commit b05e4da34f
4 changed files with 68 additions and 44 deletions

View file

@ -9,5 +9,4 @@ analyzer:
errors: errors:
todo: ignore todo: ignore
exclude: exclude:
- example/main.dart - example/main.dart
- lib/src/utils/logs.dart

View file

@ -59,15 +59,16 @@ class Client extends MatrixApi {
Set<String> importantStateEvents; Set<String> importantStateEvents;
Set<String> roomPreviewLastEvents;
/// Create a client /// Create a client
/// clientName = unique identifier of this client /// [clientName] = unique identifier of this client
/// debug: Print debug output? /// [database]: The database instance to use
/// database: The database instance to use /// [enableE2eeRecovery]: Enable additional logic to try to recover from bad e2ee sessions
/// enableE2eeRecovery: Enable additional logic to try to recover from bad e2ee sessions /// [verificationMethods]: A set of all the verification methods this client can handle. Includes:
/// verificationMethods: A set of all the verification methods this client can handle. Includes:
/// KeyVerificationMethod.numbers: Compare numbers. Most basic, should be supported /// KeyVerificationMethod.numbers: Compare numbers. Most basic, should be supported
/// KeyVerificationMethod.emoji: Compare emojis /// KeyVerificationMethod.emoji: Compare emojis
/// importantStateEvents: A set of all the important state events to load when the client connects. /// [importantStateEvents]: A set of all the important state events to load when the client connects.
/// To speed up performance only a set of state events is loaded on startup, those that are /// To speed up performance only a set of state events is loaded on startup, those that are
/// needed to display a room list. All the remaining state events are automatically post-loaded /// needed to display a room list. All the remaining state events are automatically post-loaded
/// when opening the timeline of a room or manually by calling `room.postLoad()`. /// when opening the timeline of a room or manually by calling `room.postLoad()`.
@ -80,6 +81,8 @@ class Client extends MatrixApi {
/// - m.room.canonical_alias /// - m.room.canonical_alias
/// - m.room.tombstone /// - m.room.tombstone
/// - *some* m.room.member events, where needed /// - *some* m.room.member events, where needed
/// [roomPreviewLastEvents]: The event types that should be used to calculate the last event
/// in a room for the room list.
Client( Client(
this.clientName, { this.clientName, {
this.database, this.database,
@ -87,11 +90,12 @@ class Client extends MatrixApi {
this.verificationMethods, this.verificationMethods,
http.Client httpClient, http.Client httpClient,
this.importantStateEvents, this.importantStateEvents,
this.roomPreviewLastEvents,
this.pinUnreadRooms = false, this.pinUnreadRooms = false,
@deprecated bool debug, @deprecated bool debug,
}) { }) {
verificationMethods ??= <KeyVerificationMethod>{}; verificationMethods ??= <KeyVerificationMethod>{};
importantStateEvents ??= <String>{}; importantStateEvents ??= {};
importantStateEvents.addAll([ importantStateEvents.addAll([
EventTypes.RoomName, EventTypes.RoomName,
EventTypes.RoomAvatar, EventTypes.RoomAvatar,
@ -101,6 +105,12 @@ class Client extends MatrixApi {
EventTypes.RoomCanonicalAlias, EventTypes.RoomCanonicalAlias,
EventTypes.RoomTombstone, EventTypes.RoomTombstone,
]); ]);
roomPreviewLastEvents ??= {};
roomPreviewLastEvents.addAll([
EventTypes.Message,
EventTypes.Encrypted,
EventTypes.Sticker,
]);
this.httpClient = httpClient ?? http.Client(); this.httpClient = httpClient ?? http.Client();
} }
@ -1099,44 +1109,49 @@ class Client extends MatrixApi {
void _updateRoomsByEventUpdate(EventUpdate eventUpdate) { void _updateRoomsByEventUpdate(EventUpdate eventUpdate) {
if (eventUpdate.type == 'history') return; if (eventUpdate.type == 'history') return;
// Search the room in the rooms
num j = 0; final room = getRoomById(eventUpdate.roomID);
for (j = 0; j < rooms.length; j++) { if (room == null) return;
if (rooms[j].id == eventUpdate.roomID) break;
} switch (eventUpdate.type) {
final found = (j < rooms.length && rooms[j].id == eventUpdate.roomID); case 'timeline':
if (!found) return; case 'state':
if (eventUpdate.type == 'timeline' || case 'invite_state':
eventUpdate.type == 'state' || var stateEvent =
eventUpdate.type == 'invite_state') { Event.fromJson(eventUpdate.content, room, eventUpdate.sortOrder);
var stateEvent = var prevState = room.getState(stateEvent.type, stateEvent.stateKey);
Event.fromJson(eventUpdate.content, rooms[j], eventUpdate.sortOrder);
if (stateEvent.type == EventTypes.Redaction) {
final String redacts = eventUpdate.content['redacts'];
rooms[j].states.states.forEach(
(String key, Map<String, Event> states) => states.forEach(
(String key, Event state) {
if (state.eventId == redacts) {
state.setRedactionEvent(stateEvent);
}
},
),
);
} else {
var prevState = rooms[j].getState(stateEvent.type, stateEvent.stateKey);
if (prevState != null && prevState.sortOrder > stateEvent.sortOrder) { if (prevState != null && prevState.sortOrder > stateEvent.sortOrder) {
Logs.warning('''
A new ${eventUpdate.type} event of the type ${stateEvent.type} has arrived with a previews
sort order ${stateEvent.sortOrder} than the current ${stateEvent.type} event with a
sort order of ${prevState.sortOrder}. This should never happen...''');
return; return;
} }
rooms[j].setState(stateEvent); if (stateEvent.type == EventTypes.Redaction) {
} final String redacts = eventUpdate.content['redacts'];
} else if (eventUpdate.type == 'account_data') { room.states.states.forEach(
rooms[j].roomAccountData[eventUpdate.eventType] = (String key, Map<String, Event> states) => states.forEach(
BasicRoomEvent.fromJson(eventUpdate.content); (String key, Event state) {
} else if (eventUpdate.type == 'ephemeral') { if (state.eventId == redacts) {
rooms[j].ephemerals[eventUpdate.eventType] = state.setRedactionEvent(stateEvent);
BasicRoomEvent.fromJson(eventUpdate.content); }
},
),
);
} else {
room.setState(stateEvent);
}
break;
case 'account_data':
room.roomAccountData[eventUpdate.eventType] =
BasicRoomEvent.fromJson(eventUpdate.content);
break;
case 'ephemeral':
room.ephemerals[eventUpdate.eventType] =
BasicRoomEvent.fromJson(eventUpdate.content);
break;
} }
if (rooms[j].onUpdate != null) rooms[j].onUpdate.add(rooms[j].id); room.onUpdate.add(room.id);
if (['timeline', 'account_data'].contains(eventUpdate.type)) _sortRooms(); if (['timeline', 'account_data'].contains(eventUpdate.type)) _sortRooms();
} }

View file

@ -264,7 +264,13 @@ class Room {
// perfect, it is only used for the room preview in the room list and sorting // perfect, it is only used for the room preview in the room list and sorting
// said room list, so it should be good enough. // said room list, so it should be good enough.
var lastTime = DateTime.fromMillisecondsSinceEpoch(0); var lastTime = DateTime.fromMillisecondsSinceEpoch(0);
var lastEvent = getState(EventTypes.Message); final lastEvents = <Event>[
for (var type in client.roomPreviewLastEvents) getState(type)
]..removeWhere((e) => e == null);
var lastEvent = lastEvents.isEmpty
? null
: lastEvents.reduce((a, b) => a.sortOrder > b.sortOrder ? a : b);
if (lastEvent == null) { if (lastEvent == null) {
states.forEach((final String key, final entry) { states.forEach((final String key, final entry) {
if (!entry.containsKey('')) return; if (!entry.containsKey('')) return;

View file

@ -26,20 +26,24 @@ abstract class Logs {
static const String _prefixText = '[Famedly Matrix SDK] '; static const String _prefixText = '[Famedly Matrix SDK] ';
// ignore: avoid_print
static void info(dynamic info) => print( static void info(dynamic info) => print(
_prefixText + _infoPen(info.toString()), _prefixText + _infoPen(info.toString()),
); );
// ignore: avoid_print
static void success(dynamic obj, [dynamic stackTrace]) => print( static void success(dynamic obj, [dynamic stackTrace]) => print(
_prefixText + _successPen(obj.toString()), _prefixText + _successPen(obj.toString()),
); );
// ignore: avoid_print
static void warning(dynamic warning, [dynamic stackTrace]) => print( static void warning(dynamic warning, [dynamic stackTrace]) => print(
_prefixText + _prefixText +
_warningPen(warning.toString()) + _warningPen(warning.toString()) +
(stackTrace != null ? '\n${stackTrace.toString()}' : ''), (stackTrace != null ? '\n${stackTrace.toString()}' : ''),
); );
// ignore: avoid_print
static void error(dynamic obj, [dynamic stackTrace]) => print( static void error(dynamic obj, [dynamic stackTrace]) => print(
_prefixText + _prefixText +
_errorPen(obj.toString()) + _errorPen(obj.toString()) +