Various fixes

This commit is contained in:
Ilya Laktyushin 2022-06-08 20:25:57 +04:00
parent 041b37b9af
commit 3e8e152ca5
5 changed files with 69 additions and 8 deletions

View File

@ -32,6 +32,11 @@ public final class InAppPurchaseManager: NSObject {
case notAllowed case notAllowed
} }
public enum RestoreState {
case succeed
case failed
}
private final class PaymentTransactionContext { private final class PaymentTransactionContext {
var state: SKPaymentTransactionState? var state: SKPaymentTransactionState?
let subscriber: (TransactionState) -> Void let subscriber: (TransactionState) -> Void
@ -59,6 +64,8 @@ public final class InAppPurchaseManager: NSObject {
private let stateQueue = Queue() private let stateQueue = Queue()
private var paymentContexts: [String: PaymentTransactionContext] = [:] private var paymentContexts: [String: PaymentTransactionContext] = [:]
private var onRestoreCompletion: ((RestoreState) -> Void)?
private let disposableSet = DisposableDict<String>() private let disposableSet = DisposableDict<String>()
public init(engine: TelegramEngine, premiumProductId: String) { public init(engine: TelegramEngine, premiumProductId: String) {
@ -79,6 +86,7 @@ public final class InAppPurchaseManager: NSObject {
guard !self.premiumProductId.isEmpty else { guard !self.premiumProductId.isEmpty else {
return return
} }
Logger.shared.log("InAppPurchaseManager", "Requesting products")
let productRequest = SKProductsRequest(productIdentifiers: Set([self.premiumProductId])) let productRequest = SKProductsRequest(productIdentifiers: Set([self.premiumProductId]))
productRequest.delegate = self productRequest.delegate = self
productRequest.start() productRequest.start()
@ -93,7 +101,17 @@ public final class InAppPurchaseManager: NSObject {
return self.productsPromise.get() return self.productsPromise.get()
} }
public func restorePurchases(completion: @escaping (RestoreState) -> Void) {
Logger.shared.log("InAppPurchaseManager", "Restoring purchases")
self.onRestoreCompletion = completion
let paymentQueue = SKPaymentQueue.default()
paymentQueue.restoreCompletedTransactions()
}
public func finishAllTransactions() { public func finishAllTransactions() {
Logger.shared.log("InAppPurchaseManager", "Finishing all transactions")
let paymentQueue = SKPaymentQueue.default() let paymentQueue = SKPaymentQueue.default()
let transactions = paymentQueue.transactions let transactions = paymentQueue.transactions
for transaction in transactions { for transaction in transactions {
@ -102,6 +120,8 @@ public final class InAppPurchaseManager: NSObject {
} }
public func buyProduct(_ product: Product, account: Account) -> Signal<PurchaseState, PurchaseError> { public func buyProduct(_ product: Product, account: Account) -> Signal<PurchaseState, PurchaseError> {
Logger.shared.log("InAppPurchaseManager", "Buying product: \(product.skProduct.productIdentifier), price \(product.price)")
let payment = SKPayment(product: product.skProduct) let payment = SKPayment(product: product.skProduct)
SKPaymentQueue.default().add(payment) SKPaymentQueue.default().add(payment)
@ -162,7 +182,10 @@ extension InAppPurchaseManager: SKProductsRequestDelegate {
self.productRequest = nil self.productRequest = nil
Queue.mainQueue().async { Queue.mainQueue().async {
self.productsPromise.set(.single(response.products.map { Product(skProduct: $0) })) let products = response.products.map { Product(skProduct: $0) }
Logger.shared.log("InAppPurchaseManager", "Received products \(products.map({ $0.skProduct.productIdentifier }).joined(separator: ", "))")
self.productsPromise.set(.single(products))
} }
} }
} }
@ -187,37 +210,46 @@ extension InAppPurchaseManager: SKPaymentTransactionObserver {
let transactionState: TransactionState? let transactionState: TransactionState?
switch transaction.transactionState { switch transaction.transactionState {
case .purchased: case .purchased:
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? ""), original transaction \(transaction.original?.transactionIdentifier ?? "none") purchased")
let transactionIdentifier = transaction.transactionIdentifier let transactionIdentifier = transaction.transactionIdentifier
transactionState = .purchased(transactionId: transactionIdentifier) transactionState = .purchased(transactionId: transactionIdentifier)
if let transactionIdentifier = transactionIdentifier { if let transactionIdentifier = transactionIdentifier {
self.disposableSet.set( self.disposableSet.set(
self.engine.payments.assignAppStoreTransaction(transactionId: transactionIdentifier, receipt: getReceiptData() ?? Data(), restore: false).start(error: { _ in self.engine.payments.assignAppStoreTransaction(transactionId: transactionIdentifier, receipt: getReceiptData() ?? Data(), restore: false).start(error: { _ in
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") failed to assign AppStore transaction")
queue.finishTransaction(transaction) queue.finishTransaction(transaction)
}, completed: { }, completed: {
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") successfully assigned AppStore transaction")
queue.finishTransaction(transaction) queue.finishTransaction(transaction)
}), }),
forKey: transactionIdentifier forKey: transactionIdentifier
) )
} }
case .restored: case .restored:
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? ""), original transaction \(transaction.original?.transactionIdentifier ?? "") restroring")
let transactionIdentifier = transaction.transactionIdentifier let transactionIdentifier = transaction.transactionIdentifier
transactionState = .restored(transactionId: transactionIdentifier) transactionState = .restored(transactionId: transactionIdentifier)
if let transactionIdentifier = transactionIdentifier { if let transactionIdentifier = transactionIdentifier {
self.disposableSet.set( self.disposableSet.set(
self.engine.payments.assignAppStoreTransaction(transactionId: transactionIdentifier, receipt: getReceiptData() ?? Data(), restore: true).start(error: { _ in self.engine.payments.assignAppStoreTransaction(transactionId: transactionIdentifier, receipt: getReceiptData() ?? Data(), restore: true).start(error: { _ in
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") failed to assign AppStore transaction")
queue.finishTransaction(transaction) queue.finishTransaction(transaction)
}, completed: { }, completed: {
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") successfully assigned AppStore transaction")
queue.finishTransaction(transaction) queue.finishTransaction(transaction)
}), }),
forKey: transactionIdentifier forKey: transactionIdentifier
) )
} }
case .failed: case .failed:
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") failed \((transaction.error as? SKError)?.localizedDescription ?? "")")
transactionState = .failed(error: transaction.error as? SKError) transactionState = .failed(error: transaction.error as? SKError)
queue.finishTransaction(transaction) queue.finishTransaction(transaction)
case .purchasing: case .purchasing:
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") purchasing")
transactionState = .purchasing transactionState = .purchasing
case .deferred: case .deferred:
Logger.shared.log("InAppPurchaseManager", "Transaction \(transaction.transactionIdentifier ?? "") deferred")
transactionState = .deferred transactionState = .deferred
default: default:
transactionState = nil transactionState = nil
@ -230,4 +262,20 @@ extension InAppPurchaseManager: SKPaymentTransactionObserver {
} }
} }
} }
public func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
if let onRestoreCompletion = self.onRestoreCompletion {
Logger.shared.log("InAppPurchaseManager", "Transactions restoration finished")
onRestoreCompletion(.succeed)
self.onRestoreCompletion = nil
}
}
public func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
if let onRestoreCompletion = self.onRestoreCompletion {
Logger.shared.log("InAppPurchaseManager", "Transactions restoration failed with error \((error as? SKError)?.localizedDescription ?? "")")
onRestoreCompletion(.failed)
self.onRestoreCompletion = nil
}
}
} }

