mirror of
https://github.com/exituser/Pearcleaner.git
synced 2026-09-17 08:29:07 +00:00
3.1.0
This commit is contained in:
@@ -29,7 +29,6 @@ class AppState: ObservableObject
|
||||
@Published var showProgress: Bool = false
|
||||
@Published var popCount: Int = 0
|
||||
|
||||
|
||||
|
||||
init() {
|
||||
self.appInfo = AppInfo(
|
||||
|
||||
@@ -157,6 +157,52 @@ func isDarkModeEnabled() -> Bool {
|
||||
}
|
||||
|
||||
|
||||
// Check if appearance is dark mode
|
||||
//func getCasks() -> [String] {
|
||||
// let process = Process()
|
||||
//#if arch(x86_64)
|
||||
// let cmd = "/usr/local/bin/brew"
|
||||
//#elseif arch(arm64)
|
||||
// let cmd = "/opt/homebrew/bin/brew"
|
||||
//#endif
|
||||
// process.executableURL = URL(fileURLWithPath: cmd)
|
||||
// process.arguments = ["list", "--cask"]
|
||||
// let pipe = Pipe()
|
||||
// process.standardOutput = pipe
|
||||
// process.standardError = pipe
|
||||
// try? process.run()
|
||||
// process.waitUntilExit() // Ensure the process completes
|
||||
// let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
// if let output = String(data: data, encoding: .utf8), !output.isEmpty {
|
||||
// return output.components(separatedBy: "\n").filter { !$0.isEmpty }.map { $0.replacingOccurrences(of: "-", with: " ") }
|
||||
// } else {
|
||||
// return []
|
||||
// }
|
||||
//}
|
||||
|
||||
// Brew cleanup
|
||||
func caskCleanup(app: String) {
|
||||
Task(priority: .high) {
|
||||
let process = Process()
|
||||
#if arch(x86_64)
|
||||
let cmd = "/usr/local/bin/brew"
|
||||
#elseif arch(arm64)
|
||||
let cmd = "/opt/homebrew/bin/brew"
|
||||
#endif
|
||||
process.executableURL = URL(fileURLWithPath: "/bin/zsh")
|
||||
process.arguments = ["-c", "\(cmd) uninstall --cask \(app) --force; \(cmd) cleanup"]
|
||||
// let pipe = Pipe()
|
||||
process.standardOutput = FileHandle.nullDevice//pipe
|
||||
process.standardError = FileHandle.nullDevice//pipe
|
||||
try? process.run()
|
||||
process.waitUntilExit() // Ensure the process completes
|
||||
// let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
// let output = (String(data: data, encoding: .utf8) ?? "") as String
|
||||
// print(output)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check if symlink
|
||||
func isSymlink(atPath path: URL) -> Bool {
|
||||
do {
|
||||
@@ -218,22 +264,6 @@ func getIconForFileOrFolderNS(atPath path: URL) -> NSImage? {
|
||||
}
|
||||
|
||||
// Get average color from image
|
||||
//extension NSImage {
|
||||
// var averageColor2: NSColor? {
|
||||
// guard let inputImage = CIImage(image: self) else { return nil }
|
||||
// let extentVector = CIVector(x: inputImage.extent.origin.x, y: inputImage.extent.origin.y, z: inputImage.extent.size.width, w: inputImage.extent.size.height)
|
||||
//
|
||||
// guard let filter = CIFilter(name: "CIAreaAverage", parameters: [kCIInputImageKey: inputImage, kCIInputExtentKey: extentVector]) else { return nil }
|
||||
// guard let outputImage = filter.outputImage else { return nil }
|
||||
//
|
||||
// var bitmap = [UInt8](repeating: 0, count: 4)
|
||||
// let context = CIContext(options: [.workingColorSpace: kCFNull!])
|
||||
// context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: .RGBA8, colorSpace: nil)
|
||||
//
|
||||
// return NSColor(red: CGFloat(bitmap[0]) / 255, green: CGFloat(bitmap[1]) / 255, blue: CGFloat(bitmap[2]) / 255, alpha: CGFloat(bitmap[3]) / 255)
|
||||
// }
|
||||
//}
|
||||
|
||||
extension NSImage {
|
||||
var averageColor: NSColor? {
|
||||
guard let tiffData = self.tiffRepresentation, let bitmapImage = NSBitmapImageRep(data: tiffData), let inputImage = CIImage(bitmapImageRep: bitmapImage) else { return nil }
|
||||
@@ -279,13 +309,10 @@ func removeApp(appState: AppState, withId id: UUID) {
|
||||
appState.sortedApps.remove(at: index)
|
||||
return // Exit the function if the app was found and removed
|
||||
}
|
||||
|
||||
// Remove from appInfoStore if found
|
||||
if let index = appState.appInfoStore.firstIndex(where: { $0.id == id }) {
|
||||
appState.appInfoStore.remove(at: index)
|
||||
}
|
||||
// Clear out AppInfo state
|
||||
appState.appInfo = AppInfo.empty
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ struct PearcleanerApp: App {
|
||||
@AppStorage("settings.general.miniview") private var miniView: Bool = true
|
||||
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
|
||||
@AppStorage("settings.general.features") private var features: String = ""
|
||||
@AppStorage("settings.general.brew") private var brew: Bool = false
|
||||
@State private var search = ""
|
||||
@State private var showPopover: Bool = false
|
||||
@State private var showFeature: Bool = false
|
||||
@@ -94,14 +95,11 @@ struct PearcleanerApp: App {
|
||||
appState.sortedApps = sortedApps
|
||||
|
||||
|
||||
// Find all app paths on load
|
||||
// Find all app paths/information on load if instantSearch is enabled
|
||||
if instantSearch {
|
||||
// startEnd {
|
||||
loadAllPaths(allApps: sortedApps, appState: appState, locations: locations)
|
||||
// }
|
||||
loadAllPaths(allApps: sortedApps, appState: appState, locations: locations)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if !DEBUG
|
||||
Task {
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ 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.brew") private var brew: 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
|
||||
@@ -82,6 +83,30 @@ struct GeneralSettingsTab: View {
|
||||
.padding(.leading)
|
||||
|
||||
|
||||
HStack(spacing: 0) {
|
||||
Image(systemName: brew ? "mug.fill" : "mug")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
.padding(.trailing)
|
||||
.foregroundStyle(.gray)
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("\(brew ? "Homebrew cleanup is enabled" : "Homebrew cleanup is disabled")")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
|
||||
InfoButton(text: "When homebrew cleanup is enabled, Pearcleaner will check if the app you are removing was installed via homebrew and execute a brew uninstall and brew cleanup command as well to let homebrew know that the app is removed. This way your homebrew list will be synced up correctly and caching will be removed.\n\nNOTE: If you undo the file delete with CMD+Z, the files will be put back but homebrew will not be aware of it. To get the homebrew list back in sync you'd need to run:\n brew install APPNAME --force", color: nil)
|
||||
|
||||
Spacer()
|
||||
Toggle(isOn: $brew, label: {
|
||||
})
|
||||
.toggleStyle(.switch)
|
||||
}
|
||||
.padding(5)
|
||||
.padding(.leading)
|
||||
|
||||
|
||||
HStack(spacing: 0) {
|
||||
Image(systemName: displayMode.colorScheme == .dark ? "moon.fill" : "sun.max.fill")
|
||||
.resizable()
|
||||
@@ -346,7 +371,7 @@ struct GeneralSettingsTab: View {
|
||||
|
||||
}
|
||||
.padding(20)
|
||||
.frame(width: 500, height: 650)
|
||||
.frame(width: 500, height: 690)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ import SwiftUI
|
||||
struct SettingsView: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@Binding var showPopover: Bool
|
||||
|
||||
@AppStorage("settings.general.glass") private var glass: Bool = true
|
||||
|
||||
var body: some View {
|
||||
|
||||
TabView() {
|
||||
@@ -33,6 +34,8 @@ struct SettingsView: View {
|
||||
.tag(CurrentTabView.about)
|
||||
|
||||
}
|
||||
.background(glass ? GlassEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all) : nil)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ struct FilesView: View {
|
||||
@AppStorage("settings.general.mini") private var mini: Bool = false
|
||||
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
|
||||
@AppStorage("settings.general.instant") var instantSearch: Bool = true
|
||||
@AppStorage("settings.general.brew") private var brew: Bool = false
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
@Binding var showPopover: Bool
|
||||
@Binding var search: String
|
||||
@@ -216,12 +217,18 @@ struct FilesView: View {
|
||||
withAnimation {
|
||||
showPopover = false
|
||||
updateOnMain {
|
||||
appState.currentView = mini ? .apps : .empty
|
||||
appState.isReminderVisible.toggle()
|
||||
}
|
||||
}
|
||||
// Remove app from app list
|
||||
removeApp(appState: appState, withId: appState.appInfo.id)
|
||||
|
||||
// refreshAppList(appState.appInfo)
|
||||
// Brew cleanup if enabled
|
||||
if brew {
|
||||
caskCleanup(app: appState.appInfo.appName)
|
||||
}
|
||||
// Clear out AppInfo state
|
||||
appState.appInfo = AppInfo.empty
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ struct MiniAppView: View {
|
||||
AppsListView(search: $search, showPopover: $showPopover, filteredApps: filteredApps)
|
||||
|
||||
if appState.currentView != .empty {
|
||||
SearchBarMiniBottom(search: $search).background(.ultraThinMaterial)
|
||||
SearchBarMiniBottom(search: $search)
|
||||
}
|
||||
}
|
||||
.padding(.bottom)
|
||||
|
||||
Reference in New Issue
Block a user