This commit is contained in:
Alin
2024-03-11 11:59:02 -06:00
parent bc8d4d22f6
commit f9430218fc
9 changed files with 99 additions and 35 deletions
+8 -4
View File
@@ -36,6 +36,7 @@
C7D31D482AFEB23700C7ED9E /* TopBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D472AFEB23700C7ED9E /* TopBar.swift */; };
C7D31D4A2AFEB26700C7ED9E /* AppListItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D492AFEB26700C7ED9E /* AppListItems.swift */; };
C7D31D512AFF00F300C7ED9E /* Locations.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D31D502AFF00F300C7ED9E /* Locations.swift */; };
C7DC1FEE2B9F7D3D009AC317 /* features.json in Resources */ = {isa = PBXBuildFile; fileRef = C7DC1FED2B9F7D3D009AC317 /* features.json */; };
C7F539382AF60865007DF1B2 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F539372AF60865007DF1B2 /* Utilities.swift */; };
C7FB173B2B96321300B96F9A /* AppsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7FB173A2B96321300B96F9A /* AppsListView.swift */; };
/* End PBXBuildFile section */
@@ -95,6 +96,7 @@
C7D31D472AFEB23700C7ED9E /* TopBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBar.swift; sourceTree = "<group>"; };
C7D31D492AFEB26700C7ED9E /* AppListItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppListItems.swift; sourceTree = "<group>"; };
C7D31D502AFF00F300C7ED9E /* Locations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Locations.swift; sourceTree = "<group>"; };
C7DC1FED2B9F7D3D009AC317 /* features.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = features.json; sourceTree = SOURCE_ROOT; };
C7F539372AF60865007DF1B2 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; };
C7FB173A2B96321300B96F9A /* AppsListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppsListView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -175,6 +177,7 @@
C76D084F2AF84E0100D07867 /* Resources */ = {
isa = PBXGroup;
children = (
C7DC1FED2B9F7D3D009AC317 /* features.json */,
C7A27E802AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist */,
C77B90142AF18E7C009CC655 /* Info.plist */,
C77B90072AF18E2F009CC655 /* Assets.xcassets */,
@@ -320,6 +323,7 @@
files = (
C77B90082AF18E2F009CC655 /* Assets.xcassets in Resources */,
C7A27E812AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist in Resources */,
C7DC1FEE2B9F7D3D009AC317 /* features.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -539,7 +543,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 21;
CURRENT_PROJECT_VERSION = 22;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU;
@@ -557,7 +561,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 3.0.2;
MARKETING_VERSION = 3.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -574,7 +578,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 21;
CURRENT_PROJECT_VERSION = 22;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU;
@@ -592,7 +596,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 3.0.2;
MARKETING_VERSION = 3.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
-1
View File
@@ -29,7 +29,6 @@ class AppState: ObservableObject
@Published var showProgress: Bool = false
@Published var popCount: Int = 0
init() {
self.appInfo = AppInfo(
+46 -19
View File
@@ -157,6 +157,52 @@ func isDarkModeEnabled() -> Bool {
}
// Check if appearance is dark mode
//func getCasks() -> [String] {
// let process = Process()
//#if arch(x86_64)
// let cmd = "/usr/local/bin/brew"
//#elseif arch(arm64)
// let cmd = "/opt/homebrew/bin/brew"
//#endif
// process.executableURL = URL(fileURLWithPath: cmd)
// process.arguments = ["list", "--cask"]
// let pipe = Pipe()
// process.standardOutput = pipe
// process.standardError = pipe
// try? process.run()
// process.waitUntilExit() // Ensure the process completes
// let data = pipe.fileHandleForReading.readDataToEndOfFile()
// if let output = String(data: data, encoding: .utf8), !output.isEmpty {
// return output.components(separatedBy: "\n").filter { !$0.isEmpty }.map { $0.replacingOccurrences(of: "-", with: " ") }
// } else {
// return []
// }
//}
// Brew cleanup
func caskCleanup(app: String) {
Task(priority: .high) {
let process = Process()
#if arch(x86_64)
let cmd = "/usr/local/bin/brew"
#elseif arch(arm64)
let cmd = "/opt/homebrew/bin/brew"
#endif
process.executableURL = URL(fileURLWithPath: "/bin/zsh")
process.arguments = ["-c", "\(cmd) uninstall --cask \(app) --force; \(cmd) cleanup"]
// let pipe = Pipe()
process.standardOutput = FileHandle.nullDevice//pipe
process.standardError = FileHandle.nullDevice//pipe
try? process.run()
process.waitUntilExit() // Ensure the process completes
// let data = pipe.fileHandleForReading.readDataToEndOfFile()
// let output = (String(data: data, encoding: .utf8) ?? "") as String
// print(output)
}
}
// Check if symlink
func isSymlink(atPath path: URL) -> Bool {
do {
@@ -218,22 +264,6 @@ func getIconForFileOrFolderNS(atPath path: URL) -> NSImage? {
}
// Get average color from image
//extension NSImage {
// var averageColor2: NSColor? {
// guard let inputImage = CIImage(image: self) else { return nil }
// let extentVector = CIVector(x: inputImage.extent.origin.x, y: inputImage.extent.origin.y, z: inputImage.extent.size.width, w: inputImage.extent.size.height)
//
// guard let filter = CIFilter(name: "CIAreaAverage", parameters: [kCIInputImageKey: inputImage, kCIInputExtentKey: extentVector]) else { return nil }
// guard let outputImage = filter.outputImage else { return nil }
//
// var bitmap = [UInt8](repeating: 0, count: 4)
// let context = CIContext(options: [.workingColorSpace: kCFNull!])
// context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: .RGBA8, colorSpace: nil)
//
// return NSColor(red: CGFloat(bitmap[0]) / 255, green: CGFloat(bitmap[1]) / 255, blue: CGFloat(bitmap[2]) / 255, alpha: CGFloat(bitmap[3]) / 255)
// }
//}
extension NSImage {
var averageColor: NSColor? {
guard let tiffData = self.tiffRepresentation, let bitmapImage = NSBitmapImageRep(data: tiffData), let inputImage = CIImage(bitmapImageRep: bitmapImage) else { return nil }
@@ -279,13 +309,10 @@ func removeApp(appState: AppState, withId id: UUID) {
appState.sortedApps.remove(at: index)
return // Exit the function if the app was found and removed
}
// Remove from appInfoStore if found
if let index = appState.appInfoStore.firstIndex(where: { $0.id == id }) {
appState.appInfoStore.remove(at: index)
}
// Clear out AppInfo state
appState.appInfo = AppInfo.empty
}
}
+4 -6
View File
@@ -23,6 +23,7 @@ struct PearcleanerApp: App {
@AppStorage("settings.general.miniview") private var miniView: Bool = true
@AppStorage("settings.general.instant") private var instantSearch: Bool = true
@AppStorage("settings.general.features") private var features: String = ""
@AppStorage("settings.general.brew") private var brew: Bool = false
@State private var search = ""
@State private var showPopover: Bool = false
@State private var showFeature: Bool = false
@@ -94,14 +95,11 @@ struct PearcleanerApp: App {
appState.sortedApps = sortedApps
// Find all app paths on load
// Find all app paths/information on load if instantSearch is enabled
if instantSearch {
// startEnd {
loadAllPaths(allApps: sortedApps, appState: appState, locations: locations)
// }
loadAllPaths(allApps: sortedApps, appState: appState, locations: locations)
}
#if !DEBUG
Task {
+26 -1
View File
@@ -19,6 +19,7 @@ struct GeneralSettingsTab: View {
@AppStorage("settings.general.sidebarWidth") private var sidebarWidth: Double = 280
@AppStorage("displayMode") var displayMode: DisplayMode = .system
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
@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"
@State private var diskStatus: Bool = false
@@ -82,6 +83,30 @@ struct GeneralSettingsTab: View {
.padding(.leading)
HStack(spacing: 0) {
Image(systemName: brew ? "mug.fill" : "mug")
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.padding(.trailing)
.foregroundStyle(.gray)
VStack(alignment: .leading, spacing: 5) {
Text("\(brew ? "Homebrew cleanup is enabled" : "Homebrew cleanup is disabled")")
.font(.callout)
.foregroundStyle(.gray)
}
InfoButton(text: "When homebrew cleanup is enabled, Pearcleaner will check if the app you are removing was installed via homebrew and execute a brew uninstall and brew cleanup command as well to let homebrew know that the app is removed. This way your homebrew list will be synced up correctly and caching will be removed.\n\nNOTE: If you undo the file delete with CMD+Z, the files will be put back but homebrew will not be aware of it. To get the homebrew list back in sync you'd need to run:\n brew install APPNAME --force", color: nil)
Spacer()
Toggle(isOn: $brew, label: {
})
.toggleStyle(.switch)
}
.padding(5)
.padding(.leading)
HStack(spacing: 0) {
Image(systemName: displayMode.colorScheme == .dark ? "moon.fill" : "sun.max.fill")
.resizable()
@@ -346,7 +371,7 @@ struct GeneralSettingsTab: View {
}
.padding(20)
.frame(width: 500, height: 650)
.frame(width: 500, height: 690)
}
+4 -1
View File
@@ -10,7 +10,8 @@ import SwiftUI
struct SettingsView: View {
@EnvironmentObject var appState: AppState
@Binding var showPopover: Bool
@AppStorage("settings.general.glass") private var glass: Bool = true
var body: some View {
TabView() {
@@ -33,6 +34,8 @@ struct SettingsView: View {
.tag(CurrentTabView.about)
}
.background(glass ? GlassEffect(material: .sidebar, blendingMode: .behindWindow).edgesIgnoringSafeArea(.all) : nil)
}
+9 -2
View File
@@ -15,6 +15,7 @@ struct FilesView: View {
@AppStorage("settings.general.mini") private var mini: Bool = false
@AppStorage("settings.sentinel.enable") private var sentinel: Bool = false
@AppStorage("settings.general.instant") var instantSearch: Bool = true
@AppStorage("settings.general.brew") private var brew: Bool = false
@Environment(\.colorScheme) var colorScheme
@Binding var showPopover: Bool
@Binding var search: String
@@ -216,12 +217,18 @@ struct FilesView: View {
withAnimation {
showPopover = false
updateOnMain {
appState.currentView = mini ? .apps : .empty
appState.isReminderVisible.toggle()
}
}
// Remove app from app list
removeApp(appState: appState, withId: appState.appInfo.id)
// refreshAppList(appState.appInfo)
// Brew cleanup if enabled
if brew {
caskCleanup(app: appState.appInfo.appName)
}
// Clear out AppInfo state
appState.appInfo = AppInfo.empty
}
}
+1 -1
View File
@@ -182,7 +182,7 @@ struct MiniAppView: View {
AppsListView(search: $search, showPopover: $showPopover, filteredApps: filteredApps)
if appState.currentView != .empty {
SearchBarMiniBottom(search: $search).background(.ultraThinMaterial)
SearchBarMiniBottom(search: $search)
}
}
.padding(.bottom)
+1
View File
@@ -1,3 +1,4 @@
{
"3.1.0": "- Brew Cleanup: If you install apps using Homebrew, you can now enable brew cleanup in Pearcleaner settings to have it uninstall the app via brew as well to keep Homebrew synced up.",
"3.0.0": "- Instant Search: Enable in settings to load app files on startup|- Semantic Versioning: Going forward will use semver (Ex. v0.0.0)|-Feature Alert: For each version, a feature alert will popup once on startup to show details|- Leftover File Cleaning: Search your mac for files leftover by uninstalled apps|- Sidebar Drag Handle: Resize the sidebar in regular mode|- Redesign UI/Settings/Icon: Some new buttons, layout changes, new official app icon and pear color theme accents|- File Sort: Sort files alphabetically or by size|- Socket File Removal: Finds socket files that aren't even visible in Finder with show hidden files enabled|- OSLog Output: Will print errors to the Console app for easier troubleshooting"
}