From 789d82632a998cd0405be9485b86fedc95063494 Mon Sep 17 00:00:00 2001 From: Thomas <9749173+uhthomas@users.noreply.github.com> Date: Fri, 27 Feb 2026 06:42:24 +0000 Subject: [PATCH] fix(mobile): race condition showing details (#26559) Asset details are prematurely hidden when a drag ends if the simulation shows that it will close given its current velocity. It makes for a much more responsible feeling UI. However, this behaviour conflicts with the logic which determines whether details are showing based on the current offset. The result is that the details are hidden, then immediately shown again, and then hidden once it passes the min snap distance threshold. This can be fixed by only evaluating the position based logic when a drag is active, and then inferring upcoming state with a simulation. --- .../widgets/asset_viewer/asset_page.widget.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mobile/lib/presentation/widgets/asset_viewer/asset_page.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/asset_page.widget.dart index 686b3fcf10..b62f579762 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/asset_page.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/asset_page.widget.dart @@ -64,7 +64,6 @@ class _AssetPageState extends ConsumerState { @override void initState() { super.initState(); - _proxyScrollController.addListener(_onScroll); _eventSubscription = EventStream.shared.listen(_onEvent); WidgetsBinding.instance.addPostFrameCallback((_) { if (!mounted || !_proxyScrollController.hasClients) return; @@ -94,6 +93,7 @@ class _AssetPageState extends ConsumerState { void _showDetails() { if (!_proxyScrollController.hasClients || _snapOffset <= 0) return; + _viewer.setShowingDetails(true); _proxyScrollController.animateTo(_snapOffset, duration: Durations.medium2, curve: Curves.easeOutCubic); } @@ -105,7 +105,7 @@ class _AssetPageState extends ConsumerState { SnapScrollPhysics.target(position, scrollVelocity, _snapOffset) < SnapScrollPhysics.minSnapDistance; } - void _onScroll() { + void _syncShowingDetails() { final offset = _proxyScrollController.offset; if (offset > SnapScrollPhysics.minSnapDistance) { _viewer.setShowingDetails(true); @@ -149,6 +149,8 @@ class _AssetPageState extends ConsumerState { case _DragIntent.scroll: if (_drag == null) _startProxyDrag(); _drag?.update(details); + + _syncShowingDetails(); case _DragIntent.dismiss: _handleDragDown(context, details.localPosition - _dragStart!.localPosition); } @@ -167,9 +169,8 @@ class _AssetPageState extends ConsumerState { case _DragIntent.none: case _DragIntent.scroll: final scrollVelocity = -(details.primaryVelocity ?? 0.0); - if (_willClose(scrollVelocity)) { - _viewer.setShowingDetails(false); - } + _viewer.setShowingDetails(!_willClose(scrollVelocity)); + _drag?.end(details); _drag = null; case _DragIntent.dismiss: