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<List<Thread>> getThreadList(String roomId, Client client);
|
||||||
|
|
||||||
|
Future<Thread?> getThread(String roomId, String threadRootEventId, Client client);
|
||||||
|
|
||||||
Future<void> storeThread(
|
Future<void> storeThread(
|
||||||
String roomId,
|
String roomId,
|
||||||
Event threadRootEvent,
|
Event threadRootEvent,
|
||||||
|
|
|
||||||
|
|
@ -1368,18 +1368,34 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
|
||||||
@override
|
@override
|
||||||
Future<List<Thread>> getThreadList(String roomId, Client client) async {
|
Future<List<Thread>> getThreadList(String roomId, Client client) async {
|
||||||
final allThreadsKeys = await _threadsBox.getAllKeys();
|
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>{};
|
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();
|
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
|
@override
|
||||||
Future<void> storeThread(
|
Future<void> storeThread(
|
||||||
String roomId,
|
String roomId,
|
||||||
|
|
@ -1396,10 +1412,12 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
|
||||||
Thread(
|
Thread(
|
||||||
room: Room(id: roomId, client: client),
|
room: Room(id: roomId, client: client),
|
||||||
rootEvent: threadRootEvent,
|
rootEvent: threadRootEvent,
|
||||||
|
lastEvent: lastEvent,
|
||||||
client: client,
|
client: client,
|
||||||
currentUserParticipated: currentUserParticipated,
|
currentUserParticipated: currentUserParticipated,
|
||||||
count: count,
|
count: count,
|
||||||
).toJson());
|
).toJson(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -130,9 +130,52 @@ class Room {
|
||||||
for (final state in allStates) {
|
for (final state in allStates) {
|
||||||
setState(state);
|
setState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await _loadThreadsFromServer();
|
||||||
|
|
||||||
partial = false;
|
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].
|
/// Returns the [Event] for the given [typeKey] and optional [stateKey].
|
||||||
/// If no [stateKey] is provided, it defaults to an empty string.
|
/// If no [stateKey] is provided, it defaults to an empty string.
|
||||||
/// This returns either a `StrippedStateEvent` for rooms with membership
|
/// This returns either a `StrippedStateEvent` for rooms with membership
|
||||||
|
|
@ -174,6 +217,15 @@ class Room {
|
||||||
client.onRoomState.add((roomId: id, state: state));
|
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.
|
/// ID of the fully read marker event.
|
||||||
String get fullyRead =>
|
String get fullyRead =>
|
||||||
roomAccountData['m.fully_read']?.content.tryGet<String>('event_id') ?? '';
|
roomAccountData['m.fully_read']?.content.tryGet<String>('event_id') ?? '';
|
||||||
|
|
|
||||||
|
|
@ -436,13 +436,16 @@ class RoomTimeline extends Timeline {
|
||||||
try {
|
try {
|
||||||
if (event.roomId != room.id) return;
|
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) {
|
if (type != EventUpdateType.timeline && type != EventUpdateType.history) {
|
||||||
return;
|
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) {
|
if (type == EventUpdateType.timeline) {
|
||||||
onNewEvent?.call();
|
onNewEvent?.call();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ class Thread {
|
||||||
final Event rootEvent;
|
final Event rootEvent;
|
||||||
Event? lastEvent;
|
Event? lastEvent;
|
||||||
String? prev_batch;
|
String? prev_batch;
|
||||||
bool currentUserParticipated;
|
bool? currentUserParticipated;
|
||||||
int count;
|
int? count;
|
||||||
final Client client;
|
final Client client;
|
||||||
|
|
||||||
Thread({
|
Thread({
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ class ThreadTimeline extends Timeline {
|
||||||
|
|
||||||
bool _collectHistoryUpdates = false;
|
bool _collectHistoryUpdates = false;
|
||||||
|
|
||||||
|
bool isRequestingFuture = false;
|
||||||
|
|
||||||
ThreadTimeline({
|
ThreadTimeline({
|
||||||
required this.thread,
|
required this.thread,
|
||||||
required this.chunk,
|
required this.chunk,
|
||||||
|
|
@ -367,14 +369,6 @@ class ThreadTimeline extends Timeline {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
// TODO: implement canRequestFuture
|
|
||||||
bool get canRequestFuture => throw UnimplementedError();
|
|
||||||
|
|
||||||
@override
|
|
||||||
// TODO: implement canRequestHistory
|
|
||||||
bool get canRequestHistory => throw UnimplementedError();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void cancelSubscriptions() {
|
void cancelSubscriptions() {
|
||||||
// TODO: implement cancelSubscriptions
|
// TODO: implement cancelSubscriptions
|
||||||
|
|
@ -392,13 +386,6 @@ class ThreadTimeline extends Timeline {
|
||||||
return _eventCache[id];
|
return _eventCache[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> requestFuture(
|
|
||||||
{int historyCount = Room.defaultHistoryCount, StateFilter? filter}) {
|
|
||||||
// TODO: implement requestFuture
|
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> requestHistory(
|
Future<void> requestHistory(
|
||||||
{int historyCount = Room.defaultHistoryCount, StateFilter? filter}) async {
|
{int historyCount = Room.defaultHistoryCount, StateFilter? filter}) async {
|
||||||
|
|
@ -412,12 +399,6 @@ class ThreadTimeline extends Timeline {
|
||||||
isRequestingHistory = false;
|
isRequestingHistory = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void requestKeys(
|
|
||||||
{bool tryOnlineBackup = true, bool onlineKeyBackupOnly = true}) {
|
|
||||||
// TODO: implement requestKeys
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> setReadMarker({String? eventId, bool? public}) {
|
Future<void> setReadMarker({String? eventId, bool? public}) {
|
||||||
return thread.setReadMarker(
|
return thread.setReadMarker(
|
||||||
|
|
@ -438,4 +419,47 @@ class ThreadTimeline extends Timeline {
|
||||||
// TODO: implement startSearch
|
// TODO: implement startSearch
|
||||||
throw UnimplementedError();
|
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