MapTab.dart (5680B)
1 import 'package:flutter/material.dart'; 2 import 'package:flutter_bloc/flutter_bloc.dart'; 3 import 'package:flutter_map/flutter_map.dart'; 4 import 'package:flutter_map_marker_cluster/flutter_map_marker_cluster.dart'; 5 import 'package:latlong/latlong.dart'; 6 7 import '../../blocs/MapBloc.dart'; 8 import '../../events/MapEvent.dart'; 9 import '../../models/models.dart'; 10 import '../../repos/repositories.dart'; 11 import '../../states/MapState.dart'; 12 import '../DetailsPage.dart'; 13 14 class MapTab extends StatefulWidget { 15 final RailwayStationsRepository railwayStationsRepository; 16 17 MapTab({@required this.railwayStationsRepository}) 18 : assert(railwayStationsRepository != null); 19 20 @override 21 MapTabState createState() => MapTabState(); 22 } 23 24 class MapTabState extends State<MapTab> 25 with AutomaticKeepAliveClientMixin<MapTab> { 26 MapTabState(); 27 28 List<Station> stations; 29 final _initialCenter = LatLng(51.133481, 10.018343); 30 final _initialZoom = 6.0; 31 32 List<Marker> _makeStationMarkers(List<Station> stations) { 33 List<Marker> stationMarkers = List(); 34 stations.forEach((element) { 35 if (element.active) { 36 stationMarkers.add(Marker( 37 anchorPos: AnchorPos.align(AnchorAlign.center), 38 height: 30, 39 width: 30, 40 point: LatLng(element.lat, element.lon), 41 builder: (BuildContext context) => Icon(Icons.pin_drop), 42 )); 43 } 44 // Todo calculate an extra layer for deactivated stations 45 }); 46 return stationMarkers; 47 } 48 49 @override 50 Widget build(BuildContext context) { 51 super.build(context); 52 53 // Fetch map data on opening 54 if (stations == null) { 55 BlocProvider.of<MapBloc>(context).add(FetchStations()); 56 } 57 58 return BlocBuilder<MapBloc, MapState>(builder: (context, state) { 59 if (state is MapLoading) { 60 return Center(child: CircularProgressIndicator()); 61 } 62 if (state is MapRender) { 63 return FlutterMap( 64 options: MapOptions( 65 center: _initialCenter, 66 zoom: _initialZoom, 67 plugins: [ 68 MarkerClusterPlugin(), 69 ], 70 ), 71 layers: [ 72 // Mapbox 73 /*TileLayerOptions( 74 //tileSize: 1024, 75 zoomOffset: -1, 76 urlTemplate: 77 "https://api.mapbox.com/styles/v1/mapbox/{id}/tiles/256/{z}/{x}/{y}@2x?access_token={accessToken}", 78 additionalOptions: { 79 'accessToken': 80 'pk.eyJ1IjoibXRybm9yZCIsImEiOiJjaXIyZTRhNDcwMDhwaTJtZzBseTNkancxIn0.09m6ZCFvkKL6Ppss7XAnfA', 81 'id': 'streets-v11', 82 }, 83 ),*/ 84 // Openstreetmap 85 /*TileLayerOptions( 86 urlTemplate: "https://{s}.tile.openstreetmap.de/{z}/{x}/{y}.png", 87 subdomains: ['a', 'b', 'c'], 88 ),*/ 89 // Transport Map 90 TileLayerOptions( 91 urlTemplate: "http://tile.memomaps.de/tilegen/{z}/{x}/{y}.png", 92 subdomains: [], 93 ), 94 // Railway overlay 95 /*TileLayerOptions( 96 urlTemplate: 97 "https://{s}.tiles.openrailwaymap.org/standard/{z}/{x}/{y}.png", 98 subdomains: ['a', 'b', 'c'], 99 opacity: 0.2, 100 ),*/ 101 MarkerClusterLayerOptions( 102 maxClusterRadius: 120, 103 size: Size(50, 50), 104 fitBoundsOptions: FitBoundsOptions( 105 padding: EdgeInsets.all(50), 106 ), 107 markers: _makeStationMarkers(stations), 108 polygonOptions: PolygonOptions( 109 borderColor: Colors.blueAccent, 110 color: Colors.black12, 111 borderStrokeWidth: 3, 112 ), 113 onMarkerTap: (Marker marker) { 114 Station station = stations.firstWhere((element) => 115 element.lat == marker.point.latitude && 116 element.lon == marker.point.longitude); 117 Navigator.of(context).push( 118 MaterialPageRoute( 119 builder: (BuildContext context) => DetailsPage( 120 station: station, 121 railwayStationsRepository: 122 widget.railwayStationsRepository, 123 ), 124 ), 125 ); 126 }, 127 builder: (context, markers) { 128 return ClipRRect( 129 borderRadius: BorderRadius.circular(50), 130 child: Container( 131 color: Theme.of(context).primaryColor, 132 child: Center( 133 child: Text( 134 markers.length.toString(), 135 ), 136 ), 137 ), 138 ); 139 }, 140 ), 141 ], 142 ); 143 } 144 if (state is MapLoaded) { 145 return FutureBuilder( 146 future: _cacheData(state.stations), 147 builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) { 148 return Center(child: CircularProgressIndicator()); 149 }, 150 ); 151 } 152 // Todo show reload button on error 153 if (state is MapError) { 154 return Text( 155 'Something went wrong!', 156 style: TextStyle(color: Colors.red), 157 ); 158 } 159 return Text( 160 'Something went wrong2!', 161 style: TextStyle(color: Colors.red), 162 ); 163 }); 164 } 165 166 _cacheData(List<Station> stations) async { 167 setState(() { 168 this.stations = stations; 169 BlocProvider.of<MapBloc>(context).add(RenderMap()); 170 }); 171 } 172 173 @override 174 bool get wantKeepAlive => true; 175 }