import Foundation import ServiceManagement /// The viewer's own preferences. The connections themselves are in /// ConnectionStore. final class ViewerSettings: ObservableObject { static let shared = ViewerSettings() private let defaults = UserDefaults.standard /// Keep the display on while a dashboard is on screen — a booth display /// that dims halfway through a service is the failure this is here for. @Published var keepDisplayAwake: Bool { didSet { defaults.set(keepDisplayAwake, forKey: "keepDisplayAwake") } } private init() { defaults.register(defaults: ["keepDisplayAwake": true]) keepDisplayAwake = defaults.bool(forKey: "keepDisplayAwake") } /// The window was in full screen when the viewer last quit, so it opens in /// full screen again — a booth Mac that restarts comes back as it was left. var reopenInFullScreen: Bool { get { defaults.bool(forKey: "reopenInFullScreen") } set { defaults.set(newValue, forKey: "reopenInFullScreen") } } /// The tab that was showing, so the viewer reopens on it. var selectedConnection: UUID? { get { defaults.string(forKey: "selectedConnection").flatMap(UUID.init(uuidString:)) } set { defaults.set(newValue?.uuidString, forKey: "selectedConnection") } } } /// "Open at login", through the macOS 13 login-item API. The operator may /// still have to approve it in System Settings — hence `needsApproval`, which /// Settings shows rather than failing silently. enum LoginItem { static var isEnabled: Bool { SMAppService.mainApp.status == .enabled } static var needsApproval: Bool { SMAppService.mainApp.status == .requiresApproval } /// Nil when it worked; otherwise what went wrong, for Settings to show. static func set(_ enabled: Bool) -> String? { do { if enabled { if SMAppService.mainApp.status != .enabled { try SMAppService.mainApp.register() } } else { if SMAppService.mainApp.status != .notRegistered { try SMAppService.mainApp.unregister() } } return nil } catch { return error.localizedDescription } } static func openSystemSettings() { SMAppService.openSystemSettingsLoginItems() } }