import AppKit // MARK: - Settings Keys private enum SettingsKey { static let intensityScale = "pommedoro.intensityScale" static let blinkDurationScale = "pommedoro.blinkDurationScale" static let gradientColorRed = "pommedoro.gradientColor.red" static let gradientColorGreen = "pommedoro.gradientColor.green" static let gradientColorBlue = "pommedoro.gradientColor.blue" } // MARK: - Settings Manager class Settings { static let shared = Settings() /// Notification posted when any setting changes static let didChangeNotification = Notification.Name("PommedoroSettingsDidChange") private let defaults = UserDefaults.standard private init() { registerDefaults() } private func registerDefaults() { // Extract default teal components for consistent defaults let teal = NSColor.systemTeal.usingColorSpace(.sRGB) ?? NSColor.systemTeal defaults.register(defaults: [ SettingsKey.intensityScale: 1.0, SettingsKey.blinkDurationScale: 1.0, SettingsKey.gradientColorRed: Double(teal.redComponent), SettingsKey.gradientColorGreen: Double(teal.greenComponent), SettingsKey.gradientColorBlue: Double(teal.blueComponent), ]) } /// Intensity multiplier (0.25 to 2.0, default 1.0) var intensityScale: Double { get { defaults.double(forKey: SettingsKey.intensityScale) } set { defaults.set(newValue.clamped(to: 0.25...2.0), forKey: SettingsKey.intensityScale) notifyChange() } } /// Blink duration multiplier (0.25 to 3.0, default 1.0) var blinkDurationScale: Double { get { defaults.double(forKey: SettingsKey.blinkDurationScale) } set { defaults.set(newValue.clamped(to: 0.25...3.0), forKey: SettingsKey.blinkDurationScale) notifyChange() } } /// Gradient color as NSColor var gradientColor: NSColor { get { NSColor( srgbRed: CGFloat(defaults.double(forKey: SettingsKey.gradientColorRed)), green: CGFloat(defaults.double(forKey: SettingsKey.gradientColorGreen)), blue: CGFloat(defaults.double(forKey: SettingsKey.gradientColorBlue)), alpha: 1.0 ) } set { let c = newValue.usingColorSpace(.sRGB) ?? newValue defaults.set(Double(c.redComponent), forKey: SettingsKey.gradientColorRed) defaults.set(Double(c.greenComponent), forKey: SettingsKey.gradientColorGreen) defaults.set(Double(c.blueComponent), forKey: SettingsKey.gradientColorBlue) notifyChange() } } func resetToDefaults() { for key in [ SettingsKey.intensityScale, SettingsKey.blinkDurationScale, SettingsKey.gradientColorRed, SettingsKey.gradientColorGreen, SettingsKey.gradientColorBlue, ] { defaults.removeObject(forKey: key) } notifyChange() } private func notifyChange() { NotificationCenter.default.post(name: Settings.didChangeNotification, object: nil) } } // MARK: - Comparable Clamping private extension Comparable { func clamped(to range: ClosedRange) -> Self { min(max(self, range.lowerBound), range.upperBound) } }