mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-24 02:18:50 +01:00
Map browser now default to the position of the last known latest photo
This commit is contained in:
parent
0c8b611e46
commit
8c8dcb3e8e
11 changed files with 95 additions and 16 deletions
|
@ -1,11 +1,14 @@
|
|||
// ignore_for_file: deprecated_member_use_from_same_package
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/di_container.dart';
|
||||
import 'package:nc_photos/entity/collection/util.dart';
|
||||
import 'package:nc_photos/entity/pref.dart';
|
||||
import 'package:nc_photos/json_util.dart';
|
||||
import 'package:nc_photos/language_util.dart';
|
||||
import 'package:nc_photos/object_extension.dart';
|
||||
import 'package:nc_photos/protected_page_handler.dart';
|
||||
|
@ -158,6 +161,13 @@ class PrefController {
|
|||
value: value,
|
||||
);
|
||||
|
||||
Future<bool> setMapBrowserPrevPosition(MapCoord value) => _set<MapCoord?>(
|
||||
controller: _mapBrowserPrevPositionController,
|
||||
setter: (pref, value) => pref.setMapBrowserPrevPosition(
|
||||
jsonEncode([value!.latitude, value.longitude])),
|
||||
value: value,
|
||||
);
|
||||
|
||||
Future<bool> _set<T>({
|
||||
required BehaviorSubject<T> controller,
|
||||
required Future<bool> Function(Pref pref, T value) setter,
|
||||
|
@ -258,6 +268,11 @@ class PrefController {
|
|||
@npSubjectAccessor
|
||||
late final _isDontShowVideoPreviewHintController =
|
||||
BehaviorSubject.seeded(_c.pref.isDontShowVideoPreviewHintOr(false));
|
||||
@npSubjectAccessor
|
||||
late final _mapBrowserPrevPositionController = BehaviorSubject.seeded(_c.pref
|
||||
.getMapBrowserPrevPosition()
|
||||
?.let(tryJsonDecode)
|
||||
?.let(_tryMapCoordFromJson));
|
||||
}
|
||||
|
||||
@npSubjectAccessor
|
||||
|
|
|
@ -157,6 +157,15 @@ extension $PrefControllerNpSubjectAccessor on PrefController {
|
|||
isDontShowVideoPreviewHint.distinct().skip(1);
|
||||
bool get isDontShowVideoPreviewHintValue =>
|
||||
_isDontShowVideoPreviewHintController.value;
|
||||
// _mapBrowserPrevPositionController
|
||||
ValueStream<MapCoord?> get mapBrowserPrevPosition =>
|
||||
_mapBrowserPrevPositionController.stream;
|
||||
Stream<MapCoord?> get mapBrowserPrevPositionNew =>
|
||||
mapBrowserPrevPosition.skip(1);
|
||||
Stream<MapCoord?> get mapBrowserPrevPositionChange =>
|
||||
mapBrowserPrevPosition.distinct().skip(1);
|
||||
MapCoord? get mapBrowserPrevPositionValue =>
|
||||
_mapBrowserPrevPositionController.value;
|
||||
}
|
||||
|
||||
extension $SecurePrefControllerNpSubjectAccessor on SecurePrefController {
|
||||
|
|
|
@ -88,4 +88,20 @@ extension on Pref {
|
|||
isDontShowVideoPreviewHint() ?? def;
|
||||
Future<bool> setDontShowVideoPreviewHint(bool value) =>
|
||||
provider.setBool(PrefKey.dontShowVideoPreviewHint, value);
|
||||
|
||||
String? getMapBrowserPrevPosition() =>
|
||||
provider.getString(PrefKey.mapBrowserPrevPosition);
|
||||
Future<bool> setMapBrowserPrevPosition(String value) =>
|
||||
provider.setString(PrefKey.mapBrowserPrevPosition, value);
|
||||
}
|
||||
|
||||
MapCoord? _tryMapCoordFromJson(dynamic json) {
|
||||
try {
|
||||
final j = (json as List).cast<double>();
|
||||
return MapCoord(j[0], j[1]);
|
||||
} catch (e, stackTrace) {
|
||||
_$__NpLog.log
|
||||
.severe("[_tryMapCoordFromJson] Failed to parse json", e, stackTrace);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ enum PrefKey implements PrefKeyInterface {
|
|||
protectedPageAuthPin,
|
||||
protectedPageAuthPassword,
|
||||
dontShowVideoPreviewHint,
|
||||
mapBrowserPrevPosition,
|
||||
;
|
||||
|
||||
@override
|
||||
|
@ -199,6 +200,8 @@ enum PrefKey implements PrefKeyInterface {
|
|||
return "protectedPageAuthPassword";
|
||||
case PrefKey.dontShowVideoPreviewHint:
|
||||
return "dontShowVideoPreviewHint";
|
||||
case PrefKey.mapBrowserPrevPosition:
|
||||
return "mapBrowserPrevPosition";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:nc_photos/object_extension.dart';
|
||||
|
||||
/// Convert a boolean to an indexable type in json for DB
|
||||
|
@ -8,3 +10,14 @@ Object? boolToJson(bool? value) => value?.run((v) => v ? 1 : 0);
|
|||
|
||||
/// Convert a boolean from an indexable type in json for DB
|
||||
bool? boolFromJson(Object? value) => value?.run((v) => v != 0);
|
||||
|
||||
Object? tryJsonDecode(String source) {
|
||||
try {
|
||||
return jsonDecode(source);
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Object? jsonDecodeOr(String source, dynamic def) =>
|
||||
tryJsonDecode(source) ?? def;
|
||||
|
|
|
@ -15,6 +15,7 @@ import 'package:nc_photos/account.dart';
|
|||
import 'package:nc_photos/app_localizations.dart';
|
||||
import 'package:nc_photos/bloc_util.dart';
|
||||
import 'package:nc_photos/controller/account_controller.dart';
|
||||
import 'package:nc_photos/controller/pref_controller.dart';
|
||||
import 'package:nc_photos/di_container.dart';
|
||||
import 'package:nc_photos/entity/collection.dart';
|
||||
import 'package:nc_photos/entity/collection/content_provider/ad_hoc.dart';
|
||||
|
@ -27,7 +28,9 @@ import 'package:nc_photos/theme.dart';
|
|||
import 'package:nc_photos/widget/collection_browser.dart';
|
||||
import 'package:nc_photos/widget/measure.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_common/object_util.dart';
|
||||
import 'package:np_datetime/np_datetime.dart';
|
||||
import 'package:np_gps_map/np_gps_map.dart';
|
||||
import 'package:to_string/to_string.dart';
|
||||
|
||||
part 'map_browser.g.dart';
|
||||
|
@ -51,6 +54,7 @@ class MapBrowser extends StatelessWidget {
|
|||
create: (_) => _Bloc(
|
||||
KiwiContainer().resolve(),
|
||||
account: context.read<AccountController>().account,
|
||||
prefController: context.read(),
|
||||
)..add(const _LoadData()),
|
||||
child: const _WrappedMapBrowser(),
|
||||
);
|
||||
|
|
|
@ -15,7 +15,7 @@ part of 'map_browser.dart';
|
|||
abstract class $_StateCopyWithWorker {
|
||||
_State call(
|
||||
{List<_DataPoint>? data,
|
||||
LatLng? initialPoint,
|
||||
MapCoord? initialPoint,
|
||||
Set<Marker>? markers,
|
||||
bool? isShowDataRangeControlPanel,
|
||||
_DateRangeType? dateRangeType,
|
||||
|
@ -39,7 +39,7 @@ class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
|
|||
data: data as List<_DataPoint>? ?? that.data,
|
||||
initialPoint: initialPoint == copyWithNull
|
||||
? that.initialPoint
|
||||
: initialPoint as LatLng?,
|
||||
: initialPoint as MapCoord?,
|
||||
markers: markers as Set<Marker>? ?? that.markers,
|
||||
isShowDataRangeControlPanel: isShowDataRangeControlPanel as bool? ??
|
||||
that.isShowDataRangeControlPanel,
|
||||
|
|
|
@ -6,6 +6,7 @@ class _Bloc extends Bloc<_Event, _State>
|
|||
_Bloc(
|
||||
this._c, {
|
||||
required this.account,
|
||||
required this.prefController,
|
||||
}) : super(_State.init(
|
||||
dateRangeType: _DateRangeType.thisMonth,
|
||||
localDateRange:
|
||||
|
@ -59,13 +60,21 @@ class _Bloc extends Bloc<_Event, _State>
|
|||
);
|
||||
final raw = await _c.imageLocationRepo.getLocations(account, utcTimeRange);
|
||||
_log.info("[_onLoadData] Loaded ${raw.length} markers");
|
||||
emit(state.copyWith(
|
||||
data: raw.map(_DataPoint.fromImageLatLng).toList(),
|
||||
initialPoint: state.initialPoint ??
|
||||
(raw.firstOrNull == null
|
||||
? null
|
||||
: LatLng(raw.first.latitude, raw.first.longitude)),
|
||||
));
|
||||
if (state.initialPoint == null) {
|
||||
final initialPoint =
|
||||
raw.firstOrNull?.let((obj) => MapCoord(obj.latitude, obj.longitude));
|
||||
if (initialPoint != null) {
|
||||
unawaited(prefController.setMapBrowserPrevPosition(initialPoint));
|
||||
}
|
||||
emit(state.copyWith(
|
||||
data: raw.map(_DataPoint.fromImageLatLng).toList(),
|
||||
initialPoint: initialPoint,
|
||||
));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
data: raw.map(_DataPoint.fromImageLatLng).toList(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _onSetMarkers(_SetMarkers ev, Emitter<_State> emit) {
|
||||
|
@ -151,6 +160,7 @@ class _Bloc extends Bloc<_Event, _State>
|
|||
|
||||
final DiContainer _c;
|
||||
final Account account;
|
||||
final PrefController prefController;
|
||||
|
||||
final _subscriptions = <StreamSubscription>[];
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ class _State {
|
|||
String toString() => _$toString();
|
||||
|
||||
final List<_DataPoint> data;
|
||||
final LatLng? initialPoint;
|
||||
final MapCoord? initialPoint;
|
||||
final Set<Marker> markers;
|
||||
|
||||
final bool isShowDataRangeControlPanel;
|
||||
|
|
|
@ -40,3 +40,7 @@ enum _DateRangeType {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension on MapCoord {
|
||||
LatLng toLatLng() => LatLng(latitude, longitude);
|
||||
}
|
||||
|
|
|
@ -18,12 +18,12 @@ class _MapViewState extends State<_MapView> {
|
|||
_clusterManager.setItems(data);
|
||||
},
|
||||
),
|
||||
_BlocListenerT<LatLng?>(
|
||||
_BlocListenerT<MapCoord?>(
|
||||
selector: (state) => state.initialPoint,
|
||||
listener: (context, initialPoint) {
|
||||
if (initialPoint != null) {
|
||||
_mapController
|
||||
?.animateCamera(CameraUpdate.newLatLngZoom(initialPoint, 10));
|
||||
_mapController?.animateCamera(
|
||||
CameraUpdate.newLatLngZoom(initialPoint.toLatLng(), 10));
|
||||
}
|
||||
},
|
||||
),
|
||||
|
@ -32,14 +32,19 @@ class _MapViewState extends State<_MapView> {
|
|||
buildWhen: (previous, current) => previous.markers != current.markers,
|
||||
builder: (context, state) => GoogleMap(
|
||||
mapType: MapType.normal,
|
||||
initialCameraPosition: const CameraPosition(target: LatLng(0, 0)),
|
||||
initialCameraPosition: context
|
||||
.read<PrefController>()
|
||||
.mapBrowserPrevPositionValue
|
||||
?.let(
|
||||
(p) => CameraPosition(target: p.toLatLng(), zoom: 10)) ??
|
||||
const CameraPosition(target: LatLng(0, 0)),
|
||||
markers: state.markers,
|
||||
onMapCreated: (controller) {
|
||||
_clusterManager.setMapId(controller.mapId);
|
||||
_mapController = controller;
|
||||
if (state.initialPoint != null) {
|
||||
controller.animateCamera(
|
||||
CameraUpdate.newLatLngZoom(state.initialPoint!, 10));
|
||||
controller.animateCamera(CameraUpdate.newLatLngZoom(
|
||||
state.initialPoint!.toLatLng(), 10));
|
||||
}
|
||||
},
|
||||
onCameraMove: _clusterManager.onCameraMove,
|
||||
|
|
Loading…
Reference in a new issue