AppDelegate.swift 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. //
  2. // AppDelegate.swift
  3. // smart_printer
  4. //
  5. import Cocoa
  6. import Contacts
  7. @main
  8. class AppDelegate: NSObject, NSApplicationDelegate {
  9. private weak var mainWindowController: MainWindowController?
  10. func applicationWillFinishLaunching(_ notification: Notification) {
  11. AppSettings.applyAppearance()
  12. }
  13. func applicationDidFinishLaunching(_ notification: Notification) {
  14. StoreManager.shared.start()
  15. resolveMainWindowController()
  16. configureMainWindow()
  17. configurePreferencesMenu()
  18. observeContactChanges()
  19. prefetchContactsIfAuthorized()
  20. NSApp.activate(ignoringOtherApps: true)
  21. }
  22. private func observeContactChanges() {
  23. NotificationCenter.default.addObserver(
  24. self,
  25. selector: #selector(contactsDidChange),
  26. name: .CNContactStoreDidChange,
  27. object: nil
  28. )
  29. }
  30. @objc private func contactsDidChange() {
  31. ContactsService.invalidateCache()
  32. }
  33. private func prefetchContactsIfAuthorized() {
  34. guard ContactsService.isAuthorized else { return }
  35. Task { @MainActor in
  36. _ = try? await ContactsService.loadContacts()
  37. }
  38. }
  39. @objc func showSettings(_ sender: Any?) {
  40. NSApp.activate(ignoringOtherApps: true)
  41. mainWindow?.makeKeyAndOrderFront(nil)
  42. NotificationCenter.default.post(name: .showSettings, object: nil)
  43. }
  44. private func configurePreferencesMenu() {
  45. guard let preferencesItem = NSApp.mainMenu?
  46. .item(withTitle: "smart_printer")?
  47. .submenu?
  48. .item(withTitle: "Preferences…") else { return }
  49. preferencesItem.target = self
  50. preferencesItem.action = #selector(showSettings(_:))
  51. }
  52. func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
  53. false
  54. }
  55. func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
  56. if !flag {
  57. resolveMainWindowController()
  58. mainWindowController?.showWindow(self)
  59. mainWindowController?.window?.makeKeyAndOrderFront(self)
  60. NSApp.activate(ignoringOtherApps: true)
  61. }
  62. return true
  63. }
  64. func applicationShouldRestoreApplicationState(_ app: NSApplication) -> Bool {
  65. false
  66. }
  67. private func configureMainWindow() {
  68. guard let window = mainWindow else {
  69. DispatchQueue.main.async { [weak self] in
  70. self?.configureMainWindow()
  71. }
  72. return
  73. }
  74. window.title = "Smart Printer"
  75. window.titlebarAppearsTransparent = true
  76. window.titleVisibility = .hidden
  77. window.styleMask.insert(.fullSizeContentView)
  78. window.isMovableByWindowBackground = true
  79. window.backgroundColor = AppTheme.background
  80. let defaultSize = NSSize(width: AppTheme.windowWidth, height: AppTheme.windowHeight)
  81. window.setContentSize(defaultSize)
  82. window.minSize = NSSize(width: AppTheme.windowMinWidth, height: AppTheme.windowMinHeight)
  83. window.maxSize = defaultSize
  84. window.isRestorable = false
  85. centerWindowOnScreen(window)
  86. DispatchQueue.main.async {
  87. self.centerWindowOnScreen(window)
  88. window.makeKeyAndOrderFront(nil)
  89. }
  90. }
  91. private func centerWindowOnScreen(_ window: NSWindow) {
  92. let screen = NSScreen.main ?? window.screen ?? NSScreen.screens.first
  93. guard let visibleFrame = screen?.visibleFrame else {
  94. window.center()
  95. return
  96. }
  97. var frame = window.frame
  98. frame.size.width = min(frame.width, visibleFrame.width)
  99. frame.size.height = min(frame.height, visibleFrame.height)
  100. frame.origin.x = visibleFrame.midX - frame.width / 2
  101. frame.origin.y = visibleFrame.midY - frame.height / 2
  102. window.setFrame(frame, display: true)
  103. }
  104. private var mainWindow: NSWindow? {
  105. mainWindowController?.window
  106. ?? NSApplication.shared.windows.first(where: \.canBecomeMain)
  107. }
  108. private func resolveMainWindowController() {
  109. guard mainWindowController == nil else { return }
  110. mainWindowController = NSApplication.shared.windows
  111. .compactMap { $0.windowController as? MainWindowController }
  112. .first
  113. if mainWindowController == nil {
  114. DispatchQueue.main.async { [weak self] in
  115. self?.resolveMainWindowController()
  116. }
  117. }
  118. }
  119. func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
  120. true
  121. }
  122. }