mirror of
https://github.com/immich-app/immich.git
synced 2026-07-08 05:17:54 -07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 41a2fa8a44 |
@@ -85,8 +85,12 @@ class TimelineFactory {
|
|||||||
TimelineService fromAssetsWithBuckets(List<BaseAsset> assets, TimelineOrigin type) =>
|
TimelineService fromAssetsWithBuckets(List<BaseAsset> assets, TimelineOrigin type) =>
|
||||||
TimelineService(_timelineRepository.fromAssetsWithBuckets(assets, type));
|
TimelineService(_timelineRepository.fromAssetsWithBuckets(assets, type));
|
||||||
|
|
||||||
TimelineService map(List<String> userIds, TimelineMapOptions options) =>
|
/// Creates a TimelineService for serving geographical map queries, such assets within bounded locations
|
||||||
TimelineService(_timelineRepository.map(userIds, options, groupBy));
|
TimelineService geographicMap(
|
||||||
|
List<String> userIds,
|
||||||
|
TimelineMapOptions Function() currentOptions,
|
||||||
|
Stream<TimelineMapOptions> optionsStream,
|
||||||
|
) => TimelineService(_timelineRepository.geographicMap(userIds, currentOptions, optionsStream, groupBy));
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimelineService {
|
class TimelineService {
|
||||||
|
|||||||
@@ -509,9 +509,21 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
return query.map((row) => row.toDto()).get();
|
return query.map((row) => row.toDto()).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineQuery map(List<String> userIds, TimelineMapOptions options, GroupAssetsBy groupBy) => (
|
/// Creates a geographic map query that can dynamically filter on changing [TimelineMapOptions]
|
||||||
bucketSource: () => _watchMapBucket(userIds, options, groupBy: groupBy),
|
/// (most notably the active map bounds)
|
||||||
assetSource: (offset, count) => _getMapBucketAssets(userIds, options, offset: offset, count: count),
|
TimelineQuery geographicMap(
|
||||||
|
List<String> userIds,
|
||||||
|
TimelineMapOptions Function() currentOptions,
|
||||||
|
Stream<TimelineMapOptions> optionsStream,
|
||||||
|
GroupAssetsBy groupBy,
|
||||||
|
) => (
|
||||||
|
bucketSource: () => Stream.value(currentOptions())
|
||||||
|
.followedBy(optionsStream)
|
||||||
|
.switchMap(
|
||||||
|
// Any error would kill the stream for all options; make sure the stream stays alive
|
||||||
|
(options) => _watchMapBucket(userIds, options, groupBy: groupBy).handleError((_) {}),
|
||||||
|
),
|
||||||
|
assetSource: (offset, count) => _getMapBucketAssets(userIds, currentOptions(), offset: offset, count: count),
|
||||||
origin: TimelineOrigin.map,
|
origin: TimelineOrigin.map,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ class _ScopedMapTimeline extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// TODO: this causes the timeline to switch to flicker to "loading" state and back. This is both janky and inefficient.
|
|
||||||
return ProviderScope(
|
return ProviderScope(
|
||||||
overrides: [
|
overrides: [
|
||||||
timelineServiceProvider.overrideWith((ref) {
|
timelineServiceProvider.overrideWith((ref) {
|
||||||
@@ -44,13 +43,16 @@ class _ScopedMapTimeline extends StatelessWidget {
|
|||||||
throw Exception('User must be logged in to access archive');
|
throw Exception('User must be logged in to access archive');
|
||||||
}
|
}
|
||||||
|
|
||||||
final users = ref.watch(mapStateProvider).withPartners
|
final withPartners = ref.watch(mapStateProvider.select((s) => s.withPartners));
|
||||||
? ref.watch(timelineUsersProvider).valueOrNull ?? [user.id]
|
final users = withPartners ? ref.watch(timelineUsersProvider).valueOrNull ?? [user.id] : [user.id];
|
||||||
: [user.id];
|
|
||||||
|
|
||||||
final timelineService = ref
|
final timelineService = ref
|
||||||
.watch(timelineFactoryProvider)
|
.watch(timelineFactoryProvider)
|
||||||
.map(users, ref.watch(mapStateProvider).toOptions());
|
.geographicMap(
|
||||||
|
users,
|
||||||
|
() => ref.read(mapStateProvider).toOptions(),
|
||||||
|
ref.read(mapStateProvider.notifier).optionsStream,
|
||||||
|
);
|
||||||
ref.onDispose(timelineService.dispose);
|
ref.onDispose(timelineService.dispose);
|
||||||
return timelineService;
|
return timelineService;
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/events.model.dart';
|
import 'package:immich_mobile/domain/models/events.model.dart';
|
||||||
@@ -63,11 +65,16 @@ class MapState {
|
|||||||
class MapStateNotifier extends Notifier<MapState> {
|
class MapStateNotifier extends Notifier<MapState> {
|
||||||
MapStateNotifier();
|
MapStateNotifier();
|
||||||
|
|
||||||
|
final StreamController<TimelineMapOptions> _optionsController = StreamController.broadcast();
|
||||||
|
|
||||||
|
Stream<TimelineMapOptions> get optionsStream => _optionsController.stream;
|
||||||
|
|
||||||
bool setBounds(LatLngBounds bounds) {
|
bool setBounds(LatLngBounds bounds) {
|
||||||
if (state.bounds == bounds) {
|
if (state.bounds == bounds) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
state = state.copyWith(bounds: bounds);
|
state = state.copyWith(bounds: bounds);
|
||||||
|
_optionsController.add(state.toOptions());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,12 +89,14 @@ class MapStateNotifier extends Notifier<MapState> {
|
|||||||
void switchFavoriteOnly(bool isFavoriteOnly) {
|
void switchFavoriteOnly(bool isFavoriteOnly) {
|
||||||
ref.read(settingsProvider).write(.mapShowFavoriteOnly, isFavoriteOnly);
|
ref.read(settingsProvider).write(.mapShowFavoriteOnly, isFavoriteOnly);
|
||||||
state = state.copyWith(onlyFavorites: isFavoriteOnly);
|
state = state.copyWith(onlyFavorites: isFavoriteOnly);
|
||||||
|
_optionsController.add(state.toOptions());
|
||||||
EventStream.shared.emit(const MapMarkerReloadEvent());
|
EventStream.shared.emit(const MapMarkerReloadEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
void switchIncludeArchived(bool isIncludeArchived) {
|
void switchIncludeArchived(bool isIncludeArchived) {
|
||||||
ref.read(settingsProvider).write(.mapIncludeArchived, isIncludeArchived);
|
ref.read(settingsProvider).write(.mapIncludeArchived, isIncludeArchived);
|
||||||
state = state.copyWith(includeArchived: isIncludeArchived);
|
state = state.copyWith(includeArchived: isIncludeArchived);
|
||||||
|
_optionsController.add(state.toOptions());
|
||||||
EventStream.shared.emit(const MapMarkerReloadEvent());
|
EventStream.shared.emit(const MapMarkerReloadEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,11 +109,13 @@ class MapStateNotifier extends Notifier<MapState> {
|
|||||||
void setRelativeTime(int relativeDays) {
|
void setRelativeTime(int relativeDays) {
|
||||||
ref.read(settingsProvider).write(.mapRelativeDate, relativeDays);
|
ref.read(settingsProvider).write(.mapRelativeDate, relativeDays);
|
||||||
state = state.copyWith(relativeDays: relativeDays);
|
state = state.copyWith(relativeDays: relativeDays);
|
||||||
|
_optionsController.add(state.toOptions());
|
||||||
EventStream.shared.emit(const MapMarkerReloadEvent());
|
EventStream.shared.emit(const MapMarkerReloadEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MapState build() {
|
MapState build() {
|
||||||
|
ref.onDispose(_optionsController.close);
|
||||||
final mapConfig = ref.read(appConfigProvider.select((config) => config.map));
|
final mapConfig = ref.read(appConfigProvider.select((config) => config.map));
|
||||||
return MapState(
|
return MapState(
|
||||||
themeMode: mapConfig.themeMode,
|
themeMode: mapConfig.themeMode,
|
||||||
|
|||||||
Reference in New Issue
Block a user