feat(study): Multiple-Choice-Karten gerendert
CardRenderer für multipleChoice ist nicht mehr Placeholder. Web-
Vorbild: MultipleChoiceView.svelte.
MultipleChoiceCardView (Features/Study/):
- Lädt Distractors vom Server beim card.id-Wechsel
(CardsAPI.distractors(deckId, cardId, field, count))
- Versucht erst field=answer, fallback field=back (für Decks mit
basic/basic-reverse-Karten daneben)
- Fallback auf distractor_pool-Feld (newline-separated) wenn
Deck zu klein
- 4 Optionen shuffled = [answer + 3 Distractors]
- User-Tap markiert Auswahl (kein erneutes Pick möglich)
- Vor Flip: nur Selected-Hint (primary border)
- Nach Flip: richtige = green-check, falsche-gewählte = red-cross,
unselected richtige bleibt green-highlight
- Fallback "tooFew" (< 1 Distractor): zeigt Antwort nach Flip
ohne Auswahl
CardsAPI.distractors → DistractorsResponse {distractors: [String]}.
Typing bleibt Placeholder — eigene UI-Pattern (Text-Input + Diff)
brauchen mehr Design-Arbeit, separate Phase.
Build 7 → 8, 35 Tests grün.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
aa94601409
commit
8b1dd5158f
5 changed files with 225 additions and 4 deletions
|
|
@ -52,6 +52,21 @@ actor CardsAPI {
|
|||
return try decoder.decode(CardListResponse.self, from: data).cards
|
||||
}
|
||||
|
||||
/// `GET /api/v1/decks/:deckId/distractors` — N zufällige Feldwerte
|
||||
/// aus anderen Karten desselben Decks. Server-Schema erlaubt nur
|
||||
/// `front`, `back`, `answer`, `question` als field.
|
||||
func distractors(
|
||||
deckId: String,
|
||||
cardId: String,
|
||||
field: String = "answer",
|
||||
count: Int = 3
|
||||
) async throws -> [String] {
|
||||
let path = "/api/v1/decks/\(deckId)/distractors?card_id=\(cardId)&field=\(field)&count=\(count)"
|
||||
let (data, http) = try await transport.request(path: path)
|
||||
try ensureOK(http, data: data)
|
||||
return try decoder.decode(DistractorsResponse.self, from: data).distractors
|
||||
}
|
||||
|
||||
/// `GET /api/v1/reviews/due?deck_id=...&limit=500` — Anzahl fälliger
|
||||
/// Reviews in einem Deck.
|
||||
func dueCount(deckId: String) async throws -> Int {
|
||||
|
|
|
|||
|
|
@ -129,3 +129,8 @@ struct CardListResponse: Decodable, Sendable {
|
|||
struct DueReviewsResponse: Decodable, Sendable {
|
||||
let total: Int
|
||||
}
|
||||
|
||||
/// Server-Response von `GET /api/v1/decks/:deckId/distractors`.
|
||||
struct DistractorsResponse: Decodable, Sendable {
|
||||
let distractors: [String]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue