ソースを参照

Fix settings links placeholders and Rate Us action reliability.

Move settings and paywall links to plist-configured placeholders, show Rate Us for all users, and route Rate Us through robust App Store fallbacks with button-based settings row actions.

Made-with: Cursor
huzaifahayat12 1 週間 前
コミット
634f9ee6d7
共有2 個のファイルを変更した78 個の追加18 個の削除を含む
  1. 14 0
      Info.plist
  2. 64 18
      meetings_app/ViewController.swift

+ 14 - 0
Info.plist

@@ -30,6 +30,20 @@
30 30
 	<string>Camera is used for video meetings you open inside this app.</string>
31 31
 	<key>NSMicrophoneUsageDescription</key>
32 32
 	<string>Microphone is used for audio in meetings you open inside this app.</string>
33
+	<key>AppLaunchPlaceholderURL</key>
34
+	<string>https://example.com/app-link-coming-soon</string>
35
+	<key>AppShareURL</key>
36
+	<string>https://example.com/app-link-coming-soon</string>
37
+	<key>SupportURL</key>
38
+	<string>https://example.com/app-link-coming-soon</string>
39
+	<key>MoreAppsURL</key>
40
+	<string>https://example.com/app-link-coming-soon</string>
41
+	<key>PrivacyPolicyURL</key>
42
+	<string>https://example.com/app-link-coming-soon</string>
43
+	<key>TermsOfServiceURL</key>
44
+	<string>https://example.com/app-link-coming-soon</string>
45
+	<key>RateUsURL</key>
46
+	<string>https://apps.apple.com/pk/app/meeting-app-for-google-meet/id6654920763?mt=12</string>
33 47
 
34 48
 	<key>CFBundleURLTypes</key>
35 49
 	<array>

+ 64 - 18
meetings_app/ViewController.swift

@@ -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 {