This commit is contained in:
Alin
2024-04-09 10:50:01 -06:00
parent 00ce0e5015
commit 5062320650
10 changed files with 254 additions and 158 deletions
+4 -4
View File
@@ -575,7 +575,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 = 30; CURRENT_PROJECT_VERSION = 31;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
@@ -593,7 +593,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 3.3.4; MARKETING_VERSION = 3.4.0;
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;
@@ -610,7 +610,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 = 30; CURRENT_PROJECT_VERSION = 31;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
@@ -628,7 +628,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 3.3.4; MARKETING_VERSION = 3.4.0;
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;
-1
View File
@@ -186,4 +186,3 @@ enum DisplayMode: Int, CaseIterable {
} }
+38
View File
@@ -123,6 +123,44 @@ struct InfoButton: View {
} }
struct UninstallButton: ButtonStyle {
var isEnabled: Bool
func makeBody(configuration: Configuration) -> some View {
HStack(alignment: .center, spacing: 10) {
Image(systemName: "trash")
.foregroundColor(isEnabled ? .white.opacity(1) : .white.opacity(0.3))
Divider()
.frame(height: 24)
.opacity(0.5)
configuration.label
.foregroundColor(isEnabled ? .white.opacity(1) : .white.opacity(0.3))
}
.frame(height: 24)
.frame(minWidth: 75)
.padding(.horizontal)
.padding(.vertical, 4)
.background(configuration.isPressed ? Color("uninstall").opacity(0.8) : Color("uninstall"))
// .background(
// configuration.isPressed ? Color("uninstall").opacity(0.8) :
// (isEnabled ? Color("uninstall") : Color.gray)
// )
.cornerRadius(8)
.onHover { over in
if over {
NSCursor.pointingHand.push()
} else {
NSCursor.pop()
}
}
}
}
struct WarningPopoverView: View { struct WarningPopoverView: View {
var label: String var label: String
var bodyText: String var bodyText: String
@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0x4D",
"green" : "0x58",
"red" : "0xD7"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0x3E",
"green" : "0x47",
"red" : "0xB0"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
+50 -1
View File
@@ -24,6 +24,8 @@ struct GeneralSettingsTab: View {
@AppStorage("settings.general.brew") private var brew: Bool = false @AppStorage("settings.general.brew") private var brew: Bool = false
@AppStorage("settings.general.instant") private var instantSearch: Bool = true @AppStorage("settings.general.instant") private var instantSearch: Bool = true
@AppStorage("settings.general.selectedTheme") var selectedTheme: String = "Auto" @AppStorage("settings.general.selectedTheme") var selectedTheme: String = "Auto"
@AppStorage("settings.general.selectedSort") var selectedSortAlpha: Bool = true
@State private var diskStatus: Bool = false @State private var diskStatus: Bool = false
@State private var accessStatus: Bool = false @State private var accessStatus: Bool = false
private let themes = ["Auto", "Dark", "Light"] private let themes = ["Auto", "Dark", "Light"]
@@ -89,6 +91,53 @@ struct GeneralSettingsTab: View {
.padding(.leading) .padding(.leading)
HStack(spacing: 0) {
Image(systemName: selectedSortAlpha ? "textformat.abc" : "textformat.123")
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.padding(.trailing)
.foregroundStyle(.gray)
VStack(alignment: .leading, spacing: 5) {
Text("File list sorting mode")
.font(.callout)
.foregroundStyle(.gray)
}
InfoButton(text: "When searching for app files or leftover files, the list will be sorted based on this choice", color: nil, label: "")
Spacer()
Picker("", selection: $selectedSortAlpha) {
Text("Alphabetical").tag(true)
Text("Size").tag(false)
}
.pickerStyle(SegmentedPickerStyle())
.frame(width: 200)
}
.padding(5)
.padding(.leading)
// HStack(spacing: 0) {
// Image(systemName: selectedSortAlpha ? "textformat.abc" : "textformat.123")
// .resizable()
// .scaledToFit()
// .frame(width: 20, height: 20)
// .padding(.trailing)
// .foregroundStyle(.gray)
// VStack(alignment: .leading, spacing: 5) {
// Text("\(selectedSortAlpha ? "File list sorted alphabetically" : "File list sorted by size")")
// .font(.callout)
// .foregroundStyle(.gray)
// }
//
// InfoButton(text: "When searching for app files or leftover files, the list will be sorted based on this choice", color: nil, label: "")
//
// Spacer()
// Toggle(isOn: $selectedSortAlpha, label: {
// })
// .toggleStyle(.switch)
// }
// .padding(5)
// .padding(.leading)
// === Perms ================================================================================================ // === Perms ================================================================================================
@@ -208,7 +257,7 @@ struct GeneralSettingsTab: View {
} }
.padding(20) .padding(20)
.frame(width: 500, height: 420) .frame(width: 500, height: 460)
} }
+24 -9
View File
@@ -18,18 +18,18 @@ struct InterfaceSettingsTab: View {
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false @AppStorage("settings.menubar.enabled") private var menubarEnabled: 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.selectedTab") private var selectedTab: CurrentTabView = .general
@AppStorage("settings.general.glass") private var glass: Bool = true @AppStorage("settings.general.glass") private var glass: Bool = true
@AppStorage("settings.general.dark") var isDark: Bool = true @AppStorage("settings.general.dark") var isDark: Bool = true
@AppStorage("settings.general.popover") private var popoverStay: Bool = true @AppStorage("settings.general.popover") private var popoverStay: Bool = true
@AppStorage("settings.general.miniview") private var miniView: Bool = true @AppStorage("settings.general.miniview") private var miniView: Bool = true
@AppStorage("settings.general.selectedTheme") var selectedTheme: String = "Auto" @AppStorage("settings.general.selectedTheme") var selectedTheme: String = "Auto"
@AppStorage("settings.interface.selectedMenubarIcon") var selectedMenubarIcon: String = "pear-4" @AppStorage("settings.interface.selectedMenubarIcon") var selectedMenubarIcon: String = "pear-4"
private let themes = ["Auto", "Dark", "Light"]
@State private var isLaunchAtLoginEnabled: Bool = false @State private var isLaunchAtLoginEnabled: Bool = false
let icons = ["externaldrive", "trash", "folder", "pear-1", "pear-1.5", "pear-2", "pear-3", "pear-4"]
@Binding var showPopover: Bool @Binding var showPopover: Bool
@Binding var search: String @Binding var search: String
let icons = ["externaldrive", "trash", "folder", "pear-1", "pear-1.5", "pear-2", "pear-3", "pear-4"]
private let themes = ["Auto", "Dark", "Light"]
var body: some View { var body: some View {
Form { Form {
@@ -67,7 +67,16 @@ struct InterfaceSettingsTab: View {
HStack(spacing: 0) { HStack(spacing: 0) {
Image(systemName: displayMode.colorScheme == .dark ? "moon.fill" : "sun.max.fill") Image(systemName: {
switch displayMode {
case .dark:
return "moon.fill"
case .light:
return "sun.max.fill"
case .system:
return "circle.righthalf.filled"
}
}())
.resizable() .resizable()
.scaledToFit() .scaledToFit()
.frame(width: 20, height: 20) .frame(width: 20, height: 20)
@@ -90,19 +99,23 @@ struct InterfaceSettingsTab: View {
switch newTheme { switch newTheme {
case "Auto": case "Auto":
displayMode.colorScheme = nil displayMode.colorScheme = nil
if isDarkModeEnabled() { // Refresh foreground colors
displayMode.colorScheme = .dark DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
MenuBarExtraManager.shared.restartMenuBarExtra() self.selectedTab = .interface
} else { }
displayMode.colorScheme = .light if menubarEnabled{
MenuBarExtraManager.shared.restartMenuBarExtra() MenuBarExtraManager.shared.restartMenuBarExtra()
} }
case "Dark": case "Dark":
displayMode.colorScheme = .dark displayMode.colorScheme = .dark
if menubarEnabled{
MenuBarExtraManager.shared.restartMenuBarExtra() MenuBarExtraManager.shared.restartMenuBarExtra()
}
case "Light": case "Light":
displayMode.colorScheme = .light displayMode.colorScheme = .light
if menubarEnabled{
MenuBarExtraManager.shared.restartMenuBarExtra() MenuBarExtraManager.shared.restartMenuBarExtra()
}
default: default:
break break
} }
@@ -148,6 +161,7 @@ struct InterfaceSettingsTab: View {
if mini { if mini {
appState.currentView = miniView ? .apps : .empty appState.currentView = miniView ? .apps : .empty
showPopover = false showPopover = false
findAndHideWindows(named: ["Pearcleaner"])
windowSettings.newWindow { windowSettings.newWindow {
MiniMode(search: $search, showPopover: $showPopover) MiniMode(search: $search, showPopover: $showPopover)
.environmentObject(locations) .environmentObject(locations)
@@ -164,6 +178,7 @@ struct InterfaceSettingsTab: View {
} else { } else {
appState.currentView = .files appState.currentView = .files
} }
findAndHideWindows(named: ["Pearcleaner"])
windowSettings.newWindow { windowSettings.newWindow {
RegularMode(search: $search, showPopover: $showPopover) RegularMode(search: $search, showPopover: $showPopover)
.environmentObject(locations) .environmentObject(locations)
+2 -3
View File
@@ -14,10 +14,11 @@ struct SettingsView: View {
@Binding var search: String @Binding var search: String
@Binding var showFeature: Bool @Binding var showFeature: Bool
@AppStorage("settings.general.glass") private var glass: Bool = true @AppStorage("settings.general.glass") private var glass: Bool = true
@AppStorage("settings.general.selectedTab") private var selectedTab: CurrentTabView = .general
var body: some View { var body: some View {
TabView() { TabView(selection: $selectedTab) {
GeneralSettingsTab(showPopover: $showPopover, search: $search) GeneralSettingsTab(showPopover: $showPopover, search: $search)
.tabItem { .tabItem {
Label(CurrentTabView.general.title, systemImage: "gear") Label(CurrentTabView.general.title, systemImage: "gear")
@@ -47,11 +48,9 @@ struct SettingsView: View {
Label(CurrentTabView.about.title, systemImage: "info.circle") Label(CurrentTabView.about.title, systemImage: "info.circle")
} }
.tag(CurrentTabView.about) .tag(CurrentTabView.about)
} }
.background(glass ? GlassEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all) : nil) .background(glass ? GlassEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all) : nil)
} }
} }
+25 -46
View File
@@ -17,15 +17,22 @@ struct FilesView: View {
@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 @AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
@AppStorage("settings.general.selectedSort") var selectedSortAlpha: Bool = true
@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 var regularWin: Bool
@State private var selectedOption = "Default" // @State private var selectedOption = "Alpha"
@State private var elapsedTime = 0 @State private var elapsedTime = 0
@State private var timer: Timer? = nil @State private var timer: Timer? = nil
var body: some View { var body: some View {
let totalSelectedSize = appState.selectedItems.reduce(Int64(0)) { (result, url) in
result + (appState.appInfo.fileSize[url] ?? 0)
}
VStack(alignment: .center) { VStack(alignment: .center) {
if appState.showProgress { if appState.showProgress {
VStack { VStack {
@@ -131,7 +138,9 @@ struct FilesView: View {
} }
} }
Text("\(appState.appInfo.bundleIdentifier)").font(.title3) Text("\(appState.appInfo.bundleIdentifier)")
.lineLimit(1)
.font(.title3)
.foregroundStyle((.gray.opacity(0.8))) .foregroundStyle((.gray.opacity(0.8)))
} }
.padding(.leading) .padding(.leading)
@@ -140,7 +149,8 @@ struct FilesView: View {
VStack(alignment: .trailing, spacing: 5) { VStack(alignment: .trailing, spacing: 5) {
Text("\(formatByte(size: appState.appInfo.totalSize))").font(.title).fontWeight(.bold) Text("\(formatByte(size: appState.appInfo.totalSize))").font(.title).fontWeight(.bold)
Text("\(appState.appInfo.fileSize.count > 1 ? "\(appState.appInfo.fileSize.count) items" : "\(appState.appInfo.fileSize.count) item")").font(.callout).underline().foregroundStyle((.gray.opacity(0.8))) Text("\(appState.appInfo.fileSize.count == 1 ? "\(appState.selectedItems.count) / \(appState.appInfo.fileSize.count) item" : "\(appState.selectedItems.count) / \(appState.appInfo.fileSize.count) items")")
.font(.callout).foregroundStyle((.gray.opacity(0.8)))
} }
} }
@@ -205,9 +215,10 @@ struct FilesView: View {
Spacer() Spacer()
Button("") { Button("") {
selectedOption = selectedOption == "Default" ? "Size" : "Default" selectedSortAlpha.toggle()
// selectedOption = selectedOption == "Alpha" ? "Size" : "Alpha"
} }
.buttonStyle(SimpleButtonStyle(icon: selectedOption == "Default" ? "textformat.abc" : "textformat.123", help: selectedOption == "Default" ? "Sorted alphabetically" : "Sorted by size", color: Color("mode"))) .buttonStyle(SimpleButtonStyle(icon: selectedSortAlpha ? "textformat.abc" : "textformat.123", help: selectedSortAlpha ? "Sorted alphabetically" : "Sorted by size", color: Color("mode")))
} }
.padding() .padding()
@@ -237,19 +248,20 @@ struct FilesView: View {
} }
} }
let sort = selectedOption == "Default" ? sortedFilesAlpha : sortedFilesSize let sort = selectedSortAlpha ? sortedFilesAlpha : sortedFilesSize
ForEach(sort, id: \.self) { path in ForEach(Array(sort.enumerated()), id: \.element) { index, path in
if let fileSize = appState.appInfo.fileSize[path], let fileIcon = appState.appInfo.fileIcon[path] { if let fileSize = appState.appInfo.fileSize[path], let fileIcon = appState.appInfo.fileIcon[path] {
let iconImage = fileIcon.map(Image.init(nsImage:)) let iconImage = fileIcon.map(Image.init(nsImage:))
VStack { VStack {
FileDetailsItem(size: fileSize, icon: iconImage, path: path) FileDetailsItem(size: fileSize, icon: iconImage, path: path)
if path != appState.appInfo.files.last { if index < sort.count - 1 {
Divider().padding(.leading, 40).opacity(0.5) Divider().padding(.leading, 40).opacity(0.5)
} }
} }
} }
} }
} }
.padding() .padding()
} }
@@ -261,8 +273,7 @@ struct FilesView: View {
Spacer() Spacer()
if !appState.selectedItems.isEmpty { Button("\(formatByte(size: totalSelectedSize))") {
Button("Uninstall") {
Task { Task {
updateOnMain { updateOnMain {
search = "" search = ""
@@ -275,35 +286,6 @@ struct FilesView: View {
} }
let selectedItemsArray = Array(appState.selectedItems) let selectedItemsArray = Array(appState.selectedItems)
// Delete all folders above app bundle between /Applications and app bundle file
// if let url = URL(string: appState.appInfo.path.absoluteString) {
// var parentURL = url.deletingLastPathComponent() // Immediate parent of the .app bundle
//
// // Traverse up the path components until just below /Applications or ~/Applications
// while parentURL.pathComponents.count > 2 && parentURL.path.contains("Applications") && parentURL.deletingLastPathComponent().path != "/Applications" && parentURL.deletingLastPathComponent().path != "\(home)/Applications" {
// parentURL = parentURL.deletingLastPathComponent()
// }
//
// // Now, parentURL should be the directory just below /Applications or ~/Applications
// if parentURL.path != "/Applications" && parentURL.path != "\(home)/Applications" {
// selectedItemsArray.insert(parentURL, at: 0) // Add the correct parent directory to the array
// }
// }
// Delete folder only 1 up from app bundle between /Applications and app bundle file
// 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
//
// if appFolderURL.path == "/Applications" || appFolderURL.path == "\(home)/Applications" {
// // Do nothing, skip insertion
// } else if appFolderURL.pathComponents.count > 2 && appFolderURL.path.contains("Applications") {
// // Insert into selectedItemsArray only if there is an intermediary folder
// selectedItemsArray.insert(appFolderURL, at: 0)
// }
// }
killApp(appId: appState.appInfo.bundleIdentifier) { killApp(appId: appState.appInfo.bundleIdentifier) {
moveFilesToTrash(at: selectedItemsArray) { moveFilesToTrash(at: selectedItemsArray) {
withAnimation { withAnimation {
@@ -343,15 +325,12 @@ struct FilesView: View {
} }
} }
.buttonStyle(NavButtonBottomBarStyle(image: "trash.fill", help: "Uninstall")) .buttonStyle(UninstallButton(isEnabled: !appState.selectedItems.isEmpty))
.disabled(appState.selectedItems.isEmpty)
} else { .padding(.top)
Text("No files selected to remove").font(.title).foregroundStyle(Color("mode")).opacity(0.2)
.padding(5)
}
Spacer() // Spacer()
} }
+2
View File
@@ -29,6 +29,7 @@ struct RegularMode: View {
} }
} }
// let slate = Color(.sRGB, red: 0.188143, green: 0.208556, blue: 0.262679, opacity: 1)
var body: some View { var body: some View {
@@ -103,6 +104,7 @@ struct RegularMode: View {
} }
.transition(.opacity) .transition(.opacity)
} }
// .background(slate)
// .onHover { hovering in // .onHover { hovering in
// withAnimation(Animation.easeInOut(duration: 0.4)) { // withAnimation(Animation.easeInOut(duration: 0.4)) {
// isHovering = hovering // isHovering = hovering
+23 -46
View File
@@ -16,24 +16,29 @@ struct ZombieView: View {
@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 @AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
@AppStorage("settings.general.selectedSort") var selectedSortAlpha: Bool = true
@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 = "Alpha"
var regularWin: Bool var regularWin: Bool
@State private var elapsedTime = 0 @State private var elapsedTime = 0
@State private var timer: Timer? = nil @State private var timer: Timer? = nil
var body: some View { var body: some View {
let totalSelectedZombieSize = appState.selectedZombieItems.reduce(Int64(0)) { (result, url) in
result + (appState.zombieFile.fileSize[url] ?? 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)
} }
let sortedFilteredFiles = filteredFiles.sorted(by: { let sortedFilteredFiles = filteredFiles.sorted(by: {
if selectedOption == "Default" { if selectedSortAlpha {
return $0.key.lastPathComponent.pearFormat() < $1.key.lastPathComponent.pearFormat() return $0.key.lastPathComponent.pearFormat() < $1.key.lastPathComponent.pearFormat()
} else { } else {
return $0.value > $1.value return $0.value > $1.value
@@ -148,7 +153,9 @@ struct ZombieView: View {
VStack(alignment: .trailing, spacing: 5) { VStack(alignment: .trailing, spacing: 5) {
Text("\(formatByte(size: filteredAndSortedFiles.1))").font(.title).fontWeight(.bold) Text("\(formatByte(size: filteredAndSortedFiles.1))").font(.title).fontWeight(.bold)
Text("\(filteredAndSortedFiles.0.count == 1 ? "\(filteredAndSortedFiles.0.count) item" : "\(filteredAndSortedFiles.0.count) items")").font(.callout).underline().foregroundStyle((.gray.opacity(0.8)))
Text("\(appState.zombieFile.fileSize.count == 1 ? "\(appState.selectedZombieItems.count) / \(appState.zombieFile.fileSize.count) item" : "\(appState.selectedZombieItems.count) / \(appState.zombieFile.fileSize.count) items")")
.font(.callout).foregroundStyle((.gray.opacity(0.8)))
} }
} }
@@ -158,10 +165,6 @@ struct ZombieView: View {
.padding(.top, 0) .padding(.top, 0)
} }
// SearchBarMiniBottom(search: $searchZ)
// .padding(.top)
// .padding(.horizontal)
// Item selection and sorting toolbar // Item selection and sorting toolbar
HStack { HStack {
Toggle("", isOn: Binding( Toggle("", isOn: Binding(
@@ -177,12 +180,11 @@ struct ZombieView: View {
// .padding(.top) // .padding(.top)
.padding(.horizontal) .padding(.horizontal)
// Spacer()
Button("") { Button("") {
selectedOption = selectedOption == "Default" ? "Size" : "Default" selectedSortAlpha.toggle()
} }
.buttonStyle(SimpleButtonStyle(icon: selectedOption == "Default" ? "textformat.abc" : "textformat.123", help: selectedOption == "Default" ? "Sorted alphabetically" : "Sorted by size", color: Color("mode"))) .buttonStyle(SimpleButtonStyle(icon: selectedSortAlpha ? "textformat.abc" : "textformat.123", help: selectedSortAlpha ? "Sorted alphabetically" : "Sorted by size", color: Color("mode")))
} }
@@ -193,23 +195,23 @@ struct ZombieView: View {
Divider() Divider()
.padding(.horizontal) .padding(.horizontal)
ScrollView() { ScrollView() {
LazyVStack { LazyVStack {
ForEach(filteredAndSortedFiles.0, id: \.self) { file in ForEach(Array(filteredAndSortedFiles.0.enumerated()), id: \.element) { index, file in
if let fileSize = appState.zombieFile.fileSize[file], let fileIcon = appState.zombieFile.fileIcon[file] { if let fileSize = appState.zombieFile.fileSize[file], let fileIcon = appState.zombieFile.fileIcon[file] {
let iconImage = fileIcon.map(Image.init(nsImage:)) let iconImage = fileIcon.map(Image.init(nsImage:))
VStack {
ZombieFileDetailsItem(size: fileSize, icon: iconImage, path: file) ZombieFileDetailsItem(size: fileSize, icon: iconImage, path: file)
.padding(.trailing) .padding(.trailing)
if file != appState.zombieFile.fileSize.keys.sorted(by: { $0.absoluteString < $1.absoluteString }).last { if index < filteredAndSortedFiles.0.count - 1 {
Divider().padding(.leading, 40).opacity(0.5) Divider().padding(.leading, 40).opacity(0.5)
} }
} }
} }
} }
}
.padding() .padding()
} }
@@ -217,26 +219,9 @@ struct ZombieView: View {
HStack() { HStack() {
// Picker("", selection: Binding(
// get: { appState.selectedZombieItems.count == appState.zombieFile.fileSize.count ? true : false },
// set: { newValue in
// updateOnMain {
// appState.selectedZombieItems = newValue ? Set(appState.zombieFile.fileSize.keys) : []
// }
// }
// )) {
// Image(systemName: "checkmark.square").tag(true)
// Image(systemName: "square").tag(false)
// }
// .pickerStyle(SegmentedPickerStyle())
// .frame(width: 100)
// .offset(x: -8)
// .help("Item Selection")
Spacer() Spacer()
if !appState.selectedZombieItems.isEmpty { Button("\(formatByte(size: totalSelectedZombieSize))") {
Button("Remove") {
Task { Task {
updateOnMain { updateOnMain {
appState.zombieFile = .empty appState.zombieFile = .empty
@@ -265,21 +250,13 @@ struct ZombieView: View {
} }
} }
.buttonStyle(NavButtonBottomBarStyle(image: "trash.fill", help: "Remove")) .buttonStyle(UninstallButton(isEnabled: !appState.selectedZombieItems.isEmpty))
} else { .disabled(appState.selectedZombieItems.isEmpty)
Text("No files selected to remove").font(.title).foregroundStyle(Color("mode")).opacity(0.2) .padding(.top)
.padding(5)
}
Spacer()
// Picker("", selection: $selectedOption) { // Spacer()
// Image(systemName: "textformat.abc").tag("Default")
// Image(systemName: "number").tag("Size")
// }
// .pickerStyle(SegmentedPickerStyle())
// .frame(width: 100)
// .help("Sorting alphabetically or by size")
} }
} }