This commit is contained in:
Alin
2023-11-20 10:28:18 -07:00
parent 78c3a2b0cf
commit 33494e87b0
8 changed files with 94 additions and 39 deletions
+4 -4
View File
@@ -535,7 +535,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 = 6; CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@@ -552,7 +552,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.5; MARKETING_VERSION = 1.6;
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;
@@ -569,7 +569,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 = 6; CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BK8443AXLU; DEVELOPMENT_TEAM = BK8443AXLU;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@@ -586,7 +586,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.5; MARKETING_VERSION = 1.6;
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;
+37 -8
View File
@@ -79,17 +79,42 @@ struct LabeledDivider: View {
struct AnimatedSearchStyle: TextFieldStyle { struct AnimatedSearchStyle: TextFieldStyle {
@State private var isHovered = false @State private var isHovered = false
@Binding var text: String @Binding var text: String
@Binding var reload: Bool
@EnvironmentObject var appState: AppState
func _body(configuration: TextField<Self._Label>) -> some View { func _body(configuration: TextField<Self._Label>) -> some View {
HStack(spacing: 5) { HStack(spacing: 5) {
if isHovered || !text.isEmpty { if isHovered || !text.isEmpty {
configuration configuration
.frame(width: 160) // .frame(minWidth: 130)
.frame(height: 15) .frame(height: 15)
.font(.title3) .font(.title3)
.textFieldStyle(PlainTextFieldStyle()) .textFieldStyle(PlainTextFieldStyle())
.padding(.leading, 50)
Image(systemName: "arrow.triangle.2.circlepath")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 15, height: 15)
.padding(.trailing, 5)
.foregroundStyle(isHovered ? Color("mode").opacity(0.8) : Color("mode").opacity(0.5))
.onTapGesture {
withAnimation {
// 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()
}
}
}
} else { } else {
Image(systemName: "magnifyingglass") Image(systemName: "magnifyingglass")
@@ -106,6 +131,7 @@ struct AnimatedSearchStyle: TextFieldStyle {
RoundedRectangle(cornerRadius: 6) RoundedRectangle(cornerRadius: 6)
.strokeBorder(Color("mode").opacity(0.4), lineWidth: 1) .strokeBorder(Color("mode").opacity(0.4), lineWidth: 1)
.allowsHitTesting(false) .allowsHitTesting(false)
.padding(.leading, 50)
} }
} }
) )
@@ -152,14 +178,17 @@ struct SimpleSearchStyle: TextFieldStyle {
.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 {
// Refresh Apps list withAnimation {
reload.toggle() // Refresh Apps list
let sortedApps = getSortedApps()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
appState.sortedApps.userApps = sortedApps.userApps
appState.sortedApps.systemApps = sortedApps.systemApps
reload.toggle() reload.toggle()
let sortedApps = getSortedApps()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
appState.sortedApps.userApps = sortedApps.userApps
appState.sortedApps.systemApps = sortedApps.systemApps
reload.toggle()
}
} }
} }
// if trash { // if trash {
+9
View File
@@ -66,6 +66,7 @@ func checkFullDiskAccessForApp() -> Bool {
// Check for access to Full Disk access // Check for access to Full Disk access
func checkAndRequestFullDiskAccess(appState: AppState, skipAlert: Bool = false) -> Bool { func checkAndRequestFullDiskAccess(appState: AppState, skipAlert: Bool = false) -> Bool {
@AppStorage("settings.permissions.disk") var diskP: Bool = false @AppStorage("settings.permissions.disk") var diskP: Bool = false
@AppStorage("settings.permissions.hasLaunched") var hasLaunched: Bool = false
let process = Process() let process = Process()
process.launchPath = "/usr/bin/sqlite3" process.launchPath = "/usr/bin/sqlite3"
@@ -137,6 +138,14 @@ func checkAndRequestAccessibilityAccess(appState: AppState) -> Bool {
} }
// Check if app is installed in /Applications directory
func isAppInApplicationsDir() -> Bool {
if let bundlePath = Bundle.main.bundlePath as NSString? {
return bundlePath.deletingLastPathComponent == "/Applications"
}
return false
}
// Check if appearance is dark mode // Check if appearance is dark mode
func isDarkModeEnabled() -> Bool { func isDarkModeEnabled() -> Bool {
let process = Process() let process = Process()
+9 -5
View File
@@ -15,6 +15,7 @@ struct PearcleanerApp: App {
@AppStorage("settings.updater.updateTimeframe") private var updateTimeframe: Int = 1 @AppStorage("settings.updater.updateTimeframe") private var updateTimeframe: Int = 1
@AppStorage("settings.permissions.disk") private var diskP: Bool = false @AppStorage("settings.permissions.disk") private var diskP: Bool = false
@AppStorage("settings.permissions.events") private var diskE: Bool = false @AppStorage("settings.permissions.events") private var diskE: 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
@State private var search = "" @State private var search = ""
@@ -53,13 +54,16 @@ struct PearcleanerApp: App {
// Make sure App Support folder exists in the future if needed for storage // Make sure App Support folder exists in the future if needed for storage
ensureApplicationSupportFolderExists(appState: appState) ensureApplicationSupportFolderExists(appState: appState)
// Check for updates // Check for updates 1 minute after app launch
if diskP && diskE { if diskP {
loadGithubReleases(appState: appState) loadGithubReleases(appState: appState)
} }
// Check for disk/accessibility permissions // Check for disk/accessibility permissions just once on initial app launch
_ = checkAndRequestFullDiskAccess(appState: appState) if !hasLaunched {
_ = checkAndRequestFullDiskAccess(appState: appState)
hasLaunched = true
}
// TIMERS //////////////////////////////////////////////////////////////////////////////////// // TIMERS ////////////////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -115,7 +115,7 @@ func checkForUpdate(appState: AppState, manual: Bool = false) {
guard let latestRelease = appState.releases.first else { return } guard let latestRelease = appState.releases.first else { return }
let currentVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String let currentVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
if latestRelease.tag_name > currentVersion ?? "" { if latestRelease.tag_name > currentVersion ?? "" {
NewWin.show(appState: appState, width: 500, height: 400, newWin: .update) NewWin.show(appState: appState, width: 500, height: 440, newWin: .update)
// appState.alertType = .update // appState.alertType = .update
// appState.showAlert = true // appState.showAlert = true
} else { } else {
+12 -12
View File
@@ -91,24 +91,24 @@ struct FilesView: View {
} }
if appState.appInfo.appName.count < 5 { if appState.appInfo.appName.count < 5 {
HStack(alignment: .center) { HStack(alignment: .center) {
Button(""){ Image(systemName: "exclamationmark.triangle.fill")
showPop = true .foregroundStyle(.red)
} .popover(isPresented: $showPop, arrowEdge: .top) {
.buttonStyle(SimpleButtonStyle(icon: "exclamationmark.triangle.fill", help: "Warning", color: .red)) VStack() {
.popover(isPresented: $showPop, arrowEdge: .top) { 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.")
VStack() { .padding()
Text("Pearcleaner searches for files with 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.") .font(.title2)
.padding(20) }
.font(.title2)
} }
} Text("Warning")
Text("Read caution message")
.foregroundStyle(Color.red) .foregroundStyle(Color.red)
Spacer() Spacer()
} }
.padding(.top) .padding(.top)
.onTapGesture { .onTapGesture {
showPop = true showPop = true
} }
+9 -9
View File
@@ -54,38 +54,38 @@ struct TopBarMini: View {
if appState.currentView == .apps { 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
} // }
} }
} }
.buttonStyle(SimpleButtonStyle(icon: "arrow.down.app", help: "Drop", color: Color("mode"))) .buttonStyle(SimpleButtonStyle(icon: "arrow.down.app", help: "Drop", color: Color("mode")))
} else if appState.currentView == .empty { } else if appState.currentView == .empty {
Button("") { Button("") {
withAnimation(.easeInOut(duration: 0.5)) { withAnimation(.easeInOut(duration: 0.5)) {
updateOnMain { // updateOnMain {
appState.currentView = .apps appState.currentView = .apps
} // }
} }
} }
.buttonStyle(SimpleButtonStyle(icon: "list.triangle", help: "Apps", color: Color("mode"))) .buttonStyle(SimpleButtonStyle(icon: "list.triangle", help: "Apps", color: Color("mode")))
} else if appState.currentView == .files { } else if appState.currentView == .files {
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
} // }
} }
} }
.buttonStyle(SimpleButtonStyle(icon: "arrow.down.app", help: "Drop", color: Color("mode"))) .buttonStyle(SimpleButtonStyle(icon: "arrow.down.app", help: "Drop", color: Color("mode")))
Button("") { Button("") {
withAnimation(.easeInOut(duration: 0.5)) { withAnimation(.easeInOut(duration: 0.5)) {
updateOnMain { // updateOnMain {
appState.currentView = .apps appState.currentView = .apps
} // }
} }
} }
.buttonStyle(SimpleButtonStyle(icon: "list.triangle", help: "Apps", color: Color("mode"))) .buttonStyle(SimpleButtonStyle(icon: "list.triangle", help: "Apps", color: Color("mode")))
@@ -107,7 +107,7 @@ struct SearchBarMini: View {
var body: some View { var body: some View {
HStack { HStack {
TextField("Search", text: $search) TextField("Search", text: $search)
.textFieldStyle(AnimatedSearchStyle(text: $search)) .textFieldStyle(AnimatedSearchStyle(text: $search, reload: $reload))
// .textFieldStyle(SimpleSearchStyle(trash: true, reload: $reload, text: $search)) // .textFieldStyle(SimpleSearchStyle(trash: true, reload: $reload, text: $search))
} }
// .frame(height: 20) // .frame(height: 20)
+13
View File
@@ -10,6 +10,7 @@ import SwiftUI
struct UpdateView: View { struct UpdateView: View {
@EnvironmentObject var appState: AppState @EnvironmentObject var appState: AppState
let isAppInAppsDir = isAppInApplicationsDir()
var body: some View { var body: some View {
VStack { VStack {
@@ -47,6 +48,18 @@ struct UpdateView: View {
Spacer() Spacer()
if !isAppInAppsDir {
HStack {
Text("Pearcleaner not in /Applications directory. Updater could have permission issues updating files.")
.font(.footnote)
.foregroundStyle(.red)
.padding()
.lineLimit(2)
.fixedSize(horizontal: false, vertical: true)
}
}
VStack() { VStack() {
ProgressView("\(appState.progressBar.0)", value: appState.progressBar.1, total: 1.0) ProgressView("\(appState.progressBar.0)", value: appState.progressBar.1, total: 1.0)