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

Refactor widget addition and deletion to avoid broken dragndrop

Deniz Cengiz 1 год назад
Родитель
Сommit
e208eeb589

+ 129 - 31
FreeAPS/Sources/Modules/LiveActivitySettings/View/LiveActivityWidgetConfiguration.swift

@@ -15,9 +15,11 @@ struct LiveActivityWidgetConfiguration: BaseView {
 
     @State private var isEditMode: Bool = false
     @State private var draggingItem: LiveActivityItem?
+    @State private var itemToDelete: LiveActivityItem?
     @State private var showDeleteAlert: Bool = false
 
     @Environment(\.colorScheme) var colorScheme
+    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
 
     private var color: LinearGradient {
         colorScheme == .dark ? LinearGradient(
@@ -230,67 +232,163 @@ struct LiveActivityWidgetConfiguration: BaseView {
 
     var body: some View {
         VStack {
-            dummyChart
+            Group {
+                VStack(alignment: .leading, spacing: 0) {
+                    Text("Live Activity Personalization".uppercased())
+                        .frame(maxWidth: .infinity, alignment: .leading)
+                        .foregroundColor(.secondary)
+                        .font(.footnote)
+                        .padding(.leading)
+                }
+                VStack {
+                    Text(
+                        "Trio offers you to customize your Live Activity lock screen widget. The default configuration will display current glucose, IOB, COB and the time of last algorithm run."
+                    )
+                    .padding()
+                    .font(.footnote)
+                    .foregroundColor(.secondary)
+                }
+                .background(
+                    RoundedRectangle(cornerRadius: 10, style: .continuous)
+                        .fill(Color.chart)
+                )
+            }
 
-            HStack {
-                ForEach(0 ..< 4) { index in
-                    widgetButton(for: index)
+            GroupBox {
+                VStack {
+                    dummyChart
+
+                    HStack(spacing: 15) {
+                        ForEach(0 ..< 4) { index in
+                            widgetButton(for: index)
+                        }
+                    }
+                    .padding()
+                    .overlay(
+                        RoundedRectangle(cornerRadius: 12)
+                            .stroke(style: StrokeStyle(lineWidth: 2, dash: [5]))
+                            .foregroundColor(.gray)
+                    )
+                    .cornerRadius(12)
                 }
+
+            }.padding(.vertical).groupBoxStyle(.dummyChart)
+
+            if isEditMode {
+                Group {
+                    Button {
+                        saveOrder()
+                        isEditMode = false
+                    } label: {
+                        Text("Save Configuration")
+                            .frame(maxWidth: .infinity, alignment: .center)
+                            .tint(Color.white)
+                            .background(Color(.systemBlue))
+                    }
+                    .padding(.vertical)
+                    .tint(Color(.systemBlue))
+                    .buttonStyle(.borderedProminent)
+                    .cornerRadius(12)
+                }.padding(.vertical)
             }
-            .padding()
+
+            Spacer()
         }
         .padding()
         .scrollContentBackground(.hidden).background(color)
         .navigationTitle("Widget Configuration")
         .navigationBarTitleDisplayMode(.automatic)
+        .toolbar {
+            ToolbarItem(placement: .topBarTrailing) {
+                Button {
+                    isEditMode.toggle()
+                } label: {
+                    Text(isEditMode ? "Cancel" : "Edit")
+                }
+            }
+        }
         .onAppear {
             loadOrder() // Load the saved order when the view appears
         }
         .confirmationDialog("Add Widget", isPresented: $showAddItemDialog, titleVisibility: .visible) {
-            ForEach(LiveActivityItem.allCases, id: \.self) { item in
+            ForEach(LiveActivityItem.allCases.filter { !selectedItems.contains($0) }, id: \.self) { item in
                 Button(item.displayName) {
                     if let index = buttonIndexToUpdate {
-                        selectedItems[index] = item // Update button index to selected item
+                        if index == selectedItems.count {
+                            selectedItems.append(item) // Item will be last element in array, just append
+                        } else {
+                            selectedItems[index] = item // Update button index to selected item
+                        }
                         saveOrder() // Save the order to UserDefaults
                     }
                 }
-                .disabled(selectedItems.contains(item))
-                // This causes the type check error
-
-//                .disabled(selectedItems.contains { $0.value == item }) // Disable already selected items
             }
         }
     }
 
     @ViewBuilder private func widgetButton(for index: Int) -> some View {
-        Button(action: {
-            buttonIndexToUpdate = index
-            showAddItemDialog.toggle()
-        }) {
-            // This causes an index out of range error
-
-//            if let selectedItem = LiveActivityItem.allCases.first(where: { $0.id == selectedItems[index].id }) {
-//                // Show item preview if an item is selected
-//                getItemPreview(for: selectedItem)
-//            }
-            if index < selectedItems.count {
-                // Zeige Vorschau, wenn ein Item ausgewählt wurde
-                let selectedItem = selectedItems[index]
+        if index < selectedItems.count {
+            let selectedItem = selectedItems[index]
+
+            ZStack(alignment: .topTrailing) {
                 getItemPreview(for: selectedItem)
-            } else {
-                // Show "+" symbol if no item is selected
+                    .frame(width: 50, height: 50)
+                    .padding(5)
+                    .background(Color.clear)
+                    .cornerRadius(12)
+                    .overlay(
+                        RoundedRectangle(cornerRadius: 12)
+                            .stroke(
+                                Color.primary,
+                                lineWidth: 1
+                            )
+                    )
+
+                if isEditMode {
+                    Button(action: {
+                        showDeleteAlert = true
+                        itemToDelete = selectedItem
+                    }) {
+                        Image(systemName: "minus.circle.fill")
+                            .foregroundColor(Color(UIColor.systemGray2)) // Opaque foreground color
+                            .background(Color.white) // Adding a background for contrast
+                            .clipShape(Circle()) // Make sure the background stays circular
+                            .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")) {
+                                if let itemToDelete = itemToDelete {
+                                    removeItem(itemToDelete)
+                                }
+                            },
+                            secondaryButton: .cancel()
+                        )
+                    }
+                }
+            }
+        } else {
+            // Show "+" symbol if no item is selected
+            Button(action: {
+                buttonIndexToUpdate = index
+                showAddItemDialog.toggle()
+            }) {
                 VStack {
                     Image(systemName: "plus")
                         .font(.title2)
-                        .foregroundColor(.gray)
+                        .foregroundColor(.accentColor)
                 }
-                .frame(width: 60, height: 40)
+                .frame(width: 50, height: 50)
+                .padding(5)
                 .overlay(
                     RoundedRectangle(cornerRadius: 12)
-                        .stroke(style: StrokeStyle(lineWidth: 2, dash: [5]))
-                        .foregroundColor(.gray)
+                        .stroke(style: StrokeStyle(lineWidth: 1, dash: [5]))
+                        .foregroundColor(.primary)
                 )
-            }
+            }.buttonStyle(.plain)
         }
     }