mirror of
https://github.com/exituser/Pearcleaner.git
synced 2026-09-17 08:29:07 +00:00
updates
This commit is contained in:
@@ -39,6 +39,7 @@
|
|||||||
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 */; };
|
||||||
|
C7D15BBE2BE85F4D007D57CF /* FeatureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D15BBD2BE85F4D007D57CF /* FeatureView.swift */; };
|
||||||
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 */; };
|
||||||
C7DC1FEE2B9F7D3D009AC317 /* features.json in Resources */ = {isa = PBXBuildFile; fileRef = C7DC1FED2B9F7D3D009AC317 /* features.json */; };
|
C7DC1FEE2B9F7D3D009AC317 /* features.json in Resources */ = {isa = PBXBuildFile; fileRef = C7DC1FED2B9F7D3D009AC317 /* features.json */; };
|
||||||
@@ -135,6 +136,7 @@
|
|||||||
C7A9CE462B89164700EB6E78 /* Authorization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Authorization.swift; sourceTree = "<group>"; };
|
C7A9CE462B89164700EB6E78 /* Authorization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Authorization.swift; sourceTree = "<group>"; };
|
||||||
C7ACADE52B92A737000B5845 /* Features.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features.swift; sourceTree = "<group>"; };
|
C7ACADE52B92A737000B5845 /* Features.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features.swift; sourceTree = "<group>"; };
|
||||||
C7CF47232B3B3F1700979C5F /* WindowSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowSettings.swift; sourceTree = "<group>"; };
|
C7CF47232B3B3F1700979C5F /* WindowSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowSettings.swift; sourceTree = "<group>"; };
|
||||||
|
C7D15BBD2BE85F4D007D57CF /* FeatureView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureView.swift; sourceTree = "<group>"; };
|
||||||
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>"; };
|
||||||
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; };
|
||||||
@@ -181,6 +183,7 @@
|
|||||||
children = (
|
children = (
|
||||||
C7045A312B068AD700376976 /* NewWin.swift */,
|
C7045A312B068AD700376976 /* NewWin.swift */,
|
||||||
C7045A332B068B2900376976 /* UpdateView.swift */,
|
C7045A332B068B2900376976 /* UpdateView.swift */,
|
||||||
|
C7D15BBD2BE85F4D007D57CF /* FeatureView.swift */,
|
||||||
C7045A352B068DD700376976 /* PermView.swift */,
|
C7045A352B068DD700376976 /* PermView.swift */,
|
||||||
C7DE672A2BA6343D00EB1633 /* MenuBarItem.swift */,
|
C7DE672A2BA6343D00EB1633 /* MenuBarItem.swift */,
|
||||||
C7CF47232B3B3F1700979C5F /* WindowSettings.swift */,
|
C7CF47232B3B3F1700979C5F /* WindowSettings.swift */,
|
||||||
@@ -492,6 +495,7 @@
|
|||||||
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 */,
|
||||||
|
C7D15BBE2BE85F4D007D57CF /* FeatureView.swift in Sources */,
|
||||||
C7A9CE472B89164700EB6E78 /* Authorization.swift in Sources */,
|
C7A9CE472B89164700EB6E78 /* Authorization.swift in Sources */,
|
||||||
C7FEBA112BDC422200AE195F /* AppSearchView.swift in Sources */,
|
C7FEBA112BDC422200AE195F /* AppSearchView.swift in Sources */,
|
||||||
C7CF47242B3B3F1700979C5F /* WindowSettings.swift in Sources */,
|
C7CF47242B3B3F1700979C5F /* WindowSettings.swift in Sources */,
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ struct AppCommands: Commands {
|
|||||||
.keyboardShortcut("r", modifiers: .command)
|
.keyboardShortcut("r", modifiers: .command)
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
uninstallPearcleaner(appState: appState, locations: locations)
|
appState.triggerUninstallAlert()
|
||||||
} label: {
|
} label: {
|
||||||
Text("Uninstall Pearcleaner")
|
Text("Uninstall Pearcleaner")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -310,7 +310,6 @@ class AppPathFinder {
|
|||||||
self.appState.appInfo = self.appInfo
|
self.appState.appInfo = self.appInfo
|
||||||
if !self.undo {
|
if !self.undo {
|
||||||
self.appState.selectedItems = Set(updatedCollection)
|
self.appState.selectedItems = Set(updatedCollection)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ import FinderSync
|
|||||||
|
|
||||||
let home = FileManager.default.homeDirectoryForCurrentUser.path
|
let home = FileManager.default.homeDirectoryForCurrentUser.path
|
||||||
|
|
||||||
class AppState: ObservableObject
|
class AppState: ObservableObject {
|
||||||
{
|
|
||||||
@Published var appInfo: AppInfo
|
@Published var appInfo: AppInfo
|
||||||
@Published var appInfoStore: [AppInfo] = []
|
@Published var appInfoStore: [AppInfo] = []
|
||||||
@Published var trashedFiles: [AppInfo] = []
|
@Published var trashedFiles: [AppInfo] = []
|
||||||
@@ -29,8 +28,10 @@ class AppState: ObservableObject
|
|||||||
@Published var showProgress: Bool = false
|
@Published var showProgress: Bool = false
|
||||||
@Published var finderExtensionEnabled: Bool = false
|
@Published var finderExtensionEnabled: Bool = false
|
||||||
@Published var updateAvailable: Bool = false
|
@Published var updateAvailable: Bool = false
|
||||||
|
@Published var featureAvailable: Bool = false
|
||||||
@Published var permissionsOkay: Bool = true
|
@Published var permissionsOkay: Bool = true
|
||||||
@Published var permissionResults: PermissionsCheckResults?
|
@Published var permissionResults: PermissionsCheckResults?
|
||||||
|
@Published var showUninstallAlert: Bool = false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -74,6 +75,11 @@ class AppState: ObservableObject
|
|||||||
self.finderExtensionEnabled = extensionStatus
|
self.finderExtensionEnabled = extensionStatus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func triggerUninstallAlert() {
|
||||||
|
self.showUninstallAlert = true
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -166,6 +172,7 @@ enum NewWindow:Int
|
|||||||
case update
|
case update
|
||||||
case no_update
|
case no_update
|
||||||
case perm
|
case perm
|
||||||
|
case feature
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -110,8 +110,8 @@ let skipConditions: [SkipCondition] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
// Skip files/folders during reverse file search
|
// 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"]
|
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
|
// Function to load additional conditions from a GitHub JSON file
|
||||||
|
|||||||
@@ -8,8 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
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")!
|
let url = URL(string: "https://api.github.com/repos/alienator88/Pearcleaner/contents/features.json")!
|
||||||
var request = URLRequest(url: url)
|
var request = URLRequest(url: url)
|
||||||
request.setValue("application/vnd.github.VERSION.raw", forHTTPHeaderField: "Accept")
|
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() {
|
if features.wrappedValue != featureText.featureFormat() {
|
||||||
updateOnMain {
|
updateOnMain {
|
||||||
features.wrappedValue = featureText.featureFormat()
|
features.wrappedValue = featureText.featureFormat()
|
||||||
show.wrappedValue = true
|
appState.featureAvailable = true
|
||||||
|
// show.wrappedValue = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
show.wrappedValue = false
|
updateOnMain {
|
||||||
|
appState.featureAvailable = false
|
||||||
|
}
|
||||||
|
// show.wrappedValue = false
|
||||||
// print("Same version")
|
// print("Same version")
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
show.wrappedValue = false
|
updateOnMain {
|
||||||
|
appState.featureAvailable = false
|
||||||
|
}
|
||||||
|
// show.wrappedValue = false
|
||||||
// print("No features for version found")
|
// print("No features for version found")
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
show.wrappedValue = false
|
|
||||||
printOS("Error reading features JSON from GitHub: \(error.localizedDescription)")
|
printOS("Error reading features JSON from GitHub: \(error.localizedDescription)")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
show.wrappedValue = false
|
|
||||||
printOS("Error reading features JSON from GitHub: \(error?.localizedDescription ?? "Unknown error")")
|
printOS("Error reading features JSON from GitHub: \(error?.localizedDescription ?? "Unknown error")")
|
||||||
}
|
}
|
||||||
}.resume()
|
}.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",
|
||||||
"\(home)/Library/Application Scripts",
|
"\(home)/Library/Application Scripts",
|
||||||
"\(home)/Library/Application Support",
|
"\(home)/Library/Application Support",
|
||||||
"\(home)/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments",
|
|
||||||
"\(home)/Library/Containers",
|
"\(home)/Library/Containers",
|
||||||
"\(home)/Library/Caches",
|
"\(home)/Library/Caches",
|
||||||
"\(home)/Library/Group Containers",
|
"\(home)/Library/Group Containers",
|
||||||
|
|||||||
@@ -6,17 +6,16 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import EventKit
|
//import EventKit
|
||||||
|
|
||||||
struct PermissionsCheckResults {
|
struct PermissionsCheckResults {
|
||||||
var fullDiskAccess: Bool
|
var fullDiskAccess: Bool
|
||||||
var accessibility: Bool
|
var accessibility: Bool
|
||||||
var automation: Bool
|
var automation: Bool
|
||||||
var reminders: Bool
|
|
||||||
|
|
||||||
// Computed property to check if all permissions are granted
|
// Computed property to check if all permissions are granted
|
||||||
var allPermissionsGranted: Bool {
|
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()
|
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
|
// Wait for all async checks to complete
|
||||||
dispatchGroup.notify(queue: .main) {
|
dispatchGroup.notify(queue: .main) {
|
||||||
let results = PermissionsCheckResults(
|
let results = PermissionsCheckResults(
|
||||||
fullDiskAccess: fullDiskAccess,
|
fullDiskAccess: fullDiskAccess,
|
||||||
accessibility: accessibilityEnabled,
|
accessibility: accessibilityEnabled,
|
||||||
automation: automationAccess,
|
automation: automationAccess
|
||||||
reminders: remindersAccess
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check if any permission is denied and show window
|
// 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 {
|
updateOnMain {
|
||||||
appState.permissionsOkay = false
|
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 {
|
struct PermissionsNotificationView: View {
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ struct InfoButtonPerms: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.popover(isPresented: $isPopoverPresented, arrowEdge: .bottom) {
|
.popover(isPresented: $isPopoverPresented, arrowEdge: .bottom) {
|
||||||
VStack(alignment: .leading, spacing: 10) {
|
VStack(alignment: .leading, spacing: 15) {
|
||||||
|
|
||||||
HStack(alignment: .top, spacing: 20) {
|
HStack(alignment: .top, spacing: 20) {
|
||||||
Image(systemName: "externaldrive")
|
Image(systemName: "externaldrive")
|
||||||
@@ -268,7 +268,7 @@ struct InfoButtonPerms: View {
|
|||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
.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)
|
.font(.callout)
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
}
|
}
|
||||||
@@ -279,7 +279,7 @@ struct InfoButtonPerms: View {
|
|||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
Text("Accessibility permission to delete files via Finder")
|
Text("Accessibility permission to allow execution of AppleScript")
|
||||||
.font(.callout)
|
.font(.callout)
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
}
|
}
|
||||||
@@ -290,21 +290,11 @@ struct InfoButtonPerms: View {
|
|||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
.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)
|
.font(.callout)
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
.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()
|
.padding()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ func findAndHideWindows(named titles: [String]) {
|
|||||||
func findAndSetWindowFrame(named titles: [String], windowSettings: WindowSettings) {
|
func findAndSetWindowFrame(named titles: [String], windowSettings: WindowSettings) {
|
||||||
for title in titles {
|
for title in titles {
|
||||||
if let window = NSApp.windows.first(where: { $0.title == title }) {
|
if let window = NSApp.windows.first(where: { $0.title == title }) {
|
||||||
// window.isRestorable = false // Doing this via view
|
window.isRestorable = false
|
||||||
let frame = windowSettings.loadWindowSettings()
|
let frame = windowSettings.loadWindowSettings()
|
||||||
window.setFrame(frame, display: true)
|
window.setFrame(frame, display: true)
|
||||||
}
|
}
|
||||||
@@ -561,10 +561,8 @@ func uninstallPearcleaner(appState: AppState, locations: Locations) {
|
|||||||
let appInfo = AppInfoFetcher.getAppInfo(atPath: Bundle.main.bundleURL)
|
let appInfo = AppInfoFetcher.getAppInfo(atPath: Bundle.main.bundleURL)
|
||||||
|
|
||||||
// Find application files for Pearcleaner
|
// Find application files for Pearcleaner
|
||||||
AppPathFinder(appInfo: appInfo!, appState: appState, locations: locations).findPaths()
|
AppPathFinder(appInfo: appInfo!, appState: appState, locations: locations, completion: {
|
||||||
|
// Kill Pearcleaner and tell Finder to trash the files
|
||||||
// Kill Pearcleaner and tell Finder to trash the files
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
|
||||||
let selectedItemsArray = Array(appState.selectedItems).filter { !$0.path.contains(".Trash") }
|
let selectedItemsArray = Array(appState.selectedItems).filter { !$0.path.contains(".Trash") }
|
||||||
let posixFiles = selectedItemsArray.map { "POSIX file \"\($0.path)\", " }.joined().dropLast(3)
|
let posixFiles = selectedItemsArray.map { "POSIX file \"\($0.path)\", " }.joined().dropLast(3)
|
||||||
let scriptSource = """
|
let scriptSource = """
|
||||||
@@ -577,8 +575,7 @@ func uninstallPearcleaner(appState: AppState, locations: Locations) {
|
|||||||
|
|
||||||
NSApp.terminate(nil)
|
NSApp.terminate(nil)
|
||||||
exit(0)
|
exit(0)
|
||||||
}
|
}).findPaths()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,10 +26,8 @@ struct PearcleanerApp: App {
|
|||||||
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
|
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
|
||||||
@AppStorage("settings.menubar.mainWin") private var mainWinEnabled: Bool = false
|
@AppStorage("settings.menubar.mainWin") private var mainWinEnabled: Bool = false
|
||||||
@AppStorage("settings.interface.selectedMenubarIcon") var selectedMenubarIcon: String = "trash"
|
@AppStorage("settings.interface.selectedMenubarIcon") var selectedMenubarIcon: String = "trash"
|
||||||
|
|
||||||
@State private var search = ""
|
@State private var search = ""
|
||||||
@State private var showPopover: Bool = false
|
@State private var showPopover: Bool = false
|
||||||
@State private var showFeature: Bool = false
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -37,21 +35,11 @@ struct PearcleanerApp: App {
|
|||||||
|
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
Group {
|
Group {
|
||||||
ZStack() {
|
|
||||||
if !mini {
|
if !mini {
|
||||||
RegularMode(search: $search, showPopover: $showPopover)
|
RegularMode(search: $search, showPopover: $showPopover)
|
||||||
} else {
|
} else {
|
||||||
MiniMode(search: $search, showPopover: $showPopover)
|
MiniMode(search: $search, showPopover: $showPopover)
|
||||||
}
|
}
|
||||||
|
|
||||||
if showFeature {
|
|
||||||
NewFeatureView(text: features, mini: mini, showFeature: $showFeature)
|
|
||||||
.transition(.opacity)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.environmentObject(appState)
|
.environmentObject(appState)
|
||||||
.environmentObject(locations)
|
.environmentObject(locations)
|
||||||
@@ -80,6 +68,16 @@ struct PearcleanerApp: App {
|
|||||||
windowSettings.saveWindowSettings(frame: newFrame)
|
windowSettings.saveWindowSettings(frame: newFrame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.alert(isPresented: $appState.showUninstallAlert) {
|
||||||
|
Alert(
|
||||||
|
title: Text("Warning!"),
|
||||||
|
message: Text("Pearcleaner and all of its files will be cleanly removed, are you sure?"),
|
||||||
|
primaryButton: .destructive(Text("Uninstall")) {
|
||||||
|
uninstallPearcleaner(appState: appState, locations: locations)
|
||||||
|
},
|
||||||
|
secondaryButton: .cancel()
|
||||||
|
)
|
||||||
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
|
|
||||||
if miniView {
|
if miniView {
|
||||||
@@ -91,10 +89,6 @@ struct PearcleanerApp: App {
|
|||||||
// Disable tabbing
|
// Disable tabbing
|
||||||
NSWindow.allowsAutomaticWindowTabbing = false
|
NSWindow.allowsAutomaticWindowTabbing = false
|
||||||
|
|
||||||
|
|
||||||
// Set window size on load
|
|
||||||
// findAndSetWindowFrame(named: ["Pearcleaner"], windowSettings: windowSettings)
|
|
||||||
|
|
||||||
// Get Apps
|
// Get Apps
|
||||||
let sortedApps = getSortedApps(paths: fsm.folderPaths, appState: appState)
|
let sortedApps = getSortedApps(paths: fsm.folderPaths, appState: appState)
|
||||||
appState.sortedApps = sortedApps
|
appState.sortedApps = sortedApps
|
||||||
@@ -112,7 +106,7 @@ struct PearcleanerApp: App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG
|
#if !DEBUG
|
||||||
Task {
|
Task {
|
||||||
|
|
||||||
|
|
||||||
@@ -124,7 +118,7 @@ struct PearcleanerApp: App {
|
|||||||
appState.permissionResults = results
|
appState.permissionResults = results
|
||||||
if results.allPermissionsGranted {
|
if results.allPermissionsGranted {
|
||||||
loadGithubReleases(appState: appState)
|
loadGithubReleases(appState: appState)
|
||||||
getFeatures(appState: appState, show: $showFeature, features: $features)
|
getFeatures(appState: appState, features: $features)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,14 +153,13 @@ struct PearcleanerApp: App {
|
|||||||
|
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
SettingsView(showPopover: $showPopover, search: $search, showFeature: $showFeature)
|
SettingsView(showPopover: $showPopover, search: $search)
|
||||||
.environmentObject(appState)
|
.environmentObject(appState)
|
||||||
.environmentObject(locations)
|
.environmentObject(locations)
|
||||||
.environmentObject(fsm)
|
.environmentObject(fsm)
|
||||||
.environmentObject(ThemeSettings.shared)
|
.environmentObject(ThemeSettings.shared)
|
||||||
.toolbarBackground(.clear)
|
.toolbarBackground(.clear)
|
||||||
.preferredColorScheme(displayMode.colorScheme)
|
.preferredColorScheme(displayMode.colorScheme)
|
||||||
.willRestore()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ struct GeneralSettingsTab: View {
|
|||||||
@State private var diskStatus: Bool = false
|
@State private var diskStatus: Bool = false
|
||||||
@State private var accessStatus: Bool = false
|
@State private var accessStatus: Bool = false
|
||||||
@State private var autoStatus: Bool = false
|
@State private var autoStatus: Bool = false
|
||||||
@State private var remStatus: Bool = false
|
|
||||||
@Binding var showPopover: Bool
|
@Binding var showPopover: Bool
|
||||||
@Binding var search: String
|
@Binding var search: String
|
||||||
@State var selectedIndex: Int?
|
@State var selectedIndex: Int?
|
||||||
@@ -182,6 +181,8 @@ struct GeneralSettingsTab: View {
|
|||||||
|
|
||||||
InfoButtonPerms()
|
InfoButtonPerms()
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
Button("Refresh") {
|
Button("Refresh") {
|
||||||
checkAllPermissions(appState: appState) { results in
|
checkAllPermissions(appState: appState) { results in
|
||||||
updateOnMain {
|
updateOnMain {
|
||||||
@@ -190,7 +191,6 @@ struct GeneralSettingsTab: View {
|
|||||||
diskStatus = results.fullDiskAccess
|
diskStatus = results.fullDiskAccess
|
||||||
accessStatus = results.accessibility
|
accessStatus = results.accessibility
|
||||||
autoStatus = results.automation
|
autoStatus = results.automation
|
||||||
remStatus = results.reminders
|
|
||||||
if results.allPermissionsGranted {
|
if results.allPermissionsGranted {
|
||||||
updateOnMain {
|
updateOnMain {
|
||||||
appState.permissionsOkay = true
|
appState.permissionsOkay = true
|
||||||
@@ -199,142 +199,91 @@ struct GeneralSettingsTab: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.triangle.2.circlepath", help: "Refresh permissions"))
|
.buttonStyle(SimpleButtonStyle(icon: "arrow.triangle.2.circlepath", help: "Refresh permissions"))
|
||||||
|
.padding(.trailing, 5)
|
||||||
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
.padding(.leading)
|
.padding(.leading)
|
||||||
|
|
||||||
|
|
||||||
HStack {
|
HStack(spacing: 0) {
|
||||||
HStack(spacing: 0) {
|
Image(systemName: "externaldrive")
|
||||||
Image(systemName: "externaldrive")
|
.resizable()
|
||||||
.resizable()
|
.scaledToFit()
|
||||||
.scaledToFit()
|
.frame(width: 20, height: 20)
|
||||||
.frame(width: 20, height: 20)
|
.padding(.trailing)
|
||||||
.padding(.trailing)
|
.foregroundStyle(diskStatus ? .green : .red)
|
||||||
.foregroundStyle(diskStatus ? .green : .red)
|
.saturation(displayMode.colorScheme == .dark ? 0.5 : 1)
|
||||||
.saturation(displayMode.colorScheme == .dark ? 0.5 : 1)
|
Text(diskStatus ? "Full Disk permission granted" : "Full Disk permission not granted")
|
||||||
Text("Full Disk")
|
.font(.callout)
|
||||||
.font(.callout)
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
|
||||||
.frame(width: 100)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Button("") {
|
|
||||||
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles") {
|
|
||||||
NSWorkspace.shared.open(url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.right.circle.fill", help: "View disk permissions pane", size: 14))
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
}
|
|
||||||
.padding(5)
|
|
||||||
.padding(.leading)
|
|
||||||
.frame(width: 200)
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
Button("") {
|
||||||
HStack(spacing: 0) {
|
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles") {
|
||||||
Image(systemName: "accessibility")
|
NSWorkspace.shared.open(url)
|
||||||
.resizable()
|
|
||||||
.scaledToFit()
|
|
||||||
.frame(width: 20, height: 20)
|
|
||||||
.padding(.trailing)
|
|
||||||
.foregroundStyle(accessStatus ? .green : .red)
|
|
||||||
.saturation(displayMode.colorScheme == .dark ? 0.5 : 1)
|
|
||||||
Text("Accessibility")
|
|
||||||
.font(.callout)
|
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
|
||||||
.frame(width: 100)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Button("") {
|
|
||||||
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility") {
|
|
||||||
NSWorkspace.shared.open(url)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.right.circle.fill", help: "View accessibility permissions pane", size: 14))
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.padding(5)
|
.buttonStyle(SimpleButtonStyle(icon: "folder", help: "View disk permissions pane"))
|
||||||
.padding(.leading)
|
|
||||||
.frame(width: 200)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
.padding(5)
|
||||||
|
.padding(.leading)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
|
||||||
HStack {
|
HStack(spacing: 0) {
|
||||||
HStack(spacing: 0) {
|
Image(systemName: "accessibility")
|
||||||
Image(systemName: "gearshape.2")
|
.resizable()
|
||||||
.resizable()
|
.scaledToFit()
|
||||||
.scaledToFit()
|
.frame(width: 20, height: 20)
|
||||||
.frame(width: 20, height: 20)
|
.padding(.trailing)
|
||||||
.padding(.trailing)
|
.foregroundStyle(accessStatus ? .green : .red)
|
||||||
.foregroundStyle(autoStatus ? .green : .red)
|
.saturation(displayMode.colorScheme == .dark ? 0.5 : 1)
|
||||||
.saturation(displayMode.colorScheme == .dark ? 0.5 : 1)
|
Text(accessStatus ? "Accessibility permission granted" : "Accessibility permission not granted")
|
||||||
Text("Automation")
|
.font(.callout)
|
||||||
.font(.callout)
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
|
||||||
.frame(width: 100)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Button("") {
|
|
||||||
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation") {
|
|
||||||
NSWorkspace.shared.open(url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.right.circle.fill", help: "View automation permissions pane", size: 14))
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
}
|
|
||||||
.padding(5)
|
|
||||||
.padding(.leading)
|
|
||||||
.frame(width: 200)
|
|
||||||
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
HStack(spacing: 0) {
|
Button("") {
|
||||||
Image(systemName: "calendar")
|
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility") {
|
||||||
.resizable()
|
NSWorkspace.shared.open(url)
|
||||||
.scaledToFit()
|
|
||||||
.frame(width: 20, height: 20)
|
|
||||||
.padding(.trailing)
|
|
||||||
.foregroundStyle(remStatus ? .green : .red)
|
|
||||||
.saturation(displayMode.colorScheme == .dark ? 0.5 : 1)
|
|
||||||
Text("Reminders")
|
|
||||||
.font(.callout)
|
|
||||||
.foregroundStyle(Color("mode").opacity(0.5))
|
|
||||||
.frame(width: 100)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Button("") {
|
|
||||||
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Reminders") {
|
|
||||||
NSWorkspace.shared.open(url)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.right.circle.fill", help: "View reminders permissions pane", size: 14))
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.padding(5)
|
.buttonStyle(SimpleButtonStyle(icon: "folder", help: "View accessibility permissions pane"))
|
||||||
.padding(.leading)
|
|
||||||
.frame(width: 200)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
.padding(5)
|
||||||
|
.padding(.leading)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
Image(systemName: "gearshape.2")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 20, height: 20)
|
||||||
|
.padding(.trailing)
|
||||||
|
.foregroundStyle(autoStatus ? .green : .red)
|
||||||
|
.saturation(displayMode.colorScheme == .dark ? 0.5 : 1)
|
||||||
|
Text(autoStatus ? "Automation permission granted" : "Automation permission not granted")
|
||||||
|
.font(.callout)
|
||||||
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Button("") {
|
||||||
|
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation") {
|
||||||
|
NSWorkspace.shared.open(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttonStyle(SimpleButtonStyle(icon: "folder", help: "View automation permissions pane"))
|
||||||
|
|
||||||
|
}
|
||||||
|
.padding(5)
|
||||||
|
.padding(.leading)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -445,7 +394,6 @@ struct GeneralSettingsTab: View {
|
|||||||
diskStatus = results.fullDiskAccess
|
diskStatus = results.fullDiskAccess
|
||||||
accessStatus = results.accessibility
|
accessStatus = results.accessibility
|
||||||
autoStatus = results.automation
|
autoStatus = results.automation
|
||||||
remStatus = results.reminders
|
|
||||||
if results.allPermissionsGranted {
|
if results.allPermissionsGranted {
|
||||||
updateOnMain {
|
updateOnMain {
|
||||||
appState.permissionsOkay = true
|
appState.permissionsOkay = true
|
||||||
@@ -457,23 +405,17 @@ struct GeneralSettingsTab: View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
.padding(20)
|
.padding(20)
|
||||||
.frame(width: 500, height: 650)
|
.frame(width: 500, height: 670)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var keysToIgnore: Set<String> {
|
|
||||||
["windowWidthKey", "windowHeightKey", "windowWidthKeyMini", "windowHeightKeyMini", "windowXKey", "windowYKey"]
|
|
||||||
}
|
|
||||||
|
|
||||||
private func resetUserDefaults() {
|
private func resetUserDefaults() {
|
||||||
isResetting = true
|
isResetting = true
|
||||||
DispatchQueue.global(qos: .background).async {
|
DispatchQueue.global(qos: .background).async {
|
||||||
let defaults = UserDefaults.standard
|
let defaults = UserDefaults.standard
|
||||||
let dictionary = defaults.dictionaryRepresentation()
|
let dictionary = defaults.dictionaryRepresentation()
|
||||||
dictionary.keys.forEach { key in
|
dictionary.keys.forEach { key in
|
||||||
if !keysToIgnore.contains(key) {
|
defaults.removeObject(forKey: key)
|
||||||
defaults.removeObject(forKey: key)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
isResetting = false
|
isResetting = false
|
||||||
|
|||||||
@@ -306,26 +306,23 @@ struct InterfaceSettingsTab: View {
|
|||||||
if mini {
|
if mini {
|
||||||
appState.currentView = miniView ? .apps : .empty
|
appState.currentView = miniView ? .apps : .empty
|
||||||
showPopover = false
|
showPopover = false
|
||||||
findAndHideWindows(named: ["Pearcleaner"])
|
windowSettings.newWindow(withView: {
|
||||||
windowSettings.newWindow {
|
|
||||||
MiniMode(search: $search, showPopover: $showPopover)
|
MiniMode(search: $search, showPopover: $showPopover)
|
||||||
.environmentObject(locations)
|
.environmentObject(locations)
|
||||||
.environmentObject(appState)
|
.environmentObject(appState)
|
||||||
.environmentObject(fsm)
|
.environmentObject(fsm)
|
||||||
.environmentObject(ThemeSettings.shared)
|
.environmentObject(ThemeSettings.shared)
|
||||||
.preferredColorScheme(displayMode.colorScheme)
|
.preferredColorScheme(displayMode.colorScheme)
|
||||||
}
|
}) {
|
||||||
updateOnMain(after: 0.1, {
|
|
||||||
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
|
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
|
||||||
})
|
}
|
||||||
} else {
|
} else {
|
||||||
if appState.appInfo.appName.isEmpty {
|
if appState.appInfo.appName.isEmpty {
|
||||||
appState.currentView = .empty
|
appState.currentView = .empty
|
||||||
} else {
|
} else {
|
||||||
appState.currentView = .files
|
appState.currentView = .files
|
||||||
}
|
}
|
||||||
findAndHideWindows(named: ["Pearcleaner"])
|
windowSettings.newWindow(withView: {
|
||||||
windowSettings.newWindow {
|
|
||||||
RegularMode(search: $search, showPopover: $showPopover)
|
RegularMode(search: $search, showPopover: $showPopover)
|
||||||
.environmentObject(locations)
|
.environmentObject(locations)
|
||||||
.environmentObject(appState)
|
.environmentObject(appState)
|
||||||
@@ -333,9 +330,9 @@ struct InterfaceSettingsTab: View {
|
|||||||
.environmentObject(ThemeSettings.shared)
|
.environmentObject(ThemeSettings.shared)
|
||||||
.preferredColorScheme(displayMode.colorScheme)
|
.preferredColorScheme(displayMode.colorScheme)
|
||||||
}
|
}
|
||||||
updateOnMain(after: 0.1, {
|
) {
|
||||||
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
|
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -443,25 +440,27 @@ struct InterfaceSettingsTab: View {
|
|||||||
NSApplication.shared.setActivationPolicy(.regular)
|
NSApplication.shared.setActivationPolicy(.regular)
|
||||||
if !hasWindowOpen() {
|
if !hasWindowOpen() {
|
||||||
if mini {
|
if mini {
|
||||||
windowSettings.newWindow {
|
windowSettings.newWindow(withView: {
|
||||||
MiniMode(search: $search, showPopover: $showPopover)
|
MiniMode(search: $search, showPopover: $showPopover)
|
||||||
.environmentObject(locations)
|
.environmentObject(locations)
|
||||||
.environmentObject(appState)
|
.environmentObject(appState)
|
||||||
.environmentObject(fsm)
|
.environmentObject(fsm)
|
||||||
.environmentObject(ThemeSettings.shared)
|
.environmentObject(ThemeSettings.shared)
|
||||||
.preferredColorScheme(displayMode.colorScheme)
|
.preferredColorScheme(displayMode.colorScheme)
|
||||||
|
}) {
|
||||||
|
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
|
||||||
}
|
}
|
||||||
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
|
|
||||||
} else {
|
} else {
|
||||||
windowSettings.newWindow {
|
windowSettings.newWindow(withView: {
|
||||||
RegularMode(search: $search, showPopover: $showPopover)
|
RegularMode(search: $search, showPopover: $showPopover)
|
||||||
.environmentObject(locations)
|
.environmentObject(locations)
|
||||||
.environmentObject(appState)
|
.environmentObject(appState)
|
||||||
.environmentObject(fsm)
|
.environmentObject(fsm)
|
||||||
.environmentObject(ThemeSettings.shared)
|
.environmentObject(ThemeSettings.shared)
|
||||||
.preferredColorScheme(displayMode.colorScheme)
|
.preferredColorScheme(displayMode.colorScheme)
|
||||||
|
}) {
|
||||||
|
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
|
||||||
}
|
}
|
||||||
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ struct SettingsView: View {
|
|||||||
@EnvironmentObject var themeSettings: ThemeSettings
|
@EnvironmentObject var themeSettings: ThemeSettings
|
||||||
@Binding var showPopover: Bool
|
@Binding var showPopover: Bool
|
||||||
@Binding var search: String
|
@Binding var search: String
|
||||||
@Binding var showFeature: Bool
|
|
||||||
@AppStorage("settings.general.glass") private var glass: Bool = false
|
@AppStorage("settings.general.glass") private var glass: Bool = false
|
||||||
@AppStorage("settings.general.selectedTab") private var selectedTab: CurrentTabView = .general
|
@AppStorage("settings.general.selectedTab") private var selectedTab: CurrentTabView = .general
|
||||||
|
|
||||||
@@ -38,7 +37,7 @@ struct SettingsView: View {
|
|||||||
}
|
}
|
||||||
.tag(CurrentTabView.folders)
|
.tag(CurrentTabView.folders)
|
||||||
|
|
||||||
UpdateSettingsTab(showFeature: $showFeature)
|
UpdateSettingsTab()
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label(CurrentTabView.update.title, systemImage: "cloud")
|
Label(CurrentTabView.update.title, systemImage: "cloud")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ struct UpdateSettingsTab: View {
|
|||||||
@State private var showAlert = false
|
@State private var showAlert = false
|
||||||
@State private var showDone = false
|
@State private var showDone = false
|
||||||
@AppStorage("settings.updater.updateTimeframe") private var updateTimeframe: Int = 1
|
@AppStorage("settings.updater.updateTimeframe") private var updateTimeframe: Int = 1
|
||||||
@Binding var showFeature: Bool
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
@@ -61,7 +60,7 @@ struct UpdateSettingsTab: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Button(""){
|
Button(""){
|
||||||
showFeature.toggle()
|
NewWin.show(appState: appState, width: 500, height: 440, newWin: .feature)
|
||||||
}
|
}
|
||||||
.buttonStyle(SimpleButtonStyle(icon: "star", help: "Show last feature alert"))
|
.buttonStyle(SimpleButtonStyle(icon: "star", help: "Show last feature alert"))
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ struct AppSearchView: View {
|
|||||||
UpdateNotificationView(appState: appState)
|
UpdateNotificationView(appState: appState)
|
||||||
} else if !appState.permissionsOkay {
|
} else if !appState.permissionsOkay {
|
||||||
PermissionsNotificationView(appState: appState)
|
PermissionsNotificationView(appState: appState)
|
||||||
|
} else if appState.featureAvailable {
|
||||||
|
FeatureNotificationView(appState: appState)
|
||||||
}
|
}
|
||||||
|
|
||||||
AppsListView(search: $search, showPopover: $showPopover, filteredApps: filteredApps)
|
AppsListView(search: $search, showPopover: $showPopover, filteredApps: filteredApps)
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// FeatureView.swift
|
||||||
|
// Pearcleaner
|
||||||
|
//
|
||||||
|
// Created by Alin Lupascu on 5/5/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
|
||||||
|
struct FeatureView: View {
|
||||||
|
@EnvironmentObject var appState: AppState
|
||||||
|
@AppStorage("settings.general.features") private var features: String = ""
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(spacing: 5) {
|
||||||
|
HStack {
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Text("New features for v\((Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String)!)!") .font(.title)
|
||||||
|
.bold()
|
||||||
|
.padding(.vertical)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Divider()
|
||||||
|
.padding([.horizontal])
|
||||||
|
|
||||||
|
Text(features)
|
||||||
|
.font(.body)
|
||||||
|
.lineLimit(3)
|
||||||
|
.multilineTextAlignment(.leading)
|
||||||
|
.padding()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
HStack(alignment: .center, spacing: 20) {
|
||||||
|
Button(action: {
|
||||||
|
NewWin.close()
|
||||||
|
}) {
|
||||||
|
Text("Okay")
|
||||||
|
}
|
||||||
|
.buttonStyle(SimpleButtonBrightStyle(icon: "checkmark.circle", label: "Ok", help: "Ok", color: .accentColor))
|
||||||
|
}
|
||||||
|
.padding(.bottom)
|
||||||
|
|
||||||
|
}
|
||||||
|
.padding(EdgeInsets(top: -25, leading: 0, bottom: 25, trailing: 0))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -80,7 +80,11 @@ class NewWin: NSWindowController {
|
|||||||
return AnyView(PermView()
|
return AnyView(PermView()
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
.background(.black.opacity(0.2))
|
.background(.black.opacity(0.2))
|
||||||
|
.environmentObject(appState))
|
||||||
|
case .feature:
|
||||||
|
return AnyView(FeatureView()
|
||||||
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
|
.background(.black.opacity(0.2))
|
||||||
.environmentObject(appState))
|
.environmentObject(appState))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class WindowSettings {
|
|||||||
return NSRect(x: x, y: y, width: width, height: height)
|
return NSRect(x: x, y: y, width: width, height: height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWindow<V: View>(withView view: @escaping () -> V) {
|
func newWindow<V: View>(withView view: @escaping () -> V, completion: @escaping () -> Void = {}) {
|
||||||
findAndHideWindows(named: ["Pearcleaner"])
|
findAndHideWindows(named: ["Pearcleaner"])
|
||||||
let contentView = view
|
let contentView = view
|
||||||
let frame = self.loadWindowSettings()
|
let frame = self.loadWindowSettings()
|
||||||
@@ -56,30 +56,32 @@ class WindowSettings {
|
|||||||
newWindow.isMovableByWindowBackground = true
|
newWindow.isMovableByWindowBackground = true
|
||||||
newWindow.center()
|
newWindow.center()
|
||||||
newWindow.title = "Pearcleaner"
|
newWindow.title = "Pearcleaner"
|
||||||
|
newWindow.isRestorable = false
|
||||||
newWindow.titleVisibility = .hidden
|
newWindow.titleVisibility = .hidden
|
||||||
newWindow.setFrameAutosaveName("Pearcleaner")
|
newWindow.setFrameAutosaveName("Pearcleaner")
|
||||||
newWindow.contentView = NSHostingView(rootView: contentView())
|
newWindow.contentView = NSHostingView(rootView: contentView())
|
||||||
self.windows.append(newWindow)
|
self.windows.append(newWindow)
|
||||||
newWindow.makeKeyAndOrderFront(nil)
|
newWindow.makeKeyAndOrderFront(nil)
|
||||||
|
completion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct WillRestore: ViewModifier {
|
//struct WillRestore: ViewModifier {
|
||||||
let restore: Bool
|
// let restore: Bool
|
||||||
|
//
|
||||||
func body(content: Content) -> some View {
|
// func body(content: Content) -> some View {
|
||||||
content
|
// content
|
||||||
.onReceive(NotificationCenter.default.publisher(for: NSWindow.didBecomeKeyNotification), perform: { output in
|
// .onReceive(NotificationCenter.default.publisher(for: NSWindow.didBecomeKeyNotification), perform: { output in
|
||||||
let window = output.object as! NSWindow
|
// let window = output.object as! NSWindow
|
||||||
window.isRestorable = false
|
// window.isRestorable = false
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
extension View {
|
//extension View {
|
||||||
func willRestore(_ restoreState: Bool = true) -> some View {
|
// func willRestore(_ restoreState: Bool = true) -> some View {
|
||||||
modifier(WillRestore(restore: restoreState))
|
// modifier(WillRestore(restore: restoreState))
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|||||||
Reference in New Issue
Block a user