Files
floodwatch/lib/pages/map_page.dart

128 lines
3.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_cancellable_tile_provider/flutter_map_cancellable_tile_provider.dart';
import 'package:flutter_map_marker_cluster/flutter_map_marker_cluster.dart';
import 'package:latlong2/latlong.dart';
import 'package:provider/provider.dart';
import '../model/flood_station.dart';
import '../services/flood_station_provider.dart';
import '../widgets/custom_marker.dart';
import '../widgets/map_popup.dart';
import 'flood_station_page.dart';
class MapPage extends StatefulWidget {
const MapPage({super.key});
static const routeName = '/map';
@override
State<MapPage> createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> {
final _mapController = MapController();
late FloodStationProvider _floodStationProvider;
bool _loading = false;
@override
Widget build(BuildContext context) {
_floodStationProvider = context.watch<FloodStationProvider>();
if (_loading == true) {
return Center(
child: CircularProgressIndicator(),
);
} else if (_floodStationProvider.allStations.isEmpty) {
return Center(
child: ElevatedButton(
onPressed: () {
setState(() {
_loading = true;
});
_floodStationProvider
.loadAllStations()
.whenComplete(() => setState(() {
_loading = false;
}));
},
child: Text('Load Map'),
),
);
}
return FlutterMap(
mapController: _mapController,
options: MapOptions(
cameraConstraint: CameraConstraint.containCenter(
bounds: LatLngBounds.fromPoints(_floodStationProvider.allStations
.map<LatLng>(
(e) => LatLng(e.lat, e.long),
)
.toList())),
initialCenter: LatLng(54.81, -4.42),
initialZoom: 6,
),
children: [
_openStreetMapTileLayer,
MarkerClusterLayerWidget(
options: MarkerClusterLayerOptions(
maxClusterRadius: 45,
size: Size(30, 30),
alignment: Alignment.center,
padding: EdgeInsets.all(50),
maxZoom: 15,
markers: _stationsAsMarkers(_floodStationProvider.allStations),
builder: _clusterMarkerBuilder),
)
],
);
}
// builds the clustered marker
Widget _clusterMarkerBuilder(BuildContext context, List<Marker> markers) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Theme.of(context).colorScheme.tertiary,
),
child: Center(
child: Text(
markers.length.toString(),
style: TextStyle(color: Theme.of(context).colorScheme.onTertiary),
),
),
);
}
// gets a list of markers from the list of all stations
List<Marker> _stationsAsMarkers(List<FloodStation> stations) {
return stations
.map<Marker>(
(station) => Marker(
alignment: Alignment.center,
point: LatLng(station.lat, station.long),
child: CustomMarker(
onTap: () => _markerTapped(station),
),
),
)
.toList();
}
void _markerTapped(FloodStation station) {
showDialog(
context: context,
builder: (context) => MapPopup(
station: station,
onShowTapped: () {
_floodStationProvider.selectedStation = station;
Navigator.of(context).pushNamed(FloodStationPage.routeName);
}),
);
}
}
TileLayer get _openStreetMapTileLayer => TileLayer(
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
userAgentPackageName: 'dev.fleaflet.flutter_map.example',
tileProvider: CancellableNetworkTileProvider(),
);