Files
Spanish/Conjuga/Conjuga/Models/ReviewCard.swift
T
Trey T c890095610 Vocab Practice — verb pool, Settings level filter, per-verb SRS
Vocab Practice used a deck picker over VocabCard rows. That meant it
ignored the Settings level toggles entirely and operated on a totally
separate vocabulary universe than the conjugation modes. Rewired
end-to-end:

Pool source
  Replaced VocabCard with the Verb table. The pool is now
  ReferenceStore.fetchVerbs(selectedLevels: UserProgress.selectedVerbLevels)
  — the same call PracticeSessionService uses for conjugation. Changes
  to level toggles in Settings (or the Verbs tab, which also writes to
  this field) immediately affect Vocab Practice.

Entry flow
  Deleted VocabPracticeEntryView. Practice → Vocabulary now has two
  direct entries:
    • Vocab Flashcards — verb.english → tap → verb.infinitive
    • Vocab Multiple Choice — verb.english → pick from 4 infinitives
  Both pull from the same level-filtered pool, shuffled.

Per-verb SRS
  New VerbReviewCard @Model (cloud-synced, mirrors CourseReviewCard's
  SM-2 fields but keyed by verbId). VerbReviewStore.rate(verbId:quality:)
  applies the existing SRSEngine. Registered in cloud container schema
  in ConjugaApp.swift.

Example sentences
  Lazy-generated via VerbExampleGenerator on first reveal, cached
  through VerbExampleCache (same path VerbDetailView uses). Empty until
  the example arrives — block hides itself if Apple Intelligence isn't
  available.

AI illustration
  VerbIllustration replaces VocabIllustration; same Image Playground
  pipeline. Cache key uses ("verb", infinitive, english) so verbs and
  course-deck vocab never collide.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 23:31:12 -05:00

85 lines
2.1 KiB
Swift

import SwiftData
import Foundation
@Model
final class ReviewCard {
var key: String = ""
var verbId: Int = 0
var tenseId: String = ""
var personIndex: Int = 0
var easeFactor: Double = 2.5
var interval: Int = 0
var repetitions: Int = 0
var dueDate: Date = Date()
var lastReviewDate: Date?
init(verbId: Int, tenseId: String, personIndex: Int) {
self.key = Self.makeKey(verbId: verbId, tenseId: tenseId, personIndex: personIndex)
self.verbId = verbId
self.tenseId = tenseId
self.personIndex = personIndex
}
static func makeKey(verbId: Int, tenseId: String, personIndex: Int) -> String {
"\(verbId)|\(tenseId)|\(personIndex)"
}
func refreshIdentityIfNeeded() {
let expected = Self.makeKey(verbId: verbId, tenseId: tenseId, personIndex: personIndex)
if key != expected {
key = expected
}
}
}
@Model
final class CourseReviewCard {
var id: String = ""
var deckId: String = ""
var front: String = ""
var back: String = ""
var easeFactor: Double = 2.5
var interval: Int = 0
var repetitions: Int = 0
var dueDate: Date = Date()
var lastReviewDate: Date?
init(id: String, deckId: String, front: String, back: String) {
self.id = id
self.deckId = deckId
self.front = front
self.back = back
}
}
/// SRS record for verb-level vocab practice (EN ES infinitive recall),
/// separate from per-form `ReviewCard` so a user's vocab progress doesn't
/// collide with conjugation form mastery.
///
/// CloudKit-synced; uniqueness on `id` is enforced via fetch-or-create in
/// `VerbReviewStore` since CloudKit forbids `@Attribute(.unique)`.
@Model
final class VerbReviewCard {
var id: String = ""
var verbId: Int = 0
var easeFactor: Double = 2.5
var interval: Int = 0
var repetitions: Int = 0
var dueDate: Date = Date()
var lastReviewDate: Date?
init(verbId: Int) {
self.id = Self.makeId(verbId: verbId)
self.verbId = verbId
}
static func makeId(verbId: Int) -> String {
"verb-\(verbId)"
}
}