mirror of
https://github.com/exituser/Pearcleaner.git
synced 2026-09-17 04:58:56 +00:00
v3.4.0
This commit is contained in:
@@ -575,7 +575,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
CURRENT_PROJECT_VERSION = 31;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = BK8443AXLU;
|
||||
@@ -593,7 +593,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 3.3.4;
|
||||
MARKETING_VERSION = 3.4.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -610,7 +610,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
CURRENT_PROJECT_VERSION = 31;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = BK8443AXLU;
|
||||
@@ -628,7 +628,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 3.3.4;
|
||||
MARKETING_VERSION = 3.4.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
|
||||
@@ -186,4 +186,3 @@ enum DisplayMode: Int, CaseIterable {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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 {
|
||||
var label: 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
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@ struct GeneralSettingsTab: View {
|
||||
@AppStorage("settings.general.brew") private var brew: Bool = false
|
||||
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
|
||||
@AppStorage("settings.general.selectedTheme") var selectedTheme: String = "Auto"
|
||||
@AppStorage("settings.general.selectedSort") var selectedSortAlpha: Bool = true
|
||||
|
||||
@State private var diskStatus: Bool = false
|
||||
@State private var accessStatus: Bool = false
|
||||
private let themes = ["Auto", "Dark", "Light"]
|
||||
@@ -89,6 +91,53 @@ struct GeneralSettingsTab: View {
|
||||
.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 ================================================================================================
|
||||
|
||||
|
||||
@@ -208,7 +257,7 @@ struct GeneralSettingsTab: View {
|
||||
|
||||
}
|
||||
.padding(20)
|
||||
.frame(width: 500, height: 420)
|
||||
.frame(width: 500, height: 460)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -18,18 +18,18 @@ struct InterfaceSettingsTab: View {
|
||||
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
|
||||
@AppStorage("settings.general.mini") private var mini: Bool = false
|
||||
@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.dark") var isDark: Bool = true
|
||||
@AppStorage("settings.general.popover") private var popoverStay: Bool = true
|
||||
@AppStorage("settings.general.miniview") private var miniView: Bool = true
|
||||
@AppStorage("settings.general.selectedTheme") var selectedTheme: String = "Auto"
|
||||
@AppStorage("settings.interface.selectedMenubarIcon") var selectedMenubarIcon: String = "pear-4"
|
||||
private let themes = ["Auto", "Dark", "Light"]
|
||||
@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 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 {
|
||||
Form {
|
||||
@@ -67,7 +67,16 @@ struct InterfaceSettingsTab: View {
|
||||
|
||||
|
||||
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()
|
||||
.scaledToFit()
|
||||
.frame(width: 20, height: 20)
|
||||
@@ -90,19 +99,23 @@ struct InterfaceSettingsTab: View {
|
||||
switch newTheme {
|
||||
case "Auto":
|
||||
displayMode.colorScheme = nil
|
||||
if isDarkModeEnabled() {
|
||||
displayMode.colorScheme = .dark
|
||||
MenuBarExtraManager.shared.restartMenuBarExtra()
|
||||
} else {
|
||||
displayMode.colorScheme = .light
|
||||
// Refresh foreground colors
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
self.selectedTab = .interface
|
||||
}
|
||||
if menubarEnabled{
|
||||
MenuBarExtraManager.shared.restartMenuBarExtra()
|
||||
}
|
||||
case "Dark":
|
||||
displayMode.colorScheme = .dark
|
||||
if menubarEnabled{
|
||||
MenuBarExtraManager.shared.restartMenuBarExtra()
|
||||
}
|
||||
case "Light":
|
||||
displayMode.colorScheme = .light
|
||||
if menubarEnabled{
|
||||
MenuBarExtraManager.shared.restartMenuBarExtra()
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
@@ -148,6 +161,7 @@ struct InterfaceSettingsTab: View {
|
||||
if mini {
|
||||
appState.currentView = miniView ? .apps : .empty
|
||||
showPopover = false
|
||||
findAndHideWindows(named: ["Pearcleaner"])
|
||||
windowSettings.newWindow {
|
||||
MiniMode(search: $search, showPopover: $showPopover)
|
||||
.environmentObject(locations)
|
||||
@@ -164,6 +178,7 @@ struct InterfaceSettingsTab: View {
|
||||
} else {
|
||||
appState.currentView = .files
|
||||
}
|
||||
findAndHideWindows(named: ["Pearcleaner"])
|
||||
windowSettings.newWindow {
|
||||
RegularMode(search: $search, showPopover: $showPopover)
|
||||
.environmentObject(locations)
|
||||
|
||||
@@ -14,10 +14,11 @@ struct SettingsView: View {
|
||||
@Binding var search: String
|
||||
@Binding var showFeature: Bool
|
||||
@AppStorage("settings.general.glass") private var glass: Bool = true
|
||||
@AppStorage("settings.general.selectedTab") private var selectedTab: CurrentTabView = .general
|
||||
|
||||
var body: some View {
|
||||
|
||||
TabView() {
|
||||
TabView(selection: $selectedTab) {
|
||||
GeneralSettingsTab(showPopover: $showPopover, search: $search)
|
||||
.tabItem {
|
||||
Label(CurrentTabView.general.title, systemImage: "gear")
|
||||
@@ -47,11 +48,9 @@ struct SettingsView: View {
|
||||
Label(CurrentTabView.about.title, systemImage: "info.circle")
|
||||
}
|
||||
.tag(CurrentTabView.about)
|
||||
|
||||
}
|
||||
.background(glass ? GlassEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all) : nil)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,15 +17,22 @@ struct FilesView: View {
|
||||
@AppStorage("settings.general.instant") var instantSearch: Bool = true
|
||||
@AppStorage("settings.general.brew") private var brew: Bool = false
|
||||
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
|
||||
@AppStorage("settings.general.selectedSort") var selectedSortAlpha: Bool = true
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
@Binding var showPopover: Bool
|
||||
@Binding var search: String
|
||||
var regularWin: Bool
|
||||
@State private var selectedOption = "Default"
|
||||
// @State private var selectedOption = "Alpha"
|
||||
@State private var elapsedTime = 0
|
||||
@State private var timer: Timer? = nil
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
let totalSelectedSize = appState.selectedItems.reduce(Int64(0)) { (result, url) in
|
||||
result + (appState.appInfo.fileSize[url] ?? 0)
|
||||
}
|
||||
|
||||
VStack(alignment: .center) {
|
||||
if appState.showProgress {
|
||||
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)))
|
||||
}
|
||||
.padding(.leading)
|
||||
@@ -140,7 +149,8 @@ struct FilesView: View {
|
||||
|
||||
VStack(alignment: .trailing, spacing: 5) {
|
||||
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()
|
||||
|
||||
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()
|
||||
@@ -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] {
|
||||
let iconImage = fileIcon.map(Image.init(nsImage:))
|
||||
VStack {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
@@ -261,8 +273,7 @@ struct FilesView: View {
|
||||
|
||||
Spacer()
|
||||
|
||||
if !appState.selectedItems.isEmpty {
|
||||
Button("Uninstall") {
|
||||
Button("\(formatByte(size: totalSelectedSize))") {
|
||||
Task {
|
||||
updateOnMain {
|
||||
search = ""
|
||||
@@ -275,35 +286,6 @@ struct FilesView: View {
|
||||
}
|
||||
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) {
|
||||
moveFilesToTrash(at: selectedItemsArray) {
|
||||
withAnimation {
|
||||
@@ -343,15 +325,12 @@ struct FilesView: View {
|
||||
}
|
||||
|
||||
}
|
||||
.buttonStyle(NavButtonBottomBarStyle(image: "trash.fill", help: "Uninstall"))
|
||||
|
||||
} else {
|
||||
Text("No files selected to remove").font(.title).foregroundStyle(Color("mode")).opacity(0.2)
|
||||
.padding(5)
|
||||
}
|
||||
.buttonStyle(UninstallButton(isEnabled: !appState.selectedItems.isEmpty))
|
||||
.disabled(appState.selectedItems.isEmpty)
|
||||
.padding(.top)
|
||||
|
||||
|
||||
Spacer()
|
||||
// Spacer()
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -103,6 +104,7 @@ struct RegularMode: View {
|
||||
}
|
||||
.transition(.opacity)
|
||||
}
|
||||
// .background(slate)
|
||||
// .onHover { hovering in
|
||||
// withAnimation(Animation.easeInOut(duration: 0.4)) {
|
||||
// isHovering = hovering
|
||||
|
||||
@@ -16,24 +16,29 @@ struct ZombieView: View {
|
||||
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
|
||||
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
|
||||
@AppStorage("settings.menubar.enabled") private var menubarEnabled: Bool = false
|
||||
@AppStorage("settings.general.selectedSort") var selectedSortAlpha: Bool = true
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
@Binding var showPopover: Bool
|
||||
@Binding var search: String
|
||||
@State private var searchZ: String = ""
|
||||
@State private var selectedOption = "Default"
|
||||
// @State private var selectedOption = "Alpha"
|
||||
var regularWin: Bool
|
||||
@State private var elapsedTime = 0
|
||||
@State private var timer: Timer? = nil
|
||||
|
||||
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 filteredFiles = appState.zombieFile.fileSize.filter { (url, _) in
|
||||
searchZ.isEmpty || url.lastPathComponent.localizedCaseInsensitiveContains(searchZ)
|
||||
}
|
||||
|
||||
let sortedFilteredFiles = filteredFiles.sorted(by: {
|
||||
if selectedOption == "Default" {
|
||||
if selectedSortAlpha {
|
||||
return $0.key.lastPathComponent.pearFormat() < $1.key.lastPathComponent.pearFormat()
|
||||
} else {
|
||||
return $0.value > $1.value
|
||||
@@ -148,7 +153,9 @@ struct ZombieView: View {
|
||||
|
||||
VStack(alignment: .trailing, spacing: 5) {
|
||||
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)
|
||||
}
|
||||
|
||||
// SearchBarMiniBottom(search: $searchZ)
|
||||
// .padding(.top)
|
||||
// .padding(.horizontal)
|
||||
|
||||
// Item selection and sorting toolbar
|
||||
HStack {
|
||||
Toggle("", isOn: Binding(
|
||||
@@ -177,12 +180,11 @@ struct ZombieView: View {
|
||||
// .padding(.top)
|
||||
.padding(.horizontal)
|
||||
|
||||
// Spacer()
|
||||
|
||||
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()
|
||||
.padding(.horizontal)
|
||||
|
||||
|
||||
|
||||
ScrollView() {
|
||||
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] {
|
||||
let iconImage = fileIcon.map(Image.init(nsImage:))
|
||||
|
||||
VStack {
|
||||
ZombieFileDetailsItem(size: fileSize, icon: iconImage, path: file)
|
||||
.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
|
||||
@@ -217,26 +219,9 @@ struct ZombieView: View {
|
||||
|
||||
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()
|
||||
|
||||
if !appState.selectedZombieItems.isEmpty {
|
||||
Button("Remove") {
|
||||
Button("\(formatByte(size: totalSelectedZombieSize))") {
|
||||
Task {
|
||||
updateOnMain {
|
||||
appState.zombieFile = .empty
|
||||
@@ -265,21 +250,13 @@ struct ZombieView: View {
|
||||
}
|
||||
|
||||
}
|
||||
.buttonStyle(NavButtonBottomBarStyle(image: "trash.fill", help: "Remove"))
|
||||
} else {
|
||||
Text("No files selected to remove").font(.title).foregroundStyle(Color("mode")).opacity(0.2)
|
||||
.padding(5)
|
||||
}
|
||||
.buttonStyle(UninstallButton(isEnabled: !appState.selectedZombieItems.isEmpty))
|
||||
.disabled(appState.selectedZombieItems.isEmpty)
|
||||
.padding(.top)
|
||||
|
||||
Spacer()
|
||||
|
||||
// Picker("", selection: $selectedOption) {
|
||||
// Image(systemName: "textformat.abc").tag("Default")
|
||||
// Image(systemName: "number").tag("Size")
|
||||
// }
|
||||
// .pickerStyle(SegmentedPickerStyle())
|
||||
// .frame(width: 100)
|
||||
// .help("Sorting alphabetically or by size")
|
||||
// Spacer()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user