Added Minimal View.
Tap the eye icon to toggle Minimal view.
This commit is contained in:
1 parent
ad9fc7c03c
commit
2aad798a56
1 file changed
+43
-5
@@ -9,27 +9,41 @@ import SwiftUI
|
|||||||
import CoreLocation
|
import CoreLocation
|
||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
|
// Location manager to track speed and position
|
||||||
@StateObject private var locationManager = LocationManager()
|
@StateObject private var locationManager = LocationManager()
|
||||||
|
|
||||||
|
// Unit toggle (true = MPH, false = KPH)
|
||||||
@State private var isMPH = true
|
@State private var isMPH = true
|
||||||
|
|
||||||
|
// For tracking total trip distance
|
||||||
@State private var previousLocation: CLLocation?
|
@State private var previousLocation: CLLocation?
|
||||||
@State private var tripDistanceMeters: Double = 0.0
|
@State private var tripDistanceMeters: Double = 0.0
|
||||||
@State private var isDarkMode = true // 🌗 Track current theme
|
|
||||||
|
|
||||||
|
// Dark mode toggle
|
||||||
|
@State private var isDarkMode = true
|
||||||
|
|
||||||
|
// Controls whether only speed is shown (minimal view)
|
||||||
|
@State private var isMinimalView = false
|
||||||
|
|
||||||
|
// Computed speed based on selected unit
|
||||||
var currentSpeed: Int {
|
var currentSpeed: Int {
|
||||||
let multiplier = isMPH ? 1.0 : 1.60934
|
let multiplier = isMPH ? 1.0 : 1.60934
|
||||||
return Int(Double(locationManager.speed) * multiplier)
|
return Int(Double(locationManager.speed) * multiplier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Label for speed unit
|
||||||
var unitLabel: String {
|
var unitLabel: String {
|
||||||
isMPH ? "mph" : "kph"
|
isMPH ? "mph" : "kph"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Distance label (formatted with appropriate unit)
|
||||||
var distanceLabel: String {
|
var distanceLabel: String {
|
||||||
let distance = isMPH ? tripDistanceMeters * 0.000621371 : tripDistanceMeters / 1000
|
let distance = isMPH ? tripDistanceMeters * 0.000621371 : tripDistanceMeters / 1000
|
||||||
let roundedDistance = Int(distance.rounded())
|
let roundedDistance = Int(distance.rounded())
|
||||||
return "\(roundedDistance) \(isMPH ? "miles" : "km")"
|
return "\(roundedDistance) \(isMPH ? "miles" : "km")"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Color indicating GPS accuracy
|
||||||
var accuracyColor: Color {
|
var accuracyColor: Color {
|
||||||
switch locationManager.accuracy {
|
switch locationManager.accuracy {
|
||||||
case ..<10:
|
case ..<10:
|
||||||
@@ -41,6 +55,7 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Text and background colors based on theme
|
||||||
var foregroundColor: Color {
|
var foregroundColor: Color {
|
||||||
isDarkMode ? .white : .black
|
isDarkMode ? .white : .black
|
||||||
}
|
}
|
||||||
@@ -55,11 +70,14 @@ struct ContentView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
|
// Full-screen background color
|
||||||
backgroundColor.ignoresSafeArea()
|
backgroundColor.ignoresSafeArea()
|
||||||
|
|
||||||
|
// Main vertical layout
|
||||||
VStack(spacing: 30) {
|
VStack(spacing: 30) {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
// Speed display with unit
|
||||||
HStack(alignment: .bottom, spacing: 4) {
|
HStack(alignment: .bottom, spacing: 4) {
|
||||||
Text("\(currentSpeed)")
|
Text("\(currentSpeed)")
|
||||||
.font(.system(size: 140, weight: .bold, design: .rounded))
|
.font(.system(size: 140, weight: .bold, design: .rounded))
|
||||||
@@ -69,18 +87,23 @@ struct ContentView: View {
|
|||||||
.font(.title2)
|
.font(.title2)
|
||||||
.foregroundColor(secondaryTextColor)
|
.foregroundColor(secondaryTextColor)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
isMPH.toggle()
|
isMPH.toggle() // Toggle between mph and kph
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show trip info and controls only if not in minimal view
|
||||||
|
if !isMinimalView {
|
||||||
|
// Trip distance
|
||||||
Text("Trip: \(distanceLabel)")
|
Text("Trip: \(distanceLabel)")
|
||||||
.font(.title2)
|
.font(.title2)
|
||||||
.foregroundColor(secondaryTextColor)
|
.foregroundColor(secondaryTextColor)
|
||||||
|
|
||||||
|
// GPS accuracy
|
||||||
Text(String(format: "GPS Accuracy: ±%.0f meters", locationManager.accuracy))
|
Text(String(format: "GPS Accuracy: ±%.0f meters", locationManager.accuracy))
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
.foregroundColor(accuracyColor)
|
.foregroundColor(accuracyColor)
|
||||||
|
|
||||||
|
// Reset trip button
|
||||||
Button(action: {
|
Button(action: {
|
||||||
tripDistanceMeters = 0
|
tripDistanceMeters = 0
|
||||||
previousLocation = nil
|
previousLocation = nil
|
||||||
@@ -93,15 +116,29 @@ struct ContentView: View {
|
|||||||
.foregroundColor(backgroundColor)
|
.foregroundColor(backgroundColor)
|
||||||
.cornerRadius(12)
|
.cornerRadius(12)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
|
|
||||||
|
// Overlay controls (bottom corners)
|
||||||
VStack {
|
VStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
HStack {
|
HStack {
|
||||||
|
// 👁 Eye icon to toggle minimal view (bottom-left)
|
||||||
|
Button(action: {
|
||||||
|
isMinimalView.toggle()
|
||||||
|
}) {
|
||||||
|
Image(systemName: isMinimalView ? "eye.slash.fill" : "eye.fill")
|
||||||
|
.font(.title2)
|
||||||
|
.foregroundColor(foregroundColor)
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
// ⚙️ Gear icon to open app settings (bottom-right)
|
||||||
Button(action: {
|
Button(action: {
|
||||||
if let url = URL(string: UIApplication.openSettingsURLString) {
|
if let url = URL(string: UIApplication.openSettingsURLString) {
|
||||||
UIApplication.shared.open(url)
|
UIApplication.shared.open(url)
|
||||||
@@ -112,15 +149,15 @@ struct ContentView: View {
|
|||||||
.foregroundColor(foregroundColor)
|
.foregroundColor(foregroundColor)
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
.padding(.bottom, 10)
|
|
||||||
}
|
}
|
||||||
.padding(.trailing)
|
.padding([.leading, .trailing, .bottom], 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
isDarkMode.toggle() // Toggle between black/white background
|
isDarkMode.toggle() // Toggle between light and dark mode
|
||||||
}
|
}
|
||||||
.alert(isPresented: $locationManager.showAlert) {
|
.alert(isPresented: $locationManager.showAlert) {
|
||||||
|
// Show alert if location services are unavailable
|
||||||
Alert(
|
Alert(
|
||||||
title: Text("Location Services"),
|
title: Text("Location Services"),
|
||||||
message: Text(locationManager.alertMessage),
|
message: Text(locationManager.alertMessage),
|
||||||
@@ -131,6 +168,7 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// Track location updates and calculate distance
|
||||||
.onReceive(locationManager.$location) { location in
|
.onReceive(locationManager.$location) { location in
|
||||||
if let newLocation = location {
|
if let newLocation = location {
|
||||||
if let oldLocation = previousLocation {
|
if let oldLocation = previousLocation {
|
||||||
|
|||||||
Reference in new issue
Block a user