Initial commit: IceGlass NHL game tracker
macOS menu bar app providing NHL game situational awareness with league-wide scoreboard, dynamic polling, notifications with team logos, and configurable display options.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// 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)"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user