View File

@ -382,6 +382,8 @@ private final class SectionGroupComponent: Component {
buttonView = current buttonView = current
} else { } else {
buttonView = HighlightTrackingButton() buttonView = HighlightTrackingButton()
buttonView.isMultipleTouchEnabled = false
buttonView.isExclusiveTouch = true
buttonView.addTarget(self, action: #selector(self.buttonPressed(_:)), for: .touchUpInside) buttonView.addTarget(self, action: #selector(self.buttonPressed(_:)), for: .touchUpInside)
self.buttonViews[item.content.id] = buttonView self.buttonViews[item.content.id] = buttonView
self.addSubview(buttonView) self.addSubview(buttonView)

View File

@ -751,6 +751,8 @@ public final class SolidRoundedButtonView: UIView {
} }
self.buttonNode = HighlightTrackingButton() self.buttonNode = HighlightTrackingButton()
self.buttonNode.isMultipleTouchEnabled = false
self.buttonNode.isExclusiveTouch = true
self.titleNode = ImmediateTextView() self.titleNode = ImmediateTextView()
self.titleNode.isUserInteractionEnabled = false self.titleNode.isUserInteractionEnabled = false

View File

@ -156,10 +156,12 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
} }
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings { if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings {
if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) { if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
if titleCredibilityIcon != .verified {
titleRightIcon = .mute titleRightIcon = .mute
} }
} }
} }
}
case let .replyThread(type, count): case let .replyThread(type, count):
let textFont = titleFont let textFont = titleFont
let textColor = titleTheme.rootController.navigationBar.primaryTextColor let textColor = titleTheme.rootController.navigationBar.primaryTextColor

