Skip to content

Commit

Permalink
v2.6
Browse files Browse the repository at this point in the history
  • Loading branch information
alienator88 committed Feb 13, 2024
1 parent 18b9ceb commit 09b2785
Show file tree
Hide file tree
Showing 13 changed files with 230 additions and 107 deletions.
8 changes: 4 additions & 4 deletions Pearcleaner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 16;
CURRENT_PROJECT_VERSION = 17;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU;
Expand All @@ -561,7 +561,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 2.5;
MARKETING_VERSION = 2.6;
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -578,7 +578,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 16;
CURRENT_PROJECT_VERSION = 17;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU;
Expand All @@ -596,7 +596,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 2.5;
MARKETING_VERSION = 2.6;
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand Down
6 changes: 4 additions & 2 deletions Pearcleaner/Logic/AppCommands.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import SwiftUI
struct AppCommands: Commands {

let appState: AppState
let locations: Locations

init(appState: AppState) {
init(appState: AppState, locations: Locations) {
self.appState = appState
self.locations = locations
}

var body: some Commands {
Expand Down Expand Up @@ -44,7 +46,7 @@ struct AppCommands: Commands {
.keyboardShortcut("r", modifiers: .command)

Button {
uninstallPearcleaner(appState: appState)
uninstallPearcleaner(appState: appState, locations: locations)
} label: {
Text("Uninstall Pearcleaner")
}
Expand Down
37 changes: 34 additions & 3 deletions Pearcleaner/Logic/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,18 @@ let home = FileManager.default.homeDirectoryForCurrentUser.path

class AppState: ObservableObject
{
// @Published var showFiles: Bool = false
@Published var appInfo: AppInfo
@Published var paths: [URL] = []
@Published var sortedApps: (userApps: [AppInfo], systemApps: [AppInfo]) = ([], [])
@Published var selectedItems = Set<URL>()
@Published var alertType = AlertType.off
@Published var currentView = CurrentDetailsView.empty
// @Published var currentMode = CurrentMode.regular
@Published var showAlert: Bool = false
@Published var sidebar: Bool = true
// @Published var showPopover: Bool = false
@Published var isReminderVisible: Bool = false
@Published var releases = [Release]()
@Published var progressBar: (String, Double) = ("Ready", 0.0)
// @Published var progressManager = ProgressManager()
@Published var reload: Bool = false


Expand All @@ -46,6 +44,39 @@ class AppState: ObservableObject
}
}


class ProgressManager: ObservableObject {
@Published var progress: Double = 0.0
@Published var total: Double = 0.0
@Published var status: String = "Ready"

func setTotal(_ total: Double) {
DispatchQueue.main.async {
self.total = total
}
}

func updateProgress() {
DispatchQueue.main.async {
self.progress = min(max(0.0, self.progress + 1.0), Double(self.total))
}
}

func updateStatus(status: String) {
DispatchQueue.main.async {
self.status = status
}
}

func resetProgress() {
DispatchQueue.main.async {
self.progress = 0.0
}
}
}



struct AppInfo: Identifiable, Hashable {
let id: UUID
let path: URL
Expand Down
10 changes: 5 additions & 5 deletions Pearcleaner/Logic/DeepLink.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ class DeeplinkManager {
static let query = "path"
}

func manage(url: URL, appState: AppState) {
func manage(url: URL, appState: AppState, locations: Locations) {
if url.pathExtension == "app" {
handleAppBundle(url: url, appState: appState)
handleAppBundle(url: url, appState: appState, locations: locations)
} else if url.scheme == DeepLinkConstants.scheme,
url.host == DeepLinkConstants.host,
let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
Expand All @@ -34,7 +34,7 @@ class DeeplinkManager {
let appInfo = getAppInfo(atPath: pathURL)
updateOnMain {
appState.appInfo = appInfo!
findPathsForApp(appState: appState, appInfo: appState.appInfo)
findPathsForApp(appState: appState, locations: locations)
if self.mini {
self.showPopover = true
} else {
Expand Down Expand Up @@ -72,11 +72,11 @@ class DeeplinkManager {
// }
// }

func handleAppBundle(url: URL, appState: AppState) {
func handleAppBundle(url: URL, appState: AppState, locations: Locations) {
let appInfo = getAppInfo(atPath: url)
updateOnMain {
appState.appInfo = appInfo!
findPathsForApp(appState: appState, appInfo: appState.appInfo)
findPathsForApp(appState: appState, locations: locations)
if self.mini {
self.showPopover = true
} else {
Expand Down
78 changes: 44 additions & 34 deletions Pearcleaner/Logic/Locations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Foundation


struct Locations {
class Locations: ObservableObject {
struct Category {
let name: String
var paths: [String]
Expand All @@ -19,8 +19,8 @@ struct Locations {
let tempDir: String

var apps: Category
var widgets: Category
var plugins: Category
// var widgets: Category
// var plugins: Category

init() {
self.home = FileManager.default.homeDirectoryForCurrentUser.path
Expand All @@ -32,7 +32,7 @@ struct Locations {
"\(home)/Library",
"\(home)/Library/Application Scripts",
"\(home)/Library/Application Support",
"\(home)/Library/Application Support/CrashReporter",
// "\(home)/Library/Application Support/CrashReporter",
"\(home)/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments",
"\(home)/Library/Containers",
// "\(home)/Library/Group Containers", // This is now handled by the function getGroupContainers()
Expand Down Expand Up @@ -70,35 +70,45 @@ struct Locations {
cacheDir,
tempDir
])

self.widgets = Category(name: "Widgets", paths: [
// User
"~/Library/Widgets",
// System
"/Library/Widgets"
])

self.plugins = Category(name: "Plugins", paths: [
// User
"~/Library/Contextual Menu Items",
"~/Library/InputManagers",
"~/Library/Internet Plug-Ins",
"~/Library/Mail/Bundles",
"~/Library/PreferencePanes",
"~/Library/QuickLook",
"~/Library/QuickTime",
"~/Library/Screen Savers",
"~/Library/Spotlight",
// System
"/Library/Contextual Menu Items",
"/Library/InputManagers",
"/Library/Internet Plug-Ins",
"/Library/Mail/Bundles",
"/Library/PreferencePanes",
"/Library/QuickLook",
"/Library/QuickTime",
"/Library/Screen Savers",
"/Library/Spotlight",
])

// Append Application Support subfolders for deeper search
do {
let subfolders = try appSupSubfolders()
for folder in subfolders {
self.apps.paths.append("\(home)/Library/Application Support/\(folder)")
}
} catch {
print("Error getting subfolders: \(error)")
}

// self.widgets = Category(name: "Widgets", paths: [
// // User
// "~/Library/Widgets",
// // System
// "/Library/Widgets"
// ])
//
// self.plugins = Category(name: "Plugins", paths: [
// // User
// "~/Library/Contextual Menu Items",
// "~/Library/InputManagers",
// "~/Library/Internet Plug-Ins",
// "~/Library/Mail/Bundles",
// "~/Library/PreferencePanes",
// "~/Library/QuickLook",
// "~/Library/QuickTime",
// "~/Library/Screen Savers",
// "~/Library/Spotlight",
// // System
// "/Library/Contextual Menu Items",
// "/Library/InputManagers",
// "/Library/Internet Plug-Ins",
// "/Library/Mail/Bundles",
// "/Library/PreferencePanes",
// "/Library/QuickLook",
// "/Library/QuickTime",
// "/Library/Screen Savers",
// "/Library/Spotlight",
// ])
}
}
47 changes: 40 additions & 7 deletions Pearcleaner/Logic/Logic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,24 @@ func darwinCT() -> (String, String) {
}


// Add subfolders of ~/Library/Application Support/ to locations for deeper search
func appSupSubfolders() throws -> [String] {
let fileManager = FileManager.default
let appSup = "\(home)/Library/Application Support/"
let subfolders = try fileManager.contentsOfDirectory(atPath: appSup)
let exclusionRegex = try NSRegularExpression(pattern: "\\bcom\\.apple\\b", options: [])
let exclusions = ["MobileSync", ".DS_Store", "Xcode", "SyncServices", "networkserviceproxy", "DiskImages", "CallHistoryTransactions", "App Store", "CloudDocs", "icdd", "iCloud", "Instruments", "AddressBook", "FaceTime", "AskPermission", "CallHistoryDB"]

let allowedFolders = subfolders.filter { folder in
let range = NSRange(location: 0, length: folder.utf16.count)
return exclusionRegex.firstMatch(in: folder, options: [], range: range) == nil && !exclusions.contains(folder)
}

return allowedFolders
}




// Check if app is running before deleting app files
func killApp(appId: String, completion: @escaping () -> Void = {}) {
Expand All @@ -284,17 +302,19 @@ func killApp(appId: String, completion: @escaping () -> Void = {}) {


// Find all possible paths for an app based on name/bundle id
func findPathsForApp(appState: AppState, appInfo: AppInfo) {
func findPathsForApp(appState: AppState, locations: Locations) {
Task(priority: .high) {
updateOnMain {
appState.paths = []
}
let appInfo = appState.appInfo
var collection: [URL] = []
if let url = URL(string: appInfo.path.absoluteString) {
collection.insert(url, at: 0)
}

let fileManager = FileManager.default
// let progressManager = appState.progressManager
let dispatchGroup = DispatchGroup()
var bundleComponents = appInfo.bundleIdentifier.components(separatedBy: ".")
if let lastComponent = bundleComponents.last, let rangeOfDash = lastComponent.range(of: "-") {
Expand All @@ -310,27 +330,37 @@ func findPathsForApp(appState: AppState, appInfo: AppInfo) {
let nameL = appInfo.appName.pearFormat()
let nameP = appInfo.path.lastPathComponent.replacingOccurrences(of: ".app", with: "")
let bundleIdentifierL = appInfo.bundleIdentifier.pearFormat()
let locations = Locations()

for location in locations.apps.paths {
if !fileManager.fileExists(atPath: location) {
continue
}



// DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
// withAnimation {
// progressManager.updateStatus(status: location)
// progressManager.updateProgress()
// progressManager.objectWillChange.send()
// }
// }


dispatchGroup.enter() // Enter the dispatch group



do {

let contents = try fileManager.contentsOfDirectory(atPath: location)

for item in contents {

let itemURL = URL(fileURLWithPath: location).appendingPathComponent(item)
let itemL = ("\(item)").replacingOccurrences(of: ".", with: "").replacingOccurrences(of: " ", with: "").lowercased()


if collection.contains(itemURL) {
return
break
}
// Catch web app plist files
if appInfo.webApp {
Expand All @@ -348,7 +378,7 @@ func findPathsForApp(appState: AppState, appInfo: AppInfo) {
}
}
// Catch Xcode files
else if itemL.contains("xcode") {
else if itemL.contains("xcode") {
if itemL.contains(bundle) || itemL.contains(bundleIdentifierL) || (nameL.count > 4 && itemL.contains(nameL)) {
collection.append(itemURL)
}
Expand All @@ -361,9 +391,12 @@ func findPathsForApp(appState: AppState, appInfo: AppInfo) {

}
} catch {
print("Error processing location:", location, error)
continue
}


// try await Task.sleep(nanoseconds: 50_000_000)

dispatchGroup.leave() // Leave the dispatch group

}
Expand Down
5 changes: 3 additions & 2 deletions Pearcleaner/Logic/Utilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -396,16 +396,17 @@ func presentAlert(appState: AppState) -> Alert {


// --- Pearcleaner Uninstall --
func uninstallPearcleaner(appState: AppState) {
func uninstallPearcleaner(appState: AppState, locations: Locations) {

// Unload Sentinel Monitor if running
launchctl(load: false)

// Get app info for Pearcleaner
let appInfo = getAppInfo(atPath: Bundle.main.bundleURL)
appState.appInfo = appInfo!

// Find application files for Pearcleaner
findPathsForApp(appState: appState, appInfo: appInfo!)
findPathsForApp(appState: appState, locations: locations)

// Kill Pearcleaner and tell Finder to trash the files
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
Expand Down
Loading

0 comments on commit 09b2785

Please sign in to comment.