Last changes not published
This commit is contained in:
parent
ac65ccf990
commit
21ec08303a
43 changed files with 607 additions and 613 deletions
|
|
@ -8,7 +8,7 @@ if (localPropertiesFile.exists()) {
|
||||||
|
|
||||||
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
||||||
if (flutterRoot == null) {
|
if (flutterRoot == null) {
|
||||||
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
@ -19,7 +19,7 @@ def keystoreProperties = new Properties()
|
||||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 27
|
compileSdkVersion 30
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
disable 'InvalidPackage'
|
disable 'InvalidPackage'
|
||||||
|
|
@ -29,7 +29,7 @@ android {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "org.comunes.fires"
|
applicationId "org.comunes.fires"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 27
|
targetSdkVersion 30
|
||||||
versionCode 9
|
versionCode 9
|
||||||
versionName "1.9"
|
versionName "1.9"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
|
|
@ -78,7 +78,7 @@ dependencies {
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'com.android.support.test:runner:1.0.1'
|
androidTestImplementation 'com.android.support.test:runner:1.0.1'
|
||||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
|
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
|
||||||
implementation 'com.google.firebase:firebase-core:15.0.2'
|
// implementation 'com.google.firebase:firebase-core:15.0.2'
|
||||||
// google recommends 16 but fails because location flutter package deps in 15
|
// google recommends 16 but fails because location flutter package deps in 15
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,6 @@
|
||||||
package org.comunes.fires;
|
package org.comunes.fires;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import io.flutter.embedding.android.FlutterActivity;
|
||||||
|
|
||||||
import io.flutter.app.FlutterActivity;
|
|
||||||
import io.flutter.plugins.GeneratedPluginRegistrant;
|
|
||||||
|
|
||||||
public class MainActivity extends FlutterActivity {
|
public class MainActivity extends FlutterActivity {
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
GeneratedPluginRegistrant.registerWith(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,8 @@
|
||||||
Flutter draws its first frame -->
|
Flutter draws its first frame -->
|
||||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">@drawable/normal_background</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ buildscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||||
classpath 'com.google.gms:google-services:4.0.1'
|
classpath 'com.google.gms:google-services:4.3.4'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
org.gradle.jvmargs=-Xmx1536M
|
org.gradle.jvmargs=-Xmx1536M
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
|
||||||
|
|
|
||||||
13
build.yaml
13
build.yaml
|
|
@ -9,11 +9,9 @@ targets:
|
||||||
# defined in `package:source_gen/source_gen.dart`.
|
# defined in `package:source_gen/source_gen.dart`.
|
||||||
#
|
#
|
||||||
# Note: use `|` to define a multi-line block.
|
# Note: use `|` to define a multi-line block.
|
||||||
header: |
|
# header: |
|
||||||
// Copyright (c) 2018, Comunes Association.
|
# // Copyright (c) 2018, Comunes Association.
|
||||||
|
# // GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
# Options configure how source code is generated for every
|
# Options configure how source code is generated for every
|
||||||
# `@JsonSerializable`-annotated class in the package.
|
# `@JsonSerializable`-annotated class in the package.
|
||||||
#
|
#
|
||||||
|
|
@ -21,8 +19,9 @@ targets:
|
||||||
#
|
#
|
||||||
# For usage information, reference the corresponding field in
|
# For usage information, reference the corresponding field in
|
||||||
# `JsonSerializableGenerator`.
|
# `JsonSerializableGenerator`.
|
||||||
use_wrappers: true
|
#use_wrappers: true
|
||||||
any_map: true
|
any_map: true
|
||||||
checked: true
|
checked: true
|
||||||
explicit_to_json: true
|
explicit_to_json: true
|
||||||
generate_to_json_function: true
|
#generate_to_json_function: true
|
||||||
|
create_to_json: true
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import 'package:fires_flutter/models/yourLocation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_fab_dialer/flutter_fab_dialer.dart';
|
import 'package:flutter_fab_dialer/flutter_fab_dialer.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:redux/src/store.dart';
|
import 'package:redux/redux.dart';
|
||||||
|
|
||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
import 'firesSpinner.dart';
|
import 'firesSpinner.dart';
|
||||||
|
|
@ -91,7 +91,7 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
|
||||||
icon: new Icon(loc.subscribed
|
icon: new Icon(loc.subscribed
|
||||||
? Icons.notifications_active
|
? Icons.notifications_active
|
||||||
: Icons.notifications_off),
|
: Icons.notifications_off),
|
||||||
color: loc.subscribed ? fires600: null,
|
color: loc.subscribed ? fires600 : null,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
loc.subscribed = !loc.subscribed;
|
loc.subscribed = !loc.subscribed;
|
||||||
onToggle(loc);
|
onToggle(loc);
|
||||||
|
|
@ -125,7 +125,8 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void showSnackMsg(String msg) {
|
void showSnackMsg(String msg) {
|
||||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
// _scaffoldKey.currentState.showSnackBar(new SnackBar(
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
|
||||||
content: new Text(msg),
|
content: new Text(msg),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -183,7 +184,7 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
|
||||||
},
|
},
|
||||||
onDelete: (loc) {
|
onDelete: (loc) {
|
||||||
store.dispatch(new DeleteYourLocationAction(loc));
|
store.dispatch(new DeleteYourLocationAction(loc));
|
||||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
|
||||||
content: new Text(S.of(context).youDeletedThisPlace),
|
content: new Text(S.of(context).youDeletedThisPlace),
|
||||||
action: new SnackBarAction(
|
action: new SnackBarAction(
|
||||||
label: S.of(context).UNDO,
|
label: S.of(context).UNDO,
|
||||||
|
|
@ -242,6 +243,7 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
|
||||||
view.onRefresh(completer);
|
view.onRefresh(completer);
|
||||||
return completer.future;
|
return completer.future;
|
||||||
}),
|
}),
|
||||||
|
// TODO: Evaluate: https://github.com/tiagojencmartins/unicornspeeddial
|
||||||
new FabDialer(_fabMiniMenuItemList(context, view.onAdd),
|
new FabDialer(_fabMiniMenuItemList(context, view.onAdd),
|
||||||
fires600, new Icon(Icons.add))
|
fires600, new Icon(Icons.add))
|
||||||
])
|
])
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:flutter_map/plugin_api.dart';
|
import 'package:flutter_map/plugin_api.dart';
|
||||||
|
|
||||||
class AttributionPluginOptions extends LayerOptions {
|
class AttributionPluginOptions extends LayerOptions {
|
||||||
|
|
@ -10,7 +9,8 @@ class AttributionPluginOptions extends LayerOptions {
|
||||||
|
|
||||||
class AttributionPlugin implements MapPlugin {
|
class AttributionPlugin implements MapPlugin {
|
||||||
@override
|
@override
|
||||||
Widget createLayer(LayerOptions options, MapState mapState) {
|
Widget createLayer(
|
||||||
|
LayerOptions options, MapState mapState, Stream<Null> stream) {
|
||||||
if (options is AttributionPluginOptions) {
|
if (options is AttributionPluginOptions) {
|
||||||
var style = new TextStyle(
|
var style = new TextStyle(
|
||||||
// fontWeight: FontWeight.bold,
|
// fontWeight: FontWeight.bold,
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,17 @@ class CustomBottomAppBar extends StatelessWidget {
|
||||||
|
|
||||||
rowContents.addAll(this.actions);
|
rowContents.addAll(this.actions);
|
||||||
|
|
||||||
return new BottomAppBar(
|
return showNotch
|
||||||
color: color,
|
? new BottomAppBar(
|
||||||
hasNotch: showNotch,
|
color: color,
|
||||||
child: new Row(
|
shape: CircularNotchedRectangle(),
|
||||||
mainAxisAlignment: mainAxisAlignment,
|
child: new Row(
|
||||||
children: rowContents),
|
mainAxisAlignment: mainAxisAlignment, children: rowContents),
|
||||||
);
|
)
|
||||||
|
: new BottomAppBar(
|
||||||
|
color: color,
|
||||||
|
child: new Row(
|
||||||
|
mainAxisAlignment: mainAxisAlignment, children: rowContents),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
// TODO(dragostis): Missing functionality:
|
// TODO(dragostis): Missing functionality:
|
||||||
// * mobile horizontal mode with adding/removing steps
|
// * mobile horizontal mode with adding/removing steps
|
||||||
// * alternative labeling
|
// * alternative labeling
|
||||||
|
|
@ -53,7 +52,8 @@ const Color _kCircleActiveDark = Colors.black87;
|
||||||
const Color _kDisabledLight = Colors.black38;
|
const Color _kDisabledLight = Colors.black38;
|
||||||
const Color _kDisabledDark = Colors.white30;
|
const Color _kDisabledDark = Colors.white30;
|
||||||
const double _kCustomStepSize = 24.0;
|
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,
|
/// 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
|
/// an icon within its circle, some content and a state that governs its
|
||||||
|
|
@ -75,9 +75,9 @@ class CustomStep {
|
||||||
@required this.content,
|
@required this.content,
|
||||||
this.state: CustomStepState.indexed,
|
this.state: CustomStepState.indexed,
|
||||||
this.isActive: false,
|
this.isActive: false,
|
||||||
}) : assert(title != null),
|
}) : assert(title != null),
|
||||||
assert(content != null),
|
assert(content != null),
|
||||||
assert(state != null);
|
assert(state != null);
|
||||||
|
|
||||||
/// The title of the step that typically describes it.
|
/// The title of the step that typically describes it.
|
||||||
final Widget title;
|
final Widget title;
|
||||||
|
|
@ -130,11 +130,11 @@ class CustomStepper extends StatefulWidget {
|
||||||
this.onCustomStepTapped,
|
this.onCustomStepTapped,
|
||||||
this.onCustomStepContinue,
|
this.onCustomStepContinue,
|
||||||
this.onCustomStepCancel,
|
this.onCustomStepCancel,
|
||||||
}) : assert(steps != null),
|
}) : assert(steps != null),
|
||||||
assert(type != null),
|
assert(type != null),
|
||||||
assert(currentCustomStep != null),
|
assert(currentCustomStep != null),
|
||||||
assert(0 <= currentCustomStep && currentCustomStep < steps.length),
|
assert(0 <= currentCustomStep && currentCustomStep < steps.length),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// The steps of the stepper whose titles, subtitles, icons always get shown.
|
/// The steps of the stepper whose titles, subtitles, icons always get shown.
|
||||||
///
|
///
|
||||||
|
|
@ -177,7 +177,7 @@ class _CustomStepperState extends State<CustomStepper> {
|
||||||
super.initState();
|
super.initState();
|
||||||
_keys = new List<GlobalKey>.generate(
|
_keys = new List<GlobalKey>.generate(
|
||||||
widget.steps.length,
|
widget.steps.length,
|
||||||
(int i) => new GlobalKey(),
|
(int i) => new GlobalKey(),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (int i = 0; i < widget.steps.length; i += 1)
|
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) {
|
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;
|
final bool isDarkActive = _isDark() && widget.steps[index].isActive;
|
||||||
assert(state != null);
|
assert(state != null);
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
|
@ -226,7 +227,9 @@ class _CustomStepperState extends State<CustomStepper> {
|
||||||
case CustomStepState.disabled:
|
case CustomStepState.disabled:
|
||||||
return new Text(
|
return new Text(
|
||||||
'${index + 1}',
|
'${index + 1}',
|
||||||
style: isDarkActive ? _kCustomStepStyle.copyWith(color: Colors.black87) : _kCustomStepStyle,
|
style: isDarkActive
|
||||||
|
? _kCustomStepStyle.copyWith(color: Colors.black87)
|
||||||
|
: _kCustomStepStyle,
|
||||||
);
|
);
|
||||||
case CustomStepState.editing:
|
case CustomStepState.editing:
|
||||||
return new Icon(
|
return new Icon(
|
||||||
|
|
@ -247,9 +250,13 @@ class _CustomStepperState extends State<CustomStepper> {
|
||||||
Color _circleColor(int index) {
|
Color _circleColor(int index) {
|
||||||
final ThemeData themeData = Theme.of(context);
|
final ThemeData themeData = Theme.of(context);
|
||||||
if (!_isDark()) {
|
if (!_isDark()) {
|
||||||
return widget.steps[index].isActive ? themeData.primaryColor : Colors.black38;
|
return widget.steps[index].isActive
|
||||||
|
? themeData.primaryColor
|
||||||
|
: Colors.black38;
|
||||||
} else {
|
} 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,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: new Center(
|
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 Center(
|
||||||
child: new SizedBox(
|
child: new SizedBox(
|
||||||
width: _kCustomStepSize,
|
width: _kCustomStepSize,
|
||||||
height: _kTriangleHeight, // Height of 24dp-long-sided equilateral triangle.
|
height:
|
||||||
|
_kTriangleHeight, // Height of 24dp-long-sided equilateral triangle.
|
||||||
child: new CustomPaint(
|
child: new CustomPaint(
|
||||||
painter: new _TrianglePainter(
|
painter: new _TrianglePainter(
|
||||||
color: _isDark() ? _kErrorDark : _kErrorLight,
|
color: _isDark() ? _kErrorDark : _kErrorLight,
|
||||||
),
|
),
|
||||||
child: new Align(
|
child: new Align(
|
||||||
alignment: const Alignment(0.0, 0.8), // 0.8 looks better than the geometrical 0.33.
|
alignment: const Alignment(
|
||||||
child: _buildCircleChild(index, oldState && widget.steps[index].state != CustomStepState.error),
|
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),
|
firstCurve: const Interval(0.0, 0.6, curve: Curves.fastOutSlowIn),
|
||||||
secondCurve: const Interval(0.4, 1.0, curve: Curves.fastOutSlowIn),
|
secondCurve: const Interval(0.4, 1.0, curve: Curves.fastOutSlowIn),
|
||||||
sizeCurve: 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,
|
duration: kThemeAnimationDuration,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -328,8 +343,9 @@ class _CustomStepperState extends State<CustomStepper> {
|
||||||
|
|
||||||
assert(cancelColor != null);
|
assert(cancelColor != null);
|
||||||
|
|
||||||
final ThemeData themeData = Theme.of(context);
|
// final ThemeData themeData = Theme.of(context);
|
||||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
// final MaterialLocalizations localizations =
|
||||||
|
// MaterialLocalizations.of(context);
|
||||||
|
|
||||||
return new Container(
|
return new Container(
|
||||||
margin: const EdgeInsets.only(top: 16.0),
|
margin: const EdgeInsets.only(top: 16.0),
|
||||||
|
|
@ -368,15 +384,13 @@ class _CustomStepperState extends State<CustomStepper> {
|
||||||
case CustomStepState.indexed:
|
case CustomStepState.indexed:
|
||||||
case CustomStepState.editing:
|
case CustomStepState.editing:
|
||||||
case CustomStepState.complete:
|
case CustomStepState.complete:
|
||||||
return textTheme.body2;
|
return textTheme.bodyText1;
|
||||||
case CustomStepState.disabled:
|
case CustomStepState.disabled:
|
||||||
return textTheme.body2.copyWith(
|
return textTheme.bodyText1
|
||||||
color: _isDark() ? _kDisabledDark : _kDisabledLight
|
.copyWith(color: _isDark() ? _kDisabledDark : _kDisabledLight);
|
||||||
);
|
|
||||||
case CustomStepState.error:
|
case CustomStepState.error:
|
||||||
return textTheme.body2.copyWith(
|
return textTheme.bodyText1
|
||||||
color: _isDark() ? _kErrorDark : _kErrorLight
|
.copyWith(color: _isDark() ? _kErrorDark : _kErrorLight);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -392,13 +406,11 @@ class _CustomStepperState extends State<CustomStepper> {
|
||||||
case CustomStepState.complete:
|
case CustomStepState.complete:
|
||||||
return textTheme.caption;
|
return textTheme.caption;
|
||||||
case CustomStepState.disabled:
|
case CustomStepState.disabled:
|
||||||
return textTheme.caption.copyWith(
|
return textTheme.caption
|
||||||
color: _isDark() ? _kDisabledDark : _kDisabledLight
|
.copyWith(color: _isDark() ? _kDisabledDark : _kDisabledLight);
|
||||||
);
|
|
||||||
case CustomStepState.error:
|
case CustomStepState.error:
|
||||||
return textTheme.caption.copyWith(
|
return textTheme.caption
|
||||||
color: _isDark() ? _kErrorDark : _kErrorLight
|
.copyWith(color: _isDark() ? _kErrorDark : _kErrorLight);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -427,33 +439,26 @@ class _CustomStepperState extends State<CustomStepper> {
|
||||||
);
|
);
|
||||||
|
|
||||||
return new Column(
|
return new Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: children
|
children: children);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildVerticalHeader(int index) {
|
Widget _buildVerticalHeader(int index) {
|
||||||
return new Container(
|
return new Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 24.0),
|
margin: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||||
child: new Row(
|
child: new Row(children: <Widget>[
|
||||||
children: <Widget>[
|
new Column(children: <Widget>[
|
||||||
new Column(
|
// Line parts are always added in order for the ink splash to
|
||||||
children: <Widget>[
|
// flood the tips of the connector lines.
|
||||||
// Line parts are always added in order for the ink splash to
|
_buildLine(!_isFirst(index)),
|
||||||
// flood the tips of the connector lines.
|
_buildIcon(index),
|
||||||
_buildLine(!_isFirst(index)),
|
_buildLine(!_isLast(index)),
|
||||||
_buildIcon(index),
|
]),
|
||||||
_buildLine(!_isLast(index)),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
new Container(
|
new Container(
|
||||||
margin: const EdgeInsetsDirectional.only(start: 12.0),
|
margin: const EdgeInsetsDirectional.only(start: 12.0),
|
||||||
child: _buildHeaderText(index)
|
child: _buildHeaderText(index))
|
||||||
)
|
]));
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildVerticalBody(int index) {
|
Widget _buildVerticalBody(int index) {
|
||||||
|
|
@ -493,7 +498,9 @@ class _CustomStepperState extends State<CustomStepper> {
|
||||||
firstCurve: const Interval(0.0, 0.6, curve: Curves.fastOutSlowIn),
|
firstCurve: const Interval(0.0, 0.6, curve: Curves.fastOutSlowIn),
|
||||||
secondCurve: const Interval(0.4, 1.0, curve: Curves.fastOutSlowIn),
|
secondCurve: const Interval(0.4, 1.0, curve: Curves.fastOutSlowIn),
|
||||||
sizeCurve: Curves.fastOutSlowIn,
|
sizeCurve: Curves.fastOutSlowIn,
|
||||||
crossFadeState: _isCurrent(index) ? CrossFadeState.showSecond : CrossFadeState.showFirst,
|
crossFadeState: _isCurrent(index)
|
||||||
|
? CrossFadeState.showSecond
|
||||||
|
: CrossFadeState.showFirst,
|
||||||
duration: kThemeAnimationDuration,
|
duration: kThemeAnimationDuration,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -504,29 +511,25 @@ class _CustomStepperState extends State<CustomStepper> {
|
||||||
final List<Widget> children = <Widget>[];
|
final List<Widget> children = <Widget>[];
|
||||||
|
|
||||||
for (int i = 0; i < widget.steps.length; i += 1) {
|
for (int i = 0; i < widget.steps.length; i += 1) {
|
||||||
children.add(
|
children.add(new Column(key: _keys[i], children: <Widget>[
|
||||||
new Column(
|
new InkWell(
|
||||||
key: _keys[i],
|
onTap: widget.steps[i].state != CustomStepState.disabled
|
||||||
children: <Widget>[
|
? () {
|
||||||
new InkWell(
|
// In the vertical case we need to scroll to the newly tapped
|
||||||
onTap: widget.steps[i].state != CustomStepState.disabled ? () {
|
// step.
|
||||||
// In the vertical case we need to scroll to the newly tapped
|
Scrollable.ensureVisible(
|
||||||
// step.
|
_keys[i].currentContext,
|
||||||
Scrollable.ensureVisible(
|
curve: Curves.fastOutSlowIn,
|
||||||
_keys[i].currentContext,
|
duration: kThemeAnimationDuration,
|
||||||
curve: Curves.fastOutSlowIn,
|
);
|
||||||
duration: kThemeAnimationDuration,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (widget.onCustomStepTapped != null)
|
if (widget.onCustomStepTapped != null)
|
||||||
widget.onCustomStepTapped(i);
|
widget.onCustomStepTapped(i);
|
||||||
} : null,
|
}
|
||||||
child: _buildVerticalHeader(i)
|
: null,
|
||||||
),
|
child: _buildVerticalHeader(i)),
|
||||||
_buildVerticalBody(i)
|
_buildVerticalBody(i)
|
||||||
]
|
]));
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ListView(
|
return new ListView(
|
||||||
|
|
@ -541,10 +544,12 @@ class _CustomStepperState extends State<CustomStepper> {
|
||||||
for (int i = 0; i < widget.steps.length; i += 1) {
|
for (int i = 0; i < widget.steps.length; i += 1) {
|
||||||
children.add(
|
children.add(
|
||||||
new InkResponse(
|
new InkResponse(
|
||||||
onTap: widget.steps[i].state != CustomStepState.disabled ? () {
|
onTap: widget.steps[i].state != CustomStepState.disabled
|
||||||
if (widget.onCustomStepTapped != null)
|
? () {
|
||||||
widget.onCustomStepTapped(i);
|
if (widget.onCustomStepTapped != null)
|
||||||
} : null,
|
widget.onCustomStepTapped(i);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
child: new Row(
|
child: new Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
new Container(
|
new Container(
|
||||||
|
|
@ -593,7 +598,7 @@ class _CustomStepperState extends State<CustomStepper> {
|
||||||
new AnimatedSize(
|
new AnimatedSize(
|
||||||
curve: Curves.fastOutSlowIn,
|
curve: Curves.fastOutSlowIn,
|
||||||
duration: kThemeAnimationDuration,
|
duration: kThemeAnimationDuration,
|
||||||
//vsync: this,
|
vsync: null,
|
||||||
child: widget.steps[widget.currentCustomStep].content,
|
child: widget.steps[widget.currentCustomStep].content,
|
||||||
),
|
),
|
||||||
_buildVerticalControls(),
|
_buildVerticalControls(),
|
||||||
|
|
@ -608,12 +613,11 @@ class _CustomStepperState extends State<CustomStepper> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
assert(debugCheckHasMaterial(context));
|
assert(debugCheckHasMaterial(context));
|
||||||
assert(() {
|
assert(() {
|
||||||
if (context.ancestorWidgetOfExactType(CustomStepper) != null)
|
if (context.findAncestorWidgetOfExactType<CustomStepper>() != null)
|
||||||
throw new FlutterError(
|
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. '
|
'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;
|
return true;
|
||||||
}());
|
}());
|
||||||
assert(widget.type != null);
|
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
|
// Paints a triangle whose base is the bottom of the bounding rectangle and its
|
||||||
// top vertex the middle of its top.
|
// top vertex the middle of its top.
|
||||||
class _TrianglePainter extends CustomPainter {
|
class _TrianglePainter extends CustomPainter {
|
||||||
_TrianglePainter({
|
_TrianglePainter({this.color});
|
||||||
this.color
|
|
||||||
});
|
|
||||||
|
|
||||||
final Color 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/material.dart';
|
||||||
|
import 'package:flutter_map/plugin_api.dart';
|
||||||
|
|
||||||
class DummyMapPluginOptions extends LayerOptions {
|
class DummyMapPluginOptions extends LayerOptions {
|
||||||
final String text;
|
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
|
// https://github.com/apptreesoftware/flutter_map/blob/master/flutter_map_example/lib/pages/plugin_api.dart
|
||||||
class DummyMapPlugin extends MapPlugin {
|
class DummyMapPlugin extends MapPlugin {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget createLayer(LayerOptions options, MapState mapState) {
|
Widget createLayer(
|
||||||
|
LayerOptions options, MapState mapState, Stream<Null> stream) {
|
||||||
if (options is DummyMapPluginOptions) {
|
if (options is DummyMapPluginOptions) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,34 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/services.dart' show rootBundle;
|
import 'package:flutter/services.dart' show rootBundle;
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
final esRegExp = new RegExp("^es-");
|
final esRegExp = new RegExp("^es-");
|
||||||
|
|
||||||
String getFallbackLang(String lang) {
|
String getFallbackLang(String lang) {
|
||||||
if (lang == 'ast' || lang == 'gl' || lang == 'eu' ||
|
if (lang == 'ast' ||
|
||||||
lang == 'es' || lang == 'ca' || (esRegExp).allMatches(lang).length > 0) {
|
lang == 'gl' ||
|
||||||
|
lang == 'eu' ||
|
||||||
|
lang == 'es' ||
|
||||||
|
lang == 'ca' ||
|
||||||
|
(esRegExp).allMatches(lang).length > 0) {
|
||||||
return 'es';
|
return 'es';
|
||||||
}
|
}
|
||||||
return 'en';
|
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 base = '$dir/$fileName';
|
||||||
String fallback = getFallbackLang(lang);
|
String fallback = getFallbackLang(lang);
|
||||||
String file = '${base}-${lang}.${ext}';
|
String file = '$base-$lang.$ext';
|
||||||
if (await assetNotExists(file)) {
|
if (await assetNotExists(file)) {
|
||||||
file = '${base}-${fallback}.${ext}';
|
file = '$base-$fallback.$ext';
|
||||||
if (await assetNotExists(file)) {
|
if (await assetNotExists(file)) {
|
||||||
file = '${base}.${ext}';
|
file = '$base.$ext';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
|
|
@ -28,5 +37,9 @@ Future<String> getFileNameOfLang({@required String dir,@required String fileNam
|
||||||
// https://github.com/flutter/flutter/issues/15325
|
// https://github.com/flutter/flutter/issues/15325
|
||||||
Future<bool> assetNotExists(String asset) {
|
Future<bool> assetNotExists(String asset) {
|
||||||
print('Does not exists $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:flutter/material.dart';
|
||||||
import 'package:share/share.dart';
|
import 'package:share/share.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import 'customStepper.dart';
|
|
||||||
import 'mainDrawer.dart';
|
|
||||||
|
|
||||||
|
import 'customStepper.dart';
|
||||||
import 'generated/i18n.dart';
|
import 'generated/i18n.dart';
|
||||||
|
import 'mainDrawer.dart';
|
||||||
import 'placesAutocompleteUtils.dart';
|
import 'placesAutocompleteUtils.dart';
|
||||||
|
|
||||||
class FireAlert extends StatefulWidget {
|
class FireAlert extends StatefulWidget {
|
||||||
|
|
@ -40,7 +40,7 @@ class _FireAlertState extends State<FireAlert> {
|
||||||
heroTag: 'neighAction',
|
heroTag: 'neighAction',
|
||||||
child: const Icon(CommunityMaterialIcons.bullhorn),
|
child: const Icon(CommunityMaterialIcons.bullhorn),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
|
||||||
content: new Text(S.of(context).inDevelopment),
|
content: new Text(S.of(context).inDevelopment),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
|
@ -48,7 +48,6 @@ class _FireAlertState extends State<FireAlert> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Widget buildTweetButton() {
|
Widget buildTweetButton() {
|
||||||
return new Align(
|
return new Align(
|
||||||
alignment: const Alignment(0.0, -0.2),
|
alignment: const Alignment(0.0, -0.2),
|
||||||
|
|
@ -62,9 +61,11 @@ class _FireAlertState extends State<FireAlert> {
|
||||||
String where =
|
String where =
|
||||||
yourLocation.description.replaceAll(' ', '').split(',')[0];
|
yourLocation.description.replaceAll(' ', '').split(',')[0];
|
||||||
print(where);
|
print(where);
|
||||||
Share.share(S.of(context).tweetAboutSelf(yourLocation.description, '#IF${where}'));
|
Share.share(S
|
||||||
|
.of(context)
|
||||||
|
.tweetAboutSelf(yourLocation.description, '#IF$where'));
|
||||||
}).catchError((onError) {
|
}).catchError((onError) {
|
||||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
|
||||||
content: new Text(
|
content: new Text(
|
||||||
S.of(_scaffoldKey.currentContext).errorFirePlaceDialog)));
|
S.of(_scaffoldKey.currentContext).errorFirePlaceDialog)));
|
||||||
});
|
});
|
||||||
|
|
@ -87,13 +88,13 @@ class _FireAlertState extends State<FireAlert> {
|
||||||
buildCallButton()
|
buildCallButton()
|
||||||
])),
|
])),
|
||||||
new CustomStep(
|
new CustomStep(
|
||||||
title: new Text(S.of(context).notifyNeighbours),
|
title: new Text(S.of(context).notifyNeighbours),
|
||||||
// state: CustomStepState.disabled,
|
// state: CustomStepState.disabled,
|
||||||
content: new Column(children: <Widget>[
|
content: new Column(children: <Widget>[
|
||||||
new Text(S.of(context).notifyNeighboursDescription),
|
new Text(S.of(context).notifyNeighboursDescription),
|
||||||
new SizedBox(height: 20.0),
|
new SizedBox(height: 20.0),
|
||||||
buildNotifyNeighboursButton()
|
buildNotifyNeighboursButton()
|
||||||
])),
|
])),
|
||||||
// TODO conditional: this only in Spain
|
// TODO conditional: this only in Spain
|
||||||
new CustomStep(
|
new CustomStep(
|
||||||
title: new Text(S.of(context).tweetAboutAFireTitle),
|
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/flutter_map.dart';
|
||||||
import 'package:flutter_map/plugin_api.dart';
|
import 'package:flutter_map/plugin_api.dart';
|
||||||
import 'package:latlong/latlong.dart';
|
import 'package:latlong/latlong.dart';
|
||||||
import 'fireMarkerIcon.dart';
|
|
||||||
import 'fireMarkType.dart';
|
import 'fireMarkType.dart';
|
||||||
|
import 'fireMarkerIcon.dart';
|
||||||
|
|
||||||
class FireMarker extends Marker {
|
class FireMarker extends Marker {
|
||||||
|
|
||||||
FireMarker(LatLng pos, type,
|
FireMarker(LatLng pos, type,
|
||||||
[onTap = null, AnchorPos anchor = AnchorPos.center, Anchor anchorOverride])
|
[onTap,
|
||||||
|
// AnchorPos anchor = AnchorPos.center,
|
||||||
|
Anchor anchorOverride])
|
||||||
: super(
|
: super(
|
||||||
width: 80.0,
|
width: 80.0,
|
||||||
height: 80.0,
|
height: 80.0,
|
||||||
point: pos,
|
point: pos,
|
||||||
builder: (ctx) => new Container(
|
builder: (ctx) => new Container(
|
||||||
child: new GestureDetector(
|
child: new GestureDetector(
|
||||||
child: new FireMarkerIcon(type), onTap: onTap)
|
child: new FireMarkerIcon(type), onTap: onTap)),
|
||||||
),
|
// anchor: anchor,
|
||||||
anchor: anchor,
|
anchorPos: anchorOverride ?? type == FireMarkType.position
|
||||||
anchorOverride: anchorOverride ?? type == FireMarkType.position
|
? AnchorPos.exactly(new Anchor(40.0, 20.0))
|
||||||
? new Anchor(40.0, 20.0)
|
|
||||||
: type == FireMarkType.fire
|
: type == FireMarkType.fire
|
||||||
? new Anchor(40.0, 24.0)
|
? AnchorPos.exactly(new Anchor(40.0, 24.0))
|
||||||
: type == FireMarkType.pixel
|
: type == FireMarkType.pixel
|
||||||
? null // auto calculate with height/width in Marker
|
? null // auto calculate with height/width in Marker
|
||||||
// industries, etc (below)
|
// industries, etc (below)
|
||||||
// FIXME check if this is accurate
|
// 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:fires_flutter/models/yourLocation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:redux/src/store.dart';
|
import 'package:redux/redux.dart';
|
||||||
|
|
||||||
import 'customMoment.dart';
|
import 'customMoment.dart';
|
||||||
|
import 'firesSpinner.dart';
|
||||||
import 'generated/i18n.dart';
|
import 'generated/i18n.dart';
|
||||||
import 'genericMap.dart';
|
import 'genericMap.dart';
|
||||||
import 'mainDrawer.dart';
|
import 'mainDrawer.dart';
|
||||||
import 'models/appState.dart';
|
import 'models/appState.dart';
|
||||||
import 'redux/actions.dart';
|
import 'redux/actions.dart';
|
||||||
import 'firesSpinner.dart';
|
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class _ViewModel {
|
class _ViewModel {
|
||||||
|
|
@ -76,7 +76,7 @@ class _FireNotificationListState extends State<FireNotificationList> {
|
||||||
return new ListTile(
|
return new ListTile(
|
||||||
dense: true,
|
dense: true,
|
||||||
leading: const Icon(Icons.whatshot),
|
leading: const Icon(Icons.whatshot),
|
||||||
title: new Text('${prefix}${notif.description}',
|
title: new Text('$prefix${notif.description}',
|
||||||
style: new TextStyle(
|
style: new TextStyle(
|
||||||
fontWeight: notif.read ? FontWeight.normal : FontWeight.bold)),
|
fontWeight: notif.read ? FontWeight.normal : FontWeight.bold)),
|
||||||
subtitle: new Text(Moment.now().from(context, notif.when)),
|
subtitle: new Text(Moment.now().from(context, notif.when)),
|
||||||
|
|
@ -89,7 +89,7 @@ class _FireNotificationListState extends State<FireNotificationList> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void showSnackMsg(String msg) {
|
void showSnackMsg(String msg) {
|
||||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
|
||||||
content: new Text(msg),
|
content: new Text(msg),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -149,8 +149,8 @@ class _FireNotificationListState extends State<FireNotificationList> {
|
||||||
return new StoreConnector<AppState, _ViewModel>(
|
return new StoreConnector<AppState, _ViewModel>(
|
||||||
distinct: true,
|
distinct: true,
|
||||||
converter: (store) {
|
converter: (store) {
|
||||||
print('New ViewModel of Fires Notifications (unread: ${store.state
|
print(
|
||||||
.fireNotificationsUnread})');
|
'New ViewModel of Fires Notifications (unread: ${store.state.fireNotificationsUnread})');
|
||||||
return new _ViewModel(
|
return new _ViewModel(
|
||||||
isLoaded: store.state.isLoaded,
|
isLoaded: store.state.isLoaded,
|
||||||
onDeleteAll: () {
|
onDeleteAll: () {
|
||||||
|
|
@ -158,7 +158,7 @@ class _FireNotificationListState extends State<FireNotificationList> {
|
||||||
},
|
},
|
||||||
onDelete: (notif) {
|
onDelete: (notif) {
|
||||||
store.dispatch(new DeleteFireNotificationAction(notif));
|
store.dispatch(new DeleteFireNotificationAction(notif));
|
||||||
_scaffoldKey.currentState.showSnackBar(new SnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
|
||||||
content: new Text(S.of(context).youDeletedThisNotification),
|
content: new Text(S.of(context).youDeletedThisNotification),
|
||||||
action: new SnackBarAction(
|
action: new SnackBarAction(
|
||||||
label: S.of(context).UNDO,
|
label: S.of(context).UNDO,
|
||||||
|
|
@ -202,25 +202,33 @@ class _FireNotificationListState extends State<FireNotificationList> {
|
||||||
onPressed: () => _showConfirmDialog(view))
|
onPressed: () => _showConfirmDialog(view))
|
||||||
: null
|
: null
|
||||||
])),
|
])),
|
||||||
body: !view.isLoaded ? new FiresSpinner() : !hasFireNotifications
|
body: !view.isLoaded
|
||||||
? Padding(
|
? new FiresSpinner()
|
||||||
padding: const EdgeInsets.all(20.0),
|
: !hasFireNotifications
|
||||||
child: new Card(
|
? Padding(
|
||||||
child: new Padding(
|
padding: const EdgeInsets.all(20.0),
|
||||||
padding: const EdgeInsets.all(20.0),
|
child: new Card(
|
||||||
child: new CenteredColumn(children: <Widget>[
|
child: new Padding(
|
||||||
new Icon(Icons.notifications_none,
|
padding: const EdgeInsets.all(20.0),
|
||||||
size: 150.0, color: Colors.black26),
|
child: new CenteredColumn(children: <Widget>[
|
||||||
new SizedBox(height: 20.0),
|
new Icon(Icons.notifications_none,
|
||||||
new Text(
|
size: 150.0, color: Colors.black26),
|
||||||
S.of(context).fireNotificationsDescription,
|
new SizedBox(height: 20.0),
|
||||||
textAlign: TextAlign.center,
|
new Text(
|
||||||
textScaleFactor: 1.1,
|
S
|
||||||
style: new TextStyle(
|
.of(context)
|
||||||
height: 1.3, color: Colors.black45))
|
.fireNotificationsDescription,
|
||||||
]))))
|
textAlign: TextAlign.center,
|
||||||
: _buildSavedFireNotifications(context, view.yourLocations,
|
textScaleFactor: 1.1,
|
||||||
view.fireNotifications, view.onDelete, view.onTap));
|
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:comunes_flutter/comunes_flutter.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
import 'package:redux/src/store.dart';
|
|
||||||
|
|
||||||
import 'globals.dart';
|
|
||||||
import 'monitoredAreas.dart';
|
|
||||||
import 'activeFires.dart';
|
import 'activeFires.dart';
|
||||||
import 'fireAlert.dart';
|
import 'fireAlert.dart';
|
||||||
import 'fireNotificationList.dart';
|
import 'fireNotificationList.dart';
|
||||||
import 'generated/i18n.dart';
|
import 'generated/i18n.dart';
|
||||||
|
import 'globals.dart';
|
||||||
import 'homePage.dart';
|
import 'homePage.dart';
|
||||||
import 'introPage.dart';
|
import 'introPage.dart';
|
||||||
import 'models/appState.dart';
|
import 'models/appState.dart';
|
||||||
|
import 'monitoredAreas.dart';
|
||||||
import 'privacyPage.dart';
|
import 'privacyPage.dart';
|
||||||
import 'redux/actions.dart';
|
import 'redux/actions.dart';
|
||||||
import 'sandbox.dart';
|
import 'sandbox.dart';
|
||||||
|
|
@ -47,16 +45,15 @@ class _FiresAppState extends State<FiresApp> {
|
||||||
SupportPage.routeName: (BuildContext context) => new SupportPage(),
|
SupportPage.routeName: (BuildContext context) => new SupportPage(),
|
||||||
FireNotificationList.routeName: (BuildContext context) =>
|
FireNotificationList.routeName: (BuildContext context) =>
|
||||||
new FireNotificationList(),
|
new FireNotificationList(),
|
||||||
MonitoredAreasPage.routeName: (BuildContext context) => new MonitoredAreasPage()
|
MonitoredAreasPage.routeName: (BuildContext context) =>
|
||||||
|
new MonitoredAreasPage()
|
||||||
};
|
};
|
||||||
|
|
||||||
final Store<AppState> store;
|
final Store<AppState> store;
|
||||||
|
|
||||||
|
|
||||||
// globals.getIt.registerSingleton
|
// globals.getIt.registerSingleton
|
||||||
_FiresAppState(this.store);
|
_FiresAppState(this.store);
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
StatefulWidget home = new MaterialAppWithIntroHome(
|
StatefulWidget home = new MaterialAppWithIntroHome(
|
||||||
|
|
@ -82,7 +79,7 @@ class _FiresAppState extends State<FiresApp> {
|
||||||
}
|
}
|
||||||
return S.of(context).appName;
|
return S.of(context).appName;
|
||||||
},
|
},
|
||||||
theme: isDevelopment? devFiresTheme: firesTheme,
|
theme: isDevelopment ? devFiresTheme : firesTheme,
|
||||||
routes: routes));
|
routes: routes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
import 'locationUtils.dart';
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||||
import 'package:fires_flutter/models/yourLocation.dart';
|
import 'package:fires_flutter/models/yourLocation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
@ -11,6 +11,7 @@ import 'package:share/share.dart';
|
||||||
|
|
||||||
import 'attributionMapPlugin.dart';
|
import 'attributionMapPlugin.dart';
|
||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
|
import 'customMoment.dart';
|
||||||
import 'dummyMapPlugin.dart';
|
import 'dummyMapPlugin.dart';
|
||||||
import 'fireMarkType.dart';
|
import 'fireMarkType.dart';
|
||||||
import 'fireMarker.dart';
|
import 'fireMarker.dart';
|
||||||
|
|
@ -18,13 +19,13 @@ import 'generated/i18n.dart';
|
||||||
import 'genericMapBottom.dart';
|
import 'genericMapBottom.dart';
|
||||||
import 'globals.dart' as globals;
|
import 'globals.dart' as globals;
|
||||||
import 'layerSelectorMapPlugin.dart';
|
import 'layerSelectorMapPlugin.dart';
|
||||||
|
import 'locationUtils.dart';
|
||||||
import 'models/appState.dart';
|
import 'models/appState.dart';
|
||||||
import 'models/fireMapState.dart';
|
import 'models/fireMapState.dart';
|
||||||
import 'redux/actions.dart';
|
import 'redux/actions.dart';
|
||||||
import 'sentryReport.dart';
|
import 'sentryReport.dart';
|
||||||
import 'slider.dart';
|
import 'slider.dart';
|
||||||
import 'zoomMapPlugin.dart';
|
import 'zoomMapPlugin.dart';
|
||||||
import 'customMoment.dart';
|
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class _ViewModel {
|
class _ViewModel {
|
||||||
|
|
@ -142,33 +143,34 @@ class _genericMapState extends State<genericMap> {
|
||||||
double maxZoom = 18.0; // works?
|
double maxZoom = 18.0; // works?
|
||||||
|
|
||||||
MapOptions mapOptions = new MapOptions(
|
MapOptions mapOptions = new MapOptions(
|
||||||
center: new LatLng(_location.lat, _location.lon),
|
center: new LatLng(_location.lat, _location.lon),
|
||||||
plugins: globals.isDevelopment
|
plugins: globals.isDevelopment
|
||||||
? [
|
? [
|
||||||
new ZoomMapPlugin(),
|
new ZoomMapPlugin(),
|
||||||
new AttributionPlugin(),
|
new AttributionPlugin(),
|
||||||
new LayerSelectorMapPlugin()
|
new LayerSelectorMapPlugin()
|
||||||
]
|
]
|
||||||
: [
|
: [
|
||||||
new DummyMapPlugin(),
|
new DummyMapPlugin(),
|
||||||
new AttributionPlugin(),
|
new AttributionPlugin(),
|
||||||
new LayerSelectorMapPlugin()
|
new LayerSelectorMapPlugin()
|
||||||
],
|
],
|
||||||
// this works ?
|
// this works ?
|
||||||
interactive: false,
|
interactive: true,
|
||||||
zoom: 13.0,
|
zoom: 13.0,
|
||||||
// THIS does not works as expected
|
// THIS does not works as expected
|
||||||
maxZoom: maxZoom,
|
maxZoom: maxZoom,
|
||||||
onTap: (callback) {
|
onTap: (callback) {
|
||||||
if (status == FireMapStatus.edit) {
|
if (status == FireMapStatus.edit) {
|
||||||
_location = _location.copyWith(
|
_location = _location.copyWith(
|
||||||
lat: callback.latitude, lon: callback.longitude);
|
lat: callback.latitude, lon: callback.longitude);
|
||||||
view.onEditing(_location);
|
view.onEditing(_location);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onPositionChanged: (positionCallback) {
|
// onPositionChanged: (positionCallback) {
|
||||||
// print('${positionCallback.center}, ${positionCallback.zoom}');
|
// print('${positionCallback.center}, ${positionCallback.zoom}');
|
||||||
});
|
//}
|
||||||
|
);
|
||||||
var mapController = new MapController();
|
var mapController = new MapController();
|
||||||
|
|
||||||
// mapController.fitBounds(bounds);
|
// mapController.fitBounds(bounds);
|
||||||
|
|
@ -312,7 +314,7 @@ class _genericMapState extends State<genericMap> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// https://github.com/flutter/flutter/issues/17583
|
// https://github.com/flutter/flutter/issues/17583
|
||||||
heroTag: "firesmap" + _location.id.toHexString(),
|
heroTag: "firesmap" + _location.id.hexString,
|
||||||
icon: new Icon(btnIcon, color: fires600),
|
icon: new Icon(btnIcon, color: fires600),
|
||||||
label: new Text(
|
label: new Text(
|
||||||
btnText,
|
btnText,
|
||||||
|
|
@ -388,8 +390,7 @@ class _genericMapState extends State<genericMap> {
|
||||||
icon: new Icon(Icons.share),
|
icon: new Icon(Icons.share),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Share.share(
|
Share.share(
|
||||||
'${view.mapState.fireNotification.description}. ${view
|
'${view.mapState.fireNotification.description}. ${view.serverUrl}fire/${view.mapState.fireNotification.sealed}');
|
||||||
.serverUrl}fire/${view.mapState.fireNotification.sealed}');
|
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
default:
|
default:
|
||||||
|
|
@ -405,14 +406,14 @@ class _genericMapState extends State<genericMap> {
|
||||||
bool isNotif,
|
bool isNotif,
|
||||||
OnFirePressedInMap onFirePressed) {
|
OnFirePressedInMap onFirePressed) {
|
||||||
List<Marker> markers = [];
|
List<Marker> markers = [];
|
||||||
print('building markers: fires: ${fires.length} falsePos: ${falsePosList
|
print(
|
||||||
.length} industries: ${industries.length}, isNotif: ${isNotif} ');
|
'building markers: fires: ${fires.length} falsePos: ${falsePosList.length} industries: ${industries.length}, isNotif: $isNotif ');
|
||||||
const calibrate = false; // useful when we change the fire icons size
|
const calibrate = false; // useful when we change the fire icons size
|
||||||
falsePosList.forEach((falsePos) {
|
falsePosList.forEach((falsePos) {
|
||||||
try {
|
try {
|
||||||
var coords = falsePos['geo']['coordinates'];
|
var coords = falsePos['geo']['coordinates'];
|
||||||
// print('false pos: ${coords}');
|
// 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));
|
markers.add(FireMarker(loc, FireMarkType.falsePos));
|
||||||
if (calibrate) markers.add(FireMarker(loc, FireMarkType.pixel));
|
if (calibrate) markers.add(FireMarker(loc, FireMarkType.pixel));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||||
import 'package:fires_flutter/models/yourLocation.dart';
|
|
||||||
import 'package:fires_flutter/models/fireNotification.dart';
|
import 'package:fires_flutter/models/fireNotification.dart';
|
||||||
|
import 'package:fires_flutter/models/yourLocation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
|
|
@ -27,7 +27,7 @@ class GenericMapBottom extends StatelessWidget {
|
||||||
GenericMapBottom(
|
GenericMapBottom(
|
||||||
{@required this.onSave,
|
{@required this.onSave,
|
||||||
@required this.onCancel,
|
@required this.onCancel,
|
||||||
@required this.onFalsePositive,
|
@required this.onFalsePositive,
|
||||||
@required this.state,
|
@required this.state,
|
||||||
@required this.scaffoldKey});
|
@required this.scaffoldKey});
|
||||||
|
|
||||||
|
|
@ -45,7 +45,7 @@ class GenericMapBottom extends StatelessWidget {
|
||||||
|
|
||||||
List<Widget> buildActionList(YourLocation loc, BuildContext context,
|
List<Widget> buildActionList(YourLocation loc, BuildContext context,
|
||||||
int kmAround, GlobalKey<ScaffoldState> scaffoldState) {
|
int kmAround, GlobalKey<ScaffoldState> scaffoldState) {
|
||||||
List<Widget> actionList = new List<Widget>();
|
List<Widget> actionList = [];
|
||||||
switch (state.status) {
|
switch (state.status) {
|
||||||
case FireMapStatus.edit:
|
case FireMapStatus.edit:
|
||||||
actionList.add(new FlatButton(
|
actionList.add(new FlatButton(
|
||||||
|
|
@ -74,8 +74,7 @@ class GenericMapBottom extends StatelessWidget {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
new Icon(Icons.access_time),
|
new Icon(Icons.access_time),
|
||||||
new SizedBox(width: 5.0),
|
new SizedBox(width: 5.0),
|
||||||
new Text(Moment
|
new Text(Moment.now()
|
||||||
.now()
|
|
||||||
.from(context, state.fireNotification.when)),
|
.from(context, state.fireNotification.when)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -113,7 +112,8 @@ class GenericMapBottom extends StatelessWidget {
|
||||||
onFalsePositive(state.fireNotification, value);
|
onFalsePositive(state.fireNotification, value);
|
||||||
await new Future.delayed(
|
await new Future.delayed(
|
||||||
new Duration(milliseconds: 500));
|
new Duration(milliseconds: 500));
|
||||||
scaffoldKey.currentState.showSnackBar(new SnackBar(
|
ScaffoldMessenger.of(context)
|
||||||
|
.showSnackBar(new SnackBar(
|
||||||
content: new Text(
|
content: new Text(
|
||||||
S.of(context).thanksForParticipating),
|
S.of(context).thanksForParticipating),
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:bson_objectid/bson_objectid.dart';
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||||
import 'package:connectivity/connectivity.dart';
|
import 'package:connectivity/connectivity.dart';
|
||||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
import 'package:fires_flutter/models/fireNotification.dart';
|
import 'package:fires_flutter/models/fireNotification.dart';
|
||||||
|
import 'package:fires_flutter/objectIdUtils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:flutter_simple_dependency_injection/injector.dart';
|
import 'package:flutter_simple_dependency_injection/injector.dart';
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
|
|
||||||
import 'firesSpinner.dart';
|
|
||||||
import 'activeFires.dart';
|
import 'activeFires.dart';
|
||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
import 'fireAlert.dart';
|
import 'fireAlert.dart';
|
||||||
import 'fireNotificationList.dart';
|
import 'fireNotificationList.dart';
|
||||||
|
import 'firesSpinner.dart';
|
||||||
import 'generated/i18n.dart';
|
import 'generated/i18n.dart';
|
||||||
import 'mainDrawer.dart';
|
import 'mainDrawer.dart';
|
||||||
import 'models/appState.dart';
|
import 'models/appState.dart';
|
||||||
|
|
@ -28,14 +28,13 @@ class _ViewModel {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is _ViewModel &&
|
other is _ViewModel &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
isLoaded == other.isLoaded;
|
isLoaded == other.isLoaded;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => isLoaded.hashCode;
|
int get hashCode => isLoaded.hashCode;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class HomePage extends StatefulWidget {
|
class HomePage extends StatefulWidget {
|
||||||
|
|
@ -83,16 +82,20 @@ class _HomePageState extends State<HomePage> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_firebaseMessaging.configure(onMessage: (Map<String, dynamic> message) {
|
_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));
|
_showItemDialog(message, _notifForMessage(message, store.state.isLoaded));
|
||||||
|
return;
|
||||||
}, onLaunch: (Map<String, dynamic> message) {
|
}, onLaunch: (Map<String, dynamic> message) {
|
||||||
debugPrint("onLaunch (isLoaded: ${store.state.isLoaded}): $message");
|
debugPrint("onLaunch (isLoaded: ${store.state.isLoaded}): $message");
|
||||||
_notifForMessage(message, store.state.isLoaded);
|
_notifForMessage(message, store.state.isLoaded);
|
||||||
_navigateToItemDetail(message);
|
_navigateToItemDetail(message);
|
||||||
|
return;
|
||||||
}, onResume: (Map<String, dynamic> message) {
|
}, onResume: (Map<String, dynamic> message) {
|
||||||
debugPrint("onResume (isLoaded: ${store.state.isLoaded}): $message");
|
debugPrint("onResume (isLoaded: ${store.state.isLoaded}): $message");
|
||||||
_notifForMessage(message, store.state.isLoaded);
|
_notifForMessage(message, store.state.isLoaded);
|
||||||
_navigateToItemDetail(message);
|
_navigateToItemDetail(message);
|
||||||
|
return;
|
||||||
});
|
});
|
||||||
_firebaseMessaging.requestNotificationPermissions(
|
_firebaseMessaging.requestNotificationPermissions(
|
||||||
const IosNotificationSettings(sound: true, badge: true, alert: true));
|
const IosNotificationSettings(sound: true, badge: true, alert: true));
|
||||||
|
|
@ -140,9 +143,7 @@ class _HomePageState extends State<HomePage> {
|
||||||
});
|
});
|
||||||
newNotifications.clear();
|
newNotifications.clear();
|
||||||
}
|
}
|
||||||
return new _ViewModel(
|
return new _ViewModel(isLoaded: store.state.isLoaded);
|
||||||
isLoaded: store.state.isLoaded
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
builder: (context, view) {
|
builder: (context, view) {
|
||||||
return new Scaffold(
|
return new Scaffold(
|
||||||
|
|
@ -179,45 +180,47 @@ class _HomePageState extends State<HomePage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
body: !view.isLoaded? new FiresSpinner(): new SafeArea(
|
body: !view.isLoaded
|
||||||
child: Center(
|
? new FiresSpinner()
|
||||||
child: new CenteredColumn(children: <Widget>[
|
: new SafeArea(
|
||||||
new Row(
|
child: Center(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
child: new CenteredColumn(children: <Widget>[
|
||||||
children: <Widget>[
|
new Row(
|
||||||
new IconButton(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
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>[
|
children: <Widget>[
|
||||||
new Padding(
|
new IconButton(
|
||||||
padding: const EdgeInsets.symmetric(
|
onPressed: () {
|
||||||
vertical: 10.0, horizontal: 20.0),
|
_scaffoldKey.currentState.openDrawer();
|
||||||
child: FittedBox(
|
},
|
||||||
child: new Text(S.of(context).appName,
|
icon: new Icon(Icons.menu,
|
||||||
maxLines: 2,
|
size: 30.0, color: Colors.black38)),
|
||||||
textAlign: TextAlign.center,
|
]),
|
||||||
style: _homeFont),
|
new Expanded(
|
||||||
fit: BoxFit.scaleDown,
|
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-
|
// https://pub.dartlang.org/packages/firebase_messaging#-example-tab-
|
||||||
final FirebaseMessaging _firebaseMessaging = new FirebaseMessaging();
|
final FirebaseMessaging _firebaseMessaging = new FirebaseMessaging();
|
||||||
|
|
||||||
FireNotification _notifForMessage(Map<String, dynamic> message, bool isLoaded) {
|
FireNotification _notifForMessage(
|
||||||
|
Map<String, dynamic> message, bool isLoaded) {
|
||||||
FireNotification notif;
|
FireNotification notif;
|
||||||
try {
|
try {
|
||||||
notif = new FireNotification(
|
notif = new FireNotification(
|
||||||
id: new ObjectId.fromHexString(message['id']),
|
id: objectIdFromJson(message['id']),
|
||||||
subsId: new ObjectId.fromHexString(message['subsId']),
|
subsId: objectIdFromJson(message['subsId']),
|
||||||
lat: double.parse(message['lat']),
|
lat: double.parse(message['lat']),
|
||||||
lon: double.parse(message['lon']),
|
lon: double.parse(message['lon']),
|
||||||
description: message['description'],
|
description: message['description'],
|
||||||
|
|
@ -299,12 +303,12 @@ class _HomePageState extends State<HomePage> {
|
||||||
debugPrint(e.toString());
|
debugPrint(e.toString());
|
||||||
}
|
}
|
||||||
if (notif != null)
|
if (notif != null)
|
||||||
// if our store is loaded, we just dispatch the notification, if not, we wait til is loaded
|
// if our store is loaded, we just dispatch the notification, if not, we wait til is loaded
|
||||||
if (isLoaded) {
|
if (isLoaded) {
|
||||||
store.dispatch(new AddFireNotificationAction(notif));
|
store.dispatch(new AddFireNotificationAction(notif));
|
||||||
} else {
|
} else {
|
||||||
newNotifications.add(notif);
|
newNotifications.add(notif);
|
||||||
}
|
}
|
||||||
return notif;
|
return notif;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:flutter_map/plugin_api.dart';
|
import 'package:flutter_map/plugin_api.dart';
|
||||||
import 'package:flutter_simple_dependency_injection/injector.dart';
|
import 'package:flutter_simple_dependency_injection/injector.dart';
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
|
|
@ -18,16 +17,19 @@ class LayerSelectorMapPluginOptions extends LayerOptions {
|
||||||
class LayerSelectorMapPlugin extends MapPlugin {
|
class LayerSelectorMapPlugin extends MapPlugin {
|
||||||
Widget LayerSelectorButton(Store<AppState> store) {
|
Widget LayerSelectorButton(Store<AppState> store) {
|
||||||
return new FloatingActionButton(
|
return new FloatingActionButton(
|
||||||
backgroundColor: Colors.black26,
|
backgroundColor: Colors.black26,
|
||||||
mini: true,
|
mini: true,
|
||||||
child: Icon(Icons.layers, /* size: 40.0, color: Colors.black45, */ ),
|
child: Icon(
|
||||||
|
Icons.layers, /* size: 40.0, color: Colors.black45, */
|
||||||
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
store.dispatch(new ToggleMapLayerAction());
|
store.dispatch(new ToggleMapLayerAction());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget createLayer(LayerOptions options, MapState mapState) {
|
Widget createLayer(
|
||||||
|
LayerOptions options, MapState mapState, Stream<Null> stream) {
|
||||||
Store<AppState> store = Injector.getInjector().get<Store<AppState>>();
|
Store<AppState> store = Injector.getInjector().get<Store<AppState>>();
|
||||||
if (options is LayerSelectorMapPluginOptions) {
|
if (options is LayerSelectorMapPluginOptions) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,32 @@
|
||||||
import 'package:location/location.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:fires_flutter/models/yourLocation.dart';
|
import 'package:fires_flutter/models/yourLocation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:geocoder/geocoder.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'generated/i18n.dart';
|
|
||||||
import 'package:flutter_simple_dependency_injection/injector.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(
|
Future<YourLocation> getUserLocation(
|
||||||
GlobalKey<ScaffoldState> scaffoldKey) async {
|
GlobalKey<ScaffoldState> scaffoldKey) async {
|
||||||
// Platform messages may fail, so we use a try/catch PlatformException.
|
// Platform messages may fail, so we use a try/catch PlatformException.
|
||||||
try {
|
try {
|
||||||
Location _location = new Location();
|
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
|
// It seems that the lib fails with lat/lon values
|
||||||
var yl = new YourLocation(
|
var yl = new YourLocation(lat: location.latitude, lon: location.longitude);
|
||||||
lat: location['latitude'], lon: location['longitude']);
|
|
||||||
var address;
|
var address;
|
||||||
try {
|
try {
|
||||||
address = await getReverseLocation(lat: yl.lat, lon: yl.lon);
|
address = await getReverseLocation(lat: yl.lat, lon: yl.lon);
|
||||||
yl.description = address;
|
yl.description = address;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
try {
|
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;
|
yl.description = address;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('We cannot reverse geolocate');
|
print('We cannot reverse geolocate');
|
||||||
|
|
@ -32,22 +35,25 @@ Future<YourLocation> getUserLocation(
|
||||||
return yl;
|
return yl;
|
||||||
} on PlatformException catch (e) {
|
} on PlatformException catch (e) {
|
||||||
if (e.code == 'PERMISSION_DENIED') {
|
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),
|
content: new Text(S.of(scaffoldKey.currentContext).notPermsUbication),
|
||||||
));
|
));
|
||||||
} else if (e.code == 'PERMISSION_DENIED_NEVER_ASK') {}
|
} else if (e.code == 'PERMISSION_DENIED_NEVER_ASK') {}
|
||||||
scaffoldKey.currentState.showSnackBar(new SnackBar(
|
ScaffoldMessenger.of(scaffoldKey.currentContext).showSnackBar(new SnackBar(
|
||||||
content: new Text(S.of(scaffoldKey.currentContext).isYourUbicationEnabled
|
content:
|
||||||
),
|
new Text(S.of(scaffoldKey.currentContext).isYourUbicationEnabled),
|
||||||
));
|
));
|
||||||
return YourLocation.noLocation;
|
return YourLocation.noLocation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> getReverseLocation({@required lat, @required lon,
|
Future<String> getReverseLocation(
|
||||||
bool external = false}) async {
|
{@required lat, @required lon, bool external = false}) async {
|
||||||
final coordinates = new Coordinates(lat, lon);
|
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 addresses = await geoCoder.findAddressesFromCoordinates(coordinates);
|
||||||
var first = addresses.first;
|
var first = addresses.first;
|
||||||
print("${first.featureName} : ${first.addressLine}");
|
print("${first.featureName} : ${first.addressLine}");
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import 'dart:async';
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_simple_dependency_injection/injector.dart';
|
import 'package:flutter_simple_dependency_injection/injector.dart';
|
||||||
|
import 'package:package_info/package_info.dart';
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
import 'package:sentry/sentry.dart';
|
import 'package:sentry/sentry.dart';
|
||||||
|
|
||||||
|
|
@ -12,7 +13,6 @@ import 'models/appState.dart';
|
||||||
import 'models/firesApi.dart';
|
import 'models/firesApi.dart';
|
||||||
import 'redux/fetchDataMiddleware.dart';
|
import 'redux/fetchDataMiddleware.dart';
|
||||||
import 'redux/reducers.dart';
|
import 'redux/reducers.dart';
|
||||||
import 'package:package_info/package_info.dart';
|
|
||||||
import 'sentryReport.dart';
|
import 'sentryReport.dart';
|
||||||
|
|
||||||
Future<PackageInfo> loadPackageInfo() async {
|
Future<PackageInfo> loadPackageInfo() async {
|
||||||
|
|
@ -22,13 +22,14 @@ Future<PackageInfo> loadPackageInfo() async {
|
||||||
|
|
||||||
Future<Map<String, dynamic>> loadSecrets() async {
|
Future<Map<String, dynamic>> loadSecrets() async {
|
||||||
return await SecretLoader(
|
return await SecretLoader(
|
||||||
secretPath: globals.isDevelopment?
|
secretPath: globals.isDevelopment
|
||||||
'assets/private-settings-dev.json' :
|
? 'assets/private-settings-dev.json'
|
||||||
'assets/private-settings.json'
|
: 'assets/private-settings.json')
|
||||||
).load();
|
.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainCommon(List<Middleware<AppState>> otherMiddleware) {
|
void mainCommon(List<Middleware<AppState>> otherMiddleware) {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
final injector = Injector.getInjector();
|
final injector = Injector.getInjector();
|
||||||
injector.map<FiresApi>((i) => new FiresApi(), isSingleton: true);
|
injector.map<FiresApi>((i) => new FiresApi(), isSingleton: true);
|
||||||
loadPackageInfo().then((packageInfo) {
|
loadPackageInfo().then((packageInfo) {
|
||||||
|
|
@ -36,13 +37,12 @@ void mainCommon(List<Middleware<AppState>> otherMiddleware) {
|
||||||
print('Running version ${packageInfo.version}');
|
print('Running version ${packageInfo.version}');
|
||||||
loadSecrets().then((secrets) {
|
loadSecrets().then((secrets) {
|
||||||
final store = new Store<AppState>(appStateReducer,
|
final store = new Store<AppState>(appStateReducer,
|
||||||
initialState: new AppState(
|
initialState: new AppState(
|
||||||
gmapKey: secrets['gmapKey'],
|
gmapKey: secrets['gmapKey'],
|
||||||
firesApiKey: secrets['firesApiKey'],
|
firesApiKey: secrets['firesApiKey'],
|
||||||
serverUrl: secrets['firesApiUrl'],
|
serverUrl: secrets['firesApiUrl'],
|
||||||
firesApiUrl: secrets['firesApiUrl'] + "api/v1/"),
|
firesApiUrl: secrets['firesApiUrl'] + "api/v1/"),
|
||||||
middleware: List.from(otherMiddleware)
|
middleware: List.from(otherMiddleware)..add(fetchDataMiddleware));
|
||||||
..add(fetchDataMiddleware));
|
|
||||||
|
|
||||||
injector.map<Store<AppState>>((i) => store);
|
injector.map<Store<AppState>>((i) => store);
|
||||||
injector.map<String>((i) => store.state.firesApiUrl, key: "firesApiUrl");
|
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/
|
// https://flutter.io/cookbook/maintenance/error-reporting/
|
||||||
runZoned<Future<Null>>(() async {
|
runZonedGuarded<Future<void>>(() async {
|
||||||
runApp(new FiresApp(store));
|
runApp(new FiresApp(store));
|
||||||
}, onError: (error, stackTrace) {
|
}, (Object error, StackTrace stackTrace) {
|
||||||
// Whenever an error occurs, call the `_reportError` function. This will send
|
// Whenever an error occurs, call the `_reportError` function. This will send
|
||||||
// Dart errors to our dev console or Sentry depending on the environment.
|
// Dart errors to our dev console or Sentry depending on the environment.
|
||||||
reportError(error, stackTrace);
|
reportError(error, stackTrace);
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ LoggingMiddleware customLogPrinter<State>({
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
globals.isDevelopment = true;
|
globals.isDevelopment = true;
|
||||||
|
print("Is development!");
|
||||||
String onlyLogActionFormatter<State>(
|
String onlyLogActionFormatter<State>(
|
||||||
State state,
|
State state,
|
||||||
dynamic action,
|
dynamic action,
|
||||||
|
|
@ -39,9 +39,9 @@ void main() {
|
||||||
return ">>>>> ${action.toString().replaceAll('Instance of ', '')}";
|
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(
|
customLogPrinter(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:badge/badge.dart';
|
import 'package:badges/badges.dart';
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
|
|
@ -97,13 +97,28 @@ Widget mainDrawer(BuildContext context, String currentRoute) {
|
||||||
new ListTile(
|
new ListTile(
|
||||||
leading: const Icon(Icons.notifications),
|
leading: const Icon(Icons.notifications),
|
||||||
selected: currentRoute == FireNotificationList.routeName,
|
selected: currentRoute == FireNotificationList.routeName,
|
||||||
title: view.unreadCount > 0
|
title: Text(S.of(context).fireNotificationsTitleShort),
|
||||||
? Badge.after(
|
trailing: SizedBox(
|
||||||
spacing: 5.0,
|
width: 100,
|
||||||
borderColor: Colors.red,
|
child: Row(
|
||||||
child: Text(S.of(context).fireNotificationsTitleShort),
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
value: ' ${view.unreadCount.toString()} ')
|
children: <Widget>[
|
||||||
: Text(S.of(context).fireNotificationsTitleShort),
|
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: () {
|
onTap: () {
|
||||||
Navigator.popAndPushNamed(
|
Navigator.popAndPushNamed(
|
||||||
context, FireNotificationList.routeName);
|
context, FireNotificationList.routeName);
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,21 @@ import 'package:connectivity/connectivity.dart';
|
||||||
import 'package:fires_flutter/models/fireNotification.dart';
|
import 'package:fires_flutter/models/fireNotification.dart';
|
||||||
import 'package:fires_flutter/models/yourLocation.dart';
|
import 'package:fires_flutter/models/yourLocation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:latlong/latlong.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
import 'fireMapState.dart';
|
import 'fireMapState.dart';
|
||||||
import 'user.dart';
|
import 'user.dart';
|
||||||
|
|
||||||
export 'fireMapState.dart';
|
export 'fireMapState.dart';
|
||||||
import 'package:flutter_map/flutter_map.dart';
|
|
||||||
import 'package:latlong/latlong.dart';
|
|
||||||
|
|
||||||
part 'appState.g.dart';
|
part 'appState.g.dart';
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
@JsonSerializable(nullable: false)
|
@JsonSerializable(nullable: false)
|
||||||
class AppState extends Object with _$AppStateSerializerMixin {
|
class AppState {
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
final bool isLoading;
|
final bool isLoading;
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
|
|
@ -58,7 +58,7 @@ class AppState extends Object with _$AppStateSerializerMixin {
|
||||||
this.user: const User.initial(),
|
this.user: const User.initial(),
|
||||||
this.isLoading: false,
|
this.isLoading: false,
|
||||||
this.isLoaded: false,
|
this.isLoaded: false,
|
||||||
this.error: null,
|
this.error,
|
||||||
this.gmapKey,
|
this.gmapKey,
|
||||||
this.firesApiKey,
|
this.firesApiKey,
|
||||||
this.firesApiUrl,
|
this.firesApiUrl,
|
||||||
|
|
@ -102,11 +102,7 @@ class AppState extends Object with _$AppStateSerializerMixin {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'AppState{\nuser: ${user}\nconnectivity: ${connectivity
|
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}';
|
||||||
.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
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
part of 'appState.dart';
|
part of 'appState.dart';
|
||||||
|
|
@ -8,37 +6,30 @@ part of 'appState.dart';
|
||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
AppState _$AppStateFromJson(Map<String, dynamic> json) => new AppState(
|
AppState _$AppStateFromJson(Map json) {
|
||||||
yourLocations: (json['yourLocations'] as List)
|
return $checkedNew('AppState', json, () {
|
||||||
.map((e) => new YourLocation.fromJson(e as Map<String, dynamic>))
|
final val = AppState(
|
||||||
.toList(),
|
yourLocations: $checkedConvert(
|
||||||
fireNotifications: (json['fireNotifications'] as List)
|
json,
|
||||||
.map((e) => new FireNotification.fromJson(e as Map<String, dynamic>))
|
'yourLocations',
|
||||||
.toList());
|
(v) => (v as List)
|
||||||
|
.map((e) =>
|
||||||
abstract class _$AppStateSerializerMixin {
|
YourLocation.fromJson(Map<String, dynamic>.from(e as Map)))
|
||||||
List<YourLocation> get yourLocations;
|
.toList()),
|
||||||
List<FireNotification> get fireNotifications;
|
fireNotifications: $checkedConvert(
|
||||||
Map<String, dynamic> toJson() => new _$AppStateJsonMapWrapper(this);
|
json,
|
||||||
|
'fireNotifications',
|
||||||
|
(v) => (v as List)
|
||||||
|
.map((e) => FireNotification.fromJson(
|
||||||
|
Map<String, dynamic>.from(e as Map)))
|
||||||
|
.toList()),
|
||||||
|
);
|
||||||
|
return val;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class _$AppStateJsonMapWrapper extends $JsonMapWrapper {
|
Map<String, dynamic> _$AppStateToJson(AppState instance) => <String, dynamic>{
|
||||||
final _$AppStateSerializerMixin _v;
|
'yourLocations': instance.yourLocations.map((e) => e.toJson()).toList(),
|
||||||
_$AppStateJsonMapWrapper(this._v);
|
'fireNotifications':
|
||||||
|
instance.fireNotifications.map((e) => e.toJson()).toList(),
|
||||||
@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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
import 'package:bson_objectid/bson_objectid.dart';
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:objectid/objectid.dart';
|
||||||
|
|
||||||
import '../objectIdUtils.dart';
|
import '../objectIdUtils.dart';
|
||||||
|
|
||||||
part 'fireNotification.g.dart';
|
part 'fireNotification.g.dart';
|
||||||
|
|
||||||
@JsonSerializable(nullable: false)
|
@JsonSerializable(nullable: false)
|
||||||
class FireNotification extends Object with _$FireNotificationSerializerMixin {
|
class FireNotification {
|
||||||
@JsonKey(toJson: objectIdToJson, fromJson: objectIdFromJson)
|
@JsonKey(toJson: objectIdToJson, fromJson: objectIdFromJson)
|
||||||
ObjectId id;
|
ObjectId id;
|
||||||
final double lat;
|
final double lat;
|
||||||
|
|
@ -74,11 +75,11 @@ class FireNotification extends Object with _$FireNotificationSerializerMixin {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'FireNotification {id: $id, lat: $lat, lon: $lon, when: $when, read: $read, subsId: $subsId, sealed ${ellipse(
|
return 'FireNotification {id: $id, lat: $lat, lon: $lon, when: $when, read: $read, subsId: $subsId, sealed ${ellipse(sealed)}';
|
||||||
sealed)}';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static final Map<String, Route<Null>> routes = <String, Route<Null>>{};
|
static final Map<String, Route<Null>> routes = <String, Route<Null>>{};
|
||||||
|
Map<String, dynamic> toJson() => _$FireNotificationToJson(this);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Route<Null> getRoute(Store store) {
|
Route<Null> getRoute(Store store) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// Copyright (c) 2018, Comunes Association.
|
|
||||||
|
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
part of 'fireNotification.dart';
|
part of 'fireNotification.dart';
|
||||||
|
|
@ -8,67 +6,31 @@ part of 'fireNotification.dart';
|
||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
FireNotification _$FireNotificationFromJson(Map<String, dynamic> json) =>
|
FireNotification _$FireNotificationFromJson(Map json) {
|
||||||
new FireNotification(
|
return $checkedNew('FireNotification', json, () {
|
||||||
id: objectIdFromJson(json['id'] as String),
|
final val = FireNotification(
|
||||||
lat: (json['lat'] as num).toDouble(),
|
id: $checkedConvert(json, 'id', (v) => objectIdFromJson(v as String)),
|
||||||
lon: (json['lon'] as num).toDouble(),
|
lat: $checkedConvert(json, 'lat', (v) => (v as num).toDouble()),
|
||||||
description: json['description'] as String,
|
lon: $checkedConvert(json, 'lon', (v) => (v as num).toDouble()),
|
||||||
when: DateTime.parse(json['when'] as String),
|
description: $checkedConvert(json, 'description', (v) => v as String),
|
||||||
read: json['read'] as bool,
|
when: $checkedConvert(json, 'when', (v) => DateTime.parse(v as String)),
|
||||||
sealed: json['sealed'] as String,
|
read: $checkedConvert(json, 'read', (v) => v as bool),
|
||||||
subsId: objectIdFromJson(json['subsId'] as String));
|
sealed: $checkedConvert(json, 'sealed', (v) => v as String),
|
||||||
|
subsId:
|
||||||
abstract class _$FireNotificationSerializerMixin {
|
$checkedConvert(json, 'subsId', (v) => objectIdFromJson(v as String)),
|
||||||
ObjectId get id;
|
);
|
||||||
double get lat;
|
return val;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _$FireNotificationJsonMapWrapper extends $JsonMapWrapper {
|
Map<String, dynamic> _$FireNotificationToJson(FireNotification instance) =>
|
||||||
final _$FireNotificationSerializerMixin _v;
|
<String, dynamic>{
|
||||||
_$FireNotificationJsonMapWrapper(this._v);
|
'id': objectIdToJson(instance.id),
|
||||||
|
'lat': instance.lat,
|
||||||
@override
|
'lon': instance.lon,
|
||||||
Iterable<String> get keys => const [
|
'description': instance.description,
|
||||||
'id',
|
'when': instance.when.toIso8601String(),
|
||||||
'lat',
|
'sealed': instance.sealed,
|
||||||
'lon',
|
'subsId': objectIdToJson(instance.subsId),
|
||||||
'description',
|
'read': instance.read,
|
||||||
'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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:fires_flutter/models/fireNotification.dart';
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||||
|
import 'package:fires_flutter/models/fireNotification.dart';
|
||||||
|
|
||||||
import '../globals.dart' as globals;
|
import '../globals.dart' as globals;
|
||||||
|
|
||||||
final String fireNotificationKey = 'fireNotifications';
|
final String fireNotificationKey = 'fireNotifications';
|
||||||
|
|
@ -10,7 +11,7 @@ final String fireNotificationKey = 'fireNotifications';
|
||||||
Future<List<FireNotification>> loadFireNotifications() async {
|
Future<List<FireNotification>> loadFireNotifications() async {
|
||||||
return await globals.prefs.then((prefs) {
|
return await globals.prefs.then((prefs) {
|
||||||
List<String> FireNotifications = prefs.getStringList(fireNotificationKey);
|
List<String> FireNotifications = prefs.getStringList(fireNotificationKey);
|
||||||
List<FireNotification> persistedList = List<FireNotification>();
|
List<FireNotification> persistedList = [];
|
||||||
if (FireNotifications == null) {
|
if (FireNotifications == null) {
|
||||||
FireNotifications = [];
|
FireNotifications = [];
|
||||||
// first run, init with empty list
|
// first run, init with empty list
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,26 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
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: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:http/http.dart' as ht;
|
||||||
import 'package:jaguar_resty/jaguar_resty.dart' as resty;
|
import 'package:jaguar_resty/jaguar_resty.dart' as resty;
|
||||||
import 'package:latlong/latlong.dart';
|
import 'package:latlong/latlong.dart';
|
||||||
|
|
||||||
import '../globals.dart' as globals;
|
import '../globals.dart' as globals;
|
||||||
|
import '../objectIdUtils.dart';
|
||||||
import '../redux/actions.dart';
|
import '../redux/actions.dart';
|
||||||
import 'appState.dart';
|
import 'appState.dart';
|
||||||
|
import 'falsePositiveTypes.dart';
|
||||||
|
|
||||||
class FiresApi {
|
class FiresApi {
|
||||||
FiresApi() {
|
FiresApi() {
|
||||||
resty.globalClient = new ht.IOClient();
|
resty.globalClient = new ht.IOClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> createUser(AppState state, String mobileToken,
|
Future<String> createUser(
|
||||||
String lang) async {
|
AppState state, String mobileToken, String lang) async {
|
||||||
assert(state.firesApiUrl != null);
|
assert(state.firesApiUrl != null);
|
||||||
assert(state.firesApiKey != null);
|
assert(state.firesApiKey != null);
|
||||||
assert(mobileToken != null);
|
assert(mobileToken != null);
|
||||||
|
|
@ -38,6 +38,8 @@ class FiresApi {
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
// print(response.body);
|
// print(response.body);
|
||||||
return json.decode(response.body)['data']['userId'];
|
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 {
|
Future<List<YourLocation>> fetchYourLocations(AppState state) async {
|
||||||
final apiKey = state.firesApiKey;
|
final apiKey = state.firesApiKey;
|
||||||
final mobileToken = state.user.token;
|
final mobileToken = state.user.token;
|
||||||
final String url = '${state
|
final String url =
|
||||||
.firesApiUrl}mobile/subscriptions/all/$apiKey/$mobileToken';
|
'${state.firesApiUrl}mobile/subscriptions/all/$apiKey/$mobileToken';
|
||||||
// if (globals.isDevelopment) print('$url');
|
// if (globals.isDevelopment) print('$url');
|
||||||
return await resty.get(url).go().then((response) {
|
return await resty.get(url).go().then((response) {
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
// if (globals.isDevelopment) print(response.body);
|
// if (globals.isDevelopment) print(response.body);
|
||||||
final dataSubscriptions =
|
final dataSubscriptions =
|
||||||
json.decode(response.body)['data']['subscriptions'];
|
json.decode(response.body)['data']['subscriptions'];
|
||||||
List<YourLocation> subscribed = [];
|
List<YourLocation> subscribed = [];
|
||||||
for (int i = 0; i < dataSubscriptions.length; i++) {
|
for (int i = 0; i < dataSubscriptions.length; i++) {
|
||||||
var el = dataSubscriptions[i];
|
var el = dataSubscriptions[i];
|
||||||
var lat = el['location']['lat'];
|
var lat = el['location']['lat'];
|
||||||
var lon = el['location']['lon'];
|
var lon = el['location']['lon'];
|
||||||
subscribed.add(new YourLocation(
|
subscribed.add(new YourLocation(
|
||||||
id: ObjectId.fromHexString(el['_id']['_str']),
|
id: objectIdFromJson(el['_id']['_str']),
|
||||||
lat: lat,
|
lat: lat,
|
||||||
lon: lon,
|
lon: lon,
|
||||||
subscribed: true,
|
subscribed: true,
|
||||||
distance: el['distance']));
|
distance: el['distance']));
|
||||||
}
|
}
|
||||||
|
|
||||||
return subscribed;
|
return subscribed;
|
||||||
|
} else {
|
||||||
|
return throw "Unexpected error fetching your locations";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -83,13 +86,12 @@ class FiresApi {
|
||||||
final params = {
|
final params = {
|
||||||
"token": state.firesApiKey,
|
"token": state.firesApiKey,
|
||||||
"mobileToken": state.user.token,
|
"mobileToken": state.user.token,
|
||||||
"id": loc.id.toHexString(),
|
"id": loc.id.hexString,
|
||||||
"lat": loc.lat,
|
"lat": loc.lat,
|
||||||
"lon": loc.lon,
|
"lon": loc.lon,
|
||||||
"distance": loc.distance
|
"distance": loc.distance
|
||||||
};
|
};
|
||||||
final String url = '${state
|
final String url = '${state.firesApiUrl}mobile/subscriptions';
|
||||||
.firesApiUrl}mobile/subscriptions';
|
|
||||||
return await resty.post(url).json(params).go().then((response) {
|
return await resty.post(url).json(params).go().then((response) {
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
// print(response.body);
|
// print(response.body);
|
||||||
|
|
@ -97,6 +99,7 @@ class FiresApi {
|
||||||
} else {
|
} else {
|
||||||
// take care of? "Unexpected error in REST call: Error: The user is already subscribed to this area [on-already-subscribed]"
|
// take care of? "Unexpected error in REST call: Error: The user is already subscribed to this area [on-already-subscribed]"
|
||||||
print(response.body);
|
print(response.body);
|
||||||
|
return throw "Unexpected error on subscribe";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -108,22 +111,24 @@ class FiresApi {
|
||||||
final apiKey = state.firesApiKey;
|
final apiKey = state.firesApiKey;
|
||||||
final mobileToken = state.user.token;
|
final mobileToken = state.user.token;
|
||||||
assert(subsId != null);
|
assert(subsId != null);
|
||||||
final String url = '${state
|
final String url =
|
||||||
.firesApiUrl}mobile/subscriptions/$apiKey/$mobileToken/$subsId';
|
'${state.firesApiUrl}mobile/subscriptions/$apiKey/$mobileToken/$subsId';
|
||||||
return await resty.delete(url).go().then((response) {
|
return await resty.delete(url).go().then((response) {
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
// print(response.body);
|
// print(response.body);
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
return throw "Unexpected error on unsubscribe";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<UpdateFireMapStatsAction> getFiresInLocation(
|
Future<UpdateFireMapStatsAction> getFiresInLocation(
|
||||||
{AppState state, double lat, double lon, int distance}) async {
|
{AppState state, double lat, double lon, int distance}) async {
|
||||||
assert(state.firesApiUrl != null);
|
assert(state.firesApiUrl != null);
|
||||||
assert(state.firesApiKey != null);
|
assert(state.firesApiKey != null);
|
||||||
var url = '${state.firesApiUrl}fires-in-full/${state
|
var url =
|
||||||
.firesApiKey}/${lat}/${lon}/${distance}';
|
'${state.firesApiUrl}fires-in-full/${state.firesApiKey}/$lat/$lon/$distance';
|
||||||
if (globals.isDevelopment) print(url);
|
if (globals.isDevelopment) print(url);
|
||||||
return await resty.get(url).go().then((response) {
|
return await resty.get(url).go().then((response) {
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
|
|
@ -138,13 +143,13 @@ class FiresApi {
|
||||||
var industriesCount = industries.length;
|
var industriesCount = industries.length;
|
||||||
var falsePosCount = falsePos.length;
|
var falsePosCount = falsePos.length;
|
||||||
print(
|
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(
|
return new UpdateFireMapStatsAction(
|
||||||
numFires: numFires,
|
numFires: numFires,
|
||||||
fires: fires,
|
fires: fires,
|
||||||
falsePos: falsePos,
|
falsePos: falsePos,
|
||||||
industries: industries);
|
industries: industries);
|
||||||
} else
|
} else
|
||||||
throw Exception('Wrong response trying to get fire data');
|
throw Exception('Wrong response trying to get fire data');
|
||||||
});
|
});
|
||||||
|
|
@ -153,8 +158,8 @@ class FiresApi {
|
||||||
Future<List<Polyline>> getMonitoredAreas({AppState state}) async {
|
Future<List<Polyline>> getMonitoredAreas({AppState state}) async {
|
||||||
assert(state.firesApiUrl != null);
|
assert(state.firesApiUrl != null);
|
||||||
assert(state.firesApiKey != null);
|
assert(state.firesApiKey != null);
|
||||||
var url = '${state.firesApiUrl}status/subs-public-union/${state
|
var url =
|
||||||
.firesApiKey}';
|
'${state.firesApiUrl}status/subs-public-union/${state.firesApiKey}';
|
||||||
var color = const Color(0xFF145A32);
|
var color = const Color(0xFF145A32);
|
||||||
return await resty.get(url).go().then((response) {
|
return await resty.get(url).go().then((response) {
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
|
|
@ -162,8 +167,8 @@ class FiresApi {
|
||||||
// print(resultDecoded['data']['union']);
|
// print(resultDecoded['data']['union']);
|
||||||
List<Polyline> union = [];
|
List<Polyline> union = [];
|
||||||
final multipolygon =
|
final multipolygon =
|
||||||
json.decode(resultDecoded['data']['union']['value'])['geometry']
|
json.decode(resultDecoded['data']['union']['value'])['geometry']
|
||||||
['coordinates'];
|
['coordinates'];
|
||||||
for (List<dynamic> polygon in multipolygon) {
|
for (List<dynamic> polygon in multipolygon) {
|
||||||
for (List<dynamic> hole in polygon) {
|
for (List<dynamic> hole in polygon) {
|
||||||
List<LatLng> points = [];
|
List<LatLng> points = [];
|
||||||
|
|
@ -171,7 +176,7 @@ class FiresApi {
|
||||||
points.add(new LatLng(point[1].toDouble(), point[0].toDouble()));
|
points.add(new LatLng(point[1].toDouble(), point[0].toDouble()));
|
||||||
}
|
}
|
||||||
union.add(
|
union.add(
|
||||||
new Polyline(points: points, color: color, strokeWidth: 3.0));
|
new Polyline(points: points, color: color, strokeWidth: 3.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return union;
|
return union;
|
||||||
|
|
@ -181,7 +186,7 @@ class FiresApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> markFalsePositive(AppState state, String mobileToken,
|
Future<bool> markFalsePositive(AppState state, String mobileToken,
|
||||||
String sealed, FalsePositiveType type) async {
|
String sealed, FalsePositiveType type) async {
|
||||||
assert(state.firesApiUrl != null);
|
assert(state.firesApiUrl != null);
|
||||||
assert(state.firesApiKey != null);
|
assert(state.firesApiKey != null);
|
||||||
assert(mobileToken != null);
|
assert(mobileToken != null);
|
||||||
|
|
@ -198,8 +203,8 @@ class FiresApi {
|
||||||
return await resty.post(url).json(params).go().then((response) {
|
return await resty.post(url).json(params).go().then((response) {
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
// print(response.body);
|
// print(response.body);
|
||||||
if (globals.isDevelopment) print(
|
if (globals.isDevelopment)
|
||||||
json.decode(response.body)['data']['upsert']);
|
print(json.decode(response.body)['data']['upsert']);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
debugPrint(json.decode(response.body));
|
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:flutter/material.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:fires_flutter/objectIdUtils.dart';
|
import 'package:objectid/objectid.dart';
|
||||||
|
|
||||||
part 'yourLocation.g.dart';
|
part 'yourLocation.g.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@JsonSerializable(nullable: false)
|
@JsonSerializable(nullable: false)
|
||||||
class YourLocation extends Object with _$YourLocationSerializerMixin {
|
class YourLocation {
|
||||||
@JsonKey(toJson: objectIdToJson, fromJson: objectIdFromJson)
|
@JsonKey(toJson: objectIdToJson, fromJson: objectIdFromJson)
|
||||||
ObjectId id;
|
ObjectId id;
|
||||||
final double lat;
|
final double lat;
|
||||||
|
|
@ -22,40 +20,33 @@ class YourLocation extends Object with _$YourLocationSerializerMixin {
|
||||||
_$YourLocationFromJson(json);
|
_$YourLocationFromJson(json);
|
||||||
|
|
||||||
static YourLocation noLocation = new YourLocation(lat: 0.0, lon: 0.0);
|
static YourLocation noLocation = new YourLocation(lat: 0.0, lon: 0.0);
|
||||||
static const int withoutStats = null;
|
static const int withoutStats = null;
|
||||||
YourLocation(
|
YourLocation(
|
||||||
{this.id,
|
{this.id,
|
||||||
@required this.lat,
|
@required this.lat,
|
||||||
@required this.lon,
|
@required this.lon,
|
||||||
this.description,
|
this.description,
|
||||||
this.distance: 10,
|
this.distance: 10,
|
||||||
int currentNumFires: withoutStats,
|
int currentNumFires: withoutStats,
|
||||||
this.subscribed: false}) {
|
this.subscribed: false}) {
|
||||||
if (this.description == null)
|
if (this.description == null)
|
||||||
this.description = 'Position: ${this.lat}, ${this.lon}';
|
this.description = 'Position: ${this.lat}, ${this.lon}';
|
||||||
if (this.id == null) this.id = new ObjectId();
|
if (this.id == null) this.id = new ObjectId();
|
||||||
}
|
}
|
||||||
|
Map<String, dynamic> toJson() => _$YourLocationToJson(this);
|
||||||
|
|
||||||
YourLocation copyWith(
|
YourLocation copyWith(
|
||||||
{id,
|
{id, lat, lon, description, distance, currentNumFires, subscribed}) {
|
||||||
lat,
|
|
||||||
lon,
|
|
||||||
description,
|
|
||||||
distance,
|
|
||||||
currentNumFires,
|
|
||||||
subscribed}) {
|
|
||||||
return new YourLocation(
|
return new YourLocation(
|
||||||
id: id?? this.id,
|
id: id ?? this.id,
|
||||||
lat: lat?? this.lat,
|
lat: lat ?? this.lat,
|
||||||
lon: lon?? this.lon,
|
lon: lon ?? this.lon,
|
||||||
description: description?? this.description,
|
description: description ?? this.description,
|
||||||
distance: distance?? this.distance,
|
distance: distance ?? this.distance,
|
||||||
currentNumFires: currentNumFires ?? this.currentNumFires,
|
currentNumFires: currentNumFires ?? this.currentNumFires,
|
||||||
subscribed: subscribed?? this.subscribed
|
subscribed: subscribed ?? this.subscribed);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
|
|
@ -66,7 +57,7 @@ static const int withoutStats = null;
|
||||||
lon == other.lon &&
|
lon == other.lon &&
|
||||||
description == other.description &&
|
description == other.description &&
|
||||||
subscribed == other.subscribed &&
|
subscribed == other.subscribed &&
|
||||||
currentNumFires == other.currentNumFires &&
|
currentNumFires == other.currentNumFires &&
|
||||||
distance == other.distance;
|
distance == other.distance;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// Copyright (c) 2018, Comunes Association.
|
|
||||||
|
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
part of 'yourLocation.dart';
|
part of 'yourLocation.dart';
|
||||||
|
|
@ -8,51 +6,29 @@ part of 'yourLocation.dart';
|
||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
YourLocation _$YourLocationFromJson(Map<String, dynamic> json) =>
|
YourLocation _$YourLocationFromJson(Map json) {
|
||||||
new YourLocation(
|
return $checkedNew('YourLocation', json, () {
|
||||||
id: objectIdFromJson(json['id'] as String),
|
final val = YourLocation(
|
||||||
lat: (json['lat'] as num).toDouble(),
|
id: $checkedConvert(json, 'id', (v) => objectIdFromJson(v as String)),
|
||||||
lon: (json['lon'] as num).toDouble(),
|
lat: $checkedConvert(json, 'lat', (v) => (v as num).toDouble()),
|
||||||
description: json['description'] as String,
|
lon: $checkedConvert(json, 'lon', (v) => (v as num).toDouble()),
|
||||||
distance: json['distance'] as int,
|
description: $checkedConvert(json, 'description', (v) => v as String),
|
||||||
subscribed: json['subscribed'] as bool);
|
distance: $checkedConvert(json, 'distance', (v) => v as int),
|
||||||
|
currentNumFires:
|
||||||
abstract class _$YourLocationSerializerMixin {
|
$checkedConvert(json, 'currentNumFires', (v) => v as int),
|
||||||
ObjectId get id;
|
subscribed: $checkedConvert(json, 'subscribed', (v) => v as bool),
|
||||||
double get lat;
|
);
|
||||||
double get lon;
|
return val;
|
||||||
String get description;
|
});
|
||||||
bool get subscribed;
|
|
||||||
int get distance;
|
|
||||||
Map<String, dynamic> toJson() => new _$YourLocationJsonMapWrapper(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _$YourLocationJsonMapWrapper extends $JsonMapWrapper {
|
Map<String, dynamic> _$YourLocationToJson(YourLocation instance) =>
|
||||||
final _$YourLocationSerializerMixin _v;
|
<String, dynamic>{
|
||||||
_$YourLocationJsonMapWrapper(this._v);
|
'id': objectIdToJson(instance.id),
|
||||||
|
'lat': instance.lat,
|
||||||
@override
|
'lon': instance.lon,
|
||||||
Iterable<String> get keys =>
|
'description': instance.description,
|
||||||
const ['id', 'lat', 'lon', 'description', 'subscribed', 'distance'];
|
'subscribed': instance.subscribed,
|
||||||
|
'distance': instance.distance,
|
||||||
@override
|
'currentNumFires': instance.currentNumFires,
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:fires_flutter/models/yourLocation.dart';
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
import 'package:comunes_flutter/comunes_flutter.dart';
|
||||||
|
import 'package:fires_flutter/models/yourLocation.dart';
|
||||||
|
|
||||||
import '../globals.dart' as globals;
|
import '../globals.dart' as globals;
|
||||||
|
|
||||||
final String locationKey = 'yourlocations';
|
final String locationKey = 'yourlocations';
|
||||||
|
|
@ -10,7 +11,7 @@ final String locationKey = 'yourlocations';
|
||||||
Future<List<YourLocation>> loadYourLocations() async {
|
Future<List<YourLocation>> loadYourLocations() async {
|
||||||
return await globals.prefs.then((prefs) {
|
return await globals.prefs.then((prefs) {
|
||||||
List<String> yourLocations = prefs.getStringList(locationKey);
|
List<String> yourLocations = prefs.getStringList(locationKey);
|
||||||
List<YourLocation> persistedList = List<YourLocation>();
|
List<YourLocation> persistedList = [];
|
||||||
if (yourLocations == null) {
|
if (yourLocations == null) {
|
||||||
yourLocations = [];
|
yourLocations = [];
|
||||||
// first run, init with empty list
|
// first run, init with empty list
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import 'package:bson_objectid/bson_objectid.dart';
|
import 'package:objectid/objectid.dart';
|
||||||
|
|
||||||
objectIdFromJson(String json) {
|
objectIdFromJson(String json) {
|
||||||
return new ObjectId.fromHexString(json);
|
return new ObjectId.fromHexString(
|
||||||
|
json.replaceFirst("ObjectId(", "").replaceAll(")", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
objectIdToJson(ObjectId o) {
|
objectIdToJson(ObjectId o) {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:fires_flutter/models/yourLocation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_google_places_autocomplete/flutter_google_places_autocomplete.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 'package:flutter_simple_dependency_injection/injector.dart';
|
||||||
|
|
||||||
|
import 'generated/i18n.dart';
|
||||||
|
|
||||||
Future<YourLocation> openPlacesDialog(GlobalKey<ScaffoldState> sc) async {
|
Future<YourLocation> openPlacesDialog(GlobalKey<ScaffoldState> sc) async {
|
||||||
Mode _mode = Mode.overlay;
|
Mode _mode = Mode.overlay;
|
||||||
String gmapKey = Injector.getInjector().get<String>(key: "gmapKey");
|
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,
|
hint: S.of(sc.currentContext).typeTheNameOfAPlace,
|
||||||
apiKey: gmapKey,
|
apiKey: gmapKey,
|
||||||
onError: (res) {
|
onError: (res) {
|
||||||
sc.currentState
|
ScaffoldMessenger.of(sc.currentContext)
|
||||||
.showSnackBar(new SnackBar(content: new Text(res.errorMessage)));
|
.showSnackBar(new SnackBar(content: new Text(res.errorMessage)));
|
||||||
print('Error $res');
|
print('Error $res');
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:bson_objectid/bson_objectid.dart';
|
|
||||||
import 'package:fires_flutter/models/fireNotification.dart';
|
import 'package:fires_flutter/models/fireNotification.dart';
|
||||||
import 'package:fires_flutter/models/yourLocation.dart';
|
import 'package:fires_flutter/models/yourLocation.dart';
|
||||||
import 'package:flutter_simple_dependency_injection/injector.dart';
|
import 'package:flutter_simple_dependency_injection/injector.dart';
|
||||||
import 'package:just_debounce_it/just_debounce_it.dart';
|
import 'package:just_debounce_it/just_debounce_it.dart';
|
||||||
|
import 'package:objectid/objectid.dart';
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
|
|
||||||
import '../models/appState.dart';
|
import '../models/appState.dart';
|
||||||
import '../models/fireNotificationsPersist.dart';
|
import '../models/fireNotificationsPersist.dart';
|
||||||
import '../models/firesApi.dart';
|
import '../models/firesApi.dart';
|
||||||
import '../models/yourLocationPersist.dart';
|
import '../models/yourLocationPersist.dart';
|
||||||
|
import '../objectIdUtils.dart';
|
||||||
import 'actions.dart';
|
import 'actions.dart';
|
||||||
|
|
||||||
// A middleware takes in 3 parameters: your Store, which you can use to
|
// 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) {
|
.then((List<YourLocation> subscribedLocations) {
|
||||||
// If it succeeds, dispatch a success action with the YourLocations.
|
// If it succeeds, dispatch a success action with the YourLocations.
|
||||||
// Our reducer will then update the State using these 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) {
|
if (subscribedLocations is List) {
|
||||||
// unsubscribe all locally to sync the subs state
|
// unsubscribe all locally to sync the subs state
|
||||||
localLocations.forEach((location) => location.subscribed = false);
|
localLocations.forEach((location) => location.subscribed = false);
|
||||||
// print('Local persisted: ${localLocations.length}');
|
print('Local persisted: ${localLocations.length}');
|
||||||
subscribedLocations.forEach((subsLoc) {
|
subscribedLocations.forEach((subsLoc) {
|
||||||
localLocations.firstWhere(
|
var locSubs = localLocations.firstWhere(
|
||||||
(localLocation) => localLocation.id == subsLoc.id, orElse: () {
|
(localLocation) => localLocation.id == subsLoc.id, orElse: () {
|
||||||
localLocations.add(subsLoc);
|
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) {
|
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();
|
onUnsubs();
|
||||||
persistYourLocations(store.state.yourLocations);
|
persistYourLocations(store.state.yourLocations);
|
||||||
});
|
});
|
||||||
|
|
@ -260,9 +263,9 @@ void unsubsViaApi(Store<AppState> store, ObjectId id, onUnsubs) {
|
||||||
void subscribeViaApi(Store<AppState> store, YourLocation loc, onSubs) {
|
void subscribeViaApi(Store<AppState> store, YourLocation loc, onSubs) {
|
||||||
api.subscribe(store.state, loc).then((subsId) {
|
api.subscribe(store.state, loc).then((subsId) {
|
||||||
YourLocation sub = loc;
|
YourLocation sub = loc;
|
||||||
if (loc.id != subsId) {
|
// if (loc.id != subsId) {
|
||||||
sub.id = new ObjectId.fromHexString(subsId);
|
sub.id = objectIdFromJson(subsId);
|
||||||
}
|
// }
|
||||||
onSubs(sub);
|
onSubs(sub);
|
||||||
persistYourLocations(store.state.yourLocations);
|
persistYourLocations(store.state.yourLocations);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ List<FireNotification> _deletedFireNotification(
|
||||||
}
|
}
|
||||||
|
|
||||||
List<FireNotification> _updatedFireNotification(
|
List<FireNotification> _updatedFireNotification(
|
||||||
List<FireNotification> notifications, UpdatedFireNotificationAction action) {
|
List<FireNotification> notifications,
|
||||||
|
UpdatedFireNotificationAction action) {
|
||||||
return notifications
|
return notifications
|
||||||
.map((notif) => notif.id == action.notif.id ? action.notif : notif)
|
.map((notif) => notif.id == action.notif.id ? action.notif : notif)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
@ -45,5 +46,5 @@ List<FireNotification> _readedFireNotification(
|
||||||
List<FireNotification> _deletedAllFireNotifications(
|
List<FireNotification> _deletedAllFireNotifications(
|
||||||
List<FireNotification> notifications,
|
List<FireNotification> notifications,
|
||||||
DeletedAllFireNotificationAction action) {
|
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:fires_flutter/models/yourLocation.dart';
|
||||||
|
import 'package:objectid/objectid.dart';
|
||||||
|
|
||||||
abstract class YourLocationActions {}
|
abstract class YourLocationActions {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ ThemeData _buildFiresTheme() {
|
||||||
buttonColor: fires900,
|
buttonColor: fires900,
|
||||||
scaffoldBackgroundColor: firesSurfaceWhite,
|
scaffoldBackgroundColor: firesSurfaceWhite,
|
||||||
cardColor: firesBackgroundWhite,
|
cardColor: firesBackgroundWhite,
|
||||||
textSelectionColor: fires300,
|
textSelectionTheme: TextSelectionThemeData(selectionColor: fires300),
|
||||||
errorColor: firesErrorRed,
|
errorColor: firesErrorRed,
|
||||||
|
|
||||||
//TODO: Add the text themes (103)
|
//TODO: Add the text themes (103)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ ThemeData _buildFiresTheme() {
|
||||||
buttonColor: fires900,
|
buttonColor: fires900,
|
||||||
scaffoldBackgroundColor: firesSurfaceWhite,
|
scaffoldBackgroundColor: firesSurfaceWhite,
|
||||||
cardColor: firesBackgroundWhite,
|
cardColor: firesBackgroundWhite,
|
||||||
textSelectionColor: fires300,
|
textSelectionTheme: TextSelectionThemeData(selectionColor: fires300),
|
||||||
errorColor: firesErrorRed,
|
errorColor: firesErrorRed,
|
||||||
|
|
||||||
//TODO: Add the text themes (103)
|
//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:comunes_flutter/comunes_flutter.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_map/plugin_api.dart';
|
||||||
|
|
||||||
class ZoomMapPluginOptions extends LayerOptions {
|
class ZoomMapPluginOptions extends LayerOptions {
|
||||||
final String text;
|
final String text;
|
||||||
|
|
@ -22,7 +21,8 @@ class ZoomMapPlugin extends MapPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget createLayer(LayerOptions options, MapState mapState) {
|
Widget createLayer(
|
||||||
|
LayerOptions options, MapState mapState, Stream<Null> stream) {
|
||||||
if (options is ZoomMapPluginOptions) {
|
if (options is ZoomMapPluginOptions) {
|
||||||
/* print('point ${mapState
|
/* print('point ${mapState
|
||||||
.getPixelBounds(mapState.zoom)
|
.getPixelBounds(mapState.zoom)
|
||||||
|
|
|
||||||
54
pubspec.yaml
54
pubspec.yaml
|
|
@ -1,39 +1,42 @@
|
||||||
name: fires_flutter
|
name: fires_flutter
|
||||||
description: All Against Fire
|
description: All Against Fire
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ">=2.7.0 <3.0.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
# i18n
|
# i18n
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
intl: "^0.15.6"
|
intl: "^0.16.1"
|
||||||
|
|
||||||
# https://pub.dartlang.org/packages/flutter
|
# https://pub.dartlang.org/packages/flutter
|
||||||
|
|
||||||
# utils
|
# utils
|
||||||
simple_moment: "^0.0.3"
|
simple_moment: "^1.0.7"
|
||||||
just_debounce_it: "^1.0.4"
|
just_debounce_it: "^3.0.0+2"
|
||||||
flutter_simple_dependency_injection: "^0.0.2"
|
flutter_simple_dependency_injection: "^0.0.2"
|
||||||
sentry: "^2.0.2"
|
sentry: "^2.0.2"
|
||||||
flutter_markdown: "^0.1.5"
|
flutter_markdown: "^0.5.1"
|
||||||
url_launcher: "^3.0.2"
|
url_launcher: "^5.7.10"
|
||||||
package_info: "^0.3.2"
|
package_info: ^0.4.3+2
|
||||||
launch_review: "^1.0.1"
|
launch_review: "^1.0.1"
|
||||||
|
|
||||||
# net
|
# net
|
||||||
http: "^0.11.3+16"
|
http: "^0.11.3+16"
|
||||||
jaguar_resty: "^2.5.5"
|
jaguar_resty: "^2.5.5"
|
||||||
connectivity: "^0.3.1"
|
connectivity: ^2.0.2
|
||||||
share: "^0.5.2"
|
share: "^0.5.2"
|
||||||
|
|
||||||
# data
|
# data
|
||||||
json_annotation: "^0.2.3"
|
json_annotation: "^3.1.1"
|
||||||
shared_preferences: "^0.4.2"
|
shared_preferences: "^0.4.2"
|
||||||
bson_objectid: "^0.1.0"
|
# bson_objectid: "^0.1.0
|
||||||
|
objectid: 1.1.0
|
||||||
comunes_flutter:
|
comunes_flutter:
|
||||||
git: git@github.com:comunes/comunes-flutter.git
|
#git: git@github.com:comunes/comunes-flutter.git
|
||||||
# path: /home/vjrj/dev/comunes_flutter
|
path: /home/vjrj/dev/comunes_flutter
|
||||||
# version: "^0.0.12"
|
# version: "^0.0.12"
|
||||||
|
|
||||||
# redux
|
# redux
|
||||||
|
|
@ -42,33 +45,36 @@ dependencies:
|
||||||
redux_logging: "^0.3.0"
|
redux_logging: "^0.3.0"
|
||||||
|
|
||||||
# maps, geo, etc
|
# maps, geo, etc
|
||||||
flutter_map: "^0.0.10"
|
flutter_map: ^0.10.1+1
|
||||||
flutter_google_places_autocomplete: "^0.0.4"
|
flutter_google_places_autocomplete: "^0.1.3"
|
||||||
location: "^1.3.4"
|
location: ^3.2.1
|
||||||
geocoder: "^0.0.1"
|
geocoder: "^0.2.1"
|
||||||
|
|
||||||
# layout
|
# layout
|
||||||
fluttery: "^0.0.7"
|
# fluttery: "^0.0.7"
|
||||||
# https://pub.dartlang.org/packages/padder
|
# https://pub.dartlang.org/packages/padder
|
||||||
padder: "^1.0.1"
|
padder: "^1.0.1"
|
||||||
flutter_fab_dialer: "^0.0.5"
|
flutter_fab_dialer: "^0.0.5"
|
||||||
badge: "^0.0.2"
|
# badge: "^0.0.2"
|
||||||
|
badges: ^1.1.6
|
||||||
flutter_spinkit: "^1.0.0"
|
flutter_spinkit: "^1.0.0"
|
||||||
|
|
||||||
# firebase
|
# firebase
|
||||||
firebase_messaging: "^1.0.4"
|
firebase_core: ^0.5.3
|
||||||
|
firebase_messaging: ^7.0.3
|
||||||
|
|
||||||
# icons
|
# icons
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: "^0.1.2"
|
cupertino_icons: "^0.1.2"
|
||||||
community_material_icon: "^0.1.2"
|
community_material_icon: "^5.4.55"
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
build_runner: ^0.8.0
|
build_runner: "^1.0.0"
|
||||||
json_serializable: ^0.5.0
|
json_serializable: ^3.5.1
|
||||||
|
test: ^1.15.7
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://www.dartlang.org/tools/pub/pubspec
|
# following page: https://www.dartlang.org/tools/pub/pubspec
|
||||||
|
|
@ -119,3 +125,7 @@ flutter:
|
||||||
#
|
#
|
||||||
# For details regarding fonts from package dependencies,
|
# For details regarding fonts from package dependencies,
|
||||||
# see https://flutter.io/custom-fonts/#from-packages
|
# see https://flutter.io/custom-fonts/#from-packages
|
||||||
|
|
||||||
|
# https://github.com/flutter/flutter/issues/70433
|
||||||
|
dependency_overrides:
|
||||||
|
intl: ^0.17.0-nullsafety.2
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue