Переглянути джерело

Update LA when the labels in settings are reordered

polscm32 aka Marvout 1 рік тому
батько
коміт
bbaf0853e7

+ 31 - 39
FreeAPS/Sources/Modules/LiveActivitySettings/View/LiveActivityBottomRowConfiguration.swift

@@ -13,6 +13,7 @@ struct LiveActivityBottomRowConfiguration: BaseView {
     @State private var showAddItemDialog: Bool = false
     @State private var isEditMode: Bool = false
     @State private var draggingItem: LiveActivityItem?
+    @State private var showDeleteAlert: Bool = false
 
     @Environment(\.colorScheme) var colorScheme
 
@@ -130,11 +131,16 @@ struct LiveActivityBottomRowConfiguration: BaseView {
                                             )
                                         )
                                         .disabled(!isEditMode)
-                                    // TODO: fix the jiggle modifier to make use of animation
-//                                        .jiggle(amount: 2, isEnabled: showItemDeleteButtons)
+                                        .rotationEffect(.degrees(isEditMode ? 2.5 : 0))
+                                        .rotation3DEffect(.degrees(isEditMode ? 2.5 : 0), axis: (x: 0, y: -5, z: 0))
+                                        .animation(
+                                            isEditMode ? Animation.easeInOut(duration: 0.15)
+                                                .repeatForever(autoreverses: true) : .default,
+                                            value: isEditMode
+                                        )
                                     if isEditMode {
                                         Button(action: {
-                                            removeItem(item)
+                                            showDeleteAlert = true
                                         }) {
                                             Image(systemName: "minus.circle.fill")
                                                 .foregroundColor(Color(UIColor.systemGray2)) // Opaque foreground color
@@ -143,6 +149,16 @@ struct LiveActivityBottomRowConfiguration: BaseView {
                                                 .font(.system(size: 20))
                                         }
                                         .offset(x: -45, y: -10)
+                                        .alert(isPresented: $showDeleteAlert) {
+                                            Alert(
+                                                title: Text("Delete Widget"),
+                                                message: Text("Are you sure you want to delete this widget?"),
+                                                primaryButton: .destructive(Text("Delete")) {
+                                                    removeItem(item)
+                                                },
+                                                secondaryButton: .cancel()
+                                            )
+                                        }
                                     }
                                 }
                                 .animation(.easeInOut, value: draggingItem)
@@ -304,10 +320,12 @@ struct LiveActivityBottomRowConfiguration: BaseView {
             selectedItems = LiveActivityItem.defaultItems
             saveOrder()
         }
+        print("Loaded order: \(selectedItems.map(\.rawValue))")
         updateVisibilityForSelectedItems()
     }
 
     private func saveOrder() {
+        print("Saving order: \(selectedItems.map(\.rawValue))")
         UserDefaults.standard.saveLiveActivityOrder(selectedItems)
     }
 
@@ -346,14 +364,6 @@ struct LiveActivityBottomRowConfiguration: BaseView {
             setItemVisibility(item: item, isVisible: false)
         }
     }
-
-    @ViewBuilder func jiggle(amount: Double = 2, isEnabled: Bool = true) -> some View {
-        if isEnabled {
-            modifier(JiggleViewModifier(amount: amount))
-        } else {
-            self
-        }
-    }
 }
 
 struct DropViewDelegate: DropDelegate {
@@ -371,6 +381,12 @@ struct DropViewDelegate: DropDelegate {
             withAnimation {
                 items.move(fromOffsets: IndexSet(integer: fromIndex), toOffset: toIndex > fromIndex ? toIndex + 1 : toIndex)
             }
+
+            // Save to User Defaults
+            saveOrder()
+
+            // Trigger Live Activity Update
+            Foundation.NotificationCenter.default.post(name: .liveActivityOrderDidChange, object: nil)
         }
     }
 
@@ -378,6 +394,10 @@ struct DropViewDelegate: DropDelegate {
         draggingItem = nil
         return true
     }
+
+    private func saveOrder() {
+        UserDefaults.standard.saveLiveActivityOrder(items)
+    }
 }
 
 // Extension for UserDefaults to save and load the order
@@ -447,31 +467,3 @@ struct DummyChartGroupBoxStyle: GroupBoxStyle {
 extension GroupBoxStyle where Self == DummyChartGroupBoxStyle {
     static var dummyChart: DummyChartGroupBoxStyle { .init() }
 }
-
-struct JiggleViewModifier: ViewModifier {
-    let amount: Double
-
-    @State private var isJiggling = false
-
-    func body(content: Content) -> some View {
-        content
-            .rotationEffect(.degrees(isJiggling ? amount : 0))
-            .animation(
-                .easeInOut(duration: randomize(interval: 0.14, withVariance: 0.025))
-                    .repeatForever(autoreverses: true),
-                value: isJiggling
-            )
-            .animation(
-                .easeInOut(duration: randomize(interval: 0.18, withVariance: 0.025))
-                    .repeatForever(autoreverses: true),
-                value: isJiggling
-            )
-            .onAppear {
-                isJiggling.toggle()
-            }
-    }
-
-    private func randomize(interval: TimeInterval, withVariance variance: Double) -> TimeInterval {
-        interval + variance * (Double.random(in: 500 ... 1000) / 500)
-    }
-}

+ 2 - 0
FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift

@@ -15,6 +15,8 @@ struct LiveActivityAttributes: ActivityAttributes {
         let showCurrentGlucose: Bool
         let showUpdatedLabel: Bool
 
+        let itemOrder: [String]
+
         /// true for the first state that is set on the activity
         let isInitialState: Bool
     }

+ 14 - 0
FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift

@@ -1,5 +1,15 @@
 import Foundation
 
+extension UserDefaults {
+    private enum Keys {
+        static let liveActivityOrder = "liveActivityOrder"
+    }
+
+    func loadLiveActivityOrderFromUserDefaults() -> [String]? {
+        array(forKey: Keys.liveActivityOrder) as? [String]
+    }
+}
+
 extension LiveActivityAttributes.ContentState {
     static func formatGlucose(_ value: Int, units: GlucoseUnits, forceSign: Bool) -> String {
         let formatter = NumberFormatter()
@@ -100,6 +110,9 @@ extension LiveActivityAttributes.ContentState {
             detailedState = nil
         }
 
+        let itemOrder = UserDefaults.standard
+            .loadLiveActivityOrderFromUserDefaults() ?? ["currentGlucose", "iob", "cob", "updatedLabel"]
+
         self.init(
             bg: formattedBG,
             direction: trendString,
@@ -110,6 +123,7 @@ extension LiveActivityAttributes.ContentState {
             showIOB: settings.showIOB,
             showCurrentGlucose: settings.showCurrentGlucose,
             showUpdatedLabel: settings.showUpdatedLabel,
+            itemOrder: itemOrder,
             isInitialState: false
         )
     }

+ 31 - 0
FreeAPS/Sources/Services/LiveActivity/LiveActivityBridge.swift

@@ -70,6 +70,12 @@ import UIKit
             .addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: nil) { [weak self] _ in
                 self?.forceActivityUpdate()
             }
+        notificationCenter.addObserver(
+            self,
+            selector: #selector(handleLiveActivityOrderChange),
+            name: .liveActivityOrderDidChange,
+            object: nil
+        )
     }
 
     // TODO: - use a delegate or a custom notification here instead
@@ -124,6 +130,30 @@ import UIKit
         }
     }
 
