HistoryRootView+Adjustments.swift 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import CoreData
  2. import SwiftUI
  3. extension History.RootView {
  4. var adjustmentsList: some View {
  5. List {
  6. HStack {
  7. Text("Adjustment").foregroundStyle(.secondary)
  8. Spacer()
  9. }
  10. if !combinedAdjustments.isEmpty {
  11. ForEach(combinedAdjustments) { item in
  12. adjustmentView(for: item)
  13. }
  14. } else {
  15. ContentUnavailableView(
  16. String(localized: "No data."),
  17. systemImage: "clock.arrow.2.circlepath"
  18. )
  19. }
  20. }
  21. .listRowBackground(Color.chart)
  22. }
  23. fileprivate var combinedAdjustments: [AdjustmentItem] {
  24. let overrides = overrideRunStored.map { override -> AdjustmentItem in
  25. AdjustmentItem(
  26. id: override.objectID,
  27. name: override.name ?? String(localized: "Override"),
  28. startDate: override.startDate ?? Date(),
  29. endDate: override.endDate ?? Date(),
  30. target: override.target?.decimalValue,
  31. type: .override
  32. )
  33. }
  34. let tempTargets = tempTargetRunStored.map { tempTarget -> AdjustmentItem in
  35. AdjustmentItem(
  36. id: tempTarget.objectID,
  37. name: tempTarget.name ?? String(localized: "Temp Target"),
  38. startDate: tempTarget.startDate ?? Date(),
  39. endDate: tempTarget.endDate ?? Date(),
  40. target: tempTarget.target?.decimalValue,
  41. type: .tempTarget
  42. )
  43. }
  44. let combined = overrides + tempTargets
  45. return combined.sorted {
  46. if $0.startDate == $1.startDate {
  47. return $0.endDate > $1.endDate
  48. }
  49. return $0.startDate > $1.startDate
  50. }
  51. }
  52. fileprivate struct AdjustmentItem: Identifiable {
  53. let id: NSManagedObjectID
  54. let name: String
  55. let startDate: Date
  56. let endDate: Date
  57. let target: Decimal?
  58. let type: AdjustmentType
  59. }
  60. fileprivate enum AdjustmentType {
  61. case override
  62. case tempTarget
  63. var symbolName: String {
  64. switch self {
  65. case .override:
  66. return "clock.arrow.2.circlepath"
  67. case .tempTarget:
  68. return "target"
  69. }
  70. }
  71. var symbolColor: Color {
  72. switch self {
  73. case .override:
  74. return .orange
  75. case .tempTarget:
  76. return .blue
  77. }
  78. }
  79. }
  80. @ViewBuilder fileprivate func adjustmentView(for item: AdjustmentItem) -> some View {
  81. let formattedDates =
  82. "\(Formatter.dateFormatter.string(from: item.startDate)) - \(Formatter.dateFormatter.string(from: item.endDate))"
  83. let targetDescription: String = {
  84. guard let target = item.target, target != 0 else {
  85. return ""
  86. }
  87. return "\(state.units == .mgdL ? target : target.asMmolL) \(state.units.rawValue)"
  88. }()
  89. let labels: [String] = [
  90. targetDescription,
  91. formattedDates
  92. ].filter { !$0.isEmpty }
  93. ZStack(alignment: .trailing) {
  94. HStack {
  95. VStack(alignment: .leading) {
  96. HStack {
  97. Image(systemName: item.type.symbolName)
  98. .foregroundStyle(item.type == .override ? Color.purple : Color.green)
  99. Text(item.name)
  100. .font(.headline)
  101. Spacer()
  102. }
  103. HStack(spacing: 5) {
  104. ForEach(labels, id: \.self) { label in
  105. Text(label)
  106. if label != labels.last {
  107. Divider()
  108. }
  109. }
  110. Spacer()
  111. }
  112. .padding(.top, 2)
  113. .foregroundColor(.secondary)
  114. .font(.caption)
  115. }
  116. .contentShape(Rectangle())
  117. }
  118. }
  119. .padding(.vertical, 8)
  120. }
  121. }