Files
byre/mac/Sources/Byre/ByreApp.swift
T

140 lines
4.1 KiB
Swift
Raw Normal View History

import AppKit
import SwiftUI
#if DEBUG
#error("debug builds are unsupported: build with mac/bundle.sh")
#endif
typealias ViewState = State
2026-10-16 23:30:57 -07:00
@MainActor
final class AppDelegate: NSObject, NSApplicationDelegate {
private var quitting = false
func applicationDidFinishLaunching(_ notification: Notification) {
Notifier.shared.install()
Updater.shared.start()
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
false
}
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
if flag {
return true
}
Servers.shared.openAll()
return false
}
2026-10-16 23:30:57 -07:00
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
let stores = Servers.shared.connections.values.compactMap(\.store)
guard !stores.isEmpty, !quitting else {
2026-10-16 23:30:57 -07:00
return .terminateNow
}
quitting = true
var replied = false
let reply = {
if !replied {
replied = true
sender.reply(toApplicationShouldTerminate: true)
}
}
Task {
await withTaskGroup(of: Void.self) { group in
for store in stores {
group.addTask {
await store.stop()
}
}
}
2026-10-16 23:30:57 -07:00
reply()
}
Task {
try? await Task.sleep(for: .seconds(2))
reply()
}
return .terminateLater
}
}
@main
struct ByreApp: App {
2026-10-16 23:30:57 -07:00
@NSApplicationDelegateAdaptor private var delegate: AppDelegate
var body: some Scene {
WindowGroup(id: "main", for: String.self) { $origin in
ServerWindow(origin: $origin)
}
2026-10-16 23:30:57 -07:00
.defaultSize(width: 1280, height: 820)
.restorationBehavior(.disabled)
.defaultLaunchBehavior(.presented)
.commands {
ByreCommands()
}
}
}
struct ByreCommands: Commands {
@FocusedValue(\.serverWindow) private var focus
@Environment(\.openWindow) private var openWindow
var body: some Commands {
CommandGroup(after: .appInfo) {
Button("Check for Updates…") {
Updater.shared.check()
2026-10-16 22:46:54 -07:00
}
Button("Forget Server") {
focus?.forget?()
}
.disabled(focus?.forget == nil)
}
CommandGroup(replacing: .newItem) {
Button("New Server Window") {
openWindow(id: "main")
}
.keyboardShortcut("n")
Menu("Open Server") {
ForEach(Servers.shared.origins, id: \.self) { origin in
Button(URL(string: origin)?.host() ?? origin) {
openWindow(id: "main", value: origin)
}
}
}
.disabled(Servers.shared.origins.isEmpty)
}
PasteboardCommands()
CommandMenu("Go") {
goButton("Switch Task", "k")
goButton("Project", "p")
goButton("Lead", "l")
goButton("Merge", "s")
2026-10-18 21:40:27 -07:00
serverButton("Previous Server", "[", -1)
serverButton("Next Server", "]", 1)
Divider()
goButton("Keyboard Shortcuts", "/")
}
}
2026-10-18 21:40:27 -07:00
private func serverButton(_ label: String, _ key: Character, _ step: Int) -> some View {
Button(label) {
if let origin = Servers.shared.step(from: focus?.origin, by: step) {
openWindow(id: "main", value: origin)
}
}
.keyboardShortcut(KeyEquivalent(key))
.disabled(Servers.shared.origins.isEmpty)
}
private func goButton(_ label: String, _ key: String) -> some View {
Button(label) {
if let store = focus?.store, let overlays = focus?.overlays {
runGo(key, store, overlays)
}
}
.keyboardShortcut(KeyEquivalent(Character(key)))
.disabled(focus?.store == nil || focus?.overlays.dialogOpen == true)
}
}