diff --git a/lib/controllers/client_controller.dart b/lib/controllers/client_controller.dart index 537480e..6639de6 100644 --- a/lib/controllers/client_controller.dart +++ b/lib/controllers/client_controller.dart @@ -1,6 +1,7 @@ import "dart:developer"; import "dart:ffi"; import "dart:isolate"; +import "package:collection/collection.dart"; import "package:fast_immutable_collections/fast_immutable_collections.dart"; import "package:ffi/ffi.dart"; import "package:flutter/foundation.dart"; @@ -170,8 +171,12 @@ class ClientController extends AsyncNotifier { } Future getEvent(GetEventRequest request) async { - final json = await _sendCommand("get_event", request.toJson()); + final event = request.room.events.firstWhereOrNull( + (event) => event.eventId == request.eventId, + ); + if (event != null) return event; + final json = await _sendCommand("get_event", request.toJson()); return json == null ? null : Event.fromJson(json); } diff --git a/lib/controllers/message_controller.dart b/lib/controllers/message_controller.dart index dc93f0e..f0caea1 100644 --- a/lib/controllers/message_controller.dart +++ b/lib/controllers/message_controller.dart @@ -1,3 +1,4 @@ +import "package:collection/collection.dart"; import "package:flutter_chat_core/flutter_chat_core.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:nexus/controllers/client_controller.dart"; @@ -6,7 +7,6 @@ import "package:nexus/controllers/profile_controller.dart"; import "package:nexus/helpers/extensions/mxc_to_https.dart"; import "package:nexus/models/message_config.dart"; import "package:nexus/models/requests/get_event_request.dart"; -import "package:nexus/models/requests/get_related_events_request.dart"; class MessageController extends AsyncNotifier { final MessageConfig config; @@ -19,22 +19,20 @@ class MessageController extends AsyncNotifier { } final client = ref.watch(ClientController.provider.notifier); - final newEvents = await client.getRelatedEvents( - GetRelatedEventsRequest( - roomId: config.event.roomId, - eventId: config.event.eventId, - relationType: "m.replace", - ), - ); if (!ref.mounted) return null; - final event = newEvents?.lastOrNull ?? config.event; + final event = config.event.lastEditRowId == null + ? config.event + : config.room.events.firstWhereOrNull( + (e) => e.rowId == config.event.lastEditRowId, + ) ?? + config.event; final replyId = config.event.content["m.relates_to"]?["m.in_reply_to"]?["event_id"]; final replyEvent = replyId == null ? null : await client.getEvent( - GetEventRequest(roomId: config.event.roomId, eventId: replyId), + GetEventRequest(room: config.room, eventId: replyId), ); if (!ref.mounted) return null; @@ -58,7 +56,11 @@ class MessageController extends AsyncNotifier { if (replyEvent != null) "reply": await ref.watch( MessageController.provider( - MessageConfig(event: replyEvent, mustBeText: true), + MessageConfig( + event: replyEvent, + room: config.room, + mustBeText: true, + ), ).future, ), "body": newContent?["body"] ?? content["body"], @@ -152,21 +154,24 @@ class MessageController extends AsyncNotifier { ), _ => asText, }, - "m.room.member" => Message.system( - metadata: metadata, - id: config.event.eventId, - authorId: event.authorId, - deliveredAt: config.event.timestamp, - text: - "${content["displayname"] ?? event.stateKey} ${switch (content["membership"]) { - "invite" => "was invited to", - "join" => "joined", - "leave" => "left", - "knock" => "asked to join", - "ban" => "was banned from", - _ => "did something relating to", - }} the room.", - ), + "m.room.member" => + content["membership"] == event.unsigned["prev_content"]?["membership"] + ? null + : Message.system( + metadata: metadata, + id: config.event.eventId, + authorId: event.authorId, + deliveredAt: config.event.timestamp, + text: + "${content["displayname"] ?? event.stateKey} ${switch (content["membership"]) { + "invite" => "was invited to", + "join" => "joined", + "leave" => "left", + "knock" => "asked to join", + "ban" => "was banned from", + _ => "did something relating to", + }} the room.", + ), "m.room.redaction" => null, _ => // Turn this on for debugging purposes diff --git a/lib/controllers/messages_controller.dart b/lib/controllers/messages_controller.dart index 3edc8ab..83bd815 100644 --- a/lib/controllers/messages_controller.dart +++ b/lib/controllers/messages_controller.dart @@ -2,24 +2,26 @@ import "package:fast_immutable_collections/fast_immutable_collections.dart"; import "package:flutter_chat_core/flutter_chat_core.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:nexus/controllers/message_controller.dart"; -import "package:nexus/models/event.dart"; import "package:nexus/models/message_config.dart"; +import "package:nexus/models/messages_config.dart"; class MessagesController extends AsyncNotifier> { - final IList events; - MessagesController(this.events); + final MessagesConfig config; + MessagesController(this.config); @override Future> build() async => (await Future.wait( - events.map( + config.events.map( (event) => ref.watch( - MessageController.provider(MessageConfig(event: event)).future, + MessageController.provider( + MessageConfig(event: event, room: config.room), + ).future, ), ), )).nonNulls.toIList(); static final provider = AsyncNotifierProvider.family - .autoDispose, IList>( + .autoDispose, MessagesConfig>( MessagesController.new, ); } diff --git a/lib/controllers/room_chat_controller.dart b/lib/controllers/room_chat_controller.dart index 091cdc9..108a439 100644 --- a/lib/controllers/room_chat_controller.dart +++ b/lib/controllers/room_chat_controller.dart @@ -11,6 +11,7 @@ import "package:nexus/controllers/new_events_controller.dart"; import "package:nexus/controllers/rooms_controller.dart"; import "package:nexus/controllers/selected_room_controller.dart"; import "package:nexus/models/message_config.dart"; +import "package:nexus/models/messages_config.dart"; import "package:nexus/models/requests/get_room_state_request.dart"; import "package:nexus/models/requests/paginate_request.dart"; import "package:nexus/models/requests/redact_event_request.dart"; @@ -30,14 +31,17 @@ class RoomChatController extends AsyncNotifier { final messages = await ref.watch( MessagesController.provider( - room.timeline - .map( - (timelineRowTuple) => room.events.firstWhereOrNull( - (event) => event.rowId == timelineRowTuple.eventRowId, - ), - ) - .nonNulls - .toIList(), + MessagesConfig( + room: room, + events: room.timeline + .map( + (timelineRowTuple) => room.events.firstWhereOrNull( + (event) => event.rowId == timelineRowTuple.eventRowId, + ), + ) + .nonNulls + .toIList(), + ), ).future, ); final controller = InMemoryChatController(messages: messages.toList()); @@ -57,7 +61,7 @@ class RoomChatController extends AsyncNotifier { } else { final message = await ref.watch( MessageController.provider( - MessageConfig(event: event, includeEdits: true), + MessageConfig(event: event, room: room, includeEdits: true), ).future, ); if (event.relationType == "m.replace") { @@ -191,8 +195,13 @@ class RoomChatController extends AsyncNotifier { const ISet.empty(), ); + final room = ref.watch(RoomsController.provider)[roomId]; + if (room == null) return; + final messages = await ref.watch( - MessagesController.provider(response.events.reversed).future, + MessagesController.provider( + MessagesConfig(room: room, events: response.events.reversed), + ).future, ); await controller.insertAllMessages( messages diff --git a/lib/models/event.dart b/lib/models/event.dart index 623116b..c2f157f 100644 --- a/lib/models/event.dart +++ b/lib/models/event.dart @@ -27,7 +27,7 @@ abstract class Event with _$Event { String? decryptionError, String? sendError, @Default(IMap.empty()) IMap reactions, - int? lastEditRowId, + @JsonKey(name: "last_edit_rowid") int? lastEditRowId, @UnreadTypeConverter() UnreadType? unreadType, }) = _Event; diff --git a/lib/models/message_config.dart b/lib/models/message_config.dart index 4e5ff71..4f3abf3 100644 --- a/lib/models/message_config.dart +++ b/lib/models/message_config.dart @@ -1,5 +1,6 @@ import "package:freezed_annotation/freezed_annotation.dart"; import "package:nexus/models/event.dart"; +import "package:nexus/models/room.dart"; part "message_config.freezed.dart"; part "message_config.g.dart"; @@ -8,6 +9,7 @@ abstract class MessageConfig with _$MessageConfig { const factory MessageConfig({ @Default(false) bool mustBeText, @Default(false) bool includeEdits, + required Room room, required Event event, }) = _MessageConfig; diff --git a/lib/models/messages_config.dart b/lib/models/messages_config.dart new file mode 100644 index 0000000..b33a71c --- /dev/null +++ b/lib/models/messages_config.dart @@ -0,0 +1,17 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:freezed_annotation/freezed_annotation.dart"; +import "package:nexus/models/event.dart"; +import "package:nexus/models/room.dart"; +part "messages_config.freezed.dart"; +part "messages_config.g.dart"; + +@freezed +abstract class MessagesConfig with _$MessagesConfig { + const factory MessagesConfig({ + required Room room, + required IList events, + }) = _MessagesConfig; + + factory MessagesConfig.fromJson(Map json) => + _$MessagesConfigFromJson(json); +} diff --git a/lib/models/requests/get_event_request.dart b/lib/models/requests/get_event_request.dart index 3812d50..d599225 100644 --- a/lib/models/requests/get_event_request.dart +++ b/lib/models/requests/get_event_request.dart @@ -1,11 +1,12 @@ import "package:freezed_annotation/freezed_annotation.dart"; +import "package:nexus/models/room.dart"; part "get_event_request.freezed.dart"; part "get_event_request.g.dart"; @freezed abstract class GetEventRequest with _$GetEventRequest { const factory GetEventRequest({ - required String roomId, + required Room room, required String eventId, @Default(false) bool unredact, }) = _GetEventRequest;