mirror of
https://github.com/immich-app/immich.git
synced 2025-08-11 09:16:31 -04:00
refactor: map query
This commit is contained in:
parent
48f0e2d898
commit
fca27e1cee
@ -2,7 +2,11 @@ import 'package:immich_mobile/domain/models/map.model.dart';
|
|||||||
import 'package:immich_mobile/infrastructure/repositories/map.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/map.repository.dart';
|
||||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||||
|
|
||||||
typedef MapMarkerSource = Stream<List<Marker>> Function(LatLngBounds bounds);
|
typedef MapMarkerSource = Stream<List<Marker>> Function(LatLngBounds? bounds);
|
||||||
|
|
||||||
|
typedef MapQuery = ({
|
||||||
|
MapMarkerSource markerSource,
|
||||||
|
});
|
||||||
|
|
||||||
class MapFactory {
|
class MapFactory {
|
||||||
final DriftMapRepository _mapRepository;
|
final DriftMapRepository _mapRepository;
|
||||||
@ -11,25 +15,29 @@ class MapFactory {
|
|||||||
required DriftMapRepository mapRepository,
|
required DriftMapRepository mapRepository,
|
||||||
}) : _mapRepository = mapRepository;
|
}) : _mapRepository = mapRepository;
|
||||||
|
|
||||||
MapService main(List<String> timelineUsers) => MapService(
|
MapService remote(String ownerId) =>
|
||||||
markerSource: (bounds) =>
|
MapService(_mapRepository.remote(ownerId));
|
||||||
_mapRepository.watchMainMarker(timelineUsers, bounds: bounds),
|
|
||||||
);
|
|
||||||
|
|
||||||
MapService remoteAlbum({required String albumId}) => MapService(
|
MapService favorite(String ownerId) =>
|
||||||
markerSource: (bounds) =>
|
MapService(_mapRepository.favorite(ownerId));
|
||||||
_mapRepository.watchRemoteAlbumMarker(albumId, bounds: bounds),
|
|
||||||
);
|
MapService locked(String ownerId) =>
|
||||||
|
MapService(_mapRepository.locked(ownerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
class MapService {
|
class MapService {
|
||||||
final MapMarkerSource _markerSource;
|
final MapMarkerSource _markerSource;
|
||||||
|
|
||||||
const MapService({
|
MapService(MapQuery query)
|
||||||
|
: this._(
|
||||||
|
markerSource: query.markerSource,
|
||||||
|
);
|
||||||
|
|
||||||
|
MapService._({
|
||||||
required MapMarkerSource markerSource,
|
required MapMarkerSource markerSource,
|
||||||
}) : _markerSource = markerSource;
|
}) : _markerSource = markerSource;
|
||||||
|
|
||||||
Stream<List<Marker>> Function(LatLngBounds bounds) get watchMarkers =>
|
Stream<List<Marker>> Function(LatLngBounds? bounds) get watchMarkers =>
|
||||||
_markerSource;
|
_markerSource;
|
||||||
|
|
||||||
Future<void> dispose() async {}
|
Future<void> dispose() async {}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.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/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/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:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||||
import 'package:stream_transform/stream_transform.dart';
|
import 'package:stream_transform/stream_transform.dart';
|
||||||
@ -11,36 +13,44 @@ class DriftMapRepository extends DriftDatabaseRepository {
|
|||||||
|
|
||||||
const DriftMapRepository(super._db) : _db = _db;
|
const DriftMapRepository(super._db) : _db = _db;
|
||||||
|
|
||||||
Stream<List<Marker>> watchMainMarker(
|
MapQuery remote(String ownerId) => _mapQueryBuilder(
|
||||||
List<String> userIds, {
|
assetFilter: (row) =>
|
||||||
required LatLngBounds bounds,
|
row.deletedAt.isNull() &
|
||||||
}) {
|
row.visibility.equalsValue(AssetVisibility.timeline) &
|
||||||
final query = _db.remoteExifEntity.select().join([
|
row.ownerId.equals(ownerId),
|
||||||
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),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return query
|
MapQuery favorite(String ownerId) => _mapQueryBuilder(
|
||||||
.map((row) => row.readTable(_db.remoteExifEntity).toMarker())
|
assetFilter: (row) =>
|
||||||
.watch()
|
row.deletedAt.isNull() &
|
||||||
.throttle(const Duration(seconds: 3));
|
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<bool> Function($RemoteAssetEntityTable row)? assetFilter,
|
||||||
|
Expression<bool> Function($RemoteExifEntityTable row)? exifFilter,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
markerSource: (bounds) => _watchMapMarker(
|
||||||
|
assetFilter: assetFilter,
|
||||||
|
exifFilter: exifFilter,
|
||||||
|
bounds: bounds,
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<List<Marker>> watchRemoteAlbumMarker(
|
Stream<List<Marker>> _watchMapMarker({
|
||||||
String albumId, {
|
Expression<bool> Function($RemoteAssetEntityTable row)? assetFilter,
|
||||||
required LatLngBounds bounds,
|
Expression<bool> Function($RemoteExifEntityTable row)? exifFilter,
|
||||||
|
LatLngBounds? bounds,
|
||||||
}) {
|
}) {
|
||||||
final query = _db.remoteExifEntity.select().join([
|
final query = _db.remoteExifEntity.select().join([
|
||||||
innerJoin(
|
innerJoin(
|
||||||
@ -48,20 +58,24 @@ class DriftMapRepository extends DriftDatabaseRepository {
|
|||||||
_db.remoteAssetEntity.id.equalsExp(_db.remoteExifEntity.assetId),
|
_db.remoteAssetEntity.id.equalsExp(_db.remoteExifEntity.assetId),
|
||||||
useColumns: false,
|
useColumns: false,
|
||||||
),
|
),
|
||||||
leftOuterJoin(
|
|
||||||
_db.remoteAlbumAssetEntity,
|
|
||||||
_db.remoteAlbumAssetEntity.assetId.equalsExp(_db.remoteAssetEntity.id),
|
|
||||||
useColumns: false,
|
|
||||||
),
|
|
||||||
])
|
])
|
||||||
..where(
|
..where(
|
||||||
_db.remoteExifEntity.latitude.isNotNull() &
|
_db.remoteExifEntity.latitude.isNotNull() &
|
||||||
_db.remoteExifEntity.longitude.isNotNull() &
|
_db.remoteExifEntity.longitude.isNotNull(),
|
||||||
_db.remoteExifEntity.inBounds(bounds) &
|
|
||||||
_db.remoteAssetEntity.deletedAt.isNull() &
|
|
||||||
_db.remoteAlbumAssetEntity.albumId.equals(albumId),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
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
|
return query
|
||||||
.map((row) => row.readTable(_db.remoteExifEntity).toMarker())
|
.map((row) => row.readTable(_db.remoteExifEntity).toMarker())
|
||||||
.watch()
|
.watch()
|
||||||
|
@ -19,7 +19,7 @@ class MapBottomSheet extends ConsumerWidget {
|
|||||||
|
|
||||||
return ProviderScope(
|
return ProviderScope(
|
||||||
overrides: [
|
overrides: [
|
||||||
// TODO: refactor (timeline): when ProviderScope changed, we should refresh timeline
|
// TODO: when ProviderScope changed, we should refresh timeline
|
||||||
timelineServiceProvider.overrideWith((ref) {
|
timelineServiceProvider.overrideWith((ref) {
|
||||||
final timelineService =
|
final timelineService =
|
||||||
ref.watch(timelineFactoryProvider).map(bounds);
|
ref.watch(timelineFactoryProvider).map(bounds);
|
||||||
|
@ -74,7 +74,8 @@ class _DriftMapWithMarkerState extends ConsumerState<DriftMapWithMarker> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await mapController!.addSource(
|
await mapController!.addSource(
|
||||||
MapUtils.defaultSourceId, GeojsonSourceProperties(data: markers),
|
MapUtils.defaultSourceId,
|
||||||
|
GeojsonSourceProperties(data: markers),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
|
@ -2,7 +2,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:immich_mobile/infrastructure/repositories/map.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/map.repository.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||||
import 'package:immich_mobile/domain/services/map.service.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<DriftMapRepository>(
|
final mapRepositoryProvider = Provider<DriftMapRepository>(
|
||||||
(ref) => DriftMapRepository(ref.watch(driftProvider)),
|
(ref) => DriftMapRepository(ref.watch(driftProvider)),
|
||||||
@ -10,8 +10,12 @@ final mapRepositoryProvider = Provider<DriftMapRepository>(
|
|||||||
|
|
||||||
final mapServiceProvider = Provider<MapService>(
|
final mapServiceProvider = Provider<MapService>(
|
||||||
(ref) {
|
(ref) {
|
||||||
final timelineUsers = ref.watch(timelineUsersProvider).valueOrNull ?? [];
|
final user = ref.watch(currentUserProvider);
|
||||||
final mapService = ref.watch(mapFactoryProvider).main(timelineUsers);
|
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);
|
ref.onDispose(mapService.dispose);
|
||||||
return mapService;
|
return mapService;
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user