v0.3.0 — Phase β-2 Study-Loop
Voller Lern-Flow mit Web-Parität: fällige Karten via /reviews/due laden, flip + rate (4 Buttons + Haptic), Grades via Offline-Queue ans Server-FSRS schicken. - Card/Review/DueReview DTOs mit snake_case + camelCase-deckId- Sonderfall im embedded card-Subobjekt - CardType-Enum (alle 7 Typen), Rating-Enum mit deutschen Labels - Cloze-Helper 1:1-Port aus cards-domain (extractClusterIds, subIndexCount, clusterId, renderPrompt/Answer, hint) - CardsAPI.dueReviews(deckId:) + gradeReview(cardId,subIndex,rating,reviewedAt) - PendingGrade SwiftData-Model + GradeQueue (FIFO-Drain, originaler Timestamp bleibt, bei Netzfehler in Queue, Retry beim nächsten Drain) - StudySession @Observable State-Machine - CardRenderer für basic, basic-reverse, cloze; Placeholder für image-occlusion/audio-front/typing/multiple-choice (β-3/β-4) - RatingBar mit UIImpactFeedbackGenerator (medium/heavy) - StudySessionView per NavigationLink aus DeckListView - 9 neue Tests (Cloze: 8, Review-Decoding: 3), insgesamt 17 grün Server-authoritative FSRS bleibt — kein ts-fsrs-Port. Endurance-Test auf realem Gerät steht aus (siehe PLAN.md). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f664a00b64
commit
3b861af3fb
15 changed files with 1013 additions and 23 deletions
31
Sources/Core/Storage/PendingGrade.swift
Normal file
31
Sources/Core/Storage/PendingGrade.swift
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import Foundation
|
||||
import SwiftData
|
||||
|
||||
/// Offline-Grade in der lokalen Queue. Wird beim Reconnect der Reihe nach
|
||||
/// an `POST /reviews/:cardId/:subIndex/grade` gesendet — mit dem
|
||||
/// **originalen** `reviewedAt`-Timestamp, damit der Server-FSRS
|
||||
/// korrekt rechnet.
|
||||
@Model
|
||||
final class PendingGrade {
|
||||
@Attribute(.unique) var id: String
|
||||
var cardId: String
|
||||
var subIndex: Int
|
||||
var ratingRaw: String
|
||||
var reviewedAt: Date
|
||||
var queuedAt: Date
|
||||
var lastTryAt: Date?
|
||||
var lastError: String?
|
||||
|
||||
init(cardId: String, subIndex: Int, rating: Rating, reviewedAt: Date) {
|
||||
id = "\(cardId)-\(subIndex)-\(reviewedAt.timeIntervalSince1970)"
|
||||
self.cardId = cardId
|
||||
self.subIndex = subIndex
|
||||
ratingRaw = rating.rawValue
|
||||
self.reviewedAt = reviewedAt
|
||||
queuedAt = .now
|
||||
}
|
||||
|
||||
var rating: Rating? {
|
||||
Rating(rawValue: ratingRaw)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue