refactor: delete not sent events without eventupdate stream workaround
This fixes several problems. First sending a fake event through the onEventUpdate stream was not a good design and lead to problems if you expect a timeline event but then are unable to build the event from json. This now uses a new stream in the Client which is listened to in the timeline to delete an event which should be much more reliable. It also now throws an exception if deleting the event fails instead of returning true or false. A deprecation note is added.
This commit is contained in:
parent
e4acb1f510
commit
501c457ea1
|
|
@ -1312,6 +1312,9 @@ class Client extends MatrixApi {
|
|||
|
||||
final CachedStreamController<Event> onGroupMember = CachedStreamController();
|
||||
|
||||
final CachedStreamController<String> onCancelSendEvent =
|
||||
CachedStreamController();
|
||||
|
||||
/// When a state in a room has been updated this will return the room ID
|
||||
/// and the state event.
|
||||
final CachedStreamController<({String roomId, StrippedStateEvent state})>
|
||||
|
|
|
|||
|
|
@ -322,28 +322,27 @@ class Event extends MatrixEvent {
|
|||
return receiptsList;
|
||||
}
|
||||
|
||||
/// Removes this event if the status is [sending], [error] or [removed].
|
||||
/// This event will just be removed from the database and the timelines.
|
||||
/// Returns [false] if not removed.
|
||||
@Deprecated('Use [cancelSend()] instead.')
|
||||
Future<bool> remove() async {
|
||||
final room = this.room;
|
||||
|
||||
if (!status.isSent) {
|
||||
await room.client.database?.removeEvent(eventId, room.id);
|
||||
|
||||
room.client.onEvent.add(EventUpdate(
|
||||
roomID: room.id,
|
||||
type: EventUpdateType.timeline,
|
||||
content: {
|
||||
'event_id': eventId,
|
||||
'status': EventStatus.removed.intValue,
|
||||
'content': {'body': 'Removed...'}
|
||||
},
|
||||
));
|
||||
try {
|
||||
await cancelSend();
|
||||
return true;
|
||||
}
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes an unsent or yet-to-send event from the database and timeline.
|
||||
/// These are events marked with the status `SENDING` or `ERROR`.
|
||||
/// Throws an exception if used for an already sent event!
|
||||
Future<void> cancelSend() async {
|
||||
if (status.isSent) {
|
||||
throw Exception('Can only delete events which are not sent yet!');
|
||||
}
|
||||
|
||||
await room.client.database?.removeEvent(eventId, room.id);
|
||||
room.client.onCancelSendEvent.add(eventId);
|
||||
}
|
||||
|
||||
/// Try to send this event again. Only works with events of status -1.
|
||||
Future<String?> sendAgain({String? txid}) async {
|
||||
|
|
@ -358,7 +357,7 @@ class Event extends MatrixEvent {
|
|||
}.contains(messageType)) {
|
||||
final file = room.sendingFilePlaceholders[eventId];
|
||||
if (file == null) {
|
||||
await remove();
|
||||
await cancelSend();
|
||||
throw Exception('Can not try to send again. File is no longer cached.');
|
||||
}
|
||||
final thumbnail = room.sendingFileThumbnails[eventId];
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
/// - synced: (event came from sync loop)
|
||||
/// - roomState
|
||||
enum EventStatus {
|
||||
removed,
|
||||
error,
|
||||
sending,
|
||||
sent,
|
||||
|
|
@ -33,7 +32,6 @@ EventStatus latestEventStatus(EventStatus status1, EventStatus status2) =>
|
|||
extension EventStatusExtension on EventStatus {
|
||||
/// Returns int value of the event status.
|
||||
///
|
||||
/// - -2 == removed;
|
||||
/// - -1 == error;
|
||||
/// - 0 == sending;
|
||||
/// - 1 == sent;
|
||||
|
|
@ -41,9 +39,6 @@ extension EventStatusExtension on EventStatus {
|
|||
/// - 3 == roomState;
|
||||
int get intValue => (index - 2);
|
||||
|
||||
/// Return `true` if the `EventStatus` equals `removed`.
|
||||
bool get isRemoved => this == EventStatus.removed;
|
||||
|
||||
/// Return `true` if the `EventStatus` equals `error`.
|
||||
bool get isError => this == EventStatus.error;
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class Timeline {
|
|||
StreamSubscription<EventUpdate>? sub;
|
||||
StreamSubscription<SyncUpdate>? roomSub;
|
||||
StreamSubscription<String>? sessionIdReceivedSub;
|
||||
StreamSubscription<String>? cancelSendEventSub;
|
||||
bool isRequestingHistory = false;
|
||||
bool isRequestingFuture = false;
|
||||
|
||||
|
|
@ -278,6 +279,8 @@ class Timeline {
|
|||
|
||||
sessionIdReceivedSub =
|
||||
room.onSessionKeyReceived.stream.listen(_sessionKeyReceived);
|
||||
cancelSendEventSub =
|
||||
room.client.onCancelSendEvent.stream.listen(_cleanUpCancelledEvent);
|
||||
|
||||
// we want to populate our aggregated events
|
||||
for (final e in events) {
|
||||
|
|
@ -291,6 +294,16 @@ class Timeline {
|
|||
}
|
||||
}
|
||||
|
||||
void _cleanUpCancelledEvent(String eventId) {
|
||||
final i = _findEvent(event_id: eventId);
|
||||
if (i < events.length) {
|
||||
removeAggregatedEvent(events[i]);
|
||||
events.removeAt(i);
|
||||
onRemove?.call(i);
|
||||
onUpdate?.call();
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes all entries from [events] which are not in this SyncUpdate.
|
||||
void _removeEventsNotInThisSync(SyncUpdate sync) {
|
||||
final newSyncEvents = sync.rooms?.join?[room.id]?.timeline?.events ?? [];
|
||||
|
|
@ -306,6 +319,8 @@ class Timeline {
|
|||
roomSub?.cancel();
|
||||
// ignore: discarded_futures
|
||||
sessionIdReceivedSub?.cancel();
|
||||
// ignore: discarded_futures
|
||||
cancelSendEventSub?.cancel();
|
||||
}
|
||||
|
||||
void _sessionKeyReceived(String sessionId) async {
|
||||
|
|
@ -462,14 +477,6 @@ class Timeline {
|
|||
: null) ??
|
||||
EventStatus.synced.intValue);
|
||||
|
||||
if (status.isRemoved) {
|
||||
final i = _findEvent(event_id: eventUpdate.content['event_id']);
|
||||
if (i < events.length) {
|
||||
removeAggregatedEvent(events[i]);
|
||||
events.removeAt(i);
|
||||
onRemove?.call(i);
|
||||
}
|
||||
} else {
|
||||
final i = _findEvent(
|
||||
event_id: eventUpdate.content['event_id'],
|
||||
unsigned_txid: eventUpdate.content['unsigned'] is Map
|
||||
|
|
@ -511,7 +518,6 @@ class Timeline {
|
|||
|
||||
addAggregatedEvent(newEvent);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle redaction events
|
||||
if (eventUpdate.content['type'] == EventTypes.Redaction) {
|
||||
|
|
|
|||
|
|
@ -242,12 +242,12 @@ void main() {
|
|||
|
||||
test('remove', () async {
|
||||
final event = Event.fromJson(
|
||||
jsonObj, Room(id: '1234', client: Client('testclient')));
|
||||
final removed1 = await event.remove();
|
||||
jsonObj,
|
||||
Room(id: '1234', client: Client('testclient')),
|
||||
);
|
||||
expect(() async => await event.cancelSend(), throwsException);
|
||||
event.status = EventStatus.sending;
|
||||
final removed2 = await event.remove();
|
||||
expect(removed1, false);
|
||||
expect(removed2, true);
|
||||
await event.cancelSend();
|
||||
});
|
||||
|
||||
test('sendAgain', () async {
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ void main() {
|
|||
));
|
||||
await waitForCount(7);
|
||||
|
||||
await timeline.events[0].remove();
|
||||
await timeline.events[0].cancelSend();
|
||||
|
||||
await waitForCount(8);
|
||||
expect(updateCount, 8);
|
||||
|
|
|
|||
|
|
@ -507,7 +507,7 @@ void main() {
|
|||
));
|
||||
await waitForCount(1);
|
||||
|
||||
await timeline.events[0].remove();
|
||||
await timeline.events[0].cancelSend();
|
||||
|
||||
await waitForCount(2);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue