Refactoring QOL Changes

This commit is contained in:
zontreck 2025-07-22 12:17:11 -07:00
parent 7e13057e43
commit 845e35fe74
6 changed files with 176 additions and 80 deletions

View file

@ -9,7 +9,7 @@ class TTConsts {
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.34"; static const VERSION = "1.0.0-beta.35";
static bool UPDATE_AVAILABLE = false; static bool UPDATE_AVAILABLE = false;
static UpdateChannel UPDATE_CHANNEL = UpdateChannel.beta; static UpdateChannel UPDATE_CHANNEL = UpdateChannel.beta;

View file

@ -1,3 +1,5 @@
// ignore_for_file: deprecated_member_use_from_same_package
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:math' as math; import 'dart:math' as math;
@ -31,7 +33,7 @@ class SessionData {
static List<Trip> Trips = []; static List<Trip> Trips = [];
static Delivery? currentDelivery; //static Delivery? currentDelivery;
static Trip? currentTrip; static Trip? currentTrip;
static List<SmallPosition> positions = []; static List<SmallPosition> positions = [];
static late StreamSubscription<Position> _listener; static late StreamSubscription<Position> _listener;
@ -74,6 +76,7 @@ class SessionData {
int total = 0; int total = 0;
for (var trip in Trips) { for (var trip in Trips) {
total += trip.deliveries.length; total += trip.deliveries.length;
total += trip.DropOffLocations.length;
} }
return total; return total;
@ -302,7 +305,7 @@ class SessionData {
static Future<void> Logout() async { static Future<void> Logout() async {
IsOnTheClock = false; IsOnTheClock = false;
currentDelivery = null; //currentDelivery = null;
currentTrip = null; currentTrip = null;
_listener.cancel(); _listener.cancel();
@ -409,7 +412,7 @@ class SessionData {
IsOnTheClock = false; IsOnTheClock = false;
StartTime = DateTime.fromMillisecondsSinceEpoch(0); StartTime = DateTime.fromMillisecondsSinceEpoch(0);
Trips = []; Trips = [];
currentDelivery = null; //currentDelivery = null;
currentTrip = null; currentTrip = null;
positions = []; positions = [];
EndTime = DateTime.fromMillisecondsSinceEpoch(0); EndTime = DateTime.fromMillisecondsSinceEpoch(0);
@ -454,7 +457,7 @@ class SessionData {
if (DirtyState) { if (DirtyState) {
DirtyState = false; DirtyState = false;
DisplayMessage = "Saved cache state"; //DisplayMessage = "Saved cache state";
} }
} }
@ -504,10 +507,6 @@ class SessionData {
currentTrip = Trips.last; currentTrip = Trips.last;
} }
if (ct.containsKey("current_delivery")) {
currentDelivery = currentTrip!.deliveries.last;
}
print("Deserialized data: ${SnbtIo.writeToString(ct)}"); print("Deserialized data: ${SnbtIo.writeToString(ct)}");
} }
@ -542,13 +541,8 @@ class SessionData {
} }
ct.put("trips", myTrips); ct.put("trips", myTrips);
// This format supports saving current trip and current delivery.
if (currentDelivery != null) {
ct.put("current_delivery", await currentDelivery!.toNBT());
}
if (currentTrip != null) { if (currentTrip != null) {
ct.put("current_trip", await currentTrip!.toNBT()); NbtUtils.writeBoolean(ct, "current_trip", true);
} }
if (TotalPay != null) { if (TotalPay != null) {
@ -673,11 +667,11 @@ class SessionData {
return currentTrip!; return currentTrip!;
} }
static Delivery GetNewDelivery() { static Future<void> DropOffCompleted() async {
if (currentTrip != null) { if (currentTrip != null) {
var dropOff = currentTrip!.startNewDelivery(); currentTrip!.DropOffLocations.add(
currentDelivery = dropOff; SmallPosition.fromPosition(await GetNewLocation()),
return dropOff; );
} else { } else {
throw Exception("A delivery cannot exist without a trip"); throw Exception("A delivery cannot exist without a trip");
} }
@ -687,7 +681,6 @@ class SessionData {
if (currentTrip != null) { if (currentTrip != null) {
currentTrip!.EndTime = DateTime.now(); currentTrip!.EndTime = DateTime.now();
} }
currentDelivery = null;
currentTrip = null; currentTrip = null;
} }
@ -729,6 +722,10 @@ class SessionData {
} }
} }
@Deprecated(
"This struct is left here for legacy compatibility. It is not used anymore.",
)
/// This struct is left here for legacy compatibility. It is not used anymore.
class Delivery { class Delivery {
SmallPosition? endLocation; SmallPosition? endLocation;
DateTime StartTime = DateTime.now(); DateTime StartTime = DateTime.now();
@ -787,7 +784,12 @@ class Delivery {
} }
class Trip { class Trip {
@Deprecated(
"The old Deliveries struct has been deprecated. Please use DropOffLocations instead.",
)
/// The old Deliveries struct has been deprecated. Please use DropOffLocations instead.
List<Delivery> deliveries = []; List<Delivery> deliveries = [];
List<SmallPosition> DropOffLocations = [];
DateTime StartTime = DateTime(0); DateTime StartTime = DateTime(0);
DateTime EndTime = DateTime(0); DateTime EndTime = DateTime(0);
@ -796,13 +798,6 @@ class Trip {
StartTime = DateTime.now(); StartTime = DateTime.now();
} }
Delivery startNewDelivery() {
var delivery = Delivery();
deliveries.add(delivery);
return delivery;
}
Map<String, dynamic> toJsonMap() { Map<String, dynamic> toJsonMap() {
Map<String, Object> trip = { Map<String, Object> trip = {
"start": StartTime.toIso8601String(), "start": StartTime.toIso8601String(),
@ -813,7 +808,9 @@ class Trip {
dropOffs.add(delivery.toJsonMap()); dropOffs.add(delivery.toJsonMap());
} }
trip["deliveries"] = dropOffs; if (deliveries.isNotEmpty) trip["deliveries"] = dropOffs;
// if(DropOffLocations.isNotEmpty)
// trip["dropoffs"] = [];
return trip; return trip;
} }
@ -845,10 +842,17 @@ class Trip {
} }
ListTag drops = ListTag(); ListTag drops = ListTag();
for (var drop in deliveries) { if (deliveries.isNotEmpty) {
drops.add(await drop.toNBT()); for (var drop in deliveries) {
drops.add(await drop.toNBT());
}
ct.put("deliveries", drops);
} else {
for (var drop in DropOffLocations) {
drops.add(await drop.toNBT());
}
ct.put("dropOffs", drops);
} }
ct.put("deliveries", drops);
return ct; return ct;
} }
@ -864,12 +868,19 @@ class Trip {
trip.EndTime = DateTime.parse(tag.get("end")!.asString()); trip.EndTime = DateTime.parse(tag.get("end")!.asString());
} }
ListTag drops = tag.get("deliveries")! as ListTag; if (tag.containsKey("deliveries")) {
for (var drop in drops.value) { ListTag drops = tag.get("deliveries")! as ListTag;
Delivery del = await Delivery.fromNBT(drop.asCompoundTag()); for (var drop in drops.value) {
trip.deliveries.add(del); Delivery del = await Delivery.fromNBT(drop.asCompoundTag());
trip.deliveries.add(del);
}
} else if (tag.containsKey("dropOffs")) {
ListTag drops = tag.get("dropOffs")! as ListTag;
for (var drop in drops.value) {
SmallPosition pos = await SmallPosition.fromNBT(drop.asCompoundTag());
trip.DropOffLocations.add(pos);
}
} }
return trip; return trip;
} }
} }

View file

@ -223,7 +223,7 @@ class _HomePageState extends State<HomePage> {
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
SessionData.currentDelivery!.MarkEndLocation(); //SessionData.currentDelivery!.MarkEndLocation();
SessionData.EndTrip(); SessionData.EndTrip();
@ -254,24 +254,36 @@ class _HomePageState extends State<HomePage> {
Widget GetDeliveryWidgets() { Widget GetDeliveryWidgets() {
return Column( return Column(
children: [ children: [
ElevatedButton( ListTile(
onPressed: () async { title: Text("Drop Off Completed"),
subtitle: Text("Drop a pin at your location."),
onLongPress: () async {
//SessionData.currentDelivery!.MarkEndLocation();
//SessionData.GetNewDelivery();
setState(() {});
SessionData.DirtyState = true;
SessionData.ActionPerformed();
},
onTap: () async {
await showDialog( await showDialog(
context: context, context: context,
builder: (builder) { builder: (builder) {
return AlertDialog( return AlertDialog(
icon: Icon(Icons.warning), icon: Icon(Icons.warning),
title: Text("Are you sure you want to start a new delivery?"), title: Text(
"Are you sure you want to mark a completed delivery?",
),
content: Text( content: Text(
"Once ended, a marker for your current delivery will be dropped at your current location", "A marker for your current delivery will be dropped at your current location",
), ),
actions: [ actions: [
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
SessionData.currentDelivery!.MarkEndLocation(); SessionData.DropOffCompleted();
SessionData.GetNewDelivery();
setState(() {}); setState(() {});
@ -291,7 +303,6 @@ class _HomePageState extends State<HomePage> {
}, },
); );
}, },
child: Text("Start new delivery"),
), ),
], ],
); );
@ -300,22 +311,41 @@ class _HomePageState extends State<HomePage> {
Widget GetNonTripWidgets() { Widget GetNonTripWidgets() {
return Column( return Column(
children: [ children: [
ElevatedButton( ListTile(
onPressed: () async { title: Text("Start Active Time"),
subtitle: Text(
"Long press this when starting a trip, or when actively being paid for driving.",
),
onLongPress: () async {
//Navigator.pop(context);
SessionData.GetNewTrip();
//SessionData.GetNewDelivery();
setState(() {});
SessionData.DirtyState = true;
SessionData.ActionPerformed();
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text("Active time started")));
},
onTap: () async {
await showDialog( await showDialog(
context: context, context: context,
builder: (builder) { builder: (builder) {
return AlertDialog( return AlertDialog(
icon: Icon(Icons.warning), icon: Icon(Icons.warning),
title: Text("Are you sure you want to start a new trip?"), title: Text("Are you sure you want to start active time?"),
content: Text("Starting a trip will also start a delivery."), content: Text("Active paid time, trip, offer, etc."),
actions: [ actions: [
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
SessionData.GetNewTrip(); SessionData.GetNewTrip();
SessionData.GetNewDelivery(); //SessionData.GetNewDelivery();
setState(() {}); setState(() {});
@ -335,19 +365,18 @@ class _HomePageState extends State<HomePage> {
}, },
); );
}, },
child: Text("Start New Trip"),
), ),
ElevatedButton( SizedBox(height: 50),
onPressed: () async { ListTile(
if (SessionData.currentTrip != null || onTap: () async {
SessionData.currentDelivery != null) { if (SessionData.currentTrip != null) {
showDialog( showDialog(
context: context, context: context,
builder: (build) { builder: (build) {
return AlertDialog( return AlertDialog(
title: Text("Cannot end work day"), title: Text("Cannot end work day"),
content: Text( content: Text(
"You must end the trip and any delivery before you can fully end the work day.", "You must end your active time before you can fully end the work day.",
), ),
); );
}, },
@ -407,7 +436,11 @@ class _HomePageState extends State<HomePage> {
); );
} }
}, },
child: Text("End work day"), title: Text("End work day"),
tileColor: LibACFlutterConstants.TITLEBAR_COLOR,
subtitle: Text(
"Ends the current work day, and marks the session as read only. Data will then be uploaded to the configured backend server.",
),
), ),
], ],
); );
@ -421,7 +454,7 @@ class _HomePageState extends State<HomePage> {
style: TextStyle(fontSize: 18), style: TextStyle(fontSize: 18),
), ),
if (SessionData.currentTrip != null) GetTripWidgets(), if (SessionData.currentTrip != null) GetTripWidgets(),
if (SessionData.currentDelivery != null) GetDeliveryWidgets(), if (SessionData.currentTrip != null) GetDeliveryWidgets(),
if (SessionData.currentTrip == null) GetNonTripWidgets(), if (SessionData.currentTrip == null) GetNonTripWidgets(),
], ],
); );

View file

@ -56,7 +56,22 @@ class _MapPage extends State<MapPage> {
print("Total trips: ${SessionData.Trips.length}"); print("Total trips: ${SessionData.Trips.length}");
for (var trip in SessionData.Trips) { for (var trip in SessionData.Trips) {
for (var dropOff in trip.DropOffLocations) {
Markers.add(
Marker(
point: LatLng(dropOff.latitude, dropOff.longitude),
child: Stack(
children: GetDropOffWidgets(
dropOff,
trip.DropOffLocations.indexOf(dropOff) + 1,
SessionData.Trips.indexOf(trip) + 1,
),
),
),
);
}
for (var dropOff in trip.deliveries) { for (var dropOff in trip.deliveries) {
if (dropOff.endLocation == null) continue;
Markers.add( Markers.add(
Marker( Marker(
point: LatLng( point: LatLng(
@ -64,38 +79,63 @@ class _MapPage extends State<MapPage> {
dropOff.endLocation!.longitude, dropOff.endLocation!.longitude,
), ),
child: Stack( child: Stack(
children: [ children: GetDropOffWidgets(
IconButton( dropOff.endLocation!,
onPressed: () { trip.deliveries.indexOf(dropOff) + 1,
showDialog( SessionData.Trips.indexOf(trip) + 1,
context: context, ),
builder: (builder) {
return AlertDialog(
title: Text(
"Trip #${SessionData.Trips.indexOf(trip) + 1}; DropOff #${trip.deliveries.indexOf(dropOff) + 1}",
),
);
},
);
},
icon: Icon(
Icons.location_on_rounded,
size: 24,
color: Colors.red,
),
),
],
), ),
), ),
); );
print("Marker added"); print("Marker added");
} }
if (SessionData.IsOnTheClock) {
Markers.add(
Marker(
point: GetCurrentPosition(),
child: Stack(
children: [
Icon(Icons.circle_outlined, color: Colors.lightBlue, size: 28),
Icon(Icons.circle, color: Colors.blue, size: 24),
],
),
),
);
}
} }
setState(() {}); setState(() {});
super.didChangeDependencies(); super.didChangeDependencies();
} }
LatLng GetCurrentPosition() {
SmallPosition pos = SessionData.positions.last;
return LatLng(pos.latitude, pos.longitude);
}
List<Widget> GetDropOffWidgets(
SmallPosition pos,
int dropOffNumber,
int tripNumber,
) {
return [
IconButton(
onPressed: () {
showDialog(
context: context,
builder: (builder) {
return AlertDialog(
title: Text("Trip #${tripNumber}; DropOff #${dropOffNumber}"),
);
},
);
},
icon: Icon(Icons.location_on_rounded, size: 24, color: Colors.red),
),
];
}
@override @override
void dispose() { void dispose() {
SessionData.Calls.MapCallback = null; SessionData.Calls.MapCallback = null;
@ -137,7 +177,10 @@ class _MapPage extends State<MapPage> {
minZoom: 1, minZoom: 1,
maxZoom: 30, maxZoom: 30,
initialZoom: 15, initialZoom: 15,
initialCenter: initialPosition, initialCenter:
SessionData.IsOnTheClock
? GetCurrentPosition()
: initialPosition,
keepAlive: false, keepAlive: false,
), ),
children: [ children: [

View file

@ -121,6 +121,15 @@ class _WorkData extends State<WorkDataPage> {
ElevatedButton( ElevatedButton(
onPressed: () async { onPressed: () async {
// Process data export to GPX format. // Process data export to GPX format.
await showDialog(
context: context,
builder: (buildx) {
return AlertDialog(
title: Text("Not yet implemented"),
content: Text("GPX is not yet fully implemented."),
);
},
);
}, },
child: Text("Export as GPX"), 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.34 version: 1.0.0-beta.35
environment: environment:
sdk: ^3.7.2 sdk: ^3.7.2