did something
This commit is contained in:
parent
0fb0a6c47f
commit
74c39f91fe
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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') ?? '';
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue