This commit is contained in:
Alin
2024-07-08 11:09:30 -06:00
parent 68aab7c1a2
commit 4610ae90f2
5 changed files with 156 additions and 126 deletions
+4 -6
View File
@@ -34,7 +34,6 @@
C77B90232AF2D616009CC655 /* FilesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B90222AF2D616009CC655 /* FilesView.swift */; }; C77B90232AF2D616009CC655 /* FilesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77B90222AF2D616009CC655 /* FilesView.swift */; };
C78121662BC892A000BE06BD /* FinderOpen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C78121652BC892A000BE06BD /* FinderOpen.swift */; }; C78121662BC892A000BE06BD /* FinderOpen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C78121652BC892A000BE06BD /* FinderOpen.swift */; };
C781216B2BC892A000BE06BD /* FinderOpen.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C78121632BC892A000BE06BD /* FinderOpen.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; C781216B2BC892A000BE06BD /* FinderOpen.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C78121632BC892A000BE06BD /* FinderOpen.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
C786F1A82C29E599001B3800 /* Builds in Resources */ = {isa = PBXBuildFile; fileRef = C786F1A72C29E599001B3800 /* Builds */; };
C79947962C34A794007279CC /* Tips.swift in Sources */ = {isa = PBXBuildFile; fileRef = C79947952C34A794007279CC /* Tips.swift */; }; C79947962C34A794007279CC /* Tips.swift in Sources */ = {isa = PBXBuildFile; fileRef = C79947952C34A794007279CC /* Tips.swift */; };
C79D05202BC99EB40083F976 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C79D051F2BC99EB40083F976 /* ThemeManager.swift */; }; C79D05202BC99EB40083F976 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C79D051F2BC99EB40083F976 /* ThemeManager.swift */; };
C7A27E812AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist in Resources */ = {isa = PBXBuildFile; fileRef = C7A27E802AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist */; }; C7A27E812AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist in Resources */ = {isa = PBXBuildFile; fileRef = C7A27E802AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist */; };
@@ -447,7 +446,6 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
C77B90082AF18E2F009CC655 /* Assets.xcassets in Resources */, C77B90082AF18E2F009CC655 /* Assets.xcassets in Resources */,
C786F1A82C29E599001B3800 /* Builds in Resources */,
C7A27E812AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist in Resources */, C7A27E812AFD7C4600166168 /* com.alienator88.PearcleanerSentinel.plist in Resources */,
C7DC1FEE2B9F7D3D009AC317 /* features.json in Resources */, C7DC1FEE2B9F7D3D009AC317 /* features.json in Resources */,
); );
@@ -588,8 +586,8 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
APP_BUILD = 53; APP_BUILD = 54;
APP_VERSION = 3.7.8; APP_VERSION = 3.8.0;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
@@ -658,8 +656,8 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
APP_BUILD = 53; APP_BUILD = 54;
APP_VERSION = 3.7.8; APP_VERSION = 3.8.0;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+5 -5
View File
@@ -962,10 +962,10 @@ struct PickerModifier: ViewModifier {
content content
.buttonStyle(.borderless) .buttonStyle(.borderless)
.padding(4) .padding(4)
.background { // .background {
backgroundView(themeSettings: themeSettings, darker: isHovered) // backgroundView(themeSettings: themeSettings, darker: isHovered)
.clipShape(RoundedRectangle(cornerRadius: 10)) // .clipShape(RoundedRectangle(cornerRadius: 10))
} // }
.onHover { hovering in .onHover { hovering in
isHovered = hovering isHovered = hovering
} }
@@ -995,7 +995,7 @@ struct PresetColor: ButtonStyle {
.help(label) .help(label)
.overlay( .overlay(
RoundedRectangle(cornerRadius: 25) RoundedRectangle(cornerRadius: 25)
.strokeBorder(Color("mode").opacity(0.8), lineWidth: 1.5)) .strokeBorder(Color("mode").opacity(0.8), lineWidth: 1))
// Text(label) // Text(label)
} }
.onHover { inside in inside ? NSCursor.pointingHand.push() : NSCursor.pop() } .onHover { inside in inside ? NSCursor.pointingHand.push() : NSCursor.pop() }
+5 -5
View File
@@ -28,15 +28,15 @@ class ThemeSettings: ObservableObject {
themeColor = userDefaults.color(forKey: colorKey) ?? .clear themeColor = userDefaults.color(forKey: colorKey) ?? .clear
} }
func setupInitialColor() { func setupInitialColor(forcedDarkMode: Bool? = nil) {
if userDefaults.color(forKey: colorKey) == nil { // Determine dark mode either from forced setting or system setting
// Only set the initial color if it has not been set by the user. let darkMode = forcedDarkMode ?? isDarkMode()
let darkMode = isDarkMode() // Safe to call here after the application is fully set up.
// Set the theme color based on the dark mode status
themeColor = darkMode ? Color(.sRGB, red: 0.188143, green: 0.208556, blue: 0.262679, opacity: 1) : themeColor = darkMode ? Color(.sRGB, red: 0.188143, green: 0.208556, blue: 0.262679, opacity: 1) :
Color(.sRGB, red: 1.0, green: 1.0, blue: 1.0, opacity: 1) Color(.sRGB, red: 1.0, green: 1.0, blue: 1.0, opacity: 1)
saveThemeColor() saveThemeColor()
} }
}
private func loadThemeColor() { private func loadThemeColor() {
if let components = UserDefaults.standard.array(forKey: colorKey) as? [CGFloat], components.count == 4 { if let components = UserDefaults.standard.array(forKey: colorKey) as? [CGFloat], components.count == 4 {
+34 -22
View File
@@ -178,10 +178,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
findAndSetWindowFrame(named: ["Pearcleaner"], windowSettings: windowSettings) findAndSetWindowFrame(named: ["Pearcleaner"], windowSettings: windowSettings)
// if UserDefaults.standard.object(forKey: "themeColor") == nil {
// self.appearanceChanged()
// }
self.appearanceCheck() self.appearanceCheck()
if menubarEnabled { if menubarEnabled {
@@ -191,42 +187,58 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
// Start observing the appearance change // Start observing the appearance change
observer = DistributedNotificationCenter.default().addObserver(forName: NSNotification.Name(rawValue: "AppleInterfaceThemeChangedNotification"), object: nil, queue: OperationQueue.main) { [weak self] _ in observer = DistributedNotificationCenter.default().addObserver(forName: NSNotification.Name(rawValue: "AppleInterfaceThemeChangedNotification"), object: nil, queue: OperationQueue.main) { [weak self] _ in
// let themeMode = UserDefaults.standard.string(forKey: "settings.general.selectedTheme") let themeMode = UserDefaults.standard.string(forKey: "settings.general.selectedTheme")
// if themeMode == "Auto" { let themesEnabled = UserDefaults.standard.bool(forKey: "settings.interface.themesEnabled")
// self?.appearanceCheck() if themeMode == "Auto" && !themesEnabled {
// }
self?.appearanceCheck(reset: true) self?.appearanceCheck(reset: true)
} }
}
} }
func appearanceCheck(reset: Bool = false) { func appearanceCheck(reset: Bool = false) {
// Setup initial color let themesEnabled = UserDefaults.standard.bool(forKey: "settings.interface.themesEnabled")
ThemeSettings.shared.setupInitialColor() let themeMode = UserDefaults.standard.string(forKey: "settings.general.selectedTheme")
// Get the current theme color if themesEnabled {
let themeColor = ThemeSettings.shared.themeColor // Custom theming is enabled; user's manual settings take priority.
// Determine if the color is light or dark
if let isLightColor = themeColor.isLight() {
let shouldUseDarkMode = !isLightColor // Use dark mode if color is dark
UserDefaults.standard.set(shouldUseDarkMode ? DisplayMode.dark.rawValue : DisplayMode.light.rawValue, forKey: "displayMode")
} else { } else {
// Default to system preference if unable to determine color brightness switch themeMode {
let dark = isDarkMode() case "Auto":
UserDefaults.standard.set(dark ? DisplayMode.dark.rawValue : DisplayMode.light.rawValue, forKey: "displayMode") // Auto mode: adjust theme based on system appearance.
ThemeSettings.shared.setupInitialColor()
updateDisplayModeBasedOnThemeColor()
case "Light", "Dark":
// Specific mode set: ensure theme color matches the display mode.
ThemeSettings.shared.setupInitialColor(forcedDarkMode: themeMode == "Dark")
UserDefaults.standard.set(themeMode == "Dark" ? DisplayMode.dark.rawValue : DisplayMode.light.rawValue, forKey: "displayMode")
default:
// No specific handling needed or unrecognized mode; fall back to default behavior.
printOS("No specific theme mode set or unrecognized value.")
}
} }
// Reset theme when OS changes appearance if reset && themeMode == "Auto" {
if reset {
let dark = isDarkMode() let dark = isDarkMode()
ThemeSettings.shared.resetToDefault(dark: dark) ThemeSettings.shared.resetToDefault(dark: dark)
} }
} }
func updateDisplayModeBasedOnThemeColor() {
let themeColor = ThemeSettings.shared.themeColor
if let isLightColor = themeColor.isLight() {
let shouldUseDarkMode = !isLightColor
UserDefaults.standard.set(shouldUseDarkMode ? DisplayMode.dark.rawValue : DisplayMode.light.rawValue, forKey: "displayMode")
} else {
// Default to system preference if brightness cannot be determined.
let dark = isDarkMode()
UserDefaults.standard.set(dark ? DisplayMode.dark.rawValue : DisplayMode.light.rawValue, forKey: "displayMode")
}
}
func applicationWillTerminate(_ notification: Notification) { func applicationWillTerminate(_ notification: Notification) {
// Stop observing the appearance change // Stop observing the appearance change
if let observer = observer { if let observer = observer {
+60 -40
View File
@@ -23,9 +23,9 @@ struct InterfaceSettingsTab: View {
@AppStorage("settings.general.selectedTab") private var selectedTab: CurrentTabView = .general @AppStorage("settings.general.selectedTab") private var selectedTab: CurrentTabView = .general
@AppStorage("settings.general.glass") private var glass: Bool = false @AppStorage("settings.general.glass") private var glass: Bool = false
@AppStorage("settings.general.dark") var isDark: Bool = true @AppStorage("settings.general.dark") var isDark: Bool = true
@AppStorage("settings.interface.themesEnabled") var themesEnabled: Bool = false
@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.miniview") private var miniView: Bool = true
// @AppStorage("settings.general.animateLogo") private var animateLogo: Bool = true
@AppStorage("settings.general.selectedTheme") var selectedTheme: String = "Auto" @AppStorage("settings.general.selectedTheme") var selectedTheme: String = "Auto"
@AppStorage("settings.interface.selectedMenubarIcon") var selectedMenubarIcon: String = "pear-4" @AppStorage("settings.interface.selectedMenubarIcon") var selectedMenubarIcon: String = "pear-4"
@State private var isLaunchAtLoginEnabled: Bool = false @State private var isLaunchAtLoginEnabled: Bool = false
@@ -69,38 +69,43 @@ struct InterfaceSettingsTab: View {
.padding(.leading) .padding(.leading)
// HStack(spacing: 0) {
// Image(systemName: animateLogo ? "play.fill" : "pause")
// .resizable()
// .scaledToFit()
// .frame(width: 20, height: 20)
// .padding(.trailing)
// .foregroundStyle(Color("mode").opacity(0.5))
// VStack(alignment: .leading, spacing: 5) {
// Text("\(animateLogo ? "Logo animation enabled" : "Logo animation disabled")")
// .font(.callout)
// .foregroundStyle(Color("mode").opacity(0.5))
//
// }
// if !isMacOS14OrHigher {
// Text("(macOS 14+)")
// .font(.footnote)
// .foregroundStyle(Color("mode").opacity(0.3))
// .padding(.leading, 5)
// }
//// InfoButton(text: "The logo animation is only available in macOS 14 or higher")
// Spacer()
// Toggle(isOn: $animateLogo, label: {
// })
// .toggleStyle(.switch)
// .disabled(!isMacOS14OrHigher)
// }
// .padding(5)
// .padding(.leading)
HStack(spacing: 0) {
Image(systemName: themesEnabled ? "paintpalette.fill" : "paintpalette")
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.padding(.trailing)
.foregroundStyle(Color("mode").opacity(0.5))
VStack(alignment: .leading, spacing: 5) {
Text("\(themesEnabled ? "Custom theming is enabled" : "Custom theming is disabled")")
.font(.callout)
.foregroundStyle(Color("mode").opacity(0.5))
}
Spacer()
Toggle(isOn: $themesEnabled, label: {
})
.toggleStyle(.switch)
.onChange(of: themesEnabled) { newVal in
themeSettings.resetToDefault(dark: isDarkMode())
if isDarkMode() {
displayMode.colorScheme = .dark
} else {
displayMode.colorScheme = .light
}
if newVal {
selectedTheme = isDarkMode() ? "Dark" : "Light"
} else {
selectedTheme = "Auto"
}
}
}
.padding(5)
.padding(.leading)
/// Show theme color selector if theming is enabled
if themesEnabled {
HStack(spacing: 0) { HStack(spacing: 0) {
Image(systemName: "paintbrush") Image(systemName: "paintbrush")
.resizable() .resizable()
@@ -109,11 +114,11 @@ struct InterfaceSettingsTab: View {
.padding(.trailing) .padding(.trailing)
.foregroundStyle(Color("mode").opacity(0.5)) .foregroundStyle(Color("mode").opacity(0.5))
VStack(alignment: .leading, spacing: 5) { VStack(alignment: .leading, spacing: 5) {
Text("Application base color") Text("Application theme color")
.font(.callout) .font(.callout)
.foregroundStyle(Color("mode").opacity(0.5)) .foregroundStyle(Color("mode").opacity(0.5))
} }
InfoButton(text: "When using a custom color, you might need to change the application color mode below to Dark or Light so text is readable") // InfoButton(text: "When using a custom color, you might need to change the application color mode below to Dark or Light so text is readable")
Spacer() Spacer()
@@ -130,13 +135,11 @@ struct InterfaceSettingsTab: View {
Button("") { Button("") {
themeSettings.setPreset(preset: "solarized", colorScheme: displayMode) themeSettings.setPreset(preset: "solarized", colorScheme: displayMode)
themeSettings.saveThemeColor()
} }
.buttonStyle(PresetColor(fillColor: themeSettings.getColorForPreset(preset: "solarized", colorScheme: displayMode), label: "Solarized")) .buttonStyle(PresetColor(fillColor: themeSettings.getColorForPreset(preset: "solarized", colorScheme: displayMode), label: "Solarized"))
Button("") { Button("") {
themeSettings.setPreset(preset: "macOS", colorScheme: displayMode) themeSettings.setPreset(preset: "macOS", colorScheme: displayMode)
themeSettings.saveThemeColor()
} }
.buttonStyle(PresetColor(fillColor: themeSettings.getColorForPreset(preset: "macOS", colorScheme: displayMode), label: "macOS")) .buttonStyle(PresetColor(fillColor: themeSettings.getColorForPreset(preset: "macOS", colorScheme: displayMode), label: "macOS"))
} }
@@ -153,13 +156,20 @@ struct InterfaceSettingsTab: View {
.padding(.horizontal, 5) .padding(.horizontal, 5)
Button("") { Button("") {
themeSettings.resetToDefault(dark: colorScheme == .dark) themeSettings.resetToDefault(dark: isDarkMode())
if isDarkMode() {
displayMode.colorScheme = .dark
} else {
displayMode.colorScheme = .light
}
selectedTheme = isDarkMode() ? "Dark" : "Light"
} }
.buttonStyle(SimpleButtonStyle(icon: "arrow.uturn.left.circle", help: "Reset color to default")) .buttonStyle(SimpleButtonStyle(icon: "arrow.uturn.left.circle", help: "Reset color to default"))
} }
.padding(5) .padding(5)
.padding(.leading) .padding(.leading)
}
@@ -180,18 +190,20 @@ struct InterfaceSettingsTab: View {
.padding(.trailing) .padding(.trailing)
.foregroundStyle(Color("mode").opacity(0.5)) .foregroundStyle(Color("mode").opacity(0.5))
VStack(alignment: .leading, spacing: 5) { VStack(alignment: .leading, spacing: 5) {
Text("Application color mode") Text(themesEnabled ? "Application font color" : "Application color mode")
.font(.callout) .font(.callout)
.foregroundStyle(Color("mode").opacity(0.5)) .foregroundStyle(Color("mode").opacity(0.5))
} }
InfoButton(text: "This changes the text color to match the OS. It will also reset the base color to defaults when swapping between these.") InfoButton(text: "When custom theming is disabled, you can set the application color mode to follow the operating system using Auto. Or manually set it to Light or Dark. When custom theming is enabled, this selector acts mainly as a font color picker between light or dark to match your custom theme color.")
Spacer() Spacer()
Picker("", selection: $selectedTheme) { Picker("", selection: $selectedTheme) {
if !themesEnabled {
Text("Auto") Text("Auto")
.tag("Auto") .tag("Auto")
Text("Dark") }
Text(themesEnabled ? "Light" : "Dark")
.tag("Dark") .tag("Dark")
Text("Light") Text(themesEnabled ? "Dark" : "Light")
.tag("Light") .tag("Light")
} }
.pickerStyle(themeSettings: themeSettings) .pickerStyle(themeSettings: themeSettings)
@@ -203,7 +215,9 @@ struct InterfaceSettingsTab: View {
} else { } else {
displayMode.colorScheme = .light displayMode.colorScheme = .light
} }
if !themesEnabled {
themeSettings.resetToDefault(dark: isDarkMode()) themeSettings.resetToDefault(dark: isDarkMode())
}
// Refresh foreground colors // Refresh foreground colors
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.selectedTab = .interface self.selectedTab = .interface
@@ -213,7 +227,9 @@ struct InterfaceSettingsTab: View {
} }
case "Dark": case "Dark":
displayMode.colorScheme = .dark displayMode.colorScheme = .dark
if !themesEnabled {
themeSettings.resetToDefault(dark: true) themeSettings.resetToDefault(dark: true)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.selectedTab = .interface self.selectedTab = .interface
} }
@@ -222,7 +238,9 @@ struct InterfaceSettingsTab: View {
} }
case "Light": case "Light":
displayMode.colorScheme = .light displayMode.colorScheme = .light
if !themesEnabled {
themeSettings.resetToDefault(dark: false) themeSettings.resetToDefault(dark: false)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.selectedTab = .interface self.selectedTab = .interface
} }
@@ -515,6 +533,8 @@ struct InterfaceSettingsTab: View {
.onChange(of: selectedMenubarIcon) { newValue in .onChange(of: selectedMenubarIcon) { newValue in
MenuBarExtraManager.shared.swapMenuBarIcon(icon: newValue) MenuBarExtraManager.shared.swapMenuBarIcon(icon: newValue)
} }
.pickerStyle(themeSettings: themeSettings)
} }
.padding(5) .padding(5)
@@ -525,7 +545,7 @@ struct InterfaceSettingsTab: View {
} }
.padding(20) .padding(20)
.frame(width: 500, height: 580) .frame(width: 500, height: themesEnabled ? 600 : 580)
} }