98 lines
3.3 KiB
Swift
98 lines
3.3 KiB
Swift
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>) -> Self {
|
|
min(max(self, range.lowerBound), range.upperBound)
|
|
}
|
|
}
|