From 2774b3ea8fbcc13dc69bbd2cde9e641eeb105679 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Thu, 11 Jun 2026 19:06:33 +0800
Subject: [PATCH] Add uncategorized layout reset option
---
src/Apptag/DataLayer.swift | 43 +++++++++++++++++++++++++++++++++++++------
1 files changed, 37 insertions(+), 6 deletions(-)
diff --git a/src/Apptag/DataLayer.swift b/src/Apptag/DataLayer.swift
index d6cd436..1cc92f4 100644
--- a/src/Apptag/DataLayer.swift
+++ b/src/Apptag/DataLayer.swift
@@ -334,7 +334,7 @@
}
}
- return deduplicated(apps).sorted {
+ return deduplicated(apps.filter { !isInternalHelperAppPath($0.path) }).sorted {
$0.name.localizedStandardCompare($1.name) == .orderedAscending
}
}
@@ -363,10 +363,10 @@
guard url.pathExtension.lowercased() == "app" else { return }
let displayURL = url.standardizedFileURL
- guard !isNestedInsideAppBundle(displayURL) else { return }
+ guard !isInternalHelperAppPath(displayURL) else { return }
let resolvedURL = displayURL.resolvingSymlinksInPath().standardizedFileURL
- guard !isNestedInsideAppBundle(resolvedURL) else { return }
+ guard !isInternalHelperAppPath(resolvedURL) else { return }
guard seenResolvedPaths.insert(resolvedURL.path).inserted else { return }
let bundle = Bundle(url: displayURL) ?? Bundle(url: resolvedURL)
@@ -624,11 +624,29 @@
}
static func isNestedInsideAppBundle(_ url: URL) -> Bool {
- let components = url.standardizedFileURL.pathComponents
- guard let lastAppIndex = components.lastIndex(where: { $0.lowercased().hasSuffix(".app") }) else {
+ isNestedInsideAppBundlePath(url.standardizedFileURL.path)
+ }
+
+ static func isInternalHelperAppPath(_ url: URL) -> Bool {
+ let path = url.standardizedFileURL.path
+ let lowercasedPath = path.lowercased()
+ return isNestedInsideAppBundlePath(path)
+ || lowercasedPath.contains("/contents/helpers/")
+ || lowercasedPath.contains("/contents/xpcservices/")
+ || lowercasedPath.contains("/wrapper/")
+ }
+
+ private static func isNestedInsideAppBundlePath(_ path: String) -> Bool {
+ let lowercasedPath = path.lowercased()
+ guard lowercasedPath.hasSuffix(".app") else { return false }
+ let components = lowercasedPath.split(separator: "/", omittingEmptySubsequences: true)
+ guard let lastAppIndex = components.lastIndex(where: { $0.hasSuffix(".app") }) else {
return false
}
- return components[..<lastAppIndex].contains { $0.lowercased().hasSuffix(".app") }
+ if components[..<lastAppIndex].contains(where: { $0.hasSuffix(".app") }) {
+ return true
+ }
+ return lowercasedPath.range(of: ".app/", options: .caseInsensitive) != nil
}
private static func deduplicated(_ apps: [AppInfo]) -> [AppInfo] {
@@ -1216,6 +1234,19 @@
return store
}
+ @discardableResult
+ static func resetAppTagAssignmentsToUncategorized() -> Store {
+ let previousStore = loadWithEnsuredCategoryScheme()
+ var store = previousStore
+ store.appTags = [:]
+ saveUserCategorySchemeMutation(
+ store,
+ previous: previousStore,
+ reason: "reset-uncategorized"
+ )
+ return loadWithEnsuredCategoryScheme()
+ }
+
private static func applyImportedCategorySchemeMetadata(to store: inout Store, importedFileURL url: URL) {
let importedCreatedAt = importedSchemeCreatedAt(from: url)
store.categoryScheme.currentCreatedAt = importedCreatedAt
--
Gitblit v1.9.3