jump to pinned events in view

This commit is contained in:
Henry Hiles 2026-07-14 23:00:48 +00:00
commit f6da59ad40
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
2 changed files with 45 additions and 33 deletions

View file

@ -9,8 +9,14 @@ import "package:nexus/widgets/renderers/event.dart";
class PinnedEventsDrawer extends HookConsumerWidget { class PinnedEventsDrawer extends HookConsumerWidget {
final String roomId; final String roomId;
final IList<PopupMenuEntry> Function(Event event)? getEventOptions; final IList<PopupMenuEntry> Function(Event event) getEventOptions;
const PinnedEventsDrawer(this.roomId, {this.getEventOptions, super.key}); final Future<void> Function(String eventId) jumpToId;
const PinnedEventsDrawer(
this.roomId, {
required this.getEventOptions,
required this.jumpToId,
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -60,14 +66,17 @@ class PinnedEventsDrawer extends HookConsumerWidget {
borderRadius: .circular(12), borderRadius: .circular(12),
onTap: () { onTap: () {
Navigator.pop(context); Navigator.pop(context);
// TODO: // Close drawer, then scroll to the message jumpToId(event.eventId);
}, },
child: Padding(
padding: .symmetric(vertical: 4),
child: EventRenderer( child: EventRenderer(
event, event,
maxLines: 2, maxLines: 2,
isGrouped: false, isGrouped: false,
getEventOptions: getEventOptions, getEventOptions: getEventOptions,
), ),
),
); );
}, },
), ),

View file

@ -81,6 +81,27 @@ class RoomChat extends HookConsumerWidget {
final topEventBeforeLoad = useState<String?>(null); final topEventBeforeLoad = useState<String?>(null);
Future<void> jumpToId(String eventId) async {
final index = controllerData.value?.indexWhere(
(element) => element.eventId == eventId,
);
if (index == null) return;
listController.value.animateToItem(
index: index,
scrollController: scrollController,
alignment: 0.5,
duration: (_) => .new(milliseconds: 700),
curve: (_) => Curves.easeInOut,
);
highlightedEvent.value = eventId;
await Future.delayed(.new(seconds: 1), () {
if (highlightedEvent.value == eventId) {
highlightedEvent.value = null;
}
});
}
Future<void> loadOlder() async { Future<void> loadOlder() async {
if (controllerData case AsyncData(:final value?)) { if (controllerData case AsyncData(:final value?)) {
topEventBeforeLoad.value = value.firstOrNull?.eventId; topEventBeforeLoad.value = value.firstOrNull?.eventId;
@ -414,7 +435,11 @@ class RoomChat extends HookConsumerWidget {
} }
return Scaffold( return Scaffold(
endDrawer: PinnedEventsDrawer(roomId, getEventOptions: getEventOptions), endDrawer: PinnedEventsDrawer(
roomId,
getEventOptions: getEventOptions,
jumpToId: jumpToId,
),
body: Builder( body: Builder(
builder: (middleContext) => Scaffold( builder: (middleContext) => Scaffold(
endDrawer: showMembersByDefault ? null : MemberList(roomId), endDrawer: showMembersByDefault ? null : MemberList(roomId),
@ -468,30 +493,8 @@ class RoomChat extends HookConsumerWidget {
return HighlightWrapper( return HighlightWrapper(
EventRenderer( EventRenderer(
event, event,
onTapReply: () async { onTapReply: () =>
final replyId = event.replyTo; jumpToId(event.replyTo!),
listController.value.animateToItem(
index: value.indexWhere(
(element) =>
element.eventId == replyId,
),
scrollController: scrollController,
alignment: 0.5,
duration: (_) =>
.new(milliseconds: 700),
curve: (_) => Curves.easeInOut,
);
highlightedEvent.value = replyId;
await Future.delayed(
.new(seconds: 1),
() {
if (highlightedEvent.value ==
replyId) {
highlightedEvent.value = null;
}
},
);
},
getEventOptions: getEventOptions, getEventOptions: getEventOptions,
isGrouped: isGrouped:
previousEvent?.content previousEvent?.content