diff --git a/lib/controllers/room_chat.dart b/lib/controllers/room_chat.dart index 4043922..35dee48 100644 --- a/lib/controllers/room_chat.dart +++ b/lib/controllers/room_chat.dart @@ -17,7 +17,7 @@ import "package:nexus/models/requests/send_message.dart"; import "package:nexus/models/room.dart"; import "package:nexus/models/room_chat.dart"; -class RoomChatController(final (String roomId, String? withEventId) info) +class RoomChatController(final (String roomId, String? contextualEvent) info) extends AsyncNotifier { @override Future build() async { @@ -34,31 +34,47 @@ class RoomChatController(final (String roomId, String? withEventId) info) await ref.read(RoomsController.provider.notifier).addState(roomId, state); } - return .new( - events: room.timeline - .toEntryIList(compare: (a, b) => (a?.key ?? 0).compareTo(b?.key ?? 0)) - .map((element) => element.value) - .toIList() - .addAll(room.clientSticky) - .map((entry) { - final foundEvent = entry == null ? null : room.events[entry]; + if (info.$2 == null || + room.events.values.map((e) => e.eventId).contains(info.$2)) { + return .new( + events: room.timeline + .toEntryIList( + compare: (a, b) => (a?.key ?? 0).compareTo(b?.key ?? 0), + ) + .map((element) => element.value) + .toIList() + .addAll(room.clientSticky) + .map((entry) { + final foundEvent = entry == null ? null : room.events[entry]; - final editedEvent = - foundEvent == null || foundEvent.lastEditRowId == 0 - ? null - : room.events[foundEvent.lastEditRowId]; + final editedEvent = + foundEvent == null || foundEvent.lastEditRowId == 0 + ? null + : room.events[foundEvent.lastEditRowId]; - return editedEvent == null - ? foundEvent - : foundEvent?.copyWith( - content: editedEvent.content, - localContent: editedEvent.localContent, - ); - }) - .nonNulls - .toIList(), - hasMore: room.hasMore, - ); + return editedEvent == null + ? foundEvent + : foundEvent?.copyWith( + content: editedEvent.content, + localContent: editedEvent.localContent, + ); + }) + .nonNulls + .toIList(), + hasMore: room.hasMore, + ); + } + { + final context = await client.getEventContext( + .new(roomId: roomId, eventId: info.$2!, limit: 20), + ); + + return .new( + events: context.events, + hasMore: true, + historicalData: .new(start: context.start, end: context.end), + ); + } } Future deleteMessage(Event event, {String? reason}) => ref diff --git a/lib/helpers/hooks/chat_scroll.dart b/lib/helpers/hooks/chat_scroll.dart index 9efd3b2..6420726 100644 --- a/lib/helpers/hooks/chat_scroll.dart +++ b/lib/helpers/hooks/chat_scroll.dart @@ -92,19 +92,14 @@ final class ChatScroll({ (item) => item.eventId == itemId, ); + double? offset; if (historyIndex != -1) { // TODO: Replace SuperSliverView because of the bug that requires this: #94 // ignore: invalid_use_of_visible_for_testing_member - final offset = historyListController.value.getOffsetToReveal( + offset = historyListController.value.getOffsetToReveal( historyIndex, 0.5, ); - - await scrollController.animateTo( - offset, - duration: const Duration(milliseconds: 700), - curve: Curves.easeInOut, - ); } else { final liveIndex = split.live.indexWhere( (item) => item.eventId == itemId, @@ -112,18 +107,21 @@ final class ChatScroll({ if (liveIndex != -1) { // ignore: invalid_use_of_visible_for_testing_member - final offset = liveListController.value.getOffsetToReveal( - liveIndex, - 0.5, - ); - - await scrollController.animateTo( - offset, - duration: const Duration(milliseconds: 700), - curve: Curves.easeInOut, - ); + offset = liveListController.value.getOffsetToReveal(liveIndex, 0.5); } } + + if (offset == null) { + // not in current timeline + } + + if (offset != null) { + await scrollController.animateTo( + offset, + duration: const Duration(milliseconds: 700), + curve: Curves.easeInOut, + ); + } } return .new( diff --git a/lib/models/room.dart b/lib/models/room.dart index 6d7553f..96b29b4 100644 --- a/lib/models/room.dart +++ b/lib/models/room.dart @@ -12,17 +12,26 @@ part "room.g.dart"; class const Room({ @JsonKey(name: "meta") final RoomMetadata? metadata, + /// [timeline] is an IMap of timelineRowId to eventRowId @JsonKey(fromJson: Room.timelineTupleJsonToIMap) final IMap timeline = const IMap.empty(), + /// [clientSticky] is an ISet of eventRowId + @JsonKey(includeFromJson: false, includeToJson: false) final ISet clientSticky = const ISet.empty(), + /// [events] is an IMap of eventRowId to event @JsonKey(fromJson: Room.eventsJsonToIMap) final IMap events = const IMap.empty(), final bool reset = false, + + @JsonKey(includeFromJson: false, includeToJson: false) final bool hasFetchedState = false, + + @JsonKey(includeFromJson: false, includeToJson: false) final bool hasFetchedMembers = false, + final IMap> state = const IMap.empty(), final IMap> receipts = const IMap.empty(), @@ -32,9 +41,6 @@ class const Room({ // IMap accountData, // IList notifications, }) with _$Room { - /// [timeline] is an IMap of timelineRowId to eventRowId - /// [events] is an IMap of eventRowId to event - /// [clientSticky] is an ISet of eventRowId static IMap timelineTupleJsonToIMap(List json) => IMap.fromEntries( json.map( diff --git a/lib/models/room_chat.dart b/lib/models/room_chat.dart index e952d42..ca9799c 100644 --- a/lib/models/room_chat.dart +++ b/lib/models/room_chat.dart @@ -21,8 +21,8 @@ class const RoomChat({ @Freezed(toJson: false, fromJson: false) @JsonSerializable() class const HistoricalData({ - required final String end, required final String start, + required final String end, }) with _$HistoricalData { Map toJson() => _$HistoricalDataToJson(this); diff --git a/lib/widgets/room_chat/room_chat.dart b/lib/widgets/room_chat/room_chat.dart index 186b2a6..2aee4a5 100644 --- a/lib/widgets/room_chat/room_chat.dart +++ b/lib/widgets/room_chat/room_chat.dart @@ -31,6 +31,7 @@ final class const RoomChat({ Widget build(BuildContext context, WidgetRef ref) { final relatedEvent = useState(null); final relationType = useState(RelationType.reply); + final contextualEvent = useState(initialHighlightedEvent); final highlightedEvent = useState(initialHighlightedEvent); final composerSize = useState(64); @@ -62,7 +63,7 @@ final class const RoomChat({ final controllerProvider = RoomChatController.provider(( roomId, - initialHighlightedEvent, + contextualEvent.value, )); final notifier = ref.watch(controllerProvider.notifier);