forked from Henry-Hiles/nexus
working message rendering
This commit is contained in:
parent
a28bced44d
commit
7c76bb6e66
20 changed files with 305 additions and 197 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import "dart:developer";
|
||||
import "dart:ffi";
|
||||
import "dart:isolate";
|
||||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||
import "package:ffi/ffi.dart";
|
||||
import "package:flutter/foundation.dart";
|
||||
import "package:nexus/controllers/client_state_controller.dart";
|
||||
|
|
@ -10,8 +11,12 @@ import "package:nexus/controllers/sync_status_controller.dart";
|
|||
import "package:nexus/controllers/top_level_spaces_controller.dart";
|
||||
import "package:nexus/helpers/extensions/gomuks_buffer.dart";
|
||||
import "package:nexus/models/client_state.dart";
|
||||
import "package:nexus/models/login.dart";
|
||||
import "package:nexus/models/report.dart";
|
||||
import "package:nexus/models/event.dart";
|
||||
import "package:nexus/models/get_event_request.dart";
|
||||
import "package:nexus/models/get_related_events_request.dart";
|
||||
import "package:nexus/models/login_request.dart";
|
||||
import "package:nexus/models/profile.dart";
|
||||
import "package:nexus/models/report_request.dart";
|
||||
import "package:nexus/models/room.dart";
|
||||
import "package:nexus/models/sync_data.dart";
|
||||
import "package:nexus/models/sync_status.dart";
|
||||
|
|
@ -34,7 +39,7 @@ class ClientController extends AsyncNotifier<int> {
|
|||
try {
|
||||
final muksEventType = command.cast<Utf8>().toDartString();
|
||||
debugPrint("Handling $muksEventType...");
|
||||
final Map<String, dynamic> decodedMuksEvent = data.toJson();
|
||||
final decodedMuksEvent = data.toJson();
|
||||
|
||||
switch (muksEventType) {
|
||||
case "client_state":
|
||||
|
|
@ -92,10 +97,7 @@ class ClientController extends AsyncNotifier<int> {
|
|||
throw Exception("GomuksStart returned error code $errorCode");
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> sendCommand(
|
||||
String command,
|
||||
Map<String, dynamic> data,
|
||||
) async {
|
||||
Future<dynamic> sendCommand(String command, Map<String, dynamic> data) async {
|
||||
final bufferPointer = data.toGomuksBufferPtr();
|
||||
final handle = await future;
|
||||
final response = await Isolate.run(
|
||||
|
|
@ -125,7 +127,27 @@ class ClientController extends AsyncNotifier<int> {
|
|||
await sendCommand("leave_room", {"room_id": room.metadata!.id});
|
||||
}
|
||||
|
||||
Future<void> reportEvent(Report report) =>
|
||||
Future<IList<Event>?> getRelatedEvents(
|
||||
GetRelatedEventsRequest request,
|
||||
) async {
|
||||
final response =
|
||||
(await sendCommand("get_related_events", request.toJson())) as List?;
|
||||
return response?.map((event) => Event.fromJson(event)).toIList();
|
||||
}
|
||||
|
||||
Future<Event?> getEvent(GetEventRequest request) async {
|
||||
final json = await sendCommand("get_event", request.toJson());
|
||||
|
||||
return json == null ? null : Event.fromJson(json);
|
||||
}
|
||||
|
||||
Future<Profile?> getProfile(String userId) async {
|
||||
final json = await sendCommand("get_profile", {"user_id": userId});
|
||||
|
||||
return json == null ? null : Profile.fromJson(json);
|
||||
}
|
||||
|
||||
Future<void> reportEvent(ReportRequest report) =>
|
||||
sendCommand("report_event", report.toJson());
|
||||
|
||||
Future<void> markRead(Room room) async {
|
||||
|
|
@ -137,7 +159,7 @@ class ClientController extends AsyncNotifier<int> {
|
|||
});
|
||||
}
|
||||
|
||||
Future<bool> login(Login login) async {
|
||||
Future<bool> login(LoginRequest login) async {
|
||||
try {
|
||||
await sendCommand("login", login.toJson());
|
||||
return true;
|
||||
|
|
@ -151,7 +173,7 @@ class ClientController extends AsyncNotifier<int> {
|
|||
final response = await sendCommand("discover_homeserver", {
|
||||
"user_id": "@fakeuser:${homeserver.host}",
|
||||
});
|
||||
return (response["m.homeserver"] as Map<String, dynamic>)["base_url"];
|
||||
return response["m.homeserver"]?["base_url"];
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||
import "package:matrix/matrix.dart";
|
||||
|
||||
class EventsController extends AsyncNotifier<Timeline> {
|
||||
EventsController(this.room);
|
||||
final Room room;
|
||||
|
||||
@override
|
||||
Future<Timeline> build({String? from}) => room.getTimeline();
|
||||
|
||||
Future<void> prev() async {
|
||||
final timeline = await future;
|
||||
await timeline.requestHistory();
|
||||
}
|
||||
|
||||
static final provider = AsyncNotifierProvider.autoDispose
|
||||
.family<EventsController, Timeline, Room>(EventsController.new);
|
||||
}
|
||||
18
lib/controllers/new_events_controller.dart
Normal file
18
lib/controllers/new_events_controller.dart
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||
import "package:nexus/models/event.dart";
|
||||
|
||||
class NewEventsController extends Notifier<IList<Event>> {
|
||||
final String roomId;
|
||||
NewEventsController(this.roomId);
|
||||
|
||||
@override
|
||||
IList<Event> build() => const IList.empty();
|
||||
|
||||
void add(IList<Event> newEvents) => state = newEvents;
|
||||
|
||||
static final provider = NotifierProvider.autoDispose
|
||||
.family<NewEventsController, IList<Event>, String>(
|
||||
NewEventsController.new,
|
||||
);
|
||||
}
|
||||
|
|
@ -1,65 +1,72 @@
|
|||
import "package:collection/collection.dart";
|
||||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||
import "package:flutter_chat_core/flutter_chat_core.dart";
|
||||
import "package:flutter_chat_core/flutter_chat_core.dart" as chat;
|
||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||
import "package:fluttertagger/fluttertagger.dart" as tagger;
|
||||
import "package:nexus/controllers/client_controller.dart";
|
||||
import "package:nexus/controllers/new_events_controller.dart";
|
||||
import "package:nexus/controllers/selected_room_controller.dart";
|
||||
import "package:nexus/helpers/extensions/event_to_message.dart";
|
||||
import "package:nexus/helpers/extensions/list_to_messages.dart";
|
||||
import "package:nexus/models/relation_type.dart";
|
||||
import "package:nexus/models/room.dart";
|
||||
|
||||
class RoomChatController extends AsyncNotifier<ChatController> {
|
||||
final Room room;
|
||||
RoomChatController(this.room);
|
||||
final String roomId;
|
||||
RoomChatController(this.roomId);
|
||||
|
||||
@override
|
||||
Future<ChatController> build() async {
|
||||
// final timeline = await ref.watch(EventsController.provider(room).future);
|
||||
final client = ref.watch(ClientController.provider.notifier);
|
||||
final events =
|
||||
ref.read(SelectedRoomController.provider)?.events ??
|
||||
const IList.empty();
|
||||
|
||||
return InMemoryChatController();
|
||||
ref.onDispose(
|
||||
ref.listen(NewEventsController.provider(roomId), (_, next) async {
|
||||
for (final event in next) {
|
||||
if (event.type == "m.room.redaction") {
|
||||
final controller = await future;
|
||||
final message = controller.messages.firstWhereOrNull(
|
||||
(message) => message.id == event.content["redacts"],
|
||||
);
|
||||
if (message == null) return;
|
||||
|
||||
// ref.onDispose(
|
||||
// room.client.onTimelineEvent.stream.listen((event) async {
|
||||
// if (event.roomId != room.metadata.id) return;
|
||||
await controller.removeMessage(message);
|
||||
} else {
|
||||
final message = await event.toMessage(client, includeEdits: true);
|
||||
if (event.relationType == "m.replace") {
|
||||
final controller = await future;
|
||||
final oldMessage = controller.messages.firstWhereOrNull(
|
||||
(element) => element.id == event.relatesTo,
|
||||
);
|
||||
if (oldMessage == null || message == null) return;
|
||||
|
||||
// if (event.type == "m.room.redaction") {
|
||||
// final controller = await future;
|
||||
// final message = controller.messages.firstWhereOrNull(
|
||||
// (message) => message.id == event.redacts,
|
||||
// );
|
||||
// if (message == null) return;
|
||||
return await updateMessage(
|
||||
oldMessage,
|
||||
message.copyWith(
|
||||
id: oldMessage.id,
|
||||
replyToMessageId: oldMessage.replyToMessageId,
|
||||
metadata: {
|
||||
...(oldMessage.metadata ?? {}),
|
||||
...(message.metadata ?? {})
|
||||
.toIMap()
|
||||
.where((key, value) => value != null)
|
||||
.unlock,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
if (message != null) {
|
||||
return await insertMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).close,
|
||||
);
|
||||
|
||||
// await controller.removeMessage(message);
|
||||
// } else {
|
||||
// final message = await event.toMessage(includeEdits: true, timeline);
|
||||
// if (event.relationshipType == RelationshipTypes.edit) {
|
||||
// final controller = await future;
|
||||
// final oldMessage = controller.messages.firstWhereOrNull(
|
||||
// (element) => element.id == event.relationshipEventId,
|
||||
// );
|
||||
// if (oldMessage == null || message == null) return;
|
||||
// return await updateMessage(
|
||||
// oldMessage,
|
||||
// message.copyWith(
|
||||
// id: oldMessage.id,
|
||||
// replyToMessageId: oldMessage.replyToMessageId,
|
||||
// metadata: {
|
||||
// ...(oldMessage.metadata ?? {}),
|
||||
// ...((message.metadata ?? {}).filterMap(
|
||||
// (key, value) => value == null ? null : MapEntry(key, value),
|
||||
// )),
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// if (message != null) {
|
||||
// return await insertMessage(message);
|
||||
// }
|
||||
// }
|
||||
// }).cancel,
|
||||
// );
|
||||
|
||||
// return InMemoryChatController(
|
||||
// messages: await timeline.events.toMessages(room, timeline),
|
||||
// );
|
||||
final messages = await events.toMessages(client);
|
||||
return InMemoryChatController(messages: messages);
|
||||
}
|
||||
|
||||
Future<void> insertMessage(Message message) async {
|
||||
|
|
@ -145,8 +152,8 @@ class RoomChatController extends AsyncNotifier<ChatController> {
|
|||
);
|
||||
}
|
||||
|
||||
static final provider = AsyncNotifierProvider.family
|
||||
.autoDispose<RoomChatController, ChatController, Room>(
|
||||
static final provider =
|
||||
AsyncNotifierProvider.family<RoomChatController, ChatController, String>(
|
||||
RoomChatController.new,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||
import "package:nexus/controllers/new_events_controller.dart";
|
||||
import "package:nexus/models/read_receipt.dart";
|
||||
import "package:nexus/models/room.dart";
|
||||
|
||||
|
|
@ -13,11 +14,18 @@ class RoomsController extends Notifier<IMap<String, Room>> {
|
|||
final incoming = entry.value;
|
||||
final existing = acc[roomId];
|
||||
|
||||
ref
|
||||
.watch(NewEventsController.provider(roomId).notifier)
|
||||
.add(incoming.events);
|
||||
|
||||
return acc.add(
|
||||
roomId,
|
||||
existing?.copyWith(
|
||||
metadata: incoming.metadata ?? existing.metadata,
|
||||
events: existing.events.addAll(incoming.events),
|
||||
events: existing.events.updateById(
|
||||
incoming.events,
|
||||
(item) => item.eventId,
|
||||
),
|
||||
state: incoming.state.entries.fold(
|
||||
existing.state,
|
||||
(stateAcc, event) => stateAcc.add(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue