8f8f8b2755
macOS menu bar app providing NHL game situational awareness with league-wide scoreboard, dynamic polling, notifications with team logos, and configurable display options.
74 lines
2.2 KiB
Swift
74 lines
2.2 KiB
Swift
//
|
|
// StatusItemManager.swift
|
|
// IceGlass
|
|
//
|
|
// Copyright 2026 Rouslan Zenetl. All Rights Reserved.
|
|
//
|
|
|
|
import AppKit
|
|
|
|
final class StatusItemManager: @unchecked Sendable {
|
|
private let logger = IceGlassLogger(
|
|
subsystem: Bundle.main.bundleIdentifier ?? "dev.rzen.indie.IceGlass",
|
|
category: "StatusItemManager"
|
|
)
|
|
|
|
static let shared = StatusItemManager()
|
|
|
|
var statusItem: NSStatusItem?
|
|
|
|
private init() {
|
|
DispatchQueue.main.async { [weak self] in
|
|
guard let self = self else {
|
|
AppTerminator.terminate()
|
|
return
|
|
}
|
|
self.setupStatusItem()
|
|
}
|
|
}
|
|
|
|
private func setupStatusItem() {
|
|
logger.debug("Initializing")
|
|
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
|
updateIcon()
|
|
}
|
|
|
|
func updateIcon() {
|
|
Task { @MainActor in
|
|
guard let button = self.statusItem?.button else { return }
|
|
|
|
guard let baseImage = NSImage(named: NSImage.Name("NHLShield")) else {
|
|
button.title = "NHL"
|
|
return
|
|
}
|
|
|
|
let pointSize = button.frame.size.height > 0 ? button.frame.size.height : 22
|
|
let resizedImage = NSImage(size: NSSize(width: pointSize, height: pointSize))
|
|
resizedImage.lockFocus()
|
|
baseImage.draw(
|
|
in: NSRect(x: 0, y: 0, width: pointSize, height: pointSize),
|
|
from: NSRect(x: 0, y: 0, width: baseImage.size.width, height: baseImage.size.height),
|
|
operation: .copy,
|
|
fraction: 1.0
|
|
)
|
|
resizedImage.unlockFocus()
|
|
|
|
button.image = resizedImage
|
|
button.imageScaling = .scaleProportionallyDown
|
|
}
|
|
}
|
|
|
|
/// Update status bar text with per-day game counts (e.g. "6/10/9" or "10/9")
|
|
func updateGameCounts(_ gameDays: [Scoreboard.GameDay]) {
|
|
Task { @MainActor in
|
|
guard let button = self.statusItem?.button else { return }
|
|
if gameDays.isEmpty {
|
|
button.title = ""
|
|
return
|
|
}
|
|
let counts = gameDays.map { "\($0.games.count)" }.joined(separator: "/")
|
|
button.title = " \(counts)"
|
|
}
|
|
}
|
|
}
|