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
82 lines
3.3 KiB
Swift
82 lines
3.3 KiB
Swift
import AppKit
|
|
import Foundation
|
|
|
|
// Simple .properties loader with bundle defaults and user override support
|
|
final class Config {
|
|
static let shared = Config()
|
|
|
|
private var props: [String: String] = [:]
|
|
|
|
private init() {
|
|
// Defaults
|
|
props = [
|
|
"svc.host": "svc.prole.org",
|
|
"svc.port": "443",
|
|
"k3s.retropie.host": "retropie.prole.org",
|
|
"k3s.retropie.port": "6443",
|
|
"k3s.pi.host": "pi.prole.org",
|
|
"k3s.pi.port": "6443",
|
|
"k3d.local.host": "localhost",
|
|
"k3d.local.port": "6443"
|
|
]
|
|
|
|
// Load bundled defaults if present
|
|
if let url = Bundle.main.url(forResource: "prole", withExtension: "properties") {
|
|
merge(loadProperties(url: url))
|
|
}
|
|
|
|
// Load user override from Application Support
|
|
let fm = FileManager.default
|
|
if let appSupport = try? fm.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false) {
|
|
let dir = appSupport.appendingPathComponent("Prole", isDirectory: true)
|
|
let url = dir.appendingPathComponent("prole.properties")
|
|
if fm.fileExists(atPath: url.path) {
|
|
merge(loadProperties(url: url))
|
|
}
|
|
}
|
|
}
|
|
|
|
private func merge(_ other: [String: String]) { for (k, v) in other { props[k] = v } }
|
|
|
|
private func loadProperties(url: URL) -> [String: String] {
|
|
guard let data = try? Data(contentsOf: url), let text = String(data: data, encoding: .utf8) else { return [:] }
|
|
var result: [String: String] = [:]
|
|
for line in text.components(separatedBy: .newlines) {
|
|
let trimmed = line.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
if trimmed.isEmpty || trimmed.hasPrefix("#") { continue }
|
|
if let eq = trimmed.firstIndex(of: "=") {
|
|
let key = String(trimmed[..<eq]).trimmingCharacters(in: .whitespaces)
|
|
let value = String(trimmed[trimmed.index(after: eq)...]).trimmingCharacters(in: .whitespaces)
|
|
if !key.isEmpty { result[key] = value }
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func string(_ key: String, default def: String) -> String { props[key] ?? def }
|
|
func int(_ key: String, default def: Int) -> Int { Int(props[key] ?? "") ?? def }
|
|
|
|
// Convenience accessors used by ServiceChecker/StatusView
|
|
var svcHost: String { string("svc.host", default: "svc.prole.org") }
|
|
var svcPort: Int { int("svc.port", default: 443) }
|
|
|
|
var retropieHost: String { string("k3s.retropie.host", default: "retropie.prole.org") }
|
|
var retropiePort: Int { int("k3s.retropie.port", default: 6443) }
|
|
|
|
var piHost: String { string("k3s.pi.host", default: "pi.prole.org") }
|
|
var piPort: Int { int("k3s.pi.port", default: 6443) }
|
|
|
|
var localHost: String { string("k3d.local.host", default: "localhost") }
|
|
var localPort: Int { int("k3d.local.port", default: 6443) }
|
|
|
|
// UI asset config
|
|
// Background image file name relative to the app bundle Resources. If a path is provided, only the last component is used.
|
|
var uiBackground: String {
|
|
let raw = string("ui.background", default: "img/proleLogoSepia.png")
|
|
if let lastSlash = raw.lastIndex(of: "/") {
|
|
return String(raw[raw.index(after: lastSlash)...])
|
|
}
|
|
return raw
|
|
}
|
|
}
|