Keine Beschreibung

AppDelegate.swift 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. //
  2. // AppDelegate.swift
  3. // App for Indeed
  4. //
  5. // Created by Mql Mac 2 on 11/05/2026.
  6. //
  7. import Cocoa
  8. enum AppWindowConfiguration {
  9. static let defaultContentSize = NSSize(width: 1120, height: 800)
  10. static let minimumContentSize = NSSize(width: 1120, height: 800)
  11. @MainActor
  12. static func apply(to window: NSWindow) {
  13. window.minSize = minimumContentSize
  14. window.isRestorable = false
  15. window.title = AppMarketingLinks.appDisplayName
  16. window.styleMask.insert(.fullSizeContentView)
  17. window.titlebarAppearsTransparent = true
  18. window.titleVisibility = .hidden
  19. window.isMovableByWindowBackground = true
  20. // Same as `DashboardView` chrome — avoids a white halo outside the grey frame with fullSizeContentView.
  21. window.backgroundColor = NSColor(srgbRed: 247 / 255, green: 247 / 255, blue: 247 / 255, alpha: 1)
  22. let targetContent = NSRect(origin: .zero, size: defaultContentSize)
  23. let targetFrame = window.frameRect(forContentRect: targetContent)
  24. var frame = targetFrame
  25. let current = window.frame
  26. frame.origin.x = current.midX - frame.width / 2
  27. frame.origin.y = current.midY - frame.height / 2
  28. window.setFrame(frame, display: false, animate: false)
  29. window.setContentSize(defaultContentSize)
  30. }
  31. @MainActor
  32. static func mainWindow(in app: NSApplication = .shared) -> NSWindow? {
  33. app.mainWindow
  34. ?? app.keyWindow
  35. ?? app.windows.first(where: { $0.isVisible && $0.canBecomeKey })
  36. }
  37. }
  38. @main
  39. class AppDelegate: NSObject, NSApplicationDelegate {
  40. /// Avoids hammering StoreKit when `didBecomeActive` fires in quick succession (e.g. after system sheets).
  41. private var lastSubscriptionRefreshAt: Date?
  42. func applicationWillFinishLaunching(_ notification: Notification) {
  43. // Dashboard is light-themed; without this, a Dark Mode Mac paints a dark title bar.
  44. NSApp.appearance = NSAppearance(named: .aqua)
  45. }
  46. func applicationDidFinishLaunching(_ aNotification: Notification) {
  47. AppRatingCoordinator.shared.start()
  48. NotificationCenter.default.addObserver(
  49. forName: NSApplication.didBecomeActiveNotification,
  50. object: nil,
  51. queue: .main
  52. ) { [weak self] _ in
  53. Task { @MainActor in
  54. guard let self else { return }
  55. let now = Date()
  56. if let last = self.lastSubscriptionRefreshAt, now.timeIntervalSince(last) < 2.5 {
  57. return
  58. }
  59. self.lastSubscriptionRefreshAt = now
  60. await SubscriptionStore.shared.refreshEntitlements(deep: true)
  61. }
  62. }
  63. // Initial StoreKit refresh runs on `LoadingViewController` before the dashboard is shown.
  64. NSApp.activate(ignoringOtherApps: true)
  65. applyDefaultWindowSize()
  66. }
  67. @MainActor
  68. private func applyDefaultWindowSize() {
  69. DispatchQueue.main.async { [weak self] in
  70. guard let self, let window = AppWindowConfiguration.mainWindow() else { return }
  71. AppWindowConfiguration.apply(to: window)
  72. window.center()
  73. window.makeKeyAndOrderFront(nil)
  74. // Layout can run after the first pass; enforce default size once more.
  75. DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { [weak self] in
  76. guard self != nil, let window = AppWindowConfiguration.mainWindow() else { return }
  77. AppWindowConfiguration.apply(to: window)
  78. window.center()
  79. }
  80. }
  81. }
  82. func applicationWillTerminate(_ aNotification: Notification) {
  83. // Insert code here to tear down your application
  84. }
  85. func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
  86. // Opt out until real `NSWindowRestoration` is implemented (avoids null className restore logs).
  87. return false
  88. }
  89. }