Procházet zdrojové kódy

Merge branch 'dev' of github.com:nightscout/Trio-dev into beta-watch-fixes

Deniz Cengiz před 1 rokem
rodič
revize
0e10a55220
100 změnil soubory, kde provedl 181953 přidání a 51610 odebrání
  1. 12 2
      Model/CoreDataStack.swift
  2. 14 0
      Model/Helper/AdjustmentStored+Helper.swift
  3. 9 6
      Model/Helper/CoreDataError.swift
  4. 0 10
      Model/Helper/OverrideStored+helper.swift
  5. 87 3
      Model/Helper/PumpEvent+helper.swift
  6. 11 1
      Trio Watch App Extension/Helper/Helper+ButtonStyles.swift
  7. 20 0
      Trio Watch App Extension/Views/BolusProgressOverlay.swift
  8. 2 2
      Trio Watch App Extension/Views/GlucoseChartView.swift
  9. 9 4
      Trio Watch App Extension/Views/TrioMainWatchView.swift
  10. 16 115
      Trio.xcodeproj/project.pbxproj
  11. 0 23
      Trio/Resources/Base.lproj/InfoPlist.strings
  12. 1059 0
      Trio/Resources/InfoPlist.xcstrings
  13. 0 20
      Trio/Resources/ar.lproj/InfoPlist.strings
  14. 0 20
      Trio/Resources/ca.lproj/InfoPlist.strings
  15. 0 20
      Trio/Resources/da.lproj/InfoPlist.strings
  16. 0 20
      Trio/Resources/de.lproj/InfoPlist.strings
  17. 0 20
      Trio/Resources/es.lproj/InfoPlist.strings
  18. 0 20
      Trio/Resources/fi.lproj/InfoPlist.strings
  19. 0 20
      Trio/Resources/fr.lproj/InfoPlist.strings
  20. 0 20
      Trio/Resources/he.lproj/InfoPlist.strings
  21. 0 20
      Trio/Resources/hu.lproj/InfoPlist.strings
  22. 0 20
      Trio/Resources/it.lproj/InfoPlist.strings
  23. 0 20
      Trio/Resources/nb.lproj/InfoPlist.strings
  24. 0 20
      Trio/Resources/nl.lproj/InfoPlist.strings
  25. 0 20
      Trio/Resources/pl.lproj/InfoPlist.strings
  26. 0 20
      Trio/Resources/pt-BR.lproj/InfoPlist.strings
  27. 0 20
      Trio/Resources/pt-PT.lproj/InfoPlist.strings
  28. 0 20
      Trio/Resources/ru.lproj/InfoPlist.strings
  29. 0 20
      Trio/Resources/sk.lproj/InfoPlist.strings
  30. 0 20
      Trio/Resources/sv.lproj/InfoPlist.strings
  31. 0 20
      Trio/Resources/tr.lproj/InfoPlist.strings
  32. 0 20
      Trio/Resources/uk.lproj/InfoPlist.strings
  33. 0 20
      Trio/Resources/vi.lproj/InfoPlist.strings
  34. 0 20
      Trio/Resources/zh-Hans.lproj/InfoPlist.strings
  35. 9 3
      Trio/Sources/APS/APSManager.swift
  36. 1 1
      Trio/Sources/APS/CGM/AppGroupSource.swift
  37. 8 7
      Trio/Sources/APS/CGM/CGMType.swift
  38. 4 3
      Trio/Sources/APS/CGM/PluginSource.swift
  39. 27 5
      Trio/Sources/APS/FetchGlucoseManager.swift
  40. 25 10
      Trio/Sources/APS/OpenAPS/OpenAPS.swift
  41. 1 1
      Trio/Sources/APS/Storage/ContactImageStorage.swift
  42. 2 2
      Trio/Sources/APS/Storage/GlucoseStorage.swift
  43. 3 3
      Trio/Sources/APS/Storage/OverrideStorage.swift
  44. 3 3
      Trio/Sources/APS/Storage/TempTargetsStorage.swift
  45. 22 7
      Trio/Sources/Application/TrioApp.swift
  46. 4 4
      Trio/Sources/Helpers/BuildDetails.swift
  47. 4 4
      Trio/Sources/Helpers/HKUnit.swift
  48. 180308 0
      Trio/Sources/Localizations/Main/Localizable.xcstrings
  49. 0 2223
      Trio/Sources/Localizations/Main/ar.lproj/Localizable.strings
  50. 0 1917
      Trio/Sources/Localizations/Main/ca.lproj/Localizable.strings
  51. 0 2184
      Trio/Sources/Localizations/Main/da.lproj/Localizable.strings
  52. 0 2229
      Trio/Sources/Localizations/Main/de.lproj/Localizable.strings
  53. 0 2231
      Trio/Sources/Localizations/Main/en.lproj/Localizable.strings
  54. 0 2228
      Trio/Sources/Localizations/Main/es.lproj/Localizable.strings
  55. 0 2229
      Trio/Sources/Localizations/Main/fi.lproj/Localizable.strings
  56. 0 2220
      Trio/Sources/Localizations/Main/fr.lproj/Localizable.strings
  57. 0 2223
      Trio/Sources/Localizations/Main/he.lproj/Localizable.strings
  58. 0 2178
      Trio/Sources/Localizations/Main/hu.lproj/Localizable.strings
  59. 0 2225
      Trio/Sources/Localizations/Main/it.lproj/Localizable.strings
  60. 0 2223
      Trio/Sources/Localizations/Main/nb.lproj/Localizable.strings
  61. 0 2231
      Trio/Sources/Localizations/Main/nl.lproj/Localizable.strings
  62. 0 2225
      Trio/Sources/Localizations/Main/pl.lproj/Localizable.strings
  63. 0 2223
      Trio/Sources/Localizations/Main/pt-BR.lproj/Localizable.strings
  64. 0 2223
      Trio/Sources/Localizations/Main/pt-PT.lproj/Localizable.strings
  65. 0 2226
      Trio/Sources/Localizations/Main/ru.lproj/Localizable.strings
  66. 0 2178
      Trio/Sources/Localizations/Main/sk.lproj/Localizable.strings
  67. 0 2223
      Trio/Sources/Localizations/Main/sv.lproj/Localizable.strings
  68. 0 2227
      Trio/Sources/Localizations/Main/tr.lproj/Localizable.strings
  69. 0 2223
      Trio/Sources/Localizations/Main/uk.lproj/Localizable.strings
  70. 0 2180
      Trio/Sources/Localizations/Main/vi.lproj/Localizable.strings
  71. 0 2225
      Trio/Sources/Localizations/Main/zh-Hans.lproj/Localizable.strings
  72. 4 0
      Trio/Sources/Logger/Logger.swift
  73. 16 16
      Trio/Sources/Models/ContactTrickEntry.swift
  74. 2 2
      Trio/Sources/Models/ForecastDisplayType.swift
  75. 2 2
      Trio/Sources/Models/HbA1cDisplayUnit.swift
  76. 2 2
      Trio/Sources/Models/LockScreenView.swift
  77. 2 2
      Trio/Sources/Models/TimeInRangeChartStyle.swift
  78. 2 2
      Trio/Sources/Models/TotalInsulinDisplayType.swift
  79. 2 5
      Trio/Sources/Modules/Adjustments/AdjustmentsDataFlow.swift
  80. 2 2
      Trio/Sources/Modules/Adjustments/AdjustmentsStateModel+Extensions/AdjustmentsStateModel+Overrides.swift
  81. 5 5
      Trio/Sources/Modules/Adjustments/AdjustmentsStateModel+Extensions/AdjustmentsStateModel+TempTargets.swift
  82. 65 34
      Trio/Sources/Modules/AlgorithmAdvancedSettings/View/AlgorithmAdvancedSettingsRootView.swift
  83. 9 9
      Trio/Sources/Modules/AutosensSettings/View/AutosensSettingsRootView.swift
  84. 15 15
      Trio/Sources/Modules/BolusCalculatorConfig/View/BolusCalculatorConfigRootView.swift
  85. 10 6
      Trio/Sources/Modules/CGMSettings/CGMSettingsStateModel.swift
  86. 4 4
      Trio/Sources/Modules/CGMSettings/View/CGMRootView.swift
  87. 11 11
      Trio/Sources/Modules/CalendarEventSettings/View/CalendarEventSettingsRootView.swift
  88. 6 6
      Trio/Sources/Modules/ContactImage/View/ContactImageHelpView.swift
  89. 17 23
      Trio/Sources/Modules/DataTable/DataTableDataFlow.swift
  90. 15 15
      Trio/Sources/Modules/DataTable/View/DataTableRootView.swift
  91. 28 26
      Trio/Sources/Modules/DynamicSettings/View/DynamicSettingsRootView.swift
  92. 12 12
      Trio/Sources/Modules/GeneralSettings/View/UnitsLimitsSettingsRootView.swift
  93. 26 26
      Trio/Sources/Modules/GlucoseNotificationSettings/View/GlucoseNotificationSettingsRootView.swift
  94. 5 5
      Trio/Sources/Modules/HealthKit/View/AppleHealthKitRootView.swift
  95. 1 1
      Trio/Sources/Modules/Home/HomeStateModel+Setup/DeterminationSetup.swift
  96. 9 5
      Trio/Sources/Modules/Home/HomeStateModel.swift
  97. 2 2
      Trio/Sources/Modules/Home/View/Chart/ChartElements/SelectionPopoverView.swift
  98. 17 17
      Trio/Sources/Modules/Home/View/Chart/ChartLegendView.swift
  99. 2 2
      Trio/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift
  100. 0 0
      Trio/Sources/Modules/Home/View/Header/LoopStatusHelpView.swift

+ 12 - 2
Model/CoreDataStack.swift

@@ -105,7 +105,7 @@ class CoreDataStack: ObservableObject {
     private func fetchPersistentHistoryTransactionsAndChanges() async throws {
     private func fetchPersistentHistoryTransactionsAndChanges() async throws {
         let taskContext = newTaskContext()
         let taskContext = newTaskContext()
         taskContext.name = "persistentHistoryContext"
         taskContext.name = "persistentHistoryContext"
-//        debugPrint("Start fetching persistent history changes from the store ... \(DebuggingIdentifiers.inProgress)")
+        //        debugPrint("Start fetching persistent history changes from the store ... \(DebuggingIdentifiers.inProgress)")
 
 
         try await taskContext.perform {
         try await taskContext.perform {
             // Execute the persistent history change since the last transaction
             // Execute the persistent history change since the last transaction
@@ -120,7 +120,7 @@ class CoreDataStack: ObservableObject {
     }
     }
 
 
     private func mergePersistentHistoryChanges(from history: [NSPersistentHistoryTransaction]) {
     private func mergePersistentHistoryChanges(from history: [NSPersistentHistoryTransaction]) {
-//        debugPrint("Received \(history.count) persistent history transactions")
+        //        debugPrint("Received \(history.count) persistent history transactions")
         // Update view context with objectIDs from history change request
         // Update view context with objectIDs from history change request
         /// - Tag: mergeChanges
         /// - Tag: mergeChanges
         let viewContext = persistentContainer.viewContext
         let viewContext = persistentContainer.viewContext
@@ -150,6 +150,16 @@ class CoreDataStack: ObservableObject {
             }
             }
         }
         }
     }
     }
+
+    func initializeStack() throws {
+        // Force initialization of persistent container
+        let container = persistentContainer
+
+        // Verify the store is loaded and available
+        guard container.persistentStoreCoordinator.persistentStores.isNotEmpty else {
+            throw CoreDataError.storeNotInitializedError
+        }
+    }
 }
 }
 
 
 // MARK: - Delete
 // MARK: - Delete

+ 14 - 0
Model/Helper/AdjustmentStored+Helper.swift

@@ -0,0 +1,14 @@
+import CoreData
+import Foundation
+
+extension NSPredicate {
+    static var lastActiveAdjustmentNotYetUploadedToNightscout: NSPredicate {
+        let date = Date.oneDayAgo
+        return NSPredicate(
+            format: "date >= %@ AND enabled == %@ AND isUploadedToNS == %@",
+            date as NSDate,
+            true as NSNumber,
+            false as NSNumber
+        )
+    }
+}

+ 9 - 6
Model/Helper/CoreDataError.swift

@@ -7,23 +7,26 @@ enum CoreDataError: Error {
     case persistentHistoryChangeError
     case persistentHistoryChangeError
     case unexpectedError(error: Error)
     case unexpectedError(error: Error)
     case fetchError
     case fetchError
+    case storeNotInitializedError
 }
 }
 
 
 extension CoreDataError: LocalizedError {
 extension CoreDataError: LocalizedError {
     var errorDescription: String? {
     var errorDescription: String? {
         switch self {
         switch self {
         case .creationError:
         case .creationError:
-            return NSLocalizedString("Failed to create a new object.", comment: "")
+            return String(localized: "Failed to create a new object.", comment: "")
         case .batchInsertError:
         case .batchInsertError:
-            return NSLocalizedString("Failed to execute a batch insert request.", comment: "")
+            return String(localized: "Failed to execute a batch insert request.", comment: "")
         case .batchDeleteError:
         case .batchDeleteError:
-            return NSLocalizedString("Failed to execute a batch delete request.", comment: "")
+            return String(localized: "Failed to execute a batch delete request.", comment: "")
         case .persistentHistoryChangeError:
         case .persistentHistoryChangeError:
-            return NSLocalizedString("Failed to execute a persistent history change request.", comment: "")
+            return String(localized: "Failed to execute a persistent history change request.", comment: "")
         case let .unexpectedError(error):
         case let .unexpectedError(error):
-            return NSLocalizedString("Received unexpected error. \(error.localizedDescription)", comment: "")
+            return String(localized: "Received unexpected error. \(error.localizedDescription)", comment: "")
         case .fetchError:
         case .fetchError:
-            return NSLocalizedString("Failed to fetch object \(DebuggingIdentifiers.failed).", comment: "")
+            return String(localized: "Failed to fetch object \(DebuggingIdentifiers.failed).", comment: "")
+        case .storeNotInitializedError:
+            return String(localized: "Failed to initialize Core Data's persistent store.", comment: "")
         }
         }
     }
     }
 }
 }

+ 0 - 10
Model/Helper/OverrideStored+helper.swift

@@ -14,16 +14,6 @@ extension NSPredicate {
             true as NSNumber
             true as NSNumber
         )
         )
     }
     }
-
-    static var lastActiveOverrideNotYetUploadedToNightscout: NSPredicate {
-        let date = Date.oneDayAgo
-        return NSPredicate(
-            format: "date >= %@ AND enabled == %@ AND isUploadedToNS == %@",
-            date as NSDate,
-            true as NSNumber,
-            false as NSNumber
-        )
-    }
 }
 }
 
 
 extension OverrideStored {
 extension OverrideStored {

+ 87 - 3
Model/Helper/PumpEvent+helper.swift

@@ -102,7 +102,7 @@ struct BolusDTO: Codable {
     var isExternal: Bool
     var isExternal: Bool
     var isSMB: Bool
     var isSMB: Bool
     var duration: Int
     var duration: Int
-    var _type: String = "Bolus"
+    var _type: String = EventType.bolus.rawValue
 }
 }
 
 
 struct TempBasalDTO: Codable {
 struct TempBasalDTO: Codable {
@@ -110,14 +110,14 @@ struct TempBasalDTO: Codable {
     var timestamp: String
     var timestamp: String
     var temp: String
     var temp: String
     var rate: Double
     var rate: Double
-    var _type: String = "TempBasal"
+    var _type: String = EventType.tempBasal.rawValue
 }
 }
 
 
 struct TempBasalDurationDTO: Codable {
 struct TempBasalDurationDTO: Codable {
     var id: String
     var id: String
     var timestamp: String
     var timestamp: String
     var duration: Int
     var duration: Int
-    var _type: String = "TempBasalDuration"
+    var _type: String = EventType.tempBasalDuration.rawValue
 
 
     private enum CodingKeys: String, CodingKey {
     private enum CodingKeys: String, CodingKey {
         case id
         case id
@@ -127,11 +127,39 @@ struct TempBasalDurationDTO: Codable {
     }
     }
 }
 }
 
 
+struct SuspendDTO: Codable {
+    var id: String
+    var timestamp: String
+    var _type: String = EventType.pumpSuspend.rawValue
+}
+
+struct ResumeDTO: Codable {
+    var id: String
+    var timestamp: String
+    var _type: String = EventType.pumpResume.rawValue
+}
+
+struct RewindDTO: Codable {
+    var id: String
+    var timestamp: String
+    var _type: String = EventType.rewind.rawValue
+}
+
+struct PrimeDTO: Codable {
+    var id: String
+    var timestamp: String
+    var _type: String = EventType.prime.rawValue
+}
+
 // Mask distinct DTO subtypes with a common enum that conforms to Encodable
 // Mask distinct DTO subtypes with a common enum that conforms to Encodable
 enum PumpEventDTO: Encodable {
 enum PumpEventDTO: Encodable {
     case bolus(BolusDTO)
     case bolus(BolusDTO)
     case tempBasal(TempBasalDTO)
     case tempBasal(TempBasalDTO)
     case tempBasalDuration(TempBasalDurationDTO)
     case tempBasalDuration(TempBasalDurationDTO)
+    case suspend(SuspendDTO)
+    case resume(ResumeDTO)
+    case rewind(RewindDTO)
+    case prime(PrimeDTO)
 
 
     func encode(to encoder: Encoder) throws {
     func encode(to encoder: Encoder) throws {
         switch self {
         switch self {
@@ -141,6 +169,14 @@ enum PumpEventDTO: Encodable {
             try tempBasal.encode(to: encoder)
             try tempBasal.encode(to: encoder)
         case let .tempBasalDuration(tempBasalDuration):
         case let .tempBasalDuration(tempBasalDuration):
             try tempBasalDuration.encode(to: encoder)
             try tempBasalDuration.encode(to: encoder)
+        case let .suspend(suspend):
+            try suspend.encode(to: encoder)
+        case let .resume(resume):
+            try resume.encode(to: encoder)
+        case let .rewind(rewind):
+            try rewind.encode(to: encoder)
+        case let .prime(prime):
+            try prime.encode(to: encoder)
         }
         }
     }
     }
 }
 }
@@ -195,4 +231,52 @@ extension PumpEventStored {
         )
         )
         return .tempBasalDuration(tempBasalDurationDTO)
         return .tempBasalDuration(tempBasalDurationDTO)
     }
     }
+
+    func toPumpSuspendDTO() -> PumpEventDTO? {
+        guard let id = id, let timestamp = timestamp, let type = type, type == EventType.pumpSuspend.rawValue else {
+            return nil
+        }
+
+        let suspendDTO = SuspendDTO(
+            id: id,
+            timestamp: PumpEventStored.dateFormatter.string(from: timestamp)
+        )
+        return .suspend(suspendDTO)
+    }
+
+    func toPumpResumeDTO() -> PumpEventDTO? {
+        guard let id = id, let timestamp = timestamp, let type = type, type == EventType.pumpResume.rawValue else {
+            return nil
+        }
+
+        let resumeDTO = ResumeDTO(
+            id: id,
+            timestamp: PumpEventStored.dateFormatter.string(from: timestamp)
+        )
+        return .resume(resumeDTO)
+    }
+
+    func toRewindDTO() -> PumpEventDTO? {
+        guard let id = id, let timestamp = timestamp, let type = type, type == EventType.rewind.rawValue else {
+            return nil
+        }
+
+        let rewindDTO = RewindDTO(
+            id: id,
+            timestamp: PumpEventStored.dateFormatter.string(from: timestamp)
+        )
+        return .rewind(rewindDTO)
+    }
+
+    func toPrimeDTO() -> PumpEventDTO? {
+        guard let id = id, let timestamp = timestamp, let type = type, type == EventType.prime.rawValue else {
+            return nil
+        }
+
+        let primeDTO = PrimeDTO(
+            id: id,
+            timestamp: PumpEventStored.dateFormatter.string(from: timestamp)
+        )
+        return .prime(primeDTO)
+    }
 }
 }

+ 11 - 1
Trio Watch App Extension/Helper/Helper+ButtonStyles.swift

