about summary refs log tree commit diff
path: root/modules/BlueskyClip/ViewController.swift
diff options
context:
space:
mode:
authorHailey <me@haileyok.com>2024-06-21 21:38:04 -0700
committerGitHub <noreply@github.com>2024-06-21 21:38:04 -0700
commitf089f4578131e83cd177b7809ce0f7b75779dfdc (patch)
tree51978aede2040fb8dc319f0749d3de77c7811fbe /modules/BlueskyClip/ViewController.swift
parent35f64535cb8dfa0fe46e740a6398f3b991ecfbc7 (diff)
downloadvoidsky-f089f4578131e83cd177b7809ce0f7b75779dfdc.tar.zst
Starter Packs (#4332)
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Co-authored-by: Eric Bailey <git@esb.lol>
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Diffstat (limited to 'modules/BlueskyClip/ViewController.swift')
-rw-r--r--modules/BlueskyClip/ViewController.swift133
1 files changed, 133 insertions, 0 deletions
diff --git a/modules/BlueskyClip/ViewController.swift b/modules/BlueskyClip/ViewController.swift
new file mode 100644
index 000000000..b178644b8
--- /dev/null
+++ b/modules/BlueskyClip/ViewController.swift
@@ -0,0 +1,133 @@
+import UIKit
+import WebKit
+import StoreKit
+
+class ViewController: UIViewController, WKScriptMessageHandler, WKNavigationDelegate {
+  let defaults = UserDefaults(suiteName: "group.app.bsky")
+
+  var window: UIWindow
+  var webView: WKWebView?
+
+  var prevUrl: URL?
+  var starterPackUrl: URL?
+
+  init(window: UIWindow) {
+    self.window = window
+    super.init(nibName: nil, bundle: nil)
+  }
+
+  required init?(coder: NSCoder) {
+    fatalError("init(coder:) has not been implemented")
+  }
+
+  override func viewDidLoad() {
+    super.viewDidLoad()
+
+    let contentController = WKUserContentController()
+    contentController.add(self, name: "onMessage")
+    let configuration = WKWebViewConfiguration()
+    configuration.userContentController = contentController
+
+    let webView = WKWebView(frame: self.view.bounds, configuration: configuration)
+    webView.translatesAutoresizingMaskIntoConstraints = false
+    webView.contentMode = .scaleToFill
+    webView.navigationDelegate = self
+    self.view.addSubview(webView)
+    self.webView = webView
+  }
+
+  func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
+    guard let response = message.body as? String,
+          let data = response.data(using: .utf8),
+          let payload = try? JSONDecoder().decode(WebViewActionPayload.self, from: data) else {
+      return
+    }
+
+    switch payload.action {
+    case .present:
+      guard let url = self.starterPackUrl else {
+        return
+      }
+
+      self.presentAppStoreOverlay()
+      defaults?.setValue(url.absoluteString, forKey: "starterPackUri")
+
+    case .store:
+      guard let keyToStoreAs = payload.keyToStoreAs, let jsonToStore = payload.jsonToStore else {
+        return
+      }
+
+      self.defaults?.setValue(jsonToStore, forKey: keyToStoreAs)
+    }
+  }
+
+  func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction) async -> WKNavigationActionPolicy {
+    // Detect when we land on the right URL. This is incase of a short link opening the app clip
+    guard let url = navigationAction.request.url else {
+      return .allow
+    }
+
+    // Store the previous one to compare later, but only set starterPackUrl when we find the right one
+    prevUrl = url
+    // pathComponents starts with "/" as the first component, then each path name. so...
+    // ["/", "start", "name", "rkey"]
+    if url.pathComponents.count == 4,
+       url.pathComponents[1] == "start" {
+      self.starterPackUrl = url
+    }
+
+    return .allow
+  }
+
+  func handleURL(url: URL) {
+    let urlString = "\(url.absoluteString)?clip=true"
+    if let url = URL(string: urlString) {
+      self.webView?.load(URLRequest(url: url))
+    }
+  }
+
+  func presentAppStoreOverlay() {
+    guard let windowScene = self.window.windowScene else {
+      return
+    }
+
+    let configuration = SKOverlay.AppClipConfiguration(position: .bottomRaised)
+    let overlay = SKOverlay(configuration: configuration)
+
+    overlay.present(in: windowScene)
+  }
+
+  func getHost(_ url: URL?) -> String? {
+    if #available(iOS 16.0, *) {
+      return url?.host()
+    } else {
+      return url?.host
+    }
+  }
+
+  func getQuery(_ url: URL?) -> String? {
+    if #available(iOS 16.0, *) {
+      return url?.query()
+    } else {
+      return url?.query
+    }
+  }
+
+  func urlMatchesPrevious(_ url: URL?) -> Bool {
+    if #available(iOS 16.0, *) {
+      return url?.query() == prevUrl?.query() && url?.host() == prevUrl?.host() && url?.query() == prevUrl?.query()
+    } else {
+      return url?.query == prevUrl?.query && url?.host == prevUrl?.host && url?.query == prevUrl?.query
+    }
+  }
+}
+
+struct WebViewActionPayload: Decodable {
+  enum Action: String, Decodable {
+    case present, store
+  }
+
+  let action: Action
+  let keyToStoreAs: String?
+  let jsonToStore: String?
+}