Преглед изворни кода

Begin refactoring; remove unnecessary font handling WIP

Deniz Cengiz пре 1 година
родитељ
комит
a701e71b5c

+ 0 - 8
FreeAPS.xcodeproj/project.pbxproj

@@ -533,8 +533,6 @@
 		E592A37F2CEEC046009A472C /* ContactPicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = E592A37D2CEEC046009A472C /* ContactPicture.swift */; };
 		E592A3802CEEC046009A472C /* ContactTrickManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E592A37B2CEEC046009A472C /* ContactTrickManager.swift */; };
 		E592A3812CEEC046009A472C /* ContactTrickState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E592A37C2CEEC046009A472C /* ContactTrickState.swift */; };
-		E592A3832CEEC227009A472C /* FontWeight.swift in Sources */ = {isa = PBXBuildFile; fileRef = E592A3822CEEC227009A472C /* FontWeight.swift */; };
-		E592A3852CEEC245009A472C /* FontTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = E592A3842CEEC245009A472C /* FontTracking.swift */; };
 		E974172296125A5AE99E634C /* PumpConfigRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD22C985B79A2F0D2EA3D9D /* PumpConfigRootView.swift */; };
 		F5CA3DB1F9DC8B05792BBFAA /* CGMDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B5C0607505A38F256BF99A /* CGMDataFlow.swift */; };
 		F5F7E6C1B7F098F59EB67EC5 /* TargetsEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA49538D56989D8DA6FCF538 /* TargetsEditorDataFlow.swift */; };
@@ -1221,8 +1219,6 @@
 		E592A37B2CEEC046009A472C /* ContactTrickManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactTrickManager.swift; sourceTree = "<group>"; };
 		E592A37C2CEEC046009A472C /* ContactTrickState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactTrickState.swift; sourceTree = "<group>"; };
 		E592A37D2CEEC046009A472C /* ContactPicture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactPicture.swift; sourceTree = "<group>"; };
-		E592A3822CEEC227009A472C /* FontWeight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontWeight.swift; sourceTree = "<group>"; };
-		E592A3842CEEC245009A472C /* FontTracking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontTracking.swift; sourceTree = "<group>"; };
 		E625985B47742D498CB1681A /* GlucoseNotificationSettingsProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GlucoseNotificationSettingsProvider.swift; sourceTree = "<group>"; };
 		F816825D28DB441200054060 /* HeartBeatManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeartBeatManager.swift; sourceTree = "<group>"; };
 		F816825F28DB441800054060 /* BluetoothTransmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothTransmitter.swift; sourceTree = "<group>"; };
@@ -1987,8 +1983,6 @@
 				38D0B3D825EC07C400CB6E88 /* CarbsEntry.swift */,
 				3811DF0125CA9FEA00A708ED /* Credentials.swift */,
 				E592A36F2CEEC01E009A472C /* ContactTrickEntry.swift */,
-				E592A3822CEEC227009A472C /* FontWeight.swift */,
-				E592A3842CEEC245009A472C /* FontTracking.swift */,
 				38AEE73C25F0200C0013F05B /* FreeAPSSettings.swift */,
 				383948D925CD64D500E91849 /* Glucose.swift */,
 				382C133625F13A1E00715CE1 /* InsulinSensitivities.swift */,
@@ -3385,7 +3379,6 @@
 				E00EEC0527368630002FF094 /* StorageAssembly.swift in Sources */,
 				DD1745552C55CA6C00211FAC /* UnitsLimitsSettingsRootView.swift in Sources */,
 				384E803825C388640086DB71 /* Script.swift in Sources */,
-				E592A3832CEEC227009A472C /* FontWeight.swift in Sources */,
 				CE94597E29E9E1EE0047C9C6 /* GarminManager.swift in Sources */,
 				3883583425EEB38000E024B2 /* PumpSettings.swift in Sources */,
 				38DAB280260CBB7F00F74C1A /* PumpView.swift in Sources */,
@@ -3763,7 +3756,6 @@
 				DDE179562C910127003CDDB7 /* BolusStored+CoreDataClass.swift in Sources */,
 				DDE179572C910127003CDDB7 /* BolusStored+CoreDataProperties.swift in Sources */,
 				DDE179582C910127003CDDB7 /* ForecastValue+CoreDataClass.swift in Sources */,
-				E592A3852CEEC245009A472C /* FontTracking.swift in Sources */,
 				DDE179592C910127003CDDB7 /* ForecastValue+CoreDataProperties.swift in Sources */,
 				DDE1795A2C910127003CDDB7 /* CarbEntryStored+CoreDataClass.swift in Sources */,
 				DDE1795B2C910127003CDDB7 /* CarbEntryStored+CoreDataProperties.swift in Sources */,

+ 1 - 1
FreeAPS/Resources/Base.lproj/InfoPlist.strings

