Checkpoint exams appear after each week in the course view, testing
all words from week 1 through the current week within the same course.
Users can choose 25, 50, or 100 questions with even distribution
across weeks. Results are tracked separately from weekly tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New EnglishConjugator in SharedModels constructs English translations
by combining the verb's infinitive with person pronouns and tense
auxiliaries (e.g., abatir conditional yo → "I would knock down").
Covers all 20 tense IDs, handles 60+ irregular English verbs,
multi-word verbs, 3rd person rules, gerund and participle formation.
VerbDetailView shows the English below each conjugated form, plus a
legend explaining red = irregular conjugation. 42 tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New feature in the Practice tab that lets users search for Spanish songs
by artist + title, fetch lyrics from LRCLIB (free, no API key), pull
album art from iTunes Search API, auto-translate to English via Apple's
on-device Translation framework, and save for offline reading.
Components:
- SavedSong SwiftData model (local container, no CloudKit sync)
- LyricsSearchService actor (LRCLIB + iTunes Search, concurrent)
- LyricsSearchView (artist/song fields, result list with album art)
- LyricsConfirmationView (lyrics preview, auto-translation, save)
- LyricsLibraryView (saved songs list, swipe to delete)
- LyricsReaderView (Spanish lines with English subtitles)
- Practice tab integration (Lyrics button with NavigationLink)
- localStoreResetVersion bumped to 3 for schema migration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: the widget was opening the shared local.store with a 2-entity
schema (VocabCard, CourseDeck), causing SwiftData to destructively migrate
the file and drop the 4 entities the widget didn't know about (Verb,
VerbForm, IrregularSpan, TenseGuide). The main app would then re-seed on
next launch, and the cycle repeated forever.
Fix: move Verb, VerbForm, IrregularSpan, TenseGuide from the app target
into SharedModels so both the main app and the widget use the exact same
types from the same module. Both now declare all 6 local entities in their
ModelContainer, producing identical schema hashes and eliminating the
destructive migration.
Other changes bundled in this commit (accumulated during debugging):
- Split ModelContainer into localContainer + cloudContainer (no more
CloudKit + non-CloudKit configs in one container)
- Add SharedStore.localStoreURL() helper and a global reference for
bypass-environment fetches
- One-time store reset mechanism to wipe stale schema metadata from
previous broken iterations
- Bootstrap/maintenance split so only seeding gates the UI; dedup and
cloud repair run in the background
- Sync status toast that shows "Syncing" while background maintenance
runs (network-aware, auto-dismisses)
- Background app refresh task to keep the widget word-of-day fresh
- Speaker icon on VerbDetailView for TTS
- Grammar notes navigation fix (nested NavigationStack was breaking
detail pane on iPhone)
- Word-of-day widget swaps front/back when the deck is reversed so the
Spanish word always shows in bold
- StoreInspector diagnostic helper for raw SQLite table inspection
- Add Conjuga scheme explicitly to project.yml so xcodegen doesn't drop it
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>