Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions Strand/Collect/RawHistoryArchive.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,6 @@ struct RawHistoryArchive {
/// kept as distinct buckets (their layouts differ despite the shared version number).
private struct VersionKey: Hashable { let family: String; let version: Int }

private func versionKey(family: DeviceFamily, version: Int) -> VersionKey {
VersionKey(family: family.rawValue, version: version)
}

/// Durably append `frames` as JSONL. `trim`/`family` tag each line so the corpus is replayable.
/// Empty input is a no-op success. See `Result` for the ack contract.
///
Expand Down
7 changes: 0 additions & 7 deletions Strand/Screens/BiofeedbackController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,6 @@ final class BiofeedbackController: ObservableObject {
model.buzz(loops: UInt8(clamping: loops), gate: HapticPrefs.breathing)
}

/// Schedule one cancellable buzz at `offsetMs` from now (the asyncAfter walk, cancellable on stop).
private func scheduleBuzz(loops: Int, afterMs: Int) {
let item = DispatchWorkItem { [weak self] in self?.fireBuzz(loops: loops) }
pending.append(item)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(afterMs), execute: item)
}

private func startSecondTimer() {
elapsedSeconds = 0
secondTimer = Timer.publish(every: 1, on: .main, in: .common)
Expand Down
2 changes: 0 additions & 2 deletions Strand/Screens/FullDayChartView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ struct FullDayChartView: View {
/// The visible window the chart's gestures mutate. nil → full day (the chart falls back to `dayBounds`).
@State private var zoomDomain: ClosedRange<Date>? = nil
@State private var loading = true
/// Bumped on every settled zoom/metric change so the re-read task re-runs at the new resolution.
@State private var reloadTick = 0

/// The full clamp the zoom window can never escape — the selected calendar day.
private var dayBounds: ClosedRange<Date> {
Expand Down
8 changes: 0 additions & 8 deletions Strand/Screens/IntervalTimerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,6 @@ struct IntervalTimerView: View {
}
}

private var phaseTone: StrandTone {
switch phase {
case .work: return .accent
case .rest: return .neutral
case .done: return .positive
}
}

private var isFinished: Bool { phase == .done }

// MARK: Body
Expand Down
3 changes: 0 additions & 3 deletions Strand/Screens/LiveView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -979,9 +979,6 @@ private struct LivePhysiology: View {
/// Oura ring actively streaming live HR — trusted stream without a WHOOP bond (see LiveView.ringStreaming).
private var ringStreaming: Bool { live.connected && live.streamingLiveHR }

/// The liquid heart pink (matches LiquidThread's default + the mockup #ff6b81).
private let liquidHeart = Color(.sRGB, red: 1, green: 107 / 255, blue: 129 / 255, opacity: 1)

var body: some View {
VStack(alignment: .leading, spacing: NoopMetrics.space4) {
HStack(alignment: .firstTextBaseline) {
Expand Down
16 changes: 0 additions & 16 deletions Strand/Screens/LiveWorkoutView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -437,22 +437,6 @@ struct LiveWorkoutView: View {
.accessibilityLabel(Text("Delete"))
}

private var activeSportName: String {
model.activeWorkout?.sport ?? WorkoutCatalog.defaultSportName
}

private var workoutTypeGlassButton: some View {
Button {
// Placeholder — sport-type picker lands later; chrome and sizing stay put.
} label: {
WorkoutTypeIcon(workoutType: activeSportName, size: 22, weight: .semibold)
.frame(width: Self.bottomControlDiameter, height: Self.bottomControlDiameter)
.contentShape(Circle())
}
.nativeLiquidGlassWorkoutControl()
.accessibilityLabel(Text("\(WorkoutSource.displaySport(activeSportName)) workout"))
}

// MARK: - Helpers

/// Delegates to the shared clock. This carried its own `%d:%02d` with NO hour roll-over, so a
Expand Down
553 changes: 0 additions & 553 deletions Strand/Screens/SettingsView.swift

Large diffs are not rendered by default.

8 changes: 0 additions & 8 deletions Strand/Screens/SleepView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2224,14 +2224,6 @@ struct SleepView: View {
return stages.total > 0 ? (stages, intervals) : nil
}

/// yyyy-MM-dd → Date (en_US_POSIX, UTC), per task spec.
private static let dayParser: DateFormatter = {
let f = DateFormatter()
f.locale = Locale(identifier: "en_US_POSIX")
f.timeZone = TimeZone(identifier: "UTC")
f.dateFormat = "yyyy-MM-dd"
return f
}()
}

/// Original atmospheric night hero — photographic moonlit lake plus lightweight static depth layers.
Expand Down
98 changes: 0 additions & 98 deletions Strand/Screens/TodayView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1711,69 +1711,6 @@ struct TodayView: View {

// MARK: First-run scoring-guide card (one-time, dismissible)

/// "New here?", a single, dismissible card that points first-time users at the guide. Tapping the
/// card opens the guide; the ✕ closes it. Either action sets `scoringGuideCardSeen`, so it shows
/// once and never again. Follows the in-flow, never-modal card pattern.
private var scoringGuideFirstRunCard: some View {
NoopCard {
HStack(alignment: .top, spacing: 14) {
Image(systemName: "sparkles")
.font(.system(size: 18))
.foregroundStyle(StrandPalette.accent)
.accessibilityHidden(true)
VStack(alignment: .leading, spacing: 4) {
Text("New here?")
.font(StrandFont.headline)
.foregroundStyle(StrandPalette.textPrimary)
Text("See how Charge, Effort and Rest are calculated, and how they differ from WHOOP.")
.font(StrandFont.subhead)
.foregroundStyle(StrandPalette.textSecondary)
.fixedSize(horizontal: false, vertical: true)
Button {
scoringGuideCardSeen = true
showGuideTop = true
} label: {
Label("How your scores work", systemImage: "arrow.right")
.font(StrandFont.subhead)
}
.buttonStyle(.plain)
.foregroundStyle(StrandPalette.accent)
.padding(.top, 2)
}
Spacer(minLength: 0)
Button {
// Dismiss INTO the Updates inbox (restorable), rather than permanently hiding.
withAnimation(StrandMotion.interactive) {
dismissTodayCard(
id: "newHere",
title: String(localized: "New here?"),
message: String(localized: "How Charge, Effort and Rest are calculated, and how they differ from WHOOP.")
)
}
} label: {
Image(systemName: "xmark")
.font(.system(size: 12, weight: .semibold))
.foregroundStyle(StrandPalette.textTertiary)
.padding(6)
.contentShape(Rectangle())
}
.buttonStyle(.plain)
.accessibilityLabel("Dismiss")
}
// The whole card is tappable as the primary action; the ✕ stops the tap from also firing.
.contentShape(Rectangle())
.onTapGesture {
#if os(iOS)
StrandHaptic.selection.play()
#endif
scoringGuideCardSeen = true
showGuideTop = true
}
}
// Press-down feedback for the tappable card surface.
.strandPressable()
}

// MARK: Readiness, on-device training-readiness synthesis (HRV / resting-HR / load).

/// S4: Readiness now lives behind the Charge-ring tap (in `chargeBreakdownSheet`), not as a standalone
Expand Down Expand Up @@ -3168,14 +3105,6 @@ struct TodayView: View {
return hrvInsightDetail(d, score: score)
}

/// The Synthesis status colour, keyed on the carried prior recovery when carrying, else today's.
private func synthesisCardColor(score: Double?) -> Color {
if let rec = lastScoredRecoveryDay?.recovery {
return StrandPalette.recoveryColor(rec)
}
return score.map { StrandPalette.recoveryColor($0) } ?? StrandPalette.textTertiary
}

/// Screen-4 insight headline, when the HRV baseline is established, the gold "primed" read
/// keyed on how far today's HRV sits above/below the learned baseline ("HRV 12% over baseline");
/// otherwise the recovery-state word. Purely a re-presentation of the existing recovery + HRV
Expand Down Expand Up @@ -5276,27 +5205,6 @@ struct TodayView: View {
}
}

private var dateLine: String {
// The selected day's date when navigated; today's banked-row date (or today) at offset 0.
if selectedDayOffset == 0, let day = repo.today?.day, let date = Self.dayParser.date(from: day) {
return date.formatted(
.dateTime.weekday(.wide).day().month(.wide).locale(AppLanguage.activeLocale)
)
}
return selectedLogicalDay.formatted(
.dateTime.weekday(.wide).day().month(.wide).locale(AppLanguage.activeLocale)
)
}

/// Hero title that names the selected day, "Today's"/"Yesterday's"/"Day's" Synthesis.
private var synthesisTitle: LocalizedStringKey {
switch selectedDayOffset {
case 0: return "Today’s Synthesis"
case 1: return "Yesterday’s Synthesis"
default: return "Synthesis"
}
}

/// Section overline naming the selected day, "Today"/"Yesterday"/"EEE d MMM".
private var selectedDayOverline: String {
switch selectedDayOffset {
Expand Down Expand Up @@ -5357,12 +5265,6 @@ struct TodayView: View {
}
}

private func ringSupporting(_ d: DailyMetric?) -> String {
let hrv = d?.avgHrv.map { String(localized: "\(Int($0.rounded())) ms") } ?? " - ms"
let rhr = d?.restingHr.map { "\($0)" } ?? "—"
return String(localized: "HRV \(hrv) · RHR \(rhr)")
}

private func sleepValue(_ d: DailyMetric?) -> String {
guard let m = d?.totalSleepMin else { return "—" }
let h = Int(m) / 60, mm = Int(m) % 60
Expand Down
6 changes: 0 additions & 6 deletions Strand/Screens/TrendsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,6 @@ struct TrendsView: View {

// MARK: Window selection (relative to the LATEST day, with auto-expand)

/// The latest recorded day across all history (anchors every window).
private var latestDay: Date? {
guard let d = repo.days.last?.day else { return nil }
return date(d)
}

/// Days for a given range, taken RELATIVE TO TODAY (the phone's local date) — not the latest
/// recorded day, which on a stale import anchored W/M/3M to months-old data so it looked current
/// (issue #23). Empty short windows auto-widen (see `resolve`), so old imports surface under a
Expand Down
2 changes: 0 additions & 2 deletions Strand/Screens/WeeklyDigestView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,6 @@ struct WeeklyDigestContent: View {
@Environment(\.dynamicTypeSize) private var dynamicTypeSize
#endif

/// Display order: the two daily scores first, then the nightly signals.
private static let order: [WeeklyMetric] = [.charge, .effort, .rest, .hrv, .rhr]
/// The three headline 0–100 scores shown as domain summaries.
private static let scoreOrder: [WeeklyMetric] = [.charge, .effort, .rest]

Expand Down
Loading