@@ -5,6 +5,8 @@ struct WatchOSButtonStyle: ButtonStyle {
     var foregroundColor: Color = .white
     var foregroundColor: Color = .white
     var fontSize: Font = .title2
     var fontSize: Font = .title2
 
 
+    @Environment(\.isEnabled) private var isEnabled: Bool
+
     private var fontWeight: Font.Weight {
     private var fontWeight: Font.Weight {
         switch deviceType {
         switch deviceType {
         case .watch40mm:
         case .watch40mm:
@@ -44,11 +46,19 @@ struct WatchOSButtonStyle: ButtonStyle {
     }
     }
 
 
     func makeBody(configuration: Configuration) -> some View {
     func makeBody(configuration: Configuration) -> some View {
+        var buttonBackground: Color {
+            if isEnabled {
+                return Color.tabBar.opacity(configuration.isPressed ? 0.8 : 1.0)
+            } else {
+                return Color.tabBar.opacity(0.4)
+            }
+        }
+
         configuration.label
         configuration.label
             .font(fontSize)
             .font(fontSize)
             .fontWeight(fontWeight)
             .fontWeight(fontWeight)
             .padding(buttonPadding)
             .padding(buttonPadding)
-            .background(Color.tabBar.opacity(configuration.isPressed ? 0.8 : 1.0))
+            .background(buttonBackground)
             .clipShape(Circle())
             .clipShape(Circle())
             .animation(.easeInOut(duration: 0.1), value: configuration.isPressed)
             .animation(.easeInOut(duration: 0.1), value: configuration.isPressed)
     }
     }

+ 20 - 0
Trio Watch App Extension/Views/BolusProgressOverlay.swift

@@ -16,6 +16,25 @@ struct BolusProgressOverlay: View {
         endPoint: .trailing
         endPoint: .trailing
     )
     )
 
 
+    private var isWatchStateDated: Bool {
+        // If `lastWatchStateUpdate` is nil, treat as "dated"
+        guard let lastUpdateTimestamp = state.lastWatchStateUpdate else {
+            return true
+        }
+        let now = Date().timeIntervalSince1970
+        let secondsSinceUpdate = now - lastUpdateTimestamp
+        // Return true if last update older than 5 min, so 1 loop cycle
+        return secondsSinceUpdate > 5 * 60
+    }
+
+    private var isSessionUnreachable: Bool {
+        guard let session = state.session else {
+            return true // No session at all => unreachable
+        }
+        // Return true if not .activated OR not reachable
+        return session.activationState != .activated
+    }
+
     var body: some View {
     var body: some View {
         VStack(spacing: 10) {
         VStack(spacing: 10) {
             VStack {
             VStack {
@@ -45,6 +64,7 @@ struct BolusProgressOverlay: View {
                 }
                 }
                 .buttonStyle(.bordered)
                 .buttonStyle(.bordered)
                 .padding()
                 .padding()
+                .disabled(isWatchStateDated || isSessionUnreachable)
             }
             }
             .padding()
             .padding()
             .background(Color.black.opacity(0.9))
             .background(Color.black.opacity(0.9))

+ 2 - 2
Trio Watch App Extension/Views/GlucoseChartView.swift

@@ -6,8 +6,8 @@ import SwiftUI
 
 
 struct GlucoseChartView: View {
 struct GlucoseChartView: View {
     let glucoseValues: [(date: Date, glucose: Double, color: Color)]
     let glucoseValues: [(date: Date, glucose: Double, color: Color)]
-    @Binding var minYAxisValue: Decimal
-    @Binding var maxYAxisValue: Decimal
+    let minYAxisValue: Decimal
+    let maxYAxisValue: Decimal
     @State private var timeWindow: TimeWindow = .threeHours
     @State private var timeWindow: TimeWindow = .threeHours
 
 
     enum TimeWindow: Int {
     enum TimeWindow: Int {

+ 9 - 4
Trio Watch App Extension/Views/TrioMainWatchView.swift

@@ -90,8 +90,8 @@ struct TrioMainWatchView: View {
                 // Page 2: Glucose chart
                 // Page 2: Glucose chart
                 GlucoseChartView(
                 GlucoseChartView(
                     glucoseValues: state.glucoseValues,
                     glucoseValues: state.glucoseValues,
-                    minYAxisValue: $state.minYAxisValue,
-                    maxYAxisValue: $state.maxYAxisValue
+                    minYAxisValue: state.minYAxisValue,
+                    maxYAxisValue: state.maxYAxisValue
                 )
                 )
                 .tag(1)
                 .tag(1)
             }
             }
@@ -139,7 +139,9 @@ struct TrioMainWatchView: View {
                     } label: {
                     } label: {
                         Image(systemName: "clock.arrow.2.circlepath")
                         Image(systemName: "clock.arrow.2.circlepath")
                             .foregroundStyle(Color.primary, isOverrideActive ? Color.primary : Color.purple)
                             .foregroundStyle(Color.primary, isOverrideActive ? Color.primary : Color.purple)
-                    }.tint(isOverrideActive ? Color.purple : nil)
+                    }
+                    .tint(isOverrideActive ? Color.purple : nil)
+                    .disabled(isWatchStateDated || isSessionUnreachable)
 
 
                     Button {
                     Button {
                         showingTreatmentMenuSheet = true
                         showingTreatmentMenuSheet = true
@@ -149,13 +151,16 @@ struct TrioMainWatchView: View {
                     }
                     }
                     .controlSize(.large)
                     .controlSize(.large)
                     .buttonStyle(WatchOSButtonStyle(deviceType: state.deviceType))
                     .buttonStyle(WatchOSButtonStyle(deviceType: state.deviceType))
+                    .disabled(isWatchStateDated || isSessionUnreachable)
 
 
                     Button {
                     Button {
                         showingTempTargetSheet = true
                         showingTempTargetSheet = true
                     } label: {
                     } label: {
                         Image(systemName: "target")
                         Image(systemName: "target")
                             .foregroundStyle(isTempTargetActive ? Color.primary : Color.loopGreen.opacity(0.75))
                             .foregroundStyle(isTempTargetActive ? Color.primary : Color.loopGreen.opacity(0.75))
-                    }.tint(isTempTargetActive ? Color.loopGreen.opacity(0.75) : nil)
+                    }
+                    .tint(isTempTargetActive ? Color.loopGreen.opacity(0.75) : nil)
+                    .disabled(isWatchStateDated || isSessionUnreachable)
                 }
                 }
             }
             }
             .fullScreenCover(isPresented: $showingTreatmentMenuSheet) {
             .fullScreenCover(isPresented: $showingTreatmentMenuSheet) {

+ 16 - 115
Trio.xcodeproj/project.pbxproj

@@ -28,7 +28,6 @@
 		190EBCC829FF13AA00BA767D /* UserInterfaceSettingsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 190EBCC729FF13AA00BA767D /* UserInterfaceSettingsStateModel.swift */; };
 		190EBCC829FF13AA00BA767D /* UserInterfaceSettingsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 190EBCC729FF13AA00BA767D /* UserInterfaceSettingsStateModel.swift */; };
 		190EBCCB29FF13CB00BA767D /* UserInterfaceSettingsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 190EBCCA29FF13CB00BA767D /* UserInterfaceSettingsRootView.swift */; };
 		190EBCCB29FF13CB00BA767D /* UserInterfaceSettingsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 190EBCCA29FF13CB00BA767D /* UserInterfaceSettingsRootView.swift */; };
 		191F62682AD6B05A004D7911 /* NightscoutSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191F62672AD6B05A004D7911 /* NightscoutSettings.swift */; };
 		191F62682AD6B05A004D7911 /* NightscoutSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191F62672AD6B05A004D7911 /* NightscoutSettings.swift */; };
-		1927C8E62744606D00347C69 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1927C8E82744606D00347C69 /* InfoPlist.strings */; };
 		1935364028496F7D001E0B16 /* Oref2_variables.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1935363F28496F7D001E0B16 /* Oref2_variables.swift */; };
 		1935364028496F7D001E0B16 /* Oref2_variables.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1935363F28496F7D001E0B16 /* Oref2_variables.swift */; };
 		193F6CDD2A512C8F001240FD /* Loops.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193F6CDC2A512C8F001240FD /* Loops.swift */; };
 		193F6CDD2A512C8F001240FD /* Loops.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193F6CDC2A512C8F001240FD /* Loops.swift */; };
 		195D80B42AF6973A00D25097 /* DynamicSettingsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 195D80B32AF6973A00D25097 /* DynamicSettingsRootView.swift */; };
 		195D80B42AF6973A00D25097 /* DynamicSettingsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 195D80B32AF6973A00D25097 /* DynamicSettingsRootView.swift */; };
@@ -38,7 +37,6 @@
 		1967DFBE29D052C200759F30 /* Icons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1967DFBD29D052C200759F30 /* Icons.swift */; };
 		1967DFBE29D052C200759F30 /* Icons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1967DFBD29D052C200759F30 /* Icons.swift */; };
 		1967DFC029D053AC00759F30 /* IconSelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1967DFBF29D053AC00759F30 /* IconSelection.swift */; };
 		1967DFC029D053AC00759F30 /* IconSelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1967DFBF29D053AC00759F30 /* IconSelection.swift */; };
 		1967DFC229D053D300759F30 /* IconImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1967DFC129D053D300759F30 /* IconImage.swift */; };
 		1967DFC229D053D300759F30 /* IconImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1967DFC129D053D300759F30 /* IconImage.swift */; };
-		198377D2266BFFF6004DE65E /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 198377D4266BFFF6004DE65E /* Localizable.strings */; };
 		19A910302A24BF6300C8951B /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A9102F2A24BF6300C8951B /* StatsView.swift */; };
 		19A910302A24BF6300C8951B /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A9102F2A24BF6300C8951B /* StatsView.swift */; };
 		19A910362A24D6D700C8951B /* DateFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A910352A24D6D700C8951B /* DateFilter.swift */; };
 		19A910362A24D6D700C8951B /* DateFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A910352A24D6D700C8951B /* DateFilter.swift */; };
 		19A910382A24EF3200C8951B /* ChartsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A910372A24EF3200C8951B /* ChartsView.swift */; };
 		19A910382A24EF3200C8951B /* ChartsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A910372A24EF3200C8951B /* ChartsView.swift */; };
@@ -212,6 +210,7 @@
 		491D6FBE2D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FB92D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift */; };
 		491D6FBE2D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FB92D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift */; };
 		491D6FBF2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */; };
 		491D6FBF2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */; };
 		491D6FC02D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBB2D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift */; };
 		491D6FC02D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBB2D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift */; };
+		49B9B57F2D5768D2009C6B59 /* AdjustmentStored+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49B9B57E2D5768D2009C6B59 /* AdjustmentStored+Helper.swift */; };
 		5075C1608E6249A51495C422 /* TargetsEditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BDEA2DC60EDE0A3CA54DC73 /* TargetsEditorProvider.swift */; };
 		5075C1608E6249A51495C422 /* TargetsEditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BDEA2DC60EDE0A3CA54DC73 /* TargetsEditorProvider.swift */; };
 		53F2382465BF74DB1A967C8B /* PumpConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8630D58BDAD6D9C650B9B39 /* PumpConfigProvider.swift */; };
 		53F2382465BF74DB1A967C8B /* PumpConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8630D58BDAD6D9C650B9B39 /* PumpConfigProvider.swift */; };
 		581516A42BCED84A00BF67D7 /* DebuggingIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581516A32BCED84A00BF67D7 /* DebuggingIdentifiers.swift */; };
 		581516A42BCED84A00BF67D7 /* DebuggingIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581516A32BCED84A00BF67D7 /* DebuggingIdentifiers.swift */; };
@@ -277,6 +276,8 @@
 		7F7B756BE8543965D9FDF1A2 /* DataTableDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A401509D21F7F35D4E109EDA /* DataTableDataFlow.swift */; };
 		7F7B756BE8543965D9FDF1A2 /* DataTableDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A401509D21F7F35D4E109EDA /* DataTableDataFlow.swift */; };
 		8194B80890CDD6A3C13B0FEE /* SnoozeStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26904AACA8D9C15D229D675 /* SnoozeStateModel.swift */; };
 		8194B80890CDD6A3C13B0FEE /* SnoozeStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26904AACA8D9C15D229D675 /* SnoozeStateModel.swift */; };
 		88AB39B23C9552BD6E0C9461 /* ISFEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBB3BAE7494CB771ABAC7B8B /* ISFEditorRootView.swift */; };
 		88AB39B23C9552BD6E0C9461 /* ISFEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBB3BAE7494CB771ABAC7B8B /* ISFEditorRootView.swift */; };
+		8A91342A2D63D9A1007F8874 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 8A9134292D63D9A1007F8874 /* Localizable.xcstrings */; };
+		8A91342C2D63D9A2007F8874 /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 8A91342B2D63D9A2007F8874 /* InfoPlist.xcstrings */; };
 		8B759CFCF47B392BB365C251 /* BasalProfileEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67F94DD2853CF42BA4E30616 /* BasalProfileEditorDataFlow.swift */; };
 		8B759CFCF47B392BB365C251 /* BasalProfileEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67F94DD2853CF42BA4E30616 /* BasalProfileEditorDataFlow.swift */; };
 		9702FF92A09C53942F20D7EA /* TargetsEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DD795BA46B193644D48138C /* TargetsEditorRootView.swift */; };
 		9702FF92A09C53942F20D7EA /* TargetsEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DD795BA46B193644D48138C /* TargetsEditorRootView.swift */; };
 		9825E5E923F0B8FA80C8C7C7 /* NightscoutConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0A48AE3AC813A49A517846A /* NightscoutConfigStateModel.swift */; };
 		9825E5E923F0B8FA80C8C7C7 /* NightscoutConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0A48AE3AC813A49A517846A /* NightscoutConfigStateModel.swift */; };
@@ -689,33 +690,8 @@
 		190EBCC529FF138000BA767D /* UserInterfaceSettingsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInterfaceSettingsProvider.swift; sourceTree = "<group>"; };
 		190EBCC529FF138000BA767D /* UserInterfaceSettingsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInterfaceSettingsProvider.swift; sourceTree = "<group>"; };
 		190EBCC729FF13AA00BA767D /* UserInterfaceSettingsStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInterfaceSettingsStateModel.swift; sourceTree = "<group>"; };
 		190EBCC729FF13AA00BA767D /* UserInterfaceSettingsStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInterfaceSettingsStateModel.swift; sourceTree = "<group>"; };
 		190EBCCA29FF13CB00BA767D /* UserInterfaceSettingsRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInterfaceSettingsRootView.swift; sourceTree = "<group>"; };
 		190EBCCA29FF13CB00BA767D /* UserInterfaceSettingsRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInterfaceSettingsRootView.swift; sourceTree = "<group>"; };
-		1918333A26ADA46800F45722 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; };
 		191F62672AD6B05A004D7911 /* NightscoutSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutSettings.swift; sourceTree = "<group>"; };
 		191F62672AD6B05A004D7911 /* NightscoutSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutSettings.swift; sourceTree = "<group>"; };
-		1927C8E92744611700347C69 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8EA2744611800347C69 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8EB2744611900347C69 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
-		1927C8EC2744611A00347C69 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8ED2744611B00347C69 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8EE2744611C00347C69 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8EF2744611D00347C69 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8F02744611E00347C69 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8F12744611E00347C69 /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8F22744611F00347C69 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8F32744612000347C69 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8F42744612100347C69 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8F52744612100347C69 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
-		1927C8F62744612200347C69 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
-		1927C8F72744612300347C69 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8F82744612400347C69 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8F92744612400347C69 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8FA2744612500347C69 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8FB2744612600347C69 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1927C8FE274489BA00347C69 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		1935363F28496F7D001E0B16 /* Oref2_variables.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Oref2_variables.swift; sourceTree = "<group>"; };
 		1935363F28496F7D001E0B16 /* Oref2_variables.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Oref2_variables.swift; sourceTree = "<group>"; };
-		193F1E392B44C13B00525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		193F1E3A2B44C13B00525770 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
-		193F1E3B2B44C14800525770 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		193F1E3C2B44C14800525770 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
 		193F6CDC2A512C8F001240FD /* Loops.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Loops.swift; sourceTree = "<group>"; };
 		193F6CDC2A512C8F001240FD /* Loops.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Loops.swift; sourceTree = "<group>"; };
 		195D80B32AF6973A00D25097 /* DynamicSettingsRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicSettingsRootView.swift; sourceTree = "<group>"; };
 		195D80B32AF6973A00D25097 /* DynamicSettingsRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicSettingsRootView.swift; sourceTree = "<group>"; };
 		195D80B62AF697B800D25097 /* DynamicSettingsDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicSettingsDataFlow.swift; sourceTree = "<group>"; };
 		195D80B62AF697B800D25097 /* DynamicSettingsDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicSettingsDataFlow.swift; sourceTree = "<group>"; };
@@ -724,32 +700,11 @@
 		1967DFBD29D052C200759F30 /* Icons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icons.swift; sourceTree = "<group>"; };
 		1967DFBD29D052C200759F30 /* Icons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icons.swift; sourceTree = "<group>"; };
 		1967DFBF29D053AC00759F30 /* IconSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconSelection.swift; sourceTree = "<group>"; };
 		1967DFBF29D053AC00759F30 /* IconSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconSelection.swift; sourceTree = "<group>"; };
 		1967DFC129D053D300759F30 /* IconImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconImage.swift; sourceTree = "<group>"; };
 		1967DFC129D053D300759F30 /* IconImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconImage.swift; sourceTree = "<group>"; };
-		198377D3266BFFF6004DE65E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377D5266C0A05004DE65E /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377D6266C0A0A004DE65E /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377D7266C0A15004DE65E /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
-		198377D8266C0A1C004DE65E /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377D9266C0A21004DE65E /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377DA266C0A2B004DE65E /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377DB266C0A32004DE65E /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377DC266C0A3C004DE65E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377DD266C0A51004DE65E /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377DE266C0A69004DE65E /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377DF266C0A7F004DE65E /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377E0266C0AB5004DE65E /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377E1266C0ABF004DE65E /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377E2266C0AC8004DE65E /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377E3266C0ADC004DE65E /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = "<group>"; };
-		198377E4266C13D2004DE65E /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
 		199561C0275E61A50077B976 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS8.0.sdk/System/Library/Frameworks/HealthKit.framework; sourceTree = DEVELOPER_DIR; };
 		199561C0275E61A50077B976 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS8.0.sdk/System/Library/Frameworks/HealthKit.framework; sourceTree = DEVELOPER_DIR; };
-		199732B4271B72DD00129A3F /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/Localizable.strings"; sourceTree = "<group>"; };
-		199732B5271B9EE900129A3F /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
 		19A9102F2A24BF6300C8951B /* StatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsView.swift; sourceTree = "<group>"; };
 		19A9102F2A24BF6300C8951B /* StatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsView.swift; sourceTree = "<group>"; };
 		19A910352A24D6D700C8951B /* DateFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateFilter.swift; sourceTree = "<group>"; };
 		19A910352A24D6D700C8951B /* DateFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateFilter.swift; sourceTree = "<group>"; };
 		19A910372A24EF3200C8951B /* ChartsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartsView.swift; sourceTree = "<group>"; };
 		19A910372A24EF3200C8951B /* ChartsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartsView.swift; sourceTree = "<group>"; };
 		19B0EF2028F6D66200069496 /* Statistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Statistics.swift; sourceTree = "<group>"; };
 		19B0EF2028F6D66200069496 /* Statistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Statistics.swift; sourceTree = "<group>"; };
-		19C166682756EFBD00ED12E3 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		19C166692756EFBD00ED12E3 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
 		19D466A229AA2B80004D5F33 /* MealSettingsDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealSettingsDataFlow.swift; sourceTree = "<group>"; };
 		19D466A229AA2B80004D5F33 /* MealSettingsDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealSettingsDataFlow.swift; sourceTree = "<group>"; };
 		19D466A429AA2BD4004D5F33 /* MealSettingsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealSettingsProvider.swift; sourceTree = "<group>"; };
 		19D466A429AA2BD4004D5F33 /* MealSettingsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealSettingsProvider.swift; sourceTree = "<group>"; };
 		19D466A629AA2C22004D5F33 /* MealSettingsStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealSettingsStateModel.swift; sourceTree = "<group>"; };
 		19D466A629AA2C22004D5F33 /* MealSettingsStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealSettingsStateModel.swift; sourceTree = "<group>"; };
@@ -942,6 +897,7 @@
 		491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
 		491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
 		491D6FBB2D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		491D6FBB2D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		491D6FBC2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
 		491D6FBC2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
+		49B9B57E2D5768D2009C6B59 /* AdjustmentStored+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AdjustmentStored+Helper.swift"; sourceTree = "<group>"; };
 		4DD795BA46B193644D48138C /* TargetsEditorRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorRootView.swift; sourceTree = "<group>"; };
 		4DD795BA46B193644D48138C /* TargetsEditorRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorRootView.swift; sourceTree = "<group>"; };
 		505E09DC17A0C3D0AF4B66FE /* ISFEditorStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ISFEditorStateModel.swift; sourceTree = "<group>"; };
 		505E09DC17A0C3D0AF4B66FE /* ISFEditorStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ISFEditorStateModel.swift; sourceTree = "<group>"; };
 		581516A32BCED84A00BF67D7 /* DebuggingIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggingIdentifiers.swift; sourceTree = "<group>"; };
 		581516A32BCED84A00BF67D7 /* DebuggingIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggingIdentifiers.swift; sourceTree = "<group>"; };
@@ -1003,6 +959,8 @@
 		7E22146D3DF4853786C78132 /* CarbRatioEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CarbRatioEditorDataFlow.swift; sourceTree = "<group>"; };
 		7E22146D3DF4853786C78132 /* CarbRatioEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CarbRatioEditorDataFlow.swift; sourceTree = "<group>"; };
 		8782B44544F38F2B2D82C38E /* NightscoutConfigRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NightscoutConfigRootView.swift; sourceTree = "<group>"; };
 		8782B44544F38F2B2D82C38E /* NightscoutConfigRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NightscoutConfigRootView.swift; sourceTree = "<group>"; };
 		881E04BA5E0A003DE8E0A9C6 /* DataTableRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DataTableRootView.swift; sourceTree = "<group>"; };
 		881E04BA5E0A003DE8E0A9C6 /* DataTableRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DataTableRootView.swift; sourceTree = "<group>"; };
+		8A9134292D63D9A1007F8874 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
+		8A91342B2D63D9A2007F8874 /* InfoPlist.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = InfoPlist.xcstrings; sourceTree = "<group>"; };
 		920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorRootView.swift; sourceTree = "<group>"; };
 		920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorRootView.swift; sourceTree = "<group>"; };
 		9455FA2D92E77A6C4AFED8A3 /* DataTableStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DataTableStateModel.swift; sourceTree = "<group>"; };
 		9455FA2D92E77A6C4AFED8A3 /* DataTableStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DataTableStateModel.swift; sourceTree = "<group>"; };
 		96653287EDB276A111288305 /* ManualTempBasalDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ManualTempBasalDataFlow.swift; sourceTree = "<group>"; };
 		96653287EDB276A111288305 /* ManualTempBasalDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ManualTempBasalDataFlow.swift; sourceTree = "<group>"; };
@@ -1527,7 +1485,7 @@
 		19D440A926B6FEBD008DA6C8 /* Main */ = {
 		19D440A926B6FEBD008DA6C8 /* Main */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
-				198377D4266BFFF6004DE65E /* Localizable.strings */,
+				8A9134292D63D9A1007F8874 /* Localizable.xcstrings */,
 			);
 			);
 			path = Main;
 			path = Main;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -1849,7 +1807,7 @@
 				388E596E25AD96040019842D /* javascript */,
 				388E596E25AD96040019842D /* javascript */,
 				3811DEC725C9DA7300A708ED /* Trio.entitlements */,
 				3811DEC725C9DA7300A708ED /* Trio.entitlements */,
 				388E596425AD948E0019842D /* Info.plist */,
 				388E596425AD948E0019842D /* Info.plist */,
-				1927C8E82744606D00347C69 /* InfoPlist.strings */,
+				8A91342B2D63D9A2007F8874 /* InfoPlist.xcstrings */,
 				B9CAAEFB2AE70836000F68BC /* branch.txt */,
 				B9CAAEFB2AE70836000F68BC /* branch.txt */,
 				19DA487F29CD2B8400EEA1E7 /* Assets.xcassets */,
 				19DA487F29CD2B8400EEA1E7 /* Assets.xcassets */,
 			);
 			);
@@ -2354,6 +2312,7 @@
 		5825D1622BD405AE00F36E9B /* Helper */ = {
 		5825D1622BD405AE00F36E9B /* Helper */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				49B9B57E2D5768D2009C6B59 /* AdjustmentStored+Helper.swift */,
 				581516A82BCEEDF800BF67D7 /* NSPredicates.swift */,
 				581516A82BCEEDF800BF67D7 /* NSPredicates.swift */,
 				583684052BD178DB00070A60 /* GlucoseStored+helper.swift */,
 				583684052BD178DB00070A60 /* GlucoseStored+helper.swift */,
 				58F107732BD1A4D000B1A680 /* Determination+helper.swift */,
 				58F107732BD1A4D000B1A680 /* Determination+helper.swift */,
@@ -3410,15 +3369,15 @@
 			isa = PBXResourcesBuildPhase;
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			buildActionMask = 2147483647;
 			files = (
 			files = (
-				198377D2266BFFF6004DE65E /* Localizable.strings in Resources */,
+				8A91342C2D63D9A2007F8874 /* InfoPlist.xcstrings in Resources */,
 				CE1F6DE72BAF1A180064EB8D /* BuildDetails.plist in Resources */,
 				CE1F6DE72BAF1A180064EB8D /* BuildDetails.plist in Resources */,
 				38DF178D27733E6800B3528F /* snow.sks in Resources */,
 				38DF178D27733E6800B3528F /* snow.sks in Resources */,
 				388E597225AD9CF10019842D /* json in Resources */,
 				388E597225AD9CF10019842D /* json in Resources */,
 				38DF178E27733E6800B3528F /* Assets.xcassets in Resources */,
 				38DF178E27733E6800B3528F /* Assets.xcassets in Resources */,
 				19DA48E829CD339B00EEA1E7 /* Assets.xcassets in Resources */,
 				19DA48E829CD339B00EEA1E7 /* Assets.xcassets in Resources */,
+				8A91342A2D63D9A1007F8874 /* Localizable.xcstrings in Resources */,
 				388E596F25AD96040019842D /* javascript in Resources */,
 				388E596F25AD96040019842D /* javascript in Resources */,
 				B9CAAEFC2AE70836000F68BC /* branch.txt in Resources */,
 				B9CAAEFC2AE70836000F68BC /* branch.txt in Resources */,
-				1927C8E62744606D00347C69 /* InfoPlist.strings in Resources */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};
@@ -3962,6 +3921,7 @@
 				DD1745222C55524800211FAC /* SMBSettingsProvider.swift in Sources */,
 				DD1745222C55524800211FAC /* SMBSettingsProvider.swift in Sources */,
 				BF1667ADE69E4B5B111CECAE /* ManualTempBasalProvider.swift in Sources */,
 				BF1667ADE69E4B5B111CECAE /* ManualTempBasalProvider.swift in Sources */,
 				583684062BD178DB00070A60 /* GlucoseStored+helper.swift in Sources */,
 				583684062BD178DB00070A60 /* GlucoseStored+helper.swift in Sources */,
+				49B9B57F2D5768D2009C6B59 /* AdjustmentStored+Helper.swift in Sources */,
 				F90692D6274B9A450037068D /* HealthKitStateModel.swift in Sources */,
 				F90692D6274B9A450037068D /* HealthKitStateModel.swift in Sources */,
 				BD1661312B82ADAB00256551 /* CustomProgressView.swift in Sources */,
 				BD1661312B82ADAB00256551 /* CustomProgressView.swift in Sources */,
 				C967DACD3B1E638F8B43BE06 /* ManualTempBasalStateModel.swift in Sources */,
 				C967DACD3B1E638F8B43BE06 /* ManualTempBasalStateModel.swift in Sources */,
@@ -4146,69 +4106,6 @@
 		};
 		};
 /* End PBXTargetDependency section */
 /* End PBXTargetDependency section */
 
 
-/* Begin PBXVariantGroup section */
-		1927C8E82744606D00347C69 /* InfoPlist.strings */ = {
-			isa = PBXVariantGroup;
-			children = (
-				1927C8E92744611700347C69 /* ar */,
-				1927C8EA2744611800347C69 /* ca */,
-				1927C8EB2744611900347C69 /* zh-Hans */,
-				1927C8EC2744611A00347C69 /* da */,
-				1927C8ED2744611B00347C69 /* fi */,
-				1927C8EE2744611C00347C69 /* nl */,
-				1927C8EF2744611D00347C69 /* fr */,
-				1927C8F02744611E00347C69 /* de */,
-				1927C8F12744611E00347C69 /* he */,
-				1927C8F22744611F00347C69 /* it */,
-				1927C8F32744612000347C69 /* nb */,
-				1927C8F42744612100347C69 /* pl */,
-				1927C8F52744612100347C69 /* pt-BR */,
-				1927C8F62744612200347C69 /* pt-PT */,
-				1927C8F72744612300347C69 /* ru */,
-				1927C8F82744612400347C69 /* es */,
-				1927C8F92744612400347C69 /* sv */,
-				1927C8FA2744612500347C69 /* tr */,
-				1927C8FB2744612600347C69 /* uk */,
-				1927C8FE274489BA00347C69 /* Base */,
-				19C166682756EFBD00ED12E3 /* sk */,
-				193F1E392B44C13B00525770 /* hu */,
-				193F1E3B2B44C14800525770 /* vi */,
-			);
-			name = InfoPlist.strings;
-			sourceTree = "<group>";
-		};
-		198377D4266BFFF6004DE65E /* Localizable.strings */ = {
-			isa = PBXVariantGroup;
-			children = (
-				198377D3266BFFF6004DE65E /* en */,
-				198377D5266C0A05004DE65E /* ar */,
-				198377D6266C0A0A004DE65E /* ca */,
-				198377D7266C0A15004DE65E /* zh-Hans */,
-				198377D8266C0A1C004DE65E /* da */,
-				198377D9266C0A21004DE65E /* nl */,
-				198377DA266C0A2B004DE65E /* fr */,
-				198377DB266C0A32004DE65E /* de */,
-				198377DC266C0A3C004DE65E /* he */,
-				198377DD266C0A51004DE65E /* it */,
-				198377DE266C0A69004DE65E /* nb */,
-				198377DF266C0A7F004DE65E /* pl */,
-				198377E0266C0AB5004DE65E /* ru */,
-				198377E1266C0ABF004DE65E /* es */,
-				198377E2266C0AC8004DE65E /* sv */,
-				198377E3266C0ADC004DE65E /* tr */,
-				198377E4266C13D2004DE65E /* uk */,
-				1918333A26ADA46800F45722 /* fi */,
-				199732B4271B72DD00129A3F /* pt-PT */,
-				199732B5271B9EE900129A3F /* pt-BR */,
-				19C166692756EFBD00ED12E3 /* sk */,
-				193F1E3A2B44C13B00525770 /* hu */,
-				193F1E3C2B44C14800525770 /* vi */,
-			);
-			name = Localizable.strings;
-			sourceTree = "<group>";
-		};
-/* End PBXVariantGroup section */
-
 /* Begin XCBuildConfiguration section */
 /* Begin XCBuildConfiguration section */
 		388E596525AD948E0019842D /* Debug */ = {
 		388E596525AD948E0019842D /* Debug */ = {
 			isa = XCBuildConfiguration;
 			isa = XCBuildConfiguration;
@@ -4266,12 +4163,14 @@
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				IPHONEOS_DEPLOYMENT_TARGET = 17.0;
 				IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
 				MARKETING_VERSION = "$(APP_VERSION)";
 				MARKETING_VERSION = "$(APP_VERSION)";
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
 				MTL_FAST_MATH = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = iphoneos;
 				SDKROOT = iphoneos;
 				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
 				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_EMIT_LOC_STRINGS = YES;
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
 			};
 			};
 			name = Debug;
 			name = Debug;
@@ -4326,11 +4225,13 @@
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				IPHONEOS_DEPLOYMENT_TARGET = 17.0;
 				IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
 				MARKETING_VERSION = "$(APP_VERSION)";
 				MARKETING_VERSION = "$(APP_VERSION)";
 				MTL_ENABLE_DEBUG_INFO = NO;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				MTL_FAST_MATH = YES;
 				MTL_FAST_MATH = YES;
 				SDKROOT = iphoneos;
 				SDKROOT = iphoneos;
 				SWIFT_COMPILATION_MODE = wholemodule;
 				SWIFT_COMPILATION_MODE = wholemodule;
+				SWIFT_EMIT_LOC_STRINGS = YES;
 				SWIFT_OPTIMIZATION_LEVEL = "-O";
 				SWIFT_OPTIMIZATION_LEVEL = "-O";
 				VALIDATE_PRODUCT = YES;
 				VALIDATE_PRODUCT = YES;
 			};
 			};

+ 0 - 23
Trio/Resources/Base.lproj/InfoPlist.strings

@@ -1,23 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC is used to scan Libre sensors.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "For authorized acces to bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Calendar is used to create a new glucose events.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
-
-/* Privacy - Contacts Usage Description */
-"NSContactsUsageDescription" = "Allows Trio to access your contacts for live updates to your Apple Watch contact complication using the 'Contact Trick' feature.";

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1059 - 0
Trio/Resources/InfoPlist.xcstrings


+ 0 - 20
Trio/Resources/ar.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC is used to scan Libre sensors.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "For authorized acces to bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Calendar is used to create a new glucose events.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose, carbs and insulin";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App is used to store blood glucose, carbs and insulin";

+ 0 - 20
Trio/Resources/ca.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC is used to scan Libre sensors.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "For authorized acces to bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Calendar is used to create a new glucose events.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";

+ 0 - 20
Trio/Resources/da.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC bruges til at scanne Libre sensorer.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth bliver brugt til at kommunikere med din insulin pumpe og dine glukose monitor enheder";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth bliver brugt til at kommunikere med din insulin pumpe og dine glukose monitor enheder";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "For autoriseret adgang til bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Kalender bruges til at oprette en ny glucose begivenheder.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App bruges til at opbevare blodglukose, insulin og kulhydrater";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App bruges til at opbevare blodglukose, insulin og kulhydrater";

+ 0 - 20
Trio/Resources/de.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC wird zum Scannen von Libre Sensoren benutzt.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth wird verwendet, um mit Insulinpumpen und CGMs zu kommunizieren.";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth wird verwendet, um mit Insulinpumpen und CGMs zu kommunizieren.";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "Autorisierung für Bolusabgabe";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "BZ-Werte werden im Kalender als temporärer Termin erstellt.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Die Apple Health App wird zum Speichern von Blutzuckerwerten, Insulin und Kohlenhydraten verwendet";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Die Apple Health App wird zum Speichern von Blutzuckerwerten, Insulin und Kohlenhydraten verwendet";

+ 0 - 20
Trio/Resources/es.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC is used to scan Libre sensors.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "For authorized acces to bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Calendar is used to create a new glucose events.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";

+ 0 - 20
Trio/Resources/fi.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC is used to scan Libre sensors.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "For authorized acces to bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Calendar is used to create a new glucose events.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";

+ 0 - 20
Trio/Resources/fr.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC est utilisé pour scanner les capteurs Libre.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth est utilisé pour communiquer avec la pompe à insuline et les dispositifs de surveillance continue du glucose";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth est utilisé pour communiquer avec la pompe à insuline et les dispositifs de surveillance continue du glucose";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "Pour les accès autorisés au bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Le calendrier est utilisé pour créer un nouvel événement de glycémie.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "L'application Santé est utilisée pour stocker la glycémie, l'insuline et les glucides";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "L'application Santé est utilisée pour stocker la glycémie, l'insuline et les glucides";

+ 0 - 20
Trio/Resources/he.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC is used to scan Libre sensors.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "For authorized acces to bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Calendar is used to create a new glucose events.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";

+ 0 - 20
Trio/Resources/hu.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC is used to scan Libre sensors.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "For authorized acces to bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Calendar is used to create a new glucose events.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";

+ 0 - 20
Trio/Resources/it.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC è usato per scansionare i sensori di Libre.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Il bluetooth viene utilizzato per comunicare con il microinfusore e i dispositivi CGM";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Il Bluetooth viene utilizzato per comunicare con il microinfusore e i dispositivi CGM";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "Per accesso autorizzato al bolo";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Il calendario è usato per creare nuovi eventi di glicemia.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "L'app Salute è usata per memorizzare glicemie, insulina e carboidrati";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "L'app Salute è usata per memorizzare glicemie, insulina e carboidrati";

+ 0 - 20
Trio/Resources/nb.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC brukes til å skanne Libre-sensorer.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth brukes til å kommunisere med insulinpumpe og blodsukkersensor";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth brukes til å kommunisere med insulinpumpe og blodsukkersensor-enheter";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "For autorisert tilgang til bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Kalender brukes til å opprette nye blodsukker-oppføringer.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Helse-appen brukes til å lagre blodsukker, insulin og karbohydrater";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Helse-appen brukes til å lagre blodsukker, insulin og karbohydrater";

+ 0 - 20
Trio/Resources/nl.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC wordt gebruikt voor het scannen van Libre sensoren.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth wordt gebruikt om te communiceren met de insuline pomp en de continue glucose meter";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth wordt gebruikt om te communiceren met de insuline pomp en de continue glucose meter";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "Voor geautoriseerde toegang tot bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Agenda wordt gebruikt om nieuwe glucose gebeurtenissen aan te maken.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Apple Gezondheid wordt gebruikt om bloedglucose, insuline en koolhydraten op te slaan";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Apple Gezondheid wordt gebruikt om bloedglucose, insuline en koolhydraten op te slaan";

+ 0 - 20
Trio/Resources/pl.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC is used to scan Libre sensors.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "For authorized acces to bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Calendar is used to create a new glucose events.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";

+ 0 - 20
Trio/Resources/pt-BR.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC is used to scan Libre sensors.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "For authorized acces to bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Calendar is used to create a new glucose events.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";

+ 0 - 20
Trio/Resources/pt-PT.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC is used to scan Libre sensors.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "For authorized acces to bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Calendar is used to create a new glucose events.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";

+ 0 - 20
Trio/Resources/ru.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC используется для сканирования сенсоров Libre.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth используется для связи с инсулиновой помпой и устройствами непрерывного мониторинга глюкозы";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth используется для связи с инсулиновой помпой и устройствами непрерывного мониторинга глюкозы";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "Для авторизованного болюса";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Календарь используется для создания новых событий о глюкозе.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Приложение здоровья используется для хранения глюкозы, инсулина и углеводов в крови";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Приложение здоровья используется для хранения глюкозы, инсулина и углеводов в крови";

+ 0 - 20
Trio/Resources/sk.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC sa používa na skenovanie snímačov Libre.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth sa používa pre komunikáciu s inzulínovou pumpou a zariadeniami na kontinuálne monitorovanie krvného cukru";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth sa používa pre komunikáciu s inzulínovou pumpou a zariadeniami na kontinuálne monitorovanie krvného cukru";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "Pre autorizovaný prístup k bolusu";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Kalendár slúži na vytvorenie novej udalosti s glukózou.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Aplikácia Zdravie sa používa na meranie glukózy v krvi, inzulínu a ukladanie sacharidov";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Aplikácia Zdravie sa používa na meranie glukózy v krvi, inzulínu a ukladanie sacharidov";

+ 0 - 20
Trio/Resources/sv.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC används för att skanna Libre-sensorn vid uppstart.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth används för att kommunicera med pump och kontinuerlig glukosmätare";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth används för att kommunicera med insulinpumpen och kontinuerliga glukosmätare";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "För auktoriserad åtkomst till bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Kalendern används för att skapa kalenderhändelser för glukosvärden.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Appen Hälsa används för att lagra blodsockervärden, insulin samt kolhydrater";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Appen Hälsa används för att lagra blodsockervärden, insulin och kolhydrater.";

+ 0 - 20
Trio/Resources/tr.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC Libre sensörlerini taramak için kullanılır.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth, insülin pompası ve sürekli glikoz izleme cihazları ile iletişim kurmak için kullanılır";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth, insülin pompası ve sürekli glikoz izleme cihazları ile iletişim kurmak için kullanılır";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "Bolus'a yetkili erişim için";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Takvim, yeni bir glikoz olayı oluşturmak için kullanılır.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";

+ 0 - 20
Trio/Resources/uk.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC використовується для сканування сенсорів Libre.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth використовується для обміну з інсуліновими помпами та безперервним моніторингом глюкози";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth використовується для обміну з інсуліновими помпами та безперервним моніторингом глюкози";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "Для авторизованого болюсу";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Для створення нових подій глюкози використовується календар.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Додаток Health використовується для зберігання глюкози в крові, інсуліну та вуглеводів";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Додаток Health використовується для зберігання глюкози в крові, інсуліну та вуглеводів";

+ 0 - 20
Trio/Resources/vi.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC được sử dụng để quét các cảm biến Libre.";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "Bluetooth được sử dụng để liên lạc với máy bơm insulin và các thiết bị theo dõi đường huyết liên tục/CGM.";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "Bluetooth được sử dụng để liên lạc với máy bơm insulin và các thiết bị theo dõi đường huyết liên tục/CGM.";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "Được cấp quyền truy cập vào bolus";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "Lịch \nCalendar được sử dụng để tạo ra một sự kiện glucose mới.";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Ứng dụng sức khỏe \nHealth được sử dụng để lưu trữ đường huyết, insulin và carbohydrate";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Ứng dụng sức khỏe \nHealth được sử dụng để lưu trữ đường huyết, insulin và carbohydrate";

+ 0 - 20
Trio/Resources/zh-Hans.lproj/InfoPlist.strings

@@ -1,20 +0,0 @@
-/* Privacy - NFC Scan Usage Description */
-"NFCReaderUsageDescription" = "NFC 用于扫描 Libre 传感器。";
-
-/* Privacy - Bluetooth Always Usage Description */
-"NSBluetoothAlwaysUsageDescription" = "蓝牙用于与胰岛素泵和连续血糖监测设备进行通信";
-
-/* Privacy - Bluetooth Peripheral Usage Description */
-"NSBluetoothPeripheralUsageDescription" = "蓝牙用于与胰岛素泵和连续血糖监测设备进行通信";
-
-/* Privacy - Face ID Usage Description */
-"NSFaceIDUsageDescription" = "用于输注胰岛素授权";
-
-/* Privacy - Calendars Usage Description */
-"NSCalendarsUsageDescription" = "日历用于创建一个新的葡萄糖事件。";
-
-/* Privacy - Health Update Usage Description */
-"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
-
-/* Privacy - Health Share Usage Description */
-"NSHealthShareUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";

+ 9 - 3
Trio/Sources/APS/APSManager.swift

@@ -22,7 +22,7 @@ protocol APSManager {
     func enactTempBasal(rate: Double, duration: TimeInterval) async
     func enactTempBasal(rate: Double, duration: TimeInterval) async
     func determineBasal() async -> Bool
     func determineBasal() async -> Bool
     func determineBasalSync() async
     func determineBasalSync() async
-    func simulateDetermineBasal(carbs: Decimal, iob: Decimal) async -> Determination?
+    func simulateDetermineBasal(simulatedCarbsAmount: Decimal, simulatedBolusAmount: Decimal) async -> Determination?
     func roundBolus(amount: Decimal) -> Decimal
     func roundBolus(amount: Decimal) -> Decimal
     var lastError: CurrentValueSubject<Error?, Never> { get }
     var lastError: CurrentValueSubject<Error?, Never> { get }
     func cancelBolus(_ callback: ((Bool, String) -> Void)?) async
     func cancelBolus(_ callback: ((Bool, String) -> Void)?) async
@@ -413,10 +413,16 @@ final class BaseAPSManager: APSManager, Injectable {
         _ = await determineBasal()
         _ = await determineBasal()
     }
     }
 
 
