False positives in fire notifications
This commit is contained in:
parent
845c38bf04
commit
76085dcb2f
7 changed files with 107 additions and 27 deletions
|
|
@ -59,13 +59,19 @@ class S implements WidgetsLocalizations {
|
|||
String get firesNearPlace => "Fires near other place";
|
||||
String get getAlertsOfFiresinThatArea => "Get alerts of fires in that area";
|
||||
String get isYourUbicationEnabled => "I cannot get your current location. It's your ubication enabled?";
|
||||
String get itSeemsAControlledBurning => "It's a controlled burning";
|
||||
String get itSeemsAFalseAlarm => "It seems a false alarm";
|
||||
String get itSeemsAIndustry => "It's an industry";
|
||||
String get itSeemsNotAtForesFire => "It seems that this is not a forest fire.";
|
||||
String get noConnectivity => "This application needs an Internet connection to work";
|
||||
String get noFiresAround => "There is no fires";
|
||||
String get notAWildfire => "Isn't that a forest fire?";
|
||||
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, suggesting other public data sources of fires to use, etc.";
|
||||
String get supportThisInitiative => "Support this initiative";
|
||||
String get thanksForParticipating => "Thanks for participating";
|
||||
String get toDeleteThisNotification => "Slide horizontally to delete this notification";
|
||||
String get toDeleteThisPlace => "Slide horizontally to delete this place";
|
||||
String get toFiresNotifications => "Subscribe to fires notifications";
|
||||
|
|
@ -142,6 +148,10 @@ class es extends S {
|
|||
@override
|
||||
String get fireNotificationTitle => "Notificación de fuego";
|
||||
@override
|
||||
String get itSeemsAControlledBurning => "Es una quema controlada";
|
||||
@override
|
||||
String get itSeemsAIndustry => "Es una industria";
|
||||
@override
|
||||
String get youDeletedThisPlace => "Has borrado este lugar";
|
||||
@override
|
||||
String get callEmergencyServicesTitle => "Llama al 112";
|
||||
|
|
@ -154,6 +164,8 @@ class es extends S {
|
|||
@override
|
||||
String get aYear => "un año";
|
||||
@override
|
||||
String get itSeemsNotAtForesFire => "Parece que este fuego no es un fuego forestal.";
|
||||
@override
|
||||
String get UNDO => "DESHACER";
|
||||
@override
|
||||
String get tweetAboutAFireTitle => "Twittea";
|
||||
|
|
@ -170,6 +182,8 @@ class es extends S {
|
|||
@override
|
||||
String get isYourUbicationEnabled => "No podemos saber tu ubicación actual. ¿Están los servicios de ubicación en tu móvil activados?";
|
||||
@override
|
||||
String get thanksForParticipating => "Gracias por Participar";
|
||||
@override
|
||||
String get fireNotificationsTitleShort => "Notificaciones";
|
||||
@override
|
||||
String get DELETE => "BORRAR";
|
||||
|
|
@ -180,6 +194,8 @@ class es extends S {
|
|||
@override
|
||||
String get SHOW => "MOSTRAR";
|
||||
@override
|
||||
String get itSeemsAFalseAlarm => "Parece una falsa alarma";
|
||||
@override
|
||||
String get addedThisLocation => "Ya has añadido este lugar antes";
|
||||
@override
|
||||
String get typeTheNameOfAPlace => "Escribe el nombre de un lugar, zona, etc";
|
||||
|
|
@ -210,6 +226,8 @@ class es extends S {
|
|||
@override
|
||||
String get CANCEL => "CANCELAR";
|
||||
@override
|
||||
String get notAWildfire => "¿No es un fuego forestal?";
|
||||
@override
|
||||
String inMonths(String value) => "$value meses";
|
||||
@override
|
||||
String inYears(String value) => "$value años";
|
||||
|
|
|
|||
|
|
@ -292,7 +292,9 @@ class _genericMapState extends State<genericMap> {
|
|||
bottomNavigationBar: new GenericMapBottom(
|
||||
onSave: () => view.onEditConfirm(_location),
|
||||
onCancel: () => view.onEditCancel(_initialLocation),
|
||||
state: view.mapState),
|
||||
state: view.mapState,
|
||||
scaffoldKey: _scaffoldKey,
|
||||
),
|
||||
body: LayoutBuilder(
|
||||
builder: (context, constraints) =>
|
||||
Stack(fit: StackFit.expand, children: <Widget>[
|
||||
|
|
|
|||
|
|
@ -7,17 +7,20 @@ import 'customMoment.dart';
|
|||
import 'generated/i18n.dart';
|
||||
import 'models/appState.dart';
|
||||
import 'models/fireMapState.dart';
|
||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||
|
||||
typedef void OnSave();
|
||||
typedef void OnCancel();
|
||||
typedef void OnFalsePositive();
|
||||
|
||||
class GenericMapBottom extends StatelessWidget {
|
||||
final OnSave onSave;
|
||||
final OnCancel onCancel;
|
||||
final FireMapState state;
|
||||
final GlobalKey<ScaffoldState> scaffoldKey;
|
||||
|
||||
GenericMapBottom(
|
||||
{@required this.onSave, @required this.onCancel, @required this.state});
|
||||
{@required this.onSave, @required this.onCancel, @required this.state, @required this.scaffoldKey});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -28,11 +31,11 @@ class GenericMapBottom extends StatelessWidget {
|
|||
showNotch: false,
|
||||
color: fires100,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
actions: buildActionList(loc, context, kmAround));
|
||||
actions: buildActionList(loc, context, kmAround, scaffoldKey));
|
||||
}
|
||||
|
||||
List<Widget> buildActionList(
|
||||
YourLocation loc, BuildContext context, int kmAround) {
|
||||
YourLocation loc, BuildContext context, int kmAround, GlobalKey<ScaffoldState> scaffoldState) {
|
||||
List<Widget> actionList = new List<Widget>();
|
||||
switch (state.status) {
|
||||
case FireMapStatus.edit:
|
||||
|
|
@ -54,8 +57,9 @@ class GenericMapBottom extends StatelessWidget {
|
|||
child: new Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
children: listWithoutNulls(<Widget>[
|
||||
new Text(state.fireNotification.description),
|
||||
// TODO fire type (neighbout, NASA, etc)
|
||||
new SizedBox(height: 5.0),
|
||||
new Row(
|
||||
children: <Widget>[
|
||||
|
|
@ -63,10 +67,29 @@ class GenericMapBottom extends StatelessWidget {
|
|||
new SizedBox(width: 5.0),
|
||||
new Text(Moment
|
||||
.now()
|
||||
.from(context, state.fireNotification.when))
|
||||
.from(context, state.fireNotification.when)),
|
||||
],
|
||||
)
|
||||
]))));
|
||||
),
|
||||
state.industries.length >= 0 || state.falsePos.length > 0 ? new Text(S.of(context).itSeemsNotAtForesFire, style: new TextStyle(color: fires600)): null,
|
||||
new DropdownButton<String>(
|
||||
style: new TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 18.0,
|
||||
),
|
||||
hint: new Text(S.of(context).notAWildfire),
|
||||
items: <String>[S.of(context).itSeemsAIndustry, S.of(context).itSeemsAControlledBurning, S.of(context).itSeemsAFalseAlarm].map((String value) {
|
||||
return new DropdownMenuItem <String>(
|
||||
value: value,
|
||||
child: new Text(value)
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
// FIXME api call
|
||||
scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
content: new Text(S.of(context).thanksForParticipating),
|
||||
));
|
||||
}),
|
||||
])))));
|
||||
break;
|
||||
case FireMapStatus.unsubscribe:
|
||||
case FireMapStatus.view:
|
||||
|
|
|
|||
|
|
@ -113,16 +113,15 @@ class FiresApi {
|
|||
});
|
||||
}
|
||||
|
||||
Future<UpdateYourLocationMapStatsAction> getYourLocationFireStats(
|
||||
AppState state, YourLocation location) async {
|
||||
Future<UpdateYourLocationMapStatsAction> getFiresInLocation(
|
||||
{AppState state, double lat, double lon, int distance}) async {
|
||||
assert(state.firesApiUrl != null);
|
||||
assert(state.firesApiKey != null);
|
||||
var url = '${state.firesApiUrl}fires-in-full/${state
|
||||
.firesApiKey}/${location.lat}/${location.lon}/${location.distance}';
|
||||
.firesApiKey}/${lat}/${lon}/${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'];
|
||||
|
|
@ -140,7 +139,7 @@ class FiresApi {
|
|||
fires: fires,
|
||||
falsePos: falsePos,
|
||||
industries: industries);
|
||||
} else throw Exception('Wrong response trying to get stats');
|
||||
} else throw Exception('Wrong response trying to get fire data');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:bson_objectid/bson_objectid.dart';
|
||||
import 'package:fires_flutter/models/yourLocation.dart';
|
||||
import 'package:fires_flutter/models/fireNotification.dart';
|
||||
import 'package:fires_flutter/models/yourLocation.dart';
|
||||
import 'package:flutter_simple_dependency_injection/injector.dart';
|
||||
import 'package:just_debounce_it/just_debounce_it.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import '../models/appState.dart';
|
||||
import '../models/fireNotificationsPersist.dart';
|
||||
|
|
@ -87,15 +88,34 @@ void fetchDataMiddleware(Store<AppState> store, action, NextDispatcher next) {
|
|||
|
||||
if (action is ShowYourLocationMapAction) {
|
||||
api
|
||||
.getYourLocationFireStats(store.state, action.loc)
|
||||
.getFiresInLocation(
|
||||
state: store.state,
|
||||
lat: action.loc.lat,
|
||||
lon: action.loc.lon,
|
||||
distance: action.loc.distance)
|
||||
.then((result) => store.dispatch(result));
|
||||
}
|
||||
|
||||
if (action is ShowFireNotificationMapAction) {
|
||||
api
|
||||
.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.loc.subscribed)
|
||||
Debounce.seconds(
|
||||
2,
|
||||
() => api
|
||||
.getYourLocationFireStats(store.state, action.loc)
|
||||
.getFiresInLocation(
|
||||
state: store.state,
|
||||
lat: action.loc.lat,
|
||||
lon: action.loc.lon,
|
||||
distance: action.loc.distance)
|
||||
.then((result) => store.dispatch(result)));
|
||||
else {
|
||||
// FIXME do something?
|
||||
|
|
@ -147,18 +167,22 @@ void fetchDataMiddleware(Store<AppState> store, action, NextDispatcher next) {
|
|||
localLocations.forEach((location) => location.subscribed = false);
|
||||
// print('Local persisted: ${localLocations.length}');
|
||||
subscribedLocations.forEach((subsLoc) {
|
||||
localLocations
|
||||
.firstWhere(
|
||||
localLocations.firstWhere(
|
||||
(localLocation) => localLocation.id == subsLoc.id, orElse: () {
|
||||
localLocations.add(subsLoc);
|
||||
})
|
||||
.subscribed = true;
|
||||
}).subscribed = true;
|
||||
});
|
||||
}
|
||||
localLocations.forEach((yl) {
|
||||
api.getYourLocationFireStats(store.state, yl).then((value) {
|
||||
localLocations.forEach((yl) {
|
||||
api
|
||||
.getFiresInLocation(
|
||||
state: store.state,
|
||||
lat: yl.lat,
|
||||
lon: yl.lon,
|
||||
distance: yl.distance)
|
||||
.then((value) {
|
||||
yl.currentNumFires = value.numFires;
|
||||
store.dispatch(new UpdateYourLocationAction(yl));
|
||||
store.dispatch(new UpdateYourLocationAction(yl));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -180,7 +204,9 @@ void fetchDataMiddleware(Store<AppState> store, action, NextDispatcher next) {
|
|||
loadFireNotifications().then((fireNotifications) {
|
||||
int unread = 0;
|
||||
for (FireNotification notif in fireNotifications) {
|
||||
if (!notif.read) { unread++; }
|
||||
if (!notif.read) {
|
||||
unread++;
|
||||
}
|
||||
}
|
||||
store.dispatch(
|
||||
new FetchFireNotificationsSucceededAction(fireNotifications, unread));
|
||||
|
|
|
|||
|
|
@ -66,5 +66,11 @@
|
|||
"CLOSE": "CLOSE",
|
||||
"noConnectivity": "This application needs an Internet connection to work",
|
||||
"NASAAck": "We acknowledge the use of data and imagery from LANCE FIRMS operated by the NASA/GSFC/Earth Science Data and Information System (ESDIS) with funding provided by NASA/HQ.",
|
||||
"appMoto": "Strengthening neighborhoods against wildfires"
|
||||
"appMoto": "Strengthening neighborhoods against wildfires",
|
||||
"itSeemsNotAtForesFire": "It seems that this is not a forest fire.",
|
||||
"notAWildfire": "Isn't that a forest fire?",
|
||||
"itSeemsAIndustry": "It's an industry",
|
||||
"itSeemsAControlledBurning": "It's a controlled burning",
|
||||
"itSeemsAFalseAlarm": "It seems a false alarm",
|
||||
"thanksForParticipating": "Thanks for participating"
|
||||
}
|
||||
|
|
@ -66,5 +66,11 @@
|
|||
"CLOSE": "CERRAR",
|
||||
"noConnectivity": "Esta aplicación necesita una conexión a Internet para funcionar",
|
||||
"NASAAck": "Reconocemos el uso de datos e imágenes de LANCE FIRMS operadas por NASA/GSFC/Earth Science Data and Information System (ESDIS) con fondos proporcionados por NASA/HQ.",
|
||||
"appMoto": "Fortaleciendo vecindarios contra incendios forestales"
|
||||
"appMoto": "Fortaleciendo vecindarios contra incendios forestales",
|
||||
"itSeemsNotAtForesFire": "Parece que este fuego no es un fuego forestal.",
|
||||
"notAWildfire": "¿No es un fuego forestal?",
|
||||
"itSeemsAIndustry": "Es una industria",
|
||||
"itSeemsAControlledBurning": "Es una quema controlada",
|
||||
"itSeemsAFalseAlarm": "Parece una falsa alarma",
|
||||
"thanksForParticipating": "Gracias por Participar"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue