277 lines
11 KiB
Swift
277 lines
11 KiB
Swift
import Foundation
|
|
import AppKit
|
|
|
|
/// Central registry of all user-configurable notch settings.
|
|
enum NotchSettings {
|
|
|
|
enum Keys {
|
|
// General
|
|
static let showOnAllDisplays = "showOnAllDisplays"
|
|
static let openNotchOnHover = "openNotchOnHover"
|
|
static let minimumHoverDuration = "minimumHoverDuration"
|
|
static let showMenuBarIcon = "showMenuBarIcon"
|
|
static let launchAtLogin = "launchAtLogin"
|
|
|
|
// Sizing — closed state
|
|
static let notchHeight = "notchHeight"
|
|
static let nonNotchHeight = "nonNotchHeight"
|
|
static let notchHeightMode = "notchHeightMode"
|
|
static let nonNotchHeightMode = "nonNotchHeightMode"
|
|
|
|
// Sizing — open state
|
|
static let openWidth = "openWidth"
|
|
static let openHeight = "openHeight"
|
|
|
|
// Appearance
|
|
static let enableShadow = "enableShadow"
|
|
static let shadowRadius = "shadowRadius"
|
|
static let shadowOpacity = "shadowOpacity"
|
|
static let cornerRadiusScaling = "cornerRadiusScaling"
|
|
static let notchOpacity = "notchOpacity"
|
|
static let blurRadius = "blurRadius"
|
|
|
|
// Animation
|
|
static let openSpringResponse = "openSpringResponse"
|
|
static let openSpringDamping = "openSpringDamping"
|
|
static let closeSpringResponse = "closeSpringResponse"
|
|
static let closeSpringDamping = "closeSpringDamping"
|
|
static let hoverSpringResponse = "hoverSpringResponse"
|
|
static let hoverSpringDamping = "hoverSpringDamping"
|
|
static let resizeAnimationDuration = "resizeAnimationDuration"
|
|
|
|
// Behavior
|
|
static let enableGestures = "enableGestures"
|
|
static let gestureSensitivity = "gestureSensitivity"
|
|
|
|
// Terminal
|
|
static let terminalFontSize = "terminalFontSize"
|
|
static let terminalShell = "terminalShell"
|
|
static let terminalTheme = "terminalTheme"
|
|
static let terminalSizePresets = "terminalSizePresets"
|
|
static let workspaceSummaries = "workspaceSummaries"
|
|
static let screenAssignments = "screenAssignments"
|
|
|
|
// Hotkeys — each stores a HotkeyBinding JSON string
|
|
static let hotkeyToggle = "hotkey_toggle"
|
|
static let hotkeyNewTab = "hotkey_newTab"
|
|
static let hotkeyCloseTab = "hotkey_closeTab"
|
|
static let hotkeyNextTab = "hotkey_nextTab"
|
|
static let hotkeyPreviousTab = "hotkey_previousTab"
|
|
static let hotkeyNextWorkspace = "hotkey_nextWorkspace"
|
|
static let hotkeyPreviousWorkspace = "hotkey_previousWorkspace"
|
|
static let hotkeyDetachTab = "hotkey_detachTab"
|
|
}
|
|
|
|
enum Defaults {
|
|
static let showOnAllDisplays: Bool = true
|
|
static let openNotchOnHover: Bool = true
|
|
static let minimumHoverDuration: Double = 0.3
|
|
static let showMenuBarIcon: Bool = true
|
|
static let launchAtLogin: Bool = false
|
|
|
|
static let notchHeight: Double = 32
|
|
static let nonNotchHeight: Double = 32
|
|
static let notchHeightMode: Int = 0
|
|
static let nonNotchHeightMode: Int = 1
|
|
|
|
static let openWidth: Double = 640
|
|
static let openHeight: Double = 350
|
|
|
|
static let enableShadow: Bool = true
|
|
static let shadowRadius: Double = 6
|
|
static let shadowOpacity: Double = 0.5
|
|
static let cornerRadiusScaling: Bool = true
|
|
static let notchOpacity: Double = 1.0
|
|
static let blurRadius: Double = 0
|
|
|
|
static let openSpringResponse: Double = 0.42
|
|
static let openSpringDamping: Double = 0.8
|
|
static let closeSpringResponse: Double = 0.45
|
|
static let closeSpringDamping: Double = 1.0
|
|
static let hoverSpringResponse: Double = 0.38
|
|
static let hoverSpringDamping: Double = 0.8
|
|
static let resizeAnimationDuration: Double = 0.42
|
|
|
|
static let enableGestures: Bool = true
|
|
static let gestureSensitivity: Double = 0.5
|
|
|
|
static let terminalFontSize: Double = 13
|
|
static let terminalShell: String = ""
|
|
static let terminalTheme: String = TerminalTheme.terminalApp.rawValue
|
|
static let terminalSizePresets: String = TerminalSizePresetStore.defaultPresetsJSON()
|
|
|
|
// Default hotkey bindings as JSON
|
|
static let hotkeyToggle: String = HotkeyBinding.cmdReturn.toJSON()
|
|
static let hotkeyNewTab: String = HotkeyBinding.cmdT.toJSON()
|
|
static let hotkeyCloseTab: String = HotkeyBinding.cmdW.toJSON()
|
|
static let hotkeyNextTab: String = HotkeyBinding.cmdShiftRB.toJSON()
|
|
static let hotkeyPreviousTab: String = HotkeyBinding.cmdShiftLB.toJSON()
|
|
static let hotkeyNextWorkspace: String = HotkeyBinding.cmdShiftDown.toJSON()
|
|
static let hotkeyPreviousWorkspace: String = HotkeyBinding.cmdShiftUp.toJSON()
|
|
static let hotkeyDetachTab: String = HotkeyBinding.cmdD.toJSON()
|
|
}
|
|
|
|
static func registerDefaults() {
|
|
UserDefaults.standard.register(defaults: [
|
|
Keys.showOnAllDisplays: Defaults.showOnAllDisplays,
|
|
Keys.openNotchOnHover: Defaults.openNotchOnHover,
|
|
Keys.minimumHoverDuration: Defaults.minimumHoverDuration,
|
|
Keys.showMenuBarIcon: Defaults.showMenuBarIcon,
|
|
Keys.launchAtLogin: Defaults.launchAtLogin,
|
|
|
|
Keys.notchHeight: Defaults.notchHeight,
|
|
Keys.nonNotchHeight: Defaults.nonNotchHeight,
|
|
Keys.notchHeightMode: Defaults.notchHeightMode,
|
|
Keys.nonNotchHeightMode: Defaults.nonNotchHeightMode,
|
|
|
|
Keys.openWidth: Defaults.openWidth,
|
|
Keys.openHeight: Defaults.openHeight,
|
|
|
|
Keys.enableShadow: Defaults.enableShadow,
|
|
Keys.shadowRadius: Defaults.shadowRadius,
|
|
Keys.shadowOpacity: Defaults.shadowOpacity,
|
|
Keys.cornerRadiusScaling: Defaults.cornerRadiusScaling,
|
|
Keys.notchOpacity: Defaults.notchOpacity,
|
|
Keys.blurRadius: Defaults.blurRadius,
|
|
|
|
Keys.openSpringResponse: Defaults.openSpringResponse,
|
|
Keys.openSpringDamping: Defaults.openSpringDamping,
|
|
Keys.closeSpringResponse: Defaults.closeSpringResponse,
|
|
Keys.closeSpringDamping: Defaults.closeSpringDamping,
|
|
Keys.hoverSpringResponse: Defaults.hoverSpringResponse,
|
|
Keys.hoverSpringDamping: Defaults.hoverSpringDamping,
|
|
Keys.resizeAnimationDuration: Defaults.resizeAnimationDuration,
|
|
|
|
Keys.enableGestures: Defaults.enableGestures,
|
|
Keys.gestureSensitivity: Defaults.gestureSensitivity,
|
|
|
|
Keys.terminalFontSize: Defaults.terminalFontSize,
|
|
Keys.terminalShell: Defaults.terminalShell,
|
|
Keys.terminalTheme: Defaults.terminalTheme,
|
|
Keys.terminalSizePresets: Defaults.terminalSizePresets,
|
|
|
|
Keys.hotkeyToggle: Defaults.hotkeyToggle,
|
|
Keys.hotkeyNewTab: Defaults.hotkeyNewTab,
|
|
Keys.hotkeyCloseTab: Defaults.hotkeyCloseTab,
|
|
Keys.hotkeyNextTab: Defaults.hotkeyNextTab,
|
|
Keys.hotkeyPreviousTab: Defaults.hotkeyPreviousTab,
|
|
Keys.hotkeyNextWorkspace: Defaults.hotkeyNextWorkspace,
|
|
Keys.hotkeyPreviousWorkspace: Defaults.hotkeyPreviousWorkspace,
|
|
Keys.hotkeyDetachTab: Defaults.hotkeyDetachTab,
|
|
])
|
|
}
|
|
}
|
|
|
|
enum NotchHeightMode: Int, CaseIterable, Identifiable {
|
|
case matchRealNotchSize = 0
|
|
case matchMenuBar = 1
|
|
case custom = 2
|
|
|
|
var id: Int { rawValue }
|
|
var label: String {
|
|
switch self {
|
|
case .matchRealNotchSize: return "Match Notch"
|
|
case .matchMenuBar: return "Match Menu Bar"
|
|
case .custom: return "Custom"
|
|
}
|
|
}
|
|
}
|
|
|
|
enum NonNotchHeightMode: Int, CaseIterable, Identifiable {
|
|
case matchMenuBar = 1
|
|
case custom = 2
|
|
|
|
var id: Int { rawValue }
|
|
var label: String {
|
|
switch self {
|
|
case .matchMenuBar: return "Match Menu Bar"
|
|
case .custom: return "Custom"
|
|
}
|
|
}
|
|
}
|
|
|
|
struct TerminalSizePreset: Codable, Equatable, Identifiable {
|
|
var id: UUID
|
|
var name: String
|
|
var width: Double
|
|
var height: Double
|
|
var hotkey: HotkeyBinding?
|
|
|
|
init(
|
|
id: UUID = UUID(),
|
|
name: String,
|
|
width: Double,
|
|
height: Double,
|
|
hotkey: HotkeyBinding? = nil
|
|
) {
|
|
self.id = id
|
|
self.name = name
|
|
self.width = width
|
|
self.height = height
|
|
self.hotkey = hotkey
|
|
}
|
|
|
|
var size: CGSize {
|
|
CGSize(width: width, height: height)
|
|
}
|
|
}
|
|
|
|
enum TerminalSizePresetStore {
|
|
static func load() -> [TerminalSizePreset] {
|
|
let defaults = UserDefaults.standard
|
|
guard let json = defaults.string(forKey: NotchSettings.Keys.terminalSizePresets),
|
|
let presets = decodePresets(from: json) else {
|
|
return defaultPresets()
|
|
}
|
|
return presets
|
|
}
|
|
|
|
static func save(_ presets: [TerminalSizePreset]) {
|
|
UserDefaults.standard.set(encodePresets(presets), forKey: NotchSettings.Keys.terminalSizePresets)
|
|
}
|
|
|
|
static func reset() {
|
|
save(defaultPresets())
|
|
}
|
|
|
|
static func loadDefaults() -> [TerminalSizePreset] {
|
|
defaultPresets()
|
|
}
|
|
|
|
static func defaultPresetsJSON() -> String {
|
|
encodePresets(defaultPresets())
|
|
}
|
|
|
|
static func suggestedHotkey(for presets: [TerminalSizePreset]) -> HotkeyBinding? {
|
|
let used = Set(presets.compactMap(\.hotkey))
|
|
for digit in 1...9 {
|
|
guard let candidate = HotkeyBinding.cmdShiftDigit(digit) else { continue }
|
|
if !used.contains(candidate) {
|
|
return candidate
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
private static func defaultPresets() -> [TerminalSizePreset] {
|
|
[
|
|
TerminalSizePreset(name: "Compact", width: 480, height: 220, hotkey: HotkeyBinding.cmdShiftDigit(1)),
|
|
TerminalSizePreset(name: "Default", width: 640, height: 350, hotkey: HotkeyBinding.cmdShiftDigit(2)),
|
|
TerminalSizePreset(name: "Large", width: 900, height: 500, hotkey: HotkeyBinding.cmdShiftDigit(3)),
|
|
]
|
|
}
|
|
|
|
static func decodePresets(from json: String) -> [TerminalSizePreset]? {
|
|
guard let data = json.data(using: .utf8) else { return nil }
|
|
return try? JSONDecoder().decode([TerminalSizePreset].self, from: data)
|
|
}
|
|
|
|
static func encodePresets(_ presets: [TerminalSizePreset]) -> String {
|
|
guard let data = try? JSONEncoder().encode(presets),
|
|
let json = String(data: data, encoding: .utf8) else {
|
|
return "[]"
|
|
}
|
|
return json
|
|
}
|
|
}
|