-    func simulateDetermineBasal(carbs: Decimal, iob: Decimal) async -> Determination? {
+    func simulateDetermineBasal(simulatedCarbsAmount: Decimal, simulatedBolusAmount: Decimal) async -> Determination? {
         do {
         do {
             let temp = await fetchCurrentTempBasal(date: Date.now)
             let temp = await fetchCurrentTempBasal(date: Date.now)
-            return try await openAPS.determineBasal(currentTemp: temp, clock: Date(), carbs: carbs, iob: iob, simulation: true)
+            return try await openAPS.determineBasal(
+                currentTemp: temp,
+                clock: Date(),
+                simulatedCarbsAmount: simulatedCarbsAmount,
+                simulatedBolusAmount: simulatedBolusAmount,
+                simulation: true
+            )
         } catch {
         } catch {
             debugPrint(
             debugPrint(
                 "\(DebuggingIdentifiers.failed) \(#file) \(#function) Error occurred in invokeDummyDetermineBasalSync: \(error)"
                 "\(DebuggingIdentifiers.failed) \(#file) \(#function) Error occurred in invokeDummyDetermineBasalSync: \(error)"

+ 1 - 1
Trio/Sources/APS/CGM/AppGroupSource.swift

@@ -115,7 +115,7 @@ struct AppGroupSource: GlucoseSource {
     }
     }
 
 
     func sourceInfo() -> [String: Any]? {
     func sourceInfo() -> [String: Any]? {
-        [GlucoseSourceKey.description.rawValue: "Group ID: \(Bundle.main.appGroupSuiteName ?? "Not set"))"]
+        [GlucoseSourceKey.description.rawValue: "Group ID: \(Bundle.main.appGroupSuiteName ?? String(localized: "Not set"))"]
     }
     }
 }
 }
 
 

+ 8 - 7
Trio/Sources/APS/CGM/CGMType.swift

@@ -18,7 +18,7 @@ enum CGMType: String, JSON, CaseIterable, Identifiable {
         case .xdrip:
         case .xdrip:
             return "xDrip4iOS"
             return "xDrip4iOS"
         case .simulator:
         case .simulator:
-            return NSLocalizedString("Glucose Simulator", comment: "Glucose Simulator CGM type")
+            return String(localized: "Glucose Simulator", comment: "Glucose Simulator CGM type")
         case .enlite:
         case .enlite:
             return "Medtronic Enlite"
             return "Medtronic Enlite"
         case .plugin:
         case .plugin:
@@ -52,20 +52,21 @@ enum CGMType: String, JSON, CaseIterable, Identifiable {
     var subtitle: String {
     var subtitle: String {
         switch self {
         switch self {
         case .none:
         case .none:
-            return NSLocalizedString("None", comment: "No CGM selected")
+            return String(localized: "None", comment: "No CGM selected")
         case .nightscout:
         case .nightscout:
-            return NSLocalizedString("Uses your Nightscout as CGM", comment: "Online or internal server")
+            return String(localized: "Uses your Nightscout as CGM", comment: "Online or internal server")
         case .xdrip:
         case .xdrip:
-            return NSLocalizedString(
+            return String(
+                localized:
                 "Using shared app group with external CGM app xDrip4iOS",
                 "Using shared app group with external CGM app xDrip4iOS",
                 comment: "Shared app group xDrip4iOS"
                 comment: "Shared app group xDrip4iOS"
             )
             )
         case .simulator:
         case .simulator:
-            return NSLocalizedString("Glucose Simulator for Demo Only", comment: "Simple simulator")
+            return String(localized: "Glucose Simulator for Demo Only", comment: "Simple simulator")
         case .enlite:
         case .enlite:
-            return NSLocalizedString("Minilink transmitter", comment: "Minilink transmitter")
+            return String(localized: "Minilink transmitter", comment: "Minilink transmitter")
         case .plugin:
         case .plugin:
-            return NSLocalizedString("Plugin CGM", comment: "Plugin CGM")
+            return String(localized: "Plugin CGM", comment: "Plugin CGM")
         }
         }
     }
     }
 }
 }

+ 4 - 3
Trio/Sources/APS/CGM/PluginSource.swift

@@ -7,7 +7,7 @@ import LoopKit
 import LoopKitUI
 import LoopKitUI
 
 
 final class PluginSource: GlucoseSource {
 final class PluginSource: GlucoseSource {
-    private let processQueue = DispatchQueue(label: "DexcomSource.processQueue")
+    private let processQueue = DispatchQueue(label: "CGMPluginSource.processQueue")
     private let glucoseStorage: GlucoseStorage!
     private let glucoseStorage: GlucoseStorage!
     var glucoseManager: FetchGlucoseManager?
     var glucoseManager: FetchGlucoseManager?
 
 
@@ -159,8 +159,9 @@ extension PluginSource: CGMManagerDelegate {
         UUID().uuidString
         UUID().uuidString
     }
     }
 
 
-    func cgmManager(_: CGMManager, didUpdate status: CGMManagerStatus) {
-        debug(.deviceManager, "DEBUG DID UPDATE STATE")
+    func cgmManager(_ cgmManager: CGMManager, didUpdate status: CGMManagerStatus) {
+        debug(.deviceManager, "CGM Manager did update state to \(status)")
+        
         processQueue.async {
         processQueue.async {
             if self.cgmHasValidSensorSession != status.hasValidSensorSession {
             if self.cgmHasValidSensorSession != status.hasValidSensorSession {
                 self.cgmHasValidSensorSession = status.hasValidSensorSession
                 self.cgmHasValidSensorSession = status.hasValidSensorSession

+ 27 - 5
Trio/Sources/APS/FetchGlucoseManager.swift

@@ -126,11 +126,15 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
         // if plugin, if not the same pluginID, need to reset the cgmManager
         // if plugin, if not the same pluginID, need to reset the cgmManager
         // if plugin and newManager provides, update cgmManager
         // if plugin and newManager provides, update cgmManager
         debug(.apsManager, "plugin : \(String(describing: cgmManager?.pluginIdentifier))")
         debug(.apsManager, "plugin : \(String(describing: cgmManager?.pluginIdentifier))")
-        if let manager = newManager
-        {
-            cgmManager = manager
-            glucoseSource = nil
-            removeCalibrations()
+
+        if let manager = newManager {
+            // If the pointer to manager is the *same* as our current `cgmManager`, skip re-init
+            if manager !== cgmManager {
+                // or do a more thorough check to see if it is the same class & state
+                removeCalibrations()
+                cgmManager = manager
+                glucoseSource = nil
+            }
         } else if self.cgmGlucoseSourceType == .plugin, cgmManager == nil, let rawCGMManager = rawCGMManager {
         } else if self.cgmGlucoseSourceType == .plugin, cgmManager == nil, let rawCGMManager = rawCGMManager {
             cgmManager = cgmManagerFromRawValue(rawCGMManager)
             cgmManager = cgmManagerFromRawValue(rawCGMManager)
             updateManagerUnits(cgmManager)
             updateManagerUnits(cgmManager)
@@ -339,6 +343,24 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
     }
     }
 }
 }
 
 
+extension FetchGlucoseManager {
+    /// Dispatches given `functionToInvoke` to the CGM manager's queue (if any).
+    func performOnCGMManagerQueue(_ functionToInvoke: @escaping () -> Void) {
+        // If a CGM manager exists and it defines a delegate queue, use it
+        if let cgmManager = self.cgmManager,
+           let managerQueue = cgmManager.delegateQueue
+        {
+            managerQueue.async {
+                functionToInvoke()
+            }
+        } else {
+            // If there's no cgmManager or no queue, just run the block immediately
+            // This possibly executes `functionToInvoke` on main thread
+            functionToInvoke()
+        }
+    }
+}
+
 extension CGMManager {
 extension CGMManager {
     typealias RawValue = [String: Any]
     typealias RawValue = [String: Any]
 
 

+ 25 - 10
Trio/Sources/APS/OpenAPS/OpenAPS.swift

@@ -189,7 +189,10 @@ final class OpenAPS {
         }
         }
     }
     }
 
 
-    private func parsePumpHistory(_ pumpHistoryObjectIDs: [NSManagedObjectID], iob: Decimal? = nil) async -> String {
+    private func parsePumpHistory(
+        _ pumpHistoryObjectIDs: [NSManagedObjectID],
+        simulatedBolusAmount: Decimal? = nil
+    ) async -> String {
         // Return an empty JSON object if the list of object IDs is empty
         // Return an empty JSON object if the list of object IDs is empty
         guard !pumpHistoryObjectIDs.isEmpty else { return "{}" }
         guard !pumpHistoryObjectIDs.isEmpty else { return "{}" }
 
 
@@ -199,9 +202,9 @@ final class OpenAPS {
             var dtos = self.loadAndMapPumpEvents(pumpHistoryObjectIDs)
             var dtos = self.loadAndMapPumpEvents(pumpHistoryObjectIDs)
 
 
             // Optionally add the IOB as a DTO
             // Optionally add the IOB as a DTO
-            if let iob = iob {
-                let iobDTO = self.createIOBDTO(iob: iob)
-                dtos.insert(iobDTO, at: 0)
+            if let simulatedBolusAmount = simulatedBolusAmount {
+                let simulatedBolusDTO = self.createSimulatedBolusDTO(simulatedBolusAmount: simulatedBolusAmount)
+                dtos.insert(simulatedBolusDTO, at: 0)
             }
             }
 
 
             // Convert the DTOs to JSON
             // Convert the DTOs to JSON
@@ -226,12 +229,24 @@ final class OpenAPS {
             if let tempBasalDTO = event.toTempBasalDTOEnum() {
             if let tempBasalDTO = event.toTempBasalDTOEnum() {
                 eventDTOs.append(tempBasalDTO)
                 eventDTOs.append(tempBasalDTO)
             }
             }
+            if let pumpSuspendDTO = event.toPumpSuspendDTO() {
+                eventDTOs.append(pumpSuspendDTO)
+            }
+            if let pumpResumeDTO = event.toPumpResumeDTO() {
+                eventDTOs.append(pumpResumeDTO)
+            }
+            if let rewindDTO = event.toRewindDTO() {
+                eventDTOs.append(rewindDTO)
+            }
+            if let primeDTO = event.toPrimeDTO() {
+                eventDTOs.append(primeDTO)
+            }
             return eventDTOs
             return eventDTOs
         }
         }
         return dtos
         return dtos
     }
     }
 
 
-    private func createIOBDTO(iob: Decimal) -> PumpEventDTO {
+    private func createSimulatedBolusDTO(simulatedBolusAmount: Decimal) -> PumpEventDTO {
         let oneSecondAgo = Calendar.current
         let oneSecondAgo = Calendar.current
             .date(
             .date(
                 byAdding: .second,
                 byAdding: .second,
@@ -243,7 +258,7 @@ final class OpenAPS {
         let bolusDTO = BolusDTO(
         let bolusDTO = BolusDTO(
             id: UUID().uuidString,
             id: UUID().uuidString,
             timestamp: dateFormatted,
             timestamp: dateFormatted,
-            amount: Double(iob),
+            amount: Double(simulatedBolusAmount),
             isExternal: false,
             isExternal: false,
             isSMB: true,
             isSMB: true,
             duration: 0,
             duration: 0,
@@ -255,8 +270,8 @@ final class OpenAPS {
     func determineBasal(
     func determineBasal(
         currentTemp: TempBasal,
         currentTemp: TempBasal,
         clock: Date = Date(),
         clock: Date = Date(),
-        carbs: Decimal? = nil,
-        iob: Decimal? = nil,
+        simulatedCarbsAmount: Decimal? = nil,
+        simulatedBolusAmount: Decimal? = nil,
         simulation: Bool = false
         simulation: Bool = false
     ) async throws -> Determination? {
     ) async throws -> Determination? {
         debug(.openAPS, "Start determineBasal")
         debug(.openAPS, "Start determineBasal")
@@ -266,7 +281,7 @@ final class OpenAPS {
 
 
         // Perform asynchronous calls in parallel
         // Perform asynchronous calls in parallel
         async let pumpHistoryObjectIDs = fetchPumpHistoryObjectIDs() ?? []
         async let pumpHistoryObjectIDs = fetchPumpHistoryObjectIDs() ?? []
-        async let carbs = fetchAndProcessCarbs(additionalCarbs: carbs ?? 0)
+        async let carbs = fetchAndProcessCarbs(additionalCarbs: simulatedCarbsAmount ?? 0)
         async let glucose = fetchAndProcessGlucose()
         async let glucose = fetchAndProcessGlucose()
         async let oref2 = oref2()
         async let oref2 = oref2()
         async let profileAsync = loadFileFromStorageAsync(name: Settings.profile)
         async let profileAsync = loadFileFromStorageAsync(name: Settings.profile)
@@ -287,7 +302,7 @@ final class OpenAPS {
             reservoir,
             reservoir,
             preferences
             preferences
         ) = await (
         ) = await (
-            parsePumpHistory(await pumpHistoryObjectIDs, iob: iob),
+            parsePumpHistory(await pumpHistoryObjectIDs, simulatedBolusAmount: simulatedBolusAmount),
             carbs,
             carbs,
             glucose,
             glucose,
             oref2,
             oref2,

+ 1 - 1
Trio/Sources/APS/Storage/ContactImageStorage.swift

@@ -39,7 +39,7 @@ final class BaseContactImageStorage: ContactImageStorage, Injectable {
 
 
             return fetchedContactImageEntries.compactMap { entry in
             return fetchedContactImageEntries.compactMap { entry in
                 ContactImageEntry(
                 ContactImageEntry(
-                    name: entry.name ?? "No name provided",
+                    name: entry.name ?? String(localized: "No name provided"),
                     layout: ContactImageLayout(rawValue: entry.layout ?? "Default") ?? .default,
                     layout: ContactImageLayout(rawValue: entry.layout ?? "Default") ?? .default,
                     ring: ContactImageLargeRing(rawValue: entry.ring ?? "Hidden") ?? .none,
                     ring: ContactImageLargeRing(rawValue: entry.ring ?? "Hidden") ?? .none,
                     primary: ContactImageValue(rawValue: entry.primary ?? "Glucose Reading") ?? .glucose,
                     primary: ContactImageValue(rawValue: entry.primary ?? "Glucose Reading") ?? .glucose,

+ 2 - 2
Trio/Sources/APS/Storage/GlucoseStorage.swift

@@ -538,9 +538,9 @@ enum GlucoseAlarm {
     var displayName: String {
     var displayName: String {
         switch self {
         switch self {
         case .high:
         case .high:
-            return NSLocalizedString("LOWALERT!", comment: "LOWALERT!")
+            return String(localized: "LOWALERT!", comment: "LOWALERT!")
         case .low:
         case .low:
-            return NSLocalizedString("HIGHALERT!", comment: "HIGHALERT!")
+            return String(localized: "HIGHALERT!", comment: "HIGHALERT!")
         }
         }
     }
     }
 }
 }

+ 3 - 3
Trio/Sources/APS/Storage/OverrideStorage.swift

@@ -210,7 +210,7 @@ final class BaseOverrideStorage: @preconcurrency OverrideStorage, Injectable {
         let results = await CoreDataStack.shared.fetchEntitiesAsync(
         let results = await CoreDataStack.shared.fetchEntitiesAsync(
             ofType: OverrideStored.self,
             ofType: OverrideStored.self,
             onContext: backgroundContext,
             onContext: backgroundContext,
-            predicate: NSPredicate.lastActiveOverrideNotYetUploadedToNightscout,
+            predicate: NSPredicate.lastActiveAdjustmentNotYetUploadedToNightscout,
             key: "date",
             key: "date",
             ascending: false
             ascending: false
         )
         )
@@ -225,7 +225,7 @@ final class BaseOverrideStorage: @preconcurrency OverrideStorage, Injectable {
                     eventType: OverrideStored.EventType.nsExercise,
                     eventType: OverrideStored.EventType.nsExercise,
                     createdAt: override.date ?? Date(),
                     createdAt: override.date ?? Date(),
                     enteredBy: NightscoutExercise.local,
                     enteredBy: NightscoutExercise.local,
-                    notes: override.name ?? "Custom Override",
+                    notes: override.name ?? String(localized: "Custom Override"),
                     id: UUID(uuidString: override.id ?? UUID().uuidString)
                     id: UUID(uuidString: override.id ?? UUID().uuidString)
                 )
                 )
             }
             }
@@ -256,7 +256,7 @@ final class BaseOverrideStorage: @preconcurrency OverrideStorage, Injectable {
                     eventType: OverrideStored.EventType.nsExercise,
                     eventType: OverrideStored.EventType.nsExercise,
                     createdAt: (overrideRun.startDate ?? overrideRun.override?.date) ?? Date(),
                     createdAt: (overrideRun.startDate ?? overrideRun.override?.date) ?? Date(),
                     enteredBy: NightscoutExercise.local,
                     enteredBy: NightscoutExercise.local,
-                    notes: overrideRun.name ?? "Custom Override",
+                    notes: overrideRun.name ?? String(localized: "Custom Override"),
                     id: overrideRun.id
                     id: overrideRun.id
                 )
                 )
             }
             }

+ 3 - 3
Trio/Sources/APS/Storage/TempTargetsStorage.swift

@@ -14,7 +14,7 @@ protocol TempTargetsStorage {
     func fetchScheduledTempTargets() async -> [NSManagedObjectID]
     func fetchScheduledTempTargets() async -> [NSManagedObjectID]
     func fetchScheduledTempTarget(for targetDate: Date) async -> [NSManagedObjectID]
     func fetchScheduledTempTarget(for targetDate: Date) async -> [NSManagedObjectID]
     func copyRunningTempTarget(_ tempTarget: TempTargetStored) async -> NSManagedObjectID
     func copyRunningTempTarget(_ tempTarget: TempTargetStored) async -> NSManagedObjectID
-    func deleteOverridePreset(_ objectID: NSManagedObjectID) async
+    func deleteTempTargetPreset(_ objectID: NSManagedObjectID) async
     func loadLatestTempTargetConfigurations(fetchLimit: Int) async -> [NSManagedObjectID]
     func loadLatestTempTargetConfigurations(fetchLimit: Int) async -> [NSManagedObjectID]
     func syncDate() -> Date
     func syncDate() -> Date
     func recent() -> [TempTarget]
     func recent() -> [TempTarget]
@@ -216,7 +216,7 @@ final class BaseTempTargetsStorage: TempTargetsStorage, Injectable {
         return newTempTarget.objectID
         return newTempTarget.objectID
     }
     }
 
 
-    @MainActor func deleteOverridePreset(_ objectID: NSManagedObjectID) async {
+    @MainActor func deleteTempTargetPreset(_ objectID: NSManagedObjectID) async {
         await CoreDataStack.shared.deleteObject(identifiedBy: objectID)
         await CoreDataStack.shared.deleteObject(identifiedBy: objectID)
     }
     }
 
 
@@ -246,7 +246,7 @@ final class BaseTempTargetsStorage: TempTargetsStorage, Injectable {
         let results = await CoreDataStack.shared.fetchEntitiesAsync(
         let results = await CoreDataStack.shared.fetchEntitiesAsync(
             ofType: TempTargetStored.self,
             ofType: TempTargetStored.self,
             onContext: backgroundContext,
             onContext: backgroundContext,
-            predicate: NSPredicate.lastActiveOverrideNotYetUploadedToNightscout, // TODO: create adjustment predicate (OR+TT)
+            predicate: NSPredicate.lastActiveAdjustmentNotYetUploadedToNightscout,
             key: "date",
             key: "date",
             ascending: false
             ascending: false
         )
         )

+ 22 - 7
Trio/Sources/Application/TrioApp.swift

@@ -13,7 +13,7 @@ import Swinject
     // Read the color scheme preference from UserDefaults; defaults to system default setting
     // Read the color scheme preference from UserDefaults; defaults to system default setting
     @AppStorage("colorSchemePreference") private var colorSchemePreference: ColorSchemeOption = .systemDefault
     @AppStorage("colorSchemePreference") private var colorSchemePreference: ColorSchemeOption = .systemDefault
 
 
-    let coreDataStack = CoreDataStack.shared
+    let coreDataStack: CoreDataStack
 
 
     @State private var appState = AppState()
     @State private var appState = AppState()
 
 
@@ -68,14 +68,29 @@ import Swinject
             "Trio Started: v\(Bundle.main.releaseVersionNumber ?? "")(\(Bundle.main.buildVersionNumber ?? "")) [buildDate: \(String(describing: BuildDetails.default.buildDate()))] [buildExpires: \(String(describing: BuildDetails.default.calculateExpirationDate()))]"
             "Trio Started: v\(Bundle.main.releaseVersionNumber ?? "")(\(Bundle.main.buildVersionNumber ?? "")) [buildDate: \(String(describing: BuildDetails.default.buildDate()))] [buildExpires: \(String(describing: BuildDetails.default.calculateExpirationDate()))]"
         )
         )
 
 
-        // Load services
-        loadServices()
+        // Setup up the Core Data Stack
+        coreDataStack = CoreDataStack.shared
 
 
-        // Fix bug in iOS 18 related to the translucent tab bar
-        configureTabBarAppearance()
+        do {
+            // Explicitly initialize Core Data Stacak
+            try coreDataStack.initializeStack()
+
+            // Load services
+            loadServices()
+
+            // Fix bug in iOS 18 related to the translucent tab bar
+            configureTabBarAppearance()
 
 
-        // Clear the persistentHistory and the NSManagedObjects that are older than 90 days every time the app starts
-        cleanupOldData()
+            // Clear the persistentHistory and the NSManagedObjects that are older than 90 days every time the app starts
+            cleanupOldData()
+        } catch {
+            debug(
+                .coreData,
+                "Failed to initialize Core Data Stack: \(error.localizedDescription)"
+            )
+            // Handle initialization failure
+            fatalError("Core Data Stack initialization failed: \(error.localizedDescription)")
+        }
     }
     }
 
 
     var body: some Scene {
     var body: some Scene {

+ 4 - 4
Trio/Sources/Helpers/BuildDetails.swift

@@ -27,8 +27,8 @@ class BuildDetails {
     }
     }
 
 
     var branchAndSha: String {
     var branchAndSha: String {
-        let branch = dict["com-trio-branch"] as? String ?? "Unknown"
-        let sha = dict["com-trio-commit-sha"] as? String ?? "Unknown"
+        let branch = dict["com-trio-branch"] as? String ?? String(localized: "Unknown")
+        let sha = dict["com-trio-commit-sha"] as? String ?? String(localized: "Unknown")
         return "\(branch) \(sha)"
         return "\(branch) \(sha)"
     }
     }
 
 
@@ -75,9 +75,9 @@ class BuildDetails {
     // Expiration header based on build type
     // Expiration header based on build type
     var expirationHeaderString: String {
     var expirationHeaderString: String {
         if isTestFlightBuild() {
         if isTestFlightBuild() {
-            return "Beta (TestFlight) Expires"
+            return String(localized: "Beta (TestFlight) Expires")
         } else {
         } else {
-            return "App Expires"
+            return String(localized: "App Expires")
         }
         }
     }
     }
 }
 }

+ 4 - 4
Trio/Sources/Helpers/HKUnit.swift

@@ -44,13 +44,13 @@ extension HKUnit {
 
 
     var localizedShortUnitString: String {
     var localizedShortUnitString: String {
         if self == HKUnit.millimolesPerLiter {
         if self == HKUnit.millimolesPerLiter {
-            return NSLocalizedString("mmol/L", comment: "The short unit display string for millimoles of glucose per liter")
+            return String(localized: "mmol/L", comment: "The short unit display string for millimoles of glucose per liter")
         } else if self == .milligramsPerDeciliter {
         } else if self == .milligramsPerDeciliter {
-            return NSLocalizedString("mg/dL", comment: "The short unit display string for milligrams of glucose per decilter")
+            return String(localized: "mg/dL", comment: "The short unit display string for milligrams of glucose per decilter")
         } else if self == .internationalUnit() {
         } else if self == .internationalUnit() {
-            return NSLocalizedString("U", comment: "The short unit display string for international units of insulin")
+            return String(localized: "U", comment: "The short unit display string for international units of insulin")
         } else if self == .gram() {
         } else if self == .gram() {
-            return NSLocalizedString("g", comment: "The short unit display string for grams")
+            return String(localized: "g", comment: "The short unit display string for grams")
         } else {
         } else {
             return String(describing: self)
             return String(describing: self)
         }
         }

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 180308 - 0
Trio/Sources/Localizations/Main/Localizable.xcstrings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2223
Trio/Sources/Localizations/Main/ar.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 1917
Trio/Sources/Localizations/Main/ca.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2184
Trio/Sources/Localizations/Main/da.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2229
Trio/Sources/Localizations/Main/de.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2231
Trio/Sources/Localizations/Main/en.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2228
Trio/Sources/Localizations/Main/es.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2229
Trio/Sources/Localizations/Main/fi.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2220
Trio/Sources/Localizations/Main/fr.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2223
Trio/Sources/Localizations/Main/he.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2178
Trio/Sources/Localizations/Main/hu.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2225
Trio/Sources/Localizations/Main/it.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2223
Trio/Sources/Localizations/Main/nb.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2231
Trio/Sources/Localizations/Main/nl.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2225
Trio/Sources/Localizations/Main/pl.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2223
Trio/Sources/Localizations/Main/pt-BR.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2223
Trio/Sources/Localizations/Main/pt-PT.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2226
Trio/Sources/Localizations/Main/ru.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2178
Trio/Sources/Localizations/Main/sk.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2223
Trio/Sources/Localizations/Main/sv.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2227
Trio/Sources/Localizations/Main/tr.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2223
Trio/Sources/Localizations/Main/uk.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2180
Trio/Sources/Localizations/Main/vi.lproj/Localizable.strings


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2225
Trio/Sources/Localizations/Main/zh-Hans.lproj/Localizable.strings


+ 4 - 0
Trio/Sources/Logger/Logger.swift

@@ -115,6 +115,7 @@ final class Logger {
     static let remoteControl = Logger(category: .remoteControl, reporter: baseReporter)
     static let remoteControl = Logger(category: .remoteControl, reporter: baseReporter)
     static let bolusState = Logger(category: .bolusState, reporter: baseReporter)
     static let bolusState = Logger(category: .bolusState, reporter: baseReporter)
     static let watchManager = Logger(category: .watchManager, reporter: baseReporter)
     static let watchManager = Logger(category: .watchManager, reporter: baseReporter)
+    static let coreData = Logger(category: .coreData, reporter: baseReporter)
 
 
     enum Category: String {
     enum Category: String {
         case `default`
         case `default`
@@ -127,6 +128,7 @@ final class Logger {
         case remoteControl
         case remoteControl
         case bolusState
         case bolusState
         case watchManager
         case watchManager
+        case coreData
 
 
         var name: String {
         var name: String {
             rawValue.capitalizingFirstLetter()
             rawValue.capitalizingFirstLetter()
@@ -144,6 +146,7 @@ final class Logger {
             case .remoteControl: return .remoteControl
             case .remoteControl: return .remoteControl
             case .bolusState: return .bolusState
             case .bolusState: return .bolusState
             case .watchManager: return .watchManager
             case .watchManager: return .watchManager
+            case .coreData: return .coreData
             }
             }
         }
         }
 
 
@@ -154,6 +157,7 @@ final class Logger {
             case .apsManager,
             case .apsManager,
                  .bolusState,
                  .bolusState,
                  .businessLogic,
                  .businessLogic,
+                 .coreData,
                  .deviceManager,
                  .deviceManager,
                  .nightscout,
                  .nightscout,
                  .openAPS,
                  .openAPS,

+ 16 - 16
Trio/Sources/Models/ContactTrickEntry.swift

@@ -130,23 +130,23 @@ enum ContactImageValue: String, JSON, CaseIterable, Identifiable, Codable {
     var displayName: String {
     var displayName: String {
         switch self {
         switch self {
         case .none:
         case .none:
-            return NSLocalizedString("None", comment: "")
+            return String(localized: "None", comment: "")
         case .glucose:
         case .glucose:
-            return NSLocalizedString("Glucose Reading", comment: "")
+            return String(localized: "Glucose Reading", comment: "")
         case .eventualBG:
         case .eventualBG:
-            return NSLocalizedString("Eventual Glucose", comment: "")
+            return String(localized: "Eventual Glucose", comment: "")
         case .delta:
         case .delta:
-            return NSLocalizedString("Glucose Delta", comment: "")
+            return String(localized: "Glucose Delta", comment: "")
         case .trend:
         case .trend:
-            return NSLocalizedString("Glucose Trend", comment: "")
+            return String(localized: "Glucose Trend", comment: "")
         case .lastLoopDate:
         case .lastLoopDate:
-            return NSLocalizedString("Last Loop Time", comment: "")
+            return String(localized: "Last Loop Time", comment: "")
         case .cob:
         case .cob:
-            return NSLocalizedString("COB", comment: "")
+            return String(localized: "COB", comment: "")
         case .iob:
         case .iob:
-            return NSLocalizedString("IOB", comment: "")
+            return String(localized: "IOB", comment: "")
         case .ring:
         case .ring:
-            return NSLocalizedString("Loop Status", comment: "")
+            return String(localized: "Loop Status", comment: "")
         }
         }
     }
     }
 }
 }
@@ -159,9 +159,9 @@ enum ContactImageLayout: String, JSON, CaseIterable, Identifiable, Codable {
     var displayName: String {
     var displayName: String {
         switch self {
         switch self {
         case .default:
         case .default:
-            return NSLocalizedString("Default", comment: "")
+            return String(localized: "Default", comment: "")
         case .split:
         case .split:
-            return NSLocalizedString("Split", comment: "")
+            return String(localized: "Split", comment: "")
         }
         }
     }
     }
 }
 }
@@ -178,15 +178,15 @@ enum ContactImageLargeRing: String, JSON, CaseIterable, Identifiable, Codable {
     var displayName: String {
     var displayName: String {
         switch self {
         switch self {
         case .none:
         case .none:
-            return NSLocalizedString("Hidden", comment: "")
+            return String(localized: "Hidden", comment: "")
         case .loop:
         case .loop:
-            return NSLocalizedString("Loop Status", comment: "")
+            return String(localized: "Loop Status", comment: "")
 //        case .iob:
 //        case .iob:
-//            return NSLocalizedString("Insulin on Board (IOB)", comment: "")
+//            return String(localized: "Insulin on Board (IOB)", comment: "")
 //        case .cob:
 //        case .cob:
-//            return NSLocalizedString("Carbs on Board (COB)", comment: "")
+//            return String(localized: "Carbs on Board (COB)", comment: "")
 //        case .iobcob:
 //        case .iobcob:
-//            return NSLocalizedString("IOB + COB", comment: "")
+//            return String(localized: "IOB + COB", comment: "")
         }
         }
     }
     }
 }
 }

+ 2 - 2
Trio/Sources/Models/ForecastDisplayType.swift

@@ -7,10 +7,10 @@ enum ForecastDisplayType: String, JSON, CaseIterable, Identifiable, Codable, Has
     var displayName: String {
     var displayName: String {
         switch self {
         switch self {
         case .cone:
         case .cone:
-            return NSLocalizedString("Cone", comment: "")
+            return String(localized: "Cone", comment: "")
 
 
         case .lines:
         case .lines:
-            return NSLocalizedString("Lines", comment: "")
+            return String(localized: "Lines", comment: "")
         }
         }
     }
     }
 }
 }

+ 2 - 2
Trio/Sources/Models/HbA1cDisplayUnit.swift

@@ -8,9 +8,9 @@ enum HbA1cDisplayUnit: String, JSON, CaseIterable, Identifiable, Codable, Hashab
     var displayName: String {
     var displayName: String {
         switch self {
         switch self {
         case .percent:
         case .percent:
-            return NSLocalizedString("Percent", comment: "")
+            return String(localized: "Percent", comment: "")
         case .mmolMol:
         case .mmolMol:
-            return NSLocalizedString("mmol/mol", comment: "")
+            return String(localized: "mmol/mol", comment: "")
         }
         }
     }
     }
 }
 }

+ 2 - 2
Trio/Sources/Models/LockScreenView.swift

@@ -7,9 +7,9 @@ enum LockScreenView: String, JSON, CaseIterable, Identifiable, Codable, Hashable
     var displayName: String {
     var displayName: String {
         switch self {
         switch self {
         case .simple:
         case .simple:
-            return NSLocalizedString("Simple", comment: "")
+            return String(localized: "Simple", comment: "")
         case .detailed:
         case .detailed:
-            return NSLocalizedString("Detailed", comment: "")
+            return String(localized: "Detailed", comment: "")
         }
         }
     }
     }
 }
 }

+ 2 - 2
Trio/Sources/Models/TimeInRangeChartStyle.swift

@@ -8,9 +8,9 @@ enum TimeInRangeChartStyle: String, JSON, CaseIterable, Identifiable, Codable, H
     var displayName: String {
     var displayName: String {
         switch self {
         switch self {
         case .vertical:
         case .vertical:
-            return NSLocalizedString("Vertical", comment: "")
+            return String(localized: "Vertical", comment: "")
         case .horizontal:
         case .horizontal:
-            return NSLocalizedString("Horizontal", comment: "")
+            return String(localized: "Horizontal", comment: "")
         }
         }
     }
     }
 }
 }

+ 2 - 2
Trio/Sources/Models/TotalInsulinDisplayType.swift

@@ -14,9 +14,9 @@ enum TotalInsulinDisplayType: String, JSON, CaseIterable, Identifiable, Codable,
     var displayName: String {
     var displayName: String {
         switch self {
         switch self {
         case .totalDailyDose:
         case .totalDailyDose:
-            return NSLocalizedString("TDD", comment: "")
+            return String(localized: "TDD", comment: "")
         case .totalInsulinInScope:
         case .totalInsulinInScope:
-            return NSLocalizedString("TINS", comment: "")
+            return String(localized: "TINS", comment: "")
         }
         }
     }
     }
 }
 }

+ 2 - 5
Trio/Sources/Modules/Adjustments/AdjustmentsDataFlow.swift

@@ -11,15 +11,12 @@ enum Adjustments {
         var id: String { rawValue }
         var id: String { rawValue }
 
 
         var name: String {
         var name: String {
-            var name: String = ""
             switch self {
             switch self {
             case .overrides:
             case .overrides:
-                name = "Overrides"
+                return String(localized: "Overrides", comment: "Selected Tab")
             case .tempTargets:
             case .tempTargets:
-                name = "Temp Targets"
+                return String(localized: "Temp Targets", comment: "Selected Tab")
             }
             }
-
-            return NSLocalizedString(name, comment: "Selected Tab")
         }
         }
     }
     }
 }
 }

+ 2 - 2
Trio/Sources/Modules/Adjustments/AdjustmentsStateModel+Extensions/AdjustmentsStateModel+Overrides.swift

@@ -224,7 +224,7 @@ extension Adjustments.StateModel {
 
 
             if let overrideToEdit = try viewContext.existingObject(with: firstID) as? OverrideStored {
             if let overrideToEdit = try viewContext.existingObject(with: firstID) as? OverrideStored {
                 currentActiveOverride = overrideToEdit
                 currentActiveOverride = overrideToEdit
-                activeOverrideName = overrideToEdit.name ?? "Custom Override"
+                activeOverrideName = overrideToEdit.name ?? String(localized: "Custom Override")
             }
             }
         } catch {
         } catch {
             debugPrint(
             debugPrint(
@@ -248,7 +248,7 @@ extension Adjustments.StateModel {
 
 
             if let overrideToEdit = try viewContext.existingObject(with: duplicateId) as? OverrideStored {
             if let overrideToEdit = try viewContext.existingObject(with: duplicateId) as? OverrideStored {
                 currentActiveOverride = overrideToEdit
                 currentActiveOverride = overrideToEdit
-                activeOverrideName = overrideToEdit.name ?? "Custom Override"
+                activeOverrideName = overrideToEdit.name ?? String(localized: "Custom Override")
             }
             }
         } catch {
         } catch {
             debugPrint(
             debugPrint(

+ 5 - 5
Trio/Sources/Modules/Adjustments/AdjustmentsStateModel+Extensions/AdjustmentsStateModel+TempTargets.swift

@@ -44,7 +44,7 @@ extension Adjustments.StateModel {
 
 
             if let tempTargetToEdit = try viewContext.existingObject(with: firstID) as? TempTargetStored {
             if let tempTargetToEdit = try viewContext.existingObject(with: firstID) as? TempTargetStored {
                 currentActiveTempTarget = tempTargetToEdit
                 currentActiveTempTarget = tempTargetToEdit
-                activeTempTargetName = tempTargetToEdit.name ?? "Custom Temp Target"
+                activeTempTargetName = tempTargetToEdit.name ?? String(localized: "Custom Temp Target")
                 tempTargetTarget = tempTargetToEdit.target?.decimalValue ?? 0
                 tempTargetTarget = tempTargetToEdit.target?.decimalValue ?? 0
             }
             }
         } catch {
         } catch {
@@ -254,7 +254,7 @@ extension Adjustments.StateModel {
             )
             )
             tempTargetStorage.saveTempTargetsToStorage([tempTarget])
             tempTargetStorage.saveTempTargetsToStorage([tempTarget])
         } catch {
         } catch {
-            debugPrint("\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to enact Override Preset")
+            debugPrint("\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to enact TempTarget Preset")
         }
         }
     }
     }
 
 
@@ -313,7 +313,7 @@ extension Adjustments.StateModel {
 
 
     /// Duplicates the current preset and cancels the previous one.
     /// Duplicates the current preset and cancels the previous one.
     @MainActor func duplicateTempTargetPresetAndCancelPreviousTempTarget() async {
     @MainActor func duplicateTempTargetPresetAndCancelPreviousTempTarget() async {
-        // We get the current active Preset by using currentActiveTempTarget which can either be a Preset or a custom Override
+        // We get the current active Preset by using currentActiveTempTarget which can either be a Preset or a custom TempTarget
         guard let tempTargetPresetToDuplicate = currentActiveTempTarget,
         guard let tempTargetPresetToDuplicate = currentActiveTempTarget,
               tempTargetPresetToDuplicate.isPreset == true else { return }
               tempTargetPresetToDuplicate.isPreset == true else { return }
 
 
@@ -333,7 +333,7 @@ extension Adjustments.StateModel {
             if let tempTargetToEdit = try viewContext.existingObject(with: duplidateId) as? TempTargetStored
             if let tempTargetToEdit = try viewContext.existingObject(with: duplidateId) as? TempTargetStored
             {
             {
                 currentActiveTempTarget = tempTargetToEdit
                 currentActiveTempTarget = tempTargetToEdit
-                activeTempTargetName = tempTargetToEdit.name ?? "Custom Temp Target"
+                activeTempTargetName = tempTargetToEdit.name ?? String(localized: "Custom Temp Target")
             }
             }
         } catch {
         } catch {
             debugPrint(
             debugPrint(
@@ -344,7 +344,7 @@ extension Adjustments.StateModel {
 
 
     /// Deletes a Temp Target preset.
     /// Deletes a Temp Target preset.
     func invokeTempTargetPresetDeletion(_ objectID: NSManagedObjectID) async {
     func invokeTempTargetPresetDeletion(_ objectID: NSManagedObjectID) async {
-        await tempTargetStorage.deleteOverridePreset(objectID)
+        await tempTargetStorage.deleteTempTargetPreset(objectID)
         setupTempTargetPresetsArray()
         setupTempTargetPresetsArray()
     }
     }
 
 

+ 65 - 34
Trio/Sources/Modules/AlgorithmAdvancedSettings/View/AlgorithmAdvancedSettingsRootView.swift

@@ -38,13 +38,16 @@ extension AlgorithmAdvancedSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Max Daily Safety Multiplier", comment: "Max Daily Safety Multiplier")
+                            hintLabel = String(localized: "Max Daily Safety Multiplier", comment: "Max Daily Safety Multiplier")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("maxDailySafetyMultiplier"),
                     type: .decimal("maxDailySafetyMultiplier"),
-                    label: NSLocalizedString("Max Daily Safety Multiplier", comment: "Max Daily Safety Multiplier"),
-                    miniHint: "Limits temporary basal rates to this percentage of your largest basal rate.",
+                    label: String(localized: "Max Daily Safety Multiplier", comment: "Max Daily Safety Multiplier"),
+                    miniHint: String(
+                        localized: "Limits temporary basal rates to this percentage of your largest basal rate.",
+                        comment: "Mini Hint for Max Daily Safety Multiplier"
+                    ),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: 300%").bold()
                         Text("Default: 300%").bold()
@@ -64,7 +67,8 @@ extension AlgorithmAdvancedSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString(
+                            hintLabel = String(
+                                localized:
                                 "Current Basal Safety Multiplier",
                                 "Current Basal Safety Multiplier",
                                 comment: "Current Basal Safety Multiplier"
                                 comment: "Current Basal Safety Multiplier"
                             )
                             )
@@ -72,8 +76,11 @@ extension AlgorithmAdvancedSettings {
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("currentBasalSafetyMultiplier"),
                     type: .decimal("currentBasalSafetyMultiplier"),
-                    label: NSLocalizedString("Current Basal Safety Multiplier", comment: "Current Basal Safety Multiplier"),
-                    miniHint: "Limits temporary basal rates to this percentage of the current basal rate.",
+                    label: String(localized: "Current Basal Safety Multiplier", comment: "Current Basal Safety Multiplier"),
+                    miniHint: String(
+                        localized: "Limits temporary basal rates to this percentage of the current basal rate.",
+                        comment: "Mini Hint for Current Basal Safety Multiplier"
+                    ),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: 400%").bold()
                         Text("Default: 400%").bold()
@@ -95,13 +102,16 @@ extension AlgorithmAdvancedSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Duration of Insulin Action"
+                            hintLabel = String(localized: "Duration of Insulin Action", comment: "Duration of Insulin Action")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("dia"),
                     type: .decimal("dia"),
-                    label: "Duration of Insulin Action",
-                    miniHint: "Number of hours insulin is active in your body.",
+                    label: String(localized: "Duration of Insulin Action", comment: "Duration of Insulin Action"),
+                    miniHint: String(
+                        localized: "Number of hours insulin is active in your body.",
+                        comment: "Mini Hint for Duration of Insulin Action"
+                    ),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: 10 hours").bold()
                         Text("Default: 10 hours").bold()
@@ -125,14 +135,17 @@ extension AlgorithmAdvancedSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Use Custom Peak Time", comment: "Use Custom Peak Time")
+                            hintLabel = String(localized: "Use Custom Peak Time", comment: "Use Custom Peak Time")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .conditionalDecimal("insulinPeakTime"),
                     type: .conditionalDecimal("insulinPeakTime"),
-                    label: NSLocalizedString("Use Custom Peak Time", comment: "Use Custom Peak Time"),
-                    conditionalLabel: NSLocalizedString("Insulin Peak Time", comment: "Insulin Peak Time"),
-                    miniHint: "Set a custom time for peak insulin effect.",
+                    label: String(localized: "Use Custom Peak Time", comment: "Use Custom Peak Time"),
+                    conditionalLabel: String(localized: "Insulin Peak Time", comment: "Insulin Peak Time"),
+                    miniHint: String(
+                        localized: "Set a custom time for peak insulin effect.",
+                        comment: "Mini Hint for Insulin Peak Time"
+                    ),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: Set by Insulin Type").bold()
                         Text("Default: Set by Insulin Type").bold()
@@ -156,13 +169,16 @@ extension AlgorithmAdvancedSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Skip Neutral Temps", comment: "Skip Neutral Temps")
+                            hintLabel = String(localized: "Skip Neutral Temps", comment: "Skip Neutral Temps")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: NSLocalizedString("Skip Neutral Temps", comment: "Skip Neutral Temps"),
-                    miniHint: "Skip neutral temporary basal rates to reduce MDT pump alerts.",
+                    label: String(localized: "Skip Neutral Temps", comment: "Skip Neutral Temps"),
+                    miniHint: String(
+                        localized: "Skip neutral temporary basal rates to reduce MDT pump alerts.",
+                        comment: "Mini Hint for Skip Neutral Temps"
+                    ),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: OFF").bold()
                         Text("Default: OFF").bold()
@@ -183,13 +199,16 @@ extension AlgorithmAdvancedSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Unsuspend If No Temp", comment: "Unsuspend If No Temp")
+                            hintLabel = String(localized: "Unsuspend If No Temp", comment: "Unsuspend If No Temp")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: NSLocalizedString("Unsuspend If No Temp", comment: "Unsuspend If No Temp"),
-                    miniHint: "Resume pump automatically after suspension.",
+                    label: String(localized: "Unsuspend If No Temp", comment: "Unsuspend If No Temp"),
+                    miniHint: String(
+                        localized: "Resume pump automatically after suspension.",
+                        comment: "Mini Hint for Unsuspend If No Temp"
+                    ),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: OFF").bold()
                         Text("Default: OFF").bold()
@@ -208,13 +227,16 @@ extension AlgorithmAdvancedSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Suspend Zeros IOB", comment: "Suspend Zeros IOB")
+                            hintLabel = String(localized: "Suspend Zeros IOB", comment: "Suspend Zeros IOB")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: NSLocalizedString("Suspend Zeros IOB", comment: "Suspend Zeros IOB"),
-                    miniHint: "Clear temporary basal rates and reset IOB when suspended.",
+                    label: String(localized: "Suspend Zeros IOB", comment: "Suspend Zeros IOB"),
+                    miniHint: String(
+                        localized: "Clear temporary basal rates and reset IOB when suspended.",
+                        comment: "Mini Hint for Suspend Zeros IOB"
+                    ),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: OFF").bold()
                         Text("Default: OFF").bold()
@@ -236,12 +258,12 @@ extension AlgorithmAdvancedSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Min 5m Carb Impact", comment: "Min 5m Carb Impact")
+                            hintLabel = String(localized: "Min 5m Carb Impact", comment: "Min 5m Carb Impact")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("min5mCarbimpact"),
                     type: .decimal("min5mCarbimpact"),
-                    label: NSLocalizedString("Min 5m Carb Impact", comment: "Min 5m Carb Impact"),
+                    label: String(localized: "Min 5m Carb Impact", comment: "Min 5m Carb Impact"),
                     miniHint: "Default impact of carb absorption over a 5 minute interval.",
                     miniHint: "Default impact of carb absorption over a 5 minute interval.",
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
@@ -265,13 +287,16 @@ extension AlgorithmAdvancedSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Remaining Carbs Percentage", comment: "Remaining Carbs Percentage")
+                            hintLabel = String(localized: "Remaining Carbs Percentage", comment: "Remaining Carbs Percentage")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("remainingCarbsFraction"),
                     type: .decimal("remainingCarbsFraction"),
-                    label: NSLocalizedString("Remaining Carbs Percentage", comment: "Remaining Carbs Percentage"),
-                    miniHint: "Percentage of carbs still available if no absorption is detected.",
+                    label: String(localized: "Remaining Carbs Percentage", comment: "Remaining Carbs Percentage"),
+                    miniHint: String(
+                        localized: "Percentage of carbs still available if no absorption is detected.",
+                        comment: "Mini Hint for Remaining Carbs Percentage"
+                    ),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: 100%").bold()
                         Text("Default: 100%").bold()
@@ -292,13 +317,16 @@ extension AlgorithmAdvancedSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Remaining Carbs Cap", comment: "Remaining Carbs Cap")
+                            hintLabel = String(localized: "Remaining Carbs Cap", comment: "Remaining Carbs Cap")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("remainingCarbsCap"),
                     type: .decimal("remainingCarbsCap"),
-                    label: NSLocalizedString("Remaining Carbs Cap", comment: "Remaining Carbs Cap"),
-                    miniHint: "Maximum amount of carbs still available if no absorption is detected.",
+                    label: String(localized: "Remaining Carbs Cap", comment: "Remaining Carbs Cap"),
+                    miniHint: String(
+                        localized: "Maximum amount of carbs still available if no absorption is detected.",
+                        comment: "Mini hint for Remaining Carbs Cap"
+                    ),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: 90 g").bold()
                         Text("Default: 90 g").bold()
@@ -319,13 +347,16 @@ extension AlgorithmAdvancedSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Noisy CGM Target Multiplier", comment: "Noisy CGM Target Multiplier")
+                            hintLabel = String(localized: "Noisy CGM Target Multiplier", comment: "Noisy CGM Target Multiplier")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("noisyCGMTargetMultiplier"),
                     type: .decimal("noisyCGMTargetMultiplier"),
-                    label: NSLocalizedString("Noisy CGM Target Increase", comment: "Noisy CGM Target Increase"),
-                    miniHint: "Percentage increase of glucose target when CGM is inconsistent.",
+                    label: String(localized: "Noisy CGM Target Increase", comment: "Noisy CGM Target Increase"),
+                    miniHint: String(
+                        localized: "Percentage increase of glucose target when CGM is inconsistent.",
+                        comment: "Mini Hint for Noisy CGM Target Increase"
+                    ),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: 130%").bold()
                         Text("Default: 130%").bold()
@@ -346,7 +377,7 @@ extension AlgorithmAdvancedSettings {
                     shouldDisplayHint: $shouldDisplayHint,
                     shouldDisplayHint: $shouldDisplayHint,
                     hintLabel: hintLabel ?? "",
                     hintLabel: hintLabel ?? "",
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
-                    sheetTitle: "Help"
+                    sheetTitle: String(localized: "Help", comment: "Help sheet title")
                 )
                 )
             }
             }
             .scrollContentBackground(.hidden)
             .scrollContentBackground(.hidden)

+ 9 - 9
Trio/Sources/Modules/AutosensSettings/View/AutosensSettingsRootView.swift

@@ -105,7 +105,7 @@ extension AutosensSettings {
                         Spacer()
                         Spacer()
                         Button(
                         Button(
                             action: {
                             action: {
-                                hintLabel = "Autosens"
+                                hintLabel = String(localized: "Autosens")
                                 selectedVerboseHint = AnyView(autosensVerboseHint)
                                 selectedVerboseHint = AnyView(autosensVerboseHint)
                                 shouldDisplayHint.toggle()
                                 shouldDisplayHint.toggle()
                             },
                             },
@@ -134,12 +134,12 @@ extension AutosensSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Autosens Max", comment: "Autosens Max")
+                            hintLabel = String(localized: "Autosens Max", comment: "Autosens Max")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("autosensMax"),
                     type: .decimal("autosensMax"),
-                    label: NSLocalizedString("Autosens Max", comment: "Autosens Max"),
+                    label: String(localized: "Autosens Max", comment: "Autosens Max"),
                     miniHint: "Upper limit of the Autosens Ratio.",
                     miniHint: "Upper limit of the Autosens Ratio.",
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
@@ -154,7 +154,7 @@ extension AutosensSettings {
                             "Tip: Increasing this value allows automatic adjustments of basal rates to be higher, ISF to be lower, and CR to be lower."
                             "Tip: Increasing this value allows automatic adjustments of basal rates to be higher, ISF to be lower, and CR to be lower."
                         )
                         )
                     },
                     },
-                    headerText: "Glucose Deviations Algorithm"
+                    headerText: String(localized: "Glucose Deviations Algorithm")
                 )
                 )
 
 
                 SettingInputSection(
                 SettingInputSection(
@@ -165,12 +165,12 @@ extension AutosensSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Autosens Min", comment: "Autosens Min")
+                            hintLabel = String(localized: "Autosens Min", comment: "Autosens Min")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("autosensMin"),
                     type: .decimal("autosensMin"),
-                    label: NSLocalizedString("Autosens Min", comment: "Autosens Min"),
+                    label: String(localized: "Autosens Min", comment: "Autosens Min"),
                     miniHint: "Lower limit of the Autosens Ratio.",
                     miniHint: "Lower limit of the Autosens Ratio.",
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
@@ -195,12 +195,12 @@ extension AutosensSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Rewind Resets Autosens", comment: "Rewind Resets Autosens")
+                            hintLabel = String(localized: "Rewind Resets Autosens", comment: "Rewind Resets Autosens")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: NSLocalizedString("Rewind Resets Autosens", comment: "Rewind Resets Autosens"),
+                    label: String(localized: "Rewind Resets Autosens", comment: "Rewind Resets Autosens"),
                     miniHint: "Pump rewind initiates a reset in Autosens Ratio.",
                     miniHint: "Pump rewind initiates a reset in Autosens Ratio.",
                     verboseHint: VStack(alignment: .leading, spacing: 5) {
                     verboseHint: VStack(alignment: .leading, spacing: 5) {
                         Text("Default: ON").bold()
                         Text("Default: ON").bold()
@@ -226,7 +226,7 @@ extension AutosensSettings {
                     shouldDisplayHint: $shouldDisplayHint,
                     shouldDisplayHint: $shouldDisplayHint,
                     hintLabel: hintLabel ?? "",
                     hintLabel: hintLabel ?? "",
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
-                    sheetTitle: "Help"
+                    sheetTitle: String(localized: "Help", comment: "Help sheet title")
                 )
                 )
             }
             }
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))

+ 15 - 15
Trio/Sources/Modules/BolusCalculatorConfig/View/BolusCalculatorConfigRootView.swift

@@ -41,12 +41,12 @@ extension BolusCalculatorConfig {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Display Meal Presets"
+                            hintLabel = String(localized: "Display Meal Presets")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: "Display Meal Presets",
+                    label: String(localized: "Display Meal Presets"),
                     miniHint: "Allow the creation of saved, preset meals.",
                     miniHint: "Allow the creation of saved, preset meals.",
                     verboseHint: VStack(alignment: .leading, spacing: 10) {
                     verboseHint: VStack(alignment: .leading, spacing: 10) {
                         Text("Default: ON").bold()
                         Text("Default: ON").bold()
@@ -62,13 +62,13 @@ extension BolusCalculatorConfig {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Recommended Bolus Percentage"
+                            hintLabel = String(localized: "Recommended Bolus Percentage")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("overrideFactor"),
                     type: .decimal("overrideFactor"),
-                    label: "Recommended Bolus Percentage",
-                    miniHint: "Percentage of bolus suggested in bolus calculator.",
+                    label: String(localized: "Recommended Bolus Percentage"),
+                    miniHint: String(localized: "Percentage of bolus suggested in bolus calculator."),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: 80%").bold()
                         Text("Default: 80%").bold()
@@ -82,7 +82,7 @@ extension BolusCalculatorConfig {
                             "Tip: If you are a new Trio user, it is not advised to set this to 100% until you have verified that your core settings (basal rates, ISF, and CR) do not need adjusting."
                             "Tip: If you are a new Trio user, it is not advised to set this to 100% until you have verified that your core settings (basal rates, ISF, and CR) do not need adjusting."
                         )
                         )
                     },
                     },
-                    headerText: "Calculator Configuration"
+                    headerText: String(localized: "Calculator Configuration")
                 )
                 )
 
 
                 SettingInputSection(
                 SettingInputSection(
@@ -93,14 +93,14 @@ extension BolusCalculatorConfig {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Fatty Meal"
+                            hintLabel = String(localized: "Fatty Meal")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .conditionalDecimal("fattyMealFactor"),
                     type: .conditionalDecimal("fattyMealFactor"),
-                    label: "Enable Fatty Meal Option",
-                    conditionalLabel: "Fatty Meal Bolus Percentage",
-                    miniHint: "Add and set a bolus option for meals that absorb slowly.",
+                    label: String(localized: "Enable Fatty Meal Option"),
+                    conditionalLabel: String(localized: "Fatty Meal Bolus Percentage"),
+                    miniHint: String(localized: "Add and set a bolus option for meals that absorb slowly."),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: OFF").bold()
                         Text("Default: OFF").bold()
@@ -127,14 +127,14 @@ extension BolusCalculatorConfig {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Super Bolus"
+                            hintLabel = String(localized: "Super Bolus")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .conditionalDecimal("sweetMealFactor"),
                     type: .conditionalDecimal("sweetMealFactor"),
-                    label: "Enable Super Bolus Option",
-                    conditionalLabel: "Super Bolus Percentage",
-                    miniHint: "Add and set a bolus option for meals that absorb quickly.",
+                    label: String(localized: "Enable Super Bolus Option"),
+                    conditionalLabel: String(localized: "Super Bolus Percentage"),
+                    miniHint: String(localized: "Add and set a bolus option for meals that absorb quickly."),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: OFF").bold()
                         Text("Default: OFF").bold()
@@ -160,7 +160,7 @@ extension BolusCalculatorConfig {
                     shouldDisplayHint: $shouldDisplayHint,
                     shouldDisplayHint: $shouldDisplayHint,
                     hintLabel: hintLabel ?? "",
                     hintLabel: hintLabel ?? "",
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
-                    sheetTitle: "Help"
+                    sheetTitle: String(localized: "Help", comment: "Help sheet title")
                 )
                 )
             }
             }
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))

+ 10 - 6
Trio/Sources/Modules/CGMSettings/CGMSettingsStateModel.swift

@@ -134,12 +134,16 @@ extension CGMSettings {
         }
         }
 
 
         func deleteCGM() {
         func deleteCGM() {
-            shouldDisplayCGMSetupSheet = false
-
-            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
-                self.fetchGlucoseManager.deleteGlucoseSource()
-                self.completionNotifyingDidComplete(OtherCGMSourceCompletionNotifying())
-            })
+            fetchGlucoseManager.performOnCGMManagerQueue {
+                // Call plugin functionality on the manager queue (or at least attempt to)
+                self.fetchGlucoseManager?.deleteGlucoseSource()
+
+                // UI updates go back to Main
+                DispatchQueue.main.async {
+                    self.shouldDisplayCGMSetupSheet = false
+                    self.completionNotifyingDidComplete(CGMDeletionCompletionNotifying())
+                }
+            }
         }
         }
     }
     }
 }
 }

+ 4 - 4
Trio/Sources/Modules/CGMSettings/View/CGMRootView.swift

@@ -99,13 +99,13 @@ extension CGMSettings {
                             get: { selectedVerboseHint },
                             get: { selectedVerboseHint },
                             set: {
                             set: {
                                 selectedVerboseHint = $0.map { AnyView($0) }
                                 selectedVerboseHint = $0.map { AnyView($0) }
-                                hintLabel = "Smooth Glucose Value"
+                                hintLabel = String(localized: "Smooth Glucose Value")
                             }
                             }
                         ),
                         ),
                         units: state.units,
                         units: state.units,
                         type: .boolean,
                         type: .boolean,
