import AppKit // MainWindowController builds the regular window you can move/resize. // It embeds an AppStatusView (3 simple rows, no scrolling) and a tiny // control bar in the bottom‑left with: // - ⟳ Refresh (forces a status check) // - _ Minimize to Status Bar (switches to overlay mode) final class MainWindowController: NSWindowController { struct Actions { let onRefresh: () -> Void let onMinimizeToStatusBar: () -> Void } private let statusView = AppStatusView() private let actions: Actions init(serviceChecker: ServiceChecker, actions: Actions) { // Initialize stored properties before calling super.init self.actions = actions let style: NSWindow.StyleMask = [.titled, .closable, .miniaturizable, .resizable] let initialRect = NSRect(x: 0, y: 0, width: 720, height: 420) let window = NSWindow(contentRect: initialRect, styleMask: style, backing: .buffered, defer: false) super.init(window: window) window.isReleasedWhenClosed = false window.title = "ProleStatus" window.center() window.level = .normal window.collectionBehavior = [.canJoinAllSpaces] window.appearance = NSAppearance(named: .aqua) // A plain NSView acts as the content container let content = NSView() content.translatesAutoresizingMaskIntoConstraints = false window.contentView = content statusView.translatesAutoresizingMaskIntoConstraints = false content.addSubview(statusView) // Bottom-left control bar with Refresh and Minimize buttons let controls = NSStackView() controls.orientation = .horizontal controls.spacing = 8 controls.alignment = .centerY controls.translatesAutoresizingMaskIntoConstraints = false content.addSubview(controls) let refreshButton = NSButton(title: "⟳", target: nil, action: nil) refreshButton.bezelStyle = .texturedRounded refreshButton.toolTip = "Refresh Now" refreshButton.target = self refreshButton.action = #selector(didTapRefresh) let minimizeButton = NSButton(title: "_", target: nil, action: nil) minimizeButton.bezelStyle = .texturedRounded minimizeButton.toolTip = "Minimize to Status Bar" minimizeButton.target = self minimizeButton.action = #selector(didTapMinimize) controls.addArrangedSubview(refreshButton) controls.addArrangedSubview(minimizeButton) NSLayoutConstraint.activate([ content.widthAnchor.constraint(equalToConstant: initialRect.width), content.heightAnchor.constraint(equalToConstant: initialRect.height), // AppStatusView pinned to top/leading/trailing so timestamp can sit top-right statusView.leadingAnchor.constraint(equalTo: content.leadingAnchor), statusView.trailingAnchor.constraint(equalTo: content.trailingAnchor), statusView.topAnchor.constraint(equalTo: content.topAnchor), controls.leadingAnchor.constraint(equalTo: content.leadingAnchor, constant: 8), controls.bottomAnchor.constraint(equalTo: content.bottomAnchor, constant: -8) ]) statusView.bindTo(serviceChecker: serviceChecker) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func show() { guard let window = window else { return } window.makeKeyAndOrderFront(nil) NSApp.activate(ignoringOtherApps: false) } func hide() { window?.orderOut(nil) } var isVisible: Bool { window?.isVisible ?? false } // MARK: - Actions @objc private func didTapRefresh() { actions.onRefresh() } @objc private func didTapMinimize() { actions.onMinimizeToStatusBar() } }