This commit is contained in:
Alin
2024-02-14 18:09:43 -07:00
parent fd583b6676
commit 17a81343aa
15 changed files with 423 additions and 231 deletions
+4 -4
View File
@@ -543,7 +543,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 = 17; CURRENT_PROJECT_VERSION = 18;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
@@ -561,7 +561,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 2.6; MARKETING_VERSION = 2.7;
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;
@@ -578,7 +578,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 = 17; CURRENT_PROJECT_VERSION = 18;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
@@ -596,7 +596,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 2.6; MARKETING_VERSION = 2.7;
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;
+29 -29
View File
@@ -45,35 +45,35 @@ class AppState: ObservableObject
} }
class ProgressManager: ObservableObject { //class ProgressManager: ObservableObject {
@Published var progress: Double = 0.0 // @Published var progress: Double = 0.0
@Published var total: Double = 0.0 // @Published var total: Double = 0.0
@Published var status: String = "Ready" // @Published var status: String = "Ready"
//
func setTotal(_ total: Double) { // func setTotal(_ total: Double) {
DispatchQueue.main.async { // DispatchQueue.main.async {
self.total = total // self.total = total
} // }
} // }
//
func updateProgress() { // func updateProgress() {
DispatchQueue.main.async { // DispatchQueue.main.async {
self.progress = min(max(0.0, self.progress + 1.0), Double(self.total)) // self.progress = min(max(0.0, self.progress + 1.0), Double(self.total))
} // }
} // }
//
func updateStatus(status: String) { // func updateStatus(status: String) {
DispatchQueue.main.async { // DispatchQueue.main.async {
self.status = status // self.status = status
} // }
} // }
//
func resetProgress() { // func resetProgress() {
DispatchQueue.main.async { // DispatchQueue.main.async {
self.progress = 0.0 // self.progress = 0.0
} // }
} // }
} //}
+2 -5
View File
@@ -72,13 +72,10 @@ class Locations: ObservableObject {
]) ])
// Append Application Support subfolders for deeper search // Append Application Support subfolders for deeper search
do { let subfolders = listAppSupportDirectories()
let subfolders = try appSupSubfolders()
for folder in subfolders { for folder in subfolders {
self.apps.paths.append("\(home)/Library/Application Support/\(folder)") self.apps.paths.append("\(home)/Library/Application Support/\(folder)")
} // writeLog(string: "Adding subfolder: \(home)/Library/Application Support/\(folder)")
} catch {
print("Error getting subfolders: \(error)")
} }
// self.widgets = Category(name: "Widgets", paths: [ // self.widgets = Category(name: "Widgets", paths: [
+50 -12
View File
@@ -269,21 +269,53 @@ func darwinCT() -> (String, String) {
// Add subfolders of ~/Library/Application Support/ to locations for deeper search // Add subfolders of ~/Library/Application Support/ to locations for deeper search
func appSupSubfolders() throws -> [String] { //func appSupSubfolders2() throws -> [String] {
let fileManager = FileManager.default // let fileManager = FileManager.default
let appSup = "\(home)/Library/Application Support/" // let appSup = "\(home)/Library/Application Support/"
let subfolders = try fileManager.contentsOfDirectory(atPath: appSup) // let subfolders = try fileManager.contentsOfDirectory(atPath: appSup)
let exclusionRegex = try NSRegularExpression(pattern: "\\bcom\\.apple\\b", options: []) // let exclusionRegex = try NSRegularExpression(pattern: "\\bcom\\.apple\\b", options: [])
let exclusions = ["MobileSync", ".DS_Store", "Xcode", "SyncServices", "networkserviceproxy", "DiskImages", "CallHistoryTransactions", "App Store", "CloudDocs", "icdd", "iCloud", "Instruments", "AddressBook", "FaceTime", "AskPermission", "CallHistoryDB"] // let exclusions = ["MobileSync", ".DS_Store", "Xcode", "SyncServices", "networkserviceproxy", "DiskImages", "CallHistoryTransactions", "App Store", "CloudDocs", "icdd", "iCloud", "Instruments", "AddressBook", "FaceTime", "AskPermission", "CallHistoryDB"]
//
// let allowedFolders = subfolders.filter { folder in
// let range = NSRange(location: 0, length: folder.utf16.count)
// return exclusionRegex.firstMatch(in: folder, options: [], range: range) == nil && !exclusions.contains(folder)
// }
//
// return allowedFolders
//}
let allowedFolders = subfolders.filter { folder in
let range = NSRange(location: 0, length: folder.utf16.count) func listAppSupportDirectories() -> [String] {
return exclusionRegex.firstMatch(in: folder, options: [], range: range) == nil && !exclusions.contains(folder) let home = FileManager.default.homeDirectoryForCurrentUser
let appSupportLocation = home.appendingPathComponent("Library/Application Support/")
let exclusions = ["MobileSync", ".DS_Store", "Xcode", "SyncServices", "networkserviceproxy", "DiskImages", "CallHistoryTransactions", "App Store", "CloudDocs", "icdd", "iCloud", "Instruments", "AddressBook", "FaceTime", "AskPermission", "CallHistoryDB"]
let exclusionRegex = try! NSRegularExpression(pattern: "\\bcom\\.apple\\b", options: [])
do {
let fileManager = FileManager.default
let directoryContents = try fileManager.contentsOfDirectory(at: appSupportLocation, includingPropertiesForKeys: [.isDirectoryKey], options: .skipsHiddenFiles)
let filteredDirectories: [String] = directoryContents.compactMap { url in
var isDirectory: ObjCBool = false
guard fileManager.fileExists(atPath: url.path, isDirectory: &isDirectory) else {
return nil
} }
return allowedFolders let directoryName = url.lastPathComponent
}
// Check for exclusions using regex and provided list
let excludeByRegex = exclusionRegex.firstMatch(in: directoryName, options: [], range: NSRange(location: 0, length: directoryName.utf16.count)) != nil
let excludeByList = exclusions.contains(directoryName)
return isDirectory.boolValue && !excludeByRegex && !excludeByList ? directoryName : nil
}
return filteredDirectories
} catch {
print("Error listing AppSupport directories: \(error.localizedDescription)")
return []
}
}
@@ -360,7 +392,7 @@ func findPathsForApp(appState: AppState, locations: Locations) {
if collection.contains(itemURL) { if collection.contains(itemURL) {
break continue
} }
// Catch web app plist files // Catch web app plist files
if appInfo.webApp { if appInfo.webApp {
@@ -391,6 +423,7 @@ func findPathsForApp(appState: AppState, locations: Locations) {
} }
} catch { } catch {
// writeLog(string: "Error processing location: \(location)\n\(error)")
print("Error processing location:", location, error) print("Error processing location:", location, error)
continue continue
} }
@@ -406,11 +439,16 @@ func findPathsForApp(appState: AppState, locations: Locations) {
collection.append(contentsOf: groupContainers) collection.append(contentsOf: groupContainers)
let sortedCollection = collection.sorted(by: { $0.absoluteString < $1.absoluteString }) let sortedCollection = collection.sorted(by: { $0.absoluteString < $1.absoluteString })
// writeLog(string: "\n\nsortedCollection: \(sortedCollection)")
// Save to appState // Save to appState
dispatchGroup.notify(queue: .main) { dispatchGroup.notify(queue: .main) {
updateOnMain { updateOnMain {
appState.paths = sortedCollection appState.paths = sortedCollection
appState.selectedItems = Set(sortedCollection) appState.selectedItems = Set(sortedCollection)
// writeLog(string: "\n\nappStatePaths: \(appState.paths)")
// writeLog(string: "\n\nappStateSelected: \(appState.selectedItems)")
} }
} }
+24 -21
View File
@@ -30,7 +30,7 @@ struct SimpleButtonStyle: ButtonStyle {
.frame(width: 20) .frame(width: 20)
.foregroundColor(hovered ? color : color.opacity(0.5)) .foregroundColor(hovered ? color : color.opacity(0.5))
} }
.padding(8) .padding(5)
// .background { // .background {
// if hovered && !(shield ?? false) { // if hovered && !(shield ?? false) {
//// Circle() //// Circle()
@@ -173,6 +173,7 @@ struct AnimatedSearchStyle: TextFieldStyle {
struct SimpleSearchStyle: TextFieldStyle { struct SimpleSearchStyle: TextFieldStyle {
@State private var isHovered = false @State private var isHovered = false
@FocusState private var isFocused: Bool
@State var icon: Image? @State var icon: Image?
@State var trash: Bool = false @State var trash: Bool = false
@Binding var text: String @Binding var text: String
@@ -195,25 +196,25 @@ struct SimpleSearchStyle: TextFieldStyle {
.font(.title3) .font(.title3)
.textFieldStyle(PlainTextFieldStyle()) .textFieldStyle(PlainTextFieldStyle())
Image(systemName: "arrow.triangle.2.circlepath") // Image(systemName: "arrow.triangle.2.circlepath")
.resizable() // .resizable()
.aspectRatio(contentMode: .fit) // .aspectRatio(contentMode: .fit)
.frame(width: 15, height: 15) // .frame(width: 15, height: 15)
.padding(.trailing, 5) // .padding(.trailing, 5)
.foregroundStyle(isHovered ? Color("mode").opacity(0.8) : Color("mode").opacity(0.5)) // .foregroundStyle(isHovered ? Color("mode").opacity(0.8) : Color("mode").opacity(0.5))
.onTapGesture { // .onTapGesture {
withAnimation { // withAnimation {
// Refresh Apps list // // Refresh Apps list
appState.reload.toggle() // appState.reload.toggle()
let sortedApps = getSortedApps() // let sortedApps = getSortedApps()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { // DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
appState.sortedApps.userApps = sortedApps.userApps // appState.sortedApps.userApps = sortedApps.userApps
appState.sortedApps.systemApps = sortedApps.systemApps // appState.sortedApps.systemApps = sortedApps.systemApps
appState.reload.toggle() // appState.reload.toggle()
} // }
} // }
//
} // }
if trash && text != "" { if trash && text != "" {
Image(systemName: "xmark") Image(systemName: "xmark")
@@ -240,10 +241,12 @@ struct SimpleSearchStyle: TextFieldStyle {
} }
) )
.onHover { hovering in .onHover { hovering in
withAnimation(Animation.easeIn(duration: 0.15)) { withAnimation(Animation.easeInOut(duration: 0.15)) {
self.isHovered = hovering self.isHovered = hovering
self.isFocused = hovering
} }
} }
.focused($isFocused)
} }
} }
+7
View File
@@ -32,6 +32,13 @@ func resizeWindow(width: CGFloat, height: CGFloat) {
} }
} }
func resizeWindowAuto(windowSettings: WindowSettings) {
if let window = NSApplication.shared.windows.first {
let newSize = NSSize(width: windowSettings.loadWindowSettings().width, height: windowSettings.loadWindowSettings().height)
window.setContentSize(newSize)
}
}
// Check FDA // Check FDA
func checkFullDiskAccessForApp() -> Bool { func checkFullDiskAccessForApp() -> Bool {
+9 -5
View File
@@ -10,22 +10,26 @@ import SwiftUI
class WindowSettings { class WindowSettings {
private let windowWidthKey = "windowWidthKey" private let windowWidthKey = "windowWidthKey"
private let windowHeightKey = "windowHeightKey" private let windowHeightKey = "windowHeightKey"
private let windowWidthKeyMini = "windowWidthKeyMini"
private let windowHeightKeyMini = "windowHeightKeyMini"
private let windowXKey = "windowXKey" private let windowXKey = "windowXKey"
private let windowYKey = "windowYKey" private let windowYKey = "windowYKey"
@AppStorage("settings.general.mini") private var mini: Bool = false
func saveWindowSettings(frame: NSRect) { func saveWindowSettings(frame: NSRect) {
UserDefaults.standard.set(Float(frame.size.width), forKey: windowWidthKey)
UserDefaults.standard.set(Float(frame.size.height), forKey: windowHeightKey) UserDefaults.standard.set(Float(frame.size.width), forKey: mini ? windowWidthKeyMini : windowWidthKey)
UserDefaults.standard.set(Float(frame.size.height), forKey: mini ? windowHeightKeyMini : windowHeightKey)
UserDefaults.standard.set(Float(frame.origin.x), forKey: windowXKey) UserDefaults.standard.set(Float(frame.origin.x), forKey: windowXKey)
UserDefaults.standard.set(Float(frame.origin.y), forKey: windowYKey) UserDefaults.standard.set(Float(frame.origin.y), forKey: windowYKey)
} }
func loadWindowSettings() -> NSRect { func loadWindowSettings() -> NSRect {
let width = CGFloat(UserDefaults.standard.float(forKey: windowWidthKey))
let height = CGFloat(UserDefaults.standard.float(forKey: windowHeightKey)) let width = CGFloat(UserDefaults.standard.float(forKey: mini ? windowWidthKeyMini : windowWidthKey))
let height = CGFloat(UserDefaults.standard.float(forKey: mini ? windowHeightKeyMini : windowHeightKey))
let x = CGFloat(UserDefaults.standard.float(forKey: windowXKey)) let x = CGFloat(UserDefaults.standard.float(forKey: windowXKey))
let y = CGFloat(UserDefaults.standard.float(forKey: windowYKey)) let y = CGFloat(UserDefaults.standard.float(forKey: windowYKey))
return NSRect(x: x, y: y, width: width, height: height) return NSRect(x: x, y: y, width: width, height: height)
} }
} }
+16
View File
@@ -20,6 +20,7 @@ struct PearcleanerApp: App {
@AppStorage("settings.permissions.hasLaunched") private var hasLaunched: Bool = false @AppStorage("settings.permissions.hasLaunched") private var hasLaunched: Bool = false
@AppStorage("displayMode") var displayMode: DisplayMode = .system @AppStorage("displayMode") var displayMode: DisplayMode = .system
@AppStorage("settings.general.mini") private var mini: Bool = false @AppStorage("settings.general.mini") private var mini: Bool = false
@AppStorage("settings.general.miniview") private var miniView: Bool = true
@State private var search = "" @State private var search = ""
@State private var showPopover: Bool = false @State private var showPopover: Bool = false
@@ -65,6 +66,13 @@ struct PearcleanerApp: App {
} }
} }
.onAppear { .onAppear {
if miniView {
appState.currentView = .apps
} else {
appState.currentView = .empty
}
// Disable tabbing // Disable tabbing
NSWindow.allowsAutomaticWindowTabbing = false NSWindow.allowsAutomaticWindowTabbing = false
@@ -80,6 +88,8 @@ struct PearcleanerApp: App {
// Load progressbar total // Load progressbar total
// appState.progressManager.total = Double(locations.apps.paths.count) // appState.progressManager.total = Double(locations.apps.paths.count)
Task { Task {
#if !DEBUG #if !DEBUG
@@ -140,5 +150,11 @@ class AppDelegate: NSObject, NSApplicationDelegate {
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true return true
} }
// func applicationDidFinishLaunching(_ notification: Notification, win: WindowSettings) {
// let frame = win.loadWindowSettings()
// NSApplication.shared.windows.first?.setFrame(frame, display: true)
// }
} }
+51 -12
View File
@@ -10,10 +10,13 @@ import SwiftUI
struct GeneralSettingsTab: View { struct GeneralSettingsTab: View {
@EnvironmentObject var appState: AppState @EnvironmentObject var appState: AppState
@State private var windowSettings = WindowSettings()
@AppStorage("settings.general.glass") private var glass: Bool = true @AppStorage("settings.general.glass") private var glass: Bool = true
@AppStorage("settings.general.mini") private var mini: Bool = false @AppStorage("settings.general.mini") private var mini: Bool = false
@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.sidebarWidth") private var sidebarWidth: Double = 280
@AppStorage("displayMode") var displayMode: DisplayMode = .system @AppStorage("displayMode") var displayMode: DisplayMode = .system
@State private var selectedTheme = "Auto" @State private var selectedTheme = "Auto"
private let themes = ["Auto", "Dark", "Light"] private let themes = ["Auto", "Dark", "Light"]
@@ -39,6 +42,25 @@ struct GeneralSettingsTab: View {
.fill(Color("mode").opacity(0.05)) .fill(Color("mode").opacity(0.05))
) )
HStack {
VStack(alignment: .leading, spacing: 5) {
Text("Sidebar").font(.title2)
Text("Adjust sidebar width")
.font(.footnote)
.foregroundStyle(.gray)
}
Spacer()
Slider(value: $sidebarWidth, in: 200...400) {
Text("\(Int(sidebarWidth))")
}
.padding(.horizontal)
}
.padding()
.background(
RoundedRectangle(cornerRadius: 8)
.fill(Color("mode").opacity(0.05))
)
HStack { HStack {
VStack(alignment: .leading, spacing: 5) { VStack(alignment: .leading, spacing: 5) {
Text("Appearance").font(.title2) Text("Appearance").font(.title2)
@@ -73,12 +95,7 @@ struct GeneralSettingsTab: View {
break break
} }
} }
// Toggle(isOn: $isDark, label: {
// })
// .toggleStyle(.switch)
// .onChange(of: isDark) { newValue in
// displayMode.colorScheme = newValue ? .dark : .light
// }
} }
.padding() .padding()
.background( .background(
@@ -99,10 +116,12 @@ struct GeneralSettingsTab: View {
.toggleStyle(.switch) .toggleStyle(.switch)
.onChange(of: mini) { newVal in .onChange(of: mini) { newVal in
if mini { if mini {
resizeWindow(width: 300, height: 300) resizeWindowAuto(windowSettings: windowSettings)
appState.currentView = .empty // resizeWindow(width: 300, height: 300)
appState.currentView = miniView ? .apps : .empty
} else { } else {
resizeWindow(width: 700, height: 500) resizeWindowAuto(windowSettings: windowSettings)
// resizeWindow(width: 700, height: 500)
if appState.appInfo.appName.isEmpty { if appState.appInfo.appName.isEmpty {
appState.currentView = .empty appState.currentView = .empty
} else { } else {
@@ -118,11 +137,31 @@ struct GeneralSettingsTab: View {
) )
HStack {
VStack(alignment: .leading, spacing: 5) {
Text("Mini - Default View").font(.title2)
Text("Toggles drop target or apps list view on launch")
.font(.footnote)
.foregroundStyle(.gray)
}
Spacer()
Toggle(isOn: $miniView, label: {
})
.toggleStyle(.switch)
.onChange(of: miniView) { newVal in
appState.currentView = newVal ? .apps : .empty
}
}
.padding()
.background(
RoundedRectangle(cornerRadius: 8)
.fill(Color("mode").opacity(0.05))
)
HStack { HStack {
VStack(alignment: .leading, spacing: 5) { VStack(alignment: .leading, spacing: 5) {
Text("Mini - Files View").font(.title2) Text("Mini - Popover").font(.title2)
Text("Keeps file search view on top in mini mode") Text("Keeps file search popover on top in mini mode")
.font(.footnote) .font(.footnote)
.foregroundStyle(.gray) .foregroundStyle(.gray)
} }
@@ -145,7 +184,7 @@ struct GeneralSettingsTab: View {
} }
.padding(20) .padding(20)
.frame(width: 400, height: 350) .frame(width: 400, height: 500)
} }
+34 -25
View File
@@ -42,27 +42,36 @@ struct AppListItems: View {
.truncationMode(.tail) .truncationMode(.tail)
.padding(.horizontal, 5) .padding(.horizontal, 5)
} }
Spacer()
if appInfo.webApp { if appInfo.webApp {
Text("web") Text("web")
.font(.footnote) .font(.footnote)
.foregroundStyle(Color("mode").opacity(0.5)) .foregroundStyle(Color("mode").opacity(0.3))
.frame(minWidth: 30, minHeight: 15) .frame(minWidth: 30, minHeight: 15)
.padding(2) .padding(2)
.background(Color("mode").opacity(0.1)) .background(
.clipShape(.capsule) Capsule().strokeBorder(Color("mode").opacity(0.3), lineWidth: 1)
)
// .background(Color("mode").opacity(0.1))
// .clipShape(.capsule)
} }
if appInfo.wrapped { if appInfo.wrapped {
Text("iOS") Text("iOS")
.font(.footnote) .font(.footnote)
.foregroundStyle(Color("mode").opacity(0.5)) .foregroundStyle(Color("mode").opacity(0.3))
.frame(minWidth: 30, minHeight: 15) .frame(minWidth: 30, minHeight: 15)
.padding(2) .padding(2)
.background(Color("mode").opacity(0.1)) .background(
.clipShape(.capsule) Capsule().strokeBorder(Color("mode").opacity(0.3), lineWidth: 1)
)
// .background(Color("mode").opacity(0.1))
// .clipShape(.capsule)
} }
Spacer()
Text(appInfo.appVersion) Text(appInfo.appVersion)
.font(.footnote) .font(.footnote)
.foregroundStyle(Color("mode").opacity(0.5)) .foregroundStyle(Color("mode").opacity(0.5))
@@ -105,24 +114,24 @@ struct AppListItems: View {
} }
} }
.popover(isPresented: Binding( // .popover(isPresented: Binding(
get: { showPopover && appState.appInfo.id == appInfo.id}, // get: { showPopover && appState.appInfo.id == appInfo.id},
set: { _ in showPopover = false} // set: { _ in showPopover = false}
), attachmentAnchor: .rect(.rect(CGRect(x: windowSettings.loadWindowSettings().width - 17, y: 15, width: 0, height: 0))), arrowEdge: .trailing) { // ), attachmentAnchor: .rect(.rect(CGRect(x: windowSettings.loadWindowSettings().width - 17, y: 15, width: 0, height: 0))), arrowEdge: .trailing) {
// .popover(isPresented: $showPopover, arrowEdge: .trailing) { // .popover(isPresented: $showPopover, arrowEdge: .trailing) {
VStack { // VStack {
FilesView(showPopover: $showPopover, search: $search) // FilesView(showPopover: $showPopover, search: $search)
.id(appState.appInfo.id) // .id(appState.appInfo.id)
} // }
.interactiveDismissDisabled(popoverStay) // .interactiveDismissDisabled(popoverStay)
.background( // .background(
Rectangle() // Rectangle()
.fill(Color("pop")) // .fill(Color("pop"))
.padding(-80) // .padding(-80)
) // )
.frame(minWidth: 650, minHeight: 500) // .frame(minWidth: 650, minHeight: 500)
//
} // }
} }
} }
+46 -7
View File
@@ -11,6 +11,7 @@ import SwiftUI
struct AppListView: View { struct AppListView: View {
@EnvironmentObject var appState: AppState @EnvironmentObject var appState: AppState
@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
@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
@@ -47,14 +48,15 @@ struct AppListView: View {
ProgressView("Refreshing applications") ProgressView("Refreshing applications")
Spacer() Spacer()
} }
.frame(width: 250) .frame(width: sidebarWidth)
.padding(.vertical) .padding(.vertical)
} else { } else {
VStack(alignment: .center) { VStack(alignment: .center) {
VStack(alignment: .center, spacing: 20) { VStack(alignment: .center, spacing: 20) {
HStack { HStack {
SearchBar(search: $search) SearchBarMiniBottom(search: $search)
// SearchBar(search: $search)
// Button("") { // Button("") {
// withAnimation(.easeInOut(duration: 0.5)) { // withAnimation(.easeInOut(duration: 0.5)) {
@@ -72,13 +74,13 @@ struct AppListView: View {
// .buttonStyle(SimpleButtonStyle(icon: "arrow.triangle.2.circlepath", help: "Refresh app list", color: Color("mode"))) // .buttonStyle(SimpleButtonStyle(icon: "arrow.triangle.2.circlepath", help: "Refresh app list", color: Color("mode")))
} }
} }
.padding(.horizontal) // .padding(.horizontal)
.padding(.top, 20) .padding(.top, 20)
.padding(.bottom) .padding(.bottom)
ScrollView { ScrollView {
VStack(alignment: .leading) { LazyVStack(alignment: .leading, pinnedViews: [.sectionHeaders]) {
if filteredUserApps.count > 0 { if filteredUserApps.count > 0 {
VStack { VStack {
@@ -113,7 +115,7 @@ struct AppListView: View {
.scrollIndicators(.never) .scrollIndicators(.never)
} }
.frame(width: 250) .frame(width: sidebarWidth)
.padding(.vertical) .padding(.vertical)
} }
@@ -130,7 +132,7 @@ struct AppListView: View {
// Details View // Details View
VStack(spacing: 0) { VStack(spacing: 0) {
if appState.currentView == .empty { if appState.currentView == .empty || appState.currentView == .apps {
TopBar() TopBar()
AppDetailsEmptyView(showPopover: $showPopover) AppDetailsEmptyView(showPopover: $showPopover)
} else if appState.currentView == .files { } else if appState.currentView == .files {
@@ -236,11 +238,38 @@ struct SearchBar: View {
struct Header: View { struct Header: View {
let title: String let title: String
let count: Int let count: Int
@State private var hovered = false
@EnvironmentObject var appState: AppState
var body: some View { var body: some View {
HStack { HStack {
Text(title).opacity(0.5) Text(title).opacity(0.5)
Spacer()
// Spacer()
HStack {
if hovered {
withAnimation() {
Image(systemName: "arrow.circlepath")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 19, height: 19)
.onTapGesture {
withAnimation {
// Refresh Apps list
appState.reload.toggle()
let sortedApps = getSortedApps()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
appState.sortedApps.userApps = sortedApps.userApps
appState.sortedApps.systemApps = sortedApps.systemApps
appState.reload.toggle()
}
}
}
.help("Refresh apps")
}
} else {
Text("\(count)") Text("\(count)")
.font(.system(size: 10)) .font(.system(size: 10))
.frame(minWidth: count > 99 ? 30 : 20, minHeight: 15) .frame(minWidth: count > 99 ? 30 : 20, minHeight: 15)
@@ -249,6 +278,16 @@ struct Header: View {
.clipShape(.capsule) .clipShape(.capsule)
// .clipShape(RoundedRectangle(cornerRadius: 6, style: .continuous)) // .clipShape(RoundedRectangle(cornerRadius: 6, style: .continuous))
} }
}
.onHover { hovering in
withAnimation() {
hovered = hovering
}
}
Spacer()
}
.padding(4) .padding(4)
} }
} }
+2 -15
View File
@@ -34,20 +34,7 @@ struct FilesView: View {
ProgressView() ProgressView()
.progressViewStyle(.linear) .progressViewStyle(.linear)
.frame(width: 400, height: 10) .frame(width: 400, height: 10)
// ProgressView("\(appState.progressManager.status)", value: appState.progressManager.progress, total: Double(appState.progressManager.total))
// .progressViewStyle(LinearProgressViewStyle(tint: .blue))
// .frame(width: 400, height: 10)
// .padding(.top)
// .onReceive(appState.progressManager.$progress) { newProgress in
// DispatchQueue.main.async {
// appState.objectWillChange.send()
// }
// }
// .onReceive(appState.progressManager.$status) { newStatus in
// DispatchQueue.main.async {
// appState.objectWillChange.send()
// }
// }
Spacer() Spacer()
} }
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
@@ -272,10 +259,10 @@ struct FilesView: View {
} }
if let appSize = totalSizeOnDisk(for: appState.paths) { if let appSize = totalSizeOnDisk(for: appState.paths) {
self.appSize = "\(appSize)" self.appSize = "\(appSize)"
self.showDetails = true
} else { } else {
print("Error calculating the total size on disk.") print("Error calculating the total size on disk.")
} }
self.showDetails = true
} }
} else { } else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
+45 -16
View File
@@ -39,24 +39,24 @@ struct MiniMode: View {
} }
// .padding(.leading, appState.sidebar ? 0 : 10) // .padding(.leading, appState.sidebar ? 0 : 10)
.transition(.move(edge: .leading)) .transition(.move(edge: .leading))
// .popover(isPresented: $showPopover, arrowEdge: .trailing) { .popover(isPresented: $showPopover, arrowEdge: .trailing) {
// VStack { VStack {
// FilesView(showPopover: $showPopover, search: $search) FilesView(showPopover: $showPopover, search: $search)
// .id(appState.appInfo.id) .id(appState.appInfo.id)
// } }
// .interactiveDismissDisabled(popoverStay) .interactiveDismissDisabled(popoverStay)
// .background( .background(
// Rectangle() Rectangle()
// .fill(Color("pop")) .fill(Color("pop"))
// .padding(-80) .padding(-80)
// ) )
// .frame(minWidth: 600, minHeight: 500) .frame(minWidth: 650, minHeight: 500)
//
// } }
} }
.frame(minWidth: 300, minHeight: 300) .frame(minWidth: 300, minHeight: 335)
.edgesIgnoringSafeArea(.all) .edgesIgnoringSafeArea(.all)
.background(glass ? GlassEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all) : nil) .background(glass ? GlassEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all) : nil)
@@ -185,11 +185,36 @@ struct MiniAppView: View {
} else { } else {
VStack(alignment: .center) { VStack(alignment: .center) {
// if appState.currentView == .apps {
// HStack(alignment: .center, spacing: 0) {
// Spacer()
//
// Button("") {
// withAnimation(.easeInOut(duration: 0.5)) {
// // updateOnMain {
// appState.currentView = .empty
// appState.appInfo = AppInfo.empty
// showPopover = false
// // }
// }
// }
// .buttonStyle(SimpleButtonStyle(icon: "arrow.backward.square", help: "Back to Drop Zone", color: Color("mode")))
// .padding(.leading, 10)
// .padding(.trailing, 0)
//
// SearchBarMiniBottom(search: $search)
//
// Spacer()
// }
// .padding(.top, 30)
// }
ScrollView { ScrollView {
VStack(alignment: .leading) { LazyVStack(alignment: .leading, pinnedViews: [.sectionHeaders]) {
if filteredUserApps.count > 0 { if filteredUserApps.count > 0 {
VStack { VStack {
Header(title: "User", count: filteredUserApps.count) Header(title: "User", count: filteredUserApps.count)
ForEach(filteredUserApps, id: \.self) { appInfo in ForEach(filteredUserApps, id: \.self) { appInfo in
@@ -203,6 +228,7 @@ struct MiniAppView: View {
} }
if filteredSystemApps.count > 0 { if filteredSystemApps.count > 0 {
VStack { VStack {
Header(title: "System", count: filteredSystemApps.count) Header(title: "System", count: filteredSystemApps.count)
ForEach(filteredSystemApps, id: \.self) { appInfo in ForEach(filteredSystemApps, id: \.self) { appInfo in
@@ -220,6 +246,9 @@ struct MiniAppView: View {
} }
.scrollIndicators(.never) .scrollIndicators(.never)
if appState.currentView == .apps {
SearchBarMiniBottom(search: $search)
}
} }
.padding(.bottom) .padding(.bottom)
} }
+1 -1
View File
@@ -37,7 +37,7 @@ struct TopBar: View {
Spacer() Spacer()
if appState.currentView != .empty { if appState.currentView != .empty || appState.currentView != .apps {
Button("") { Button("") {
withAnimation(.easeInOut(duration: 0.5)) { withAnimation(.easeInOut(duration: 0.5)) {
appState.currentView = .empty appState.currentView = .empty
+82 -58
View File
@@ -21,82 +21,93 @@ struct TopBarMini: View {
Spacer() Spacer()
if appState.currentView == .apps { // if appState.currentView == .apps {
// HStack { // Button("") {
// Spacer() // withAnimation(.easeInOut(duration: 0.5)) {
// // updateOnMain {
// appState.currentView = .empty
// appState.appInfo = AppInfo.empty
// showPopover = false
// // }
// }
// }
// .buttonStyle(SimpleButtonStyle(icon: "arrow.backward.square", help: "Back to Drop Zone", color: Color("mode")))
// } else
if appState.currentView == .empty {
Button("") {
withAnimation(.easeInOut(duration: 0.5)) {
// updateOnMain {
appState.currentView = .apps
// }
}
}
.buttonStyle(SimpleButtonStyle(icon: "list.dash", help: "Apps List", color: Color("mode")))
} else if appState.currentView == .files {
Button("") {
withAnimation(.easeInOut(duration: 0.5)) {
// updateOnMain {
appState.currentView = .empty
appState.appInfo = AppInfo.empty
// }
SearchBarMini(search: $search) }
}
.buttonStyle(SimpleButtonStyle(icon: "plus.square.dashed", help: "Drop Target", color: Color("mode")))
Button("") {
withAnimation(.easeInOut(duration: 0.5)) {
// updateOnMain {
appState.currentView = .apps
// }
}
}
.buttonStyle(SimpleButtonStyle(icon: "list.dash", help: "Apps List", color: Color("mode")))
}
if appState.currentView == .apps {
HStack {
Spacer()
// SearchBarMini(search: $search)
// .frame(width: 150) // .frame(width: 150)
// .offset(x: 20) // .offset(x: 20)
// .padding(.horizontal, 30) // .padding(.horizontal, 30)
// .padding(.top, 5) // .padding(.top, 5)
// Spacer() //////////////
// Button("") {
// withAnimation(.easeInOut(duration: 0.5)) {
// // Refresh Apps list
// reload.toggle()
// let sortedApps = getSortedApps()
// DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// appState.sortedApps.userApps = sortedApps.userApps
// appState.sortedApps.systemApps = sortedApps.systemApps
// reload.toggle()
// }
//
// }
// }
// .buttonStyle(SimpleButtonStyle(icon: "arrow.triangle.2.circlepath", help: "Refresh app list", color: Color("mode")))
// .padding(.leading, 5)
// }
}
if appState.currentView == .apps {
Button("") { Button("") {
withAnimation(.easeInOut(duration: 0.5)) { withAnimation(.easeInOut(duration: 0.5)) {
// updateOnMain { // updateOnMain {
appState.currentView = .empty appState.currentView = .empty
appState.appInfo = AppInfo.empty appState.appInfo = AppInfo.empty
showPopover = false showPopover = false
// } // }
} }
} }
.buttonStyle(SimpleButtonStyle(icon: "arrow.down.app", help: "Back to Drop Zone", color: Color("mode"))) .buttonStyle(SimpleButtonStyle(icon: "plus.square.dashed", help: "Drop Target", color: Color("mode")))
} else if appState.currentView == .empty {
Button("") {
withAnimation(.easeInOut(duration: 0.5)) {
// updateOnMain {
appState.currentView = .apps
// }
}
}
.buttonStyle(SimpleButtonStyle(icon: "list.triangle", help: "Apps List", color: Color("mode")))
} else if appState.currentView == .files {
Button("") {
withAnimation(.easeInOut(duration: 0.5)) {
// updateOnMain {
appState.currentView = .empty
appState.appInfo = AppInfo.empty
// }
} // Spacer()
}
.buttonStyle(SimpleButtonStyle(icon: "arrow.down.app", help: "Back to Drop Zone", color: Color("mode"))) // Button("") {
Button("") { // withAnimation {
withAnimation(.easeInOut(duration: 0.5)) { // // Refresh Apps list
// updateOnMain { // appState.reload.toggle()
appState.currentView = .apps // let sortedApps = getSortedApps()
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
// appState.sortedApps.userApps = sortedApps.userApps
// appState.sortedApps.systemApps = sortedApps.systemApps
// appState.reload.toggle()
// } // }
// }
// }
// .buttonStyle(SimpleButtonStyle(icon: "arrow.circlepath", help: "Refresh app list", color: Color("mode")))
// .padding(.leading, 5)
} }
} }
.buttonStyle(SimpleButtonStyle(icon: "list.triangle", help: "Apps List", color: Color("mode")))
}
} }
.padding(.horizontal, 5) .padding(.horizontal, 10)
.padding(.top, 5) .padding(.top, 10)
.padding(.bottom, 10) .padding(.bottom, 5)
} }
} }
@@ -108,8 +119,21 @@ struct SearchBarMini: View {
HStack { HStack {
TextField("Search", text: $search) TextField("Search", text: $search)
.textFieldStyle(AnimatedSearchStyle(text: $search)) .textFieldStyle(AnimatedSearchStyle(text: $search))
// .textFieldStyle(SimpleSearchStyle(trash: true, reload: $reload, text: $search)) // .textFieldStyle(SimpleSearchStyle(trash: true, reload: $reload, text: $search))
} }
// .frame(height: 20) .frame(height: 20)
}
}
struct SearchBarMiniBottom: View {
@Binding var search: String
var body: some View {
HStack {
TextField("Search", text: $search)
.textFieldStyle(SimpleSearchStyle(trash: true, text: $search))
}
.padding(.horizontal)
.padding(.bottom, 0)
} }
} }