DiagnosticsStepView.swift 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import SwiftUI
  2. struct DiagnosticsStepView: View {
  3. @Bindable var state: Onboarding.StateModel
  4. @Environment(\.openURL) var openURL
  5. var body: some View {
  6. VStack(alignment: .leading, spacing: 20) {
  7. Text("Help us improve Trio. Pick how much you'd like to share — or opt out entirely.")
  8. .font(.headline)
  9. .padding(.horizontal)
  10. .multilineTextAlignment(.leading)
  11. ForEach(DiagnosticsSharingOption.allCases, id: \.self) { option in
  12. Button(action: {
  13. state.updateDiagnosticsOption(to: option)
  14. }) {
  15. HStack(alignment: .top, spacing: 12) {
  16. Image(systemName: state.diagnosticsSharingOption == option ? "largecircle.fill.circle" : "circle")
  17. .foregroundColor(state.diagnosticsSharingOption == option ? .accentColor : .secondary)
  18. .imageScale(.large)
  19. VStack(alignment: .leading, spacing: 4) {
  20. Text(option.displayName)
  21. .foregroundColor(.primary)
  22. .bold()
  23. Text(option.caption)
  24. .font(.footnote)
  25. .foregroundColor(.secondary)
  26. }
  27. Spacer()
  28. }
  29. .padding()
  30. .background(Color.chart.opacity(0.65))
  31. .cornerRadius(10)
  32. }
  33. .buttonStyle(.plain)
  34. }
  35. NavigationLink {
  36. TelemetryPreviewView()
  37. } label: {
  38. Label("See exactly what's sent", systemImage: "doc.text.magnifyingglass")
  39. .font(.footnote)
  40. }
  41. .padding(.horizontal)
  42. Toggle(isOn: $state.hasAcceptedPrivacyPolicy) {
  43. HStack {
  44. Text("I have read and accept the")
  45. Button("Privacy Policy") {
  46. if let url = URL(string: "https://github.com/nightscout/Trio/blob/dev/PRIVACY_POLICY.md") {
  47. openURL(url)
  48. } else {
  49. debug(.default, "Invalid URL! Could not gracefully unwrap privacy policy link!")
  50. }
  51. }
  52. .foregroundColor(.accentColor)
  53. .underline()
  54. }
  55. .font(.footnote)
  56. .bold()
  57. }
  58. .toggleStyle(CheckboxToggleStyle(tint: Color.accentColor))
  59. .padding(.horizontal)
  60. .disabled(state.diagnosticsSharingOption == .disabled)
  61. .opacity(state.diagnosticsSharingOption == .disabled ? 0.35 : 1)
  62. VStack(alignment: .leading, spacing: 8) {
  63. Text("Why does Trio collect this data?").bold()
  64. VStack(alignment: .leading, spacing: 4) {
  65. BulletPoint(
  66. String(
  67. localized: "App diagnostic insights — based on crash reports only — help us enhance app stability, ensure safety for all users, and quickly identify and resolve critical issues."
  68. )
  69. )
  70. BulletPoint(
  71. String(
  72. localized: "Crash reports include the app's state on crash, device, iOS info, and a stack trace. They are sent to Google Firebase Crashlytics, maintained by the Trio team."
  73. )
  74. )
  75. BulletPoint(
  76. String(
  77. localized: "Anonymous usage statistics include the app version, your device and iOS version, your paired pump and CGM, and whether Nightscout, Tidepool, and Apple Health are configured (yes/no). No URLs, tokens, or credentials are included."
  78. )
  79. )
  80. BulletPoint(
  81. String(
  82. localized: "Trio never collects glucose readings, insulin rates or doses, meal data, therapy setting values, or any other health information."
  83. )
  84. )
  85. }
  86. }
  87. .multilineTextAlignment(.leading)
  88. .padding(.horizontal)
  89. .font(.footnote)
  90. .foregroundStyle(Color.secondary)
  91. }
  92. .onAppear {
  93. state.syncDiagnosticsOptionFromStorage()
  94. }
  95. }
  96. }