import Foundation import Combine @MainActor final class AppSettingsController: ObservableObject, TerminalSessionConfigurationProviding { static let shared = AppSettingsController( store: UserDefaultsAppSettingsStore(), observeExternalChanges: true ) @Published private(set) var settings: AppSettings private let store: any AppSettingsStoreType private let notificationCenter: NotificationCenter private var defaultsObserver: NSObjectProtocol? init( store: any AppSettingsStoreType, observeExternalChanges: Bool = false, notificationCenter: NotificationCenter = .default ) { self.store = store self.notificationCenter = notificationCenter self.settings = store.load() if observeExternalChanges { defaultsObserver = notificationCenter.addObserver( forName: UserDefaults.didChangeNotification, object: nil, queue: .main ) { [weak self] _ in Task { @MainActor in self?.refresh() } } } } deinit { if let defaultsObserver { notificationCenter.removeObserver(defaultsObserver) } } var terminalSessionConfiguration: TerminalSessionConfiguration { TerminalSessionConfiguration( fontSize: CGFloat(settings.terminal.fontSize), theme: settings.terminal.theme, shellPath: settings.terminal.shellPath ) } var hotkeySettings: AppSettings.HotkeySettings { settings.hotkeys } var terminalSizePresets: [TerminalSizePreset] { settings.terminal.sizePresets } func refresh() { let loaded = store.load() guard loaded != settings else { return } settings = loaded } func update(_ mutate: (inout AppSettings) -> Void) { var updated = settings mutate(&updated) guard updated != settings else { return } settings = updated store.save(updated) } }