Browse Source

Implement contactTrickStorage methods; adjust manager WIP

Deniz Cengiz 1 năm trước cách đây
mục cha
commit
535a3cb73c

+ 4 - 0
FreeAPS.xcodeproj/project.pbxproj

@@ -466,6 +466,7 @@
 		DD9ECB722CA9A0BA00AA7C45 /* RemoteControlConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9ECB6F2CA9A0BA00AA7C45 /* RemoteControlConfigDataFlow.swift */; };
 		DD9ECB742CA9A0C300AA7C45 /* RemoteControlConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9ECB732CA9A0C300AA7C45 /* RemoteControlConfig.swift */; };
 		DDB37CC52D05048F00D99BF4 /* ContactTrickStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB37CC42D05048F00D99BF4 /* ContactTrickStorage.swift */; };
+		DDB37CC72D05127500D99BF4 /* FontExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB37CC62D05127500D99BF4 /* FontExtensions.swift */; };
 		DDCEBF5B2CC1B76400DF4C36 /* LiveActivity+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCEBF5A2CC1B76400DF4C36 /* LiveActivity+Helper.swift */; };
 		DDD163122C4C689900CD525A /* OverrideStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD163112C4C689900CD525A /* OverrideStateModel.swift */; };
 		DDD163142C4C68D300CD525A /* OverrideProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD163132C4C68D300CD525A /* OverrideProvider.swift */; };
@@ -1157,6 +1158,7 @@
 		DDB37CC22D05044D00D99BF4 /* ContactTrickEntryStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactTrickEntryStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		DDB37CC32D05044D00D99BF4 /* ContactTrickEntryStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactTrickEntryStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
 		DDB37CC42D05048F00D99BF4 /* ContactTrickStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactTrickStorage.swift; sourceTree = "<group>"; };
+		DDB37CC62D05127500D99BF4 /* FontExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontExtensions.swift; sourceTree = "<group>"; };
 		DDCEBF5A2CC1B76400DF4C36 /* LiveActivity+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LiveActivity+Helper.swift"; sourceTree = "<group>"; };
 		DDD163112C4C689900CD525A /* OverrideStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideStateModel.swift; sourceTree = "<group>"; };
 		DDD163132C4C68D300CD525A /* OverrideProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideProvider.swift; sourceTree = "<group>"; };
@@ -2083,6 +2085,7 @@
 		38A504F625DDA0E200C5B9E8 /* Extensions */ = {
 			isa = PBXGroup;
 			children = (
+				DDB37CC62D05127500D99BF4 /* FontExtensions.swift */,
 				38A5049125DD9C4000C5B9E8 /* UserDefaultsExtensions.swift */,
 				38BF021625E7CBBC00579895 /* PumpManagerExtensions.swift */,
 				CEB434E628B9053300B70274 /* LoopUIColorPalette+Default.swift */,
@@ -3639,6 +3642,7 @@
 				BDF34EBE2C0A31D100D51995 /* CustomNotification.swift in Sources */,
 				BDC2EA472C3045AD00E5BBD0 /* Override.swift in Sources */,
 				1BBB001DAD60F3B8CEA4B1C7 /* ISFEditorStateModel.swift in Sources */,
+				DDB37CC72D05127500D99BF4 /* FontExtensions.swift in Sources */,
 				582DF9772C8CDBE7001F516D /* InsulinView.swift in Sources */,
 				F816826028DB441800054060 /* BluetoothTransmitter.swift in Sources */,
 				DD68889D2C386E17006E3C44 /* NightscoutExercise.swift in Sources */,

+ 83 - 0
FreeAPS/Sources/APS/Extensions/FontExtensions.swift

@@ -0,0 +1,83 @@
+import SwiftUI
+
+extension Font.Weight {
+    var displayName: String {
+        switch self {
+        case .light: return "Light"
+        case .regular: return "Regular"
+        case .medium: return "Medium"
+        case .bold: return "Bold"
+        default: return "Unknown"
+        }
+    }
+
+    private static let stringToFontWeight: [String: Font.Weight] = [
+        "ultraLight": .ultraLight,
+        "thin": .thin,
+        "light": .light,
+        "regular": .regular,
+        "medium": .medium,
+        "semibold": .semibold,
+        "bold": .bold,
+        "heavy": .heavy,
+        "black": .black
+    ]
+
+    private static let fontWeightToString: [Font.Weight: String] = [
+        .ultraLight: "ultraLight",
+        .thin: "thin",
+        .light: "light",
+        .regular: "regular",
+        .medium: "medium",
+        .semibold: "semibold",
+        .bold: "bold",
+        .heavy: "heavy",
+        .black: "black"
+    ]
+
+    /// Initialize `Font.Weight` from a string
+    static func fromString(_ string: String) -> Font.Weight {
+        stringToFontWeight[string] ?? .regular // Default fallback
+    }
+
+    /// Convert `Font.Weight` to a string
+    var asString: String {
+        Font.Weight.fontWeightToString[self] ?? "regular" // Default fallback
+    }
+}
+
+extension Font.Width {
+    var displayName: String {
+        switch self {
+        case .condensed: return "Condensed"
+        case .expanded: return "Expanded"
+        case .compressed: return "Compressed"
+        case .standard: return "Standard"
+        default: return "Unknown"
+        }
+    }
+
+    private static let stringToFontWidth: [String: Font.Width] = [
+        "compressed": .compressed,
+        "condensed": .condensed,
+        "standard": .standard,
+        "expanded": .expanded
+    ]
+
+    private static let fontWidthToString: [Font.Width: String] = [
+        .compressed: "compressed",
+        .condensed: "condensed",
+        .standard: "standard",
+        .expanded: "expanded"
+    ]
+
+    /// Initialize `Font.Width` from a string
+    static func fromString(_ string: String) -> Font.Width {
+        stringToFontWidth[string] ?? .standard // Default fallback
+    }
+
+    /// Convert `Font.Width` to a string
+    var asString: String {
+        Font.Width.fontWidthToString[self] ?? "standard" // Default fallback
+    }
+}

+ 61 - 8
FreeAPS/Sources/APS/Storage/ContactTrickStorage.swift

@@ -1,9 +1,10 @@
 import CoreData
 import Foundation
+import SwiftUI
 import Swinject
 
 protocol ContactTrickStorage {
-    func fetchContactTrickEntryIds() async -> [NSManagedObjectID]
+    func fetchContactTrickEntries() async -> [ContactTrickEntry]
     func storeContactTrickEntry(_ entry: ContactTrickEntry) async
     func deleteContactTrickEntry(_ objectID: NSManagedObjectID) async
 }
@@ -18,16 +19,68 @@ final class BaseContactTrickStorage: ContactTrickStorage, Injectable {
         injectServices(resolver)
     }
 
-    func fetchContactTrickEntryIds() async -> [NSManagedObjectID] {
-        // TODO: implement
-        []
+    func fetchContactTrickEntries() async -> [ContactTrickEntry] {
+        let results = await CoreDataStack.shared.fetchEntitiesAsync(
+            ofType: ContactTrickEntryStored.self,
+            onContext: backgroundContext,
+            predicate: NSPredicate.lastActiveOverrideNotYetUploadedToNightscout,
+            key: "date",
+            ascending: false
+        )
+
+        guard let fetchedContactTrickEntries = results as? [ContactTrickEntryStored] else { return [] }
+
+        return fetchedContactTrickEntries.map { entry in
+            ContactTrickEntry(
+                layout: ContactTrickLayout.init(rawValue: entry.layout ?? "Single") ?? .single,
+                ring1: ContactTrickLargeRing.init(rawValue: entry.ring1 ?? "DontShowRing") ?? .none,
+                primary: ContactTrickValue.init(rawValue: entry.primary ?? "GlucoseContactValue") ?? .glucose,
+                top: ContactTrickValue.init(rawValue: entry.top ?? "NoneContactValue") ?? .none,
+                bottom: ContactTrickValue.init(rawValue: entry.top ?? "NoneContactValue") ?? .none,
+                contactId: entry.contactId?.string,
+                darkMode: entry.isDarkMode,
+                ringWidth: ContactTrickEntry.RingWidth.init(rawValue: Int(entry.ringWidth)) ?? .regular,
+                ringGap: ContactTrickEntry.RingGap.init(rawValue: Int(entry.ringWidth)) ?? .small,
+                fontSize: ContactTrickEntry.FontSize.init(rawValue: Int(entry.fontSize)) ?? .regular,
+                secondaryFontSize: ContactTrickEntry.FontSize.init(rawValue: Int(entry.fontSize)) ?? .small,
+                fontWeight: Font.Weight.fromString(entry.fontWeight ?? "regular"),
+                fontWidth: Font.Width.fromString(entry.fontWidth ?? "standard")
+            )
+        }
     }
 
-    func storeContactTrickEntry(_: ContactTrickEntry) async {
-        // TODO: implement
+    func storeContactTrickEntry(_ contactTrickEntry: ContactTrickEntry) async {
+        await backgroundContext.perform {
+            let newContactTrickEntry = ContactTrickEntryStored(context: self.backgroundContext)
+
+            newContactTrickEntry.id = UUID()
+            newContactTrickEntry.contactId = contactTrickEntry.contactId
+            newContactTrickEntry.layout = contactTrickEntry.layout.rawValue
+            newContactTrickEntry.ring1 = contactTrickEntry.ring1.rawValue
+            newContactTrickEntry.primary = contactTrickEntry.primary.rawValue
+            newContactTrickEntry.top = contactTrickEntry.top.rawValue
+            newContactTrickEntry.bottom = contactTrickEntry.bottom.rawValue
+            newContactTrickEntry.contactId = contactTrickEntry.ring1.rawValue
+            newContactTrickEntry.isDarkMode = contactTrickEntry.darkMode
+            newContactTrickEntry.ringWidth = Int16(contactTrickEntry.ringWidth.rawValue)
+            newContactTrickEntry.ringGap = Int16(contactTrickEntry.ringGap.rawValue)
+            newContactTrickEntry.fontSize = Int16(contactTrickEntry.fontSize.rawValue)
+            newContactTrickEntry.fontSizeSecondary = Int16(contactTrickEntry.secondaryFontSize.rawValue)
+            newContactTrickEntry.fontWidth = contactTrickEntry.fontWeight.asString
+            newContactTrickEntry.fontWeight = contactTrickEntry.fontWidth.asString
+
+            do {
+                guard self.backgroundContext.hasChanges else { return }
+                try self.backgroundContext.save()
+            } catch let error as NSError {
+                debugPrint(
+                    "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to save Contract Trick Entry to Core Data with error: \(error.userInfo)"
+                )
+            }
+        }
     }
 
-    func deleteContactTrickEntry(_: NSManagedObjectID) async {
-        // TODO: implement
+    func deleteContactTrickEntry(_ objectID: NSManagedObjectID) async {
+        await CoreDataStack.shared.deleteObject(identifiedBy: objectID)
     }
 }

+ 65 - 72
FreeAPS/Sources/Models/ContactTrickEntry.swift

@@ -35,7 +35,7 @@ struct ContactTrickEntry: Hashable, Sendable {
         Font.Width.fromString(string)
     }
 
-    enum FontSize: Int, Sendable {
+    enum FontSize: Int, Codable, Sendable {
         case tiny = 200
         case small = 250
         case regular = 300
@@ -51,7 +51,7 @@ struct ContactTrickEntry: Hashable, Sendable {
         }
     }
 
-    enum RingWidth: Int, Sendable {
+    enum RingWidth: Int, Codable, Sendable {
         case tiny = 3
         case small = 5
         case regular = 7
@@ -69,7 +69,7 @@ struct ContactTrickEntry: Hashable, Sendable {
         }
     }
 
-    enum RingGap: Int, Sendable {
+    enum RingGap: Int, Codable, Sendable {
         case tiny = 1
         case small = 2
         case regular = 3
@@ -88,89 +88,82 @@ struct ContactTrickEntry: Hashable, Sendable {
     }
 }
 
-// TODO: is this required?
 protocol ContactTrickObserver: Sendable {
-    func basalProfileDidChange(_ entry: [ContactTrickEntry])
+    // TODO: is this required?
+//    func basalProfileDidChange(_ entry: [ContactTrickEntry])
 }
 
-extension Font.Weight {
+enum ContactTrickValue: String, JSON, CaseIterable, Identifiable, Codable {
+    var id: String { rawValue }
+    case none
+    case glucose
+    case eventualBG
+    case delta
+    case trend
+    case lastLoopDate
+    case cob
+    case iob
+    case ring
+
     var displayName: String {
         switch self {
-        case .light: return "Light"
-        case .regular: return "Regular"
-        case .medium: return "Medium"
-        case .bold: return "Bold"
-        default: return "Unknown"
+        case .none:
+            return NSLocalizedString("NoneContactValue", comment: "")
+        case .glucose:
+            return NSLocalizedString("GlucoseContactValue", comment: "")
+        case .eventualBG:
+            return NSLocalizedString("EventualBGContactValue", comment: "")
+        case .delta:
+            return NSLocalizedString("DeltaContactValue", comment: "")
+        case .trend:
+            return NSLocalizedString("TrendContactValue", comment: "")
+        case .lastLoopDate:
+            return NSLocalizedString("LastLoopTimeContactValue", comment: "")
+        case .cob:
+            return NSLocalizedString("COBContactValue", comment: "")
+        case .iob:
+            return NSLocalizedString("IOBContactValue", comment: "")
+        case .ring:
+            return NSLocalizedString("LoopStatusContactValue", comment: "")
         }
     }
-
-    private static let stringToFontWeight: [String: Font.Weight] = [
-        "ultraLight": .ultraLight,
-        "thin": .thin,
-        "light": .light,
-        "regular": .regular,
-        "medium": .medium,
-        "semibold": .semibold,
-        "bold": .bold,
-        "heavy": .heavy,
-        "black": .black
-    ]
-
-    private static let fontWeightToString: [Font.Weight: String] = [
-        .ultraLight: "ultraLight",
-        .thin: "thin",
-        .light: "light",
-        .regular: "regular",
-        .medium: "medium",
-        .semibold: "semibold",
-        .bold: "bold",
-        .heavy: "heavy",
-        .black: "black"
-    ]
-
-    /// Initialize `Font.Weight` from a string
-    static func fromString(_ string: String) -> Font.Weight {
-        stringToFontWeight[string] ?? .regular // Default fallback
-    }
-
-    /// Convert `Font.Weight` to a string
-    var asString: String {
-        Font.Weight.fontWeightToString[self] ?? "regular" // Default fallback
-    }
 }
 
-extension Font.Width {
+enum ContactTrickLayout: String, JSON, CaseIterable, Identifiable, Codable {
+    var id: String { rawValue }
+    case single
+    case split
+
     var displayName: String {
         switch self {
-        case .condensed: return "Condensed"
-        case .expanded: return "Expanded"
-        case .compressed: return "Compressed"
-        case .standard: return "Standard"
-        default: return "Unknown"
+        case .single:
+            return NSLocalizedString("Single", comment: "")
+        case .split:
+            return NSLocalizedString("Split", comment: "")
         }
     }
+}
 
-    private static let stringToFontWidth: [String: Font.Width] = [
-        "compressed": .compressed,
-        "condensed": .condensed,
-        "standard": .standard,
-        "expanded": .expanded
-    ]
-
-    private static let fontWidthToString: [Font.Width: String] = [
-        .compressed: "compressed",
-        .condensed: "condensed",
-        .standard: "standard",
-        .expanded: "expanded"
-    ]
-
-    /// Initialize `Font.Width` from a string
-    static func fromString(_ string: String) -> Font.Width {
-        stringToFontWidth[string] ?? .standard // Default fallback
-    }
+enum ContactTrickLargeRing: String, JSON, CaseIterable, Identifiable, Codable {
+    var id: String { rawValue }
+    case none
+    case loop
+    case iob
+    case cob
+    case iobcob
 
-    /// Convert `Font.Width` to a string
-    var asString: String {
-        Font.Width.fontWidthToString[self] ?? "standard" // Default fallback
+    var displayName: String {
+        switch self {
+        case .none:
+            return NSLocalizedString("DontShowRing", comment: "")
+        case .loop:
+            return NSLocalizedString("LoopStatusRing", comment: "")
+        case .iob:
+            return NSLocalizedString("IOBRing", comment: "")
+        case .cob:
+            return NSLocalizedString("COBRing", comment: "")
+        case .iobcob:
+            return NSLocalizedString("IOB+COBRing", comment: "")
+        }
     }
 }

+ 1 - 4
FreeAPS/Sources/Modules/ContactTrick/ContactTrickDataFlow.swift

@@ -24,7 +24,4 @@ enum ContactTrick {
     }
 }
 
-protocol ContactTrickProvider: Provider {
-    var contacts: [ContactTrickEntry] { get }
-    func saveContacts(_ contacts: [ContactTrickEntry]) -> AnyPublisher<[ContactTrickEntry], Error>
-}
+protocol ContactTrickProvider: Provider {}

+ 1 - 20
FreeAPS/Sources/Modules/ContactTrick/ContactTrickProvider.swift

@@ -2,24 +2,5 @@ import Combine
 import Foundation
 
 extension ContactTrick {
-    final class Provider: BaseProvider, ContactTrickProvider {
-        private let processQueue = DispatchQueue(label: "ContactTrickProvider.processQueue")
-
-        var contacts: [ContactTrickEntry] {
-            contactTrickManager.currentContacts
-        }
-
-        func saveContacts(_ contacts: [ContactTrickEntry]) -> AnyPublisher<[ContactTrickEntry], Error> {
-            Future { promise in
-                self.contactTrickManager.updateContacts(contacts: contacts) { result in
-                    switch result {
-                    case let .success(updated):
-                        promise(.success(updated))
-                    case let .failure(error):
-                        promise(.failure(error))
-                    }
-                }
-            }.eraseToAnyPublisher()
-        }
-    }
+    final class Provider: BaseProvider, ContactTrickProvider {}
 }

+ 18 - 91
FreeAPS/Sources/Modules/ContactTrick/ContactTrickStateModel.swift

@@ -1,92 +1,19 @@
 import ConnectIQ
 import SwiftUI
 
-enum ContactTrickValue: String, JSON, CaseIterable, Identifiable, Codable {
-    var id: String { rawValue }
-    case none
-    case glucose
-    case eventualBG
-    case delta
-    case trend
-    case lastLoopDate
-    case cob
-    case iob
-    case ring
-
-    var displayName: String {
-        switch self {
-        case .none:
-            return NSLocalizedString("NoneContactValue", comment: "")
-        case .glucose:
-            return NSLocalizedString("GlucoseContactValue", comment: "")
-        case .eventualBG:
-            return NSLocalizedString("EventualBGContactValue", comment: "")
-        case .delta:
-            return NSLocalizedString("DeltaContactValue", comment: "")
-        case .trend:
-            return NSLocalizedString("TrendContactValue", comment: "")
-        case .lastLoopDate:
-            return NSLocalizedString("LastLoopTimeContactValue", comment: "")
-        case .cob:
-            return NSLocalizedString("COBContactValue", comment: "")
-        case .iob:
-            return NSLocalizedString("IOBContactValue", comment: "")
-        case .ring:
-            return NSLocalizedString("LoopStatusContactValue", comment: "")
-        }
-    }
-}
-
-enum ContactTrickLayout: String, JSON, CaseIterable, Identifiable, Codable {
-    var id: String { rawValue }
-    case single
-    case split
-
-    var displayName: String {
-        switch self {
-        case .single:
-            return NSLocalizedString("Single", comment: "")
-        case .split:
-            return NSLocalizedString("Split", comment: "")
-        }
-    }
-}
-
-enum ContactTrickLargeRing: String, JSON, CaseIterable, Identifiable, Codable {
-    var id: String { rawValue }
-    case none
-    case loop
-    case iob
-    case cob
-    case iobcob
-
-    var displayName: String {
-        switch self {
-        case .none:
-            return NSLocalizedString("DontShowRing", comment: "")
-        case .loop:
-            return NSLocalizedString("LoopStatusRing", comment: "")
-        case .iob:
-            return NSLocalizedString("IOBRing", comment: "")
-        case .cob:
-            return NSLocalizedString("COBRing", comment: "")
-        case .iobcob:
-            return NSLocalizedString("IOB+COBRing", comment: "")
-        }
-    }
-}
-
 extension ContactTrick {
-    final class StateModel: BaseStateModel<Provider> {
-        @Published private(set) var syncInProgress = false
-        @Published private(set) var items: [Item] = []
-        @Published private(set) var changed: Bool = false
+    @Observable final class StateModel: BaseStateModel<Provider> {
+        private(set) var syncInProgress = false
+        private(set) var items: [Item] = []
+        private(set) var changed: Bool = false
+
+        @ObservationIgnored @Injected() var contactTrickManager: ContactTrickManager!
 
         var units: GlucoseUnits = .mmolL
 
         override func subscribe() {
             units = settingsManager.settings.units
-            items = provider.contacts.enumerated().map { index, contact in
+            items = contactTrickManager.currentContacts.enumerated().map { index, contact in
                 Item(
                     index: index,
                     entry: contact
@@ -120,17 +47,17 @@ extension ContactTrick {
             let contacts = items.map { item -> ContactTrickEntry in
                 item.entry
             }
-            provider.saveContacts(contacts)
-                .receive(on: DispatchQueue.main)
-                .sink { _ in
-                    self.syncInProgress = false
-                    self.changed = false
-                } receiveValue: { contacts in
-                    contacts.enumerated().forEach { index, item in
-                        self.items[index].entry = item
-                    }
-                }
-                .store(in: &lifetime)
+//            provider.saveContacts(contacts)
+//                .receive(on: DispatchQueue.main)
+//                .sink { _ in
+//                    self.syncInProgress = false
+//                    self.changed = false
+//                } receiveValue: { contacts in
+//                    contacts.enumerated().forEach { index, item in
+//                        self.items[index].entry = item
+//                    }
+//                }
+//                .store(in: &lifetime)
         }
     }
 }

+ 1 - 0
FreeAPS/Sources/Modules/ContactTrick/View/ContactTrickRootView.swift

@@ -10,6 +10,7 @@ extension ContactTrick {
 
         @State private var contactStore = CNContactStore()
         @State private var authorization = CNContactStore.authorizationStatus(for: .contacts)
+        @State private var contactTrickEntries = [ContactTrickEntry]()
 
         var body: some View {
             Form {

+ 26 - 31
FreeAPS/Sources/Services/ContactTrick/ContactTrickManager.swift

@@ -20,7 +20,7 @@ final class BaseContactTrickManager: NSObject, ContactTrickManager, Injectable {
     @Injected() private var broadcaster: Broadcaster!
     @Injected() private var settingsManager: SettingsManager!
     @Injected() private var apsManager: APSManager!
-    @Injected() private var storage: FileStorage!
+    @Injected() private var contactTrickStorage: ContactTrickStorage!
     @Injected() private var carbsStorage: CarbsStorage!
     @Injected() private var tempTargetsStorage: TempTargetsStorage!
     @Injected() private var glucoseStorage: GlucoseStorage!
@@ -84,6 +84,9 @@ final class BaseContactTrickManager: NSObject, ContactTrickManager, Injectable {
 //        contacts = storage.retrieve(OpenAPS.Settings.contactTrick, as: [ContactTrickEntry].self)
 //            ?? [ContactTrickEntry](from: OpenAPS.defaults(for: OpenAPS.Settings.contactTrick))
 //            ?? []
+        Task {
+            contacts = await contactTrickStorage.fetchContactTrickEntries()
+        }
 
         knownIds = contacts.compactMap(\.contactId)
 
@@ -115,13 +118,6 @@ final class BaseContactTrickManager: NSObject, ContactTrickManager, Injectable {
             }
         }.store(in: &subscriptions)
 
-        coreDataPublisher?.filterByEntityName("OverrideStored").sink { [weak self] _ in
-            guard let self = self else { return }
-            Task {
-                await self.configureState()
-            }
-        }.store(in: &subscriptions)
-
         // Observes Deletion of Glucose Objects
         coreDataPublisher?.filterByEntityName("GlucoseStored").sink { [weak self] _ in
             guard let self = self else { return }
@@ -155,24 +151,6 @@ final class BaseContactTrickManager: NSObject, ContactTrickManager, Injectable {
         }
     }
 
-    private func fetchLatestOverride() async -> NSManagedObjectID? {
-        let results = await CoreDataStack.shared.fetchEntitiesAsync(
-            ofType: OverrideStored.self,
-            onContext: context,
-            predicate: NSPredicate.predicateForOneDayAgo,
-            key: "date",
-            ascending: false,
-            fetchLimit: 1,
-            propertiesToFetch: ["enabled", "percentage", "objectID"]
-        )
-
-        return await context.perform {
-            guard let fetchedResults = results as? [[String: Any]] else { return nil }
-
-            return fetchedResults.compactMap { $0["objectID"] as? NSManagedObjectID }.first
-        }
-    }
-
     private func fetchGlucose() async -> [NSManagedObjectID] {
         let results = await CoreDataStack.shared.fetchEntitiesAsync(
             ofType: GlucoseStored.self,
@@ -251,19 +229,36 @@ final class BaseContactTrickManager: NSObject, ContactTrickManager, Injectable {
     }
 
     private func sendState() {
+        // TODO: why does this have to be JSON ?!
         guard let data = try? JSONEncoder().encode(state) else {
             warning(.service, "Cannot encode watch state")
             return
         }
 
         if contacts.isNotEmpty, CNContactStore.authorizationStatus(for: .contacts) == .authorized {
-            let newContacts = contacts.enumerated().map { index, entry in renderContact(entry, index + 1, self.state) }
-            if newContacts != contacts {
-                // when we create new contacts we store the IDs, in that case we need to write into the settings storage
+            let newContacts = contacts.enumerated().map { index, entry in
+                renderContact(entry, index + 1, self.state)
+            }
+            //            if newContacts != contacts {
+            //                // when we create new contacts we store the IDs, in that case we need to write into the settings storage
+            //
+            //                // TODO: save this in CD
+            ////                storage.save(newContacts, as: OpenAPS.Settings.contactTrick)
+            //            }
+
+            // Find new entries in newContacts that are not in contacts
+            let newEntries = newContacts.filter { newContact in
+                !contacts.contains(where: { $0.contactId == newContact.contactId })
+            }
 
-                // TODO: save this in CD
-//                storage.save(newContacts, as: OpenAPS.Settings.contactTrick)
+            // When we create new contacts we store the IDs, in that case we need to write into the settings storage
+            // Save the new entries into Core Data
+            for newEntry in newEntries {
+                Task {
+                    await contactTrickStorage.storeContactTrickEntry(newEntry)
+                }
             }
+
             contacts = newContacts
         }
     }

+ 0 - 9
FreeAPS/Sources/Services/WatchManager/WatchManager.swift

@@ -248,15 +248,6 @@ final class BaseWatchManager: NSObject, WatchManager, Injectable {
                 self.state.maxCOB = self.settingsManager.preferences.maxCOB
                 self.state.maxBolus = self.settingsManager.pumpSettings.maxBolus
                 self.state.carbsRequired = lastDetermination?.carbsRequired as? Decimal
-
-//                var insulinRequired = lastDetermination?.insulinReq as? Decimal ?? 0
-//
-//                var double: Decimal = 2
-//                if lastDetermination?.manualBolusErrorString == 0 {
-//                    insulinRequired = lastDetermination?.insulinForManualBolus as? Decimal ?? 0
-//                    double = 1
-//                }
-
                 self.state.bolusRecommended = self.apsManager
                     .roundBolus(amount: max(recommendedInsulin, 0))
                 self.state.displayOnWatch = self.settingsManager.settings.displayOnWatch