mirror of
https://github.com/immich-app/immich.git
synced 2025-07-31 15:08:44 -04:00
fix(mobile): deep links when using the beta timeline (#20111)
* fix: deep links when using the beta timeline * Update remote_asset.repository.dart * Update mobile/lib/domain/services/asset.service.dart Co-authored-by: Alex <alex.tran1502@gmail.com> * return optional from album get * do not include trashed assets in album asset count Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> * formatting --------- Co-authored-by: Alex <alex.tran1502@gmail.com> Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
This commit is contained in:
parent
2e0ee6ec05
commit
f9292c9c96
@ -22,6 +22,10 @@ class AssetService {
|
|||||||
return asset is LocalAsset ? _localAssetRepository.watchAsset(id) : _remoteAssetRepository.watchAsset(id);
|
return asset is LocalAsset ? _localAssetRepository.watchAsset(id) : _remoteAssetRepository.watchAsset(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<RemoteAsset?> getRemoteAsset(String id) {
|
||||||
|
return _remoteAssetRepository.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<RemoteAsset>> getStack(RemoteAsset asset) async {
|
Future<List<RemoteAsset>> getStack(RemoteAsset asset) async {
|
||||||
if (asset.stackId == null) {
|
if (asset.stackId == null) {
|
||||||
return [];
|
return [];
|
||||||
|
@ -13,6 +13,10 @@ class DriftMemoryService {
|
|||||||
return _repository.getAll(ownerId);
|
return _repository.getAll(ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<DriftMemory?> get(String memoryId) {
|
||||||
|
return _repository.get(memoryId);
|
||||||
|
}
|
||||||
|
|
||||||
Future<int> getCount() {
|
Future<int> getCount() {
|
||||||
return _repository.getCount();
|
return _repository.getCount();
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,10 @@ class RemoteAlbumService {
|
|||||||
return _repository.getAll();
|
return _repository.getAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<RemoteAlbum?> get(String albumId) {
|
||||||
|
return _repository.get(albumId);
|
||||||
|
}
|
||||||
|
|
||||||
List<RemoteAlbum> sortAlbums(
|
List<RemoteAlbum> sortAlbums(
|
||||||
List<RemoteAlbum> albums,
|
List<RemoteAlbum> albums,
|
||||||
RemoteAlbumSortMode sortMode, {
|
RemoteAlbumSortMode sortMode, {
|
||||||
|
@ -58,6 +58,43 @@ class DriftMemoryRepository extends DriftDatabaseRepository {
|
|||||||
return memoriesMap.values.toList();
|
return memoriesMap.values.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<DriftMemory?> get(String memoryId) async {
|
||||||
|
final query = _db.select(_db.memoryEntity).join([
|
||||||
|
leftOuterJoin(
|
||||||
|
_db.memoryAssetEntity,
|
||||||
|
_db.memoryAssetEntity.memoryId.equalsExp(_db.memoryEntity.id),
|
||||||
|
),
|
||||||
|
leftOuterJoin(
|
||||||
|
_db.remoteAssetEntity,
|
||||||
|
_db.remoteAssetEntity.id.equalsExp(_db.memoryAssetEntity.assetId) &
|
||||||
|
_db.remoteAssetEntity.deletedAt.isNull() &
|
||||||
|
_db.remoteAssetEntity.visibility.equalsValue(AssetVisibility.timeline),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
..where(_db.memoryEntity.id.equals(memoryId))
|
||||||
|
..where(_db.memoryEntity.deletedAt.isNull())
|
||||||
|
..orderBy([
|
||||||
|
OrderingTerm.desc(_db.memoryEntity.memoryAt),
|
||||||
|
OrderingTerm.asc(_db.remoteAssetEntity.createdAt),
|
||||||
|
]);
|
||||||
|
|
||||||
|
final rows = await query.get();
|
||||||
|
|
||||||
|
if (rows.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final memory = rows.first.readTable(_db.memoryEntity);
|
||||||
|
final assets = <RemoteAsset>[];
|
||||||
|
|
||||||
|
for (final row in rows) {
|
||||||
|
final asset = row.readTable(_db.remoteAssetEntity);
|
||||||
|
assets.add(asset.toDto());
|
||||||
|
}
|
||||||
|
|
||||||
|
return memory.toDto().copyWith(assets: assets);
|
||||||
|
}
|
||||||
|
|
||||||
Future<int> getCount() {
|
Future<int> getCount() {
|
||||||
return _db.managers.memoryEntity.count();
|
return _db.managers.memoryEntity.count();
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,41 @@ class DriftRemoteAlbumRepository extends DriftDatabaseRepository {
|
|||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<RemoteAlbum?> get(String albumId) {
|
||||||
|
final assetCount = _db.remoteAlbumAssetEntity.assetId.count();
|
||||||
|
|
||||||
|
final query = _db.remoteAlbumEntity.select().join([
|
||||||
|
leftOuterJoin(
|
||||||
|
_db.remoteAlbumAssetEntity,
|
||||||
|
_db.remoteAlbumAssetEntity.albumId.equalsExp(_db.remoteAlbumEntity.id),
|
||||||
|
useColumns: false,
|
||||||
|
),
|
||||||
|
leftOuterJoin(
|
||||||
|
_db.remoteAssetEntity,
|
||||||
|
_db.remoteAssetEntity.id.equalsExp(_db.remoteAlbumAssetEntity.assetId),
|
||||||
|
useColumns: false,
|
||||||
|
),
|
||||||
|
leftOuterJoin(
|
||||||
|
_db.userEntity,
|
||||||
|
_db.userEntity.id.equalsExp(_db.remoteAlbumEntity.ownerId),
|
||||||
|
useColumns: false,
|
||||||
|
),
|
||||||
|
])
|
||||||
|
..where(_db.remoteAlbumEntity.id.equals(albumId) & _db.remoteAssetEntity.deletedAt.isNull())
|
||||||
|
..addColumns([assetCount])
|
||||||
|
..addColumns([_db.userEntity.name])
|
||||||
|
..groupBy([_db.remoteAlbumEntity.id]);
|
||||||
|
|
||||||
|
return query
|
||||||
|
.map(
|
||||||
|
(row) => row.readTable(_db.remoteAlbumEntity).toDto(
|
||||||
|
assetCount: row.read(assetCount) ?? 0,
|
||||||
|
ownerName: row.read(_db.userEntity.name)!,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.getSingleOrNull();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> create(
|
Future<void> create(
|
||||||
RemoteAlbum album,
|
RemoteAlbum album,
|
||||||
List<String> assetIds,
|
List<String> assetIds,
|
||||||
|
@ -29,6 +29,33 @@ class RemoteAssetRepository extends DriftDatabaseRepository {
|
|||||||
return query.map((row) => row.toDto()).get();
|
return query.map((row) => row.toDto()).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SingleOrNullSelectable<RemoteAsset?> _assetSelectable(String id) {
|
||||||
|
final query = _db.remoteAssetEntity.select().addColumns([
|
||||||
|
_db.localAssetEntity.id,
|
||||||
|
]).join([
|
||||||
|
leftOuterJoin(
|
||||||
|
_db.localAssetEntity,
|
||||||
|
_db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum),
|
||||||
|
useColumns: false,
|
||||||
|
),
|
||||||
|
])
|
||||||
|
..where(_db.remoteAssetEntity.id.equals(id))
|
||||||
|
..limit(1);
|
||||||
|
|
||||||
|
return query.map((row) {
|
||||||
|
final asset = row.readTable(_db.remoteAssetEntity).toDto();
|
||||||
|
return asset.copyWith(localId: row.read(_db.localAssetEntity.id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<RemoteAsset?> watch(String id) {
|
||||||
|
return _assetSelectable(id).watchSingleOrNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<RemoteAsset?> get(String id) {
|
||||||
|
return _assetSelectable(id).getSingleOrNull();
|
||||||
|
}
|
||||||
|
|
||||||
Stream<RemoteAsset?> watchAsset(String id) {
|
Stream<RemoteAsset?> watchAsset(String id) {
|
||||||
final query = _db.remoteAssetEntity.select().addColumns([
|
final query = _db.remoteAssetEntity.select().addColumns([
|
||||||
_db.localAssetEntity.id,
|
_db.localAssetEntity.id,
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.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/remote_album.service.dart';
|
||||||
|
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
||||||
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/providers/album/current_album.provider.dart';
|
import 'package:immich_mobile/providers/album/current_album.provider.dart';
|
||||||
import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart';
|
import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart' as beta_asset_provider;
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/memory.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:immich_mobile/services/album.service.dart';
|
import 'package:immich_mobile/services/album.service.dart';
|
||||||
import 'package:immich_mobile/services/asset.service.dart';
|
import 'package:immich_mobile/services/asset.service.dart';
|
||||||
@ -15,24 +25,53 @@ final deepLinkServiceProvider = Provider(
|
|||||||
ref.watch(albumServiceProvider),
|
ref.watch(albumServiceProvider),
|
||||||
ref.watch(currentAssetProvider.notifier),
|
ref.watch(currentAssetProvider.notifier),
|
||||||
ref.watch(currentAlbumProvider.notifier),
|
ref.watch(currentAlbumProvider.notifier),
|
||||||
|
// Below is used for beta timeline
|
||||||
|
ref.watch(timelineFactoryProvider),
|
||||||
|
ref.watch(beta_asset_provider.assetServiceProvider),
|
||||||
|
ref.watch(currentRemoteAlbumProvider.notifier),
|
||||||
|
ref.watch(remoteAlbumServiceProvider),
|
||||||
|
ref.watch(driftMemoryServiceProvider),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
class DeepLinkService {
|
class DeepLinkService {
|
||||||
|
/// TODO: Remove this when beta is default
|
||||||
final MemoryService _memoryService;
|
final MemoryService _memoryService;
|
||||||
final AssetService _assetService;
|
final AssetService _assetService;
|
||||||
final AlbumService _albumService;
|
final AlbumService _albumService;
|
||||||
final CurrentAsset _currentAsset;
|
final CurrentAsset _currentAsset;
|
||||||
final CurrentAlbum _currentAlbum;
|
final CurrentAlbum _currentAlbum;
|
||||||
|
|
||||||
|
/// Used for beta timeline
|
||||||
|
final TimelineFactory _betaTimelineFactory;
|
||||||
|
final beta_asset_service.AssetService _betaAssetService;
|
||||||
|
final CurrentAlbumNotifier _betaCurrentAlbumNotifier;
|
||||||
|
final RemoteAlbumService _betaRemoteAlbumService;
|
||||||
|
final DriftMemoryService _betaMemoryServiceProvider;
|
||||||
|
|
||||||
const DeepLinkService(
|
const DeepLinkService(
|
||||||
this._memoryService,
|
this._memoryService,
|
||||||
this._assetService,
|
this._assetService,
|
||||||
this._albumService,
|
this._albumService,
|
||||||
this._currentAsset,
|
this._currentAsset,
|
||||||
this._currentAlbum,
|
this._currentAlbum,
|
||||||
|
this._betaTimelineFactory,
|
||||||
|
this._betaAssetService,
|
||||||
|
this._betaCurrentAlbumNotifier,
|
||||||
|
this._betaRemoteAlbumService,
|
||||||
|
this._betaMemoryServiceProvider,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
DeepLink _handleColdStart(PageRouteInfo<dynamic> 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) (Store.isBetaTimelineEnabled) ? const MainTimelineRoute() : const PhotosRoute(),
|
||||||
|
route,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
Future<DeepLink> handleScheme(PlatformDeepLink link, bool isColdStart) async {
|
Future<DeepLink> handleScheme(PlatformDeepLink link, bool isColdStart) async {
|
||||||
// get everything after the scheme, since Uri cannot parse path
|
// get everything after the scheme, since Uri cannot parse path
|
||||||
final intent = link.uri.host;
|
final intent = link.uri.host;
|
||||||
@ -54,11 +93,7 @@ class DeepLinkService {
|
|||||||
return DeepLink.none;
|
return DeepLink.none;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeepLink([
|
return _handleColdStart(deepLinkRoute, isColdStart);
|
||||||
// we need something to segue back to if the app was cold started
|
|
||||||
if (isColdStart) const PhotosRoute(),
|
|
||||||
deepLinkRoute,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<DeepLink> handleMyImmichApp(
|
Future<DeepLink> handleMyImmichApp(
|
||||||
@ -86,49 +121,80 @@ class DeepLinkService {
|
|||||||
return DeepLink.none;
|
return DeepLink.none;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeepLink([
|
return _handleColdStart(deepLinkRoute, isColdStart);
|
||||||
// we need something to segue back to if the app was cold started
|
|
||||||
if (isColdStart) const PhotosRoute(),
|
|
||||||
deepLinkRoute,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<PageRouteInfo?> _buildMemoryDeepLink(String memoryId) async {
|
Future<PageRouteInfo?> _buildMemoryDeepLink(String memoryId) async {
|
||||||
final memory = await _memoryService.getMemoryById(memoryId);
|
if (Store.isBetaTimelineEnabled) {
|
||||||
|
final memory = await _betaMemoryServiceProvider.get(memoryId);
|
||||||
|
|
||||||
if (memory == null) {
|
if (memory == null) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DriftMemoryRoute(memories: [memory], memoryIndex: 0);
|
||||||
|
} else {
|
||||||
|
// TODO: Remove this when beta is default
|
||||||
|
final memory = await _memoryService.getMemoryById(memoryId);
|
||||||
|
|
||||||
|
if (memory == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MemoryRoute(memories: [memory], memoryIndex: 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MemoryRoute(memories: [memory], memoryIndex: 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<PageRouteInfo?> _buildAssetDeepLink(String assetId) async {
|
Future<PageRouteInfo?> _buildAssetDeepLink(String assetId) async {
|
||||||
final asset = await _assetService.getAssetByRemoteId(assetId);
|
if (Store.isBetaTimelineEnabled) {
|
||||||
if (asset == null) {
|
final asset = await _betaAssetService.getRemoteAsset(assetId);
|
||||||
return null;
|
if (asset == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AssetViewerRoute(
|
||||||
|
initialIndex: 0,
|
||||||
|
timelineService: _betaTimelineFactory.fromAssets([asset]),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// TODO: Remove this when beta is default
|
||||||
|
final asset = await _assetService.getAssetByRemoteId(assetId);
|
||||||
|
if (asset == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentAsset.set(asset);
|
||||||
|
final renderList = await RenderList.fromAssets([asset], GroupAssetsBy.auto);
|
||||||
|
|
||||||
|
return GalleryViewerRoute(
|
||||||
|
renderList: renderList,
|
||||||
|
initialIndex: 0,
|
||||||
|
heroOffset: 0,
|
||||||
|
showStack: true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentAsset.set(asset);
|
|
||||||
final renderList = await RenderList.fromAssets([asset], GroupAssetsBy.auto);
|
|
||||||
|
|
||||||
return GalleryViewerRoute(
|
|
||||||
renderList: renderList,
|
|
||||||
initialIndex: 0,
|
|
||||||
heroOffset: 0,
|
|
||||||
showStack: true,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<PageRouteInfo?> _buildAlbumDeepLink(String albumId) async {
|
Future<PageRouteInfo?> _buildAlbumDeepLink(String albumId) async {
|
||||||
final album = await _albumService.getAlbumByRemoteId(albumId);
|
if (Store.isBetaTimelineEnabled) {
|
||||||
|
final album = await _betaRemoteAlbumService.get(albumId);
|
||||||
|
|
||||||
if (album == null) {
|
if (album == null) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_betaCurrentAlbumNotifier.setAlbum(album);
|
||||||
|
return RemoteAlbumRoute(album: album);
|
||||||
|
} else {
|
||||||
|
// TODO: Remove this when beta is default
|
||||||
|
final album = await _albumService.getAlbumByRemoteId(albumId);
|
||||||
|
|
||||||
|
if (album == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentAlbum.set(album);
|
||||||
|
return AlbumViewerRoute(albumId: album.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentAlbum.set(album);
|
|
||||||
|
|
||||||
return AlbumViewerRoute(albumId: album.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user