From aba608b433a9dd7e218239947c2c983741fc7fc7 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Wed, 17 Jun 2026 20:42:14 +0800
Subject: [PATCH] Prepare 7.9.2 build 20260617.2028
---
src/Apptag/ContentView.swift | 109 +++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 99 insertions(+), 10 deletions(-)
diff --git a/src/Apptag/ContentView.swift b/src/Apptag/ContentView.swift
index e2bf1c7..745a918 100644
--- a/src/Apptag/ContentView.swift
+++ b/src/Apptag/ContentView.swift
@@ -82,6 +82,10 @@
}
func updateNSView(_ container: TextFieldContainer, context: Context) {
+ if let editor = container.textField.currentEditor() as? NSTextView,
+ editor.hasMarkedText() {
+ return
+ }
if container.textField.stringValue != text {
container.textField.stringValue = text
}
@@ -106,6 +110,9 @@
}
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
+ if textView.hasMarkedText() {
+ return false
+ }
if commandSelector == #selector(NSResponder.insertNewline(_:)) {
onSubmit?()
return true
@@ -350,9 +357,13 @@
@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
+ @State private var selectedUsageTipIndex = 0
+ @State private var usageTipsHovered = false
// Edit mode
@State private var editPhase: EditPhase = .none
@@ -414,6 +425,7 @@
@AppStorage("displayMode") private var displayMode = AppDefaults.displayMode
@AppStorage("hideAppNames") private var hideAppNames = AppDefaults.hideAppNames
@AppStorage("showUncommonAppBubbles") private var showUncommonAppBubbles = AppDefaults.showUncommonAppBubbles
+ @AppStorage("hideUsageTips") private var hideUsageTips = AppDefaults.hideUsageTips
@AppStorage("useAppKitTagNavigation") private var useAppKitTagNavigation = AppDefaults.useAppKitTagNavigation
@AppStorage("skipTagRemovalDropConfirm") private var skipTagRemovalDropConfirm = false
@AppStorage("skipUncategorizedDropConfirm") private var skipUncategorizedDropConfirm = false
@@ -423,7 +435,8 @@
private let floatingControlsTrailingInset: CGFloat = 20
private let floatingControlsReservedWidth: CGFloat = 120
private var appBubbleDisabled: Bool {
- appGridInteraction.appDragModeActive
+ usageTipsHovered
+ || appGridInteraction.appDragModeActive
|| appGridInteraction.pendingUncategorizedDrop != nil
|| appGridInteraction.pendingTagRemovalDrop != nil
}
@@ -432,8 +445,8 @@
?? (isColorlessContainerMode ? filledColorlessContainer : nil)
}
private let rightSidebarFloatingClearance: CGFloat = 44
+ private let tagNavigationHoverScrollDelay: TimeInterval = 0.14
private let tagNavigationHoverScrollInterval: TimeInterval = 0.22
-
private var floatingButtonSurfaceColor: Color {
colorScheme == .dark
? Color.white.opacity(0.10)
@@ -450,6 +463,23 @@
private var isColorlessContainerMode: Bool {
displayMode == "container" || displayMode == "gridContainer"
+ }
+
+ private var shouldShowUsageTips: Bool {
+ !hideUsageTips && !allApps.isEmpty && !quickSearchOnlySession
+ }
+
+ private var appGridUsageTips: [AppGridUsageTip] {
+ [
+ AppGridUsageTip(id: 1, titleKey: "usageTips.tip1.title", detailKey: "usageTips.tip1.detail"),
+ AppGridUsageTip(id: 2, titleKey: "usageTips.tip2.title", detailKey: "usageTips.tip2.detail"),
+ AppGridUsageTip(id: 3, titleKey: "usageTips.tip3.title", detailKey: "usageTips.tip3.detail"),
+ AppGridUsageTip(id: 4, titleKey: "usageTips.tip4.title", detailKey: "usageTips.tip4.detail"),
+ AppGridUsageTip(id: 5, titleKey: "usageTips.tip5.title", detailKey: "usageTips.tip5.detail"),
+ AppGridUsageTip(id: 6, titleKey: "usageTips.tip6.title", detailKey: "usageTips.tip6.detail"),
+ AppGridUsageTip(id: 7, titleKey: "usageTips.tip7.title", detailKey: "usageTips.tip7.detail"),
+ AppGridUsageTip(id: 8, titleKey: "usageTips.tip8.title", detailKey: "usageTips.tip8.detail"),
+ ]
}
private var shouldRenderAppGridBehindQuickSearch: Bool {
@@ -623,6 +653,9 @@
.onChange(of: appGridInteraction.pendingTagRemovalDrop != nil) { _, _ in
publishModalInteractionState()
}
+ .onChange(of: smartStartNotice != nil) { _, _ in
+ publishModalInteractionState()
+ }
.onDisappear {
NotificationCenter.default.post(
name: .tagLauncherModalInteractionChanged,
@@ -636,7 +669,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
+ ]
)
}
@@ -1116,6 +1153,10 @@
bubbleDisabled: appBubbleDisabled,
showUncommonAppBubbles: showUncommonAppBubbles,
highlightedGroupName: appGridHighlightedGroupName,
+ bottomContentPadding: shouldShowUsageTips ? AppGridUsageTipsMetrics.reservedHeight : 0,
+ usageTipsVisible: shouldShowUsageTips,
+ usageTips: appGridUsageTips,
+ selectedUsageTipIndex: $selectedUsageTipIndex,
contentRevision: groupLayoutVersion,
scrollTargetID: appGridScrollTargetID,
scrollRequestToken: appGridScrollRequestToken,
@@ -1128,13 +1169,17 @@
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 {
toggleColorlessFill(groupName)
}
},
onScrollActivity: handleAppGridScrollActivity,
- onDragModeChange: { setAppDragMode($0) }
+ onDragModeChange: { setAppDragMode($0) },
+ onUsageTipsHoverChange: handleUsageTipsHoverChange
)
}
}
@@ -1775,13 +1820,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
}
@@ -1840,6 +1899,13 @@
private func handleAppGridScrollActivity() {
if appGridInteraction.hoveredBubble != nil {
+ appGridInteraction.hoveredBubble = nil
+ }
+ }
+
+ private func handleUsageTipsHoverChange(_ hovering: Bool) {
+ usageTipsHovered = hovering
+ if hovering, appGridInteraction.hoveredBubble != nil {
appGridInteraction.hoveredBubble = nil
}
}
@@ -1985,7 +2051,7 @@
}
private func handleTagNavigationHover(_ id: String, active: Bool) {
- if appGridInteraction.appDragModeActive {
+ if appGridInteraction.appDragModeActive || tagNavDragModeActive {
if !active, appGridInteraction.tagNavigationHoveredGroupName == id {
appGridInteraction.tagNavigationHoveredGroupName = nil
}
@@ -2001,7 +2067,7 @@
appGridInteraction.tagNavigationHoveredGroupName = id
fillColorlessContainer(id)
- scrollToTagFromHover(id)
+ scheduleTagNavigationHoverScroll(id)
}
private func handleTagNavigationAppDropHover(_ id: String, active: Bool) {
@@ -2020,6 +2086,14 @@
}
appGridInteraction.tagNavigationAppDropTargetName = id
+ }
+
+ private func scheduleTagNavigationHoverScroll(_ id: String) {
+ DispatchQueue.main.asyncAfter(deadline: .now() + tagNavigationHoverScrollDelay) {
+ guard appGridInteraction.tagNavigationHoveredGroupName == id else { return }
+ guard !appGridInteraction.appDragModeActive && !tagNavDragModeActive else { return }
+ scrollToTagFromHover(id)
+ }
}
private func scrollToTagFromHover(_ id: String) {
@@ -2136,6 +2210,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 +2223,6 @@
}
guard tagColors[targetTag] != nil else { return }
- guard sourceTag != targetTag || copy else { return }
TagEditor.moveApp(
path: path,
from: sourceTag,
@@ -2166,6 +2241,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 +2559,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