Files
AFFiNE-Mirror/packages/frontend/apps/ios/App/App/AffineViewController.swift
T
Lakr 7a90e1551c fix(ios): complete iap user interface (#13639)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- New Features
- In-app purchases fully integrated for Pro and AI plans with restore,
live product loading, and StoreKit test configuration.

- Improvements
- Refreshed paywall: intro animation, delayed close button, smoother
horizontal paging, page dots interaction, per-item reveal animations,
and purchase-state UI (disabled/checked when owned).

- Changes
- "Believer" plan and related screens removed; Pro simplified to Monthly
and Annual offerings.

- Chores
- iOS project and build settings updated for newer toolchain and
StoreKit support.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-09-25 04:50:12 +00:00

103 lines
3.3 KiB
Swift

import Capacitor
import Intelligents
import UIKit
class AFFiNEViewController: CAPBridgeViewController {
var intelligentsButton: IntelligentsButton?
override func viewDidLoad() {
super.viewDidLoad()
webView?.allowsBackForwardNavigationGestures = true
navigationController?.navigationBar.isHidden = true
extendedLayoutIncludesOpaqueBars = false
edgesForExtendedLayout = []
let intelligentsButton = installIntelligentsButton()
intelligentsButton.delegate = self
self.intelligentsButton = intelligentsButton
dismissIntelligentsButton()
}
override func webViewConfiguration(for instanceConfiguration: InstanceConfiguration) -> WKWebViewConfiguration {
let configuration = super.webViewConfiguration(for: instanceConfiguration)
return configuration
}
override func webView(with frame: CGRect, configuration: WKWebViewConfiguration) -> WKWebView {
super.webView(with: frame, configuration: configuration)
}
override func capacitorDidLoad() {
let plugins: [CAPPlugin] = [
AuthPlugin(),
CookiePlugin(),
HashcashPlugin(),
NavigationGesturePlugin(),
NbStorePlugin(),
PayWallPlugin(associatedController: self),
]
plugins.forEach { bridge?.registerPluginInstance($0) }
}
private var intelligentsButtonTimer: Timer?
private var isCheckingIntelligentEligibility = false
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
IntelligentContext.shared.webView = webView
navigationController?.setNavigationBarHidden(false, animated: animated)
let timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { [weak self] _ in
self?.checkEligibilityOfIntelligent()
}
intelligentsButtonTimer = timer
RunLoop.main.add(timer, forMode: .common)
}
private func checkEligibilityOfIntelligent() {
guard !isCheckingIntelligentEligibility else { return }
assert(intelligentsButton != nil)
guard intelligentsButton?.isHidden ?? false else { return } // already eligible
isCheckingIntelligentEligibility = true
IntelligentContext.shared.webView = webView
IntelligentContext.shared.preparePresent { [self] result in
DispatchQueue.main.async {
defer { self.isCheckingIntelligentEligibility = false }
switch result {
case .failure: break
case .success:
self.presentIntelligentsButton()
}
}
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
intelligentsButtonTimer?.invalidate()
}
#if DEBUG
override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
if motion == .motionShake {
showDebugMenu()
}
}
#endif
}
#if DEBUG
import AffinePaywall
extension AFFiNEViewController {
@objc private func showDebugMenu() {
let alert = UIAlertController(title: "Debug Menu", message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Show Paywall - Pro", style: .default) { _ in
Paywall.presentWall(toController: self, type: "Pro")
})
alert.addAction(UIAlertAction(title: "Show Paywall - AI", style: .default) { _ in
Paywall.presentWall(toController: self, type: "AI")
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
present(alert, animated: true)
}
}
#endif