Просмотр исходного кода

feat: Add Display Glucose Forecasts toggle to Live Activity settings

Adds a new on/off setting under Settings > Notifications > Live Activity,
styled identically to "Enable Live Activity". Default is OFF.

When enabled, the lock screen live activity chart shows the glucose
forecast from the Oref algorithm (cone or lines, controlled by the
existing Forecast Display Type setting under Features > User Interface).
When disabled, all forecast arrays are sent empty so no data is
included in the content state payload.

Changes:
- TrioSettings: add displayGlucoseForecasts Bool property (default OFF)
  with custom decoder entry alongside other Live Activity settings
- LiveActivitySettingsStateModel: add @Published property and
  subscribeSetting binding
- LiveActivitySettingsRootView: add SettingInputSection with miniHint,
  verboseHint, and hint sheet following the existing pattern; placed
  first inside the if-useLiveActivity block
- LiveActivityAttributes+Helper: gate all forecast arrays on
  settings.displayGlucoseForecasts
- SettingsExportStateModel: add export entry under Live Activity subcategory
Magnus Reintz 1 месяц назад
Родитель
Сommit
b1b5a5f281

+ 5 - 0
Trio/Sources/Models/TrioSettings.swift

@@ -66,6 +66,7 @@ struct TrioSettings: JSON, Equatable, Encodable {
     var useLiveActivity: Bool = false
     var lockScreenView: LockScreenView = .simple
     var smartStackView: LockScreenView = .simple
+    var displayGlucoseForecasts: Bool = false
     var bolusShortcut: BolusShortcutLimit = .notAllowed
     var timeInRangeType: TimeInRangeType = .timeInTightRange
     var requireAdjustmentsConfirmation: Bool = false
@@ -311,6 +312,10 @@ extension TrioSettings: Decodable {
             settings.smartStackView = smartStackView
         }
 
+        if let displayGlucoseForecasts = try? container.decode(Bool.self, forKey: .displayGlucoseForecasts) {
+            settings.displayGlucoseForecasts = displayGlucoseForecasts
+        }
+
         if let bolusShortcut = try? container.decode(BolusShortcutLimit.self, forKey: .bolusShortcut) {
             settings.bolusShortcut = bolusShortcut
         }

+ 2 - 0
Trio/Sources/Modules/LiveActivitySettings/LiveActivitySettingsStateModel.swift

@@ -9,11 +9,13 @@ extension LiveActivitySettings {
         @Published var useLiveActivity = false
         @Published var lockScreenView: LockScreenView = .simple
         @Published var smartStackView: LockScreenView = .simple
+        @Published var displayGlucoseForecasts = false
         override func subscribe() {
             units = settingsManager.settings.units
             subscribeSetting(\.useLiveActivity, on: $useLiveActivity) { useLiveActivity = $0 }
             subscribeSetting(\.lockScreenView, on: $lockScreenView) { lockScreenView = $0 }
             subscribeSetting(\.smartStackView, on: $smartStackView) { smartStackView = $0 }
+            subscribeSetting(\.displayGlucoseForecasts, on: $displayGlucoseForecasts) { displayGlucoseForecasts = $0 }
         }
     }
 }

+ 34 - 0
Trio/Sources/Modules/LiveActivitySettings/View/LiveActivitySettingsRootView.swift

@@ -9,6 +9,7 @@ extension LiveActivitySettings {
 
         @State private var shouldDisplayHintLockScreen: Bool = false
         @State private var shouldDisplayHintSmartStack: Bool = false
+        @State private var shouldDisplayHintGlucoseForecasts: Bool = false
         @State var hintDetent = PresentationDetent.large
         @State var selectedVerboseHint: AnyView?
         @State var hintLabel: String?
@@ -83,6 +84,30 @@ extension LiveActivitySettings {
                     )
 
                     if state.useLiveActivity {
+                        SettingInputSection(
+                            decimalValue: $decimalPlaceholder,
+                            booleanValue: $state.displayGlucoseForecasts,
+                            shouldDisplayHint: $shouldDisplayHintGlucoseForecasts,
+                            selectedVerboseHint: Binding(
+                                get: { selectedVerboseHint },
+                                set: {
+                                    selectedVerboseHint = $0.map { AnyView($0) }
+                                    hintLabel = String(localized: "Display Glucose Forecasts")
+                                }
+                            ),
+                            units: state.units,
+                            type: .boolean,
+                            label: String(localized: "Display Glucose Forecasts"),
+                            miniHint: String(localized: "Display Glucose Forecasts made by the Oref algorithm."),
+                            verboseHint: VStack(alignment: .leading, spacing: 10) {
+                                Text("Default: OFF").bold()
+                                Text(
+                                    "When enabled, the live activity widget on the lock screen will show glucose forecasts. The visual representation will be the same as in the Main view. To change between Cone and Lines, change the setting under Features - User Interface - Forecast Display Type."
+                                )
+                            },
+                            headerText: String(localized: "Display Glucose Forecasts")
+                        )
+
                         Section {
                             VStack {
                                 Picker(
@@ -229,6 +254,15 @@ extension LiveActivitySettings {
                     sheetTitle: String(localized: "Help", comment: "Help sheet title")
                 )
             }
+            .sheet(isPresented: $shouldDisplayHintGlucoseForecasts) {
+                SettingInputHintView(
+                    hintDetent: $hintDetent,
+                    shouldDisplayHint: $shouldDisplayHintGlucoseForecasts,
+                    hintLabel: hintLabel ?? "",
+                    hintText: selectedVerboseHint ?? AnyView(EmptyView()),
+                    sheetTitle: String(localized: "Help", comment: "Help sheet title")
+                )
+            }
             .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))
             .onAppear(perform: configureView)
             .navigationTitle("Live Activity")

+ 6 - 0
Trio/Sources/Modules/SettingsExport/SettingsExportStateModel.swift

@@ -871,6 +871,12 @@ extension SettingsExport {
                     name: String(localized: "Lock Screen Widget Style"),
                     value: trioSettings.lockScreenView.rawValue
                 )
+                addSetting(
+                    category: notificationsCategory,
+                    subcategory: liveActivitySubcategory,
+                    name: String(localized: "Display Glucose Forecasts"),
+                    value: trioSettings.displayGlucoseForecasts ? String(localized: "Enabled") : String(localized: "Disabled")
+                )
             }
 
             // Services

+ 5 - 3
Trio/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift

@@ -119,9 +119,11 @@ extension LiveActivityAttributes.ContentState {
             tempTargetDuration: tempTarget?.duration ?? 0,
             tempTargetTarget: tempTarget?.target ?? 0,
             widgetItems: widgetItems ?? [], // set empty array here to silence compiler; this can never be nil
-            minForecast: settings.forecastDisplayType == .cone ? (determination?.minForecast ?? []) : [],
-            maxForecast: settings.forecastDisplayType == .cone ? (determination?.maxForecast ?? []) : [],
-            forecastLines: settings.forecastDisplayType == .lines
+            minForecast: settings.displayGlucoseForecasts && settings.forecastDisplayType == .cone
+                ? (determination?.minForecast ?? []) : [],
+            maxForecast: settings.displayGlucoseForecasts && settings.forecastDisplayType == .cone
+                ? (determination?.maxForecast ?? []) : [],
+            forecastLines: settings.displayGlucoseForecasts && settings.forecastDisplayType == .lines
                 ? (determination?.forecastLines ?? [])
                 .map { LiveActivityAttributes.ForecastLine(type: $0.type, values: $0.values) }
                 : [],