diff --git a/Speedo/ContentView.swift b/Speedo/ContentView.swift index ef91d93..8b77ee6 100644 --- a/Speedo/ContentView.swift +++ b/Speedo/ContentView.swift @@ -9,26 +9,28 @@ import SwiftUI import CoreLocation struct ContentView: View { - @StateObject private var locationManager = LocationManager() // ๐Ÿ“ Manages real-time GPS data + @StateObject private var locationManager = LocationManager() // ๐Ÿ“ Handles GPS updates - @State private var isMPH = true // ๐Ÿš— Speed unit toggle: true = MPH, false = KPH - @State private var previousLocation: CLLocation? // ๐Ÿ“Œ Track last known location to compute trip distance - @State private var tripDistanceMeters: Double = 0.0 // ๐Ÿ“ Track trip distance in meters + // ๐Ÿš— Speed unit toggle (true = MPH, false = KPH), persisted + @State private var isMPH: Bool = UserDefaults.standard.object(forKey: "SpeedUnitIsMPH") as? Bool ?? true - // ๐ŸŒ— Track current theme (loaded from UserDefaults) + @State private var previousLocation: CLLocation? // ๐Ÿ“Œ Last location to calculate distance + @State private var tripDistanceMeters: Double = 0.0 // ๐Ÿ“ Distance in meters + + // ๐ŸŒ— Theme (persisted) @State private var isDarkMode: Bool = UserDefaults.standard.bool(forKey: "DarkModeEnabled") - // ๐Ÿ‘๏ธ Track minimal view preference (loaded from UserDefaults) + // ๐Ÿ‘๏ธ Minimal view toggle (persisted) @State private var isMinimalView: Bool = UserDefaults.standard.bool(forKey: "MinimalViewEnabled") - // ๐Ÿง  Load trip distance if saved + // ๐Ÿง  Load saved trip distance init() { if let savedDistance = UserDefaults.standard.object(forKey: "TripDistance") as? Double { _tripDistanceMeters = State(initialValue: savedDistance) } } - // ๐Ÿงฎ Calculate speed based on unit selection + // ๐Ÿงฎ Current speed in selected unit var currentSpeed: Int { let multiplier = isMPH ? 1.0 : 1.60934 return Int(Double(locationManager.speed) * multiplier) @@ -39,14 +41,14 @@ struct ContentView: View { isMPH ? "mph" : "kph" } - // ๐Ÿ“ Distance label (miles or km) + // ๐Ÿ“ Trip distance display var distanceLabel: String { let distance = isMPH ? tripDistanceMeters * 0.000621371 : tripDistanceMeters / 1000 let roundedDistance = Int(distance.rounded()) return "\(roundedDistance) \(isMPH ? "miles" : "km")" } - // ๐ŸŽฏ Color indicator for GPS accuracy + // ๐ŸŽฏ Color based on GPS accuracy var accuracyColor: Color { switch locationManager.accuracy { case ..<10: @@ -58,7 +60,7 @@ struct ContentView: View { } } - // ๐ŸŽจ Theme-dependent color helpers + // ๐ŸŽจ Theme-dependent UI colors var foregroundColor: Color { isDarkMode ? .white : .black } @@ -78,7 +80,7 @@ struct ContentView: View { VStack(spacing: 30) { Spacer() - // โฉ Speed display and unit toggle + // ๐Ÿ”ข Speed and unit toggle HStack(alignment: .bottom, spacing: 4) { Text("\(currentSpeed)") .font(.system(size: 140, weight: .bold, design: .rounded)) @@ -88,13 +90,13 @@ struct ContentView: View { .font(.title2) .foregroundColor(secondaryTextColor) .onTapGesture { - isMPH.toggle() // ๐Ÿ” Tap to switch MPH/KPH + isMPH.toggle() + UserDefaults.standard.set(isMPH, forKey: "SpeedUnitIsMPH") // ๐Ÿ’พ Save unit preference } } - // ๐Ÿ“Š Only show details if not in minimal mode if !isMinimalView { - // Trip meter + reset icon + // ๐Ÿ“Š Trip distance + reset HStack(spacing: 8) { Text("Trip: \(distanceLabel)") .font(.title2) @@ -103,16 +105,16 @@ struct ContentView: View { Button(action: { tripDistanceMeters = 0 previousLocation = nil - UserDefaults.standard.set(0.0, forKey: "TripDistance") // ๐Ÿงน Clear saved trip + UserDefaults.standard.set(0.0, forKey: "TripDistance") // ๐Ÿงน Reset saved distance }) { - Image(systemName: "arrow.counterclockwise.circle") // ๐Ÿ”„ Reset icon + Image(systemName: "arrow.counterclockwise.circle") .font(.title2) .foregroundColor(secondaryTextColor) } - .buttonStyle(PlainButtonStyle()) // Remove button glow + .buttonStyle(PlainButtonStyle()) } - // GPS accuracy indicator + // ๐ŸŽฏ GPS Accuracy indicator Text(String(format: "GPS Accuracy: ยฑ%.0f meters", locationManager.accuracy)) .font(.headline) .foregroundColor(accuracyColor) @@ -122,14 +124,14 @@ struct ContentView: View { } .padding() - // โš™๏ธ Bottom control bar (eye + gear) + // โš™๏ธ Bottom toolbar (minimal mode + settings) VStack { Spacer() HStack { - // ๐Ÿ‘๏ธ Minimal view toggle + // ๐Ÿ‘๏ธ Toggle minimal view + persist Button(action: { isMinimalView.toggle() - UserDefaults.standard.set(isMinimalView, forKey: "MinimalViewEnabled") // ๐Ÿ’พ Save preference + UserDefaults.standard.set(isMinimalView, forKey: "MinimalViewEnabled") }) { Image(systemName: isMinimalView ? "eye.slash.fill" : "eye.fill") .font(.title2) @@ -139,7 +141,7 @@ struct ContentView: View { Spacer() - // โš™๏ธ Open system settings + // โš™๏ธ Open system Settings Button(action: { if let url = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(url) @@ -155,13 +157,13 @@ struct ContentView: View { } } - // ๐ŸŒ— Tap anywhere to toggle dark/light mode and save it + // ๐ŸŒ— Tap background to toggle dark/light mode and save it .onTapGesture { isDarkMode.toggle() - UserDefaults.standard.set(isDarkMode, forKey: "DarkModeEnabled") // ๐Ÿ’พ Save theme mode + UserDefaults.standard.set(isDarkMode, forKey: "DarkModeEnabled") } - // ๐Ÿšจ Show alert for location errors or denied permissions + // ๐Ÿšจ Handle location errors with alert .alert(isPresented: $locationManager.showAlert) { Alert( title: Text("Location Services"), @@ -174,13 +176,13 @@ struct ContentView: View { ) } - // ๐Ÿงฎ Update trip distance as new GPS data comes in + // ๐Ÿงฎ Track trip distance as location updates .onReceive(locationManager.$location) { location in if let newLocation = location { if let oldLocation = previousLocation { let distance = newLocation.distance(from: oldLocation) tripDistanceMeters += distance - UserDefaults.standard.set(tripDistanceMeters, forKey: "TripDistance") // ๐Ÿ’พ Save new trip value + UserDefaults.standard.set(tripDistanceMeters, forKey: "TripDistance") // ๐Ÿ’พ Save updated distance } previousLocation = newLocation }