From 66733eb4c0cebb4807ace6c19d3e005e7888a636 Mon Sep 17 00:00:00 2001 From: Arne Schwarck Date: Fri, 13 Feb 2026 04:43:04 +0100 Subject: [PATCH] feat: add people deeplink (#25686) * Change path prefix from '/memories/' to '/people/' Updated the AndroidManifest.xml to change the path prefix from '/memories/' to '/people/'. Memories is anyway wrong and was replaced by /memory and now the people path completes the known deeplinks. * Add regex for people deep link handling Add regex for people deep link handling * Add deep link handling for 'people' route * fix: missing person route builder method --------- Co-authored-by: bwees --- .../android/app/src/main/AndroidManifest.xml | 2 +- .../lib/domain/services/people.service.dart | 4 +++ .../repositories/people.repository.dart | 7 ++++ mobile/lib/services/deep_link.service.dart | 32 ++++++++++++++++--- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/mobile/android/app/src/main/AndroidManifest.xml b/mobile/android/app/src/main/AndroidManifest.xml index eacf75b7ed..db3859ab6e 100644 --- a/mobile/android/app/src/main/AndroidManifest.xml +++ b/mobile/android/app/src/main/AndroidManifest.xml @@ -117,7 +117,7 @@ android:pathPrefix="/albums/" /> + android:pathPrefix="/people/" /> diff --git a/mobile/lib/domain/services/people.service.dart b/mobile/lib/domain/services/people.service.dart index d45f710d7b..ecfe83e5cb 100644 --- a/mobile/lib/domain/services/people.service.dart +++ b/mobile/lib/domain/services/people.service.dart @@ -10,6 +10,10 @@ class DriftPeopleService { const DriftPeopleService(this._repository, this._personApiRepository); + Future get(String personId) { + return _repository.get(personId); + } + Future> getAssetPeople(String assetId) { return _repository.getAssetPeople(assetId); } diff --git a/mobile/lib/infrastructure/repositories/people.repository.dart b/mobile/lib/infrastructure/repositories/people.repository.dart index e2b8646dba..cd5f702ce7 100644 --- a/mobile/lib/infrastructure/repositories/people.repository.dart +++ b/mobile/lib/infrastructure/repositories/people.repository.dart @@ -7,6 +7,13 @@ class DriftPeopleRepository extends DriftDatabaseRepository { final Drift _db; const DriftPeopleRepository(this._db) : super(_db); + Future get(String personId) async { + final query = _db.select(_db.personEntity)..where((row) => row.id.equals(personId)); + + final result = await query.getSingleOrNull(); + return result?.toDto(); + } + Future> getAssetPeople(String assetId) async { final query = _db.select(_db.assetFaceEntity).join([ innerJoin(_db.personEntity, _db.personEntity.id.equalsExp(_db.assetFaceEntity.personId)), diff --git a/mobile/lib/services/deep_link.service.dart b/mobile/lib/services/deep_link.service.dart index 0803cfcdf0..9d2bdbe4a0 100644 --- a/mobile/lib/services/deep_link.service.dart +++ b/mobile/lib/services/deep_link.service.dart @@ -4,6 +4,7 @@ import 'package:immich_mobile/domain/models/memory.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/services/asset.service.dart' as beta_asset_service; import 'package:immich_mobile/domain/services/memory.service.dart'; +import 'package:immich_mobile/domain/services/people.service.dart'; import 'package:immich_mobile/domain/services/remote_album.service.dart'; import 'package:immich_mobile/domain/services/timeline.service.dart'; import 'package:immich_mobile/entities/store.entity.dart'; @@ -13,6 +14,7 @@ import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart import 'package:immich_mobile/providers/infrastructure/album.provider.dart'; import 'package:immich_mobile/providers/infrastructure/asset.provider.dart' as beta_asset_provider; import 'package:immich_mobile/providers/infrastructure/memory.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/people.provider.dart'; import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/routing/router.dart'; @@ -33,6 +35,7 @@ final deepLinkServiceProvider = Provider( ref.watch(beta_asset_provider.assetServiceProvider), ref.watch(remoteAlbumServiceProvider), ref.watch(driftMemoryServiceProvider), + ref.watch(driftPeopleServiceProvider), ref.watch(currentUserProvider), ), ); @@ -49,7 +52,8 @@ class DeepLinkService { final TimelineFactory _betaTimelineFactory; final beta_asset_service.AssetService _betaAssetService; final RemoteAlbumService _betaRemoteAlbumService; - final DriftMemoryService _betaMemoryServiceProvider; + final DriftMemoryService _betaMemoryService; + final DriftPeopleService _betaPeopleService; final UserDto? _currentUser; @@ -62,7 +66,8 @@ class DeepLinkService { this._betaTimelineFactory, this._betaAssetService, this._betaRemoteAlbumService, - this._betaMemoryServiceProvider, + this._betaMemoryService, + this._betaPeopleService, this._currentUser, ); @@ -84,6 +89,7 @@ class DeepLinkService { "memory" => await _buildMemoryDeepLink(queryParams['id'] ?? ''), "asset" => await _buildAssetDeepLink(queryParams['id'] ?? '', ref), "album" => await _buildAlbumDeepLink(queryParams['id'] ?? ''), + "people" => await _buildPeopleDeepLink(queryParams['id'] ?? ''), "activity" => await _buildActivityDeepLink(queryParams['albumId'] ?? ''), _ => null, }; @@ -106,6 +112,7 @@ class DeepLinkService { 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}'; final assetRegex = RegExp('/photos/($uuidRegex)'); final albumRegex = RegExp('/albums/($uuidRegex)'); + final peopleRegex = RegExp('/people/($uuidRegex)'); PageRouteInfo? deepLinkRoute; if (assetRegex.hasMatch(path)) { @@ -114,6 +121,9 @@ class DeepLinkService { } else if (albumRegex.hasMatch(path)) { final albumId = albumRegex.firstMatch(path)?.group(1) ?? ''; deepLinkRoute = await _buildAlbumDeepLink(albumId); + } else if (peopleRegex.hasMatch(path)) { + final peopleId = peopleRegex.firstMatch(path)?.group(1) ?? ''; + deepLinkRoute = await _buildPeopleDeepLink(peopleId); } else if (path == "/memory") { deepLinkRoute = await _buildMemoryDeepLink(null); } @@ -136,9 +146,9 @@ class DeepLinkService { return null; } - memories = await _betaMemoryServiceProvider.getMemoryLane(_currentUser.id); + memories = await _betaMemoryService.getMemoryLane(_currentUser.id); } else { - final memory = await _betaMemoryServiceProvider.get(memoryId); + final memory = await _betaMemoryService.get(memoryId); if (memory != null) { memories = [memory]; } @@ -225,4 +235,18 @@ class DeepLinkService { return DriftActivitiesRoute(album: album); } + + Future _buildPeopleDeepLink(String personId) async { + if (Store.isBetaTimelineEnabled == false) { + return null; + } + + final person = await _betaPeopleService.get(personId); + + if (person == null) { + return null; + } + + return DriftPersonRoute(person: person); + } }