131 lines
3.7 KiB
Swift
131 lines
3.7 KiB
Swift
import AppKit
|
|
import SwiftUI
|
|
|
|
#if DEBUG
|
|
#error("debug builds are unsupported: build with mac/bundle.sh")
|
|
#endif
|
|
|
|
typealias ViewState = State
|
|
|
|
@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.openWindow?()
|
|
return false
|
|
}
|
|
|
|
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
|
|
let stores = Servers.shared.connections.values.compactMap(\.store)
|
|
guard !stores.isEmpty, !quitting else {
|
|
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()
|
|
}
|
|
}
|
|
}
|
|
reply()
|
|
}
|
|
Task {
|
|
try? await Task.sleep(for: .seconds(2))
|
|
reply()
|
|
}
|
|
return .terminateLater
|
|
}
|
|
}
|
|
|
|
@main
|
|
struct ByreApp: App {
|
|
@NSApplicationDelegateAdaptor private var delegate: AppDelegate
|
|
|
|
var body: some Scene {
|
|
Window("byre", id: "main") {
|
|
ServerWindow()
|
|
}
|
|
.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()
|
|
}
|
|
Button("Forget Server") {
|
|
focus?.forget()
|
|
}
|
|
.disabled(focus == nil)
|
|
}
|
|
CommandGroup(replacing: .newItem) {
|
|
Button("Add Server…") {
|
|
Servers.shared.current = nil
|
|
openWindow(id: "main")
|
|
}
|
|
.keyboardShortcut("n")
|
|
}
|
|
PasteboardCommands()
|
|
CommandMenu("Go") {
|
|
goButton("Switch Task", "k")
|
|
goButton("Project", "p")
|
|
goButton("Lead", "l")
|
|
goButton("Merge", "s")
|
|
serverButton("Previous Server", "[", -1)
|
|
serverButton("Next Server", "]", 1)
|
|
Divider()
|
|
goButton("Keyboard Shortcuts", "/")
|
|
}
|
|
}
|
|
|
|
private func serverButton(_ label: String, _ key: Character, _ step: Int) -> some View {
|
|
Button(label) {
|
|
Servers.shared.current = Servers.shared.step(from: Servers.shared.current, by: step)
|
|
}
|
|
.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)
|
|
}
|
|
}
|