feat: initial project scaffold with Watch companion app
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import SwiftUI
|
||||
|
||||
struct ActiveWorkoutView: View {
|
||||
@ObservedObject var workoutManager: WorkoutManager
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 8) {
|
||||
if workoutManager.isResting {
|
||||
RestView(workoutManager: workoutManager)
|
||||
} else {
|
||||
SwimView(workoutManager: workoutManager)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
struct SwimView: View {
|
||||
@ObservedObject var workoutManager: WorkoutManager
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 6) {
|
||||
if let workout = workoutManager.selectedWorkout,
|
||||
workoutManager.currentSetIndex < workout.sets.count {
|
||||
let currentSet = workout.sets[workoutManager.currentSetIndex]
|
||||
|
||||
Text("Set \(workoutManager.currentSetIndex + 1)/\(workout.sets.count)")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
Text(currentSet.stroke)
|
||||
.font(.headline)
|
||||
.foregroundColor(.cyan)
|
||||
|
||||
Text("Rep \(workoutManager.currentRep + 1)/\(currentSet.repCount)")
|
||||
.font(.subheadline)
|
||||
|
||||
Text("\(currentSet.distancePerRep)m")
|
||||
.font(.system(size: 36, weight: .bold, design: .rounded))
|
||||
.foregroundColor(.cyan)
|
||||
}
|
||||
|
||||
Text(formatTime(workoutManager.elapsedSeconds))
|
||||
.font(.system(.title, design: .monospaced))
|
||||
|
||||
if workoutManager.heartRate > 0 {
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "heart.fill")
|
||||
.foregroundColor(.red)
|
||||
.font(.caption)
|
||||
Text("\(Int(workoutManager.heartRate))")
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
workoutManager.completeLap()
|
||||
} label: {
|
||||
Text("Complete Lap")
|
||||
.font(.headline)
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.tint(.cyan)
|
||||
|
||||
Button("End") {
|
||||
workoutManager.endWorkout()
|
||||
}
|
||||
.font(.caption)
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
|
||||
private func formatTime(_ seconds: TimeInterval) -> String {
|
||||
let mins = Int(seconds) / 60
|
||||
let secs = Int(seconds) % 60
|
||||
return String(format: "%d:%02d", mins, secs)
|
||||
}
|
||||
}
|
||||
|
||||
struct RestView: View {
|
||||
@ObservedObject var workoutManager: WorkoutManager
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 12) {
|
||||
Text("Rest")
|
||||
.font(.headline)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
Text(formatTime(workoutManager.restTimeRemaining))
|
||||
.font(.system(size: 44, weight: .bold, design: .monospaced))
|
||||
.foregroundColor(.cyan)
|
||||
|
||||
if let workout = workoutManager.selectedWorkout,
|
||||
workoutManager.currentSetIndex + 1 < workout.sets.count {
|
||||
let nextSet = workout.sets[workoutManager.currentSetIndex + 1]
|
||||
Text("Next: \(nextSet.stroke) \(nextSet.distancePerRep)m")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func formatTime(_ seconds: TimeInterval) -> String {
|
||||
let mins = Int(seconds) / 60
|
||||
let secs = Int(seconds) % 60
|
||||
return String(format: "%d:%02d", mins, secs)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user