diff --git a/Pearcleaner.xcodeproj/project.pbxproj b/Pearcleaner.xcodeproj/project.pbxproj index cbea38f..09fe622 100644 --- a/Pearcleaner.xcodeproj/project.pbxproj +++ b/Pearcleaner.xcodeproj/project.pbxproj @@ -535,7 +535,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BK8443AXLU; ENABLE_HARDENED_RUNTIME = YES; @@ -552,7 +552,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 13.0; - MARKETING_VERSION = 1.8; + MARKETING_VERSION = 1.9; PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -569,7 +569,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = BK8443AXLU; ENABLE_HARDENED_RUNTIME = YES; @@ -586,7 +586,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 13.0; - MARKETING_VERSION = 1.8; + MARKETING_VERSION = 1.9; PRODUCT_BUNDLE_IDENTIFIER = com.alienator88.Pearcleaner; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/Pearcleaner/Logic/Logic.swift b/Pearcleaner/Logic/Logic.swift index bb990c1..9df9784 100644 --- a/Pearcleaner/Logic/Logic.swift +++ b/Pearcleaner/Logic/Logic.swift @@ -262,7 +262,6 @@ func findPathsForApp(appState: AppState, appInfo: AppInfo) { } var collection: [URL] = [] if let url = URL(string: appInfo.path.absoluteString) { - // appState.paths.insert(url, at: 0) collection.insert(url, at: 0) } @@ -270,16 +269,19 @@ func findPathsForApp(appState: AppState, appInfo: AppInfo) { let dispatchGroup = DispatchGroup() let bundleComponents = appInfo.bundleIdentifier.components(separatedBy: ".") var bundle: String = "" + var weirdFormatBundle: Bool = false if bundleComponents.count >= 3 { // get last 2 or middle 2 components bundle = bundleComponents[1...2].joined(separator: "").lowercased() } + if bundleComponents[0] != "com" { + weirdFormatBundle = true + } let nameL = appInfo.appName.pearFormat() let bundleIdentifierL = appInfo.bundleIdentifier.pearFormat() let locations = Locations() - + for location in locations.apps.paths { if !fileManager.fileExists(atPath: location) { -// print("Directory does not exist: \(location)") continue } @@ -292,7 +294,8 @@ func findPathsForApp(appState: AppState, appInfo: AppInfo) { let itemURL = URL(fileURLWithPath: location).appendingPathComponent(item) let itemL = ("\(item)").replacingOccurrences(of: ".", with: "").replacingOccurrences(of: " ", with: "").lowercased() - + + if collection.contains(itemURL) { return } @@ -318,7 +321,7 @@ func findPathsForApp(appState: AppState, appInfo: AppInfo) { } // Catch Logitech files since Logi is part of word login and can return random files } else if itemL.contains("logi") && !itemL.contains("login") { - if itemL.contains(bundleComponents[1]) || itemL.contains(bundle) || itemL.contains(bundleIdentifierL) || (nameL.count > 3 && itemL.contains(nameL)) { + if itemL.contains(bundleComponents[weirdFormatBundle ? 0 : 1]) || itemL.contains(bundle) || itemL.contains(bundleIdentifierL) || (nameL.count > 3 && itemL.contains(nameL)) { collection.append(itemURL) } // Catch MS Office files since they have many random folder names and very short names diff --git a/Pearcleaner/Logic/Styles.swift b/Pearcleaner/Logic/Styles.swift index 028fc78..fe3b0ff 100644 --- a/Pearcleaner/Logic/Styles.swift +++ b/Pearcleaner/Logic/Styles.swift @@ -115,7 +115,25 @@ struct AnimatedSearchStyle: TextFieldStyle { } } - + .help("Refresh app list") + + + if text != "" { + Image(systemName: "xmark") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 10, height: 10) + .padding(.trailing, 5) + .foregroundStyle(isHovered ? Color("mode").opacity(0.8) : Color("mode").opacity(0.5)) + .onTapGesture { + withAnimation { + text = "" + } + } + .help("Clear search") + } + + } else { Image(systemName: "magnifyingglass") .resizable() @@ -191,18 +209,18 @@ struct SimpleSearchStyle: TextFieldStyle { } -// if trash { -// Image(systemName: "xmark") -// .resizable() -// .aspectRatio(contentMode: .fit) -// .frame(width: 10, height: 10) -// .padding(.trailing, 5) -// .foregroundStyle(isHovered ? Color("mode").opacity(0.8) : Color("mode").opacity(0.5)) -// .onTapGesture { -// text = "" -// } -// .opacity(text.isEmpty ? 0 : 1) -// } + if trash && text != "" { + Image(systemName: "xmark") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 10, height: 10) + .padding(.trailing, 5) + .foregroundStyle(isHovered ? Color("mode").opacity(0.8) : Color("mode").opacity(0.5)) + .onTapGesture { + text = "" + } + .help("Clear search") + } } } @@ -290,6 +308,42 @@ struct WindowActionButton: ButtonStyle { +struct FilesViewActionButton: ButtonStyle { + enum UserAction { + case uninstall + case close + } + @State private var hovered = false + let action: UserAction + + func makeBody(configuration: Configuration) -> some View { + configuration.label + .frame(width: 70) + .padding(6) + .background( + RoundedRectangle(cornerRadius: 6) + .strokeBorder( + configuration.isPressed ? + Color("AccentColor").opacity(0.7) : + hovered ? Color("AccentColor").opacity(0.8) : Color("AccentColor").opacity(0.9), lineWidth: 2 + ) + + + ) + .foregroundColor( + action == .uninstall ? Color("AccentColor") : Color("mode") + ) + .cornerRadius(6) + .onHover { hovering in + withAnimation(Animation.easeIn(duration: 0.15)) { + hovered = hovering + } + } + } +} + + + struct SentinelToggleStyle: ToggleStyle { func makeBody(configuration: Configuration) -> some View { diff --git a/Pearcleaner/Resources/Assets.xcassets/buttonFiles.colorset/Contents.json b/Pearcleaner/Resources/Assets.xcassets/buttonFiles.colorset/Contents.json new file mode 100644 index 0000000..305826d --- /dev/null +++ b/Pearcleaner/Resources/Assets.xcassets/buttonFiles.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0xCF", + "green" : "0xCF", + "red" : "0xCF" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0x59", + "green" : "0x59", + "red" : "0x59" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Pearcleaner/Settings/General.swift b/Pearcleaner/Settings/General.swift index f0a07ed..3768003 100644 --- a/Pearcleaner/Settings/General.swift +++ b/Pearcleaner/Settings/General.swift @@ -23,7 +23,7 @@ struct GeneralSettingsTab: View { HStack { VStack(alignment: .leading, spacing: 5) { Text("Transparency").font(.title2) - Text("Toggles the sidebar material on the app list drawer") + Text("Toggles the transparent sidebar material") .font(.footnote) .foregroundStyle(.gray) } diff --git a/Pearcleaner/Views/AppListView.swift b/Pearcleaner/Views/AppListView.swift index 758d1be..2df7eeb 100644 --- a/Pearcleaner/Views/AppListView.swift +++ b/Pearcleaner/Views/AppListView.swift @@ -136,7 +136,7 @@ struct AppListView: View { AppDetailsEmptyView(showPopover: $showPopover) } else if appState.currentView == .files { TopBar(reload: $reload) - FilesView(showPopover: $showPopover) + FilesView(showPopover: $showPopover, search: $search) .id(appState.appInfo.id) } } diff --git a/Pearcleaner/Views/DropTarget.swift b/Pearcleaner/Views/DropTarget.swift index b6b6287..2804cfa 100644 --- a/Pearcleaner/Views/DropTarget.swift +++ b/Pearcleaner/Views/DropTarget.swift @@ -86,6 +86,11 @@ struct DropTarget: View, DropDelegate { } .onDrop(of: types, delegate: self) + .onTapGesture { + withAnimation(.easeInOut(duration: 0.5)) { + appState.currentView = .apps + } + } .padding(20) .frame(maxWidth: mini ? 200 : .infinity) .frame(maxHeight: mini ? 200 : .infinity) diff --git a/Pearcleaner/Views/FilesView.swift b/Pearcleaner/Views/FilesView.swift index b0be130..826b129 100644 --- a/Pearcleaner/Views/FilesView.swift +++ b/Pearcleaner/Views/FilesView.swift @@ -17,7 +17,8 @@ struct FilesView: View { @AppStorage("settings.general.mini") private var mini: Bool = false @Environment(\.colorScheme) var colorScheme @Binding var showPopover: Bool - + @Binding var search: String + var body: some View { VStack(alignment: .center) { if !self.showDetails { @@ -156,13 +157,26 @@ struct FilesView: View { HStack() { Spacer() - - + + if mini { + Button("Close") { + updateOnMain { + appState.appInfo = AppInfo.empty + search = "" + appState.currentView = .apps + showPopover = false + } + } +// .buttonStyle(FilesViewActionButton(action: .close)) + } + + Button("Uninstall") { Task { updateOnMain { appState.appInfo = AppInfo.empty if mini { + search = "" appState.currentView = .apps showPopover = false } else { @@ -191,7 +205,7 @@ struct FilesView: View { } .disabled(appState.selectedItems.isEmpty) - .buttonStyle(WindowActionButton(action: .accept)) +// .buttonStyle(FilesViewActionButton(action: .uninstall)) } // .padding(.top) diff --git a/Pearcleaner/Views/MiniMode.swift b/Pearcleaner/Views/MiniMode.swift index b556591..10a9146 100644 --- a/Pearcleaner/Views/MiniMode.swift +++ b/Pearcleaner/Views/MiniMode.swift @@ -30,7 +30,7 @@ struct MiniMode: View { MiniEmptyView(showPopover: $showPopover) } else if appState.currentView == .files { TopBarMini(reload: $reload, search: $search) - FilesView(showPopover: $showPopover) + FilesView(showPopover: $showPopover, search: $search) .id(appState.appInfo.id) } else if appState.currentView == .apps { TopBarMini(reload: $reload, search: $search) @@ -41,7 +41,7 @@ struct MiniMode: View { .transition(.move(edge: .leading)) .popover(isPresented: $showPopover, arrowEdge: .trailing) { VStack { - FilesView(showPopover: $showPopover) + FilesView(showPopover: $showPopover, search: $search) .id(appState.appInfo.id) } .background( diff --git a/Pearcleaner/Views/TopBar.swift b/Pearcleaner/Views/TopBar.swift index 1b7dd33..a4cc487 100644 --- a/Pearcleaner/Views/TopBar.swift +++ b/Pearcleaner/Views/TopBar.swift @@ -45,7 +45,7 @@ struct TopBar: View { appState.appInfo = AppInfo.empty } } - .buttonStyle(SimpleButtonStyle(icon: "arrow.down.app", help: "Drop", color: Color("mode"))) + .buttonStyle(SimpleButtonStyle(icon: "house", help: "Home", color: Color("mode"))) } diff --git a/Pearcleaner/Views/TopBarMini.swift b/Pearcleaner/Views/TopBarMini.swift index 9be7015..3273f18 100644 --- a/Pearcleaner/Views/TopBarMini.swift +++ b/Pearcleaner/Views/TopBarMini.swift @@ -60,7 +60,7 @@ struct TopBarMini: View { // } } } - .buttonStyle(SimpleButtonStyle(icon: "arrow.down.app", help: "Drop", color: Color("mode"))) + .buttonStyle(SimpleButtonStyle(icon: "arrow.down.app", help: "Back to Drop Zone", color: Color("mode"))) } else if appState.currentView == .empty { Button("") { withAnimation(.easeInOut(duration: 0.5)) { @@ -69,7 +69,7 @@ struct TopBarMini: View { // } } } - .buttonStyle(SimpleButtonStyle(icon: "list.triangle", help: "Apps", color: Color("mode"))) + .buttonStyle(SimpleButtonStyle(icon: "list.triangle", help: "Apps List", color: Color("mode"))) } else if appState.currentView == .files { Button("") { withAnimation(.easeInOut(duration: 0.5)) { @@ -80,7 +80,7 @@ struct TopBarMini: View { } } - .buttonStyle(SimpleButtonStyle(icon: "arrow.down.app", help: "Drop", color: Color("mode"))) + .buttonStyle(SimpleButtonStyle(icon: "arrow.down.app", help: "Back to Drop Zone", color: Color("mode"))) Button("") { withAnimation(.easeInOut(duration: 0.5)) { // updateOnMain { @@ -88,7 +88,7 @@ struct TopBarMini: View { // } } } - .buttonStyle(SimpleButtonStyle(icon: "list.triangle", help: "Apps", color: Color("mode"))) + .buttonStyle(SimpleButtonStyle(icon: "list.triangle", help: "Apps List", color: Color("mode"))) }