Files

213 lines
11 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Cocoa
import UserNotifications
@MainActor
final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDelegate {
static weak var shared: AppDelegate?
private(set) var windowControllers: [MainWindowController] = []
override init() {
super.init()
AppDelegate.shared = self
}
func applicationDidFinishLaunching(_ notification: Notification) {
setupMainMenu()
setupNotifications()
let initialController = MainWindowController()
addWindowController(initialController)
initialController.showWindow(nil)
NSApp.activate(ignoringOtherApps: true)
}
func addWindowController(_ controller: MainWindowController) {
if !windowControllers.contains(where: { $0 === controller }) {
windowControllers.append(controller)
}
}
func removeWindowController(_ controller: MainWindowController) {
windowControllers.removeAll(where: { $0 === controller })
}
private func setupNotifications() {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.alert, .badge, .sound]) { _, _ in }
}
nonisolated func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.banner, .badge, .sound])
}
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
if !flag {
if let first = windowControllers.first {
first.showWindow(nil)
} else {
let controller = MainWindowController()
addWindowController(controller)
controller.showWindow(nil)
}
}
return true
}
private func setupMainMenu() {
let mainMenu = NSMenu()
// App Menu
let appMenuItem = NSMenuItem()
let appMenu = NSMenu(title: "SHD")
appMenu.addItem(withTitle: "О программе SHD", action: #selector(NSApplication.orderFrontStandardAboutPanel(_:)), keyEquivalent: "")
appMenu.addItem(NSMenuItem.separator())
appMenu.addItem(withTitle: "Скрыть SHD", action: #selector(NSApplication.hide(_:)), keyEquivalent: "h")
let hideOthersItem = appMenu.addItem(withTitle: "Скрыть остальные", action: #selector(NSApplication.hideOtherApplications(_:)), keyEquivalent: "h")
hideOthersItem.keyEquivalentModifierMask = [.command, .option]
appMenu.addItem(withTitle: "Показать все", action: #selector(NSApplication.unhideAllApplications(_:)), keyEquivalent: "")
appMenu.addItem(NSMenuItem.separator())
appMenu.addItem(withTitle: "Завершить SHD", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")
appMenuItem.submenu = appMenu
mainMenu.addItem(appMenuItem)
// File Menu (New Tab, New Window, Print, Close)
let fileMenuItem = NSMenuItem()
let fileMenu = NSMenu(title: "Файл")
fileMenu.addItem(withTitle: "Новая вкладка", action: #selector(onNewTab), keyEquivalent: "t")
fileMenu.addItem(withTitle: "Новое окно", action: #selector(onNewWindow), keyEquivalent: "n")
fileMenu.addItem(NSMenuItem.separator())
fileMenu.addItem(withTitle: "Напечатать…", action: #selector(onPrint), keyEquivalent: "p")
fileMenu.addItem(NSMenuItem.separator())
fileMenu.addItem(withTitle: "Закрыть вкладку", action: #selector(onCloseTabOrWindow), keyEquivalent: "w")
fileMenuItem.submenu = fileMenu
mainMenu.addItem(fileMenuItem)
// Edit Menu
let editMenuItem = NSMenuItem()
let editMenu = NSMenu(title: "Правка")
editMenu.addItem(withTitle: "Отменить", action: Selector(("undo:")), keyEquivalent: "z")
let redoItem = editMenu.addItem(withTitle: "Повторить", action: Selector(("redo:")), keyEquivalent: "z")
redoItem.keyEquivalentModifierMask = [.command, .shift]
editMenu.addItem(NSMenuItem.separator())
editMenu.addItem(withTitle: "Вырезать", action: #selector(NSText.cut(_:)), keyEquivalent: "x")
editMenu.addItem(withTitle: "Скопировать", action: #selector(NSText.copy(_:)), keyEquivalent: "c")
editMenu.addItem(withTitle: "Вставить", action: #selector(NSText.paste(_:)), keyEquivalent: "v")
editMenu.addItem(withTitle: "Выбрать всё", action: #selector(NSText.selectAll(_:)), keyEquivalent: "a")
editMenuItem.submenu = editMenu
mainMenu.addItem(editMenuItem)
// View Menu
let viewMenuItem = NSMenuItem()
let viewMenu = NSMenu(title: "Вид")
viewMenu.addItem(withTitle: "Обновить", action: #selector(onReload), keyEquivalent: "r")
let hardReload = viewMenu.addItem(withTitle: "Очистить кэш и обновить", action: #selector(onHardReload), keyEquivalent: "r")
hardReload.keyEquivalentModifierMask = [.command, .shift]
viewMenu.addItem(NSMenuItem.separator())
viewMenu.addItem(withTitle: "Увеличить", action: #selector(onZoomIn), keyEquivalent: "+")
viewMenu.addItem(withTitle: "Уменьшить", action: #selector(onZoomOut), keyEquivalent: "-")
viewMenu.addItem(withTitle: "Исходный масштаб", action: #selector(onResetZoom), keyEquivalent: "0")
viewMenu.addItem(NSMenuItem.separator())
viewMenu.addItem(withTitle: "Полноэкранный режим", action: #selector(NSWindow.toggleFullScreen(_:)), keyEquivalent: "f")
viewMenu.addItem(NSMenuItem.separator())
let inspectorItem = viewMenu.addItem(withTitle: "Инспектор веб-страницы", action: #selector(onShowInspector), keyEquivalent: "i")
inspectorItem.keyEquivalentModifierMask = [.command, .option]
let consoleItem = viewMenu.addItem(withTitle: "Консоль JavaScript", action: #selector(onShowConsole), keyEquivalent: "c")
consoleItem.keyEquivalentModifierMask = [.command, .option]
viewMenuItem.submenu = viewMenu
mainMenu.addItem(viewMenuItem)
// Environment Menu
let envMenuItem = NSMenuItem()
let envMenu = NSMenu(title: "Контур")
let prodItem = envMenu.addItem(withTitle: "SHD Production (shd.xyz.su)", action: #selector(onSelectProd), keyEquivalent: "1")
prodItem.target = self
let devItem = envMenu.addItem(withTitle: "SHD Dev (dev-shd.xyz.su)", action: #selector(onSelectDev), keyEquivalent: "2")
devItem.target = self
envMenuItem.submenu = envMenu
mainMenu.addItem(envMenuItem)
// History Menu
let historyMenuItem = NSMenuItem()
let historyMenu = NSMenu(title: "История")
historyMenu.addItem(withTitle: "Назад", action: #selector(onGoBack), keyEquivalent: "[")
historyMenu.addItem(withTitle: "Вперед", action: #selector(onGoForward), keyEquivalent: "]")
historyMenuItem.submenu = historyMenu
mainMenu.addItem(historyMenuItem)
// Window Menu
let windowMenuItem = NSMenuItem()
let windowMenu = NSMenu(title: "Окно")
windowMenu.addItem(withTitle: "Убрать в Dock", action: #selector(NSWindow.performMiniaturize(_:)), keyEquivalent: "m")
windowMenu.addItem(withTitle: "Масштабировать", action: #selector(NSWindow.performZoom(_:)), keyEquivalent: "")
windowMenu.addItem(NSMenuItem.separator())
windowMenu.addItem(withTitle: "Объединить все окна", action: #selector(NSWindow.mergeAllWindows(_:)), keyEquivalent: "")
windowMenuItem.submenu = windowMenu
mainMenu.addItem(windowMenuItem)
NSApp.mainMenu = mainMenu
NSApp.windowsMenu = windowMenu
}
private var currentActiveController: MainWindowController? {
guard let keyWindow = NSApp.keyWindow else { return windowControllers.first }
return windowControllers.first(where: { $0.window === keyWindow }) ?? windowControllers.first
}
@objc private func onNewWindow() {
let controller = MainWindowController()
addWindowController(controller)
controller.showWindow(nil)
controller.window?.center()
}
@objc private func onNewTab() {
let controller = MainWindowController()
addWindowController(controller)
if let keyWindow = NSApp.keyWindow, let newWindow = controller.window {
keyWindow.addTabbedWindow(newWindow, ordered: .above)
newWindow.makeKeyAndOrderFront(nil)
} else {
controller.showWindow(nil)
}
}
func openTab(with request: URLRequest, relativeTo parentWindow: NSWindow?) {
let controller = MainWindowController(initialRequest: request)
addWindowController(controller)
if let hostWindow = parentWindow ?? NSApp.keyWindow, let newWindow = controller.window {
hostWindow.addTabbedWindow(newWindow, ordered: .above)
newWindow.makeKeyAndOrderFront(nil)
} else {
controller.showWindow(nil)
}
}
@objc private func onCloseTabOrWindow() {
if let keyWindow = NSApp.keyWindow {
keyWindow.performClose(nil)
}
}
@objc private func onPrint() { currentActiveController?.printCurrentPage() }
@objc private func onReload() { currentActiveController?.reload() }
@objc private func onHardReload() { currentActiveController?.reloadIgnoringCache() }
@objc private func onZoomIn() { currentActiveController?.zoomIn() }
@objc private func onZoomOut() { currentActiveController?.zoomOut() }
@objc private func onResetZoom() { currentActiveController?.resetZoom() }
@objc private func onGoBack() { currentActiveController?.goBack() }
@objc private func onGoForward() { currentActiveController?.goForward() }
@objc private func onSelectProd() { currentActiveController?.navigateToEnvironment(.production) }
@objc private func onSelectDev() { currentActiveController?.navigateToEnvironment(.dev) }
@objc private func onShowInspector() { currentActiveController?.showInspector() }
@objc private func onShowConsole() { currentActiveController?.showConsole() }
}
MainActor.assumeIsolated {
let app = NSApplication.shared
let delegate = AppDelegate()
app.delegate = delegate
app.run()
}