I forgot what I changed sorry
This commit is contained in:
parent
c4df172416
commit
889477e07c
|
|
@ -598,13 +598,44 @@ class RoomTimeline extends Timeline {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add an event to the aggregation tree
|
||||||
|
void addAggregatedEvent(Event event) {
|
||||||
|
final relationshipType = event.relationshipType;
|
||||||
|
final relationshipEventId = event.relationshipEventId;
|
||||||
|
if (relationshipType == null || relationshipEventId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final e = (aggregatedEvents[relationshipEventId] ??=
|
||||||
|
<String, Set<Event>>{})[relationshipType] ??= <Event>{};
|
||||||
|
_removeEventFromSet(e, event);
|
||||||
|
e.add(event);
|
||||||
|
if (onChange != null) {
|
||||||
|
final index = _findEvent(event_id: relationshipEventId);
|
||||||
|
onChange?.call(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension on List<Event> {
|
/// Remove an event from aggregation
|
||||||
int get firstIndexWhereNotError {
|
void removeAggregatedEvent(Event event) {
|
||||||
if (isEmpty) return 0;
|
aggregatedEvents.remove(event.eventId);
|
||||||
final index = indexWhere((event) => !event.status.isError);
|
if (event.transactionId != null) {
|
||||||
if (index == -1) return length;
|
aggregatedEvents.remove(event.transactionId);
|
||||||
return index;
|
}
|
||||||
|
for (final types in aggregatedEvents.values) {
|
||||||
|
for (final e in types.values) {
|
||||||
|
_removeEventFromSet(e, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove event from set based on event or transaction ID
|
||||||
|
void _removeEventFromSet(Set<Event> eventSet, Event event) {
|
||||||
|
eventSet.removeWhere(
|
||||||
|
(e) =>
|
||||||
|
e.matchesEventOrTransactionId(event.eventId) ||
|
||||||
|
event.unsigned != null &&
|
||||||
|
e.matchesEventOrTransactionId(event.transactionId),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,12 +4,14 @@ class Thread {
|
||||||
final Room room;
|
final Room room;
|
||||||
final Event rootEvent;
|
final Event rootEvent;
|
||||||
Event? lastEvent;
|
Event? lastEvent;
|
||||||
|
String? prev_batch;
|
||||||
final Client client;
|
final Client client;
|
||||||
|
|
||||||
Thread({
|
Thread({
|
||||||
required this.room,
|
required this.room,
|
||||||
required this.rootEvent,
|
required this.rootEvent,
|
||||||
required this.client,
|
required this.client,
|
||||||
|
this.prev_batch,
|
||||||
this.lastEvent,
|
this.lastEvent,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
import 'package:matrix/src/models/timeline_chunk.dart';
|
import 'package:matrix/src/models/timeline_chunk.dart';
|
||||||
import 'package:matrix/src/thread.dart';
|
import 'package:matrix/src/thread.dart';
|
||||||
|
|
||||||
|
// ThreadTimeline: hey RoomTimeline can i copy your homework?
|
||||||
|
// RoomTimeline: sure just don't make it too obvious
|
||||||
|
// ThreadTimeline:
|
||||||
|
|
||||||
class ThreadTimeline extends Timeline {
|
class ThreadTimeline extends Timeline {
|
||||||
final Thread thread;
|
final Thread thread;
|
||||||
|
|
||||||
|
|
@ -10,13 +16,148 @@ class ThreadTimeline extends Timeline {
|
||||||
|
|
||||||
TimelineChunk chunk;
|
TimelineChunk chunk;
|
||||||
|
|
||||||
|
StreamSubscription<Event>? timelineSub;
|
||||||
|
StreamSubscription<Event>? historySub;
|
||||||
|
StreamSubscription<SyncUpdate>? roomSub;
|
||||||
|
StreamSubscription<String>? sessionIdReceivedSub;
|
||||||
|
StreamSubscription<String>? cancelSendEventSub;
|
||||||
|
|
||||||
ThreadTimeline({
|
ThreadTimeline({
|
||||||
required this.thread,
|
required this.thread,
|
||||||
required this.chunk
|
required this.chunk,
|
||||||
|
super.onUpdate,
|
||||||
|
super.onChange,
|
||||||
|
super.onInsert,
|
||||||
|
super.onRemove,
|
||||||
|
super.onNewEvent,
|
||||||
}) {
|
}) {
|
||||||
|
final room = thread.room;
|
||||||
|
timelineSub = room.client.onTimelineEvent.stream.listen(
|
||||||
|
(event) => _handleEventUpdate(event, EventUpdateType.timeline),
|
||||||
|
);
|
||||||
|
historySub = room.client.onHistoryEvent.stream.listen(
|
||||||
|
(event) => _handleEventUpdate(event, EventUpdateType.history),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handleEventUpdate(
|
||||||
|
Event event,
|
||||||
|
EventUpdateType type, {
|
||||||
|
bool update = true,
|
||||||
|
}) {
|
||||||
|
try {
|
||||||
|
if (event.roomId != thread.room.id) return;
|
||||||
|
// Ignore events outside of this thread
|
||||||
|
if (event.relationshipType != RelationshipTypes.thread ||
|
||||||
|
event.relationshipEventId != thread.rootEvent.eventId) return;
|
||||||
|
|
||||||
|
if (type != EventUpdateType.timeline && type != EventUpdateType.history) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == EventUpdateType.timeline) {
|
||||||
|
onNewEvent?.call();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == EventUpdateType.history &&
|
||||||
|
events.indexWhere((e) => e.eventId == event.eventId) != -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var index = events.length;
|
||||||
|
if (type == EventUpdateType.history) {
|
||||||
|
events.add(event);
|
||||||
|
} else {
|
||||||
|
index = events.firstIndexWhereNotError;
|
||||||
|
events.insert(index, event);
|
||||||
|
}
|
||||||
|
onInsert?.call(index);
|
||||||
|
|
||||||
|
addAggregatedEvent(event);
|
||||||
|
|
||||||
|
// Handle redaction events
|
||||||
|
if (event.type == EventTypes.Redaction) {
|
||||||
|
final index = _findEvent(event_id: event.redacts);
|
||||||
|
if (index < events.length) {
|
||||||
|
removeAggregatedEvent(events[index]);
|
||||||
|
|
||||||
|
// Is the redacted event a reaction? Then update the event this
|
||||||
|
// belongs to:
|
||||||
|
if (onChange != null) {
|
||||||
|
final relationshipEventId = events[index].relationshipEventId;
|
||||||
|
if (relationshipEventId != null) {
|
||||||
|
onChange?.call(_findEvent(event_id: relationshipEventId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
events[index].setRedactionEvent(event);
|
||||||
|
onChange?.call(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
onUpdate?.call();
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
Logs().w('Handle event update failed', e, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an event to the aggregation tree
|
||||||
|
void addAggregatedEvent(Event event) {
|
||||||
|
final relationshipType = event.relationshipType;
|
||||||
|
final relationshipEventId = event.relationshipEventId;
|
||||||
|
if (relationshipType == null || relationshipEventId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final e = (aggregatedEvents[relationshipEventId] ??=
|
||||||
|
<String, Set<Event>>{})[relationshipType] ??= <Event>{};
|
||||||
|
_removeEventFromSet(e, event);
|
||||||
|
e.add(event);
|
||||||
|
if (onChange != null) {
|
||||||
|
final index = _findEvent(event_id: relationshipEventId);
|
||||||
|
onChange?.call(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove an event from aggregation
|
||||||
|
void removeAggregatedEvent(Event event) {
|
||||||
|
aggregatedEvents.remove(event.eventId);
|
||||||
|
if (event.transactionId != null) {
|
||||||
|
aggregatedEvents.remove(event.transactionId);
|
||||||
|
}
|
||||||
|
for (final types in aggregatedEvents.values) {
|
||||||
|
for (final e in types.values) {
|
||||||
|
_removeEventFromSet(e, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove event from set based on event or transaction ID
|
||||||
|
void _removeEventFromSet(Set<Event> eventSet, Event event) {
|
||||||
|
eventSet.removeWhere(
|
||||||
|
(e) =>
|
||||||
|
e.matchesEventOrTransactionId(event.eventId) ||
|
||||||
|
event.unsigned != null &&
|
||||||
|
e.matchesEventOrTransactionId(event.transactionId),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find event index by event ID or transaction ID
|
||||||
|
int _findEvent({String? event_id, String? unsigned_txid}) {
|
||||||
|
final searchNeedle = <String>{};
|
||||||
|
if (event_id != null) searchNeedle.add(event_id);
|
||||||
|
if (unsigned_txid != null) searchNeedle.add(unsigned_txid);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < events.length; i++) {
|
||||||
|
final searchHaystack = <String>{events[i].eventId};
|
||||||
|
final txnid = events[i].transactionId;
|
||||||
|
if (txnid != null) searchHaystack.add(txnid);
|
||||||
|
if (searchNeedle.intersection(searchHaystack).isNotEmpty) break;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// TODO: implement canRequestFuture
|
// TODO: implement canRequestFuture
|
||||||
|
|
@ -38,19 +179,22 @@ class ThreadTimeline extends Timeline {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> requestFuture({int historyCount = Room.defaultHistoryCount, StateFilter? filter}) {
|
Future<void> requestFuture(
|
||||||
|
{int historyCount = Room.defaultHistoryCount, StateFilter? filter}) {
|
||||||
// TODO: implement requestFuture
|
// TODO: implement requestFuture
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> requestHistory({int historyCount = Room.defaultHistoryCount, StateFilter? filter}) {
|
Future<void> requestHistory(
|
||||||
|
{int historyCount = Room.defaultHistoryCount, StateFilter? filter}) {
|
||||||
// TODO: implement requestHistory
|
// TODO: implement requestHistory
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void requestKeys({bool tryOnlineBackup = true, bool onlineKeyBackupOnly = true}) {
|
void requestKeys(
|
||||||
|
{bool tryOnlineBackup = true, bool onlineKeyBackupOnly = true}) {
|
||||||
// TODO: implement requestKeys
|
// TODO: implement requestKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,9 +205,15 @@ class ThreadTimeline extends Timeline {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<(List<Event>, String?)> startSearch({String? searchTerm, int requestHistoryCount = 100, int maxHistoryRequests = 10, String? prevBatch, String? sinceEventId, int? limit, bool Function(Event p1)? searchFunc}) {
|
Stream<(List<Event>, String?)> startSearch(
|
||||||
|
{String? searchTerm,
|
||||||
|
int requestHistoryCount = 100,
|
||||||
|
int maxHistoryRequests = 10,
|
||||||
|
String? prevBatch,
|
||||||
|
String? sinceEventId,
|
||||||
|
int? limit,
|
||||||
|
bool Function(Event p1)? searchFunc}) {
|
||||||
// TODO: implement startSearch
|
// TODO: implement startSearch
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -17,11 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
import 'package:matrix/src/models/timeline_chunk.dart';
|
|
||||||
|
|
||||||
/// Abstract base class for all timeline implementations.
|
/// Abstract base class for all timeline implementations.
|
||||||
/// Provides common functionality for event management, aggregation, and search.
|
/// Provides common functionality for event management, aggregation, and search.
|
||||||
|
|
@ -93,62 +89,6 @@ abstract class Timeline {
|
||||||
bool Function(Event)? searchFunc,
|
bool Function(Event)? searchFunc,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Add an event to the aggregation tree
|
|
||||||
void addAggregatedEvent(Event event) {
|
|
||||||
final relationshipType = event.relationshipType;
|
|
||||||
final relationshipEventId = event.relationshipEventId;
|
|
||||||
if (relationshipType == null || relationshipEventId == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final e = (aggregatedEvents[relationshipEventId] ??=
|
|
||||||
<String, Set<Event>>{})[relationshipType] ??= <Event>{};
|
|
||||||
_removeEventFromSet(e, event);
|
|
||||||
e.add(event);
|
|
||||||
if (onChange != null) {
|
|
||||||
final index = _findEvent(event_id: relationshipEventId);
|
|
||||||
onChange?.call(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove an event from aggregation
|
|
||||||
void removeAggregatedEvent(Event event) {
|
|
||||||
aggregatedEvents.remove(event.eventId);
|
|
||||||
if (event.transactionId != null) {
|
|
||||||
aggregatedEvents.remove(event.transactionId);
|
|
||||||
}
|
|
||||||
for (final types in aggregatedEvents.values) {
|
|
||||||
for (final e in types.values) {
|
|
||||||
_removeEventFromSet(e, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find event index by event ID or transaction ID
|
|
||||||
int _findEvent({String? event_id, String? unsigned_txid}) {
|
|
||||||
final searchNeedle = <String>{};
|
|
||||||
if (event_id != null) searchNeedle.add(event_id);
|
|
||||||
if (unsigned_txid != null) searchNeedle.add(unsigned_txid);
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < events.length; i++) {
|
|
||||||
final searchHaystack = <String>{events[i].eventId};
|
|
||||||
final txnid = events[i].transactionId;
|
|
||||||
if (txnid != null) searchHaystack.add(txnid);
|
|
||||||
if (searchNeedle.intersection(searchHaystack).isNotEmpty) break;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove event from set based on event or transaction ID
|
|
||||||
void _removeEventFromSet(Set<Event> eventSet, Event event) {
|
|
||||||
eventSet.removeWhere(
|
|
||||||
(e) =>
|
|
||||||
e.matchesEventOrTransactionId(event.eventId) ||
|
|
||||||
event.unsigned != null &&
|
|
||||||
e.matchesEventOrTransactionId(event.transactionId),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handle event updates (to be implemented by subclasses)
|
/// Handle event updates (to be implemented by subclasses)
|
||||||
void _handleEventUpdate(Event event, EventUpdateType type, {bool update = true});
|
void _handleEventUpdate(Event event, EventUpdateType type, {bool update = true});
|
||||||
|
|
||||||
|
|
@ -173,3 +113,13 @@ abstract class Timeline {
|
||||||
searchFunc: searchFunc,
|
searchFunc: searchFunc,
|
||||||
).map((result) => result.$1);
|
).map((result) => result.$1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: make up a better name
|
||||||
|
extension TimelineExtension on List<Event> {
|
||||||
|
int get firstIndexWhereNotError {
|
||||||
|
if (isEmpty) return 0;
|
||||||
|
final index = indexWhere((event) => !event.status.isError);
|
||||||
|
if (index == -1) return length;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue