3.0.2 fixes

This commit is contained in:
Alin
2024-03-04 15:32:40 -07:00
parent 7895996118
commit 583f0d40a5
18 changed files with 346 additions and 299 deletions
+19 -19
View File
@@ -15,7 +15,6 @@
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 */; };
C7575D382B0181FC006A600A /* FileWatcher in Frameworks */ = {isa = PBXBuildFile; productRef = C7575D372B0181FC006A600A /* FileWatcher */; };
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 */; };
@@ -30,6 +29,7 @@
C77B901E2AF1A9DB009CC655 /* SettingsWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B901D2AF1A9DB009CC655 /* SettingsWindow.swift */; }; C77B901E2AF1A9DB009CC655 /* SettingsWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B901D2AF1A9DB009CC655 /* SettingsWindow.swift */; };
C77B90232AF2D616009CC655 /* FilesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B90222AF2D616009CC655 /* FilesView.swift */; }; C77B90232AF2D616009CC655 /* FilesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B90222AF2D616009CC655 /* FilesView.swift */; };
C7A27E812AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist in Resources */ = {isa = PBXBuildFile; fileRef = C7A27E802AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist */; }; C7A27E812AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist in Resources */ = {isa = PBXBuildFile; fileRef = C7A27E802AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist */; };
C7A2AE5D2B9644F300161540 /* FileWatcher in Frameworks */ = {isa = PBXBuildFile; productRef = C7A2AE5C2B9644F300161540 /* FileWatcher */; };
C7A9CE472B89164700EB6E78 /* Authorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7A9CE462B89164700EB6E78 /* Authorization.swift */; }; C7A9CE472B89164700EB6E78 /* Authorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7A9CE462B89164700EB6E78 /* Authorization.swift */; };
C7ACADE62B92A737000B5845 /* Features.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7ACADE52B92A737000B5845 /* Features.swift */; }; C7ACADE62B92A737000B5845 /* Features.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7ACADE52B92A737000B5845 /* Features.swift */; };
C7CF47242B3B3F1700979C5F /* WindowSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7CF47232B3B3F1700979C5F /* WindowSettings.swift */; }; C7CF47242B3B3F1700979C5F /* WindowSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7CF47232B3B3F1700979C5F /* WindowSettings.swift */; };
@@ -37,6 +37,7 @@
C7D31D4A2AFEB26700C7ED9E /* AppListItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D492AFEB26700C7ED9E /* AppListItems.swift */; }; C7D31D4A2AFEB26700C7ED9E /* AppListItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D492AFEB26700C7ED9E /* AppListItems.swift */; };
C7D31D512AFF00F300C7ED9E /* Locations.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D502AFF00F300C7ED9E /* Locations.swift */; }; C7D31D512AFF00F300C7ED9E /* Locations.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D502AFF00F300C7ED9E /* Locations.swift */; };
C7F539382AF60865007DF1B2 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F539372AF60865007DF1B2 /* Utilities.swift */; }; C7F539382AF60865007DF1B2 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F539372AF60865007DF1B2 /* Utilities.swift */; };
C7FB173B2B96321300B96F9A /* AppsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7FB173A2B96321300B96F9A /* AppsListView.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@@ -95,6 +96,7 @@
C7D31D492AFEB26700C7ED9E /* AppListItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppListItems.swift; sourceTree = "<group>"; }; C7D31D492AFEB26700C7ED9E /* AppListItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppListItems.swift; sourceTree = "<group>"; };
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>"; };
C7F539372AF60865007DF1B2 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; }; C7F539372AF60865007DF1B2 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; };
C7FB173A2B96321300B96F9A /* AppsListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppsListView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -102,7 +104,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
C7575D382B0181FC006A600A /* FileWatcher in Frameworks */, C7A2AE5D2B9644F300161540 /* FileWatcher in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -146,7 +148,6 @@
C72893102AFD51EA00C8C1CD /* PearcleanerSentinel */ = { C72893102AFD51EA00C8C1CD /* PearcleanerSentinel */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
C7A27E822AFD996100166168 /* Resources */,
C7A27E7F2AFD70DD00166168 /* PearcleanerSentinel.entitlements */, C7A27E7F2AFD70DD00166168 /* PearcleanerSentinel.entitlements */,
C72893112AFD51EA00C8C1CD /* main.swift */, C72893112AFD51EA00C8C1CD /* main.swift */,
); );
@@ -224,17 +225,11 @@
C7D31D492AFEB26700C7ED9E /* AppListItems.swift */, C7D31D492AFEB26700C7ED9E /* AppListItems.swift */,
C7045A272B03E71D00376976 /* MiniMode.swift */, C7045A272B03E71D00376976 /* MiniMode.swift */,
C71848432B8D2D600046CB13 /* ZombieView.swift */, C71848432B8D2D600046CB13 /* ZombieView.swift */,
C7FB173A2B96321300B96F9A /* AppsListView.swift */,
); );
path = Views; path = Views;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
C7A27E822AFD996100166168 /* Resources */ = {
isa = PBXGroup;
children = (
);
path = Resources;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@@ -252,7 +247,7 @@
); );
name = PearcleanerSentinel; name = PearcleanerSentinel;
packageProductDependencies = ( packageProductDependencies = (
C7575D372B0181FC006A600A /* FileWatcher */, C7A2AE5C2B9644F300161540 /* FileWatcher */,
); );
productName = PeakPurgeMonitor; productName = PeakPurgeMonitor;
productReference = C728930F2AFD51EA00C8C1CD /* PearcleanerSentinel */; productReference = C728930F2AFD51EA00C8C1CD /* PearcleanerSentinel */;
@@ -306,7 +301,7 @@
); );
mainGroup = C77B8FF72AF18E2E009CC655; mainGroup = C77B8FF72AF18E2E009CC655;
packageReferences = ( packageReferences = (
C7575D362B0181F3006A600A /* XCRemoteSwiftPackageReference "FileWatcher" */, C7A2AE5B2B9644DA00161540 /* XCRemoteSwiftPackageReference "FileWatcher" */,
); );
productRefGroup = C77B90012AF18E2E009CC655 /* Products */; productRefGroup = C77B90012AF18E2E009CC655 /* Products */;
projectDirPath = ""; projectDirPath = "";
@@ -344,6 +339,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
C76D08482AF83C3F00D07867 /* Update.swift in Sources */, C76D08482AF83C3F00D07867 /* Update.swift in Sources */,
C7FB173B2B96321300B96F9A /* AppsListView.swift in Sources */,
C7045A342B068B2900376976 /* UpdateView.swift in Sources */, C7045A342B068B2900376976 /* UpdateView.swift in Sources */,
C77B90162AF19377009CC655 /* AppState.swift in Sources */, C77B90162AF19377009CC655 /* AppState.swift in Sources */,
C7045A322B068AD700376976 /* NewWin.swift in Sources */, C7045A322B068AD700376976 /* NewWin.swift in Sources */,
@@ -383,6 +379,7 @@
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
FRAMEWORK_SEARCH_PATHS = "";
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.PearcleanerSentinel; PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.PearcleanerSentinel;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@@ -400,6 +397,7 @@
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
FRAMEWORK_SEARCH_PATHS = "";
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.PearcleanerSentinel; PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.PearcleanerSentinel;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@@ -448,6 +446,7 @@
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_C_LANGUAGE_STANDARD = gnu17; GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
@@ -513,6 +512,7 @@
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_C_LANGUAGE_STANDARD = gnu17; GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -539,7 +539,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 = 20; CURRENT_PROJECT_VERSION = 21;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
@@ -557,7 +557,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 3.0.1; MARKETING_VERSION = 3.0.2;
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;
@@ -574,7 +574,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 = 20; CURRENT_PROJECT_VERSION = 21;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
@@ -592,7 +592,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 3.0.1; MARKETING_VERSION = 3.0.2;
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;
@@ -633,7 +633,7 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */
C7575D362B0181F3006A600A /* XCRemoteSwiftPackageReference "FileWatcher" */ = { C7A2AE5B2B9644DA00161540 /* XCRemoteSwiftPackageReference "FileWatcher" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/eonist/FileWatcher.git"; repositoryURL = "https://github.com/eonist/FileWatcher.git";
requirement = { requirement = {
@@ -644,9 +644,9 @@
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
C7575D372B0181FC006A600A /* FileWatcher */ = { C7A2AE5C2B9644F300161540 /* FileWatcher */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = C7575D362B0181F3006A600A /* XCRemoteSwiftPackageReference "FileWatcher" */; package = C7A2AE5B2B9644DA00161540 /* XCRemoteSwiftPackageReference "FileWatcher" */;
productName = FileWatcher; productName = FileWatcher;
}; };
/* End XCSwiftPackageProductDependency section */ /* End XCSwiftPackageProductDependency section */
+13 -8
View File
@@ -8,6 +8,7 @@
import SwiftUI import SwiftUI
struct AppCommands: Commands { struct AppCommands: Commands {
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
let appState: AppState let appState: AppState
let locations: Locations let locations: Locations
@@ -32,18 +33,20 @@ struct AppCommands: Commands {
Button { Button {
withAnimation(.easeInOut(duration: 0.5)) { withAnimation(.easeInOut(duration: 0.5)) {
// Refresh Apps list // Refresh Apps list
appState.reload.toggle()
let sortedApps = getSortedApps()
updateOnMain { updateOnMain {
appState.reload.toggle()
}
let sortedApps = getSortedApps()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
appState.sortedApps.userApps = [] appState.sortedApps.userApps = []
appState.sortedApps.systemApps = [] appState.sortedApps.systemApps = []
appState.sortedApps.userApps = sortedApps.userApps appState.sortedApps.userApps = sortedApps.userApps
appState.sortedApps.systemApps = sortedApps.systemApps appState.sortedApps.systemApps = sortedApps.systemApps
} if instantSearch {
Task(priority: .high){ Task(priority: .high){
loadAllPaths(allApps: sortedApps.userApps + sortedApps.systemApps, appState: appState, locations: locations) loadAllPaths(allApps: sortedApps.userApps + sortedApps.systemApps, appState: appState, locations: locations)
} }
updateOnMain { }
appState.reload.toggle() appState.reload.toggle()
} }
} }
@@ -64,16 +67,18 @@ struct AppCommands: Commands {
// Edit Menu // Edit Menu
CommandGroup(replacing: .undoRedo) { CommandGroup(replacing: .undoRedo) {
Button Button
{ {
undoTrash(appState: appState) { undoTrash(appState: appState) {
let sortedApps = getSortedApps() let sortedApps = getSortedApps()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
appState.sortedApps.userApps = []
appState.sortedApps.systemApps = []
appState.sortedApps.userApps = sortedApps.userApps appState.sortedApps.userApps = sortedApps.userApps
appState.sortedApps.systemApps = sortedApps.systemApps appState.sortedApps.systemApps = sortedApps.systemApps
loadAllPaths(allApps: sortedApps.userApps + sortedApps.systemApps, appState: appState, locations: locations) // if instantSearch {
// loadAllPaths(allApps: sortedApps.userApps + sortedApps.systemApps, appState: appState, locations: locations)
// }
} }
} }
} label: { } label: {
+10 -4
View File
@@ -321,15 +321,21 @@ func findPathsForApp(appInfo: AppInfo = .empty, appState: AppState, locations: L
var collection: [URL] = [] var collection: [URL] = []
if let url = URL(string: appInfo.path.absoluteString) { if let url = URL(string: appInfo.path.absoluteString) {
if !url.path.contains(".Trash") {
if url.path.contains("Wrapper") {
let modifiedUrl = url.deletingLastPathComponent().deletingLastPathComponent()
collection.insert(modifiedUrl, at: 0)
} else {
collection.insert(url, at: 0) collection.insert(url, at: 0)
} }
}
}
let fileManager = FileManager.default let fileManager = FileManager.default
let dispatchGroup = DispatchGroup() let dispatchGroup = DispatchGroup()
var bundleComponents = appInfo.bundleIdentifier.components(separatedBy: ".") var bundleComponents = appInfo.bundleIdentifier.components(separatedBy: ".")
if let lastComponent = bundleComponents.last, let rangeOfDash = lastComponent.range(of: "-") { if let lastComponent = bundleComponents.last, let rangeOfDash = lastComponent.range(of: "-") {
// Remove the dash and everything after it
let updatedLastComponent = String(lastComponent[..<rangeOfDash.lowerBound]) let updatedLastComponent = String(lastComponent[..<rangeOfDash.lowerBound])
bundleComponents[bundleComponents.count - 1] = updatedLastComponent bundleComponents[bundleComponents.count - 1] = updatedLastComponent
} }
@@ -370,6 +376,7 @@ func findPathsForApp(appInfo: AppInfo = .empty, appState: AppState, locations: L
if collection.contains(itemURL) { if collection.contains(itemURL) {
continue continue
} }
// Catch web app plist files // Catch web app plist files
if appInfo.webApp { if appInfo.webApp {
if itemL.contains(bundleIdentifierL) { if itemL.contains(bundleIdentifierL) {
@@ -417,7 +424,6 @@ func findPathsForApp(appInfo: AppInfo = .empty, appState: AppState, locations: L
collection.append(contentsOf: groupContainers) collection.append(contentsOf: groupContainers)
var sortedCollection = collection.sorted(by: { $0.absoluteString < $1.absoluteString }) var sortedCollection = collection.sorted(by: { $0.absoluteString < $1.absoluteString })
// Calculate file details (sizes and icons) // Calculate file details (sizes and icons)
var fileSize: [URL: Int64] = [:] var fileSize: [URL: Int64] = [:]
var fileIcon: [URL: NSImage?] = [:] var fileIcon: [URL: NSImage?] = [:]
@@ -438,6 +444,7 @@ func findPathsForApp(appInfo: AppInfo = .empty, appState: AppState, locations: L
sortedCollection = [] sortedCollection = []
} }
} }
// Save to appState // Save to appState
dispatchGroup.notify(queue: .main) { dispatchGroup.notify(queue: .main) {
@@ -593,7 +600,7 @@ func reversePathsSearch(appState: AppState, locations: Locations, completion: @e
let dispatchGroup = DispatchGroup() let dispatchGroup = DispatchGroup()
let allPaths = appState.appInfoStore.flatMap { $0.files.map { $0.path.pearFormat() } } let allPaths = appState.appInfoStore.flatMap { $0.files.map { $0.path.pearFormat() } }
let allNames = appState.appInfoStore.map { $0.appName.pearFormat() } let allNames = appState.appInfoStore.map { $0.appName.pearFormat() }
let skipped = ["apple", "comapple", "temporary", "btserver", "proapps", "scripteditor", "ilife", "livefsd", "siritoday", "addressbook", "animoji", "appstore", "askpermission", "callhistory", "clouddocs", "diskimages", "dock", "facetime", "fileprovider", "instruments", "knowledge", "mobilesync", "syncservices", "homeenergyd", "icloud", "icdd", "networkserviceproxy", "familycircle", "geoservices", "installation", "passkit", "sharedimagecache", "desktop", "mbuseragent", "swiftpm", "baseband", "coresimulator", "photoslegacyupgrade", "photosupgrade", "siritts", "ipod", "globalpreferences", "apmanalytics", "apmexperiment", "avatarcache", "byhost", "contextstoreagent", "mobilemeaccounts", "intentbuilderc", "loginwindow", "momc", "replayd", "sharedfilelistd", "clang", "audiocomponent", "csexattrcryptoservice", "livetranscriptionagent", "sandobxhelper", "statuskitagent", "betaenrollmentd", "contentlinkingd", "diagnosticextensionsd", "gamed", "heard", "homed", "itunescloudd", "lldb", "mds", "mediaanalysisd", "metrickitd", "mobiletimerd", "proactived", "ptpcamerad", "studentd", "talagent", "watchlistd", "apptranslocation", "xcrun", "ds_store", "caches", "crashreporter"] // Skip system folders let skipped = ["apple", "comapple", "temporary", "btserver", "proapps", "scripteditor", "ilife", "livefsd", "siritoday", "addressbook", "animoji", "appstore", "askpermission", "callhistory", "clouddocs", "diskimages", "dock", "facetime", "fileprovider", "instruments", "knowledge", "mobilesync", "syncservices", "homeenergyd", "icloud", "icdd", "networkserviceproxy", "familycircle", "geoservices", "installation", "passkit", "sharedimagecache", "desktop", "mbuseragent", "swiftpm", "baseband", "coresimulator", "photoslegacyupgrade", "photosupgrade", "siritts", "ipod", "globalpreferences", "apmanalytics", "apmexperiment", "avatarcache", "byhost", "contextstoreagent", "mobilemeaccounts", "intentbuilderc", "loginwindow", "momc", "replayd", "sharedfilelistd", "clang", "audiocomponent", "csexattrcryptoservice", "livetranscriptionagent", "sandobxhelper", "statuskitagent", "betaenrollmentd", "contentlinkingd", "diagnosticextensionsd", "gamed", "heard", "homed", "itunescloudd", "lldb", "mds", "mediaanalysisd", "metrickitd", "mobiletimerd", "proactived", "ptpcamerad", "studentd", "talagent", "watchlistd", "apptranslocation", "xcrun", "ds_store", "caches", "crashreporter", "trash"] // Skip system folders
// Skip locations that might not exist // Skip locations that might not exist
@@ -654,7 +661,6 @@ func reversePathsSearch(appState: AppState, locations: Locations, completion: @e
updateOnMain { updateOnMain {
updatedZombieFile.fileSize = fileSize updatedZombieFile.fileSize = fileSize
updatedZombieFile.fileIcon = fileIcon updatedZombieFile.fileIcon = fileIcon
// appState.selectedZombieItems = Set(sortedCollection)
appState.zombieFile = updatedZombieFile appState.zombieFile = updatedZombieFile
appState.showProgress = false appState.showProgress = false
} }
+34
View File
@@ -504,6 +504,40 @@ struct WindowActionButton: ButtonStyle {
} }
struct SimpleButtonBrightStyle: ButtonStyle {
@State private var hovered = false
let icon: String
let help: String
let color: Color
let shield: Bool?
init(icon: String, help: String, color: Color, shield: Bool? = nil) {
self.icon = icon
self.help = help
self.color = color
self.shield = shield
}
func makeBody(configuration: Self.Configuration) -> some View {
HStack {
Image(systemName: icon)
.resizable()
.scaledToFit()
.frame(width: 20)
.foregroundColor(hovered ? color.opacity(0.5) : color)
}
.padding(5)
.onHover { hovering in
withAnimation() {
hovered = hovering
}
}
.scaleEffect(configuration.isPressed ? 0.95 : 1)
.help(help)
}
}
struct FilesViewActionButton: ButtonStyle { struct FilesViewActionButton: ButtonStyle {
enum UserAction { enum UserAction {
+4 -2
View File
@@ -427,7 +427,7 @@ func ensureApplicationSupportFolderExists(appState: AppState) {
let fileManager = FileManager.default let fileManager = FileManager.default
let supportURL = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!.appendingPathComponent("Pearcleaner") let supportURL = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!.appendingPathComponent("Pearcleaner")
// Check to make sure Application Support/Support Admin folder exists // Check to make sure Application Support/Pearcleaner folder exists
if !fileManager.fileExists(atPath: supportURL.path) { if !fileManager.fileExists(atPath: supportURL.path) {
try! fileManager.createDirectory(at: supportURL, withIntermediateDirectories: true) try! fileManager.createDirectory(at: supportURL, withIntermediateDirectories: true)
printOS("Created Application Support/Pearcleaner folder") printOS("Created Application Support/Pearcleaner folder")
@@ -463,7 +463,7 @@ func writeLog(string: String) {
// --- Load Plist file with launchctl --- // --- Load Plist file with launchctl ---
func launchctl(load: Bool) { func launchctl(load: Bool, completion: @escaping () -> Void = {}) {
let cmd = load ? "load" : "unload" let cmd = load ? "load" : "unload"
if let plistPath = Bundle.main.path(forResource: "com.alienator88.PearcleanerSentinel", ofType: "plist") { if let plistPath = Bundle.main.path(forResource: "com.alienator88.PearcleanerSentinel", ofType: "plist") {
var plistContent = try! String(contentsOfFile: plistPath) var plistContent = try! String(contentsOfFile: plistPath)
@@ -491,6 +491,8 @@ func launchctl(load: Bool) {
task.launch() task.launch()
completion()
} }
} }
+1 -4
View File
@@ -29,8 +29,6 @@ struct PearcleanerApp: App {
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {
Group { Group {
ZStack() { ZStack() {
@@ -53,7 +51,7 @@ struct PearcleanerApp: App {
} }
.environmentObject(appState) .environmentObject(appState)
.preferredColorScheme(displayMode.colorScheme) .preferredColorScheme(displayMode.colorScheme)
.alert(isPresented: $appState.showAlert) { presentAlert(appState: appState) } // .alert(isPresented: $appState.showAlert) { presentAlert(appState: appState) }
.handlesExternalEvents(preferring: Set(arrayLiteral: "pear"), allowing: Set(arrayLiteral: "*")) .handlesExternalEvents(preferring: Set(arrayLiteral: "pear"), allowing: Set(arrayLiteral: "*"))
.onOpenURL(perform: { url in .onOpenURL(perform: { url in
let deeplinkManager = DeeplinkManager(showPopover: $showPopover) let deeplinkManager = DeeplinkManager(showPopover: $showPopover)
@@ -103,7 +101,6 @@ struct PearcleanerApp: App {
} }
#if !DEBUG #if !DEBUG
Task { Task {
@@ -5,9 +5,9 @@
"color-space" : "display-p3", "color-space" : "display-p3",
"components" : { "components" : {
"alpha" : "1.000", "alpha" : "1.000",
"blue" : "0xFF", "blue" : "0x50",
"green" : "0xFF", "green" : "0xC3",
"red" : "0xFF" "red" : "0x79"
} }
}, },
"idiom" : "universal" "idiom" : "universal"
@@ -23,9 +23,9 @@
"color-space" : "display-p3", "color-space" : "display-p3",
"components" : { "components" : {
"alpha" : "1.000", "alpha" : "1.000",
"blue" : "0xFF", "blue" : "0x50",
"green" : "0xFF", "green" : "0xC3",
"red" : "0xFF" "red" : "0x79"
} }
}, },
"idiom" : "universal" "idiom" : "universal"
+1 -1
View File
@@ -48,7 +48,7 @@ struct GeneralSettingsTab: View {
.font(.callout) .font(.callout)
.foregroundStyle(.gray) .foregroundStyle(.gray)
} }
InfoButton(text: "When transparent material is enabled, sticky section headers (User/System) in app list are disabled to keep from showing app name text overlayed under the section header text with no background to separate the two.", color: nil) // InfoButton(text: "When transparent material is enabled, sticky section headers (User/System) in app list are disabled to keep from showing app name text overlayed under the section header text with no background to separate the two.", color: nil)
Spacer() Spacer()
Toggle(isOn: $glass, label: { Toggle(isOn: $glass, label: {
}) })
+1 -1
View File
@@ -24,7 +24,7 @@ struct Asset: Codable {
extension Release { extension Release {
var modifiedBody: String { var modifiedBody: String {
return body.replacingOccurrences(of: "- [x]", with: "􀆊").replacingOccurrences(of: "###", with: "") return body.replacingOccurrences(of: "- [x]", with: ">").replacingOccurrences(of: "###", with: "")
} }
} }
+2 -46
View File
@@ -64,53 +64,9 @@ struct AppListView: View {
} }
} }
.padding(.top, 20) .padding(.top, 20)
// .padding(.bottom)
ScrollView {
LazyVStack(alignment: .leading, spacing: 0, pinnedViews: [glass ? [] : .sectionHeaders]) { AppsListView(search: $search, showPopover: $showPopover, filteredUserApps: filteredUserApps, filteredSystemApps: filteredSystemApps)
if filteredUserApps.count > 0 {
// VStack {
// Header(title: "User", count: filteredUserApps.count, showPopover: $showPopover)
ForEach(filteredUserApps, id: \.self) { appInfo in
Section(header: Header(title: "User", count: filteredUserApps.count, showPopover: $showPopover)) {
AppListItems(search: $search, showPopover: $showPopover, appInfo: appInfo)
.padding(.vertical,5)
if appInfo != filteredUserApps.last {
Divider().padding(.horizontal, 5)
}
}
// AppListItems(search: $search, showPopover: $showPopover, appInfo: appInfo)
// if appInfo != filteredUserApps.last {
// Divider().padding(.horizontal, 5)
// }
}
// }
}
if filteredSystemApps.count > 0 {
// VStack {
// Header(title: "System", count: filteredSystemApps.count, showPopover: $showPopover)
Section(header: Header(title: "System", count: filteredSystemApps.count, showPopover: $showPopover)) {
ForEach(filteredSystemApps, id: \.self) { appInfo in
AppListItems(search: $search, showPopover: $showPopover, appInfo: appInfo)
.padding(.vertical,5)
if appInfo != filteredSystemApps.last {
Divider().padding(.horizontal, 5)
}
}
}
// }
}
}
.padding(.horizontal)
}
.scrollIndicators(.never)
} }
.frame(width: sidebarWidth) .frame(width: sidebarWidth)
@@ -267,6 +223,6 @@ struct Header: View {
} }
.padding(.vertical, 9) .padding(.vertical, 9)
.padding(.leading, 6) .padding(.leading, 6)
.background(!glass ? Color("windowBG") : .clear) // .background(!glass ? Color("windowBG") : .clear)
} }
} }
+79
View File
@@ -0,0 +1,79 @@
//
// AppsListView.swift
// Pearcleaner
//
// Created by Alin Lupascu on 3/4/24.
//
import Foundation
import SwiftUI
struct AppsListView: View {
@Binding var search: String
@Binding var showPopover: Bool
var filteredUserApps: [AppInfo]
var filteredSystemApps: [AppInfo]
var body: some View {
ScrollView {
LazyVStack(alignment: .leading, spacing: 0, pinnedViews: [.sectionHeaders]) {
if filteredUserApps.count > 0 {
SectionView(title: "User", count: filteredUserApps.count, apps: filteredUserApps, search: $search, showPopover: $showPopover)
}
if filteredSystemApps.count > 0 {
SectionView(title: "System", count: filteredSystemApps.count, apps: filteredSystemApps, search: $search, showPopover: $showPopover)
}
}
.padding(.horizontal)
}
.scrollIndicators(.never)
}
}
struct SectionView: View {
var title: String
var count: Int
var apps: [AppInfo]
@Binding var search: String
@Binding var showPopover: Bool
var body: some View {
VStack(spacing: 0) {
Header(title: title, count: count, showPopover: $showPopover)
ForEach(apps, id: \.self) { appInfo in
AppListItems(search: $search, showPopover: $showPopover, appInfo: appInfo)
.padding(.vertical, 5)
if appInfo != apps.last {
Divider().padding(.horizontal, 5)
}
}
}
}
}
//List {
// Section {
// ForEach(filteredUserApps, id:\.self) { element in
// Text(element.appName)
// }
// .listRowBackground(Color.clear)
// } header: {
// Text("User Apps")
// }
//
// Section {
// ForEach(filteredSystemApps, id:\.self) { element in
// Text(element.appName)
// }
// .listRowBackground(Color.clear)
// } header: {
// Text("System Apps")
// }
//
//}
//.scrollContentBackground(.hidden)
//.background(.clear)
//.scrollIndicators(.never)
+31 -35
View File
@@ -14,6 +14,7 @@ struct FilesView: View {
@State private var showPop: Bool = false @State private var showPop: Bool = false
@AppStorage("settings.general.mini") private var mini: Bool = false @AppStorage("settings.general.mini") private var mini: Bool = false
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false @AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
@AppStorage("settings.general.instant") var instantSearch: Bool = true
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@Binding var showPopover: Bool @Binding var showPopover: Bool
@Binding var search: String @Binding var search: String
@@ -35,8 +36,24 @@ struct FilesView: View {
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.transition(.opacity) .transition(.opacity)
} else { } else {
VStack() { // Titlebar
if mini {
HStack() {
Spacer()
Button("Close") {
updateOnMain {
appState.appInfo = AppInfo.empty
search = ""
appState.currentView = .apps
showPopover = false
}
}
.buttonStyle(NavButtonBottomBarStyle(image: "x.circle.fill", help: "Close"))
}
.padding([.horizontal, .top], 5)
}
VStack(spacing: 0) {
// Main Group // Main Group
HStack(alignment: .center) { HStack(alignment: .center) {
@@ -112,7 +129,7 @@ struct FilesView: View {
} }
.padding(.horizontal, 20) .padding(.horizontal, 20)
.padding(.top, 10) .padding(.top, 0)
} }
Divider() Divider()
@@ -153,8 +170,8 @@ struct FilesView: View {
} }
} }
)) { )) {
Text("􀃲").tag(true) Image(systemName: "checkmark.square").tag(true)
Text("􀂒").tag(false) Image(systemName: "square").tag(false)
} }
.pickerStyle(SegmentedPickerStyle()) .pickerStyle(SegmentedPickerStyle())
.frame(width: 100) .frame(width: 100)
@@ -163,20 +180,6 @@ struct FilesView: View {
Spacer() Spacer()
if mini {
Button("Close") {
updateOnMain {
appState.appInfo = AppInfo.empty
search = ""
appState.currentView = .apps
showPopover = false
}
}
.buttonStyle(NavButtonBottomBarStyle(image: "x.circle.fill", help: "Close"))
}
if !appState.selectedItems.isEmpty { if !appState.selectedItems.isEmpty {
Button("Uninstall") { Button("Uninstall") {
Task { Task {
@@ -191,13 +194,9 @@ struct FilesView: View {
} }
} }
var selectedItemsArray = Array(appState.selectedItems) var selectedItemsArray = Array(appState.selectedItems)
.filter { !$0.path.contains(".Trash") }
.map { path in
return path.path.contains("Wrapper") ? path.deletingLastPathComponent().deletingLastPathComponent() : path
}
if let url = URL(string: appState.appInfo.path.absoluteString) { if let url = URL(string: appState.appInfo.path.absoluteString) {
let appFolderURL = url.deletingLastPathComponent() // Get the immediate parent directory let appFolderURL = appState.appInfo.path.absoluteString.contains("Wrapper") ? url.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent() : url.deletingLastPathComponent() // Get the immediate parent directory of regular and wrapped apps
if appFolderURL.path == "/Applications" || appFolderURL.path == "\(home)/Applications" { if appFolderURL.path == "/Applications" || appFolderURL.path == "\(home)/Applications" {
// Do nothing, skip insertion // Do nothing, skip insertion
@@ -207,7 +206,6 @@ struct FilesView: View {
} }
} }
killApp(appId: appState.appInfo.bundleIdentifier) { killApp(appId: appState.appInfo.bundleIdentifier) {
moveFilesToTrash(at: selectedItemsArray) { moveFilesToTrash(at: selectedItemsArray) {
withAnimation { withAnimation {
@@ -226,7 +224,7 @@ struct FilesView: View {
.buttonStyle(NavButtonBottomBarStyle(image: "trash.fill", help: "Uninstall")) .buttonStyle(NavButtonBottomBarStyle(image: "trash.fill", help: "Uninstall"))
} else { } else {
Text("No files selected to clean").font(.title).foregroundStyle(Color("mode")).opacity(0.2) Text("No files selected to remove").font(.title).foregroundStyle(Color("mode")).opacity(0.2)
.padding(5) .padding(5)
} }
@@ -234,17 +232,17 @@ struct FilesView: View {
Spacer() Spacer()
Picker("", selection: $selectedOption) { Picker("", selection: $selectedOption) {
Text("􀅐").tag("Default") Image(systemName: "textformat.abc").tag("Default")
Text("􀆃").tag("Size") Image(systemName: "number").tag("Size")
} }
.pickerStyle(SegmentedPickerStyle()) .pickerStyle(SegmentedPickerStyle())
.frame(width: 100) .frame(width: 100)
.help("Sorting Selection") .help("Sorting alphabetically or by size")
} }
} }
.transition(.opacity) .transition(.opacity)
.padding(20) .padding([.horizontal, .bottom], 20)
} }
@@ -254,14 +252,12 @@ struct FilesView: View {
func refreshAppList(_ appInfo: AppInfo) { func refreshAppList(_ appInfo: AppInfo) {
showPopover = false showPopover = false
let sortedApps = getSortedApps() let sortedApps = getSortedApps()
updateOnMain { DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
appState.sortedApps.userApps = []
appState.sortedApps.systemApps = []
appState.sortedApps.userApps = sortedApps.userApps appState.sortedApps.userApps = sortedApps.userApps
appState.sortedApps.systemApps = sortedApps.systemApps appState.sortedApps.systemApps = sortedApps.systemApps
} // if instantSearch {
Task(priority: .high){ // loadAllPaths(allApps: sortedApps.userApps + sortedApps.systemApps, appState: appState, locations: locations)
loadAllPaths(allApps: sortedApps.userApps + sortedApps.systemApps, appState: appState, locations: locations) // }
} }
} }
} }
+1 -43
View File
@@ -186,49 +186,7 @@ struct MiniAppView: View {
} else { } else {
VStack(alignment: .center) { VStack(alignment: .center) {
ScrollView { AppsListView(search: $search, showPopover: $showPopover, filteredUserApps: filteredUserApps, filteredSystemApps: filteredSystemApps)
LazyVStack(alignment: .leading, spacing: 0, pinnedViews: [glass ? [] : .sectionHeaders]) {
if filteredUserApps.count > 0 {
// VStack {
// Header(title: "User", count: filteredUserApps.count, showPopover: $showPopover)
Section(header: Header(title: "User", count: filteredUserApps.count, showPopover: $showPopover)) {
ForEach(filteredUserApps, id: \.self) { appInfo in
AppListItems(search: $search, showPopover: $showPopover, appInfo: appInfo)
// .padding(.vertical,5)
if appInfo != filteredUserApps.last {
Divider().padding(.horizontal, 5)
}
}
}
// }
}
if filteredSystemApps.count > 0 {
// VStack {
// Header(title: "System", count: filteredSystemApps.count, showPopover: $showPopover)
Section(header: Header(title: "System", count: filteredSystemApps.count, showPopover: $showPopover)) {
ForEach(filteredSystemApps, id: \.self) { appInfo in
AppListItems(search: $search, showPopover: $showPopover, appInfo: appInfo)
.padding(.vertical,5)
if appInfo != filteredSystemApps.last {
Divider().padding(.horizontal, 5)
}
}
}
// }
}
}
.padding(.horizontal)
}
.scrollIndicators(.never)
if appState.currentView != .empty { if appState.currentView != .empty {
SearchBarMiniBottom(search: $search).background(.ultraThinMaterial) SearchBarMiniBottom(search: $search).background(.ultraThinMaterial)
+38 -57
View File
@@ -37,8 +37,38 @@ struct ZombieView: View {
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.transition(.opacity) .transition(.opacity)
} else { } else {
VStack() { // Titlebar
if mini {
HStack(spacing: 0) {
Spacer()
Button("Rescan") {
updateOnMain {
appState.zombieFile = .empty
appState.showProgress.toggle()
if instantSearch {
reversePathsSearch(appState: appState, locations: locations)
} else {
loadAllPaths(allApps: appState.sortedApps.userApps + appState.sortedApps.systemApps, appState: appState, locations: locations, reverseAddon: true)
}
}
}
.buttonStyle(NavButtonBottomBarStyle(image: "arrow.counterclockwise.circle.fill", help: "Rescan files"))
Button("Close") {
updateOnMain {
appState.appInfo = AppInfo.empty
search = ""
appState.currentView = .apps
showPopover = false
}
}
.buttonStyle(NavButtonBottomBarStyle(image: "x.circle.fill", help: "Close"))
}
.padding([.horizontal, .top], 5)
}
VStack() {
// Main Group // Main Group
HStack() { HStack() {
@@ -74,7 +104,7 @@ struct ZombieView: View {
} }
.padding(.horizontal, 20) .padding(.horizontal, 20)
.padding(.top, 10) .padding(.top, 0)
} }
Divider() Divider()
@@ -116,8 +146,8 @@ struct ZombieView: View {
} }
} }
)) { )) {
Text("􀃲").tag(true) Image(systemName: "checkmark.square").tag(true)
Text("􀂒").tag(false) Image(systemName: "square").tag(false)
} }
.pickerStyle(SegmentedPickerStyle()) .pickerStyle(SegmentedPickerStyle())
.frame(width: 100) .frame(width: 100)
@@ -126,23 +156,6 @@ struct ZombieView: View {
Spacer() Spacer()
if mini {
Button("Close") {
updateOnMain {
appState.appInfo = AppInfo.empty
search = ""
appState.currentView = .apps
showPopover = false
}
}
.buttonStyle(NavButtonBottomBarStyle(image: "x.circle.fill", help: "Close"))
}
if !appState.selectedZombieItems.isEmpty { if !appState.selectedZombieItems.isEmpty {
Button("Remove") { Button("Remove") {
Task { Task {
@@ -158,7 +171,6 @@ struct ZombieView: View {
} }
let selectedItemsArray = Array(appState.selectedZombieItems) let selectedItemsArray = Array(appState.selectedZombieItems)
.filter { !$0.path.contains(".Trash") }
killApp(appId: appState.appInfo.bundleIdentifier) { killApp(appId: appState.appInfo.bundleIdentifier) {
moveFilesToTrash(at: selectedItemsArray) { moveFilesToTrash(at: selectedItemsArray) {
@@ -166,9 +178,6 @@ struct ZombieView: View {
showPopover = false showPopover = false
updateOnMain { updateOnMain {
appState.isReminderVisible.toggle() appState.isReminderVisible.toggle()
if sentinel {
launchctl(load: true)
}
} }
} }
} }
@@ -183,53 +192,25 @@ struct ZombieView: View {
.padding(5) .padding(5)
} }
Button("Rescan") {
updateOnMain {
appState.zombieFile = .empty
appState.showProgress.toggle()
if instantSearch {
reversePathsSearch(appState: appState, locations: locations)
} else {
loadAllPaths(allApps: appState.sortedApps.userApps + appState.sortedApps.systemApps, appState: appState, locations: locations, reverseAddon: true)
}
}
}
.buttonStyle(NavButtonBottomBarStyle(image: "arrow.counterclockwise.circle.fill", help: "Rescan files"))
Spacer() Spacer()
Picker("", selection: $selectedOption) { Picker("", selection: $selectedOption) {
Text("􀅐").tag("Default") Image(systemName: "textformat.abc").tag("Default")
Text("􀆃").tag("Size") Image(systemName: "number").tag("Size")
} }
.pickerStyle(SegmentedPickerStyle()) .pickerStyle(SegmentedPickerStyle())
.frame(width: 100) .frame(width: 100)
.help("Sorting Selection") .help("Sorting alphabetically or by size")
} }
} }
.transition(.opacity) .transition(.opacity)
.padding(20) .padding([.horizontal, .bottom], 20)
} }
} }
} }
func refreshAppList(_ appInfo: AppInfo) {
showPopover = false
let sortedApps = getSortedApps()
updateOnMain {
appState.sortedApps.userApps = []
appState.sortedApps.systemApps = []
appState.sortedApps.userApps = sortedApps.userApps
appState.sortedApps.systemApps = sortedApps.systemApps
}
Task(priority: .high){
loadAllPaths(allApps: sortedApps.userApps + sortedApps.systemApps, appState: appState, locations: locations)
}
}
} }
+5 -1
View File
@@ -47,7 +47,7 @@ class NewWin: NSWindowController {
window.titleVisibility = .hidden window.titleVisibility = .hidden
window.titlebarAppearsTransparent = true window.titlebarAppearsTransparent = true
window.center() window.center()
window.title = "Support Admin" window.title = "Pearcleaner"
} }
@@ -65,10 +65,12 @@ class NewWin: NSWindowController {
} }
private func makeNewView(appState: AppState, newWin: NewWindow) -> some View { private func makeNewView(appState: AppState, newWin: NewWindow) -> some View {
switch newWin { switch newWin {
case .update: case .update:
return AnyView(UpdateView() return AnyView(UpdateView()
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.black.opacity(0.2))
.environmentObject(appState)) .environmentObject(appState))
case .no_update: case .no_update:
return AnyView(NoUpdateView() return AnyView(NoUpdateView()
@@ -77,6 +79,8 @@ class NewWin: NSWindowController {
case .perm: case .perm:
return AnyView(PermView() return AnyView(PermView()
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.black.opacity(0.2))
.environmentObject(appState)) .environmentObject(appState))
} }
} }
+52 -22
View File
@@ -17,34 +17,69 @@ struct PermView: View {
Spacer() Spacer()
Text("Attention") Text("Pearcleaner Permissions")
.font(.title) .font(.title)
.bold() .bold()
.padding(.vertical) .padding(.vertical)
.padding(.top, 5)
Spacer() Spacer()
} }
.background(.red)
Text("Pearcleaner requires the following permissions:") Divider()
.font(.title3) .padding(.bottom)
.fontWeight(.semibold)
.padding(.vertical)
ScrollView { Spacer()
Text(" - Full Disk Access permission to find and delete files in non-user locations.\n - Accessibility permission to delete files via Finder which allows for the Undo function.\n\nAdd Pearcleaner in both Privacy panes via the + or by dragging the app over the pane. If the app is already pre-populated in the list, just toggle On. Restart app when both permissions are granted.")
.font(.body) VStack(alignment: .leading, spacing: 20) {
.multilineTextAlignment(.leading) HStack(alignment: .top, spacing: 20) {
.padding(.horizontal, 20) Image(systemName: "externaldrive")
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.foregroundStyle(.gray)
Text("Full Disk Access permission to find and delete files in system paths")
.font(.callout)
.foregroundStyle(.gray)
} }
.frame(height: 130)
.padding(.horizontal) HStack(alignment: .top, spacing: 20) {
Image(systemName: "accessibility")
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.foregroundStyle(.gray)
Text("Accessibility permission to delete files via Finder")
.font(.callout)
.foregroundStyle(.gray)
}
HStack(alignment: .top, spacing: 20) {
Image(systemName: "info.circle")
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.foregroundStyle(.gray)
Text("Add Pearcleaner in both Privacy panes via the + or by dragging the app over the pane. If the app is already pre-populated in the list, just toggle On if neeeded. Restart app when both permissions are granted")
.font(.callout)
.foregroundStyle(.gray)
}
}
.padding(.horizontal, 20)
Spacer() Spacer()
HStack { HStack {
Button(action: {
relaunchApp(afterDelay: 1)
}) {
Text("Restart")
}
.buttonStyle(SimpleButtonBrightStyle(icon: "arrow.uturn.left.circle", help: "Restart", color: .red))
.padding()
Button(action: { Button(action: {
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles") { if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles") {
NSWorkspace.shared.open(url) NSWorkspace.shared.open(url)
@@ -52,7 +87,8 @@ struct PermView: View {
}) { }) {
Text("Full Disk Access") Text("Full Disk Access")
} }
.buttonStyle(WindowActionButton(action: .accept)) .buttonStyle(SimpleButtonBrightStyle(icon: "externaldrive", help: "Full Disk", color: .accentColor))
.padding() .padding()
Button(action: { Button(action: {
@@ -62,16 +98,10 @@ struct PermView: View {
}) { }) {
Text("Accessibility") Text("Accessibility")
} }
.buttonStyle(WindowActionButton(action: .accept)) .buttonStyle(SimpleButtonBrightStyle(icon: "accessibility", help: "Accessibility", color: .accentColor))
.padding() .padding()
Button(action: {
relaunchApp(afterDelay: 1)
}) {
Text("Restart")
}
.buttonStyle(WindowActionButton(action: .cancel))
.padding()
} }
+20 -29
View File
@@ -13,7 +13,7 @@ struct UpdateView: View {
let isAppInAppsDir = isAppInApplicationsDir() let isAppInAppsDir = isAppInApplicationsDir()
var body: some View { var body: some View {
VStack { VStack(spacing: 5) {
HStack { HStack {
Spacer() Spacer()
@@ -29,36 +29,28 @@ struct UpdateView: View {
Text("v\(appState.releases.first?.tag_name ?? "")") Text("v\(appState.releases.first?.tag_name ?? "")")
.font(.title3) .font(.title3)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundStyle(Color.white.opacity(0.5)) .opacity(0.5)
.padding() .padding()
} }
.background(.blue)
Spacer() Divider()
.padding([.horizontal])
ScrollView { ScrollView {
Text("\(appState.releases.first?.body ?? "No release information")") Text("\(appState.releases.first?.modifiedBody ?? "No release information")")
.font(.body) .font(.body)
.multilineTextAlignment(.leading) .multilineTextAlignment(.leading)
.padding(.horizontal, 20) .padding(20)
} }
.frame(height: 160)
.padding()
Spacer() Spacer()
if !isAppInAppsDir { if !isAppInAppsDir {
HStack { Text("Please move Pearcleaner to the **Applications** folder before updating!")
Text("Pearcleaner not in /Applications directory. Updater could have permission issues updating files.") .font(.callout)
.font(.footnote)
.foregroundStyle(.red) .foregroundStyle(.red)
.padding() .padding(.top, 0)
.lineLimit(2)
.fixedSize(horizontal: false, vertical: true)
}
} }
VStack() { VStack() {
@@ -73,7 +65,7 @@ struct UpdateView: View {
Button(action: NewWin.close) { Button(action: NewWin.close) {
Text("Cancel") Text("Cancel")
} }
.buttonStyle(WindowActionButton(action: .cancel)) .buttonStyle(SimpleButtonBrightStyle(icon: "x.circle", help: "Close", color: .red))
if appState.progressBar.1 != 1.0 { if appState.progressBar.1 != 1.0 {
Button(action: { Button(action: {
@@ -81,7 +73,7 @@ struct UpdateView: View {
}) { }) {
Text("Update") Text("Update")
} }
.buttonStyle(WindowActionButton(action: .accept)) .buttonStyle(SimpleButtonBrightStyle(icon: "arrow.down.circle", help: "Update", color: .accentColor))
} else { } else {
Button(action: { Button(action: {
NewWin.close() NewWin.close()
@@ -89,7 +81,7 @@ struct UpdateView: View {
}) { }) {
Text("Restart") Text("Restart")
} }
.buttonStyle(WindowActionButton(action: .accept)) .buttonStyle(SimpleButtonBrightStyle(icon: "arrow.uturn.left.circle", help: "Restart", color: .accentColor))
} }
} }
@@ -112,7 +104,7 @@ struct NoUpdateView: View {
@EnvironmentObject var appState: AppState @EnvironmentObject var appState: AppState
var body: some View { var body: some View {
VStack { VStack(spacing: 5) {
HStack { HStack {
Spacer() Spacer()
@@ -128,19 +120,19 @@ struct NoUpdateView: View {
Text("v\(appState.releases.first?.tag_name ?? "")") Text("v\(appState.releases.first?.tag_name ?? "")")
.font(.title3) .font(.title3)
.fontWeight(.semibold) .fontWeight(.semibold)
.foregroundStyle(Color.white.opacity(0.5)) .opacity(0.5)
.padding() .padding()
} }
.background(.blue)
Spacer() Divider()
.padding([.horizontal])
Text("Pearcleaner is on the most current release available, but you may force a re-download of the same version below.") Text("Pearcleaner is on the most current release available, but you may force a re-download of the same version below.")
.font(.body) .font(.body)
.lineLimit(3) .lineLimit(3)
.multilineTextAlignment(.leading) .multilineTextAlignment(.leading)
.padding(20) .padding()
@@ -160,14 +152,14 @@ struct NoUpdateView: View {
}) { }) {
Text("Force Update") Text("Force Update")
} }
.buttonStyle(WindowActionButton(action: .cancel)) .buttonStyle(SimpleButtonBrightStyle(icon: "arrow.down.circle", help: "Force-Update", color: .red))
Button(action: { Button(action: {
NewWin.close() NewWin.close()
}) { }) {
Text("Okay") Text("Okay")
} }
.buttonStyle(WindowActionButton(action: .accept)) .buttonStyle(SimpleButtonBrightStyle(icon: "checkmark.circle", help: "Ok", color: .accentColor))
} }
@@ -179,7 +171,7 @@ struct NoUpdateView: View {
}) { }) {
Text("Restart") Text("Restart")
} }
.buttonStyle(WindowActionButton(action: .accept)) .buttonStyle(SimpleButtonBrightStyle(icon: "arrow.uturn.left.circle", help: "Restart", color: .accentColor))
} }
} }
.padding(.bottom) .padding(.bottom)
@@ -190,7 +182,6 @@ struct NoUpdateView: View {
.padding(EdgeInsets(top: -25, leading: 0, bottom: 25, trailing: 0)) .padding(EdgeInsets(top: -25, leading: 0, bottom: 25, trailing: 0))
} }
+9 -1
View File
@@ -6,8 +6,8 @@
// //
import Foundation import Foundation
import FileWatcher
import AppKit import AppKit
import FileWatcher
// Start Trash monitoring // Start Trash monitoring
fileWatcher() fileWatcher()
@@ -31,10 +31,18 @@ func checkApp(file: String) {
let app = URL(fileURLWithPath: file) let app = URL(fileURLWithPath: file)
let appExt = app.pathExtension let appExt = app.pathExtension
if appExt == "app" { if appExt == "app" {
if let appBundle = Bundle(url: app) {
if appBundle.bundleIdentifier == "com.alienator88.Pearcleaner" {
return
} else {
if FileManager.default.isInTrash(app) { if FileManager.default.isInTrash(app) {
NSWorkspace.shared.open(URL(string: "pear://com.alienator88.Pearcleaner?path=\(file)")!) NSWorkspace.shared.open(URL(string: "pear://com.alienator88.Pearcleaner?path=\(file)")!)
} }
} }
} else {
print("Error: Unable to get bundle information for \(file)")
}
}
} }
// --- Trash Relationship --- // --- Trash Relationship ---