AppDelegate.swift 4.7 KB

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