mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 11:03:59 +00:00
- Default to Application Window mode with full app menu; status bar overlay remains available - Restore clickable startup Splash Tip (5s) with animated GIF and live counter; use light theme (Aqua) - Status bar item: monospaced "P" icon; left click shows overlay (status mode) or main window (app mode) - Overlay: add Maximize button (□) to toggle back to main window; keep click‑through elsewhere - Global hotkey Cmd+Opt+Shift+P toggles modes; Prole menu item mirrors the same toggle and updates title dynamically - Application menu (Prole): Show Status Bar / Show Main Window (contextual), Refresh Now, Quit - Application Window layout: non‑scrolling, vertical 1‑line rows (svc, k3s aggregate, local) with top‑right timestamp; bottom‑left controls (⟳ Refresh, _ Minimize) - Parameterize endpoints via `prole.properties` (bundled + user override). Replace legacy raspberry with retropie defaults - ServiceChecker + UI read endpoints from Config loader; tooltips/labels reflect configured hosts/ports - Build script: generate `Info.plist` with `LSUIElement=false`; bundle resources (`prole-type.gif`, `prole.properties`); ad‑hoc codesign. Universal build supported - Documentation: rewrite README with technical build/run/config details and operational posture Files: - proleStatus/Sources/: AppDelegate.swift, OverlayWindow.swift, StatusView.swift, StatusItemController.swift, SplashTipWindowController.swift, MainWindowController.swift, AppStatusView.swift, ServiceChecker.swift, Config.swift - proleStatus/build.sh - proleStatus/prole.properties - proleStatus/README.md Notes: - Build verified via `./build.sh build` (arm64). App starts in App Window mode with light theme; menu + hotkey + overlay toggle operate as intended
103 lines
3.4 KiB
Swift
103 lines
3.4 KiB
Swift
import AppKit
|
|
|
|
final class StatusItemController {
|
|
struct Actions {
|
|
let onLeftClick: () -> Void
|
|
let onToggleStatusBar: () -> Void
|
|
let onToggleAppWindow: () -> Void
|
|
let onRefresh: () -> Void
|
|
let onQuit: () -> Void
|
|
}
|
|
|
|
private var statusItem: NSStatusItem?
|
|
private let actions: Actions
|
|
private var stateStatusBarVisible: Bool = true
|
|
private var stateAppWindowVisible: Bool = false
|
|
|
|
init(actions: Actions) {
|
|
self.actions = actions
|
|
createStatusItemIfNeeded()
|
|
}
|
|
|
|
func setState(statusBarVisible: Bool, appWindowVisible: Bool) {
|
|
self.stateStatusBarVisible = statusBarVisible
|
|
self.stateAppWindowVisible = appWindowVisible
|
|
}
|
|
|
|
func hideStatusItem() {
|
|
if let item = statusItem {
|
|
NSStatusBar.system.removeStatusItem(item)
|
|
statusItem = nil
|
|
}
|
|
}
|
|
|
|
func showStatusItem() {
|
|
createStatusItemIfNeeded()
|
|
}
|
|
|
|
var isVisible: Bool { statusItem != nil }
|
|
|
|
private func createStatusItemIfNeeded() {
|
|
guard statusItem == nil else { return }
|
|
let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
|
statusItem = item
|
|
if let button = item.button {
|
|
let font = NSFont.monospacedSystemFont(ofSize: 13, weight: .bold)
|
|
button.image = nil
|
|
button.attributedTitle = NSAttributedString(string: "P", attributes: [ .font: font ])
|
|
button.target = self
|
|
button.action = #selector(handleClick)
|
|
button.sendAction(on: [.leftMouseUp, .rightMouseUp])
|
|
button.toolTip = "ProleStatus"
|
|
}
|
|
}
|
|
|
|
@objc private func handleClick(_ sender: Any?) {
|
|
guard let event = NSApp.currentEvent else {
|
|
actions.onLeftClick(); return
|
|
}
|
|
switch event.type {
|
|
case .rightMouseUp:
|
|
showMenu()
|
|
default:
|
|
actions.onLeftClick()
|
|
}
|
|
}
|
|
|
|
private func showMenu() {
|
|
guard let button = statusItem?.button else { return }
|
|
let menu = NSMenu(title: "ProleStatus")
|
|
|
|
let statusBarTitle = stateStatusBarVisible ? "Hide Status Bar Icon" : "Show Status Bar Icon"
|
|
let appWindowTitle = stateAppWindowVisible ? "Hide Application Window" : "Show Application Window"
|
|
|
|
let sbItem = NSMenuItem(title: statusBarTitle, action: #selector(toggleStatusBar), keyEquivalent: "")
|
|
sbItem.target = self
|
|
menu.addItem(sbItem)
|
|
|
|
let winItem = NSMenuItem(title: appWindowTitle, action: #selector(toggleAppWindow), keyEquivalent: "")
|
|
winItem.target = self
|
|
menu.addItem(winItem)
|
|
|
|
menu.addItem(.separator())
|
|
|
|
let refreshItem = NSMenuItem(title: "Refresh Now", action: #selector(refreshNow), keyEquivalent: "r")
|
|
refreshItem.target = self
|
|
menu.addItem(refreshItem)
|
|
|
|
menu.addItem(.separator())
|
|
|
|
let quitItem = NSMenuItem(title: "Quit ProleStatus", action: #selector(quitApp), keyEquivalent: "q")
|
|
quitItem.target = self
|
|
menu.addItem(quitItem)
|
|
|
|
let point = NSPoint(x: 0, y: button.bounds.minY - 3)
|
|
menu.popUp(positioning: nil, at: point, in: button)
|
|
}
|
|
|
|
@objc private func toggleStatusBar() { actions.onToggleStatusBar() }
|
|
@objc private func toggleAppWindow() { actions.onToggleAppWindow() }
|
|
@objc private func refreshNow() { actions.onRefresh() }
|
|
@objc private func quitApp() { actions.onQuit() }
|
|
}
|