mirror of
https://github.com/exituser/Pearcleaner.git
synced 2026-09-17 04:58:56 +00:00
More
This commit is contained in:
@@ -600,7 +600,7 @@ func reversePathsSearch(appState: AppState, locations: Locations, completion: @e
|
||||
|
||||
}
|
||||
|
||||
let sortedCollection = collection.sorted(by: { $0.absoluteString < $1.absoluteString })
|
||||
// let sortedCollection = collection.sorted(by: { $0.absoluteString < $1.absoluteString })
|
||||
|
||||
// Calculate file details (sizes and icons)
|
||||
var fileSize: [URL: Int64] = [:]
|
||||
@@ -610,10 +610,8 @@ func reversePathsSearch(appState: AppState, locations: Locations, completion: @e
|
||||
for path in collection {
|
||||
var size: Int64
|
||||
var icon: NSImage? = nil
|
||||
// size = 0
|
||||
size = totalSizeOnDisk(for: path)
|
||||
icon = getIconForFileOrFolderNS(atPath: path)
|
||||
// icon = nil
|
||||
fileSize[path] = size
|
||||
fileIcon[path] = icon
|
||||
}
|
||||
@@ -622,15 +620,10 @@ func reversePathsSearch(appState: AppState, locations: Locations, completion: @e
|
||||
dispatchGroup.notify(queue: .main) {
|
||||
|
||||
updateOnMain {
|
||||
// updatedZombieFile.files = sortedCollection
|
||||
updatedZombieFile.fileSize = fileSize
|
||||
updatedZombieFile.fileIcon = fileIcon
|
||||
appState.selectedZombieItems = Set(sortedCollection)
|
||||
// appState.selectedZombieItems = Set(sortedCollection)
|
||||
appState.zombieFile = updatedZombieFile
|
||||
|
||||
// print(updatedZombieFile.fileSize.keys.count)
|
||||
// print(updatedZombieFile)
|
||||
|
||||
appState.showProgress = false
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,65 @@ struct SimpleButtonStyle: ButtonStyle {
|
||||
}
|
||||
|
||||
|
||||
struct NavButtonBottomBarStyle: ButtonStyle {
|
||||
@State private var isHovered = false
|
||||
var image: String
|
||||
var help: String
|
||||
|
||||
func makeBody(configuration: Configuration) -> some View {
|
||||
ZStack {
|
||||
Image(systemName: image)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 20, height: 20)
|
||||
.foregroundStyle(isHovered ? Color("mode").opacity(0.8) : Color("mode").opacity(0.5))
|
||||
Rectangle()
|
||||
.foregroundColor(.clear)
|
||||
.frame(width: 36, height: 36)
|
||||
.cornerRadius(6)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.scaleEffect(configuration.isPressed ? 0.95 : 1)
|
||||
.buttonStyle(.plain)
|
||||
.onHover { inside in
|
||||
isHovered = inside
|
||||
}
|
||||
.help(help)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct WarningPopoverView: View {
|
||||
var label: String
|
||||
var bodyText: String
|
||||
|
||||
@Binding var isPresented: Bool
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Image(systemName: "exclamationmark.triangle.fill")
|
||||
.foregroundStyle(.red)
|
||||
.popover(isPresented: $isPresented, arrowEdge: .top) {
|
||||
VStack {
|
||||
Text(bodyText)
|
||||
.padding()
|
||||
.font(.title2)
|
||||
}
|
||||
}
|
||||
|
||||
Text(label)
|
||||
.foregroundStyle(Color.red)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.onTapGesture {
|
||||
isPresented.toggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct LabeledDivider: View {
|
||||
let label: String
|
||||
@EnvironmentObject var appState: AppState
|
||||
|
||||
@@ -133,7 +133,7 @@ struct PearcleanerApp: App {
|
||||
|
||||
|
||||
Settings {
|
||||
SettingsView()
|
||||
SettingsView(showPopover: $showPopover)
|
||||
.environmentObject(appState)
|
||||
.toolbarBackground(.clear)
|
||||
.preferredColorScheme(displayMode.colorScheme)
|
||||
|
||||
@@ -20,6 +20,7 @@ struct GeneralSettingsTab: View {
|
||||
@AppStorage("displayMode") var displayMode: DisplayMode = .system
|
||||
@State private var selectedTheme = "Auto"
|
||||
private let themes = ["Auto", "Dark", "Light"]
|
||||
@Binding var showPopover: Bool
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
@@ -117,9 +118,9 @@ struct GeneralSettingsTab: View {
|
||||
.toggleStyle(.switch)
|
||||
.onChange(of: mini) { newVal in
|
||||
if mini {
|
||||
appState.currentView = miniView ? .apps : .empty
|
||||
showPopover = false
|
||||
resizeWindowAuto(windowSettings: windowSettings)
|
||||
// showPopover = false
|
||||
// appState.currentView = miniView ? .apps : .empty
|
||||
} else {
|
||||
resizeWindowAuto(windowSettings: windowSettings)
|
||||
if appState.appInfo.appName.isEmpty {
|
||||
|
||||
@@ -9,11 +9,12 @@ import SwiftUI
|
||||
|
||||
struct SettingsView: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@Binding var showPopover: Bool
|
||||
|
||||
var body: some View {
|
||||
|
||||
TabView() {
|
||||
GeneralSettingsTab()
|
||||
GeneralSettingsTab(showPopover: $showPopover)
|
||||
.tabItem {
|
||||
Label(CurrentTabView.general.title, systemImage: "gear")
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ struct FilesView: View {
|
||||
@Binding var showPopover: Bool
|
||||
@Binding var search: String
|
||||
@State private var selectedOption = "Default"
|
||||
@State private var toggles: Bool = true
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .center) {
|
||||
@@ -88,49 +87,35 @@ struct FilesView: View {
|
||||
// .foregroundStyle(Color("AccentColor").opacity(0.7))
|
||||
.underline()
|
||||
}
|
||||
if appState.appInfo.webApp {
|
||||
HStack {
|
||||
Text("web")
|
||||
.font(.footnote)
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
.frame(minWidth: 30, minHeight: 15)
|
||||
.padding(2)
|
||||
.background(Color("mode").opacity(0.1))
|
||||
.clipShape(.capsule)
|
||||
Spacer()
|
||||
|
||||
HStack() {
|
||||
if appState.appInfo.webApp {
|
||||
HStack {
|
||||
Text("web")
|
||||
.font(.footnote)
|
||||
.foregroundStyle(Color("mode").opacity(0.5))
|
||||
.frame(minWidth: 30, minHeight: 15)
|
||||
.padding(2)
|
||||
.background(Color("mode").opacity(0.1))
|
||||
.clipShape(.capsule)
|
||||
Spacer()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if appState.appInfo.appName.count < 5 {
|
||||
HStack(alignment: .center) {
|
||||
Image(systemName: "exclamationmark.triangle.fill")
|
||||
.foregroundStyle(.red)
|
||||
.popover(isPresented: $showPop, arrowEdge: .top) {
|
||||
VStack() {
|
||||
Text("Pearcleaner searches for files via a combination of bundle id and app name.\n**\(appState.appInfo.appName)** has a common or short app name so there might be unrelated files found.\nPlease check the list thoroughly before uninstalling.")
|
||||
.padding()
|
||||
.font(.title2)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Text("Warning")
|
||||
.foregroundStyle(Color.red)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding(.top)
|
||||
|
||||
.onTapGesture {
|
||||
showPop = true
|
||||
if appState.appInfo.appName.count < 5 {
|
||||
WarningPopoverView(label: "Caution",
|
||||
bodyText: "Pearcleaner searches for files via a combination of bundle id and app name.\n\(appState.appInfo.appName) has a common or short app name so there might be unrelated files found.\nPlease check the list thoroughly before uninstalling.",
|
||||
isPresented: $showPop)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 5)
|
||||
|
||||
|
||||
|
||||
}
|
||||
.padding(20)
|
||||
}
|
||||
// .padding(.horizontal)
|
||||
// .padding(.bottom)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
// .strokeBorder(Color("AccentColor"), lineWidth: 0.5)
|
||||
@@ -140,34 +125,15 @@ struct FilesView: View {
|
||||
// .strokeBorder(Color("AccentColor").opacity(colorScheme == .dark ? 0.1 : 0.1), lineWidth: 1)
|
||||
// )
|
||||
)
|
||||
|
||||
|
||||
HStack(alignment: .center) {
|
||||
Spacer()
|
||||
|
||||
Text("\(toggles ? "Selected: All" : "Selected: None")").font(.subheadline)
|
||||
Toggle("", isOn: $toggles)
|
||||
.onChange(of: toggles) { value in
|
||||
if value {
|
||||
updateOnMain {
|
||||
appState.selectedItems = Set(appState.appInfo.files)
|
||||
}
|
||||
} else {
|
||||
updateOnMain {
|
||||
appState.selectedItems.removeAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.top)
|
||||
.padding(.bottom)
|
||||
|
||||
ScrollView() {
|
||||
VStack {
|
||||
let sortedFilesSize = appState.appInfo.files.sorted(by: { appState.appInfo.fileSize[$0, default: 0] > appState.appInfo.fileSize[$1, default: 0] })
|
||||
|
||||
// let sortedFilesAlpha = appState.appInfo.files.sorted(by: { $0.lastPathComponent < $1.lastPathComponent })
|
||||
let sortedFilesAlpha = appState.appInfo.files
|
||||
|
||||
let sort = selectedOption == "Default" ? appState.appInfo.files : sortedFilesSize
|
||||
let sort = selectedOption == "Default" ? sortedFilesAlpha : sortedFilesSize
|
||||
|
||||
ForEach(sort, id: \.self) { path in
|
||||
if let fileSize = appState.appInfo.fileSize[path], let fileIcon = appState.appInfo.fileIcon[path] {
|
||||
@@ -195,20 +161,35 @@ struct FilesView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.padding([.bottom])
|
||||
// .background(
|
||||
// RoundedRectangle(cornerRadius: 8)
|
||||
// .fill(Color("mode").opacity(colorScheme == .dark ? 0.05 : 0.05))
|
||||
// )
|
||||
|
||||
HStack() {
|
||||
Picker(selection: $selectedOption, label: Text("Sort")) {
|
||||
Text("Default").tag("Default")
|
||||
Text("Size").tag("Size")
|
||||
|
||||
Picker("", selection: Binding(
|
||||
get: { appState.selectedItems.count == appState.appInfo.files.count ? true : false },
|
||||
set: { newValue in
|
||||
updateOnMain {
|
||||
appState.selectedItems = newValue ? Set(appState.appInfo.files) : []
|
||||
}
|
||||
}
|
||||
)) {
|
||||
Text("").tag(true)
|
||||
Text("").tag(false)
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
.frame(width: 150)
|
||||
.frame(width: 100)
|
||||
.offset(x: -8)
|
||||
.help("Item Selection")
|
||||
|
||||
Spacer()
|
||||
|
||||
if mini {
|
||||
|
||||
Button("Close") {
|
||||
updateOnMain {
|
||||
appState.appInfo = AppInfo.empty
|
||||
@@ -217,7 +198,8 @@ struct FilesView: View {
|
||||
showPopover = false
|
||||
}
|
||||
}
|
||||
// .buttonStyle(FilesViewActionButton(action: .close))
|
||||
.buttonStyle(NavButtonBottomBarStyle(image: "x.circle.fill", help: "Close"))
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -274,10 +256,20 @@ struct FilesView: View {
|
||||
}
|
||||
|
||||
}
|
||||
.buttonStyle(NavButtonBottomBarStyle(image: "trash.fill", help: "Uninstall"))
|
||||
.disabled(appState.selectedItems.isEmpty)
|
||||
// .buttonStyle(FilesViewActionButton(action: .uninstall))
|
||||
|
||||
Spacer()
|
||||
|
||||
Picker("", selection: $selectedOption) {
|
||||
Text("").tag("Default")
|
||||
Text("").tag("Size")
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
.frame(width: 100)
|
||||
.help("Sorting Selection")
|
||||
}
|
||||
// .padding(.top)
|
||||
.padding(.top)
|
||||
|
||||
}
|
||||
.transition(.opacity)
|
||||
@@ -323,25 +315,8 @@ struct FileDetailsItem: View {
|
||||
self.appState.selectedItems.remove(self.path)
|
||||
}
|
||||
}
|
||||
// get: { self.appState.selectedItems.contains(self.path) },
|
||||
// set: { isChecked in
|
||||
// if isChecked {
|
||||
// self.appState.selectedItems.insert(self.path)
|
||||
// if self.path == appState.appInfo.path {
|
||||
// self.appState.appInfo.fileSize.keys.forEach {
|
||||
// self.appState.selectedItems.insert($0)
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// self.appState.selectedItems.remove(self.path)
|
||||
// if self.path == appState.appInfo.path {
|
||||
// self.appState.selectedItems.forEach {
|
||||
// self.appState.selectedItems.remove($0)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
))
|
||||
|
||||
.disabled(self.path.path.contains(".Trash"))
|
||||
|
||||
if let appIcon = icon {
|
||||
|
||||
@@ -59,7 +59,7 @@ struct MiniMode: View {
|
||||
.fill(Color("pop"))
|
||||
.padding(-80)
|
||||
)
|
||||
.frame(width: 650, height: 500)
|
||||
.frame(width: 650, height: 550)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ struct TopBar: View {
|
||||
appState.appInfo = AppInfo.empty
|
||||
}
|
||||
}
|
||||
.buttonStyle(SimpleButtonStyle(icon: "house", help: "Home", color: Color("mode")))
|
||||
.buttonStyle(SimpleButtonStyle(icon: "plus.square.dashed", help: "Drop Target", color: Color("mode")))
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ struct TopBarMini: View {
|
||||
|
||||
Button("") {
|
||||
withAnimation(.easeInOut(duration: 0.5)) {
|
||||
showPopover = false
|
||||
updateOnMain {
|
||||
if appState.zombieFile.fileSize.keys.count == 0 {
|
||||
appState.currentView = .zombie
|
||||
|
||||
@@ -17,7 +17,7 @@ struct ZombieView: View {
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
@Binding var showPopover: Bool
|
||||
@Binding var search: String
|
||||
@State private var toggles: Bool = true
|
||||
@State private var selectedOption = "Default"
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .center) {
|
||||
@@ -87,43 +87,11 @@ struct ZombieView: View {
|
||||
// .foregroundStyle(Color("AccentColor").opacity(0.7))
|
||||
.underline()
|
||||
}
|
||||
HStack() {
|
||||
Image(systemName: "exclamationmark.triangle.fill")
|
||||
.foregroundStyle(.red)
|
||||
.popover(isPresented: $showPop, arrowEdge: .top) {
|
||||
VStack() {
|
||||
Text("Leftover file search is not 100% accurate as it doesn't have any app bundles to check against.\nThis searches for files/folders and excludes the ones that have overlap with your currently installed apps. \nMake sure to confirm files marked for removal are correct.")
|
||||
.padding()
|
||||
.font(.title2)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Text("Warning")
|
||||
.foregroundStyle(Color.red)
|
||||
|
||||
Spacer()
|
||||
Toggle("\(toggles ? "Selected: All" : "Selected: None")", isOn: $toggles)
|
||||
.controlSize(.small)
|
||||
// .toggleStyle(.switch)
|
||||
.onChange(of: toggles) { value in
|
||||
if value {
|
||||
updateOnMain {
|
||||
appState.selectedZombieItems = Set(appState.zombieFile.fileSize.keys)
|
||||
}
|
||||
} else {
|
||||
updateOnMain {
|
||||
appState.selectedZombieItems.removeAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.top)
|
||||
.onTapGesture {
|
||||
showPop = true
|
||||
}
|
||||
|
||||
|
||||
WarningPopoverView(label: "Caution - Read",
|
||||
bodyText: "Leftover file search is not 100% accurate as it doesn't have any app bundles to check against.\nThis searches for files/folders and excludes the ones that have overlap with your currently installed apps. \nMake sure to confirm files marked for removal are correct.",
|
||||
isPresented: $showPop)
|
||||
.padding(.vertical, 5)
|
||||
|
||||
|
||||
}
|
||||
@@ -144,7 +112,14 @@ struct ZombieView: View {
|
||||
|
||||
ScrollView() {
|
||||
LazyVStack {
|
||||
ForEach(appState.zombieFile.fileSize.keys.sorted(by: { $0.lastPathComponent < $1.lastPathComponent }), id: \.self) { file in
|
||||
let sortedFilesSize = appState.zombieFile.fileSize.keys.sorted(by: { appState.zombieFile.fileSize[$0, default: 0] > appState.zombieFile.fileSize[$1, default: 0] })
|
||||
|
||||
|
||||
let sortedFilesAlpha = appState.zombieFile.fileSize.keys.sorted(by: { $0.lastPathComponent < $1.lastPathComponent })
|
||||
|
||||
let sort = selectedOption == "Default" ? sortedFilesAlpha : sortedFilesSize
|
||||
|
||||
ForEach(sort, id: \.self) { file in
|
||||
if let fileSize = appState.zombieFile.fileSize[file], let fileIcon = appState.zombieFile.fileIcon[file] {
|
||||
let iconImage = fileIcon.map(Image.init(nsImage:))
|
||||
|
||||
@@ -162,6 +137,23 @@ struct ZombieView: View {
|
||||
.padding()
|
||||
|
||||
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) : []
|
||||
}
|
||||
}
|
||||
)) {
|
||||
Text("").tag(true)
|
||||
Text("").tag(false)
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
.frame(width: 100)
|
||||
.offset(x: -8)
|
||||
.help("Item Selection")
|
||||
|
||||
Spacer()
|
||||
|
||||
if mini {
|
||||
@@ -173,6 +165,8 @@ struct ZombieView: View {
|
||||
showPopover = false
|
||||
}
|
||||
}
|
||||
.buttonStyle(NavButtonBottomBarStyle(image: "x.circle.fill", help: "Close"))
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -183,6 +177,8 @@ struct ZombieView: View {
|
||||
reversePathsSearch(appState: appState, locations: locations)
|
||||
}
|
||||
}
|
||||
.buttonStyle(NavButtonBottomBarStyle(image: "arrow.counterclockwise.circle.fill", help: "Rescan files"))
|
||||
|
||||
|
||||
Button("Remove") {
|
||||
Task {
|
||||
@@ -217,7 +213,18 @@ struct ZombieView: View {
|
||||
}
|
||||
|
||||
}
|
||||
.buttonStyle(NavButtonBottomBarStyle(image: "trash.fill", help: "Remove"))
|
||||
.disabled(appState.selectedZombieItems.isEmpty)
|
||||
|
||||
Spacer()
|
||||
|
||||
Picker("", selection: $selectedOption) {
|
||||
Text("").tag("Default")
|
||||
Text("").tag("Size")
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
.frame(width: 100)
|
||||
.help("Sorting Selection")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user