Add position logging, and ability to end the work day
This commit is contained in:
parent
770c1e7c74
commit
69e82fcf4c
5 changed files with 141 additions and 15 deletions
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"alpha": "1.0.0-dev.6"
|
||||
"alpha": "1.0.0-dev.7"
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import 'package:geolocator/geolocator.dart';
|
|||
class TTConsts {
|
||||
static get UPDATE_URL =>
|
||||
"https://git.zontreck.com/AriasCreations/TimeTracker/raw/branch/main/latest-releases.json";
|
||||
static const VERSION = "1.0.0-dev.6";
|
||||
static const VERSION = "1.0.0-dev.7";
|
||||
static bool UPDATE_AVAILABLE = false;
|
||||
static UpdateChannel UPDATE_CHANNEL = UpdateChannel.alpha;
|
||||
static final LocationSettings LOCATION_SETTINGS = LocationSettings(
|
||||
|
|
128
lib/data.dart
128
lib/data.dart
|
@ -1,3 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:libac_dart/utils/TimeUtils.dart';
|
||||
import 'package:timetrack/consts.dart';
|
||||
|
@ -14,7 +17,11 @@ class SessionData {
|
|||
|
||||
static Delivery? currentDelivery;
|
||||
static Trip? currentTrip;
|
||||
List<Position> positions = [];
|
||||
static List<Position> positions = [];
|
||||
static late StreamSubscription<Position> _listener;
|
||||
|
||||
/// This flag is usually set when data is loaded from a saved state. Or when accessed using the Web version of the app.
|
||||
static bool IsReadOnly = false;
|
||||
|
||||
static Future<void> Login() async {
|
||||
StartTime = TimeUtils.getUnixTimestamp();
|
||||
|
@ -44,12 +51,68 @@ class SessionData {
|
|||
"Location permissions are denied permanently. Login cannot proceed.",
|
||||
);
|
||||
}
|
||||
|
||||
_listener = Geolocator.getPositionStream(
|
||||
locationSettings: TTConsts.LOCATION_SETTINGS,
|
||||
).listen((pos) {
|
||||
if (!IsOnTheClock) {
|
||||
_listener.cancel();
|
||||
return;
|
||||
}
|
||||
positions.add(pos);
|
||||
});
|
||||
}
|
||||
|
||||
static Future<void> Logout() async {
|
||||
IsOnTheClock = false;
|
||||
currentDelivery = null;
|
||||
currentTrip = null;
|
||||
_listener.cancel();
|
||||
|
||||
// TODO: Do other tasks to finalize the saved work data.
|
||||
var saveData = SaveData();
|
||||
print(saveData);
|
||||
|
||||
Trips = [];
|
||||
positions = [];
|
||||
|
||||
// TODO: Upload to the server.
|
||||
}
|
||||
|
||||
static String SaveData() {
|
||||
Map<String, dynamic> saveData = {};
|
||||
|
||||
List<Map<String, dynamic>> _trips = [];
|
||||
for (var trip in Trips) {
|
||||
_trips.add(trip.toJsonMap());
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> _pos = [];
|
||||
for (var pos in positions) {
|
||||
_pos.add(pos.toJson());
|
||||
}
|
||||
|
||||
saveData["trips"] = _trips;
|
||||
saveData["positions"] = _pos;
|
||||
|
||||
return json.encode(saveData);
|
||||
}
|
||||
|
||||
void LoadData(String js) {
|
||||
Map<String, dynamic> _js = json.decode(js);
|
||||
List<Map<String, dynamic>> _trips =
|
||||
_js['trips'] as List<Map<String, dynamic>>;
|
||||
List<Map<String, dynamic>> _pos =
|
||||
_js['positions'] as List<Map<String, dynamic>>;
|
||||
|
||||
for (var trip in _trips) {
|
||||
Trips.add(Trip.fromJsonMap(trip));
|
||||
}
|
||||
|
||||
for (var position in _pos) {
|
||||
positions.add(Position.fromMap(position));
|
||||
}
|
||||
|
||||
IsReadOnly = true;
|
||||
}
|
||||
|
||||
static Future<Position> GetNewLocation() async {
|
||||
|
@ -84,32 +147,48 @@ class SessionData {
|
|||
|
||||
class Delivery {
|
||||
double TipAmount = 0;
|
||||
late Position endLocation;
|
||||
int StartTime = 0;
|
||||
DateTime get StartTimeAsDateTime =>
|
||||
DateTime.fromMillisecondsSinceEpoch(StartTime * 1000);
|
||||
Position? endLocation;
|
||||
DateTime StartTime = DateTime.now();
|
||||
|
||||
Delivery() {
|
||||
StartTime = TimeUtils.getUnixTimestamp();
|
||||
StartTime = DateTime.now();
|
||||
}
|
||||
|
||||
Future<void> MarkEndLocation() async {
|
||||
var pos = await SessionData.GetNewLocation();
|
||||
endLocation = pos;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJsonMap() {
|
||||
return {
|
||||
"tip": TipAmount,
|
||||
"start": StartTime.toString(),
|
||||
"endPos": endLocation?.toJson() ?? "incomplete",
|
||||
};
|
||||
}
|
||||
|
||||
static Delivery fromMap(Map<String, dynamic> jsx) {
|
||||
Delivery delivery = Delivery();
|
||||
delivery.StartTime = DateTime.parse(jsx['start'] as String);
|
||||
delivery.TipAmount = jsx['tip'] as double;
|
||||
if (jsx['endPos'] as String == "incomplete")
|
||||
delivery.endLocation = null;
|
||||
else
|
||||
delivery.endLocation = Position.fromMap(jsx['endPos']);
|
||||
|
||||
return delivery;
|
||||
}
|
||||
}
|
||||
|
||||
class Trip {
|
||||
List<Delivery> deliveries = [];
|
||||
|
||||
int StartTime = 0;
|
||||
DateTime get StartTimeAsDateTime =>
|
||||
DateTime.fromMillisecondsSinceEpoch(StartTime * 1000);
|
||||
DateTime StartTime = DateTime(0);
|
||||
|
||||
double BasePay = 0.0;
|
||||
|
||||
Trip({required this.BasePay}) {
|
||||
StartTime = TimeUtils.getUnixTimestamp();
|
||||
StartTime = DateTime.now();
|
||||
}
|
||||
|
||||
Delivery startNewDelivery() {
|
||||
|
@ -118,4 +197,31 @@ class Trip {
|
|||
|
||||
return delivery;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJsonMap() {
|
||||
Map<String, Object> _trip = {"start": StartTime.toString(), "pay": BasePay};
|
||||
List<Map<String, dynamic>> _dropOffs = [];
|
||||
for (var delivery in deliveries) {
|
||||
_dropOffs.add(delivery.toJsonMap());
|
||||
}
|
||||
|
||||
_trip["deliveries"] = _dropOffs;
|
||||
|
||||
return _trip;
|
||||
}
|
||||
|
||||
static Trip fromJsonMap(Map<String, dynamic> jsx) {
|
||||
Trip trip = Trip(BasePay: 0);
|
||||
trip.BasePay = jsx['pay'] as double;
|
||||
trip.StartTime = DateTime.parse(jsx['start'] as String);
|
||||
trip.deliveries = [];
|
||||
List<Map<String, dynamic>> _dropOffs =
|
||||
jsx['deliveries'] as List<Map<String, dynamic>>;
|
||||
|
||||
for (var dropOff in _dropOffs) {
|
||||
trip.deliveries.add(Delivery.fromMap(dropOff));
|
||||
}
|
||||
|
||||
return trip;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:libac_dart/utils/TimeUtils.dart';
|
||||
import 'package:libacflutter/Constants.dart';
|
||||
import 'package:libacflutter/Prompt.dart';
|
||||
import 'package:timetrack/consts.dart';
|
||||
|
@ -130,6 +129,27 @@ class _HomePageState extends State<HomePage> {
|
|||
},
|
||||
child: Text("END TRIP"),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
if (SessionData.currentTrip != null ||
|
||||
SessionData.currentDelivery != null) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (build) {
|
||||
return AlertDialog(
|
||||
title: Text("Cannot end work day"),
|
||||
content: Text(
|
||||
"You must end the trip and any delivery before you can fully end the work day.",
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
SessionData.Logout();
|
||||
}
|
||||
},
|
||||
child: Text("End work day"),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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-dev.6
|
||||
version: 1.0.0-dev.7
|
||||
|
||||
environment:
|
||||
sdk: ^3.7.2
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue