I forgot what I changed sorry

This commit is contained in:
OfficialDakari 2025-10-21 21:31:42 +05:00
parent c4df172416
commit 889477e07c
4 changed files with 209 additions and 76 deletions

View File

@ -598,13 +598,44 @@ class RoomTimeline extends Timeline {
}
return;
}
}
extension on List<Event> {
int get firstIndexWhereNotError {
if (isEmpty) return 0;
final index = indexWhere((event) => !event.status.isError);
if (index == -1) return length;
return index;
/// 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),
);
}
}

View File

@ -4,12 +4,14 @@ class Thread {
final Room room;
final Event rootEvent;
Event? lastEvent;
String? prev_batch;
final Client client;
Thread({
required this.room,
required this.rootEvent,
required this.client,
this.prev_batch,
this.lastEvent,
});

View File

@ -1,22 +1,163 @@
import 'dart:async';
import 'package:matrix/matrix.dart';
import 'package:matrix/src/models/timeline_chunk.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 {
final Thread thread;
@override
List<Event> get events => chunk.events;
TimelineChunk chunk;
StreamSubscription<Event>? timelineSub;
StreamSubscription<Event>? historySub;
StreamSubscription<SyncUpdate>? roomSub;
StreamSubscription<String>? sessionIdReceivedSub;
StreamSubscription<String>? cancelSendEventSub;
ThreadTimeline({
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
// TODO: implement canRequestFuture
@ -38,19 +179,22 @@ class ThreadTimeline extends Timeline {
}
@override
Future<void> requestFuture({int historyCount = Room.defaultHistoryCount, StateFilter? filter}) {
Future<void> requestFuture(
{int historyCount = Room.defaultHistoryCount, StateFilter? filter}) {
// TODO: implement requestFuture
throw UnimplementedError();
}
@override
Future<void> requestHistory({int historyCount = Room.defaultHistoryCount, StateFilter? filter}) {
Future<void> requestHistory(
{int historyCount = Room.defaultHistoryCount, StateFilter? filter}) {
// TODO: implement requestHistory
throw UnimplementedError();
}
@override
void requestKeys({bool tryOnlineBackup = true, bool onlineKeyBackupOnly = true}) {
void requestKeys(
{bool tryOnlineBackup = true, bool onlineKeyBackupOnly = true}) {
// TODO: implement requestKeys
}
@ -61,9 +205,15 @@ class ThreadTimeline extends Timeline {
}
@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
throw UnimplementedError();
}
}
}

View File

@ -17,11 +17,7 @@
*/
import 'dart:async';
import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:matrix/matrix.dart';
import 'package:matrix/src/models/timeline_chunk.dart';
/// Abstract base class for all timeline implementations.
/// Provides common functionality for event management, aggregation, and search.
@ -93,62 +89,6 @@ abstract class Timeline {
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)
void _handleEventUpdate(Event event, EventUpdateType type, {bool update = true});
@ -172,4 +112,14 @@ abstract class Timeline {
limit: limit,
searchFunc: searchFunc,
).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;
}
}