field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

TeraNativeRepairView.swift (3026B)


      1 import SwiftUI
      2 
      3 struct TeraNativeRepairView: View {
      4   @ObservedObject var store: TeraNativeRepairStore
      5 
      6   var body: some View {
      7     if store.message != nil || store.isRunning || !store.issues.isEmpty {
      8       Section("Saved photo recovery") {
      9         TeraNativeRepairProgressView(message: store.message, remaining: store.progress?.remaining)
     10         if store.issues.count == TeraNativeRepairStore.previewLimit {
     11           Text("Showing up to \(TeraNativeRepairStore.previewLimit) repair notices.")
     12         }
     13         ForEach(Array(store.issues.enumerated()), id: \.element.id) { index, issue in
     14           TeraNativeRepairActions(issue: issue, index: index, isRunning: store.isRunning) { store.check(issue) }
     15         }
     16         if store.isRunning {
     17           ProgressView("Checking saved photos")
     18         } else {
     19           Button("Check saved photos again") { store.retry() }
     20             .accessibilityIdentifier("tera.add.recovery.check")
     21         }
     22       }
     23       .accessibilityIdentifier("tera.add.recovery.issues")
     24     }
     25   }
     26 }
     27 
     28 struct TeraNativeRepairProgressView: View {
     29   let message: String?
     30   let remaining: Int?
     31 
     32   var body: some View {
     33     if let message {
     34       Text(message).accessibilityIdentifier("tera.add.recovery.message")
     35     }
     36     if let remaining, remaining > 0 {
     37       Text("\(remaining) more saved transfer records remain to be checked in this pass.")
     38         .accessibilityIdentifier("tera.add.recovery.remaining")
     39     }
     40   }
     41 }
     42 
     43 struct TeraNativeRepairActions: View {
     44   let issue: TeraNativeRecoveryIssue
     45   let index: Int
     46   let isRunning: Bool
     47   let check: () -> Void
     48 
     49   var body: some View {
     50     VStack(alignment: .leading, spacing: 8) {
     51       Text("Saved photo \(index + 1)").font(.headline)
     52       Text(issue.reason.message)
     53         .accessibilityIdentifier("tera.add.recovery.reason.\(issue.key)")
     54       if issue.status == nil {
     55         Text("This recovery status could not be saved. Check again when local storage is available.")
     56           .foregroundStyle(.secondary)
     57       }
     58       Button("Check this photo’s saved evidence", action: check)
     59         .disabled(isRunning)
     60         .buttonStyle(.borderless)
     61         .accessibilityIdentifier("tera.add.recovery.check.\(issue.key)")
     62       Text("Checking keeps the evidence and does not start another upload. A missing or mismatched request must be restored before recovery can succeed.")
     63         .font(.footnote)
     64     }
     65     .accessibilityElement(children: .contain)
     66   }
     67 }
     68 
     69 extension TeraNativeRecoveryReason {
     70   var message: String {
     71     switch self {
     72     case .missingParent: "The saved request for this photo could not be found. Its upload evidence has been kept."
     73     case .invalidParent: "The saved request for this photo needs repair. Its upload evidence has been kept."
     74     case .associationMismatch: "This upload does not match its saved request. Its evidence has been kept."
     75     case .outcomeUnconfirmed: "This photo’s upload result is not yet confirmed. Its evidence has been kept."
     76     case .resolved: "This photo has been recovered."
     77     }
     78   }
     79 }