@@ -20,4 +20,4 @@
 "NSHealthShareUsageDescription" = "Health App is used to store blood glucose, insulin and carbohydrates";
 
 /* Privacy - Contacts Usage Description */
-"NSContactsUsageDescription" = "To enable the Contact Image feature: get live updates from Trio to your Apple Watch Contact complication";
+"NSContactsUsageDescription" = "Allows Trio to access your contacts for live updates to your Apple Watch contact complication using the 'Contact Trick' feature.";

+ 108 - 62
FreeAPS/Sources/Models/ContactTrickEntry.swift

@@ -1,5 +1,6 @@
+import SwiftUI
 
-struct ContactTrickEntry: JSON, Equatable, Hashable {
+struct ContactTrickEntry: Hashable {
     var layout: ContactTrickLayout = .single
     var ring1: ContactTrickLargeRing = .none
     var primary: ContactTrickValue = .glucose
@@ -7,73 +8,118 @@ struct ContactTrickEntry: JSON, Equatable, Hashable {
     var bottom: ContactTrickValue = .none
     var contactId: String? = nil
     var darkMode: Bool = true
-    var ringWidth: Int = 7
-    var ringGap: Int = 2
-    var fontSize: Int = 300
-    var secondaryFontSize: Int = 250
-    var fontName: String = "Default Font"
-    var fontWeight: FontWeight = .medium
-    var fontTracking: FontTracking = .normal
+    var ringWidth: ringWidth = .regular
+    var ringGap: ringGap = .small
+    var fontSize: fontSize = .regular
+    var secondaryFontSize: fontSize = .small
+    var fontWeight: Font.Weight = .medium
+    var fontWidth: Font.Width = .standard
 
-    func isDefaultFont() -> Bool {
-        fontName == "Default Font"
+    enum fontSize: Int {
+        case tiny = 200
+        case small = 250
+        case regular = 300
+        case large = 400
+
+        var displayName: String {
+            switch self {
+            case .tiny: return "Tiny"
+            case .small: return "Small"
+            case .regular: return "Regular"
+            case .large: return "Large"
+            }
+        }
     }
-}
 
-protocol ContactTrickObserver {
-    func basalProfileDidChange(_ entry: [ContactTrickEntry])
-}
+    enum ringWidth: Int {
+        case tiny = 3
+        case small = 5
+        case regular = 7
+        case medium = 10
+        case large = 15
 
-extension ContactTrickEntry {
-    private enum CodingKeys: String, CodingKey {
-        case layout
-        case ring1
-        case primary
-        case top
-        case bottom
-        case contactId
-        case darkMode
-        case ringWidth
-        case ringGap
-        case fontSize
-        case secondaryFontSize
-        case fontName
-        case fontWeight
-        case fontTracking
+        var displayName: String {
+            switch self {
+            case .tiny: return "Tiny"
+            case .small: return "Small"
+            case .regular: return "Regular"
+            case .medium: return "Medium"
+            case .large: return "Large"
+            }
+        }
     }
 
-    init(from decoder: Decoder) throws {
-        let container = try decoder.container(keyedBy: CodingKeys.self)
-        let layout = try container.decodeIfPresent(ContactTrickLayout.self, forKey: .layout) ?? .single
-        let ring1 = try container.decodeIfPresent(ContactTrickLargeRing.self, forKey: .ring1) ?? .none
-        let primary = try container.decodeIfPresent(ContactTrickValue.self, forKey: .primary) ?? .glucose
-        let top = try container.decodeIfPresent(ContactTrickValue.self, forKey: .top) ?? .none
-        let bottom = try container.decodeIfPresent(ContactTrickValue.self, forKey: .bottom) ?? .none
-        let contactId = try container.decodeIfPresent(String.self, forKey: .contactId)
-        let darkMode = try container.decodeIfPresent(Bool.self, forKey: .darkMode) ?? true
-        let ringWidth = try container.decodeIfPresent(Int.self, forKey: .ringWidth) ?? 7
-        let ringGap = try container.decodeIfPresent(Int.self, forKey: .ringGap) ?? 2
-        let fontSize = try container.decodeIfPresent(Int.self, forKey: .fontSize) ?? 300
-        let secondaryFontSize = try container.decodeIfPresent(Int.self, forKey: .secondaryFontSize) ?? 250
-        let fontName = try container.decodeIfPresent(String.self, forKey: .fontName) ?? "Default Font"
-        let fontWeight = try container.decodeIfPresent(FontWeight.self, forKey: .fontWeight) ?? .regular
-        let fontTracking = try container.decodeIfPresent(FontTracking.self, forKey: .fontTracking) ?? .normal
+    enum ringGap: Int {
+        case tiny = 1
+        case small = 2
+        case regular = 3
+        case medium = 4
+        case large = 5
 
-        self = ContactTrickEntry(
-            layout: layout,
-            ring1: ring1,
-            primary: primary,
-            top: top,
-            bottom: bottom,
-            contactId: contactId,
-            darkMode: darkMode,
-            ringWidth: ringWidth,
-            ringGap: ringGap,
-            fontSize: fontSize,
-            secondaryFontSize: secondaryFontSize,
-            fontName: fontName,
-            fontWeight: fontWeight,
-            fontTracking: fontTracking
-        )
+        var displayName: String {
+            switch self {
+            case .tiny: return "Tiny"
+            case .small: return "Small"
+            case .regular: return "Regular"
+            case .medium: return "Medium"
+            case .large: return "Large"
+            }
+        }
     }
 }
+
+protocol ContactTrickObserver {
+    func basalProfileDidChange(_ entry: [ContactTrickEntry])
+}
+
+//
+// extension ContactTrickEntry {
+//    private enum CodingKeys: String, CodingKey {
+//        case layout
+//        case ring1
+//        case primary
+//        case top
+//        case bottom
+//        case contactId
+//        case darkMode
+//        case ringWidth
+//        case ringGap
+//        case fontSize
+//        case secondaryFontSize
+//        case fontWeight
+//        case fontWidth
+//    }
+//
+//    init(from decoder: Decoder) throws {
+//        let container = try decoder.container(keyedBy: CodingKeys.self)
+//        let layout = try container.decodeIfPresent(ContactTrickLayout.self, forKey: .layout) ?? .single
+//        let ring1 = try container.decodeIfPresent(ContactTrickLargeRing.self, forKey: .ring1) ?? .none
+//        let primary = try container.decodeIfPresent(ContactTrickValue.self, forKey: .primary) ?? .glucose
+//        let top = try container.decodeIfPresent(ContactTrickValue.self, forKey: .top) ?? .none
+//        let bottom = try container.decodeIfPresent(ContactTrickValue.self, forKey: .bottom) ?? .none
+//        let contactId = try container.decodeIfPresent(String.self, forKey: .contactId)
+//        let darkMode = try container.decodeIfPresent(Bool.self, forKey: .darkMode) ?? true
+//        let ringWidth = try container.decodeIfPresent(Int.self, forKey: .ringWidth) ?? 7
+//        let ringGap = try container.decodeIfPresent(Int.self, forKey: .ringGap) ?? 2
+//        let fontSize = try container.decodeIfPresent(Int.self, forKey: .fontSize) ?? 300
+//        let secondaryFontSize = try container.decodeIfPresent(Int.self, forKey: .secondaryFontSize) ?? 250
+//        let fontWeight = try container.decodeIfPresent(Font.Weight.self, forKey: .fontWeight) ?? .medium
+//        let fontWidth = try container.decodeIfPresent(Font.Width.self, forKey: .fontWidth) ?? .standard
+//
+//        self = ContactTrickEntry(
+//            layout: layout,
+//            ring1: ring1,
+//            primary: primary,
+//            top: top,
+//            bottom: bottom,
+//            contactId: contactId,
+//            darkMode: darkMode,
+//            ringWidth: ringWidth,
+//            ringGap: ringGap,
+//            fontSize: fontSize,
+//            secondaryFontSize: secondaryFontSize,
+//            fontWeight: fontWeight,
+//            fontWidth: fontWidth
+//        )
+//    }
+// }

+ 0 - 32
FreeAPS/Sources/Models/FontTracking.swift

@@ -1,32 +0,0 @@
-import Foundation
-
-enum FontTracking: String, JSON, Identifiable, CaseIterable, Codable {
-    var id: String { rawValue }
-
-    case tighter
-    case tight
-    case normal
-    case wide
-
-    var displayName: String {
-        switch self {
-        case .tighter:
-            NSLocalizedString("TighterFontTracking", comment: "")
-        case .tight:
-            NSLocalizedString("TightFontTracking", comment: "")
-        case .normal:
-            NSLocalizedString("NormalFontTracking", comment: "")
-        case .wide:
-            NSLocalizedString("WideFontTracking", comment: "")
-        }
-    }
-
-    var value: Double {
-        switch self {
-        case .tighter: -0.07
-        case .tight: -0.04
-        case .normal: 0
-        case .wide: 0.04
-        }
-    }
-}

+ 0 - 29
FreeAPS/Sources/Models/FontWeight.swift

@@ -1,29 +0,0 @@
-import Foundation
-
-enum FontWeight: String, JSON, Identifiable, CaseIterable, Codable {
-    var id: String { rawValue }
-
-    case light
-    case regular
-    case medium
-    case semibold
-    case bold
-    case black
-
-    var displayName: String {
-        switch self {
-        case .light:
-            return NSLocalizedString("LightFontWeight", comment: "")
-        case .regular:
-            return NSLocalizedString("RegularFontWeight", comment: "")
-        case .medium:
-            return NSLocalizedString("MediumFontWeight", comment: "")
-        case .semibold:
-            return NSLocalizedString("SemiboldFontWeight", comment: "")
-        case .bold:
-            return NSLocalizedString("BoldFontWeight", comment: "")
-        case .black:
-            return NSLocalizedString("BlackFontWeight", comment: "")
-        }
-    }
-}

+ 150 - 130
FreeAPS/Sources/Modules/ContactTrick/View/ContactTrickRootView.swift

@@ -64,6 +64,12 @@ extension ContactTrick {
                         )
                     }
 
+                case .limited:
+                    Section {
+                        Text(
+                            "Access to contacts is limited. Trio needs full access to contacts for this feature to work"
+                        )
+                    }
                 @unknown default:
                     Section {
                         Text(
@@ -194,190 +200,204 @@ extension ContactTrick {
         @State private var availableFonts: [String]? = nil
         let previewState: ContactTrickState
 
-        private let fontSizes: [Int] = [100, 120, 130, 140, 160, 180, 200, 225, 250, 275, 300, 350, 400]
-        private let ringWidths: [Int] = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
-        private let ringGaps: [Int] = [0, 1, 2, 3, 4, 5]
+        private let ringWidths: [Int] = [5, 10, 15]
+        private let ringGaps: [Int] = [0, 2, 4]
 
         var body: some View {
-            Section {
-                HStack {
-                    ZStack {
-                        Circle()
-                            .fill(entry.darkMode ? .black : .white)
-                            .foregroundColor(.white)
-                        Image(uiImage: ContactPicture.getImage(contact: entry, state: previewState))
-                            .resizable()
-                            .aspectRatio(1, contentMode: .fit)
-                            .frame(width: 64, height: 64)
-                            .clipShape(Circle())
-                        Circle()
-                            .stroke(lineWidth: 2)
-                            .foregroundColor(.white)
-                    }
-                    .frame(width: 64, height: 64)
-                }
-            }
-            Form {
+            VStack {
                 Section {
-                    Picker(
-                        selection: $entry.layout,
-                        label: Text("Layout")
-                    ) {
-                        ForEach(ContactTrickLayout.allCases) { v in
-                            Text(v.displayName).tag(v)
+                    HStack {
+                        ZStack {
+                            Circle()
+                                .fill(entry.darkMode ? .black : .white)
+                            Image(uiImage: ContactPicture.getImage(contact: entry, state: previewState))
+                                .resizable()
+                                .aspectRatio(1, contentMode: .fit)
+                                .frame(width: 64, height: 64)
+                                .clipShape(Circle())
+                            Circle()
+                                .stroke(lineWidth: 2)
+                                .foregroundColor(.white)
                         }
+                        .frame(width: 64, height: 64)
                     }
                 }
-                Section {
-                    switch entry.layout {
-                    case .single:
+
+                Form {
+                    Section {
+                        Picker(
+                            selection: $entry.layout,
+                            label: Text("Layout")
+                        ) {
+                            ForEach(ContactTrickLayout.allCases, id: \.self) { layout in
+                                Text(layout.displayName).tag(layout)
+                            }
+                        }
+                    }
+
+                    layoutSpecificSection
+
+                    Section(header: Text("Ring")) {
+                        Picker(
+                            selection: $entry.ring1,
+                            label: Text("Outer")
+                        ) {
+                            ForEach(ContactTrickLargeRing.allCases, id: \.self) { ring in
+                                Text(ring.displayName).tag(ring)
+                            }
+                        }
                         Picker(
-                            selection: $entry.primary,
-                            label: Text("Primary")
+                            selection: $entry.ringWidth,
+                            label: Text("Width")
                         ) {
-                            ForEach(ContactTrickValue.allCases) { v in
-                                Text(v.displayName).tag(v)
+                            ForEach(ringWidths, id: \.self) { width in
+                                Text("\(width)").tag(width)
                             }
                         }
                         Picker(
-                            selection: $entry.top,
-                            label: Text("Top")
+                            selection: $entry.ringGap,
+                            label: Text("Gap")
+                        ) {
+                            ForEach(ringGaps, id: \.self) { gap in
+                                Text("\(gap)").tag(gap)
+                            }
+                        }
+                    }
+
+                    Section(header: Text("Font")) {
+                        Picker(
+                            selection: $entry.fontSize,
+                            label: Text("Size")
                         ) {
-                            ForEach(ContactTrickValue.allCases) { v in
-                                Text(v.displayName).tag(v)
+                            ForEach(
+                                [
+                                    ContactTrickEntry.fontSize.tiny,
+                                    ContactTrickEntry.fontSize.small,
+                                    ContactTrickEntry.fontSize.regular,
+                                    ContactTrickEntry.fontSize.large
+                                ],
+                                id: \.self
+                            ) { size in
+                                Text("\(size)").tag(size)
                             }
                         }
                         Picker(
-                            selection: $entry.bottom,
-                            label: Text("Bottom")
+                            selection: $entry.secondaryFontSize,
+                            label: Text("Secondary size")
                         ) {
-                            ForEach(ContactTrickValue.allCases) { v in
-                                Text(v.displayName).tag(v)
+                            ForEach(
+                                [
+                                    ContactTrickEntry.fontSize.tiny,
+                                    ContactTrickEntry.fontSize.small,
+                                    ContactTrickEntry.fontSize.regular,
+                                    ContactTrickEntry.fontSize.large
+                                ],
+                                id: \.self
+                            ) { size in
+                                Text("\(size)").tag(size)
                             }
                         }
-                    case .split:
                         Picker(
-                            selection: $entry.top,
-                            label: Text("Top")
+                            selection: $entry.fontWidth,
+                            label: Text("Tracking")
                         ) {
-                            ForEach(ContactTrickValue.allCases) { v in
-                                Text(v.displayName).tag(v)
+                            ForEach(
+                                [Font.Width.standard, Font.Width.condensed, Font.Width.expanded],
+                                id: \.self
+                            ) { width in
+                                Text(width.displayName).tag(width)
                             }
                         }
                         Picker(
-                            selection: $entry.bottom,
-                            label: Text("Bottom")
+                            selection: $entry.fontWeight,
+                            label: Text("Weight")
                         ) {
-                            ForEach(ContactTrickValue.allCases) { v in
-                                Text(v.displayName).tag(v)
+                            ForEach(
+                                [Font.Weight.regular, Font.Weight.bold, Font.Weight.black],
+                                id: \.self
+                            ) { weight in
+                                Text(weight.displayName).tag(weight)
                             }
                         }
                     }
-                }
 
-                Section(header: Text("Ring")) {
-                    Picker(
-                        selection: $entry.ring1,
-                        label: Text("Outer")
-                    ) {
-                        ForEach(ContactTrickLargeRing.allCases) { v in
-                            Text(v.displayName).tag(v)
-                        }
+                    Section {
+                        Toggle("Dark mode", isOn: $entry.darkMode)
                     }
+                }
+            }
+        }
+
+        private var layoutSpecificSection: some View {
+            Section {
+                if entry.layout == .single {
                     Picker(
-                        selection: $entry.ringWidth,
-                        label: Text("Width")
+                        selection: $entry.primary,
+                        label: Text("Primary")
                     ) {
-                        ForEach(ringWidths, id: \.self) { s in
-                            Text("\(s)").tag(s)
+                        ForEach(ContactTrickValue.allCases, id: \.self) { value in
+                            Text(value.displayName).tag(value)
                         }
                     }
                     Picker(
-                        selection: $entry.ringGap,
-                        label: Text("Gap")
+                        selection: $entry.top,
+                        label: Text("Top")
                     ) {
-                        ForEach(ringGaps, id: \.self) { s in
-                            Text("\(s)").tag(s)
-                        }
-                    }
-                }
-
-                Section(header: Text("Font")) {
-                    if availableFonts == nil {
-                        HStack {
-                            Spacer()
-                            Button {
-                                loadFonts()
-                            } label: {
-                                Text(entry.fontName)
-                            }
-                        }
-                    } else {
-                        Picker(
-                            selection: $entry.fontName,
-                            label: EmptyView()
-                        ) {
-                            ForEach(availableFonts!, id: \.self) { f in
-                                Text(f).tag(f)
-                            }
+                        ForEach(ContactTrickValue.allCases, id: \.self) { value in
+                            Text(value.displayName).tag(value)
                         }
-                        .pickerStyle(.navigationLink)
-                        .labelsHidden()
                     }
                     Picker(
-                        selection: $entry.fontSize,
-                        label: Text("Size")
+                        selection: $entry.bottom,
+                        label: Text("Bottom")
                     ) {
-                        ForEach(fontSizes, id: \.self) { s in
-                            Text("\(s)").tag(s)
+                        ForEach(ContactTrickValue.allCases, id: \.self) { value in
+                            Text(value.displayName).tag(value)
                         }
                     }
+                } else if entry.layout == .split {
                     Picker(
-                        selection: $entry.secondaryFontSize,
-                        label: Text("Secondary size")
+                        selection: $entry.top,
+                        label: Text("Top")
                     ) {
-                        ForEach(fontSizes, id: \.self) { s in
-                            Text("\(s)").tag(s)
+                        ForEach(ContactTrickValue.allCases, id: \.self) { value in
+                            Text(value.displayName).tag(value)
                         }
                     }
                     Picker(
-                        selection: $entry.fontTracking,
-                        label: Text("Tracking")
+                        selection: $entry.bottom,
+                        label: Text("Bottom")
                     ) {
-                        ForEach(FontTracking.allCases) { w in
-                            Text(w.displayName).tag(w)
-                        }
-                    }
-                    if entry.isDefaultFont() {
-                        Picker(
-                            selection: $entry.fontWeight,
-                            label: Text("Weight")
-                        ) {
-                            ForEach(FontWeight.allCases) { w in
-                                Text(w.displayName).tag(w)
-                            }
+                        ForEach(ContactTrickValue.allCases, id: \.self) { value in
+                            Text(value.displayName).tag(value)
                         }
                     }
                 }
-                Section {
-                    Toggle("Dark mode", isOn: $entry.darkMode)
-                }
             }
         }
+    }
+}
 
-        private func loadFonts() {
-            if availableFonts != nil {
-                return
-            }
-            var data = [String]()
+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"
+        }
+    }
+}
 
-            data.append("Default Font")
-            UIFont.familyNames.forEach { family in
-                UIFont.fontNames(forFamilyName: family).forEach { font in
-                    data.append(font)
-                }
-            }
-            availableFonts = data
+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"
         }
     }
 }

+ 53 - 89
FreeAPS/Sources/Services/ContactTrick/ContactPicture.swift

@@ -28,7 +28,7 @@ struct ContactPicture: View {
         let secondaryTextColor: Color = contact.darkMode ?
             Color(red: 220 / 256, green: 220 / 256, blue: 220 / 256) :
             Color(red: 40 / 256, green: 40 / 256, blue: 40 / 256)
-        let fontWeight = contact.fontWeight.toUI()
+        let fontWeight = contact.fontWeight
 
         UIGraphicsBeginImageContext(rect.size)
         if let context = UIGraphicsGetCurrentContext() {
@@ -36,8 +36,8 @@ struct ContactPicture: View {
             context.setAllowsAntialiasing(true)
         }
 
-        let ringWidth = Double(contact.ringWidth) / 100.0
-        let ringGap = Double(contact.ringGap) / 100.0
+        let ringWidth = Double(contact.ringWidth.rawValue) / 100.0
+        let ringGap = Double(contact.ringGap.rawValue) / 100.0
         let outerGap = 0.03
 
         if contact.ring1 != .none {
@@ -137,10 +137,9 @@ struct ContactPicture: View {
                 state: state,
                 rect: primaryRect,
                 fitHeigh: false,
-                fontName: contact.fontName,
-                fontSize: contact.fontSize,
+                fontSize: contact.fontSize.rawValue,
                 fontWeight: fontWeight,
-                fontTracking: contact.fontTracking,
+                fontWidth: contact.fontWidth,
                 color: textColor
             )
             if showTop {
@@ -150,10 +149,9 @@ struct ContactPicture: View {
                     state: state,
                     rect: topRect,
                     fitHeigh: true,
-                    fontName: contact.fontName,
-                    fontSize: secondaryFontSize,
+                    fontSize: secondaryFontSize.rawValue,
                     fontWeight: fontWeight,
-                    fontTracking: contact.fontTracking,
+                    fontWidth: contact.fontWidth,
                     color: secondaryTextColor
                 )
             }
@@ -164,10 +162,9 @@ struct ContactPicture: View {
                     state: state,
                     rect: bottomRect,
                     fitHeigh: true,
-                    fontName: contact.fontName,
-                    fontSize: secondaryFontSize,
+                    fontSize: secondaryFontSize.rawValue,
                     fontWeight: fontWeight,
-                    fontTracking: contact.fontTracking,
+                    fontWidth: contact.fontWidth,
                     color: secondaryTextColor
                 )
             }
@@ -204,10 +201,9 @@ struct ContactPicture: View {
                 state: state,
                 rect: topRect,
                 fitHeigh: true,
-                fontName: contact.fontName,
-                fontSize: topFontSize,
+                fontSize: topFontSize.rawValue,
                 fontWeight: fontWeight,
-                fontTracking: contact.fontTracking,
+                fontWidth: contact.fontWidth,
                 color: textColor
             )
             displayPiece(
@@ -216,10 +212,9 @@ struct ContactPicture: View {
                 state: state,
                 rect: bottomRect,
                 fitHeigh: true,
-                fontName: contact.fontName,
-                fontSize: bottomFontSize,
+                fontSize: bottomFontSize.rawValue,
                 fontWeight: fontWeight,
-                fontTracking: contact.fontTracking,
+                fontWidth: contact.fontWidth,
                 color: textColor
             )
         }
@@ -234,34 +229,11 @@ struct ContactPicture: View {
         state: ContactTrickState,
         rect: CGRect,
         fitHeigh: Bool,
-        fontName: String?,
         fontSize: Int,
-        fontWeight: UIFont.Weight,
-        fontTracking: FontTracking,
+        fontWeight: Font.Weight,
+        fontWidth: Font.Width,
         color: Color
     ) {
-//        guard let context = UIGraphicsGetCurrentContext() else {
-//            return
-//        }
-//
-//        // Set the fill color (optional)
-//        context.setFillColor(UIColor.red.cgColor)
-//
-//        // Set the stroke color (optional)
-//        context.setStrokeColor(UIColor.black.cgColor)
-//
-//        // Set the line width (optional)
-//        context.setLineWidth(2.0)
-//
-//        // Create a rectangle
-//        let rectangle = CGRect(x: 50, y: 50, width: 100, height: 100)
-//
-//        // Fill the rectangle (if fill color is set)
-//        context.fill(rect)
-//
-//        // Stroke the rectangle (if stroke color is set)
-//        context.stroke(rect)
-
         guard value != .none else { return }
         if value == .ring {
             drawRing(
@@ -299,10 +271,9 @@ struct ContactPicture: View {
                 text: text,
                 rect: rect,
                 fitHeigh: fitHeigh,
-                fontName: fontName,
                 fontSize: fontSize,
                 fontWeight: fontWeight,
-                fontTracking: fontTracking,
+                fontWidth: fontWidth,
                 color: textColor
             )
         }
@@ -312,24 +283,19 @@ struct ContactPicture: View {
         text: String,
         rect: CGRect,
         fitHeigh: Bool,
-        fontName: String?,
         fontSize: Int,
-        fontWeight: UIFont.Weight,
-        fontTracking: FontTracking,
+        fontWeight: Font.Weight,
+        fontWidth: Font.Width,
         color: Color
     ) {
         var theFontSize = fontSize
 
         func makeAttributes(_ size: Int) -> [NSAttributedString.Key: Any] {
-            let font = if let fontName {
-                UIFont(name: fontName, size: CGFloat(size)) ?? UIFont.systemFont(ofSize: CGFloat(size), weight: fontWeight)
-            } else {
-                UIFont.systemFont(ofSize: CGFloat(size), weight: fontWeight)
-            }
+            let font = UIFont.systemFont(ofSize: CGFloat(size), weight: fontWeight.uiFontWeight)
             return [
                 .font: font,
                 .foregroundColor: UIColor(color),
-                .tracking: fontTracking.value * Double(fontSize)
+                .kern: fontWidth.value * Double(fontSize) // `kern` is the correct key for tracking
             ]
         }
 
@@ -337,17 +303,17 @@ struct ContactPicture: View {
 
         var stringSize = text.size(withAttributes: attributes)
         while stringSize.width > rect.width * 0.90 || fitHeigh && (stringSize.height > rect.height * 0.95), theFontSize > 50 {
-            theFontSize = theFontSize - 10
+            theFontSize -= 10
             attributes = makeAttributes(theFontSize)
             stringSize = text.size(withAttributes: attributes)
         }
 
         text.draw(
-            in: CGRectMake(
-                rect.minX + (rect.width - stringSize.width) / 2,
-                rect.minY + (rect.height - stringSize.height) / 2,
-                rect.minX + stringSize.width,
-                rect.minY + stringSize.height
+            in: CGRect(
+                x: rect.minX + (rect.width - stringSize.width) / 2,
+                y: rect.minY + (rect.height - stringSize.height) / 2,
+                width: stringSize.width,
+                height: stringSize.height
             ),
             withAttributes: attributes
         )
@@ -610,21 +576,19 @@ struct ContactPicture: View {
     }
 }
 
-extension FontWeight {
-    func toUI() -> UIFont.Weight {
+extension Font.Weight {
+    var uiFontWeight: UIFont.Weight {
         switch self {
-        case .light:
-            UIFont.Weight.light
-        case .regular:
-            UIFont.Weight.regular
-        case .medium:
-            UIFont.Weight.medium
-        case .semibold:
-            UIFont.Weight.semibold
-        case .bold:
-            UIFont.Weight.bold
-        case .black:
-            UIFont.Weight.black
+        case .ultraLight: return .ultraLight
+        case .thin: return .thin
+        case .light: return .light
+        case .regular: return .regular
+        case .medium: return .medium
+        case .semibold: return .semibold
+        case .bold: return .bold
+        case .heavy: return .heavy
+        case .black: return .black
+        default: return .regular
         }
     }
 }
@@ -655,7 +619,7 @@ struct ContactPicture_Previews: PreviewProvider {
     struct Preview: View {
         @State var rangeIndicator: Bool = true
         @State var darkMode: Bool = true
-        @State var fontSize: Int = 130
+        @State var fontSize: ContactTrickEntry.fontSize = .small
         @State var fontWeight: UIFont.Weight = .bold
         @State var fontName: String? = "AmericanTypewriter"
 
@@ -666,7 +630,7 @@ struct ContactPicture_Previews: PreviewProvider {
                         primary: .glucose,
                         top: .delta,
                         bottom: .trend,
-                        fontSize: 100,
+                        fontSize: fontSize,
                         fontWeight: .medium
                     )
                 ),
@@ -685,7 +649,7 @@ struct ContactPicture_Previews: PreviewProvider {
                         ring1: .iob,
                         primary: .glucose,
                         bottom: .trend,
-                        fontSize: 100,
+                        fontSize: fontSize,
                         fontWeight: .medium
                     )
                 ),
@@ -704,7 +668,7 @@ struct ContactPicture_Previews: PreviewProvider {
                         primary: .glucose,
                         top: .ring,
                         bottom: .trend,
-                        fontSize: 100,
+                        fontSize: fontSize,
                         fontWeight: .medium
                     )
                 ),
@@ -723,7 +687,7 @@ struct ContactPicture_Previews: PreviewProvider {
                         primary: .glucose,
                         top: .none,
                         bottom: .trend,
-                        fontSize: 100,
+                        fontSize: fontSize,
                         fontWeight: .medium
                     )
                 ),
@@ -741,7 +705,7 @@ struct ContactPicture_Previews: PreviewProvider {
                         primary: .glucose,
                         top: .none,
                         bottom: .eventualBG,
-                        fontSize: 100,
+                        fontSize: fontSize,
                         fontWeight: .medium
                     )
                 ),
@@ -759,7 +723,7 @@ struct ContactPicture_Previews: PreviewProvider {
                         primary: .lastLoopDate,
                         top: .none,
                         bottom: .none,
-                        fontSize: 100,
+                        fontSize: fontSize,
                         fontWeight: .medium
                     )
                 ),
@@ -777,7 +741,7 @@ struct ContactPicture_Previews: PreviewProvider {
                         primary: .glucose,
                         top: .none,
                         bottom: .none,
-                        fontSize: 100,
+                        fontSize: fontSize,
                         fontWeight: .medium
                     )
                 ),
@@ -796,7 +760,7 @@ struct ContactPicture_Previews: PreviewProvider {
                         layout: .split,
                         top: .iob,
                         bottom: .cob,
-                        fontSize: 100,
+                        fontSize: fontSize,
                         fontWeight: .medium
                     )
                 ),
@@ -814,9 +778,9 @@ struct ContactPicture_Previews: PreviewProvider {
                         layout: .single,
                         ring1: .iobcob,
                         primary: .none,
-                        ringWidth: 8,
-                        ringGap: 3,
-                        fontSize: 100,
+                        ringWidth: .regular,
+                        ringGap: .regular,
+                        fontSize: fontSize,
                         fontWeight: .medium
                     )
                 ),
@@ -836,7 +800,7 @@ struct ContactPicture_Previews: PreviewProvider {
                         layout: .single,
                         ring1: .iobcob,
                         primary: .none,
-                        fontSize: 100,
+                        fontSize: fontSize,
                         fontWeight: .medium
                     )
                 ),
@@ -856,7 +820,7 @@ struct ContactPicture_Previews: PreviewProvider {
                         layout: .single,
                         ring1: .iobcob,
                         primary: .none,
-                        fontSize: 100,
+                        fontSize: fontSize,
                         fontWeight: .medium
                     )
                 ),
@@ -877,7 +841,7 @@ struct ContactPicture_Previews: PreviewProvider {
                         ring1: .iobcob,
                         primary: .glucose,
                         bottom: .trend,
-                        fontSize: 100,
+                        fontSize: fontSize,
                         fontWeight: .medium
                     )
                 ),

+ 7 - 4
FreeAPS/Sources/Services/ContactTrick/ContactTrickManager.swift

@@ -80,9 +80,10 @@ final class BaseContactTrickManager: NSObject, ContactTrickManager, Injectable {
                 .share()
                 .eraseToAnyPublisher()
 
-        contacts = storage.retrieve(OpenAPS.Settings.contactTrick, as: [ContactTrickEntry].self)
-            ?? [ContactTrickEntry](from: OpenAPS.defaults(for: OpenAPS.Settings.contactTrick))
-            ?? []
+        // TODO: fetch this from CD
+//        contacts = storage.retrieve(OpenAPS.Settings.contactTrick, as: [ContactTrickEntry].self)
+//            ?? [ContactTrickEntry](from: OpenAPS.defaults(for: OpenAPS.Settings.contactTrick))
+//            ?? []
 
         knownIds = contacts.compactMap(\.contactId)
 
@@ -259,7 +260,9 @@ final class BaseContactTrickManager: NSObject, ContactTrickManager, Injectable {
             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
-                storage.save(newContacts, as: OpenAPS.Settings.contactTrick)
+
+                // TODO: save this in CD
+//                storage.save(newContacts, as: OpenAPS.Settings.contactTrick)
             }
             contacts = newContacts
         }