TimeTracker/lib/data.dart

228 lines
5.4 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'package:geolocator/geolocator.dart';
import 'package:libac_dart/utils/TimeUtils.dart';
import 'package:timetrack/consts.dart';
class SessionData {
static int StartTime = 0;
static get StartTimeAsDateTime =>
DateTime.fromMillisecondsSinceEpoch(StartTime * 1000);
static bool IsOnTheClock = false;
static List<Trip> Trips = [];
static Delivery? currentDelivery;
static Trip? currentTrip;
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();
IsOnTheClock = true;
bool hasGPS;
LocationPermission perm;
hasGPS = await Geolocator.isLocationServiceEnabled();
if (!hasGPS) {
IsOnTheClock = false;
return Future.error("Location services are disabled");
}
perm = await Geolocator.checkPermission();
if (perm == LocationPermission.denied) {
perm = await Geolocator.requestPermission();
if (perm == LocationPermission.denied) {
IsOnTheClock = false;
return Future.error("Location permissions are denied");
}
}
if (perm == LocationPermission.deniedForever) {
IsOnTheClock = false;
return Future.error(
"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();
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 {
Position pos = await Geolocator.getCurrentPosition(
locationSettings: TTConsts.LOCATION_SETTINGS,
);
return pos;
}
static Trip GetNewTrip({required double basePay}) {
currentTrip = Trip(BasePay: basePay);
Trips.add(currentTrip!);
return currentTrip!;
}
static Delivery GetNewDelivery() {
if (currentTrip != null) {
var dropOff = currentTrip!.startNewDelivery();
;
currentDelivery = dropOff;
return dropOff;
} else {
throw Exception("A delivery cannot exist without a trip");
}
}
static void EndTrip() {
currentDelivery = null;
currentTrip = null;
}
}
class Delivery {
double TipAmount = 0;
Position? endLocation;
DateTime StartTime = DateTime.now();
Delivery() {
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 = [];
DateTime StartTime = DateTime(0);
double BasePay = 0.0;
Trip({required this.BasePay}) {
StartTime = DateTime.now();
}
Delivery startNewDelivery() {
var delivery = Delivery();
deliveries.add(delivery);
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;
}
}