mirror of
https://github.com/immich-app/immich
synced 2026-08-15 13:03:57 +00:00
fix(mobile): prevent iOS status bar scroll to top during transitions (#30717)
This commit is contained in:
parent
db9e7c20d7
commit
b82d480552
4 changed files with 40 additions and 5 deletions
|
|
@ -277,7 +277,7 @@ class ImmichAppState extends ConsumerState<ImmichApp> with WidgetsBindingObserve
|
|||
),
|
||||
routerConfig: router.config(
|
||||
deepLinkBuilder: _deepLinkBuilder,
|
||||
navigatorObservers: () => [AppNavigationObserver(ref: ref)],
|
||||
navigatorObservers: () => [AppNavigationObserver(ref: ref), TransitioningRouteObserver()],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import 'package:immich_mobile/providers/infrastructure/readonly_mode.provider.da
|
|||
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||
import 'package:immich_mobile/routing/app_navigation_observer.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_sliver_app_bar.dart';
|
||||
import 'package:immich_mobile/widgets/common/mesmerizing_sliver_app_bar.dart';
|
||||
import 'package:immich_mobile/widgets/common/selection_sliver_app_bar.dart';
|
||||
|
|
@ -190,7 +191,14 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> with WidgetsBi
|
|||
// may be in a background tab. In either case, `handleStatusBarTap()` still fires
|
||||
// Make sure the timeline is the primary route before scrolling to the top
|
||||
final routeData = context.findAncestorWidgetOfExactType<RouteDataScope>()?.routeData;
|
||||
if (ModalRoute.of(context)?.isCurrent == true && routeData?.isActive == true) {
|
||||
// The tap is generated async, so it can arrive after a route pop has started (due to a back button or similar)
|
||||
// Check if route is alive and not exiting before taking action
|
||||
final observers = Navigator.maybeOf(context)?.widget.observers ?? const <NavigatorObserver>[];
|
||||
final isRouteTransitioning = observers.whereType<TransitioningRouteObserver>().any(
|
||||
(observer) => observer.hasTransitioningRoute,
|
||||
);
|
||||
|
||||
if (ModalRoute.of(context)?.isCurrent == true && routeData?.isActive == true && !isRouteTransitioning) {
|
||||
_scrollToTop();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,3 +30,22 @@ class AppNavigationObserver extends AutoRouterObserver {
|
|||
ref.invalidate(isAssetViewerOpenProvider);
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks routes that are undergoing a pop transition
|
||||
class TransitioningRouteObserver extends NavigatorObserver {
|
||||
int _transitioningRoutes = 0;
|
||||
|
||||
/// Whether a "popping" route is still on screen
|
||||
bool get hasTransitioningRoute => _transitioningRoutes > 0;
|
||||
|
||||
@override
|
||||
void didPop(Route route, Route? previousRoute) {
|
||||
if (route is! TransitionRoute) {
|
||||
return;
|
||||
}
|
||||
|
||||
_transitioningRoutes += 1;
|
||||
// Transition completed and route disposed
|
||||
unawaited(route.completed.whenComplete(() => _transitioningRoutes -= 1));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue