From 9abd2554308521c72bd0c3b60f6e7f5e7a129a8b Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Mon, 18 May 2026 16:42:50 +0800
Subject: [PATCH] Fix built-in app grouping and bubble hover settings

---
 Apptag/Localization/cs.json       |    5 
 Apptag/Localization/no.json       |    5 
 Apptag/AppGridItem.swift          |   30 ++++-
 Apptag/Localization/zh-Hant.json  |    5 
 Apptag/Localization/ja.json       |    5 
 Apptag/Info.plist                 |    4 
 Apptag/Localization/th.json       |    5 
 Apptag/Localization/nl.json       |    5 
 Apptag/Localization/sr-Cyrl.json  |    5 
 Apptag/Localization/zh-Hans.json  |    5 
 Apptag/Localization/de.json       |    5 
 Apptag/Localization/ms.json       |    5 
 Apptag/Localization/nn.json       |    5 
 Apptag/Localization/pt-BR.json    |    5 
 Apptag/Localization/es.json       |    5 
 Apptag/Localization/tr.json       |    5 
 Apptag/Localization/en.json       |    5 
 Apptag/Localization/nb.json       |    5 
 Apptag/Localization/ar.json       |    5 
 Apptag/PreferencesView.swift      |   46 +++++++-
 Apptag/Localization/vi.json       |    5 
 Apptag/Localization/fr.json       |    5 
 Apptag/Localization/id.json       |    5 
 Apptag/Localization/da.json       |    5 
 CHANGELOG.md                      |    8 +
 Apptag/Localization/uk.json       |    5 
 Apptag/Localization/ar-Najdi.json |    5 
 Apptag/TagGroupView.swift         |    3 
 Apptag/Localization/ko.json       |    5 
 Apptag/ContentView.swift          |    6 +
 Apptag/DataLayer.swift            |   12 +
 Apptag/Localization/it.json       |    5 
 Apptag/Localization/sv.json       |    5 
 Apptag/Localization/ro.json       |    5 
 Apptag/Localization/pl.json       |    5 
 Apptag/Localization/ru.json       |    5 
 36 files changed, 207 insertions(+), 47 deletions(-)

diff --git a/Apptag/AppGridItem.swift b/Apptag/AppGridItem.swift
index 9848d88..5cda31b 100644
--- a/Apptag/AppGridItem.swift
+++ b/Apptag/AppGridItem.swift
@@ -12,9 +12,10 @@
     var onDragModeChange: ((Bool) -> Void)? = nil
     var onBubbleHover: ((AppInfo, CGRect, Bool) -> Void)? = nil
     var onEditNote: ((AppInfo, CGRect) -> Void)? = nil
+    var itemID: String
+    @Binding var hoveredAppItemID: String?
     let onSelect: () -> Void
 
-    @State private var isHovered = false
     @State private var wiggle = false
     @State private var interactionFrame: CGRect = .zero
     @AppStorage("showUncommonAppBubbles") private var showUncommonAppBubbles = AppDefaults.showUncommonAppBubbles
@@ -35,6 +36,7 @@
     private var iconSlotSize: CGFloat { iconSize * Self.hoverScale }
     private var labelWidth: CGFloat { iconSize + 20 }
     private var labelHeight: CGFloat { Self.labelHeight }
+    private var isHovered: Bool { hoveredAppItemID == itemID }
 
     var body: some View {
         VStack(spacing: 6) {
@@ -62,7 +64,7 @@
                 .lineLimit(1)
                 .truncationMode(.tail)
                 .frame(width: labelWidth, height: labelHeight)
-                .opacity(showName ? 1 : (isHovered ? 0.85 : 0))
+                .opacity(showName ? 1 : (shouldShowHoverName ? 0.85 : 0))
         }
         .padding(.vertical, 8)
         .padding(.horizontal, 4)
@@ -70,12 +72,15 @@
         .background(
             AppGridItemHoverTracker { hovering, frame in
                 interactionFrame = frame
-                setHoverState(hovering)
                 if hovering {
+                    setHoverState(true)
                     guard shouldShowAppBubble else { return }
                     onBubbleHover?(app, frame, hovering)
-                } else {
+                } else if isHovered {
+                    setHoverState(false)
                     onBubbleHover?(app, frame, hovering)
+                } else {
+                    setHoverState(false)
                 }
             }
         )
@@ -95,16 +100,29 @@
         .onChange(of: dragModeActive) { _, active in
             wiggle = active
         }
+        .onDisappear {
+            if hoveredAppItemID == itemID {
+                hoveredAppItemID = nil
+                onBubbleHover?(app, interactionFrame, false)
+            }
+        }
     }
 
     private var shouldShowAppBubble: Bool {
         !showUncommonAppBubbles || app.isUncommon
     }
 
+    private var shouldShowHoverName: Bool {
+        !showName && !shouldShowAppBubble && isHovered
+    }
+
     private func setHoverState(_ hovering: Bool) {
-        guard isHovered != hovering else { return }
         withAnimation(hovering ? Self.hoverInAnimation : Self.hoverOutAnimation) {
-            isHovered = hovering
+            if hovering {
+                hoveredAppItemID = itemID
+            } else if hoveredAppItemID == itemID {
+                hoveredAppItemID = nil
+            }
         }
     }
 }
diff --git a/Apptag/ContentView.swift b/Apptag/ContentView.swift
index 7cac627..045bb29 100644
--- a/Apptag/ContentView.swift
+++ b/Apptag/ContentView.swift
@@ -370,6 +370,7 @@
     @State private var refreshInProgress = false
     @State private var refreshAgainAfterCurrent = false
     @State private var refreshAgainForceLayout = false
+    @State private var hoveredAppItemID: String? = nil
     @State private var hoveredBubble: AppBubbleContext? = nil
     @State private var editingBubble: AppBubbleContext? = nil
     @State private var bubbleDraftNote = ""
@@ -825,6 +826,7 @@
                             onDragModeChange: { setAppDragMode($0) },
                             onBubbleHover: handleBubbleHover,
                             onEditNote: beginEditingBubbleNote,
+                            hoveredAppItemID: $hoveredAppItemID,
                             onDropApp: { path, source, copy in
                                 dropApp(path: path, sourceTag: source, targetTag: group.name, copy: copy)
                             }
@@ -927,6 +929,8 @@
                         onDragModeChange: { setAppDragMode($0) },
                         onBubbleHover: handleBubbleHover,
                         onEditNote: beginEditingBubbleNote,
+                        itemID: "\(group.name)|\(app.path.path)",
+                        hoveredAppItemID: $hoveredAppItemID,
                         onSelect: { openApp(app) }
                     )
                 }
@@ -1163,6 +1167,8 @@
                                 onDragModeChange: { setAppDragMode($0) },
                                 onBubbleHover: handleBubbleHover,
                                 onEditNote: beginEditingBubbleNote,
+                                itemID: "\(group.name)|\(app.path.path)",
+                                hoveredAppItemID: $hoveredAppItemID,
                                 onSelect: { openApp(app) }
                             )
                                 .frame(width: cellWidth)
diff --git a/Apptag/DataLayer.swift b/Apptag/DataLayer.swift
index 518258d..6b0f69a 100644
--- a/Apptag/DataLayer.swift
+++ b/Apptag/DataLayer.swift
@@ -220,12 +220,18 @@
         var seenAppIDsByGroup: [String: Set<URL>] = [:]
 
         for app in apps {
+            if app.isAppleApp {
+                appendGroupedApp(app, to: macCategory, groups: &dict, seenAppIDsByGroup: &seenAppIDsByGroup)
+            }
+
             if app.tags.isEmpty {
-                let bucket = app.isAppleApp ? macCategory : defaultGroupName
-                appendGroupedApp(app, to: bucket, groups: &dict, seenAppIDsByGroup: &seenAppIDsByGroup)
+                if !app.isAppleApp {
+                    appendGroupedApp(app, to: defaultGroupName, groups: &dict, seenAppIDsByGroup: &seenAppIDsByGroup)
+                }
             } else {
                 for tag in uniqueOrdered(app.tags) {
                     let displayName = nameOverrides[tag] ?? tag
+                    guard displayName != macCategory else { continue }
                     appendGroupedApp(app, to: displayName, groups: &dict, seenAppIDsByGroup: &seenAppIDsByGroup)
                 }
             }
@@ -1253,7 +1259,7 @@
         }
 
         var current = store.appTags[path] ?? []
-        if !copy, !sourceTag.isEmpty {
+        if !copy, !sourceTag.isEmpty, sourceTag != "Mac自带", sourceTag != tr("group.appleBuiltIn") {
             current.removeAll { $0 == sourceTag }
         }
         if !current.contains(targetTag) {
diff --git a/Apptag/Info.plist b/Apptag/Info.plist
index 51d99a2..206e0a3 100644
--- a/Apptag/Info.plist
+++ b/Apptag/Info.plist
@@ -19,9 +19,9 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>7.2.0</string>
+	<string>7.3.0</string>
 	<key>CFBundleVersion</key>
-	<string>738</string>
+	<string>739</string>
 	<key>LSMinimumSystemVersion</key>
 	<string>15.0</string>
 	<key>NSHighResolutionCapable</key>
diff --git a/Apptag/Localization/ar-Najdi.json b/Apptag/Localization/ar-Najdi.json
index 62de7ba..555de22 100644
--- a/Apptag/Localization/ar-Najdi.json
+++ b/Apptag/Localization/ar-Najdi.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "تم تطبيق %tagCount% تعيينات وسوم على %appCount% تطبيقات.",
   "settings.systemSchemeApplyFailed": "ما فيه نتائج تصنيف ذكي قابلة للتطبيق.",
   "scheme.local": "المخطط المحلي",
-  "scheme.systemSmartStart": "مخطط البداية الذكي للنظام"
+  "scheme.systemSmartStart": "مخطط البداية الذكي للنظام",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/ar.json b/Apptag/Localization/ar.json
index 7c33609..923f6e1 100644
--- a/Apptag/Localization/ar.json
+++ b/Apptag/Localization/ar.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "تم تطبيق %tagCount% تعيينات وسوم على %appCount% تطبيقات.",
   "settings.systemSchemeApplyFailed": "لا توجد نتائج تصنيف ذكي يمكن تطبيقها.",
   "scheme.local": "المخطط المحلي",
-  "scheme.systemSmartStart": "مخطط البداية الذكي للنظام"
+  "scheme.systemSmartStart": "مخطط البداية الذكي للنظام",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/cs.json b/Apptag/Localization/cs.json
index 391a630..13f25ff 100644
--- a/Apptag/Localization/cs.json
+++ b/Apptag/Localization/cs.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Použito %tagCount% přiřazení štítků pro %appCount% aplikací.",
   "settings.systemSchemeApplyFailed": "Nejsou k dispozici žádné výsledky chytré klasifikace.",
   "scheme.local": "Místní schéma",
-  "scheme.systemSmartStart": "Chytré počáteční schéma systému"
+  "scheme.systemSmartStart": "Chytré počáteční schéma systému",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/da.json b/Apptag/Localization/da.json
index ff31a99..0c8254a 100644
--- a/Apptag/Localization/da.json
+++ b/Apptag/Localization/da.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "%tagCount% tagtildelinger anvendt på %appCount% apps.",
   "settings.systemSchemeApplyFailed": "Ingen smarte klassificeringsresultater kan anvendes.",
   "scheme.local": "Lokalt skema",
-  "scheme.systemSmartStart": "Systemets smarte startskema"
+  "scheme.systemSmartStart": "Systemets smarte startskema",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/de.json b/Apptag/Localization/de.json
index cbc7782..696c07b 100644
--- a/Apptag/Localization/de.json
+++ b/Apptag/Localization/de.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "%tagCount% Tag-Zuordnungen auf %appCount% Apps angewendet.",
   "settings.systemSchemeApplyFailed": "Es sind keine intelligenten Klassifizierungsergebnisse verfügbar.",
   "scheme.local": "Lokales Schema",
-  "scheme.systemSmartStart": "Intelligentes System-Startschema"
+  "scheme.systemSmartStart": "Intelligentes System-Startschema",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/en.json b/Apptag/Localization/en.json
index 2f69fea..2be6257 100644
--- a/Apptag/Localization/en.json
+++ b/Apptag/Localization/en.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Applied %tagCount% tag assignments across %appCount% apps.",
   "settings.systemSchemeApplyFailed": "No smart classification results were available to apply.",
   "scheme.local": "Local scheme",
-  "scheme.systemSmartStart": "System smart initial scheme"
+  "scheme.systemSmartStart": "System smart initial scheme",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/es.json b/Apptag/Localization/es.json
index 639f90f..50e9885 100644
--- a/Apptag/Localization/es.json
+++ b/Apptag/Localization/es.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Se aplicaron %tagCount% asignaciones de etiquetas a %appCount% apps.",
   "settings.systemSchemeApplyFailed": "No hay resultados de clasificación inteligente para aplicar.",
   "scheme.local": "Esquema local",
-  "scheme.systemSmartStart": "Esquema inicial inteligente del sistema"
+  "scheme.systemSmartStart": "Esquema inicial inteligente del sistema",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/fr.json b/Apptag/Localization/fr.json
index 70da76a..c4c39c5 100644
--- a/Apptag/Localization/fr.json
+++ b/Apptag/Localization/fr.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "%tagCount% attributions de tags appliquées à %appCount% apps.",
   "settings.systemSchemeApplyFailed": "Aucun résultat de classification intelligente à appliquer.",
   "scheme.local": "Schéma local",
-  "scheme.systemSmartStart": "Schéma initial intelligent du système"
+  "scheme.systemSmartStart": "Schéma initial intelligent du système",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/id.json b/Apptag/Localization/id.json
index eed95fb..8134636 100644
--- a/Apptag/Localization/id.json
+++ b/Apptag/Localization/id.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Menerapkan %tagCount% penetapan tag pada %appCount% app.",
   "settings.systemSchemeApplyFailed": "Tidak ada hasil klasifikasi pintar yang dapat diterapkan.",
   "scheme.local": "Skema lokal",
-  "scheme.systemSmartStart": "Skema awal pintar sistem"
+  "scheme.systemSmartStart": "Skema awal pintar sistem",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/it.json b/Apptag/Localization/it.json
index cefd33c..0dfa553 100644
--- a/Apptag/Localization/it.json
+++ b/Apptag/Localization/it.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Applicate %tagCount% assegnazioni tag a %appCount% app.",
   "settings.systemSchemeApplyFailed": "Nessun risultato di classificazione intelligente disponibile.",
   "scheme.local": "Schema locale",
-  "scheme.systemSmartStart": "Schema iniziale intelligente di sistema"
+  "scheme.systemSmartStart": "Schema iniziale intelligente di sistema",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/ja.json b/Apptag/Localization/ja.json
index 5308e85..ec069c4 100644
--- a/Apptag/Localization/ja.json
+++ b/Apptag/Localization/ja.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "%appCount% 個のアプリに %tagCount% 件のタグ割り当てを適用しました。",
   "settings.systemSchemeApplyFailed": "適用できるスマート分類結果がありませんでした。",
   "scheme.local": "ローカル分類スキーム",
-  "scheme.systemSmartStart": "システム初期スマート分類"
+  "scheme.systemSmartStart": "システム初期スマート分類",
+  "settings.bubbleDisplayScope": "吹き出しの表示対象:",
+  "settings.bubbleAllApps": "すべてのアプリ",
+  "settings.bubbleUncommonOnly": "あまり使わないアプリのみ"
 }
diff --git a/Apptag/Localization/ko.json b/Apptag/Localization/ko.json
index dccbb8c..844b0df 100644
--- a/Apptag/Localization/ko.json
+++ b/Apptag/Localization/ko.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "%appCount%개의 앱에 %tagCount%개의 태그 할당을 적용했습니다.",
   "settings.systemSchemeApplyFailed": "적용할 수 있는 스마트 분류 결과가 없습니다.",
   "scheme.local": "로컬 분류 방식",
-  "scheme.systemSmartStart": "시스템 스마트 초기 분류"
+  "scheme.systemSmartStart": "시스템 스마트 초기 분류",
+  "settings.bubbleDisplayScope": "말풍선 표시 대상:",
+  "settings.bubbleAllApps": "모든 앱",
+  "settings.bubbleUncommonOnly": "자주 쓰지 않는 앱만"
 }
diff --git a/Apptag/Localization/ms.json b/Apptag/Localization/ms.json
index 18c3dd2..c5f57d9 100644
--- a/Apptag/Localization/ms.json
+++ b/Apptag/Localization/ms.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "%tagCount% tugasan tag digunakan pada %appCount% app.",
   "settings.systemSchemeApplyFailed": "Tiada hasil pengelasan pintar untuk digunakan.",
   "scheme.local": "Skema setempat",
-  "scheme.systemSmartStart": "Skema awal pintar sistem"
+  "scheme.systemSmartStart": "Skema awal pintar sistem",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/nb.json b/Apptag/Localization/nb.json
index eacb11f..656c969 100644
--- a/Apptag/Localization/nb.json
+++ b/Apptag/Localization/nb.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Brukte %tagCount% taggtildelinger på %appCount% apper.",
   "settings.systemSchemeApplyFailed": "Ingen smarte klassifiseringsresultater kan brukes.",
   "scheme.local": "Lokalt skjema",
-  "scheme.systemSmartStart": "Systemets smarte startskjema"
+  "scheme.systemSmartStart": "Systemets smarte startskjema",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/nl.json b/Apptag/Localization/nl.json
index dd9ca83..1f752ad 100644
--- a/Apptag/Localization/nl.json
+++ b/Apptag/Localization/nl.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "%tagCount% tagtoewijzingen toegepast op %appCount% apps.",
   "settings.systemSchemeApplyFailed": "Geen slimme classificatieresultaten beschikbaar om toe te passen.",
   "scheme.local": "Lokaal schema",
-  "scheme.systemSmartStart": "Slim beginschema van systeem"
+  "scheme.systemSmartStart": "Slim beginschema van systeem",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/nn.json b/Apptag/Localization/nn.json
index a1f05a2..41227a6 100644
--- a/Apptag/Localization/nn.json
+++ b/Apptag/Localization/nn.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Brukte %tagCount% taggtildelinger på %appCount% apper.",
   "settings.systemSchemeApplyFailed": "Ingen smarte klassifiseringsresultater kan brukes.",
   "scheme.local": "Lokalt skjema",
-  "scheme.systemSmartStart": "Systemets smarte startskjema"
+  "scheme.systemSmartStart": "Systemets smarte startskjema",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/no.json b/Apptag/Localization/no.json
index eacb11f..656c969 100644
--- a/Apptag/Localization/no.json
+++ b/Apptag/Localization/no.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Brukte %tagCount% taggtildelinger på %appCount% apper.",
   "settings.systemSchemeApplyFailed": "Ingen smarte klassifiseringsresultater kan brukes.",
   "scheme.local": "Lokalt skjema",
-  "scheme.systemSmartStart": "Systemets smarte startskjema"
+  "scheme.systemSmartStart": "Systemets smarte startskjema",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/pl.json b/Apptag/Localization/pl.json
index a5f4b48..1ebcbca 100644
--- a/Apptag/Localization/pl.json
+++ b/Apptag/Localization/pl.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Zastosowano %tagCount% przypisań tagów dla %appCount% aplikacji.",
   "settings.systemSchemeApplyFailed": "Brak wyników inteligentnej klasyfikacji do zastosowania.",
   "scheme.local": "Schemat lokalny",
-  "scheme.systemSmartStart": "Inteligentny schemat początkowy systemu"
+  "scheme.systemSmartStart": "Inteligentny schemat początkowy systemu",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/pt-BR.json b/Apptag/Localization/pt-BR.json
index 2412cac..3f20cb4 100644
--- a/Apptag/Localization/pt-BR.json
+++ b/Apptag/Localization/pt-BR.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Foram aplicadas %tagCount% atribuições de tags em %appCount% apps.",
   "settings.systemSchemeApplyFailed": "Não há resultados de classificação inteligente para aplicar.",
   "scheme.local": "Esquema local",
-  "scheme.systemSmartStart": "Esquema inicial inteligente do sistema"
+  "scheme.systemSmartStart": "Esquema inicial inteligente do sistema",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/ro.json b/Apptag/Localization/ro.json
index 0e7f37a..bfa075a 100644
--- a/Apptag/Localization/ro.json
+++ b/Apptag/Localization/ro.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Au fost aplicate %tagCount% atribuiri de etichete pentru %appCount% aplicații.",
   "settings.systemSchemeApplyFailed": "Nu există rezultate de clasificare inteligentă de aplicat.",
   "scheme.local": "Schema locală",
-  "scheme.systemSmartStart": "Schema inteligentă inițială a sistemului"
+  "scheme.systemSmartStart": "Schema inteligentă inițială a sistemului",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/ru.json b/Apptag/Localization/ru.json
index d050f63..a778443 100644
--- a/Apptag/Localization/ru.json
+++ b/Apptag/Localization/ru.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Применено %tagCount% назначений тегов для %appCount% приложений.",
   "settings.systemSchemeApplyFailed": "Нет результатов интеллектуальной классификации для применения.",
   "scheme.local": "Локальная схема",
-  "scheme.systemSmartStart": "Интеллектуальная начальная схема системы"
+  "scheme.systemSmartStart": "Интеллектуальная начальная схема системы",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/sr-Cyrl.json b/Apptag/Localization/sr-Cyrl.json
index a78473d..ca61f58 100644
--- a/Apptag/Localization/sr-Cyrl.json
+++ b/Apptag/Localization/sr-Cyrl.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Примењено је %tagCount% додела ознака за %appCount% апликација.",
   "settings.systemSchemeApplyFailed": "Нема резултата паметне класификације за примену.",
   "scheme.local": "Локална шема",
-  "scheme.systemSmartStart": "Паметна почетна шема система"
+  "scheme.systemSmartStart": "Паметна почетна шема система",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/sv.json b/Apptag/Localization/sv.json
index 65c3ec6..5c49131 100644
--- a/Apptag/Localization/sv.json
+++ b/Apptag/Localization/sv.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "%tagCount% taggtilldelningar tillämpades på %appCount% appar.",
   "settings.systemSchemeApplyFailed": "Inga smarta klassificeringsresultat kunde tillämpas.",
   "scheme.local": "Lokalt schema",
-  "scheme.systemSmartStart": "Systemets smarta startschema"
+  "scheme.systemSmartStart": "Systemets smarta startschema",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/th.json b/Apptag/Localization/th.json
index 7517594..4d4c8f6 100644
--- a/Apptag/Localization/th.json
+++ b/Apptag/Localization/th.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "นำการกำหนดแท็ก %tagCount% รายการไปใช้กับแอป %appCount% รายการแล้ว",
   "settings.systemSchemeApplyFailed": "ไม่มีผลการจัดหมวดหมู่อัจฉริยะให้ใช้",
   "scheme.local": "ชุดภายในเครื่อง",
-  "scheme.systemSmartStart": "ชุดเริ่มต้นอัจฉริยะของระบบ"
+  "scheme.systemSmartStart": "ชุดเริ่มต้นอัจฉริยะของระบบ",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/tr.json b/Apptag/Localization/tr.json
index 5772220..9be388a 100644
--- a/Apptag/Localization/tr.json
+++ b/Apptag/Localization/tr.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "%appCount% uygulamada %tagCount% etiket ataması uygulandı.",
   "settings.systemSchemeApplyFailed": "Uygulanacak akıllı sınıflandırma sonucu yok.",
   "scheme.local": "Yerel şema",
