diff --git a/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift b/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift index 594272e10b..df32f8ba53 100644 --- a/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift +++ b/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift @@ -219,36 +219,22 @@ private func getReceiptData() -> Data? { extension InAppPurchaseManager: SKPaymentTransactionObserver { public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { - for transaction in transactions { + self.stateQueue.async { let accountPeerId = "\(self.engine.account.peerId.toInt64())" - if let applicationUsername = transaction.payment.applicationUsername, applicationUsername != accountPeerId { - continue - } - - let productIdentifier = transaction.payment.productIdentifier - self.stateQueue.async { + var transactionsToAssign: [SKPaymentTransaction] = [] + for transaction in transactions { + if let applicationUsername = transaction.payment.applicationUsername, applicationUsername != accountPeerId { + continue + } + + let productIdentifier = transaction.payment.productIdentifier let transactionState: TransactionState? switch transaction.transactionState { case .purchased: Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? ""), original transaction \(transaction.original?.transactionIdentifier ?? "none") purchased") - let transactionIdentifier = transaction.transactionIdentifier - transactionState = .purchased(transactionId: transactionIdentifier) - if let transactionIdentifier = transactionIdentifier { - self.disposableSet.set( - self.engine.payments.sendAppStoreReceipt(receipt: getReceiptData() ?? Data(), restore: false).start(error: { [weak self] _ in - Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") failed to assign AppStore transaction") - queue.finishTransaction(transaction) - - if let strongSelf = self, let context = strongSelf.paymentContexts[productIdentifier] { - context.subscriber(.assignFailed) - } - }, completed: { - Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") successfully assigned AppStore transaction") - queue.finishTransaction(transaction) - }), - forKey: transactionIdentifier - ) - } + + transactionState = .purchased(transactionId: transaction.transactionIdentifier) + transactionsToAssign.append(transaction) case .restored: Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? ""), original transaction \(transaction.original?.transactionIdentifier ?? "") restroring") let transactionIdentifier = transaction.transactionIdentifier @@ -272,6 +258,31 @@ extension InAppPurchaseManager: SKPaymentTransactionObserver { } } } + + if !transactionsToAssign.isEmpty { + let transactionIds = transactionsToAssign.compactMap({ $0.transactionIdentifier }).joined(separator: ", ") + Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), sending receipt for transactions [\(transactionIds)]") + + self.disposableSet.set( + self.engine.payments.sendAppStoreReceipt(receipt: getReceiptData() ?? Data(), restore: false).start(error: { [weak self] _ in + Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transactions [\(transactionIds)] failed to assign") + for transaction in transactions { + self?.stateQueue.async { + if let strongSelf = self, let context = strongSelf.paymentContexts[transaction.payment.productIdentifier] { + context.subscriber(.assignFailed) + } + } + queue.finishTransaction(transaction) + } + }, completed: { + Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transactions [\(transactionIds)] successfully assigned") + for transaction in transactions { + queue.finishTransaction(transaction) + } + }), + forKey: transactionIds + ) + } } } diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index aac2278425..afcaf06ea6 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -1422,16 +1422,23 @@ private final class PremiumIntroScreenComponent: CombinedComponent { return .never() } |> timeout(15.0, queue: Queue.mainQueue(), alternate: .fail(.timeout)) - |> deliverOnMainQueue).start(error: { _ in - addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium.promo_screen_fail") - - let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } - let errorText = presentationData.strings.Premium_Purchase_ErrorUnknown - let alertController = textAlertController(context: strongSelf.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]) - strongSelf.present(alertController) + |> deliverOnMainQueue).start(error: { [weak self] _ in + if let strongSelf = self { + strongSelf.inProgress = false + strongSelf.updated(transition: .immediate) + strongSelf.completion() + + addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium.promo_screen_fail") + + let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } + let errorText = presentationData.strings.Premium_Purchase_ErrorUnknown + let alertController = textAlertController(context: strongSelf.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]) + strongSelf.present(alertController) + } }, completed: { [weak self] in if let strongSelf = self { let _ = updatePremiumPromoConfigurationOnce(account: strongSelf.context.account).start() + strongSelf.inProgress = false strongSelf.isPremium = true strongSelf.updated(transition: .easeInOut(duration: 0.25)) strongSelf.completion() diff --git a/submodules/PremiumUI/Sources/PremiumLimitScreen.swift b/submodules/PremiumUI/Sources/PremiumLimitScreen.swift index e06998de3c..275b522b93 100644 --- a/submodules/PremiumUI/Sources/PremiumLimitScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumLimitScreen.swift @@ -851,23 +851,24 @@ private final class LimitSheetContent: CombinedComponent { availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height), transition: .immediate ) - - let gradientColors: [UIColor] - if isPremiumDisabled { - gradientColors = [ - UIColor(rgb: 0x007afe), - UIColor(rgb: 0x5494ff) - ] - } else { - gradientColors = [ - UIColor(rgb: 0x0077ff), - UIColor(rgb: 0x6b93ff), - UIColor(rgb: 0x8878ff), - UIColor(rgb: 0xe46ace) - ] - } - + + let contentSize: CGSize if state.initialized { + let gradientColors: [UIColor] + if isPremiumDisabled { + gradientColors = [ + UIColor(rgb: 0x007afe), + UIColor(rgb: 0x5494ff) + ] + } else { + gradientColors = [ + UIColor(rgb: 0x0077ff), + UIColor(rgb: 0x6b93ff), + UIColor(rgb: 0x8878ff), + UIColor(rgb: 0xe46ace) + ] + } + let limit = limit.update( component: PremiumLimitDisplayComponent( inactiveColor: theme.list.itemBlocksSeparatorColor.withAlphaComponent(0.5), @@ -889,58 +890,60 @@ private final class LimitSheetContent: CombinedComponent { context.add(limit .position(CGPoint(x: context.availableSize.width / 2.0, y: limit.size.height / 2.0 + 44.0)) ) - } - let isIncreaseButton = !reachedMaximumLimit && !isPremiumDisabled - let button = button.update( - component: SolidRoundedButtonComponent( - title: isIncreaseButton ? strings.Premium_IncreaseLimit : strings.Common_OK, - - theme: SolidRoundedButtonComponent.Theme( - backgroundColor: .black, - backgroundColors: gradientColors, - foregroundColor: .white + let isIncreaseButton = !reachedMaximumLimit && !isPremiumDisabled + let button = button.update( + component: SolidRoundedButtonComponent( + title: isIncreaseButton ? strings.Premium_IncreaseLimit : strings.Common_OK, + + theme: SolidRoundedButtonComponent.Theme( + backgroundColor: .black, + backgroundColors: gradientColors, + foregroundColor: .white + ), + font: .bold, + fontSize: 17.0, + height: 50.0, + cornerRadius: 10.0, + gloss: isIncreaseButton, + animationName: isIncreaseButton ? buttonAnimationName : nil, + iconPosition: .right, + action: { [weak component] in + guard let component = component else { + return + } + component.dismiss() + if isIncreaseButton { + component.action() + } + } ), - font: .bold, - fontSize: 17.0, - height: 50.0, - cornerRadius: 10.0, - gloss: isIncreaseButton, - animationName: isIncreaseButton ? buttonAnimationName : nil, - iconPosition: .right, - action: { [weak component] in - guard let component = component else { - return - } - component.dismiss() - if isIncreaseButton { - component.action() - } - } - ), - availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0), - transition: context.transition - ) + availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0), + transition: context.transition + ) + + var textOffset: CGFloat = 228.0 + if isPremiumDisabled { + textOffset -= 68.0 + } + + context.add(title + .position(CGPoint(x: context.availableSize.width / 2.0, y: 28.0)) + ) + context.add(text + .position(CGPoint(x: context.availableSize.width / 2.0, y: textOffset)) + ) + + let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: textOffset + ceil(text.size.height / 2.0) + 38.0), size: button.size) + context.add(button + .position(CGPoint(x: buttonFrame.midX, y: buttonFrame.midY)) + ) - var textOffset: CGFloat = 228.0 - if isPremiumDisabled { - textOffset -= 68.0 + contentSize = CGSize(width: context.availableSize.width, height: buttonFrame.maxY + 5.0 + environment.safeInsets.bottom) + } else { + contentSize = CGSize(width: context.availableSize.width, height: 351.0 + environment.safeInsets.bottom) } - context.add(title - .position(CGPoint(x: context.availableSize.width / 2.0, y: 28.0)) - ) - context.add(text - .position(CGPoint(x: context.availableSize.width / 2.0, y: textOffset)) - ) - - let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: textOffset + ceil(text.size.height / 2.0) + 38.0), size: button.size) - context.add(button - .position(CGPoint(x: buttonFrame.midX, y: buttonFrame.midY)) - ) - - let contentSize = CGSize(width: context.availableSize.width, height: buttonFrame.maxY + 5.0 + environment.safeInsets.bottom) - return contentSize } } diff --git a/submodules/SolidRoundedButtonNode/Sources/SolidRoundedButtonNode.swift b/submodules/SolidRoundedButtonNode/Sources/SolidRoundedButtonNode.swift index ae976a8581..04c3773cc8 100644 --- a/submodules/SolidRoundedButtonNode/Sources/SolidRoundedButtonNode.swift +++ b/submodules/SolidRoundedButtonNode/Sources/SolidRoundedButtonNode.swift @@ -808,6 +808,10 @@ public final class SolidRoundedButtonView: UIView { fatalError("init(coder:) has not been implemented") } + deinit { + self.animationTimer?.invalidate() + } + private func setupGloss() { if self.gloss { if self.shimmerView == nil { @@ -1002,7 +1006,7 @@ public final class SolidRoundedButtonView: UIView { compositingFilter = nil } - let globalTimeOffset = self.icon == nil + let globalTimeOffset = self.icon == nil && self.animation == nil shimmerView.update(backgroundColor: .clear, foregroundColor: color.withAlphaComponent(alpha), gradientSize: 70.0, globalTimeOffset: globalTimeOffset, duration: 3.0, horizontal: true) borderShimmerView.update(backgroundColor: .clear, foregroundColor: color.withAlphaComponent(borderAlpha), gradientSize: 70.0, globalTimeOffset: globalTimeOffset, duration: 3.0, horizontal: true)