Merge branch 'IAPImrovements' into Integration
# Conflicts: # VoidLink/Localization/Localizable.xcstrings xiap button for aboutView
This commit is contained in:
commit
45ccfa0c7f
6 files changed
+266
-58
No files matched your search
@@ -61,6 +61,7 @@ static NSString* DB_NAME = @"Limelight_iOS.sqlite";
|
|||||||
// Override point for command tool customization after application launch (works only when user default is nil)
|
// Override point for command tool customization after application launch (works only when user default is nil)
|
||||||
[CommandManager presetDefaultCommands];
|
[CommandManager presetDefaultCommands];
|
||||||
[GenericUtils installSegmentedControlPreviousSelectionTracking];
|
[GenericUtils installSegmentedControlPreviousSelectionTracking];
|
||||||
|
[IAPManager shared];
|
||||||
|
|
||||||
// For iOS 12 and below, we need to manually create the window
|
// For iOS 12 and below, we need to manually create the window
|
||||||
if (@available(iOS 13.0, *)) {
|
if (@available(iOS 13.0, *)) {
|
||||||
|
|||||||
@@ -260,17 +260,18 @@ import UIKit
|
|||||||
|
|
||||||
|
|
||||||
let strokePhase = getStrokePhase(sampleIndex: self.strokeSampleIndex)
|
let strokePhase = getStrokePhase(sampleIndex: self.strokeSampleIndex)
|
||||||
|
let forceMapping = pressureCurveEnabled ? self.strokeLUT.value(at: force) : force
|
||||||
switch strokePhase {
|
switch strokePhase {
|
||||||
case .phase1:
|
case .phase1:
|
||||||
targetForce = pencilTickEnabled ? 0 : self.strokeLUT.value(at: force)
|
targetForce = pencilTickEnabled ? 0 : forceMapping
|
||||||
case .phase2:
|
case .phase2:
|
||||||
targetForce = self.strokeLUT.value(at: force)
|
targetForce = forceMapping
|
||||||
targetForce = max(targetForce,previousTargetForce)
|
targetForce = max(targetForce,previousTargetForce)
|
||||||
equalizedForce = targetForce*(phase2EqualizationStrength - equalizationStep*Float(strokeSampleIndex-phase1StrokeSampleIndexEnd-1))
|
equalizedForce = targetForce*(phase2EqualizationStrength - equalizationStep*Float(strokeSampleIndex-phase1StrokeSampleIndexEnd-1))
|
||||||
case .phase3:
|
case .phase3:
|
||||||
targetForce = self.strokeLUT.value(at: force)
|
targetForce = forceMapping
|
||||||
}
|
}
|
||||||
targetForce = self.pressureCurveEnabled ? targetForce : force
|
targetForce = pencilTickEnabled ? targetForce : force
|
||||||
|
|
||||||
previousForce = force
|
previousForce = force
|
||||||
previousTargetForce = targetForce
|
previousTargetForce = targetForce
|
||||||
|
|||||||
@@ -513,6 +513,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"[%@] has been restored" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "【%@】已恢复"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-Hant" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "「%@」已恢復"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-HK" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "「%@」已恢復"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"%@ is currently running" : {
|
"%@ is currently running" : {
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -715,7 +738,7 @@
|
|||||||
},
|
},
|
||||||
"zh-HK" : {
|
"zh-HK" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
"state" : "needs_review",
|
"state" : "translated",
|
||||||
"value" : "方向鍵"
|
"value" : "方向鍵"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6629,6 +6652,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Drawing Toolkit already purchased" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "您已拥有【绘画进阶套件】"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-Hant" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "您已擁有「繪畫進階套件」"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-HK" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "您已擁有「繪畫進階套件」"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Drift Correction" : {
|
"Drift Correction" : {
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -6721,7 +6767,7 @@
|
|||||||
},
|
},
|
||||||
"zh-HK" : {
|
"zh-HK" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
"state" : "translated",
|
"state" : "needs_review",
|
||||||
"value" : "一塊啥都不幹的擋板區域"
|
"value" : "一塊啥都不幹的擋板區域"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9085,29 +9131,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"I'm an artist" : {
|
|
||||||
"extractionState" : "manual",
|
|
||||||
"localizations" : {
|
|
||||||
"zh-Hans" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "我是画手"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"zh-Hant" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "我是畫手"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"zh-HK" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "我是畫手"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Import" : {
|
"Import" : {
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -9154,6 +9177,52 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"In-app-purchase not available" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "无法使用 App 内购买"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-Hant" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "無法使用 App 內購買"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-HK" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "無法使用 App 內購買"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"In-app-purchase not available on this device." : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "此设备无法使用该 App 内购买项目。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-Hant" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "此裝置無法使用該 App 內購買項目。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-HK" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "此裝置無法使用該 App 內購買項目。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Indicator offset: %.0f" : {
|
"Indicator offset: %.0f" : {
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -10971,19 +11040,19 @@
|
|||||||
"zh-Hans" : {
|
"zh-Hans" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
"state" : "translated",
|
"state" : "translated",
|
||||||
"value" : "购买 [%@] 可解锁:\n- 专业级压力曲线工具。\n- 在远程绘图流程中提升笔触传输效率与响应表现,并支持用户自定义的双击及捏合键盘/鼠标快捷键。\n- 专属绘图相关的屏显按钮。\n以及更多功能..."
|
"value" : "购买 [%@] 可解锁:\n- 专业级笔压曲线工具。\n- 远程绘画笔迹传输、笔触响应性能优化。\n- 支持用户自定义的双击及捏合键盘/鼠标快捷键。\n- 专属绘图相关的屏显按钮。\n以及更多...\n未购买该套件不影响基础绘画功能。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"zh-Hant" : {
|
"zh-Hant" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
"state" : "translated",
|
"state" : "translated",
|
||||||
"value" : "解鎖 [%@] :\n- 專業級壓力曲線工具。\n- 在遠端繪圖流程中提升筆觸傳輸效率與響應表現,並支援使用者自訂的雙擊及捏合鍵盤/滑鼠快捷鍵。\n- 專屬繪圖相關的螢幕顯示按鈕。\n- 以及更多功能..."
|
"value" : "解鎖 [%@] :\n- 專業級筆壓曲線工具。\n- 最佳化遠端繪畫的筆跡傳輸與筆觸響應效能。\n- 並支援使用者自訂的雙擊及捏合鍵盤/滑鼠快捷鍵。\n- 專屬繪圖相關的螢幕顯示按鈕。\n以及更多...\n未購買此套件不影響基礎繪畫功能。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"zh-HK" : {
|
"zh-HK" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
"state" : "translated",
|
"state" : "translated",
|
||||||
"value" : "解鎖 [%@] :\n- 專業級壓力曲線工具。\n- 在遠端繪圖流程中提升筆觸傳輸效率與響應表現,並支援使用者自訂的雙擊及捏合鍵盤/滑鼠快捷鍵。\n- 專屬繪圖相關的螢幕顯示按鈕。\n- 以及更多功能...\n基礎繪畫功能無需購買 [%@] 即可使用。"
|
"value" : "解鎖 [%@] :\n- 專業級筆壓曲線工具。\n- 最佳化遠端繪畫的筆跡傳輸與筆觸響應效能。\n- 並支援使用者自訂的雙擊及捏合鍵盤/滑鼠快捷鍵。\n- 專屬繪圖相關的螢幕顯示按鈕。\n以及更多...\n未購買此套件不影響基礎繪畫功能。"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16353,6 +16422,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Unable to detect purchased product: %@" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "未检测到已购产品【%@】"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-Hant" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "未偵測到已購產品「%@」"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-HK" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "未偵測到已購產品「%@」"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Undo" : {
|
"Undo" : {
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
|||||||
@@ -702,6 +702,44 @@ import UIKit
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc static func rootViewController() -> UIViewController? {
|
||||||
|
if #available(iOS 13.0, *) {
|
||||||
|
return UIApplication.shared.connectedScenes
|
||||||
|
.compactMap { $0 as? UIWindowScene }
|
||||||
|
.first { $0.activationState == .foregroundActive }?
|
||||||
|
.windows
|
||||||
|
.first { $0.isKeyWindow }?
|
||||||
|
.rootViewController
|
||||||
|
} else {
|
||||||
|
return UIApplication.shared.keyWindow?.rootViewController
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc static func topViewController() -> UIViewController? {
|
||||||
|
return topViewController(from: rootViewController())
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func topViewController(from rootViewController: UIViewController?) -> UIViewController? {
|
||||||
|
if let navigationController = rootViewController as? UINavigationController {
|
||||||
|
return topViewController(from: navigationController.visibleViewController)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let tabBarController = rootViewController as? UITabBarController {
|
||||||
|
return topViewController(from: tabBarController.selectedViewController)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let splitViewController = rootViewController as? UISplitViewController,
|
||||||
|
let lastViewController = splitViewController.viewControllers.last {
|
||||||
|
return topViewController(from: lastViewController)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let presentedViewController = rootViewController?.presentedViewController {
|
||||||
|
return topViewController(from: presentedViewController)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rootViewController
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UIView {
|
extension UIView {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import StoreKit
|
import StoreKit
|
||||||
|
import UIKit
|
||||||
|
|
||||||
@objc public enum PurchaseStatus: Int {
|
@objc public enum PurchaseStatus: Int {
|
||||||
case notPurchased
|
case notPurchased
|
||||||
@@ -135,6 +136,11 @@ import StoreKit
|
|||||||
await listenForTransactions()
|
await listenForTransactions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if #available(iOS 16.4, *) {
|
||||||
|
Task {
|
||||||
|
await listenForPurchaseIntents()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Fetch Products (StoreKit 2)
|
// MARK: - Fetch Products (StoreKit 2)
|
||||||
@@ -199,6 +205,18 @@ import StoreKit
|
|||||||
|
|
||||||
@available(iOS 15.0, *, *)
|
@available(iOS 15.0, *, *)
|
||||||
private func purchaseStoreKit2(_ product: AddOnProduct) async {
|
private func purchaseStoreKit2(_ product: AddOnProduct) async {
|
||||||
|
guard IAPManager.canPurchase(product) else {
|
||||||
|
AlertControllerUtil.showAlert(
|
||||||
|
in: GenericUtils.topViewController(),
|
||||||
|
title: "In-app-purchase not available".localized,
|
||||||
|
message: "In-app-purchase not available on this device.".localized,
|
||||||
|
withCancel: false,
|
||||||
|
buttonTitle: "OK".localized,
|
||||||
|
countdown: 6
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let pid = product.productId()
|
let pid = product.productId()
|
||||||
do {
|
do {
|
||||||
let products = try await Product.products(for: [pid])
|
let products = try await Product.products(for: [pid])
|
||||||
@@ -211,30 +229,7 @@ import StoreKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
let result = try await sk2p.purchase()
|
let result = try await sk2p.purchase()
|
||||||
|
await handleStoreKit2PurchaseResult(result, product: product)
|
||||||
switch result {
|
|
||||||
case .success(let verification):
|
|
||||||
switch verification {
|
|
||||||
case .verified(let transaction):
|
|
||||||
await MainActor.run {
|
|
||||||
self.delegate?.iapManagerDidPurchase(product)
|
|
||||||
}
|
|
||||||
await transaction.finish()
|
|
||||||
IAPManager.handlePurchaseSuccess(product)
|
|
||||||
NotificationCenter.default.post(name: product.purchaseSucceededNotification(), object: nil)
|
|
||||||
case .unverified(_, let err):
|
|
||||||
NotificationCenter.default.post(name: product.purchaseAbortedNotification(), object: PurchaseInterruption.unlockNow, userInfo:["interruption": PurchaseInterruption.unlockNow.rawValue])
|
|
||||||
await MainActor.run {
|
|
||||||
self.delegate?.iapManagerDidFailWithError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case .userCancelled:
|
|
||||||
NotificationCenter.default.post(name: product.purchaseAbortedNotification(), object: PurchaseInterruption.unlockNow, userInfo:["interruption": PurchaseInterruption.unlockNow.rawValue])
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
NotificationCenter.default.post(name: product.purchaseAbortedNotification(), object: PurchaseInterruption.unlockNow, userInfo:["interruption": PurchaseInterruption.unlockNow.rawValue])
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} catch {
|
} catch {
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
NotificationCenter.default.post(name: product.purchaseAbortedNotification(), object: PurchaseInterruption.unlockNow, userInfo:["interruption": PurchaseInterruption.unlockNow.rawValue])
|
NotificationCenter.default.post(name: product.purchaseAbortedNotification(), object: PurchaseInterruption.unlockNow, userInfo:["interruption": PurchaseInterruption.unlockNow.rawValue])
|
||||||
@@ -243,12 +238,47 @@ import StoreKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static func canPurchase(_ product: AddOnProduct) -> Bool {
|
||||||
|
switch product {
|
||||||
|
case .PencilProPack:
|
||||||
|
return GenericUtils.isIPad()
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 15.0, *)
|
||||||
|
private func handleStoreKit2PurchaseResult(_ result: Product.PurchaseResult,
|
||||||
|
product: AddOnProduct) async {
|
||||||
|
switch result {
|
||||||
|
case .success(let verification):
|
||||||
|
switch verification {
|
||||||
|
case .verified(let transaction):
|
||||||
|
await MainActor.run {
|
||||||
|
self.delegate?.iapManagerDidPurchase(product)
|
||||||
|
}
|
||||||
|
await transaction.finish()
|
||||||
|
IAPManager.handlePurchaseSuccess(product)
|
||||||
|
case .unverified(_, let err):
|
||||||
|
NotificationCenter.default.post(name: product.purchaseAbortedNotification(), object: PurchaseInterruption.unlockNow, userInfo:["interruption": PurchaseInterruption.unlockNow.rawValue])
|
||||||
|
await MainActor.run {
|
||||||
|
self.delegate?.iapManagerDidFailWithError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .userCancelled:
|
||||||
|
NotificationCenter.default.post(name: product.purchaseAbortedNotification(), object: PurchaseInterruption.unlockNow, userInfo:["interruption": PurchaseInterruption.unlockNow.rawValue])
|
||||||
|
default:
|
||||||
|
NotificationCenter.default.post(name: product.purchaseAbortedNotification(), object: PurchaseInterruption.unlockNow, userInfo:["interruption": PurchaseInterruption.unlockNow.rawValue])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc static func handlePurchaseSuccess(_ product: AddOnProduct) {
|
@objc static func handlePurchaseSuccess(_ product: AddOnProduct) {
|
||||||
switch product {
|
switch product {
|
||||||
case .PencilProPack:
|
case .PencilProPack:
|
||||||
let dataMan = DataManager()
|
let dataMan = DataManager()
|
||||||
let settings = dataMan.retrieveSettings()
|
let settings = dataMan.retrieveSettings()
|
||||||
settings?.onscreenControls = 1
|
settings?.onscreenControls = 1
|
||||||
|
settings?.pencilTickMode = NSNumber(value: PencilTickMode.ManualTick.rawValue)
|
||||||
dataMan.saveData()
|
dataMan.saveData()
|
||||||
let profileMan = OSCProfilesManager.sharedManager(.zero)
|
let profileMan = OSCProfilesManager.sharedManager(.zero)
|
||||||
var toolkitProfileIndex = profileMan.getIndex(byName: "Pencil Pro")
|
var toolkitProfileIndex = profileMan.getIndex(byName: "Pencil Pro")
|
||||||
@@ -258,6 +288,7 @@ import StoreKit
|
|||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
NotificationCenter.default.post(name: product.purchaseSucceededNotification(), object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func purchaseLegacy(_ product: AddOnProduct) {
|
private func purchaseLegacy(_ product: AddOnProduct) {
|
||||||
@@ -319,6 +350,28 @@ import StoreKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.4, *)
|
||||||
|
private func listenForPurchaseIntents() async {
|
||||||
|
for await intent in PurchaseIntent.intents {
|
||||||
|
guard let product = AddOnProduct.from(productId: intent.product.id) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
guard IAPManager.canPurchase(product) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
let result = try await intent.product.purchase()
|
||||||
|
await handleStoreKit2PurchaseResult(result, product: product)
|
||||||
|
} catch {
|
||||||
|
await MainActor.run {
|
||||||
|
NotificationCenter.default.post(name: product.purchaseAbortedNotification(), object: PurchaseInterruption.unlockNow, userInfo:["interruption": PurchaseInterruption.unlockNow.rawValue])
|
||||||
|
self.delegate?.iapManagerDidFailWithError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Utils
|
// MARK: Utils
|
||||||
@objc static public func checkPurchaseInfo(
|
@objc static public func checkPurchaseInfo(
|
||||||
_ product: AddOnProduct,
|
_ product: AddOnProduct,
|
||||||
@@ -382,8 +435,30 @@ import StoreKit
|
|||||||
do {
|
do {
|
||||||
if #available(iOS 15.0, *) {
|
if #available(iOS 15.0, *) {
|
||||||
try await AppStore.sync()
|
try await AppStore.sync()
|
||||||
} else {
|
IAPManager.checkPurchaseInfo(product) { info in
|
||||||
// Fallback on earlier versions
|
if info.valid {
|
||||||
|
IAPManager.handlePurchaseSuccess(product)
|
||||||
|
AlertControllerUtil.showAlert(
|
||||||
|
in: viewController,
|
||||||
|
title: "",
|
||||||
|
message: LocalizationHelper.localizedString(forKey:"[%@] has been restored", product.productName()),
|
||||||
|
withCancel: false,
|
||||||
|
buttonTitle: "OK".localized,
|
||||||
|
countdown: 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NotificationCenter.default.post(name: product.purchaseAbortedNotification(), object: PurchaseInterruption.restore, userInfo:["interruption": PurchaseInterruption.restore.rawValue])
|
||||||
|
AlertControllerUtil.showAlert(
|
||||||
|
in: viewController,
|
||||||
|
title: "",
|
||||||
|
message: LocalizationHelper.localizedString(forKey:"Unable to detect purchased product: %@", product.productName()),
|
||||||
|
withCancel: false,
|
||||||
|
buttonTitle: "OK".localized,
|
||||||
|
countdown: 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
NotificationCenter.default.post(name: product.purchaseAbortedNotification(), object: PurchaseInterruption.restore, userInfo:["interruption": PurchaseInterruption.restore.rawValue])
|
NotificationCenter.default.post(name: product.purchaseAbortedNotification(), object: PurchaseInterruption.restore, userInfo:["interruption": PurchaseInterruption.restore.rawValue])
|
||||||
|
|||||||
@@ -3849,6 +3849,7 @@ BOOL isCustomResolution(int resolutionSelected) {
|
|||||||
|
|
||||||
- (void)pencilProPurchaseSucceeded:(NSNotification *)notification{
|
- (void)pencilProPurchaseSucceeded:(NSNotification *)notification{
|
||||||
self.onScreenWidgetSelector.selectedSegmentIndex = OnScreenControlsLevelCustom;
|
self.onScreenWidgetSelector.selectedSegmentIndex = OnScreenControlsLevelCustom;
|
||||||
|
self.pencilTickSelector.selectedSegmentIndex = ManualTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pencilTickIntervalSliderMoved:(UISlider* )sender{
|
- (void)pencilTickIntervalSliderMoved:(UISlider* )sender{
|
||||||
|
|||||||
Reference in new issue
Block a user