Commit Graph

34 Commits

Author SHA1 Message Date
Trey t
a3318adf5e Use ViewThatFits for study time and activity cards layout
Side by side on iPad, stacked vertically on iPhone. Fixes
calendar grid overflowing on narrow screens.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:28:02 -05:00
Trey t
a3807faf2d Fix speech authorization crash on device from dispatch queue assertion
Request authorization off main queue and marshal callback result back
via DispatchQueue.main.async. Check current status first to avoid
unnecessary system prompt if already authorized or denied.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:19:03 -05:00
Trey t
a663bc03cd Add 6 new practice features, offline dictionary, and feature reference
New features:
- Offline Dictionary: reverse index of 175K verb forms + 200 common
  words, cached to disk, powers instant word lookups in Stories
- Vocab SRS Review: spaced repetition for course vocabulary cards
  with due count badge and Again/Hard/Good/Easy rating
- Cloze Practice: fill-in-the-blank using SentenceQuizEngine with
  distractor generation from vocabulary pool
- Grammar Exercises: interactive quizzes for 5 grammar topics
  (ser/estar, por/para, preterite/imperfect, subjunctive, personal a)
  with "Practice This" button on grammar note detail
- Listening Practice: listen-and-type + pronunciation check modes
  using Speech framework with word-by-word match scoring
- Conversational Practice: AI chat partner via Foundation Models
  with 10 scenario types, saved to cloud container

Other changes:
- Add Conversation model to SharedModels and cloud container
- Add Info.plist keys for speech recognition and microphone
- Skip speech auth on simulator to prevent crash
- Fix preparing data screen to only show during seed/migration
- Extract courseDataVersion to static property on DataLoader
- Add "How Features Work" reference page in Settings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:12:36 -05:00
Trey t
451866e988 Add AI-generated short stories with tappable words and comprehension quiz
Generate one-paragraph Spanish stories on-device using Foundation Models,
matched to user's level and enabled tenses. Every word is tappable —
pre-annotated words show instantly, others get a quick on-device AI
lookup with caching. English translation hidden by default behind a
toggle. Comprehension quiz with 3 multiple-choice questions. Stories
saved to cloud container for sync and persistence across resets.

Closes #9

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 11:31:58 -05:00
Trey t
79c4c6e290 Add irregular verbs reference guides to grammar section
Add two grammar notes under new "Irregular Verbs" category:
- Most Common Irregular Verbs: 15 essential verbs with present
  and preterite forms plus example sentences
- Types of Irregular Verbs: spelling changes, stem changes, and
  unique irregulars with patterns and examples

Closes #5

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:56:34 -05:00
Trey t
282cd1b3a3 Fix lyrics wiped on schema reset by moving SavedSong to cloud container
SavedSong was in the local container alongside reference data, so it
got deleted whenever localStoreResetVersion was bumped. Move it to the
cloud container (CloudKit-synced) so saved songs persist across schema
changes. Update lyrics views to use cloudModelContextProvider.

Closes #4

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:27:21 -05:00
Trey t
40d436ad9c Highlight main tenses with Essential badges and focus mode
Mark 6 core tenses (presente, pretérito, imperfecto, futuro,
subjuntivo presente, imperativo) as essential. Add "Common Tenses"
quick action in Practice to drill only these. Show "Essential"
badge on core tenses in Guide > Tenses list.

Closes #3

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:07:46 -05:00
Trey t
473eb271cc Add background study timer tracking foreground time per day
Track how long users spend studying by timing foreground sessions.
StudyTimerService starts on app active, stops on background, and
accumulates seconds into DailyLog.studySeconds (CloudKit-synced).
Dashboard shows today/total study time with a 7-day bar chart.

Closes #1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 09:44:44 -05:00
Trey t
877e699c56 Add Spanish Suffixes grammar guide with card-based content layout
Add comprehensive suffix reference (diminutives, augmentatives, verb
endings, noun/adjective-forming, adverbs, pejoratives) as grammar note
#21 under Word Building category.

