// // ZyquoCloudApp.swift // Zyquo Cloud // // Author: Simon-Pierre Boucher // Mail: contact@spboucher.ai // import SwiftUI struct ZyquoCloudApp: App { @NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate @StateObject private var environment = AppEnvironment() @State private var quickChat: QuickChatController? @AppStorage("menuBarExtraEnabled") private var menuBarExtraEnabled = true var body: some Scene { WindowGroup("Zyquo Cloud") { MainWindowView() .environmentObject(environment.conversations) .environmentObject(environment.catalog) .environmentObject(environment.vault) .environmentObject(environment.appearance) .onAppear { if quickChat == nil { quickChat = QuickChatController(environment: environment) } } } .defaultSize( width: ZyquoMetrics.windowDefaultWidth, height: ZyquoMetrics.windowDefaultHeight ) .commands { AppCommands(environment: environment, quickChat: { quickChat }) } Settings { SettingsView() .environmentObject(environment.conversations) .environmentObject(environment.catalog) .environmentObject(environment.vault) .environmentObject(environment.appearance) } MenuBarExtra(isInserted: $menuBarExtraEnabled) { Button("New Chat") { _ = environment.conversations.newConversation() NSApp.activate(ignoringOtherApps: true) } Button("Quick Chat ⌄Space") { quickChat?.show() } Divider() Button("Open Zyquo Cloud") { NSApp.activate(ignoringOtherApps: true) } Button("Quit") { NSApp.terminate(nil) } } label: { MenuBarIconView() } } } /// Menu bar glyph: the shipped template PNG when bundled, SF Symbol fallback /// during `swift run` (no bundle resources). struct MenuBarIconView: View { var body: some View { if let image = Self.templateImage() { Image(nsImage: image) } else { Image(systemName: "cloud.fill") } } private static func templateImage() -> NSImage? { guard let path = Bundle.main.path(forResource: "MenuBarIcon", ofType: "png"), let image = NSImage(contentsOfFile: path) else { return nil } image.isTemplate = true image.size = NSSize(width: 18, height: 18) return image } } final class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { // Ensure the app fronts correctly when launched outside Finder // (e.g. `swift run` or `open` from a terminal during development). NSApplication.shared.setActivationPolicy(.regular) NSApplication.shared.activate(ignoringOtherApps: true) } } /// App-level menu commands and shortcuts. struct AppCommands: Commands { let environment: AppEnvironment var quickChat: () -> QuickChatController? var body: some Commands { CommandGroup(replacing: .newItem) { Button("New Chat") { _ = environment.conversations.newConversation() } .keyboardShortcut("n", modifiers: .command) } CommandMenu("Chat") { Button("Quick Chat") { quickChat()?.show() } Button("Stop Generating") { if let id = environment.conversations.selectedID { environment.conversations.stopStreaming(id) } } .keyboardShortcut(".", modifiers: .command) Divider() Button("Export Conversation…") { if let conversation = environment.conversations.selected { ConversationExporter.presentSavePanel(for: conversation) } } .keyboardShortcut("e", modifiers: [.command, .shift]) } } }