|
|
@@ -696,6 +696,51 @@ private extension ViewController {
|
|
696
|
696
|
}
|
|
697
|
697
|
}
|
|
698
|
698
|
|
|
|
699
|
+ private func openRateUsDestination() {
|
|
|
700
|
+ let configured = (Bundle.main.object(forInfoDictionaryKey: "RateUsURL") as? String)?
|
|
|
701
|
+ .trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
702
|
+ let placeholder = (Bundle.main.object(forInfoDictionaryKey: "AppLaunchPlaceholderURL") as? String)?
|
|
|
703
|
+ .trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
704
|
+ let hardcodedRateUsURL = "https://apps.apple.com/pk/app/meeting-app-for-google-meet/id6654920763?mt=12"
|
|
|
705
|
+
|
|
|
706
|
+ var candidateStrings = [String]()
|
|
|
707
|
+ if let configured, !configured.isEmpty {
|
|
|
708
|
+ candidateStrings.append(configured)
|
|
|
709
|
+ if let appID = extractAppleAppID(from: configured) {
|
|
|
710
|
+ candidateStrings.append("macappstore://apps.apple.com/app/id\(appID)")
|
|
|
711
|
+ candidateStrings.append("macappstore://itunes.apple.com/app/id\(appID)")
|
|
|
712
|
+ }
|
|
|
713
|
+ }
|
|
|
714
|
+ candidateStrings.append(hardcodedRateUsURL)
|
|
|
715
|
+ candidateStrings.append("macappstore://apps.apple.com/app/id6654920763")
|
|
|
716
|
+ candidateStrings.append("macappstore://itunes.apple.com/app/id6654920763")
|
|
|
717
|
+ if let placeholder, !placeholder.isEmpty {
|
|
|
718
|
+ candidateStrings.append(placeholder)
|
|
|
719
|
+ }
|
|
|
720
|
+
|
|
|
721
|
+ for candidate in candidateStrings {
|
|
|
722
|
+ guard let url = URL(string: candidate) else { continue }
|
|
|
723
|
+ if NSWorkspace.shared.open(url) {
|
|
|
724
|
+ return
|
|
|
725
|
+ }
|
|
|
726
|
+ }
|
|
|
727
|
+
|
|
|
728
|
+ showSimpleAlert(
|
|
|
729
|
+ title: "Unable to Open Rate Page",
|
|
|
730
|
+ message: "Could not open the App Store rating page. Please try again."
|
|
|
731
|
+ )
|
|
|
732
|
+
|
|
|
733
|
+ requestAppRatingIfEligible(markAsRated: true)
|
|
|
734
|
+ }
|
|
|
735
|
+
|
|
|
736
|
+ private func extractAppleAppID(from urlString: String) -> String? {
|
|
|
737
|
+ guard let match = urlString.range(of: "id[0-9]+", options: .regularExpression) else {
|
|
|
738
|
+ return nil
|
|
|
739
|
+ }
|
|
|
740
|
+ let token = String(urlString[match])
|
|
|
741
|
+ return String(token.dropFirst())
|
|
|
742
|
+ }
|
|
|
743
|
+
|
|
699
|
744
|
private func openInSafari(url: URL) {
|
|
700
|
745
|
guard let safariAppURL = NSWorkspace.shared.urlForApplication(withBundleIdentifier: "com.apple.Safari") else {
|
|
701
|
746
|
NSWorkspace.shared.open(url)
|
|
|
@@ -836,18 +881,19 @@ private extension ViewController {
|
|
836
|
881
|
case .rateUs:
|
|
837
|
882
|
settingsPopover?.performClose(nil)
|
|
838
|
883
|
settingsPopover = nil
|
|
839
|
|
- requestAppRatingIfEligible(markAsRated: true)
|
|
|
884
|
+ openRateUsDestination()
|
|
840
|
885
|
case .support:
|
|
841
|
886
|
settingsPopover?.performClose(nil)
|
|
842
|
887
|
settingsPopover = nil
|
|
843
|
|
- if let url = URL(string: "https://support.google.com/meet") {
|
|
|
888
|
+ if let supportURL = Bundle.main.object(forInfoDictionaryKey: "SupportURL") as? String,
|
|
|
889
|
+ let url = URL(string: supportURL) {
|
|
844
|
890
|
openInAppBrowser(with: url, policy: inAppBrowserDefaultPolicy)
|
|
845
|
891
|
}
|
|
846
|
892
|
case .moreApps:
|
|
847
|
893
|
settingsPopover?.performClose(nil)
|
|
848
|
894
|
settingsPopover = nil
|
|
849
|
|
- // Replace with your App Store developer page URL.
|
|
850
|
|
- if let url = URL(string: "https://apps.apple.com/developer/id0000000000") {
|
|
|
895
|
+ if let moreAppsURL = Bundle.main.object(forInfoDictionaryKey: "MoreAppsURL") as? String,
|
|
|
896
|
+ let url = URL(string: moreAppsURL) {
|
|
851
|
897
|
openInAppBrowser(with: url, policy: inAppBrowserDefaultPolicy)
|
|
852
|
898
|
}
|
|
853
|
899
|
case .shareApp:
|
|
|
@@ -1056,10 +1102,11 @@ private extension ViewController {
|
|
1056
|
1102
|
@objc private func paywallFooterLinkClicked(_ sender: NSClickGestureRecognizer) {
|
|
1057
|
1103
|
guard let view = sender.view else { return }
|
|
1058
|
1104
|
let text = (view.subviews.first { $0 is NSTextField } as? NSTextField)?.stringValue ?? "Link"
|
|
|
1105
|
+ let defaultURL = (Bundle.main.object(forInfoDictionaryKey: "AppLaunchPlaceholderURL") as? String) ?? "https://example.com/app-link-coming-soon"
|
|
1059
|
1106
|
let map: [String: String] = [
|
|
1060
|
|
- "Privacy Policy": "https://policies.google.com/privacy",
|
|
1061
|
|
- "Support": "https://support.google.com/meet",
|
|
1062
|
|
- "Terms of Services": "https://policies.google.com/terms"
|
|
|
1107
|
+ "Privacy Policy": (Bundle.main.object(forInfoDictionaryKey: "PrivacyPolicyURL") as? String) ?? defaultURL,
|
|
|
1108
|
+ "Support": (Bundle.main.object(forInfoDictionaryKey: "SupportURL") as? String) ?? defaultURL,
|
|
|
1109
|
+ "Terms of Services": (Bundle.main.object(forInfoDictionaryKey: "TermsOfServiceURL") as? String) ?? defaultURL
|
|
1063
|
1110
|
]
|
|
1064
|
1111
|
if let urlString = map[text], let url = URL(string: urlString) {
|
|
1065
|
1112
|
openInAppBrowser(with: url, policy: inAppBrowserDefaultPolicy)
|
|
|
@@ -1251,7 +1298,7 @@ private extension ViewController {
|
|
1251
|
1298
|
}
|
|
1252
|
1299
|
|
|
1253
|
1300
|
private var shouldShowRateUsInSettings: Bool {
|
|
1254
|
|
- storeKitCoordinator.hasPremiumAccess && !userHasRated && hasReachedRatingUsageThreshold
|
|
|
1301
|
+ true
|
|
1255
|
1302
|
}
|
|
1256
|
1303
|
|
|
1257
|
1304
|
private func migrateLegacyRatingStateIfNeeded() {
|
|
|
@@ -4360,9 +4407,14 @@ private final class SettingsMenuViewController: NSViewController {
|
|
4360
|
4407
|
}
|
|
4361
|
4408
|
|
|
4362
|
4409
|
private func settingsActionRow(icon: String, title: String, action: SettingsAction) -> NSView {
|
|
4363
|
|
- let row = HoverTrackingView()
|
|
|
4410
|
+ let row = HoverButton(title: "", target: self, action: #selector(settingsActionButtonPressed(_:)))
|
|
|
4411
|
+ row.tag = action.rawValue
|
|
|
4412
|
+ row.isBordered = false
|
|
4364
|
4413
|
row.translatesAutoresizingMaskIntoConstraints = false
|
|
4365
|
4414
|
row.heightAnchor.constraint(equalToConstant: 42).isActive = true
|
|
|
4415
|
+ row.wantsLayer = true
|
|
|
4416
|
+ row.layer?.cornerRadius = 10
|
|
|
4417
|
+ row.layer?.backgroundColor = NSColor.clear.cgColor
|
|
4366
|
4418
|
|
|
4367
|
4419
|
let iconLabel = NSTextField(labelWithString: icon)
|
|
4368
|
4420
|
iconLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
|
@@ -4384,12 +4436,7 @@ private final class SettingsMenuViewController: NSViewController {
|
|
4384
|
4436
|
titleLabel.centerYAnchor.constraint(equalTo: row.centerYAnchor)
|
|
4385
|
4437
|
])
|
|
4386
|
4438
|
|
|
4387
|
|
- let click = NSClickGestureRecognizer(target: self, action: #selector(settingsActionClicked(_:)))
|
|
4388
|
|
- row.addGestureRecognizer(click)
|
|
4389
|
|
- row.identifier = NSUserInterfaceItemIdentifier(rawValue: "\(action.rawValue)")
|
|
4390
|
4439
|
row.onHoverChanged = { hovering in
|
|
4391
|
|
- row.wantsLayer = true
|
|
4392
|
|
- row.layer?.cornerRadius = 10
|
|
4393
|
4440
|
row.layer?.backgroundColor = (hovering ? self.palette.inputBackground : NSColor.clear).cgColor
|
|
4394
|
4441
|
}
|
|
4395
|
4442
|
row.onHoverChanged?(false)
|
|
|
@@ -4401,12 +4448,11 @@ private final class SettingsMenuViewController: NSViewController {
|
|
4401
|
4448
|
onToggleDarkMode(sender.state == .on)
|
|
4402
|
4449
|
}
|
|
4403
|
4450
|
|
|
4404
|
|
- @objc private func settingsActionClicked(_ sender: NSClickGestureRecognizer) {
|
|
4405
|
|
- guard let view = sender.view,
|
|
4406
|
|
- let raw = Int(view.identifier?.rawValue ?? ""),
|
|
4407
|
|
- let action = SettingsAction(rawValue: raw) else { return }
|
|
|
4451
|
+ @objc private func settingsActionButtonPressed(_ sender: NSButton) {
|
|
|
4452
|
+ guard let action = SettingsAction(rawValue: sender.tag) else { return }
|
|
4408
|
4453
|
onAction(action)
|
|
4409
|
4454
|
}
|
|
|
4455
|
+
|
|
4410
|
4456
|
}
|
|
4411
|
4457
|
|
|
4412
|
4458
|
private extension ViewController {
|