mirror of
https://github.com/exituser/Pearcleaner.git
synced 2026-09-17 08:29:07 +00:00
v3.0.0
This commit is contained in:
@@ -36,10 +36,11 @@ struct AboutSettingsTab: View {
|
||||
VStack(alignment: .leading) {
|
||||
|
||||
HStack() {
|
||||
Text("Credits and Inspiration").font(.title2)
|
||||
Text("Credits").font(.title2)
|
||||
Spacer()
|
||||
}
|
||||
.padding(.leading)
|
||||
.padding(.bottom)
|
||||
|
||||
HStack{
|
||||
Image(systemName: "paintbrush.pointed")
|
||||
|
||||
@@ -19,9 +19,10 @@ struct GeneralSettingsTab: View {
|
||||
@AppStorage("settings.general.sidebarWidth") private var sidebarWidth: Double = 280
|
||||
@AppStorage("displayMode") var displayMode: DisplayMode = .system
|
||||
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
|
||||
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
|
||||
@AppStorage("settings.general.selectedTheme") var selectedTheme: String = "Auto"
|
||||
@State private var diskStatus: Bool = false
|
||||
@State private var accessStatus: Bool = false
|
||||
@State private var selectedTheme = "Auto"
|
||||
private let themes = ["Auto", "Dark", "Light"]
|
||||
@Binding var showPopover: Bool
|
||||
|
||||
@@ -57,25 +58,24 @@ struct GeneralSettingsTab: View {
|
||||
|
||||
|
||||
HStack(spacing: 0) {
|
||||
Image(systemName: "sidebar.left")
|
||||
Image(systemName: instantSearch ? "bolt" : "bolt.slash")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(.gray)
|
||||
Text("Adjust sidebar width")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("\(instantSearch ? "Instant search is enabled" : "Instant search is disabled")")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
|
||||
InfoButton(text: "When instant search is enabled, all application files are gathered and cached for later use on startup instead of on each app click. There might be a slight delay of a few seconds when launching Pearcleaner depending on the amount of apps you have installed.", color: nil)
|
||||
|
||||
Spacer()
|
||||
Slider(value: $sidebarWidth, in: 200...360) {
|
||||
// Text("\(Int(sidebarWidth))")
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.frame(width: 185)
|
||||
Button("") {
|
||||
sidebarWidth = 280
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.uturn.left.circle", help: "Reset to default size", color: Color("mode")))
|
||||
Toggle(isOn: $instantSearch, label: {
|
||||
})
|
||||
.toggleStyle(.switch)
|
||||
}
|
||||
.padding(5)
|
||||
.padding(.leading)
|
||||
@@ -89,7 +89,7 @@ struct GeneralSettingsTab: View {
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(.gray)
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("Set color mode")
|
||||
Text("Set application color mode")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
@@ -143,7 +143,7 @@ struct GeneralSettingsTab: View {
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(.gray)
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("\(mini ? "Mini window mode" : "Full size window mode")")
|
||||
Text("\(mini ? "Mini window mode selected" : "Full size window mode selected")")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
@@ -182,6 +182,9 @@ struct GeneralSettingsTab: View {
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
|
||||
InfoButton(text: "In mini window mode, you can have Pearcleaner startup to the Apps List view or the Drop Target view.", color: nil)
|
||||
|
||||
Spacer()
|
||||
Toggle(isOn: $miniView, label: {
|
||||
})
|
||||
@@ -202,10 +205,13 @@ struct GeneralSettingsTab: View {
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(.gray)
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("\(popoverStay ? "Popover window doesn't hide on outside click" : "Popover window hides on outside click")")
|
||||
Text("\(popoverStay ? "Popover window will stay on top" : "Popover window will not stay on top")")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
|
||||
InfoButton(text: "In mini window mode, if you pin the Files popover on top, clicking away from the window will not dismiss it. Otherwise, it will dismiss by clicking anywhere outside the popover.", color: nil)
|
||||
|
||||
Spacer()
|
||||
Toggle(isOn: $popoverStay, label: {
|
||||
})
|
||||
@@ -330,6 +336,11 @@ struct GeneralSettingsTab: View {
|
||||
.onAppear {
|
||||
diskStatus = checkAndRequestFullDiskAccess(appState: appState, skipAlert: true)
|
||||
accessStatus = checkAndRequestAccessibilityAccess(appState: appState)
|
||||
// if displayMode.colorScheme == .dark {
|
||||
// selectedTheme = "Dark"
|
||||
// } else if displayMode.colorScheme == .light {
|
||||
// selectedTheme = "Light"
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
//
|
||||
// Permissions.swift
|
||||
// Pearcleaner
|
||||
//
|
||||
// Created by Alin Lupascu on 11/5/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct PermissionsSettingsTab: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@State private var diskStatus: Bool = false
|
||||
@State private var accessStatus: Bool = false
|
||||
|
||||
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
|
||||
HStack(spacing: 0) {
|
||||
Image(systemName: diskStatus ? "externaldrive" : "externaldrive")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(diskStatus ? .green : .red)
|
||||
Text(diskStatus ? "Full Disk permission granted" : "Full Disk permission not granted")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
Spacer()
|
||||
|
||||
Button("") {
|
||||
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles") {
|
||||
NSWorkspace.shared.open(url)
|
||||
}
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "gear", help: "View disk permissions pane", color: Color("mode")))
|
||||
|
||||
}
|
||||
.padding(5)
|
||||
|
||||
|
||||
HStack(spacing: 0) {
|
||||
Image(systemName: accessStatus ? "accessibility" : "accessibility")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(accessStatus ? .green : .red)
|
||||
Text(accessStatus ? "Accessibility permission granted" : "Accessibility permission not granted")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
Spacer()
|
||||
|
||||
Button("") {
|
||||
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility") {
|
||||
NSWorkspace.shared.open(url)
|
||||
}
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "gear", help: "View accessibility permissions pane", color: Color("mode")))
|
||||
|
||||
}
|
||||
.padding(5)
|
||||
|
||||
|
||||
// HStack(spacing: 15) {
|
||||
// Image(systemName: "internaldrive")
|
||||
// .resizable()
|
||||
// .scaledToFit()
|
||||
// .frame(width: 20)
|
||||
//
|
||||
// VStack(alignment: .leading, spacing: 5) {
|
||||
// Text("Full Disk")
|
||||
// Text(diskStatus ? "Permission granted" : "Permission not granted")
|
||||
// .font(.footnote)
|
||||
// .foregroundStyle(diskStatus ? .green : .red)
|
||||
// }
|
||||
//
|
||||
// Spacer()
|
||||
//
|
||||
// Button("") {
|
||||
// if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles") {
|
||||
// NSWorkspace.shared.open(url)
|
||||
// }
|
||||
// }
|
||||
// .buttonStyle(SimpleButtonStyle(icon: "paperplane", help: "View disk permission pane", color: Color("AccentColor")))
|
||||
// }
|
||||
// .padding()
|
||||
// .background(
|
||||
// RoundedRectangle(cornerRadius: 8)
|
||||
// .fill(Color("mode").opacity(0.05))
|
||||
// )
|
||||
|
||||
|
||||
// HStack(spacing: 15) {
|
||||
// Image(systemName: "accessibility")
|
||||
// .resizable()
|
||||
// .scaledToFit()
|
||||
// .frame(width: 20)
|
||||
//
|
||||
// VStack(alignment: .leading, spacing: 5) {
|
||||
// Text("Accessibility")
|
||||
// Text(accessStatus ? "Permission granted" : "Permission not granted")
|
||||
// .font(.footnote)
|
||||
// .foregroundStyle(accessStatus ? .green : .red)
|
||||
// }
|
||||
//
|
||||
// Spacer()
|
||||
//
|
||||
// Button("") {
|
||||
// if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility") {
|
||||
// NSWorkspace.shared.open(url)
|
||||
// }
|
||||
// }
|
||||
// .buttonStyle(SimpleButtonStyle(icon: "paperplane", help: "View accessibility pane", color: Color("AccentColor")))
|
||||
// }
|
||||
// .padding()
|
||||
// .background(
|
||||
// RoundedRectangle(cornerRadius: 8)
|
||||
// .fill(Color("mode").opacity(0.05))
|
||||
// )
|
||||
|
||||
|
||||
|
||||
// HStack(alignment: .center) {
|
||||
// Spacer()
|
||||
// Button("") {
|
||||
// relaunchApp()
|
||||
// }
|
||||
// .buttonStyle(SimpleButtonStyle(icon: "restart", help: "Restart application", color: Color("AccentColor")))
|
||||
// Text("Restart")
|
||||
// Spacer()
|
||||
// }
|
||||
// .padding()
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
.padding(20)
|
||||
.frame(width: 400, height: 200)
|
||||
.onAppear {
|
||||
diskStatus = checkAndRequestFullDiskAccess(appState: appState, skipAlert: true)
|
||||
accessStatus = checkAndRequestAccessibilityAccess(appState: appState)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
//
|
||||
// Sentinel.swift
|
||||
// Pearcleaner
|
||||
//
|
||||
// Created by Alin Lupascu on 11/9/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct SentinelSettingsTab: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
VStack {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("Sentinel Monitor").font(.title2)
|
||||
Text("Detects when apps are moved to Trash for file removal")
|
||||
.font(.footnote)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
Spacer()
|
||||
Toggle(isOn: $sentinel, label: {
|
||||
})
|
||||
.toggleStyle(SentinelToggleStyle())
|
||||
.onChange(of: sentinel) { newValue in
|
||||
if newValue {
|
||||
launchctl(load: true)
|
||||
} else {
|
||||
launchctl(load: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.fill(Color("mode").opacity(0.05))
|
||||
)
|
||||
Text("If you uninstall Pearcleaner, make sure to disable Sentinel first").font(.footnote)
|
||||
.foregroundStyle(Color.red)
|
||||
.padding()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
.padding(20)
|
||||
.frame(width: 450, height: 130)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,18 +20,6 @@ struct SettingsView: View {
|
||||
}
|
||||
.tag(CurrentTabView.general)
|
||||
|
||||
// PermissionsSettingsTab()
|
||||
// .tabItem {
|
||||
// Label(CurrentTabView.permissions.title, systemImage: "lock")
|
||||
// }
|
||||
// .tag(CurrentTabView.permissions)
|
||||
|
||||
// SentinelSettingsTab()
|
||||
// .tabItem {
|
||||
// Label(CurrentTabView.sentinel.title, systemImage: "eye.circle")
|
||||
// }
|
||||
// .tag(CurrentTabView.sentinel)
|
||||
|
||||
UpdateSettingsTab()
|
||||
.tabItem {
|
||||
Label(CurrentTabView.update.title, systemImage: "cloud")
|
||||
@@ -45,7 +33,7 @@ struct SettingsView: View {
|
||||
.tag(CurrentTabView.about)
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -56,3 +44,5 @@ struct SettingsView: View {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -71,23 +71,25 @@ struct UpdateSettingsTab: View {
|
||||
|
||||
HStack(alignment: .center, spacing: 20) {
|
||||
Spacer()
|
||||
|
||||
Button("Update Notes"){
|
||||
loadGithubReleases(appState: appState)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "list.bullet", help: "Check release notes", color: Color("mode")))
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("Force Update"){
|
||||
loadGithubReleases(appState: appState, manual: true)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "arrow.down.square", help: "Check for updates", color: Color("mode")))
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("GitHub"){
|
||||
NSWorkspace.shared.open(URL(string: "https://github.com/alienator88/Pearcleaner/releases")!)
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "link", help: "View releases on GitHub", color: Color("mode")))
|
||||
|
||||
|
||||
Spacer()
|
||||
}
|
||||
@@ -130,13 +132,9 @@ func checkForUpdate(appState: AppState, manual: Bool = false) {
|
||||
let currentVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
|
||||
if latestRelease.tag_name > currentVersion ?? "" {
|
||||
NewWin.show(appState: appState, width: 500, height: 440, newWin: .update)
|
||||
// appState.alertType = .update
|
||||
// appState.showAlert = true
|
||||
} else {
|
||||
if manual {
|
||||
NewWin.show(appState: appState, width: 500, height: 300, newWin: .no_update)
|
||||
// appState.alertType = .no_update
|
||||
// appState.showAlert = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,22 +213,14 @@ func UnzipAndReplace(DownloadedFileURL fileURL: String, appState: AppState) {
|
||||
|
||||
// Unzip the downloaded update file to your app's bundle path
|
||||
let process = Process()
|
||||
// process.executableURL = URL(fileURLWithPath: "/usr/bin/unzip")
|
||||
// process.arguments = [fileURL, "-d", appDirectory]
|
||||
process.executableURL = URL(fileURLWithPath: "/usr/bin/ditto")
|
||||
process.arguments = ["-xk", fileURL, appDirectory]
|
||||
// let pipe = Pipe()
|
||||
process.standardOutput = FileHandle.nullDevice
|
||||
process.standardError = FileHandle.nullDevice
|
||||
|
||||
try process.run()
|
||||
process.waitUntilExit()
|
||||
|
||||
// let outputData = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
// let output = String(decoding: outputData, as: UTF8.self)
|
||||
//
|
||||
// writeLog(string: output)
|
||||
|
||||
|
||||
updateOnMain {
|
||||
appState.progressBar.0 = "Deleting update file"
|
||||
appState.progressBar.1 = 0.8
|
||||
@@ -239,12 +229,6 @@ func UnzipAndReplace(DownloadedFileURL fileURL: String, appState: AppState) {
|
||||
// After unzipping, remove the update file
|
||||
try fileManager.removeItem(atPath: fileURL)
|
||||
|
||||
// Show Restart dialog
|
||||
// updateOnMain {
|
||||
// appState.alertType = .restartApp
|
||||
// appState.showAlert = true
|
||||
// }
|
||||
|
||||
|
||||
} catch {
|
||||
printOS("Error updating the app: \(error)")
|
||||
|
||||
Reference in New Issue
Block a user