This commit is contained in:
Alin
2024-10-07 15:15:09 -06:00
parent b4d676d8a4
commit 7f1aaf4650
9 changed files with 257 additions and 136 deletions
+3 -2
View File
@@ -14,7 +14,8 @@ import AlinFoundation
class MetadataAppInfoFetcher {
static func getAppInfo(fromMetadata metadata: [String: Any], atPath path: URL) -> AppInfo? {
// Extract metadata attributes for known fields
let displayName = metadata["kMDItemDisplayName"] as? String ?? ""
var displayName = metadata["kMDItemDisplayName"] as? String ?? ""
displayName = displayName.replacingOccurrences(of: ".app", with: "").capitalizingFirstLetter()
let fsName = metadata["kMDItemFSName"] as? String ?? path.lastPathComponent
let appName = displayName.isEmpty ? fsName : displayName
@@ -152,7 +153,7 @@ class AppInfoUtils {
static func fetchAppIcon(for path: URL, wrapped: Bool, md: Bool = false) -> NSImage? {
let iconPath = wrapped ? (md ? path : path.deletingLastPathComponent().deletingLastPathComponent()) : path
if let appIcon = getIconForFileOrFolderNS(atPath: iconPath) {
return convertICNSToPNG(icon: appIcon, size: NSSize(width: 100, height: 100))
return convertICNSToPNG(icon: appIcon, size: NSSize(width: 50, height: 50))
} else {
printOS("App Icon not found for app at path: \(path)")
return nil
+15
View File
@@ -208,6 +208,21 @@ enum CurrentPage:Int, CaseIterable, Identifiable
}
}
enum SortOption:Int, CaseIterable, Identifiable {
case alphabetical
case size
case creationDate
case contentChangeDate
case lastUsedDate
var id: Int { rawValue }
var title: String {
let titles: [String] = ["App Name", "App Size", "Install Date", "Modified Date", "Last Used Date"]
return titles[rawValue]
}
}
enum CurrentTabView:Int
{
+1
View File
@@ -186,6 +186,7 @@ struct Sponsor: Identifiable {
let url: URL
static let sponsors: [Sponsor] = [
Sponsor(name: "mzdr (monthly)", url: URL(string: "https://github.com/mzdr")!),
Sponsor(name: "chris3ware", url: URL(string: "https://github.com/chris3ware")!),
Sponsor(name: "fpuhan", url: URL(string: "https://github.com/fpuhan")!),
Sponsor(name: "HungThinhIT", url: URL(string: "https://github.com/HungThinhIT")!),
+25 -25
View File
@@ -19,7 +19,7 @@ struct GeneralSettingsTab: View {
@AppStorage("settings.general.brew") private var brew: Bool = false
@AppStorage("settings.general.oneshot") private var oneShotMode: Bool = false
@AppStorage("settings.general.confirmAlert") private var confirmAlert: Bool = false
@AppStorage("settings.general.selectedSort") var selectedSortAlpha: Bool = true
// @AppStorage("settings.general.selectedSort") var selectedSortAlpha: Bool = true
@AppStorage("settings.general.sizeType") var sizeType: String = "Real"
@State private var isCLISymlinked = false
@@ -107,28 +107,28 @@ struct GeneralSettingsTab: View {
HStack(spacing: 0) {
Image(systemName: selectedSortAlpha ? "textformat.abc" : "textformat.123")
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.padding(.trailing)
.foregroundStyle(.primary)
VStack(alignment: .leading, spacing: 5) {
Text("File list sorting order")
.font(.callout)
.foregroundStyle(.primary)
}
Spacer()
Picker("", selection: $selectedSortAlpha) {
Text("Alphabetical")
.tag(true)
Text("File Size")
.tag(false)
}
.buttonStyle(.borderless)
}
.padding(5)
// HStack(spacing: 0) {
// Image(systemName: selectedSortAlpha ? "textformat.abc" : "textformat.123")
// .resizable()
// .scaledToFit()
// .frame(width: 20, height: 20)
// .padding(.trailing)
// .foregroundStyle(.primary)
// VStack(alignment: .leading, spacing: 5) {
// Text("File list sorting order")
// .font(.callout)
// .foregroundStyle(.primary)
// }
// Spacer()
// Picker("", selection: $selectedSortAlpha) {
// Text("Alphabetical")
// .tag(true)
// Text("File Size")
// .tag(false)
// }
// .buttonStyle(.borderless)
// }
// .padding(5)
@@ -151,8 +151,8 @@ struct GeneralSettingsTab: View {
.tag("Real")
Text("Logical")
.tag("Logical")
Text("Finder")
.tag("Finder")
// Text("Finder")
// .tag("Finder")
}
.buttonStyle(.borderless)
+70 -12
View File
@@ -22,7 +22,7 @@ struct AppSearchView: View {
@Binding var showPopover: Bool
@State private var showMenu = false
@Binding var isMenuBar: Bool
@AppStorage("settings.general.selectedSortAppsList") var selectedSortAlpha: Bool = true
@AppStorage("settings.general.selectedSortAppsList") var selectedSortOption: SortOption = .alphabetical
@AppStorage("settings.interface.animationEnabled") private var animationEnabled: Bool = true
@@ -81,10 +81,10 @@ struct AppSearchView: View {
.buttonStyle(SimpleButtonStyle(icon: "arrow.counterclockwise.circle", help: "Refresh apps (⌘+R)", size: 16))
}
SearchBar(search: $search, darker: (mini || menubarEnabled) ? false : true, glass: glass)
SearchBar(search: $search, darker: (mini || menubarEnabled) ? false : true, glass: glass, sidebar: false)
if search.isEmpty {
if search.isEmpty && (mini || menubarEnabled) {
Button("More") {
self.showMenu.toggle()
}
@@ -94,10 +94,19 @@ struct AppSearchView: View {
Button("") {
withAnimation(Animation.easeInOut(duration: animationEnabled ? 0.35 : 0)) {
selectedSortAlpha.toggle()
// Cycle through all enum cases using `CaseIterable`
if let nextSortOption = SortOption(rawValue: selectedSortOption.rawValue + 1) {
selectedSortOption = nextSortOption
showPopover = false
showMenu = false
} else {
selectedSortOption = .alphabetical
showPopover = false
showMenu = false
}
}
}
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: "Sorting: \(selectedSortAlpha ? "Name" : "Size")", help: "Sort app list alphabetically by name or by size", size: 5))
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: "Sorting: \(selectedSortOption.title)", help: "Sort app list alphabetically by name or by size", size: 5))
if mini && !menubarEnabled {
Button("") {
@@ -149,15 +158,48 @@ struct AppSearchView: View {
Button("Quit") {
NSApp.terminate(nil)
}
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: "Quit Pearcleaner", help: "Quit Pearcleaner", size: 5))
.buttonStyle(SimpleButtonStyle(icon: "circle.fill", label: "Quit", help: "Quit Pearcleaner", size: 5))
}
}
.padding()
.background(backgroundView(themeManager: themeManager, glass: glass).padding(-80))
.frame(width: 150)
// .frame(width: 200)
}
} else if search.isEmpty && (!mini || !menubarEnabled) {
Button("") {
withAnimation(Animation.easeInOut(duration: animationEnabled ? 0.35 : 0)) {
showMenu.toggle()
}
}
.buttonStyle(SimpleButtonStyle(icon: "line.3.horizontal.decrease.circle", help: selectedSortOption.title, size: 16))
.popover(isPresented: $showMenu, arrowEdge: .bottom) {
VStack(alignment: .leading, spacing: 10) {
HStack {
Spacer()
Text("Sorting Options").font(.subheadline).foregroundStyle(.secondary)
Spacer()
}
Divider()
ForEach(SortOption.allCases) { option in
Button("") {
withAnimation(Animation.easeInOut(duration: animationEnabled ? 0.35 : 0)) {
selectedSortOption = option
showMenu = false
}
}
.buttonStyle(SimpleButtonStyle(icon: selectedSortOption == option ? "circle.inset.filled" : "circle", label: option.title, help: "", size: 5))
}
}
.padding()
.background(backgroundView(themeManager: themeManager, glass: glass).padding(-80))
// .frame(width: 160)
}
}
@@ -174,12 +216,28 @@ struct AppSearchView: View {
apps = appState.sortedApps.filter { $0.appName.localizedCaseInsensitiveContains(search) }
}
switch selectedSortAlpha {
case true:
return apps.sorted { $0.appName.replacingOccurrences(of: ".", with: "").lowercased() < $1.appName.replacingOccurrences(of: ".", with: "").lowercased() }
case false:
// Sort based on the selected option
switch selectedSortOption {
case .alphabetical:
return apps.sorted {
$0.appName.replacingOccurrences(of: ".", with: "").lowercased() < $1.appName.replacingOccurrences(of: ".", with: "").lowercased()
}
case .size:
return apps.sorted { $0.bundleSize > $1.bundleSize }
case .creationDate:
return apps.sorted { ($0.creationDate ?? Date.distantPast) > ($1.creationDate ?? Date.distantPast) }
case .contentChangeDate:
return apps.sorted { ($0.contentChangeDate ?? Date.distantPast) > ($1.contentChangeDate ?? Date.distantPast) }
case .lastUsedDate:
return apps.sorted { ($0.lastUsedDate ?? Date.distantPast) > ($1.lastUsedDate ?? Date.distantPast) }
}
// switch selectedSortAlpha {
// case true:
// return apps.sorted { $0.appName.replacingOccurrences(of: ".", with: "").lowercased() < $1.appName.replacingOccurrences(of: ".", with: "").lowercased() }
// case false:
// return apps.sorted { $0.bundleSize > $1.bundleSize }
// }
}
}
@@ -218,7 +276,7 @@ struct SimpleSearchStyle: TextFieldStyle {
Spacer()
Text(isFocused ? "Type to search" : "Click to search")
.font(.subheadline)
.foregroundColor(.primary.opacity(0.2))
.foregroundColor(.secondary)
Spacer()
}
}
+98 -54
View File
@@ -22,6 +22,7 @@ struct FilesView: View {
@AppStorage("settings.general.filesWarning") private var warning: Bool = false
@AppStorage("settings.interface.animationEnabled") private var animationEnabled: Bool = true
@AppStorage("settings.general.confirmAlert") private var confirmAlert: Bool = false
@AppStorage("settings.interface.details") private var detailsEnabled: Bool = true
@State private var showAlert = false
@Environment(\.colorScheme) var colorScheme
@Binding var showPopover: Bool
@@ -30,7 +31,7 @@ struct FilesView: View {
var body: some View {
var totalSelectedSize: (real: String, logical: String, finder: String) {
var totalSelectedSize: (real: String, logical: String) {
var totalReal: Int64 = 0
var totalLogical: Int64 = 0
for url in appState.selectedItems {
@@ -39,12 +40,11 @@ struct FilesView: View {
totalReal += realSize
totalLogical += logicalSize
}
return (real: formatByte(size: totalReal).human, logical: formatByte(size: totalLogical).human, finder: "\(formatByte(size: totalLogical).byte) (\(formatByte(size: totalReal).human))")
return (real: formatByte(size: totalReal).human, logical: formatByte(size: totalLogical).human)
}
let displaySizeTotal = sizeType == "Real" ? formatByte(size: appState.appInfo.totalSize).human :
sizeType == "Logical" ? formatByte(size: appState.appInfo.totalSizeLogical).human :
"\(formatByte(size: appState.appInfo.totalSizeLogical).byte) (\(formatByte(size: appState.appInfo.totalSize).human))"
formatByte(size: appState.appInfo.totalSizeLogical).human
VStack(alignment: .center) {
if appState.showProgress {
@@ -91,65 +91,112 @@ struct FilesView: View {
HStack(alignment: .center) {
//app icon, title, size and items
VStack(alignment: .center) {
HStack(alignment: .center) {
if let appIcon = appState.appInfo.appIcon {
Image(nsImage: appIcon)
.resizable()
.scaledToFit()
.frame(width: 50, height: 50)
.padding()
.background{
RoundedRectangle(cornerRadius: 16)
.fill(Color((appState.appInfo.appIcon?.averageColor)!))
VStack(alignment: .leading, spacing: 5){
PearGroupBox(header: {
HStack(alignment: .center, spacing: 15) {
if let appIcon = appState.appInfo.appIcon {
Image(nsImage: appIcon)
.resizable()
.scaledToFit()
.frame(width: 50, height: 50)
.padding(5)
.background{
RoundedRectangle(cornerRadius: 10)
.fill(Color((appState.appInfo.appIcon?.averageColor)!))
}
}
VStack(alignment: .leading) {
HStack(alignment: .center) {
Text("\(appState.appInfo.appName)").font(.title).fontWeight(.bold).lineLimit(1)
Image(systemName: "circle.fill").foregroundStyle(Color("AccentColor")).font(.system(size: 5))
Text("\(appState.appInfo.appVersion)").font(.title3)
}
}
VStack(alignment: .leading, spacing: 5){
HStack {
Text("\(appState.appInfo.appName)").font(.title).fontWeight(.bold).lineLimit(1)
Text("").foregroundStyle(Color("AccentColor"))
Text("v\(appState.appInfo.appVersion)").font(.title3)
Text("\(appState.appInfo.bundleIdentifier)")
.lineLimit(1)
.font(.title3)
.foregroundStyle((.primary.opacity(0.5)))
}
Text("\(appState.appInfo.bundleIdentifier)")
.lineLimit(1)
.font(.title3)
.foregroundStyle((.primary.opacity(0.5)))
Spacer()
if let creationDate = appState.appInfo.creationDate {
Text("Installed: \(formattedMDDate(from: creationDate))")
.font(.footnote)
}
if let modificationDate = appState.appInfo.contentChangeDate {
Text("Modified: \(formattedMDDate(from: modificationDate))")
.font(.footnote)
}
if let lastUsedDate = appState.appInfo.lastUsedDate {
Text("Last Used: \(formattedMDDate(from: lastUsedDate))")
.font(.footnote)
Button("\(detailsEnabled ? "Hide Details" : "Show Details")") {
withAnimation(Animation.easeInOut(duration: animationEnabled ? 0.35 : 0)) {
detailsEnabled.toggle()
}
}
}
.padding(.leading)
Spacer()
}, content: {
VStack(alignment: .trailing, spacing: 5) {
if detailsEnabled {
HStack(spacing: 20) {
VStack(alignment: .leading, spacing: 5) {
Text("Total size of files:")
.font(.callout).fontWeight(.bold)
Text("")
.font(.footnote)
Text("Installed Date:")
.font(.footnote)
Text("Modified Date:")
.font(.footnote)
Text("Last Used Date:")
.font(.footnote)
Text("\(displaySizeTotal)").font(.title).fontWeight(.bold).help("Total size on disk")
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((.primary.opacity(0.5)))
}
Spacer()
VStack(alignment: .trailing, spacing: 5) {
Text("\(displaySizeTotal)").font(.callout).fontWeight(.bold)//.help("Total size on disk")
Text("\(appState.appInfo.fileSize.count == 1 ? "\(appState.selectedItems.count) of \(appState.appInfo.fileSize.count) item" : "\(appState.selectedItems.count) of \(appState.appInfo.fileSize.count) items")")
.font(.footnote)
if let creationDate = appState.appInfo.creationDate {
Text(formattedMDDate(from: creationDate))
.font(.footnote)
.foregroundStyle(.secondary)
} else {
Text("Not available")
.font(.footnote)
.foregroundStyle(.secondary)
}
if let modificationDate = appState.appInfo.contentChangeDate {
Text(formattedMDDate(from: modificationDate))
.font(.footnote)
.foregroundStyle(.secondary)
} else {
Text("Not available")
.font(.footnote)
.foregroundStyle(.secondary)
}
if let lastUsedDate = appState.appInfo.lastUsedDate {
Text(formattedMDDate(from: lastUsedDate))
.font(.footnote)
.foregroundStyle(.secondary)
} else {
Text("Not available")
.font(.footnote)
.foregroundStyle(.secondary)
}
}
}
}
}
})
}
.padding(.horizontal, 20)
.padding(.top, 0)
}
@@ -166,7 +213,6 @@ struct FilesView: View {
.toggleStyle(SimpleCheckboxToggleStyle())
.help("All checkboxes")
Spacer()
@@ -228,7 +274,7 @@ struct FilesView: View {
Button("") {
selectedSortAlpha.toggle()
}
.buttonStyle(SimpleButtonStyle(icon: selectedSortAlpha ? "textformat.abc" : "textformat.123", help: selectedSortAlpha ? "Sorted alphabetically" : "Sorted by size"))
.buttonStyle(SimpleButtonStyle(icon: "line.3.horizontal.decrease.circle", label: selectedSortAlpha ? "Name" : "Size", help: selectedSortAlpha ? "Sorted alphabetically" : "Sorted by size", size: 16))
}
.padding()
@@ -290,11 +336,11 @@ struct FilesView: View {
Spacer()
InfoButton(text: "Always double-check the files/folders marked for removal. In some rare cases, Pearcleaner may find some unrelated files when app names are too similar.", color: .primary.opacity(0.5), warning: true, edge: .top)
.padding(.top)
// InfoButton(text: "Always double-check the files/folders marked for removal. In some rare cases, Pearcleaner may find some unrelated files when app names are too similar.", color: .primary.opacity(0.5), warning: true, edge: .top)
// .padding(.top)
Button("\(sizeType == "Logical" ? totalSelectedSize.logical : sizeType == "Finder" ? totalSelectedSize.finder : totalSelectedSize.real)") {
Button("\(sizeType == "Logical" ? totalSelectedSize.logical : totalSelectedSize.real)") {
showCustomAlert(enabled: confirmAlert, title: "Warning", message: "Are you sure you want to remove these files?", style: .warning, onOk: {
Task {
@@ -377,7 +423,7 @@ struct FilesView: View {
}
.buttonStyle(UninstallButton(isEnabled: !appState.selectedItems.isEmpty))
.disabled(appState.selectedItems.isEmpty)
.padding(.top)
.padding(.top, 5)
}
@@ -509,9 +555,7 @@ struct FileDetailsItem: View {
Spacer()
let displaySize = sizeType == "Real" ? formatByte(size: size!).human :
sizeType == "Logical" ? formatByte(size: sizeL!).human :
"\(formatByte(size: sizeL!).byte) (\(formatByte(size: size!).human))"
formatByte(size: sizeL!).human
Text("\(displaySize)")
}
+5 -5
View File
@@ -114,10 +114,10 @@ struct RegularMode: View {
.buttonStyle(.borderless)
.padding(2)
.padding(.vertical, 2)
.background {
RoundedRectangle(cornerRadius: 8)
.strokeBorder(.secondary.opacity(0.5), lineWidth: 1)
}
// .background {
// RoundedRectangle(cornerRadius: 8)
// .strokeBorder(.secondary.opacity(0.5), lineWidth: 1)
// }
}
.padding(6)
@@ -126,7 +126,7 @@ struct RegularMode: View {
}
}
.frame(minWidth: 900, minHeight: 600)
.frame(minWidth: appState.currentPage == .orphans ? 700 : 900, minHeight: 600)
.edgesIgnoringSafeArea(.all)
+36 -34
View File
@@ -35,7 +35,6 @@ struct ZombieView: View {
@State private var totalLogicalSize: Int64 = 0
@State private var totalRealSizeUninstallBtn: String = ""
@State private var totalLogicalSizeUninstallBtn: String = ""
@State private var totalFinderSizeUninstallBtn: String = ""
var body: some View {
@@ -80,39 +79,45 @@ struct ZombieView: View {
.padding(.trailing, (mini || menubarEnabled) ? 6 : 0)
VStack() {
VStack(spacing: 0) {
// Main Group
HStack() {
HStack(alignment: .center) {
VStack(alignment: .center) {
VStack(alignment: .leading, spacing: 5){
HStack(alignment: .center) {
Image(systemName: "doc.badge.clock.fill")
.resizable()
.scaledToFit()
.frame(width: 50, height: 50)
.symbolRenderingMode(.hierarchical)
.padding(.trailing)
PearGroupBox(header: {
HStack(alignment: .center, spacing: 15) {
Image(systemName: "doc.badge.clock.fill")
.resizable()
.scaledToFit()
.frame(width: 50, height: 50)
.symbolRenderingMode(.hierarchical)
VStack(alignment: .leading, spacing: 10){
HStack {
VStack(alignment: .leading){
Text("Orphaned Files").font(.title).fontWeight(.bold)
Spacer()
Text("Remaining files and folders from previous applications")
.font(.callout).foregroundStyle(.primary.opacity(0.5))
}
Text("Remaining files and folders from previous applications")
.font(.callout).foregroundStyle(.primary.opacity(0.5))
}
}, content: {
HStack(spacing: 20) {
VStack(alignment: .leading, spacing: 5) {
Text("Total size of files:")
.font(.callout).fontWeight(.bold)
Text("")
.font(.footnote)
}
Spacer()
VStack(alignment: .trailing, spacing: 5) {
Text("\(displaySizeTotal)").font(.callout).fontWeight(.bold)//.help("Total size on disk")
Spacer()
Text("\(selectedZombieItemsLocal.count) of \(searchZ.isEmpty ? appState.zombieFile.fileSize.count : memoizedFiles.count) \(appState.zombieFile.fileSize.count == 1 ? "item" : "items")")
.font(.footnote).foregroundStyle(.secondary)
}
VStack(alignment: .trailing, spacing: 5) {
Text("\(displaySizeTotal)").font(.title).fontWeight(.bold).help("Total size on disk")
Text("\(selectedZombieItemsLocal.count) / \(searchZ.isEmpty ? appState.zombieFile.fileSize.count : memoizedFiles.count) \(appState.zombieFile.fileSize.count == 1 ? "item" : "items")")
.font(.callout).foregroundStyle(.primary.opacity(0.5))
}
}
})
}
.padding(.horizontal, 20)
@@ -157,7 +162,6 @@ struct ZombieView: View {
.toggleStyle(SimpleCheckboxToggleStyle())
.help("All checkboxes")
SearchBar(search: $searchZ, darker: true, glass: glass, sidebar: false)
.padding(.horizontal)
.onChange(of: searchZ) { newValue in
@@ -170,7 +174,7 @@ struct ZombieView: View {
selectedSortAlpha.toggle()
updateMemoizedFiles(for: searchZ, sizeType: sizeType, selectedSortAlpha: selectedSortAlpha, force: true)
}
.buttonStyle(SimpleButtonStyle(icon: selectedSortAlpha ? "textformat.abc" : "textformat.123", help: selectedSortAlpha ? "Sorted alphabetically" : "Sorted by size"))
.buttonStyle(SimpleButtonStyle(icon: "line.3.horizontal.decrease.circle", label: selectedSortAlpha ? "Name" : "Size", help: selectedSortAlpha ? "Sorted alphabetically" : "Sorted by size", size: 16))
}
@@ -203,7 +207,7 @@ struct ZombieView: View {
Spacer()
InfoButton(text: "Leftover file search is not 100% accurate as it doesn't have any uninstalled app bundles to check against for file exclusion. This does a best guess search for files/folders and excludes the ones that have overlap with your currently installed applications. Please confirm files marked for deletion really do belong to uninstalled applications.", color: .orange, warning: true, edge: .top)
// InfoButton(text: "Leftover file search is not 100% accurate as it doesn't have any uninstalled app bundles to check against for file exclusion. This does a best guess search for files/folders and excludes the ones that have overlap with your currently installed applications. Please confirm files marked for deletion really do belong to uninstalled applications.", color: .orange, warning: true, edge: .top)
Button("Rescan") {
updateOnMain {
@@ -214,7 +218,7 @@ struct ZombieView: View {
}
.buttonStyle(RescanButton())
Button("\(sizeType == "Logical" ? totalLogicalSizeUninstallBtn : sizeType == "Finder" ? totalFinderSizeUninstallBtn : totalRealSizeUninstallBtn)") {
Button("\(sizeType == "Logical" ? totalLogicalSizeUninstallBtn : totalRealSizeUninstallBtn)") {
showCustomAlert(enabled: confirmAlert, title: "Warning", message: "Are you sure you want to remove these files?", style: .warning, onOk: {
Task {
@@ -342,7 +346,7 @@ struct ZombieView: View {
let filteredFilesReal = fileSizeReal.filter { url, _ in searchTerm.isEmpty || url.lastPathComponent.localizedCaseInsensitiveContains(searchTerm) }
let filteredFilesLogical = fileSizeLogical.filter { url, _ in searchTerm.isEmpty || url.lastPathComponent.localizedCaseInsensitiveContains(searchTerm) }
let filesToSort = sizeType == "Real" || sizeType == "Finder" ? filteredFilesReal : filteredFilesLogical
let filesToSort = sizeType == "Real" ? filteredFilesReal : filteredFilesLogical
let sortedFilteredFiles = filesToSort.sorted { (left, right) -> Bool in
if selectedSortAlpha {
return left.key.lastPathComponent.pearFormat() < right.key.lastPathComponent.pearFormat()
@@ -377,15 +381,14 @@ struct ZombieView: View {
let sizes = calculateTotalSelectedZombieSize()
totalRealSizeUninstallBtn = sizes.real
totalLogicalSizeUninstallBtn = sizes.logical
totalFinderSizeUninstallBtn = "\(sizes.logical) (\(sizes.real))"
}
private var displaySizeText: String {
switch sizeType {
case "Logical":
return totalLogicalSizeUninstallBtn
case "Finder":
return totalFinderSizeUninstallBtn
case "Real":
return totalRealSizeUninstallBtn
default:
return totalRealSizeUninstallBtn
}
@@ -481,8 +484,7 @@ struct ZombieFileDetailsItem: View {
Spacer()
let displaySize = sizeType == "Real" ? formatByte(size: size!).human :
sizeType == "Logical" ? formatByte(size: sizeL!).human :
"\(formatByte(size: sizeL!).byte) (\(formatByte(size: size!).human))"
formatByte(size: sizeL!).human
Text("\(displaySize)")