TeraSubmissionViews.swift (4445B)
1 import SwiftUI 2 3 struct TeraSubmissionStatusView: View { 4 @ObservedObject var store: TeraSubmissionStore 5 6 var body: some View { 7 if store.hasAction { 8 Section("Submission") { 9 if store.status?.canOfferStop != false { 10 Button("Stop publication") { Task { await store.requestStop() } } 11 .accessibilityIdentifier("tera.add.submission.stop") 12 } 13 if store.isWorking { 14 ProgressView(store.status?.summary ?? "Checking the original submission request…") 15 .accessibilityIdentifier("tera.add.submission.progress") 16 Button("Stop waiting") { store.stopWaiting() } 17 .accessibilityIdentifier("tera.add.submission.stop_waiting") 18 } 19 if !store.isWorking { 20 if store.request != nil { 21 Button("Check saved submission status") { Task { await store.refreshSelected() } } 22 .accessibilityIdentifier("tera.add.submission.check") 23 } 24 if store.canContinue { 25 Button("Continue original submission") { Task { await store.continueSelected() } } 26 .accessibilityIdentifier("tera.add.submission.continue") 27 } 28 } 29 if let status = store.status { 30 Text(status.summary) 31 .accessibilityIdentifier("tera.add.submission.status") 32 if let explanation = status.retry.explanation { 33 Text(explanation).accessibilityIdentifier("tera.add.submission.retry_status") 34 } 35 TeraPublicationTargetsView(details: status.targetDetails) 36 if !status.media.isEmpty { 37 Text(status.mediaSummary) 38 .accessibilityIdentifier("tera.add.submission.media_status") 39 } 40 DisclosureGroup("Captured form") { 41 Text(status.captured.form.editingValue.commandType.label).font(.headline) 42 Text(status.captured.form.editingValue.content) 43 if let title = status.captured.form.editingValue.title { 44 Text(title) 45 } 46 Text("Editing continues separately. This submission keeps the form captured when you tapped Submit.") 47 .font(.footnote) 48 } 49 .accessibilityIdentifier("tera.add.submission.captured") 50 } 51 if let message = store.message { 52 Text(message).accessibilityIdentifier("tera.add.submission.message") 53 } 54 Text("Retry uses this original request. Choose New for another intentional submission.") 55 .font(.footnote) 56 } 57 } 58 } 59 } 60 61 struct TeraSubmissionInventoryView: View { 62 @ObservedObject var store: TeraSubmissionStore 63 @ObservedObject private var inventory: TeraSubmissionInventory 64 65 init(store: TeraSubmissionStore) { 66 self.store = store 67 inventory = store.inventory 68 } 69 70 var body: some View { 71 Section("Submissions") { 72 if inventory.isLoading { 73 ProgressView("Loading submissions…") 74 } 75 if let message = inventory.message { 76 Text(message).foregroundStyle(.secondary) 77 } 78 ForEach(inventory.entries) { entry in 79 switch entry { 80 case let .submission(summary): 81 VStack(alignment: .leading, spacing: 8) { 82 Text(label(summary.state)) 83 Text(Date(timeIntervalSince1970: Double(summary.reservedAtUnixMilliseconds) / 1000), 84 format: .dateTime.year().month().day().hour().minute()).font(.caption) 85 Button("View submission") { Task { await store.select(summary) } } 86 .disabled(store.isWorking) 87 } 88 .accessibilityIdentifier("tera.add.submission.\(summary.id)") 89 case let .repair(_, _, reason): 90 Text(reason == .unsupportedSchema 91 ? "This saved submission needs a compatible app. Its data is preserved." 92 : "This submission needs attention. Its data is preserved; other work remains available.") 93 .accessibilityIdentifier("tera.add.submission.repair") 94 } 95 } 96 if inventory.cursor != nil { 97 Button("Next submissions page") { inventory.more() }.disabled(inventory.isLoading) 98 } 99 Button("Reload submissions") { inventory.start() }.disabled(inventory.isLoading) 100 } 101 TeraSubmissionStatusView(store: store) 102 } 103 104 private func label(_ state: TeraSubmissionSummaryState) -> String { 105 switch state { 106 case .reserved: "Reserved; local preparation is pending." 107 case let .operation(_, _, _, state): state.label 108 } 109 } 110 }