-
Notifications
You must be signed in to change notification settings - Fork 0
/
ContentView.swift
182 lines (162 loc) · 7.08 KB
/
ContentView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Summary: ContentView manages the overall app state, switching between welcome, start, and recording screens.
import SwiftUI
import CoreLocation
import WatchKit
// Stores travel-related information like distance, speed, and time
struct TravelData: Hashable {
var milesTraveled: Double
var topSpeed: Double
var averageSpeed: Double
var totalTime: Int
var elapsedTime: String
}
// Defines navigation items for the app, currently only handling recorded travel data
enum NavigationItem: Hashable {
case travelRecorded(TravelData)
}
// Managing overall app state and navigation. Handles recording state, GPS signal, and user interactions. Displays different screens based on app state (welcome, start, or recording)
struct ContentView: View {
@State private var showSettings = false
@StateObject private var locationManager = LocationManager()
@State private var selectedTab = 1
@State private var isLocked = false
@State private var paused = false
@State private var navigationPath = NavigationPath()
@State private var showWaypointScreen = false
@State private var creatingWaypoint = false
@State private var elapsedTime = 0
@StateObject private var userSettings = UserSettings()
@State private var obtainedGPS = false
@State private var showWelcomeScreen: Bool = UserDefaults.standard.bool(forKey: "showWelcomeScreen") == false
var body: some View {
NavigationStack(path: $navigationPath) {
Group {
if showWelcomeScreen {
WelcomeScreen(showWelcomeScreen: $showWelcomeScreen)
} else if locationManager.recording {
RecordingTabs(selectedTab: $selectedTab,
locationManager: locationManager,
isLocked: $isLocked,
paused: $paused,
showWaypointScreen: $showWaypointScreen,
creatingWaypoint: $creatingWaypoint,
navigationPath: $navigationPath,
prepareTravelData: prepareTravelData,
elapsedTime: elapsedTime)
} else {
StartScreen(showSettings: $showSettings,
obtainedGPS: $obtainedGPS,
locationManager: locationManager,
startRecording: startRecording)
}
}
.navigationDestination(for: NavigationItem.self) { item in
switch item {
case .travelRecorded(let travelData):
TravelRecordedView(travelData: travelData, navigationPath: $navigationPath, locationManager: locationManager)
}
}
.background(userSettings.isDarkMode ? Color.white.opacity(1.0) : Color.black.opacity(1.0))
.fullScreenCover(isPresented: $showWaypointScreen) {
WaypointCreationView(creatingWaypoint: $creatingWaypoint)
}
}
.onChange(of: locationManager.obtainedGPS) {
obtainedGPS = locationManager.obtainedGPS
}
.sheet(isPresented: $showSettings) {
SettingsView()
.environmentObject(userSettings)
}
}
// Initiates the recording process, resets relevant data, and updates the UI
private func startRecording() {
withAnimation {
locationManager.elevationReadings.removeAll()
Haptics.vibrate(.start)
elapsedTime = 0
locationManager.startRecording()
selectedTab = 1 // recordingViewTab
creatingWaypoint = false
locationManager.moderateAltitudeNotificationSent = false
locationManager.highAltitudeNotificationSent = false
}
}
// Gathers current travel data from the location manager for display or storage
func prepareTravelData() -> TravelData {
return TravelData(
milesTraveled: locationManager.distance,
topSpeed: locationManager.topSpeed,
averageSpeed: locationManager.averageSpeed,
totalTime: elapsedTime,
elapsedTime: locationManager.totalTimeTextTimer
)
}
}
// Manages the tab view displayed during recording. Includes tabs for various features like Now Playing, Waypoint, Speed Target, etc.
struct RecordingTabs: View {
@Binding var selectedTab: Int
@ObservedObject var locationManager: LocationManager
@Binding var isLocked: Bool
@Binding var paused: Bool
@Binding var showWaypointScreen: Bool
@Binding var creatingWaypoint: Bool
@Binding var navigationPath: NavigationPath
let prepareTravelData: () -> TravelData
let elapsedTime: Int
var body: some View {
TabView(selection: $selectedTab) {
NowPlayingView()
.tabItem { Text("Now Playing") }
.tag(-3)
SpeedGoalScreen(locationManager: locationManager)
.tabItem { Text("Target Speed") }
.tag(-2)
WaypointScreen(locationManager: locationManager)
.tabItem { Text("Waypoint")}
.tag(-1)
CompassScreen(viewModel: locationManager)
.tabItem { Text("Waypoint")}
.tag(0)
RecordingView(locationManager: locationManager)
.tabItem { Text("Recording") }
.tag(1)
OptionsScreen(isLocked: $isLocked, showWaypointScreen: $showWaypointScreen, creatingWaypoint: $creatingWaypoint, selectedTab: $selectedTab, locationManager: locationManager, navigationPath: $navigationPath, prepareTravelData: prepareTravelData, elapsedTime: elapsedTime)
.tabItem { Text("Stop Recording") }
.tag(3)
}
.animation(.easeInOut(duration: 0.3), value: selectedTab)
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
}
}
// Shows a simple view when creating a new waypoint
struct WaypointCreationView: View {
@Binding var creatingWaypoint: Bool
var body: some View {
VStack {
Spacer()
Shine(
iconName: "mappin.and.ellipse",
text: "Creating waypoint",
baseColor: Color(hex: "#545454")
)
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.black.edgesIgnoringSafeArea(.all))
}
}
extension Color {
init(hex: String) {
let scanner = Scanner(string: hex)
_ = scanner.scanString("#")
var rgbValue: UInt64 = 0
scanner.scanHexInt64(&rgbValue)
let red = Double((rgbValue >> 16) & 0xFF) / 255.0
let green = Double((rgbValue >> 8) & 0xFF) / 255.0
let blue = Double(rgbValue & 0xFF) / 255.0
self.init(red: red, green: green, blue: blue)
}
}