浏览代码

Alarm gui adjustments

Jonas Björkert 1 年之前
父节点
当前提交
6118f48f2d

+ 8 - 4
LoopFollow.xcodeproj/project.pbxproj

@@ -97,6 +97,7 @@
 		DD7E198A2ACDA62600DBD158 /* SensorStart.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7E19892ACDA62600DBD158 /* SensorStart.swift */; };
 		DD7F4B9D2DD1EAE500D449E9 /* AlarmAudioSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7F4B9C2DD1EAE500D449E9 /* AlarmAudioSection.swift */; };
 		DD7F4B9F2DD1F92700D449E9 /* AlarmActiveSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7F4B9E2DD1F92700D449E9 /* AlarmActiveSection.swift */; };
+		DD7F4BA12DD2193F00D449E9 /* AlarmSnoozeSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7F4BA02DD2193F00D449E9 /* AlarmSnoozeSection.swift */; };
 		DD7FFAFD2A72953000C3A304 /* EKEventStore+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7FFAFC2A72953000C3A304 /* EKEventStore+Extensions.swift */; };
 		DD85E9952D739CFE001C8BB7 /* OmnipodDashHeartbeatBluetoothTransmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD85E9942D739CED001C8BB7 /* OmnipodDashHeartbeatBluetoothTransmitter.swift */; };
 		DD91E4DD2BDEC3F8002D9E97 /* GlucoseConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD91E4DC2BDEC3F8002D9E97 /* GlucoseConversion.swift */; };
@@ -122,7 +123,7 @@
 		DDC7E5152DBCFA7900EB1127 /* SnoozerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC7E5132DBCE1B900EB1127 /* SnoozerViewController.swift */; };
 		DDC7E5162DBCFA7F00EB1127 /* SnoozerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC7E5122DBCE1B900EB1127 /* SnoozerView.swift */; };
 		DDC7E5382DBD887400EB1127 /* isOnPhoneCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC7E5372DBD887400EB1127 /* isOnPhoneCall.swift */; };
-		DDC7E5422DBD8A1600EB1127 /* AlarmEditorFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC7E5392DBD8A1600EB1127 /* AlarmEditorFields.swift */; };
+		DDC7E5422DBD8A1600EB1127 /* AlarmGeneralSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC7E5392DBD8A1600EB1127 /* AlarmGeneralSection.swift */; };
 		DDC7E5432DBD8A1600EB1127 /* SoundFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC7E53A2DBD8A1600EB1127 /* SoundFile.swift */; };
 		DDC7E5442DBD8A1600EB1127 /* BuildExpireAlarmEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC7E53C2DBD8A1600EB1127 /* BuildExpireAlarmEditor.swift */; };
 		DDC7E5462DBD8A1600EB1127 /* LowBgAlarmEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC7E53E2DBD8A1600EB1127 /* LowBgAlarmEditor.swift */; };
