Files
phbar/Sources/phbar/Views/BarController.swift
T

108 lines
2.9 KiB
Swift

import SwiftUI
@MainActor
final class BarController: ObservableObject {
let config: PHConfig
let screen: NSScreen
let theme: PHTheme
let window: PHThemeWindow
@Published var blocks: [PHBlock]
var arrangedBlocks: [PHBlock] {
blocks.filter { $0.centered != true }
}
var centeredBlocks: [PHBlock] {
blocks.filter { $0.centered == true }
}
init(config: PHConfig, screen: NSScreen, theme: PHTheme, blocks: [PHBlock], environment: PHEnvironment = .process, debug: Bool) {
self.config = config
self.screen = screen
self.theme = theme
self.window = Self.window(for: config, screen: screen, from: theme)
self.blocks = blocks
for block in blocks {
block.text = text(for: block)
block.style = style(for: block)
block.environment = environment
block.debug = debug
}
}
}
// Theming
extension BarController {
/// Resolve the window definition for a given screen, applying any
/// per-monitor override from the config. Selection lives on `PHConfig`
/// (see `window(screenName:screenIndex:)`); this looks the name up in the
/// theme, falling back to "default".
static func window(for config: PHConfig, screen: NSScreen, from theme: PHTheme) -> PHThemeWindow {
let name = config.window(
screenName: screen.localizedName,
screenIndex: NSScreen.screens.firstIndex(of: screen)
)
return resolve(window: name, from: theme)
}
/// Look up a window definition by name, falling back to "default" then the
/// built-in default.
static func resolve(window name: String, from theme: PHTheme) -> PHThemeWindow {
guard let window = theme.windows?.first(where: { $0.name == name }) else {
guard let defaultWindow = theme.windows?.first(where: { $0.name == "default" }) else {
return PHThemeWindow.default
}
return defaultWindow
}
return window
}
func text(for block: PHBlock) -> PHThemeText {
guard let text = theme.texts?.first(where: { $0.name == block.textName }) else {
guard let defaultText = theme.texts?.first(where: { $0.name == "default" }) else {
return PHThemeText.default
}
return defaultText
}
return text
}
func style(for block: PHBlock) -> PHThemeStyle {
guard let style = theme.styles?.first(where: { $0.name == block.styleName }) else {
guard let defaultStyle = theme.styles?.first(where: { $0.name == "default" }) else {
return PHThemeStyle.default
}
return defaultStyle
}
return style
}
}
// Refresh
extension BarController {
/// Start auto-refresh for every block.
func startAutoRefresh() {
for block in blocks {
block.startAutoRefresh()
}
}
/// Stop auto-refresh for every block.
func stopAutoRefresh() {
for block in blocks {
block.stopAutoRefresh()
}
}
/// Force every block to recompute its label immediately (manual refresh).
/// Each block updates concurrently; the view refreshes as results arrive.
func refresh() {
for block in blocks {
Task { await block.update() }
}
}
}