From 141e7c1f49685ac1e1109c9efadd8f30c47c3bc2 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 7 Sep 2025 06:49:28 +0500 Subject: [PATCH] Gift original details removal --- .../Telegram-iOS/en.lproj/Localizable.strings | 2 + .../AccountContext/Sources/Premium.swift | 1 + .../MultilineTextWithEntitiesComponent.swift | 15 ++- .../Payments/BotPaymentForm.swift | 6 +- .../TelegramEngine/Payments/StarGifts.swift | 69 ++++++++++++ .../TelegramEngine/Payments/Stars.swift | 2 +- .../Payments/TelegramEnginePayments.swift | 4 + .../GiftRemoveInfoAlertController.swift | 6 +- .../Sources/GiftViewScreen.swift | 106 +++++++++++++++--- .../Sources/TableComponent.swift | 18 ++- .../Sources/PeerInfoScreen.swift | 6 + .../Sources/GiftsListView.swift | 6 + .../Sources/StarsPurchaseScreen.swift | 4 +- submodules/WebUI/Sources/WebAppWebView.swift | 2 +- 14 files changed, 221 insertions(+), 26 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index bc5270db2d..9adf4412eb 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -15013,3 +15013,5 @@ Sorry for the inconvenience."; "Gift.Options.Collectibles.Text" = "Collectible gifts are unique digital items you can exchange or sell."; "Gift.Upgrade.UpgradeFor" = "Upgrade for %@"; + +"Stars.Purchase.RemoveOriginalDetailsStarGiftInfo" = "Buy Stars to remove original details of your gift."; diff --git a/submodules/AccountContext/Sources/Premium.swift b/submodules/AccountContext/Sources/Premium.swift index 997b692306..47e50d3b10 100644 --- a/submodules/AccountContext/Sources/Premium.swift +++ b/submodules/AccountContext/Sources/Premium.swift @@ -143,6 +143,7 @@ public enum StarsPurchasePurpose: Equatable { case transferStarGift(requiredStars: Int64) case sendMessage(peerId: EnginePeer.Id, requiredStars: Int64) case buyStarGift(requiredStars: Int64) + case removeOriginalDetailsStarGift(requiredStars: Int64) } public struct PremiumConfiguration { diff --git a/submodules/Components/MultilineTextWithEntitiesComponent/Sources/MultilineTextWithEntitiesComponent.swift b/submodules/Components/MultilineTextWithEntitiesComponent/Sources/MultilineTextWithEntitiesComponent.swift index aeb2ea838f..2476daa993 100644 --- a/submodules/Components/MultilineTextWithEntitiesComponent/Sources/MultilineTextWithEntitiesComponent.swift +++ b/submodules/Components/MultilineTextWithEntitiesComponent/Sources/MultilineTextWithEntitiesComponent.swift @@ -35,6 +35,7 @@ public final class MultilineTextWithEntitiesComponent: Component { public let manualVisibilityControl: Bool public let resetAnimationsOnVisibilityChange: Bool public let displaysAsynchronously: Bool + public let maxWidth: CGFloat? public let highlightAction: (([NSAttributedString.Key: Any]) -> NSAttributedString.Key?)? public let tapAction: (([NSAttributedString.Key: Any], Int) -> Void)? public let longTapAction: (([NSAttributedString.Key: Any], Int) -> Void)? @@ -60,6 +61,7 @@ public final class MultilineTextWithEntitiesComponent: Component { manualVisibilityControl: Bool = false, resetAnimationsOnVisibilityChange: Bool = false, displaysAsynchronously: Bool = true, + maxWidth: CGFloat? = nil, highlightAction: (([NSAttributedString.Key: Any]) -> NSAttributedString.Key?)? = nil, tapAction: (([NSAttributedString.Key: Any], Int) -> Void)? = nil, longTapAction: (([NSAttributedString.Key: Any], Int) -> Void)? = nil @@ -85,6 +87,7 @@ public final class MultilineTextWithEntitiesComponent: Component { self.manualVisibilityControl = manualVisibilityControl self.resetAnimationsOnVisibilityChange = resetAnimationsOnVisibilityChange self.displaysAsynchronously = displaysAsynchronously + self.maxWidth = maxWidth self.tapAction = tapAction self.longTapAction = longTapAction } @@ -126,6 +129,9 @@ public final class MultilineTextWithEntitiesComponent: Component { if lhs.displaysAsynchronously != rhs.displaysAsynchronously { return false } + if lhs.maxWidth != rhs.maxWidth { + return false + } if let lhsTextShadowColor = lhs.textShadowColor, let rhsTextShadowColor = rhs.textShadowColor { if !lhsTextShadowColor.isEqual(rhsTextShadowColor) { return false @@ -237,7 +243,12 @@ public final class MultilineTextWithEntitiesComponent: Component { ) } - let size = self.textNode.updateLayout(availableSize) + var constrainedSize = availableSize + if let maxWidth = component.maxWidth { + constrainedSize.width = maxWidth + } + + let size = self.textNode.updateLayout(constrainedSize) self.textNode.frame = CGRect(origin: .zero, size: size) if component.handleSpoilers { @@ -266,7 +277,7 @@ public final class MultilineTextWithEntitiesComponent: Component { spoilerTextNode.textStroke = component.textStroke spoilerTextNode.isUserInteractionEnabled = false - let size = spoilerTextNode.updateLayout(availableSize) + let size = spoilerTextNode.updateLayout(constrainedSize) spoilerTextNode.frame = CGRect(origin: .zero, size: size) if spoilerTextNode.view.superview == nil { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift index 755a87caec..29a0d4dffe 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift @@ -19,7 +19,7 @@ public enum BotPaymentInvoiceSource { case premiumGift(peerId: EnginePeer.Id, option: CachedPremiumGiftOption, text: String?, entities: [MessageTextEntity]?) case starGiftResale(slug: String, toPeerId: EnginePeer.Id, ton: Bool) case starGiftPrepaidUpgrade(peerId: EnginePeer.Id, hash: String) - case starGiftDropOriginalInfo(reference: StarGiftReference) + case starGiftDropOriginalDetails(reference: StarGiftReference) } public struct BotPaymentInvoiceFields: OptionSet { @@ -421,7 +421,7 @@ func _internal_parseInputInvoice(transaction: Transaction, source: BotPaymentInv return nil } return .inputInvoiceStarGiftPrepaidUpgrade(peer: inputPeer, hash: hash) - case let .starGiftDropOriginalInfo(reference): + case let .starGiftDropOriginalDetails(reference): return reference.apiStarGiftReference(transaction: transaction).flatMap { .inputInvoiceStarGiftDropOriginalDetails(stargift: $0) } } } @@ -764,7 +764,7 @@ func _internal_sendBotPaymentForm(account: Account, formId: Int64, source: BotPa receiptMessageId = id } } - case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalInfo: + case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalDetails: receiptMessageId = nil } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift index 437ad1ffea..fdf02ea5f8 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift @@ -830,6 +830,27 @@ public enum StarGift: Equatable, Codable, PostboxCoding { themePeerId: themePeerId ) } + + public func withAttributes(_ attributes: [Attribute]) -> UniqueGift { + return UniqueGift( + id: self.id, + giftId: self.giftId, + title: self.title, + number: self.number, + slug: self.slug, + owner: self.owner, + attributes: attributes, + availability: self.availability, + giftAddress: self.giftAddress, + resellAmounts: self.resellAmounts, + resellForTonOnly: self.resellForTonOnly, + releasedBy: self.releasedBy, + valueAmount: self.valueAmount, + valueCurrency: self.valueCurrency, + flags: self.flags, + themePeerId: self.themePeerId + ) + } } public enum DecodingError: Error { @@ -1135,6 +1156,25 @@ func _internal_buyStarGift(account: Account, slug: String, peerId: EnginePeer.Id } } +public enum DropStarGiftOriginalDetailsError { + case generic +} + +func _internal_dropStarGiftOriginalDetails(account: Account, reference: StarGiftReference) -> Signal { + let source: BotPaymentInvoiceSource = .starGiftDropOriginalDetails(reference: reference) + return _internal_fetchBotPaymentForm(accountPeerId: account.peerId, postbox: account.postbox, network: account.network, source: source, themeParams: nil) + |> `catch` { error -> Signal in + return .fail(.generic) + } + |> mapToSignal { paymentForm in + return _internal_sendStarsPaymentForm(account: account, formId: paymentForm.id, source: source) + |> mapError { _ -> DropStarGiftOriginalDetailsError in + return .generic + } + |> ignoreValues + } +} + func _internal_transferStarGift(account: Account, prepaid: Bool, reference: StarGiftReference, peerId: EnginePeer.Id) -> Signal { return account.postbox.transaction { transaction -> (Api.InputPeer, Api.InputSavedStarGift)? in guard let inputPeer = transaction.getPeer(peerId).flatMap(apiInputPeer), let starGift = reference.apiStarGiftReference(transaction: transaction) else { @@ -1791,6 +1831,21 @@ private final class ProfileGiftsContextImpl { }) ) } + + public func dropOriginalDetails(reference: StarGiftReference) -> Signal { + if let index = self.gifts.firstIndex(where: { $0.reference == reference }), case let .unique(uniqueGift) = self.gifts[index].gift { + let updatedUniqueGift = uniqueGift.withAttributes(uniqueGift.attributes.filter { $0.attributeType != .originalInfo }) + self.gifts[index] = self.gifts[index].withGift(.unique(updatedUniqueGift)) + } + if let index = self.filteredGifts.firstIndex(where: { $0.reference == reference }), case let .unique(uniqueGift) = self.filteredGifts[index].gift { + let updatedUniqueGift = uniqueGift.withAttributes(uniqueGift.attributes.filter { $0.attributeType != .originalInfo }) + self.filteredGifts[index] = self.filteredGifts[index].withGift(.unique(updatedUniqueGift)) + } + + self.pushState() + + return _internal_dropStarGiftOriginalDetails(account: self.account, reference: reference) + } func convertStarGift(reference: StarGiftReference) { self.actionDisposable.set( @@ -2503,6 +2558,20 @@ public final class ProfileGiftsContext { } } + public func dropOriginalDetails(reference: StarGiftReference) -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.dropOriginalDetails(reference: reference).start(error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) + } + return disposable + } + } + public func convertStarGift(reference: StarGiftReference) { self.impl.with { impl in impl.convertStarGift(reference: reference) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift index 4c2bcc9481..7b8bb42737 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift @@ -1626,7 +1626,7 @@ func _internal_sendStarsPaymentForm(account: Account, formId: Int64, source: Bot receiptMessageId = id } } - case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalInfo: + case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalDetails: receiptMessageId = nil } } else if case let .starGiftUnique(gift, _, _, savedToProfile, canExportDate, transferStars, _, _, peerId, _, savedId, _, canTransferDate, canResaleDate, dropOriginalDetailsStars) = action.action, case let .Id(messageId) = message.id { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift index d1e4183ffb..4454f56559 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift @@ -125,6 +125,10 @@ public extension TelegramEngine { return _internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: added) } + public func dropStarGiftOriginalDetails(reference: StarGiftReference) -> Signal { + return _internal_dropStarGiftOriginalDetails(account: self.account, reference: reference) + } + public func transferStarGift(prepaid: Bool, reference: StarGiftReference, peerId: EnginePeer.Id) -> Signal { return _internal_transferStarGift(account: self.account, prepaid: prepaid, reference: reference, peerId: peerId) } diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftRemoveInfoAlertController.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftRemoveInfoAlertController.swift index 203f9ec1a4..4e4a1940a2 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftRemoveInfoAlertController.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftRemoveInfoAlertController.swift @@ -241,7 +241,7 @@ private final class GiftRemoveInfoAlertContentNode: AlertContentNode { ) ), environment: {}, - containerSize: CGSize(width: contentWidth - 32.0, height: size.height) + containerSize: CGSize(width: contentWidth - 64.0, height: size.height) ) let infoFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - infoSize.width) / 2.0), y: titleSize.height + textSize.height + 54.0), size: infoSize) if let view = self.infoView.view { @@ -326,8 +326,8 @@ public func giftRemoveInfoAlertController( var contentNode: GiftRemoveInfoAlertContentNode? var dismissImpl: ((Bool) -> Void)? - let actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: buttonText, action: { [weak contentNode] in - contentNode?.inProgress = true + let actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: buttonText, action: { + dismissImpl?(true) commit() }), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { dismissImpl?(true) diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index d826c3ff36..2436a8385f 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -664,22 +664,98 @@ private final class GiftViewSheetContent: CombinedComponent { controller.push(introController) } - func openRemoveInfo() { - guard let controller = self.getController(), let gift = self.subject.arguments?.gift, case let .unique(uniqueGift) = gift else { + func openDropOriginalDetails() { + guard let controller = self.getController(), let gift = self.subject.arguments?.gift, case let .unique(uniqueGift) = gift, let price = self.subject.arguments?.dropOriginalDetailsStars else { return } - //TODO:release let removeInfoController = giftRemoveInfoAlertController( context: self.context, gift: uniqueGift, peers: self.peerMap, - removeInfoStars: 1000, + removeInfoStars: price, navigationController: controller.navigationController as? NavigationController, - commit: {} + commit: { [weak self] in + guard let self else { + return + } + self.commitDropOriginalDetails() + } ) controller.present(removeInfoController, in: .window(.root)) } + func commitDropOriginalDetails() { + guard let arguments = self.subject.arguments, let controller = self.getController() as? GiftViewScreen, let gift = self.subject.arguments?.gift, case let .unique(uniqueGift) = gift, let starsContext = self.context.starsContext, let starsState = starsContext.currentState, let reference = arguments.reference, let price = self.subject.arguments?.dropOriginalDetailsStars else { + return + } + + let context = self.context + let proceed = { + let dropOriginalDetailsImpl = controller.dropOriginalDetails + + let signal: Signal + if let dropOriginalDetailsImpl { + signal = dropOriginalDetailsImpl(reference) + } else { + signal = (context.engine.payments.dropStarGiftOriginalDetails(reference: reference) + |> deliverOnMainQueue) + } + + self.upgradeDisposable = (signal + |> deliverOnMainQueue).start(error: { _ in + }, completed: { [weak self, weak starsContext] in + guard let self else { + return + } + Queue.mainQueue().after(0.5) { + starsContext?.load(force: true) + } + switch self.subject { + case let .profileGift(peerId, gift): + let updatedAttributes = uniqueGift.attributes.filter { $0.attributeType != .originalInfo } + self.subject = .profileGift(peerId, gift.withGift(.unique(uniqueGift.withAttributes(updatedAttributes)))) + default: + break + } + self.updated(transition: .spring(duration: 0.3)) + }) + } + + if starsState.balance < StarsAmount(value: price, nanos: 0) { + let _ = (self.optionsPromise.get() + |> filter { $0 != nil } + |> take(1) + |> deliverOnMainQueue).startStandalone(next: { [weak self] options in + guard let self, let controller = self.getController() else { + return + } + let purchaseController = self.context.sharedContext.makeStarsPurchaseScreen( + context: self.context, + starsContext: starsContext, + options: options ?? [], + purpose: .removeOriginalDetailsStarGift(requiredStars: price), + targetPeerId: nil, + completion: { [weak self, weak starsContext] stars in + guard let self, let starsContext else { + return + } + self.inProgress = true + self.updated() + + starsContext.add(balance: StarsAmount(value: stars, nanos: 0)) + let _ = (starsContext.onUpdate + |> deliverOnMainQueue).start(next: { + proceed() + }) + } + ) + controller.push(purchaseController) + }) + } else { + proceed() + } + } + private var isOpeningValue = false func openValue() { guard let controller = self.getController(), let gift = self.subject.arguments?.gift, case let .unique(uniqueGift) = gift, !self.isOpeningValue else { @@ -3493,6 +3569,7 @@ private final class GiftViewSheetContent: CombinedComponent { insets: id == "originalInfo" ? UIEdgeInsets(top: 2.0, left: 0.0, bottom: 2.0, right: 0.0) : .zero, highlightColor: tableLinkColor.withAlphaComponent(0.1), handleSpoilers: true, + maxWidth: id == "originalInfo" ? context.availableSize.width - sideInset * 2.0 - 68.0 : nil, highlightAction: { attributes in if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention)] { return NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention) @@ -3530,13 +3607,13 @@ private final class GiftViewSheetContent: CombinedComponent { var itemAlignment: HStackAlignment = .left var itemSpacing: CGFloat = 4.0 - if !"".isEmpty && id == "originalInfo" { + if id == "originalInfo", let _ = subject.arguments?.dropOriginalDetailsStars { items.append(AnyComponentWithIdentity( id: AnyHashable(1), component: AnyComponent(Button( content: AnyComponent(BundleIconComponent(name: "Chat/Context Menu/Delete", tintColor: tableLinkColor)), action: { [weak state] in - state?.openRemoveInfo() + state?.openDropOriginalDetails() } )) )) @@ -4495,7 +4572,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { case upgradePreview([StarGift.UniqueGift.Attribute], String) case wearPreview(StarGift.UniqueGift) - var arguments: (peerId: EnginePeer.Id?, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, reference: StarGiftReference?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, pinnedToTop: Bool?, converted: Bool, upgraded: Bool, refunded: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, resellAmounts: [CurrencyAmount]?, canExportDate: Int32?, upgradeMessageId: Int32?, canTransferDate: Int32?, canResaleDate: Int32?, prepaidUpgradeHash: String?, upgradeSeparate: Bool)? { + var arguments: (peerId: EnginePeer.Id?, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, reference: StarGiftReference?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, pinnedToTop: Bool?, converted: Bool, upgraded: Bool, refunded: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, resellAmounts: [CurrencyAmount]?, canExportDate: Int32?, upgradeMessageId: Int32?, canTransferDate: Int32?, canResaleDate: Int32?, prepaidUpgradeHash: String?, upgradeSeparate: Bool, dropOriginalDetailsStars: Int64?)? { switch self { case let .message(message): if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction { @@ -4509,8 +4586,8 @@ public class GiftViewScreen: ViewControllerComponentContainer { } else { reference = .message(messageId: message.id) } - return (message.id.peerId, senderId ?? message.author?.id, message.author?.compactDisplayTitle, message.id, reference, message.flags.contains(.Incoming), gift, message.timestamp, convertStars, text, entities, nameHidden, savedToProfile, nil, converted, upgraded, isRefunded, canUpgrade, upgradeStars, nil, nil, nil, upgradeMessageId, nil, nil, prepaidUpgradeHash, upgradeSeparate) - case let .starGiftUnique(gift, isUpgrade, isTransferred, savedToProfile, canExportDate, transferStars, _, _, peerId, senderId, savedId, _, canTransferDate, canResaleDate, _): + return (message.id.peerId, senderId ?? message.author?.id, message.author?.compactDisplayTitle, message.id, reference, message.flags.contains(.Incoming), gift, message.timestamp, convertStars, text, entities, nameHidden, savedToProfile, nil, converted, upgraded, isRefunded, canUpgrade, upgradeStars, nil, nil, nil, upgradeMessageId, nil, nil, prepaidUpgradeHash, upgradeSeparate, nil) + case let .starGiftUnique(gift, isUpgrade, isTransferred, savedToProfile, canExportDate, transferStars, _, _, peerId, senderId, savedId, _, canTransferDate, canResaleDate, dropOriginalDetailsStars): var reference: StarGiftReference if let peerId, let savedId { reference = .peer(peerId: peerId, id: savedId) @@ -4534,13 +4611,13 @@ public class GiftViewScreen: ViewControllerComponentContainer { if case let .unique(uniqueGift) = gift { resellAmounts = uniqueGift.resellAmounts } - return (message.id.peerId, senderId ?? message.author?.id, message.author?.compactDisplayTitle, message.id, reference, incoming, gift, message.timestamp, nil, nil, nil, false, savedToProfile, nil, false, false, false, false, nil, transferStars, resellAmounts, canExportDate, nil, canTransferDate, canResaleDate, nil, false) + return (message.id.peerId, senderId ?? message.author?.id, message.author?.compactDisplayTitle, message.id, reference, incoming, gift, message.timestamp, nil, nil, nil, false, savedToProfile, nil, false, false, false, false, nil, transferStars, resellAmounts, canExportDate, nil, canTransferDate, canResaleDate, nil, false, dropOriginalDetailsStars) default: return nil } } case let .uniqueGift(gift, _), let .wearPreview(gift): - return (nil, nil, nil, nil, nil, false, .unique(gift), 0, nil, nil, nil, false, false, nil, false, false, false, false, nil, nil, gift.resellAmounts, nil, nil, nil, nil, nil, false) + return (nil, nil, nil, nil, nil, false, .unique(gift), 0, nil, nil, nil, false, false, nil, false, false, false, false, nil, nil, gift.resellAmounts, nil, nil, nil, nil, nil, false, nil) case let .profileGift(peerId, gift): var messageId: EngineMessage.Id? if case let .message(messageIdValue) = gift.reference { @@ -4550,7 +4627,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { if case let .unique(uniqueGift) = gift.gift { resellAmounts = uniqueGift.resellAmounts } - return (peerId, gift.fromPeer?.id, gift.fromPeer?.compactDisplayTitle, messageId, gift.reference, false, gift.gift, gift.date, gift.convertStars, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, gift.pinnedToTop, false, false, false, gift.canUpgrade, gift.upgradeStars, gift.transferStars, resellAmounts, gift.canExportDate, nil, gift.canTransferDate, gift.canResaleDate, gift.prepaidUpgradeHash, gift.upgradeSeparate) + return (peerId, gift.fromPeer?.id, gift.fromPeer?.compactDisplayTitle, messageId, gift.reference, false, gift.gift, gift.date, gift.convertStars, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, gift.pinnedToTop, false, false, false, gift.canUpgrade, gift.upgradeStars, gift.transferStars, resellAmounts, gift.canExportDate, nil, gift.canTransferDate, gift.canResaleDate, gift.prepaidUpgradeHash, gift.upgradeSeparate, gift.dropOriginalDetailsStars) case .soldOutGift: return nil case .upgradePreview: @@ -4592,6 +4669,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { fileprivate let updateSavedToProfile: ((StarGiftReference, Bool) -> Void)? fileprivate let convertToStars: ((StarGiftReference) -> Void)? + fileprivate let dropOriginalDetails: ((StarGiftReference) -> Signal)? fileprivate let transferGift: ((Bool, StarGiftReference, EnginePeer.Id) -> Signal)? fileprivate let upgradeGift: ((Int64?, StarGiftReference, Bool) -> Signal)? fileprivate let buyGift: ((String, EnginePeer.Id, CurrencyAmount?) -> Signal)? @@ -4610,6 +4688,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { forceDark: Bool = false, updateSavedToProfile: ((StarGiftReference, Bool) -> Void)? = nil, convertToStars: ((StarGiftReference) -> Void)? = nil, + dropOriginalDetails: ((StarGiftReference) -> Signal)? = nil, transferGift: ((Bool, StarGiftReference, EnginePeer.Id) -> Signal)? = nil, upgradeGift: ((Int64?, StarGiftReference, Bool) -> Signal)? = nil, buyGift: ((String, EnginePeer.Id, CurrencyAmount?) -> Signal)? = nil, @@ -4623,6 +4702,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { self.updateSavedToProfile = updateSavedToProfile self.convertToStars = convertToStars + self.dropOriginalDetails = dropOriginalDetails self.transferGift = transferGift self.upgradeGift = upgradeGift self.buyGift = buyGift diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/TableComponent.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/TableComponent.swift index 751dd50684..7c9bf666be 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/TableComponent.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/TableComponent.swift @@ -7,15 +7,22 @@ import MultilineTextComponent final class TableComponent: CombinedComponent { class Item: Equatable { + enum TitleFont { + case regular + case bold + } + public let id: AnyHashable public let title: String? + public let titleFont: TitleFont public let hasBackground: Bool public let component: AnyComponent public let insets: UIEdgeInsets? - public init(id: IdType, title: String?, hasBackground: Bool = false, component: AnyComponent, insets: UIEdgeInsets? = nil) { + public init(id: IdType, title: String?, titleFont: TitleFont = .regular, hasBackground: Bool = false, component: AnyComponent, insets: UIEdgeInsets? = nil) { self.id = AnyHashable(id) self.title = title + self.titleFont = titleFont self.hasBackground = hasBackground self.component = component self.insets = insets @@ -28,6 +35,9 @@ final class TableComponent: CombinedComponent { if lhs.title != rhs.title { return false } + if lhs.titleFont != rhs.titleFont { + return false + } if lhs.hasBackground != rhs.hasBackground { return false } @@ -99,7 +109,7 @@ final class TableComponent: CombinedComponent { } let titleChild = titleChildren[item.id].update( component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString(string: title, font: Font.regular(15.0), textColor: context.component.theme.list.itemPrimaryTextColor)) + text: .plain(NSAttributedString(string: title, font: item.titleFont == .bold ? Font.semibold(15.0) : Font.regular(15.0), textColor: context.component.theme.list.itemPrimaryTextColor)) )), availableSize: context.availableSize, transition: context.transition @@ -259,12 +269,16 @@ final class TableComponent: CombinedComponent { context.add(valueChild .position(valueFrame.center) + .appear(.default(alpha: true)) + .disappear(.default(alpha: true)) ) if i < updatedBorderChildren.count { let borderChild = updatedBorderChildren[i] context.add(borderChild .position(CGPoint(x: context.availableSize.width / 2.0, y: originY + rowHeight - borderWidth / 2.0)) + .appear(.default(alpha: true)) + .disappear(.default(alpha: true)) ) } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index ba34471182..5233c7af60 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -5020,6 +5020,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } profileGifts.convertStarGift(reference: reference) }, + dropOriginalDetails: { [weak profileGifts] reference in + guard let profileGifts else { + return .complete() + } + return profileGifts.dropOriginalDetails(reference: reference) + }, transferGift: { [weak profileGifts] prepaid, reference, peerId in guard let profileGifts else { return .complete() diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftsListView.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftsListView.swift index ac6ade2870..08c6b85a34 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftsListView.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftsListView.swift @@ -617,6 +617,12 @@ final class GiftsListView: UIView { } self.profileGifts.convertStarGift(reference: reference) }, + dropOriginalDetails: { [weak self] reference in + guard let self else { + return .complete() + } + return self.profileGifts.dropOriginalDetails(reference: reference) + }, transferGift: { [weak self] prepaid, reference, peerId in guard let self else { return .complete() diff --git a/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift b/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift index 5847fe1151..adfe977e20 100644 --- a/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift @@ -251,6 +251,8 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent { } case .buyStarGift: textString = strings.Stars_Purchase_BuyStarGiftInfo + case .removeOriginalDetailsStarGift: + textString = strings.Stars_Purchase_RemoveOriginalDetailsStarGiftInfo } let markdownAttributes = MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: textColor), bold: MarkdownAttributeSet(font: boldTextFont, textColor: textColor), link: MarkdownAttributeSet(font: textFont, textColor: accentColor), linkAttribute: { contents in @@ -834,7 +836,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent { titleText = strings.Stars_Purchase_GetStars case .gift: titleText = strings.Stars_Purchase_GiftStars - case let .topUp(requiredStars, _), let .transfer(_, requiredStars), let .reactions(_, requiredStars), let .subscription(_, requiredStars, _), let .unlockMedia(requiredStars), let .starGift(_, requiredStars), let .upgradeStarGift(requiredStars), let .transferStarGift(requiredStars), let .sendMessage(_, requiredStars), let .buyStarGift(requiredStars): + case let .topUp(requiredStars, _), let .transfer(_, requiredStars), let .reactions(_, requiredStars), let .subscription(_, requiredStars, _), let .unlockMedia(requiredStars), let .starGift(_, requiredStars), let .upgradeStarGift(requiredStars), let .transferStarGift(requiredStars), let .sendMessage(_, requiredStars), let .buyStarGift(requiredStars), let .removeOriginalDetailsStarGift(requiredStars): titleText = strings.Stars_Purchase_StarsNeeded(Int32(requiredStars)) } diff --git a/submodules/WebUI/Sources/WebAppWebView.swift b/submodules/WebUI/Sources/WebAppWebView.swift index 3ad33bca74..2c82e6c57a 100644 --- a/submodules/WebUI/Sources/WebAppWebView.swift +++ b/submodules/WebUI/Sources/WebAppWebView.swift @@ -227,7 +227,7 @@ final class WebAppWebView: WKWebView { } func sendEvent(name: String, data: String?) { - let script = "window.TelegramGameProxy.receiveEvent(\"\(name)\", \(data ?? "null"))" + let script = "window.TelegramGameProxy && window.TelegramGameProxy.receiveEvent && window.TelegramGameProxy.receiveEvent(\"\(name)\", \(data ?? "null"))" self.evaluateJavaScript(script, completionHandler: { _, _ in }) }