Last changes not published
This commit is contained in:
parent
ac65ccf990
commit
21ec08303a
43 changed files with 607 additions and 613 deletions
|
|
@ -5,7 +5,7 @@ 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 'package:redux/redux.dart';
|
||||
|
||||
import 'colors.dart';
|
||||
import 'firesSpinner.dart';
|
||||
|
|
@ -91,7 +91,7 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
|
|||
icon: new Icon(loc.subscribed
|
||||
? Icons.notifications_active
|
||||
: Icons.notifications_off),
|
||||
color: loc.subscribed ? fires600: null,
|
||||
color: loc.subscribed ? fires600 : null,
|
||||
onPressed: () {
|
||||
loc.subscribed = !loc.subscribed;
|
||||
onToggle(loc);
|
||||
|
|
@ -125,7 +125,8 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
|
|||
}
|
||||
|
||||
void showSnackMsg(String msg) {
|
||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
// _scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
|
||||
content: new Text(msg),
|
||||
));
|
||||
}
|
||||
|
|
@ -183,7 +184,7 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
|
|||
},
|
||||
onDelete: (loc) {
|
||||
store.dispatch(new DeleteYourLocationAction(loc));
|
||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
|
||||
content: new Text(S.of(context).youDeletedThisPlace),
|
||||
action: new SnackBarAction(
|
||||
label: S.of(context).UNDO,
|
||||
|
|
@ -242,6 +243,7 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
|
|||
view.onRefresh(completer);
|
||||
return completer.future;
|
||||
}),
|
||||
// TODO: Evaluate: https://github.com/tiagojencmartins/unicornspeeddial
|
||||
new FabDialer(_fabMiniMenuItemList(context, view.onAdd),
|
||||
fires600, new Icon(Icons.add))
|
||||
])
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/src/widgets/framework.dart';
|
||||
import 'package:flutter_map/plugin_api.dart';
|
||||
|
||||
class AttributionPluginOptions extends LayerOptions {
|
||||
|
|
@ -10,7 +9,8 @@ class AttributionPluginOptions extends LayerOptions {
|
|||
|
||||
class AttributionPlugin implements MapPlugin {
|
||||
@override
|
||||
Widget createLayer(LayerOptions options, MapState mapState) {
|
||||
Widget createLayer(
|
||||
LayerOptions options, MapState mapState, Stream<Null> stream) {
|
||||
if (options is AttributionPluginOptions) {
|
||||
var style = new TextStyle(
|
||||
// fontWeight: FontWeight.bold,
|
||||
|
|
|
|||
|
|
@ -34,12 +34,17 @@ class CustomBottomAppBar extends StatelessWidget {
|
|||
|
||||
rowContents.addAll(this.actions);
|
||||
|
||||
return new BottomAppBar(
|
||||
color: color,
|
||||
hasNotch: showNotch,
|
||||
child: new Row(
|
||||
mainAxisAlignment: mainAxisAlignment,
|
||||
children: rowContents),
|
||||
);
|
||||
return showNotch
|
||||
? new BottomAppBar(
|
||||
color: color,
|
||||
shape: CircularNotchedRectangle(),
|
||||
child: new Row(
|
||||
mainAxisAlignment: mainAxisAlignment, children: rowContents),
|
||||
)
|
||||
: new BottomAppBar(
|
||||
color: color,
|
||||
child: new Row(
|
||||
mainAxisAlignment: mainAxisAlignment, children: rowContents),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
// found in the LICENSE file.
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
// TODO(dragostis): Missing functionality:
|
||||
// * mobile horizontal mode with adding/removing steps
|
||||
// * alternative labeling
|
||||
|
|
@ -53,7 +52,8 @@ const Color _kCircleActiveDark = Colors.black87;
|
|||
const Color _kDisabledLight = Colors.black38;
|
||||
const Color _kDisabledDark = Colors.white30;
|
||||
const double _kCustomStepSize = 24.0;
|
||||
const double _kTriangleHeight = _kCustomStepSize * 0.866025; // Triangle height. sqrt(3.0) / 2.0
|
||||
const double _kTriangleHeight =
|
||||
_kCustomStepSize * 0.866025; // Triangle height. sqrt(3.0) / 2.0
|
||||
|
||||
/// A material step used in [CustomStepper]. The step can have a title and subtitle,
|
||||
/// an icon within its circle, some content and a state that governs its
|
||||
|
|
@ -75,9 +75,9 @@ class CustomStep {
|
|||
@required this.content,
|
||||
this.state: CustomStepState.indexed,
|
||||
this.isActive: false,
|
||||
}) : assert(title != null),
|
||||
assert(content != null),
|
||||
assert(state != null);
|
||||
}) : assert(title != null),
|
||||
assert(content != null),
|
||||
assert(state != null);
|
||||
|
||||
/// The title of the step that typically describes it.
|
||||
final Widget title;
|
||||
|
|
@ -130,11 +130,11 @@ class CustomStepper extends StatefulWidget {
|
|||
this.onCustomStepTapped,
|
||||
this.onCustomStepContinue,
|
||||
this.onCustomStepCancel,
|
||||
}) : assert(steps != null),
|
||||
assert(type != null),
|
||||
assert(currentCustomStep != null),
|
||||
assert(0 <= currentCustomStep && currentCustomStep < steps.length),
|
||||
super(key: key);
|
||||
}) : assert(steps != null),
|
||||
assert(type != null),
|
||||
assert(currentCustomStep != null),
|
||||
assert(0 <= currentCustomStep && currentCustomStep < steps.length),
|
||||
super(key: key);
|
||||
|
||||
/// The steps of the stepper whose titles, subtitles, icons always get shown.
|
||||
///
|
||||
|
|
@ -177,7 +177,7 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
super.initState();
|
||||
_keys = new List<GlobalKey>.generate(
|
||||
widget.steps.length,
|
||||
(int i) => new GlobalKey(),
|
||||
(int i) => new GlobalKey(),
|
||||
);
|
||||
|
||||
for (int i = 0; i < widget.steps.length; i += 1)
|
||||
|
|
@ -218,7 +218,8 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
}
|
||||
|
||||
Widget _buildCircleChild(int index, bool oldState) {
|
||||
final CustomStepState state = oldState ? _oldStates[index] : widget.steps[index].state;
|
||||
final CustomStepState state =
|
||||
oldState ? _oldStates[index] : widget.steps[index].state;
|
||||
final bool isDarkActive = _isDark() && widget.steps[index].isActive;
|
||||
assert(state != null);
|
||||
switch (state) {
|
||||
|
|
@ -226,7 +227,9 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
case CustomStepState.disabled:
|
||||
return new Text(
|
||||
'${index + 1}',
|
||||
style: isDarkActive ? _kCustomStepStyle.copyWith(color: Colors.black87) : _kCustomStepStyle,
|
||||
style: isDarkActive
|
||||
? _kCustomStepStyle.copyWith(color: Colors.black87)
|
||||
: _kCustomStepStyle,
|
||||
);
|
||||
case CustomStepState.editing:
|
||||
return new Icon(
|
||||
|
|
@ -247,9 +250,13 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
Color _circleColor(int index) {
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
if (!_isDark()) {
|
||||
return widget.steps[index].isActive ? themeData.primaryColor : Colors.black38;
|
||||
return widget.steps[index].isActive
|
||||
? themeData.primaryColor
|
||||
: Colors.black38;
|
||||
} else {
|
||||
return widget.steps[index].isActive ? themeData.accentColor : themeData.backgroundColor;
|
||||
return widget.steps[index].isActive
|
||||
? themeData.accentColor
|
||||
: themeData.backgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -266,7 +273,8 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
shape: BoxShape.circle,
|
||||
),
|
||||
child: new Center(
|
||||
child: _buildCircleChild(index, oldState && widget.steps[index].state == CustomStepState.error),
|
||||
child: _buildCircleChild(index,
|
||||
oldState && widget.steps[index].state == CustomStepState.error),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -280,14 +288,19 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
child: new Center(
|
||||
child: new SizedBox(
|
||||
width: _kCustomStepSize,
|
||||
height: _kTriangleHeight, // Height of 24dp-long-sided equilateral triangle.
|
||||
height:
|
||||
_kTriangleHeight, // Height of 24dp-long-sided equilateral triangle.
|
||||
child: new CustomPaint(
|
||||
painter: new _TrianglePainter(
|
||||
color: _isDark() ? _kErrorDark : _kErrorLight,
|
||||
),
|
||||
child: new Align(
|
||||
alignment: const Alignment(0.0, 0.8), // 0.8 looks better than the geometrical 0.33.
|
||||
child: _buildCircleChild(index, oldState && widget.steps[index].state != CustomStepState.error),
|
||||
alignment: const Alignment(
|
||||
0.0, 0.8), // 0.8 looks better than the geometrical 0.33.
|
||||
child: _buildCircleChild(
|
||||
index,
|
||||
oldState &&
|
||||
widget.steps[index].state != CustomStepState.error),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -303,7 +316,9 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
firstCurve: const Interval(0.0, 0.6, curve: Curves.fastOutSlowIn),
|
||||
secondCurve: const Interval(0.4, 1.0, curve: Curves.fastOutSlowIn),
|
||||
sizeCurve: Curves.fastOutSlowIn,
|
||||
crossFadeState: widget.steps[index].state == CustomStepState.error ? CrossFadeState.showSecond : CrossFadeState.showFirst,
|
||||
crossFadeState: widget.steps[index].state == CustomStepState.error
|
||||
? CrossFadeState.showSecond
|
||||
: CrossFadeState.showFirst,
|
||||
duration: kThemeAnimationDuration,
|
||||
);
|
||||
} else {
|
||||
|
|
@ -328,8 +343,9 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
|
||||
assert(cancelColor != null);
|
||||
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||
// final ThemeData themeData = Theme.of(context);
|
||||
// final MaterialLocalizations localizations =
|
||||
// MaterialLocalizations.of(context);
|
||||
|
||||
return new Container(
|
||||
margin: const EdgeInsets.only(top: 16.0),
|
||||
|
|
@ -368,15 +384,13 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
case CustomStepState.indexed:
|
||||
case CustomStepState.editing:
|
||||
case CustomStepState.complete:
|
||||
return textTheme.body2;
|
||||
return textTheme.bodyText1;
|
||||
case CustomStepState.disabled:
|
||||
return textTheme.body2.copyWith(
|
||||
color: _isDark() ? _kDisabledDark : _kDisabledLight
|
||||
);
|
||||
return textTheme.bodyText1
|
||||
.copyWith(color: _isDark() ? _kDisabledDark : _kDisabledLight);
|
||||
case CustomStepState.error:
|
||||
return textTheme.body2.copyWith(
|
||||
color: _isDark() ? _kErrorDark : _kErrorLight
|
||||
);
|
||||
return textTheme.bodyText1
|
||||
.copyWith(color: _isDark() ? _kErrorDark : _kErrorLight);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -392,13 +406,11 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
case CustomStepState.complete:
|
||||
return textTheme.caption;
|
||||
case CustomStepState.disabled:
|
||||
return textTheme.caption.copyWith(
|
||||
color: _isDark() ? _kDisabledDark : _kDisabledLight
|
||||
);
|
||||
return textTheme.caption
|
||||
.copyWith(color: _isDark() ? _kDisabledDark : _kDisabledLight);
|
||||
case CustomStepState.error:
|
||||
return textTheme.caption.copyWith(
|
||||
color: _isDark() ? _kErrorDark : _kErrorLight
|
||||
);
|
||||
return textTheme.caption
|
||||
.copyWith(color: _isDark() ? _kErrorDark : _kErrorLight);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -427,33 +439,26 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
);
|
||||
|
||||
return new Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: children
|
||||
);
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: children);
|
||||
}
|
||||
|
||||
Widget _buildVerticalHeader(int index) {
|
||||
return new Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: new Row(
|
||||
children: <Widget>[
|
||||
new Column(
|
||||
children: <Widget>[
|
||||
// Line parts are always added in order for the ink splash to
|
||||
// flood the tips of the connector lines.
|
||||
_buildLine(!_isFirst(index)),
|
||||
_buildIcon(index),
|
||||
_buildLine(!_isLast(index)),
|
||||
]
|
||||
),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: new Row(children: <Widget>[
|
||||
new Column(children: <Widget>[
|
||||
// Line parts are always added in order for the ink splash to
|
||||
// flood the tips of the connector lines.
|
||||
_buildLine(!_isFirst(index)),
|
||||
_buildIcon(index),
|
||||
_buildLine(!_isLast(index)),
|
||||
]),
|
||||
new Container(
|
||||
margin: const EdgeInsetsDirectional.only(start: 12.0),
|
||||
child: _buildHeaderText(index)
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
margin: const EdgeInsetsDirectional.only(start: 12.0),
|
||||
child: _buildHeaderText(index))
|
||||
]));
|
||||
}
|
||||
|
||||
Widget _buildVerticalBody(int index) {
|
||||
|
|
@ -493,7 +498,9 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
firstCurve: const Interval(0.0, 0.6, curve: Curves.fastOutSlowIn),
|
||||
secondCurve: const Interval(0.4, 1.0, curve: Curves.fastOutSlowIn),
|
||||
sizeCurve: Curves.fastOutSlowIn,
|
||||
crossFadeState: _isCurrent(index) ? CrossFadeState.showSecond : CrossFadeState.showFirst,
|
||||
crossFadeState: _isCurrent(index)
|
||||
? CrossFadeState.showSecond
|
||||
: CrossFadeState.showFirst,
|
||||
duration: kThemeAnimationDuration,
|
||||
),
|
||||
],
|
||||
|
|
@ -504,29 +511,25 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
final List<Widget> children = <Widget>[];
|
||||
|
||||
for (int i = 0; i < widget.steps.length; i += 1) {
|
||||
children.add(
|
||||
new Column(
|
||||
key: _keys[i],
|
||||
children: <Widget>[
|
||||
new InkWell(
|
||||
onTap: widget.steps[i].state != CustomStepState.disabled ? () {
|
||||
// In the vertical case we need to scroll to the newly tapped
|
||||
// step.
|
||||
Scrollable.ensureVisible(
|
||||
_keys[i].currentContext,
|
||||
curve: Curves.fastOutSlowIn,
|
||||
duration: kThemeAnimationDuration,
|
||||
);
|
||||
children.add(new Column(key: _keys[i], children: <Widget>[
|
||||
new InkWell(
|
||||
onTap: widget.steps[i].state != CustomStepState.disabled
|
||||
? () {
|
||||
// In the vertical case we need to scroll to the newly tapped
|
||||
// step.
|
||||
Scrollable.ensureVisible(
|
||||
_keys[i].currentContext,
|
||||
curve: Curves.fastOutSlowIn,
|
||||
duration: kThemeAnimationDuration,
|
||||
);
|
||||
|
||||
if (widget.onCustomStepTapped != null)
|
||||
widget.onCustomStepTapped(i);
|
||||
} : null,
|
||||
child: _buildVerticalHeader(i)
|
||||
),
|
||||
_buildVerticalBody(i)
|
||||
]
|
||||
)
|
||||
);
|
||||
if (widget.onCustomStepTapped != null)
|
||||
widget.onCustomStepTapped(i);
|
||||
}
|
||||
: null,
|
||||
child: _buildVerticalHeader(i)),
|
||||
_buildVerticalBody(i)
|
||||
]));
|
||||
}
|
||||
|
||||
return new ListView(
|
||||
|
|
@ -541,10 +544,12 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
for (int i = 0; i < widget.steps.length; i += 1) {
|
||||
children.add(
|
||||
new InkResponse(
|
||||
onTap: widget.steps[i].state != CustomStepState.disabled ? () {
|
||||
if (widget.onCustomStepTapped != null)
|
||||
widget.onCustomStepTapped(i);
|
||||
} : null,
|
||||
onTap: widget.steps[i].state != CustomStepState.disabled
|
||||
? () {
|
||||
if (widget.onCustomStepTapped != null)
|
||||
widget.onCustomStepTapped(i);
|
||||
}
|
||||
: null,
|
||||
child: new Row(
|
||||
children: <Widget>[
|
||||
new Container(
|
||||
|
|
@ -593,7 +598,7 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
new AnimatedSize(
|
||||
curve: Curves.fastOutSlowIn,
|
||||
duration: kThemeAnimationDuration,
|
||||
//vsync: this,
|
||||
vsync: null,
|
||||
child: widget.steps[widget.currentCustomStep].content,
|
||||
),
|
||||
_buildVerticalControls(),
|
||||
|
|
@ -608,12 +613,11 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
assert(() {
|
||||
if (context.ancestorWidgetOfExactType(CustomStepper) != null)
|
||||
if (context.findAncestorWidgetOfExactType<CustomStepper>() != null)
|
||||
throw new FlutterError(
|
||||
'CustomSteppers must not be nested. The material specification advises '
|
||||
'CustomSteppers must not be nested. The material specification advises '
|
||||
'that one should avoid embedding steppers within steppers. '
|
||||
'https://material.google.com/components/steppers.html#steppers-usage\n'
|
||||
);
|
||||
'https://material.google.com/components/steppers.html#steppers-usage\n');
|
||||
return true;
|
||||
}());
|
||||
assert(widget.type != null);
|
||||
|
|
@ -630,9 +634,7 @@ class _CustomStepperState extends State<CustomStepper> {
|
|||
// Paints a triangle whose base is the bottom of the bounding rectangle and its
|
||||
// top vertex the middle of its top.
|
||||
class _TrianglePainter extends CustomPainter {
|
||||
_TrianglePainter({
|
||||
this.color
|
||||
});
|
||||
_TrianglePainter({this.color});
|
||||
|
||||
final Color color;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:flutter/src/widgets/framework.dart';
|
||||
import 'package:flutter_map/plugin_api.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/plugin_api.dart';
|
||||
|
||||
class DummyMapPluginOptions extends LayerOptions {
|
||||
final String text;
|
||||
|
|
@ -10,9 +9,9 @@ class DummyMapPluginOptions extends LayerOptions {
|
|||
|
||||
// https://github.com/apptreesoftware/flutter_map/blob/master/flutter_map_example/lib/pages/plugin_api.dart
|
||||
class DummyMapPlugin extends MapPlugin {
|
||||
|
||||
@override
|
||||
Widget createLayer(LayerOptions options, MapState mapState) {
|
||||
Widget createLayer(
|
||||
LayerOptions options, MapState mapState, Stream<Null> stream) {
|
||||
if (options is DummyMapPluginOptions) {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,34 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart' show rootBundle;
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
final esRegExp = new RegExp("^es-");
|
||||
|
||||
String getFallbackLang(String lang) {
|
||||
if (lang == 'ast' || lang == 'gl' || lang == 'eu' ||
|
||||
lang == 'es' || lang == 'ca' || (esRegExp).allMatches(lang).length > 0) {
|
||||
String getFallbackLang(String lang) {
|
||||
if (lang == 'ast' ||
|
||||
lang == 'gl' ||
|
||||
lang == 'eu' ||
|
||||
lang == 'es' ||
|
||||
lang == 'ca' ||
|
||||
(esRegExp).allMatches(lang).length > 0) {
|
||||
return 'es';
|
||||
}
|
||||
return 'en';
|
||||
}
|
||||
|
||||
Future<String> getFileNameOfLang({@required String dir,@required String fileName,@required String ext,@required String lang}) async {
|
||||
Future<String> getFileNameOfLang(
|
||||
{@required String dir,
|
||||
@required String fileName,
|
||||
@required String ext,
|
||||
@required String lang}) async {
|
||||
String base = '$dir/$fileName';
|
||||
String fallback = getFallbackLang(lang);
|
||||
String file = '${base}-${lang}.${ext}';
|
||||
String file = '$base-$lang.$ext';
|
||||
if (await assetNotExists(file)) {
|
||||
file = '${base}-${fallback}.${ext}';
|
||||
file = '$base-$fallback.$ext';
|
||||
if (await assetNotExists(file)) {
|
||||
file = '${base}.${ext}';
|
||||
file = '$base.$ext';
|
||||
}
|
||||
}
|
||||
return file;
|
||||
|
|
@ -28,5 +37,9 @@ Future<String> getFileNameOfLang({@required String dir,@required String fileNam
|
|||
// https://github.com/flutter/flutter/issues/15325
|
||||
Future<bool> assetNotExists(String asset) {
|
||||
print('Does not exists $asset ?');
|
||||
return rootBundle.load(asset).then((_) => false).catchError((err, stack) { print (err); print(stack); return true;});
|
||||
}
|
||||
return rootBundle.load(asset).then((_) => false).catchError((err, stack) {
|
||||
print(err);
|
||||
print(stack);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ import 'package:comunes_flutter/comunes_flutter.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:share/share.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'customStepper.dart';
|
||||
import 'mainDrawer.dart';
|
||||
|
||||
import 'customStepper.dart';
|
||||
import 'generated/i18n.dart';
|
||||
import 'mainDrawer.dart';
|
||||
import 'placesAutocompleteUtils.dart';
|
||||
|
||||
class FireAlert extends StatefulWidget {
|
||||
|
|
@ -40,7 +40,7 @@ class _FireAlertState extends State<FireAlert> {
|
|||
heroTag: 'neighAction',
|
||||
child: const Icon(CommunityMaterialIcons.bullhorn),
|
||||
onPressed: () {
|
||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
|
||||
content: new Text(S.of(context).inDevelopment),
|
||||
));
|
||||
},
|
||||
|
|
@ -48,7 +48,6 @@ class _FireAlertState extends State<FireAlert> {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
Widget buildTweetButton() {
|
||||
return new Align(
|
||||
alignment: const Alignment(0.0, -0.2),
|
||||
|
|
@ -62,9 +61,11 @@ class _FireAlertState extends State<FireAlert> {
|
|||
String where =
|
||||
yourLocation.description.replaceAll(' ', '').split(',')[0];
|
||||
print(where);
|
||||
Share.share(S.of(context).tweetAboutSelf(yourLocation.description, '#IF${where}'));
|
||||
Share.share(S
|
||||
.of(context)
|
||||
.tweetAboutSelf(yourLocation.description, '#IF$where'));
|
||||
}).catchError((onError) {
|
||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
|
||||
content: new Text(
|
||||
S.of(_scaffoldKey.currentContext).errorFirePlaceDialog)));
|
||||
});
|
||||
|
|
@ -87,13 +88,13 @@ class _FireAlertState extends State<FireAlert> {
|
|||
buildCallButton()
|
||||
])),
|
||||
new CustomStep(
|
||||
title: new Text(S.of(context).notifyNeighbours),
|
||||
// state: CustomStepState.disabled,
|
||||
content: new Column(children: <Widget>[
|
||||
new Text(S.of(context).notifyNeighboursDescription),
|
||||
new SizedBox(height: 20.0),
|
||||
buildNotifyNeighboursButton()
|
||||
])),
|
||||
title: new Text(S.of(context).notifyNeighbours),
|
||||
// state: CustomStepState.disabled,
|
||||
content: new Column(children: <Widget>[
|
||||
new Text(S.of(context).notifyNeighboursDescription),
|
||||
new SizedBox(height: 20.0),
|
||||
buildNotifyNeighboursButton()
|
||||
])),
|
||||
// TODO conditional: this only in Spain
|
||||
new CustomStep(
|
||||
title: new Text(S.of(context).tweetAboutAFireTitle),
|
||||
|
|
|
|||
|
|
@ -2,30 +2,33 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_map/plugin_api.dart';
|
||||
import 'package:latlong/latlong.dart';
|
||||
import 'fireMarkerIcon.dart';
|
||||
|
||||
import 'fireMarkType.dart';
|
||||
import 'fireMarkerIcon.dart';
|
||||
|
||||
class FireMarker extends Marker {
|
||||
|
||||
FireMarker(LatLng pos, type,
|
||||
[onTap = null, AnchorPos anchor = AnchorPos.center, Anchor anchorOverride])
|
||||
[onTap,
|
||||
// AnchorPos anchor = AnchorPos.center,
|
||||
Anchor anchorOverride])
|
||||
: super(
|
||||
width: 80.0,
|
||||
height: 80.0,
|
||||
point: pos,
|
||||
builder: (ctx) => new Container(
|
||||
child: new GestureDetector(
|
||||
child: new FireMarkerIcon(type), onTap: onTap)
|
||||
),
|
||||
anchor: anchor,
|
||||
anchorOverride: anchorOverride ?? type == FireMarkType.position
|
||||
? new Anchor(40.0, 20.0)
|
||||
child: new GestureDetector(
|
||||
child: new FireMarkerIcon(type), onTap: onTap)),
|
||||
// anchor: anchor,
|
||||
anchorPos: anchorOverride ?? type == FireMarkType.position
|
||||
? AnchorPos.exactly(new Anchor(40.0, 20.0))
|
||||
: type == FireMarkType.fire
|
||||
? new Anchor(40.0, 24.0)
|
||||
? AnchorPos.exactly(new Anchor(40.0, 24.0))
|
||||
: type == FireMarkType.pixel
|
||||
? null // auto calculate with height/width in Marker
|
||||
// industries, etc (below)
|
||||
// FIXME check if this is accurate
|
||||
: new Anchor(40.0, 35.0),
|
||||
);
|
||||
: AnchorPos.exactly(new Anchor(40.0, 35.0)),
|
||||
) {
|
||||
// anchor = anchorOverride;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,15 @@ import 'package:fires_flutter/models/fireNotification.dart';
|
|||
import 'package:fires_flutter/models/yourLocation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:redux/src/store.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
|
||||
import 'customMoment.dart';
|
||||
import 'firesSpinner.dart';
|
||||
import 'generated/i18n.dart';
|
||||
import 'genericMap.dart';
|
||||
import 'mainDrawer.dart';
|
||||
import 'models/appState.dart';
|
||||
import 'redux/actions.dart';
|
||||
import 'firesSpinner.dart';
|
||||
|
||||
@immutable
|
||||
class _ViewModel {
|
||||
|
|
@ -76,7 +76,7 @@ class _FireNotificationListState extends State<FireNotificationList> {
|
|||
return new ListTile(
|
||||
dense: true,
|
||||
leading: const Icon(Icons.whatshot),
|
||||
title: new Text('${prefix}${notif.description}',
|
||||
title: new Text('$prefix${notif.description}',
|
||||
style: new TextStyle(
|
||||
fontWeight: notif.read ? FontWeight.normal : FontWeight.bold)),
|
||||
subtitle: new Text(Moment.now().from(context, notif.when)),
|
||||
|
|
@ -89,7 +89,7 @@ class _FireNotificationListState extends State<FireNotificationList> {
|
|||
}
|
||||
|
||||
void showSnackMsg(String msg) {
|
||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
|
||||
content: new Text(msg),
|
||||
));
|
||||
}
|
||||
|
|
@ -149,8 +149,8 @@ class _FireNotificationListState extends State<FireNotificationList> {
|
|||
return new StoreConnector<AppState, _ViewModel>(
|
||||
distinct: true,
|
||||
converter: (store) {
|
||||
print('New ViewModel of Fires Notifications (unread: ${store.state
|
||||
.fireNotificationsUnread})');
|
||||
print(
|
||||
'New ViewModel of Fires Notifications (unread: ${store.state.fireNotificationsUnread})');
|
||||
return new _ViewModel(
|
||||
isLoaded: store.state.isLoaded,
|
||||
onDeleteAll: () {
|
||||
|
|
@ -158,7 +158,7 @@ class _FireNotificationListState extends State<FireNotificationList> {
|
|||
},
|
||||
onDelete: (notif) {
|
||||
store.dispatch(new DeleteFireNotificationAction(notif));
|
||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
|
||||
content: new Text(S.of(context).youDeletedThisNotification),
|
||||
action: new SnackBarAction(
|
||||
label: S.of(context).UNDO,
|
||||
|
|
@ -202,25 +202,33 @@ class _FireNotificationListState extends State<FireNotificationList> {
|
|||
onPressed: () => _showConfirmDialog(view))
|
||||
: null
|
||||
])),
|
||||
body: !view.isLoaded ? new FiresSpinner() : !hasFireNotifications
|
||||
? Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: new Card(
|
||||
child: new Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: new CenteredColumn(children: <Widget>[
|
||||
new Icon(Icons.notifications_none,
|
||||
size: 150.0, color: Colors.black26),
|
||||
new SizedBox(height: 20.0),
|
||||
new Text(
|
||||
S.of(context).fireNotificationsDescription,
|
||||
textAlign: TextAlign.center,
|
||||
textScaleFactor: 1.1,
|
||||
style: new TextStyle(
|
||||
height: 1.3, color: Colors.black45))
|
||||
]))))
|
||||
: _buildSavedFireNotifications(context, view.yourLocations,
|
||||
view.fireNotifications, view.onDelete, view.onTap));
|
||||
body: !view.isLoaded
|
||||
? new FiresSpinner()
|
||||
: !hasFireNotifications
|
||||
? Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: new Card(
|
||||
child: new Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: new CenteredColumn(children: <Widget>[
|
||||
new Icon(Icons.notifications_none,
|
||||
size: 150.0, color: Colors.black26),
|
||||
new SizedBox(height: 20.0),
|
||||
new Text(
|
||||
S
|
||||
.of(context)
|
||||
.fireNotificationsDescription,
|
||||
textAlign: TextAlign.center,
|
||||
textScaleFactor: 1.1,
|
||||
style: new TextStyle(
|
||||
height: 1.3, color: Colors.black45))
|
||||
]))))
|
||||
: _buildSavedFireNotifications(
|
||||
context,
|
||||
view.yourLocations,
|
||||
view.fireNotifications,
|
||||
view.onDelete,
|
||||
view.onTap));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,18 @@
|
|||
|
||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:redux/src/store.dart';
|
||||
|
||||
import 'globals.dart';
|
||||
import 'monitoredAreas.dart';
|
||||
import 'activeFires.dart';
|
||||
import 'fireAlert.dart';
|
||||
import 'fireNotificationList.dart';
|
||||
import 'generated/i18n.dart';
|
||||
import 'globals.dart';
|
||||
import 'homePage.dart';
|
||||
import 'introPage.dart';
|
||||
import 'models/appState.dart';
|
||||
import 'monitoredAreas.dart';
|
||||
import 'privacyPage.dart';
|
||||
import 'redux/actions.dart';
|
||||
import 'sandbox.dart';
|
||||
|
|
@ -47,16 +45,15 @@ class _FiresAppState extends State<FiresApp> {
|
|||
SupportPage.routeName: (BuildContext context) => new SupportPage(),
|
||||
FireNotificationList.routeName: (BuildContext context) =>
|
||||
new FireNotificationList(),
|
||||
MonitoredAreasPage.routeName: (BuildContext context) => new MonitoredAreasPage()
|
||||
MonitoredAreasPage.routeName: (BuildContext context) =>
|
||||
new MonitoredAreasPage()
|
||||
};
|
||||
|
||||
final Store<AppState> store;
|
||||
|
||||
|
||||
// globals.getIt.registerSingleton
|
||||
_FiresAppState(this.store);
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
StatefulWidget home = new MaterialAppWithIntroHome(
|
||||
|
|
@ -82,7 +79,7 @@ class _FiresAppState extends State<FiresApp> {
|
|||
}
|
||||
return S.of(context).appName;
|
||||
},
|
||||
theme: isDevelopment? devFiresTheme: firesTheme,
|
||||
theme: isDevelopment ? devFiresTheme : firesTheme,
|
||||
routes: routes));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import 'dart:core';
|
||||
import 'locationUtils.dart';
|
||||
|
||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||
import 'package:fires_flutter/models/yourLocation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
@ -11,6 +11,7 @@ import 'package:share/share.dart';
|
|||
|
||||
import 'attributionMapPlugin.dart';
|
||||
import 'colors.dart';
|
||||
import 'customMoment.dart';
|
||||
import 'dummyMapPlugin.dart';
|
||||
import 'fireMarkType.dart';
|
||||
import 'fireMarker.dart';
|
||||
|
|
@ -18,13 +19,13 @@ import 'generated/i18n.dart';
|
|||
import 'genericMapBottom.dart';
|
||||
import 'globals.dart' as globals;
|
||||
import 'layerSelectorMapPlugin.dart';
|
||||
import 'locationUtils.dart';
|
||||
import 'models/appState.dart';
|
||||
import 'models/fireMapState.dart';
|
||||
import 'redux/actions.dart';
|
||||
import 'sentryReport.dart';
|
||||
import 'slider.dart';
|
||||
import 'zoomMapPlugin.dart';
|
||||
import 'customMoment.dart';
|
||||
|
||||
@immutable
|
||||
class _ViewModel {
|
||||
|
|
@ -142,33 +143,34 @@ class _genericMapState extends State<genericMap> {
|
|||
double maxZoom = 18.0; // works?
|
||||
|
||||
MapOptions mapOptions = new MapOptions(
|
||||
center: new LatLng(_location.lat, _location.lon),
|
||||
plugins: globals.isDevelopment
|
||||
? [
|
||||
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: maxZoom,
|
||||
onTap: (callback) {
|
||||
if (status == FireMapStatus.edit) {
|
||||
_location = _location.copyWith(
|
||||
lat: callback.latitude, lon: callback.longitude);
|
||||
view.onEditing(_location);
|
||||
}
|
||||
},
|
||||
onPositionChanged: (positionCallback) {
|
||||
// print('${positionCallback.center}, ${positionCallback.zoom}');
|
||||
});
|
||||
center: new LatLng(_location.lat, _location.lon),
|
||||
plugins: globals.isDevelopment
|
||||
? [
|
||||
new ZoomMapPlugin(),
|
||||
new AttributionPlugin(),
|
||||
new LayerSelectorMapPlugin()
|
||||
]
|
||||
: [
|
||||
new DummyMapPlugin(),
|
||||
new AttributionPlugin(),
|
||||
new LayerSelectorMapPlugin()
|
||||
],
|
||||
// this works ?
|
||||
interactive: true,
|
||||
zoom: 13.0,
|
||||
// THIS does not works as expected
|
||||
maxZoom: maxZoom,
|
||||
onTap: (callback) {
|
||||
if (status == FireMapStatus.edit) {
|
||||
_location = _location.copyWith(
|
||||
lat: callback.latitude, lon: callback.longitude);
|
||||
view.onEditing(_location);
|
||||
}
|
||||
},
|
||||
// onPositionChanged: (positionCallback) {
|
||||
// print('${positionCallback.center}, ${positionCallback.zoom}');
|
||||
//}
|
||||
);
|
||||
var mapController = new MapController();
|
||||
|
||||
// mapController.fitBounds(bounds);
|
||||
|
|
@ -312,7 +314,7 @@ class _genericMapState extends State<genericMap> {
|
|||
}
|
||||
},
|
||||
// https://github.com/flutter/flutter/issues/17583
|
||||
heroTag: "firesmap" + _location.id.toHexString(),
|
||||
heroTag: "firesmap" + _location.id.hexString,
|
||||
icon: new Icon(btnIcon, color: fires600),
|
||||
label: new Text(
|
||||
btnText,
|
||||
|
|
@ -388,8 +390,7 @@ class _genericMapState extends State<genericMap> {
|
|||
icon: new Icon(Icons.share),
|
||||
onPressed: () {
|
||||
Share.share(
|
||||
'${view.mapState.fireNotification.description}. ${view
|
||||
.serverUrl}fire/${view.mapState.fireNotification.sealed}');
|
||||
'${view.mapState.fireNotification.description}. ${view.serverUrl}fire/${view.mapState.fireNotification.sealed}');
|
||||
})
|
||||
];
|
||||
default:
|
||||
|
|
@ -405,14 +406,14 @@ class _genericMapState extends State<genericMap> {
|
|||
bool isNotif,
|
||||
OnFirePressedInMap onFirePressed) {
|
||||
List<Marker> markers = [];
|
||||
print('building markers: fires: ${fires.length} falsePos: ${falsePosList
|
||||
.length} industries: ${industries.length}, isNotif: ${isNotif} ');
|
||||
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
|
||||
falsePosList.forEach((falsePos) {
|
||||
try {
|
||||
var coords = falsePos['geo']['coordinates'];
|
||||
// print('false pos: ${coords}');
|
||||
var loc = LatLng(coords[1], coords[0]);
|
||||
var loc = LatLng(coords[1].toDouble(), coords[0].toDouble());
|
||||
markers.add(FireMarker(loc, FireMarkType.falsePos));
|
||||
if (calibrate) markers.add(FireMarker(loc, FireMarkType.pixel));
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:comunes_flutter/comunes_flutter.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/material.dart';
|
||||
|
||||
import 'colors.dart';
|
||||
|
|
@ -27,7 +27,7 @@ class GenericMapBottom extends StatelessWidget {
|
|||
GenericMapBottom(
|
||||
{@required this.onSave,
|
||||
@required this.onCancel,
|
||||
@required this.onFalsePositive,
|
||||
@required this.onFalsePositive,
|
||||
@required this.state,
|
||||
@required this.scaffoldKey});
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ class GenericMapBottom extends StatelessWidget {
|
|||
|
||||
List<Widget> buildActionList(YourLocation loc, BuildContext context,
|
||||
int kmAround, GlobalKey<ScaffoldState> scaffoldState) {
|
||||
List<Widget> actionList = new List<Widget>();
|
||||
List<Widget> actionList = [];
|
||||
switch (state.status) {
|
||||
case FireMapStatus.edit:
|
||||
actionList.add(new FlatButton(
|
||||
|
|
@ -74,8 +74,7 @@ class GenericMapBottom extends StatelessWidget {
|
|||
children: <Widget>[
|
||||
new Icon(Icons.access_time),
|
||||
new SizedBox(width: 5.0),
|
||||
new Text(Moment
|
||||
.now()
|
||||
new Text(Moment.now()
|
||||
.from(context, state.fireNotification.when)),
|
||||
],
|
||||
),
|
||||
|
|
@ -113,7 +112,8 @@ class GenericMapBottom extends StatelessWidget {
|
|||
onFalsePositive(state.fireNotification, value);
|
||||
await new Future.delayed(
|
||||
new Duration(milliseconds: 500));
|
||||
scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(new SnackBar(
|
||||
content: new Text(
|
||||
S.of(context).thanksForParticipating),
|
||||
));
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:bson_objectid/bson_objectid.dart';
|
||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||
import 'package:connectivity/connectivity.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:fires_flutter/models/fireNotification.dart';
|
||||
import 'package:fires_flutter/objectIdUtils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:flutter_simple_dependency_injection/injector.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
|
||||
import 'firesSpinner.dart';
|
||||
import 'activeFires.dart';
|
||||
import 'colors.dart';
|
||||
import 'fireAlert.dart';
|
||||
import 'fireNotificationList.dart';
|
||||
import 'firesSpinner.dart';
|
||||
import 'generated/i18n.dart';
|
||||
import 'mainDrawer.dart';
|
||||
import 'models/appState.dart';
|
||||
|
|
@ -28,14 +28,13 @@ class _ViewModel {
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
identical(this, other) ||
|
||||
other is _ViewModel &&
|
||||
runtimeType == other.runtimeType &&
|
||||
isLoaded == other.isLoaded;
|
||||
runtimeType == other.runtimeType &&
|
||||
isLoaded == other.isLoaded;
|
||||
|
||||
@override
|
||||
int get hashCode => isLoaded.hashCode;
|
||||
|
||||
}
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
|
|
@ -83,16 +82,20 @@ class _HomePageState extends State<HomePage> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
_firebaseMessaging.configure(onMessage: (Map<String, dynamic> message) {
|
||||
debugPrint("onMessage in fireApp (isLoaded: ${store.state.isLoaded}): $message");
|
||||
debugPrint(
|
||||
"onMessage in fireApp (isLoaded: ${store.state.isLoaded}): $message");
|
||||
_showItemDialog(message, _notifForMessage(message, store.state.isLoaded));
|
||||
return;
|
||||
}, onLaunch: (Map<String, dynamic> message) {
|
||||
debugPrint("onLaunch (isLoaded: ${store.state.isLoaded}): $message");
|
||||
_notifForMessage(message, store.state.isLoaded);
|
||||
_navigateToItemDetail(message);
|
||||
return;
|
||||
}, onResume: (Map<String, dynamic> message) {
|
||||
debugPrint("onResume (isLoaded: ${store.state.isLoaded}): $message");
|
||||
_notifForMessage(message, store.state.isLoaded);
|
||||
_navigateToItemDetail(message);
|
||||
return;
|
||||
});
|
||||
_firebaseMessaging.requestNotificationPermissions(
|
||||
const IosNotificationSettings(sound: true, badge: true, alert: true));
|
||||
|
|
@ -140,9 +143,7 @@ class _HomePageState extends State<HomePage> {
|
|||
});
|
||||
newNotifications.clear();
|
||||
}
|
||||
return new _ViewModel(
|
||||
isLoaded: store.state.isLoaded
|
||||
);
|
||||
return new _ViewModel(isLoaded: store.state.isLoaded);
|
||||
},
|
||||
builder: (context, view) {
|
||||
return new Scaffold(
|
||||
|
|
@ -179,45 +180,47 @@ class _HomePageState extends State<HomePage> {
|
|||
),
|
||||
),
|
||||
]),
|
||||
body: !view.isLoaded? new FiresSpinner(): new SafeArea(
|
||||
child: Center(
|
||||
child: new CenteredColumn(children: <Widget>[
|
||||
new Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
new IconButton(
|
||||
onPressed: () {
|
||||
_scaffoldKey.currentState.openDrawer();
|
||||
},
|
||||
icon: new Icon(Icons.menu,
|
||||
size: 30.0, color: Colors.black38)),
|
||||
]),
|
||||
new Expanded(
|
||||
child: new FractionallySizedBox(
|
||||
alignment: FractionalOffset.center,
|
||||
heightFactor: 0.7,
|
||||
child: new Image.asset('images/logo-200.png',
|
||||
fit: BoxFit.fitHeight))),
|
||||
new Expanded(
|
||||
child: new FractionallySizedBox(
|
||||
alignment: FractionalOffset.topCenter,
|
||||
heightFactor: 1.0,
|
||||
child: new Column(
|
||||
body: !view.isLoaded
|
||||
? new FiresSpinner()
|
||||
: new SafeArea(
|
||||
child: Center(
|
||||
child: new CenteredColumn(children: <Widget>[
|
||||
new Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
new Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10.0, horizontal: 20.0),
|
||||
child: FittedBox(
|
||||
child: new Text(S.of(context).appName,
|
||||
maxLines: 2,
|
||||
textAlign: TextAlign.center,
|
||||
style: _homeFont),
|
||||
fit: BoxFit.scaleDown,
|
||||
)),
|
||||
],
|
||||
)))
|
||||
])),
|
||||
));
|
||||
new IconButton(
|
||||
onPressed: () {
|
||||
_scaffoldKey.currentState.openDrawer();
|
||||
},
|
||||
icon: new Icon(Icons.menu,
|
||||
size: 30.0, color: Colors.black38)),
|
||||
]),
|
||||
new Expanded(
|
||||
child: new FractionallySizedBox(
|
||||
alignment: FractionalOffset.center,
|
||||
heightFactor: 0.7,
|
||||
child: new Image.asset('images/logo-200.png',
|
||||
fit: BoxFit.fitHeight))),
|
||||
new Expanded(
|
||||
child: new FractionallySizedBox(
|
||||
alignment: FractionalOffset.topCenter,
|
||||
heightFactor: 1.0,
|
||||
child: new Column(
|
||||
children: <Widget>[
|
||||
new Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10.0, horizontal: 20.0),
|
||||
child: FittedBox(
|
||||
child: new Text(S.of(context).appName,
|
||||
maxLines: 2,
|
||||
textAlign: TextAlign.center,
|
||||
style: _homeFont),
|
||||
fit: BoxFit.scaleDown,
|
||||
)),
|
||||
],
|
||||
)))
|
||||
])),
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -282,12 +285,13 @@ class _HomePageState extends State<HomePage> {
|
|||
// https://pub.dartlang.org/packages/firebase_messaging#-example-tab-
|
||||
final FirebaseMessaging _firebaseMessaging = new FirebaseMessaging();
|
||||
|
||||
FireNotification _notifForMessage(Map<String, dynamic> message, bool isLoaded) {
|
||||
FireNotification _notifForMessage(
|
||||
Map<String, dynamic> message, bool isLoaded) {
|
||||
FireNotification notif;
|
||||
try {
|
||||
notif = new FireNotification(
|
||||
id: new ObjectId.fromHexString(message['id']),
|
||||
subsId: new ObjectId.fromHexString(message['subsId']),
|
||||
id: objectIdFromJson(message['id']),
|
||||
subsId: objectIdFromJson(message['subsId']),
|
||||
lat: double.parse(message['lat']),
|
||||
lon: double.parse(message['lon']),
|
||||
description: message['description'],
|
||||
|
|
@ -299,12 +303,12 @@ class _HomePageState extends State<HomePage> {
|
|||
debugPrint(e.toString());
|
||||
}
|
||||
if (notif != null)
|
||||
// if our store is loaded, we just dispatch the notification, if not, we wait til is loaded
|
||||
if (isLoaded) {
|
||||
store.dispatch(new AddFireNotificationAction(notif));
|
||||
} else {
|
||||
newNotifications.add(notif);
|
||||
}
|
||||
// if our store is loaded, we just dispatch the notification, if not, we wait til is loaded
|
||||
if (isLoaded) {
|
||||
store.dispatch(new AddFireNotificationAction(notif));
|
||||
} else {
|
||||
newNotifications.add(notif);
|
||||
}
|
||||
return notif;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
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';
|
||||
|
|
@ -18,16 +17,19 @@ class LayerSelectorMapPluginOptions extends LayerOptions {
|
|||
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, */ ),
|
||||
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) {
|
||||
Widget createLayer(
|
||||
LayerOptions options, MapState mapState, Stream<Null> stream) {
|
||||
Store<AppState> store = Injector.getInjector().get<Store<AppState>>();
|
||||
if (options is LayerSelectorMapPluginOptions) {
|
||||
return LayoutBuilder(
|
||||
|
|
|
|||
|
|
@ -1,29 +1,32 @@
|
|||
import 'package:location/location.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fires_flutter/models/yourLocation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geocoder/geocoder.dart';
|
||||
import 'generated/i18n.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_simple_dependency_injection/injector.dart';
|
||||
import 'package:geocoder/geocoder.dart';
|
||||
import 'package:location/location.dart';
|
||||
|
||||
import 'generated/i18n.dart';
|
||||
|
||||
Future<YourLocation> getUserLocation(
|
||||
GlobalKey<ScaffoldState> scaffoldKey) async {
|
||||
// Platform messages may fail, so we use a try/catch PlatformException.
|
||||
try {
|
||||
Location _location = new Location();
|
||||
Map<String, double> location = await _location.getLocation;
|
||||
|
||||
LocationData location = await _location.getLocation();
|
||||
|
||||
// It seems that the lib fails with lat/lon values
|
||||
var yl = new YourLocation(
|
||||
lat: location['latitude'], lon: location['longitude']);
|
||||
var yl = new YourLocation(lat: location.latitude, lon: location.longitude);
|
||||
var address;
|
||||
try {
|
||||
address = await getReverseLocation(lat: yl.lat, lon: yl.lon);
|
||||
yl.description = address;
|
||||
} catch (e) {
|
||||
try {
|
||||
address = await getReverseLocation(lat: yl.lat, lon: yl.lon, external: true);
|
||||
address =
|
||||
await getReverseLocation(lat: yl.lat, lon: yl.lon, external: true);
|
||||
yl.description = address;
|
||||
} catch (e) {
|
||||
print('We cannot reverse geolocate');
|
||||
|
|
@ -32,22 +35,25 @@ Future<YourLocation> getUserLocation(
|
|||
return yl;
|
||||
} on PlatformException catch (e) {
|
||||
if (e.code == 'PERMISSION_DENIED') {
|
||||
scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
ScaffoldMessenger.of(scaffoldKey.currentContext)
|
||||
.showSnackBar(new SnackBar(
|
||||
content: new Text(S.of(scaffoldKey.currentContext).notPermsUbication),
|
||||
));
|
||||
} else if (e.code == 'PERMISSION_DENIED_NEVER_ASK') {}
|
||||
scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||
content: new Text(S.of(scaffoldKey.currentContext).isYourUbicationEnabled
|
||||
),
|
||||
ScaffoldMessenger.of(scaffoldKey.currentContext).showSnackBar(new SnackBar(
|
||||
content:
|
||||
new Text(S.of(scaffoldKey.currentContext).isYourUbicationEnabled),
|
||||
));
|
||||
return YourLocation.noLocation;
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getReverseLocation({@required lat, @required lon,
|
||||
bool external = false}) async {
|
||||
Future<String> getReverseLocation(
|
||||
{@required lat, @required lon, bool external = false}) async {
|
||||
final coordinates = new Coordinates(lat, lon);
|
||||
var geoCoder = external ? Geocoder.google(Injector.getInjector().get<String>(key: "gmapKey")) : Geocoder.local;
|
||||
var geoCoder = external
|
||||
? Geocoder.google(Injector.getInjector().get<String>(key: "gmapKey"))
|
||||
: Geocoder.local;
|
||||
var addresses = await geoCoder.findAddressesFromCoordinates(coordinates);
|
||||
var first = addresses.first;
|
||||
print("${first.featureName} : ${first.addressLine}");
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'dart:async';
|
|||
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_simple_dependency_injection/injector.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:sentry/sentry.dart';
|
||||
|
||||
|
|
@ -12,7 +13,6 @@ import 'models/appState.dart';
|
|||
import 'models/firesApi.dart';
|
||||
import 'redux/fetchDataMiddleware.dart';
|
||||
import 'redux/reducers.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
import 'sentryReport.dart';
|
||||
|
||||
Future<PackageInfo> loadPackageInfo() async {
|
||||
|
|
@ -22,13 +22,14 @@ Future<PackageInfo> loadPackageInfo() async {
|
|||
|
||||
Future<Map<String, dynamic>> loadSecrets() async {
|
||||
return await SecretLoader(
|
||||
secretPath: globals.isDevelopment?
|
||||
'assets/private-settings-dev.json' :
|
||||
'assets/private-settings.json'
|
||||
).load();
|
||||
secretPath: globals.isDevelopment
|
||||
? 'assets/private-settings-dev.json'
|
||||
: 'assets/private-settings.json')
|
||||
.load();
|
||||
}
|
||||
|
||||
void mainCommon(List<Middleware<AppState>> otherMiddleware) {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final injector = Injector.getInjector();
|
||||
injector.map<FiresApi>((i) => new FiresApi(), isSingleton: true);
|
||||
loadPackageInfo().then((packageInfo) {
|
||||
|
|
@ -36,13 +37,12 @@ void mainCommon(List<Middleware<AppState>> otherMiddleware) {
|
|||
print('Running version ${packageInfo.version}');
|
||||
loadSecrets().then((secrets) {
|
||||
final store = new Store<AppState>(appStateReducer,
|
||||
initialState: new AppState(
|
||||
gmapKey: secrets['gmapKey'],
|
||||
firesApiKey: secrets['firesApiKey'],
|
||||
serverUrl: secrets['firesApiUrl'],
|
||||
firesApiUrl: secrets['firesApiUrl'] + "api/v1/"),
|
||||
middleware: List.from(otherMiddleware)
|
||||
..add(fetchDataMiddleware));
|
||||
initialState: new AppState(
|
||||
gmapKey: secrets['gmapKey'],
|
||||
firesApiKey: secrets['firesApiKey'],
|
||||
serverUrl: secrets['firesApiUrl'],
|
||||
firesApiUrl: secrets['firesApiUrl'] + "api/v1/"),
|
||||
middleware: List.from(otherMiddleware)..add(fetchDataMiddleware));
|
||||
|
||||
injector.map<Store<AppState>>((i) => store);
|
||||
injector.map<String>((i) => store.state.firesApiUrl, key: "firesApiUrl");
|
||||
|
|
@ -56,9 +56,9 @@ void mainCommon(List<Middleware<AppState>> otherMiddleware) {
|
|||
}
|
||||
|
||||
// https://flutter.io/cookbook/maintenance/error-reporting/
|
||||
runZoned<Future<Null>>(() async {
|
||||
runZonedGuarded<Future<void>>(() async {
|
||||
runApp(new FiresApp(store));
|
||||
}, onError: (error, stackTrace) {
|
||||
}, (Object error, StackTrace stackTrace) {
|
||||
// Whenever an error occurs, call the `_reportError` function. This will send
|
||||
// Dart errors to our dev console or Sentry depending on the environment.
|
||||
reportError(error, stackTrace);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ LoggingMiddleware customLogPrinter<State>({
|
|||
|
||||
void main() {
|
||||
globals.isDevelopment = true;
|
||||
|
||||
print("Is development!");
|
||||
String onlyLogActionFormatter<State>(
|
||||
State state,
|
||||
dynamic action,
|
||||
|
|
@ -39,9 +39,9 @@ void main() {
|
|||
return ">>>>> ${action.toString().replaceAll('Instance of ', '')}";
|
||||
}
|
||||
|
||||
LogLevel logRedux = LogLevel.none;
|
||||
LogLevel logRedux = LogLevel.actions;
|
||||
|
||||
List<Middleware> devMiddlewares = logRedux == LogLevel.none
|
||||
List<Middleware> devMiddlewares = logRedux == LogLevel.actions
|
||||
? []
|
||||
: [
|
||||
customLogPrinter(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:badge/badge.dart';
|
||||
import 'package:badges/badges.dart';
|
||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
|
|
@ -97,13 +97,28 @@ Widget mainDrawer(BuildContext context, String currentRoute) {
|
|||
new ListTile(
|
||||
leading: const Icon(Icons.notifications),
|
||||
selected: currentRoute == FireNotificationList.routeName,
|
||||
title: view.unreadCount > 0
|
||||
? Badge.after(
|
||||
spacing: 5.0,
|
||||
borderColor: Colors.red,
|
||||
child: Text(S.of(context).fireNotificationsTitleShort),
|
||||
value: ' ${view.unreadCount.toString()} ')
|
||||
: Text(S.of(context).fireNotificationsTitleShort),
|
||||
title: Text(S.of(context).fireNotificationsTitleShort),
|
||||
trailing: SizedBox(
|
||||
width: 100,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
Badge(
|
||||
position: BadgePosition(top: 0, end: 0),
|
||||
padding: EdgeInsets.all(7),
|
||||
badgeColor: view.unreadCount > 0
|
||||
? Colors.red
|
||||
: Colors.grey,
|
||||
// spacing: 5.0,
|
||||
// borderColor: Colors.red,
|
||||
//child: Text(S.of(context).fireNotificationsTitleShort),
|
||||
badgeContent: Text(
|
||||
'${view.unreadCount.toString()}',
|
||||
style: TextStyle(color: Colors.white),
|
||||
))
|
||||
])),
|
||||
|
||||
// Text(S.of(context).fireNotificationsTitleShort),
|
||||
onTap: () {
|
||||
Navigator.popAndPushNamed(
|
||||
context, FireNotificationList.routeName);
|
||||
|
|
|
|||
|
|
@ -5,21 +5,21 @@ import 'package:connectivity/connectivity.dart';
|
|||
import 'package:fires_flutter/models/fireNotification.dart';
|
||||
import 'package:fires_flutter/models/yourLocation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:latlong/latlong.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'fireMapState.dart';
|
||||
import 'user.dart';
|
||||
|
||||
export 'fireMapState.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:latlong/latlong.dart';
|
||||
|
||||
part 'appState.g.dart';
|
||||
|
||||
@immutable
|
||||
@JsonSerializable(nullable: false)
|
||||
class AppState extends Object with _$AppStateSerializerMixin {
|
||||
class AppState {
|
||||
@JsonKey(ignore: true)
|
||||
final bool isLoading;
|
||||
@JsonKey(ignore: true)
|
||||
|
|
@ -58,7 +58,7 @@ class AppState extends Object with _$AppStateSerializerMixin {
|
|||
this.user: const User.initial(),
|
||||
this.isLoading: false,
|
||||
this.isLoaded: false,
|
||||
this.error: null,
|
||||
this.error,
|
||||
this.gmapKey,
|
||||
this.firesApiKey,
|
||||
this.firesApiUrl,
|
||||
|
|
@ -102,11 +102,7 @@ class AppState extends Object with _$AppStateSerializerMixin {
|
|||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppState{\nuser: ${user}\nconnectivity: ${connectivity
|
||||
.toString()}\nisLoading: $isLoading\nisLoaded: $isLoaded\napiKey: ${ellipse(
|
||||
firesApiKey,
|
||||
8)}\napiUrl: ${firesApiUrl}\nserverUrl: ${serverUrl}\nfireMapState: $fireMapState\nyourLocations count: ${yourLocations
|
||||
.length}\nunread notif: ${fireNotificationsUnread}\nfireNotifications: ${fireNotifications}\nyourLocations: ${yourLocations}}';
|
||||
return 'AppState{\nuser: $user\nconnectivity: ${connectivity.toString()}\nisLoading: $isLoading\nisLoaded: $isLoaded\napiKey: ${ellipse(firesApiKey, 8)}\napiUrl: $firesApiUrl\nserverUrl: $serverUrl\nfireMapState: $fireMapState\nyourLocations count: ${yourLocations.length}\nunread notif: $fireNotificationsUnread\nfireNotifications: $fireNotifications\nyourLocations: $yourLocations}';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
// Copyright (c) 2018, Comunes Association.
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'appState.dart';
|
||||
|
|
@ -8,37 +6,30 @@ part of 'appState.dart';
|
|||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
AppState _$AppStateFromJson(Map<String, dynamic> json) => new AppState(
|
||||
yourLocations: (json['yourLocations'] as List)
|
||||
.map((e) => new YourLocation.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
fireNotifications: (json['fireNotifications'] as List)
|
||||
.map((e) => new FireNotification.fromJson(e as Map<String, dynamic>))
|
||||
.toList());
|
||||
|
||||
abstract class _$AppStateSerializerMixin {
|
||||
List<YourLocation> get yourLocations;
|
||||
List<FireNotification> get fireNotifications;
|
||||
Map<String, dynamic> toJson() => new _$AppStateJsonMapWrapper(this);
|
||||
AppState _$AppStateFromJson(Map json) {
|
||||
return $checkedNew('AppState', json, () {
|
||||
final val = AppState(
|
||||
yourLocations: $checkedConvert(
|
||||
json,
|
||||
'yourLocations',
|
||||
(v) => (v as List)
|
||||
.map((e) =>
|
||||
YourLocation.fromJson(Map<String, dynamic>.from(e as Map)))
|
||||
.toList()),
|
||||
fireNotifications: $checkedConvert(
|
||||
json,
|
||||
'fireNotifications',
|
||||
(v) => (v as List)
|
||||
.map((e) => FireNotification.fromJson(
|
||||
Map<String, dynamic>.from(e as Map)))
|
||||
.toList()),
|
||||
);
|
||||
return val;
|
||||
});
|
||||
}
|
||||
|
||||
class _$AppStateJsonMapWrapper extends $JsonMapWrapper {
|
||||
final _$AppStateSerializerMixin _v;
|
||||
_$AppStateJsonMapWrapper(this._v);
|
||||
|
||||
@override
|
||||
Iterable<String> get keys => const ['yourLocations', 'fireNotifications'];
|
||||
|
||||
@override
|
||||
dynamic operator [](Object key) {
|
||||
if (key is String) {
|
||||
switch (key) {
|
||||
case 'yourLocations':
|
||||
return _v.yourLocations;
|
||||
case 'fireNotifications':
|
||||
return _v.fireNotifications;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Map<String, dynamic> _$AppStateToJson(AppState instance) => <String, dynamic>{
|
||||
'yourLocations': instance.yourLocations.map((e) => e.toJson()).toList(),
|
||||
'fireNotifications':
|
||||
instance.fireNotifications.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import 'package:bson_objectid/bson_objectid.dart';
|
||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:objectid/objectid.dart';
|
||||
|
||||
import '../objectIdUtils.dart';
|
||||
|
||||
part 'fireNotification.g.dart';
|
||||
|
||||
@JsonSerializable(nullable: false)
|
||||
class FireNotification extends Object with _$FireNotificationSerializerMixin {
|
||||
class FireNotification {
|
||||
@JsonKey(toJson: objectIdToJson, fromJson: objectIdFromJson)
|
||||
ObjectId id;
|
||||
final double lat;
|
||||
|
|
@ -74,11 +75,11 @@ class FireNotification extends Object with _$FireNotificationSerializerMixin {
|
|||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FireNotification {id: $id, lat: $lat, lon: $lon, when: $when, read: $read, subsId: $subsId, sealed ${ellipse(
|
||||
sealed)}';
|
||||
return 'FireNotification {id: $id, lat: $lat, lon: $lon, when: $when, read: $read, subsId: $subsId, sealed ${ellipse(sealed)}';
|
||||
}
|
||||
|
||||
static final Map<String, Route<Null>> routes = <String, Route<Null>>{};
|
||||
Map<String, dynamic> toJson() => _$FireNotificationToJson(this);
|
||||
|
||||
/*
|
||||
Route<Null> getRoute(Store store) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
// Copyright (c) 2018, Comunes Association.
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'fireNotification.dart';
|
||||
|
|
@ -8,67 +6,31 @@ part of 'fireNotification.dart';
|
|||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
FireNotification _$FireNotificationFromJson(Map<String, dynamic> json) =>
|
||||
new FireNotification(
|
||||
id: objectIdFromJson(json['id'] as String),
|
||||
lat: (json['lat'] as num).toDouble(),
|
||||
lon: (json['lon'] as num).toDouble(),
|
||||
description: json['description'] as String,
|
||||
when: DateTime.parse(json['when'] as String),
|
||||
read: json['read'] as bool,
|
||||
sealed: json['sealed'] as String,
|
||||
subsId: objectIdFromJson(json['subsId'] as String));
|
||||
|
||||
abstract class _$FireNotificationSerializerMixin {
|
||||
ObjectId get id;
|
||||
double get lat;
|
||||
double get lon;
|
||||
String get description;
|
||||
DateTime get when;
|
||||
String get sealed;
|
||||
ObjectId get subsId;
|
||||
bool get read;
|
||||
Map<String, dynamic> toJson() => new _$FireNotificationJsonMapWrapper(this);
|
||||
FireNotification _$FireNotificationFromJson(Map json) {
|
||||
return $checkedNew('FireNotification', json, () {
|
||||
final val = FireNotification(
|
||||
id: $checkedConvert(json, 'id', (v) => objectIdFromJson(v as String)),
|
||||
lat: $checkedConvert(json, 'lat', (v) => (v as num).toDouble()),
|
||||
lon: $checkedConvert(json, 'lon', (v) => (v as num).toDouble()),
|
||||
description: $checkedConvert(json, 'description', (v) => v as String),
|
||||
when: $checkedConvert(json, 'when', (v) => DateTime.parse(v as String)),
|
||||
read: $checkedConvert(json, 'read', (v) => v as bool),
|
||||
sealed: $checkedConvert(json, 'sealed', (v) => v as String),
|
||||
subsId:
|
||||
$checkedConvert(json, 'subsId', (v) => objectIdFromJson(v as String)),
|
||||
);
|
||||
return val;
|
||||
});
|
||||
}
|
||||
|
||||
class _$FireNotificationJsonMapWrapper extends $JsonMapWrapper {
|
||||
final _$FireNotificationSerializerMixin _v;
|
||||
_$FireNotificationJsonMapWrapper(this._v);
|
||||
|
||||
@override
|
||||
Iterable<String> get keys => const [
|
||||
'id',
|
||||
'lat',
|
||||
'lon',
|
||||
'description',
|
||||
'when',
|
||||
'sealed',
|
||||
'subsId',
|
||||
'read'
|
||||
];
|
||||
|
||||
@override
|
||||
dynamic operator [](Object key) {
|
||||
if (key is String) {
|
||||
switch (key) {
|
||||
case 'id':
|
||||
return objectIdToJson(_v.id);
|
||||
case 'lat':
|
||||
return _v.lat;
|
||||
case 'lon':
|
||||
return _v.lon;
|
||||
case 'description':
|
||||
return _v.description;
|
||||
case 'when':
|
||||
return _v.when.toIso8601String();
|
||||
case 'sealed':
|
||||
return _v.sealed;
|
||||
case 'subsId':
|
||||
return objectIdToJson(_v.subsId);
|
||||
case 'read':
|
||||
return _v.read;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Map<String, dynamic> _$FireNotificationToJson(FireNotification instance) =>
|
||||
<String, dynamic>{
|
||||
'id': objectIdToJson(instance.id),
|
||||
'lat': instance.lat,
|
||||
'lon': instance.lon,
|
||||
'description': instance.description,
|
||||
'when': instance.when.toIso8601String(),
|
||||
'sealed': instance.sealed,
|
||||
'subsId': objectIdToJson(instance.subsId),
|
||||
'read': instance.read,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:fires_flutter/models/fireNotification.dart';
|
||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||
import 'package:fires_flutter/models/fireNotification.dart';
|
||||
|
||||
import '../globals.dart' as globals;
|
||||
|
||||
final String fireNotificationKey = 'fireNotifications';
|
||||
|
|
@ -10,7 +11,7 @@ final String fireNotificationKey = 'fireNotifications';
|
|||
Future<List<FireNotification>> loadFireNotifications() async {
|
||||
return await globals.prefs.then((prefs) {
|
||||
List<String> FireNotifications = prefs.getStringList(fireNotificationKey);
|
||||
List<FireNotification> persistedList = List<FireNotification>();
|
||||
List<FireNotification> persistedList = [];
|
||||
if (FireNotifications == null) {
|
||||
FireNotifications = [];
|
||||
// first run, init with empty list
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'falsePositiveTypes.dart';
|
||||
|
||||
import 'package:bson_objectid/bson_objectid.dart';
|
||||
import 'package:fires_flutter/models/yourLocation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:http/http.dart' as ht;
|
||||
import 'package:jaguar_resty/jaguar_resty.dart' as resty;
|
||||
import 'package:latlong/latlong.dart';
|
||||
|
||||
import '../globals.dart' as globals;
|
||||
import '../objectIdUtils.dart';
|
||||
import '../redux/actions.dart';
|
||||
import 'appState.dart';
|
||||
import 'falsePositiveTypes.dart';
|
||||
|
||||
class FiresApi {
|
||||
FiresApi() {
|
||||
resty.globalClient = new ht.IOClient();
|
||||
}
|
||||
|
||||
Future<String> createUser(AppState state, String mobileToken,
|
||||
String lang) async {
|
||||
Future<String> createUser(
|
||||
AppState state, String mobileToken, String lang) async {
|
||||
assert(state.firesApiUrl != null);
|
||||
assert(state.firesApiKey != null);
|
||||
assert(mobileToken != null);
|
||||
|
|
@ -38,6 +38,8 @@ class FiresApi {
|
|||
if (response.statusCode == 200) {
|
||||
// print(response.body);
|
||||
return json.decode(response.body)['data']['userId'];
|
||||
} else {
|
||||
return throw "Unexpected error on create user";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -45,28 +47,29 @@ class FiresApi {
|
|||
Future<List<YourLocation>> fetchYourLocations(AppState state) async {
|
||||
final apiKey = state.firesApiKey;
|
||||
final mobileToken = state.user.token;
|
||||
final String url = '${state
|
||||
.firesApiUrl}mobile/subscriptions/all/$apiKey/$mobileToken';
|
||||
final String url =
|
||||
'${state.firesApiUrl}mobile/subscriptions/all/$apiKey/$mobileToken';
|
||||
// if (globals.isDevelopment) print('$url');
|
||||
return await resty.get(url).go().then((response) {
|
||||
if (response.statusCode == 200) {
|
||||
// if (globals.isDevelopment) print(response.body);
|
||||
final dataSubscriptions =
|
||||
json.decode(response.body)['data']['subscriptions'];
|
||||
json.decode(response.body)['data']['subscriptions'];
|
||||
List<YourLocation> subscribed = [];
|
||||
for (int i = 0; i < dataSubscriptions.length; i++) {
|
||||
var el = dataSubscriptions[i];
|
||||
var lat = el['location']['lat'];
|
||||
var lon = el['location']['lon'];
|
||||
subscribed.add(new YourLocation(
|
||||
id: ObjectId.fromHexString(el['_id']['_str']),
|
||||
lat: lat,
|
||||
lon: lon,
|
||||
subscribed: true,
|
||||
distance: el['distance']));
|
||||
id: objectIdFromJson(el['_id']['_str']),
|
||||
lat: lat,
|
||||
lon: lon,
|
||||
subscribed: true,
|
||||
distance: el['distance']));
|
||||
}
|
||||
|
||||
return subscribed;
|
||||
} else {
|
||||
return throw "Unexpected error fetching your locations";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -83,13 +86,12 @@ class FiresApi {
|
|||
final params = {
|
||||
"token": state.firesApiKey,
|
||||
"mobileToken": state.user.token,
|
||||
"id": loc.id.toHexString(),
|
||||
"id": loc.id.hexString,
|
||||
"lat": loc.lat,
|
||||
"lon": loc.lon,
|
||||
"distance": loc.distance
|
||||
};
|
||||
final String url = '${state
|
||||
.firesApiUrl}mobile/subscriptions';
|
||||
final String url = '${state.firesApiUrl}mobile/subscriptions';
|
||||
return await resty.post(url).json(params).go().then((response) {
|
||||
if (response.statusCode == 200) {
|
||||
// print(response.body);
|
||||
|
|
@ -97,6 +99,7 @@ class FiresApi {
|
|||
} else {
|
||||
// take care of? "Unexpected error in REST call: Error: The user is already subscribed to this area [on-already-subscribed]"
|
||||
print(response.body);
|
||||
return throw "Unexpected error on subscribe";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -108,22 +111,24 @@ class FiresApi {
|
|||
final apiKey = state.firesApiKey;
|
||||
final mobileToken = state.user.token;
|
||||
assert(subsId != null);
|
||||
final String url = '${state
|
||||
.firesApiUrl}mobile/subscriptions/$apiKey/$mobileToken/$subsId';
|
||||
final String url =
|
||||
'${state.firesApiUrl}mobile/subscriptions/$apiKey/$mobileToken/$subsId';
|
||||
return await resty.delete(url).go().then((response) {
|
||||
if (response.statusCode == 200) {
|
||||
// print(response.body);
|
||||
return true;
|
||||
} else {
|
||||
return throw "Unexpected error on unsubscribe";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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.firesApiKey != null);
|
||||
var url = '${state.firesApiUrl}fires-in-full/${state
|
||||
.firesApiKey}/${lat}/${lon}/${distance}';
|
||||
var url =
|
||||
'${state.firesApiUrl}fires-in-full/${state.firesApiKey}/$lat/$lon/$distance';
|
||||
if (globals.isDevelopment) print(url);
|
||||
return await resty.get(url).go().then((response) {
|
||||
if (response.statusCode == 200) {
|
||||
|
|
@ -138,13 +143,13 @@ class FiresApi {
|
|||
var industriesCount = industries.length;
|
||||
var falsePosCount = falsePos.length;
|
||||
print(
|
||||
'(Pos: $lat, $lon) real: $numFires, fire: $firesCount falsePos: $falsePosCount industries: $industriesCount');
|
||||
'(Pos: $lat, $lon) real: $numFires, fire: $firesCount falsePos: $falsePosCount industries: $industriesCount');
|
||||
}
|
||||
return new UpdateFireMapStatsAction(
|
||||
numFires: numFires,
|
||||
fires: fires,
|
||||
falsePos: falsePos,
|
||||
industries: industries);
|
||||
numFires: numFires,
|
||||
fires: fires,
|
||||
falsePos: falsePos,
|
||||
industries: industries);
|
||||
} else
|
||||
throw Exception('Wrong response trying to get fire data');
|
||||
});
|
||||
|
|
@ -153,8 +158,8 @@ class FiresApi {
|
|||
Future<List<Polyline>> getMonitoredAreas({AppState state}) async {
|
||||
assert(state.firesApiUrl != null);
|
||||
assert(state.firesApiKey != null);
|
||||
var url = '${state.firesApiUrl}status/subs-public-union/${state
|
||||
.firesApiKey}';
|
||||
var url =
|
||||
'${state.firesApiUrl}status/subs-public-union/${state.firesApiKey}';
|
||||
var color = const Color(0xFF145A32);
|
||||
return await resty.get(url).go().then((response) {
|
||||
if (response.statusCode == 200) {
|
||||
|
|
@ -162,8 +167,8 @@ class FiresApi {
|
|||
// print(resultDecoded['data']['union']);
|
||||
List<Polyline> union = [];
|
||||
final multipolygon =
|
||||
json.decode(resultDecoded['data']['union']['value'])['geometry']
|
||||
['coordinates'];
|
||||
json.decode(resultDecoded['data']['union']['value'])['geometry']
|
||||
['coordinates'];
|
||||
for (List<dynamic> polygon in multipolygon) {
|
||||
for (List<dynamic> hole in polygon) {
|
||||
List<LatLng> points = [];
|
||||
|
|
@ -171,7 +176,7 @@ class FiresApi {
|
|||
points.add(new LatLng(point[1].toDouble(), point[0].toDouble()));
|
||||
}
|
||||
union.add(
|
||||
new Polyline(points: points, color: color, strokeWidth: 3.0));
|
||||
new Polyline(points: points, color: color, strokeWidth: 3.0));
|
||||
}
|
||||
}
|
||||
return union;
|
||||
|
|
@ -181,7 +186,7 @@ class FiresApi {
|
|||
}
|
||||
|
||||
Future<bool> markFalsePositive(AppState state, String mobileToken,
|
||||
String sealed, FalsePositiveType type) async {
|
||||
String sealed, FalsePositiveType type) async {
|
||||
assert(state.firesApiUrl != null);
|
||||
assert(state.firesApiKey != null);
|
||||
assert(mobileToken != null);
|
||||
|
|
@ -198,8 +203,8 @@ class FiresApi {
|
|||
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']);
|
||||
if (globals.isDevelopment)
|
||||
print(json.decode(response.body)['data']['upsert']);
|
||||
return true;
|
||||
} else {
|
||||
debugPrint(json.decode(response.body));
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
import 'package:bson_objectid/bson_objectid.dart';
|
||||
import 'package:fires_flutter/objectIdUtils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:fires_flutter/objectIdUtils.dart';
|
||||
import 'package:objectid/objectid.dart';
|
||||
|
||||
part 'yourLocation.g.dart';
|
||||
|
||||
|
||||
|
||||
@JsonSerializable(nullable: false)
|
||||
class YourLocation extends Object with _$YourLocationSerializerMixin {
|
||||
class YourLocation {
|
||||
@JsonKey(toJson: objectIdToJson, fromJson: objectIdFromJson)
|
||||
ObjectId id;
|
||||
final double lat;
|
||||
|
|
@ -22,40 +20,33 @@ class YourLocation extends Object with _$YourLocationSerializerMixin {
|
|||
_$YourLocationFromJson(json);
|
||||
|
||||
static YourLocation noLocation = new YourLocation(lat: 0.0, lon: 0.0);
|
||||
static const int withoutStats = null;
|
||||
static const int withoutStats = null;
|
||||
YourLocation(
|
||||
{this.id,
|
||||
@required this.lat,
|
||||
@required this.lon,
|
||||
this.description,
|
||||
this.distance: 10,
|
||||
int currentNumFires: withoutStats,
|
||||
int currentNumFires: withoutStats,
|
||||
this.subscribed: false}) {
|
||||
if (this.description == null)
|
||||
this.description = 'Position: ${this.lat}, ${this.lon}';
|
||||
if (this.id == null) this.id = new ObjectId();
|
||||
}
|
||||
Map<String, dynamic> toJson() => _$YourLocationToJson(this);
|
||||
|
||||
YourLocation copyWith(
|
||||
{id,
|
||||
lat,
|
||||
lon,
|
||||
description,
|
||||
distance,
|
||||
currentNumFires,
|
||||
subscribed}) {
|
||||
{id, lat, lon, description, distance, currentNumFires, subscribed}) {
|
||||
return new YourLocation(
|
||||
id: id?? this.id,
|
||||
lat: lat?? this.lat,
|
||||
lon: lon?? this.lon,
|
||||
description: description?? this.description,
|
||||
distance: distance?? this.distance,
|
||||
currentNumFires: currentNumFires ?? this.currentNumFires,
|
||||
subscribed: subscribed?? this.subscribed
|
||||
);
|
||||
id: id ?? this.id,
|
||||
lat: lat ?? this.lat,
|
||||
lon: lon ?? this.lon,
|
||||
description: description ?? this.description,
|
||||
distance: distance ?? this.distance,
|
||||
currentNumFires: currentNumFires ?? this.currentNumFires,
|
||||
subscribed: subscribed ?? this.subscribed);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
|
|
@ -66,7 +57,7 @@ static const int withoutStats = null;
|
|||
lon == other.lon &&
|
||||
description == other.description &&
|
||||
subscribed == other.subscribed &&
|
||||
currentNumFires == other.currentNumFires &&
|
||||
currentNumFires == other.currentNumFires &&
|
||||
distance == other.distance;
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
// Copyright (c) 2018, Comunes Association.
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'yourLocation.dart';
|
||||
|
|
@ -8,51 +6,29 @@ part of 'yourLocation.dart';
|
|||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
YourLocation _$YourLocationFromJson(Map<String, dynamic> json) =>
|
||||
new YourLocation(
|
||||
id: objectIdFromJson(json['id'] as String),
|
||||
lat: (json['lat'] as num).toDouble(),
|
||||
lon: (json['lon'] as num).toDouble(),
|
||||
description: json['description'] as String,
|
||||
distance: json['distance'] as int,
|
||||
subscribed: json['subscribed'] as bool);
|
||||
|
||||
abstract class _$YourLocationSerializerMixin {
|
||||
ObjectId get id;
|
||||
double get lat;
|
||||
double get lon;
|
||||
String get description;
|
||||
bool get subscribed;
|
||||
int get distance;
|
||||
Map<String, dynamic> toJson() => new _$YourLocationJsonMapWrapper(this);
|
||||
YourLocation _$YourLocationFromJson(Map json) {
|
||||
return $checkedNew('YourLocation', json, () {
|
||||
final val = YourLocation(
|
||||
id: $checkedConvert(json, 'id', (v) => objectIdFromJson(v as String)),
|
||||
lat: $checkedConvert(json, 'lat', (v) => (v as num).toDouble()),
|
||||
lon: $checkedConvert(json, 'lon', (v) => (v as num).toDouble()),
|
||||
description: $checkedConvert(json, 'description', (v) => v as String),
|
||||
distance: $checkedConvert(json, 'distance', (v) => v as int),
|
||||
currentNumFires:
|
||||
$checkedConvert(json, 'currentNumFires', (v) => v as int),
|
||||
subscribed: $checkedConvert(json, 'subscribed', (v) => v as bool),
|
||||
);
|
||||
return val;
|
||||
});
|
||||
}
|
||||
|
||||
class _$YourLocationJsonMapWrapper extends $JsonMapWrapper {
|
||||
final _$YourLocationSerializerMixin _v;
|
||||
_$YourLocationJsonMapWrapper(this._v);
|
||||
|
||||
@override
|
||||
Iterable<String> get keys =>
|
||||
const ['id', 'lat', 'lon', 'description', 'subscribed', 'distance'];
|
||||
|
||||
@override
|
||||
dynamic operator [](Object key) {
|
||||
if (key is String) {
|
||||
switch (key) {
|
||||
case 'id':
|
||||
return objectIdToJson(_v.id);
|
||||
case 'lat':
|
||||
return _v.lat;
|
||||
case 'lon':
|
||||
return _v.lon;
|
||||
case 'description':
|
||||
return _v.description;
|
||||
case 'subscribed':
|
||||
return _v.subscribed;
|
||||
case 'distance':
|
||||
return _v.distance;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Map<String, dynamic> _$YourLocationToJson(YourLocation instance) =>
|
||||
<String, dynamic>{
|
||||
'id': objectIdToJson(instance.id),
|
||||
'lat': instance.lat,
|
||||
'lon': instance.lon,
|
||||
'description': instance.description,
|
||||
'subscribed': instance.subscribed,
|
||||
'distance': instance.distance,
|
||||
'currentNumFires': instance.currentNumFires,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:fires_flutter/models/yourLocation.dart';
|
||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||
import 'package:fires_flutter/models/yourLocation.dart';
|
||||
|
||||
import '../globals.dart' as globals;
|
||||
|
||||
final String locationKey = 'yourlocations';
|
||||
|
|
@ -10,7 +11,7 @@ final String locationKey = 'yourlocations';
|
|||
Future<List<YourLocation>> loadYourLocations() async {
|
||||
return await globals.prefs.then((prefs) {
|
||||
List<String> yourLocations = prefs.getStringList(locationKey);
|
||||
List<YourLocation> persistedList = List<YourLocation>();
|
||||
List<YourLocation> persistedList = [];
|
||||
if (yourLocations == null) {
|
||||
yourLocations = [];
|
||||
// first run, init with empty list
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import 'package:bson_objectid/bson_objectid.dart';
|
||||
import 'package:objectid/objectid.dart';
|
||||
|
||||
objectIdFromJson(String json) {
|
||||
return new ObjectId.fromHexString(json);
|
||||
return new ObjectId.fromHexString(
|
||||
json.replaceFirst("ObjectId(", "").replaceAll(")", ""));
|
||||
}
|
||||
|
||||
objectIdToJson(ObjectId o) {
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:fires_flutter/models/yourLocation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_google_places_autocomplete/flutter_google_places_autocomplete.dart';
|
||||
|
||||
import 'package:fires_flutter/models/yourLocation.dart';
|
||||
import 'generated/i18n.dart';
|
||||
import 'package:flutter_simple_dependency_injection/injector.dart';
|
||||
|
||||
import 'generated/i18n.dart';
|
||||
|
||||
Future<YourLocation> openPlacesDialog(GlobalKey<ScaffoldState> sc) async {
|
||||
Mode _mode = Mode.overlay;
|
||||
String gmapKey = Injector.getInjector().get<String>(key: "gmapKey");
|
||||
|
|
@ -16,7 +16,7 @@ Future<YourLocation> openPlacesDialog(GlobalKey<ScaffoldState> sc) async {
|
|||
hint: S.of(sc.currentContext).typeTheNameOfAPlace,
|
||||
apiKey: gmapKey,
|
||||
onError: (res) {
|
||||
sc.currentState
|
||||
ScaffoldMessenger.of(sc.currentContext)
|
||||
.showSnackBar(new SnackBar(content: new Text(res.errorMessage)));
|
||||
print('Error $res');
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:bson_objectid/bson_objectid.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:objectid/objectid.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
|
||||
import '../models/appState.dart';
|
||||
import '../models/fireNotificationsPersist.dart';
|
||||
import '../models/firesApi.dart';
|
||||
import '../models/yourLocationPersist.dart';
|
||||
import '../objectIdUtils.dart';
|
||||
import 'actions.dart';
|
||||
|
||||
// A middleware takes in 3 parameters: your Store, which you can use to
|
||||
|
|
@ -147,16 +148,18 @@ void fetchDataMiddleware(Store<AppState> store, action, NextDispatcher next) {
|
|||
.then((List<YourLocation> subscribedLocations) {
|
||||
// If it succeeds, dispatch a success action with the YourLocations.
|
||||
// Our reducer will then update the State using these YourLocations.
|
||||
// print('Subscribed to: ${subscribedLocations.length}');
|
||||
print('Subscribed to: ${subscribedLocations.length}');
|
||||
if (subscribedLocations is List) {
|
||||
// unsubscribe all locally to sync the subs state
|
||||
localLocations.forEach((location) => location.subscribed = false);
|
||||
// print('Local persisted: ${localLocations.length}');
|
||||
print('Local persisted: ${localLocations.length}');
|
||||
subscribedLocations.forEach((subsLoc) {
|
||||
localLocations.firstWhere(
|
||||
var locSubs = localLocations.firstWhere(
|
||||
(localLocation) => localLocation.id == subsLoc.id, orElse: () {
|
||||
localLocations.add(subsLoc);
|
||||
}).subscribed = true;
|
||||
return subsLoc;
|
||||
});
|
||||
locSubs.subscribed = true;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -251,7 +254,7 @@ void getFiresStatsInFire(Store<AppState> store, FireNotification notif) {
|
|||
}
|
||||
|
||||
void unsubsViaApi(Store<AppState> store, ObjectId id, onUnsubs) {
|
||||
api.unsubscribe(store.state, id.toHexString()).then((res) {
|
||||
api.unsubscribe(store.state, id.hexString).then((res) {
|
||||
onUnsubs();
|
||||
persistYourLocations(store.state.yourLocations);
|
||||
});
|
||||
|
|
@ -260,9 +263,9 @@ void unsubsViaApi(Store<AppState> store, ObjectId id, onUnsubs) {
|
|||
void subscribeViaApi(Store<AppState> store, YourLocation loc, onSubs) {
|
||||
api.subscribe(store.state, loc).then((subsId) {
|
||||
YourLocation sub = loc;
|
||||
if (loc.id != subsId) {
|
||||
sub.id = new ObjectId.fromHexString(subsId);
|
||||
}
|
||||
// if (loc.id != subsId) {
|
||||
sub.id = objectIdFromJson(subsId);
|
||||
// }
|
||||
onSubs(sub);
|
||||
persistYourLocations(store.state.yourLocations);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ List<FireNotification> _deletedFireNotification(
|
|||
}
|
||||
|
||||
List<FireNotification> _updatedFireNotification(
|
||||
List<FireNotification> notifications, UpdatedFireNotificationAction action) {
|
||||
List<FireNotification> notifications,
|
||||
UpdatedFireNotificationAction action) {
|
||||
return notifications
|
||||
.map((notif) => notif.id == action.notif.id ? action.notif : notif)
|
||||
.toList();
|
||||
|
|
@ -45,5 +46,5 @@ List<FireNotification> _readedFireNotification(
|
|||
List<FireNotification> _deletedAllFireNotifications(
|
||||
List<FireNotification> notifications,
|
||||
DeletedAllFireNotificationAction action) {
|
||||
return new List<FireNotification>();
|
||||
return [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:bson_objectid/bson_objectid.dart';
|
||||
import 'package:fires_flutter/models/yourLocation.dart';
|
||||
import 'package:objectid/objectid.dart';
|
||||
|
||||
abstract class YourLocationActions {}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ ThemeData _buildFiresTheme() {
|
|||
buttonColor: fires900,
|
||||
scaffoldBackgroundColor: firesSurfaceWhite,
|
||||
cardColor: firesBackgroundWhite,
|
||||
textSelectionColor: fires300,
|
||||
textSelectionTheme: TextSelectionThemeData(selectionColor: fires300),
|
||||
errorColor: firesErrorRed,
|
||||
|
||||
//TODO: Add the text themes (103)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ ThemeData _buildFiresTheme() {
|
|||
buttonColor: fires900,
|
||||
scaffoldBackgroundColor: firesSurfaceWhite,
|
||||
cardColor: firesBackgroundWhite,
|
||||
textSelectionColor: fires300,
|
||||
textSelectionTheme: TextSelectionThemeData(selectionColor: fires300),
|
||||
errorColor: firesErrorRed,
|
||||
|
||||
//TODO: Add the text themes (103)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:flutter/src/widgets/framework.dart';
|
||||
import 'package:flutter_map/plugin_api.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/plugin_api.dart';
|
||||
|
||||
class ZoomMapPluginOptions extends LayerOptions {
|
||||
final String text;
|
||||
|
|
@ -22,7 +21,8 @@ class ZoomMapPlugin extends MapPlugin {
|
|||
}
|
||||
|
||||
@override
|
||||
Widget createLayer(LayerOptions options, MapState mapState) {
|
||||
Widget createLayer(
|
||||
LayerOptions options, MapState mapState, Stream<Null> stream) {
|
||||
if (options is ZoomMapPluginOptions) {
|
||||
/* print('point ${mapState
|
||||
.getPixelBounds(mapState.zoom)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue