ente/lib/ui/map/map_view.dart

188 lines
5.5 KiB
Dart
Raw Normal View History

import "package:flutter/material.dart";
import "package:flutter_map/flutter_map.dart";
import "package:flutter_map_marker_cluster/flutter_map_marker_cluster.dart";
import "package:latlong2/latlong.dart";
import "package:photos/ui/map/image_marker.dart";
import "package:photos/ui/map/map_button.dart";
import 'package:photos/ui/map/map_gallery_tile.dart';
import 'package:photos/ui/map/map_gallery_tile_badge.dart';
import "package:photos/ui/map/map_marker.dart";
2023-06-07 11:08:25 +00:00
import "package:photos/ui/map/tile/layers.dart";
import "package:photos/utils/debouncer.dart";
class MapView extends StatefulWidget {
final List<ImageMarker> imageMarkers;
final Function updateVisibleImages;
final MapController controller;
final LatLng center;
final double minZoom;
final double maxZoom;
final double initialZoom;
final int debounceDuration;
2023-06-22 05:50:03 +00:00
final double bottomSheetDraggableAreaHeight;
const MapView({
Key? key,
required this.updateVisibleImages,
required this.imageMarkers,
required this.controller,
required this.center,
required this.minZoom,
required this.maxZoom,
required this.initialZoom,
required this.debounceDuration,
2023-06-22 05:50:03 +00:00
required this.bottomSheetDraggableAreaHeight,
}) : super(key: key);
@override
State<StatefulWidget> createState() => _MapViewState();
}
class _MapViewState extends State<MapView> {
2023-06-14 17:39:16 +00:00
late List<Marker> _markers;
final _debouncer = Debouncer(
const Duration(milliseconds: 300),
executionInterval: const Duration(milliseconds: 750),
);
2023-06-05 13:11:39 +00:00
@override
void initState() {
super.initState();
2023-06-14 17:39:16 +00:00
_markers = _buildMakers();
2023-06-05 13:11:39 +00:00
}
@override
void dispose() {
super.dispose();
}
2023-06-14 18:27:34 +00:00
void onChange(LatLngBounds bounds) {
_debouncer.run(
() async {
widget.updateVisibleImages(bounds);
},
);
2023-06-14 18:27:34 +00:00
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
FlutterMap(
mapController: widget.controller,
options: MapOptions(
2023-06-10 07:21:34 +00:00
center: widget.center,
minZoom: widget.minZoom,
maxZoom: widget.maxZoom,
enableMultiFingerGestureRace: true,
2023-06-10 07:21:34 +00:00
zoom: widget.initialZoom,
maxBounds: LatLngBounds(
LatLng(-90, -180),
LatLng(90, 180),
),
onPositionChanged: (position, hasGesture) {
if (position.bounds != null) {
2023-06-14 18:27:34 +00:00
onChange(position.bounds!);
}
},
),
2023-06-22 05:50:03 +00:00
nonRotatedChildren: [
2023-06-21 17:19:56 +00:00
Padding(
2023-06-22 05:50:03 +00:00
padding: EdgeInsets.only(
bottom: widget.bottomSheetDraggableAreaHeight,
),
child: const OSMFranceTileAttributes(),
2023-08-19 11:39:56 +00:00
),
2023-06-21 17:19:56 +00:00
],
2023-06-07 11:08:25 +00:00
children: [
const OSMFranceTileLayer(),
2023-06-06 09:45:18 +00:00
MarkerClusterLayerWidget(
options: MarkerClusterLayerOptions(
anchorPos: AnchorPos.align(AnchorAlign.top),
2023-06-06 09:45:18 +00:00
maxClusterRadius: 100,
2023-06-14 17:39:16 +00:00
showPolygon: false,
2023-06-06 09:45:18 +00:00
size: const Size(75, 75),
fitBoundsOptions: const FitBoundsOptions(
padding: EdgeInsets.all(80),
2023-06-06 09:45:18 +00:00
),
2023-06-14 17:39:16 +00:00
markers: _markers,
2023-06-14 18:27:34 +00:00
onClusterTap: (_) {
2023-06-28 11:39:35 +00:00
onChange(widget.controller.bounds!);
2023-06-14 18:27:34 +00:00
},
2023-06-14 17:39:16 +00:00
builder: (context, List<Marker> markers) {
2023-06-06 09:45:18 +00:00
final index = int.parse(
markers.first.key
.toString()
.replaceAll(RegExp(r'[^0-9]'), ''),
);
2023-06-14 17:39:16 +00:00
final String clusterKey =
'map-badge-$index-len-${markers.length}';
2023-06-06 09:45:18 +00:00
return Stack(
2023-06-14 17:39:16 +00:00
key: ValueKey(clusterKey),
2023-06-06 09:45:18 +00:00
children: [
MapGalleryTile(
key: Key(markers.first.key.toString()),
imageMarker: widget.imageMarkers[index],
),
2023-08-19 11:39:56 +00:00
MapGalleryTileBadge(size: markers.length),
2023-06-06 09:45:18 +00:00
],
);
},
),
2023-08-19 11:39:56 +00:00
),
],
),
Positioned(
top: 4,
left: 10,
child: SafeArea(
child: MapButton(
icon: Icons.arrow_back,
onPressed: () {
Navigator.pop(context);
},
heroTag: 'back',
),
),
),
Positioned(
2023-06-22 05:50:03 +00:00
bottom: widget.bottomSheetDraggableAreaHeight + 10,
right: 10,
child: Column(
children: [
MapButton(
icon: Icons.add,
onPressed: () {
widget.controller.move(
widget.controller.center,
widget.controller.zoom + 1,
);
},
heroTag: 'zoom-in',
),
MapButton(
icon: Icons.remove,
onPressed: () {
widget.controller.move(
widget.controller.center,
widget.controller.zoom - 1,
);
},
heroTag: 'zoom-out',
),
],
),
),
],
);
}
2023-06-14 17:39:16 +00:00
List<Marker> _buildMakers() {
return List<Marker>.generate(widget.imageMarkers.length, (index) {
final imageMarker = widget.imageMarkers[index];
return mapMarker(imageMarker, index.toString());
});
}
}