DataSourceChoiceStepView.swift 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. // LoopFollow
  2. // DataSourceChoiceStepView.swift
  3. import SwiftUI
  4. struct DataSourceChoiceStepView: View {
  5. @ObservedObject var viewModel: OnboardingViewModel
  6. var body: some View {
  7. ScrollView {
  8. VStack(spacing: 24) {
  9. OnboardingStepHeader(
  10. systemImage: "antenna.radiowaves.left.and.right",
  11. title: "Choose a data source",
  12. subtitle: "LoopFollow needs a glucose data source. Pick one now — you can change or add more later in Settings."
  13. )
  14. .padding(.horizontal)
  15. VStack(spacing: 14) {
  16. choiceCard(
  17. source: .nightscout,
  18. icon: "globe",
  19. title: "Nightscout",
  20. detail: "Follow a Nightscout site. Works with Loop, Trio, and most uploaders. Enables the full set of LoopFollow features."
  21. )
  22. choiceCard(
  23. source: .dexcom,
  24. icon: "sensor.tag.radiowaves.forward.fill",
  25. title: "Dexcom Share",
  26. detail: "Follow glucose directly from a Dexcom Share account, without a Nightscout site."
  27. )
  28. choiceCard(
  29. source: .copyFromPhone,
  30. icon: "qrcode",
  31. title: "Copy from another phone",
  32. detail: "Already using LoopFollow on another phone? Scan its QR code to copy the connection here."
  33. )
  34. }
  35. .padding(.horizontal)
  36. }
  37. .padding(.bottom, 24)
  38. }
  39. }
  40. private func choiceCard(source: OnboardingViewModel.DataSource, icon: String, title: String, detail: String) -> some View {
  41. let isSelected = viewModel.dataSource == source
  42. return Button {
  43. viewModel.dataSource = source
  44. } label: {
  45. HStack(alignment: .top, spacing: 14) {
  46. Image(systemName: icon)
  47. .font(.title2)
  48. .foregroundStyle(isSelected ? Color.accentColor : .secondary)
  49. .frame(width: 32)
  50. VStack(alignment: .leading, spacing: 4) {
  51. Text(title)
  52. .font(.headline)
  53. .foregroundColor(.primary)
  54. Text(detail)
  55. .font(.subheadline)
  56. .foregroundColor(.secondary)
  57. .multilineTextAlignment(.leading)
  58. }
  59. Spacer(minLength: 0)
  60. Image(systemName: isSelected ? "checkmark.circle.fill" : "circle")
  61. .font(.title3)
  62. .foregroundStyle(isSelected ? Color.accentColor : Color(.systemGray3))
  63. }
  64. .padding()
  65. .background(
  66. RoundedRectangle(cornerRadius: 14, style: .continuous)
  67. .fill(Color(.secondarySystemGroupedBackground))
  68. )
  69. .overlay(
  70. RoundedRectangle(cornerRadius: 14, style: .continuous)
  71. .stroke(isSelected ? Color.accentColor : Color.clear, lineWidth: 2)
  72. )
  73. }
  74. .buttonStyle(.plain)
  75. }
  76. }