-                        label: "Smooth Glucose Value",
-                        miniHint: "Smooth CGM readings using Savitzky-Golay filtering.",
+                        label: String(localized: "Smooth Glucose Value"),
+                        miniHint: String(localized: "Smooth CGM readings using Savitzky-Golay filtering."),
                         verboseHint:
                         verboseHint:
                         VStack(alignment: .leading, spacing: 10) {
                         VStack(alignment: .leading, spacing: 10) {
                             Text("Default: OFF").bold()
                             Text("Default: OFF").bold()
@@ -192,7 +192,7 @@ extension CGMSettings {
                                 )
                                 )
                             }
                             }
                         ),
                         ),
-                        sheetTitle: "Help"
+                        sheetTitle: String(localized: "Help", comment: "Help sheet title")
                     )
                     )
                 }
                 }
                 .confirmationDialog("CGM Model", isPresented: $showCGMSelection) {
                 .confirmationDialog("CGM Model", isPresented: $showCGMSelection) {

+ 11 - 11
Trio/Sources/Modules/CalendarEventSettings/View/CalendarEventSettingsRootView.swift

@@ -26,13 +26,13 @@ extension CalendarEventSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Create Events in Calendar"
+                            hintLabel = String(localized: "Create Events in Calendar")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: "Create Events in Calendar",
-                    miniHint: "Use calendar events to display current data.",
+                    label: String(localized: "Create Events in Calendar"),
+                    miniHint: String(localized: "Use calendar events to display current data."),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: OFF").bold()
                         Text("Default: OFF").bold()
@@ -47,7 +47,7 @@ extension CalendarEventSettings {
                         )
                         )
                         Text("Note: Once a new calendar event is created, the previous event will be deleted.")
                         Text("Note: Once a new calendar event is created, the previous event will be deleted.")
                     },
                     },
