mirror of
https://github.com/exituser/Pearcleaner.git
synced 2026-09-17 09:38:51 +00:00
updates
This commit is contained in:
@@ -50,7 +50,7 @@ struct AppCommands: Commands {
|
||||
.keyboardShortcut("r", modifiers: .command)
|
||||
|
||||
Button {
|
||||
uninstallPearcleaner(appState: appState, locations: locations)
|
||||
appState.triggerUninstallAlert()
|
||||
} label: {
|
||||
Text("Uninstall Pearcleaner")
|
||||
}
|
||||
|
||||
@@ -310,7 +310,6 @@ class AppPathFinder {
|
||||
self.appState.appInfo = self.appInfo
|
||||
if !self.undo {
|
||||
self.appState.selectedItems = Set(updatedCollection)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,7 @@ import FinderSync
|
||||
|
||||
let home = FileManager.default.homeDirectoryForCurrentUser.path
|
||||
|
||||
class AppState: ObservableObject
|
||||
{
|
||||
class AppState: ObservableObject {
|
||||
@Published var appInfo: AppInfo
|
||||
@Published var appInfoStore: [AppInfo] = []
|
||||
@Published var trashedFiles: [AppInfo] = []
|
||||
@@ -29,8 +28,10 @@ class AppState: ObservableObject
|
||||
@Published var showProgress: Bool = false
|
||||
@Published var finderExtensionEnabled: Bool = false
|
||||
@Published var updateAvailable: Bool = false
|
||||
@Published var featureAvailable: Bool = false
|
||||
@Published var permissionsOkay: Bool = true
|
||||
@Published var permissionResults: PermissionsCheckResults?
|
||||
@Published var showUninstallAlert: Bool = false
|
||||
|
||||
|
||||
|
||||
@@ -74,6 +75,11 @@ class AppState: ObservableObject
|
||||
self.finderExtensionEnabled = extensionStatus
|
||||
}
|
||||
}
|
||||
|
||||
func triggerUninstallAlert() {
|
||||
self.showUninstallAlert = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -166,6 +172,7 @@ enum NewWindow:Int
|
||||
case update
|
||||
case no_update
|
||||
case perm
|
||||
case feature
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -110,8 +110,8 @@ let skipConditions: [SkipCondition] = [
|
||||
]
|
||||
|
||||
|
||||
// Skip files/folders during reverse file search
|
||||
let skipReverse = ["apple", "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", "sandboxhelper", "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", "pearcleaner", "amsdatamigratortool", "arfilecache", "assistant", "chromium", "cloudkit", "webkit", "databases", "diagnostic", "cache", "gamekit", "homebrew", "logi", "microsoft", "mozilla", "sync", "google", "sentinel", "hexnode", "sentry", "tvappservices"]
|
||||
// Skip files/folders during leftover file search
|
||||
let skipReverse = ["apple", "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", "sandboxhelper", "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", "pearcleaner", "amsdatamigratortool", "arfilecache", "assistant", "chromium", "cloudkit", "webkit", "databases", "diagnostic", "cache", "gamekit", "homebrew", "logi", "microsoft", "mozilla", "sync", "google", "sentinel", "hexnode", "sentry", "tvappservices", "reminders"]
|
||||
|
||||
|
||||
// Function to load additional conditions from a GitHub JSON file
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
func getFeatures(appState: AppState, show: Binding<Bool>, features: Binding<String>) {
|
||||
|
||||
func getFeatures(appState: AppState, features: Binding<String>) {
|
||||
let url = URL(string: "https://api.github.com/repos/alienator88/Pearcleaner/contents/features.json")!
|
||||
var request = URLRequest(url: url)
|
||||
request.setValue("application/vnd.github.VERSION.raw", forHTTPHeaderField: "Accept")
|
||||
@@ -25,25 +24,88 @@ func getFeatures(appState: AppState, show: Binding<Bool>, features: Binding<Stri
|
||||
if features.wrappedValue != featureText.featureFormat() {
|
||||
updateOnMain {
|
||||
features.wrappedValue = featureText.featureFormat()
|
||||
show.wrappedValue = true
|
||||
appState.featureAvailable = true
|
||||
// show.wrappedValue = true
|
||||
}
|
||||
} else {
|
||||
show.wrappedValue = false
|
||||
updateOnMain {
|
||||
appState.featureAvailable = false
|
||||
}
|
||||
// show.wrappedValue = false
|
||||
// print("Same version")
|
||||
}
|
||||
|
||||
} else {
|
||||
show.wrappedValue = false
|
||||
updateOnMain {
|
||||
appState.featureAvailable = false
|
||||
}
|
||||
// show.wrappedValue = false
|
||||
// print("No features for version found")
|
||||
}
|
||||
} catch {
|
||||
show.wrappedValue = false
|
||||
printOS("Error reading features JSON from GitHub: \(error.localizedDescription)")
|
||||
}
|
||||
} else {
|
||||
show.wrappedValue = false
|
||||
printOS("Error reading features JSON from GitHub: \(error?.localizedDescription ?? "Unknown error")")
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct FeatureNotificationView: View {
|
||||
let appState: AppState
|
||||
@State private var hovered: Bool = false
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
|
||||
Text("New Features!")
|
||||
.font(.callout)
|
||||
.opacity(0.5)
|
||||
.padding(.leading, 7)
|
||||
|
||||
Spacer()
|
||||
|
||||
HStack(alignment: .center) {
|
||||
Image(systemName: !hovered ? "star" : "star.fill")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 14, height: 14)
|
||||
.animation(.easeInOut(duration: 0.2), value: hovered)
|
||||
.foregroundStyle(.white)
|
||||
|
||||
|
||||
Text("Show")
|
||||
.foregroundStyle(.white)
|
||||
|
||||
}
|
||||
.padding(3)
|
||||
.onHover { hovering in
|
||||
withAnimation() {
|
||||
hovered = hovering
|
||||
}
|
||||
}
|
||||
.onTapGesture {
|
||||
NewWin.show(appState: appState, width: 500, height: 400, newWin: .feature)
|
||||
updateOnMain {
|
||||
appState.featureAvailable = false
|
||||
}
|
||||
}
|
||||
.help("View latest features")
|
||||
.padding(.horizontal, 5)
|
||||
.padding(.vertical, 4)
|
||||
.background(Color("pear"))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 6))
|
||||
|
||||
}
|
||||
.frame(height: 30)
|
||||
.padding(5)
|
||||
.background(Color("mode").opacity(0.05))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 6))
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ class Locations: ObservableObject {
|
||||
"\(home)/Library",
|
||||
"\(home)/Library/Application Scripts",
|
||||
"\(home)/Library/Application Support",
|
||||
"\(home)/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments",
|
||||
"\(home)/Library/Containers",
|
||||
"\(home)/Library/Caches",
|
||||
"\(home)/Library/Group Containers",
|
||||
|
||||
@@ -6,17 +6,16 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import EventKit
|
||||
//import EventKit
|
||||
|
||||
struct PermissionsCheckResults {
|
||||
var fullDiskAccess: Bool
|
||||
var accessibility: Bool
|
||||
var automation: Bool
|
||||
var reminders: Bool
|
||||
|
||||
|
||||
// Computed property to check if all permissions are granted
|
||||
var allPermissionsGranted: Bool {
|
||||
return fullDiskAccess && accessibility && automation && reminders
|
||||
return fullDiskAccess && accessibility && automation
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,25 +50,17 @@ func checkAllPermissions(appState: AppState, completion: @escaping (PermissionsC
|
||||
dispatchGroup.leave()
|
||||
}
|
||||
|
||||
// Check Reminders Permission
|
||||
var remindersAccess = false
|
||||
dispatchGroup.enter()
|
||||
checkRemindersAccess(appState: appState) { granted in
|
||||
remindersAccess = granted
|
||||
dispatchGroup.leave()
|
||||
}
|
||||
|
||||
// Wait for all async checks to complete
|
||||
dispatchGroup.notify(queue: .main) {
|
||||
let results = PermissionsCheckResults(
|
||||
fullDiskAccess: fullDiskAccess,
|
||||
accessibility: accessibilityEnabled,
|
||||
automation: automationAccess,
|
||||
reminders: remindersAccess
|
||||
automation: automationAccess
|
||||
)
|
||||
|
||||
// Check if any permission is denied and show window
|
||||
if !(results.fullDiskAccess && results.accessibility && results.automation && results.reminders) {
|
||||
if !(results.fullDiskAccess && results.accessibility && results.automation) {
|
||||
updateOnMain {
|
||||
appState.permissionsOkay = false
|
||||
}
|
||||
@@ -99,22 +90,6 @@ func checkAutomationPermission(appState: AppState, completion: @escaping (Bool)
|
||||
}
|
||||
}
|
||||
|
||||
// Check Reminders storage permission
|
||||
func checkRemindersAccess(appState: AppState, completion: @escaping (Bool) -> Void) {
|
||||
let eventStore = EKEventStore()
|
||||
eventStore.requestAccess(to: .reminder) { granted, error in
|
||||
DispatchQueue.main.async {
|
||||
if error != nil {
|
||||
completion(false)
|
||||
} else {
|
||||
completion(granted)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct PermissionsNotificationView: View {
|
||||
|
||||
@@ -260,7 +260,7 @@ struct InfoButtonPerms: View {
|
||||
}
|
||||
}
|
||||
.popover(isPresented: $isPopoverPresented, arrowEdge: .bottom) {
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
VStack(alignment: .leading, spacing: 15) {
|
||||
|
||||
HStack(alignment: .top, spacing: 20) {
|
||||
Image(systemName: "externaldrive")
|
||||
@@ -268,7 +268,7 @@ struct InfoButtonPerms: View {
|
||||
.scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
Text("Full Disk Access permission to find and delete files in system paths")
|
||||
Text("Full Disk permission to access files/folders in system paths")
|
||||
.font(.callout)
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
}
|
||||
@@ -279,7 +279,7 @@ struct InfoButtonPerms: View {
|
||||
.scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
Text("Accessibility permission to delete files via Finder")
|
||||
Text("Accessibility permission to allow execution of AppleScript")
|
||||
.font(.callout)
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
}
|
||||
@@ -290,21 +290,11 @@ struct InfoButtonPerms: View {
|
||||
.scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
Text("Automation permission to perform extension actions via Finder")
|
||||
Text("Automation permission to perform delete actions via Finder")
|
||||
.font(.callout)
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
}
|
||||
|
||||
HStack(alignment: .top, spacing: 20) {
|
||||
Image(systemName: "calendar")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
Text("Reminders permission to find and delete some reminder files that certain apps cache")
|
||||
.font(.callout)
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ func findAndHideWindows(named titles: [String]) {
|
||||
func findAndSetWindowFrame(named titles: [String], windowSettings: WindowSettings) {
|
||||
for title in titles {
|
||||
if let window = NSApp.windows.first(where: { $0.title == title }) {
|
||||
// window.isRestorable = false // Doing this via view
|
||||
window.isRestorable = false
|
||||
let frame = windowSettings.loadWindowSettings()
|
||||
window.setFrame(frame, display: true)
|
||||
}
|
||||
@@ -561,10 +561,8 @@ func uninstallPearcleaner(appState: AppState, locations: Locations) {
|
||||
let appInfo = AppInfoFetcher.getAppInfo(atPath: Bundle.main.bundleURL)
|
||||
|
||||
// Find application files for Pearcleaner
|
||||
AppPathFinder(appInfo: appInfo!, appState: appState, locations: locations).findPaths()
|
||||
|
||||
// Kill Pearcleaner and tell Finder to trash the files
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||||
AppPathFinder(appInfo: appInfo!, appState: appState, locations: locations, completion: {
|
||||
// Kill Pearcleaner and tell Finder to trash the files
|
||||
let selectedItemsArray = Array(appState.selectedItems).filter { !$0.path.contains(".Trash") }
|
||||
let posixFiles = selectedItemsArray.map { "POSIX file \"\($0.path)\", " }.joined().dropLast(3)
|
||||
let scriptSource = """
|
||||
@@ -577,8 +575,7 @@ func uninstallPearcleaner(appState: AppState, locations: Locations) {
|
||||
|
||||
NSApp.terminate(nil)
|
||||
exit(0)
|
||||
}
|
||||
|
||||
}).findPaths()
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user