From dc6f8e746e8ae7ffbca15bca0148eaf9fbe178bd Mon Sep 17 00:00:00 2001 From: Brandon Wees Date: Tue, 12 May 2026 11:19:54 -0500 Subject: [PATCH] fix: deep link for assets when asset viewer already open (#27971) --- mobile/lib/main.dart | 29 ++++++++---- mobile/lib/services/deep_link.service.dart | 51 +++++----------------- 2 files changed, 32 insertions(+), 48 deletions(-) diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index 14d09e4cb7..19455be61c 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -179,19 +179,32 @@ class ImmichAppState extends ConsumerState with WidgetsBindingObserve final isColdStart = currentRouteName == null || currentRouteName == SplashScreenRoute.name; + PageRouteInfo? route; if (deepLink.uri.scheme == "immich") { - final proposedRoute = await deepLinkHandler.handleScheme(deepLink, ref, isColdStart); - - return proposedRoute; + route = await deepLinkHandler.handleScheme(deepLink, ref); + } else if (deepLink.uri.host == "my.immich.app") { + route = await deepLinkHandler.handleMyImmichApp(deepLink, ref); + } else { + return DeepLink.path(deepLink.path); } - if (deepLink.uri.host == "my.immich.app") { - final proposedRoute = await deepLinkHandler.handleMyImmichApp(deepLink, ref, isColdStart); - - return proposedRoute; + if (route == null) { + return isColdStart ? DeepLink.defaultPath : DeepLink.none; } - return DeepLink.path(deepLink.path); + // We need to replace the route if the destination is the current route + if (!isColdStart) { + unawaited( + ref.read(appRouterProvider).pushAndPopUntil(route, predicate: (r) => r.settings.name != route!.routeName), + ); + return DeepLink.none; + } + + return DeepLink([ + // we need something to segue back to if the app was cold started + if (isColdStart) const TabShellRoute(children: [MainTimelineRoute()]), + route, + ]); } @override diff --git a/mobile/lib/services/deep_link.service.dart b/mobile/lib/services/deep_link.service.dart index 3d2d702917..26f2fb685b 100644 --- a/mobile/lib/services/deep_link.service.dart +++ b/mobile/lib/services/deep_link.service.dart @@ -45,21 +45,12 @@ class DeepLinkService { this._currentUser, ); - DeepLink _handleColdStart(PageRouteInfo route, bool isColdStart) { - return DeepLink([ - // we need something to segue back to if the app was cold started - // TODO: use MainTimelineRoute this when beta is default - if (isColdStart) const TabShellRoute(), - route, - ]); - } - - Future handleScheme(PlatformDeepLink link, WidgetRef ref, bool isColdStart) async { + Future handleScheme(PlatformDeepLink link, WidgetRef ref) async { // get everything after the scheme, since Uri cannot parse path final intent = link.uri.host; final queryParams = link.uri.queryParameters; - PageRouteInfo? deepLinkRoute = switch (intent) { + return switch (intent) { "memory" => await _buildMemoryDeepLink(queryParams['id'] ?? ''), "asset" => await _buildAssetDeepLink(queryParams['id'] ?? '', ref), "album" => await _buildAlbumDeepLink(queryParams['id'] ?? ''), @@ -67,20 +58,9 @@ class DeepLinkService { "activity" => await _buildActivityDeepLink(queryParams['albumId'] ?? ''), _ => null, }; - - // Deep link resolution failed, safely handle it based on the app state - if (deepLinkRoute == null) { - if (isColdStart) { - return DeepLink.defaultPath; - } - - return DeepLink.none; - } - - return _handleColdStart(deepLinkRoute, isColdStart); } - Future handleMyImmichApp(PlatformDeepLink link, WidgetRef ref, bool isColdStart) async { + Future handleMyImmichApp(PlatformDeepLink link, WidgetRef ref) async { final path = link.uri.path; const uuidRegex = r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'; @@ -88,29 +68,20 @@ class DeepLinkService { final albumRegex = RegExp('/albums/($uuidRegex)'); final peopleRegex = RegExp('/people/($uuidRegex)'); - PageRouteInfo? deepLinkRoute; if (assetRegex.hasMatch(path)) { final assetId = assetRegex.firstMatch(path)?.group(1) ?? ''; - deepLinkRoute = await _buildAssetDeepLink(assetId, ref); - } else if (albumRegex.hasMatch(path)) { + return _buildAssetDeepLink(assetId, ref); + } + if (albumRegex.hasMatch(path)) { final albumId = albumRegex.firstMatch(path)?.group(1) ?? ''; - deepLinkRoute = await _buildAlbumDeepLink(albumId); - } else if (peopleRegex.hasMatch(path)) { + return _buildAlbumDeepLink(albumId); + } + if (peopleRegex.hasMatch(path)) { final peopleId = peopleRegex.firstMatch(path)?.group(1) ?? ''; - deepLinkRoute = await _buildPeopleDeepLink(peopleId); - } else if (path == "/memory") { - deepLinkRoute = await _buildMemoryDeepLink(null); + return _buildPeopleDeepLink(peopleId); } - // Deep link resolution failed, safely handle it based on the app state - if (deepLinkRoute == null) { - if (isColdStart) { - return DeepLink.defaultPath; - } - return DeepLink.none; - } - - return _handleColdStart(deepLinkRoute, isColdStart); + return null; } Future _buildMemoryDeepLink(String? memoryId) async {