mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
8f9f7185af
commit
06d97d2f4d
@ -14,6 +14,8 @@ swift_library(
|
|||||||
"//submodules/Postbox:Postbox",
|
"//submodules/Postbox:Postbox",
|
||||||
"//submodules/TelegramCore:TelegramCore",
|
"//submodules/TelegramCore:TelegramCore",
|
||||||
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
|
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
|
||||||
|
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
|
||||||
|
"//submodules/PersistentStringHash:PersistentStringHash",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -5,6 +5,8 @@ import StoreKit
|
|||||||
import Postbox
|
import Postbox
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
import TelegramStringFormatting
|
import TelegramStringFormatting
|
||||||
|
import TelegramUIPreferences
|
||||||
|
import PersistentStringHash
|
||||||
|
|
||||||
private let productIdentifiers = [
|
private let productIdentifiers = [
|
||||||
"org.telegram.telegramPremium.annual",
|
"org.telegram.telegramPremium.annual",
|
||||||
@ -14,6 +16,10 @@ private let productIdentifiers = [
|
|||||||
"org.telegram.telegramPremium.threeMonths"
|
"org.telegram.telegramPremium.threeMonths"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
private func isSubscriptionProductId(_ id: String) -> Bool {
|
||||||
|
return id.hasSuffix(".monthly") || id.hasSuffix(".annual")
|
||||||
|
}
|
||||||
|
|
||||||
private extension NSDecimalNumber {
|
private extension NSDecimalNumber {
|
||||||
func round(_ decimals: Int) -> NSDecimalNumber {
|
func round(_ decimals: Int) -> NSDecimalNumber {
|
||||||
return self.rounding(accordingToBehavior:
|
return self.rounding(accordingToBehavior:
|
||||||
@ -322,6 +328,16 @@ extension InAppPurchaseManager: SKPaymentTransactionObserver {
|
|||||||
case .purchasing:
|
case .purchasing:
|
||||||
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") purchasing")
|
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") purchasing")
|
||||||
transactionState = .purchasing
|
transactionState = .purchasing
|
||||||
|
if let paymentContext = self.paymentContexts[transaction.payment.productIdentifier] {
|
||||||
|
let _ = updatePendingInAppPurchaseState(
|
||||||
|
engine: self.engine,
|
||||||
|
productId: transaction.payment.productIdentifier,
|
||||||
|
content: PendingInAppPurchaseState(
|
||||||
|
productId: transaction.payment.productIdentifier,
|
||||||
|
targetPeerId: paymentContext.targetPeerId
|
||||||
|
)
|
||||||
|
).start()
|
||||||
|
}
|
||||||
case .deferred:
|
case .deferred:
|
||||||
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") deferred")
|
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), transaction \(transaction.transactionIdentifier ?? "") deferred")
|
||||||
transactionState = .deferred
|
transactionState = .deferred
|
||||||
@ -339,29 +355,52 @@ extension InAppPurchaseManager: SKPaymentTransactionObserver {
|
|||||||
let transactionIds = transactionsToAssign.compactMap({ $0.transactionIdentifier }).joined(separator: ", ")
|
let transactionIds = transactionsToAssign.compactMap({ $0.transactionIdentifier }).joined(separator: ", ")
|
||||||
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), sending receipt for transactions [\(transactionIds)]")
|
Logger.shared.log("InAppPurchaseManager", "Account \(accountPeerId), sending receipt for transactions [\(transactionIds)]")
|
||||||
|
|
||||||
let transaction = transactionsToAssign.first
|
guard let transaction = transactionsToAssign.first else {
|
||||||
let purposeSignal: Signal<AppStoreTransactionPurpose, NoError>
|
return
|
||||||
if let productIdentifier = transaction?.payment.productIdentifier, let targetPeerId = paymentContexts[productIdentifier]?.targetPeerId {
|
}
|
||||||
purposeSignal = self.availableProducts
|
let productIdentifier = transaction.payment.productIdentifier
|
||||||
|
|
||||||
|
var completion: Signal<Never, NoError> = .never()
|
||||||
|
|
||||||
|
let purpose: Signal<AppStoreTransactionPurpose, NoError>
|
||||||
|
if !isSubscriptionProductId(productIdentifier) {
|
||||||
|
let peerId: Signal<PeerId, NoError>
|
||||||
|
if let targetPeerId = paymentContexts[productIdentifier]?.targetPeerId {
|
||||||
|
peerId = .single(targetPeerId)
|
||||||
|
} else {
|
||||||
|
peerId = pendingInAppPurchaseState(engine: self.engine, productId: productIdentifier)
|
||||||
|
|> mapToSignal { state -> Signal<PeerId, NoError> in
|
||||||
|
if let state = state, let peerId = state.targetPeerId {
|
||||||
|
return .single(peerId)
|
||||||
|
} else {
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
completion = updatePendingInAppPurchaseState(engine: self.engine, productId: productIdentifier, content: nil)
|
||||||
|
|
||||||
|
let products = self.availableProducts
|
||||||
|> filter { products in
|
|> filter { products in
|
||||||
return !products.isEmpty
|
return !products.isEmpty
|
||||||
}
|
}
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> map { products -> AppStoreTransactionPurpose in
|
|
||||||
|
purpose = combineLatest(products, peerId)
|
||||||
|
|> map { products, peerId -> AppStoreTransactionPurpose in
|
||||||
if let product = products.first(where: { $0.id == productIdentifier }) {
|
if let product = products.first(where: { $0.id == productIdentifier }) {
|
||||||
let (currency, amount) = product.priceCurrencyAndAmount
|
let (currency, amount) = product.priceCurrencyAndAmount
|
||||||
return .gift(peerId: targetPeerId, currency: currency, amount: amount)
|
return .gift(peerId: peerId, currency: currency, amount: amount)
|
||||||
} else {
|
} else {
|
||||||
return .gift(peerId: targetPeerId, currency: "", amount: 0)
|
return .gift(peerId: peerId, currency: "", amount: 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
purposeSignal = .single(.subscription)
|
purpose = .single(.subscription)
|
||||||
}
|
}
|
||||||
|
|
||||||
let receiptData = getReceiptData() ?? Data()
|
let receiptData = getReceiptData() ?? Data()
|
||||||
self.disposableSet.set(
|
self.disposableSet.set(
|
||||||
(purposeSignal
|
(purpose
|
||||||
|> castError(AssignAppStoreTransactionError.self)
|
|> castError(AssignAppStoreTransactionError.self)
|
||||||
|> mapToSignal { purpose -> Signal<Never, AssignAppStoreTransactionError> in
|
|> mapToSignal { purpose -> Signal<Never, AssignAppStoreTransactionError> in
|
||||||
self.engine.payments.sendAppStoreReceipt(receipt: receiptData, purpose: purpose)
|
self.engine.payments.sendAppStoreReceipt(receipt: receiptData, purpose: purpose)
|
||||||
@ -380,6 +419,8 @@ extension InAppPurchaseManager: SKPaymentTransactionObserver {
|
|||||||
for transaction in transactions {
|
for transaction in transactions {
|
||||||
queue.finishTransaction(transaction)
|
queue.finishTransaction(transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _ = completion.start()
|
||||||
}),
|
}),
|
||||||
forKey: transactionIds
|
forKey: transactionIds
|
||||||
)
|
)
|
||||||
@ -428,3 +469,50 @@ extension InAppPurchaseManager: SKPaymentTransactionObserver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class PendingInAppPurchaseState: Codable {
|
||||||
|
public let productId: String
|
||||||
|
public let targetPeerId: PeerId?
|
||||||
|
|
||||||
|
public init(productId: String, targetPeerId: PeerId?) {
|
||||||
|
self.productId = productId
|
||||||
|
self.targetPeerId = targetPeerId
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||||
|
|
||||||
|
self.productId = try container.decode(String.self, forKey: "productId")
|
||||||
|
self.targetPeerId = (try container.decodeIfPresent(Int64.self, forKey: "targetPeerId")).flatMap { PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value($0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||||
|
|
||||||
|
try container.encode(self.productId, forKey: "productId")
|
||||||
|
if let targetPeerId = self.targetPeerId {
|
||||||
|
try container.encode(targetPeerId.id._internalGetInt64Value(), forKey: "targetPeerId")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func pendingInAppPurchaseState(engine: TelegramEngine, productId: String) -> Signal<PendingInAppPurchaseState?, NoError> {
|
||||||
|
let key = ValueBoxKey(length: 8)
|
||||||
|
key.setInt64(0, value: Int64(bitPattern: productId.persistentHashValue))
|
||||||
|
|
||||||
|
return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.pendingInAppPurchaseState, id: key))
|
||||||
|
|> map { entry -> PendingInAppPurchaseState? in
|
||||||
|
return entry?.get(PendingInAppPurchaseState.self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updatePendingInAppPurchaseState(engine: TelegramEngine, productId: String, content: PendingInAppPurchaseState?) -> Signal<Never, NoError> {
|
||||||
|
let key = ValueBoxKey(length: 8)
|
||||||
|
key.setInt64(0, value: Int64(bitPattern: productId.persistentHashValue))
|
||||||
|
|
||||||
|
if let content = content {
|
||||||
|
return engine.itemCache.put(collectionId: ApplicationSpecificItemCacheCollectionId.pendingInAppPurchaseState, id: key, item: content)
|
||||||
|
} else {
|
||||||
|
return engine.itemCache.remove(collectionId: ApplicationSpecificItemCacheCollectionId.pendingInAppPurchaseState, id: key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -977,7 +977,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if item.message.forwardInfo != nil || item.message.attributes.first(where: { $0 is ReplyMessageAttribute }) != nil {
|
if item.message.forwardInfo != nil || item.message.attributes.first(where: { $0 is ReplyMessageAttribute }) != nil {
|
||||||
tmpWidth -= 60.0
|
tmpWidth -= 45.0
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpWidth -= deliveryFailedInset
|
tmpWidth -= deliveryFailedInset
|
||||||
|
@ -521,17 +521,20 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
let credibilityIconNode: ASImageNode
|
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||||
if let current = self.credibilityIconNode {
|
if !premiumConfiguration.isPremiumDisabled {
|
||||||
credibilityIconNode = current
|
let credibilityIconNode: ASImageNode
|
||||||
} else {
|
if let current = self.credibilityIconNode {
|
||||||
credibilityIconNode = ASImageNode()
|
credibilityIconNode = current
|
||||||
credibilityIconNode.displaysAsynchronously = false
|
} else {
|
||||||
credibilityIconNode.displayWithoutProcessing = true
|
credibilityIconNode = ASImageNode()
|
||||||
credibilityIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/PeerPremiumIcon"), color: .white)
|
credibilityIconNode.displaysAsynchronously = false
|
||||||
self.containerNode.addSubnode(credibilityIconNode)
|
credibilityIconNode.displayWithoutProcessing = true
|
||||||
|
credibilityIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/PeerPremiumIcon"), color: .white)
|
||||||
|
self.containerNode.addSubnode(credibilityIconNode)
|
||||||
|
}
|
||||||
|
credibilityIconNode.frame = CGRect(origin: CGPoint(x: 29.0 - UIScreenPixel, y: 29.0 - UIScreenPixel), size: CGSize(width: 10.0, height: 10.0))
|
||||||
}
|
}
|
||||||
credibilityIconNode.frame = CGRect(origin: CGPoint(x: 29.0 - UIScreenPixel, y: 29.0 - UIScreenPixel), size: CGSize(width: 10.0, height: 10.0))
|
|
||||||
} else {
|
} else {
|
||||||
self.credibilityIconNode?.removeFromSupernode()
|
self.credibilityIconNode?.removeFromSupernode()
|
||||||
self.credibilityIconNode = nil
|
self.credibilityIconNode = nil
|
||||||
|
@ -443,7 +443,8 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
self.animationNode.playOnce()
|
self.animationNode.playOnce()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !alreadySeen {
|
if !alreadySeen && self.animationNode.isPlaying {
|
||||||
|
item.controllerInteraction.playNextOutgoingGift = false
|
||||||
Queue.mainQueue().after(1.0) {
|
Queue.mainQueue().after(1.0) {
|
||||||
item.controllerInteraction.animateDiceSuccess(false, true)
|
item.controllerInteraction.animateDiceSuccess(false, true)
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@ private enum ApplicationSpecificItemCacheCollectionIdValues: Int8 {
|
|||||||
case cachedGeocodes = 4
|
case cachedGeocodes = 4
|
||||||
case visualMediaStoredState = 5
|
case visualMediaStoredState = 5
|
||||||
case cachedImageRecognizedContent = 6
|
case cachedImageRecognizedContent = 6
|
||||||
|
case pendingInAppPurchaseState = 7
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ApplicationSpecificItemCacheCollectionId {
|
public struct ApplicationSpecificItemCacheCollectionId {
|
||||||
@ -78,6 +79,7 @@ public struct ApplicationSpecificItemCacheCollectionId {
|
|||||||
public static let cachedGeocodes = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.cachedGeocodes.rawValue)
|
public static let cachedGeocodes = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.cachedGeocodes.rawValue)
|
||||||
public static let visualMediaStoredState = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.visualMediaStoredState.rawValue)
|
public static let visualMediaStoredState = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.visualMediaStoredState.rawValue)
|
||||||
public static let cachedImageRecognizedContent = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.cachedImageRecognizedContent.rawValue)
|
public static let cachedImageRecognizedContent = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.cachedImageRecognizedContent.rawValue)
|
||||||
|
public static let pendingInAppPurchaseState = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.pendingInAppPurchaseState.rawValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum ApplicationSpecificOrderedItemListCollectionIdValues: Int32 {
|
private enum ApplicationSpecificOrderedItemListCollectionIdValues: Int32 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user