-  "scheme.systemSmartStart": "Sistem akıllı başlangıç şeması"
+  "scheme.systemSmartStart": "Sistem akıllı başlangıç şeması",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/uk.json b/Apptag/Localization/uk.json
index 6177c09..a8e5d2b 100644
--- a/Apptag/Localization/uk.json
+++ b/Apptag/Localization/uk.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Застосовано %tagCount% призначень тегів для %appCount% програм.",
   "settings.systemSchemeApplyFailed": "Немає результатів розумної класифікації для застосування.",
   "scheme.local": "Локальна схема",
-  "scheme.systemSmartStart": "Розумна початкова схема системи"
+  "scheme.systemSmartStart": "Розумна початкова схема системи",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/vi.json b/Apptag/Localization/vi.json
index 3e9ee56..af84dbf 100644
--- a/Apptag/Localization/vi.json
+++ b/Apptag/Localization/vi.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "Đã áp dụng %tagCount% gán thẻ cho %appCount% ứng dụng.",
   "settings.systemSchemeApplyFailed": "Không có kết quả phân loại thông minh để áp dụng.",
   "scheme.local": "Sơ đồ cục bộ",
-  "scheme.systemSmartStart": "Sơ đồ khởi tạo thông minh của hệ thống"
+  "scheme.systemSmartStart": "Sơ đồ khởi tạo thông minh của hệ thống",
+  "settings.bubbleDisplayScope": "Bubble tips show for:",
+  "settings.bubbleAllApps": "All apps",
+  "settings.bubbleUncommonOnly": "Uncommon apps only"
 }
diff --git a/Apptag/Localization/zh-Hans.json b/Apptag/Localization/zh-Hans.json
index fcc0c71..4708a12 100644
--- a/Apptag/Localization/zh-Hans.json
+++ b/Apptag/Localization/zh-Hans.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "已为 %appCount% 个应用应用 %tagCount% 个标签分配。",
   "settings.systemSchemeApplyFailed": "没有找到可应用的智能分类结果。",
   "scheme.local": "本地分类方案",
-  "scheme.systemSmartStart": "系统智能化初始分类"
+  "scheme.systemSmartStart": "系统智能化初始分类",
+  "settings.bubbleDisplayScope": "气泡提示框显示位置:",
+  "settings.bubbleAllApps": "全部应用",
+  "settings.bubbleUncommonOnly": "仅不常用应用"
 }
diff --git a/Apptag/Localization/zh-Hant.json b/Apptag/Localization/zh-Hant.json
index 6474ee7..66c44e1 100644
--- a/Apptag/Localization/zh-Hant.json
+++ b/Apptag/Localization/zh-Hant.json
@@ -139,5 +139,8 @@
   "settings.systemSchemeAppliedMessage": "已為 %appCount% 個 App 套用 %tagCount% 個標籤分配。",
   "settings.systemSchemeApplyFailed": "沒有找到可套用的智慧分類結果。",
   "scheme.local": "本機分類方案",
-  "scheme.systemSmartStart": "系統智慧化初始分類"
+  "scheme.systemSmartStart": "系統智慧化初始分類",
+  "settings.bubbleDisplayScope": "氣泡提示框顯示位置:",
+  "settings.bubbleAllApps": "全部 App",
+  "settings.bubbleUncommonOnly": "僅不常用 App"
 }
diff --git a/Apptag/PreferencesView.swift b/Apptag/PreferencesView.swift
index cd28edb..2ed9218 100644
--- a/Apptag/PreferencesView.swift
+++ b/Apptag/PreferencesView.swift
@@ -219,6 +219,25 @@
         return FileManager.default.fileExists(atPath: path)
     }
 
