This commit is contained in:
Alin
2024-04-27 19:28:33 -06:00
parent e964f9529b
commit a54371fb14
20 changed files with 591 additions and 769 deletions
+8 -16
View File
@@ -8,7 +8,6 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
C7045A282B03E71D00376976 /* MiniMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7045A272B03E71D00376976 /* MiniMode.swift */; }; C7045A282B03E71D00376976 /* MiniMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7045A272B03E71D00376976 /* MiniMode.swift */; };
C7045A2A2B03FAF000376976 /* TopBarMini.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7045A292B03FAF000376976 /* TopBarMini.swift */; };
C7045A322B068AD700376976 /* NewWin.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7045A312B068AD700376976 /* NewWin.swift */; }; C7045A322B068AD700376976 /* NewWin.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7045A312B068AD700376976 /* NewWin.swift */; };
C7045A342B068B2900376976 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7045A332B068B2900376976 /* UpdateView.swift */; }; C7045A342B068B2900376976 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7045A332B068B2900376976 /* UpdateView.swift */; };
C7045A362B068DD700376976 /* PermView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7045A352B068DD700376976 /* PermView.swift */; }; C7045A362B068DD700376976 /* PermView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7045A352B068DD700376976 /* PermView.swift */; };
@@ -39,7 +38,6 @@
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 */; };
C7D31D482AFEB23700C7ED9E /* TopBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D472AFEB23700C7ED9E /* TopBar.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 */; };
@@ -47,11 +45,11 @@
C7DD49EE2BAB7F6000CCBA16 /* ReversePathsFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49ED2BAB7F6000CCBA16 /* ReversePathsFetch.swift */; }; C7DD49EE2BAB7F6000CCBA16 /* ReversePathsFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49ED2BAB7F6000CCBA16 /* ReversePathsFetch.swift */; };
C7DD49F02BABA14400CCBA16 /* Folders.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49EF2BABA14400CCBA16 /* Folders.swift */; }; C7DD49F02BABA14400CCBA16 /* Folders.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DD49EF2BABA14400CCBA16 /* Folders.swift */; };
C7DE672B2BA6343D00EB1633 /* MenuBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DE672A2BA6343D00EB1633 /* MenuBarItem.swift */; }; C7DE672B2BA6343D00EB1633 /* MenuBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DE672A2BA6343D00EB1633 /* MenuBarItem.swift */; };
C7DE672D2BA6356500EB1633 /* MenuBarMiniAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DE672C2BA6356500EB1633 /* MenuBarMiniAppView.swift */; };
C7ED86B12BA8A35500F13DE4 /* Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7ED86B02BA8A35500F13DE4 /* Interface.swift */; }; C7ED86B12BA8A35500F13DE4 /* Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7ED86B02BA8A35500F13DE4 /* Interface.swift */; };
C7ED86B32BA8ED8800F13DE4 /* Trash.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7ED86B22BA8ED8800F13DE4 /* Trash.swift */; }; C7ED86B32BA8ED8800F13DE4 /* Trash.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7ED86B22BA8ED8800F13DE4 /* Trash.swift */; };
C7F539382AF60865007DF1B2 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F539372AF60865007DF1B2 /* Utilities.swift */; }; C7F539382AF60865007DF1B2 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F539372AF60865007DF1B2 /* Utilities.swift */; };
C7FB173B2B96321300B96F9A /* AppsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7FB173A2B96321300B96F9A /* AppsListView.swift */; }; C7FB173B2B96321300B96F9A /* AppsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7FB173A2B96321300B96F9A /* AppsListView.swift */; };
C7FEBA112BDC422200AE195F /* Searchbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7FEBA102BDC422200AE195F /* Searchbar.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@@ -99,7 +97,6 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
C7045A272B03E71D00376976 /* MiniMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiniMode.swift; sourceTree = "<group>"; }; C7045A272B03E71D00376976 /* MiniMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiniMode.swift; sourceTree = "<group>"; };
C7045A292B03FAF000376976 /* TopBarMini.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBarMini.swift; sourceTree = "<group>"; };
C7045A312B068AD700376976 /* NewWin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewWin.swift; sourceTree = "<group>"; }; C7045A312B068AD700376976 /* NewWin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewWin.swift; sourceTree = "<group>"; };
C7045A332B068B2900376976 /* UpdateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateView.swift; sourceTree = "<group>"; }; C7045A332B068B2900376976 /* UpdateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateView.swift; sourceTree = "<group>"; };
C7045A352B068DD700376976 /* PermView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermView.swift; sourceTree = "<group>"; }; C7045A352B068DD700376976 /* PermView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermView.swift; sourceTree = "<group>"; };
@@ -135,7 +132,6 @@
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>"; };
C7D31D472AFEB23700C7ED9E /* TopBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBar.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; };
@@ -143,11 +139,11 @@
C7DD49ED2BAB7F6000CCBA16 /* ReversePathsFetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReversePathsFetch.swift; sourceTree = "<group>"; }; C7DD49ED2BAB7F6000CCBA16 /* ReversePathsFetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReversePathsFetch.swift; sourceTree = "<group>"; };
C7DD49EF2BABA14400CCBA16 /* Folders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Folders.swift; sourceTree = "<group>"; }; C7DD49EF2BABA14400CCBA16 /* Folders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Folders.swift; sourceTree = "<group>"; };
C7DE672A2BA6343D00EB1633 /* MenuBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarItem.swift; sourceTree = "<group>"; }; C7DE672A2BA6343D00EB1633 /* MenuBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarItem.swift; sourceTree = "<group>"; };
C7DE672C2BA6356500EB1633 /* MenuBarMiniAppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarMiniAppView.swift; sourceTree = "<group>"; };
C7ED86B02BA8A35500F13DE4 /* Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Interface.swift; sourceTree = "<group>"; }; C7ED86B02BA8A35500F13DE4 /* Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Interface.swift; sourceTree = "<group>"; };
C7ED86B22BA8ED8800F13DE4 /* Trash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Trash.swift; sourceTree = "<group>"; }; C7ED86B22BA8ED8800F13DE4 /* Trash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Trash.swift; sourceTree = "<group>"; };
C7F539372AF60865007DF1B2 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; }; C7F539372AF60865007DF1B2 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; };
C7FB173A2B96321300B96F9A /* AppsListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppsListView.swift; sourceTree = "<group>"; }; C7FB173A2B96321300B96F9A /* AppsListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppsListView.swift; sourceTree = "<group>"; };
C7FEBA102BDC422200AE195F /* Searchbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Searchbar.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -300,12 +296,10 @@
C77B90222AF2D616009CC655 /* FilesView.swift */, C77B90222AF2D616009CC655 /* FilesView.swift */,
C71848432B8D2D600046CB13 /* ZombieView.swift */, C71848432B8D2D600046CB13 /* ZombieView.swift */,
C76D08542AF89CDE00D07867 /* RegularMode.swift */, C76D08542AF89CDE00D07867 /* RegularMode.swift */,
C7D31D472AFEB23700C7ED9E /* TopBar.swift */,
C7045A292B03FAF000376976 /* TopBarMini.swift */,
C7D31D492AFEB26700C7ED9E /* AppListItems.swift */, C7D31D492AFEB26700C7ED9E /* AppListItems.swift */,
C7045A272B03E71D00376976 /* MiniMode.swift */, C7045A272B03E71D00376976 /* MiniMode.swift */,
C7FB173A2B96321300B96F9A /* AppsListView.swift */, C7FB173A2B96321300B96F9A /* AppsListView.swift */,
C7DE672C2BA6356500EB1633 /* MenuBarMiniAppView.swift */, C7FEBA102BDC422200AE195F /* Searchbar.swift */,
); );
path = Views; path = Views;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -467,11 +461,9 @@
C7DD49EE2BAB7F6000CCBA16 /* ReversePathsFetch.swift in Sources */, C7DD49EE2BAB7F6000CCBA16 /* ReversePathsFetch.swift in Sources */,
C7045A322B068AD700376976 /* NewWin.swift in Sources */, C7045A322B068AD700376976 /* NewWin.swift in Sources */,
C7DD49F02BABA14400CCBA16 /* Folders.swift in Sources */, C7DD49F02BABA14400CCBA16 /* Folders.swift in Sources */,
C7DE672D2BA6356500EB1633 /* MenuBarMiniAppView.swift in Sources */,
C7ED86B32BA8ED8800F13DE4 /* Trash.swift in Sources */, C7ED86B32BA8ED8800F13DE4 /* Trash.swift in Sources */,
C7D31D512AFF00F300C7ED9E /* Locations.swift in Sources */, C7D31D512AFF00F300C7ED9E /* Locations.swift in Sources */,
C77B901A2AF1938F009CC655 /* Logic.swift in Sources */, C77B901A2AF1938F009CC655 /* Logic.swift in Sources */,
C7045A2A2B03FAF000376976 /* TopBarMini.swift in Sources */,
C77B901C2AF193A3009CC655 /* Styles.swift in Sources */, C77B901C2AF193A3009CC655 /* Styles.swift in Sources */,
C7045A282B03E71D00376976 /* MiniMode.swift in Sources */, C7045A282B03E71D00376976 /* MiniMode.swift in Sources */,
C7ED86B12BA8A35500F13DE4 /* Interface.swift in Sources */, C7ED86B12BA8A35500F13DE4 /* Interface.swift in Sources */,
@@ -488,12 +480,12 @@
C771CB762BD028AF00C33A18 /* SegmentedPicker.swift in Sources */, C771CB762BD028AF00C33A18 /* SegmentedPicker.swift in Sources */,
C74412C72BBF249000DDFCA8 /* AppPathsFetch.swift in Sources */, C74412C72BBF249000DDFCA8 /* AppPathsFetch.swift in Sources */,
C79D05202BC99EB40083F976 /* ThemeManager.swift in Sources */, C79D05202BC99EB40083F976 /* ThemeManager.swift in Sources */,
C7D31D482AFEB23700C7ED9E /* TopBar.swift in Sources */,
C74FDC632BCD833D00B8960F /* Conditions.swift in Sources */, C74FDC632BCD833D00B8960F /* Conditions.swift in Sources */,
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 */,
C7A9CE472B89164700EB6E78 /* Authorization.swift in Sources */, C7A9CE472B89164700EB6E78 /* Authorization.swift in Sources */,
C7FEBA112BDC422200AE195F /* Searchbar.swift in Sources */,
C7CF47242B3B3F1700979C5F /* WindowSettings.swift in Sources */, C7CF47242B3B3F1700979C5F /* WindowSettings.swift in Sources */,
C77B90232AF2D616009CC655 /* FilesView.swift in Sources */, C77B90232AF2D616009CC655 /* FilesView.swift in Sources */,
); );
@@ -564,8 +556,8 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
APP_BUILD = 38; APP_BUILD = 39;
APP_VERSION = 3.5.4; APP_VERSION = 3.6.0;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
@@ -634,8 +626,8 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
APP_BUILD = 38; APP_BUILD = 39;
APP_VERSION = 3.5.4; APP_VERSION = 3.6.0;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+1 -1
View File
@@ -69,7 +69,7 @@ struct AppCommands: Commands {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
appState.sortedApps = sortedApps appState.sortedApps = sortedApps
for app in appState.trashedFiles { for app in appState.trashedFiles {
AppPathFinder(appInfo: app, appState: appState, locations: locations).findPaths() AppPathFinder(appInfo: app, appState: appState, locations: locations, undo: true).findPaths()
} }
} }
} }
+6 -1
View File
@@ -16,16 +16,18 @@ class AppPathFinder {
private var locations: Locations private var locations: Locations
private var backgroundRun: Bool private var backgroundRun: Bool
private var reverseAddon: Bool private var reverseAddon: Bool
private var undo: Bool
private var completion: () -> Void = {} private var completion: () -> Void = {}
private var collection: [URL] = [] private var collection: [URL] = []
private let collectionAccessQueue = DispatchQueue(label: "com.alienator88.Pearcleaner.appPathFinder.collectionAccess") private let collectionAccessQueue = DispatchQueue(label: "com.alienator88.Pearcleaner.appPathFinder.collectionAccess")
init(appInfo: AppInfo = .empty, appState: AppState, locations: Locations, backgroundRun: Bool = false, reverseAddon: Bool = false, completion: @escaping () -> Void = {}) { init(appInfo: AppInfo = .empty, appState: AppState, locations: Locations, backgroundRun: Bool = false, reverseAddon: Bool = false, undo: Bool = false, completion: @escaping () -> Void = {}) {
self.appInfo = appInfo self.appInfo = appInfo
self.appState = appState self.appState = appState
self.locations = locations self.locations = locations
self.backgroundRun = backgroundRun self.backgroundRun = backgroundRun
self.reverseAddon = reverseAddon self.reverseAddon = reverseAddon
self.undo = undo
self.completion = completion self.completion = completion
} }
@@ -306,7 +308,10 @@ class AppPathFinder {
if !self.backgroundRun { if !self.backgroundRun {
self.appState.appInfo = self.appInfo self.appState.appInfo = self.appInfo
if !self.undo {
self.appState.selectedItems = Set(updatedCollection) self.appState.selectedItems = Set(updatedCollection)
}
} }
// Append object to store if running reverse search with empty store // Append object to store if running reverse search with empty store
-1
View File
@@ -24,7 +24,6 @@ class AppState: ObservableObject
@Published var currentView = CurrentDetailsView.empty @Published var currentView = CurrentDetailsView.empty
@Published var showAlert: Bool = false @Published var showAlert: Bool = false
@Published var sidebar: Bool = true @Published var sidebar: Bool = true
// @Published var isReminderVisible: Bool = false
@Published var releases = [Release]() @Published var releases = [Release]()
@Published var progressBar: (String, Double) = ("Ready", 0.0) @Published var progressBar: (String, Double) = ("Ready", 0.0)
@Published var reload: Bool = false @Published var reload: Bool = false
@@ -39,6 +39,7 @@ class ReversePathsSearcher {
let allNames = appState.appInfoStore.map { $0.appName.pearFormat() } let allNames = appState.appInfoStore.map { $0.appName.pearFormat() }
for location in locations.reverse.paths where fileManager.fileExists(atPath: location) { for location in locations.reverse.paths where fileManager.fileExists(atPath: location) {
dispatchGroup.enter() dispatchGroup.enter()
processLocation(location, allPaths: allPaths, allNames: allNames) processLocation(location, allPaths: allPaths, allNames: allNames)
dispatchGroup.leave() dispatchGroup.leave()
+71 -70
View File
@@ -11,22 +11,26 @@ 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 iconFlip: String
let label: String let label: String
let help: String let help: String
let color: Color let color: Color
let size: CGFloat let size: CGFloat
let padding: CGFloat
init(icon: String, label: String = "", help: String, color: Color = Color("mode"), size: CGFloat = 20) { init(icon: String, iconFlip: String = "", label: String = "", help: String, color: Color = Color("mode"), size: CGFloat = 20, padding: CGFloat = 5) {
self.icon = icon self.icon = icon
self.iconFlip = iconFlip
self.label = label self.label = label
self.help = help self.help = help
self.color = color self.color = color
self.size = size self.size = size
self.padding = padding
} }
func makeBody(configuration: Self.Configuration) -> some View { func makeBody(configuration: Self.Configuration) -> some View {
HStack { HStack(alignment: .center) {
Image(systemName: icon) Image(systemName: (hovered && !iconFlip.isEmpty) ? iconFlip : icon)
.resizable() .resizable()
.scaledToFit() .scaledToFit()
.frame(width: size, height: size) .frame(width: size, height: size)
@@ -35,7 +39,7 @@ struct SimpleButtonStyle: ButtonStyle {
} }
} }
.foregroundColor(hovered ? color : color.opacity(0.5)) .foregroundColor(hovered ? color : color.opacity(0.5))
.padding(5) .padding(padding)
.onHover { hovering in .onHover { hovering in
withAnimation() { withAnimation() {
hovered = hovering hovered = hovering
@@ -121,6 +125,35 @@ struct ResetSettingsButtonStyle: ButtonStyle {
} }
struct SimpleCheckboxToggleStyle: ToggleStyle {
@EnvironmentObject private var themeSettings: ThemeSettings
@State private var isHovered: Bool = false
func makeBody(configuration: Configuration) -> some View {
HStack {
RoundedRectangle(cornerRadius: 4)
.fill(themeSettings.themeColor.darker(by: 5))
.frame(width: 18, height: 18)
.overlay {
if configuration.isOn {
Image(systemName: "checkmark")
.foregroundStyle(Color("mode"))
.scaleEffect(isHovered ? 0.8 : 1.0)
}
}
.onTapGesture {
withAnimation(.smooth()) {
configuration.isOn.toggle()
}
}
configuration.label
}
.onHover(perform: { hovering in
self.isHovered = hovering
})
}
}
struct InfoButton: View { struct InfoButton: View {
@State private var isPopoverPresented: Bool = false @State private var isPopoverPresented: Bool = false
@@ -192,10 +225,40 @@ struct UninstallButton: ButtonStyle {
.padding(.horizontal) .padding(.horizontal)
.padding(.vertical, 4) .padding(.vertical, 4)
.background(configuration.isPressed ? Color("uninstall").opacity(0.8) : Color("uninstall")) .background(configuration.isPressed ? Color("uninstall").opacity(0.8) : Color("uninstall"))
// .background( .cornerRadius(8)
// configuration.isPressed ? Color("uninstall").opacity(0.8) : .onHover { over in
// (isEnabled ? Color("uninstall") : Color.gray) if over {
// ) NSCursor.pointingHand.push()
} else {
NSCursor.pop()
}
}
}
}
struct RescanButton: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
HStack(alignment: .center, spacing: 10) {
Image(systemName: "arrow.counterclockwise.circle")
.foregroundColor(.white)
Divider()
.frame(height: 24)
.foregroundColor(.white)
.opacity(0.5)
configuration.label
.foregroundColor(.white)
}
.frame(height: 24)
.frame(minWidth: 75)
.padding(.horizontal)
.padding(.vertical, 4)
.background(configuration.isPressed ? Color("button").opacity(0.8) : Color("button"))
.cornerRadius(8) .cornerRadius(8)
.onHover { over in .onHover { over in
if over { if over {
@@ -475,68 +538,6 @@ struct AnimatedSearchStyle: TextFieldStyle {
struct SimpleSearchStyle: TextFieldStyle {
@State private var isHovered = false
@FocusState private var isFocused: Bool
@State var icon: Image?
@State var trash: Bool = false
@Binding var text: String
@EnvironmentObject var appState: AppState
@AppStorage("settings.general.mini") private var mini: Bool = false
func _body(configuration: TextField<Self._Label>) -> some View {
HStack(spacing: 5) {
HStack(spacing: 5) {
if icon != nil {
icon
.foregroundColor(Color("mode").opacity(0.5))
}
configuration
.font(.title3)
.textFieldStyle(PlainTextFieldStyle())
if trash && text != "" {
Image(systemName: "xmark")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 10, height: 10)
.padding(.trailing, 5)
.foregroundStyle(isHovered ? Color("mode").opacity(0.8) : Color("mode").opacity(0.5))
.onTapGesture {
text = ""
}
.help("Clear search")
}
}
}
.padding(6)
.overlay(
RoundedRectangle(cornerRadius: 6)
.strokeBorder(Color("mode").opacity(0.2), lineWidth: 1)
.allowsHitTesting(false)
)
.onHover { hovering in
withAnimation(Animation.easeInOut(duration: 0.15)) {
self.isHovered = hovering
self.isFocused = true
}
}
.focused($isFocused)
.onAppear {
updateOnMain {
self.isFocused = false
}
}
}
}
struct GlassEffect: NSViewRepresentable { struct GlassEffect: NSViewRepresentable {
var material: NSVisualEffectView.Material // Choose the material you want var material: NSVisualEffectView.Material // Choose the material you want
var blendingMode: NSVisualEffectView.BlendingMode // Choose the blending mode var blendingMode: NSVisualEffectView.BlendingMode // Choose the blending mode
+3
View File
@@ -386,6 +386,9 @@ func removeApp(appState: AppState, withId id: UUID) {
if brew { if brew {
caskCleanup(app: appState.appInfo.appName) caskCleanup(app: appState.appInfo.appName)
} }
appState.appInfo = AppInfo.empty
} }
} }
+1 -1
View File
@@ -104,7 +104,7 @@ struct PearcleanerApp: App {
// Enable menubar item // Enable menubar item
if menubarEnabled { if menubarEnabled {
MenuBarExtraManager.shared.addMenuBarExtra(withView: { MenuBarExtraManager.shared.addMenuBarExtra(withView: {
MenuBarMiniAppView(search: $search, showPopover: $showPopover) MiniAppView(search: $search, showPopover: $showPopover)
.environmentObject(locations) .environmentObject(locations)
.environmentObject(appState) .environmentObject(appState)
.environmentObject(fsm) .environmentObject(fsm)
@@ -5,9 +5,9 @@
"color-space" : "display-p3", "color-space" : "display-p3",
"components" : { "components" : {
"alpha" : "1.000", "alpha" : "1.000",
"blue" : "0xFF", "blue" : "0xE8",
"green" : "0x83", "green" : "0x7D",
"red" : "0x24" "red" : "0x4D"
} }
}, },
"idiom" : "universal" "idiom" : "universal"
@@ -23,9 +23,9 @@
"color-space" : "display-p3", "color-space" : "display-p3",
"components" : { "components" : {
"alpha" : "1.000", "alpha" : "1.000",
"blue" : "0xFF", "blue" : "0xBE",
"green" : "0x83", "green" : "0x67",
"red" : "0x24" "red" : "0x3F"
} }
}, },
"idiom" : "universal" "idiom" : "universal"
+1 -1
View File
@@ -428,7 +428,7 @@ struct InterfaceSettingsTab: View {
.onChange(of: menubarEnabled) { newVal in .onChange(of: menubarEnabled) { newVal in
if newVal { if newVal {
MenuBarExtraManager.shared.addMenuBarExtra(withView: { MenuBarExtraManager.shared.addMenuBarExtra(withView: {
MenuBarMiniAppView(search: $search, showPopover: $showPopover) MiniAppView(search: $search, showPopover: $showPopover)
.environmentObject(locations) .environmentObject(locations)
.environmentObject(appState) .environmentObject(appState)
.environmentObject(fsm) .environmentObject(fsm)
+3 -2
View File
@@ -25,7 +25,7 @@ struct AppListItems: View {
let itemId = UUID() let itemId = UUID()
let appInfo: AppInfo let appInfo: AppInfo
var isSelected: Bool { var isSelected: Bool {
appState.appInfo.id == appInfo.id appState.appInfo.path == appInfo.path
} }
@State private var hoveredItemPath: URL? = nil @State private var hoveredItemPath: URL? = nil
var body: some View { var body: some View {
@@ -39,7 +39,8 @@ struct AppListItems: View {
Image(nsImage: appIcon) Image(nsImage: appIcon)
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: (isHovered || isSelected) ? 32 : 30, height: (isHovered || isSelected) ? 32 : 30) .frame(width: 30)
// .frame(width: (isHovered || isSelected) ? 32 : 30, height: (isHovered || isSelected) ? 32 : 30)
.clipShape(RoundedRectangle(cornerRadius: 8)) .clipShape(RoundedRectangle(cornerRadius: 8))
// .shadow(color: Color("pop").opacity(0.8), radius: isSelected ? 2 : 0) // .shadow(color: Color("pop").opacity(0.8), radius: isSelected ? 2 : 0)
} }
+67 -2
View File
@@ -30,13 +30,13 @@ struct AppsListView: View {
SectionView(title: "System", count: filteredSystemApps.count, apps: filteredSystemApps, search: $search, showPopover: $showPopover) SectionView(title: "System", count: filteredSystemApps.count, apps: filteredSystemApps, search: $search, showPopover: $showPopover)
} }
} }
// .padding(.horizontal)
.padding(.top, !mini ? 4 : 0) .padding(.top, !mini ? 4 : 0)
} }
.scrollIndicators(.never) .scrollIndicators(.never)
} }
} }
struct SectionView: View { struct SectionView: View {
var title: String var title: String
var count: Int var count: Int
@@ -51,7 +51,6 @@ struct SectionView: View {
ForEach(apps, id: \.self) { appInfo in ForEach(apps, id: \.self) { appInfo in
AppListItems(search: $search, showPopover: $showPopover, appInfo: appInfo) AppListItems(search: $search, showPopover: $showPopover, appInfo: appInfo)
if appInfo != apps.last { if appInfo != apps.last {
// Divider().padding(.horizontal, 5)
} }
} }
} }
@@ -59,6 +58,72 @@ struct SectionView: View {
} }
struct Header: View {
let title: String
let count: Int
@State private var hovered = false
@EnvironmentObject var appState: AppState
@EnvironmentObject var locations: Locations
@EnvironmentObject var fsm: FolderSettingsManager
@Binding var showPopover: Bool
@AppStorage("settings.general.glass") private var glass: Bool = true
var body: some View {
HStack {
Text("\(title)").foregroundStyle(Color("mode")).opacity(0.5)
Text("\(count)")
.font(.system(size: 10))
.monospacedDigit()
.frame(minWidth: count > 99 ? 30 : 24, minHeight: 17)
.background(Color("mode").opacity(0.1))
.clipShape(.capsule)
.padding(.leading, 2)
Spacer()
if hovered {
Text("REFRESH")
.font(.system(size: 10))
.monospaced()
.foregroundStyle(Color("mode").opacity(0.8))
}
}
.onHover { hovering in
withAnimation() {
hovered = hovering
}
}
.onTapGesture {
withAnimation {
// Refresh Apps list
appState.reload.toggle()
showPopover = false
let sortedApps = getSortedApps(paths: fsm.folderPaths, appState: appState)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
appState.sortedApps = sortedApps
appState.reload.toggle()
}
}
}
.frame(minHeight: 20)
.help("Click header or ⌘+R to refresh apps list")
.padding(5)
}
}
//List { //List {
// Section { // Section {
// ForEach(filteredUserApps, id:\.self) { element in // ForEach(filteredUserApps, id:\.self) { element in
+48 -28
View File
@@ -80,7 +80,6 @@ struct FilesView: View {
} }
} else { } else {
// Titlebar // Titlebar
if !regularWin {
HStack(spacing: 0) { HStack(spacing: 0) {
Spacer() Spacer()
@@ -93,10 +92,11 @@ struct FilesView: View {
showPopover = false showPopover = false
} }
} }
.buttonStyle(SimpleButtonStyle(icon: "x.circle.fill", help: "Close")) .buttonStyle(SimpleButtonStyle(icon: "x.circle", iconFlip: "x.circle.fill", help: "Close"))
}
.padding([.horizontal, .top], 5)
} }
.padding(.top, 6)
.padding(.trailing, (mini || menubarEnabled) ? 6 : 0)
VStack(spacing: 0) { VStack(spacing: 0) {
// Main Group // Main Group
@@ -163,6 +163,8 @@ struct FilesView: View {
} }
} }
)) ))
.toggleStyle(SimpleCheckboxToggleStyle())
.help("All checkboxes")
Spacer() Spacer()
@@ -244,9 +246,11 @@ struct FilesView: View {
let iconImage = fileIcon.map(Image.init(nsImage:)) let iconImage = fileIcon.map(Image.init(nsImage:))
VStack { VStack {
FileDetailsItem(size: fileSize, sizeL: fileSizeL, icon: iconImage, path: path) FileDetailsItem(size: fileSize, sizeL: fileSizeL, icon: iconImage, path: path)
if index < sort.count - 1 { .padding(.vertical, 5)
Divider().padding(.leading, 40).opacity(0.5) // .padding(.leading, 40)
} // if index < sort.count - 1 {
// Divider().padding(.leading, 40).opacity(0.5)
// }
} }
} }
} }
@@ -269,25 +273,27 @@ struct FilesView: View {
Button("\(sizeType == "Logical" ? totalSelectedSize.logical : sizeType == "Finder" ? totalSelectedSize.finder : totalSelectedSize.real)") { Button("\(sizeType == "Logical" ? totalSelectedSize.logical : sizeType == "Finder" ? totalSelectedSize.finder : totalSelectedSize.real)") {
Task { Task {
if appState.selectedItems.count == appState.appInfo.fileSize.keys.count {
updateOnMain { updateOnMain {
search = "" search = ""
if !regularWin { if mini || menubarEnabled {
appState.currentView = .apps appState.currentView = .apps
showPopover = false showPopover = false
} else { } else {
appState.currentView = .empty appState.currentView = .empty
} }
} }
}
let selectedItemsArray = Array(appState.selectedItems) let selectedItemsArray = Array(appState.selectedItems)
killApp(appId: appState.appInfo.bundleIdentifier) { killApp(appId: appState.appInfo.bundleIdentifier) {
moveFilesToTrash(at: selectedItemsArray) { moveFilesToTrash(at: selectedItemsArray) {
withAnimation { withAnimation {
showPopover = false showPopover = false
updateOnMain { // updateOnMain {
appState.currentView = mini ? .apps : .empty // appState.currentView = mini ? .apps : .empty
// appState.isReminderVisible.toggle() // }
}
if sentinel { if sentinel {
launchctl(load: true) launchctl(load: true)
} }
@@ -300,15 +306,20 @@ struct FilesView: View {
removeApp(appState: appState, withId: appState.appInfo.id) removeApp(appState: appState, withId: appState.appInfo.id)
} else { } else {
// Add deleted appInfo object to trashed array // Add deleted appInfo object to trashed array
appState.appInfo.fileSize = [:]
appState.trashedFiles.append(appState.appInfo) appState.trashedFiles.append(appState.appInfo)
// Clear out appInfoStore object // Clear out appInfoStore object (Used for leftover file search)
if let index = appState.appInfoStore.firstIndex(where: { $0.path == appState.appInfo.path }) { if let index = appState.appInfoStore.firstIndex(where: { $0.path == appState.appInfo.path }) {
appState.appInfoStore[index] = .empty appState.appInfoStore[index] = .empty
} }
updateOnMain {
// Remove items from the list
appState.appInfo.fileSize = appState.appInfo.fileSize.filter { !appState.selectedItems.contains($0.key) }
// Update the selectedFiles to remove references that are no longer present
appState.selectedItems.removeAll()
}
} }
appState.appInfo = AppInfo.empty
} }
} }
@@ -320,8 +331,6 @@ struct FilesView: View {
.padding(.top) .padding(.top)
// Spacer()
} }
} }
@@ -360,7 +369,7 @@ struct FileDetailsItem: View {
} }
} }
)) ))
.toggleStyle(SimpleCheckboxToggleStyle())
.disabled(self.path.path.contains(".Trash")) .disabled(self.path.path.contains(".Trash"))
if let appIcon = icon { if let appIcon = icon {
@@ -369,8 +378,6 @@ struct FileDetailsItem: View {
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30) .frame(width: 30, height: 30)
.clipShape(RoundedRectangle(cornerRadius: 8)) .clipShape(RoundedRectangle(cornerRadius: 8))
.brightness(isHovered ? 0.2 : 0)
.shadow(color: Color("mode"), radius: isHovered ? 2 : 0)
} }
@@ -382,6 +389,17 @@ struct FileDetailsItem: View {
.lineLimit(1) .lineLimit(1)
.truncationMode(.tail) .truncationMode(.tail)
.help(path.lastPathComponent) .help(path.lastPathComponent)
.overlay{
if (isHovered) {
VStack {
Spacer()
RoundedRectangle(cornerRadius: 10)
.fill(Color("mode").opacity(0.5))
.frame(height: 1.5)
.offset(y: 3)
}
}
}
if isNested(path: path) { if isNested(path: path) {
InfoButton(text: "Application file is nested within subdirectories. To prevent deleting incorrect folders, Pearcleaner will leave these alone. You may manually delete the remaining folders if required.", color: nil, label: "") InfoButton(text: "Application file is nested within subdirectories. To prevent deleting incorrect folders, Pearcleaner will leave these alone. You may manually delete the remaining folders if required.", color: nil, label: "")
@@ -398,7 +416,17 @@ struct FileDetailsItem: View {
.truncationMode(.tail) .truncationMode(.tail)
.opacity(0.5) .opacity(0.5)
.help(path.path) .help(path.path)
} }
.onTapGesture {
NSWorkspace.shared.selectFile(path.path, inFileViewerRootedAtPath: path.deletingLastPathComponent().path)
}
.onHover { hovering in
withAnimation(Animation.easeIn(duration: 0.2)) {
self.isHovered = hovering
}
}
Spacer() Spacer()
@@ -409,14 +437,6 @@ struct FileDetailsItem: View {
Text("\(displaySize)") Text("\(displaySize)")
} }
.onHover { hovering in
withAnimation(Animation.easeIn(duration: 0.2)) {
self.isHovered = hovering
}
}
.onTapGesture {
NSWorkspace.shared.selectFile(path.path, inFileViewerRootedAtPath: path.deletingLastPathComponent().path)
}
.contextMenu { .contextMenu {
if path.pathExtension == "app" { if path.pathExtension == "app" {
Button("Open \(path.deletingPathExtension().lastPathComponent)") { Button("Open \(path.deletingPathExtension().lastPathComponent)") {
-142
View File
@@ -1,142 +0,0 @@
//
// MenuBarAppsListView.swift
// Pearcleaner
//
// Created by Alin Lupascu on 3/16/24.
//
import Foundation
import SwiftUI
struct MenuBarMiniAppView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var appState: AppState
@EnvironmentObject var locations: Locations
@EnvironmentObject var themeSettings: ThemeSettings
@State private var animateGradient: Bool = false
@Binding var search: String
@State private var showSys: Bool = true
@State private var showUsr: Bool = true
@AppStorage("settings.general.mini") private var mini: Bool = false
@AppStorage("settings.general.glass") private var glass: Bool = true
@AppStorage("settings.general.popover") private var popoverStay: Bool = true
@Binding var showPopover: Bool
@State private var showMenu = false
var body: some View {
var filteredApps: [AppInfo] {
if search.isEmpty {
return appState.sortedApps
} else {
return appState.sortedApps.filter { $0.appName.localizedCaseInsensitiveContains(search) }
}
}
ZStack {
HStack(spacing: 0){
if appState.reload {
VStack {
Spacer()
ProgressView("Refreshing app list")
Spacer()
}
.padding(.vertical)
} else {
VStack(alignment: .center) {
AppsListView(search: $search, showPopover: $showPopover, filteredApps: filteredApps).padding(.top, 8)
HStack(spacing: 10) {
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()
reversePreloader(allApps: appState.sortedApps, appState: appState, locations: locations, reverseAddon: true)
} else {
appState.currentView = .zombie
showPopover.toggle()
}
}
}
}
.buttonStyle(SimpleButtonStyle(icon: "clock.arrow.circlepath", help: "Leftover Files"))
.padding(.leading, 10)
SearchBarMiniBottom(search: $search)
Button("More") {
self.showMenu.toggle()
}
.padding(.trailing, 10)
.buttonStyle(SimpleButtonStyle(icon: "ellipsis.circle", help: "More"))
.popover(isPresented: $showMenu) {
VStack(alignment: .leading) {
if #available(macOS 14.0, *) {
SettingsLink{
Label("Settings", systemImage: "gear")
}
.buttonStyle(SimpleButtonStyle(icon: "gear", label: "Settings", help: "Settings"))
} else {
Button("Settings") {
NSApp.sendAction(Selector(("showPreferencesWindow:")), to: NSApp.delegate, from: nil)
showMenu = false
}
.buttonStyle(SimpleButtonStyle(icon: "gear", label: "Settings", help: "Settings"))
}
Button("Quit") {
NSApp.terminate(nil)
}
.buttonStyle(SimpleButtonStyle(icon: "x.circle.fill", label: "Quit Pearcleaner", help: "Quit Pearcleaner"))
}
.padding()
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
}
}
.padding(.top, 5)
}
.padding(.vertical, 8)
.padding(.bottom, 8)
}
}
}
.frame(minWidth: 300, minHeight: 370)
.edgesIgnoringSafeArea(.all)
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
.transition(.opacity)
.popover(isPresented: $showPopover, arrowEdge: .leading) {
VStack {
if appState.currentView == .files {
FilesView(showPopover: $showPopover, search: $search, regularWin: false)
.id(appState.appInfo.id)
} else if appState.currentView == .zombie {
ZombieView(showPopover: $showPopover, search: $search, regularWin: false)
.id(appState.appInfo.id)
}
}
.interactiveDismissDisabled(popoverStay)
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
.frame(width: 650, height: 500)
}
}
}
+43 -83
View File
@@ -28,56 +28,17 @@ struct MiniMode: View {
VStack(spacing: 0) { VStack(spacing: 0) {
Group { Group {
if appState.currentView == .empty { if appState.currentView == .empty {
TopBarMini(search: $search, showPopover: $showPopover)
MiniEmptyView(showPopover: $showPopover) MiniEmptyView(showPopover: $showPopover)
} else { } else {
TopBarMini(search: $search, showPopover: $showPopover)
MiniAppView(search: $search, showPopover: $showPopover) MiniAppView(search: $search, showPopover: $showPopover)
} }
} }
.transition(.opacity) .transition(.opacity)
} }
.popover(isPresented: $showPopover, arrowEdge: .trailing) {
VStack {
if appState.currentView == .files {
FilesView(showPopover: $showPopover, search: $search, regularWin: false)
.id(appState.appInfo.id)
} else if appState.currentView == .zombie {
ZombieView(showPopover: $showPopover, search: $search, regularWin: false)
.id(appState.appInfo.id)
}
}
.interactiveDismissDisabled(popoverStay)
// .background(Color("pop"))
// .background(backgroundView(themeSettings: themeSettings, glass: false).padding(-80))
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
// .background(
// Group {
// if glass {
// backgroundView(themeSettings: themeSettings).padding(-80)
//// GlassEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all)
// } else {
// Rectangle()
// .fill(Color("pop"))
// .padding(-80)
// }
// }
// )
.frame(width: 650, height: 550)
}
} }
.frame(minWidth: 300, minHeight: 345) .frame(minWidth: 300, minHeight: 345)
.edgesIgnoringSafeArea(.all) .edgesIgnoringSafeArea(.all)
.background(backgroundView(themeSettings: themeSettings, glass: glass)) .background(backgroundView(themeSettings: themeSettings, glass: glass))
// .background(glass ? GlassEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all) : nil)
// MARK: Background for whole app
// .background(Color("bg").opacity(1))
// .background(VisualEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all))
} }
} }
@@ -95,6 +56,7 @@ struct MiniEmptyView: View {
@AppStorage("settings.general.mini") private var mini: Bool = false @AppStorage("settings.general.mini") private var mini: Bool = false
@AppStorage("settings.general.animateLogo") private var animateLogo: Bool = true @AppStorage("settings.general.animateLogo") private var animateLogo: Bool = true
@Binding var showPopover: Bool @Binding var showPopover: Bool
@State private var animationStart = false
var body: some View { var body: some View {
VStack(alignment: .center) { VStack(alignment: .center) {
@@ -102,7 +64,7 @@ struct MiniEmptyView: View {
Spacer() Spacer()
if #available(macOS 14, *) { if #available(macOS 14, *) {
if animateLogo { if animateLogo && animationStart {
LinearGradient(gradient: Gradient(colors: [.green, .orange]), startPoint: .leading, endPoint: .trailing) LinearGradient(gradient: Gradient(colors: [.green, .orange]), startPoint: .leading, endPoint: .trailing)
.mask( .mask(
Image(systemName: "plus.square.dashed") Image(systemName: "plus.square.dashed")
@@ -144,36 +106,28 @@ struct MiniEmptyView: View {
) )
} }
Text("Drop an app here") Text("Drop an app here")
.font(.title3) .font(.title3)
.opacity(0.7)
Text("Click for apps list")
.font(.footnote)
.padding(.bottom, 25) .padding(.bottom, 25)
.opacity(0.5) .opacity(0.5)
Spacer() Spacer()
// if appState.isReminderVisible { }
// Text("CMD + Z to undo") .onTapGesture {
// .font(.title2) withAnimation(.easeInOut(duration: 0.5)) {
// .foregroundStyle(Color("mode").opacity(0.5)) appState.currentView = .apps
// .fontWeight(.medium) }
// .onAppear { }
// DispatchQueue.main.asyncAfter(deadline: .now() + 2) { .onAppear {
// withAnimation { DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// updateOnMain { animationStart = true
// appState.isReminderVisible = false }
// }
// }
// }
// }
// }
//
// Spacer()
} }
} }
} }
@@ -185,26 +139,24 @@ struct MiniEmptyView: View {
struct MiniAppView: View { struct MiniAppView: View {
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@EnvironmentObject var appState: AppState @EnvironmentObject var appState: AppState
@EnvironmentObject var locations: Locations
@EnvironmentObject var themeSettings: ThemeSettings
@State private var animateGradient: Bool = false @State private var animateGradient: Bool = false
@Binding var search: String @Binding var search: String
@State private var showSys: Bool = true @State private var showSys: Bool = true
@State private var showUsr: Bool = true @State private var showUsr: Bool = true
@AppStorage("settings.general.mini") private var mini: Bool = false @AppStorage("settings.general.mini") private var mini: Bool = false
@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.menubar.enabled") private var menubarEnabled: Bool = false
@AppStorage("settings.general.sidebarWidth") private var sidebarWidth: Double = 280
@Binding var showPopover: Bool @Binding var showPopover: Bool
@State private var showMenu = false
var body: some View { var body: some View {
var filteredApps: [AppInfo] {
if search.isEmpty {
return appState.sortedApps
} else {
return appState.sortedApps.filter { $0.appName.localizedCaseInsensitiveContains(search) }
}
}
ZStack { ZStack {
HStack(spacing: 0){
if appState.reload { if appState.reload {
VStack { VStack {
@@ -214,23 +166,31 @@ struct MiniAppView: View {
} }
.padding(.vertical) .padding(.vertical)
} else { } else {
VStack(alignment: .center) { Searchbar(glass: glass, sidebarWidth: sidebarWidth, menubarEnabled: menubarEnabled, mini: mini, search: $search, showPopover: $showPopover)
AppsListView(search: $search, showPopover: $showPopover, filteredApps: filteredApps)
if appState.currentView != .empty {
SearchBarMiniBottom(search: $search)
.padding(.horizontal)
.padding(.top, 5)
}
}
.padding(.bottom)
} }
}
} }
.transition(.opacity) .transition(.opacity)
.frame(minWidth: 300, minHeight: 370)
.edgesIgnoringSafeArea(.all)
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
.transition(.opacity)
.popover(isPresented: $showPopover, arrowEdge: .trailing) {
VStack {
if appState.currentView == .files {
FilesView(showPopover: $showPopover, search: $search, regularWin: false)
.id(appState.appInfo.id)
} else if appState.currentView == .zombie {
ZombieView(showPopover: $showPopover, search: $search, regularWin: false)
.id(appState.appInfo.id)
}
}
.interactiveDismissDisabled(popoverStay)
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
.frame(width: 650, height: 500)
}
} }
} }
+14 -99
View File
@@ -11,26 +11,22 @@ import SwiftUI
struct RegularMode: View { struct RegularMode: View {
@EnvironmentObject var appState: AppState @EnvironmentObject var appState: AppState
@EnvironmentObject var themeSettings: ThemeSettings @EnvironmentObject var themeSettings: ThemeSettings
@EnvironmentObject var locations: Locations
@AppStorage("settings.general.glass") private var glass: Bool = false @AppStorage("settings.general.glass") private var glass: Bool = false
@AppStorage("settings.general.sidebarWidth") private var sidebarWidth: Double = 280 @AppStorage("settings.general.sidebarWidth") private var sidebarWidth: Double = 280
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
@AppStorage("settings.general.mini") private var mini: Bool = false
@Binding var search: String @Binding var search: String
@State private var showSys: Bool = true @State private var showSys: Bool = true
@State private var showUsr: Bool = true @State private var showUsr: Bool = true
@Binding var showPopover: Bool @Binding var showPopover: Bool
@State private var showMenu = false
var filteredApps: [AppInfo] {
if search.isEmpty {
return appState.sortedApps
} else {
return appState.sortedApps.filter { $0.appName.localizedCaseInsensitiveContains(search) }
}
}
var body: some View { var body: some View {
HStack(alignment: .center, spacing: 0) { HStack(alignment: .center, spacing: 0) {
// App List // App List
HStack(spacing: 0){ HStack(spacing: 0){
@@ -43,26 +39,10 @@ struct RegularMode: View {
.frame(width: sidebarWidth) .frame(width: sidebarWidth)
.padding(.vertical) .padding(.vertical)
} else { } else {
VStack(alignment: .center) { Searchbar(glass: glass, sidebarWidth: sidebarWidth, menubarEnabled: menubarEnabled, mini: mini, search: $search, showPopover: $showPopover)
VStack(alignment: .center, spacing: 20) {
HStack {
SearchBarMiniBottom(search: $search)
.padding(.horizontal)
}
}
.padding(.top, 20)
AppsListView(search: $search, showPopover: $showPopover, filteredApps: filteredApps)
}
.frame(width: sidebarWidth) .frame(width: sidebarWidth)
.padding(.vertical, 7)
} }
} }
.background(backgroundView(themeSettings: themeSettings, darker: true, glass: glass)) .background(backgroundView(themeSettings: themeSettings, darker: true, glass: glass))
.transition(.opacity) .transition(.opacity)
@@ -73,22 +53,21 @@ struct RegularMode: View {
// Details View // Details View
VStack(spacing: 0) { HStack(spacing: 0) {
Spacer()
Group { Group {
if appState.currentView == .empty || appState.currentView == .apps { if appState.currentView == .empty || appState.currentView == .apps {
TopBar(showPopover: $showPopover)
AppDetailsEmptyView(showPopover: $showPopover) AppDetailsEmptyView(showPopover: $showPopover)
} else if appState.currentView == .files { } else if appState.currentView == .files {
TopBar(showPopover: $showPopover)
FilesView(showPopover: $showPopover, search: $search, regularWin: true) 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)
ZombieView(showPopover: $showPopover, search: $search, regularWin: true) ZombieView(showPopover: $showPopover, search: $search, regularWin: true)
.id(appState.appInfo.id) .id(appState.appInfo.id)
} }
} }
.transition(.opacity) .transition(.opacity)
Spacer()
} }
.zIndex(2) .zIndex(2)
.background(backgroundView(themeSettings: themeSettings)) .background(backgroundView(themeSettings: themeSettings))
@@ -109,13 +88,14 @@ struct AppDetailsEmptyView: View {
@EnvironmentObject var locations: Locations @EnvironmentObject var locations: Locations
@AppStorage("settings.general.animateLogo") private var animateLogo: Bool = true @AppStorage("settings.general.animateLogo") private var animateLogo: Bool = true
@Binding var showPopover: Bool @Binding var showPopover: Bool
@State private var animationStart = false
var body: some View { var body: some View {
VStack(alignment: .center) { VStack(alignment: .center) {
Spacer() Spacer()
if #available(macOS 14, *) { if #available(macOS 14, *) {
if animateLogo { if animateLogo && animationStart {
PearDropView() PearDropView()
.phaseAnimator([false, true]) { wwdc24, chromaRotate in .phaseAnimator([false, true]) { wwdc24, chromaRotate in
wwdc24 wwdc24
@@ -139,75 +119,10 @@ struct AppDetailsEmptyView: View {
.padding(.bottom, 25) .padding(.bottom, 25)
.opacity(0.5) .opacity(0.5)
} }
} .onAppear {
} DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
animationStart = true
struct SearchBar: View {
@Binding var search: String
var body: some View {
HStack {
TextField("Search", text: $search)
.textFieldStyle(SimpleSearchStyle(icon: Image(systemName: "magnifyingglass"),trash: true, text: $search))
}
.frame(height: 30)
}
}
struct Header: View {
let title: String
let count: Int
@State private var hovered = false
@EnvironmentObject var appState: AppState
@EnvironmentObject var locations: Locations
@EnvironmentObject var fsm: FolderSettingsManager
@Binding var showPopover: Bool
@AppStorage("settings.general.glass") private var glass: Bool = true
var body: some View {
HStack {
Text("\(title)").foregroundStyle(Color("mode")).opacity(0.5)
Text("\(count)")
.font(.system(size: 10))
.monospacedDigit()
.frame(minWidth: count > 99 ? 30 : 24, minHeight: 17)
.background(Color("mode").opacity(0.1))
.clipShape(.capsule)
.padding(.leading, 2)
Spacer()
if hovered {
Text("REFRESH")
.font(.system(size: 10))
.monospaced()
.foregroundStyle(Color("mode").opacity(0.8))
}
}
.onHover { hovering in
withAnimation() {
hovered = hovering
}
}
.onTapGesture {
withAnimation {
// Refresh Apps list
appState.reload.toggle()
showPopover = false
let sortedApps = getSortedApps(paths: fsm.folderPaths, appState: appState)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
appState.sortedApps = sortedApps
appState.reload.toggle()
} }
} }
} }
.frame(minHeight: 20)
.help("Click header or ⌘+R to refresh apps list")
.padding(5)
}
} }
+213
View File
@@ -0,0 +1,213 @@
//
// Searchbar.swift
// Pearcleaner
//
// Created by Alin Lupascu on 4/26/24.
//
import SwiftUI
struct Searchbar: View {
@EnvironmentObject var appState: AppState
@EnvironmentObject var themeSettings: ThemeSettings
@EnvironmentObject var locations: Locations
var glass: Bool
var sidebarWidth: Double
var menubarEnabled: Bool
var mini: Bool
@Binding var search: String
@Binding var showPopover: Bool
@State private var showMenu = false
@State private var showSys: Bool = true
@State private var showUsr: Bool = true
var body: some View {
VStack(alignment: .center, spacing: 0) {
Spacer()
.frame(height: 10)
AppsListView(search: $search, showPopover: $showPopover, filteredApps: filteredApps)
.padding(.top, 25)
Divider()
HStack(spacing: 10) {
SearchBar(search: $search, darker: (mini || menubarEnabled) ? false : true, glass: glass)
if search.isEmpty {
Button("More") {
self.showMenu.toggle()
}
.buttonStyle(SimpleButtonStyle(icon: "ellipsis.circle", help: "More"))
.popover(isPresented: $showMenu) {
VStack(alignment: .leading) {
if mini && !menubarEnabled {
Button("") {
withAnimation(.easeInOut(duration: 0.5)) {
appState.currentView = .empty
appState.appInfo = AppInfo.empty
showPopover = false
}
}
.buttonStyle(SimpleButtonStyle(icon: "plus.square.dashed", label: "Drop Target", help: "Drop Target"))
}
Button("Leftover Files") {
showMenu = false
withAnimation(.easeInOut(duration: 0.5)) {
showPopover = false
appState.appInfo = .empty
appState.selectedZombieItems = []
if appState.zombieFile.fileSize.keys.isEmpty {
appState.currentView = .zombie
appState.showProgress.toggle()
showPopover.toggle()
reversePreloader(allApps: appState.sortedApps, appState: appState, locations: locations, reverseAddon: true)
} else {
appState.currentView = .zombie
showPopover.toggle()
}
}
}
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: "Leftover Files", help: "Leftover Files", size: 5))
if #available(macOS 14.0, *) {
SettingsLink {}
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: "Settings", help: "Settings", size: 5))
} else {
Button("Settings") {
NSApp.sendAction(Selector(("showPreferencesWindow:")), to: NSApp.delegate, from: nil)
showMenu = false
}
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: "Settings", help: "Settings", size: 5))
}
if menubarEnabled {
Button("Quit") {
NSApp.terminate(nil)
}
.buttonStyle(SimpleButtonStyle(icon: "x.circle.fill", label: "Quit Pearcleaner", help: "Quit Pearcleaner"))
}
}
.padding()
.background(backgroundView(themeSettings: themeSettings, glass: glass).padding(-80))
}
}
}
.padding(.horizontal, search.isEmpty ? 10 : 5)
.padding(.vertical, 5)
}
}
private var filteredApps: [AppInfo] {
if search.isEmpty {
return appState.sortedApps
} else {
return appState.sortedApps.filter { $0.appName.localizedCaseInsensitiveContains(search) }
}
}
}
struct SimpleSearchStyle: TextFieldStyle {
@State private var isHovered = false
@FocusState private var isFocused: Bool
@State var trash: Bool = false
@Binding var text: String
@State var darker: Bool = false
@State var glass: Bool = false
@State var padding: CGFloat = 5
@EnvironmentObject var appState: AppState
@EnvironmentObject var themeSettings: ThemeSettings
@AppStorage("settings.general.mini") private var mini: Bool = false
func _body(configuration: TextField<Self._Label>) -> some View {
ZStack {
RoundedRectangle(cornerRadius: 8)
.fill(darker ? themeSettings.themeColor.darker(by: 5) : themeSettings.themeColor)
.allowsHitTesting(false)
.frame(height: 30)
.opacity(glass ? 0.0 : 1.0)
ZStack {
if text.isEmpty {
HStack {
Spacer()
Text(isFocused ? "Type to search" : "Click to search")
.font(.subheadline)
.foregroundColor(Color("mode").opacity(0.2))
Spacer()
}
}
HStack {
configuration
.font(.title3)
.textFieldStyle(PlainTextFieldStyle())
Spacer()
if trash && text != "" {
Button("") {
text = ""
}
.buttonStyle(SimpleButtonStyle(icon: "delete.left.fill", help: "Clear text", size: 14, padding: padding))
}
}
}
.padding(.horizontal, 8)
}
.onHover { hovering in
withAnimation(Animation.easeInOut(duration: 0.15)) {
self.isHovered = hovering
self.isFocused = true
}
}
.focused($isFocused)
.onAppear {
updateOnMain {
self.isFocused = true
}
}
}
}
// Hide blinking textfield caret
extension NSTextView {
open override var frame: CGRect {
didSet {
insertionPointColor = .clear
}
}
}
struct SearchBar: View {
@Binding var search: String
@State var darker: Bool = false
@State var glass: Bool = false
@State var padding: CGFloat = 5
@EnvironmentObject var appState: AppState
var body: some View {
HStack {
TextField("", text: $search)
.textFieldStyle(SimpleSearchStyle(trash: true, text: $search, darker: darker, glass: glass, padding: padding))
}
}
}
-96
View File
@@ -1,96 +0,0 @@
//
// TopBar.swift
// Pearcleaner
//
// Created by Alin Lupascu on 11/10/23.
//
import Foundation
import SwiftUI
struct TopBar: View {
@AppStorage("displayMode") var displayMode: DisplayMode = .system
@AppStorage("settings.general.glass") private var glass: Bool = false
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
@AppStorage("settings.general.mini") private var mini: Bool = false
@EnvironmentObject var appState: AppState
@Binding var showPopover: Bool
@EnvironmentObject var locations: Locations
var body: some View {
HStack(alignment: .center, spacing: 0) {
// Spacer()
//
// if appState.isReminderVisible {
// Text("CMD + Z to undo")
// .font(.title2)
// .foregroundStyle(Color("mode").opacity(0.5))
// .fontWeight(.medium)
// .onAppear {
// DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
// withAnimation {
// appState.isReminderVisible = false
// }
// }
// }
// }
Spacer()
HStack() {
Spacer()
if appState.currentView == .zombie {
Button("Rescan") {
updateOnMain {
appState.zombieFile = .empty
appState.showProgress.toggle()
reversePreloader(allApps: appState.sortedApps, appState: appState, locations: locations, reverseAddon: true)
}
}
.buttonStyle(SimpleButtonStyle(icon: "arrow.counterclockwise.circle.fill", help: "Rescan files"))
}
if appState.currentView != .zombie {
Button("") {
withAnimation(.easeInOut(duration: 0.5)) {
updateOnMain {
appState.appInfo = .empty
appState.selectedZombieItems = []
if appState.zombieFile.fileSize.keys.count == 0 {
appState.currentView = .zombie
appState.showProgress.toggle()
showPopover.toggle()
reversePreloader(allApps: appState.sortedApps, appState: appState, locations: locations, reverseAddon: true)
} else {
appState.currentView = .zombie
showPopover.toggle()
}
}
}
}
.buttonStyle(SimpleButtonStyle(icon: "clock.arrow.circlepath", help: "Leftover Files"))
}
if appState.currentView == .files || appState.currentView == .zombie {
Button("") {
withAnimation(.easeInOut(duration: 0.5)) {
appState.currentView = .empty
appState.appInfo = AppInfo.empty
}
}
.buttonStyle(SimpleButtonStyle(icon: "plus.square.dashed", help: "Drop Target"))
}
}
}
.padding(6)
}
}
-128
View File
@@ -1,128 +0,0 @@
//
// TopBarMini.swift
// Pearcleaner
//
// Created by Alin Lupascu on 11/14/23.
//
import Foundation
import SwiftUI
struct TopBarMini: View {
@AppStorage("displayMode") var displayMode: DisplayMode = .system
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
@AppStorage("settings.general.mini") private var mini: Bool = false
@Binding var search: String
@Binding var showPopover: Bool
@EnvironmentObject var appState: AppState
@EnvironmentObject var locations: Locations
var body: some View {
HStack(alignment: .center, spacing: 0) {
Spacer()
if appState.currentView == .empty {
HStack {
Spacer()
Button("") {
withAnimation(.easeInOut(duration: 0.5)) {
showPopover = false
updateOnMain {
if appState.zombieFile.fileSize.keys.count == 0 {
appState.currentView = .zombie
appState.showProgress.toggle()
showPopover.toggle()
reversePreloader(allApps: appState.sortedApps, appState: appState, locations: locations, reverseAddon: true)
} else {
appState.currentView = .zombie
showPopover.toggle()
}
}
}
}
.buttonStyle(SimpleButtonStyle(icon: "clock.arrow.circlepath", help: "Leftover Files"))
Button("") {
withAnimation(.easeInOut(duration: 0.5)) {
appState.currentView = .apps
}
}
.buttonStyle(SimpleButtonStyle(icon: "square.grid.3x3.square", help: "Apps List"))
}
}
if appState.currentView != .empty {
HStack {
Spacer()
Button("") {
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()
reversePreloader(allApps: appState.sortedApps, appState: appState, locations: locations, reverseAddon: true)
} else {
appState.currentView = .zombie
showPopover.toggle()
}
}
}
}
.buttonStyle(SimpleButtonStyle(icon: "clock.arrow.circlepath", help: "Leftover Files"))
Button("") {
withAnimation(.easeInOut(duration: 0.5)) {
appState.currentView = .empty
appState.appInfo = AppInfo.empty
showPopover = false
}
}
.buttonStyle(SimpleButtonStyle(icon: "plus.square.dashed", help: "Drop Target"))
}
}
}
.padding(.horizontal, 10)
.padding(.top, 10)
.padding(.bottom, 5)
}
}
struct SearchBarMini: View {
@Binding var search: String
var body: some View {
HStack {
TextField("Search", text: $search)
.textFieldStyle(AnimatedSearchStyle(text: $search))
}
.frame(height: 20)
}
}
struct SearchBarMiniBottom: View {
@Binding var search: String
@EnvironmentObject var appState: AppState
var body: some View {
HStack {
TextField(" Search", text: $search)
.textFieldStyle(SimpleSearchStyle(trash: true, text: $search))
}
}
}
+55 -42
View File
@@ -13,6 +13,7 @@ struct ZombieView: View {
@EnvironmentObject var locations: Locations @EnvironmentObject var locations: Locations
@State private var showPop: Bool = false @State private var showPop: Bool = false
@AppStorage("settings.general.mini") private var mini: Bool = false @AppStorage("settings.general.mini") private var mini: Bool = false
@AppStorage("settings.general.glass") private var glass: Bool = false
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false @AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false @AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
@AppStorage("settings.general.selectedSort") var selectedSortAlpha: Bool = true @AppStorage("settings.general.selectedSort") var selectedSortAlpha: Bool = true
@@ -108,19 +109,9 @@ struct ZombieView: View {
} }
} else { } else {
// Titlebar // Titlebar
if !regularWin {
HStack(spacing: 0) { HStack(spacing: 0) {
Spacer() Spacer()
Button("Rescan") {
updateOnMain {
appState.zombieFile = .empty
appState.showProgress.toggle()
reversePreloader(allApps: appState.sortedApps, appState: appState, locations: locations, reverseAddon: true)
}
}
.buttonStyle(SimpleButtonStyle(icon: "arrow.counterclockwise.circle.fill", help: "Rescan files"))
Button("Close") { Button("Close") {
updateOnMain { updateOnMain {
appState.appInfo = AppInfo.empty appState.appInfo = AppInfo.empty
@@ -129,10 +120,11 @@ struct ZombieView: View {
showPopover = false showPopover = false
} }
} }
.buttonStyle(SimpleButtonStyle(icon: "x.circle.fill", help: "Close")) .buttonStyle(SimpleButtonStyle(icon: "x.circle", iconFlip: "x.circle.fill", help: "Close"))
}
.padding([.horizontal, .top], 5)
} }
.padding(.top, 6)
.padding(.trailing, (mini || menubarEnabled) ? 6 : 0)
VStack() { VStack() {
// Main Group // Main Group
@@ -141,7 +133,7 @@ struct ZombieView: View {
VStack(alignment: .center) { VStack(alignment: .center) {
HStack(alignment: .center) { HStack(alignment: .center) {
Image(systemName: "clock.arrow.circlepath") Image(systemName: "doc.badge.clock.fill")
.resizable() .resizable()
.scaledToFit() .scaledToFit()
.frame(width: 50, height: 50) .frame(width: 50, height: 50)
@@ -185,9 +177,11 @@ struct ZombieView: View {
} }
} }
)) ))
.toggleStyle(SimpleCheckboxToggleStyle())
.help("All checkboxes")
SearchBarMiniBottom(search: $searchZ)
// .padding(.top) SearchBar(search: $searchZ, darker: true, glass: glass)
.padding(.horizontal) .padding(.horizontal)
@@ -212,11 +206,7 @@ struct ZombieView: View {
let iconImage = fileIcon.map(Image.init(nsImage:)) let iconImage = fileIcon.map(Image.init(nsImage:))
VStack { VStack {
ZombieFileDetailsItem(size: fileSize, sizeL: fileSizeL, icon: iconImage, path: file) ZombieFileDetailsItem(size: fileSize, sizeL: fileSizeL, icon: iconImage, path: file)
.padding(.trailing) .padding(.vertical, 5)
if index < filteredAndSortedFiles.0.count - 1 {
Divider().padding(.leading, 40).opacity(0.5)
}
} }
} }
} }
@@ -226,8 +216,9 @@ struct ZombieView: View {
.onChange(of: sizeType) { _ in .onChange(of: sizeType) { _ in
localKey = UUID() localKey = UUID()
} }
.id(localKey)
} }
.id(localKey)
Spacer() Spacer()
@@ -236,30 +227,45 @@ struct ZombieView: View {
Spacer() Spacer()
Button("Rescan") {
updateOnMain {
appState.zombieFile = .empty
appState.showProgress.toggle()
reversePreloader(allApps: appState.sortedApps, appState: appState, locations: locations, reverseAddon: true)
}
}
.buttonStyle(RescanButton())
Button("\(sizeType == "Logical" ? totalSelectedZombieSize.logical : sizeType == "Finder" ? totalSelectedZombieSize.finder : totalSelectedZombieSize.real)") { Button("\(sizeType == "Logical" ? totalSelectedZombieSize.logical : sizeType == "Finder" ? totalSelectedZombieSize.finder : totalSelectedZombieSize.real)") {
Task { Task {
if appState.selectedZombieItems.count == appState.zombieFile.fileSize.keys.count {
updateOnMain { updateOnMain {
appState.zombieFile = .empty appState.zombieFile = .empty
search = "" search = ""
if !regularWin { searchZ = ""
if mini || menubarEnabled {
appState.currentView = .apps appState.currentView = .apps
showPopover = false showPopover = false
} else { } else {
appState.currentView = .empty appState.currentView = .empty
} }
} }
}
let selectedItemsArray = Array(appState.selectedZombieItems) let selectedItemsArray = Array(appState.selectedZombieItems)
killApp(appId: appState.appInfo.bundleIdentifier) {
moveFilesToTrash(at: selectedItemsArray) { moveFilesToTrash(at: selectedItemsArray) {
withAnimation { withAnimation {
showPopover = false showPopover = false
// updateOnMain {
// appState.isReminderVisible.toggle()
// }
} }
updateOnMain {
// Remove items from the list
appState.zombieFile.fileSize = appState.zombieFile.fileSize.filter { !appState.selectedZombieItems.contains($0.key) }
// Update the selectedZombieFiles to remove references that are no longer present
appState.selectedZombieItems.removeAll()
} }
} }
} }
@@ -267,20 +273,16 @@ struct ZombieView: View {
} }
.buttonStyle(UninstallButton(isEnabled: !appState.selectedZombieItems.isEmpty)) .buttonStyle(UninstallButton(isEnabled: !appState.selectedZombieItems.isEmpty))
.disabled(appState.selectedZombieItems.isEmpty) .disabled(appState.selectedZombieItems.isEmpty)
.padding(.top)
// Spacer()
} }
.padding(.top)
} }
.transition(.opacity) .transition(.opacity)
.padding([.horizontal, .bottom], 20) .padding([.horizontal, .bottom], 20)
.padding(.top, !mini ? 10 : 0) .padding(.top, !mini ? 10 : 0)
} }
} }
} }
} }
@@ -309,6 +311,7 @@ struct ZombieFileDetailsItem: View {
} }
} }
)) ))
.toggleStyle(SimpleCheckboxToggleStyle())
if let appIcon = icon { if let appIcon = icon {
appIcon appIcon
@@ -316,10 +319,9 @@ struct ZombieFileDetailsItem: View {
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30) .frame(width: 30, height: 30)
.clipShape(RoundedRectangle(cornerRadius: 8)) .clipShape(RoundedRectangle(cornerRadius: 8))
.brightness(isHovered ? 0.2 : 0)
.shadow(color: Color("mode"), radius: isHovered ? 2 : 0)
} }
VStack(alignment: .leading, spacing: 5) { VStack(alignment: .leading, spacing: 5) {
HStack(alignment: .center) { HStack(alignment: .center) {
@@ -328,6 +330,17 @@ struct ZombieFileDetailsItem: View {
.lineLimit(1) .lineLimit(1)
.truncationMode(.tail) .truncationMode(.tail)
.help(path.lastPathComponent) .help(path.lastPathComponent)
.overlay{
if (isHovered) {
VStack {
Spacer()
RoundedRectangle(cornerRadius: 10)
.fill(Color("mode").opacity(0.5))
.frame(height: 1.5)
.offset(y: 3)
}
}
}
if let imageView = folderImages(for: path.path) { if let imageView = folderImages(for: path.path) {
imageView imageView
@@ -341,6 +354,14 @@ struct ZombieFileDetailsItem: View {
.opacity(0.5) .opacity(0.5)
.help(path.path) .help(path.path)
} }
.onHover { hovering in
withAnimation(Animation.easeIn(duration: 0.2)) {
self.isHovered = hovering
}
}
.onTapGesture {
NSWorkspace.shared.selectFile(path.path, inFileViewerRootedAtPath: path.deletingLastPathComponent().path)
}
Spacer() Spacer()
@@ -351,14 +372,6 @@ struct ZombieFileDetailsItem: View {
Text("\(displaySize)") Text("\(displaySize)")
} }
.onHover { hovering in
withAnimation(Animation.easeIn(duration: 0.2)) {
self.isHovered = hovering
}
}
.onTapGesture {
NSWorkspace.shared.selectFile(path.path, inFileViewerRootedAtPath: path.deletingLastPathComponent().path)
}
.contextMenu { .contextMenu {
if path.pathExtension == "app" { if path.pathExtension == "app" {
Button("Open \(path.deletingPathExtension().lastPathComponent)") { Button("Open \(path.deletingPathExtension().lastPathComponent)") {