Refactor grammar detail rendering to group paragraphs with their
examples into visual cards, replacing the flat wall-of-text layout.
Suffix entries get pill-styled labels with compact inline examples.
Bump courseDataVersion to 5.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:31:30 -05:00
Trey t
d372a5c77f Add checkpoint exams with cumulative vocabulary review per course
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>
2026-04-12 12:45:25 -05:00
Trey t
a1dc17bf00 Add per-form English translations to verb conjugation table
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>
2026-04-11 23:44:17 -05:00
Trey t
c58313496e Avoid showing the same verb back-to-back in practice
fetchDueCard now accepts the last-shown verb ID and prefers a
different verb from the due queue. Falls back to the same verb
only when it's the sole due card.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 23:27:29 -05:00
Trey t
636193fae1 Fix lyrics navigation, translation line alignment, and store reset
Navigation: present search as a sheet from library (avoids nested
NavigationStack), use view-based NavigationLink for song rows (fixes
double-push from duplicate navigationDestination).

Translation: Apple Translation inserts a blank line after every
translated line. Strip all blanks from the EN output, then re-insert
them at the same positions where the original ES has blanks. Result
is 1:1 line pairing between Spanish and English.

Store reset: revert localStoreResetVersion bump — adding SavedSong
is a lightweight SwiftData migration, no store nuke needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 23:08:32 -05:00
Trey t
faef20e5b8 Add Lyrics practice: search, translate, and read Spanish song lyrics
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>
2026-04-11 22:44:40 -05:00
Trey t
5fa1cc3921 Filter phonetic glosses from Complete the Sentence quiz
Examples shorter than 4 words (like pronunciation guides
"discutir(dees-koo-teer)") are now rejected by both
isBlankResolvable and buildQuestion. The engine only picks real
multi-word sentences for the quiz prompt.

