Jonas Björkert 1 год назад
Родитель
Сommit
392e08c18d

+ 4 - 0
LoopFollow.xcodeproj/project.pbxproj

@@ -150,6 +150,7 @@
 		DDB9FC7B2DDB573F00EFAA76 /* IOBCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB9FC7A2DDB573F00EFAA76 /* IOBCondition.swift */; };
 		DDB9FC7D2DDB575300EFAA76 /* IOBAlarmEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB9FC7C2DDB575300EFAA76 /* IOBAlarmEditor.swift */; };
 		DDB9FC7F2DDB584500EFAA76 /* BolusEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB9FC7E2DDB584500EFAA76 /* BolusEntry.swift */; };
+		DDBD19962DFB44B0005C2D69 /* Alarm+byPriorityThenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDBD19952DFB44B0005C2D69 /* Alarm+byPriorityThenSpec.swift */; };
 		DDBE3ABD2CB5A961006B37DC /* OverrideView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDBE3ABC2CB5A961006B37DC /* OverrideView.swift */; };
 		DDC6CA3D2DD7C6090060EE25 /* TemporaryCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC6CA3C2DD7C6090060EE25 /* TemporaryCondition.swift */; };
 		DDC6CA3F2DD7C6340060EE25 /* TemporaryAlarmEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC6CA3E2DD7C6340060EE25 /* TemporaryAlarmEditor.swift */; };
@@ -519,6 +520,7 @@
 		DDB9FC7A2DDB573F00EFAA76 /* IOBCondition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOBCondition.swift; sourceTree = "<group>"; };
 		DDB9FC7C2DDB575300EFAA76 /* IOBAlarmEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOBAlarmEditor.swift; sourceTree = "<group>"; };
 		DDB9FC7E2DDB584500EFAA76 /* BolusEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusEntry.swift; sourceTree = "<group>"; };
+		DDBD19952DFB44B0005C2D69 /* Alarm+byPriorityThenSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Alarm+byPriorityThenSpec.swift"; sourceTree = "<group>"; };
 		DDBE3ABC2CB5A961006B37DC /* OverrideView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideView.swift; sourceTree = "<group>"; };
 		DDC6CA3C2DD7C6090060EE25 /* TemporaryCondition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemporaryCondition.swift; sourceTree = "<group>"; };
 		DDC6CA3E2DD7C6340060EE25 /* TemporaryAlarmEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemporaryAlarmEditor.swift; sourceTree = "<group>"; };
@@ -1117,6 +1119,7 @@
 				DDCF9A8B2D86005E004DF4DD /* AlarmManager.swift */,
 				DDCF9A872D85FD33004DF4DD /* AlarmData.swift */,
 				DDCF9A7F2D85FD09004DF4DD /* Alarm.swift */,
+				DDBD19952DFB44B0005C2D69 /* Alarm+byPriorityThenSpec.swift */,
 			);
 			path = Alarm;
 			sourceTree = "<group>";
@@ -1815,6 +1818,7 @@
 				DD0247712DB4337700FCADF6 /* BuildExpireCondition.swift in Sources */,
 				DDF6999B2C5AA32E0058A8D9 /* TempTargetPreset.swift in Sources */,
 				DD7F4C0F2DD51EC200D449E9 /* TempTargetStartCondition.swift in Sources */,
+				DDBD19962DFB44B0005C2D69 /* Alarm+byPriorityThenSpec.swift in Sources */,
 				DDC6CA3D2DD7C6090060EE25 /* TemporaryCondition.swift in Sources */,
 				DD9ACA0E2D340BFF00415D8A /* AlarmTask.swift in Sources */,
 				DDCF9A822D85FD15004DF4DD /* AlarmType.swift in Sources */,

+ 31 - 0
LoopFollow/Alarm/Alarm+byPriorityThenSpec.swift

@@ -0,0 +1,31 @@
+// LoopFollow
+// Alarm+byPriorityThenSpec.swift
+// Created by Jonas Björkert on 2025-06-12.
+
+import Foundation
+
+extension Alarm {
+    /// Sorts by `AlarmType.priority`, then the per-type `sortSpec` if one exists.
+    static let byPriorityThenSpec: (Alarm, Alarm) -> Bool = { lhs, rhs in
+        // 1) type-level priority
+        if lhs.type.priority != rhs.type.priority {
+            return lhs.type.priority < rhs.type.priority
+        }
+
+        // 2) per-type “main value” ordering
+        if lhs.type == rhs.type,
+           let spec = lhs.type.sortSpec
+        {
+            let lv = spec.key(lhs)
+            let rv = spec.key(rhs)
+
+            switch spec.direction {
+            case .ascending: return (lv ?? .infinity) < (rv ?? .infinity)
+            case .descending: return (lv ?? -.infinity) > (rv ?? -.infinity)
+            }
+        }
+
+        // 3) fallback – keep original insertion order
+        return false
+    }
+}

+ 1 - 1
LoopFollow/Alarm/AlarmListView.swift

@@ -95,7 +95,7 @@ struct AlarmListView: View {
 
     var body: some View {
         List {
-            ForEach(store.value) { alarm in
+            ForEach(store.value.sorted(by: Alarm.byPriorityThenSpec)) { alarm in
                 Button {
                     selectedAlarm = alarm
                     sheetInfo = .editor(id: alarm.id, isNew: false)

+ 1 - 24
LoopFollow/Alarm/AlarmManager.swift

@@ -45,30 +45,7 @@ class AlarmManager {
         var alarmTriggered = false
         let alarms = Storage.shared.alarms.value
 
-        let sorted = alarms.sorted { lhs, rhs in
-            // 1) type-level priority (hard-coded table in AlarmType)
-            if lhs.type.priority != rhs.type.priority {
-                return lhs.type.priority < rhs.type.priority
-            }
-
-            // 2) per-type “main value” ordering
-            if lhs.type == rhs.type, // only makes sense within the same type
-               let spec = lhs.type.sortSpec
-            { // (direction, key extractor)
-                let lv = spec.key(lhs)
-                let rv = spec.key(rhs)
-
-                switch spec.direction {
-                case .ascending: // smaller ⇒ more urgent
-                    return (lv ?? Double.infinity) < (rv ?? Double.infinity)
-                case .descending: // bigger  ⇒ more urgent
-                    return (lv ?? -Double.infinity) > (rv ?? -Double.infinity)
-                }
-            }
-
-            // 3) fallback – keep original insertion order
-            return false
-        }
+        let sorted = alarms.sorted(by: Alarm.byPriorityThenSpec)
         var skipType: AlarmType?
 
         let isLatestReadingRecent: Bool = {