diff --git a/Space_Mapper/lib/models/list_view.dart b/Space_Mapper/lib/models/list_view.dart index fcf4621a..08fa79cb 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 = []; @@ -16,24 +18,9 @@ class CustomLocationsManager { .firstWhereOrNull((element) => element.getUUID() == uuid); return ret; } -} - -class CustomLocation { - late final String _uuid; - late String _locality = ""; - late String _subAdministrativeArea = ""; - 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 _activity = ""; - late num _speed = -1; //in meters / second - late num _speedAccuracy = -1; //in meters / second - late num _altitude = -1; //in meters - late num _altitudeAccuracy = -1; // in meters /// Makes timestamp readable by a human - String formatTimestamp(String timestamp) { + 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 = ""; @@ -46,6 +33,22 @@ class CustomLocation { } return result; } +} + +class CustomLocation { + late final String _uuid; + late String _locality = ""; + late String _subAdministrativeArea = ""; + late String _street = ""; + // ignore: non_constant_identifier_names + late String _ISOCountry = ""; // 2 letter code + late String _timestamp = ""; + late String _activity = ""; + late num _speed = -1; //in meters / second + late num _speedAccuracy = -1; //in meters / second + late num _altitude = -1; //in meters + late num _altitudeAccuracy = -1; // in meters + late bool _toDelete = false; /// Checks if data is valid and then displays 3 lines with: Activity, Speed and Altitude String displayCustomText(num maxSpeedAccuracy, num maxAltitudeAccuracy) { @@ -64,6 +67,16 @@ class CustomLocation { return ret; } + Future deleteThisLocation() async { + if (_toDelete == false) { + /// We need this checker to ensure that the user doesn't send the delete request twice, causing an exception + _toDelete = true; + await bg.BackgroundGeolocation.destroyLocation(this.getUUID()); + CustomLocationsManager.customLocations + .removeWhere((element) => element.getUUID() == this.getUUID()); + } + } + // Variable setters void setUUID(String uuid) { _uuid = uuid; @@ -86,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/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, 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], + ), + ); + } +} diff --git a/Space_Mapper/lib/ui/side_drawer.dart b/Space_Mapper/lib/ui/side_drawer.dart index 4b0b6377..27e8252b 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,43 @@ 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 = []; + + // 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.longitude); + customLocation.add(_loc); + } + + String prettyString = JsonEncoder.withIndent(' ').convert(customLocation); + String subject = + "space_mapper_trajectory_" + now.toIso8601String() + ".json"; + Share.share(prettyString, 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"); }); });