parent
427e06be3e
commit
a54004736b
5 changed files with 427 additions and 143 deletions
|
|
@ -41,6 +41,7 @@ import "package:nexus/models/requests/paginate_manual.dart";
|
|||
import "package:nexus/models/requests/redact_event.dart";
|
||||
import "package:nexus/models/requests/register_pusher.dart";
|
||||
import "package:nexus/models/requests/report.dart";
|
||||
import "package:nexus/models/requests/search.dart";
|
||||
import "package:nexus/models/requests/send_event.dart";
|
||||
import "package:nexus/models/requests/send_message.dart";
|
||||
import "package:nexus/models/requests/set_account_data.dart";
|
||||
|
|
@ -276,6 +277,12 @@ class ClientController extends AsyncNotifier<int> {
|
|||
Future<PaginateManual> paginateManual(PaginateManualRequest request) async =>
|
||||
.fromJson(await _sendCommand("paginate_manual", request.toJson()));
|
||||
|
||||
Future<PaginateManual> searchLocal(SearchRequest request) async =>
|
||||
.fromJson(await _sendCommand("search_local", request.toJson()));
|
||||
|
||||
Future<PaginateManual> searchServer(SearchRequest request) async =>
|
||||
.fromJson(await _sendCommand("search_server", request.toJson()));
|
||||
|
||||
Future<EventContext> getEventContext(GetEventContextRequest request) async =>
|
||||
.fromJson(await _sendCommand("get_event_context", request.toJson()));
|
||||
|
||||
|
|
|
|||
97
lib/controllers/event_search.dart
Normal file
97
lib/controllers/event_search.dart
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||
import "package:nexus/controllers/client.dart";
|
||||
import "package:nexus/controllers/rooms.dart";
|
||||
import "package:nexus/models/requests/search.dart";
|
||||
|
||||
typedef EventSearchParams = ({String roomId, String query});
|
||||
typedef EventSearchResults = ({IList<int> rowIds, String? nextBatch});
|
||||
|
||||
class EventSearchController(final EventSearchParams info)
|
||||
extends AsyncNotifier<EventSearchResults> {
|
||||
// We could have a mode without this for power users in the future
|
||||
static String toFtsQuery(String query) => query
|
||||
.split(RegExp(r"\s+"))
|
||||
.where((word) => word.isNotEmpty)
|
||||
.map((word) => '"${word.replaceAll('"', '""')}"*')
|
||||
.join(" ");
|
||||
|
||||
@override
|
||||
Future<EventSearchResults> build() async {
|
||||
if (info.query.trim().isEmpty) {
|
||||
return (rowIds: IList<int>(), nextBatch: null);
|
||||
}
|
||||
|
||||
final client = ref.read(ClientController.provider.notifier);
|
||||
|
||||
final encrypted = ref.read(
|
||||
RoomsController.provider.select(
|
||||
(rooms) => rooms[info.roomId]?.metadata?.encryptionEvent != null,
|
||||
),
|
||||
);
|
||||
final request = SearchRequest(
|
||||
searchTerm: encrypted ? toFtsQuery(info.query) : info.query,
|
||||
roomIds: .new([info.roomId]),
|
||||
);
|
||||
final response = encrypted
|
||||
? await client.searchLocal(request)
|
||||
: await client.searchServer(request);
|
||||
|
||||
if (!ref.mounted) return (rowIds: IList<int>(), nextBatch: null);
|
||||
|
||||
ref
|
||||
.read(RoomsController.provider.notifier)
|
||||
.storeEvents(response.events.addAll(response.relatedEvents));
|
||||
|
||||
return (
|
||||
rowIds: response.events.map((event) => event.rowId).toIList(),
|
||||
nextBatch: response.nextBatch,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> paginate() async {
|
||||
if (state.isLoading) return;
|
||||
|
||||
final results = await future;
|
||||
if (!ref.mounted || results.nextBatch == null) return;
|
||||
|
||||
state = .loading();
|
||||
|
||||
final encrypted = ref.read(
|
||||
RoomsController.provider.select(
|
||||
(rooms) => rooms[info.roomId]?.metadata?.encryptionEvent != null,
|
||||
),
|
||||
);
|
||||
|
||||
final request = SearchRequest(
|
||||
searchTerm: encrypted ? toFtsQuery(info.query) : info.query,
|
||||
roomIds: .new([info.roomId]),
|
||||
nextBatch: results.nextBatch,
|
||||
);
|
||||
|
||||
final client = ref.read(ClientController.provider.notifier);
|
||||
final response = encrypted
|
||||
? await client.searchLocal(request)
|
||||
: await client.searchServer(request);
|
||||
|
||||
if (!ref.mounted) return;
|
||||
|
||||
ref
|
||||
.read(RoomsController.provider.notifier)
|
||||
.storeEvents(response.events.addAll(response.relatedEvents));
|
||||
|
||||
state = .data((
|
||||
rowIds: results.rowIds.addAll(
|
||||
response.events.map((event) => event.rowId),
|
||||
),
|
||||
nextBatch: response.nextBatch,
|
||||
));
|
||||
}
|
||||
|
||||
static final provider = AsyncNotifierProvider.family
|
||||
.autoDispose<
|
||||
EventSearchController,
|
||||
EventSearchResults,
|
||||
EventSearchParams
|
||||
>(EventSearchController.new);
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
import "package:collection/collection.dart";
|
||||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||
import "package:nexus/controllers/client.dart";
|
||||
|
|
@ -9,26 +8,6 @@ typedef NotificationsRequest = (UnreadType? unreadType, String? roomId);
|
|||
|
||||
class NotificationsController(final NotificationsRequest request)
|
||||
extends AsyncNotifier<IList<(int, String)>> {
|
||||
void storeEvents(Iterable<Event> events) => ref
|
||||
.read(RoomsController.provider.notifier)
|
||||
.update(
|
||||
.new(
|
||||
events
|
||||
.groupListsBy((event) => event.roomId)
|
||||
.map(
|
||||
(roomId, roomEvents) => .new(
|
||||
roomId,
|
||||
.new(
|
||||
events: IMap.fromIterable(
|
||||
roomEvents,
|
||||
keyMapper: (event) => event.rowId,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
Future<IList<(int, String)>> build() async {
|
||||
final client = ref.read(ClientController.provider.notifier);
|
||||
|
|
@ -43,7 +22,9 @@ class NotificationsController(final NotificationsRequest request)
|
|||
),
|
||||
);
|
||||
|
||||
storeEvents(mentions.events.addAll(mentions.relatedEvents));
|
||||
ref
|
||||
.read(RoomsController.provider.notifier)
|
||||
.storeEvents(mentions.events.addAll(mentions.relatedEvents));
|
||||
|
||||
return .new(mentions.events.map((event) => (event.rowId, event.roomId)));
|
||||
}
|
||||
|
|
@ -76,9 +57,11 @@ class NotificationsController(final NotificationsRequest request)
|
|||
),
|
||||
);
|
||||
|
||||
storeEvents(
|
||||
newNotifications.events.addAll(newNotifications.relatedEvents),
|
||||
);
|
||||
ref
|
||||
.read(RoomsController.provider.notifier)
|
||||
.storeEvents(
|
||||
newNotifications.events.addAll(newNotifications.relatedEvents),
|
||||
);
|
||||
|
||||
return currentNotifications.addAll(
|
||||
newNotifications.events.map((event) => (event.rowId, event.roomId)),
|
||||
|
|
|
|||
|
|
@ -73,16 +73,7 @@ class RoomChatController(final ChatParams info)
|
|||
.addAll(context.after);
|
||||
ref
|
||||
.read(RoomsController.provider.notifier)
|
||||
.update(
|
||||
.new({
|
||||
info.roomId: Room(
|
||||
events: IMap.fromIterable(
|
||||
events.addAll(context.relatedEvents),
|
||||
keyMapper: (event) => event.rowId,
|
||||
),
|
||||
),
|
||||
}),
|
||||
);
|
||||
.storeEvents(events.addAll(context.relatedEvents));
|
||||
return .new(
|
||||
timeline: .new(events.map((element) => element.rowId)),
|
||||
hasMoreBackward: true,
|
||||
|
|
@ -186,17 +177,8 @@ class RoomChatController(final ChatParams info)
|
|||
|
||||
ref
|
||||
.read(RoomsController.provider.notifier)
|
||||
.update(
|
||||
.new({
|
||||
info.roomId: Room(
|
||||
events: IMap.fromIterable(
|
||||
paginationResponse.events.addAll(
|
||||
paginationResponse.relatedEvents,
|
||||
),
|
||||
keyMapper: (event) => event.rowId,
|
||||
),
|
||||
),
|
||||
}),
|
||||
.storeEvents(
|
||||
paginationResponse.events.addAll(paginationResponse.relatedEvents),
|
||||
);
|
||||
|
||||
final eventRowIds =
|
||||
|
|
|
|||
|
|
@ -33,6 +33,26 @@ class RoomsController extends Notifier<IMap<String, Room>> {
|
|||
.new(),
|
||||
);
|
||||
|
||||
/// Adds events to their rooms, without changing the rooms' timelines.
|
||||
void storeEvents(Iterable<Event> events) => update(
|
||||
.new(
|
||||
events
|
||||
.groupListsBy((event) => event.roomId)
|
||||
.map(
|
||||
(roomId, roomEvents) => .new(
|
||||
roomId,
|
||||
Room(
|
||||
// ignore: unused_result - I am using it you donkey
|
||||
events: .fromIterable(
|
||||
roomEvents,
|
||||
keyMapper: (event) => event.rowId,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
void update(
|
||||
IMap<String, Room> rooms, [
|
||||
ISet<String> leftRooms = const .empty(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue