From cc75eee3160d200410dd84e5361dc11af7f01baa Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Fri, 12 Jun 2026 11:22:51 +0800
Subject: [PATCH] Prepare 7.9.0 App Store build metadata

---
 src/Apptag/ContentView.swift |   68 +++++++++++++++++++++++-----------
 1 files changed, 46 insertions(+), 22 deletions(-)

diff --git a/src/Apptag/ContentView.swift b/src/Apptag/ContentView.swift
index e2bf1c7..1afa3e3 100644
--- a/src/Apptag/ContentView.swift
+++ b/src/Apptag/ContentView.swift
@@ -319,8 +319,6 @@
     var bubbleDraftNote = ""
     var tagNavigationHoveredGroupName: String? = nil
     var tagNavigationAppDropTargetName: String? = nil
-    var tagNavigationLastHoverScrollID: String? = nil
-    var tagNavigationLastHoverScrollAt: Date? = nil
 }
 
 private struct EditActionFeedback: Identifiable {
@@ -350,6 +348,8 @@
     @State private var allApps: [AppInfo] = []
     @State private var displayGroups: [TagGroup] = []
     @State private var tagColors: [String: Int] = [:]
+    @State private var tagDefinitions: [String: TagDatabase.TagDef] = [:]
+    @State private var containerAppOrder: [String: [String]] = [:]
     @State private var groupLayoutVersion = 0
     @State private var appGridScrollTargetID: String? = nil
     @State private var appGridScrollRequestToken = 0
@@ -432,8 +432,6 @@
             ?? (isColorlessContainerMode ? filledColorlessContainer : nil)
     }
     private let rightSidebarFloatingClearance: CGFloat = 44
-    private let tagNavigationHoverScrollInterval: TimeInterval = 0.22
-
     private var floatingButtonSurfaceColor: Color {
         colorScheme == .dark
             ? Color.white.opacity(0.10)
@@ -623,6 +621,9 @@
         .onChange(of: appGridInteraction.pendingTagRemovalDrop != nil) { _, _ in
             publishModalInteractionState()
         }
+        .onChange(of: smartStartNotice != nil) { _, _ in
+            publishModalInteractionState()
+        }
         .onDisappear {
             NotificationCenter.default.post(
                 name: .tagLauncherModalInteractionChanged,
@@ -636,7 +637,11 @@
         NotificationCenter.default.post(
             name: .tagLauncherModalInteractionChanged,
             object: nil,
-            userInfo: ["active": appGridInteraction.pendingUncategorizedDrop != nil || appGridInteraction.pendingTagRemovalDrop != nil]
+            userInfo: [
+                "active": smartStartNotice != nil
+                    || appGridInteraction.pendingUncategorizedDrop != nil
+                    || appGridInteraction.pendingTagRemovalDrop != nil
+            ]
         )
     }
 
@@ -1127,6 +1132,9 @@
                     },
                     onDropOutsideGroup: { path, source, copy in
                         dropAppOutsideGroup(path: path, sourceTag: source, copy: copy)
+                    },
+                    onReorderApps: { containerID, orderedPaths in
+                        reorderApps(inContainer: containerID, orderedPaths: orderedPaths)
                     },
                     onGroupActivate: { groupName in
                         if isColorlessContainerMode {
@@ -1775,13 +1783,27 @@
 
     private func makeDisplayGroups(apps: [AppInfo], tagOrder: [String]) -> [TagGroup] {
         let order = tagOrder.isEmpty ? TagEditor.orderedTagNames() : tagOrder
-        let rawGroups = AppIndexer.group(apps: apps, defaultGroupName: defaultGroupName, tagOrder: order)
+        let rawGroups = AppIndexer.group(
+            apps: apps,
+            defaultGroupName: defaultGroupName,
+            tagOrder: order,
+            tagDefinitions: tagDefinitions,
+            containerAppOrder: containerAppOrder
+        )
         return rawGroups.map { group in
             if group.name == defaultGroupName {
-                return TagGroup(name: tr("group.uncategorized"), apps: group.apps)
+                return TagGroup(
+                    containerID: group.containerID,
+                    name: tr("group.uncategorized"),
+                    apps: group.apps
+                )
             }
             if group.name == "Mac自带" {
-                return TagGroup(name: tr("group.appleBuiltIn"), apps: group.apps)
+                return TagGroup(
+                    containerID: group.containerID,
+                    name: tr("group.appleBuiltIn"),
+                    apps: group.apps
+                )
             }
             return group
         }
@@ -2001,7 +2023,6 @@
 
         appGridInteraction.tagNavigationHoveredGroupName = id
         fillColorlessContainer(id)
-        scrollToTagFromHover(id)
     }
 
     private func handleTagNavigationAppDropHover(_ id: String, active: Bool) {
@@ -2020,18 +2041,6 @@
         }
 
         appGridInteraction.tagNavigationAppDropTargetName = id
-    }
-
-    private func scrollToTagFromHover(_ id: String) {
-        let now = Date()
-        if appGridInteraction.tagNavigationLastHoverScrollID == id,
-           let lastScrollAt = appGridInteraction.tagNavigationLastHoverScrollAt,
-           now.timeIntervalSince(lastScrollAt) < tagNavigationHoverScrollInterval {
-            return
-        }
-        appGridInteraction.tagNavigationLastHoverScrollID = id
-        appGridInteraction.tagNavigationLastHoverScrollAt = now
-        scrollTo(id)
     }
 
     private func fillColorlessContainer(_ id: String) {
@@ -2136,6 +2145,8 @@
     private func dropApp(path: String, sourceTag: String, targetTag: String, copy: Bool) {
         resetTransientDragState(keepingPendingUncategorizedDrop: true)
 
+        guard sourceTag != targetTag else { return }
+
         if isUncategorizedDropTarget(targetTag) {
             confirmAndMoveAppToUncategorized(path: path)
             return
@@ -2147,7 +2158,6 @@
         }
 
         guard tagColors[targetTag] != nil else { return }
-        guard sourceTag != targetTag || copy else { return }
         TagEditor.moveApp(
             path: path,
             from: sourceTag,
@@ -2166,6 +2176,18 @@
         guard !appHasTag(app, tagName: targetTag) else { return }
         TagEditor.appendTags([targetTag], to: [path])
         showDropRefresh()
+        refreshApps(forceLayoutRefresh: true)
+    }
+
+    private func reorderApps(inContainer containerID: String, orderedPaths: [String]) {
+        resetTransientDragState()
+        let key = TagDatabase.normalizedContainerID(containerID, tags: tagDefinitions)
+        let paths = TagDatabase.normalizedAppOrderPaths(orderedPaths)
+        guard !key.isEmpty, !paths.isEmpty else { return }
+
+        containerAppOrder[key] = paths
+        rebuildDisplayGroups(apps: allApps, tagOrder: draggedTagNames)
+        TagEditor.reorderApps(inContainer: key, orderedPaths: paths)
         refreshApps(forceLayoutRefresh: true)
     }
 
@@ -2472,6 +2494,8 @@
         allApps = snapshot.apps
         quickSearchDocuments = snapshot.quickSearchDocuments
         tagColors = snapshot.tagColors
+        tagDefinitions = snapshot.tagDefinitions
+        containerAppOrder = snapshot.containerAppOrder
         draggedTagNames = snapshot.tagOrder
         rebuildDisplayGroups(apps: snapshot.apps, tagOrder: snapshot.tagOrder)
         if quickSearchVisible {

--
Gitblit v1.9.3