From eedd39f6fcc833dc6015d574a5073be2f8e2b8d3 Mon Sep 17 00:00:00 2001 From: vjrj Date: Fri, 29 Jun 2018 00:36:43 +0200 Subject: [PATCH] More redux work --- lib/activeFires.dart | 54 +++---- lib/mainDev.dart | 2 +- lib/models/appState.dart | 5 +- lib/models/fireMapState.dart | 66 ++++++-- lib/models/firesApi.dart | 33 ++++ lib/redux/fetchDataMiddleware.dart | 40 ++++- lib/redux/fireMapReducer.dart | 43 ++++- lib/redux/yourLocationActions.dart | 40 +++-- lib/redux/yourLocationsReducer.dart | 37 ++--- lib/{genericMap.dart => yourLocationMap.dart} | 149 +++++++----------- lib/yourLocationMapBottom.dart | 58 +++++++ 11 files changed, 346 insertions(+), 181 deletions(-) rename lib/{genericMap.dart => yourLocationMap.dart} (66%) create mode 100644 lib/yourLocationMapBottom.dart diff --git a/lib/activeFires.dart b/lib/activeFires.dart index ca80d54..f162556 100644 --- a/lib/activeFires.dart +++ b/lib/activeFires.dart @@ -5,17 +5,17 @@ import 'package:fires_flutter/models/yourLocation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_fab_dialer/flutter_fab_dialer.dart'; import 'package:flutter_redux/flutter_redux.dart'; +import 'package:redux/src/store.dart'; import 'colors.dart'; import 'generated/i18n.dart'; -import 'genericMap.dart'; import 'globalFiresBottomStats.dart'; import 'locationUtils.dart'; import 'mainDrawer.dart'; import 'models/appState.dart'; -import 'package:redux/src/store.dart'; import 'placesAutocompleteUtils.dart'; import 'redux/actions.dart'; +import 'yourLocationMap.dart'; @immutable class _ViewModel { @@ -124,31 +124,13 @@ class _ActiveFiresPageState extends State { }); } - void handleUndo(YourLocation item) { - setState(() { - /* FIXME - globals.yourLocations.add(item); - persistYourLocations(); */ - }); - } - Widget _buildItem(YourLocation item, onDelete, onToggle, onTap) { final ThemeData theme = Theme.of(context); return new Dismissible( key: new ObjectKey(item), direction: DismissDirection.horizontal, onDismissed: (DismissDirection direction) { - setState(() { - onDelete(item.id); - }); - - _scaffoldKey.currentState.showSnackBar(new SnackBar( - content: new Text(S.of(context).youDeletedThisPlace), - action: new SnackBarAction( - label: S.of(context).UNDO, - onPressed: () { - handleUndo(item); - }))); + onDelete(item); }, background: new Container( color: theme.primaryColor, @@ -175,11 +157,26 @@ class _ActiveFiresPageState extends State { converter: (store) { return new _ViewModel( onAdd: (loc) { - store.dispatch(new AddYourLocationAction(loc)); - gotoLocationMap(store, loc, context); + if (store.state.yourLocations + .any((l) => loc.lat == l.lat && loc.lon == l.lon)) { + // Already added + showSnackMsg(S.of(context).addedThisLocation); + } else { + store.dispatch(new AddYourLocationAction(loc)); + new Timer(new Duration(milliseconds: 1000), () { + gotoLocationMap(store, loc, context); + }); + } }, - onDelete: (id) { - store.dispatch(new DeleteYourLocationAction(id)); + onDelete: (loc) { + store.dispatch(new DeleteYourLocationAction(loc)); + _scaffoldKey.currentState.showSnackBar(new SnackBar( + content: new Text(S.of(context).youDeletedThisPlace), + action: new SnackBarAction( + label: S.of(context).UNDO, + onPressed: () { + store.dispatch(new AddYourLocationAction(loc)); + }))); }, onToggleSubs: (loc) { store.dispatch(new ToggleSubscriptionAction(loc)); @@ -237,10 +234,11 @@ class _ActiveFiresPageState extends State { }); } - void gotoLocationMap(Store store, YourLocation loc, BuildContext context) { + void gotoLocationMap( + Store store, YourLocation loc, BuildContext context) { store.dispatch(new ShowYourLocationMapAction(loc)); - Navigator.push( - context, new MaterialPageRoute(builder: (context) => new GenericMap())); + Navigator.push(context, + new MaterialPageRoute(builder: (context) => new YourLocationMap())); } void onAddYourLocation(AddYourLocationFunction onAdd) { diff --git a/lib/mainDev.dart b/lib/mainDev.dart index a1d08a7..68c8506 100644 --- a/lib/mainDev.dart +++ b/lib/mainDev.dart @@ -6,7 +6,7 @@ import 'package:redux/redux.dart'; void main() { globals.isDevelopment = true; - var logRedux = false; + var logRedux = true; List devMiddlewares = logRedux ? [ LoggingMiddleware.printer(formatter: LoggingMiddleware.multiLineFormatter) diff --git a/lib/models/appState.dart b/lib/models/appState.dart index a2a2d4c..a8bb432 100644 --- a/lib/models/appState.dart +++ b/lib/models/appState.dart @@ -72,16 +72,17 @@ class AppState extends Object with _$AppStateSerializerMixin { return 'AppState{\nuser: ${user}\nisLoading: $isLoading\nisLoaded: $isLoaded\napiKey: ${ellipse( firesApiKey, 8)}\napiUrl: ${ellipse( firesApiUrl, 8)}\nyourLocations count: ${yourLocations - .length}\nyourLocations: ${yourLocations}'; + .length}\nyourLocations: ${yourLocations}\nfireMapState: $fireMapState}'; } } typedef void AddYourLocationFunction(YourLocation loc); -typedef void DeleteYourLocationFunction(ObjectId id); +typedef void DeleteYourLocationFunction(YourLocation loc); typedef void ToggleSubscriptionFunction(YourLocation loc); typedef void OnLocationTapFunction(YourLocation loc); typedef void OnSubscribeFunction(YourLocation loc); +typedef void OnSubscribeDistanceChangeFunction(YourLocation loc); typedef void OnUnSubscribeFunction(YourLocation loc); typedef void OnSubscribeConfirmedFunction(YourLocation loc); diff --git a/lib/models/fireMapState.dart b/lib/models/fireMapState.dart index 117076c..a8e2fe8 100644 --- a/lib/models/fireMapState.dart +++ b/lib/models/fireMapState.dart @@ -1,33 +1,75 @@ -import 'package:meta/meta.dart'; import 'package:fires_flutter/models/yourLocation.dart'; -import 'package:redux/redux.dart'; +import 'package:meta/meta.dart'; + enum FireMapStatus { view, subscriptionConfirm, unsubscribe } @immutable class FireMapState { final FireMapStatus status; + final int numFires; + final List fires; + final List falsePos; + final List industries; final YourLocation yourLocation; - const FireMapState.initial(): this.status = FireMapStatus.view, this.yourLocation = null; + const FireMapState.initial() + : this.status = FireMapStatus.view, + this.yourLocation = null, + this.numFires = 0, + this.fires = const [], + this.falsePos = const [], + this.industries = const []; - FireMapState({this.status: FireMapStatus.view, this.yourLocation}); + FireMapState( + {this.status: FireMapStatus.view, + this.yourLocation, + this.numFires, + this.fires, + this.falsePos, + this.industries}); - FireMapState copyWith({FireMapStatus status, YourLocation yourLocation}) { + FireMapState copyWith({ + FireMapStatus status, + YourLocation yourLocation, + int numFires, + List fires, + List falsePos, + List industries, + }) { return new FireMapState( - yourLocation: yourLocation ?? this.yourLocation, + yourLocation: yourLocation ?? this.yourLocation, + numFires: numFires ?? this.numFires, + fires: fires ?? this.fires, + falsePos: falsePos ?? this.falsePos, + industries: industries ?? this.industries, status: status ?? this.status); } @override bool operator ==(Object other) => - identical(this, other) || + identical(this, other) || other is FireMapState && - runtimeType == other.runtimeType && - status == other.status && - yourLocation == other.yourLocation; + runtimeType == other.runtimeType && + status == other.status && + numFires == other.numFires && + fires == other.fires && + falsePos == other.falsePos && + industries == other.industries && + yourLocation == other.yourLocation; @override int get hashCode => - status.hashCode ^ - yourLocation.hashCode; + status.hashCode ^ + numFires.hashCode ^ + fires.hashCode ^ + falsePos.hashCode ^ + industries.hashCode ^ + yourLocation.hashCode; + + @override + String toString() { + return 'FireMapState{status: $status, numFires: $numFires, fires: ${fires + .length}, falsePos: ${falsePos.length}, industries: ${industries + .length}, yourLocation: $yourLocation}'; + } } diff --git a/lib/models/firesApi.dart b/lib/models/firesApi.dart index 42803cd..29f2754 100644 --- a/lib/models/firesApi.dart +++ b/lib/models/firesApi.dart @@ -6,6 +6,8 @@ import 'package:fires_flutter/models/yourLocation.dart'; import 'package:http/http.dart' as ht; import 'package:jaguar_resty/jaguar_resty.dart' as resty; +import '../globals.dart' as globals; +import '../redux/actions.dart'; import 'appState.dart'; class FiresApi { @@ -110,4 +112,35 @@ class FiresApi { } }); } + + Future getYourLocationFireStats( + AppState state, YourLocation location) async { + assert(state.firesApiUrl != null); + assert(state.firesApiKey != null); + var url = '${state.firesApiUrl}fires-in-full/${state + .firesApiKey}/${location.lat}/${location.lon}/${location.distance}'; + return await resty.get(url).go().then((response) { + if (response.statusCode == 200) { + var resultDecoded = json.decode(response.body); + // print(resultDecoded); + int numFires = resultDecoded['real']; + List fires = resultDecoded['fires']; + List falsePos = resultDecoded['falsePos']; + List industries = resultDecoded['industries']; + + if (globals.isDevelopment) { + var firesCount = fires.length; + var industriesCount = industries.length; + var falsePosCount = falsePos.length; + print( + 'real: $numFires, fire: $firesCount falsePos: $falsePosCount industries: $industriesCount'); + } + return new UpdateYourLocationMapStatsAction( + numFires: numFires, + fires: fires, + falsePos: falsePos, + industries: industries); + } else throw Exception('Wrong response trying to get stats'); + }); + } } diff --git a/lib/redux/fetchDataMiddleware.dart b/lib/redux/fetchDataMiddleware.dart index 77e6747..108d73c 100644 --- a/lib/redux/fetchDataMiddleware.dart +++ b/lib/redux/fetchDataMiddleware.dart @@ -1,5 +1,6 @@ import 'package:bson_objectid/bson_objectid.dart'; import 'package:fires_flutter/models/yourLocation.dart'; +import 'package:just_debounce_it/just_debounce_it.dart'; import 'package:redux/redux.dart'; import '../globals.dart' as globals; @@ -47,8 +48,43 @@ void fetchYourLocationsMiddleware( } if (action is DeleteYourLocationAction) { - unsubsViaApi(store, action.id, - () => store.dispatch(new DeletedYourLocationAction(action.id))); + store.dispatch(new DeletedYourLocationAction(action.loc.id)); + if (action.loc.subscribed) { + unsubsViaApi(store, action.loc.id, () { + persistYourLocations(store.state.yourLocations); + }); + } else { + persistYourLocations(store.state.yourLocations); + } + } + + if (action is ShowYourLocationMapAction) { + api + .getYourLocationFireStats(store.state, action.loc) + .then((result) => store.dispatch(result)); + } + + if (action is UpdateLocalYourLocationAction) { + if (action.loc.subscribed) + Debounce.seconds( + 2, + () => api + .getYourLocationFireStats(store.state, action.loc) + .then((result) => store.dispatch(result))); + } + + if (action is SubscribeConfirmAction) { + subscribeViaApi(store, action.loc, (sub) { + store.dispatch(new UpdateLocalYourLocationAction(action.loc)); + persistYourLocations(store.state.yourLocations); + }); + } + + if (action is UnSubscribeAction) { + unsubsViaApi(store, action.loc.id, () { + store.dispatch(new UpdateLocalYourLocationAction(action.loc)); + persistYourLocations(store.state.yourLocations); + }); } if (action is ToggleSubscriptionAction) { diff --git a/lib/redux/fireMapReducer.dart b/lib/redux/fireMapReducer.dart index 59f19d4..27e6664 100644 --- a/lib/redux/fireMapReducer.dart +++ b/lib/redux/fireMapReducer.dart @@ -6,15 +6,44 @@ import 'actions.dart'; final fireMapReducer = combineReducers([ new TypedReducer( _showYourLocationMap), + new TypedReducer( + _updateYourLocationMapStats), + new TypedReducer(_subscribeYourLocationMap), + new TypedReducer( + _subscribeConfirmYourLocationMap), + new TypedReducer( + _unsubscribeYourLocationMap), ]); +FireMapState _updateYourLocationMapStats( + FireMapState state, UpdateYourLocationMapStatsAction action) { + return state.copyWith( + numFires: action.numFires, + fires: action.fires, + falsePos: action.falsePos, + industries: action.industries); +} + FireMapState _showYourLocationMap( FireMapState state, ShowYourLocationMapAction action) { - if (action.loc.subscribed) { - return state.copyWith( - status: action.loc.subscribed - ? FireMapStatus.unsubscribe - : FireMapStatus.view, - yourLocation: action.loc); - } + return state.copyWith( + status: action.loc.subscribed + ? FireMapStatus.unsubscribe + : FireMapStatus.view, + yourLocation: action.loc); +} + +FireMapState _subscribeYourLocationMap( + FireMapState state, SubscribeAction action) { + return state.copyWith(status: FireMapStatus.subscriptionConfirm); +} + +FireMapState _subscribeConfirmYourLocationMap( + FireMapState state, SubscribeConfirmAction action) { + return state.copyWith(status: FireMapStatus.unsubscribe); +} + +FireMapState _unsubscribeYourLocationMap( + FireMapState state, UnSubscribeAction action) { + return state.copyWith(status: FireMapStatus.view); } diff --git a/lib/redux/yourLocationActions.dart b/lib/redux/yourLocationActions.dart index 437a3be..f98661f 100644 --- a/lib/redux/yourLocationActions.dart +++ b/lib/redux/yourLocationActions.dart @@ -1,6 +1,6 @@ import 'package:bson_objectid/bson_objectid.dart'; import 'package:fires_flutter/models/yourLocation.dart'; - +import 'package:meta/meta.dart'; abstract class YourLocationActions {} @@ -22,10 +22,23 @@ class ShowYourLocationMapAction extends YourLocationActions { ShowYourLocationMapAction(this.loc); } -class DeleteYourLocationAction extends YourLocationActions { - ObjectId id; +class UpdateYourLocationMapStatsAction extends YourLocationActions { + int numFires; + List fires = []; + List falsePos = []; + List industries = []; - DeleteYourLocationAction(this.id); + UpdateYourLocationMapStatsAction( + {@required this.numFires, + @required this.fires, + @required this.falsePos, + @required this.industries}); +} + +class DeleteYourLocationAction extends YourLocationActions { + YourLocation loc; + + DeleteYourLocationAction(this.loc); } class DeletedYourLocationAction extends YourLocationActions { @@ -34,12 +47,10 @@ class DeletedYourLocationAction extends YourLocationActions { DeletedYourLocationAction(this.id); } - -class UpdateYourLocationAction extends YourLocationActions { - ObjectId id; +class UpdateLocalYourLocationAction extends YourLocationActions { YourLocation loc; - UpdateYourLocationAction(this.id, this.loc); + UpdateLocalYourLocationAction(this.loc); } class ToggleSubscriptionAction extends YourLocationActions { @@ -55,13 +66,18 @@ class ToggledSubscriptionAction extends YourLocationActions { } class SubscribeAction extends YourLocationActions { - ObjectId id; + SubscribeAction(); +} - SubscribeAction(this.id); +class SubscribeConfirmAction extends YourLocationActions { + YourLocation loc; + + SubscribeConfirmAction(this.loc); } class UnSubscribeAction extends YourLocationActions { - ObjectId id; + YourLocation loc; - UnSubscribeAction(this.id); + UnSubscribeAction(this.loc); } + diff --git a/lib/redux/yourLocationsReducer.dart b/lib/redux/yourLocationsReducer.dart index 05c5213..e5cb001 100644 --- a/lib/redux/yourLocationsReducer.dart +++ b/lib/redux/yourLocationsReducer.dart @@ -4,16 +4,14 @@ import 'package:redux/redux.dart'; import 'actions.dart'; final yourLocationsReducer = combineReducers>([ - new TypedReducer, AddedYourLocationAction>(_addedYourLocation), + new TypedReducer, AddedYourLocationAction>( + _addedYourLocation), new TypedReducer, DeletedYourLocationAction>( _deletedYourLocation), - new TypedReducer, UpdateYourLocationAction>( - _updateYourLocation), - new TypedReducer, ToggledSubscriptionAction>(_toggledSubscriptionAction) - - /* new TypedReducer, ToggleSubscriptionAction>(_toggleSubscriptionAction), - new TypedReducer, SubscribeAction>(_setLoadedYourLocations), - new TypedReducer, UnSubscribeAction>(_setNoYourLocations), */ + new TypedReducer, UpdateLocalYourLocationAction>( + _updateLocalYourLocation), + new TypedReducer, ToggledSubscriptionAction>( + _toggledSubscriptionAction) ]); List _addedYourLocation( @@ -28,25 +26,18 @@ List _deletedYourLocation( .toList(); } -List _updateYourLocation( - List yourLocations, UpdateYourLocationAction action) { +List _updateLocalYourLocation( + List yourLocations, UpdateLocalYourLocationAction action) { return yourLocations .map((yourLocation) => - yourLocation.id == action.id ? action.loc : yourLocation) + yourLocation.id == action.loc.id ? action.loc : yourLocation) .toList(); } -List _toggledSubscriptionAction(List yourLocations, ToggledSubscriptionAction action) { +List _toggledSubscriptionAction( + List yourLocations, ToggledSubscriptionAction action) { return yourLocations - .map((yourLocation) => yourLocation.id == action.loc.id ? action.loc : yourLocation) - .toList(); + .map((yourLocation) => + yourLocation.id == action.loc.id ? action.loc : yourLocation) + .toList(); } -/* -List _setLoadedYourLocations(List yourLocations, YourLocationsLoadedAction action) { - return action.yourLocations; -} - -List _setNoYourLocations(List yourLocations, YourLocationsNotLoadedAction action) { - return []; -} -*/ diff --git a/lib/genericMap.dart b/lib/yourLocationMap.dart similarity index 66% rename from lib/genericMap.dart rename to lib/yourLocationMap.dart index 8d38c47..479861d 100644 --- a/lib/genericMap.dart +++ b/lib/yourLocationMap.dart @@ -1,4 +1,3 @@ -import 'dart:convert' show json; import 'dart:core'; import 'package:comunes_flutter/comunes_flutter.dart'; @@ -9,12 +8,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/plugin_api.dart'; import 'package:flutter_redux/flutter_redux.dart'; -import 'package:http/http.dart' as http; -import 'package:just_debounce_it/just_debounce_it.dart'; import 'package:latlong/latlong.dart'; import 'colors.dart'; -import 'customBottomAppBar.dart'; import 'dummyMapPlugin.dart'; import 'fireMarkType.dart'; import 'fireMarker.dart'; @@ -24,6 +20,7 @@ import 'models/appState.dart'; import 'models/fireMapState.dart'; import 'redux/actions.dart'; import 'slider.dart'; +import 'yourLocationMapBottom.dart'; import 'zoomMapPlugin.dart'; @immutable @@ -32,12 +29,14 @@ class _ViewModel { final OnSubscribeFunction onSubs; final OnSubscribeConfirmedFunction onSubsConfirmed; final OnUnSubscribeFunction onUnSubs; + final OnSubscribeDistanceChangeFunction onSlide; _ViewModel( {@required this.mapState, @required this.onSubs, @required this.onSubsConfirmed, - @required this.onUnSubs}); + @required this.onUnSubs, + @required this.onSlide}); @override bool operator ==(Object other) => @@ -47,78 +46,57 @@ class _ViewModel { mapState == other.mapState && onSubs == other.onSubs && onSubsConfirmed == other.onSubsConfirmed && - onUnSubs == other.onUnSubs; + onUnSubs == other.onUnSubs && + onSlide == other.onSlide; @override int get hashCode => mapState.hashCode ^ onSubs.hashCode ^ onSubsConfirmed.hashCode ^ - onUnSubs.hashCode; + onUnSubs.hashCode ^ + onSlide.hashCode; } -class GenericMap extends StatefulWidget { - GenericMap(); +class YourLocationMap extends StatefulWidget { + YourLocationMap(); @override - _GenericMapState createState() => _GenericMapState(); + _YourLocationMapState createState() => _YourLocationMapState(); } -class _GenericMapState extends State { +class _YourLocationMapState extends State { final GlobalKey _scaffoldKey = new GlobalKey(); final FirebaseMessaging _firebaseMessaging = new FirebaseMessaging(); - int numFires; - int kmAround = 100; - List fires = []; - List falsePos = []; - List industries = []; - - void updateFireStats(YourLocation location) { - var url = '${globals.firesApiUrl}fires-in-full/${globals - .firesApiKey}/${location.lat}/${location.lon}/$kmAround'; - http.read(url).then((result) { - setState(() { - var resultDecoded = json.decode(result); - // print(resultDecoded); - numFires = resultDecoded['real']; - fires = resultDecoded['fires']; - falsePos = resultDecoded['falsePos']; - industries = resultDecoded['industries']; - - if (globals.isDevelopment) { - var firesCount = fires.length; - var industriesCount = industries.length; - var falsePosCount = falsePos.length; - print( - 'real: $numFires, fire: $firesCount falsePos: $falsePosCount industries: $industriesCount'); - } - }); - }); - } - - _GenericMapState(); + _YourLocationMapState(); @override Widget build(BuildContext context) { - // print('Build map with operation: $operation'); + return new StoreConnector( distinct: false, // FIXME converter: (store) { return new _ViewModel( onSubs: (loc) { - store.dispatch(new SubscribeAction(loc.id)); + store.dispatch(new SubscribeAction()); }, onSubsConfirmed: (loc) { - store.dispatch(new SubscribeAction(loc.id)); + loc.subscribed = true; + store.dispatch(new SubscribeConfirmAction(loc)); }, onUnSubs: (loc) { - store.dispatch(new UnSubscribeAction(loc.id)); + loc.subscribed = false; + store.dispatch(new UnSubscribeAction(loc)); + }, + onSlide: (loc) { + store.dispatch(new UpdateLocalYourLocationAction(loc)); }, mapState: store.state.fireMapState); }, builder: (context, view) { YourLocation location = view.mapState.yourLocation; + assert(location != null); MapOptions mapOptions = new MapOptions( center: new LatLng(location.lat, location.lon), plugins: globals.isDevelopment @@ -137,7 +115,9 @@ class _GenericMapState extends State { // mapController.fitBounds(bounds); // mapController.center - FireMapStatus operation = view.mapState.status; + FireMapState mapState = view.mapState; + FireMapStatus operation = mapState.status; + print('Build map with operation: $operation'); final btnText = operation == FireMapStatus.view ? S.of(context).toFiresNotifications : operation == FireMapStatus.subscriptionConfirm @@ -148,7 +128,6 @@ class _GenericMapState extends State { : operation == FireMapStatus.subscriptionConfirm ? Icons.check : Icons.notifications_off; - updateFireStats(location); return new Scaffold( key: _scaffoldKey, appBar: new AppBar( @@ -156,23 +135,19 @@ class _GenericMapState extends State { ), floatingActionButton: FloatingActionButton.extended( onPressed: () { - - switch (operation) { - case FireMapStatus.view: - view.onSubs(location); - break; - case FireMapStatus.subscriptionConfirm: - view.onSubsConfirmed(location); - // IOS specific - _firebaseMessaging.requestNotificationPermissions(); - operation = FireMapStatus.unsubscribe; - break; - case FireMapStatus.unsubscribe: - view.onUnSubs(location); - operation = FireMapStatus.view; - break; - } - + switch (operation) { + case FireMapStatus.view: + view.onSubs(location); + break; + case FireMapStatus.subscriptionConfirm: + view.onSubsConfirmed(location); + // IOS specific + _firebaseMessaging.requestNotificationPermissions(); + break; + case FireMapStatus.unsubscribe: + view.onUnSubs(location); + break; + } }, // https://github.com/flutter/flutter/issues/17583 heroTag: "firesmap" + location.id.toHexString(), @@ -185,24 +160,7 @@ class _GenericMapState extends State { ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, - bottomNavigationBar: new CustomBottomAppBar( - fabLocation: FloatingActionButtonLocation.centerFloat, - showNotch: false, - color: fires100, - // height: 170.0, - mainAxisAlignment: MainAxisAlignment.center, - actions: listWithoutNulls([ - operation == FireMapStatus.subscriptionConfirm || - numFires == null - ? null - : new Text(numFires > 0 - ? S.of(context).firesAroundThisArea( - numFires.toString(), kmAround.toString()) - : S - .of(context) - .noFiresAroundThisArea(kmAround.toString())), - SizedBox(width: 10.0) - ])), + bottomNavigationBar: new YourLocationMapBottom(), body: LayoutBuilder( builder: (context, constraints) => Stack(fit: StackFit.expand, children: [ @@ -231,8 +189,8 @@ class _GenericMapState extends State { ? new ZoomMapPluginOptions() : new DummyMapPluginOptions(), new MarkerLayerOptions( - markers: buildMarkers(location, this.fires, - this.industries, this.falsePos), + markers: buildMarkers(location, mapState.fires, + mapState.industries, mapState.falsePos), ), ], )), @@ -243,19 +201,22 @@ class _GenericMapState extends State { child: new CenteredRow( // Fit sample: // https://github.com/apptreesoftware/flutter_map/blob/master/flutter_map_example/lib/pages/map_controller.dart - children: operation == - FireMapStatus.subscriptionConfirm - ? [ - new FireDistanceSlider( - initialValue: kmAround, - onSlide: (distance) { + children: + operation == FireMapStatus.subscriptionConfirm + ? [ + new FireDistanceSlider( + initialValue: location.distance, + onSlide: (distance) { + location.distance = distance; + view.onSlide(location); + /* FIXME setState(() { kmAround = distance; Debounce.seconds(1, updateFireStats); - }); - }) - ] - : [], + }); */ + }) + ] + : [], ), ) ]), diff --git a/lib/yourLocationMapBottom.dart b/lib/yourLocationMapBottom.dart new file mode 100644 index 0000000..352022e --- /dev/null +++ b/lib/yourLocationMapBottom.dart @@ -0,0 +1,58 @@ +import 'package:comunes_flutter/comunes_flutter.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_redux/flutter_redux.dart'; + +import 'colors.dart'; +import 'customBottomAppBar.dart'; +import 'generated/i18n.dart'; +import 'models/appState.dart'; +import 'models/fireMapState.dart'; + +@immutable +class _ViewModel { + final FireMapState state; + + _ViewModel({@required this.state}); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is _ViewModel && + runtimeType == other.runtimeType && + state == other.state; + + @override + int get hashCode => state.hashCode; +} + +class YourLocationMapBottom extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new StoreConnector( + distinct: true, // FIXME + converter: (store) { + return new _ViewModel(state: store.state.fireMapState); + }, + builder: (context, view) { + int kmAround = view.state.yourLocation.distance; + return new CustomBottomAppBar( + fabLocation: FloatingActionButtonLocation.centerFloat, + showNotch: false, + color: fires100, + // height: 170.0, + mainAxisAlignment: MainAxisAlignment.center, + actions: listWithoutNulls([ + view.state.status == FireMapStatus.subscriptionConfirm || + view.state.numFires == null + ? null + : new Text(view.state.numFires > 0 + ? S.of(context).firesAroundThisArea( + view.state.numFires.toString(), kmAround.toString()) + : S + .of(context) + .noFiresAroundThisArea(kmAround.toString())), + SizedBox(width: 10.0) + ])); + }); + } +}