This commit is contained in:
Alin
2024-03-19 16:21:01 -06:00
parent 2318949caf
commit a55396cdaa
15 changed files with 227 additions and 152 deletions
+4 -4
View File
@@ -559,7 +559,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 24; CURRENT_PROJECT_VERSION = 25;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
@@ -577,7 +577,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 3.2.0; MARKETING_VERSION = 3.2.1;
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner; PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
@@ -594,7 +594,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 24; CURRENT_PROJECT_VERSION = 25;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
@@ -612,7 +612,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 3.2.0; MARKETING_VERSION = 3.2.1;
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner; PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
+2 -2
View File
@@ -34,7 +34,7 @@ class DeeplinkManager {
if let path = queryItems.first(where: { $0.name == DeepLinkConstants.query })?.value { if let path = queryItems.first(where: { $0.name == DeepLinkConstants.query })?.value {
let pathURL = URL(fileURLWithPath: path) let pathURL = URL(fileURLWithPath: path)
let appInfo = getAppInfo(atPath: pathURL) let appInfo = getAppInfo(atPath: pathURL)
showAppInFiles(appInfo: appInfo!, mini: mini, appState: appState, locations: locations, showPopover: $showPopover) showAppInFiles(appInfo: appInfo!, appState: appState, locations: locations, showPopover: $showPopover)
} else { } else {
printOS("No path query parameter found in the URL") printOS("No path query parameter found in the URL")
} }
@@ -46,7 +46,7 @@ class DeeplinkManager {
func handleAppBundle(url: URL, appState: AppState, locations: Locations) { func handleAppBundle(url: URL, appState: AppState, locations: Locations) {
let appInfo = getAppInfo(atPath: url) let appInfo = getAppInfo(atPath: url)
showAppInFiles(appInfo: appInfo!, mini: mini, appState: appState, locations: locations, showPopover: $showPopover) showAppInFiles(appInfo: appInfo!, appState: appState, locations: locations, showPopover: $showPopover)
} }
} }
+9 -14
View File
@@ -471,7 +471,7 @@ func loadAllPaths(allApps: [AppInfo], appState: AppState, locations: Locations,
// Load item in Files view // Load item in Files view
func showAppInFiles(appInfo: AppInfo, mini: Bool, appState: AppState, locations: Locations, showPopover: Binding<Bool>) { func showAppInFiles(appInfo: AppInfo, appState: AppState, locations: Locations, showPopover: Binding<Bool>) {
showPopover.wrappedValue = false showPopover.wrappedValue = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
updateOnMain { updateOnMain {
@@ -481,23 +481,15 @@ func showAppInFiles(appInfo: AppInfo, mini: Bool, appState: AppState, locations:
appState.appInfo = storedAppInfo appState.appInfo = storedAppInfo
appState.selectedItems = Set(storedAppInfo.files) appState.selectedItems = Set(storedAppInfo.files)
withAnimation(Animation.easeIn(duration: 0.4)) { withAnimation(Animation.easeIn(duration: 0.4)) {
if mini { appState.currentView = .files
appState.currentView = .files showPopover.wrappedValue.toggle()
showPopover.wrappedValue.toggle()
} else {
appState.currentView = .files
}
} }
} else { } else {
// Handle the case where the appInfo is not found in the store // Handle the case where the appInfo is not found in the store
withAnimation(Animation.easeIn(duration: 0.4)) { withAnimation(Animation.easeIn(duration: 0.4)) {
appState.showProgress = true appState.showProgress = true
if mini { appState.currentView = .files
appState.currentView = .files showPopover.wrappedValue.toggle()
showPopover.wrappedValue.toggle()
} else {
appState.currentView = .files
}
} }
appState.appInfo = appInfo appState.appInfo = appInfo
findPathsForApp(appInfo: appInfo, appState: appState, locations: locations) { findPathsForApp(appInfo: appInfo, appState: appState, locations: locations) {
@@ -640,7 +632,9 @@ func reversePathsSearch(appState: AppState, locations: Locations, completion: @e
// Move files to trash using applescript/Finder so it asks for user password if needed // Move files to trash using applescript/Finder so it asks for user password if needed
func moveFilesToTrash(at fileURLs: [URL], completion: @escaping () -> Void = {}) { func moveFilesToTrash(at fileURLs: [URL], completion: @escaping () -> Void = {}) {
@AppStorage("settings.sentinel.enable") var sentinel: Bool = false @AppStorage("settings.sentinel.enable") var sentinel: Bool = false
if sentinel {
launchctl(load: false)
}
updateOnBackground { updateOnBackground {
let posixFiles = fileURLs.map { "POSIX file \"\($0.path)\", " }.joined().dropLast(3) let posixFiles = fileURLs.map { "POSIX file \"\($0.path)\", " }.joined().dropLast(3)
let scriptSource = """ let scriptSource = """
@@ -660,6 +654,7 @@ func moveFilesToTrash(at fileURLs: [URL], completion: @escaping () -> Void = {})
completion() completion()
} }
} }
} }
+8 -5
View File
@@ -11,15 +11,15 @@ import SwiftUI
struct SimpleButtonStyle: ButtonStyle { struct SimpleButtonStyle: ButtonStyle {
@State private var hovered = false @State private var hovered = false
let icon: String let icon: String
let label: String?
let help: String let help: String
let color: Color let color: Color
let shield: Bool?
init(icon: String, label: String? = "", help: String, color: Color) {
init(icon: String, help: String, color: Color, shield: Bool? = nil) {
self.icon = icon self.icon = icon
self.label = label
self.help = help self.help = help
self.color = color self.color = color
self.shield = shield
} }
func makeBody(configuration: Self.Configuration) -> some View { func makeBody(configuration: Self.Configuration) -> some View {
@@ -28,8 +28,11 @@ struct SimpleButtonStyle: ButtonStyle {
.resizable() .resizable()
.scaledToFit() .scaledToFit()
.frame(width: 20) .frame(width: 20)
.foregroundColor(hovered ? color : color.opacity(0.5)) if label != "" {
Text(label!)
}
} }
.foregroundColor(hovered ? color : color.opacity(0.5))
.padding(5) .padding(5)
.onHover { hovering in .onHover { hovering in
withAnimation() { withAnimation() {
+10 -9
View File
@@ -34,15 +34,15 @@ func updateOnBackground(_ updates: @escaping () -> Void) {
// Resize window // Resize window
func resizeWindow(width: CGFloat, height: CGFloat) { //func resizeWindow(width: CGFloat, height: CGFloat) {
if let window = NSApplication.shared.windows.first { // if let window = NSApplication.shared.windows.first {
let newSize = NSSize(width: width, height: height) // let newSize = NSSize(width: width, height: height)
window.setContentSize(newSize) // window.setContentSize(newSize)
} // }
} //}
func resizeWindowAuto(windowSettings: WindowSettings) { func resizeWindowAuto(windowSettings: WindowSettings, title: String) {
if let window = NSApplication.shared.windows.first { if let window = NSApplication.shared.windows.first(where: { $0.title == title }) {
let newSize = NSSize(width: windowSettings.loadWindowSettings().width, height: windowSettings.loadWindowSettings().height) let newSize = NSSize(width: windowSettings.loadWindowSettings().width, height: windowSettings.loadWindowSettings().height)
window.setContentSize(newSize) window.setContentSize(newSize)
} }
@@ -168,7 +168,8 @@ func hasWindowOpen() -> Bool {
func findAndHideWindows(named titles: [String]) { func findAndHideWindows(named titles: [String]) {
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.orderOut(nil) // window.orderOut(nil)
window.close()
} }
} }
} }
+11 -32
View File
@@ -110,6 +110,7 @@ struct PearcleanerApp: App {
MenuBarMiniAppView(search: $search, showPopover: $showPopover) MenuBarMiniAppView(search: $search, showPopover: $showPopover)
.environmentObject(locations) .environmentObject(locations)
.environmentObject(appState) .environmentObject(appState)
.preferredColorScheme(displayMode.colorScheme)
}, icon: selectedMenubarIcon) }, icon: selectedMenubarIcon)
} }
@@ -181,49 +182,27 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
} }
#if !DEBUG //#if !DEBUG
func windowShouldClose(_ sender: NSWindow) -> Bool { // func windowShouldClose(_ sender: NSWindow) -> Bool {
let menubarEnabled = UserDefaults.standard.bool(forKey: "settings.menubar.enabled") // let menubarEnabled = UserDefaults.standard.bool(forKey: "settings.menubar.enabled")
// let alert = NSAlert.init() // if menubarEnabled {
// alert.addButton(withTitle: "Return") // findAndHideWindows(named: ["Pearcleaner"])
// alert.addButton(withTitle: "Quit")
// alert.informativeText = "Quit or return to application?"
// let response = alert.runModal()
// if response == NSApplication.ModalResponse.alertFirstButtonReturn {
// return false // return false
// } else { // } else {
// NSApplication.shared.terminate(self)
// return true // return true
// } // }
if menubarEnabled { // }
findAndHideWindows(named: ["Pearcleaner"]) //#endif
return false
} else {
return true
}
}
#endif
func applicationDidFinishLaunching(_ notification: Notification) { func applicationDidFinishLaunching(_ notification: Notification) {
let menubarEnabled = UserDefaults.standard.bool(forKey: "settings.menubar.enabled") let menubarEnabled = UserDefaults.standard.bool(forKey: "settings.menubar.enabled")
// let dockEnabled = UserDefaults.standard.bool(forKey: "settings.dock.enabled")
if menubarEnabled { if menubarEnabled {
#if !DEBUG
findAndHideWindows(named: ["Pearcleaner"]) findAndHideWindows(named: ["Pearcleaner"])
// NSApp.windows.first?.close()
NSApplication.shared.setActivationPolicy(.accessory) NSApplication.shared.setActivationPolicy(.accessory)
#endif
// if dockEnabled {
// NSApplication.shared.setActivationPolicy(.regular)
// } else {
// NSApplication.shared.setActivationPolicy(.accessory)
// }
} }
// Link window to delegate
// Link window to delegate // let mainWindow = NSApp.windows[0]
let mainWindow = NSApp.windows[0] // mainWindow.delegate = self
mainWindow.delegate = self
} }
+41 -14
View File
@@ -15,7 +15,6 @@ struct InterfaceSettingsTab: View {
@EnvironmentObject var locations: Locations @EnvironmentObject var locations: Locations
@State private var windowSettings = WindowSettings() @State private var windowSettings = WindowSettings()
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false @AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
// @AppStorage("settings.dock.enabled") private var dockEnabled: Bool = false
@AppStorage("settings.general.mini") private var mini: Bool = false @AppStorage("settings.general.mini") private var mini: Bool = false
@AppStorage("displayMode") var displayMode: DisplayMode = .system @AppStorage("displayMode") var displayMode: DisplayMode = .system
@AppStorage("settings.general.glass") private var glass: Bool = true @AppStorage("settings.general.glass") private var glass: Bool = true
@@ -57,6 +56,9 @@ struct InterfaceSettingsTab: View {
Toggle(isOn: $glass, label: { Toggle(isOn: $glass, label: {
}) })
.toggleStyle(.switch) .toggleStyle(.switch)
.onChange(of: glass) { newVal in
MenuBarExtraManager.shared.restartMenuBarExtra()
}
} }
.padding(5) .padding(5)
.padding(.leading) .padding(.leading)
@@ -89,13 +91,17 @@ struct InterfaceSettingsTab: View {
displayMode.colorScheme = nil displayMode.colorScheme = nil
if isDarkModeEnabled() { if isDarkModeEnabled() {
displayMode.colorScheme = .dark displayMode.colorScheme = .dark
MenuBarExtraManager.shared.restartMenuBarExtra()
} else { } else {
displayMode.colorScheme = .light displayMode.colorScheme = .light
MenuBarExtraManager.shared.restartMenuBarExtra()
} }
case "Dark": case "Dark":
displayMode.colorScheme = .dark displayMode.colorScheme = .dark
MenuBarExtraManager.shared.restartMenuBarExtra()
case "Light": case "Light":
displayMode.colorScheme = .light displayMode.colorScheme = .light
MenuBarExtraManager.shared.restartMenuBarExtra()
default: default:
break break
} }
@@ -135,19 +141,35 @@ struct InterfaceSettingsTab: View {
Toggle(isOn: $mini, label: { Toggle(isOn: $mini, label: {
}) })
.toggleStyle(.switch) .toggleStyle(.switch)
.disabled(menubarEnabled)
.help(menubarEnabled ? "Disabled when menubar icon is enabled" : "")
.onChange(of: mini) { newVal in .onChange(of: mini) { newVal in
if mini { if mini {
appState.currentView = miniView ? .apps : .empty appState.currentView = miniView ? .apps : .empty
showPopover = false showPopover = false
resizeWindowAuto(windowSettings: windowSettings) windowSettings.newWindow {
} else { MiniMode(search: $search, showPopover: $showPopover)
resizeWindowAuto(windowSettings: windowSettings) .environmentObject(locations)
if appState.appInfo.appName.isEmpty { .environmentObject(appState)
appState.currentView = .empty .preferredColorScheme(displayMode.colorScheme)
}
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
} else { } else {
appState.currentView = .files if appState.appInfo.appName.isEmpty {
appState.currentView = .empty
} else {
appState.currentView = .files
}
windowSettings.newWindow {
RegularMode(search: $search, showPopover: $showPopover)
.environmentObject(locations)
.environmentObject(appState)
.preferredColorScheme(displayMode.colorScheme)
}
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
} }
}
} }
} }
.padding(5) .padding(5)
@@ -229,7 +251,7 @@ struct InterfaceSettingsTab: View {
.font(.callout) .font(.callout)
.foregroundStyle(.gray) .foregroundStyle(.gray)
} }
InfoButton(text: "When menubar icon is enabled, the main app window and dock icon will be hidden. You can still pop-out the main app window from the menubar icon temporarily if you'd like.", color: nil, label: "") InfoButton(text: "When menubar icon is enabled, the main app window and dock icon will be disabled since the app will be put in accessory mode.", color: nil, label: "")
Spacer() Spacer()
Toggle(isOn: $menubarEnabled, label: { Toggle(isOn: $menubarEnabled, label: {
}) })
@@ -240,12 +262,13 @@ struct InterfaceSettingsTab: View {
MenuBarMiniAppView(search: $search, showPopover: $showPopover) MenuBarMiniAppView(search: $search, showPopover: $showPopover)
.environmentObject(locations) .environmentObject(locations)
.environmentObject(appState) .environmentObject(appState)
.preferredColorScheme(displayMode.colorScheme)
}, icon: selectedMenubarIcon) }, icon: selectedMenubarIcon)
NSApplication.shared.setActivationPolicy(.accessory) NSApplication.shared.setActivationPolicy(.accessory)
findAndShowWindows(named: ["Pearcleaner", "Interface"]) findAndHideWindows(named: ["Pearcleaner"])
// findAndShowWindows(named: ["Pearcleaner", "Interface"])
} else { } else {
MenuBarExtraManager.shared.removeMenuBarExtra() MenuBarExtraManager.shared.removeMenuBarExtra()
// dockEnabled = true
NSApplication.shared.setActivationPolicy(.regular) NSApplication.shared.setActivationPolicy(.regular)
if !hasWindowOpen() { if !hasWindowOpen() {
if mini { if mini {
@@ -253,13 +276,17 @@ struct InterfaceSettingsTab: View {
MiniMode(search: $search, showPopover: $showPopover) MiniMode(search: $search, showPopover: $showPopover)
.environmentObject(locations) .environmentObject(locations)
.environmentObject(appState) .environmentObject(appState)
.preferredColorScheme(displayMode.colorScheme)
} }
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
} else { } else {
windowSettings.newWindow { windowSettings.newWindow {
RegularMode(search: $search, showPopover: $showPopover) RegularMode(search: $search, showPopover: $showPopover)
.environmentObject(locations) .environmentObject(locations)
.environmentObject(appState) .environmentObject(appState)
.preferredColorScheme(displayMode.colorScheme)
} }
resizeWindowAuto(windowSettings: windowSettings, title: "Pearcleaner")
} }
} }
+3 -3
View File
@@ -14,8 +14,8 @@ struct AppListItems: View {
@State private var isHovered = false @State private var isHovered = false
@State private var windowSettings = WindowSettings() @State private var windowSettings = WindowSettings()
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@AppStorage("settings.general.mini") private var mini: Bool = false // @AppStorage("settings.general.mini") private var mini: Bool = false
@AppStorage("settings.general.popover") private var popoverStay: Bool = true // @AppStorage("settings.general.popover") private var popoverStay: Bool = true
@AppStorage("displayMode") var displayMode: DisplayMode = .system @AppStorage("displayMode") var displayMode: DisplayMode = .system
@Binding var showPopover: Bool @Binding var showPopover: Bool
@EnvironmentObject var locations: Locations @EnvironmentObject var locations: Locations
@@ -110,7 +110,7 @@ struct AppListItems: View {
} }
.onTapGesture { .onTapGesture {
withAnimation(Animation.easeInOut(duration: 0.4)) { withAnimation(Animation.easeInOut(duration: 0.4)) {
showAppInFiles(appInfo: appInfo, mini: mini, appState: appState, locations: locations, showPopover: $showPopover) showAppInFiles(appInfo: appInfo, appState: appState, locations: locations, showPopover: $showPopover)
} }
} }
+7 -3
View File
@@ -16,9 +16,11 @@ struct FilesView: View {
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false @AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
@AppStorage("settings.general.instant") var instantSearch: Bool = true @AppStorage("settings.general.instant") var instantSearch: Bool = true
@AppStorage("settings.general.brew") private var brew: Bool = false @AppStorage("settings.general.brew") private var brew: Bool = false
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@Binding var showPopover: Bool @Binding var showPopover: Bool
@Binding var search: String @Binding var search: String
var regularWin: Bool
@State private var selectedOption = "Default" @State private var selectedOption = "Default"
var body: some View { var body: some View {
@@ -38,7 +40,7 @@ struct FilesView: View {
.transition(.opacity) .transition(.opacity)
} else { } else {
// Titlebar // Titlebar
if mini { if !regularWin {
HStack() { HStack() {
Spacer() Spacer()
@@ -192,7 +194,7 @@ struct FilesView: View {
updateOnMain { updateOnMain {
// appState.appInfo = AppInfo.empty // appState.appInfo = AppInfo.empty
search = "" search = ""
if mini { if !regularWin {
appState.currentView = .apps appState.currentView = .apps
showPopover = false showPopover = false
} else { } else {
@@ -200,7 +202,6 @@ struct FilesView: View {
} }
} }
var selectedItemsArray = Array(appState.selectedItems) var selectedItemsArray = Array(appState.selectedItems)
if let url = URL(string: appState.appInfo.path.absoluteString) { if let url = URL(string: appState.appInfo.path.absoluteString) {
let appFolderURL = appState.appInfo.path.absoluteString.contains("Wrapper") ? url.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent() : url.deletingLastPathComponent() // Get the immediate parent directory of regular and wrapped apps let appFolderURL = appState.appInfo.path.absoluteString.contains("Wrapper") ? url.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent() : url.deletingLastPathComponent() // Get the immediate parent directory of regular and wrapped apps
@@ -220,6 +221,9 @@ struct FilesView: View {
appState.currentView = mini ? .apps : .empty appState.currentView = mini ? .apps : .empty
appState.isReminderVisible.toggle() appState.isReminderVisible.toggle()
} }
if sentinel {
launchctl(load: true)
}
} }
// Remove app from app list // Remove app from app list
removeApp(appState: appState, withId: appState.appInfo.id) removeApp(appState: appState, withId: appState.appInfo.id)
+98 -41
View File
@@ -22,6 +22,7 @@ struct MenuBarMiniAppView: View {
@AppStorage("settings.general.glass") private var glass: Bool = true @AppStorage("settings.general.glass") private var glass: Bool = true
@AppStorage("settings.general.popover") private var popoverStay: Bool = true @AppStorage("settings.general.popover") private var popoverStay: Bool = true
@Binding var showPopover: Bool @Binding var showPopover: Bool
@State private var showMenu = false
var body: some View { var body: some View {
@@ -57,20 +58,11 @@ struct MenuBarMiniAppView: View {
AppsListView(search: $search, showPopover: $showPopover, filteredApps: filteredApps).padding(0) AppsListView(search: $search, showPopover: $showPopover, filteredApps: filteredApps).padding(0)
HStack(spacing: 10) { HStack(spacing: 10) {
if #available(macOS 14.0, *) { Button("Leftover Files") {
SettingsLink() showMenu = false
.buttonStyle(SimpleButtonStyle(icon: "gear", help: "Settings", color: Color("mode")))
} else {
Button("Settings") {
NSApp.sendAction(Selector(("showPreferencesWindow:")), to: NSApp.delegate, from: nil)
}
.buttonStyle(SimpleButtonStyle(icon: "gear", help: "Settings", color: Color("mode")))
}
Button("") {
withAnimation(.easeInOut(duration: 0.5)) { withAnimation(.easeInOut(duration: 0.5)) {
showPopover = false showPopover = false
updateOnMain { updateOnMain() {
appState.appInfo = .empty appState.appInfo = .empty
appState.selectedZombieItems = [] appState.selectedZombieItems = []
if appState.zombieFile.fileSize.keys.count == 0 { if appState.zombieFile.fileSize.keys.count == 0 {
@@ -91,34 +83,89 @@ struct MenuBarMiniAppView: View {
} }
} }
.buttonStyle(SimpleButtonStyle(icon: "clock.arrow.circlepath", help: "Leftover Files", color: Color("mode"))) .buttonStyle(SimpleButtonStyle(icon: "clock.arrow.circlepath", help: "Leftover Files", color: Color("mode")))
.padding(.leading, 10)
SearchBarMiniBottom(search: $search) SearchBarMiniBottom(search: $search)
// .padding(.leading, 20)
Button("Main") { Button("More") {
findAndShowWindows(named: ["Pearcleaner"]) self.showMenu.toggle()
// if mini {
// windowSettings.newWindow {
// MiniMode(search: $search, showPopover: $showPopover)
// .environmentObject(locations)
// .environmentObject(appState)
// }
// } else {
// windowSettings.newWindow {
// RegularMode(search: $search, showPopover: $showPopover)
// .environmentObject(locations)
// .environmentObject(appState)
// }
// }
} }
.buttonStyle(SimpleButtonStyle(icon: "macwindow.on.rectangle", help: "Pop Out Window", color: Color("mode"))) .padding(.trailing, 10)
.buttonStyle(SimpleButtonStyle(icon: "ellipsis.circle", help: "More", color: Color("mode")))
.popover(isPresented: $showMenu) {
VStack(alignment: .leading) {
Button("Kill") { if #available(macOS 14.0, *) {
NSApp.terminate(nil) SettingsLink{
Label("Settings", systemImage: "gear")
}
.buttonStyle(SimpleButtonStyle(icon: "gear", label: "Settings", help: "Settings", color: Color("mode")))
} else {
Button("Settings") {
NSApp.sendAction(Selector(("showPreferencesWindow:")), to: NSApp.delegate, from: nil)
showMenu = false
}
.buttonStyle(SimpleButtonStyle(icon: "gear", label: "Settings", help: "Settings", color: Color("mode")))
}
// Button("Leftover Files") {
// showMenu = false
// withAnimation(.easeInOut(duration: 0.5)) {
// showPopover = false
// updateOnMain() {
// appState.appInfo = .empty
// appState.selectedZombieItems = []
// if appState.zombieFile.fileSize.keys.count == 0 {
// appState.currentView = .zombie
// appState.showProgress.toggle()
// showPopover.toggle()
// if instantSearch {
// reversePathsSearch(appState: appState, locations: locations)
// } else {
// loadAllPaths(allApps: appState.sortedApps, appState: appState, locations: locations, reverseAddon: true)
// }
// } else {
// appState.currentView = .zombie
// showPopover.toggle()
// }
// }
//
// }
// }
// .buttonStyle(SimpleButtonStyle(icon: "clock.arrow.circlepath", label: "Leftover Files", help: "Leftover Files", color: Color("mode")))
Button("Quit") {
NSApp.terminate(nil)
}
.buttonStyle(SimpleButtonStyle(icon: "x.circle.fill", label: "Quit Pearcleaner", help: "Quit Pearcleaner", color: Color("mode")))
}
.padding()
.background(
Group {
if glass {
GlassEffect(material: .sidebar, blendingMode: .behindWindow)
.edgesIgnoringSafeArea(.all)
} else {
Rectangle()
.fill(Color("pop"))
.padding(-80)
}
}
)
} }
.buttonStyle(SimpleButtonStyle(icon: "x.circle.fill", help: "Quit", color: Color("mode")))
} }
.padding(.horizontal) // .padding(.horizontal)
} }
.padding(.vertical, 5) .padding(.vertical, 5)
@@ -136,30 +183,40 @@ struct MenuBarMiniAppView: View {
GlassEffect(material: .sidebar, blendingMode: .behindWindow) GlassEffect(material: .sidebar, blendingMode: .behindWindow)
.edgesIgnoringSafeArea(.all) .edgesIgnoringSafeArea(.all)
} else { } else {
Color("pop") Rectangle()
.fill(Color("pop"))
.padding(-80) .padding(-80)
} }
} }
) )
.transition(.opacity) .transition(.opacity)
.popover(isPresented: $showPopover, arrowEdge: .trailing) { .popover(isPresented: $showPopover, arrowEdge: .leading) {
VStack { VStack {
if appState.currentView == .files { if appState.currentView == .files {
FilesView(showPopover: $showPopover, search: $search) FilesView(showPopover: $showPopover, search: $search, regularWin: false)
.id(appState.appInfo.id) .id(appState.appInfo.id)
} else if appState.currentView == .zombie { } else if appState.currentView == .zombie {
ZombieView(showPopover: $showPopover, search: $search) ZombieView(showPopover: $showPopover, search: $search, regularWin: false)
.id(appState.appInfo.id) .id(appState.appInfo.id)
} }
} }
.interactiveDismissDisabled(popoverStay) .interactiveDismissDisabled(popoverStay)
.background( .background(
Rectangle() Group {
.fill(Color("pop")) if glass {
.padding(-80) GlassEffect(material: .sidebar, blendingMode: .behindWindow)
.edgesIgnoringSafeArea(.all)
} else {
Rectangle()
.fill(Color("pop"))
.padding(-80)
}
}
) )
.frame(width: 650, height: 550) .frame(width: 650, height: 500)
} }
} }
+2 -2
View File
@@ -39,10 +39,10 @@ struct MiniMode: View {
.popover(isPresented: $showPopover, arrowEdge: .trailing) { .popover(isPresented: $showPopover, arrowEdge: .trailing) {
VStack { VStack {
if appState.currentView == .files { if appState.currentView == .files {
FilesView(showPopover: $showPopover, search: $search) FilesView(showPopover: $showPopover, search: $search, regularWin: false)
.id(appState.appInfo.id) .id(appState.appInfo.id)
} else if appState.currentView == .zombie { } else if appState.currentView == .zombie {
ZombieView(showPopover: $showPopover, search: $search) ZombieView(showPopover: $showPopover, search: $search, regularWin: false)
.id(appState.appInfo.id) .id(appState.appInfo.id)
} }
+2 -2
View File
@@ -93,11 +93,11 @@ struct RegularMode: View {
AppDetailsEmptyView(showPopover: $showPopover) AppDetailsEmptyView(showPopover: $showPopover)
} else if appState.currentView == .files { } else if appState.currentView == .files {
TopBar(showPopover: $showPopover) TopBar(showPopover: $showPopover)
FilesView(showPopover: $showPopover, search: $search) FilesView(showPopover: $showPopover, search: $search, regularWin: true)
.id(appState.appInfo.id) .id(appState.appInfo.id)
} else if appState.currentView == .zombie { } else if appState.currentView == .zombie {
TopBar(showPopover: $showPopover) TopBar(showPopover: $showPopover)
ZombieView(showPopover: $showPopover, search: $search) ZombieView(showPopover: $showPopover, search: $search, regularWin: true)
.id(appState.appInfo.id) .id(appState.appInfo.id)
} }
} }
+5 -12
View File
@@ -15,23 +15,16 @@ struct ZombieView: View {
@AppStorage("settings.general.mini") private var mini: Bool = false @AppStorage("settings.general.mini") private var mini: Bool = false
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false @AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
@AppStorage("settings.general.instant") private var instantSearch: Bool = true @AppStorage("settings.general.instant") private var instantSearch: Bool = true
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@Binding var showPopover: Bool @Binding var showPopover: Bool
@Binding var search: String @Binding var search: String
@State private var searchZ: String = "" @State private var searchZ: String = ""
@State private var selectedOption = "Default" @State private var selectedOption = "Default"
var regularWin: Bool
var body: some View { var body: some View {
// let filteredAndSortedFiles: [URL] = {
// let files = appState.zombieFile.fileSize.keys.filter { url in
// searchZ.isEmpty || url.lastPathComponent.localizedCaseInsensitiveContains(searchZ)
// }
//
// return selectedOption == "Default" ?
// files.sorted(by: { $0.lastPathComponent < $1.lastPathComponent }) :
// files.sorted(by: { appState.zombieFile.fileSize[$0, default: 0] > appState.zombieFile.fileSize[$1, default: 0] })
// }()
let filteredAndSortedFiles: ([URL], Int64) = { let filteredAndSortedFiles: ([URL], Int64) = {
let filteredFiles = appState.zombieFile.fileSize.filter { (url, _) in let filteredFiles = appState.zombieFile.fileSize.filter { (url, _) in
searchZ.isEmpty || url.lastPathComponent.localizedCaseInsensitiveContains(searchZ) searchZ.isEmpty || url.lastPathComponent.localizedCaseInsensitiveContains(searchZ)
@@ -68,7 +61,7 @@ struct ZombieView: View {
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
} else { } else {
// Titlebar // Titlebar
if mini { if !regularWin {
HStack(spacing: 0) { HStack(spacing: 0) {
Spacer() Spacer()
@@ -188,7 +181,7 @@ struct ZombieView: View {
updateOnMain { updateOnMain {
appState.zombieFile = .empty appState.zombieFile = .empty
search = "" search = ""
if mini { if !regularWin {
appState.currentView = .apps appState.currentView = .apps
showPopover = false showPopover = false
} else { } else {
+21 -8
View File
@@ -12,15 +12,22 @@ class MenuBarExtraManager {
static let shared = MenuBarExtraManager() static let shared = MenuBarExtraManager()
private var statusItem: NSStatusItem? private var statusItem: NSStatusItem?
private var popover = NSPopover() private var popover = NSPopover()
// Store the last view and icon for restart
private var lastView: (() -> AnyView)?
private var lastIcon: String?
func addMenuBarExtra<V: View>(withView view: @escaping () -> V, icon: String) { func addMenuBarExtra<V: View>(withView view: @escaping () -> V, icon: String) {
guard statusItem == nil else { return } guard statusItem == nil else { return }
// Remember the last view and icon
lastView = { AnyView(view()) }
lastIcon = icon
// Initialize the status item // Initialize the status item
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
// Set up the status item's button // Set up the status item's button
if let button = statusItem?.button { if let button = statusItem?.button{
if NSImage(systemSymbolName: icon, accessibilityDescription: nil) != nil { if NSImage(systemSymbolName: icon, accessibilityDescription: nil) != nil {
button.image = NSImage(systemSymbolName: icon, accessibilityDescription: "Pearcleaner") button.image = NSImage(systemSymbolName: icon, accessibilityDescription: "Pearcleaner")
} else { } else {
@@ -29,6 +36,7 @@ class MenuBarExtraManager {
} }
button.action = #selector(togglePopover(_:)) button.action = #selector(togglePopover(_:))
button.target = self button.target = self
button.sendAction(on: [.leftMouseDown, .rightMouseDown])
} }
// Set up the popover // Set up the popover
@@ -54,13 +62,16 @@ class MenuBarExtraManager {
} }
} }
// func getStatus() -> Bool { func restartMenuBarExtra() {
// if let item = statusItem { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
// return true self.removeMenuBarExtra()
// } else {
// return false // Ensure the last view and icon are available before re-adding
// } if let lastView = self.lastView, let lastIcon = self.lastIcon {
// } self.addMenuBarExtra(withView: lastView, icon: lastIcon)
}
}
}
@objc func togglePopover(_ sender: AnyObject?) { @objc func togglePopover(_ sender: AnyObject?) {
if let button = statusItem?.button { if let button = statusItem?.button {
@@ -71,4 +82,6 @@ class MenuBarExtraManager {
} }
} }
} }
} }
+4 -1
View File
@@ -35,6 +35,7 @@ class WindowSettings {
} }
func newWindow<V: View>(withView view: @escaping () -> V) { func newWindow<V: View>(withView view: @escaping () -> V) {
findAndHideWindows(named: ["Pearcleaner"])
let contentView = view let contentView = view
let frame = self.loadWindowSettings() let frame = self.loadWindowSettings()
let newWindow = NSWindow( let newWindow = NSWindow(
@@ -44,7 +45,9 @@ class WindowSettings {
newWindow.titlebarAppearsTransparent = true newWindow.titlebarAppearsTransparent = true
newWindow.isMovableByWindowBackground = true newWindow.isMovableByWindowBackground = true
newWindow.center() newWindow.center()
newWindow.setFrameAutosaveName("Main Window") newWindow.title = "Pearcleaner"
newWindow.titleVisibility = .hidden
newWindow.setFrameAutosaveName("Pearcleaner")
newWindow.contentView = NSHostingView(rootView: contentView()) newWindow.contentView = NSHostingView(rootView: contentView())
// self.window = newWindow // self.window = newWindow
self.windows.append(newWindow) self.windows.append(newWindow)