|
|
@@ -19,7 +19,7 @@ private enum PremiumSheetLayout {
|
|
19
|
19
|
static let overscanExtraTop: CGFloat = 0.5
|
|
20
|
20
|
}
|
|
21
|
21
|
|
|
22
|
|
-final class DashboardView: NSView, NSTextFieldDelegate {
|
|
|
22
|
+final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDelegate, NSSharingServiceDelegate {
|
|
23
|
23
|
/// Indeed.com-inspired neutrals and brand blue (white surfaces, `#2557a7` accent, `#2d2d2d` / `#767676` text, `#d4d2d0` borders).
|
|
24
|
24
|
private enum Theme {
|
|
25
|
25
|
static let brandBlue = NSColor(srgbRed: 37 / 255, green: 87 / 255, blue: 167 / 255, alpha: 1)
|
|
|
@@ -161,6 +161,8 @@ final class DashboardView: NSView, NSTextFieldDelegate {
|
|
161
|
161
|
private weak var sidebarUpgradeDescription: NSTextField?
|
|
162
|
162
|
private weak var sidebarUpgradeButton: HoverableButton?
|
|
163
|
163
|
private var subscriptionObserver: NSObjectProtocol?
|
|
|
164
|
+ /// Retains the system share picker until the user picks a destination or dismisses the menu.
|
|
|
165
|
+ private var appSharePicker: NSSharingServicePicker?
|
|
164
|
166
|
|
|
165
|
167
|
/// Upper bound sent to the model per request (was fixed at 8 in the prompt). Clamped when calling the API.
|
|
166
|
168
|
private static let jobsPerSearchDefault = 15
|
|
|
@@ -1496,8 +1498,8 @@ final class DashboardView: NSView, NSTextFieldDelegate {
|
|
1496
|
1498
|
contentStack.translatesAutoresizingMaskIntoConstraints = false
|
|
1497
|
1499
|
|
|
1498
|
1500
|
let settingsSection = makeSettingsSection(rows: [
|
|
1499
|
|
- makeSettingsRow(title: "Share App", systemImage: "square.and.arrow.up", accessory: nil),
|
|
1500
|
|
- makeSettingsRow(title: "More Apps", systemImage: "square.grid.2x2", accessory: nil)
|
|
|
1501
|
+ makeSettingsRow(title: "Share App", systemImage: "square.and.arrow.up", accessory: nil, tapAction: #selector(didTapShareApp)),
|
|
|
1502
|
+ makeSettingsRow(title: "More Apps", systemImage: "square.grid.2x2", accessory: nil, tapAction: #selector(didTapMoreApps))
|
|
1501
|
1503
|
])
|
|
1502
|
1504
|
|
|
1503
|
1505
|
let aboutTitle = NSTextField(labelWithString: "About")
|
|
|
@@ -1796,6 +1798,73 @@ final class DashboardView: NSView, NSTextFieldDelegate {
|
|
1796
|
1798
|
focusSearchField(seed: "Find jobs that require skill: ")
|
|
1797
|
1799
|
}
|
|
1798
|
1800
|
|
|
|
1801
|
+ @objc private func didTapShareApp(_ sender: NSButton) {
|
|
|
1802
|
+ presentAppShareMenu(anchoredTo: sender)
|
|
|
1803
|
+ }
|
|
|
1804
|
+
|
|
|
1805
|
+ /// Shows the macOS share menu (Mail, Messages, AirDrop, Copy Link, etc.) with the app link.
|
|
|
1806
|
+ private func presentAppShareMenu(anchoredTo sender: NSButton) {
|
|
|
1807
|
+ guard let row = sender.superview else { return }
|
|
|
1808
|
+ let items = AppMarketingLinks.shareItems
|
|
|
1809
|
+ guard !items.isEmpty else { return }
|
|
|
1810
|
+
|
|
|
1811
|
+ let picker = NSSharingServicePicker(items: items)
|
|
|
1812
|
+ picker.delegate = self
|
|
|
1813
|
+ appSharePicker = picker
|
|
|
1814
|
+
|
|
|
1815
|
+ // Match `makeSettingsRow` layout: 16pt leading inset + 38pt icon tile — anchor the
|
|
|
1816
|
+ // popover beside the share icon, not the horizontal center of the full-width row.
|
|
|
1817
|
+ let iconTileInset: CGFloat = 16
|
|
|
1818
|
+ let iconTileSize: CGFloat = 38
|
|
|
1819
|
+ let anchorRect = NSRect(
|
|
|
1820
|
+ x: iconTileInset,
|
|
|
1821
|
+ y: row.bounds.minY + 6,
|
|
|
1822
|
+ width: iconTileSize,
|
|
|
1823
|
+ height: max(row.bounds.height - 12, 1)
|
|
|
1824
|
+ )
|
|
|
1825
|
+ picker.show(relativeTo: anchorRect, of: row, preferredEdge: .minY)
|
|
|
1826
|
+ }
|
|
|
1827
|
+
|
|
|
1828
|
+ func sharingServicePicker(_ sharingServicePicker: NSSharingServicePicker, delegateFor sharingService: NSSharingService) -> Any? {
|
|
|
1829
|
+ self
|
|
|
1830
|
+ }
|
|
|
1831
|
+
|
|
|
1832
|
+ func sharingServicePicker(_ sharingServicePicker: NSSharingServicePicker, didChoose sharingService: NSSharingService?) {
|
|
|
1833
|
+ appSharePicker = nil
|
|
|
1834
|
+ }
|
|
|
1835
|
+
|
|
|
1836
|
+ func sharingService(_ sharingService: NSSharingService, willShareItems items: [Any]) -> [Any] {
|
|
|
1837
|
+ if sharingService == NSSharingService(named: .composeEmail) {
|
|
|
1838
|
+ sharingService.subject = AppMarketingLinks.shareEmailSubject
|
|
|
1839
|
+ }
|
|
|
1840
|
+ return items
|
|
|
1841
|
+ }
|
|
|
1842
|
+
|
|
|
1843
|
+ @objc private func didTapMoreApps() {
|
|
|
1844
|
+ guard let url = AppMarketingLinks.developerAppsURL else {
|
|
|
1845
|
+ presentAppMarketingConfigurationAlert(feature: "More Apps")
|
|
|
1846
|
+ return
|
|
|
1847
|
+ }
|
|
|
1848
|
+ NSWorkspace.shared.open(url)
|
|
|
1849
|
+ }
|
|
|
1850
|
+
|
|
|
1851
|
+ private func presentAppMarketingConfigurationAlert(feature: String) {
|
|
|
1852
|
+ let alert = NSAlert()
|
|
|
1853
|
+ alert.messageText = "\(feature) isn’t available yet"
|
|
|
1854
|
+ alert.informativeText = """
|
|
|
1855
|
+ Add your Mac App Store IDs in the target’s build settings:
|
|
|
1856
|
+ • AppStoreAppID — numeric app ID from App Store Connect
|
|
|
1857
|
+ • AppStoreDeveloperID — numeric developer ID (for your other apps page)
|
|
|
1858
|
+ """
|
|
|
1859
|
+ alert.alertStyle = .informational
|
|
|
1860
|
+ alert.addButton(withTitle: "OK")
|
|
|
1861
|
+ if let window {
|
|
|
1862
|
+ alert.beginSheetModal(for: window)
|
|
|
1863
|
+ } else {
|
|
|
1864
|
+ alert.runModal()
|
|
|
1865
|
+ }
|
|
|
1866
|
+ }
|
|
|
1867
|
+
|
|
1799
|
1868
|
@objc private func didTapSupport() {
|
|
1800
|
1869
|
presentSettingsPlaceholderAlert(for: "Support")
|
|
1801
|
1870
|
}
|