Implement map

This commit is contained in:
zontreck 2025-05-15 19:49:19 -07:00
parent 69e82fcf4c
commit a5fa4e0309
7 changed files with 184 additions and 57 deletions

View file

@ -24,16 +24,17 @@ The app does not store data locally, due to the way android permissions function
# Implementation
- [ ] Basic UI
- [x] Basic UI
- [x] Permissions
- [x] Automatic updates
- [ ] GPS Tracking
- [ ] Formatting GPS on a viewable map
- [ ] Track driving hours
- [ ] Track trips
- [ ] Track stops/deliveries
- [ ] Track trip base pay
- [ ] Track each delivery's tips
- [x] GPS Tracking
- [x] Formatting GPS on a viewable map
- [x] Track driving hours
- [x] Track trips
- [x] Track stops/deliveries
- [x] Track trip base pay
- [x] Track each delivery's tips
- [ ] Map marker for each stop/delivery with text saying "Trip #X/DropOff #X\nBase Pay: $$$; Tip: $$$"
- [ ] Basic version of the app in readonly mode when deployed on a web server.
- [ ] Backend server
- [ ] PHP?

View file

@ -1,3 +1,3 @@
{
"alpha": "1.0.0-dev.7"
"alpha": "1.0.0-dev.8"
}

View file

@ -6,11 +6,12 @@ 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.7";
static const VERSION = "1.0.0-dev.8";
static bool UPDATE_AVAILABLE = false;
static UpdateChannel UPDATE_CHANNEL = UpdateChannel.alpha;
static final LocationSettings LOCATION_SETTINGS = LocationSettings(
accuracy: LocationAccuracy.bestForNavigation,
distanceFilter: 50,
);
static Future<void> checkUpdate() async {

View file

@ -53,6 +53,16 @@ class _HomePageState extends State<HomePage> {
},
leading: Icon(Icons.update),
),
ListTile(
title: Text("Trip Map"),
leading: Icon(Icons.map),
subtitle: Text(
"View a map of the route\n(NOTE: This is not live, and reflects the current state as of the time the map is opened.)",
),
onTap: () async {
await Navigator.pushNamed(context, "/map");
},
),
ListTile(
title: Text("RESET APP SESSION"),
onTap: () async {
@ -72,6 +82,10 @@ class _HomePageState extends State<HomePage> {
body: SingleChildScrollView(
child: Column(
children: [
Text(
"Hit engage when you are ready to go online and start tracking location data, and trips.",
style: TextStyle(fontSize: 18),
),
if (!SessionData.IsOnTheClock)
Center(
child: ElevatedButton(
@ -129,27 +143,6 @@ 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"),
),
],
);
}
@ -185,6 +178,57 @@ class _HomePageState extends State<HomePage> {
);
}
Widget GetNonTripWidgets() {
return Column(
children: [
ElevatedButton(
onPressed: () async {
var reply = await showDialog(
context: context,
builder: (builder) {
return InputPrompt(
title: "What is the base pay?",
prompt: "Enter the base pay amount below.",
type: InputPromptType.Number,
);
},
);
if (reply == null || reply == "") reply = "0";
double basePay = double.parse(reply as String);
SessionData.GetNewTrip(basePay: basePay);
SessionData.GetNewDelivery();
setState(() {});
},
child: Text("Start New 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();
setState(() {});
}
},
child: Text("End work day"),
),
],
);
}
Widget GetLoggedInWidgets() {
return Column(
children: [
@ -194,29 +238,7 @@ class _HomePageState extends State<HomePage> {
),
if (SessionData.currentTrip != null) GetTripWidgets(),
if (SessionData.currentDelivery != null) GetDeliveryWidgets(),
if (SessionData.currentTrip == null)
ElevatedButton(
onPressed: () async {
var reply = await showDialog(
context: context,
builder: (builder) {
return InputPrompt(
title: "What is the base pay?",
prompt: "Enter the base pay amount below.",
type: InputPromptType.Number,
);
},
);
if (reply == null || reply == "") reply = "0";
double basePay = double.parse(reply as String);
SessionData.GetNewTrip(basePay: basePay);
SessionData.GetNewDelivery();
setState(() {});
},
child: Text("Start New Trip"),
),
if (SessionData.currentTrip == null) GetNonTripWidgets(),
],
);
}

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:timetrack/pages/HomePage.dart';
import 'package:timetrack/pages/MapPage.dart';
import 'package:timetrack/pages/UpdateSettings.dart';
class MainApp extends StatefulWidget {
@ -21,7 +22,11 @@ class MainAppState extends State<MainApp> {
Widget build(BuildContext context) {
return MaterialApp(
title: "Time Tracker",
routes: {"/": (ctx) => HomePage(), "/upd": (ctx) => UpdateSettingsPage()},
routes: {
"/": (ctx) => HomePage(),
"/upd": (ctx) => UpdateSettingsPage(),
"/map": (ctx) => MapPage(),
},
theme: ThemeData.dark(),
);
}

97
lib/pages/MapPage.dart Normal file
View file

@ -0,0 +1,97 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:libacflutter/Constants.dart';
import 'package:timetrack/data.dart';
class MapPage extends StatefulWidget {
MapPage({super.key});
@override
State<StatefulWidget> createState() {
return _MapPage();
}
}
class _MapPage extends State<MapPage> {
MapController controller = MapController();
LatLng initialPosition = LatLng(0, 0);
List<LatLng> PointMap = [];
@override
void didChangeDependencies() {
PointMap = [];
var firstPos = SessionData.positions[0];
initialPosition = LatLng(firstPos.latitude, firstPos.longitude);
for (var position in SessionData.positions) {
PointMap.add(LatLng(position.latitude, position.longitude));
}
setState(() {});
super.didChangeDependencies();
}
@override
void dispose() {
print("Map page disposed");
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Time Tracker - Map View"),
backgroundColor: LibACFlutterConstants.TITLEBAR_COLOR,
actions: [
IconButton(
onPressed: () async {
didChangeDependencies();
},
icon: Icon(Icons.refresh),
),
],
),
body: GestureDetector(
onTap: FocusScope.of(context).unfocus,
child: SafeArea(
child: FlutterMap(
mapController: controller,
options: MapOptions(
minZoom: 1,
maxZoom: 30,
initialZoom: 15,
initialCenter: initialPosition,
keepAlive: false,
),
children: [
TileLayer(
urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
userAgentPackageName: "dev.zontreck.timetrack",
),
PolylineLayer(
polylines: [
Polyline(
points: PointMap,
color: Colors.blue,
borderStrokeWidth: 3,
borderColor: Colors.blue,
),
],
),
RichAttributionWidget(
attributions: [
TextSourceAttribution('OpenStreetMap contributors'),
],
),
],
),
),
),
);
}
}

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
# 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.7
version: 1.0.0-dev.8
environment:
sdk: ^3.7.2
@ -43,7 +43,8 @@ dependencies:
dio: ^5.8.0+1
ota_update: ^7.0.1
geolocator: ^14.0.0
free_map: ^2.0.3
flutter_map: ^8.1.1
latlong2: ^0.9.1
dev_dependencies:
flutter_test: