mirror of
https://github.com/exituser/Pearcleaner.git
synced 2026-09-17 06:09:01 +00:00
3.3.4
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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")
|
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user