TelemetryPreviewView.swift 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import SwiftUI
  2. /// Renders the exact payload that would be sent right now, with a copy button.
  3. /// Linked to from Settings → App Diagnostics and from the migration sheet.
  4. struct TelemetryPreviewView: View {
  5. @State private var jsonText: String = ""
  6. @State private var showResetConfirm: Bool = false
  7. @State private var resetStatus: String?
  8. var body: some View {
  9. ScrollView {
  10. VStack(alignment: .leading, spacing: 12) {
  11. Text(
  12. "Below is the exact JSON object Trio would send right now. No glucose, insulin, carbs, credentials, or settings values are included."
  13. )
  14. .font(.subheadline)
  15. .foregroundColor(.secondary)
  16. .padding(.bottom, 4)
  17. Text(jsonText)
  18. .font(.system(.footnote, design: .monospaced))
  19. .frame(maxWidth: .infinity, alignment: .leading)
  20. .textSelection(.enabled)
  21. .padding(8)
  22. .background(Color(.secondarySystemBackground))
  23. .cornerRadius(6)
  24. Button {
  25. UIPasteboard.general.string = jsonText
  26. } label: {
  27. Label("Copy JSON", systemImage: "doc.on.doc")
  28. }
  29. .buttonStyle(.bordered)
  30. Button(role: .destructive) {
  31. showResetConfirm = true
  32. } label: {
  33. Label("Reset App Attest state", systemImage: "arrow.counterclockwise.circle")
  34. }
  35. .buttonStyle(.bordered)
  36. if let resetStatus {
  37. Text(resetStatus)
  38. .font(.footnote)
  39. .foregroundColor(.secondary)
  40. }
  41. }
  42. .padding()
  43. }
  44. .navigationTitle("What's sent")
  45. .navigationBarTitleDisplayMode(.inline)
  46. .onAppear { jsonText = Self.renderPayload() }
  47. .confirmationDialog(
  48. "Reset App Attest state?",
  49. isPresented: $showResetConfirm,
  50. titleVisibility: .visible
  51. ) {
  52. Button("Reset and retry send", role: .destructive) {
  53. TelemetryAttestor.shared.resetAttestState()
  54. resetStatus = "Reset done — attempting a fresh send. Check logs for status."
  55. Task { await TelemetryClient.shared.maybeSend() }
  56. }
  57. Button("Cancel", role: .cancel) {}
  58. } message: {
  59. Text(
  60. "Clears the local App Attest key, registered flag, and forbidden flag. The next telemetry send will re-attest from scratch. Use only if telemetry is stuck."
  61. )
  62. }
  63. }
  64. private static func renderPayload() -> String {
  65. let payload = TelemetryClient.shared.buildPayload()
  66. guard
  67. let data = try? JSONSerialization.data(
  68. withJSONObject: payload,
  69. options: [.prettyPrinted, .sortedKeys]
  70. ),
  71. let text = String(data: data, encoding: .utf8)
  72. else {
  73. return String(localized: "Unable to render payload.")
  74. }
  75. return text
  76. }
  77. }