Gift original details removal

This commit is contained in:
Ilya Laktyushin 2025-09-07 06:49:28 +05:00
parent 5c0796b536
commit 141e7c1f49
14 changed files with 221 additions and 26 deletions

View File

@ -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.";

View File

@ -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 {

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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<Never, DropStarGiftOriginalDetailsError> {
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<BotPaymentForm, DropStarGiftOriginalDetailsError> 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<Never, TransferStarGiftError> {
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 {
@ -1792,6 +1832,21 @@ private final class ProfileGiftsContextImpl {
)
}
public func dropOriginalDetails(reference: StarGiftReference) -> Signal<Never, DropStarGiftOriginalDetailsError> {
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(
_internal_convertStarGift(account: self.account, reference: reference).startStrict()
@ -2503,6 +2558,20 @@ public final class ProfileGiftsContext {
}
}
public func dropOriginalDetails(reference: StarGiftReference) -> Signal<Never, DropStarGiftOriginalDetailsError> {
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)

View File

@ -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 {

View File

@ -125,6 +125,10 @@ public extension TelegramEngine {
return _internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: added)
}
public func dropStarGiftOriginalDetails(reference: StarGiftReference) -> Signal<Never, DropStarGiftOriginalDetailsError> {
return _internal_dropStarGiftOriginalDetails(account: self.account, reference: reference)
}
public func transferStarGift(prepaid: Bool, reference: StarGiftReference, peerId: EnginePeer.Id) -> Signal<Never, TransferStarGiftError> {
return _internal_transferStarGift(account: self.account, prepaid: prepaid, reference: reference, peerId: peerId)
}

View File

@ -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)

View File

@ -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<Never, DropStarGiftOriginalDetailsError>
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<Never, DropStarGiftOriginalDetailsError>)?
fileprivate let transferGift: ((Bool, StarGiftReference, EnginePeer.Id) -> Signal<Never, TransferStarGiftError>)?
fileprivate let upgradeGift: ((Int64?, StarGiftReference, Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError>)?
fileprivate let buyGift: ((String, EnginePeer.Id, CurrencyAmount?) -> Signal<Never, BuyStarGiftError>)?
@ -4610,6 +4688,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
forceDark: Bool = false,
updateSavedToProfile: ((StarGiftReference, Bool) -> Void)? = nil,
convertToStars: ((StarGiftReference) -> Void)? = nil,
dropOriginalDetails: ((StarGiftReference) -> Signal<Never, DropStarGiftOriginalDetailsError>)? = nil,
transferGift: ((Bool, StarGiftReference, EnginePeer.Id) -> Signal<Never, TransferStarGiftError>)? = nil,
upgradeGift: ((Int64?, StarGiftReference, Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError>)? = nil,
buyGift: ((String, EnginePeer.Id, CurrencyAmount?) -> Signal<Never, BuyStarGiftError>)? = 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

View File

@ -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<Empty>
public let insets: UIEdgeInsets?
public init<IdType: Hashable>(id: IdType, title: String?, hasBackground: Bool = false, component: AnyComponent<Empty>, insets: UIEdgeInsets? = nil) {
public init<IdType: Hashable>(id: IdType, title: String?, titleFont: TitleFont = .regular, hasBackground: Bool = false, component: AnyComponent<Empty>, 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))
)
}

View File

@ -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()

View File

@ -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()

View File

@ -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))
}

View File

@ -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
})
}