Restructure into a three-tab app with Progress, goals, and Meditation
The UX redesign's first landing (spec in UX-REDESIGN.md): ContentView becomes a Today / Progress / Settings TabView, "Routine" replaces "Split" in every user-facing string and view name (code-level types keep their names), and workout starting moves to shared WorkoutStarter / StartedWorkoutNavigator plumbing. - New Progress tab: weekly goal streaks, workout trends, per-exercise weight progression, achievements, and the full history list (WorkoutLogsView -> WorkoutHistoryView). - Goals: stable categories workouts roll up to, managed from Settings. - New Meditation exercise + starter routine; timed sits record to Apple Health as Mind & Body sessions. Claude-Session: https://claude.ai/code/session_012qw2itfzKyEJ1HpsFt8Ex4
This commit is contained in:
@@ -61,7 +61,7 @@ enum SessionEndPlanner {
|
||||
!isRunning && !activeIDs(in: workouts).isEmpty
|
||||
}
|
||||
|
||||
/// The run whose split configures a self-started session: the most recently started
|
||||
/// The run whose routine configures a self-started session: the most recently started
|
||||
/// active one (ties broken by id for determinism).
|
||||
static func runToStart(in workouts: [WorkoutDocument]) -> WorkoutDocument? {
|
||||
let ids = activeIDs(in: workouts)
|
||||
@@ -148,17 +148,17 @@ final class WorkoutSessionCoordinator {
|
||||
}
|
||||
|
||||
/// Self-start a session when an active run has none (see `SessionEndPlanner.shouldStart`).
|
||||
/// The activity type comes from the run's split so the saved Health workout is categorized
|
||||
/// the same way a phone-launched one would be; a run whose split is gone (deleted, or not
|
||||
/// The activity type comes from the run's routine so the saved Health workout is categorized
|
||||
/// the same way a phone-launched one would be; a run whose routine is gone (deleted, or not
|
||||
/// yet synced) falls back to traditional strength training.
|
||||
private func startIfNeeded(workouts: [WorkoutDocument]) {
|
||||
guard SessionEndPlanner.shouldStart(isRunning: sessionManager.isRunning, workouts: workouts),
|
||||
let run = SessionEndPlanner.runToStart(in: workouts) else { return }
|
||||
let split = run.splitID.flatMap { id in
|
||||
(try? context.fetch(FetchDescriptor<Split>())).flatMap { $0.first { $0.id == id } }
|
||||
let routine = run.routineID.flatMap { id in
|
||||
(try? context.fetch(FetchDescriptor<Routine>())).flatMap { $0.first { $0.id == id } }
|
||||
}
|
||||
let configuration = HKWorkoutConfiguration()
|
||||
configuration.activityType = split?.activityTypeEnum.hkActivityType ?? .traditionalStrengthTraining
|
||||
configuration.activityType = routine?.activityTypeEnum.hkActivityType ?? .traditionalStrengthTraining
|
||||
configuration.locationType = .indoor
|
||||
sessionManager.start(with: configuration)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user