@@ -418,6 +419,7 @@
 		DD7E19892ACDA62600DBD158 /* SensorStart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorStart.swift; sourceTree = "<group>"; };
 		DD7F4B9C2DD1EAE500D449E9 /* AlarmAudioSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmAudioSection.swift; sourceTree = "<group>"; };
 		DD7F4B9E2DD1F92700D449E9 /* AlarmActiveSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmActiveSection.swift; sourceTree = "<group>"; };
+		DD7F4BA02DD2193F00D449E9 /* AlarmSnoozeSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmSnoozeSection.swift; sourceTree = "<group>"; };
 		DD7FFAFC2A72953000C3A304 /* EKEventStore+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EKEventStore+Extensions.swift"; sourceTree = "<group>"; };
 		DD85E9942D739CED001C8BB7 /* OmnipodDashHeartbeatBluetoothTransmitter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmnipodDashHeartbeatBluetoothTransmitter.swift; sourceTree = "<group>"; };
 		DD91E4DC2BDEC3F8002D9E97 /* GlucoseConversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseConversion.swift; sourceTree = "<group>"; };
@@ -444,7 +446,7 @@
 		DDC7E5122DBCE1B900EB1127 /* SnoozerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnoozerView.swift; sourceTree = "<group>"; };
 		DDC7E5132DBCE1B900EB1127 /* SnoozerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnoozerViewController.swift; sourceTree = "<group>"; };
 		DDC7E5372DBD887400EB1127 /* isOnPhoneCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = isOnPhoneCall.swift; sourceTree = "<group>"; };
-		DDC7E5392DBD8A1600EB1127 /* AlarmEditorFields.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmEditorFields.swift; sourceTree = "<group>"; };
+		DDC7E5392DBD8A1600EB1127 /* AlarmGeneralSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmGeneralSection.swift; sourceTree = "<group>"; };
 		DDC7E53A2DBD8A1600EB1127 /* SoundFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoundFile.swift; sourceTree = "<group>"; };
 		DDC7E53C2DBD8A1600EB1127 /* BuildExpireAlarmEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildExpireAlarmEditor.swift; sourceTree = "<group>"; };
 		DDC7E53E2DBD8A1600EB1127 /* LowBgAlarmEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LowBgAlarmEditor.swift; sourceTree = "<group>"; };
@@ -919,12 +921,13 @@
 		DDC7E53B2DBD8A1600EB1127 /* Components */ = {
 			isa = PBXGroup;
 			children = (
+				DD7F4BA02DD2193F00D449E9 /* AlarmSnoozeSection.swift */,
 				DD7F4B9E2DD1F92700D449E9 /* AlarmActiveSection.swift */,
 				DD7F4B9C2DD1EAE500D449E9 /* AlarmAudioSection.swift */,
 				DD0650F62DCFDA26004D3B41 /* InfoBanner.swift */,
 				DD0650F42DCF303F004D3B41 /* AlarmStepperSection.swift */,
 				DD0650A82DCA8A10004D3B41 /* AlarmBGSection.swift */,
-				DDC7E5392DBD8A1600EB1127 /* AlarmEditorFields.swift */,
+				DDC7E5392DBD8A1600EB1127 /* AlarmGeneralSection.swift */,
 				DDC7E53A2DBD8A1600EB1127 /* SoundFile.swift */,
 			);
 			path = Components;
@@ -1700,6 +1703,7 @@
 				DD0650F72DCFDA26004D3B41 /* InfoBanner.swift in Sources */,
 				DD4AFB612DB68BBC00BB593F /* AlarmListView.swift in Sources */,
 				DD7B0D442D730A3B0063DCB6 /* CycleHelper.swift in Sources */,
+				DD7F4BA12DD2193F00D449E9 /* AlarmSnoozeSection.swift in Sources */,
 				DD9ACA0C2D33BB8600415D8A /* CalendarTask.swift in Sources */,
 				DD13BC792C3FE63A0062313B /* InfoManager.swift in Sources */,
 				DD0C0C702C4AFFE800DBADDF /* RemoteViewController.swift in Sources */,
@@ -1707,7 +1711,7 @@
 				FCFEECA02488157B00402A7F /* Chart.swift in Sources */,
 				DDCF979424C0D380002C9752 /* UIViewExtension.swift in Sources */,
 				DD0C0C6D2C48606200DBADDF /* CarbMetric.swift in Sources */,
-				DDC7E5422DBD8A1600EB1127 /* AlarmEditorFields.swift in Sources */,
+				DDC7E5422DBD8A1600EB1127 /* AlarmGeneralSection.swift in Sources */,
 				DDC7E5432DBD8A1600EB1127 /* SoundFile.swift in Sources */,
 				DDC7E5442DBD8A1600EB1127 /* BuildExpireAlarmEditor.swift in Sources */,
 				DDC7E5462DBD8A1600EB1127 /* LowBgAlarmEditor.swift in Sources */,

+ 0 - 89
LoopFollow/Alarm/AlarmEditing/Components/AlarmEditorFields.swift

@@ -1,89 +0,0 @@
-//
-//  AlarmEditorFields.swift
-//  LoopFollow
-//
-//  Created by Jonas Björkert on 2025-04-21.
-//  Copyright © 2025 Jon Fawcett. All rights reserved.
-//
-
-import SwiftUI
-
-struct AlarmGeneralSection: View {
-    @Binding var alarm: Alarm
-
-    var body: some View {
-        Section(header: Text("General")) {
-            HStack {
-                Text("Name")
-                TextField("Alarm Name", text: $alarm.name)
-                    .multilineTextAlignment(.trailing)
-                    .textFieldStyle(.plain)
-            }
-            Toggle("Enabled", isOn: $alarm.isEnabled)
-        }
-    }
-}
-
-struct AlarmSnoozeSection: View {
-    let title: String
-    let range: ClosedRange<Double>
-    let step: Double
-    let unitLabel: String
-    @Binding var value: Double
-
-    var body: some View {
-        Section(
-          header: Text(title),
-          footer: Text("How long to snooze after firing \(Int(range.lowerBound))–\(Int(range.upperBound)) \(unitLabel)")
-        ) {
-            Stepper(
-                "\(title): \(Int(value)) \(unitLabel)",
-                value: $value,
-                in: range,
-                step: step
-            )
-        }
-    }
-}
-
-struct AlarmSnoozedUntilSection: View {
-    @Binding var alarm: Alarm
-
-    private var isSnoozed: Binding<Bool> {
-        Binding(
-            get: {
-                if let until = alarm.snoozedUntil, until > Date() {
-                    return true
-                }
-                return false
-            },
-            set: { on in
-                if on {
-                    // keep existing future snooze or set default ahead
-                    if let until = alarm.snoozedUntil, until > Date() {
-                        alarm.snoozedUntil = until
-                    } else {
-                        let secs = alarm.type.timeUnit.seconds
-                        alarm.snoozedUntil = Date().addingTimeInterval(Double(alarm.snoozeDuration) * secs)
-                    }
-                } else {
-                    alarm.snoozedUntil = nil
-                }
-            }
-        )
-    }
-
-    var body: some View {
-        Section(header: Text("Snoozed Until")) {
-            Toggle("Snoozed", isOn: isSnoozed)
-            if isSnoozed.wrappedValue, let until = alarm.snoozedUntil {
-                DatePicker("Until", selection: Binding(
-                    get: { until },
-                    set: { alarm.snoozedUntil = $0 }
-                ), displayedComponents: [.date, .hourAndMinute])
-            }
-        }
-    }
-}
-
-

+ 29 - 0
LoopFollow/Alarm/AlarmEditing/Components/AlarmGeneralSection.swift

@@ -0,0 +1,29 @@
+//
+//  AlarmGeneralSection.swift
+//  LoopFollow
+//
+//  Created by Jonas Björkert on 2025-04-21.
+//  Copyright © 2025 Jon Fawcett. All rights reserved.
+//
+
+import SwiftUI
+
+struct AlarmGeneralSection: View {
+    @Binding var alarm: Alarm
+
+    var body: some View {
+        Section(
+            header: Text("General"),
+            footer: Text("Give each alarm a unique name—especially if you’ve added more than one of the same kind—so you can tell them apart at a glance."))
+        {
+            HStack {
+                Text("Name")
+                TextField("Alarm Name", text: $alarm.name)
+                    .multilineTextAlignment(.trailing)
+                    .textFieldStyle(.plain)
+                    .foregroundColor(.secondary)
+            }
+            Toggle("Enabled", isOn: $alarm.isEnabled)
+        }
+    }
+}

+ 82 - 0
LoopFollow/Alarm/AlarmEditing/Components/AlarmSnoozeSection.swift

@@ -0,0 +1,82 @@
+//
+//  AlarmSnoozeSection.swift
+//  LoopFollow
+//
+//  Created by Jonas Björkert on 2025-05-12.
+//  Copyright © 2025 Jon Fawcett. All rights reserved.
+//
+
+
+import SwiftUI
+
+struct AlarmSnoozeSection: View {
+    @Binding var alarm: Alarm
+    let range: ClosedRange<Int>
+    let step:  Int
+
+    private var unitLabel: String { alarm.type.timeUnit.label }
+
+    private var defaultSnoozeBinding: Binding<Int> {
+        Binding(
+            get: { alarm.snoozeDuration },
+            set: { alarm.snoozeDuration = $0 }
+        )
+    }
+
+    private var isSnoozed: Binding<Bool> {
+        Binding(
+            get: {
+                if let until = alarm.snoozedUntil, until > Date() { return true }
+                return false
+            },
+            set: { on in
+                if on {
+                    if alarm.snoozedUntil == nil || alarm.snoozedUntil! < Date() {
+                        let secs = alarm.type.timeUnit.seconds
+                        alarm.snoozedUntil = Date()
+                            .addingTimeInterval(Double(alarm.snoozeDuration) * secs)
+                    }
+                } else {
+                    alarm.snoozedUntil = nil
+                }
+            }
+        )
+    }
+
+    var body: some View {
+        Section(
+            header: Text("SNOOZE"),
+            footer: Text(
+                "“Default Snooze” controls how long the alert stays quiet after "
+              + "you press Snooze. Toggle “Snoozed” to mute this alarm right now "
+              + "until the time below."
+            )
+        ) {
+            Stepper(
+                value: defaultSnoozeBinding,
+                in: range,
+                step: step
+            ) {
+                HStack {
+                    Text("Default Snooze:")
+                    Spacer()
+                    Text("\(alarm.snoozeDuration) \(unitLabel)")
+                        .foregroundColor(.secondary)
+                }
+            }
+
+            Toggle("Snoozed", isOn: isSnoozed)
+
+            if isSnoozed.wrappedValue, let until = alarm.snoozedUntil {
+                DatePicker(
+                    "Until",
+                    selection: Binding(
+                        get: { until },
+                        set: { alarm.snoozedUntil = $0 }
+                    ),
+                    displayedComponents: [.date, .hourAndMinute]
+                )
+            }
+        }
+    }
+}

+ 5 - 12
LoopFollow/Alarm/AlarmEditing/Editors/BuildExpireAlarmEditor.swift

@@ -31,20 +31,13 @@ struct BuildExpireAlarmEditor: View {
                 )
             )
 
