did something

This commit is contained in:
OfficialDakari 2025-10-24 21:21:20 +05:00
parent 0fb0a6c47f
commit 74c39f91fe
6 changed files with 142 additions and 43 deletions

View File

@ -61,6 +61,8 @@ abstract class DatabaseApi {
Future<List<Thread>> getThreadList(String roomId, Client client);
Future<Thread?> getThread(String roomId, String threadRootEventId, Client client);
Future<void> storeThread(
String roomId,
Event threadRootEvent,

View File

@ -1368,18 +1368,34 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
@override
Future<List<Thread>> getThreadList(String roomId, Client client) async {
final allThreadsKeys = await _threadsBox.getAllKeys();
final threadsKeys = <String>{};
// TERRIBLE implementation. Better to create another box (String[roomId]->List<string>[event ids])
for (final key in allThreadsKeys) {
if (key.startsWith(roomId)) threadsKeys.add(key);
}
final threads = <Thread>{};
// TERRIBLE implementation. Better to create another box (String[roomId]->List<string>[event ids])
for (final key in allThreadsKeys) {
if (key.startsWith('$roomId|')) {
final thread = await getThread(roomId, key.split('|')[1], client);
if (thread != null) {
threads.add(thread);
}
}
}
return threads.toList();
}
@override
Future<Thread?> getThread(
String roomId,
String threadRootEventId,
Client client,
) async {
final key = TupleKey(roomId, threadRootEventId).toString();
final thread = await _threadsBox.get(key);
if (thread == null) return null;
Logs().w(thread.toString());
return Thread.fromJson(thread.cast<String, dynamic>(), client);
}
@override
Future<void> storeThread(
String roomId,
@ -1392,14 +1408,16 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
final key = TupleKey(roomId, threadRootEvent.eventId).toString();
// final currentRawThread = await _threadsBox.get(key);
await _threadsBox.put(
key,
Thread(
room: Room(id: roomId, client: client),
rootEvent: threadRootEvent,
client: client,
currentUserParticipated: currentUserParticipated,
count: count,
).toJson());
key,
Thread(
room: Room(id: roomId, client: client),
rootEvent: threadRootEvent,
lastEvent: lastEvent,
client: client,
currentUserParticipated: currentUserParticipated,
count: count,
).toJson(),
);
}
@override

View File

@ -130,9 +130,52 @@ class Room {
for (final state in allStates) {
setState(state);
}
await _loadThreadsFromServer();
partial = false;
}
Future<void> _loadThreadsFromServer() async {
try {
final response = await client.getThreadRoots(id);
for (final threadEvent in response.chunk) {
final event = Event.fromMatrixEvent(threadEvent, this);
// Store thread in database
await client.database.storeThread(
id,
event,
event, // lastEvent
false, // currentUserParticipated
1, // count
client,
);
}
} catch (e) {
Logs().w('Failed to load threads from server', e);
}
}
Future<void> handleThreadSync(Event event) async {
// This should be called from the client's sync handling
// when a thread-related event is received
if (event.relationshipType == RelationshipTypes.thread && event.relationshipEventId != null) {
// Update thread metadata in database
final root = await getEventById(event.relationshipEventId!);
if (root == null) return;
await client.database.storeThread(
id,
root,
event, // update last event
event.senderId == client.userID, // currentUserParticipated
1, // increment count - should be calculated properly
client,
);
}
}
/// Returns the [Event] for the given [typeKey] and optional [stateKey].
/// If no [stateKey] is provided, it defaults to an empty string.
/// This returns either a `StrippedStateEvent` for rooms with membership
@ -174,6 +217,15 @@ class Room {
client.onRoomState.add((roomId: id, state: state));
}
Future<Map<String, Thread>> getThreads() async {
final dict = <String, Thread>{};
final list = await client.database.getThreadList(id, client);
for (final thread in list) {
dict[thread.rootEvent.eventId] = thread;
}
return dict;
}
/// ID of the fully read marker event.
String get fullyRead =>
roomAccountData['m.fully_read']?.content.tryGet<String>('event_id') ?? '';

View File

@ -36,7 +36,7 @@ class RoomTimeline extends Timeline {
StreamSubscription<SyncUpdate>? roomSub;
StreamSubscription<String>? sessionIdReceivedSub;
StreamSubscription<String>? cancelSendEventSub;
bool isRequestingHistory = false;
bool isRequestingFuture = false;
bool allowNewEvent = true;
@ -417,7 +417,7 @@ class RoomTimeline extends Timeline {
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};
@ -436,13 +436,16 @@ class RoomTimeline extends Timeline {
try {
if (event.roomId != room.id) return;
// This will be handled by ThreadTimeline
if (event.relationshipType == RelationshipTypes.thread) return;
if (type != EventUpdateType.timeline && type != EventUpdateType.history) {
return;
}
// Skip thread events in main timeline - THEY SHOULD ONLY APPEAR IN THREAD TIMELINES
if (event.relationshipType == RelationshipTypes.thread &&
event.relationshipEventId != null) {
unawaited(room.handleThreadSync(event));
}
if (type == EventUpdateType.timeline) {
onNewEvent?.call();
}
@ -641,4 +644,4 @@ class RoomTimeline extends Timeline {
e.matchesEventOrTransactionId(event.transactionId),
);
}
}
}

View File

@ -7,8 +7,8 @@ class Thread {
final Event rootEvent;
Event? lastEvent;
String? prev_batch;
bool currentUserParticipated;
int count;
bool? currentUserParticipated;
int? count;
final Client client;
Thread({

View File

@ -33,6 +33,8 @@ class ThreadTimeline extends Timeline {
bool allowNewEvent = true;
bool _collectHistoryUpdates = false;
bool isRequestingFuture = false;
ThreadTimeline({
required this.thread,
@ -367,14 +369,6 @@ class ThreadTimeline extends Timeline {
return i;
}
@override
// TODO: implement canRequestFuture
bool get canRequestFuture => throw UnimplementedError();
@override
// TODO: implement canRequestHistory
bool get canRequestHistory => throw UnimplementedError();
@override
void cancelSubscriptions() {
// TODO: implement cancelSubscriptions
@ -392,13 +386,6 @@ class ThreadTimeline extends Timeline {
return _eventCache[id];
}
@override
Future<void> requestFuture(
{int historyCount = Room.defaultHistoryCount, StateFilter? filter}) {
// TODO: implement requestFuture
throw UnimplementedError();
}
@override
Future<void> requestHistory(
{int historyCount = Room.defaultHistoryCount, StateFilter? filter}) async {
@ -412,12 +399,6 @@ class ThreadTimeline extends Timeline {
isRequestingHistory = false;
}
@override
void requestKeys(
{bool tryOnlineBackup = true, bool onlineKeyBackupOnly = true}) {
// TODO: implement requestKeys
}
@override
Future<void> setReadMarker({String? eventId, bool? public}) {
return thread.setReadMarker(
@ -438,4 +419,47 @@ class ThreadTimeline extends Timeline {
// TODO: implement startSearch
throw UnimplementedError();
}
@override
bool get canRequestFuture => chunk.nextBatch != null && chunk.nextBatch!.isNotEmpty;
@override
bool get canRequestHistory => chunk.prevBatch != null && chunk.prevBatch!.isNotEmpty;
@override
Future<void> requestFuture({
int historyCount = Room.defaultHistoryCount,
StateFilter? filter,
}) async {
if (isRequestingFuture || !canRequestFuture) return;
isRequestingFuture = true;
try {
await getThreadEvents(
historyCount: historyCount,
direction: Direction.f,
filter: filter,
);
} finally {
isRequestingFuture = false;
}
}
@override
void requestKeys({
bool tryOnlineBackup = true,
bool onlineKeyBackupOnly = true,
}) {
for (final event in events) {
if (event.type == EventTypes.Encrypted &&
event.messageType == MessageTypes.BadEncrypted &&
event.content['can_request_session'] == true) {
final sessionId = event.content.tryGet<String>('session_id');
final senderKey = event.content.tryGet<String>('sender_key');
if (sessionId != null && senderKey != null) {
thread.room.requestSessionKey(sessionId, senderKey);
}
}
}
}
}