tweak scroll behavior
This commit is contained in:
parent
3217c17ea0
commit
d712bb3193
2 changed files with 53 additions and 57 deletions
|
|
@ -12,11 +12,11 @@ final class ChatScroll({
|
||||||
required final IList<Event> historyItems,
|
required final IList<Event> historyItems,
|
||||||
required final IList<Event> liveItems,
|
required final IList<Event> liveItems,
|
||||||
required final GlobalKey centerKey,
|
required final GlobalKey centerKey,
|
||||||
required final GlobalKey anchorItemKey,
|
|
||||||
required final ScrollController scrollController,
|
required final ScrollController scrollController,
|
||||||
required final bool atBottom,
|
required final bool atBottom,
|
||||||
required final Future<void> Function(String id) jumpToId,
|
required final Future<void> Function(String id) jumpToId,
|
||||||
required final Future<void> Function() jumpToBottom,
|
required final Future<void> Function() jumpToBottom,
|
||||||
|
required final GlobalKey Function(String eventId) keyFor,
|
||||||
}) {
|
}) {
|
||||||
factory use({
|
factory use({
|
||||||
required AsyncValue<RoomChat?> controllerData,
|
required AsyncValue<RoomChat?> controllerData,
|
||||||
|
|
@ -26,7 +26,9 @@ final class ChatScroll({
|
||||||
}) {
|
}) {
|
||||||
final anchorId = useState<String?>(null);
|
final anchorId = useState<String?>(null);
|
||||||
|
|
||||||
final anchorItemKey = useMemoized(GlobalKey.new, [anchorId.value]);
|
final itemKeys = useMemoized(() => <String, GlobalKey>{}, []);
|
||||||
|
GlobalKey keyFor(String eventId) =>
|
||||||
|
itemKeys.putIfAbsent(eventId, GlobalKey.new);
|
||||||
|
|
||||||
final scrollController = useScrollController();
|
final scrollController = useScrollController();
|
||||||
final centerKey = useMemoized(GlobalKey.new);
|
final centerKey = useMemoized(GlobalKey.new);
|
||||||
|
|
@ -83,7 +85,7 @@ final class ChatScroll({
|
||||||
if (completer == null) return null;
|
if (completer == null) return null;
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
final context = anchorItemKey.currentContext;
|
final context = keyFor(anchorId.value!).currentContext;
|
||||||
if (context != null && context.mounted) {
|
if (context != null && context.mounted) {
|
||||||
anchorMountedCompleter.value?.complete(context);
|
anchorMountedCompleter.value?.complete(context);
|
||||||
anchorMountedCompleter.value = null;
|
anchorMountedCompleter.value = null;
|
||||||
|
|
@ -151,10 +153,25 @@ final class ChatScroll({
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<void> jumpToId(String itemId) async {
|
return .new(
|
||||||
|
historyItems: split.history,
|
||||||
|
liveItems: split.live,
|
||||||
|
centerKey: centerKey,
|
||||||
|
scrollController: scrollController,
|
||||||
|
atBottom: atBottom.value,
|
||||||
|
jumpToId: (String itemId) async {
|
||||||
if (!scrollController.hasClients) return;
|
if (!scrollController.hasClients) return;
|
||||||
|
|
||||||
if (anchorId.value != itemId) {
|
final existing = keyFor(itemId).currentContext;
|
||||||
|
if (existing != null && existing.mounted) {
|
||||||
|
// Already mounted, just scroll
|
||||||
|
await Scrollable.ensureVisible(
|
||||||
|
existing,
|
||||||
|
alignment: 0.5,
|
||||||
|
duration: const .new(milliseconds: 700),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
final completer = Completer<BuildContext>();
|
final completer = Completer<BuildContext>();
|
||||||
anchorMountedCompleter.value = completer;
|
anchorMountedCompleter.value = completer;
|
||||||
pendingAnchorTarget.value = itemId;
|
pendingAnchorTarget.value = itemId;
|
||||||
|
|
@ -163,27 +180,17 @@ final class ChatScroll({
|
||||||
final context = await completer.future;
|
final context = await completer.future;
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
|
|
||||||
|
await Scrollable.ensureVisible(context, alignment: 10);
|
||||||
|
if (!context.mounted) return;
|
||||||
await Scrollable.ensureVisible(
|
await Scrollable.ensureVisible(
|
||||||
context,
|
context,
|
||||||
alignment: 0.5,
|
alignment: 0.5,
|
||||||
duration: const .new(milliseconds: 700),
|
duration: const .new(milliseconds: 700),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeOutCirc,
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final context = anchorItemKey.currentContext;
|
|
||||||
if (context != null && context.mounted) {
|
|
||||||
await Scrollable.ensureVisible(
|
|
||||||
context,
|
|
||||||
alignment: 0.5,
|
|
||||||
duration: const .new(milliseconds: 700),
|
|
||||||
curve: Curves.easeInOut,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
jumpToBottom: () async {
|
||||||
Future<void> jumpToBottom() async {
|
|
||||||
if (contextualEvent.value != null) {
|
if (contextualEvent.value != null) {
|
||||||
anchorId.value = null;
|
anchorId.value = null;
|
||||||
contextualEvent.value = null;
|
contextualEvent.value = null;
|
||||||
|
|
@ -196,17 +203,8 @@ final class ChatScroll({
|
||||||
duration: const .new(milliseconds: 700),
|
duration: const .new(milliseconds: 700),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
|
keyFor: keyFor,
|
||||||
return .new(
|
|
||||||
historyItems: split.history,
|
|
||||||
liveItems: split.live,
|
|
||||||
centerKey: centerKey,
|
|
||||||
anchorItemKey: anchorItemKey,
|
|
||||||
scrollController: scrollController,
|
|
||||||
atBottom: atBottom.value,
|
|
||||||
jumpToId: jumpToId,
|
|
||||||
jumpToBottom: jumpToBottom,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,7 @@ class const ChatTimeline({
|
||||||
jumpToId: jumpToId,
|
jumpToId: jumpToId,
|
||||||
getEventOptions: getEventOptions,
|
getEventOptions: getEventOptions,
|
||||||
highlightedEvent: highlightedEvent,
|
highlightedEvent: highlightedEvent,
|
||||||
key: index == 0
|
key: scroll.keyFor(scroll.liveItems[index].eventId),
|
||||||
? scroll.anchorItemKey
|
|
||||||
: ValueKey(scroll.liveItems[index].eventId),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
@ -74,7 +72,7 @@ class const ChatTimeline({
|
||||||
jumpToId: jumpToId,
|
jumpToId: jumpToId,
|
||||||
getEventOptions: getEventOptions,
|
getEventOptions: getEventOptions,
|
||||||
highlightedEvent: highlightedEvent,
|
highlightedEvent: highlightedEvent,
|
||||||
key: ValueKey(scroll.historyItems[index].eventId),
|
key: scroll.keyFor(scroll.historyItems[index].eventId),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue