Kaynağa Gözat

Refactor UI settings; add new totalDailyDoseType setting

Deniz Cengiz 1 yıl önce
ebeveyn
işleme
42fbcd29b9

+ 2 - 1
FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json

@@ -24,8 +24,9 @@
   "lowGlucose" : 72,
   "highGlucose" : 270,
   "carbsRequiredThreshold" : 10,
+  "showCarbsRequiredBadge" : true,
   "useFPUconversion" : true,
-  "tins": false,
+  "totalInsulinDisplayType": "totalDailyDose",
   "individualAdjustmentFactor" : 0.5,
   "timeCap" : 8,
   "minuteInterval" : 30,

+ 8 - 3
FreeAPS/Sources/Models/FreeAPSSettings.swift

@@ -40,8 +40,9 @@ struct FreeAPSSettings: JSON, Equatable {
     var lowGlucose: Decimal = 72
     var highGlucose: Decimal = 270
     var carbsRequiredThreshold: Decimal = 10
+    var showCarbsRequiredBadge: Bool = true
     var useFPUconversion: Bool = true
-    var tins: Bool = false
+    var totalInsulinDisplayType: TotalInsulinDisplayType = .totalDailyDose
     var individualAdjustmentFactor: Decimal = 0.5
     var timeCap: Int = 8
     var minuteInterval: Int = 30
@@ -167,8 +168,8 @@ extension FreeAPSSettings: Decodable {
             settings.useFPUconversion = useFPUconversion
         }
 
-        if let tins = try? container.decode(Bool.self, forKey: .tins) {
-            settings.tins = tins
+        if let totalInsulinDisplayType = try? container.decode(TotalInsulinDisplayType.self, forKey: .totalInsulinDisplayType) {
+            settings.totalInsulinDisplayType = totalInsulinDisplayType
         }
 
         if let individualAdjustmentFactor = try? container.decode(Decimal.self, forKey: .individualAdjustmentFactor) {
@@ -238,6 +239,10 @@ extension FreeAPSSettings: Decodable {
             settings.carbsRequiredThreshold = carbsRequiredThreshold
         }
 
+        if let showCarbsRequiredBadge = try? container.decode(Bool.self, forKey: .showCarbsRequiredBadge) {
+            settings.showCarbsRequiredBadge = showCarbsRequiredBadge
+        }
+
         if let smoothGlucose = try? container.decode(Bool.self, forKey: .smoothGlucose) {
             settings.smoothGlucose = smoothGlucose
         }

+ 6 - 3
FreeAPS/Sources/Modules/Home/HomeStateModel.swift

@@ -57,7 +57,7 @@ extension Home {
         @Published var isStatusPopupPresented: Bool = false
         @Published var isLegendPresented: Bool = false
         @Published var legendSheetDetent = PresentationDetent.large
-        @Published var tins: Bool = false
+        @Published var totalInsulinDisplayType: TotalInsulinDisplayType = .totalDailyDose
         @Published var isTempTargetActive: Bool = false
         @Published var roundedTotalBolus: String = ""
         @Published var selectedTab: Int = 0
@@ -79,6 +79,7 @@ extension Home {
         @Published var preprocessedData: [(id: UUID, forecast: Forecast, forecastValue: ForecastValue)] = []
         @Published var pumpStatusHighlightMessage: String? = nil
         @Published var cgmAvailable: Bool = false
+        @Published var showCarbsRequiredBadge: Bool = true
 
         let context = CoreDataStack.shared.newTaskContext()
         let viewContext = CoreDataStack.shared.persistentContainer.viewContext
@@ -125,8 +126,9 @@ extension Home {
             displayXgridLines = settingsManager.settings.xGridLines
             displayYgridLines = settingsManager.settings.yGridLines
             thresholdLines = settingsManager.settings.rulerMarks
-            tins = settingsManager.settings.tins
+            totalInsulinDisplayType = settingsManager.settings.totalInsulinDisplayType
             cgmAvailable = fetchGlucoseManager.cgmGlucoseSourceType != CGMType.none
+            showCarbsRequiredBadge = settingsManager.settings.showCarbsRequiredBadge
 
             broadcaster.register(GlucoseObserver.self, observer: self)
             broadcaster.register(DeterminationObserver.self, observer: self)
@@ -455,7 +457,8 @@ extension Home.StateModel:
         displayXgridLines = settingsManager.settings.xGridLines
         displayYgridLines = settingsManager.settings.yGridLines
         thresholdLines = settingsManager.settings.rulerMarks
-        tins = settingsManager.settings.tins
+        totalInsulinDisplayType = settingsManager.settings.totalInsulinDisplayType
+        showCarbsRequiredBadge = settingsManager.settings.showCarbsRequiredBadge
         cgmAvailable = (fetchGlucoseManager.cgmGlucoseSourceType != CGMType.none)
         displayPumpStatusHighlightMessage()
         setupBatteryArray()

+ 4 - 3
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -268,7 +268,7 @@ extension Home {
                         .foregroundColor(.insulin)
                         .padding(.leading, 8)
                 }
-                if state.tins {
+                if state.totalInsulinDisplayType == .totalInsulinInScope {
                     Text(
                         "TINS: \(state.calculateTINS())" +
                             NSLocalizedString(" U", comment: "Unit in number of units delivered (keep the space character!)")
@@ -462,7 +462,7 @@ extension Home {
                             .font(.system(size: 16, weight: .bold, design: .rounded))
                     }
                 }
-                if !state.tins {
+                if state.totalInsulinDisplayType == .totalDailyDose {
                     Spacer()
                     Text(
                         "TDD: " +
@@ -806,7 +806,8 @@ extension Home {
             ZStack(alignment: .bottom) {
                 TabView(selection: $selectedTab) {
                     let carbsRequiredBadge: String? = {
-                        guard let carbsRequired = state.determinationsFromPersistence.first?.carbsRequired as? Decimal
+                        guard let carbsRequired = state.determinationsFromPersistence.first?.carbsRequired as? Decimal,
+                              state.showCarbsRequiredBadge
                         else { return nil }
                         if carbsRequired > state.settingsManager.settings.carbsRequiredThreshold {
                             let numberAsNSNumber = NSDecimalNumber(decimal: carbsRequired)

+ 1 - 1
FreeAPS/Sources/Modules/LiveActivitySettings/View/LiveActivitySettingsRootView.swift

@@ -89,7 +89,7 @@ extension LiveActivitySettings {
                                     ForEach(LockScreenView.allCases) { selection in
                                         Text(selection.displayName).tag(selection)
                                     }
-                                }
+                                }.padding(.top)
 
                                 HStack(alignment: .top) {
                                     Text(

+ 21 - 5
FreeAPS/Sources/Modules/UserInterfaceSettings/UserInterfaceSettingsStateModel.swift

@@ -3,8 +3,6 @@ import SwiftUI
 extension UserInterfaceSettings {
     final class StateModel: BaseStateModel<Provider> {
         @Published var overrideHbA1cUnit = false
-        @Published var tins: Bool = false
-        @Published var lockScreenView: LockScreenView = .simple
         @Published var low: Decimal = 70
         @Published var high: Decimal = 180
         @Published var hours: Decimal = 6
@@ -12,6 +10,8 @@ extension UserInterfaceSettings {
         @Published var yGridLines: Bool = false
         @Published var oneDimensionalGraph = false
         @Published var rulerMarks: Bool = true
+        @Published var totalInsulinDisplayType: TotalInsulinDisplayType = .totalDailyDose
+        @Published var showCarbsRequiredBadge: Bool = true
         @Published var carbsRequiredThreshold: Decimal = 0
 
         var units: GlucoseUnits = .mgdL
@@ -24,9 +24,9 @@ extension UserInterfaceSettings {
             subscribeSetting(\.xGridLines, on: $xGridLines) { xGridLines = $0 }
             subscribeSetting(\.yGridLines, on: $yGridLines) { yGridLines = $0 }
             subscribeSetting(\.rulerMarks, on: $rulerMarks) { rulerMarks = $0 }
-            subscribeSetting(\.tins, on: $tins) { tins = $0 }
             subscribeSetting(\.oneDimensionalGraph, on: $oneDimensionalGraph) { oneDimensionalGraph = $0 }
-            subscribeSetting(\.lockScreenView, on: $lockScreenView) { lockScreenView = $0 }
+
+            subscribeSetting(\.totalInsulinDisplayType, on: $totalInsulinDisplayType) { totalInsulinDisplayType = $0 }
 
             subscribeSetting(\.low, on: $low, initial: {
                 let value = max(min($0, 90), 40)
@@ -35,7 +35,6 @@ extension UserInterfaceSettings {
                 guard units == .mmolL else { return $0 }
                 return $0.asMgdL
             })
-
             subscribeSetting(\.high, on: $high, initial: {
                 let value = max(min($0, 270), 110)
                 high = units == .mmolL ? value.asMmolL : value
@@ -44,6 +43,8 @@ extension UserInterfaceSettings {
                 return $0.asMgdL
             })
 
+            subscribeSetting(\.showCarbsRequiredBadge, on: $showCarbsRequiredBadge) { showCarbsRequiredBadge = $0 }
+
             subscribeSetting(
                 \.carbsRequiredThreshold,
                 on: $carbsRequiredThreshold
@@ -51,3 +52,18 @@ extension UserInterfaceSettings {
         }
     }
 }
+
+enum TotalInsulinDisplayType: String, JSON, CaseIterable, Identifiable, Codable, Hashable {
+    var id: String { rawValue }
+    case totalDailyDose
+    case totalInsulinInScope
+
+    var displayName: String {
+        switch self {
+        case .totalDailyDose:
+            return NSLocalizedString("Total Daily Dose", comment: "")
+        case .totalInsulinInScope:
+            return NSLocalizedString("Total Insulin in Scope", comment: "")
+        }
+    }
+}

+ 226 - 39
FreeAPS/Sources/Modules/UserInterfaceSettings/View/UserInterfaceSettingsRootView.swift

@@ -6,6 +6,13 @@ extension UserInterfaceSettings {
         let resolver: Resolver
         @StateObject var state = StateModel()
 
+        @State private var shouldDisplayHint: Bool = false
+        @State var hintDetent = PresentationDetent.large
+        @State var selectedVerboseHint: String?
+        @State var hintLabel: String?
+        @State private var decimalPlaceholder: Decimal = 0.0
+        @State private var booleanPlaceholder: Bool = false
+
         @Environment(\.colorScheme) var colorScheme
         var color: LinearGradient {
             colorScheme == .dark ? LinearGradient(
@@ -44,50 +51,230 @@ extension UserInterfaceSettings {
 
         var body: some View {
             Form {
-                Section {
-                    Toggle("Display Chart X - Grid lines", isOn: $state.xGridLines)
-                    Toggle("Display Chart Y - Grid lines", isOn: $state.yGridLines)
-                    Toggle("Display Chart Threshold lines for Low and High", isOn: $state.rulerMarks)
-                    Toggle("Standing / Laying TIR Chart", isOn: $state.oneDimensionalGraph)
-                    Toggle("Enable total insulin in scope", isOn: $state.tins)
-                    HStack {
-                        Text("Hours X-Axis (6 default)")
-                        Spacer()
-                        TextFieldWithToolBar(text: $state.hours, placeholder: "6", numberFormatter: carbsFormatter)
-                        Text("hours").foregroundColor(.secondary)
+                Section(
+                    header: Text("Home View Settings"),
+                    content: {
+                        VStack {
+                            Toggle("Show X-Axis Grid Lines", isOn: $state.xGridLines)
+                            Toggle("Show Y-Axis Grid Line", isOn: $state.yGridLines)
+
+                            HStack(alignment: .top) {
+                                Text(
+                                    "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
+                                )
+                                .font(.footnote)
+                                .foregroundColor(.secondary)
+                                .lineLimit(nil)
+                                Spacer()
+                                Button(
+                                    action: {
+                                        hintLabel = "Show Main Chart X- and Y-Axis Grid Lines"
+                                        selectedVerboseHint = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
+                                        shouldDisplayHint.toggle()
+                                    },
+                                    label: {
+                                        HStack {
+                                            Image(systemName: "questionmark.circle")
+                                        }
+                                    }
+                                ).buttonStyle(BorderlessButtonStyle())
+                            }.padding(.top)
+                        }.padding(.bottom)
                     }
-                } header: { Text("Home Chart settings ") }
+                ).listRowBackground(Color.chart)
+
+                SettingInputSection(
+                    decimalValue: $decimalPlaceholder,
+                    booleanValue: $state.rulerMarks,
+                    shouldDisplayHint: $shouldDisplayHint,
+                    selectedVerboseHint: Binding(
+                        get: { selectedVerboseHint },
+                        set: {
+                            selectedVerboseHint = $0
+                            hintLabel = "Show Low and High Thresholds"
+                        }
+                    ),
+                    type: .boolean,
+                    label: "Show Low and High Thresholds",
+                    miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
+                    verboseHint: "Display Low and High Thresholds… bla bla bla"
+                )
 
                 Section {
-                    HStack {
-                        Text("Low")
-                        Spacer()
-                        TextFieldWithToolBar(text: $state.low, placeholder: "0", numberFormatter: glucoseFormatter)
-                        Text(state.units.rawValue).foregroundColor(.secondary)
-                    }
-                    HStack {
-                        Text("High")
-                        Spacer()
-                        TextFieldWithToolBar(text: $state.high, placeholder: "0", numberFormatter: glucoseFormatter)
-                        Text(state.units.rawValue).foregroundColor(.secondary)
-                    }
-                    Toggle("Override HbA1c Unit", isOn: $state.overrideHbA1cUnit)
-
-                } header: { Text("Statistics settings ") }
-
-                Section(header: Text("Other")) {
-                    HStack {
-                        Text("Carbs Required Threshold")
-                        Spacer()
-                        TextFieldWithToolBar(
-                            text: $state.carbsRequiredThreshold,
-                            placeholder: "0",
-                            numberFormatter: carbsFormatter
-                        )
-                        Text("g").foregroundColor(.secondary)
-                    }
+                    VStack {
+                        HStack {
+                            Text("Low Threshold")
+                            Spacer()
+                            TextFieldWithToolBar(text: $state.low, placeholder: "0", numberFormatter: glucoseFormatter)
+                            Text(state.units.rawValue).foregroundColor(.secondary)
+                        }.padding(.top)
+                        HStack {
+                            Text("High Threshold")
+                            Spacer()
+                            TextFieldWithToolBar(text: $state.high, placeholder: "0", numberFormatter: glucoseFormatter)
+                            Text(state.units.rawValue).foregroundColor(.secondary)
+                        }
+
+                        HStack(alignment: .top) {
+                            Text(
+                                "Sets thresholds for low and high glucose in home view main chart and statistics view."
+                            )
+                            .lineLimit(nil)
+                            .font(.footnote)
+                            .foregroundColor(.secondary)
+
+                            Spacer()
+                            Button(
+                                action: {
+                                    hintLabel = "Low and High Thresholds"
+                                    selectedVerboseHint = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
+                                    shouldDisplayHint.toggle()
+                                },
+                                label: {
+                                    HStack {
+                                        Image(systemName: "questionmark.circle")
+                                    }
+                                }
+                            ).buttonStyle(BorderlessButtonStyle())
+                        }
+                    }.padding(.bottom)
+                }.listRowBackground(Color.chart)
+
+                SettingInputSection(
+                    decimalValue: $state.hours,
+                    booleanValue: $booleanPlaceholder,
+                    shouldDisplayHint: $shouldDisplayHint,
+                    selectedVerboseHint: Binding(
+                        get: { selectedVerboseHint },
+                        set: {
+                            selectedVerboseHint = $0
+                            hintLabel = "X-Axis Interval Step"
+                        }
+                    ),
+                    type: .decimal,
+                    label: "X-Axis Interval Step",
+                    miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
+                    verboseHint: "X-Axis Interval Step… bla bla bla"
+                )
+
+                Section {
+                    VStack {
+                        Picker(
+                            selection: $state.totalInsulinDisplayType,
+                            label: Text("Total Insulin Display Type")
+                        ) {
+                            ForEach(TotalInsulinDisplayType.allCases) { selection in
+                                Text(selection.displayName).tag(selection)
+                            }
+                        }.padding(.top)
+
+                        HStack(alignment: .top) {
+                            Text(
+                                "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
+                            )
+                            .font(.footnote)
+                            .foregroundColor(.secondary)
+                            .lineLimit(nil)
+                            Spacer()
+                            Button(
+                                action: {
+                                    hintLabel = "Total Insulin Display Type"
+                                    selectedVerboseHint = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
+                                    shouldDisplayHint.toggle()
+                                },
+                                label: {
+                                    HStack {
+                                        Image(systemName: "questionmark.circle")
+                                    }
+                                }
+                            ).buttonStyle(BorderlessButtonStyle())
+                        }.padding(.top)
+                    }.padding(.bottom)
+                }.listRowBackground(Color.chart)
+
+                // TODO: this needs to be a picker: mmol/L or %
+                SettingInputSection(
+                    decimalValue: $decimalPlaceholder,
+                    booleanValue: $state.overrideHbA1cUnit,
+                    shouldDisplayHint: $shouldDisplayHint,
+                    selectedVerboseHint: Binding(
+                        get: { selectedVerboseHint },
+                        set: {
+                            selectedVerboseHint = $0
+                            hintLabel = "Override HbA1c Unit"
+                        }
+                    ),
+                    type: .boolean,
+                    label: "Override HbA1c Unit",
+                    miniHint: "Display HbA1c in mmol/L or %. Default is percent.",
+                    verboseHint: "Override HbA1c Unit… bla bla bla",
+                    headerText: "Trio Statistics"
+                )
+
+                // TODO: this needs to be a picker: choose bar chart or progress bar
+                SettingInputSection(
+                    decimalValue: $decimalPlaceholder,
+                    booleanValue: $state.oneDimensionalGraph,
+                    shouldDisplayHint: $shouldDisplayHint,
+                    selectedVerboseHint: Binding(
+                        get: { selectedVerboseHint },
+                        set: {
+                            selectedVerboseHint = $0
+                            hintLabel = "Standing / Laying TIR Chart"
+                        }
+                    ),
+                    type: .boolean,
+                    label: "Standing / Laying TIR Chart",
+                    miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
+                    verboseHint: "Standing / Laying TIR Chart… bla bla bla"
+                )
+
+                SettingInputSection(
+                    decimalValue: $decimalPlaceholder,
+                    booleanValue: $state.showCarbsRequiredBadge,
+                    shouldDisplayHint: $shouldDisplayHint,
+                    selectedVerboseHint: Binding(
+                        get: { selectedVerboseHint },
+                        set: {
+                            selectedVerboseHint = $0
+                            hintLabel = "Show Carbs Required Badge"
+                        }
+                    ),
+                    type: .boolean,
+                    label: "Show Carbs Required Badge",
+                    miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
+                    verboseHint: "Show Carbs Required Badge… bla bla bla",
+                    headerText: "Carbs Required Badge"
+                )
+
+                if state.showCarbsRequiredBadge {
+                    SettingInputSection(
+                        decimalValue: $state.carbsRequiredThreshold,
+                        booleanValue: $booleanPlaceholder,
+                        shouldDisplayHint: $shouldDisplayHint,
+                        selectedVerboseHint: Binding(
+                            get: { selectedVerboseHint },
+                            set: {
+                                selectedVerboseHint = $0
+                                hintLabel = "Carbs Required Threshold"
+                            }
+                        ),
+                        type: .decimal,
+                        label: "Carbs Required Threshold",
+                        miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
+                        verboseHint: "Carbs Required Threshold… bla bla bla"
+                    )
                 }
             }
+            .sheet(isPresented: $shouldDisplayHint) {
+                SettingInputHintView(
+                    hintDetent: $hintDetent,
+                    shouldDisplayHint: $shouldDisplayHint,
+                    hintLabel: hintLabel ?? "",
+                    hintText: selectedVerboseHint ?? "",
+                    sheetTitle: "Help"
+                )
+            }
             .scrollContentBackground(.hidden).background(color)
             .onAppear(perform: configureView)
             .navigationBarTitle("User Interface")

+ 2 - 2
Trio.xcworkspace/xcshareddata/swiftpm/Package.resolved

@@ -1,5 +1,5 @@
 {
-  "originHash" : "59ac7eba66375d6eb406e758cb0b9964f4b3b0ae45c5665596f00384c32262b9",
+  "originHash" : "f5c836c216c4ca7d356e3777e58d6d4f9502b03f3974891349eb775f4c4cf750",
   "pins" : [
     {
       "identity" : "cryptoswift",
@@ -49,7 +49,7 @@
     {
       "identity" : "swiftcharts",
       "kind" : "remoteSourceControl",
-      "location" : "https://github.com/ivanschuetz/SwiftCharts.git",
+      "location" : "https://github.com/ivanschuetz/SwiftCharts",
       "state" : {
         "branch" : "master",
         "revision" : "c354c1945bb35a1f01b665b22474f6db28cba4a2"