YourLocation and some persist work

This commit is contained in:
vjrj 2018-06-27 08:22:00 +02:00
parent 6488957148
commit c9941429f0
13 changed files with 240 additions and 85 deletions

View file

@ -4,8 +4,6 @@ import 'package:comunes_flutter/comunes_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_fab_dialer/flutter_fab_dialer.dart';
import 'basicLocation.dart';
import 'basicLocationPersist.dart';
import 'colors.dart';
import 'generated/i18n.dart';
import 'genericMap.dart';
@ -14,6 +12,7 @@ import 'globals.dart' as globals;
import 'locationUtils.dart';
import 'mainDrawer.dart';
import 'placesAutocompleteUtils.dart';
import 'yourLocation.dart';
class ActiveFiresPage extends StatefulWidget {
static const String routeName = '/fires';
@ -50,17 +49,20 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
_ActiveFiresPageState();
Widget _buildRow(BasicLocation loc) {
Widget _buildRow(YourLocation loc) {
return new ListTile(
dense: true,
leading: const Icon(Icons.location_on),
trailing: new IconButton(
icon: new Icon(loc.isSubscribed
icon: new Icon(loc.subscribed
? Icons.notifications_active
: Icons.notifications_off),
onPressed: () {
loc.subscribed = !loc.isSubscribed;
persistYourLocations();
loc.subscribed = !loc.subscribed;
int i = globals.yourLocations.indexOf(loc);
YourLocationRepository.repo.update(i, loc);
globals.yourLocations.removeAt(i);
globals.yourLocations.insert(i, loc);
setState(() {});
}),
title: new Text(loc.description),
@ -72,7 +74,7 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
});
}
void showLocationMap(BasicLocation loc) {
void showLocationMap(YourLocation loc) {
// , VoidCallback onSubs
Navigator.push(
context,
@ -94,32 +96,17 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
padding: const EdgeInsets.all(16.0),
itemCount: globals.yourLocations.length,
itemBuilder: (BuildContext _context, int i) {
// Add a one-pixel-high divider widget before each row
// in the ListView.
/* if (i.isOdd) {
return new Divider();
} */
// The syntax "i ~/ 2" divides i by 2 and returns an
// integer result.
// For example: 1, 2, 3, 4, 5 becomes 0, 1, 1, 2, 2.
// This calculates the actual number of saved items
// in the ListView, minus the divider widgets.
// final int index = i ~/ 2;
// print('$i $index');
// if (index >= _saved.length) return null;
return _buildItem(globals.yourLocations.elementAt(i));
});
}
void handleUndo(BasicLocation item) {
void handleUndo(YourLocation item) {
setState(() {
globals.yourLocations.add(item);
persistYourLocations();
YourLocationRepository.repo.save(item);
});
}
Widget _buildItem(BasicLocation item) {
Widget _buildItem(YourLocation item) {
final ThemeData theme = Theme.of(context);
return new Dismissible(
key: new ObjectKey(item),
@ -127,7 +114,8 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
onDismissed: (DismissDirection direction) {
setState(() {
globals.yourLocations.remove(item);
persistYourLocations();
int i = globals.yourLocations.indexOf(item);
YourLocationRepository.repo.remove(i);
});
_scaffoldKey.currentState.showSnackBar(new SnackBar(
@ -195,33 +183,31 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
new RoundedBtn(
icon: Icons.edit_location,
text: S.of(context).firesNearPlace,
onPressed: () {
onAddOtherLocation();
},
onPressed: onAddOtherLocation,
backColor: fires600),
])),
);
}
void onAddYourLocation() {
Future<BasicLocation> location = getUserLocation(_scaffoldKey);
Future<YourLocation> location = getUserLocation(_scaffoldKey);
_saveLocation(location);
}
void onAddOtherLocation() {
Future<BasicLocation> location = openPlacesDialog(_scaffoldKey);
Future<YourLocation> location = openPlacesDialog(_scaffoldKey);
_saveLocation(location);
}
void _saveLocation(Future<BasicLocation> location) {
void _saveLocation(Future<YourLocation> location) {
location.then((newLocation) {
if (newLocation != BasicLocation.noLocation) {
if (newLocation != YourLocation.noLocation) {
if (globals.yourLocations.contains(newLocation)) {
showSnackMsg(S.of(context).addedThisLocation);
} else
this.setState(() {
globals.yourLocations.add(newLocation);
persistYourLocations();
YourLocationRepository.repo.save(newLocation);
new Timer(new Duration(milliseconds: 1000), () {
showLocationMap(newLocation);
});

View file

@ -4,11 +4,10 @@ class BasicLocation extends Comparable<BasicLocation> {
final double lat;
final double lon;
String description;
bool subscribed;
static BasicLocation noLocation = new BasicLocation(lat: 0.0, lon: 0.0);
// static BasicLocation noLocation = new BasicLocation(lat: 0.0, lon: 0.0);
BasicLocation({@required this.lat, @required this.lon, this.description, this.subscribed: false}) {
BasicLocation({@required this.lat, @required this.lon, this.description}) {
if (this.description == null)
this.description = 'Position: ${this.lat}, ${this.lon}';
}
@ -26,10 +25,6 @@ class BasicLocation extends Comparable<BasicLocation> {
return hash;
}
bool get isSubscribed {
return subscribed == null ? false : subscribed;
}
BasicLocation.fromJson(Map<String, dynamic> json)
: lat = json['lat'],
lon = json['lon'],

View file

@ -10,7 +10,7 @@ import 'package:http/http.dart' as http;
import 'package:just_debounce_it/just_debounce_it.dart';
import 'package:latlong/latlong.dart';
import 'basicLocation.dart';
import 'yourLocation.dart';
import 'colors.dart';
import 'customBottomAppBar.dart';
import 'dummyMapPlugin.dart';
@ -20,11 +20,12 @@ import 'generated/i18n.dart';
import 'globals.dart' as globals;
import 'slider.dart';
import 'zoomMapPlugin.dart';
import 'basicLocation.dart';
enum MapOperation { view, subscriptionConfirm, unsubscribe }
class GenericMap extends StatefulWidget {
final BasicLocation location;
final YourLocation location;
final String title;
final MapOperation operation;
@ -42,7 +43,7 @@ class _GenericMapState extends State<GenericMap> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final FirebaseMessaging _firebaseMessaging = new FirebaseMessaging();
final BasicLocation location;
final YourLocation location;
final String title;
int numFires;
int kmAround = 100;
@ -220,7 +221,7 @@ class _GenericMapState extends State<GenericMap> {
));
}
List<Marker> buildMarkers(BasicLocation yourLocation, List<dynamic> fires,
List<Marker> buildMarkers(YourLocation yourLocation, List<dynamic> fires,
List<dynamic> falsePos, List<dynamic> industries) {
List<Marker> markers = [];
const calibrate = false; // useful when we change the fire icons size

View file

@ -1,18 +1,20 @@
library fires.globals;
import 'package:get_it/get_it.dart';
import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';
import 'basicLocation.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'yourLocation.dart';
String gmapKey;
String firesApiKey;
String firesApiUrl;
final String appVersion = '0.0.1';
final Widget appMediumIcon = Image.asset('images/logo-200.png', width: 60.0, height: 60.0);
final Widget appIcon = Image.asset('images/logo-200.png', width: 24.0, height: 24.0);
final Future<SharedPreferences> prefs = SharedPreferences.getInstance();
final List<BasicLocation> yourLocations = [];
final Widget appMediumIcon =
Image.asset('images/logo-200.png', width: 60.0, height: 60.0);
final Widget appIcon =
Image.asset('images/logo-200.png', width: 24.0, height: 24.0);
// final Future<SharedPreferences> prefs = SharedPreferences.getInstance();
List<YourLocation> yourLocations = [];
final GetIt getIt = new GetIt();
bool isDevelopment = false;

View file

@ -37,7 +37,7 @@ class HomePage extends StatelessWidget {
new Expanded(
child: new FractionallySizedBox(
alignment: FractionalOffset.center,
heightFactor: 0.8,
heightFactor: 0.7,
child: new Image.asset('images/logo-200.png',
fit: BoxFit.fitHeight))),
new Expanded(

View file

@ -1,13 +1,13 @@
import 'package:location/location.dart';
import 'package:flutter/services.dart';
import 'dart:async';
import 'basicLocation.dart';
import 'yourLocation.dart';
import 'package:flutter/material.dart';
import 'package:geocoder/geocoder.dart';
import 'globals.dart' as globals;
import 'generated/i18n.dart';
Future<BasicLocation> getUserLocation(
Future<YourLocation> getUserLocation(
GlobalKey<ScaffoldState> scaffoldKey) async {
// Platform messages may fail, so we use a try/catch PlatformException.
try {
@ -15,21 +15,21 @@ Future<BasicLocation> getUserLocation(
Map<String, double> location = await _location.getLocation;
// It seems that the lib fails with lat/lon values
var basicLocation = new BasicLocation(
var yourLocation = new YourLocation(
lat: location['latitude'], lon: location['longitude']);
var address;
try {
address = await getReverseLocation(basicLocation);
basicLocation.description = address;
address = await getReverseLocation(yourLocation);
yourLocation.description = address;
} catch (e) {
try {
address = await getReverseLocation(basicLocation, true);
basicLocation.description = address;
address = await getReverseLocation(yourLocation, true);
yourLocation.description = address;
} catch (e) {
print('We cannot reverse geolocate');
}
}
return basicLocation;
return yourLocation;
} on PlatformException catch (e) {
if (e.code == 'PERMISSION_DENIED') {
scaffoldKey.currentState.showSnackBar(new SnackBar(
@ -40,11 +40,11 @@ Future<BasicLocation> getUserLocation(
content: new Text(S.of(scaffoldKey.currentContext).isYourUbicationEnabled
),
));
return BasicLocation.noLocation;
return YourLocation.noLocation;
}
}
Future<String> getReverseLocation(BasicLocation loc,
Future<String> getReverseLocation(YourLocation loc,
[bool external = false]) async {
final coordinates = new Coordinates(loc.lat, loc.lon);
var geoCoder = external ? Geocoder.google(globals.gmapKey) : Geocoder.local;

View file

@ -1,12 +1,12 @@
import 'package:flutter/material.dart';
import 'firesApp.dart';
import 'dart:async';
import 'package:comunes_flutter/comunes_flutter.dart';
import 'dart:async';
import 'globals.dart' as globals;
import 'basicLocationPersist.dart';
import 'firebaseMessagingConf.dart';
import 'package:flutter/material.dart';
import 'firebaseMessagingConf.dart';
import 'firesApp.dart';
import 'globals.dart' as globals;
import 'yourLocation.dart';
Future<Map<String, dynamic>> loadSecrets() async {
return await SecretLoader(secretPath: 'assets/private-settings.json').load();
}
@ -16,8 +16,9 @@ void mainCommon() {
globals.gmapKey = secrets['gmapKey'];
globals.firesApiKey = secrets['firesApiKey'];
globals.firesApiUrl = secrets['firesApiUrl'] + "api/v1/";
globals.prefs.then((prefs) {
loadYourLocationsWithPrefs(prefs);
YourLocationRepository.repo.remove(0);
YourLocationRepository.repo.getAll().then((yourLocations) {
globals.yourLocations = yourLocations;
firebaseConfig();
// Run baby run!

View file

@ -1,11 +1,13 @@
import 'package:flutter_google_places_autocomplete/flutter_google_places_autocomplete.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'basicLocation.dart';
import 'globals.dart' as globals;
import 'generated/i18n.dart';
Future<BasicLocation> openPlacesDialog(GlobalKey<ScaffoldState> sc) async {
import 'package:flutter/material.dart';
import 'package:flutter_google_places_autocomplete/flutter_google_places_autocomplete.dart';
import 'yourLocation.dart';
import 'generated/i18n.dart';
import 'globals.dart' as globals;
Future<YourLocation> openPlacesDialog(GlobalKey<ScaffoldState> sc) async {
Mode _mode = Mode.overlay;
GoogleMapsPlaces _places = new GoogleMapsPlaces(globals.gmapKey);
Prediction p = await showGooglePlacesAutocomplete(
@ -13,8 +15,8 @@ Future<BasicLocation> openPlacesDialog(GlobalKey<ScaffoldState> sc) async {
hint: S.of(sc.currentContext).typeTheNameOfAPlace,
apiKey: globals.gmapKey,
onError: (res) {
/* sc.currentState.showSnackBar(
new SnackBar(content: new Text(res.errorMessage))); */
sc.currentState
.showSnackBar(new SnackBar(content: new Text(res.errorMessage)));
print('Error $res');
},
mode: _mode,
@ -28,7 +30,7 @@ Future<BasicLocation> openPlacesDialog(GlobalKey<ScaffoldState> sc) async {
PlacesDetailsResponse detail = await _places.getDetailsByPlaceId(p.placeId);
final lat = detail.result.geometry.location.lat;
final lng = detail.result.geometry.location.lng;
return new BasicLocation(lat: lat, lon: lng, description: p.description);
return new YourLocation(lat: lat, lon: lng, description: p.description);
}
return BasicLocation.noLocation;
return YourLocation.noLocation;
}

78
lib/yourLocation.dart Normal file
View file

@ -0,0 +1,78 @@
import 'package:bson_objectid/bson_objectid.dart';
import 'package:flutter/material.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:pref_dessert/pref_dessert.dart';
import 'dart:convert';
part 'yourLocation.g.dart';
_objectIdFromJson(String json) {
return new ObjectId.fromHexString(json);
}
_objectIdToJson(ObjectId o) {
return o.toString();
}
@JsonSerializable(nullable: false)
class YourLocation extends Object with _$YourLocationSerializerMixin {
@JsonKey(toJson: _objectIdToJson, fromJson: _objectIdFromJson)
ObjectId id;
final double lat;
final double lon;
String description;
bool subscribed;
factory YourLocation.fromJson(Map<String, dynamic> json) =>
_$YourLocationFromJson(json);
static YourLocation noLocation = new YourLocation(lat: 0.0, lon: 0.0);
YourLocation(
{this.id,
@required this.lat,
@required this.lon,
this.description,
this.subscribed: false}) {
if (this.description == null)
this.description = 'Position: ${this.lat}, ${this.lon}';
if (this.id == null) this.id = new ObjectId();
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is YourLocation &&
runtimeType == other.runtimeType &&
id == other.id &&
lat == other.lat &&
lon == other.lon &&
description == other.description &&
subscribed == other.subscribed;
@override
int get hashCode =>
id.hashCode ^
lat.hashCode ^
lon.hashCode ^
description.hashCode ^
subscribed.hashCode;
}
class YourLocationRepository extends PreferencesRepository<YourLocation> {
static final repo = new YourLocationRepository();
YourLocationRepository() : super();
@override
YourLocation deserialize(String s) {
return YourLocation.fromJson(json.decode(s));
}
@override
String serialize(YourLocation y) {
return json.encode(y.toJson());
}
}

54
lib/yourLocation.g.dart Normal file
View file

@ -0,0 +1,54 @@
// Copyright (c) 2018, Comunes Association.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'yourLocation.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
YourLocation _$YourLocationFromJson(Map<String, dynamic> json) =>
new YourLocation(
id: _objectIdFromJson(json['id'] as String),
lat: (json['lat'] as num).toDouble(),
lon: (json['lon'] as num).toDouble(),
description: json['description'] as String,
subscribed: json['subscribed'] as bool);
abstract class _$YourLocationSerializerMixin {
ObjectId get id;
double get lat;
double get lon;
String get description;
bool get subscribed;
Map<String, dynamic> toJson() => new _$YourLocationJsonMapWrapper(this);
}
class _$YourLocationJsonMapWrapper extends $JsonMapWrapper {
final _$YourLocationSerializerMixin _v;
_$YourLocationJsonMapWrapper(this._v);
@override
Iterable<String> get keys =>
const ['id', 'lat', 'lon', 'description', 'subscribed'];
@override
dynamic operator [](Object key) {
if (key is String) {
switch (key) {
case 'id':
return _objectIdToJson(_v.id);
case 'lat':
return _v.lat;
case 'lon':
return _v.lon;
case 'description':
return _v.description;
case 'subscribed':
return _v.subscribed;
}
}
return null;
}
}