Better fire stats. False positives mark api part

This commit is contained in:
Vicente J. Ruiz Jurado 2018-08-08 08:55:31 +02:00
parent e9c6c3fc55
commit cb02156ae1
10 changed files with 174 additions and 75 deletions

View file

@ -7,12 +7,12 @@ import 'fireMarkType.dart';
class FireMarker extends Marker { class FireMarker extends Marker {
FireMarker(location, type, FireMarker(LatLng pos, type,
[onTap = null, AnchorPos anchor = AnchorPos.center, Anchor anchorOverride]) [onTap = null, AnchorPos anchor = AnchorPos.center, Anchor anchorOverride])
: super( : super(
width: 80.0, width: 80.0,
height: 80.0, height: 80.0,
point: new LatLng(location.lat, location.lon), point: pos,
builder: (ctx) => new Container( builder: (ctx) => new Container(
child: new GestureDetector( child: new GestureDetector(
child: new FireMarkerIcon(type), onTap: onTap) child: new FireMarkerIcon(type), onTap: onTap)

View file

@ -1,7 +1,6 @@
import 'dart:core'; import 'dart:core';
import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:comunes_flutter/comunes_flutter.dart';
import 'package:fires_flutter/models/basicLocation.dart';
import 'package:fires_flutter/models/yourLocation.dart'; import 'package:fires_flutter/models/yourLocation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/flutter_map.dart';
@ -18,12 +17,13 @@ import 'fireMarker.dart';
import 'generated/i18n.dart'; import 'generated/i18n.dart';
import 'genericMapBottom.dart'; import 'genericMapBottom.dart';
import 'globals.dart' as globals; import 'globals.dart' as globals;
import 'layerSelectorMapPlugin.dart';
import 'models/appState.dart'; import 'models/appState.dart';
import 'models/fireMapState.dart'; import 'models/fireMapState.dart';
import 'redux/actions.dart'; import 'redux/actions.dart';
import 'slider.dart'; import 'slider.dart';
import 'zoomMapPlugin.dart'; import 'zoomMapPlugin.dart';
import 'layerSelectorMapPlugin.dart';
@immutable @immutable
class _ViewModel { class _ViewModel {
final String serverUrl; final String serverUrl;
@ -36,6 +36,7 @@ class _ViewModel {
final OnLocationEditConfirm onEditConfirm; final OnLocationEditConfirm onEditConfirm;
final OnLocationEditCancel onEditCancel; final OnLocationEditCancel onEditCancel;
final OnLocationEditing onEditing; final OnLocationEditing onEditing;
final OnFalsePositive onFalsePositive;
_ViewModel( _ViewModel(
{@required this.mapState, {@required this.mapState,
@ -47,6 +48,7 @@ class _ViewModel {
@required this.onEdit, @required this.onEdit,
@required this.onEditing, @required this.onEditing,
@required this.onEditConfirm, @required this.onEditConfirm,
@required this.onFalsePositive,
@required this.onEditCancel}); @required this.onEditCancel});
@override @override
@ -108,6 +110,8 @@ class _genericMapState extends State<genericMap> {
store.dispatch(new UpdateYourLocationMapAction(loc)); store.dispatch(new UpdateYourLocationMapAction(loc));
store.dispatch(new EditConfirmYourLocationAction(loc)); store.dispatch(new EditConfirmYourLocationAction(loc));
}, },
onFalsePositive: (notif, type) => store
.dispatch(new MarkFireAsFalsePositiveAction(notif, type)),
serverUrl: store.state.serverUrl, serverUrl: store.state.serverUrl,
mapState: store.state.fireMapState); mapState: store.state.fireMapState);
}, },
@ -127,8 +131,16 @@ class _genericMapState extends State<genericMap> {
MapOptions mapOptions = new MapOptions( MapOptions mapOptions = new MapOptions(
center: new LatLng(_location.lat, _location.lon), center: new LatLng(_location.lat, _location.lon),
plugins: globals.isDevelopment plugins: globals.isDevelopment
? [new ZoomMapPlugin(), new AttributionPlugin(), new LayerSelectorMapPlugin()] ? [
: [new DummyMapPlugin(), new AttributionPlugin(), new LayerSelectorMapPlugin()], new ZoomMapPlugin(),
new AttributionPlugin(),
new LayerSelectorMapPlugin()
]
: [
new DummyMapPlugin(),
new AttributionPlugin(),
new LayerSelectorMapPlugin()
],
// this works ? // this works ?
interactive: false, interactive: false,
zoom: 13.0, zoom: 13.0,
@ -166,8 +178,8 @@ class _genericMapState extends State<genericMap> {
switch (layer) { switch (layer) {
case FireMapLayer.osmc: case FireMapLayer.osmc:
case FireMapLayer.osmcGrey: case FireMapLayer.osmcGrey:
attribution = '© OpenStreetMap contributors'; attribution = '© OpenStreetMap contributors';
break; break;
case FireMapLayer.esri: case FireMapLayer.esri:
case FireMapLayer.esriSatellite: case FireMapLayer.esriSatellite:
case FireMapLayer.esriTerrain: case FireMapLayer.esriTerrain:
@ -177,20 +189,24 @@ class _genericMapState extends State<genericMap> {
switch (layer) { switch (layer) {
case FireMapLayer.osmc: case FireMapLayer.osmc:
subdomains = ['a', 'b', 'c']; subdomains = ['a', 'b', 'c'];
baseLayer = 'https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png'; baseLayer =
'https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png';
break; break;
case FireMapLayer.osmcGrey: case FireMapLayer.osmcGrey:
subdomains = ['a', 'b', 'c']; subdomains = ['a', 'b', 'c'];
baseLayer = 'https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png'; baseLayer = 'https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png';
break; break;
case FireMapLayer.esri: case FireMapLayer.esri:
baseLayer = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}'; baseLayer =
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}';
break; break;
case FireMapLayer.esriSatellite: case FireMapLayer.esriSatellite:
baseLayer = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'; baseLayer =
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}';
break; break;
case FireMapLayer.esriTerrain: case FireMapLayer.esriTerrain:
baseLayer = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}'; baseLayer =
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}';
} }
FlutterMap map = new FlutterMap( FlutterMap map = new FlutterMap(
options: mapOptions, options: mapOptions,
@ -209,7 +225,7 @@ class _genericMapState extends State<genericMap> {
: new DummyMapPluginOptions(), : new DummyMapPluginOptions(),
new MarkerLayerOptions( new MarkerLayerOptions(
markers: buildMarkers( markers: buildMarkers(
_location, mapState.status == FireMapStatus.viewFireNotification ? new LatLng(mapState.fireNotification.lat, mapState.fireNotification.lon): new LatLng(_location.lat, _location.lon),
mapState.fires, mapState.fires,
mapState.industries, mapState.industries,
mapState.falsePos, mapState.falsePos,
@ -290,9 +306,11 @@ class _genericMapState extends State<genericMap> {
floatingActionButtonLocation: floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat, FloatingActionButtonLocation.centerFloat,
bottomNavigationBar: new GenericMapBottom( bottomNavigationBar: new GenericMapBottom(
onSave: () => view.onEditConfirm(_location), onSave: () => view.onEditConfirm(_location),
onCancel: () => view.onEditCancel(_initialLocation), onCancel: () => view.onEditCancel(_initialLocation),
state: view.mapState, onFalsePositive: (sealed, type) =>
view.onFalsePositive(sealed, type),
state: view.mapState,
scaffoldKey: _scaffoldKey, scaffoldKey: _scaffoldKey,
), ),
body: LayoutBuilder( body: LayoutBuilder(
@ -362,28 +380,30 @@ class _genericMapState extends State<genericMap> {
} }
} }
List<Marker> buildMarkers(YourLocation yourLocation, List<dynamic> fires, List<Marker> buildMarkers(LatLng pos, List<dynamic> fires,
List<dynamic> falsePos, List<dynamic> industries, bool isNotif) { List<dynamic> falsePosList, List<dynamic> industries, bool isNotif) {
List<Marker> markers = []; List<Marker> markers = [];
print('building markers: fires: ${fires.length} falsePos: ${falsePosList.length} industries: ${industries.length}, isNotif: ${isNotif} ');
const calibrate = false; // useful when we change the fire icons size const calibrate = false; // useful when we change the fire icons size
markers.add(FireMarker( markers.add(FireMarker(
yourLocation, isNotif ? FireMarkType.fire : FireMarkType.position)); pos, isNotif ? FireMarkType.fire : FireMarkType.position));
if (calibrate) markers.add(FireMarker(yourLocation, FireMarkType.pixel)); if (calibrate) markers.add(FireMarker(pos, FireMarkType.pixel));
falsePos.forEach((fire) { falsePosList.forEach((falsePos) {
var coords = fire['geo']['coordinates']; var coords = falsePos['geo']['coordinates'];
var loc = BasicLocation(lon: coords[0], lat: coords[1]); print('false pos: ${coords}');
var loc = LatLng(coords[1], coords[0]);
markers.add(FireMarker(loc, FireMarkType.falsePos)); markers.add(FireMarker(loc, FireMarkType.falsePos));
if (calibrate) markers.add(FireMarker(loc, FireMarkType.pixel)); if (calibrate) markers.add(FireMarker(loc, FireMarkType.pixel));
}); });
industries.forEach((fire) { industries.forEach((industry) {
// print(fire['geo']['coordinates']); // print(fire['geo']['coordinates']);
var coords = fire['geo']['coordinates']; var coords = industry['geo']['coordinates'];
var loc = BasicLocation(lon: coords[0], lat: coords[1]); var loc = LatLng(coords[1], coords[0]);
markers.add(FireMarker(loc, FireMarkType.industry)); markers.add(FireMarker(loc, FireMarkType.industry));
if (calibrate) markers.add(FireMarker(loc, FireMarkType.pixel)); if (calibrate) markers.add(FireMarker(loc, FireMarkType.pixel));
}); });
fires.forEach((fire) { fires.forEach((fire) {
var loc = new BasicLocation(lat: fire['lat'], lon: fire['lon']); var loc = new LatLng(fire['lat'], fire['lon']);
markers.add( markers.add(
FireMarker(loc, FireMarkType.fire, () => print('marker pressed'))); FireMarker(loc, FireMarkType.fire, () => print('marker pressed')));
markers.add(FireMarker(loc, FireMarkType.pixel)); markers.add(FireMarker(loc, FireMarkType.pixel));

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:comunes_flutter/comunes_flutter.dart';
import 'package:fires_flutter/models/yourLocation.dart'; import 'package:fires_flutter/models/yourLocation.dart';
import 'package:fires_flutter/models/fireNotification.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'colors.dart'; import 'colors.dart';
@ -14,17 +15,19 @@ import 'models/fireMapState.dart';
typedef void OnSave(); typedef void OnSave();
typedef void OnCancel(); typedef void OnCancel();
typedef void OnFalsePositive(); typedef void OnFalsePositive(FireNotification notif, FalsePositiveType type);
class GenericMapBottom extends StatelessWidget { class GenericMapBottom extends StatelessWidget {
final OnSave onSave; final OnSave onSave;
final OnCancel onCancel; final OnCancel onCancel;
final OnFalsePositive onFalsePositive;
final FireMapState state; final FireMapState state;
final GlobalKey<ScaffoldState> scaffoldKey; final GlobalKey<ScaffoldState> scaffoldKey;
GenericMapBottom( GenericMapBottom(
{@required this.onSave, {@required this.onSave,
@required this.onCancel, @required this.onCancel,
@required this.onFalsePositive,
@required this.state, @required this.state,
@required this.scaffoldKey}); @required this.scaffoldKey});
@ -107,7 +110,7 @@ class GenericMapBottom extends StatelessWidget {
value: value, child: new Text(menuText)); value: value, child: new Text(menuText));
}).toList(), }).toList(),
onChanged: (value) async { onChanged: (value) async {
// FIXME api call onFalsePositive(state.fireNotification, value);
await new Future.delayed( await new Future.delayed(
new Duration(milliseconds: 500)); new Duration(milliseconds: 500));
scaffoldKey.currentState.showSnackBar(new SnackBar( scaffoldKey.currentState.showSnackBar(new SnackBar(

View file

@ -1,8 +1,14 @@
import 'package:fires_flutter/models/yourLocation.dart';
import 'package:fires_flutter/models/fireNotification.dart'; import 'package:fires_flutter/models/fireNotification.dart';
import 'package:fires_flutter/models/yourLocation.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
enum FireMapStatus { view, subscriptionConfirm, unsubscribe, edit, viewFireNotification } enum FireMapStatus {
view,
subscriptionConfirm,
unsubscribe,
edit,
viewFireNotification
}
enum FireMapLayer { osmcGrey, esriSatellite, osmc, esri, esriTerrain } enum FireMapLayer { osmcGrey, esriSatellite, osmc, esri, esriTerrain }
@immutable @immutable
@ -18,9 +24,9 @@ class FireMapState {
const FireMapState.initial() const FireMapState.initial()
: this.status = FireMapStatus.view, : this.status = FireMapStatus.view,
this.layer = FireMapLayer.osmcGrey, this.layer = FireMapLayer.osmcGrey,
this.yourLocation = null, this.yourLocation = null,
this.fireNotification = null, this.fireNotification = null,
this.numFires = 0, this.numFires = 0,
this.fires = const [], this.fires = const [],
this.falsePos = const [], this.falsePos = const [],
@ -28,11 +34,11 @@ class FireMapState {
FireMapState( FireMapState(
{this.status: FireMapStatus.view, {this.status: FireMapStatus.view,
this.layer: FireMapLayer.osmcGrey, this.layer: FireMapLayer.osmcGrey,
this.yourLocation, this.yourLocation,
this.numFires, this.numFires,
this.fires, this.fires,
this.fireNotification, this.fireNotification,
this.falsePos, this.falsePos,
this.industries}); this.industries});
@ -63,9 +69,9 @@ class FireMapState {
other is FireMapState && other is FireMapState &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
status == other.status && status == other.status &&
layer == other.layer && layer == other.layer &&
numFires == other.numFires && numFires == other.numFires &&
fireNotification == other.fireNotification && fireNotification == other.fireNotification &&
fires == other.fires && fires == other.fires &&
falsePos == other.falsePos && falsePos == other.falsePos &&
industries == other.industries && industries == other.industries &&

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/flutter_map.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'falsePositiveTypes.dart';
import 'package:bson_objectid/bson_objectid.dart'; import 'package:bson_objectid/bson_objectid.dart';
import 'package:fires_flutter/models/yourLocation.dart'; import 'package:fires_flutter/models/yourLocation.dart';
@ -18,8 +19,8 @@ class FiresApi {
resty.globalClient = new ht.IOClient(); resty.globalClient = new ht.IOClient();
} }
Future<String> createUser( Future<String> createUser(AppState state, String mobileToken,
AppState state, String mobileToken, String lang) async { String lang) async {
assert(state.firesApiUrl != null); assert(state.firesApiUrl != null);
assert(state.firesApiKey != null); assert(state.firesApiKey != null);
assert(mobileToken != null); assert(mobileToken != null);
@ -50,18 +51,18 @@ class FiresApi {
if (response.statusCode == 200) { if (response.statusCode == 200) {
// print(response.body); // print(response.body);
final dataSubscriptions = final dataSubscriptions =
json.decode(response.body)['data']['subscriptions']; json.decode(response.body)['data']['subscriptions'];
List<YourLocation> subscribed = []; List<YourLocation> subscribed = [];
for (int i = 0; i < dataSubscriptions.length; i++) { for (int i = 0; i < dataSubscriptions.length; i++) {
var el = dataSubscriptions[i]; var el = dataSubscriptions[i];
var lat = el['location']['lat']; var lat = el['location']['lat'];
var lon = el['location']['lon']; var lon = el['location']['lon'];
subscribed.add(new YourLocation( subscribed.add(new YourLocation(
id: ObjectId.fromHexString(el['_id']['_str']), id: ObjectId.fromHexString(el['_id']['_str']),
lat: lat, lat: lat,
lon: lon, lon: lon,
subscribed: true, subscribed: true,
distance: el['distance'])); distance: el['distance']));
} }
return subscribed; return subscribed;
@ -116,12 +117,13 @@ class FiresApi {
}); });
} }
Future<UpdateYourLocationMapStatsAction> getFiresInLocation( Future<UpdateFireMapStatsAction> getFiresInLocation(
{AppState state, double lat, double lon, int distance}) async { {AppState state, double lat, double lon, int distance}) async {
assert(state.firesApiUrl != null); assert(state.firesApiUrl != null);
assert(state.firesApiKey != null); assert(state.firesApiKey != null);
var url = '${state.firesApiUrl}fires-in-full/${state var url = '${state.firesApiUrl}fires-in-full/${state
.firesApiKey}/${lat}/${lon}/${distance}'; .firesApiKey}/${lat}/${lon}/${distance}';
if (globals.isDevelopment) print(url);
return await resty.get(url).go().then((response) { return await resty.get(url).go().then((response) {
if (response.statusCode == 200) { if (response.statusCode == 200) {
var resultDecoded = json.decode(response.body); var resultDecoded = json.decode(response.body);
@ -135,13 +137,13 @@ class FiresApi {
var industriesCount = industries.length; var industriesCount = industries.length;
var falsePosCount = falsePos.length; var falsePosCount = falsePos.length;
print( print(
'real: $numFires, fire: $firesCount falsePos: $falsePosCount industries: $industriesCount'); '(Pos: $lat, $lon) real: $numFires, fire: $firesCount falsePos: $falsePosCount industries: $industriesCount');
} }
return new UpdateYourLocationMapStatsAction( return new UpdateFireMapStatsAction(
numFires: numFires, numFires: numFires,
fires: fires, fires: fires,
falsePos: falsePos, falsePos: falsePos,
industries: industries); industries: industries);
} else } else
throw Exception('Wrong response trying to get fire data'); throw Exception('Wrong response trying to get fire data');
}); });
@ -159,15 +161,16 @@ class FiresApi {
// print(resultDecoded['data']['union']); // print(resultDecoded['data']['union']);
List<Polyline> union = []; List<Polyline> union = [];
final multipolygon = final multipolygon =
json.decode(resultDecoded['data']['union']['value'])['geometry'] json.decode(resultDecoded['data']['union']['value'])['geometry']
['coordinates']; ['coordinates'];
for (List<dynamic> polygon in multipolygon) { for (List<dynamic> polygon in multipolygon) {
for (List<dynamic> hole in polygon) { for (List<dynamic> hole in polygon) {
List<LatLng> points = []; List<LatLng> points = [];
for (List<dynamic> point in hole) { for (List<dynamic> point in hole) {
points.add(new LatLng(point[1].toDouble(), point[0].toDouble())); points.add(new LatLng(point[1].toDouble(), point[0].toDouble()));
} }
union.add(new Polyline(points: points, color: color, strokeWidth: 3.0)); union.add(
new Polyline(points: points, color: color, strokeWidth: 3.0));
} }
} }
return union; return union;
@ -175,4 +178,32 @@ class FiresApi {
throw Exception('Wrong response trying to get fire data'); throw Exception('Wrong response trying to get fire data');
}); });
} }
Future<bool> markFalsePositive(AppState state, String mobileToken,
String sealed, FalsePositiveType type) async {
assert(state.firesApiUrl != null);
assert(state.firesApiKey != null);
assert(mobileToken != null);
assert(sealed != null);
assert(type != null);
final params = {
"token": state.firesApiKey,
"mobileToken": mobileToken,
"sealed": sealed,
"type": type.toString()
};
final String url = '${state.firesApiUrl}mobile/falsepositive';
return await resty.post(url).json(params).go().then((response) {
if (response.statusCode == 200) {
// print(response.body);
if (globals.isDevelopment) print(
json.decode(response.body)['data']['upsert']);
return true;
} else {
debugPrint(json.decode(response.body));
return false;
}
});
}
} }

View file

@ -97,13 +97,7 @@ void fetchDataMiddleware(Store<AppState> store, action, NextDispatcher next) {
} }
if (action is ShowFireNotificationMapAction) { if (action is ShowFireNotificationMapAction) {
api getFiresStatsInFire(store, action.notif);
.getFiresInLocation(
state: store.state,
lat: action.notif.lat,
lon: action.notif.lon,
distance: 1) // FalsePositive/server/publications.js
.then((result) => store.dispatch(result));
} }
if (action is UpdateYourLocationAction) { if (action is UpdateYourLocationAction) {
@ -221,10 +215,30 @@ void fetchDataMiddleware(Store<AppState> store, action, NextDispatcher next) {
}); });
} }
if (action is MarkFireAsFalsePositiveAction) {
api.markFalsePositive(store.state, store.state.user.token, action.notif.sealed, action.type).then((result) {
if (result) {
// Not necessary
// store.dispatch(new UpdatedFireNotificationAction(action.notif));
getFiresStatsInFire(store, action.notif);
}
});
}
// Make sure our actions continue on to the reducer. // Make sure our actions continue on to the reducer.
next(action); next(action);
} }
void getFiresStatsInFire(Store<AppState> store, FireNotification notif) {
api
.getFiresInLocation(
state: store.state,
lat: notif.lat,
lon: notif.lon,
distance: 1) // FalsePositive/server/publications.js
.then((result) => store.dispatch(result));
}
void unsubsViaApi(Store<AppState> store, ObjectId id, onUnsubs) { void unsubsViaApi(Store<AppState> store, ObjectId id, onUnsubs) {
api.unsubscribe(store.state, id.toHexString()).then((res) { api.unsubscribe(store.state, id.toHexString()).then((res) {
onUnsubs(); onUnsubs();

View file

@ -12,13 +12,13 @@ class UpdateYourLocationMapAction extends FiresMapActions {
); );
} }
class UpdateYourLocationMapStatsAction extends FiresMapActions { class UpdateFireMapStatsAction extends FiresMapActions {
int numFires; int numFires;
List<dynamic> fires = []; List<dynamic> fires = [];
List<dynamic> falsePos = []; List<dynamic> falsePos = [];
List<dynamic> industries = []; List<dynamic> industries = [];
UpdateYourLocationMapStatsAction( UpdateFireMapStatsAction(
{@required this.numFires, {@required this.numFires,
@required this.fires, @required this.fires,
@required this.falsePos, @required this.falsePos,

View file

@ -8,7 +8,7 @@ final fireMapReducer = combineReducers<FireMapState>([
_showYourLocationMap), _showYourLocationMap),
new TypedReducer<FireMapState, ShowFireNotificationMapAction>( new TypedReducer<FireMapState, ShowFireNotificationMapAction>(
_showFireNotificationMap), _showFireNotificationMap),
new TypedReducer<FireMapState, UpdateYourLocationMapStatsAction>( new TypedReducer<FireMapState, UpdateFireMapStatsAction>(
_updateYourLocationMapStats), _updateYourLocationMapStats),
new TypedReducer<FireMapState, SubscribeAction>(_subscribeYourLocationMap), new TypedReducer<FireMapState, SubscribeAction>(_subscribeYourLocationMap),
new TypedReducer<FireMapState, SubscribeConfirmAction>( new TypedReducer<FireMapState, SubscribeConfirmAction>(
@ -27,7 +27,7 @@ final fireMapReducer = combineReducers<FireMapState>([
]); ]);
FireMapState _updateYourLocationMapStats( FireMapState _updateYourLocationMapStats(
FireMapState state, UpdateYourLocationMapStatsAction action) { FireMapState state, UpdateFireMapStatsAction action) {
return state.copyWith( return state.copyWith(
numFires: action.numFires, numFires: action.numFires,
fires: action.fires, fires: action.fires,

View file

@ -1,4 +1,5 @@
import 'package:fires_flutter/models/fireNotification.dart'; import 'package:fires_flutter/models/fireNotification.dart';
import '../models/falsePositiveTypes.dart';
abstract class FireNotificationActions {} abstract class FireNotificationActions {}
@ -45,3 +46,16 @@ class ReadedFireNotificationAction extends FireNotificationActions {
ReadedFireNotificationAction(this.notif); ReadedFireNotificationAction(this.notif);
} }
class MarkFireAsFalsePositiveAction extends FireNotificationActions {
final FireNotification notif;
final FalsePositiveType type;
MarkFireAsFalsePositiveAction(this.notif, this.type);
}
class UpdatedFireNotificationAction extends FireNotificationActions {
final FireNotification notif;
UpdatedFireNotificationAction(this.notif);
}

View file

@ -1,17 +1,19 @@
import 'package:fires_flutter/models/fireNotification.dart';
import 'package:redux/redux.dart'; import 'package:redux/redux.dart';
import 'actions.dart'; import 'actions.dart';
import 'package:fires_flutter/models/fireNotification.dart';
final fireNotificationReducer = combineReducers<List<FireNotification>>([ final fireNotificationReducer = combineReducers<List<FireNotification>>([
new TypedReducer<List<FireNotification>, AddedFireNotificationAction>( new TypedReducer<List<FireNotification>, AddedFireNotificationAction>(
_addedFireNotification), _addedFireNotification),
new TypedReducer<List<FireNotification>, DeletedFireNotificationAction>( new TypedReducer<List<FireNotification>, DeletedFireNotificationAction>(
_deletedFireNotification), _deletedFireNotification),
new TypedReducer<List<FireNotification>, UpdatedFireNotificationAction>(
_updatedFireNotification),
new TypedReducer<List<FireNotification>, DeletedAllFireNotificationAction>( new TypedReducer<List<FireNotification>, DeletedAllFireNotificationAction>(
_deletedAllFireNotifications), _deletedAllFireNotifications),
new TypedReducer<List<FireNotification>, ReadedFireNotificationAction>( new TypedReducer<List<FireNotification>, ReadedFireNotificationAction>(
_readedFireNotification) _readedFireNotification)
]); ]);
List<FireNotification> _addedFireNotification( List<FireNotification> _addedFireNotification(
@ -20,10 +22,18 @@ List<FireNotification> _addedFireNotification(
} }
List<FireNotification> _deletedFireNotification( List<FireNotification> _deletedFireNotification(
List<FireNotification> notifications, DeletedFireNotificationAction action) { List<FireNotification> notifications,
DeletedFireNotificationAction action) {
return new List.from(notifications)..remove(action.notif); return new List.from(notifications)..remove(action.notif);
} }
List<FireNotification> _updatedFireNotification(
List<FireNotification> notifications, UpdatedFireNotificationAction action) {
return notifications
.map((notif) => notif.id == action.notif.id ? action.notif : notif)
.toList();
}
List<FireNotification> _readedFireNotification( List<FireNotification> _readedFireNotification(
List<FireNotification> notifications, ReadedFireNotificationAction action) { List<FireNotification> notifications, ReadedFireNotificationAction action) {
return notifications return notifications
@ -33,6 +43,7 @@ List<FireNotification> _readedFireNotification(
} }
List<FireNotification> _deletedAllFireNotifications( List<FireNotification> _deletedAllFireNotifications(
List<FireNotification> notifications, DeletedAllFireNotificationAction action) { List<FireNotification> notifications,
DeletedAllFireNotificationAction action) {
return new List<FireNotification>(); return new List<FireNotification>();
} }