View File

@ -2609,7 +2609,9 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let _ = nextPanelSubtitleNodeLayout[TitleNodeStateRegular]!.size let _ = nextPanelSubtitleNodeLayout[TitleNodeStateRegular]!.size
let usernameSize = usernameNodeLayout[TitleNodeStateRegular]!.size let usernameSize = usernameNodeLayout[TitleNodeStateRegular]!.size
var titleHorizontalOffset: CGFloat = 0.0
if let image = self.titleCredibilityIconNode.image { if let image = self.titleCredibilityIconNode.image {
titleHorizontalOffset = -(image.size.width + 4.0) / 2.0
transition.updateFrame(node: self.titleCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleSize.width + 4.0, y: floor((titleSize.height - image.size.height) / 2.0) + 1.0), size: image.size)) transition.updateFrame(node: self.titleCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleSize.width + 4.0, y: floor((titleSize.height - image.size.height) / 2.0) + 1.0), size: image.size))
transition.updateFrame(node: self.titleExpandedCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleExpandedSize.width + 4.0, y: floor((titleExpandedSize.height - image.size.height) / 2.0) + 1.0), size: image.size)) transition.updateFrame(node: self.titleExpandedCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleExpandedSize.width + 4.0, y: floor((titleExpandedSize.height - image.size.height) / 2.0) + 1.0), size: image.size))
} }
@ -2629,14 +2631,14 @@ final class PeerInfoHeaderNode: ASDisplayNode {
subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: minTitleFrame.maxY + 2.0), size: subtitleSize) subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: minTitleFrame.maxY + 2.0), size: subtitleSize)
usernameFrame = CGRect(origin: CGPoint(x: width - usernameSize.width - 16.0, y: minTitleFrame.midY - usernameSize.height / 2.0), size: usernameSize) usernameFrame = CGRect(origin: CGPoint(x: width - usernameSize.width - 16.0, y: minTitleFrame.midY - usernameSize.height / 2.0), size: usernameSize)
} else { } else {
titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 7.0 + (subtitleSize.height.isZero ? 11.0 : 0.0) + 11.0), size: titleSize) titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 7.0 + (subtitleSize.height.isZero ? 11.0 : 0.0) + 11.0), size: titleSize)
let totalSubtitleWidth = subtitleSize.width + usernameSpacing + usernameSize.width let totalSubtitleWidth = subtitleSize.width + usernameSpacing + usernameSize.width
if usernameSize.width == 0.0 { if usernameSize.width == 0.0 {
subtitleFrame = CGRect(origin: CGPoint(x: floor((width - subtitleSize.width) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize) subtitleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - subtitleSize.width) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize)
usernameFrame = CGRect(origin: CGPoint(x: floor((width - usernameSize.width) / 2.0), y: subtitleFrame.maxY + 1.0), size: usernameSize) usernameFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - usernameSize.width) / 2.0), y: subtitleFrame.maxY + 1.0), size: usernameSize)
} else { } else {
subtitleFrame = CGRect(origin: CGPoint(x: floor((width - totalSubtitleWidth) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize) subtitleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - totalSubtitleWidth) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize)
usernameFrame = CGRect(origin: CGPoint(x: subtitleFrame.maxX + usernameSpacing, y: titleFrame.maxY + 1.0), size: usernameSize) usernameFrame = CGRect(origin: CGPoint(x: subtitleFrame.maxX + usernameSpacing, y: titleFrame.maxY + 1.0), size: usernameSize)
} }
} }
@ -2855,6 +2857,11 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let titleScale = (transitionFraction * transitionSourceTitleFrame.height + (1.0 - transitionFraction) * titleFrame.height * neutralTitleScale) / (titleFrame.height) let titleScale = (transitionFraction * transitionSourceTitleFrame.height + (1.0 - transitionFraction) * titleFrame.height * neutralTitleScale) / (titleFrame.height)
let subtitleScale = max(0.01, min(10.0, (transitionFraction * transitionSourceSubtitleFrame.height + (1.0 - transitionFraction) * subtitleFrame.height * neutralSubtitleScale) / (subtitleFrame.height))) let subtitleScale = max(0.01, min(10.0, (transitionFraction * transitionSourceSubtitleFrame.height + (1.0 - transitionFraction) * subtitleFrame.height * neutralSubtitleScale) / (subtitleFrame.height)))
var titleFrame = titleFrame
if !self.isAvatarExpanded {
titleFrame = titleFrame.offsetBy(dx: self.isAvatarExpanded ? 0.0 : titleHorizontalOffset * titleScale, dy: 0.0)
}
let titleCenter = CGPoint(x: transitionFraction * transitionSourceTitleFrame.midX + (1.0 - transitionFraction) * titleFrame.midX, y: transitionFraction * transitionSourceTitleFrame.midY + (1.0 - transitionFraction) * titleFrame.midY) let titleCenter = CGPoint(x: transitionFraction * transitionSourceTitleFrame.midX + (1.0 - transitionFraction) * titleFrame.midX, y: transitionFraction * transitionSourceTitleFrame.midY + (1.0 - transitionFraction) * titleFrame.midY)
let subtitleCenter = CGPoint(x: transitionFraction * transitionSourceSubtitleFrame.midX + (1.0 - transitionFraction) * subtitleFrame.midX, y: transitionFraction * transitionSourceSubtitleFrame.midY + (1.0 - transitionFraction) * subtitleFrame.midY) let subtitleCenter = CGPoint(x: transitionFraction * transitionSourceSubtitleFrame.midX + (1.0 - transitionFraction) * subtitleFrame.midX, y: transitionFraction * transitionSourceSubtitleFrame.midY + (1.0 - transitionFraction) * subtitleFrame.midY)
@ -2885,7 +2892,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
subtitleOffset = titleCollapseFraction * -2.0 subtitleOffset = titleCollapseFraction * -2.0
} }
let rawTitleFrame = titleFrame let rawTitleFrame = titleFrame.offsetBy(dx: self.isAvatarExpanded ? 0.0 : titleHorizontalOffset * titleScale, dy: 0.0)
self.titleNodeRawContainer.frame = rawTitleFrame self.titleNodeRawContainer.frame = rawTitleFrame
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: CGSize())) transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: CGSize()))
let rawSubtitleFrame = subtitleFrame let rawSubtitleFrame = subtitleFrame