|
@@ -19,7 +19,7 @@ private enum PremiumSheetLayout {
|
|
|
static let overscanExtraTop: CGFloat = 0.5
|
|
static let overscanExtraTop: CGFloat = 0.5
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-final class DashboardView: NSView, NSTextFieldDelegate {
|
|
|
|
|
|
|
+final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDelegate, NSSharingServiceDelegate {
|
|
|
/// Indeed.com-inspired neutrals and brand blue (white surfaces, `#2557a7` accent, `#2d2d2d` / `#767676` text, `#d4d2d0` borders).
|
|
/// Indeed.com-inspired neutrals and brand blue (white surfaces, `#2557a7` accent, `#2d2d2d` / `#767676` text, `#d4d2d0` borders).
|
|
|
private enum Theme {
|
|
private enum Theme {
|
|
|
static let brandBlue = NSColor(srgbRed: 37 / 255, green: 87 / 255, blue: 167 / 255, alpha: 1)
|
|
static let brandBlue = NSColor(srgbRed: 37 / 255, green: 87 / 255, blue: 167 / 255, alpha: 1)
|
|
@@ -161,6 +161,8 @@ final class DashboardView: NSView, NSTextFieldDelegate {
|
|
|
private weak var sidebarUpgradeDescription: NSTextField?
|
|
private weak var sidebarUpgradeDescription: NSTextField?
|
|
|
private weak var sidebarUpgradeButton: HoverableButton?
|
|
private weak var sidebarUpgradeButton: HoverableButton?
|
|
|
private var subscriptionObserver: NSObjectProtocol?
|
|
private var subscriptionObserver: NSObjectProtocol?
|
|
|
|
|
+ /// Retains the system share picker until the user picks a destination or dismisses the menu.
|
|
|
|
|
+ private var appSharePicker: NSSharingServicePicker?
|
|
|
|
|
|
|
|
/// Upper bound sent to the model per request (was fixed at 8 in the prompt). Clamped when calling the API.
|
|
/// Upper bound sent to the model per request (was fixed at 8 in the prompt). Clamped when calling the API.
|
|
|
private static let jobsPerSearchDefault = 15
|
|
private static let jobsPerSearchDefault = 15
|
|
@@ -1496,8 +1498,8 @@ final class DashboardView: NSView, NSTextFieldDelegate {
|
|
|
contentStack.translatesAutoresizingMaskIntoConstraints = false
|
|
contentStack.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
|
|
|
let settingsSection = makeSettingsSection(rows: [
|
|
let settingsSection = makeSettingsSection(rows: [
|
|
|
- makeSettingsRow(title: "Share App", systemImage: "square.and.arrow.up", accessory: nil),
|
|
|
|
|
- makeSettingsRow(title: "More Apps", systemImage: "square.grid.2x2", accessory: nil)
|
|
|
|
|
|
|
+ makeSettingsRow(title: "Share App", systemImage: "square.and.arrow.up", accessory: nil, tapAction: #selector(didTapShareApp)),
|
|
|
|
|
+ makeSettingsRow(title: "More Apps", systemImage: "square.grid.2x2", accessory: nil, tapAction: #selector(didTapMoreApps))
|
|
|
])
|
|
])
|
|
|
|
|
|
|
|
let aboutTitle = NSTextField(labelWithString: "About")
|
|
let aboutTitle = NSTextField(labelWithString: "About")
|
|
@@ -1796,6 +1798,73 @@ final class DashboardView: NSView, NSTextFieldDelegate {
|
|
|
focusSearchField(seed: "Find jobs that require skill: ")
|
|
focusSearchField(seed: "Find jobs that require skill: ")
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @objc private func didTapShareApp(_ sender: NSButton) {
|
|
|
|
|
+ presentAppShareMenu(anchoredTo: sender)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// Shows the macOS share menu (Mail, Messages, AirDrop, Copy Link, etc.) with the app link.
|
|
|
|
|
+ private func presentAppShareMenu(anchoredTo sender: NSButton) {
|
|
|
|
|
+ guard let row = sender.superview else { return }
|
|
|
|
|
+ let items = AppMarketingLinks.shareItems
|
|
|
|
|
+ guard !items.isEmpty else { return }
|
|
|
|
|
+
|
|
|
|
|
+ let picker = NSSharingServicePicker(items: items)
|
|
|
|
|
+ picker.delegate = self
|
|
|
|
|
+ appSharePicker = picker
|
|
|
|
|
+
|
|
|
|
|
+ // Match `makeSettingsRow` layout: 16pt leading inset + 38pt icon tile — anchor the
|
|
|
|
|
+ // popover beside the share icon, not the horizontal center of the full-width row.
|
|
|
|
|
+ let iconTileInset: CGFloat = 16
|
|
|
|
|
+ let iconTileSize: CGFloat = 38
|
|
|
|
|
+ let anchorRect = NSRect(
|
|
|
|
|
+ x: iconTileInset,
|
|
|
|
|
+ y: row.bounds.minY + 6,
|
|
|
|
|
+ width: iconTileSize,
|
|
|
|
|
+ height: max(row.bounds.height - 12, 1)
|
|
|
|
|
+ )
|
|
|
|
|
+ picker.show(relativeTo: anchorRect, of: row, preferredEdge: .minY)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ func sharingServicePicker(_ sharingServicePicker: NSSharingServicePicker, delegateFor sharingService: NSSharingService) -> Any? {
|
|
|
|
|
+ self
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ func sharingServicePicker(_ sharingServicePicker: NSSharingServicePicker, didChoose sharingService: NSSharingService?) {
|
|
|
|
|
+ appSharePicker = nil
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ func sharingService(_ sharingService: NSSharingService, willShareItems items: [Any]) -> [Any] {
|
|
|
|
|
+ if sharingService == NSSharingService(named: .composeEmail) {
|
|
|
|
|
+ sharingService.subject = AppMarketingLinks.shareEmailSubject
|
|
|
|
|
+ }
|
|
|
|
|
+ return items
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @objc private func didTapMoreApps() {
|
|
|
|
|
+ guard let url = AppMarketingLinks.developerAppsURL else {
|
|
|
|
|
+ presentAppMarketingConfigurationAlert(feature: "More Apps")
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ NSWorkspace.shared.open(url)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private func presentAppMarketingConfigurationAlert(feature: String) {
|
|
|
|
|
+ let alert = NSAlert()
|
|
|
|
|
+ alert.messageText = "\(feature) isn’t available yet"
|
|
|
|
|
+ alert.informativeText = """
|
|
|
|
|
+ Add your Mac App Store IDs in the target’s build settings:
|
|
|
|
|
+ • AppStoreAppID — numeric app ID from App Store Connect
|
|
|
|
|
+ • AppStoreDeveloperID — numeric developer ID (for your other apps page)
|
|
|
|
|
+ """
|
|
|
|
|
+ alert.alertStyle = .informational
|
|
|
|
|
+ alert.addButton(withTitle: "OK")
|
|
|
|
|
+ if let window {
|
|
|
|
|
+ alert.beginSheetModal(for: window)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ alert.runModal()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@objc private func didTapSupport() {
|
|
@objc private func didTapSupport() {
|
|
|
presentSettingsPlaceholderAlert(for: "Support")
|
|
presentSettingsPlaceholderAlert(for: "Support")
|
|
|
}
|
|
}
|