-            AlarmStepperSection(
-                title: "Default Snooze",
-                range: 1...14,
-                step: 1,
-                unitLabel: alarm.type.timeUnit.label,
-                value: Binding(
-                    get: { Double(alarm.snoozeDuration) },
-                    set: { alarm.snoozeDuration = Int($0) }
-                )
-            )
-
             AlarmAudioSection(alarm: $alarm)
             AlarmActiveSection(alarm: $alarm)
-            AlarmSnoozedUntilSection(alarm: $alarm)
+            AlarmSnoozeSection(
+                alarm: $alarm,
+                range: 1...14,
+                step: 1
+            )
         }
         .navigationTitle(alarm.type.rawValue)
     }

+ 7 - 16
LoopFollow/Alarm/AlarmEditing/Editors/FastDropAlarmEditor.swift

@@ -68,24 +68,15 @@ struct FastDropAlarmEditor: View {
                 .opacity(useLimit ? 1 : 0.35)
             }   // Section
 */
-            // ────────── SNOOZE  ────────────
-            AlarmStepperSection(
-                header: "Default Snooze",
-                footer: "How long to silence this alert after you press Snooze.",
-                title: "Default Snooze",
-                range: 5...60,
-                step: 5,
-                unitLabel: alarm.type.timeUnit.label,
-                value: Binding(
-                    get: { Double(alarm.snoozeDuration) },
-                    set: { alarm.snoozeDuration = Int($0) }
-                )
-            )
-
-            // ────── SOUND / ACTIVE / UNTIL ──────
             AlarmAudioSection(alarm: $alarm)
