Vocab Practice — speaker button to hear the Spanish word

Both vocab session reveal panes now show a speaker button next to the
Spanish infinitive. Tapping it speaks the word via the existing
SpeechService (Spanish voice), same TTS the Course flashcards use.

Flashcard mode: button beside the infinitive in the reveal pane.
Multiple choice: button beside the infinitive in the answer feedback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey T
2026-05-15 15:15:12 -05:00
parent 900a927f95
commit d61f9e50b1
2 changed files with 32 additions and 6 deletions
@@ -20,6 +20,7 @@ struct VocabFlashcardPracticeView: View {
@State private var revealed: Bool = false @State private var revealed: Bool = false
@State private var exampleByVerbId: [Int: VerbExample] = [:] @State private var exampleByVerbId: [Int: VerbExample] = [:]
@State private var generatingExampleForVerbId: Int? = nil @State private var generatingExampleForVerbId: Int? = nil
@State private var speech = SpeechService()
private var cloudContext: ModelContext { cloudModelContextProvider() } private var cloudContext: ModelContext { cloudModelContextProvider() }
@@ -100,10 +101,22 @@ struct VocabFlashcardPracticeView: View {
private func revealedContent(_ verb: Verb) -> some View { private func revealedContent(_ verb: Verb) -> some View {
VStack(spacing: 18) { VStack(spacing: 18) {
HStack(spacing: 12) {
Text(verb.infinitive) Text(verb.infinitive)
.font(.title.weight(.semibold)) .font(.title.weight(.semibold))
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
Button {
speech.speak(verb.infinitive)
} label: {
Image(systemName: "speaker.wave.2.fill")
.font(.title3)
.padding(10)
}
.glassEffect(in: .circle)
.accessibilityLabel("Say it out loud")
}
exampleBlock(for: verb) exampleBlock(for: verb)
ratingButtons ratingButtons
@@ -19,6 +19,7 @@ struct VocabMultipleChoicePracticeView: View {
@State private var selectedOption: Verb? = nil @State private var selectedOption: Verb? = nil
@State private var exampleByVerbId: [Int: VerbExample] = [:] @State private var exampleByVerbId: [Int: VerbExample] = [:]
@State private var generatingExampleForVerbId: Int? = nil @State private var generatingExampleForVerbId: Int? = nil
@State private var speech = SpeechService()
private var cloudContext: ModelContext { cloudModelContextProvider() } private var cloudContext: ModelContext { cloudModelContextProvider() }
@@ -109,8 +110,20 @@ struct VocabMultipleChoicePracticeView: View {
Text(correct ? "Correct!" : "Not quite") Text(correct ? "Correct!" : "Not quite")
.font(.headline) .font(.headline)
.foregroundStyle(correct ? .green : .red) .foregroundStyle(correct ? .green : .red)
HStack(spacing: 10) {
Text(verb.infinitive) Text(verb.infinitive)
.font(.title2.weight(.semibold)) .font(.title2.weight(.semibold))
Button {
speech.speak(verb.infinitive)
} label: {
Image(systemName: "speaker.wave.2.fill")
.font(.body)
.padding(8)
}
.glassEffect(in: .circle)
.accessibilityLabel("Say it out loud")
}
.padding(.top, 4) .padding(.top, 4)
} }
} }