Every card already has at least one real sentence alongside its
phonetic entries, so no data regeneration is needed — the filter
alone fixes the issue.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:22:28 -05:00
Trey t
a51d2abd47 Defer AVSpeechSynthesisVoice init to first speak() call
AVSpeechSynthesisVoice(language:) triggers a malloc double-free on
iOS 26 simulators when deserializing voice metadata during app launch.
Move voice resolution from init() to first speak() so the framework
call happens after the app is fully initialized.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:52:56 -05:00
Trey t
2a062cf484 Bump courseDataVersion to 4 for sentence gap-fill re-seed
Existing installs will delete and re-seed all VocabCard/CourseDeck data
on next launch, picking up the ~6,300 new example sentences and blank
fields added for the Complete the Sentence quiz type.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:47:31 -05:00
Trey t
02e8d5141a Complete the Sentence: fill sentences for final batches 26-29
290 cards: Intermediate III tail (48), Advanced I (95), Advanced II
(147). All 8 courses now have complete sentence coverage for the
Complete the Sentence quiz type.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:43:49 -05:00
Trey t
cd67f32302 Complete the Sentence: fill sentences for Intermediate III batches 23-25
300 cards across Intermediate III Spanish Through Stories weeks 1-6.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:34:19 -05:00
Trey t
79d9b7cb1d Complete the Sentence: fill sentences for Intermediate II batches 20-22
219 cards: Intermediate II batches 20, 21, 22 — clothing, business,
beliefs, citizenship, addictions, authority, rest. Intermediate II
now 100% complete.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:27:51 -05:00
Trey t
d666d0991a Complete the Sentence: fill sentences for batches 17-19
248 cards: Intermediate I finishing (148 cards across batches 17-18)
and Intermediate II batch 19 (100 cards).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:22:08 -05:00
Trey t
4e575a22c8 Complete the Sentence: fill sentences for batches 14-16
294 cards: Beginner III Conversation finishing (194 cards) and
Intermediate I batch 16 (100 cards).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:15:01 -05:00
Trey t
d538123251 Complete the Sentence: fill sentences for batches 11-13
289 cards: Beginner II batches 11-12 finishing (200 cards) and Beginner
III Conversation batch 13 (100 cards).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:09:23 -05:00
Trey t
54c1b05411 Complete the Sentence: fill sentences for Beginner II batches 8-10
300 cards across Beginner II weeks 1-5: body parts, animals, verbos
como gustar, food, clothing, city expansions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 20:04:07 -05:00
Trey t
99fc3c91f5 Complete the Sentence: fill sentences for Beginner I batches 5-7/7
233 cards across Beginner I weeks 4-8: Adjectives, Family reversed,
stem-changing verbs, reflexives, Daily Routine, City, Time/Seasons,
tener idioms, Hobbies. Finishes Beginner I content (508 cards total).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:58:45 -05:00
Trey t
ca7640b100 Complete the Sentence: fill sentences for Beginner I batches 2-4/7
300 cards across Beginner I weeks 2-4: Adjectives, Numbers, Professions,
House, -AR/-ER/-IR verbs, Family. Each card now has at least 3 example
sentences with stored blank fields.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:53:37 -05:00
Trey t
719134c6c7 Complete the Sentence: fill sentences for Beginner I batch 1/7
100 cards from Beginner I — Greetings / Basic Verbs / early decks.
Each card now has at least 3 example sentences with a stored `blank`
field identifying the exact substring to hide in the quiz.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:47:48 -05:00
Trey t
143e356b75 Complete the Sentence quiz type: engine, UI, tests
Add a new Complete the Sentence quiz type that renders a Spanish example
sentence from the card with the target word blanked out and asks the
student to pick the missing word from 4 choices (other cards' fronts
from the same week's pool).

Core logic lives in SharedModels/SentenceQuizEngine as pure functions
over VocabCard, covered by 18 Swift Testing tests. CourseQuizView calls
the engine, pre-filters the card pool to cards that can produce a
resolvable blank, and reuses the existing MC rendering via a new
correctAnswer(for:) helper.

VocabCard gains examplesBlanks (parallel array to examplesES) so content
can explicitly tag the blanked substring; DataLoader reads an optional
"blank" key on each example. Additive schema change, CloudKit-safe
default.

Also adds ContentCoverageTests that parse the repo's course_data.json
and assert every card has >=3 examples and yields a resolvable question.
These tests currently fail: 1,117 cards still need sentences. They are
the oracle for the gap-fill pass that follows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:33:50 -05:00
Trey t
3b8a8a7f1a Guard quiz Next/Previous against double taps
A rapid second tap on Next (easy to trigger with Apple Pencil) called
advance() twice before the view tree re-rendered, skipping a card.
Share a single isAdvancing flag between advance() and a new goBack()
helper, disable both buttons while the flag is set, and clear it after
350 ms so queued Pencil events are absorbed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:52:08 -05:00
Trey t
4e874f60d7 Move Settings to Dashboard toolbar to kill iPhone More overflow
Six tabs forced iPhone to spill Course into the system "More" tab, whose
own NavigationStack nested with CourseView's and produced a double back
chevron on every week/deck push. Drop the Settings tab, reach it from a
gear button on Dashboard that presents SettingsView as a sheet, and keep
the visible tab count at five so no More overflow exists.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:22:27 -05:00
Trey t
644dbb7230 Scope week tests to the selected course
WeekTestView filtered decks and TestResults by weekNumber alone, so Week 3
of any course pulled content from every course's Week 3 simultaneously.
Thread courseName through the navigation destination, quiz view, and
TestResult model so quiz cards, score history, and focus-area missed items
are all scoped to the active course.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:17:30 -05:00
Trey t
f59d81fc5a Widget word-of-day picks from master verb list filtered by user level
Previously the widget was picking from course VocabCards, which could
land on any course week and was showing unrelated phrases instead of the
verbs the user is actually studying.

Now the widget uses a new VerbStore.fetchVerbOfDay helper that:
- Expands the user's selectedLevel via VerbLevelGroup.dataLevels
- Runs a FetchDescriptor<Verb> filtered by those levels, sorted by rank
- Uses fetchCount + fetchOffset for a deterministic daily pick

The main app mirrors UserProgress.selectedLevel into the shared app
group UserDefaults (key "selectedVerbLevel") on every WidgetDataService
update, so the widget process can read it without touching the cloud
store.

WordOfDay.weekNumber was replaced with a more flexible subtitle: String
so widgets can display "Level: Basic" instead of course week numbers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:04:45 -05:00
Trey t
fd5861c48d Move reference-data models to SharedModels to fix widget-triggered data loss
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>
2026-04-10 13:51:02 -05:00
Trey t
4b467ec136 Initial commit: Conjuga Spanish conjugation app
Includes SwiftData dual-store architecture (local reference + CloudKit user data),
JSON-based data seeding, 20 tense guides, 20 grammar notes, SRS review system,
course vocabulary, and widget support.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 20:58:33 -05:00