ProdDash Viewer 1.0.0: a Mac app that only shows ProdDash, with a tab per installation
A new Apple-silicon app in viewer/macos (Swift, no dependencies, ~1 MB): one window showing a ProdDash dashboard in WebKit, and nothing else. It runs no server; it points at any ProdDash on the network. - Connections (name + address) in Settings; the add/edit sheet asks /api/modules whether ProdDash answers as you type. No port means 24500. - Two or more connections bring a slim tab bar of their names. In a window it floats over the dashboard and comes out while the pointer is on the title bar; it is not part of the title bar, because anything there makes WebKit push the page down. In full screen it is a titlebar accessory that comes down with the menu bar, and it flashes up after each switch. ⌃Tab / ⌃⇧Tab and ⌘1–9 switch from the keyboard. - Full screen, reopening in full screen if it quit there; window size and the selected tab are kept too. The dashboard's own full-screen button works as well. - Menus: View (Back, Forward, Reload Page, Enter Full Screen), Settings, Edit (copy/paste in the page's text fields), Window, Help (a guide that ships in the app). - Every installation keeps its own live web view. One that can't be reached says why and retries at 2, 4, 8, then every 15 s; a redirect off the installation is reported, not handed to the browser. JS alert, confirm and prompt show as sheets; links to other sites open in the browser. - General settings: open at login (SMAppService), keep the display awake while a dashboard is on screen (default on). build.sh signs with the Developer ID when one is installed and makes a notarised DMG with --notarize, as the launcher's does. It needs Xcode: with only the command line tools the macOS 27 SDK can't expand SwiftUI's @State. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c043834d1e
commit
8d8c0ee0c3
@@ -0,0 +1,61 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user