From fca27e1ceef58e2fa950a3b2d55ae13726e67902 Mon Sep 17 00:00:00 2001 From: wuzihao051119 Date: Wed, 16 Jul 2025 17:28:01 +0800 Subject: [PATCH] refactor: map query --- mobile/lib/domain/services/map.service.dart | 30 ++++--- .../repositories/map.repository.dart | 84 +++++++++++-------- .../bottom_sheet/map_bottom_sheet.widget.dart | 2 +- .../presentation/widgets/map/map.widget.dart | 3 +- .../infrastructure/map.provider.dart | 10 ++- 5 files changed, 78 insertions(+), 51 deletions(-) diff --git a/mobile/lib/domain/services/map.service.dart b/mobile/lib/domain/services/map.service.dart index de9e9eb270..9378345091 100644 --- a/mobile/lib/domain/services/map.service.dart +++ b/mobile/lib/domain/services/map.service.dart @@ -2,7 +2,11 @@ import 'package:immich_mobile/domain/models/map.model.dart'; import 'package:immich_mobile/infrastructure/repositories/map.repository.dart'; import 'package:maplibre_gl/maplibre_gl.dart'; -typedef MapMarkerSource = Stream> Function(LatLngBounds bounds); +typedef MapMarkerSource = Stream> Function(LatLngBounds? bounds); + +typedef MapQuery = ({ + MapMarkerSource markerSource, +}); class MapFactory { final DriftMapRepository _mapRepository; @@ -11,25 +15,29 @@ class MapFactory { required DriftMapRepository mapRepository, }) : _mapRepository = mapRepository; - MapService main(List timelineUsers) => MapService( - markerSource: (bounds) => - _mapRepository.watchMainMarker(timelineUsers, bounds: bounds), - ); + MapService remote(String ownerId) => + MapService(_mapRepository.remote(ownerId)); - MapService remoteAlbum({required String albumId}) => MapService( - markerSource: (bounds) => - _mapRepository.watchRemoteAlbumMarker(albumId, bounds: bounds), - ); + MapService favorite(String ownerId) => + MapService(_mapRepository.favorite(ownerId)); + + MapService locked(String ownerId) => + MapService(_mapRepository.locked(ownerId)); } class MapService { final MapMarkerSource _markerSource; - const MapService({ + MapService(MapQuery query) + : this._( + markerSource: query.markerSource, + ); + + MapService._({ required MapMarkerSource markerSource, }) : _markerSource = markerSource; - Stream> Function(LatLngBounds bounds) get watchMarkers => + Stream> Function(LatLngBounds? bounds) get watchMarkers => _markerSource; Future dispose() async {} diff --git a/mobile/lib/infrastructure/repositories/map.repository.dart b/mobile/lib/infrastructure/repositories/map.repository.dart index aaf402a422..f57449ebbe 100644 --- a/mobile/lib/infrastructure/repositories/map.repository.dart +++ b/mobile/lib/infrastructure/repositories/map.repository.dart @@ -1,7 +1,9 @@ import 'package:drift/drift.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/map.model.dart'; +import 'package:immich_mobile/domain/services/map.service.dart'; import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart'; +import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'; import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; import 'package:maplibre_gl/maplibre_gl.dart'; import 'package:stream_transform/stream_transform.dart'; @@ -11,36 +13,44 @@ class DriftMapRepository extends DriftDatabaseRepository { const DriftMapRepository(super._db) : _db = _db; - Stream> watchMainMarker( - List userIds, { - required LatLngBounds bounds, - }) { - final query = _db.remoteExifEntity.select().join([ - innerJoin( - _db.remoteAssetEntity, - _db.remoteAssetEntity.id.equalsExp(_db.remoteExifEntity.assetId), - useColumns: false, - ), - ]) - ..where( - _db.remoteExifEntity.latitude.isNotNull() & - _db.remoteExifEntity.longitude.isNotNull() & - _db.remoteExifEntity.inBounds(bounds) & - _db.remoteAssetEntity.visibility - .equalsValue(AssetVisibility.timeline) & - _db.remoteAssetEntity.deletedAt.isNull() & - _db.remoteAssetEntity.ownerId.isIn(userIds), + MapQuery remote(String ownerId) => _mapQueryBuilder( + assetFilter: (row) => + row.deletedAt.isNull() & + row.visibility.equalsValue(AssetVisibility.timeline) & + row.ownerId.equals(ownerId), ); - return query - .map((row) => row.readTable(_db.remoteExifEntity).toMarker()) - .watch() - .throttle(const Duration(seconds: 3)); + MapQuery favorite(String ownerId) => _mapQueryBuilder( + assetFilter: (row) => + row.deletedAt.isNull() & + row.isFavorite.equals(true) & + row.ownerId.equals(ownerId), + ); + + MapQuery locked(String userId) => _mapQueryBuilder( + assetFilter: (row) => + row.deletedAt.isNull() & + row.visibility.equalsValue(AssetVisibility.locked) & + row.ownerId.equals(userId), + ); + + MapQuery _mapQueryBuilder({ + Expression Function($RemoteAssetEntityTable row)? assetFilter, + Expression Function($RemoteExifEntityTable row)? exifFilter, + }) { + return ( + markerSource: (bounds) => _watchMapMarker( + assetFilter: assetFilter, + exifFilter: exifFilter, + bounds: bounds, + ) + ); } - Stream> watchRemoteAlbumMarker( - String albumId, { - required LatLngBounds bounds, + Stream> _watchMapMarker({ + Expression Function($RemoteAssetEntityTable row)? assetFilter, + Expression Function($RemoteExifEntityTable row)? exifFilter, + LatLngBounds? bounds, }) { final query = _db.remoteExifEntity.select().join([ innerJoin( @@ -48,20 +58,24 @@ class DriftMapRepository extends DriftDatabaseRepository { _db.remoteAssetEntity.id.equalsExp(_db.remoteExifEntity.assetId), useColumns: false, ), - leftOuterJoin( - _db.remoteAlbumAssetEntity, - _db.remoteAlbumAssetEntity.assetId.equalsExp(_db.remoteAssetEntity.id), - useColumns: false, - ), ]) ..where( _db.remoteExifEntity.latitude.isNotNull() & - _db.remoteExifEntity.longitude.isNotNull() & - _db.remoteExifEntity.inBounds(bounds) & - _db.remoteAssetEntity.deletedAt.isNull() & - _db.remoteAlbumAssetEntity.albumId.equals(albumId), + _db.remoteExifEntity.longitude.isNotNull(), ); + if (assetFilter != null) { + query.where(assetFilter(_db.remoteAssetEntity)); + } + + if (exifFilter != null) { + query.where(exifFilter(_db.remoteExifEntity)); + } + + if (bounds != null) { + query.where(_db.remoteExifEntity.inBounds(bounds)); + } + return query .map((row) => row.readTable(_db.remoteExifEntity).toMarker()) .watch() diff --git a/mobile/lib/presentation/widgets/bottom_sheet/map_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/map_bottom_sheet.widget.dart index 542ededbbf..bc8239a5d3 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/map_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/map_bottom_sheet.widget.dart @@ -19,7 +19,7 @@ class MapBottomSheet extends ConsumerWidget { return ProviderScope( overrides: [ - // TODO: refactor (timeline): when ProviderScope changed, we should refresh timeline + // TODO: when ProviderScope changed, we should refresh timeline timelineServiceProvider.overrideWith((ref) { final timelineService = ref.watch(timelineFactoryProvider).map(bounds); diff --git a/mobile/lib/presentation/widgets/map/map.widget.dart b/mobile/lib/presentation/widgets/map/map.widget.dart index ed99a1f4c0..31e130afcb 100644 --- a/mobile/lib/presentation/widgets/map/map.widget.dart +++ b/mobile/lib/presentation/widgets/map/map.widget.dart @@ -74,7 +74,8 @@ class _DriftMapWithMarkerState extends ConsumerState { } await mapController!.addSource( - MapUtils.defaultSourceId, GeojsonSourceProperties(data: markers), + MapUtils.defaultSourceId, + GeojsonSourceProperties(data: markers), ); if (Platform.isAndroid) { diff --git a/mobile/lib/providers/infrastructure/map.provider.dart b/mobile/lib/providers/infrastructure/map.provider.dart index fa07c0f099..bf37d30d47 100644 --- a/mobile/lib/providers/infrastructure/map.provider.dart +++ b/mobile/lib/providers/infrastructure/map.provider.dart @@ -2,7 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/infrastructure/repositories/map.repository.dart'; import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; import 'package:immich_mobile/domain/services/map.service.dart'; -import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart'; +import 'package:immich_mobile/providers/user.provider.dart'; final mapRepositoryProvider = Provider( (ref) => DriftMapRepository(ref.watch(driftProvider)), @@ -10,8 +10,12 @@ final mapRepositoryProvider = Provider( final mapServiceProvider = Provider( (ref) { - final timelineUsers = ref.watch(timelineUsersProvider).valueOrNull ?? []; - final mapService = ref.watch(mapFactoryProvider).main(timelineUsers); + final user = ref.watch(currentUserProvider); + if (user == null) { + throw Exception('User must be logged in to access map'); + } + + final mapService = ref.watch(mapFactoryProvider).remote(user.id); ref.onDispose(mapService.dispose); return mapService; },