From 444d67cb28e04415d2c962735e8b24db6feda627 Mon Sep 17 00:00:00 2001 From: zontreck Date: Sat, 17 May 2025 02:04:54 -0700 Subject: [PATCH] Fix the start and end time being missing --- lib/consts.dart | 4 +- lib/data.dart | 102 ++++++++++++++++++++++------------ lib/pages/MapPage.dart | 3 +- lib/pages/UpdateSettings.dart | 1 - lib/pages/WebMainPage.dart | 4 +- lib/pages/WorkData.dart | 30 +++++++++- pubspec.yaml | 2 +- 7 files changed, 102 insertions(+), 44 deletions(-) diff --git a/lib/consts.dart b/lib/consts.dart index 9ef773f..4e54f7a 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -7,9 +7,9 @@ class TTConsts { static get UPDATE_URL => "https://git.zontreck.com/AriasCreations/TimeTracker/raw/branch/main/latest-releases.json"; static get SESSION_SERVER => - "https://api.zontreck.com/timetrack/${UPDATE_CHANNEL}/timetrack.php"; + "https://api.zontreck.com/timetrack/$UPDATE_CHANNEL/timetrack.php"; - static const VERSION = "1.0.0-beta.5"; + static const VERSION = "1.0.0-beta.6"; static bool UPDATE_AVAILABLE = false; static UpdateChannel UPDATE_CHANNEL = UpdateChannel.beta; diff --git a/lib/data.dart b/lib/data.dart index 8ba75f4..92b9c2e 100644 --- a/lib/data.dart +++ b/lib/data.dart @@ -11,6 +11,7 @@ import 'package:timetrack/consts.dart'; class SessionData { static DateTime StartTime = DateTime(0); + static DateTime EndTime = DateTime(0); static bool IsOnTheClock = false; @@ -102,8 +103,9 @@ class SessionData { ); if (d < minDistanceMeters) continue; // too small → jitter - if (maxDistanceMeters != null && d > maxDistanceMeters) + if (maxDistanceMeters != null && d > maxDistanceMeters) { continue; // glitch + } meters += d; } @@ -159,6 +161,8 @@ class SessionData { currentTrip = null; _listener.cancel(); + EndTime = DateTime.now(); + var saveData = SaveData(); print(saveData); @@ -183,18 +187,20 @@ class SessionData { static Map SaveData() { Map saveData = {}; - List> _trips = []; + List> trips = []; for (var trip in Trips) { - _trips.add(trip.toJsonMap()); + trips.add(trip.toJsonMap()); } - List> _pos = []; + List> posx = []; for (var pos in positions) { - _pos.add(pos.toMap()); + posx.add(pos.toMap()); } - saveData["trips"] = _trips; - saveData["positions"] = _pos; + saveData["trips"] = trips; + saveData["positions"] = posx; + saveData["start"] = StartTime.toIso8601String(); + saveData["end"] = EndTime.toIso8601String(); return saveData; } @@ -209,28 +215,32 @@ class SessionData { data: json.encode(payload), ); - LoadData(reply.data as String); + LoadData(reply.data as Map); } - static void LoadData(String js) { - Map _js = json.decode(js); - if (_js.containsKey("error")) { + static void LoadData(Map jsMap) { + if (jsMap.containsKey("error")) { LastSessionID = ""; return; } - List> _trips = - _js['trips'] as List>; - List> _pos = - _js['positions'] as List>; + List trips = jsMap['trips'] as List; + List pos = jsMap['positions'] as List; - for (var trip in _trips) { - Trips.add(Trip.fromJsonMap(trip)); + for (var trip in trips) { + Trips.add(Trip.fromJsonMap(trip as Map)); } - for (var position in _pos) { - positions.add(SmallPosition.fromMap(position)); + for (var position in pos) { + positions.add(SmallPosition.fromMap(position as Map)); } + if (jsMap.containsKey("start")) { + StartTime = DateTime.parse(jsMap['start'] as String); + } + + if (jsMap.containsKey("end")) + EndTime = DateTime.parse(jsMap["end"] as String); + IsReadOnly = true; } @@ -251,7 +261,6 @@ class SessionData { static Delivery GetNewDelivery() { if (currentTrip != null) { var dropOff = currentTrip!.startNewDelivery(); - ; currentDelivery = dropOff; return dropOff; } else { @@ -263,10 +272,31 @@ class SessionData { currentDelivery = null; currentTrip = null; } + + /// [a] should be the Start Time, + /// + /// [b] is the end time + static String GetTotalTimeWorked(DateTime a, DateTime b) { + Duration diff = b.difference(a); + + int days = diff.inDays; + int hours = diff.inHours.remainder(24); + int minutes = diff.inMinutes.remainder(60); + int seconds = diff.inSeconds.remainder(60); + + List parts = []; + + if (days > 0) parts.add('${days}d'); + if (hours > 0) parts.add('${hours}h'); + if (minutes > 0) parts.add('${minutes}m'); + if (seconds > 0) parts.add('${seconds}s'); + + return parts.join(' '); + } } class Delivery { - Position? endLocation; + SmallPosition? endLocation; DateTime StartTime = DateTime.now(); Delivery() { @@ -275,23 +305,26 @@ class Delivery { Future MarkEndLocation() async { var pos = await SessionData.GetNewLocation(); - endLocation = pos; + endLocation = SmallPosition.fromPosition(pos); } Map toJsonMap() { return { "start": StartTime.toString(), - "endPos": endLocation?.toJson() ?? "incomplete", + "endPos": endLocation?.toMap() ?? "incomplete", }; } static Delivery fromMap(Map jsx) { Delivery delivery = Delivery(); delivery.StartTime = DateTime.parse(jsx['start'] as String); - if (jsx['endPos'] as String == "incomplete") + if (jsx['endPos'] is String) { delivery.endLocation = null; - else - delivery.endLocation = Position.fromMap(jsx['endPos']); + } else { + delivery.endLocation = SmallPosition.fromMap( + jsx['endPos'] as Map, + ); + } return delivery; } @@ -314,26 +347,25 @@ class Trip { } Map toJsonMap() { - Map _trip = {"start": StartTime.toString()}; - List> _dropOffs = []; + Map trip = {"start": StartTime.toString()}; + List> dropOffs = []; for (var delivery in deliveries) { - _dropOffs.add(delivery.toJsonMap()); + dropOffs.add(delivery.toJsonMap()); } - _trip["deliveries"] = _dropOffs; + trip["deliveries"] = dropOffs; - return _trip; + return trip; } static Trip fromJsonMap(Map jsx) { Trip trip = Trip(); trip.StartTime = DateTime.parse(jsx['start'] as String); trip.deliveries = []; - List> _dropOffs = - jsx['deliveries'] as List>; + List dropOffs = jsx['deliveries'] as List; - for (var dropOff in _dropOffs) { - trip.deliveries.add(Delivery.fromMap(dropOff)); + for (var dropOff in dropOffs) { + trip.deliveries.add(Delivery.fromMap(dropOff as Map)); } return trip; diff --git a/lib/pages/MapPage.dart b/lib/pages/MapPage.dart index ce07fc5..a6be1c5 100644 --- a/lib/pages/MapPage.dart +++ b/lib/pages/MapPage.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; import 'package:libacflutter/Constants.dart'; @@ -7,7 +6,7 @@ import 'package:timetrack/data.dart'; import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart'; class MapPage extends StatefulWidget { - MapPage({super.key}); + const MapPage({super.key}); @override State createState() { diff --git a/lib/pages/UpdateSettings.dart b/lib/pages/UpdateSettings.dart index 2922068..04a924d 100644 --- a/lib/pages/UpdateSettings.dart +++ b/lib/pages/UpdateSettings.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:libacflutter/Constants.dart'; import 'package:ota_update/ota_update.dart'; import 'package:timetrack/consts.dart'; diff --git a/lib/pages/WebMainPage.dart b/lib/pages/WebMainPage.dart index 41db49f..d5301fb 100644 --- a/lib/pages/WebMainPage.dart +++ b/lib/pages/WebMainPage.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:libacflutter/Constants.dart'; import 'package:timetrack/consts.dart'; import 'package:timetrack/data.dart'; class WebMain extends StatefulWidget { + const WebMain({super.key}); + @override State createState() { return _WebMain(); @@ -117,6 +118,7 @@ class _WebMain extends State { ), ElevatedButton( onPressed: () async { + SessionData.LastSessionID = sessionIDController.text; await SessionData.DownloadData(); setState(() {}); }, diff --git a/lib/pages/WorkData.dart b/lib/pages/WorkData.dart index deb322e..6bf2097 100644 --- a/lib/pages/WorkData.dart +++ b/lib/pages/WorkData.dart @@ -1,10 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:libacflutter/Constants.dart'; import 'package:timetrack/data.dart'; class WorkDataPage extends StatefulWidget { - WorkDataPage({super.key}); + const WorkDataPage({super.key}); @override State createState() { @@ -50,12 +49,39 @@ class _WorkData extends State { "Start Date & Time: ${SessionData.StartTime.toString()}", style: TextStyle(fontSize: 18), ), + if (SessionData.IsReadOnly) + Text( + "End Date & Time: ${SessionData.EndTime.toString()}", + style: TextStyle(fontSize: 18), + ), + + Text( + "Total time worked: ${SessionData.GetTotalTimeWorked(SessionData.StartTime, SessionData.EndTime)}", + style: TextStyle(fontSize: 18), + ), + if (SessionData.StartTime.year == 0) + ListTile( + title: Text("ERROR"), + subtitle: Text( + "This TTX session file appears to have been saved in an early alpha version. It does not contain the Start time or End timestamp information.", + ), + tileColor: LibACFlutterConstants.TITLEBAR_COLOR, + ), + SizedBox(height: 20), Text( "Total Estimated Miles: ${SessionData.GetTotalMilesAsString()}\n(Note: The miles displayed above may not be 100% accurate)", style: TextStyle(fontSize: 24), ), + + SizedBox(height: 40), + ElevatedButton( + onPressed: () async { + // Process data export to GPX format. + }, + child: Text("Export as GPX"), + ), ], ), ), diff --git a/pubspec.yaml b/pubspec.yaml index d10286a..079681b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.0-beta.5 +version: 1.0.0-beta.6 environment: sdk: ^3.7.2