QOL: Add confirmation dialogs and re-add total pay as a single final number at the end of work day
This commit is contained in:
parent
199a3585d7
commit
ac7a5c885d
6 changed files with 241 additions and 38 deletions
|
@ -9,7 +9,7 @@ class TTConsts {
|
|||
static get SESSION_SERVER =>
|
||||
"https://api.zontreck.com/timetrack/$UPDATE_CHANNEL/timetrack.php";
|
||||
|
||||
static const VERSION = "1.0.0-beta.8";
|
||||
static const VERSION = "1.0.0-beta.9";
|
||||
|
||||
static bool UPDATE_AVAILABLE = false;
|
||||
static UpdateChannel UPDATE_CHANNEL = UpdateChannel.beta;
|
||||
|
|
|
@ -24,6 +24,7 @@ class SessionData {
|
|||
static Callbacks Calls = Callbacks();
|
||||
static String LastSessionID = "";
|
||||
static String DisplayError = "";
|
||||
static double? TotalPay;
|
||||
|
||||
/// Is true if the try-catch is tripped or if not running on Android
|
||||
static bool isWeb = false;
|
||||
|
@ -204,27 +205,32 @@ class SessionData {
|
|||
saveData["positions"] = posx;
|
||||
saveData["start"] = StartTime.toIso8601String();
|
||||
saveData["end"] = EndTime.toIso8601String();
|
||||
if (TotalPay != null) saveData["totalPay"] = TotalPay;
|
||||
|
||||
return saveData;
|
||||
}
|
||||
|
||||
static Future<void> DownloadData() async {
|
||||
static Future<bool> DownloadData() async {
|
||||
Dio dio = Dio();
|
||||
Map<String, dynamic> payload = {"cmd": "get", "id": LastSessionID};
|
||||
|
||||
// Send the data, and get the response
|
||||
var reply = await dio.post(
|
||||
TTConsts.SESSION_SERVER,
|
||||
data: json.encode(payload),
|
||||
);
|
||||
try {
|
||||
var reply = await dio.post(
|
||||
TTConsts.SESSION_SERVER,
|
||||
data: json.encode(payload),
|
||||
);
|
||||
|
||||
LoadData(reply.data as Map<String, dynamic>);
|
||||
return LoadData(reply.data as Map<String, dynamic>);
|
||||
} catch (E) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void LoadData(Map<String, dynamic> jsMap) {
|
||||
static bool LoadData(Map<String, dynamic> jsMap) {
|
||||
if (jsMap.containsKey("error")) {
|
||||
LastSessionID = "";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
List<dynamic> trips = jsMap['trips'] as List<dynamic>;
|
||||
List<dynamic> pos = jsMap['positions'] as List<dynamic>;
|
||||
|
@ -244,7 +250,14 @@ class SessionData {
|
|||
if (jsMap.containsKey("end"))
|
||||
EndTime = DateTime.parse(jsMap["end"] as String);
|
||||
|
||||
if (jsMap.containsKey("totalPay"))
|
||||
TotalPay = jsMap["totalPay"] as double;
|
||||
else
|
||||
TotalPay = null;
|
||||
|
||||
IsReadOnly = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static Future<Position> GetNewLocation() async {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:libacflutter/Constants.dart';
|
||||
import 'package:libacflutter/Prompt.dart';
|
||||
import 'package:timetrack/consts.dart';
|
||||
import 'package:timetrack/data.dart';
|
||||
|
||||
|
@ -164,11 +165,38 @@ class _HomePageState extends State<HomePage> {
|
|||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
SessionData.currentDelivery!.MarkEndLocation();
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (builder) {
|
||||
return AlertDialog(
|
||||
icon: Icon(Icons.warning),
|
||||
title: Text("Are you sure you want to end the trip?"),
|
||||
content: Text(
|
||||
"Once ended, a marker for your current delivery will be dropped at your current location",
|
||||
),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
|
||||
SessionData.EndTrip();
|
||||
SessionData.currentDelivery!.MarkEndLocation();
|
||||
|
||||
setState(() {});
|
||||
SessionData.EndTrip();
|
||||
|
||||
setState(() {});
|
||||
},
|
||||
child: Text("Yes"),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text("Cancel"),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Text("END TRIP"),
|
||||
),
|
||||
|
@ -181,10 +209,37 @@ class _HomePageState extends State<HomePage> {
|
|||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
SessionData.currentDelivery!.MarkEndLocation();
|
||||
SessionData.GetNewDelivery();
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (builder) {
|
||||
return AlertDialog(
|
||||
icon: Icon(Icons.warning),
|
||||
title: Text("Are you sure you want to start a new delivery?"),
|
||||
content: Text(
|
||||
"Once ended, a marker for your current delivery will be dropped at your current location",
|
||||
),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
|
||||
setState(() {});
|
||||
SessionData.currentDelivery!.MarkEndLocation();
|
||||
SessionData.GetNewDelivery();
|
||||
|
||||
setState(() {});
|
||||
},
|
||||
child: Text("Yes"),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text("Cancel"),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Text("Start new delivery"),
|
||||
),
|
||||
|
@ -197,10 +252,35 @@ class _HomePageState extends State<HomePage> {
|
|||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
SessionData.GetNewTrip();
|
||||
SessionData.GetNewDelivery();
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (builder) {
|
||||
return AlertDialog(
|
||||
icon: Icon(Icons.warning),
|
||||
title: Text("Are you sure you want to start a new trip?"),
|
||||
content: Text("Starting a trip will also start a delivery."),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
|
||||
setState(() {});
|
||||
SessionData.GetNewTrip();
|
||||
SessionData.GetNewDelivery();
|
||||
|
||||
setState(() {});
|
||||
},
|
||||
child: Text("Yes"),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text("Cancel"),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Text("Start New Trip"),
|
||||
),
|
||||
|
@ -220,8 +300,55 @@ class _HomePageState extends State<HomePage> {
|
|||
},
|
||||
);
|
||||
} else {
|
||||
SessionData.Logout();
|
||||
setState(() {});
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (builder) {
|
||||
return AlertDialog(
|
||||
icon: Icon(Icons.warning),
|
||||
title: Text("Are you sure you want to end the work day?"),
|
||||
content: Text(
|
||||
"Ending the work day will finalize your session. A code will pop up. To copy a URL to this session to your clipboard, tap and hold on the session code. You will be asked to enter the total pay if you tap yes.\n\nEnding the work day cannot be undone.",
|
||||
),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
Navigator.pop(context);
|
||||
|
||||
// Prompt for the total pay
|
||||
var reply = await showDialog(
|
||||
context: context,
|
||||
builder: (bldx) {
|
||||
return InputPrompt(
|
||||
title: "What was the total pay?",
|
||||
prompt:
|
||||
"Enter the total pay here. If you do not want to, simply leave the field blank and a 0 will be used instead.",
|
||||
type: InputPromptType.Number,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (reply == null || reply as String == "") {
|
||||
reply = 0.0;
|
||||
}
|
||||
|
||||
if (reply is String) reply = double.parse(reply);
|
||||
|
||||
SessionData.TotalPay = reply as double;
|
||||
|
||||
await SessionData.Logout();
|
||||
setState(() {});
|
||||
},
|
||||
child: Text("Yes"),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text("Cancel"),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text("End work day"),
|
||||
|
@ -234,7 +361,7 @@ class _HomePageState extends State<HomePage> {
|
|||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
"You are now on the clock\nYour location is being tracked for record keeping purposes.\n\nYou started at ${SessionData.StartTime.toLocal()}\n\n",
|
||||
"You are now on the clock\nYour location is being tracked for record keeping purposes.\n\nYou started ${SessionData.GetTotalTimeWorked(SessionData.StartTime, DateTime.now())}\n\n",
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
if (SessionData.currentTrip != null) GetTripWidgets(),
|
||||
|
|
|
@ -96,10 +96,43 @@ class _WebMain extends State<WebMain> {
|
|||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
SessionData.IsReadOnly = false;
|
||||
SessionData.Trips = [];
|
||||
SessionData.positions = [];
|
||||
SessionData.DisplayError = "";
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (builder) {
|
||||
return AlertDialog(
|
||||
icon: Icon(Icons.warning_amber),
|
||||
title: Text("Are you sure?"),
|
||||
content: Text(
|
||||
"If you close the session, you will need to re-enter the session code if you wish to load it again.",
|
||||
),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
SessionData.IsReadOnly = false;
|
||||
SessionData.Trips = [];
|
||||
SessionData.positions = [];
|
||||
SessionData.DisplayError = "";
|
||||
SessionData.StartTime = DateTime(0);
|
||||
SessionData.EndTime = DateTime(0);
|
||||
SessionData.LastSessionID = "";
|
||||
sessionIDController.text = "";
|
||||
|
||||
setState(() {});
|
||||
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text("Yes"),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text("Cancel"),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Text("Close Session"),
|
||||
),
|
||||
|
@ -119,7 +152,22 @@ class _WebMain extends State<WebMain> {
|
|||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
SessionData.LastSessionID = sessionIDController.text;
|
||||
await SessionData.DownloadData();
|
||||
bool success = await SessionData.DownloadData();
|
||||
|
||||
if (!success) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
"ERROR: The provided session code was not found on the server",
|
||||
style: TextStyle(fontSize: 18, color: Colors.white),
|
||||
),
|
||||
backgroundColor: LibACFlutterConstants.TITLEBAR_COLOR,
|
||||
),
|
||||
snackBarAnimationStyle: AnimationStyle(
|
||||
duration: Duration(seconds: 5),
|
||||
),
|
||||
);
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
child: Text("Load Session", style: TextStyle(fontSize: 18)),
|
||||
|
|
|
@ -45,20 +45,21 @@ class _WorkData extends State<WorkDataPage> {
|
|||
"Total saved GPS Positions: ${SessionData.positions.length}",
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
Text(
|
||||
"Start Date & Time: ${SessionData.StartTime.toString()}",
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
if (SessionData.IsReadOnly)
|
||||
if (SessionData.StartTime.year != 0)
|
||||
Text(
|
||||
"Start Date & Time: ${SessionData.StartTime.toString()}",
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
if (SessionData.IsReadOnly && SessionData.StartTime.year != 0)
|
||||
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)
|
||||
Text(
|
||||
"Total time worked: ${SessionData.GetTotalTimeWorked(SessionData.StartTime, SessionData.EndTime)}",
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
if (SessionData.StartTime.year == 0)
|
||||
ListTile(
|
||||
title: Text("ERROR"),
|
||||
|
@ -67,6 +68,20 @@ class _WorkData extends State<WorkDataPage> {
|
|||
),
|
||||
tileColor: LibACFlutterConstants.TITLEBAR_COLOR,
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
if (SessionData.TotalPay == null)
|
||||
ListTile(
|
||||
title: Text("ERROR"),
|
||||
subtitle: Text(
|
||||
"This TTX session file appears to have been saved in a early beta build. It does not contain the total pay.",
|
||||
),
|
||||
tileColor: LibACFlutterConstants.TITLEBAR_COLOR,
|
||||
),
|
||||
if (SessionData.TotalPay != null)
|
||||
Text(
|
||||
"Total Pay: ${SessionData.TotalPay!}",
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
|
||||
SizedBox(height: 20),
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: timetrack
|
||||
description: "A new Flutter project."
|
||||
description: "Time Track - A simple, yet effective GPS, time, and mile tracker"
|
||||
# The following line prevents the package from being accidentally published to
|
||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||
|
@ -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.8
|
||||
version: 1.0.0-beta.9
|
||||
|
||||
environment:
|
||||
sdk: ^3.7.2
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue