diff --git a/mobile/lib/presentation/pages/drift_memory.page.dart b/mobile/lib/presentation/pages/drift_memory.page.dart index 6919925d55..f601bf8419 100644 --- a/mobile/lib/presentation/pages/drift_memory.page.dart +++ b/mobile/lib/presentation/pages/drift_memory.page.dart @@ -12,6 +12,7 @@ import 'package:immich_mobile/presentation/widgets/images/image_provider.dart'; import 'package:immich_mobile/presentation/widgets/memory/memory_bottom_info.widget.dart'; import 'package:immich_mobile/presentation/widgets/memory/memory_card.widget.dart'; import 'package:immich_mobile/providers/haptic_feedback.provider.dart'; +import 'package:immich_mobile/utils/system_ui.utils.dart'; import 'package:immich_mobile/widgets/memories/memory_epilogue.dart'; import 'package:immich_mobile/widgets/memories/memory_progress_indicator.dart'; @@ -49,7 +50,7 @@ class DriftMemoryPage extends HookConsumerWidget { SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive); return () { // Clean up to normal edge to edge when we are done - SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); + restoreEdgeToEdge(); }; }); @@ -328,7 +329,7 @@ class DriftMemoryPage extends HookConsumerWidget { // turn off full screen mode here // https://github.com/Milad-Akarie/auto_route_library/issues/1799 context.maybePop(); - SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); + restoreEdgeToEdge(); }, shape: const CircleBorder(), color: Colors.white.withValues(alpha: 0.2), diff --git a/mobile/lib/presentation/pages/drift_slideshow.page.dart b/mobile/lib/presentation/pages/drift_slideshow.page.dart index 4fae0709aa..596b6fdf36 100644 --- a/mobile/lib/presentation/pages/drift_slideshow.page.dart +++ b/mobile/lib/presentation/pages/drift_slideshow.page.dart @@ -19,6 +19,7 @@ import 'package:immich_mobile/providers/asset_viewer/asset_viewer.provider.dart' import 'package:immich_mobile/providers/asset_viewer/video_player_provider.dart'; import 'package:immich_mobile/providers/infrastructure/settings.provider.dart'; import 'package:immich_mobile/routing/router.dart'; +import 'package:immich_mobile/utils/system_ui.utils.dart'; import 'package:immich_mobile/widgets/common/immich_loading_indicator.dart'; import 'package:immich_mobile/widgets/photo_view/photo_view.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; @@ -76,7 +77,7 @@ class _DriftSlideshowPageState extends ConsumerState with Si _pageController.dispose(); _crossfadeController.dispose(); unawaited(WakelockPlus.disable()); - SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); + unawaited(restoreEdgeToEdge()); super.dispose(); } @@ -255,7 +256,7 @@ class _DriftSlideshowPageState extends ConsumerState with Si } void _onTapUp() async { - await SystemChrome.setEnabledSystemUIMode(_showAppBar ? SystemUiMode.immersive : SystemUiMode.edgeToEdge); + await (_showAppBar ? SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive) : restoreEdgeToEdge()); WidgetsBinding.instance.addPostFrameCallback((_) { setState(() { diff --git a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart index c8d8f63fa9..8b9dc6f887 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart @@ -23,6 +23,7 @@ import 'package:immich_mobile/providers/asset_viewer/asset_viewer.provider.dart' import 'package:immich_mobile/providers/cast.provider.dart'; import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart'; import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; +import 'package:immich_mobile/utils/system_ui.utils.dart'; import 'package:immich_mobile/widgets/photo_view/photo_view.dart'; @RoutePage() @@ -128,7 +129,7 @@ class _AssetViewerState extends ConsumerState { _reloadSubscription?.cancel(); _stackChildrenKeepAlive?.close(); - SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); + unawaited(restoreEdgeToEdge()); super.dispose(); } @@ -251,10 +252,8 @@ class _AssetViewerState extends ConsumerState { } void _setSystemUIMode(bool controls, bool details) { - final mode = !controls || (CurrentPlatform.isIOS && details) - ? SystemUiMode.immersiveSticky - : SystemUiMode.edgeToEdge; - unawaited(SystemChrome.setEnabledSystemUIMode(mode)); + final immersive = !controls || (CurrentPlatform.isIOS && details); + unawaited(immersive ? SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky) : restoreEdgeToEdge()); } @override diff --git a/mobile/lib/utils/system_ui.utils.dart b/mobile/lib/utils/system_ui.utils.dart new file mode 100644 index 0000000000..0d6d65082f --- /dev/null +++ b/mobile/lib/utils/system_ui.utils.dart @@ -0,0 +1,14 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; + +/// Restore the system bars and return to edge-to-edge layout. +/// +/// On Android 15+/API 36 edge-to-edge is enforced, so calling +/// setEnabledSystemUIMode(edgeToEdge) does NOT re-show bars that an immersive +/// mode (immersive / immersiveSticky) previously hid. Explicitly request all +/// overlays first, then return to edge-to-edge layout. +Future restoreEdgeToEdge() async { + await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); + await SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); +}