-                    headerText: "Diabetes Data as Calendar Event"
+                    headerText: String(localized: "Diabetes Data as Calendar Event")
                 )
                 )
 
 
                 if state.calendarIDs.isNotEmpty, state.useCalendar {
                 if state.calendarIDs.isNotEmpty, state.useCalendar {
@@ -69,13 +69,13 @@ extension CalendarEventSettings {
                             get: { selectedVerboseHint },
                             get: { selectedVerboseHint },
                             set: {
                             set: {
                                 selectedVerboseHint = $0.map { AnyView($0) }
                                 selectedVerboseHint = $0.map { AnyView($0) }
-                                hintLabel = "Display Emojis as Labels"
+                                hintLabel = String(localized: "Display Emojis as Labels")
                             }
                             }
                         ),
                         ),
                         units: state.units,
                         units: state.units,
                         type: .boolean,
                         type: .boolean,
-                        label: "Display Emojis as Labels",
-                        miniHint: "Use emojis for calendar events. See hint for more details.",
+                        label: String(localized: "Display Emojis as Labels"),
+                        miniHint: String(localized: "Use emojis for calendar events. See hint for more details."),
                         verboseHint: VStack(alignment: .leading, spacing: 10) {
                         verboseHint: VStack(alignment: .leading, spacing: 10) {
                             Text("Default: OFF").bold()
                             Text("Default: OFF").bold()
                             VStack(alignment: .leading, spacing: 5) {
                             VStack(alignment: .leading, spacing: 5) {
@@ -104,13 +104,13 @@ extension CalendarEventSettings {
                             get: { selectedVerboseHint },
                             get: { selectedVerboseHint },
                             set: {
                             set: {
                                 selectedVerboseHint = $0.map { AnyView($0) }
                                 selectedVerboseHint = $0.map { AnyView($0) }
-                                hintLabel = "Display IOB and COB"
+                                hintLabel = String(localized: "Display IOB and COB")
                             }
                             }
                         ),
                         ),
                         units: state.units,
                         units: state.units,
                         type: .boolean,
                         type: .boolean,
-                        label: "Display IOB and COB",
-                        miniHint: "Include IOB & COB in the calendar event data.",
+                        label: String(localized: "Display IOB and COB"),
+                        miniHint: String(localized: "Include IOB & COB in the calendar event data."),
                         verboseHint: VStack(alignment: .leading, spacing: 10) {
                         verboseHint: VStack(alignment: .leading, spacing: 10) {
                             Text("Default: OFF").bold()
                             Text("Default: OFF").bold()
                             Text(
                             Text(
@@ -140,7 +140,7 @@ extension CalendarEventSettings {
                     shouldDisplayHint: $shouldDisplayHint,
                     shouldDisplayHint: $shouldDisplayHint,
                     hintLabel: hintLabel ?? "",
                     hintLabel: hintLabel ?? "",
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
-                    sheetTitle: "Help"
+                    sheetTitle: String(localized: "Help", comment: "Help sheet title")
                 )
                 )
             }
             }
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))

+ 6 - 6
Trio/Sources/Modules/ContactImage/View/ContactImageHelpView.swift

@@ -8,20 +8,20 @@ struct ContactImageHelpView: View {
         NavigationStack {
         NavigationStack {
             List {
             List {
                 DefinitionRow(
                 DefinitionRow(
-                    term: "How Trio Manages Contact Images",
+                    term: String(localized: "How Trio Manages Contact Images"),
                     definition: Text(
                     definition: Text(
                         "Trio will automatically assign a name like 'Trio 1' to any contact image you add, and a create an entry under your iOS Contacts. Use the 'Save' button at the bottom to save your customized contact image."
                         "Trio will automatically assign a name like 'Trio 1' to any contact image you add, and a create an entry under your iOS Contacts. Use the 'Save' button at the bottom to save your customized contact image."
                     )
                     )
                 ).listRowBackground(Color.gray.opacity(0.1))
                 ).listRowBackground(Color.gray.opacity(0.1))
 
 
                 DefinitionRow(
                 DefinitionRow(
-                    term: "Preview Contact Image",
+                    term: String(localized: "Preview Contact Image"),
                     definition: Text(
                     definition: Text(
                         "See a live preview of your contact image design at the top of the screen. Changes made to styles, layouts, or settings are instantly reflected."
                         "See a live preview of your contact image design at the top of the screen. Changes made to styles, layouts, or settings are instantly reflected."
                     )
                     )
                 ).listRowBackground(Color.gray.opacity(0.1))
                 ).listRowBackground(Color.gray.opacity(0.1))
 
 
-                DefinitionRow(term: "Customize Layout and Style", definition: VStack(alignment: .leading) {
+                DefinitionRow(term: String(localized: "Customize Layout and Style"), definition: VStack(alignment: .leading) {
                     Text("Choose from multiple layout options using the Layout Picker in the 'Style' section.")
                     Text("Choose from multiple layout options using the Layout Picker in the 'Style' section.")
                     Text("Enable High Contrast Mode for better visibility in certain conditions.")
                     Text("Enable High Contrast Mode for better visibility in certain conditions.")
                     Text("Available Layouts:")
                     Text("Available Layouts:")
@@ -29,7 +29,7 @@ struct ContactImageHelpView: View {
                     Text("• Split: Divides values into two separate areas of same size.")
                     Text("• Split: Divides values into two separate areas of same size.")
                 }).listRowBackground(Color.gray.opacity(0.1))
                 }).listRowBackground(Color.gray.opacity(0.1))
 
 
-                DefinitionRow(term: "Set Display Values", definition: VStack(alignment: .leading) {
+                DefinitionRow(term: String(localized: "Set Display Values"), definition: VStack(alignment: .leading) {
                     Text("Select what values to show on the contact image (e.g., glucose, trend, none) for the available slots:")
                     Text("Select what values to show on the contact image (e.g., glucose, trend, none) for the available slots:")
                     Text("• None: No value displayed.")
                     Text("• None: No value displayed.")
                     Text("• Glucose Reading: Current CGM provided glucose value.")
                     Text("• Glucose Reading: Current CGM provided glucose value.")
@@ -42,7 +42,7 @@ struct ContactImageHelpView: View {
                     Text("• Last Loop Time: Time of the last algorithm run.")
                     Text("• Last Loop Time: Time of the last algorithm run.")
                 }).listRowBackground(Color.gray.opacity(0.1))
                 }).listRowBackground(Color.gray.opacity(0.1))
 
 
-                DefinitionRow(term: "Adjust Ring Settings", definition: VStack(alignment: .leading) {
+                DefinitionRow(term: String(localized: "Adjust Ring Settings"), definition: VStack(alignment: .leading) {
                     Text("Add visual Rings around the contact image to highlight information.")
                     Text("Add visual Rings around the contact image to highlight information.")
                     Text("Fine-tune the ring’s Width and Gap to suit your design preferences.")
                     Text("Fine-tune the ring’s Width and Gap to suit your design preferences.")
                     Text("Available Rings:")
                     Text("Available Rings:")
@@ -50,7 +50,7 @@ struct ContactImageHelpView: View {
                     Text("• Loop Status: Indicates current loop status (green, yellow, red).")
                     Text("• Loop Status: Indicates current loop status (green, yellow, red).")
                 }).listRowBackground(Color.gray.opacity(0.1))
                 }).listRowBackground(Color.gray.opacity(0.1))
 
 
-                DefinitionRow(term: "Customize Fonts", definition: VStack(alignment: .leading) {
+                DefinitionRow(term: String(localized: "Customize Fonts"), definition: VStack(alignment: .leading) {
                     Text("Select font size, weight, and width to match your style:")
                     Text("Select font size, weight, and width to match your style:")
                     Text("• Font Size: Adjust the main text size.")
                     Text("• Font Size: Adjust the main text size.")
                     Text("• Secondary Font Size: Adjust text size for values in split layouts.")
                     Text("• Secondary Font Size: Adjust text size for values in split layouts.")

+ 17 - 23
Trio/Sources/Modules/DataTable/DataTableDataFlow.swift

@@ -15,19 +15,16 @@ enum DataTable {
         var id: String { rawValue }
         var id: String { rawValue }
 
 
         var name: String {
         var name: String {
-            var name: String = ""
             switch self {
             switch self {
             case .treatments:
             case .treatments:
-                name = "Treatments"
+                return String(localized: "Treatments", comment: "History Mode")
             case .meals:
             case .meals:
-                name = "Meals"
+                return String(localized: "Meals", comment: "History Mode")
             case .glucose:
             case .glucose:
-                name = "Glucose"
+                return String(localized: "Glucose", comment: "History Mode")
             case .adjustments:
             case .adjustments:
-                name = "Adjustments"
+                return String(localized: "Adjustments", comment: "History Mode")
             }
             }
-
-            return NSLocalizedString(name, comment: "History Mode")
         }
         }
     }
     }
 
 
@@ -41,25 +38,22 @@ enum DataTable {
         case resume
         case resume
 
 
         var name: String {
         var name: String {
-            var name: String = ""
             switch self {
             switch self {
             case .carbs:
             case .carbs:
-                name = "Carbs"
+                return String(localized: "Carbs", comment: "Treatment type")
             case .fpus:
             case .fpus:
-                name = "Protein / Fat"
+                return String(localized: "Protein / Fat", comment: "Treatment type")
             case .bolus:
             case .bolus:
-                name = "Bolus"
+                return String(localized: "Bolus", comment: "Treatment type")
             case .tempBasal:
             case .tempBasal:
-                name = "Temp Basal"
+                return String(localized: "Temp Basal", comment: "Treatment type")
             case .tempTarget:
             case .tempTarget:
-                name = "Temp Target"
+                return String(localized: "Temp Target", comment: "Treatment type")
             case .suspend:
             case .suspend:
-                name = "Suspend"
+                return String(localized: "Suspend", comment: "Treatment type")
             case .resume:
             case .resume:
-                name = "Resume"
+                return String(localized: "Resume", comment: "Treatment type")
             }
             }
-
-            return NSLocalizedString(name, comment: "Treatment type")
         }
         }
     }
     }
 
 
@@ -142,24 +136,24 @@ enum DataTable {
             switch type {
             switch type {
             case .carbs:
             case .carbs:
                 return numberFormatter
                 return numberFormatter
-                    .string(from: amount as NSNumber)! + NSLocalizedString(" g", comment: "gram of carbs")
+                    .string(from: amount as NSNumber)! + String(localized: " g", comment: "gram of carbs")
             case .fpus:
             case .fpus:
                 return numberFormatter
                 return numberFormatter
-                    .string(from: amount as NSNumber)! + NSLocalizedString(" g", comment: "gram of carb equilvalents")
+                    .string(from: amount as NSNumber)! + String(localized: " g", comment: "gram of carb equilvalents")
             case .bolus:
             case .bolus:
                 var bolusText = " "
                 var bolusText = " "
                 if isSMB ?? false {}
                 if isSMB ?? false {}
                 else if isExternal ?? false {
                 else if isExternal ?? false {
-                    bolusText += NSLocalizedString("External", comment: "External Insulin")
+                    bolusText += String(localized: "External", comment: "External Insulin")
                 } else {
                 } else {
-                    bolusText += NSLocalizedString("Manual", comment: "Manual Bolus")
+                    bolusText += String(localized: "Manual", comment: "Manual Bolus")
                 }
                 }
 
 
                 return numberFormatter
                 return numberFormatter
-                    .string(from: amount as NSNumber)! + NSLocalizedString(" U", comment: "Insulin unit") + bolusText
+                    .string(from: amount as NSNumber)! + String(localized: " U", comment: "Insulin unit") + bolusText
             case .tempBasal:
             case .tempBasal:
                 return numberFormatter
                 return numberFormatter
-                    .string(from: amount as NSNumber)! + NSLocalizedString(" U/hr", comment: "Unit insulin per hour")
+                    .string(from: amount as NSNumber)! + String(localized: " U/hr", comment: "Unit insulin per hour")
             case .tempTarget:
             case .tempTarget:
                 var converted = amount
                 var converted = amount
                 if units == .mmolL {
                 if units == .mmolL {

+ 15 - 15
Trio/Sources/Modules/DataTable/View/DataTableRootView.swift

@@ -227,7 +227,7 @@ extension DataTable {
             let overrides = overrideRunStored.map { override -> AdjustmentItem in
             let overrides = overrideRunStored.map { override -> AdjustmentItem in
                 AdjustmentItem(
                 AdjustmentItem(
                     id: override.objectID,
                     id: override.objectID,
-                    name: override.name ?? "Override",
+                    name: override.name ?? String(localized: "Override"),
                     startDate: override.startDate ?? Date(),
                     startDate: override.startDate ?? Date(),
                     endDate: override.endDate ?? Date(),
                     endDate: override.endDate ?? Date(),
                     target: override.target?.decimalValue,
                     target: override.target?.decimalValue,
@@ -238,7 +238,7 @@ extension DataTable {
             let tempTargets = tempTargetRunStored.map { tempTarget -> AdjustmentItem in
             let tempTargets = tempTargetRunStored.map { tempTarget -> AdjustmentItem in
                 AdjustmentItem(
                 AdjustmentItem(
                     id: tempTarget.objectID,
                     id: tempTarget.objectID,
-                    name: tempTarget.name ?? "Temp Target",
+                    name: tempTarget.name ?? String(localized: "Temp Target"),
                     startDate: tempTarget.startDate ?? Date(),
                     startDate: tempTarget.startDate ?? Date(),
                     endDate: tempTarget.endDate ?? Date(),
                     endDate: tempTarget.endDate ?? Date(),
                     target: tempTarget.target?.decimalValue,
                     target: tempTarget.target?.decimalValue,
@@ -367,7 +367,7 @@ extension DataTable {
                             ).tint(.red)
                             ).tint(.red)
                         }
                         }
                         .alert(
                         .alert(
-                            Text(NSLocalizedString(alertTitle, comment: "")),
+                            Text(alertTitle),
                             isPresented: $isRemoveHistoryItemAlertPresented
                             isPresented: $isRemoveHistoryItemAlertPresented
                         ) {
                         ) {
                             Button("Cancel", role: .cancel) {}
                             Button("Cancel", role: .cancel) {}
@@ -380,7 +380,7 @@ extension DataTable {
                                 state.invokeGlucoseDeletionTask(glucoseToDeleteObjectID)
                                 state.invokeGlucoseDeletionTask(glucoseToDeleteObjectID)
                             }
                             }
                         } message: {
                         } message: {
-                            Text("\n" + NSLocalizedString(alertMessage, comment: ""))
+                            Text("\n" + alertMessage)
                         }
                         }
                     }
                     }
                 } else {
                 } else {
@@ -482,18 +482,18 @@ extension DataTable {
                     Text(bolus.isSMB ? "SMB" : item.type ?? "Bolus")
                     Text(bolus.isSMB ? "SMB" : item.type ?? "Bolus")
                     Text(
                     Text(
                         (Formatter.decimalFormatterWithTwoFractionDigits.string(from: amount) ?? "0") +
                         (Formatter.decimalFormatterWithTwoFractionDigits.string(from: amount) ?? "0") +
-                            NSLocalizedString(" U", comment: "Insulin unit")
+                            String(localized: " U", comment: "Insulin unit")
                     )
                     )
                     .foregroundColor(.secondary)
                     .foregroundColor(.secondary)
                     if bolus.isExternal {
                     if bolus.isExternal {
-                        Text(NSLocalizedString("External", comment: "External Insulin")).foregroundColor(.secondary)
+                        Text(String(localized: "External", comment: "External Insulin")).foregroundColor(.secondary)
                     }
                     }
                 } else if let tempBasal = item.tempBasal, let rate = tempBasal.rate {
                 } else if let tempBasal = item.tempBasal, let rate = tempBasal.rate {
                     Image(systemName: "circle.fill").foregroundColor(Color.insulin.opacity(0.4))
                     Image(systemName: "circle.fill").foregroundColor(Color.insulin.opacity(0.4))
                     Text("Temp Basal")
                     Text("Temp Basal")
                     Text(
                     Text(
                         (Formatter.decimalFormatterWithTwoFractionDigits.string(from: rate) ?? "0") +
                         (Formatter.decimalFormatterWithTwoFractionDigits.string(from: rate) ?? "0") +
-                            NSLocalizedString(" U/hr", comment: "Unit insulin per hour")
+                            String(localized: " U/hr", comment: "Unit insulin per hour")
                     )
                     )
                     .foregroundColor(.secondary)
                     .foregroundColor(.secondary)
                     if tempBasal.duration > 0 {
                     if tempBasal.duration > 0 {
@@ -518,7 +518,7 @@ extension DataTable {
                             alertMessage = Formatter.dateFormatter
                             alertMessage = Formatter.dateFormatter
                                 .string(from: item.timestamp ?? Date()) + ", " +
                                 .string(from: item.timestamp ?? Date()) + ", " +
                                 (Formatter.decimalFormatterWithTwoFractionDigits.string(from: item.bolus?.amount ?? 0) ?? "0") +
                                 (Formatter.decimalFormatterWithTwoFractionDigits.string(from: item.bolus?.amount ?? 0) ?? "0") +
-                                NSLocalizedString(" U", comment: "Insulin unit")
+                                String(localized: " U", comment: "Insulin unit")
 
 
                             if let bolus = item.bolus {
                             if let bolus = item.bolus {
                                 // Add text snippet, so that alert message is more descriptive for SMBs
                                 // Add text snippet, so that alert message is more descriptive for SMBs
@@ -531,7 +531,7 @@ extension DataTable {
                 }
                 }
             }
             }
             .alert(
             .alert(
-                Text(NSLocalizedString(alertTitle, comment: "")),
+                Text(alertTitle),
                 isPresented: $isRemoveHistoryItemAlertPresented
                 isPresented: $isRemoveHistoryItemAlertPresented
             ) {
             ) {
                 Button("Cancel", role: .cancel) {}
                 Button("Cancel", role: .cancel) {}
@@ -545,7 +545,7 @@ extension DataTable {
                     state.invokeInsulinDeletionTask(treatmentObjectID)
                     state.invokeInsulinDeletionTask(treatmentObjectID)
                 }
                 }
             } message: {
             } message: {
-                Text("\n" + NSLocalizedString(alertMessage, comment: ""))
+                Text("\n" + alertMessage)
             }
             }
         }
         }
 
 
@@ -557,14 +557,14 @@ extension DataTable {
                         Text("Fat / Protein")
                         Text("Fat / Protein")
                         Text(
                         Text(
                             (Formatter.decimalFormatterWithTwoFractionDigits.string(for: meal.carbs) ?? "0") +
                             (Formatter.decimalFormatterWithTwoFractionDigits.string(for: meal.carbs) ?? "0") +
-                                NSLocalizedString(" g", comment: "gram of carbs")
+                                String(localized: " g", comment: "gram of carbs")
                         )
                         )
                     } else {
                     } else {
                         Image(systemName: "circle.fill").foregroundColor(Color.loopYellow)
                         Image(systemName: "circle.fill").foregroundColor(Color.loopYellow)
                         Text("Carbs")
                         Text("Carbs")
                         Text(
                         Text(
                             (Formatter.decimalFormatterWithTwoFractionDigits.string(for: meal.carbs) ?? "0") +
                             (Formatter.decimalFormatterWithTwoFractionDigits.string(for: meal.carbs) ?? "0") +
-                                NSLocalizedString(" g", comment: "gram of carb equilvalents")
+                                String(localized: " g", comment: "gram of carb equilvalents")
                         )
                         )
                     }
                     }
 
 
@@ -595,7 +595,7 @@ extension DataTable {
                             alertMessage = Formatter.dateFormatter
                             alertMessage = Formatter.dateFormatter
                                 .string(from: meal.date ?? Date()) + ", " +
                                 .string(from: meal.date ?? Date()) + ", " +
                                 (Formatter.decimalFormatterWithTwoFractionDigits.string(for: meal.carbs) ?? "0") +
                                 (Formatter.decimalFormatterWithTwoFractionDigits.string(for: meal.carbs) ?? "0") +
-                                NSLocalizedString(" g", comment: "gram of carbs")
+                                String(localized: " g", comment: "gram of carbs")
                         }
                         }
                         // meal is complex-meal or fpu-only
                         // meal is complex-meal or fpu-only
                         else {
                         else {
@@ -620,7 +620,7 @@ extension DataTable {
                 .disabled(!state.settingsManager.settings.useFPUconversion && meal.isFPU)
                 .disabled(!state.settingsManager.settings.useFPUconversion && meal.isFPU)
             }
             }
             .alert(
             .alert(
-                Text(NSLocalizedString(alertTitle, comment: "")),
+                Text(alertTitle),
                 isPresented: $isRemoveHistoryItemAlertPresented
                 isPresented: $isRemoveHistoryItemAlertPresented
             ) {
             ) {
                 Button("Cancel", role: .cancel) {}
                 Button("Cancel", role: .cancel) {}
@@ -637,7 +637,7 @@ extension DataTable {
                     )
                     )
                 }
                 }
             } message: {
             } message: {
-                Text("\n" + NSLocalizedString(alertMessage, comment: ""))
+                Text("\n" + alertMessage)
             }
             }
         }
         }
 
 

+ 28 - 26
Trio/Sources/Modules/DynamicSettings/View/DynamicSettingsRootView.swift

@@ -49,13 +49,15 @@ extension DynamicSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Activate Dynamic Sensitivity (Dynamic ISF)"
+                            hintLabel = String(localized: "Activate Dynamic Sensitivity (Dynamic ISF)")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: "Activate Dynamic ISF",
-                    miniHint: "Dynamically adjust insulin sensitivity using Dynamic Ratio rather than Autosens Ratio.",
+                    label: String(localized: "Activate Dynamic ISF"),
+                    miniHint: String(
+                        localized: "Dynamically adjust insulin sensitivity using Dynamic Ratio rather than Autosens Ratio."
+                    ),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: OFF").bold()
                         Text("Default: OFF").bold()
@@ -73,7 +75,7 @@ extension DynamicSettings {
                         )
                         )
                         .bold()
                         .bold()
                     },
                     },
-                    headerText: "Dynamic Settings"
+                    headerText: String(localized: "Dynamic Settings")
                 )
                 )
 
 
                 if state.useNewFormula {
                 if state.useNewFormula {
@@ -85,13 +87,13 @@ extension DynamicSettings {
                             get: { selectedVerboseHint },
                             get: { selectedVerboseHint },
                             set: {
                             set: {
                                 selectedVerboseHint = $0.map { AnyView($0) }
                                 selectedVerboseHint = $0.map { AnyView($0) }
-                                hintLabel = "Activate Dynamic CR (Carb Ratio)"
+                                hintLabel = String(localized: "Activate Dynamic CR (Carb Ratio)")
                             }
                             }
                         ),
                         ),
                         units: state.units,
                         units: state.units,
                         type: .boolean,
                         type: .boolean,
-                        label: "Activate Dynamic CR (Carb Ratio)",
-                        miniHint: "Dynamically adjust your Carb Ratio (CR).",
+                        label: String(localized: "Activate Dynamic CR (Carb Ratio)"),
+                        miniHint: String(localized: "Dynamically adjust your Carb Ratio (CR)."),
                         verboseHint:
                         verboseHint:
 
 
                         VStack(alignment: .leading, spacing: 10) {
                         VStack(alignment: .leading, spacing: 10) {
@@ -116,13 +118,13 @@ extension DynamicSettings {
                             get: { selectedVerboseHint },
                             get: { selectedVerboseHint },
                             set: {
                             set: {
                                 selectedVerboseHint = $0.map { AnyView($0) }
                                 selectedVerboseHint = $0.map { AnyView($0) }
-                                hintLabel = "Use Sigmoid Formula"
+                                hintLabel = String(localized: "Use Sigmoid Formula")
                             }
                             }
                         ),
                         ),
                         units: state.units,
                         units: state.units,
                         type: .boolean,
                         type: .boolean,
-                        label: "Use Sigmoid Formula",
-                        miniHint: "Adjust insulin sensitivity using a sigmoid-shaped curve.",
+                        label: String(localized: "Use Sigmoid Formula"),
+                        miniHint: String(localized: "Adjust insulin sensitivity using a sigmoid-shaped curve."),
                         verboseHint:
                         verboseHint:
                         VStack(alignment: .leading, spacing: 10) {
                         VStack(alignment: .leading, spacing: 10) {
                             Text("Default: OFF").bold()
                             Text("Default: OFF").bold()
@@ -152,14 +154,14 @@ extension DynamicSettings {
                                 get: { selectedVerboseHint },
                                 get: { selectedVerboseHint },
                                 set: {
                                 set: {
                                     selectedVerboseHint = $0.map { AnyView($0) }
                                     selectedVerboseHint = $0.map { AnyView($0) }
-                                    hintLabel = "Adjustment Factor (AF)"
+                                    hintLabel = String(localized: "Adjustment Factor (AF)")
                                 }
                                 }
                             ),
                             ),
                             // TODO?: include conditional links to Desmos logarithmic graphs based on which .glucose setting is used
                             // TODO?: include conditional links to Desmos logarithmic graphs based on which .glucose setting is used
                             units: state.units,
                             units: state.units,
                             type: .decimal("adjustmentFactor"),
                             type: .decimal("adjustmentFactor"),
-                            label: "Adjustment Factor (AF)",
-                            miniHint: "Alter the rate of Dynamic ISF (Sensitivity) adjustments.",
+                            label: String(localized: "Adjustment Factor (AF)"),
+                            miniHint: String(localized: "Alter the rate of Dynamic ISF (Sensitivity) adjustments."),
                             verboseHint:
                             verboseHint:
                             VStack(alignment: .leading, spacing: 10) {
                             VStack(alignment: .leading, spacing: 10) {
                                 Text("Default: 80%").bold()
                                 Text("Default: 80%").bold()
@@ -183,13 +185,13 @@ extension DynamicSettings {
                                 get: { selectedVerboseHint },
                                 get: { selectedVerboseHint },
                                 set: {
                                 set: {
                                     selectedVerboseHint = $0.map { AnyView($0) }
                                     selectedVerboseHint = $0.map { AnyView($0) }
-                                    hintLabel = "Sigmoid Adjustment Factor"
+                                    hintLabel = String(localized: "Sigmoid Adjustment Factor")
                                 }
                                 }
                             ),
                             ),
                             units: state.units,
                             units: state.units,
                             type: .decimal("adjustmentFactorSigmoid"),
                             type: .decimal("adjustmentFactorSigmoid"),
-                            label: "Sigmoid Adjustment Factor",
-                            miniHint: "Alter the rate of dynamic sensitivity adjustments for Sigmoid.",
+                            label: String(localized: "Sigmoid Adjustment Factor"),
+                            miniHint: String(localized: "Alter the rate of dynamic sensitivity adjustments for Sigmoid."),
                             verboseHint:
                             verboseHint:
                             VStack(alignment: .leading, spacing: 10) {
                             VStack(alignment: .leading, spacing: 10) {
                                 Text("Default: 50%").bold()
                                 Text("Default: 50%").bold()
@@ -217,13 +219,13 @@ extension DynamicSettings {
                             get: { selectedVerboseHint },
                             get: { selectedVerboseHint },
                             set: {
                             set: {
                                 selectedVerboseHint = $0.map { AnyView($0) }
                                 selectedVerboseHint = $0.map { AnyView($0) }
-                                hintLabel = "Weighted Average of TDD"
+                                hintLabel = String(localized: "Weighted Average of TDD")
                             }
                             }
                         ),
                         ),
                         units: state.units,
                         units: state.units,
                         type: .decimal("weightPercentage"),
                         type: .decimal("weightPercentage"),
-                        label: "Weighted Average of TDD",
-                        miniHint: "Weight of 24-hr TDD against 10-day TDD.",
+                        label: String(localized: "Weighted Average of TDD"),
+                        miniHint: String(localized: "Weight of 24-hr TDD against 10-day TDD."),
                         verboseHint:
                         verboseHint:
                         VStack(alignment: .leading, spacing: 10) {
                         VStack(alignment: .leading, spacing: 10) {
                             Text("Default: 35%").bold()
                             Text("Default: 35%").bold()
@@ -246,13 +248,13 @@ extension DynamicSettings {
                             get: { selectedVerboseHint },
                             get: { selectedVerboseHint },
                             set: {
                             set: {
                                 selectedVerboseHint = $0.map { AnyView($0) }
                                 selectedVerboseHint = $0.map { AnyView($0) }
-                                hintLabel = "Adjust Basal"
+                                hintLabel = String(localized: "Adjust Basal")
                             }
                             }
                         ),
                         ),
                         units: state.units,
                         units: state.units,
                         type: .boolean,
                         type: .boolean,
-                        label: "Adjust Basal",
-                        miniHint: "Use Dynamic Ratio to adjust basal rates.",
+                        label: String(localized: "Adjust Basal"),
+                        miniHint: String(localized: "Use Dynamic Ratio to adjust basal rates."),
                         verboseHint: VStack(alignment: .leading, spacing: 10) {
                         verboseHint: VStack(alignment: .leading, spacing: 10) {
                             Text("Default: OFF").bold()
                             Text("Default: OFF").bold()
                             Text(
                             Text(
@@ -274,13 +276,13 @@ extension DynamicSettings {
                             get: { selectedVerboseHint },
                             get: { selectedVerboseHint },
                             set: {
                             set: {
                                 selectedVerboseHint = $0.map { AnyView($0) }
                                 selectedVerboseHint = $0.map { AnyView($0) }
-                                hintLabel = "Minimum Safety Threshold"
+                                hintLabel = String(localized: "Minimum Safety Threshold")
                             }
                             }
                         ),
                         ),
                         units: state.units,
                         units: state.units,
                         type: .decimal("threshold_setting"),
                         type: .decimal("threshold_setting"),
-                        label: "Minimum Safety Threshold",
-                        miniHint: "Increase the safety threshold used to suspend insulin delivery.",
+                        label: String(localized: "Minimum Safety Threshold"),
+                        miniHint: String(localized: "Increase the safety threshold used to suspend insulin delivery."),
                         verboseHint:
                         verboseHint:
                         VStack(alignment: .leading, spacing: 10) {
                         VStack(alignment: .leading, spacing: 10) {
                             Text("Default: Set by Algorithm").bold()
                             Text("Default: Set by Algorithm").bold()
@@ -321,7 +323,7 @@ extension DynamicSettings {
                     shouldDisplayHint: $shouldDisplayHint,
                     shouldDisplayHint: $shouldDisplayHint,
                     hintLabel: hintLabel ?? "",
                     hintLabel: hintLabel ?? "",
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
-                    sheetTitle: "Help"
+                    sheetTitle: String(localized: "Help", comment: "Help sheet title")
                 )
                 )
             }
             }
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))

+ 12 - 12
Trio/Sources/Modules/GeneralSettings/View/UnitsLimitsSettingsRootView.swift

@@ -36,12 +36,12 @@ extension UnitsLimitsSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Max IOB", comment: "Max IOB")
+                            hintLabel = String(localized: "Max IOB", comment: "Max IOB")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("maxIOB"),
                     type: .decimal("maxIOB"),
-                    label: NSLocalizedString("Max IOB", comment: "Max IOB"),
+                    label: String(localized: "Max IOB", comment: "Max IOB"),
                     miniHint: "Maximum units of insulin allowed to be active.",
                     miniHint: "Maximum units of insulin allowed to be active.",
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
@@ -69,13 +69,13 @@ extension UnitsLimitsSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Max Bolus"
+                            hintLabel = String(localized: "Max Bolus")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("maxBolus"),
                     type: .decimal("maxBolus"),
-                    label: "Max Bolus",
-                    miniHint: "Largest bolus of insulin allowed.",
+                    label: String(localized: "Max Bolus"),
+                    miniHint: String(localized: "Largest bolus of insulin allowed."),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: 10 units").bold()
                         Text("Default: 10 units").bold()
@@ -95,13 +95,13 @@ extension UnitsLimitsSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Max Basal"
+                            hintLabel = String(localized: "Max Basal")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("maxBasal"),
                     type: .decimal("maxBasal"),
-                    label: "Max Basal",
-                    miniHint: "Largest basal rate allowed.",
+                    label: String(localized: "Max Basal"),
+                    miniHint: String(localized: "Largest basal rate allowed."),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: 2 units").bold()
                         Text("Default: 2 units").bold()
@@ -122,13 +122,13 @@ extension UnitsLimitsSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = NSLocalizedString("Max COB", comment: "Max COB")
+                            hintLabel = String(localized: "Max COB", comment: "Max COB")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .decimal("maxCOB"),
                     type: .decimal("maxCOB"),
-                    label: NSLocalizedString("Max COB", comment: "Max COB"),
-                    miniHint: "Maximum Carbs On Board (COB) allowed.",
+                    label: String(localized: "Max COB", comment: "Max COB"),
+                    miniHint: String(localized: "Maximum Carbs On Board (COB) allowed."),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: 120 grams of carbs").bold()
                         Text("Default: 120 grams of carbs").bold()
@@ -149,7 +149,7 @@ extension UnitsLimitsSettings {
                     shouldDisplayHint: $shouldDisplayHint,
                     shouldDisplayHint: $shouldDisplayHint,
                     hintLabel: hintLabel ?? "",
                     hintLabel: hintLabel ?? "",
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
-                    sheetTitle: "Help"
+                    sheetTitle: String(localized: "Help", comment: "Help sheet title")
                 )
                 )
             }
             }
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))

+ 26 - 26
Trio/Sources/Modules/GlucoseNotificationSettings/View/GlucoseNotificationSettingsRootView.swift

@@ -48,13 +48,13 @@ extension GlucoseNotificationSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Play Alarm Sound"
+                            hintLabel = String(localized: "Play Alarm Sound")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: "Play Alarm Sound",
-                    miniHint: "Alarm with every Trio notification.",
+                    label: String(localized: "Play Alarm Sound"),
+                    miniHint: String(localized: "Alarm with every Trio notification."),
                     verboseHint: VStack(alignment: .leading, spacing: 10) {
                     verboseHint: VStack(alignment: .leading, spacing: 10) {
                         Text("Default: OFF").bold()
                         Text("Default: OFF").bold()
                         Text(
                         Text(
@@ -70,13 +70,13 @@ extension GlucoseNotificationSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Always Notify Pump"
+                            hintLabel = String(localized: "Always Notify Pump")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: "Always Notify Pump",
-                    miniHint: "Always Notify Pump Warnings.",
+                    label: String(localized: "Always Notify Pump"),
+                    miniHint: String(localized: "Always Notify Pump Warnings."),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: ON").bold()
                         Text("Default: ON").bold()
@@ -86,7 +86,7 @@ extension GlucoseNotificationSettings {
                         Text("If iOS Trio Notifications is disabled, Trio will display these messages in-app as a banner only.")
                         Text("If iOS Trio Notifications is disabled, Trio will display these messages in-app as a banner only.")
                         Text("An example of a Pump Warning is 'Pod Expiration Reminder'")
                         Text("An example of a Pump Warning is 'Pod Expiration Reminder'")
                     },
                     },
-                    headerText: "Trio Information Notifications"
+                    headerText: String(localized: "Trio Information Notifications")
                 )
                 )
                 SettingInputSection(
                 SettingInputSection(
                     decimalValue: $decimalPlaceholder,
                     decimalValue: $decimalPlaceholder,
@@ -96,13 +96,13 @@ extension GlucoseNotificationSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Always Notify CGM"
+                            hintLabel = String(localized: "Always Notify CGM")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: "Always Notify CGM",
-                    miniHint: "Always Notify CGM Warnings.",
+                    label: String(localized: "Always Notify CGM"),
+                    miniHint: String(localized: "Always Notify CGM Warnings."),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: ON").bold()
                         Text("Default: ON").bold()
@@ -121,13 +121,13 @@ extension GlucoseNotificationSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Always Notify Carb"
+                            hintLabel = String(localized: "Always Notify Carb")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: "Always Notify Carb",
-                    miniHint: "Always Notify Carb Warnings.",
+                    label: String(localized: "Always Notify Carb"),
+                    miniHint: String(localized: "Always Notify Carb Warnings."),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: ON").bold()
                         Text("Default: ON").bold()
@@ -146,13 +146,13 @@ extension GlucoseNotificationSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Always Notify Algorithm"
+                            hintLabel = String(localized: "Always Notify Algorithm")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: "Always Notify Algorithm",
-                    miniHint: "Always Notify Algorithm Warnings.",
+                    label: String(localized: "Always Notify Algorithm"),
+                    miniHint: String(localized: "Always Notify Algorithm Warnings."),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: ON").bold()
                         Text("Default: ON").bold()
@@ -174,20 +174,20 @@ extension GlucoseNotificationSettings {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Show Glucose App Badge"
+                            hintLabel = String(localized: "Show Glucose App Badge")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: "Show Glucose App Badge",
-                    miniHint: "Show your current glucose on Trio app icon.",
+                    label: String(localized: "Show Glucose App Badge"),
+                    miniHint: String(localized: "Show your current glucose on Trio app icon."),
                     verboseHint: VStack(alignment: .leading, spacing: 10) {
                     verboseHint: VStack(alignment: .leading, spacing: 10) {
                         Text("Default: OFF").bold()
                         Text("Default: OFF").bold()
                         Text(
                         Text(
                             "This will add your current glucose on the top right of your Trio icon as a red notification badge. Changing setting takes effect on next Glucose reading."
                             "This will add your current glucose on the top right of your Trio icon as a red notification badge. Changing setting takes effect on next Glucose reading."
                         )
                         )
                     },
                     },
-                    headerText: "Various Glucose Notifications"
+                    headerText: String(localized: "Various Glucose Notifications")
                 )
                 )
 
 
                 Section {
                 Section {
@@ -211,7 +211,7 @@ extension GlucoseNotificationSettings {
                             Spacer()
                             Spacer()
                             Button(
                             Button(
                                 action: {
                                 action: {
-                                    hintLabel = "Glucose Notifications"
+                                    hintLabel = String(localized: "Glucose Notifications")
                                     selectedVerboseHint =
                                     selectedVerboseHint =
                                         AnyView(
                                         AnyView(
                                             VStack(alignment: .leading, spacing: 10) {
                                             VStack(alignment: .leading, spacing: 10) {
@@ -258,13 +258,13 @@ extension GlucoseNotificationSettings {
                             get: { selectedVerboseHint },
                             get: { selectedVerboseHint },
                             set: {
                             set: {
                                 selectedVerboseHint = $0.map { AnyView($0) }
                                 selectedVerboseHint = $0.map { AnyView($0) }
-                                hintLabel = "Add Glucose Source to Alarm"
+                                hintLabel = String(localized: "Add Glucose Source to Alarm")
                             }
                             }
                         ),
                         ),
                         units: state.units,
                         units: state.units,
                         type: .boolean,
                         type: .boolean,
-                        label: "Add Glucose Source to Alarm",
-                        miniHint: "Source of the glucose reading will be added to the notification.",
+                        label: String(localized: "Add Glucose Source to Alarm"),
+                        miniHint: String(localized: "Source of the glucose reading will be added to the notification."),
                         verboseHint: VStack(alignment: .leading, spacing: 10) {
                         verboseHint: VStack(alignment: .leading, spacing: 10) {
                             Text("Default: OFF").bold()
                             Text("Default: OFF").bold()
                             Text("The source of the glucose reading will be added to the notification.")
                             Text("The source of the glucose reading will be added to the notification.")
@@ -279,7 +279,7 @@ extension GlucoseNotificationSettings {
                     shouldDisplayHint: $shouldDisplayHint,
                     shouldDisplayHint: $shouldDisplayHint,
                     hintLabel: hintLabel ?? "",
                     hintLabel: hintLabel ?? "",
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
-                    sheetTitle: "Help"
+                    sheetTitle: String(localized: "Help", comment: "Help sheet title")
                 )
                 )
             }
             }
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))
@@ -374,7 +374,7 @@ extension GlucoseNotificationSettings {
                         Spacer()
                         Spacer()
                         Button(
                         Button(
                             action: {
                             action: {
-                                hintLabel = "Low and High Glucose Alarm Limits"
+                                hintLabel = String(localized: "Low and High Glucose Alarm Limits")
                                 selectedVerboseHint =
                                 selectedVerboseHint =
                                     AnyView(VStack(alignment: .leading, spacing: 10) {
                                     AnyView(VStack(alignment: .leading, spacing: 10) {
                                         let low: Decimal = 70
                                         let low: Decimal = 70

+ 5 - 5
Trio/Sources/Modules/HealthKit/View/AppleHealthKitRootView.swift

@@ -26,20 +26,20 @@ extension AppleHealthKit {
                         get: { selectedVerboseHint },
                         get: { selectedVerboseHint },
                         set: {
                         set: {
                             selectedVerboseHint = $0.map { AnyView($0) }
                             selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Connect to Apple Health"
+                            hintLabel = String(localized: "Connect to Apple Health")
                         }
                         }
                     ),
                     ),
                     units: state.units,
                     units: state.units,
                     type: .boolean,
                     type: .boolean,
-                    label: "Connect to Apple Health",
-                    miniHint: "Allow Trio to read from and write to Apple Health.",
+                    label: String(localized: "Connect to Apple Health"),
+                    miniHint: String(localized: "Allow Trio to read from and write to Apple Health."),
                     verboseHint:
                     verboseHint:
                     VStack(alignment: .leading, spacing: 10) {
                     VStack(alignment: .leading, spacing: 10) {
                         Text("Default: OFF").bold()
                         Text("Default: OFF").bold()
                         Text("This allows Trio to read from and write to Apple Health.")
                         Text("This allows Trio to read from and write to Apple Health.")
                         Text("Warning: You must also give permissions in iOS System Settings for the Health app.").bold()
                         Text("Warning: You must also give permissions in iOS System Settings for the Health app.").bold()
                     },
                     },
-                    headerText: "Apple Health Integration"
+                    headerText: String(localized: "Apple Health Integration")
                 )
                 )
 
 
                 if !state.needShowInformationTextForSetPermissions {
                 if !state.needShowInformationTextForSetPermissions {
@@ -71,7 +71,7 @@ extension AppleHealthKit {
                     shouldDisplayHint: $shouldDisplayHint,
                     shouldDisplayHint: $shouldDisplayHint,
                     hintLabel: hintLabel ?? "",
                     hintLabel: hintLabel ?? "",
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
                     hintText: selectedVerboseHint ?? AnyView(EmptyView()),
-                    sheetTitle: "Help"
+                    sheetTitle: String(localized: "Help", comment: "Help sheet title")
                 )
                 )
             }
             }
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))

+ 1 - 1
Trio/Sources/Modules/Home/HomeStateModel+Setup/DeterminationSetup.swift

@@ -43,7 +43,7 @@ extension Home.StateModel {
             batchSize: 50,
             batchSize: 50,
             propertiesToFetch: ["cob", "iob", "deliverAt", "objectID"]
             propertiesToFetch: ["cob", "iob", "deliverAt", "objectID"]
         )
         )
-        
+
         return await determinationFetchContext.perform {
         return await determinationFetchContext.perform {
             guard let fetchedResults = results as? [[String: Any]] else {
             guard let fetchedResults = results as? [[String: Any]] else {
                 return []
                 return []

+ 9 - 5
Trio/Sources/Modules/Home/HomeStateModel.swift

@@ -454,12 +454,16 @@ extension Home {
         }
         }
 
 
         func deleteCGM() {
         func deleteCGM() {
-            shouldDisplayCGMSetupSheet = false
-
-            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
+            fetchGlucoseManager.performOnCGMManagerQueue {
+                // Call plugin functionality on the manager queue (or at least attempt to)
                 self.fetchGlucoseManager?.deleteGlucoseSource()
                 self.fetchGlucoseManager?.deleteGlucoseSource()
-                self.completionNotifyingDidComplete(CGMDeletionCompletionNotifying())
-            })
+
+                // UI updates go back to Main
+                DispatchQueue.main.async {
+                    self.shouldDisplayCGMSetupSheet = false
+                    self.completionNotifyingDidComplete(CGMDeletionCompletionNotifying())
+                }
+            }
         }
         }
 
 
         /// Display the eventual status message provided by the manager of the pump
         /// Display the eventual status message provided by the manager of the pump

+ 2 - 2
Trio/Sources/Modules/Home/View/Chart/ChartElements/SelectionPopoverView.swift

@@ -80,7 +80,7 @@ struct SelectionPopoverView: ChartContent {
                     Image(systemName: "syringe.fill").frame(width: 15)
                     Image(systemName: "syringe.fill").frame(width: 15)
                     Text(Formatter.bolusFormatter.string(from: iob) ?? "")
                     Text(Formatter.bolusFormatter.string(from: iob) ?? "")
                         .bold()
                         .bold()
-                        + Text(NSLocalizedString(" U", comment: "Insulin unit"))
+                        + Text(String(localized: " U", comment: "Insulin unit"))
                 }
                 }
                 .foregroundStyle(Color.insulin).font(.body)
                 .foregroundStyle(Color.insulin).font(.body)
             }
             }
@@ -90,7 +90,7 @@ struct SelectionPopoverView: ChartContent {
                     Image(systemName: "fork.knife").frame(width: 15)
                     Image(systemName: "fork.knife").frame(width: 15)
                     Text(Formatter.integerFormatter.string(from: selectedCOBValue.cob as NSNumber) ?? "")
                     Text(Formatter.integerFormatter.string(from: selectedCOBValue.cob as NSNumber) ?? "")
                         .bold()
                         .bold()
-                        + Text(NSLocalizedString(" g", comment: "gram of carbs"))
+                        + Text(String(localized: " g", comment: "gram of carbs"))
                 }
                 }
                 .foregroundStyle(Color.orange).font(.body)
                 .foregroundStyle(Color.orange).font(.body)
             }
             }

+ 17 - 17
Trio/Sources/Modules/Home/View/Chart/ChartLegendView.swift

@@ -38,7 +38,7 @@ struct ChartLegendView: View {
                         Text("Other Elements & Shapes").bold().padding(.bottom, 5).textCase(.uppercase)
                         Text("Other Elements & Shapes").bold().padding(.bottom, 5).textCase(.uppercase)
 
 
                         DefinitionRow(
                         DefinitionRow(
-                            term: "Scheduled Basal Rate",
+                            term: String(localized: "Scheduled Basal Rate"),
                             definition: VStack(alignment: .leading, spacing: 10) {
                             definition: VStack(alignment: .leading, spacing: 10) {
                                 Text("This dotted line represents the hourly insulin rate of your scheduled basal insulin.")
                                 Text("This dotted line represents the hourly insulin rate of your scheduled basal insulin.")
                                 Text("To review or change your scheduled basal rates, go to Settings > Therapy > Basal Rates.")
                                 Text("To review or change your scheduled basal rates, go to Settings > Therapy > Basal Rates.")
@@ -48,7 +48,7 @@ struct ChartLegendView: View {
                         )
                         )
 
 
                         DefinitionRow(
                         DefinitionRow(
-                            term: "Temporary Basal Rate (TBR)",
+                            term: String(localized: "Temporary Basal Rate (TBR)"),
                             definition: Text(
                             definition: Text(
                                 "Shows current or past TBRs, which can be set by the oref algorithm or manually."
                                 "Shows current or past TBRs, which can be set by the oref algorithm or manually."
                             ),
                             ),
@@ -57,14 +57,14 @@ struct ChartLegendView: View {
                         )
                         )
 
 
                         DefinitionRow(
                         DefinitionRow(
-                            term: "Pump Suspension",
+                            term: String(localized: "Pump Suspension"),
                             definition: Text("Indicates when insulin delivery was paused, i.e. pump is suspended."),
                             definition: Text("Indicates when insulin delivery was paused, i.e. pump is suspended."),
                             color: Color.loopGray.opacity(colorScheme == .dark ? 0.3 : 0.8),
                             color: Color.loopGray.opacity(colorScheme == .dark ? 0.3 : 0.8),
                             iconString: "square.fill"
                             iconString: "square.fill"
                         )
                         )
 
 
                         DefinitionRow(
                         DefinitionRow(
-                            term: "CGM Glucose Value",
+                            term: String(localized: "CGM Glucose Value"),
                             definition: VStack(alignment: .leading, spacing: 10) {
                             definition: VStack(alignment: .leading, spacing: 10) {
                                 if state.settingsManager.settings.smoothGlucose {
                                 if state.settingsManager.settings.smoothGlucose {
                                     Text(
                                     Text(
@@ -92,14 +92,14 @@ struct ChartLegendView: View {
                         )
                         )
 
 
                         DefinitionRow(
                         DefinitionRow(
-                            term: "Manual Glucose Measurement",
+                            term: String(localized: "Manual Glucose Measurement"),
                             definition: Text("Manually entered blood glucose, such as a fingerstick test."),
                             definition: Text("Manually entered blood glucose, such as a fingerstick test."),
                             color: Color.red,
                             color: Color.red,
                             iconString: "drop.fill"
                             iconString: "drop.fill"
                         )
                         )
 
 
                         DefinitionRow(
                         DefinitionRow(
-                            term: "Bolus",
+                            term: String(localized: "Bolus"),
                             definition: Text(
                             definition: Text(
                                 "Shows an insulin dose, which can be a small automated dose (super-micro-bolus), a manually entered dose, or one given externally (e.g., a pen shot)."
                                 "Shows an insulin dose, which can be a small automated dose (super-micro-bolus), a manually entered dose, or one given externally (e.g., a pen shot)."
                             ),
                             ),
@@ -108,7 +108,7 @@ struct ChartLegendView: View {
                         )
                         )
 
 
                         DefinitionRow(
                         DefinitionRow(
-                            term: "Carb Entry",
+                            term: String(localized: "Carb Entry"),
                             definition: Text("Tracks the carbohydrates you eat, entered to guide insulin dosing."),
                             definition: Text("Tracks the carbohydrates you eat, entered to guide insulin dosing."),
                             color: Color.orange,
                             color: Color.orange,
                             iconString: "arrowtriangle.down.fill",
                             iconString: "arrowtriangle.down.fill",
@@ -116,7 +116,7 @@ struct ChartLegendView: View {
                         )
                         )
 
 
                         DefinitionRow(
                         DefinitionRow(
-                            term: "Fat-Protein Carb Equivalent",
+                            term: String(localized: "Fat-Protein Carb Equivalent"),
                             definition: VStack(alignment: .leading, spacing: 10) {
                             definition: VStack(alignment: .leading, spacing: 10) {
                                 Text(
                                 Text(
                                     "Represents carb equivalent for fat and protein, calculated using the Warsaw Method."
                                     "Represents carb equivalent for fat and protein, calculated using the Warsaw Method."
@@ -130,7 +130,7 @@ struct ChartLegendView: View {
                         )
                         )
 
 
                         DefinitionRow(
                         DefinitionRow(
-                            term: "Override",
+                            term: String(localized: "Override"),
                             definition: Text(
                             definition: Text(
                                 "Indicates when an override is or was active, temporarily changing therapy settings (e.g., basal rate, insulin sensitivity, carb ratio, target glucose, or whether Trio can dose SMBs)."
                                 "Indicates when an override is or was active, temporarily changing therapy settings (e.g., basal rate, insulin sensitivity, carb ratio, target glucose, or whether Trio can dose SMBs)."
                             ),
                             ),
@@ -139,7 +139,7 @@ struct ChartLegendView: View {
                         )
                         )
 
 
                         DefinitionRow(
                         DefinitionRow(
-                            term: "Temporary Target",
+                            term: String(localized: "Temporary Target"),
                             definition: Text(
                             definition: Text(
                                 "Marks when a short-term temporary glucose target is or was active, (potentially) altering when or how much insulin is delivered."
                                 "Marks when a short-term temporary glucose target is or was active, (potentially) altering when or how much insulin is delivered."
                             ),
                             ),
@@ -148,7 +148,7 @@ struct ChartLegendView: View {
                         )
                         )
 
 
                         DefinitionRow(
                         DefinitionRow(
-                            term: "Past Insulin-on-Board (IOB)",
+                            term: String(localized: "Past Insulin-on-Board (IOB)"),
                             definition: Text(
                             definition: Text(
                                 "Shows the IOB value calculated by the algorithm at a specific time in the past. These values are snapshots and won’t change if insulin is added or removed after the fact."
                                 "Shows the IOB value calculated by the algorithm at a specific time in the past. These values are snapshots and won’t change if insulin is added or removed after the fact."
                             ),
                             ),
@@ -157,7 +157,7 @@ struct ChartLegendView: View {
                         )
                         )
 
 
                         DefinitionRow(
                         DefinitionRow(
-                            term: "Past Carbs-on-Board (COB)",
+                            term: String(localized: "Past Carbs-on-Board (COB)"),
                             definition: Text(
                             definition: Text(
                                 "Shows the COB value calculated by the algorithm at a specific time in the past. These values are snapshots and won’t change if carbs are added or removed after the fact."
                                 "Shows the COB value calculated by the algorithm at a specific time in the past. These values are snapshots and won’t change if carbs are added or removed after the fact."
                             ),
                             ),
@@ -192,7 +192,7 @@ struct ChartLegendView: View {
     var legendLinesView: some View {
     var legendLinesView: some View {
         Group {
         Group {
             DefinitionRow(
             DefinitionRow(
-                term: "IOB (Insulin on Board)",
+                term: String(localized: "IOB (Insulin on Board)"),
                 definition: Text(
                 definition: Text(
                     "Forecasts future glucose readings based on the amount of insulin still active in the body."
                     "Forecasts future glucose readings based on the amount of insulin still active in the body."
                 ),
                 ),
@@ -200,7 +200,7 @@ struct ChartLegendView: View {
             )
             )
 
 
             DefinitionRow(
             DefinitionRow(
-                term: "ZT (Zero-Temp)",
+                term: String(localized: "ZT (Zero-Temp)"),
                 definition: Text(
                 definition: Text(
                     "Forecasts the worst-case future glucose reading scenario if no carbs are absorbed and insulin delivery is stopped until glucose starts rising."
                     "Forecasts the worst-case future glucose reading scenario if no carbs are absorbed and insulin delivery is stopped until glucose starts rising."
                 ),
                 ),
@@ -208,7 +208,7 @@ struct ChartLegendView: View {
             )
             )
 
 
             DefinitionRow(
             DefinitionRow(
-                term: "COB (Carbs on Board)",
+                term: String(localized: "COB (Carbs on Board)"),
                 definition: Text(
                 definition: Text(
                     "Forecasts future glucose reading changes by considering the amount of carbohydrates still being absorbed in the body."
                     "Forecasts future glucose reading changes by considering the amount of carbohydrates still being absorbed in the body."
                 ),
                 ),
@@ -216,7 +216,7 @@ struct ChartLegendView: View {
             )
             )
 
 
             DefinitionRow(
             DefinitionRow(
-                term: "UAM (Unannounced Meal)",
+                term: String(localized: "UAM (Unannounced Meal)"),
                 definition: Text(
                 definition: Text(
                     "Forecasts future glucose levels and insulin dosing needs for unexpected meals or other causes of glucose reading increases without prior notice."
                     "Forecasts future glucose levels and insulin dosing needs for unexpected meals or other causes of glucose reading increases without prior notice."
                 ),
                 ),
@@ -227,7 +227,7 @@ struct ChartLegendView: View {
 
 
     var legendConeOfUncertaintyView: some View {
     var legendConeOfUncertaintyView: some View {
         DefinitionRow(
         DefinitionRow(
-            term: "Cone of Uncertainty",
+            term: String(localized: "Cone of Uncertainty"),
             definition: VStack(alignment: .leading, spacing: 10) {
             definition: VStack(alignment: .leading, spacing: 10) {
                 Text(
                 Text(
                     "For simplicity reasons, oref's various forecast curves are displayed as a \"Cone of Uncertainty\" that depicts a possible, forecasted range of future glucose fluctuation based on the current data and the algothim's result."
                     "For simplicity reasons, oref's various forecast curves are displayed as a \"Cone of Uncertainty\" that depicts a possible, forecasted range of future glucose fluctuation based on the current data and the algothim's result."

+ 2 - 2
Trio/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift

@@ -93,9 +93,9 @@ struct CurrentGlucoseView: View {
                         let minutesAgo = -1 * (glucose.last?.date?.timeIntervalSinceNow ?? 0) / 60
                         let minutesAgo = -1 * (glucose.last?.date?.timeIntervalSinceNow ?? 0) / 60
                         let text = timaAgoFormatter.string(for: Double(minutesAgo)) ?? ""
                         let text = timaAgoFormatter.string(for: Double(minutesAgo)) ?? ""
                         Text(
                         Text(
-                            minutesAgo <= 1 ? "< 1 " + NSLocalizedString("min", comment: "Short form for minutes") : (
+                            minutesAgo <= 1 ? "< 1 " + String(localized: "min", comment: "Short form for minutes") : (
                                 text + " " +
                                 text + " " +
-                                    NSLocalizedString("min", comment: "Short form for minutes") + " "
+                                    String(localized: "min", comment: "Short form for minutes") + " "
                             )
                             )
                         )
                         )
                         .font(.caption2).foregroundStyle(colorScheme == .dark ? Color.white.opacity(0.9) : Color.secondary)
                         .font(.caption2).foregroundStyle(colorScheme == .dark ? Color.white.opacity(0.9) : Color.secondary)

+ 0 - 0
Trio/Sources/Modules/Home/View/Header/LoopStatusHelpView.swift


Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů