From 65068dd5579cdfe1c0441c14ef6b16198db08efd Mon Sep 17 00:00:00 2001 From: Pablo Galve Date: Fri, 5 Nov 2021 13:29:06 +0100 Subject: [PATCH 1/4] Remove location from location history list --- Space_Mapper/lib/models/list_view.dart | 13 ++ Space_Mapper/lib/ui/list_view.dart | 163 +++++++++---------------- 2 files changed, 72 insertions(+), 104 deletions(-) diff --git a/Space_Mapper/lib/models/list_view.dart b/Space_Mapper/lib/models/list_view.dart index fcf4621a..d4494b13 100644 --- a/Space_Mapper/lib/models/list_view.dart +++ b/Space_Mapper/lib/models/list_view.dart @@ -1,4 +1,6 @@ import 'package:collection/collection.dart'; +import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' + as bg; class CustomLocationsManager { static List customLocations = []; @@ -31,6 +33,7 @@ class CustomLocation { late num _speedAccuracy = -1; //in meters / second late num _altitude = -1; //in meters late num _altitudeAccuracy = -1; // in meters + late bool to_delete = false; /// Makes timestamp readable by a human String formatTimestamp(String timestamp) { @@ -64,6 +67,16 @@ class CustomLocation { return ret; } + Future deleteThisLocation() async { + if (to_delete == false) { + /// We need this checker to ensure that the user doesn't send the delete request twice, causing an exception + to_delete = true; + await bg.BackgroundGeolocation.destroyLocation(this.getUUID()); + CustomLocationsManager.customLocations + .removeWhere((element) => element.getUUID() == this.getUUID()); + } + } + // Variable setters void setUUID(String uuid) { _uuid = uuid; diff --git a/Space_Mapper/lib/ui/list_view.dart b/Space_Mapper/lib/ui/list_view.dart index 611c5e48..d3ae0198 100644 --- a/Space_Mapper/lib/ui/list_view.dart +++ b/Space_Mapper/lib/ui/list_view.dart @@ -105,114 +105,69 @@ class _STOListViewState extends State { itemCount: customLocations.length, itemBuilder: (context, index) { CustomLocation thisLocation = customLocations[index]; - return _tile( - thisLocation.getLocality() + - ", " + - thisLocation.getSubAdministrativeArea() + - ", " + - thisLocation.getISOCountryCode(), - thisLocation.getTimestamp() + "\n" + thisLocation.getStreet(), - thisLocation.displayCustomText(10.0, 10.0), - Icons.gps_fixed); - }, - )); - } - - ListTile _tile(String title, String subtitle, String text, IconData icon) => - ListTile( - title: Text(title, - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 20, - )), - subtitle: new RichText( - text: new TextSpan( - // Note: Styles for TextSpans must be explicitly defined. - // Child text spans will inherit styles from parent - style: new TextStyle( - fontSize: 14.0, - color: Colors.black, - ), - children: [ - new TextSpan( - text: subtitle, - style: new TextStyle(fontWeight: FontWeight.bold)), - new TextSpan(text: text), - ], - ), - ), - leading: Icon( - icon, - color: Colors.blue[500], - ), - ); -} - -/*class STOListView extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: Text("Locations History")), - body: FutureBuilder( - future: buildLocationsList(), - builder: (context, snapshot) { - if (snapshot.hasData) { - List? data = snapshot.data; - return _jobsListView(data); - } else if (snapshot.hasError) { - return Text("${snapshot.error}"); - } - return Center( - child: CircularProgressIndicator(), + return Dismissible( + child: _tile(thisLocation), + background: Container( + child: Container( + margin: EdgeInsets.only(right: 10.0), + alignment: Alignment.centerRight, + child: new LayoutBuilder(builder: (context, constraint) { + return new Icon(Icons.delete_forever, + size: constraint.biggest.height * 0.5); + }), + ), + color: Colors.red, + ), + key: ValueKey(customLocations[index]), + confirmDismiss: (DismissDirection direction) async { + await thisLocation.deleteThisLocation(); + setState(() { + customLocations = + CustomLocationsManager.fetchAll(sortByNewest: true); + thisLocation = customLocations[index]; + }); + return true; + }, ); }, )); } - ListView _jobsListView(data) { - return ListView.builder( - itemCount: data.length, - itemBuilder: (context, index) { - CustomLocation thisLocation = data[index]; - return _tile( - thisLocation.getUUID().toString() + - thisLocation.getLocality() + - ", " + - thisLocation.getSubAdministrativeArea() + - ", " + - thisLocation.getISOCountryCode(), - thisLocation.getTimestamp(), - thisLocation.displayCustomText(10.0, 10.0), - Icons.gps_fixed); - }); - } - - ListTile _tile(String title, String subtitle, String text, IconData icon) => - ListTile( - title: Text(title, - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 20, - )), - subtitle: new RichText( - text: new TextSpan( - // Note: Styles for TextSpans must be explicitly defined. - // Child text spans will inherit styles from parent - style: new TextStyle( - fontSize: 14.0, - color: Colors.black, - ), - children: [ - new TextSpan( - text: subtitle, - style: new TextStyle(fontWeight: FontWeight.bold)), - new TextSpan(text: text), - ], + ListTile _tile(CustomLocation thisLocation) { + String title = thisLocation.getLocality() + + ", " + + thisLocation.getSubAdministrativeArea() + + ", " + + thisLocation.getISOCountryCode(); + String subtitle = + thisLocation.getTimestamp() + "\n" + thisLocation.getStreet(); + String text = thisLocation.displayCustomText(10.0, 10.0); + return ListTile( + title: Text(title, + style: TextStyle( + fontWeight: FontWeight.w500, + fontSize: 20, + )), + subtitle: new RichText( + text: new TextSpan( + // Note: Styles for TextSpans must be explicitly defined. + // Child text spans will inherit styles from parent + style: new TextStyle( + fontSize: 14.0, + color: Colors.black, ), + children: [ + new TextSpan( + text: subtitle, + style: new TextStyle(fontWeight: FontWeight.bold)), + new TextSpan(text: text), + ], ), - leading: Icon( - icon, - color: Colors.blue[500], - ), - ); -}*/ + ), + leading: Icon( + Icons.gps_fixed, + color: Colors.blue[500], + ), + ); + } +} From aea1e1d83e4ea0b03aae5e593280c52f79bee74f Mon Sep 17 00:00:00 2001 From: Pablo Galve Date: Fri, 5 Nov 2021 17:15:55 +0100 Subject: [PATCH 2/4] Enable button to move user to its current location in the map --- Space_Mapper/lib/models/list_view.dart | 6 +++--- Space_Mapper/lib/ui/home_view.dart | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Space_Mapper/lib/models/list_view.dart b/Space_Mapper/lib/models/list_view.dart index d4494b13..85a4cc42 100644 --- a/Space_Mapper/lib/models/list_view.dart +++ b/Space_Mapper/lib/models/list_view.dart @@ -33,7 +33,7 @@ class CustomLocation { late num _speedAccuracy = -1; //in meters / second late num _altitude = -1; //in meters late num _altitudeAccuracy = -1; // in meters - late bool to_delete = false; + late bool _toDelete = false; /// Makes timestamp readable by a human String formatTimestamp(String timestamp) { @@ -68,9 +68,9 @@ class CustomLocation { } Future deleteThisLocation() async { - if (to_delete == false) { + if (_toDelete == false) { /// We need this checker to ensure that the user doesn't send the delete request twice, causing an exception - to_delete = true; + _toDelete = true; await bg.BackgroundGeolocation.destroyLocation(this.getUUID()); CustomLocationsManager.customLocations .removeWhere((element) => element.getUUID() == this.getUUID()); diff --git a/Space_Mapper/lib/ui/home_view.dart b/Space_Mapper/lib/ui/home_view.dart index cbc02c6e..5fed07cd 100644 --- a/Space_Mapper/lib/ui/home_view.dart +++ b/Space_Mapper/lib/ui/home_view.dart @@ -365,13 +365,11 @@ class HomeViewState extends State }, ), actions: [ - /* IconButton( icon: Icon(Icons.gps_fixed), color: Colors.yellow, - onPressed: - _onClickGetCurrentPosition, - ),*/ + onPressed: _onClickGetCurrentPosition, + ), Switch( value: _enabled, onChanged: _onClickEnable, From 5d05da2e0d6db34ab8ed23e4d049e87ba01b9892 Mon Sep 17 00:00:00 2001 From: Pablo Galve Date: Sun, 7 Nov 2021 12:53:18 +0100 Subject: [PATCH 3/4] Share Locations - Share Only Coordinates and Timestamp --- Space_Mapper/lib/models/list_view.dart | 34 +++++++++---------- Space_Mapper/lib/ui/side_drawer.dart | 39 ++++++++++++++++++++-- Space_Mapper/test/unit/list_view_test.dart | 3 +- 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/Space_Mapper/lib/models/list_view.dart b/Space_Mapper/lib/models/list_view.dart index 85a4cc42..08fa79cb 100644 --- a/Space_Mapper/lib/models/list_view.dart +++ b/Space_Mapper/lib/models/list_view.dart @@ -18,6 +18,21 @@ class CustomLocationsManager { .firstWhereOrNull((element) => element.getUUID() == uuid); return ret; } + + /// Makes timestamp readable by a human + static String formatTimestamp(String timestamp) { + //2021-10-25T21:25:08.210Z <- This is the original format + //2021-10-25 | 21:25:08 <- This is the result + String result = ""; + for (int i = 0; i < timestamp.length; ++i) { + if (timestamp[i] != "T" && timestamp[i] != ".") + result += timestamp[i]; + else if (timestamp[i] == "T") + result += " | "; + else if (timestamp[i] == ".") break; + } + return result; + } } class CustomLocation { @@ -27,7 +42,7 @@ class CustomLocation { late String _street = ""; // ignore: non_constant_identifier_names late String _ISOCountry = ""; // 2 letter code - late String _timestamp = ""; // ex: 2021-10-25T21:25:08.210Z + late String _timestamp = ""; late String _activity = ""; late num _speed = -1; //in meters / second late num _speedAccuracy = -1; //in meters / second @@ -35,21 +50,6 @@ class CustomLocation { late num _altitudeAccuracy = -1; // in meters late bool _toDelete = false; - /// Makes timestamp readable by a human - String formatTimestamp(String timestamp) { - //2021-10-25T21:25:08.210Z <- This is the original format - //2021-10-25 | 21:25:08 <- This is the result - String result = ""; - for (int i = 0; i < timestamp.length; ++i) { - if (timestamp[i] != "T" && timestamp[i] != ".") - result += timestamp[i]; - else if (timestamp[i] == "T") - result += " | "; - else if (timestamp[i] == ".") break; - } - return result; - } - /// Checks if data is valid and then displays 3 lines with: Activity, Speed and Altitude String displayCustomText(num maxSpeedAccuracy, num maxAltitudeAccuracy) { String ret = ""; @@ -99,7 +99,7 @@ class CustomLocation { } void setTimestamp(String timestamp) { - _timestamp = formatTimestamp(timestamp); + _timestamp = CustomLocationsManager.formatTimestamp(timestamp); } void setActivity(String activity) { diff --git a/Space_Mapper/lib/ui/side_drawer.dart b/Space_Mapper/lib/ui/side_drawer.dart index 4b0b6377..4fa77b0b 100644 --- a/Space_Mapper/lib/ui/side_drawer.dart +++ b/Space_Mapper/lib/ui/side_drawer.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; +import 'package:asm/models/list_view.dart'; import 'package:asm/ui/list_view.dart'; import 'package:asm/ui/report_an_issue.dart'; import 'package:asm/ui/web_view.dart'; @@ -7,12 +9,45 @@ import 'package:share/share.dart'; import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' as bg; +class ShareLocation { + late final String _timestamp; + final double _lat; + final double _long; + + ShareLocation(timestamp, this._lat, this._long) { + _timestamp = CustomLocationsManager.formatTimestamp(timestamp); + } + + Map toJson() => { + 'timestamp': _timestamp, + 'coords': { + 'latitude': _lat, + 'longitude': _long, + } + }; +} + class SpaceMapperSideDrawer extends StatelessWidget { _shareLocations() async { var now = new DateTime.now(); List allLocations = await bg.BackgroundGeolocation.locations; - Share.share(allLocations.toString(), - subject: "space_mapper_trajectory_" + now.toIso8601String() + ".json"); + List customLocation = []; + + for (var thisLocation in allLocations) { + ShareLocation _loc = new ShareLocation( + bg.Location(thisLocation).timestamp, + bg.Location(thisLocation).coords.latitude, + bg.Location(thisLocation).coords.latitude); + customLocation.add(_loc); + } + + String text = jsonEncode(customLocation); + /*for (var thisLocation in customLocation) { + text += jsonEncode(thisLocation); + }*/ + String subject = + "space_mapper_trajectory_" + now.toIso8601String() + ".json"; + Share.share(text, subject: subject); } _launchProjectURL() async { diff --git a/Space_Mapper/test/unit/list_view_test.dart b/Space_Mapper/test/unit/list_view_test.dart index fd7e0245..2d86fb96 100644 --- a/Space_Mapper/test/unit/list_view_test.dart +++ b/Space_Mapper/test/unit/list_view_test.dart @@ -10,7 +10,8 @@ void main() { String timestamp = "2021-10-25T21:25:08.210Z"; CustomLocation dL = new CustomLocation(); dL.setTimestamp(timestamp); - String ret = dL.formatTimestamp(dL.getTimestamp()); + String ret = + CustomLocationsManager.formatTimestamp(dL.getTimestamp()); expect(ret, "2021-10-25 | 21:25:08"); }); }); From 84839d6342a324f39ba627c0b478dfe6bba68c89 Mon Sep 17 00:00:00 2001 From: Pablo Galve Date: Sun, 7 Nov 2021 13:12:37 +0100 Subject: [PATCH 4/4] Share Locations - Beautify json result --- Space_Mapper/lib/ui/side_drawer.dart | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Space_Mapper/lib/ui/side_drawer.dart b/Space_Mapper/lib/ui/side_drawer.dart index 4fa77b0b..27e8252b 100644 --- a/Space_Mapper/lib/ui/side_drawer.dart +++ b/Space_Mapper/lib/ui/side_drawer.dart @@ -33,21 +33,19 @@ class SpaceMapperSideDrawer extends StatelessWidget { List allLocations = await bg.BackgroundGeolocation.locations; List customLocation = []; + // We get only timestamp and coordinates into our custom class for (var thisLocation in allLocations) { ShareLocation _loc = new ShareLocation( bg.Location(thisLocation).timestamp, bg.Location(thisLocation).coords.latitude, - bg.Location(thisLocation).coords.latitude); + bg.Location(thisLocation).coords.longitude); customLocation.add(_loc); } - String text = jsonEncode(customLocation); - /*for (var thisLocation in customLocation) { - text += jsonEncode(thisLocation); - }*/ + String prettyString = JsonEncoder.withIndent(' ').convert(customLocation); String subject = "space_mapper_trajectory_" + now.toIso8601String() + ".json"; - Share.share(text, subject: subject); + Share.share(prettyString, subject: subject); } _launchProjectURL() async {