This commit is contained in:
Alin
2024-09-30 11:20:11 -06:00
parent d8f650116c
commit dbcf0ba655
9 changed files with 149 additions and 145 deletions
+21 -9
View File
@@ -7,6 +7,7 @@
import Foundation
import SwiftUI
import AlinFoundation
//import FinderSync
let home = FileManager.default.homeDirectoryForCurrentUser.path
@@ -29,16 +30,27 @@ class AppState: ObservableObject {
@Published var sentinelMode: Bool = false
@Published var showConditionBuilder: Bool = false
var operationQueueLeftover = OperationQueue()
@Published var shouldCancelOperations = false
func cancelQueueOperations() {
operationQueueLeftover.cancelAllOperations()
shouldCancelOperations = true
func getBundleSize(for appInfo: AppInfo, updateState: @escaping (Int64) -> Void) {
// Step 1: Check if the size is available and not 0 in the sortedApps cache
if let existingAppInfo = sortedApps.first(where: { $0.path == appInfo.path }),
existingAppInfo.bundleSize != 0 {
// Size is available in the cache, update the state
DispatchQueue.main.async {
self.leftoverProgress = ("Search canceled", 0.0)
self.showProgress = false
self.currentView = .empty
updateState(existingAppInfo.bundleSize)
}
return
}
// Step 2: If we reach here, we need to calculate the size
DispatchQueue.global(qos: .userInitiated).async {
let calculatedSize = totalSizeOnDisk(for: appInfo.path).logical
DispatchQueue.main.async {
// Update the state and the array
updateState(calculatedSize)
if let index = self.sortedApps.firstIndex(where: { $0.path == appInfo.path }) {
self.sortedApps[index].bundleSize = calculatedSize
}
}
}
}
+2 -1
View File
@@ -50,8 +50,9 @@ func findAndSetWindowFrame(named titles: [String], windowSettings: WindowSetting
for title in titles {
if let window = NSApp.windows.first(where: { $0.title == title }) {
window.isRestorable = false
window.isReleasedWhenClosed = false
let frame = windowSettings.loadWindowSettings()
window.setFrame(frame, display: true)
window.setFrame(frame, display: true, animate: true)
}
}
}
+75 -22
View File
@@ -9,13 +9,84 @@ import SwiftUI
import AlinFoundation
import Combine
class WindowSettings: ObservableObject {
static let shared = WindowSettings()
class WindowSettings {
private let windowWidthKey = "windowWidthKey"
private let windowHeightKey = "windowHeightKey"
private let windowXKey = "windowXKey"
private let windowYKey = "windowYKey"
var windows: [NSWindow] = []
var windowRef: NSWindow?
init() {
trackMainWindow()
registerDefaultWindowSettings()
}
func trackMainWindow() {
if let mainWindow = NSApplication.shared.windows.first(where: { $0.title == "Pearcleaner" }) {
windowRef = mainWindow
print("Main window detected and tracked: \(mainWindow.title)")
}
}
// Launch new app windows on demand
func newWindow<V: View>(mini: Bool, withView view: @escaping () -> V) {
let frame = self.resetWindowSettings(mini: mini)
if windowRef == nil {
windowRef = NSWindow(
contentRect: .zero,
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
}
// Update the existing windowRef with all desired settings
windowRef?.contentView = NSHostingView(rootView: view())
windowRef?.setFrame(frame, display: true, animate: true)
windowRef?.isMovableByWindowBackground = true
windowRef?.title = "Pearcleaner"
windowRef?.titlebarAppearsTransparent = true
windowRef?.isRestorable = false
windowRef?.titleVisibility = .hidden
windowRef?.makeKeyAndOrderFront(nil)
windowRef?.isReleasedWhenClosed = false
// if let curWindow = windowRef {
// print("Window exists, reopening...")
// let frame = self.resetWindowSettings(mini: mini)
// curWindow.contentView = NSHostingView(rootView: view())
// curWindow.setFrame(frame, display: true, animate: true)
// curWindow.titlebarAppearsTransparent = true
// curWindow.isMovableByWindowBackground = true
// curWindow.title = "Pearcleaner"
// curWindow.isRestorable = false
// curWindow.titleVisibility = .hidden
// curWindow.makeKeyAndOrderFront(nil)
// curWindow.isReleasedWhenClosed = false
// return
// }
// print("Window doesn't exist, creating...")
//
// // Close existing window
// findAndHideWindows(named: ["Pearcleaner"])
// // Create new window using defaults
// let frame = self.resetWindowSettings(mini: mini)
// let newWindow = NSWindow(
// contentRect: .zero,
// styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
// backing: .buffered, defer: false)
// newWindow.contentView = NSHostingView(rootView: view())
// newWindow.setFrame(frame, display: true, animate: true)
// newWindow.titlebarAppearsTransparent = true
// newWindow.isMovableByWindowBackground = true
// newWindow.title = "Pearcleaner"
// newWindow.isRestorable = false
//// self.windows.append(newWindow)
// newWindow.titleVisibility = .hidden
// newWindow.makeKeyAndOrderFront(nil)
// newWindow.isReleasedWhenClosed = false
// windowRef = newWindow
}
// Register default sizes if the AppStorage keys are invalid
func registerDefaultWindowSettings(completion: @escaping () -> Void = {}) {
@@ -78,25 +149,7 @@ class WindowSettings {
return NSRect(x: defaultX, y: defaultY, width: defaultWidth, height: defaultHeight)
}
// Launch new app windows on demand
func newWindow<V: View>(mini: Bool, withView view: @escaping () -> V) {
// Close existing window
findAndHideWindows(named: ["Pearcleaner"])
// Create new window using defaults
let contentView = view
let frame = self.resetWindowSettings(mini: mini)
let newWindow = NSWindow(
contentRect: frame,
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
newWindow.contentView = NSHostingView(rootView: contentView())
newWindow.titlebarAppearsTransparent = true
newWindow.isMovableByWindowBackground = true
newWindow.title = "Pearcleaner"
newWindow.isRestorable = false
self.windows.append(newWindow)
newWindow.titleVisibility = .hidden
newWindow.makeKeyAndOrderFront(nil)
}
}
+18 -18
View File
@@ -18,7 +18,7 @@ struct PearcleanerApp: App {
@StateObject private var updater = Updater(owner: "alienator88", repo: "Pearcleaner")
@StateObject private var themeManager = ThemeManager.shared
@StateObject private var permissionManager = PermissionManager.shared
@State private var windowSettings = WindowSettings()
@StateObject private var windowSettings = WindowSettings.shared
@AppStorage("settings.permissions.hasLaunched") private var hasLaunched: Bool = false
@AppStorage("settings.general.mini") private var mini: Bool = false
@AppStorage("settings.general.miniview") private var miniView: Bool = true
@@ -48,6 +48,8 @@ struct PearcleanerApp: App {
}
var body: some Scene {
WindowGroup {
Group {
if mini {
@@ -79,12 +81,6 @@ struct PearcleanerApp: App {
}
return true
}
// Save window size on window dimension change
// .onChange(of: NSApplication.shared.windows.first?.frame) { newFrame in
// if let newFrame = newFrame {
// windowSettings.saveWindowSettings(frame: newFrame)
// }
// }
.alert(isPresented: $appState.showUninstallAlert) {
Alert(
title: Text("Warning!"),
@@ -108,7 +104,6 @@ struct PearcleanerApp: App {
appState.currentView = .empty
}
// Disable tabbing
NSWindow.allowsAutomaticWindowTabbing = false
@@ -127,6 +122,10 @@ struct PearcleanerApp: App {
.environmentObject(permissionManager)
.preferredColorScheme(themeManager.displayMode.colorScheme)
})
findAndHideWindows(named: ["Pearcleaner"])
NSApplication.shared.setActivationPolicy(.accessory)
}
@@ -158,6 +157,7 @@ struct PearcleanerApp: App {
.environmentObject(themeManager)
.environmentObject(updater)
.environmentObject(permissionManager)
.environmentObject(windowSettings)
.preferredColorScheme(themeManager.displayMode.colorScheme)
.toolbarBackground(.clear)
.movableByWindowBackground()
@@ -170,7 +170,7 @@ struct PearcleanerApp: App {
class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
var windowSettings = WindowSettings()
let windowSettings = WindowSettings.shared
var themeManager = ThemeManager.shared
var windowCloseObserver: NSObjectProtocol?
var windowFrameObserver: NSObjectProtocol?
@@ -182,16 +182,17 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
let menubarEnabled = UserDefaults.standard.bool(forKey: "settings.menubar.enabled")
// UserDefaults.standard.register(defaults: ["NSQuitAlwaysKeepsWindows" : false])
if !menubarEnabled {
findAndSetWindowFrame(named: ["Pearcleaner"], windowSettings: windowSettings)
}
themeManager.setupAppearance()
if menubarEnabled {
findAndHideWindows(named: ["Pearcleaner"])
NSApplication.shared.setActivationPolicy(.accessory)
}
// if menubarEnabled {
// findAndHideWindows(named: ["Pearcleaner"])
// NSApplication.shared.setActivationPolicy(.accessory)
// }
windowFrameObserver = NotificationCenter.default.addObserver(forName: nil, object: nil, queue: nil) { notification in
if let window = notification.object as? NSWindow, window.title == "Pearcleaner" {
@@ -203,6 +204,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
windowCloseObserver = NotificationCenter.default.addObserver(forName: NSWindow.willCloseNotification, object: nil, queue: nil) { notification in
if let window = notification.object as? NSWindow, window.title == "Pearcleaner" {
// Save window settings before removal (existing logic)
self.windowSettings.saveWindowSettings(frame: window.frame)
}
}
@@ -225,16 +227,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
let windowSettings = WindowSettings()
let windowSettings = WindowSettings.shared
if !flag {
// No visible windows, so let's open a new one
for window in sender.windows {
window.title = "Pearcleaner"
window.makeKeyAndOrderFront(self)
updateOnMain(after: 0.1, {
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
})
window.setFrame(windowSettings.loadWindowSettings(), display: true, animate: true)
}
return true // Indicates you've handled the re-open
}
+2 -3
View File
@@ -18,7 +18,7 @@ struct InterfaceSettingsTab: View {
@EnvironmentObject var permissionManager: PermissionManager
@EnvironmentObject var fsm: FolderSettingsManager
@EnvironmentObject var themeManager: ThemeManager
@State private var windowSettings = WindowSettings()
@EnvironmentObject var windowSettings: WindowSettings
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
@AppStorage("settings.general.mini") private var mini: Bool = false
@AppStorage("settings.general.glass") private var glass: Bool = false
@@ -287,7 +287,7 @@ struct InterfaceSettingsTab: View {
} else {
MenuBarExtraManager.shared.removeMenuBarExtra()
NSApplication.shared.setActivationPolicy(.regular)
if !hasWindowOpen() {
if mini {
windowSettings.newWindow(mini: true, withView: {
MiniMode(search: $search, showPopover: $showPopover)
@@ -311,7 +311,6 @@ struct InterfaceSettingsTab: View {
.preferredColorScheme(themeManager.displayMode.colorScheme)
})
}
}
}
}
@@ -13,6 +13,7 @@ struct SettingsView: View {
@EnvironmentObject var fsm: FolderSettingsManager
@EnvironmentObject var themeManager: ThemeManager
@EnvironmentObject var updater: Updater
@EnvironmentObject var windowSettings: WindowSettings
@Binding var showPopover: Bool
@Binding var search: String
@AppStorage("settings.general.glass") private var glass: Bool = false
@@ -93,6 +94,7 @@ struct SettingsView: View {
case .interface:
InterfaceSettingsTab(showPopover: $showPopover, search: $search)
.environmentObject(themeManager)
.environmentObject(windowSettings)
case .folders:
FolderSettingsTab()
.environmentObject(themeManager)
+1 -9
View File
@@ -156,16 +156,8 @@ struct AppListItems: View {
}
.onAppear {
if self.bundleSize == 0 {
DispatchQueue.global(qos: .userInitiated).async {
let size = totalSizeOnDisk(for: appInfo.path).logical
DispatchQueue.main.async {
print("Sizing up")
appState.getBundleSize(for: appInfo) { size in
self.bundleSize = size
// Update the appInfo in the appState array
if let index = appState.sortedApps.firstIndex(where: { $0.path == appInfo.path }) {
appState.sortedApps[index].bundleSize = size
}
}
}
}
}
+3 -3
View File
@@ -407,7 +407,7 @@ struct FilesView: View {
.font(.headline)
Divider()
Spacer()
Text("Always double-check the files/folders marked for removal. In some rare cases, Pearcleaner may find some unrelated files when app names are too similar.")
Text("Always confirm the files marked for removal. In rare cases, unrelated files may be found when app names are too similar.\n\nNOTE: Pearcleaner uses AppleScript to remove files. Currently macOS does not allow AppleScript to authenticate using the fingerprint sensor, only password authentication is supported.")
.font(.subheadline)
Spacer()
Button("Close") {
@@ -415,10 +415,10 @@ struct FilesView: View {
showAlert = false
}
.buttonStyle(SimpleButtonStyle(icon: "x.circle.fill", label: "Close", help: "Dismiss"))
Spacer()
// Spacer()
}
.padding(15)
.frame(width: 400, height: 220)
.frame(width: 400, height: 250)
.background(GlassEffect(material: .hudWindow, blendingMode: .behindWindow))
})
.sheet(isPresented: $appState.showConditionBuilder, content: {
-55
View File
@@ -28,8 +28,6 @@ struct ZombieView: View {
@Binding var showPopover: Bool
@Binding var search: String
@State private var searchZ: String = ""
// @State private var elapsedTime = 0
// @State private var timer: Timer? = nil
@State private var selectedZombieItemsLocal: Set<URL> = []
@State private var memoizedFiles: [URL] = []
@State private var lastSearchTermUsed: String? = nil
@@ -53,67 +51,14 @@ struct ZombieView: View {
ProgressView().controlSize(.small)
}
// ProgressView()
// .progressViewStyle(.linear)
// .frame(width: 400, height: 10)
// Text("\(elapsedTime)")
// .font(.title).monospacedDigit()
// .foregroundStyle(.primary.opacity(0.5))
// .opacity(elapsedTime == 0 ? 0 : 1)
// .contentTransition(.numericText())
Spacer()
}
.transition(.opacity)
// Spacer()
//
// HStack {
// Text("\(appState.leftoverProgress.0)").font(.title3)
// .foregroundStyle(.primary.opacity(0.5))
// Spacer()
// }
//
// HStack {
// ProgressView(value: appState.leftoverProgress.1, total: 1.0)
// .progressViewStyle(.linear)
// Button("Cancel") {
// updateOnMain {
// appState.cancelQueueOperations()
// }
// }
// .buttonStyle(SimpleButtonBrightStyle(icon: "x.circle", help: "Cancel search", color: .primary))
// }
//
//
//
// Text("\(Int(appState.leftoverProgress.1 * 100)) %")
// .font(.title).monospacedDigit()
// .foregroundStyle(.primary.opacity(0.5))
// .contentTransition(.numericText())
//
//
// Spacer()
}
.padding(50)
.transition(.opacity)
.frame(maxWidth: .infinity, maxHeight: .infinity)
// .onAppear {
// self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
// withAnimation {
// self.elapsedTime += 1
// }
// }
// }
// .onDisappear {
// self.timer?.invalidate()
// self.timer = nil
// self.elapsedTime = 0
// }
} else {
// Titlebar
HStack(spacing: 0) {