Fix the start and end time being missing

This commit is contained in:
zontreck 2025-05-17 02:04:54 -07:00
parent f6fcc4c390
commit 444d67cb28
7 changed files with 102 additions and 44 deletions

View file

@ -7,9 +7,9 @@ class TTConsts {
static get UPDATE_URL => static get UPDATE_URL =>
"https://git.zontreck.com/AriasCreations/TimeTracker/raw/branch/main/latest-releases.json"; "https://git.zontreck.com/AriasCreations/TimeTracker/raw/branch/main/latest-releases.json";
static get SESSION_SERVER => 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 bool UPDATE_AVAILABLE = false;
static UpdateChannel UPDATE_CHANNEL = UpdateChannel.beta; static UpdateChannel UPDATE_CHANNEL = UpdateChannel.beta;

View file

@ -11,6 +11,7 @@ import 'package:timetrack/consts.dart';
class SessionData { class SessionData {
static DateTime StartTime = DateTime(0); static DateTime StartTime = DateTime(0);
static DateTime EndTime = DateTime(0);
static bool IsOnTheClock = false; static bool IsOnTheClock = false;
@ -102,8 +103,9 @@ class SessionData {
); );
if (d < minDistanceMeters) continue; // too small jitter if (d < minDistanceMeters) continue; // too small jitter
if (maxDistanceMeters != null && d > maxDistanceMeters) if (maxDistanceMeters != null && d > maxDistanceMeters) {
continue; // glitch continue; // glitch
}
meters += d; meters += d;
} }
@ -159,6 +161,8 @@ class SessionData {
currentTrip = null; currentTrip = null;
_listener.cancel(); _listener.cancel();
EndTime = DateTime.now();
var saveData = SaveData(); var saveData = SaveData();
print(saveData); print(saveData);
@ -183,18 +187,20 @@ class SessionData {
static Map<String, dynamic> SaveData() { static Map<String, dynamic> SaveData() {
Map<String, dynamic> saveData = {}; Map<String, dynamic> saveData = {};
List<Map<String, dynamic>> _trips = []; List<Map<String, dynamic>> trips = [];
for (var trip in Trips) { for (var trip in Trips) {
_trips.add(trip.toJsonMap()); trips.add(trip.toJsonMap());
} }
List<Map<String, dynamic>> _pos = []; List<Map<String, dynamic>> posx = [];
for (var pos in positions) { for (var pos in positions) {
_pos.add(pos.toMap()); posx.add(pos.toMap());
} }
saveData["trips"] = _trips; saveData["trips"] = trips;
saveData["positions"] = _pos; saveData["positions"] = posx;
saveData["start"] = StartTime.toIso8601String();
saveData["end"] = EndTime.toIso8601String();
return saveData; return saveData;
} }
@ -209,28 +215,32 @@ class SessionData {
data: json.encode(payload), data: json.encode(payload),
); );
LoadData(reply.data as String); LoadData(reply.data as Map<String, dynamic>);
} }
static void LoadData(String js) { static void LoadData(Map<String, dynamic> jsMap) {
Map<String, dynamic> _js = json.decode(js); if (jsMap.containsKey("error")) {
if (_js.containsKey("error")) {
LastSessionID = ""; LastSessionID = "";
return; return;
} }
List<Map<String, dynamic>> _trips = List<dynamic> trips = jsMap['trips'] as List<dynamic>;
_js['trips'] as List<Map<String, dynamic>>; List<dynamic> pos = jsMap['positions'] as List<dynamic>;
List<Map<String, dynamic>> _pos =
_js['positions'] as List<Map<String, dynamic>>;
for (var trip in _trips) { for (var trip in trips) {
Trips.add(Trip.fromJsonMap(trip)); Trips.add(Trip.fromJsonMap(trip as Map<String, dynamic>));
} }
for (var position in _pos) { for (var position in pos) {
positions.add(SmallPosition.fromMap(position)); positions.add(SmallPosition.fromMap(position as Map<String, dynamic>));
} }
if (jsMap.containsKey("start")) {
StartTime = DateTime.parse(jsMap['start'] as String);
}
if (jsMap.containsKey("end"))
EndTime = DateTime.parse(jsMap["end"] as String);
IsReadOnly = true; IsReadOnly = true;
} }
@ -251,7 +261,6 @@ class SessionData {
static Delivery GetNewDelivery() { static Delivery GetNewDelivery() {
if (currentTrip != null) { if (currentTrip != null) {
var dropOff = currentTrip!.startNewDelivery(); var dropOff = currentTrip!.startNewDelivery();
;
currentDelivery = dropOff; currentDelivery = dropOff;
return dropOff; return dropOff;
} else { } else {
@ -263,10 +272,31 @@ class SessionData {
currentDelivery = null; currentDelivery = null;
currentTrip = 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<String> 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 { class Delivery {
Position? endLocation; SmallPosition? endLocation;
DateTime StartTime = DateTime.now(); DateTime StartTime = DateTime.now();
Delivery() { Delivery() {
@ -275,23 +305,26 @@ class Delivery {
Future<void> MarkEndLocation() async { Future<void> MarkEndLocation() async {
var pos = await SessionData.GetNewLocation(); var pos = await SessionData.GetNewLocation();
endLocation = pos; endLocation = SmallPosition.fromPosition(pos);
} }
Map<String, dynamic> toJsonMap() { Map<String, dynamic> toJsonMap() {
return { return {
"start": StartTime.toString(), "start": StartTime.toString(),
"endPos": endLocation?.toJson() ?? "incomplete", "endPos": endLocation?.toMap() ?? "incomplete",
}; };
} }
static Delivery fromMap(Map<String, dynamic> jsx) { static Delivery fromMap(Map<String, dynamic> jsx) {
Delivery delivery = Delivery(); Delivery delivery = Delivery();
delivery.StartTime = DateTime.parse(jsx['start'] as String); delivery.StartTime = DateTime.parse(jsx['start'] as String);
if (jsx['endPos'] as String == "incomplete") if (jsx['endPos'] is String) {
delivery.endLocation = null; delivery.endLocation = null;
else } else {
delivery.endLocation = Position.fromMap(jsx['endPos']); delivery.endLocation = SmallPosition.fromMap(
jsx['endPos'] as Map<String, dynamic>,
);
}
return delivery; return delivery;
} }
@ -314,26 +347,25 @@ class Trip {
} }
Map<String, dynamic> toJsonMap() { Map<String, dynamic> toJsonMap() {
Map<String, Object> _trip = {"start": StartTime.toString()}; Map<String, Object> trip = {"start": StartTime.toString()};
List<Map<String, dynamic>> _dropOffs = []; List<Map<String, dynamic>> dropOffs = [];
for (var delivery in deliveries) { 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<String, dynamic> jsx) { static Trip fromJsonMap(Map<String, dynamic> jsx) {
Trip trip = Trip(); Trip trip = Trip();
trip.StartTime = DateTime.parse(jsx['start'] as String); trip.StartTime = DateTime.parse(jsx['start'] as String);
trip.deliveries = []; trip.deliveries = [];
List<Map<String, dynamic>> _dropOffs = List<dynamic> dropOffs = jsx['deliveries'] as List<dynamic>;
jsx['deliveries'] as List<Map<String, dynamic>>;
for (var dropOff in _dropOffs) { for (var dropOff in dropOffs) {
trip.deliveries.add(Delivery.fromMap(dropOff)); trip.deliveries.add(Delivery.fromMap(dropOff as Map<String, dynamic>));
} }
return trip; return trip;

View file

@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart'; import 'package:latlong2/latlong.dart';
import 'package:libacflutter/Constants.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'; import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart';
class MapPage extends StatefulWidget { class MapPage extends StatefulWidget {
MapPage({super.key}); const MapPage({super.key});
@override @override
State<StatefulWidget> createState() { State<StatefulWidget> createState() {

View file

@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:libacflutter/Constants.dart'; import 'package:libacflutter/Constants.dart';
import 'package:ota_update/ota_update.dart'; import 'package:ota_update/ota_update.dart';
import 'package:timetrack/consts.dart'; import 'package:timetrack/consts.dart';

View file

@ -1,10 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:libacflutter/Constants.dart'; import 'package:libacflutter/Constants.dart';
import 'package:timetrack/consts.dart'; import 'package:timetrack/consts.dart';
import 'package:timetrack/data.dart'; import 'package:timetrack/data.dart';
class WebMain extends StatefulWidget { class WebMain extends StatefulWidget {
const WebMain({super.key});
@override @override
State<StatefulWidget> createState() { State<StatefulWidget> createState() {
return _WebMain(); return _WebMain();
@ -117,6 +118,7 @@ class _WebMain extends State<WebMain> {
), ),
ElevatedButton( ElevatedButton(
onPressed: () async { onPressed: () async {
SessionData.LastSessionID = sessionIDController.text;
await SessionData.DownloadData(); await SessionData.DownloadData();
setState(() {}); setState(() {});
}, },

View file

@ -1,10 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:libacflutter/Constants.dart'; import 'package:libacflutter/Constants.dart';
import 'package:timetrack/data.dart'; import 'package:timetrack/data.dart';
class WorkDataPage extends StatefulWidget { class WorkDataPage extends StatefulWidget {
WorkDataPage({super.key}); const WorkDataPage({super.key});
@override @override
State<StatefulWidget> createState() { State<StatefulWidget> createState() {
@ -50,12 +49,39 @@ class _WorkData extends State<WorkDataPage> {
"Start Date & Time: ${SessionData.StartTime.toString()}", "Start Date & Time: ${SessionData.StartTime.toString()}",
style: TextStyle(fontSize: 18), 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), SizedBox(height: 20),
Text( Text(
"Total Estimated Miles: ${SessionData.GetTotalMilesAsString()}\n(Note: The miles displayed above may not be 100% accurate)", "Total Estimated Miles: ${SessionData.GetTotalMilesAsString()}\n(Note: The miles displayed above may not be 100% accurate)",
style: TextStyle(fontSize: 24), style: TextStyle(fontSize: 24),
), ),
SizedBox(height: 40),
ElevatedButton(
onPressed: () async {
// Process data export to GPX format.
},
child: Text("Export as GPX"),
),
], ],
), ),
), ),

View file

@ -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 # 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 # 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. # 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: environment:
sdk: ^3.7.2 sdk: ^3.7.2