Quellcode durchsuchen

Fix panel app ordering and drag-to-reorder

huzaifahayat12 vor 4 Monaten
Ursprung
Commit
a987bec73a
1 geänderte Dateien mit 38 neuen und 5 gelöschten Zeilen
  1. 38 5
      google_apps/LauncherRootView.swift

+ 38 - 5
google_apps/LauncherRootView.swift

@@ -15,6 +15,7 @@ struct LauncherRootView: View {
     @State private var customApps: [LauncherApp] = []
     @State private var appOrder: [UUID] = []
     @State private var draggedAppID: UUID?
+    @State private var lastDropDestinationAppID: UUID?
     @State private var layoutMode: LayoutMode = .grid
     @AppStorage("customLauncherAppsData") private var customAppsData = ""
     @AppStorage("launcherAppOrderData") private var appOrderData = ""
@@ -114,9 +115,15 @@ struct LauncherRootView: View {
                     .frame(maxWidth: .infinity, maxHeight: .infinity)
                 } else {
                     if layoutMode == .panel {
-                        IconPanelView(apps: filteredApps) { app in
-                            handleAppTap(app)
-                        }
+                        IconPanelView(
+                            apps: filteredApps,
+                            onAppTap: { app in
+                                handleAppTap(app)
+                            },
+                            draggedAppID: $draggedAppID,
+                            lastDropDestinationAppID: $lastDropDestinationAppID,
+                            onMove: moveApp
+                        )
                     } else {
                         ScrollView {
                             LazyVGrid(columns: columns, spacing: 20) {
@@ -126,6 +133,7 @@ struct LauncherRootView: View {
                                     }
                                     .onDrag {
                                         draggedAppID = app.id
+                                        lastDropDestinationAppID = nil
                                         return NSItemProvider(object: app.id.uuidString as NSString)
                                     }
                                     .onDrop(
@@ -133,6 +141,7 @@ struct LauncherRootView: View {
                                         delegate: TileReorderDropDelegate(
                                             destinationAppID: app.id,
                                             draggedAppID: $draggedAppID,
+                                            lastDropDestinationAppID: $lastDropDestinationAppID,
                                             onMove: moveApp
                                         )
                                     )
@@ -324,16 +333,22 @@ private struct PersistedCustomApp: Codable {
 private struct TileReorderDropDelegate: DropDelegate {
     let destinationAppID: UUID
     @Binding var draggedAppID: UUID?
+    @Binding var lastDropDestinationAppID: UUID?
     let onMove: (UUID, UUID) -> Void
 
     func dropEntered(info: DropInfo) {
         guard let draggedAppID else { return }
         guard draggedAppID != destinationAppID else { return }
+        // SwiftUI may call `dropEntered` multiple times while hovering the same tile.
+        // Avoid reordering repeatedly to keep drag-to-reorder stable.
+        guard lastDropDestinationAppID != destinationAppID else { return }
+        lastDropDestinationAppID = destinationAppID
         onMove(draggedAppID, destinationAppID)
     }
 
     func performDrop(info: DropInfo) -> Bool {
         draggedAppID = nil
+        lastDropDestinationAppID = nil
         return true
     }
 }
@@ -398,6 +413,9 @@ private struct SearchHeader: View {
 private struct IconPanelView: View {
     let apps: [LauncherApp]
     let onAppTap: (LauncherApp) -> Void
+    @Binding var draggedAppID: UUID?
+    @Binding var lastDropDestinationAppID: UUID?
+    let onMove: (UUID, UUID) -> Void
 
     private let actions = [
         "house", "magnifyingglass", "target", "map", "heart", "person.2", "clock",
@@ -408,7 +426,7 @@ private struct IconPanelView: View {
         ScrollView {
             HStack(alignment: .top, spacing: 20) {
                 VStack(alignment: .leading, spacing: 12) {
-                    ForEach(Array(apps.prefix(10))) { app in
+                    ForEach(apps) { app in
                         Button(action: { onAppTap(app) }) {
                             HStack(spacing: 14) {
                                 AppIconGlyph(app: app)
@@ -422,13 +440,28 @@ private struct IconPanelView: View {
                             .padding(.vertical, 3)
                         }
                         .buttonStyle(.plain)
+                        .onDrag {
+                            // Used by the reorder drop delegate (no need to parse the drop payload).
+                            draggedAppID = app.id
+                            lastDropDestinationAppID = nil
+                            return NSItemProvider(object: app.id.uuidString as NSString)
+                        }
+                        .onDrop(
+                            of: [UTType.text],
+                            delegate: TileReorderDropDelegate(
+                                destinationAppID: app.id,
+                                draggedAppID: $draggedAppID,
+                                lastDropDestinationAppID: $lastDropDestinationAppID,
+                                onMove: onMove
+                            )
+                        )
                     }
                     Spacer(minLength: 0)
                 }
                 .frame(width: 320, alignment: .topLeading)
 
                 VStack(alignment: .trailing, spacing: 14) {
-                    ForEach(Array(apps.prefix(10).enumerated()), id: \.offset) { index, _ in
+                    ForEach(Array(apps.enumerated()), id: \.element.id) { index, _ in
                         HStack(spacing: 12) {
                             ForEach(0..<8, id: \.self) { col in
                                 let symbol = actions[(index * 3 + col) % actions.count]