Show only the day's docket on the Today board and add ad hoc Now workouts

- Due-filter schedules: daily always, fixed days by weekday, one-offs on
  their date; rest days get an empty state
- Workouts with no due schedule row (ad hoc or off-day starts) now render
  as their own board rows
- The + sheet is now "New Workout" with a "When" picker; "Now" (offered
  when adding on today) skips the schedule and starts the workout directly
- Remove the times-per-week scheduling mode everywhere (enum, document,
  entity, mappers, planner, seeds, tests)
This commit is contained in:
2026-07-11 11:09:11 -04:00
parent 9dc9283b4c
commit 7cb2d6da26
14 changed files with 231 additions and 199 deletions
+5 -8
View File
@@ -198,14 +198,13 @@ extension GoalKind {
/// How often a schedule expects its routine. Raw values are persisted in ScheduleDocument.
enum ScheduleRecurrence: String, CaseIterable, Codable, Sendable {
case once, daily, fixedDays, frequency
case once, daily, fixedDays
var displayName: String {
switch self {
case .once: "Once"
case .daily: "Daily"
case .fixedDays: "Fixed Days"
case .frequency: "Times per Week"
}
}
}
@@ -213,10 +212,10 @@ enum ScheduleRecurrence: String, CaseIterable, Codable, Sendable {
extension ScheduleRecurrence {
/// Human-readable recurrence description shared by `ScheduleDocument` and the
/// `Schedule` cache entity, so both render identically. `weekdays` uses Calendar
/// weekday numbers (1 = Sun 7 = Sat); `timesPerWeek` is the frequency count;
/// `date` is the one-off day (`.once` only). A degenerate case (fixed days with no
/// weekdays, a nil count or date) falls back to the recurrence's own `displayName`.
func summary(weekdays: [Int]?, timesPerWeek: Int?, date: Date?) -> String {
/// weekday numbers (1 = Sun 7 = Sat); `date` is the one-off day (`.once` only).
/// A degenerate case (fixed days with no weekdays, a nil date) falls back to the
/// recurrence's own `displayName`.
func summary(weekdays: [Int]?, date: Date?) -> String {
switch self {
case .once:
return date?.formatDate() ?? displayName // "Jul 12, 2026" / "Once"
@@ -230,8 +229,6 @@ extension ScheduleRecurrence {
(1...7).contains(n) ? symbols[n - 1] : nil
}
return names.isEmpty ? displayName : Self.joined(names)
case .frequency:
return "\(timesPerWeek ?? 0)× per week"
}
}