ζ-3.6: Drop-Notification-Banner für Submission-Conflicts
Auto-Flush hat 4xx-Errors (duplicate, validation_failed, unauthorized) bisher stillschweigend gedroppt — User offline einreichen, im Web denselben Text posten, Online gehen → die Native-Submission war weg ohne Hinweis. SubmissionQueue: - struct DropRecord (textPreview, authorName, code, message, droppedAt) - private(set) var dropNotifications: [DropRecord] - tryFlush sammelt jetzt einen Pre-Delete-Snapshot in dropNotifications - consumeDropNotifications() leert die Liste — UI ruft beim Banner-Quittieren auf SubmitQuoteView: - droppedBanner zeigt alle gedroppten Drafts mit Text-Preview + lokalisierter Error-Message - "Quittieren"-Button leert nur die UI-State (Server-Drop ist final) - harvestDropNotifications() läuft nach jedem flushPending iOS + macOS BUILD SUCCEEDED. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
53f8043a2d
commit
c6127a2d31
2 changed files with 77 additions and 1 deletions
|
|
@ -21,10 +21,33 @@ final class SubmissionQueue {
|
|||
let container: ModelContainer
|
||||
private var inFlight: Bool = false
|
||||
|
||||
/// Sammelt Drop-Records vom letzten tryFlush — eine UI-Schicht kann
|
||||
/// sie als "diese N Submissions wurden permanent verworfen"-Banner
|
||||
/// anzeigen, statt dass der User stumm verliert.
|
||||
struct DropRecord: Identifiable, Sendable {
|
||||
let id = UUID()
|
||||
let textPreview: String
|
||||
let authorName: String?
|
||||
let code: String?
|
||||
let message: String
|
||||
let droppedAt: Date
|
||||
}
|
||||
|
||||
/// Drop-Notifications der letzten Session — UI liest und konsumiert
|
||||
/// via `consumeDropNotifications()`.
|
||||
private(set) var dropNotifications: [DropRecord] = []
|
||||
|
||||
init(container: ModelContainer) {
|
||||
self.container = container
|
||||
}
|
||||
|
||||
/// Leert die Liste — Caller hat sie gerade angezeigt.
|
||||
func consumeDropNotifications() -> [DropRecord] {
|
||||
let snapshot = dropNotifications
|
||||
dropNotifications.removeAll()
|
||||
return snapshot
|
||||
}
|
||||
|
||||
/// Hängt einen Draft an die Queue.
|
||||
func deposit(_ draft: QuoteDraft, error: String? = nil) {
|
||||
let ctx = ModelContext(container)
|
||||
|
|
@ -91,6 +114,15 @@ final class SubmissionQueue {
|
|||
} catch let error as ZitareAPIError where shouldDrop(error) {
|
||||
Log.app.warning("Dropping pending submission (permanent error: \(error.code ?? "?", privacy: .public))")
|
||||
entry.lastError = error.errorDescription
|
||||
// Notify UI: dieser Draft wurde verworfen. Pre-Snapshot
|
||||
// der Daten vor dem Delete machen.
|
||||
dropNotifications.append(DropRecord(
|
||||
textPreview: String(entry.text.prefix(120)),
|
||||
authorName: entry.authorName,
|
||||
code: error.code,
|
||||
message: error.errorDescription ?? "Fehler",
|
||||
droppedAt: Date()
|
||||
))
|
||||
ctx.delete(entry)
|
||||
} catch let error as LocalizedError {
|
||||
entry.lastError = error.errorDescription
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue