mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-22 08:46:18 +01:00
Add a place picker
This commit is contained in:
parent
0c78419c72
commit
92286372cb
14 changed files with 368 additions and 14 deletions
|
@ -1521,6 +1521,7 @@
|
|||
"@customizeButtonsUnsupportedWarning": {
|
||||
"description": "Some button can't be removed. This message will be shown instead when user try to do so"
|
||||
},
|
||||
"placePickerTitle": "Pick a place",
|
||||
|
||||
"errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues",
|
||||
"@errorUnauthenticated": {
|
||||
|
|
|
@ -268,6 +268,7 @@
|
|||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle",
|
||||
"errorUnauthenticated",
|
||||
"errorDisconnected",
|
||||
"errorLocked",
|
||||
|
@ -286,7 +287,8 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
],
|
||||
|
||||
"de": [
|
||||
|
@ -297,7 +299,8 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
],
|
||||
|
||||
"el": [
|
||||
|
@ -453,7 +456,8 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
],
|
||||
|
||||
"es": [
|
||||
|
@ -464,7 +468,8 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
],
|
||||
|
||||
"fi": [
|
||||
|
@ -511,7 +516,8 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
],
|
||||
|
||||
"fr": [
|
||||
|
@ -558,7 +564,8 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
],
|
||||
|
||||
"it": [
|
||||
|
@ -610,7 +617,8 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
],
|
||||
|
||||
"nl": [
|
||||
|
@ -999,6 +1007,7 @@
|
|||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle",
|
||||
"errorUnauthenticated",
|
||||
"errorDisconnected",
|
||||
"errorLocked",
|
||||
|
@ -1057,7 +1066,8 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
],
|
||||
|
||||
"pt": [
|
||||
|
@ -1124,7 +1134,8 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
],
|
||||
|
||||
"ru": [
|
||||
|
@ -1171,7 +1182,8 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
],
|
||||
|
||||
"tr": [
|
||||
|
@ -1182,7 +1194,8 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
],
|
||||
|
||||
"zh": [
|
||||
|
@ -1260,7 +1273,8 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
],
|
||||
|
||||
"zh_Hant": [
|
||||
|
@ -1432,6 +1446,7 @@
|
|||
"livePhotoTooltip",
|
||||
"dragAndDropRearrangeButtons",
|
||||
"customizeCollectionsNavBarDescription",
|
||||
"customizeButtonsUnsupportedWarning"
|
||||
"customizeButtonsUnsupportedWarning",
|
||||
"placePickerTitle"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import 'package:nc_photos/widget/image_enhancer.dart';
|
|||
import 'package:nc_photos/widget/local_file_viewer.dart';
|
||||
import 'package:nc_photos/widget/map_browser.dart';
|
||||
import 'package:nc_photos/widget/people_browser.dart';
|
||||
import 'package:nc_photos/widget/place_picker/place_picker.dart';
|
||||
import 'package:nc_photos/widget/places_browser.dart';
|
||||
import 'package:nc_photos/widget/result_viewer.dart';
|
||||
import 'package:nc_photos/widget/root_picker.dart';
|
||||
|
@ -213,6 +214,7 @@ class _WrappedAppState extends State<_WrappedApp>
|
|||
ArchiveBrowser.routeName: ArchiveBrowser.buildRoute,
|
||||
TrustedCertManager.routeName: TrustedCertManager.buildRoute,
|
||||
MapBrowser.routeName: MapBrowser.buildRoute,
|
||||
PlacePicker.routeName: PlacePicker.buildRoute,
|
||||
};
|
||||
|
||||
Route<dynamic>? _onGenerateRoute(RouteSettings settings) {
|
||||
|
|
21
app/lib/widget/place_picker/bloc.dart
Normal file
21
app/lib/widget/place_picker/bloc.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
part of 'place_picker.dart';
|
||||
|
||||
@npLog
|
||||
class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
||||
_Bloc() : super(_State.init()) {
|
||||
on<_SetPosition>(_onSetPosition);
|
||||
}
|
||||
|
||||
@override
|
||||
String get tag => _log.fullName;
|
||||
|
||||
@override
|
||||
bool Function(dynamic, dynamic)? get shouldLog => (currentState, nextState) {
|
||||
return currentState.position == nextState.position;
|
||||
};
|
||||
|
||||
void _onSetPosition(_SetPosition ev, _Emitter emit) {
|
||||
// _log.info(ev);
|
||||
emit(state.copyWith(position: ev.value));
|
||||
}
|
||||
}
|
93
app/lib/widget/place_picker/place_picker.dart
Normal file
93
app/lib/widget/place_picker/place_picker.dart
Normal file
|
@ -0,0 +1,93 @@
|
|||
import 'package:copy_with/copy_with.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:nc_photos/app_localizations.dart';
|
||||
import 'package:nc_photos/bloc_util.dart';
|
||||
import 'package:nc_photos/controller/pref_controller.dart';
|
||||
import 'package:nc_photos/stream_util.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_gps_map/np_gps_map.dart';
|
||||
import 'package:to_string/to_string.dart';
|
||||
|
||||
part 'bloc.dart';
|
||||
part 'place_picker.g.dart';
|
||||
part 'state_event.dart';
|
||||
|
||||
class PlacePicker extends StatelessWidget {
|
||||
static const routeName = "/place-picker";
|
||||
|
||||
static Route buildRoute(RouteSettings settings) =>
|
||||
MaterialPageRoute<CameraPosition>(
|
||||
builder: (_) => const PlacePicker(),
|
||||
settings: settings,
|
||||
);
|
||||
|
||||
const PlacePicker({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => _Bloc(),
|
||||
child: const _WrappedPlacePicker(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@npLog
|
||||
class _WrappedPlacePicker extends StatelessWidget {
|
||||
const _WrappedPlacePicker();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(L10n.global().placePickerTitle),
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
final position = context.state.position;
|
||||
_log.info("[build] Position picked: $position");
|
||||
Navigator.of(context).pop(position);
|
||||
},
|
||||
icon: const Icon(Icons.check_outlined),
|
||||
),
|
||||
),
|
||||
body: const _BodyView(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _BodyView extends StatelessWidget {
|
||||
const _BodyView();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final prevPosition =
|
||||
context.read<PrefController>().mapBrowserPrevPositionValue;
|
||||
return ValueStreamBuilderEx<GpsMapProvider>(
|
||||
stream: context.read<PrefController>().gpsMapProvider,
|
||||
builder: StreamWidgetBuilder.value(
|
||||
(context, gpsMapProvider) => PlacePickerView(
|
||||
providerHint: gpsMapProvider,
|
||||
initialPosition: prevPosition ?? const MapCoord(0, 0),
|
||||
initialZoom: prevPosition == null ? 2.5 : 10,
|
||||
onCameraMove: (position) {
|
||||
context.addEvent(_SetPosition(position));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// typedef _BlocBuilder = BlocBuilder<_Bloc, _State>;
|
||||
// typedef _BlocListener = BlocListener<_Bloc, _State>;
|
||||
// typedef _BlocListenerT<T> = BlocListenerT<_Bloc, _State, T>;
|
||||
// typedef _BlocSelector<T> = BlocSelector<_Bloc, _State, T>;
|
||||
typedef _Emitter = Emitter<_State>;
|
||||
|
||||
extension on BuildContext {
|
||||
_Bloc get bloc => read<_Bloc>();
|
||||
_State get state => bloc.state;
|
||||
void addEvent(_Event event) => bloc.add(event);
|
||||
}
|
73
app/lib/widget/place_picker/place_picker.g.dart
Normal file
73
app/lib/widget/place_picker/place_picker.g.dart
Normal file
|
@ -0,0 +1,73 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'place_picker.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// CopyWithLintRuleGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// ignore_for_file: library_private_types_in_public_api, duplicate_ignore
|
||||
|
||||
// **************************************************************************
|
||||
// CopyWithGenerator
|
||||
// **************************************************************************
|
||||
|
||||
abstract class $_StateCopyWithWorker {
|
||||
_State call({CameraPosition? position});
|
||||
}
|
||||
|
||||
class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
|
||||
_$_StateCopyWithWorkerImpl(this.that);
|
||||
|
||||
@override
|
||||
_State call({dynamic position = copyWithNull}) {
|
||||
return _State(
|
||||
position: position == copyWithNull
|
||||
? that.position
|
||||
: position as CameraPosition?);
|
||||
}
|
||||
|
||||
final _State that;
|
||||
}
|
||||
|
||||
extension $_StateCopyWith on _State {
|
||||
$_StateCopyWithWorker get copyWith => _$copyWith;
|
||||
$_StateCopyWithWorker get _$copyWith => _$_StateCopyWithWorkerImpl(this);
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// NpLogGenerator
|
||||
// **************************************************************************
|
||||
|
||||
extension _$_WrappedPlacePickerNpLog on _WrappedPlacePicker {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
||||
static final log =
|
||||
Logger("widget.place_picker.place_picker._WrappedPlacePicker");
|
||||
}
|
||||
|
||||
extension _$_BlocNpLog on _Bloc {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
||||
static final log = Logger("widget.place_picker.place_picker._Bloc");
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// ToStringGenerator
|
||||
// **************************************************************************
|
||||
|
||||
extension _$_StateToString on _State {
|
||||
String _$toString() {
|
||||
// ignore: unnecessary_string_interpolations
|
||||
return "_State {position: $position}";
|
||||
}
|
||||
}
|
||||
|
||||
extension _$_SetPositionToString on _SetPosition {
|
||||
String _$toString() {
|
||||
// ignore: unnecessary_string_interpolations
|
||||
return "_SetPosition {value: $value}";
|
||||
}
|
||||
}
|
28
app/lib/widget/place_picker/state_event.dart
Normal file
28
app/lib/widget/place_picker/state_event.dart
Normal file
|
@ -0,0 +1,28 @@
|
|||
part of 'place_picker.dart';
|
||||
|
||||
@genCopyWith
|
||||
@toString
|
||||
class _State {
|
||||
const _State({
|
||||
this.position,
|
||||
});
|
||||
|
||||
factory _State.init() => const _State();
|
||||
|
||||
@override
|
||||
String toString() => _$toString();
|
||||
|
||||
final CameraPosition? position;
|
||||
}
|
||||
|
||||
abstract class _Event {}
|
||||
|
||||
@toString
|
||||
class _SetPosition implements _Event {
|
||||
const _SetPosition(this.value);
|
||||
|
||||
@override
|
||||
String toString() => _$toString();
|
||||
|
||||
final CameraPosition value;
|
||||
}
|
|
@ -3,4 +3,6 @@ library np_gps_map;
|
|||
export 'src/gps_map.dart';
|
||||
export 'src/interactive_map.dart';
|
||||
export 'src/map_coord.dart';
|
||||
export 'src/place_picker.dart';
|
||||
export 'src/type.dart';
|
||||
export 'src/util.dart' show initGpsMap;
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'package:np_gps_map/src/gps_map.dart';
|
|||
import 'package:np_gps_map/src/interactive_map/google.dart';
|
||||
import 'package:np_gps_map/src/interactive_map/osm.dart';
|
||||
import 'package:np_gps_map/src/map_coord.dart';
|
||||
import 'package:np_gps_map/src/type.dart';
|
||||
import 'package:np_gps_map/src/util.dart';
|
||||
import 'package:np_platform_util/np_platform_util.dart';
|
||||
|
||||
|
@ -31,6 +32,7 @@ class InteractiveMap extends StatelessWidget {
|
|||
this.googleClusterBuilder,
|
||||
this.contentPadding,
|
||||
this.onMapCreated,
|
||||
this.onCameraMove,
|
||||
});
|
||||
|
||||
@override
|
||||
|
@ -45,6 +47,7 @@ class InteractiveMap extends StatelessWidget {
|
|||
clusterBuilder: osmClusterBuilder,
|
||||
contentPadding: contentPadding,
|
||||
onMapCreated: onMapCreated,
|
||||
onCameraMove: onCameraMove,
|
||||
);
|
||||
} else {
|
||||
return GoogleInteractiveMap(
|
||||
|
@ -55,6 +58,7 @@ class InteractiveMap extends StatelessWidget {
|
|||
clusterBuilder: googleClusterBuilder,
|
||||
contentPadding: contentPadding,
|
||||
onMapCreated: onMapCreated,
|
||||
onCameraMove: onCameraMove,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -70,4 +74,5 @@ class InteractiveMap extends StatelessWidget {
|
|||
final OsmClusterBuilder? osmClusterBuilder;
|
||||
final EdgeInsets? contentPadding;
|
||||
final void Function(InteractiveMapController controller)? onMapCreated;
|
||||
final void Function(CameraPosition position)? onCameraMove;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,11 @@ import 'dart:async';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:latlong2/latlong.dart' as type;
|
||||
import 'package:np_common/object_util.dart';
|
||||
import 'package:np_gps_map/src/interactive_map.dart';
|
||||
import 'package:np_gps_map/src/map_coord.dart';
|
||||
import 'package:np_gps_map/src/type.dart' as type;
|
||||
|
||||
typedef GoogleClusterBuilder = FutureOr<BitmapDescriptor> Function(
|
||||
BuildContext context, List<DataPoint> dataPoints);
|
||||
|
@ -20,6 +22,7 @@ class GoogleInteractiveMap extends StatefulWidget {
|
|||
this.onClusterTap,
|
||||
this.contentPadding,
|
||||
this.onMapCreated,
|
||||
this.onCameraMove,
|
||||
});
|
||||
|
||||
@override
|
||||
|
@ -32,6 +35,7 @@ class GoogleInteractiveMap extends StatefulWidget {
|
|||
final void Function(List<DataPoint> dataPoints)? onClusterTap;
|
||||
final EdgeInsets? contentPadding;
|
||||
final void Function(InteractiveMapController controller)? onMapCreated;
|
||||
final void Function(type.CameraPosition position)? onCameraMove;
|
||||
}
|
||||
|
||||
class _GoogleInteractiveMapState extends State<GoogleInteractiveMap> {
|
||||
|
@ -57,7 +61,17 @@ class _GoogleInteractiveMapState extends State<GoogleInteractiveMap> {
|
|||
const CameraPosition(target: LatLng(0, 0)),
|
||||
markers: _markers,
|
||||
onMapCreated: _onMapCreated,
|
||||
onCameraMove: _clusterManager.onCameraMove,
|
||||
onCameraMove: (position) {
|
||||
_clusterManager.onCameraMove(position);
|
||||
widget.onCameraMove?.call(type.CameraPosition(
|
||||
center: type.LatLng(
|
||||
position.target.latitude,
|
||||
position.target.longitude,
|
||||
),
|
||||
zoom: position.zoom,
|
||||
rotation: position.bearing,
|
||||
));
|
||||
},
|
||||
onCameraIdle: _clusterManager.updateMap,
|
||||
padding: widget.contentPadding ?? EdgeInsets.zero,
|
||||
);
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:latlong2/latlong.dart';
|
|||
import 'package:np_common/object_util.dart';
|
||||
import 'package:np_gps_map/src/interactive_map.dart';
|
||||
import 'package:np_gps_map/src/map_coord.dart';
|
||||
import 'package:np_gps_map/src/type.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
typedef OsmClusterBuilder = Widget Function(
|
||||
|
@ -23,6 +24,7 @@ class OsmInteractiveMap extends StatefulWidget {
|
|||
this.onClusterTap,
|
||||
this.contentPadding,
|
||||
this.onMapCreated,
|
||||
this.onCameraMove,
|
||||
});
|
||||
|
||||
@override
|
||||
|
@ -35,6 +37,7 @@ class OsmInteractiveMap extends StatefulWidget {
|
|||
final void Function(List<DataPoint> dataPoints)? onClusterTap;
|
||||
final EdgeInsets? contentPadding;
|
||||
final void Function(InteractiveMapController controller)? onMapCreated;
|
||||
final void Function(CameraPosition position)? onCameraMove;
|
||||
}
|
||||
|
||||
class _OsmInteractiveMapState extends State<OsmInteractiveMap> {
|
||||
|
@ -47,6 +50,11 @@ class _OsmInteractiveMapState extends State<OsmInteractiveMap> {
|
|||
widget.onMapCreated?.call(_parentController!);
|
||||
_subscriptions.add(_controller.mapEventStream.listen((ev) {
|
||||
_mapRotationRadSubject.add(ev.camera.rotationRad);
|
||||
widget.onCameraMove?.call(CameraPosition(
|
||||
center: ev.camera.center,
|
||||
zoom: ev.camera.zoom,
|
||||
rotation: (360 - ev.camera.rotation) % 360,
|
||||
));
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
|
46
np_gps_map/lib/src/place_picker.dart
Normal file
46
np_gps_map/lib/src/place_picker.dart
Normal file
|
@ -0,0 +1,46 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:np_gps_map/src/gps_map.dart';
|
||||
import 'package:np_gps_map/src/interactive_map.dart';
|
||||
import 'package:np_gps_map/src/map_coord.dart';
|
||||
import 'package:np_gps_map/src/type.dart';
|
||||
|
||||
class PlacePickerView extends StatelessWidget {
|
||||
const PlacePickerView({
|
||||
super.key,
|
||||
required this.providerHint,
|
||||
this.initialPosition,
|
||||
this.initialZoom,
|
||||
this.contentPadding,
|
||||
this.onCameraMove,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
InteractiveMap(
|
||||
providerHint: providerHint,
|
||||
initialPosition: initialPosition,
|
||||
initialZoom: initialZoom,
|
||||
contentPadding: contentPadding,
|
||||
onCameraMove: onCameraMove,
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Transform.translate(
|
||||
// 48(height) / 2
|
||||
offset: const Offset(0, -24),
|
||||
child: Center(
|
||||
child: Image.asset("packages/np_gps_map/assets/gps_map_pin.png"),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
final GpsMapProvider providerHint;
|
||||
final MapCoord? initialPosition;
|
||||
final double? initialZoom;
|
||||
final EdgeInsets? contentPadding;
|
||||
final void Function(CameraPosition position)? onCameraMove;
|
||||
}
|
45
np_gps_map/lib/src/type.dart
Normal file
45
np_gps_map/lib/src/type.dart
Normal file
|
@ -0,0 +1,45 @@
|
|||
import 'package:equatable/equatable.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:np_common/type.dart';
|
||||
|
||||
class CameraPosition with EquatableMixin {
|
||||
const CameraPosition({
|
||||
required this.center,
|
||||
required this.zoom,
|
||||
required this.rotation,
|
||||
});
|
||||
|
||||
factory CameraPosition.fromJson(JsonObj json) {
|
||||
return CameraPosition(
|
||||
center: LatLng.fromJson(json["center"]),
|
||||
zoom: json["zoom"],
|
||||
rotation: json["rotation"],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => "CameraPosition {"
|
||||
"center: $center, "
|
||||
"zoom: $zoom, "
|
||||
"rotation: $rotation, "
|
||||
"}";
|
||||
|
||||
JsonObj toJson() {
|
||||
return {
|
||||
"center": center.toJson(),
|
||||
"zoom": zoom,
|
||||
"rotation": rotation,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [center, zoom, rotation];
|
||||
|
||||
final LatLng center;
|
||||
final double zoom;
|
||||
// The camera's bearing in degrees, measured clockwise from north.
|
||||
//
|
||||
// A bearing of 0.0, the default, means the camera points north.
|
||||
// A bearing of 90.0 means the camera points east.
|
||||
final double rotation;
|
||||
}
|
|
@ -9,6 +9,7 @@ environment:
|
|||
flutter: ">=3.19.0"
|
||||
|
||||
dependencies:
|
||||
equatable: ^2.0.5
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_map: ^6.1.0
|
||||
|
|
Loading…
Reference in a new issue