+
             AlarmActiveSection(alarm: $alarm)
-            AlarmSnoozedUntilSection(alarm: $alarm)
+
+            AlarmSnoozeSection(
+                alarm: $alarm,
+                range: 5...60,
+                step: 5
+            )
         }
         .navigationTitle(alarm.type.rawValue)
     }

+ 5 - 12
LoopFollow/Alarm/AlarmEditing/Editors/HighBgAlarmEditor.swift

@@ -45,20 +45,13 @@ struct HighBgAlarmEditor: View {
                 )
             )
 
-            AlarmStepperSection(
-                title: "Default Snooze",
-                range: 10...120,
-                step: 5,
-                unitLabel: alarm.type.timeUnit.label,
-                value: Binding(
-                    get: { Double(alarm.snoozeDuration) },
-                    set: { alarm.snoozeDuration = Int($0) }
-                )
-            )
-
             AlarmAudioSection(alarm: $alarm)
             AlarmActiveSection(alarm: $alarm)
-            AlarmSnoozedUntilSection(alarm: $alarm)
+            AlarmSnoozeSection(
+                alarm: $alarm,
+                range: 10...120,
+                step: 5
+            )
         }
         .navigationTitle(alarm.type.rawValue)
     }

+ 9 - 12
LoopFollow/Alarm/AlarmEditing/Editors/LowBgAlarmEditor.swift

