PodDetailsView.swift 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. //
  2. // PodDetailsView.swift
  3. // OmniKit
  4. //
  5. // Created by Pete Schwamb on 4/14/20.
  6. // Copyright © 2021 LoopKit Authors. All rights reserved.
  7. //
  8. import SwiftUI
  9. import LoopKitUI
  10. import OmniKit
  11. public struct PodDetails {
  12. var lotNumber: UInt32
  13. var sequenceNumber: UInt32
  14. var piVersion: String
  15. var pmVersion: String
  16. var totalDelivery: Double?
  17. var lastStatus: Date?
  18. var fault: FaultEventCode?
  19. var activatedAt: Date?
  20. var activeTime: TimeInterval?
  21. var pdmRef: String?
  22. }
  23. struct PodDetailsView: View {
  24. @Environment(\.guidanceColors) var guidanceColors
  25. var podDetails: PodDetails
  26. var title: String
  27. let statusAgeFormatter: DateComponentsFormatter = {
  28. let formatter = DateComponentsFormatter()
  29. formatter.allowedUnits = [.day, .hour, .minute, .second]
  30. formatter.maximumUnitCount = 1
  31. formatter.unitsStyle = .short
  32. return formatter
  33. }()
  34. let activeTimeFormatter: DateComponentsFormatter = {
  35. let formatter = DateComponentsFormatter()
  36. formatter.allowedUnits = [.day, .hour, .minute]
  37. formatter.maximumUnitCount = 2
  38. formatter.unitsStyle = .full
  39. return formatter
  40. }()
  41. let dateFormatter: DateFormatter = {
  42. let dateFormatter = DateFormatter()
  43. dateFormatter.timeStyle = .short
  44. dateFormatter.dateStyle = .medium
  45. dateFormatter.doesRelativeDateFormatting = true
  46. return dateFormatter
  47. }()
  48. private func row(_ label: String, value: String) -> some View {
  49. HStack {
  50. Text(label)
  51. Spacer()
  52. Text(value)
  53. .foregroundColor(.secondary)
  54. }
  55. }
  56. var totalDeliveryText: String {
  57. if let delivery = podDetails.totalDelivery {
  58. return String(format: LocalizedString("%g U", comment: "Format string for total delivery on pod details screen"), delivery)
  59. } else {
  60. return LocalizedString("NA", comment: "String shown on pod details for total delivery when not available.")
  61. }
  62. }
  63. func activeTimeText(_ duration: TimeInterval) -> String {
  64. return activeTimeFormatter.string(from: duration) ?? LocalizedString("NA", comment: "String shown on pod details for active time when conversion fails.")
  65. }
  66. var lastStatusText: String {
  67. if let lastStatus = podDetails.lastStatus, let ageString = statusAgeFormatter.string(from: Date().timeIntervalSince(lastStatus)) {
  68. return String(format: LocalizedString("%@ ago", comment: "Format string for last status date on pod details screen"), ageString)
  69. } else {
  70. return LocalizedString("NA", comment: "String shown on pod details for last status date when not available.")
  71. }
  72. }
  73. var body: some View {
  74. List {
  75. row(LocalizedString("Lot Number", comment: "description label for lot number pod details row"), value: String(describing: podDetails.lotNumber))
  76. row(LocalizedString("Sequence Number", comment: "description label for sequence number pod details row"), value: String(format: "%07d", podDetails.sequenceNumber))
  77. row(LocalizedString("PI Version", comment: "description label for pi version pod details row"), value: podDetails.piVersion)
  78. row(LocalizedString("PM Version", comment: "description label for ble firmware version pod details row"), value: podDetails.pmVersion)
  79. row(LocalizedString("Total Delivery", comment: "description label for total delivery pod details row"), value: totalDeliveryText)
  80. if let activeTime = podDetails.activeTime, let activatedAt = podDetails.activatedAt {
  81. row(LocalizedString("Pod Activated", comment: "description label for activated at time pod details row"), value: dateFormatter.string(from: activatedAt))
  82. row(LocalizedString("Active Time", comment: "description label for active time pod details row"), value: activeTimeText(activeTime))
  83. } else {
  84. row(LocalizedString("Last Status", comment: "description label for last status date pod details row"), value: lastStatusText)
  85. }
  86. if let fault = podDetails.fault, let pdmRef = podDetails.pdmRef {
  87. Section {
  88. VStack(alignment: .leading) {
  89. HStack {
  90. Image(systemName: "exclamationmark.triangle.fill")
  91. .foregroundColor(guidanceColors.critical)
  92. Text(LocalizedString("Pod Fault Details", comment: "description label for pod fault details"))
  93. .fontWeight(.semibold)
  94. }.padding(.vertical, 4)
  95. Text(String(format: LocalizedString("Internal Pod fault code %1$03d\n%2$@\nRef: %3$@\n", comment: "The format string for the pod fault info: (1: fault code) (2: fault description) (3: pdm ref string)"), fault.rawValue, fault.faultDescription, pdmRef))
  96. .fixedSize(horizontal: false, vertical: true)
  97. .foregroundColor(.secondary)
  98. }
  99. }
  100. }
  101. }
  102. .navigationBarTitle(Text(title), displayMode: .automatic)
  103. }
  104. }
  105. struct PodDetailsView_Previews: PreviewProvider {
  106. static var previews: some View {
  107. PodDetailsView(podDetails: PodDetails(lotNumber: 123456789, sequenceNumber: 1234567, piVersion: "2.1.0", pmVersion: "2.1.0", totalDelivery: 99, lastStatus: Date(), fault: FaultEventCode(rawValue: 064), activatedAt: Date().addingTimeInterval(.days(2)), pdmRef: "19-02448-09951-064"), title: "Device Details")
  108. }
  109. }