+    @objc private func handleLiveActivityOrderChange() {
+        Task {
+            await self.updateLiveActivityOrder()
+        }
+    }
+
+    @MainActor private func updateLiveActivityOrder() async {
+        guard let latestGlucose = latestGlucose else { return }
+
+        let content = LiveActivityAttributes.ContentState(
+            new: latestGlucose,
+            prev: latestGlucose,
+            units: settings.units,
+            chart: glucoseFromPersistence ?? [],
+            settings: settings,
+            determination: determination,
+            override: isOverridesActive
+        )
+
+        if let content = content {
+            await pushUpdate(content)
+        }
+    }
+
     private func setupGlucoseArray() {
         Task {
             // Fetch and map glucose to GlucoseData struct
@@ -206,6 +236,7 @@ import UIKit
                         showIOB: true,
                         showCurrentGlucose: true,
                         showUpdatedLabel: true,
+                        itemOrder: ["currentGlucose", "iob", "cob", "updatedLabel"],
                         isInitialState: true
                     ),
                     staleDate: Date.now.addingTimeInterval(60)

+ 56 - 19
LiveActivity/LiveActivity.swift

@@ -378,30 +378,61 @@ struct LiveActivity: Widget {
                     .frame(height: 80)
 
                 HStack {
-                    if context.state.showCurrentGlucose {
-                        VStack {
-                            bgLabel(context: context, additionalState: detailedViewState)
-                            HStack {
-                                changeLabel(context: context)
+                    ForEach(context.state.itemOrder, id: \.self) { item in
+                        switch item {
+                        case "currentGlucose":
+                            if context.state.showCurrentGlucose {
+                                VStack {
+                                    bgLabel(context: context, additionalState: detailedViewState)
+                                    HStack {
+                                        changeLabel(context: context)
+                                    }
+                                }
+                            }
+                        case "iob":
+                            if context.state.showIOB {
+                                iobLabel(context: context, additionalState: detailedViewState)
+                            }
+                        case "cob":
+                            if context.state.showCOB {
+                                cobLabel(context: context, additionalState: detailedViewState)
+                            }
+                        case "updatedLabel":
+                            if context.state.showUpdatedLabel {
+                                updatedLabel(context: context)
                             }
+                        default:
+                            EmptyView()
                         }
                         Divider().foregroundStyle(.primary).fontWeight(.bold).frame(width: 10)
                     }
-
-                    if context.state.showIOB {
-                        iobLabel(context: context, additionalState: detailedViewState)
-                        Divider().foregroundStyle(.primary).fontWeight(.bold).frame(width: 10)
-                    }
-
-                    if context.state.showCOB {
-                        cobLabel(context: context, additionalState: detailedViewState)
-                        Divider().foregroundStyle(.primary).fontWeight(.bold).frame(width: 10)
-                    }
-
-                    if context.state.showUpdatedLabel {
-                        updatedLabel(context: context)
-                    }
                 }
+
+//                HStack {
+//                    if context.state.showCurrentGlucose {
+//                        VStack {
+//                            bgLabel(context: context, additionalState: detailedViewState)
+//                            HStack {
+//                                changeLabel(context: context)
+//                            }
+//                        }
+//                        Divider().foregroundStyle(.primary).fontWeight(.bold).frame(width: 10)
+//                    }
+//
+//                    if context.state.showIOB {
+//                        iobLabel(context: context, additionalState: detailedViewState)
+//                        Divider().foregroundStyle(.primary).fontWeight(.bold).frame(width: 10)
+//                    }
+//
+//                    if context.state.showCOB {
+//                        cobLabel(context: context, additionalState: detailedViewState)
+//                        Divider().foregroundStyle(.primary).fontWeight(.bold).frame(width: 10)
+//                    }
+//
+//                    if context.state.showUpdatedLabel {
+//                        updatedLabel(context: context)
+//                    }
+//                }
             })
                 .privacySensitive()
                 .padding(.all, 14)
@@ -520,6 +551,7 @@ private extension LiveActivityAttributes.ContentState {
             showIOB: true,
             showCurrentGlucose: true,
             showUpdatedLabel: true,
+            itemOrder: ["currentGlucose", "iob", "cob", "updatedLabel"],
             isInitialState: false
         )
     }
@@ -535,6 +567,7 @@ private extension LiveActivityAttributes.ContentState {
             showIOB: true,
             showCurrentGlucose: true,
             showUpdatedLabel: true,
+            itemOrder: ["currentGlucose", "iob", "cob", "updatedLabel"],
             isInitialState: false
         )
     }
@@ -550,6 +583,7 @@ private extension LiveActivityAttributes.ContentState {
             showIOB: true,
             showCurrentGlucose: true,
             showUpdatedLabel: true,
+            itemOrder: ["currentGlucose", "iob", "cob", "updatedLabel"],
             isInitialState: false
         )
     }
@@ -566,6 +600,7 @@ private extension LiveActivityAttributes.ContentState {
             showIOB: true,
             showCurrentGlucose: true,
             showUpdatedLabel: true,
+            itemOrder: ["currentGlucose", "iob", "cob", "updatedLabel"],
             isInitialState: false
         )
     }
@@ -581,6 +616,7 @@ private extension LiveActivityAttributes.ContentState {
             showIOB: true,
             showCurrentGlucose: true,
             showUpdatedLabel: true,
+            itemOrder: ["currentGlucose", "iob", "cob", "updatedLabel"],
             isInitialState: false
         )
     }
@@ -596,6 +632,7 @@ private extension LiveActivityAttributes.ContentState {
             showIOB: true,
             showCurrentGlucose: true,
             showUpdatedLabel: true,
+            itemOrder: ["currentGlucose", "iob", "cob", "updatedLabel"],
             isInitialState: true
         )
     }

+ 1 - 0
Model/Helper/CustomNotification.swift

@@ -7,4 +7,5 @@ extension Notification.Name {
     static let didUpdateDetermination = Notification.Name("didUpdateDetermination")
     static let didUpdateOverrideConfiguration = Notification.Name("didUpdateOverrideConfiguration")
     static let didUpdateCobIob = Notification.Name("didUpdateCobIob")
+    static let liveActivityOrderDidChange = Notification.Name("liveActivityOrderDidChange")
 }