@@ -31,6 +31,7 @@ struct LowBgAlarmEditor: View {
             )
 
             AlarmStepperSection(
+                header: "PERSISTENCE",
                 footer: "Glucose must stay below the threshold for this many minutes "
                 + "before the alert sounds. Set 0 to alert immediately.",
                 title: "Persistent",
@@ -44,6 +45,7 @@ struct LowBgAlarmEditor: View {
             )
 
             AlarmStepperSection(
+                header: "PREDICTION",
                 footer: "Look ahead this many minutes in Loop’s prediction; "
                 + "if any future value is at or below the threshold, "
                 + "you’ll be warned early. Set 0 to disable.",
@@ -57,20 +59,15 @@ struct LowBgAlarmEditor: View {
                 )
             )
 
-            AlarmStepperSection(
-                title: "Default Snooze",
-                range: 5...30,
-                step: 5,
-                unitLabel: alarm.type.timeUnit.label,
-                value: Binding(
-                    get: { Double(alarm.snoozeDuration) },
-                    set: { alarm.snoozeDuration = Int($0) }
-                )
-            )
-
             AlarmAudioSection(alarm: $alarm)
+
             AlarmActiveSection(alarm: $alarm)
-            AlarmSnoozedUntilSection(alarm: $alarm)
+
+            AlarmSnoozeSection(
+                alarm: $alarm,
+                range: 5...30,
+                step: 5
+            )
         }
         .navigationTitle(alarm.type.rawValue)
     }

+ 7 - 12
LoopFollow/Alarm/AlarmEditing/Editors/MissedReadingEditor.swift

@@ -29,20 +29,15 @@ struct MissedReadingEditor: View {
                 )
             )
 
-            AlarmStepperSection(
-                title: "Default Snooze",
-                range: 10...180,
-                step: 5,
-                unitLabel: alarm.type.timeUnit.label,
-                value: Binding(
-                    get: { Double(alarm.snoozeDuration) },
-                    set: { alarm.snoozeDuration = Int($0) }
-                )
-            )
-
             AlarmAudioSection(alarm: $alarm)
+
             AlarmActiveSection(alarm: $alarm)
-            AlarmSnoozedUntilSection(alarm: $alarm)
+
+            AlarmSnoozeSection(
+                alarm: $alarm,
+                range: 10...180,
+                step: 5
+            )
 
         }
         .navigationTitle(alarm.type.rawValue)