exercise architecture, migrate interval classifier
Created by: jedmund
Summary
Lays down a shared architecture for scored exercises and migrates the first two off the old ad-hoc pattern (Interval Classifier, Interval Trainer). Adds a new app icon along the way.
Shared exercise architecture
-
ExerciseStatetracks progress and results;ScoringOverlaywraps content with progress dots and a completion screen;PickerWidgethandles multiple-choice answers with adaptive grid columns (2 / 3 / 4 based on choice count). -
ExerciseLayoutContextenvironment switches exercises between standalone (centered glass card) and lesson-page (context text above card) presentations without duplicating views. -
ExerciseHost,InteractionWidget, andToolBridgeare scaffolding for future exercises that drive a tool. Not yet wired — we intentionally deferredToolBridgeuntil a keyboard-driven exercise forces its design. -
ProgressDotsViewreworked: filled circles with design tokens (.accentColor/.incorrectWarm), visible on glass. -
ActivityStateRegistry.scoredExerciseState(for:)+progressStoreintegration so progress survives navigation and gets persisted across sessions.
Interval Classifier
- Rebuilt on the shared stack. Static-prompt JSON, categorical answers.
- New design baseline: glass card,
.thinMaterialpicker buttons, centered feedback with inline bold answer, filled-circle feedback icon matching progress dots, small capsule Next button, progress dots hidden during feedback state. - Old
IntervalClassifierViewand itsToolViewFactorycase removed.
Interval Trainer
- Same visual baseline as Interval Classifier.
- First exercise with procedural prompt generation (random root in range + random interval from active pool).
ExerciseStatehandled it without changes, confirming the model is generation-agnostic. - Streak-based interval unlocks preserved (silent, no toast). Streak/unlock bookkeeping stays local to the exercise view — it's domain-specific, not universal.
-
IntervalTrainerConfiggained acontextfield (the lesson JSON already had one that was being silently dropped). - Old
IntervalTrainerViewand itsToolViewFactorycase removed.
App icon
- New waveform glyph on cream. Dark/tinted slots registered but unfilled for now (fall back to default). Build number bumped to 3.
Test plan
-
Standalone Interval Classifier: Exercises grid → tap → listen, pick, advance, complete. Retry from completion resets dots. -
Standalone Interval Trainer: Exercises grid → tap → same loop. After 3 correct, new intervals silently appear in the picker; grid stays readable. -
Lesson with each exercise: context text renders above card, progress persists across navigation away and back. -
Exercise completion records an attempt via progressStoreand allows scrolling past the gate. -
App icon renders in Springboard and reflects correctly on TestFlight / App Store Connect upload.