Voller Editor-Flow für Decks und 5 Card-Types (basic, basic-reverse, cloze, typing, multiple-choice). image-occlusion + audio-front kommen mit β-4 (Media). Anki-Import bleibt vorerst aus (Web parsed client- side, gibt keinen Server-Import-Endpoint zu rufen). - DeckCreateBody/UpdateBody, CardCreateBody/UpdateBody Encodable mit snake_case-CodingKeys, nil-Felder werden weggelassen - CardFieldsBuilder mit Type-spezifischen Pflicht-Feld-Konstruktoren - CardsAPI: createDeck/updateDeck/deleteDeck + createCard/updateCard/deleteCard - DeckEditorView (Create + Edit in einer View): Color-Picker mit 8-Preset-Palette, Category-Picker (11 Kats, deutsche Labels), Visibility-Segmented-Control - CardEditorView mit Type-Picker und dynamischen Feldern je Typ. Cloze-Sektion zeigt Live-Cluster-Count und Hint-Syntax-Hinweis. image-occlusion/audio-front zeigen β-4-Placeholder - DeckDetailView mit Action-Buttons (Lernen, Karte hinzufügen, Bearbeiten, Löschen mit Confirmation) - DeckListView: "+"-Button im Toolbar (Leading) für Create-Sheet - 7 neue Encoding-Tests (24 Unit-Tests + 1 UI-Test grün) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
56 lines
1.6 KiB
Swift
56 lines
1.6 KiB
Swift
import Foundation
|
|
|
|
/// Body für `POST /api/v1/cards`. Aus `CardCreateSchema`.
|
|
///
|
|
/// `fields` ist type-abhängig — Server validiert via
|
|
/// `validateFieldsForType()`. Pflicht-Keys pro Type:
|
|
/// - basic, basic-reverse: `front`, `back`
|
|
/// - cloze: `text` (mit `{{cN::...}}`-Clustern)
|
|
/// - typing: `front`, `answer`
|
|
/// - multiple-choice: `front`, `answer`
|
|
/// - image-occlusion: `image_ref`, `mask_regions` (β-4)
|
|
/// - audio-front: `audio_ref`, `back` (β-4)
|
|
struct CardCreateBody: Encodable, Sendable {
|
|
let deckId: String
|
|
let type: CardType
|
|
let fields: [String: String]
|
|
let mediaRefs: [String]?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case deckId = "deck_id"
|
|
case type
|
|
case fields
|
|
case mediaRefs = "media_refs"
|
|
}
|
|
}
|
|
|
|
/// Body für `PATCH /api/v1/cards/:id`. Nur `fields` und `media_refs` —
|
|
/// Type und deck_id sind immutable (Server-Schema).
|
|
struct CardUpdateBody: Encodable, Sendable {
|
|
var fields: [String: String]?
|
|
var mediaRefs: [String]?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case fields
|
|
case mediaRefs = "media_refs"
|
|
}
|
|
}
|
|
|
|
/// Hilfs-Builder für Card-Type-spezifische `fields`-Dictionaries.
|
|
enum CardFieldsBuilder {
|
|
static func basic(front: String, back: String) -> [String: String] {
|
|
["front": front, "back": back]
|
|
}
|
|
|
|
static func cloze(text: String) -> [String: String] {
|
|
["text": text]
|
|
}
|
|
|
|
static func typing(front: String, answer: String) -> [String: String] {
|
|
["front": front, "answer": answer]
|
|
}
|
|
|
|
static func multipleChoice(front: String, answer: String) -> [String: String] {
|
|
["front": front, "answer": answer]
|
|
}
|
|
}
|