Map attribution & map layers plugin

This commit is contained in:
Vicente J. Ruiz Jurado 2018-08-04 09:14:51 +02:00
parent 726cd6b65d
commit 845c38bf04
9 changed files with 168 additions and 16 deletions

View file

@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_map/plugin_api.dart';
class AttributionPluginOptions extends LayerOptions {
final String text;
AttributionPluginOptions({this.text = ""});
}
class AttributionPlugin implements MapPlugin {
@override
Widget createLayer(LayerOptions options, MapState mapState) {
if (options is AttributionPluginOptions) {
var style = new TextStyle(
// fontWeight: FontWeight.bold,
fontSize: 12.0,
color: Colors.white,
);
return Padding(
padding: const EdgeInsets.all(5.0),
child: new Text(
options.text,
style: style,
),
);
}
throw ("Unknown options type for Attribution"
"plugin: $options");
}
@override
bool supportsLayer(LayerOptions options) {
return options is AttributionPluginOptions;
}
}

View file

@ -64,7 +64,7 @@ class S implements WidgetsLocalizations {
String get notPermsUbication => "We don't have permission to get your location";
String get notifyAFire => "Notify a fire";
String get privacyPolicy => "Privacy Policy";
String get supportPageDescription => "You can support this initiative, spreading the word, helping us to develop our software, translating this app to your language, etc.";
String get supportPageDescription => "You can support this initiative, spreading the word, helping us to develop our software, translating this app to your language, suggesting other public data sources of fires to use, etc.";
String get supportThisInitiative => "Support this initiative";
String get toDeleteThisNotification => "Slide horizontally to delete this notification";
String get toDeleteThisPlace => "Slide horizontally to delete this place";
@ -158,7 +158,7 @@ class es extends S {
@override
String get tweetAboutAFireTitle => "Twittea";
@override
String get supportPageDescription => "Puedes apoyar esta iniciativa, dando difusión, ayudándonos a desarrollar nuestro software, traduciendo esta aplicación a tu idioma, etc.";
String get supportPageDescription => "Puedes apoyar esta iniciativa, dando difusión, ayudándonos a desarrollar nuestro software, traduciendo esta aplicación a tu idioma, sugeriendo otras fuentes de datos públicas de fuegos para usar, etc.";
@override
String get aMinute => "un minuto";
@override

View file

@ -10,6 +10,7 @@ import 'package:flutter_redux/flutter_redux.dart';
import 'package:latlong/latlong.dart';
import 'package:share/share.dart';
import 'attributionMapPlugin.dart';
import 'colors.dart';
import 'dummyMapPlugin.dart';
import 'fireMarkType.dart';
@ -22,7 +23,7 @@ import 'models/fireMapState.dart';
import 'redux/actions.dart';
import 'slider.dart';
import 'zoomMapPlugin.dart';
import 'layerSelectorMapPlugin.dart';
@immutable
class _ViewModel {
final String serverUrl;
@ -118,18 +119,21 @@ class _genericMapState extends State<genericMap> {
assert(_location != null);
FireMapState mapState = view.mapState;
FireMapStatus status = mapState.status;
print('Build map with status: $status');
FireMapLayer layer = mapState.layer;
print('Build map with status: $status and layer $layer');
double maxZoom = 18.0; // works?
MapOptions mapOptions = new MapOptions(
center: new LatLng(_location.lat, _location.lon),
plugins: globals.isDevelopment
? [new ZoomMapPlugin()]
: [new DummyMapPlugin()],
? [new ZoomMapPlugin(), new AttributionPlugin(), new LayerSelectorMapPlugin()]
: [new DummyMapPlugin(), new AttributionPlugin(), new LayerSelectorMapPlugin()],
// this works ?
interactive: false,
zoom: 13.0,
// THIS does not works as expected
// maxZoom: 6.0,
maxZoom: maxZoom,
onTap: (callback) {
if (status == FireMapStatus.edit) {
_location = _location.copyWith(
@ -155,19 +159,49 @@ class _genericMapState extends State<genericMap> {
: status == FireMapStatus.subscriptionConfirm
? Icons.check
: Icons.notifications_off;
String baseLayer;
List<String> subdomains = [];
String attribution;
switch (layer) {
case FireMapLayer.osmc:
case FireMapLayer.osmcGrey:
attribution = '© OpenStreetMap contributors';
break;
case FireMapLayer.esri:
case FireMapLayer.esriSatellite:
case FireMapLayer.esriTerrain:
attribution = '© ESRI';
}
/* tiles from: https://github.com/dceejay/RedMap/blob/1914ed3b9ce4e8a496049849a93282730b4fff02/worldmap/index.html */
switch (layer) {
case FireMapLayer.osmc:
subdomains = ['a', 'b', 'c'];
baseLayer = 'https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png';
break;
case FireMapLayer.osmcGrey:
subdomains = ['a', 'b', 'c'];
baseLayer = 'https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png';
break;
case FireMapLayer.esri:
baseLayer = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}';
break;
case FireMapLayer.esriSatellite:
baseLayer = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}';
break;
case FireMapLayer.esriTerrain:
baseLayer = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}';
}
FlutterMap map = new FlutterMap(
options: mapOptions,
mapController: mapController,
layers: [
new TileLayerOptions(
maxZoom: 6.0,
subdomains: ['a', 'b', 'c'],
urlTemplate:
'https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png',
maxZoom: maxZoom,
urlTemplate: baseLayer,
subdomains: subdomains,
additionalOptions: {
// 'opacity': '0.1',
'attribution':
'&copy; <a href=&quot;http://osm.org/copyright&quot;>OpenStreetMap</a> contributors'
},
),
globals.isDevelopment
@ -181,6 +215,9 @@ class _genericMapState extends State<genericMap> {
mapState.falsePos,
mapState.fireNotification != null),
),
// new AttributionPluginOptions(text: "© OpenStreetMap contributors"),
new LayerSelectorMapPluginOptions(),
new AttributionPluginOptions(text: attribution),
],
);
// mapController.

View file

@ -0,0 +1,57 @@
import 'package:comunes_flutter/comunes_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_map/plugin_api.dart';
import 'package:flutter_simple_dependency_injection/injector.dart';
import 'package:redux/redux.dart';
import 'models/appState.dart';
import 'redux/actions.dart';
class LayerSelectorMapPluginOptions extends LayerOptions {
final String text;
LayerSelectorMapPluginOptions({this.text = ""});
}
// https://github.com/apptreesoftware/flutter_map/blob/master/flutter_map_example/lib/pages/plugin_api.dart
class LayerSelectorMapPlugin extends MapPlugin {
Widget LayerSelectorButton(Store<AppState> store) {
return new FloatingActionButton(
backgroundColor: Colors.black26,
mini: true,
child: Icon(Icons.layers, /* size: 40.0, color: Colors.black45, */ ),
onPressed: () {
store.dispatch(new ToggleMapLayerAction());
});
}
@override
Widget createLayer(LayerOptions options, MapState mapState) {
Store<AppState> store = Injector.getInjector().get<Store<AppState>>();
if (options is LayerSelectorMapPluginOptions) {
return LayoutBuilder(
builder: (context, constraints) =>
Stack(fit: StackFit.expand, children: <Widget>[
Positioned(
top: constraints.maxHeight - 60,
left: 10.0,
child: new CenteredRow(
children: <Widget>[
new Column(
children: <Widget>[LayerSelectorButton(store)],
)
],
),
)
]));
}
throw ("Unknown options type for LayerSelectorMapPlugin"
"plugin: $options");
}
@override
bool supportsLayer(LayerOptions options) {
return options is LayerSelectorMapPluginOptions;
}
}

View file

@ -3,10 +3,12 @@ import 'package:fires_flutter/models/fireNotification.dart';
import 'package:meta/meta.dart';
enum FireMapStatus { view, subscriptionConfirm, unsubscribe, edit, viewFireNotification }
enum FireMapLayer { osmcGrey, esriSatellite, osmc, esri, esriTerrain }
@immutable
class FireMapState {
final FireMapStatus status;
final FireMapLayer layer;
final int numFires;
final FireNotification fireNotification;
final List<dynamic> fires;
@ -16,6 +18,7 @@ class FireMapState {
const FireMapState.initial()
: this.status = FireMapStatus.view,
this.layer = FireMapLayer.osmcGrey,
this.yourLocation = null,
this.fireNotification = null,
this.numFires = 0,
@ -25,6 +28,7 @@ class FireMapState {
FireMapState(
{this.status: FireMapStatus.view,
this.layer: FireMapLayer.osmcGrey,
this.yourLocation,
this.numFires,
this.fires,
@ -34,6 +38,7 @@ class FireMapState {
FireMapState copyWith({
FireMapStatus status,
FireMapLayer layer,
YourLocation yourLocation,
FireNotification fireNotication,
int numFires,
@ -48,6 +53,7 @@ class FireMapState {
fires: fires ?? this.fires,
falsePos: falsePos ?? this.falsePos,
industries: industries ?? this.industries,
layer: layer ?? this.layer,
status: status ?? this.status);
}
@ -57,6 +63,7 @@ class FireMapState {
other is FireMapState &&
runtimeType == other.runtimeType &&
status == other.status &&
layer == other.layer &&
numFires == other.numFires &&
fireNotification == other.fireNotification &&
fires == other.fires &&
@ -67,6 +74,7 @@ class FireMapState {
@override
int get hashCode =>
status.hashCode ^
layer.hashCode ^
numFires.hashCode ^
fireNotification.hashCode ^
fires.hashCode ^
@ -76,7 +84,7 @@ class FireMapState {
@override
String toString() {
return 'FireMapState{status: $status, numFires: $numFires, fires: ${fires
return 'FireMapState{status: $status, layer: $layer, numFires: $numFires, fires: ${fires
.length}, falsePos: ${falsePos.length}, industries: ${industries
.length}, yourLocation: $yourLocation, fireNotification: $fireNotification}';
}

View file

@ -53,3 +53,5 @@ class EditCancelYourLocationAction extends FiresMapActions {
YourLocation loc;
EditCancelYourLocationAction(this.loc);
}
class ToggleMapLayerAction extends FiresMapActions {}

View file

@ -20,6 +20,8 @@ final fireMapReducer = combineReducers<FireMapState>([
_editConfirmYourLocationMap),
new TypedReducer<FireMapState, EditCancelYourLocationAction>(
_editCancelYourLocationMap),
new TypedReducer<FireMapState, ToggleMapLayerAction>(
_toggleMapLayer),
new TypedReducer<FireMapState, UpdateYourLocationMapAction>(
_updateYourLocationMap)
]);
@ -89,3 +91,13 @@ FireMapState _editCancelYourLocationMap(
FireMapStatus restoreStatusAfterSave(loc) =>
loc.subscribed ? FireMapStatus.unsubscribe : FireMapStatus.view;
FireMapState _toggleMapLayer(
FireMapState state, ToggleMapLayerAction action) {
FireMapLayer currentLayer = state.layer;
List<FireMapLayer> list = FireMapLayer.values;
int currentPos = list.indexOf(currentLayer);
currentPos++;
FireMapLayer next = list.elementAt(currentPos >= list.length ? 0: currentPos);
return state.copyWith(layer: next);
}