aboutsummaryrefslogtreecommitdiff
path: root/Hotline/Application-macOS.swift
diff options
context:
space:
mode:
Diffstat (limited to 'Hotline/Application-macOS.swift')
-rw-r--r--Hotline/Application-macOS.swift218
1 files changed, 218 insertions, 0 deletions
diff --git a/Hotline/Application-macOS.swift b/Hotline/Application-macOS.swift
new file mode 100644
index 0000000..34fec3e
--- /dev/null
+++ b/Hotline/Application-macOS.swift
@@ -0,0 +1,218 @@
+import SwiftUI
+import SwiftData
+import UniformTypeIdentifiers
+
+#if os(macOS)
+
+@Observable
+class AppLaunchState {
+ static let shared = AppLaunchState()
+
+ enum LaunchState {
+ case loading
+ case launched
+ case terminated
+ }
+
+ var launchState = LaunchState.loading
+}
+
+class AppDelegate: NSObject, NSApplicationDelegate {
+ func applicationDidFinishLaunching(_ notification: Notification) {
+ AppLaunchState.shared.launchState = .launched
+ }
+
+ func applicationWillTerminate(_ notification: Notification) {
+ AppLaunchState.shared.launchState = .terminated
+ }
+}
+
+@main
+struct Application: App {
+ @Environment(\.scenePhase) private var scenePhase
+ @Environment(\.openWindow) private var openWindow
+ @Environment(\.openURL) private var openURL
+
+ @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
+
+ @State private var preferences = Prefs()
+ @State private var soundEffects = SoundEffectPlayer()
+ @State private var bookmarks = Bookmarks()
+ @State private var hotlinePanel: HotlinePanel? = nil
+
+ @FocusedValue(\.activeHotlineModel) private var activeHotline: Hotline?
+ @FocusedValue(\.activeServerState) private var activeServerState: ServerState?
+
+ var body: some Scene {
+ // MARK: Tracker Window
+ Window("Servers", id: "servers") {
+ TrackerView()
+ .frame(minWidth: 250, minHeight: 250)
+ .environment(bookmarks)
+ }
+ .keyboardShortcut(.init(.init("R"), modifiers: .command))
+ .defaultSize(width: 700, height: 550)
+ .defaultPosition(.center)
+ .onChange(of: AppLaunchState.shared.launchState) {
+ if AppLaunchState.shared.launchState == .launched {
+ showBannerWindow()
+ }
+ }
+
+ // MARK: Server Window
+ WindowGroup(id: "server", for: Server.self) { server in
+ ServerView(server: server)
+ .frame(minWidth: 430, minHeight: 300)
+ .environment(preferences)
+ .environment(soundEffects)
+ .environment(bookmarks)
+ } defaultValue: {
+ Server(name: nil, description: nil, address: "")
+ }
+ .defaultSize(width: 750, height: 700)
+ .defaultPosition(.center)
+ .onChange(of: activeServerState) {
+ ApplicationState.shared.activeServerState = activeServerState
+ }
+ .onChange(of: activeHotline) {
+ ApplicationState.shared.activeHotline = activeHotline
+ }
+ .onChange(of: activeHotline?.serverTitle) {
+ if let hotline = activeHotline {
+ ApplicationState.shared.activeServerName = hotline.serverTitle
+ }
+ }
+ .onChange(of: activeHotline?.bannerImage) {
+ withAnimation {
+ ApplicationState.shared.activeServerBanner = activeHotline?.bannerImage
+ }
+ }
+ .onChange(of: activeHotline) {
+ ApplicationState.shared.activeHotline = activeHotline
+ if let hotline = activeHotline {
+ ApplicationState.shared.activeServerName = hotline.serverTitle
+ }
+ }
+ .commands {
+ CommandGroup(replacing: .newItem) {
+ Button("Connect to Server...") {
+ openWindow(id: "server")
+ }
+ .keyboardShortcut(.init("K"), modifiers: .command)
+ }
+ CommandGroup(after: .singleWindowList) {
+ Button("Toolbar") {
+ toggleBannerWindow()
+ }
+ .keyboardShortcut(.init("\\"), modifiers: [.shift, .command])
+ }
+ CommandGroup(after: .help) {
+ Divider()
+ Button("Request Feature...") {
+ if let url = URL(string: "https://github.com/mierau/hotline/issues/new?labels=enhancement") {
+ openURL(url)
+ }
+ }
+ Button("Report Bug...") {
+ if let url = URL(string: "https://github.com/mierau/hotline/issues/new?labels=bug") {
+ openURL(url)
+ }
+ }
+ }
+ CommandMenu("Server") {
+ Button("Disconnect") {
+ activeHotline?.disconnect()
+ }
+ .disabled(activeHotline?.status == .disconnected)
+ Divider()
+ Button("Broadcast Message...") {
+ // TODO: Implement broadcast message when user is allowed.
+ }
+ .disabled(true)
+ .keyboardShortcut(.init("B"), modifiers: .command)
+ Divider()
+ Button("Show Chat") {
+ activeServerState?.selection = .chat
+ }
+ .disabled(activeHotline?.status != .loggedIn)
+ .keyboardShortcut(.init("1"), modifiers: .command)
+ Button("Show News") {
+ activeServerState?.selection = .news
+ }
+ .disabled(activeHotline?.status != .loggedIn)
+ .keyboardShortcut(.init("2"), modifiers: .command)
+ Button("Show Message Board") {
+ activeServerState?.selection = .board
+ }
+ .disabled(activeHotline?.status != .loggedIn)
+ .keyboardShortcut(.init("3"), modifiers: .command)
+ Button("Show Files") {
+ activeServerState?.selection = .files
+ }
+ .disabled(activeHotline?.status != .loggedIn)
+ .keyboardShortcut(.init("4"), modifiers: .command)
+ }
+ }
+
+ // MARK: Settings Window
+ Settings {
+ SettingsView()
+ .environment(preferences)
+ }
+
+ // MARK: News Editor Window
+// WindowGroup(id: "news-editor", for: NewsArticle.self) { $article in
+// NewsEditorView(article: $article)
+// }
+// .windowResizability(.contentSize)
+// .windowStyle(.titleBar)
+// .windowToolbarStyle(.unifiedCompact(showsTitle: true))
+// .defaultSize(width: 450, height: 550)
+// .defaultPosition(.center)
+
+ // MARK: Image Preview Window
+ WindowGroup(id: "preview-image", for: PreviewFileInfo.self) { $info in
+ FilePreviewImageView(info: $info)
+ }
+ .windowResizability(.contentSize)
+ .windowStyle(.titleBar)
+ .windowToolbarStyle(.unifiedCompact(showsTitle: true))
+ .defaultSize(width: 350, height: 150)
+ .defaultPosition(.center)
+
+ // MARK: Text Preview Window
+ WindowGroup(id: "preview-text", for: PreviewFileInfo.self) { $info in
+ FilePreviewTextView(info: $info)
+ }
+ .windowResizability(.automatic)
+ .windowStyle(.titleBar)
+ .windowToolbarStyle(.unifiedCompact(showsTitle: true))
+ .defaultSize(width: 450, height: 550)
+ .defaultPosition(.center)
+ }
+
+ func showBannerWindow() {
+ if hotlinePanel == nil {
+ hotlinePanel = HotlinePanel(HotlinePanelView())
+ }
+
+ if hotlinePanel?.isVisible == false {
+ hotlinePanel?.orderFront(nil)
+ }
+ }
+
+ func toggleBannerWindow() {
+ if hotlinePanel == nil {
+ hotlinePanel = HotlinePanel(HotlinePanelView())
+ }
+
+ if hotlinePanel?.isVisible == true {
+ hotlinePanel?.orderOut(nil)
+ }
+ else {
+ hotlinePanel?.orderFront(nil)
+ }
+ }
+}
+
+#endif