Compare commits

..

2 Commits

4 changed files with 110 additions and 25 deletions

View File

@@ -5,7 +5,11 @@ 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});
@@ -17,14 +21,15 @@ class MapPage extends StatefulWidget {
class _MapPageState extends State<MapPage> {
final mapController = MapController();
late FloodStationProvider _floodStationProvider;
@override
Widget build(BuildContext context) {
final floodStationProvider = context.watch<FloodStationProvider>();
if (floodStationProvider.allStations.isEmpty) {
_floodStationProvider = context.watch<FloodStationProvider>();
if (_floodStationProvider.allStations.isEmpty) {
return Center(
child: ElevatedButton(
onPressed: floodStationProvider.loadAllStations,
onPressed: _floodStationProvider.loadAllStations,
child: Text('Load Map'),
),
);
@@ -32,6 +37,12 @@ class _MapPageState extends State<MapPage> {
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,
),
@@ -44,7 +55,7 @@ class _MapPageState extends State<MapPage> {
alignment: Alignment.center,
padding: EdgeInsets.all(50),
maxZoom: 15,
markers: floodStationProvider.stationsAsMarkers,
markers: _stationsAsMarkers(_floodStationProvider.allStations),
builder: _markerBuilder),
)
],
@@ -65,6 +76,32 @@ class _MapPageState extends State<MapPage> {
),
);
}
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();
}
_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(

View File

@@ -1,10 +1,6 @@
import 'package:flutter/material.dart';
import 'package:async/async.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import '../model/flood_station.dart';
import '../widgets/custom_marker.dart';
import 'api.dart';
class FloodStationProvider extends ChangeNotifier {
@@ -16,17 +12,6 @@ class FloodStationProvider extends ChangeNotifier {
List<FloodStation> get allStations => _allStations;
List<FloodStation> get filteredStations => _filteredStations;
List<Marker> get stationsAsMarkers {
return allStations
.map<Marker>(
(e) => Marker(
alignment: Alignment.center,
point: LatLng(e.lat, e.long),
child: CustomMarker(),
),
)
.toList();
}
CancelableOperation? _filteredStationsFuture;

View File

@@ -1,15 +1,18 @@
import 'package:flutter/material.dart';
class CustomMarker extends StatelessWidget {
const CustomMarker({super.key, this.label});
final String? label;
const CustomMarker({super.key, required this.onTap});
final void Function() onTap;
@override
Widget build(BuildContext context) {
return Icon(
return GestureDetector(
onTap: onTap,
child: Icon(
Icons.location_on_sharp,
color: Theme.of(context).colorScheme.primary,
size: 30,
),
);
}
}

View File

@@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl;
import '../model/flood_station.dart';
class MapPopup extends StatelessWidget {
const MapPopup(
{super.key, required this.station, required this.onShowTapped});
final FloodStation station;
final Function() onShowTapped;
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(station.label),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.home_outlined),
Padding(padding: EdgeInsets.only(left: 8)),
Text(station.town.isEmpty ? '-' : station.town),
],
),
Row(
children: [
Icon(Icons.water),
Padding(padding: EdgeInsets.only(left: 8)),
Text(station.riverName.isEmpty ? '-' : station.riverName),
],
),
Row(
children: [
Icon(Icons.calendar_month_outlined),
Padding(padding: EdgeInsets.only(left: 8)),
Text(
station.dateOpened != null
? intl.DateFormat.yMd().format(station.dateOpened!)
: '-',
),
],
)
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('dismiss'),
),
TextButton(
onPressed: onShowTapped,
child: Text('show'),
),
],
);
}
}