From c9941429f04e6f506e904429d9deb82914615f94 Mon Sep 17 00:00:00 2001 From: vjrj Date: Wed, 27 Jun 2018 08:22:00 +0200 Subject: [PATCH] YourLocation and some persist work --- README.md | 1 + build.yaml | 28 ++++++++++++ lib/activeFires.dart | 54 ++++++++-------------- lib/basicLocation.dart | 9 +--- lib/genericMap.dart | 9 ++-- lib/globals.dart | 18 ++++---- lib/homePage.dart | 2 +- lib/locationUtils.dart | 20 ++++---- lib/mainCommon.dart | 17 +++---- lib/placesAutocompleteUtils.dart | 22 +++++---- lib/yourLocation.dart | 78 ++++++++++++++++++++++++++++++++ lib/yourLocation.g.dart | 54 ++++++++++++++++++++++ pubspec.yaml | 13 ++++-- 13 files changed, 240 insertions(+), 85 deletions(-) create mode 100644 build.yaml create mode 100644 lib/yourLocation.dart create mode 100644 lib/yourLocation.g.dart diff --git a/README.md b/README.md index 84c5687..298dbf5 100644 --- a/README.md +++ b/README.md @@ -13,3 +13,4 @@ For help getting started with Flutter, view our online - private keys in assets flutter pub pub run intl_translation:extract_to_arb --output-dir=lib/l10n lib/i18n.dart flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/i18n.dart lib/l10n/intl_*.arb +flutter packages pub run build_runner build diff --git a/build.yaml b/build.yaml new file mode 100644 index 0000000..3c7137f --- /dev/null +++ b/build.yaml @@ -0,0 +1,28 @@ +targets: + $default: + builders: + json_serializable: + options: + # Specifies a string to add to the top of every generated file. + # + # If not specified, the default is the value of `defaultFileHeader` + # defined in `package:source_gen/source_gen.dart`. + # + # Note: use `|` to define a multi-line block. + header: | + // Copyright (c) 2018, Comunes Association. + + // GENERATED CODE - DO NOT MODIFY BY HAND + + # Options configure how source code is generated for every + # `@JsonSerializable`-annotated class in the package. + # + # The default value for each of them: `false`. + # + # For usage information, reference the corresponding field in + # `JsonSerializableGenerator`. + use_wrappers: true + any_map: true + checked: true + explicit_to_json: true + generate_to_json_function: true diff --git a/lib/activeFires.dart b/lib/activeFires.dart index 673cf98..40dd599 100644 --- a/lib/activeFires.dart +++ b/lib/activeFires.dart @@ -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 { _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 { }); } - void showLocationMap(BasicLocation loc) { + void showLocationMap(YourLocation loc) { // , VoidCallback onSubs Navigator.push( context, @@ -94,32 +96,17 @@ class _ActiveFiresPageState extends State { 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 { 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 { new RoundedBtn( icon: Icons.edit_location, text: S.of(context).firesNearPlace, - onPressed: () { - onAddOtherLocation(); - }, + onPressed: onAddOtherLocation, backColor: fires600), ])), ); } void onAddYourLocation() { - Future location = getUserLocation(_scaffoldKey); + Future location = getUserLocation(_scaffoldKey); _saveLocation(location); } void onAddOtherLocation() { - Future location = openPlacesDialog(_scaffoldKey); + Future location = openPlacesDialog(_scaffoldKey); _saveLocation(location); } - void _saveLocation(Future location) { + void _saveLocation(Future 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); }); diff --git a/lib/basicLocation.dart b/lib/basicLocation.dart index c5f4a43..c7fe60d 100644 --- a/lib/basicLocation.dart +++ b/lib/basicLocation.dart @@ -4,11 +4,10 @@ class BasicLocation extends Comparable { 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 { return hash; } - bool get isSubscribed { - return subscribed == null ? false : subscribed; - } - BasicLocation.fromJson(Map json) : lat = json['lat'], lon = json['lon'], diff --git a/lib/genericMap.dart b/lib/genericMap.dart index 23673f1..bae5959 100644 --- a/lib/genericMap.dart +++ b/lib/genericMap.dart @@ -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 { final GlobalKey _scaffoldKey = new GlobalKey(); 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 { )); } - List buildMarkers(BasicLocation yourLocation, List fires, + List buildMarkers(YourLocation yourLocation, List fires, List falsePos, List industries) { List markers = []; const calibrate = false; // useful when we change the fire icons size diff --git a/lib/globals.dart b/lib/globals.dart index 003cab4..aa5f397 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -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 prefs = SharedPreferences.getInstance(); -final List 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 prefs = SharedPreferences.getInstance(); +List yourLocations = []; final GetIt getIt = new GetIt(); bool isDevelopment = false; diff --git a/lib/homePage.dart b/lib/homePage.dart index fcba053..6451499 100644 --- a/lib/homePage.dart +++ b/lib/homePage.dart @@ -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( diff --git a/lib/locationUtils.dart b/lib/locationUtils.dart index fa6bdd8..e2b41da 100644 --- a/lib/locationUtils.dart +++ b/lib/locationUtils.dart @@ -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 getUserLocation( +Future getUserLocation( GlobalKey scaffoldKey) async { // Platform messages may fail, so we use a try/catch PlatformException. try { @@ -15,21 +15,21 @@ Future getUserLocation( Map 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 getUserLocation( content: new Text(S.of(scaffoldKey.currentContext).isYourUbicationEnabled ), )); - return BasicLocation.noLocation; + return YourLocation.noLocation; } } -Future getReverseLocation(BasicLocation loc, +Future getReverseLocation(YourLocation loc, [bool external = false]) async { final coordinates = new Coordinates(loc.lat, loc.lon); var geoCoder = external ? Geocoder.google(globals.gmapKey) : Geocoder.local; diff --git a/lib/mainCommon.dart b/lib/mainCommon.dart index f6253f2..cad64c2 100644 --- a/lib/mainCommon.dart +++ b/lib/mainCommon.dart @@ -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> 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! diff --git a/lib/placesAutocompleteUtils.dart b/lib/placesAutocompleteUtils.dart index cf7ce2d..7cc8c52 100644 --- a/lib/placesAutocompleteUtils.dart +++ b/lib/placesAutocompleteUtils.dart @@ -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 openPlacesDialog(GlobalKey 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 openPlacesDialog(GlobalKey sc) async { Mode _mode = Mode.overlay; GoogleMapsPlaces _places = new GoogleMapsPlaces(globals.gmapKey); Prediction p = await showGooglePlacesAutocomplete( @@ -13,8 +15,8 @@ Future openPlacesDialog(GlobalKey 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 openPlacesDialog(GlobalKey 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; } diff --git a/lib/yourLocation.dart b/lib/yourLocation.dart new file mode 100644 index 0000000..6bca1c3 --- /dev/null +++ b/lib/yourLocation.dart @@ -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 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 { + + 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()); + } +} diff --git a/lib/yourLocation.g.dart b/lib/yourLocation.g.dart new file mode 100644 index 0000000..a5688b3 --- /dev/null +++ b/lib/yourLocation.g.dart @@ -0,0 +1,54 @@ +// Copyright (c) 2018, Comunes Association. + +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'yourLocation.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +YourLocation _$YourLocationFromJson(Map 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 toJson() => new _$YourLocationJsonMapWrapper(this); +} + +class _$YourLocationJsonMapWrapper extends $JsonMapWrapper { + final _$YourLocationSerializerMixin _v; + _$YourLocationJsonMapWrapper(this._v); + + @override + Iterable 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; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index ffc4766..6d7750e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,10 +12,16 @@ dependencies: # https://pub.dartlang.org/packages/flutter # utils - shared_preferences: "^0.4.2" - http: "^0.11.3+16" simple_moment: "^0.0.3" just_debounce_it: "^1.0.4" + # net + http: "^0.11.3+16" + jaguar_resty: "^2.5.5" + # data + json_annotation: ^0.2.3 + shared_preferences: "^0.4.2" + pref_dessert: "^0.0.2" + bson_objectid: "^0.1.0" comunes_flutter: path: /home/vjrj/dev/comunes_flutter version: "^0.0.10" @@ -46,7 +52,8 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - + build_runner: ^0.8.0 + json_serializable: ^0.5.0 # For information on the generic Dart part of this file, see the # following page: https://www.dartlang.org/tools/pub/pubspec