+    private func bubbleScopeOption(
+        _ title: String,
+        isSelected: Bool,
+        action: @escaping () -> Void
+    ) -> some View {
+        Button(action: action) {
+            HStack(spacing: 6) {
+                Image(systemName: isSelected ? "largecircle.fill.circle" : "circle")
+                    .font(.system(size: 13, weight: .medium))
+                    .frame(width: 16, height: 16)
+                Text(title)
+                    .font(.system(size: 13, weight: .medium))
+            }
+            .foregroundStyle(isSelected ? Color.accentColor : Color.primary)
+            .contentShape(Rectangle())
+        }
+        .buttonStyle(.plain)
+    }
+
     private func syncSelectedLanguage() {
         let code = L10n.currentCode
         guard selectedLanguage != code else { return }
@@ -580,15 +599,28 @@
 
                 Spacer(minLength: 22)
 
-                VStack(alignment: .leading, spacing: 5) {
-                    Toggle(tr("settings.uncommonBubble"), isOn: $showUncommonAppBubbles)
+                HStack(alignment: .center, spacing: 14) {
+                    Text(tr("settings.bubbleDisplayScope"))
                         .font(.system(size: 13, weight: .medium))
-                    Text(tr("settings.uncommonBubbleDesc"))
-                        .font(.caption)
-                        .foregroundStyle(.secondary)
-                        .fixedSize(horizontal: false, vertical: true)
+                        .frame(width: 190, alignment: .trailing)
+
+                    HStack(spacing: 20) {
+                        bubbleScopeOption(
+                            tr("settings.bubbleAllApps"),
+                            isSelected: !showUncommonAppBubbles
+                        ) {
+                            showUncommonAppBubbles = false
+                        }
+                        bubbleScopeOption(
+                            tr("settings.bubbleUncommonOnly"),
+                            isSelected: showUncommonAppBubbles
+                        ) {
+                            showUncommonAppBubbles = true
+                        }
+                    }
+                    .frame(width: 300, alignment: .leading)
                 }
-                .frame(width: 420, alignment: .leading)
+                .frame(width: 520, alignment: .center)
 
                 Spacer(minLength: 18)
             }
diff --git a/Apptag/TagGroupView.swift b/Apptag/TagGroupView.swift
index de24653..2ef0661 100644
--- a/Apptag/TagGroupView.swift
+++ b/Apptag/TagGroupView.swift
@@ -13,6 +13,7 @@
     var onDragModeChange: ((Bool) -> Void)? = nil
     var onBubbleHover: ((AppInfo, CGRect, Bool) -> Void)? = nil
     var onEditNote: ((AppInfo, CGRect) -> Void)? = nil
+    @Binding var hoveredAppItemID: String?
     var onDropApp: ((String, String, Bool) -> Void)? = nil
 
     /// Adaptive columns — auto-fit based on icon size and available width.
@@ -57,6 +58,8 @@
                         onDragModeChange: onDragModeChange,
                         onBubbleHover: onBubbleHover,
                         onEditNote: onEditNote,
+                        itemID: "\(group.name)|\(app.path.path)",
+                        hoveredAppItemID: $hoveredAppItemID,
                         onSelect: { onSelectApp(app) }
                     )
                 }
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 84248c8..57c95aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
 # Apptag Changelog
 
+## [7.3.0] — 2026-05-18
+
+- 修复 Apple 系统自带 App 被拖入其他标签后从「Mac自带」分组消失的问题,「Mac自带」现在作为客观属性始终保留
+- 气泡提示设置改为「全部应用 / 仅不常用应用」二选一,并补齐多语言文案
+- 统一 App 图标 hover 焦点状态,降低快速滑过、视图复用或同一 App 出现在多个分组时出现小名字残影的概率
+- 当气泡提示范围选择「全部应用」时,hover 不再额外显示 App 图标下方的小名字,避免和大气泡重复
+- 版本号更新为 `7.3.0`,Build 更新为 `739`
+
 ## [7.2.0] — 2026-05-18
 
 - 统筹优化 App hover 交互:容器、图标和气泡不再同时做大幅动画,避免快速滑过时出现慢动作和卡顿

--
Gitblit v1.9.3