This commit is contained in:
Alin
2024-04-04 15:36:02 -06:00
parent c878458622
commit ce120df3b9
6 changed files with 198 additions and 93 deletions
+8 -8
View File
@@ -15,6 +15,7 @@
C71848442B8D2D600046CB13 /* ZombieView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C71848432B8D2D600046CB13 /* ZombieView.swift */; }; C71848442B8D2D600046CB13 /* ZombieView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C71848432B8D2D600046CB13 /* ZombieView.swift */; };
C72893052AFD42E600C8C1CD /* DeepLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = C72893042AFD42E600C8C1CD /* DeepLink.swift */; }; C72893052AFD42E600C8C1CD /* DeepLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = C72893042AFD42E600C8C1CD /* DeepLink.swift */; };
C72893122AFD51EA00C8C1CD /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = C72893112AFD51EA00C8C1CD /* main.swift */; }; C72893122AFD51EA00C8C1CD /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = C72893112AFD51EA00C8C1CD /* main.swift */; };
C74412C72BBF249000DDFCA8 /* AppPathsFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C74412C62BBF249000DDFCA8 /* AppPathsFetch.swift */; };
C7575D392B0182DE006A600A /* PearcleanerSentinel in CopyFiles */ = {isa = PBXBuildFile; fileRef = C728930F2AFD51EA00C8C1CD /* PearcleanerSentinel */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; C7575D392B0182DE006A600A /* PearcleanerSentinel in CopyFiles */ = {isa = PBXBuildFile; fileRef = C728930F2AFD51EA00C8C1CD /* PearcleanerSentinel */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
C76D08482AF83C3F00D07867 /* Update.swift in Sources */ = {isa = PBXBuildFile; fileRef = C76D08472AF83C3F00D07867 /* Update.swift */; }; C76D08482AF83C3F00D07867 /* Update.swift in Sources */ = {isa = PBXBuildFile; fileRef = C76D08472AF83C3F00D07867 /* Update.swift */; };
C76D084A2AF83C6E00D07867 /* General.swift in Sources */ = {isa = PBXBuildFile; fileRef = C76D08492AF83C6E00D07867 /* General.swift */; }; C76D084A2AF83C6E00D07867 /* General.swift in Sources */ = {isa = PBXBuildFile; fileRef = C76D08492AF83C6E00D07867 /* General.swift */; };
@@ -38,7 +39,6 @@
C7D31D512AFF00F300C7ED9E /* Locations.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D502AFF00F300C7ED9E /* Locations.swift */; }; C7D31D512AFF00F300C7ED9E /* Locations.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D502AFF00F300C7ED9E /* Locations.swift */; };
C7DC1FEE2B9F7D3D009AC317 /* features.json in Resources */ = {isa = PBXBuildFile; fileRef = C7DC1FED2B9F7D3D009AC317 /* features.json */; }; C7DC1FEE2B9F7D3D009AC317 /* features.json in Resources */ = {isa = PBXBuildFile; fileRef = C7DC1FED2B9F7D3D009AC317 /* features.json */; };
C7DD49EA2BAB4D8100CCBA16 /* AppInfoFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49E92BAB4D8100CCBA16 /* AppInfoFetch.swift */; }; C7DD49EA2BAB4D8100CCBA16 /* AppInfoFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49E92BAB4D8100CCBA16 /* AppInfoFetch.swift */; };
C7DD49EC2BAB58AA00CCBA16 /* AppPathsFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49EB2BAB58AA00CCBA16 /* AppPathsFetch.swift */; };
C7DD49EE2BAB7F6000CCBA16 /* ReversePathsFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49ED2BAB7F6000CCBA16 /* ReversePathsFetch.swift */; }; C7DD49EE2BAB7F6000CCBA16 /* ReversePathsFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49ED2BAB7F6000CCBA16 /* ReversePathsFetch.swift */; };
C7DD49F02BABA14400CCBA16 /* Folders.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49EF2BABA14400CCBA16 /* Folders.swift */; }; C7DD49F02BABA14400CCBA16 /* Folders.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49EF2BABA14400CCBA16 /* Folders.swift */; };
C7DE672B2BA6343D00EB1633 /* MenuBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DE672A2BA6343D00EB1633 /* MenuBarItem.swift */; }; C7DE672B2BA6343D00EB1633 /* MenuBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DE672A2BA6343D00EB1633 /* MenuBarItem.swift */; };
@@ -81,6 +81,7 @@
C72893042AFD42E600C8C1CD /* DeepLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLink.swift; sourceTree = "<group>"; }; C72893042AFD42E600C8C1CD /* DeepLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLink.swift; sourceTree = "<group>"; };
C728930F2AFD51EA00C8C1CD /* PearcleanerSentinel */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = PearcleanerSentinel; sourceTree = BUILT_PRODUCTS_DIR; }; C728930F2AFD51EA00C8C1CD /* PearcleanerSentinel */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = PearcleanerSentinel; sourceTree = BUILT_PRODUCTS_DIR; };
C72893112AFD51EA00C8C1CD /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; }; C72893112AFD51EA00C8C1CD /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
C74412C62BBF249000DDFCA8 /* AppPathsFetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPathsFetch.swift; sourceTree = "<group>"; };
C76D08472AF83C3F00D07867 /* Update.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Update.swift; sourceTree = "<group>"; }; C76D08472AF83C3F00D07867 /* Update.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Update.swift; sourceTree = "<group>"; };
C76D08492AF83C6E00D07867 /* General.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = General.swift; sourceTree = "<group>"; }; C76D08492AF83C6E00D07867 /* General.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = General.swift; sourceTree = "<group>"; };
C76D08502AF850F300D07867 /* About.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = About.swift; sourceTree = "<group>"; }; C76D08502AF850F300D07867 /* About.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = About.swift; sourceTree = "<group>"; };
@@ -106,7 +107,6 @@
C7D31D502AFF00F300C7ED9E /* Locations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Locations.swift; sourceTree = "<group>"; }; C7D31D502AFF00F300C7ED9E /* Locations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Locations.swift; sourceTree = "<group>"; };
C7DC1FED2B9F7D3D009AC317 /* features.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = features.json; sourceTree = SOURCE_ROOT; }; C7DC1FED2B9F7D3D009AC317 /* features.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = features.json; sourceTree = SOURCE_ROOT; };
C7DD49E92BAB4D8100CCBA16 /* AppInfoFetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppInfoFetch.swift; sourceTree = "<group>"; }; C7DD49E92BAB4D8100CCBA16 /* AppInfoFetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppInfoFetch.swift; sourceTree = "<group>"; };
C7DD49EB2BAB58AA00CCBA16 /* AppPathsFetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPathsFetch.swift; sourceTree = "<group>"; };
C7DD49ED2BAB7F6000CCBA16 /* ReversePathsFetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReversePathsFetch.swift; sourceTree = "<group>"; }; C7DD49ED2BAB7F6000CCBA16 /* ReversePathsFetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReversePathsFetch.swift; sourceTree = "<group>"; };
C7DD49EF2BABA14400CCBA16 /* Folders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Folders.swift; sourceTree = "<group>"; }; C7DD49EF2BABA14400CCBA16 /* Folders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Folders.swift; sourceTree = "<group>"; };
C7DE672A2BA6343D00EB1633 /* MenuBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarItem.swift; sourceTree = "<group>"; }; C7DE672A2BA6343D00EB1633 /* MenuBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarItem.swift; sourceTree = "<group>"; };
@@ -153,7 +153,7 @@
children = ( children = (
C77B90192AF1938F009CC655 /* Logic.swift */, C77B90192AF1938F009CC655 /* Logic.swift */,
C7DD49E92BAB4D8100CCBA16 /* AppInfoFetch.swift */, C7DD49E92BAB4D8100CCBA16 /* AppInfoFetch.swift */,
C7DD49EB2BAB58AA00CCBA16 /* AppPathsFetch.swift */, C74412C62BBF249000DDFCA8 /* AppPathsFetch.swift */,
C7DD49ED2BAB7F6000CCBA16 /* ReversePathsFetch.swift */, C7DD49ED2BAB7F6000CCBA16 /* ReversePathsFetch.swift */,
C77B90172AF19382009CC655 /* AppCommands.swift */, C77B90172AF19382009CC655 /* AppCommands.swift */,
C77B90152AF19377009CC655 /* AppState.swift */, C77B90152AF19377009CC655 /* AppState.swift */,
@@ -392,8 +392,8 @@
C77B90182AF19382009CC655 /* AppCommands.swift in Sources */, C77B90182AF19382009CC655 /* AppCommands.swift in Sources */,
C7D31D4A2AFEB26700C7ED9E /* AppListItems.swift in Sources */, C7D31D4A2AFEB26700C7ED9E /* AppListItems.swift in Sources */,
C77B901E2AF1A9DB009CC655 /* SettingsWindow.swift in Sources */, C77B901E2AF1A9DB009CC655 /* SettingsWindow.swift in Sources */,
C74412C72BBF249000DDFCA8 /* AppPathsFetch.swift in Sources */,
C7D31D482AFEB23700C7ED9E /* TopBar.swift in Sources */, C7D31D482AFEB23700C7ED9E /* TopBar.swift in Sources */,
C7DD49EC2BAB58AA00CCBA16 /* AppPathsFetch.swift in Sources */,
C7ACADE62B92A737000B5845 /* Features.swift in Sources */, C7ACADE62B92A737000B5845 /* Features.swift in Sources */,
C7F539382AF60865007DF1B2 /* Utilities.swift in Sources */, C7F539382AF60865007DF1B2 /* Utilities.swift in Sources */,
C76D08552AF89CDE00D07867 /* RegularMode.swift in Sources */, C76D08552AF89CDE00D07867 /* RegularMode.swift in Sources */,
@@ -575,7 +575,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 28; CURRENT_PROJECT_VERSION = 30;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
@@ -593,7 +593,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 3.3.2; MARKETING_VERSION = 3.3.4;
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner; PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
@@ -610,7 +610,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 28; CURRENT_PROJECT_VERSION = 30;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
@@ -628,7 +628,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 3.3.2; MARKETING_VERSION = 3.3.4;
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner; PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
+5 -3
View File
@@ -46,9 +46,11 @@ class AppInfoFetcher {
return nil return nil
} }
let appName = bundle.localizedInfoDictionary?[kCFBundleNameKey as String] as? String // let appName = bundle.localizedInfoDictionary?[kCFBundleNameKey as String] as? String
?? bundle.infoDictionary?["CFBundleName"] as? String // ?? bundle.infoDictionary?["CFBundleName"] as? String
?? path.deletingPathExtension().lastPathComponent // ?? path.deletingPathExtension().lastPathComponent
let appName = path.deletingPathExtension().lastPathComponent.capitalized
let appVersion = bundle.infoDictionary?["CFBundleShortVersionString"] as? String let appVersion = bundle.infoDictionary?["CFBundleShortVersionString"] as? String
?? bundle.infoDictionary?["CFBundleVersion"] as? String ?? bundle.infoDictionary?["CFBundleVersion"] as? String
+167 -73
View File
@@ -1,8 +1,8 @@
// //
// AppPathsFetch.swift // AppPathsFetch-NEW.swift
// Pearcleaner // Pearcleaner
// //
// Created by Alin Lupascu on 3/20/24. // Created by Alin Lupascu on 4/4/24.
// //
import Foundation import Foundation
@@ -14,35 +14,27 @@ class AppPathFinder {
private var appState: AppState private var appState: AppState
private var locations: Locations private var locations: Locations
private var backgroundRun: Bool private var backgroundRun: Bool
private var reverseAddon: Bool
private var completion: () -> Void = {} private var completion: () -> Void = {}
private var collection: [URL] = [] private var collection: [URL] = []
private let collectionAccessQueue = DispatchQueue(label: "com.alienator88.Pearcleaner.appPathFinder.collectionAccess") private let collectionAccessQueue = DispatchQueue(label: "com.alienator88.Pearcleaner.appPathFinder.collectionAccess")
@AppStorage("settings.general.instant") var instantSearch: Bool = true @AppStorage("settings.general.instant") var instantSearch: Bool = true
init(appInfo: AppInfo = .empty, appState: AppState, locations: Locations, backgroundRun: Bool = false, completion: @escaping () -> Void = {}) { init(appInfo: AppInfo = .empty, appState: AppState, locations: Locations, backgroundRun: Bool = false, reverseAddon: Bool = false, completion: @escaping () -> Void = {}) {
self.appInfo = appInfo self.appInfo = appInfo
self.appState = appState self.appState = appState
self.locations = locations self.locations = locations
self.backgroundRun = backgroundRun self.backgroundRun = backgroundRun
self.reverseAddon = reverseAddon
self.completion = completion self.completion = completion
} }
func findPaths() { func findPaths() {
Task(priority: .background) { Task(priority: .background) {
self.initialURLProcessing() self.initialURLProcessing()
let dispatchGroup = DispatchGroup() self.collectDirectories()
self.collectFiles()
for location in self.locations.apps.paths { self.finalizeCollection()
dispatchGroup.enter()
DispatchQueue.global(qos: .userInitiated).async {
self.processLocation(location, with: dispatchGroup)
dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: .main) {
self.finalizeCollection()
}
} }
} }
@@ -53,33 +45,93 @@ class AppPathFinder {
} }
} }
private func processLocation(_ location: String, with dispatchGroup: DispatchGroup) { private func collectDirectories() {
// Check if the directory exists before attempting to read its contents let dispatchGroup = DispatchGroup()
if FileManager.default.fileExists(atPath: location) {
do {
let contents = try FileManager.default.contentsOfDirectory(atPath: location)
for item in contents { for location in self.locations.apps.paths {
let itemURL = URL(fileURLWithPath: location).appendingPathComponent(item) dispatchGroup.enter()
let itemL = item.replacingOccurrences(of: ".", with: "").replacingOccurrences(of: " ", with: "").lowercased() DispatchQueue.global(qos: .userInitiated).async {
self.processDirectoryLocation(location)
dispatchGroup.leave()
}
}
if shouldSkipItem(itemL, at: itemURL) { continue } dispatchGroup.wait()
}
if specificCondition(itemL: itemL, itemURL: itemURL) { private func processDirectoryLocation(_ location: String) {
collectionAccessQueue.async { if let contents = try? FileManager.default.contentsOfDirectory(atPath: location) {
for item in contents {
let itemURL = URL(fileURLWithPath: location).appendingPathComponent(item)
let itemL = item.replacingOccurrences(of: ".", with: "").replacingOccurrences(of: " ", with: "").lowercased()
var isDirectory: ObjCBool = false
if FileManager.default.fileExists(atPath: itemURL.path, isDirectory: &isDirectory), isDirectory.boolValue {
// Perform the check to skip the item if needed
if shouldSkipItem(itemL, at: itemURL) {
continue
}
collectionAccessQueue.sync {
let alreadyIncluded = self.collection.contains { existingURL in
itemURL.path.hasPrefix(existingURL.path)
}
if !alreadyIncluded && specificCondition(itemL: itemL, itemURL: itemURL) {
self.collection.append(itemURL) self.collection.append(itemURL)
} }
} }
} }
} catch { // if FileManager.default.fileExists(atPath: itemURL.path, isDirectory: &isDirectory),
// If an error occurs while trying to read the directory's contents, log or handle it here if needed // isDirectory.boolValue,
printOS("Error processing location: \(location), \(error)") // !shouldSkipItem(itemL, at: itemURL),
// specificCondition(itemL: itemL, itemURL: itemURL) {
// collectionAccessQueue.sync {
// self.collection.append(itemURL)
// }
// }
} }
} else {
// The directory does not exist; skip it
} }
} }
private func collectFiles() {
let dispatchGroup = DispatchGroup()
for location in self.locations.apps.paths {
dispatchGroup.enter()
DispatchQueue.global(qos: .userInitiated).async {
self.processFileLocation(location)
dispatchGroup.leave()
}
}
dispatchGroup.wait()
}
private func processFileLocation(_ location: String) {
if let contents = try? FileManager.default.contentsOfDirectory(atPath: location) {
for item in contents {
let itemURL = URL(fileURLWithPath: location).appendingPathComponent(item)
let itemL = item.replacingOccurrences(of: ".", with: "").replacingOccurrences(of: " ", with: "").lowercased()
var isDirectory: ObjCBool = false
if FileManager.default.fileExists(atPath: itemURL.path, isDirectory: &isDirectory),
!isDirectory.boolValue,
!shouldSkipItem(itemL, at: itemURL),
specificCondition(itemL: itemL, itemURL: itemURL) {
collectionAccessQueue.sync {
let parentDirectory = itemURL.deletingLastPathComponent()
if !self.collection.contains(parentDirectory) {
self.collection.append(itemURL)
}
}
}
}
}
}
private func shouldSkipItem(_ itemL: String, at itemURL: URL) -> Bool { private func shouldSkipItem(_ itemL: String, at itemURL: URL) -> Bool {
var containsItem = false var containsItem = false
collectionAccessQueue.sync { collectionAccessQueue.sync {
@@ -88,6 +140,10 @@ class AppPathFinder {
return itemL.hasPrefix("comapple") && !["comappleconfigurator", "comappledt", "comappleiwork"].contains(where: itemL.hasPrefix) || containsItem || !isSupportedFileType(at: itemURL.path) return itemL.hasPrefix("comapple") && !["comappleconfigurator", "comappledt", "comappleiwork"].contains(where: itemL.hasPrefix) || containsItem || !isSupportedFileType(at: itemURL.path)
} }
private func specificCondition(itemL: String, itemURL: URL) -> Bool { private func specificCondition(itemL: String, itemURL: URL) -> Bool {
let bundleIdentifierL = self.appInfo.bundleIdentifier.pearFormat() let bundleIdentifierL = self.appInfo.bundleIdentifier.pearFormat()
let bundleComponents = self.appInfo.bundleIdentifier.components(separatedBy: ".").compactMap { $0 != "-" ? $0.lowercased() : nil } let bundleComponents = self.appInfo.bundleIdentifier.components(separatedBy: ".").compactMap { $0 != "-" ? $0.lowercased() : nil }
@@ -95,44 +151,57 @@ class AppPathFinder {
let nameL = self.appInfo.appName.pearFormat() let nameL = self.appInfo.appName.pearFormat()
let nameP = self.appInfo.path.lastPathComponent.replacingOccurrences(of: ".app", with: "") let nameP = self.appInfo.path.lastPathComponent.replacingOccurrences(of: ".app", with: "")
let exclusions = [
"comappledtxcode": ["comrobotsandpencilsxcodesapp", "comoneminutegamesxcodecleaner", "iohyperappxcodecleaner", "xcodesjson"],
"comrobotsandpencilsxcodesapp": ["comappledtxcode", "comoneminutegamesxcodecleaner", "iohyperappxcodecleaner"],
"iohyperappxcodecleaner": ["comrobotsandpencilsxcodesapp", "comoneminutegamesxcodecleaner", "comappledtxcode", "xcodesjson"]
]
if let excludedApps = exclusions[bundleIdentifierL], excludedApps.contains(where: { itemL.contains($0) }) {
return false
}
if bundleIdentifierL.contains("comappledtxcode") {
// Include items that are part of the Xcode ecosystem
if itemL.contains("comappledt") || itemL.contains("xcode") || itemL.contains("simulator") {
return true
}
}
if bundleIdentifierL.contains("uszoomxos") {
// Include items for Zoom that are not similar to the app name and/or bundle id
if itemL.contains("zoom") {
return true
}
}
if bundleIdentifierL.contains("combravebrowser") {
// Include items for Zoom that are not similar to the app name and/or bundle id
if itemL.contains("bravesoftware") {
return true
}
}
if bundleIdentifierL.contains("comlogioptionsplus") {
// Include items for Zoom that are not similar to the app name and/or bundle id
if itemL.contains("logi") && !itemL.contains("login") && !itemL.contains("logic") {
return true
}
}
if bundleIdentifierL.contains("commicrosoftvscode") {
// Include items for vscode
if itemL.contains("vscode") {
return true
}
}
if self.appInfo.webApp { if self.appInfo.webApp {
return itemL.contains(bundleIdentifierL) return itemL.contains(bundleIdentifierL)
} else {
if itemL.contains("xcode") && bundleIdentifierL.contains("comappledt") {
return !(itemURL.path.contains("comrobotsandpencilsxcodesapp") || itemURL.path.contains("comoneminutegamesxcodecleaner") || itemURL.path.contains("iohyperappxcodecleaner") || itemURL.path.contains("xcodesjson")) && (itemL.contains(bundle) || itemL.contains(bundleIdentifierL) || (nameL.count < 6 && itemL.contains(nameL)))
} else if itemL.contains("xcodes") && bundleIdentifierL.contains("comrobotsandpencilsxcodesapp") {
return !(itemURL.path.contains("comappledt")) && (itemL.contains(bundle) || itemL.contains(bundleIdentifierL) || (nameL.count > 4 && itemL.contains(nameL)))
} else {
return itemL.contains(bundleIdentifierL) || itemL.contains(bundle) || (nameL.count > 3 && itemL.contains(nameL)) || (nameP.count > 3 && itemL.contains(nameP))
}
}
}
private func filterParentDirectories(in collection: [URL]) -> [URL] {
// Normalize URLs by removing percent encoding and trailing slashes for accurate comparison
var filteredURLs: [URL] = []
let normalizedURLs = collection.map { url -> URL in
let path = url.path.removingPercentEncoding?.trimmingCharacters(in: CharacterSet(charactersIn: "/")) ?? ""
return URL(fileURLWithPath: path)
} }
for url in normalizedURLs { return itemL.contains(bundleIdentifierL) || itemL.contains(bundle) || (nameL.count > 3 && itemL.contains(nameL)) || (nameP.count > 3 && itemL.contains(nameP))
// Determine if 'url' is a parent of any path in 'filteredURLs'
if !filteredURLs.contains(where: { $0.absoluteString.hasPrefix(url.absoluteString) }) {
filteredURLs.append(url)
}
}
// Remove URLs that are parents of another URL in the list
filteredURLs = filteredURLs.filter { parentUrl in
!filteredURLs.contains { childUrl in
childUrl != parentUrl && childUrl.absoluteString.hasPrefix(parentUrl.absoluteString)
}
}
return filteredURLs
} }
@@ -166,20 +235,44 @@ class AppPathFinder {
return existingGroupContainers return existingGroupContainers
} }
private func handleOutliers() -> [URL] {
var outliers: [URL] = []
// Handle VSCode folder
if self.appInfo.bundleIdentifier.pearFormat().contains("commicrosoftvscode") {
let appSupportCodePath = "\(home)/Library/Application Support/Code"
if let codeDirectoryURL = URL(string: appSupportCodePath), FileManager.default.fileExists(atPath: codeDirectoryURL.path) {
outliers.append(codeDirectoryURL)
}
}
// Handle Xcode folder
if self.appInfo.bundleIdentifier.pearFormat().contains("comappledtxcode") {
let simulators = "\(home)/Library/Containers/com.apple.iphonesimulator.ShareExtension"
if let simulatorsURL = URL(string: simulators), FileManager.default.fileExists(atPath: simulatorsURL.path) {
outliers.append(simulatorsURL)
}
}
// Add other outlier cases here as needed
return outliers
}
private func finalizeCollection() { private func finalizeCollection() {
DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.global(qos: .userInitiated).async {
let groupContainers = self.getGroupContainers(bundleURL: self.appInfo.path) let groupContainers = self.getGroupContainers(bundleURL: self.appInfo.path)
let outliers = self.handleOutliers()
var tempCollection: [URL] = [] var tempCollection: [URL] = []
self.collectionAccessQueue.sync { self.collectionAccessQueue.sync {
tempCollection = self.collection tempCollection = self.collection
} }
tempCollection.append(contentsOf: groupContainers) tempCollection.append(contentsOf: groupContainers)
tempCollection.append(contentsOf: outliers)
// Apply the filter to remove parent directories
let filteredCollection = self.filterParentDirectories(in: tempCollection)
// Continue with the sorted collection // Continue with the sorted collection
let sortedCollection = filteredCollection.sorted(by: { $0.absoluteString < $1.absoluteString }) let sortedCollection = tempCollection.sorted(by: { $0.absoluteString < $1.absoluteString })
self.handlePostProcessing(sortedCollection: sortedCollection) self.handlePostProcessing(sortedCollection: sortedCollection)
} }
@@ -217,11 +310,12 @@ class AppPathFinder {
self.appState.instantProgress += 1 self.appState.instantProgress += 1
} }
// Append object to store if running reverse search with empty store
if self.reverseAddon {
self.appState.appInfoStore.append(self.appInfo)
}
self.completion() self.completion()
} }
} }
} }
//assert(!Thread.isMainThread, "This method should not run on the main thread")
+18 -7
View File
@@ -123,30 +123,41 @@ func loadAllPaths(allApps: [AppInfo], appState: AppState, locations: Locations,
for app in allApps { for app in allApps {
dispatchGroup.enter() dispatchGroup.enter()
DispatchQueue.global(qos: .background).async { DispatchQueue.global(qos: .background).async {
let pathFinder = AppPathFinder(appInfo: app, appState: appState, locations: locations, backgroundRun: true) let pathFinder = AppPathFinder(appInfo: app, appState: appState, locations: locations, backgroundRun: true, reverseAddon: reverseAddon)
pathFinder.findPaths() pathFinder.findPaths()
dispatchGroup.leave() dispatchGroup.leave()
} }
} }
DispatchQueue.global(qos: .background).async { dispatchGroup.notify(queue: DispatchQueue.global(qos: .background)) {
_ = dispatchGroup.wait(timeout: .now() + 60)
func checkAllAppsProcessed(retryCount: Int = 0, maxRetry: Int = 120) { func checkAllAppsProcessed(retryCount: Int = 0, maxRetry: Int = 120) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
if appState.appInfoStore.count == allApps.count { if appState.appInfoStore.count == allApps.count {
if reverseAddon { if reverseAddon {
let reverse = ReversePathsSearcher(appState: appState, locations: locations) let reverse = ReversePathsSearcher(appState: appState, locations: locations)
reverse.reversePathsSearch() reverse.reversePathsSearch() {
updateOnMain {
appState.showProgress = false
}
}
} }
// Reset progress values to 0 // Reset progress values to 0
appState.instantProgress = 0 updateOnMain {
appState.instantTotal = 0 appState.instantProgress = 0
appState.instantTotal = 0
appState.showProgress = false
}
completion() completion()
} else if retryCount < maxRetry { } else if retryCount < maxRetry {
checkAllAppsProcessed(retryCount: retryCount + 1, maxRetry: maxRetry) checkAllAppsProcessed(retryCount: retryCount + 1, maxRetry: maxRetry)
} else { } else {
// Reset progress values to 0
updateOnMain {
appState.instantProgress = 0
appState.instantTotal = 0
appState.showProgress = false
}
printOS("loadAllPaths - Retry limit reached. Not all paths were loaded.") printOS("loadAllPaths - Retry limit reached. Not all paths were loaded.")
completion() completion()
} }
-1
View File
@@ -206,7 +206,6 @@ struct Header: View {
if instantSearch { if instantSearch {
loadAllPaths(allApps: sortedApps, appState: appState, locations: locations) { loadAllPaths(allApps: sortedApps, appState: appState, locations: locations) {
appState.reload.toggle() appState.reload.toggle()
} }
} else { } else {
appState.reload.toggle() appState.reload.toggle()
-1
View File
@@ -82,7 +82,6 @@ struct TopBarMini: View {
if instantSearch { if instantSearch {
let reverse = ReversePathsSearcher(appState: appState, locations: locations) let reverse = ReversePathsSearcher(appState: appState, locations: locations)
reverse.reversePathsSearch() reverse.reversePathsSearch()
// reversePathsSearch(appState: appState, locations: locations)
} else { } else {
loadAllPaths(allApps: appState.sortedApps, appState: appState, locations: locations, reverseAddon: true) loadAllPaths(allApps: appState.sortedApps, appState: appState, locations: locations, reverseAddon: true)
} }