2025-05-05 09:33:00 -07:00
|
|
|
//
|
|
|
|
|
// ContentView.swift
|
|
|
|
|
// Speedometer
|
|
|
|
|
//
|
|
|
|
|
// Created by Justin Oros on 5/2/2025.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import SwiftUI
|
|
|
|
|
import CoreLocation
|
|
|
|
|
|
|
|
|
|
struct ContentView: View {
|
|
|
|
|
@StateObject private var locationManager = LocationManager()
|
|
|
|
|
@State private var isMPH = true
|
|
|
|
|
@State private var previousLocation: CLLocation?
|
|
|
|
|
@State private var tripDistanceMeters: Double = 0.0
|
2025-05-05 10:02:55 -07:00
|
|
|
@State private var isDarkMode = true // 🌗 Track current theme
|
2025-05-05 09:33:00 -07:00
|
|
|
|
|
|
|
|
var currentSpeed: Int {
|
2025-05-05 10:02:55 -07:00
|
|
|
let multiplier = isMPH ? 1.0 : 1.60934
|
2025-05-05 09:33:00 -07:00
|
|
|
return Int(Double(locationManager.speed) * multiplier)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var unitLabel: String {
|
|
|
|
|
isMPH ? "mph" : "kph"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var distanceLabel: String {
|
|
|
|
|
let distance = isMPH ? tripDistanceMeters * 0.000621371 : tripDistanceMeters / 1000
|
|
|
|
|
let roundedDistance = Int(distance.rounded())
|
|
|
|
|
return "\(roundedDistance) \(isMPH ? "miles" : "km")"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var accuracyColor: Color {
|
|
|
|
|
switch locationManager.accuracy {
|
|
|
|
|
case ..<10:
|
|
|
|
|
return .green
|
|
|
|
|
case 10..<30:
|
|
|
|
|
return .orange
|
|
|
|
|
default:
|
|
|
|
|
return .red
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-05 10:02:55 -07:00
|
|
|
var foregroundColor: Color {
|
|
|
|
|
isDarkMode ? .white : .black
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var secondaryTextColor: Color {
|
|
|
|
|
isDarkMode ? .gray : .gray
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var backgroundColor: Color {
|
|
|
|
|
isDarkMode ? .black : .white
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-05 09:33:00 -07:00
|
|
|
var body: some View {
|
|
|
|
|
ZStack {
|
2025-05-05 10:02:55 -07:00
|
|
|
backgroundColor.ignoresSafeArea()
|
2025-05-05 09:33:00 -07:00
|
|
|
|
|
|
|
|
VStack(spacing: 30) {
|
|
|
|
|
Spacer()
|
|
|
|
|
|
|
|
|
|
HStack(alignment: .bottom, spacing: 4) {
|
|
|
|
|
Text("\(currentSpeed)")
|
|
|
|
|
.font(.system(size: 140, weight: .bold, design: .rounded))
|
2025-05-05 10:02:55 -07:00
|
|
|
.foregroundColor(foregroundColor)
|
2025-05-05 09:33:00 -07:00
|
|
|
|
|
|
|
|
Text(unitLabel)
|
|
|
|
|
.font(.title2)
|
2025-05-05 10:02:55 -07:00
|
|
|
.foregroundColor(secondaryTextColor)
|
2025-05-05 09:33:00 -07:00
|
|
|
.onTapGesture {
|
|
|
|
|
isMPH.toggle()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Text("Trip: \(distanceLabel)")
|
|
|
|
|
.font(.title2)
|
2025-05-05 10:02:55 -07:00
|
|
|
.foregroundColor(secondaryTextColor)
|
2025-05-05 09:33:00 -07:00
|
|
|
|
|
|
|
|
Text(String(format: "GPS Accuracy: ±%.0f meters", locationManager.accuracy))
|
|
|
|
|
.font(.headline)
|
|
|
|
|
.foregroundColor(accuracyColor)
|
|
|
|
|
|
|
|
|
|
Button(action: {
|
|
|
|
|
tripDistanceMeters = 0
|
|
|
|
|
previousLocation = nil
|
|
|
|
|
}) {
|
|
|
|
|
Text("Reset Trip")
|
|
|
|
|
.font(.headline)
|
|
|
|
|
.padding(.horizontal, 20)
|
|
|
|
|
.padding(.vertical, 10)
|
2025-05-05 10:02:55 -07:00
|
|
|
.background(secondaryTextColor)
|
|
|
|
|
.foregroundColor(backgroundColor)
|
2025-05-05 09:33:00 -07:00
|
|
|
.cornerRadius(12)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Spacer()
|
|
|
|
|
}
|
|
|
|
|
.padding()
|
|
|
|
|
|
|
|
|
|
VStack {
|
|
|
|
|
Spacer()
|
|
|
|
|
HStack {
|
|
|
|
|
Spacer()
|
|
|
|
|
Button(action: {
|
|
|
|
|
if let url = URL(string: UIApplication.openSettingsURLString) {
|
|
|
|
|
UIApplication.shared.open(url)
|
|
|
|
|
}
|
|
|
|
|
}) {
|
2025-05-05 10:02:55 -07:00
|
|
|
Image(systemName: "gearshape.fill")
|
2025-05-05 09:33:00 -07:00
|
|
|
.font(.title2)
|
2025-05-05 10:02:55 -07:00
|
|
|
.foregroundColor(foregroundColor)
|
2025-05-05 09:33:00 -07:00
|
|
|
.padding()
|
|
|
|
|
}
|
2025-05-05 10:02:55 -07:00
|
|
|
.padding(.bottom, 10)
|
2025-05-05 09:33:00 -07:00
|
|
|
}
|
2025-05-05 10:02:55 -07:00
|
|
|
.padding(.trailing)
|
2025-05-05 09:33:00 -07:00
|
|
|
}
|
|
|
|
|
}
|
2025-05-05 10:02:55 -07:00
|
|
|
.onTapGesture {
|
|
|
|
|
isDarkMode.toggle() // Toggle between black/white background
|
|
|
|
|
}
|
2025-05-05 09:33:00 -07:00
|
|
|
.alert(isPresented: $locationManager.showAlert) {
|
|
|
|
|
Alert(
|
|
|
|
|
title: Text("Location Services"),
|
|
|
|
|
message: Text(locationManager.alertMessage),
|
|
|
|
|
dismissButton: .default(Text("Settings")) {
|
|
|
|
|
if let url = URL(string: UIApplication.openSettingsURLString) {
|
|
|
|
|
UIApplication.shared.open(url)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
.onReceive(locationManager.$location) { location in
|
|
|
|
|
if let newLocation = location {
|
|
|
|
|
if let oldLocation = previousLocation {
|
|
|
|
|
let distance = newLocation.distance(from: oldLocation)
|
|
|
|
|
tripDistanceMeters += distance
|
|
|
|
|
}
|
|
|
|
|
previousLocation = newLocation
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|