diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift index be25f1fa74..6e602c7f42 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift @@ -1410,6 +1410,16 @@ public struct StarGiftUpgradePreview: Equatable { public let attributes: [StarGift.UniqueGift.Attribute] public let prices: [Price] public let nextPrices: [Price] + + public init(attributes: [StarGift.UniqueGift.Attribute], prices: [Price], nextPrices: [Price]) { + self.attributes = attributes + self.prices = prices + self.nextPrices = nextPrices + } + + public func withAttributes(_ attributes: [StarGift.UniqueGift.Attribute]) -> StarGiftUpgradePreview { + return StarGiftUpgradePreview(attributes: attributes, prices: self.prices, nextPrices: self.nextPrices) + } } func _internal_starGiftUpgradePreview(account: Account, giftId: Int64) -> Signal { diff --git a/submodules/TelegramUI/Components/AnimatedTextComponent/BUILD b/submodules/TelegramUI/Components/AnimatedTextComponent/BUILD index f4ce434cc1..f6ee40df82 100644 --- a/submodules/TelegramUI/Components/AnimatedTextComponent/BUILD +++ b/submodules/TelegramUI/Components/AnimatedTextComponent/BUILD @@ -14,6 +14,7 @@ swift_library( "//submodules/Display", "//submodules/ComponentFlow", "//submodules/TelegramPresentationData", + "//submodules/Components/BundleIconComponent", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/AnimatedTextComponent/Sources/AnimatedTextComponent.swift b/submodules/TelegramUI/Components/AnimatedTextComponent/Sources/AnimatedTextComponent.swift index c5d1ea1d80..f971bfaac9 100644 --- a/submodules/TelegramUI/Components/AnimatedTextComponent/Sources/AnimatedTextComponent.swift +++ b/submodules/TelegramUI/Components/AnimatedTextComponent/Sources/AnimatedTextComponent.swift @@ -3,6 +3,7 @@ import UIKit import Display import ComponentFlow import TelegramPresentationData +import BundleIconComponent extension ComponentTransition { func animateBlur(layer: CALayer, from: CGFloat, to: CGFloat, delay: Double = 0.0, removeOnCompletion: Bool = true, completion: ((Bool) -> Void)? = nil) { @@ -26,6 +27,7 @@ public final class AnimatedTextComponent: Component { public enum Content: Equatable { case text(String) case number(Int, minDigits: Int) + case icon(String, offset: CGPoint) } public var id: AnyHashable @@ -147,6 +149,9 @@ public final class AnimatedTextComponent: Component { } else { itemText = valueText.map(String.init) } + case let .icon(iconName, _): + let characterKey = CharacterKey(itemId: item.id, index: 0, value: iconName) + validKeys.append(characterKey) } var index = 0 for character in itemText { @@ -181,13 +186,24 @@ public final class AnimatedTextComponent: Component { } for item in component.items { - var itemText: [String] = [] + enum AnimatedTextCharacter { + case text(String) + case icon(String, CGPoint) + + var value: String { + switch self { + case let .text(value), let .icon(value, _): + return value + } + } + } + var itemText: [AnimatedTextCharacter] = [] switch item.content { case let .text(text): if item.isUnbreakable { - itemText = [text] + itemText = [.text(text)] } else { - itemText = text.map(String.init) + itemText = text.map { .text(String($0)) } } case let .number(value, minDigits): var valueText: String = "\(value)" @@ -196,14 +212,16 @@ public final class AnimatedTextComponent: Component { } if item.isUnbreakable { - itemText = [valueText] + itemText = [.text(valueText)] } else { - itemText = valueText.map(String.init) + itemText = valueText.map { .text(String($0)) } } + case let .icon(iconName, offset): + itemText = [.icon(iconName, offset)] } var index = 0 for character in itemText { - let characterKey = CharacterKey(itemId: item.id, index: index, value: character) + let characterKey = CharacterKey(itemId: item.id, index: index, value: character.value) index += 1 var characterTransition = transition @@ -216,17 +234,30 @@ public final class AnimatedTextComponent: Component { self.characters[characterKey] = characterView } - let characterSize = characterView.update( - transition: characterTransition, - component: AnyComponent(Text( - text: String(character), + let characterComponent: AnyComponent + var characterOffset: CGPoint = .zero + switch character { + case let .text(text): + characterComponent = AnyComponent(Text( + text: String(text), font: component.font, color: component.color - )), + )) + case let .icon(iconName, offset): + characterComponent = AnyComponent(BundleIconComponent( + name: iconName, + tintColor: component.color + )) + characterOffset = offset + } + + let characterSize = characterView.update( + transition: characterTransition, + component: characterComponent, environment: {}, containerSize: CGSize(width: availableSize.width, height: 100.0) ) - let characterFrame = CGRect(origin: CGPoint(x: size.width, y: 0.0), size: characterSize) + let characterFrame = CGRect(origin: CGPoint(x: size.width + characterOffset.x, y: characterOffset.y), size: characterSize) if let characterComponentView = characterView.view { var animateIn = false if characterComponentView.superview == nil { @@ -358,6 +389,8 @@ public extension AnimatedTextComponent { isUnbreakable = true case .number: isUnbreakable = false + case .icon: + isUnbreakable = true } textItems.append(AnimatedTextComponent.Item(id: AnyHashable("\(id)_item_\(range.index)"), isUnbreakable: isUnbreakable, content: value)) } diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index 7d4fd7f666..c7c81927a5 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -1549,9 +1549,11 @@ private final class GiftViewSheetContent: CombinedComponent { private(set) var nextUpgradePrice: StarGiftUpgradePreview.Price? func upgradePreviewTimerTick() { - guard let upgradePreview = self.upgradePreview else { + guard let upgradePreview = self.upgradePreview, let gift = self.subject.arguments?.gift, case let .generic(gift) = gift else { return } + let context = self.context + var transition: ComponentTransition = .immediate let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) if let currentPrice = self.effectiveUpgradePrice { if let price = upgradePreview.nextPrices.reversed().first(where: { currentTime >= $0.date }) { @@ -1559,7 +1561,20 @@ private final class GiftViewSheetContent: CombinedComponent { self.effectiveUpgradePrice = price if let nextPrice = upgradePreview.nextPrices.first(where: { $0.stars < price.stars }) { self.nextUpgradePrice = nextPrice + } else { + transition = .spring(duration: 0.4) + self.nextUpgradePrice = nil } + if upgradePreview.nextPrices[upgradePreview.nextPrices.count - 2] == price { + self.upgradePreviewDisposable.add((context.engine.payments.starGiftUpgradePreview(giftId: gift.id) + |> deliverOnMainQueue).start(next: { [weak self] nextUpgradePreview in + guard let self, let nextUpgradePreview else { + return + } + self.upgradePreview = nextUpgradePreview.withAttributes(upgradePreview.attributes) + })) + } + self.fetchUpgradeForm() } } else { @@ -1573,7 +1588,7 @@ private final class GiftViewSheetContent: CombinedComponent { } } - self.updated() + self.updated(transition: transition) } func requestUpgradePreview() { @@ -4483,7 +4498,15 @@ private final class GiftViewSheetContent: CombinedComponent { var buttonTitleItems: [AnyComponentWithIdentity] = [] var upgradeString = strings.Gift_Upgrade_Upgrade if !incoming { - if let gift = state.starGiftsMap[giftId], let upgradeStars = gift.upgradeStars { + let upgradeStars: Int64? + if let stars = state.effectiveUpgradePrice?.stars { + upgradeStars = stars + } else if let gift = state.starGiftsMap[giftId], let stars = gift.upgradeStars { + upgradeStars = stars + } else { + upgradeStars = nil + } + if let upgradeStars { let priceString = presentationStringsFormattedNumber(Int32(clamping: upgradeStars), environment.dateTimeFormat.groupingSeparator) upgradeString = strings.Gift_Upgrade_GiftUpgrade(" # \(priceString)").string } @@ -4507,7 +4530,75 @@ private final class GiftViewSheetContent: CombinedComponent { let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) let upgradeTimeout = nextUpgradePrice.date - currentTime - buttonTitleItems.append(AnyComponentWithIdentity(id: "static_label", component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString))))) + if let hashIndex = buttonTitle.firstIndex(of: "#") { + var buttonAnimatedTitleItems: [AnimatedTextComponent.Item] = [] + + var prefix = String(buttonTitle[..