Merge commit 'd7f7eefd4b91c6112a30ab4755a3c4e2a352dfb9'

This commit is contained in:
Isaac 2024-05-24 13:39:26 +04:00
commit 5fe5812328
23 changed files with 383 additions and 158 deletions

View File

@ -196,7 +196,16 @@ class CreateGiveawayHeaderItemNode: ItemListControllerHeaderItemNode {
self.backgroundNode.update(size: CGSize(width: layout.size.width, height: navigationBarHeight), transition: transition) self.backgroundNode.update(size: CGSize(width: layout.size.width, height: navigationBarHeight), transition: transition)
let component = AnyComponent(PremiumStarComponent(isIntro: true, isVisible: true, hasIdleAnimations: true)) let component = AnyComponent(PremiumStarComponent(
isIntro: true,
isVisible: true,
hasIdleAnimations: true,
colors: [
UIColor(rgb: 0x6a94ff),
UIColor(rgb: 0x9472fd),
UIColor(rgb: 0xe26bd3)
]
))
let containerSize = CGSize(width: min(414.0, layout.size.width), height: 220.0) let containerSize = CGSize(width: min(414.0, layout.size.width), height: 220.0)
if let hostView = self.hostView { if let hostView = self.hostView {

View File

@ -266,7 +266,16 @@ private final class PremiumGiftCodeSheetContent: CombinedComponent {
) )
let star = star.update( let star = star.update(
component: PremiumStarComponent(isIntro: false, isVisible: true, hasIdleAnimations: true), component: PremiumStarComponent(
isIntro: false,
isVisible: true,
hasIdleAnimations: true,
colors: [
UIColor(rgb: 0x6a94ff),
UIColor(rgb: 0x9472fd),
UIColor(rgb: 0xe26bd3)
]
),
availableSize: CGSize(width: context.availableSize.width, height: 200.0), availableSize: CGSize(width: context.availableSize.width, height: 200.0),
transition: .immediate transition: .immediate
) )

View File

@ -3212,7 +3212,12 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
component: PremiumStarComponent( component: PremiumStarComponent(
isIntro: isIntro, isIntro: isIntro,
isVisible: starIsVisible, isVisible: starIsVisible,
hasIdleAnimations: state.hasIdleAnimations hasIdleAnimations: state.hasIdleAnimations,
colors: [
UIColor(rgb: 0x6a94ff),
UIColor(rgb: 0x9472fd),
UIColor(rgb: 0xe26bd3)
]
), ),
availableSize: CGSize(width: min(414.0, context.availableSize.width), height: 220.0), availableSize: CGSize(width: min(414.0, context.availableSize.width), height: 220.0),
transition: context.transition transition: context.transition

View File

@ -870,7 +870,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1108478618] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) } dict[-1108478618] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) }
dict[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) } dict[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) }
dict[198776256] = { return Api.StarsTopupOption.parse_starsTopupOption($0) } dict[198776256] = { return Api.StarsTopupOption.parse_starsTopupOption($0) }
dict[1600878860] = { return Api.StarsTransaction.parse_starsTransaction($0) } dict[-865044046] = { return Api.StarsTransaction.parse_starsTransaction($0) }
dict[-670195363] = { return Api.StarsTransactionPeer.parse_starsTransactionPeer($0) } dict[-670195363] = { return Api.StarsTransactionPeer.parse_starsTransactionPeer($0) }
dict[-1269320843] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerAppStore($0) } dict[-1269320843] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerAppStore($0) }
dict[-382740222] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerFragment($0) } dict[-382740222] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerFragment($0) }
@ -1302,6 +1302,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1610250415] = { return Api.payments.PaymentForm.parse_paymentForm($0) } dict[-1610250415] = { return Api.payments.PaymentForm.parse_paymentForm($0) }
dict[2079764828] = { return Api.payments.PaymentForm.parse_paymentFormStars($0) } dict[2079764828] = { return Api.payments.PaymentForm.parse_paymentFormStars($0) }
dict[1891958275] = { return Api.payments.PaymentReceipt.parse_paymentReceipt($0) } dict[1891958275] = { return Api.payments.PaymentReceipt.parse_paymentReceipt($0) }
dict[-319617530] = { return Api.payments.PaymentReceipt.parse_paymentReceiptStars($0) }
dict[1314881805] = { return Api.payments.PaymentResult.parse_paymentResult($0) } dict[1314881805] = { return Api.payments.PaymentResult.parse_paymentResult($0) }
dict[-666824391] = { return Api.payments.PaymentResult.parse_paymentVerificationNeeded($0) } dict[-666824391] = { return Api.payments.PaymentResult.parse_paymentVerificationNeeded($0) }
dict[-74456004] = { return Api.payments.SavedInfo.parse_savedInfo($0) } dict[-74456004] = { return Api.payments.SavedInfo.parse_savedInfo($0) }
@ -1379,7 +1380,7 @@ public extension Api {
return parser(reader) return parser(reader)
} }
else { else {
telegramApiLog("Type constructor \(String(UInt32(bitPattern: signature), radix: 16, uppercase: false)) not found") telegramApiLog("Type constructor \(String(signature, radix: 16, uppercase: false)) not found")
return nil return nil
} }
} }

View File

@ -656,46 +656,64 @@ public extension Api {
} }
public extension Api { public extension Api {
enum StarsTransaction: TypeConstructorDescription { enum StarsTransaction: TypeConstructorDescription {
case starsTransaction(id: String, stars: Int64, date: Int32, peer: Api.StarsTransactionPeer) case starsTransaction(flags: Int32, id: String, stars: Int64, date: Int32, peer: Api.StarsTransactionPeer, title: String?, description: String?, photo: Api.WebDocument?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .starsTransaction(let id, let stars, let date, let peer): case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo):
if boxed { if boxed {
buffer.appendInt32(1600878860) buffer.appendInt32(-865044046)
} }
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(id, buffer: buffer, boxed: false) serializeString(id, buffer: buffer, boxed: false)
serializeInt64(stars, buffer: buffer, boxed: false) serializeInt64(stars, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false) serializeInt32(date, buffer: buffer, boxed: false)
peer.serialize(buffer, true) peer.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeString(description!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {photo!.serialize(buffer, true)}
break break
} }
} }
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .starsTransaction(let id, let stars, let date, let peer): case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo):
return ("starsTransaction", [("id", id as Any), ("stars", stars as Any), ("date", date as Any), ("peer", peer as Any)]) return ("starsTransaction", [("flags", flags as Any), ("id", id as Any), ("stars", stars as Any), ("date", date as Any), ("peer", peer as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any)])
} }
} }
public static func parse_starsTransaction(_ reader: BufferReader) -> StarsTransaction? { public static func parse_starsTransaction(_ reader: BufferReader) -> StarsTransaction? {
var _1: String? var _1: Int32?
_1 = parseString(reader) _1 = reader.readInt32()
var _2: Int64? var _2: String?
_2 = reader.readInt64() _2 = parseString(reader)
var _3: Int32? var _3: Int64?
_3 = reader.readInt32() _3 = reader.readInt64()
var _4: Api.StarsTransactionPeer? var _4: Int32?
_4 = reader.readInt32()
var _5: Api.StarsTransactionPeer?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.StarsTransactionPeer _5 = Api.parse(reader, signature: signature) as? Api.StarsTransactionPeer
} }
var _6: String?
if Int(_1!) & Int(1 << 0) != 0 {_6 = parseString(reader) }
var _7: String?
if Int(_1!) & Int(1 << 1) != 0 {_7 = parseString(reader) }
var _8: Api.WebDocument?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_8 = Api.parse(reader, signature: signature) as? Api.WebDocument
} }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
let _c4 = _4 != nil let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 { let _c5 = _5 != nil
return Api.StarsTransaction.starsTransaction(id: _1!, stars: _2!, date: _3!, peer: _4!) let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil
let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.StarsTransaction.starsTransaction(flags: _1!, id: _2!, stars: _3!, date: _4!, peer: _5!, title: _6, description: _7, photo: _8)
} }
else { else {
return nil return nil

View File

@ -771,6 +771,7 @@ public extension Api.payments {
public extension Api.payments { public extension Api.payments {
enum PaymentReceipt: TypeConstructorDescription { enum PaymentReceipt: TypeConstructorDescription {
case paymentReceipt(flags: Int32, date: Int32, botId: Int64, providerId: Int64, title: String, description: String, photo: Api.WebDocument?, invoice: Api.Invoice, info: Api.PaymentRequestedInfo?, shipping: Api.ShippingOption?, tipAmount: Int64?, currency: String, totalAmount: Int64, credentialsTitle: String, users: [Api.User]) case paymentReceipt(flags: Int32, date: Int32, botId: Int64, providerId: Int64, title: String, description: String, photo: Api.WebDocument?, invoice: Api.Invoice, info: Api.PaymentRequestedInfo?, shipping: Api.ShippingOption?, tipAmount: Int64?, currency: String, totalAmount: Int64, credentialsTitle: String, users: [Api.User])
case paymentReceiptStars(flags: Int32, date: Int32, botId: Int64, title: String, description: String, photo: Api.WebDocument?, invoice: Api.Invoice, currency: String, totalAmount: Int64, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -798,6 +799,25 @@ public extension Api.payments {
item.serialize(buffer, true) item.serialize(buffer, true)
} }
break break
case .paymentReceiptStars(let flags, let date, let botId, let title, let description, let photo, let invoice, let currency, let totalAmount, let users):
if boxed {
buffer.appendInt32(-319617530)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
serializeInt64(botId, buffer: buffer, boxed: false)
serializeString(title, buffer: buffer, boxed: false)
serializeString(description, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {photo!.serialize(buffer, true)}
invoice.serialize(buffer, true)
serializeString(currency, buffer: buffer, boxed: false)
serializeInt64(totalAmount, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
} }
} }
@ -805,6 +825,8 @@ public extension Api.payments {
switch self { switch self {
case .paymentReceipt(let flags, let date, let botId, let providerId, let title, let description, let photo, let invoice, let info, let shipping, let tipAmount, let currency, let totalAmount, let credentialsTitle, let users): case .paymentReceipt(let flags, let date, let botId, let providerId, let title, let description, let photo, let invoice, let info, let shipping, let tipAmount, let currency, let totalAmount, let credentialsTitle, let users):
return ("paymentReceipt", [("flags", flags as Any), ("date", date as Any), ("botId", botId as Any), ("providerId", providerId as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("invoice", invoice as Any), ("info", info as Any), ("shipping", shipping as Any), ("tipAmount", tipAmount as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("credentialsTitle", credentialsTitle as Any), ("users", users as Any)]) return ("paymentReceipt", [("flags", flags as Any), ("date", date as Any), ("botId", botId as Any), ("providerId", providerId as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("invoice", invoice as Any), ("info", info as Any), ("shipping", shipping as Any), ("tipAmount", tipAmount as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("credentialsTitle", credentialsTitle as Any), ("users", users as Any)])
case .paymentReceiptStars(let flags, let date, let botId, let title, let description, let photo, let invoice, let currency, let totalAmount, let users):
return ("paymentReceiptStars", [("flags", flags as Any), ("date", date as Any), ("botId", botId as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("invoice", invoice as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("users", users as Any)])
} }
} }
@ -871,6 +893,50 @@ public extension Api.payments {
return nil return nil
} }
} }
public static func parse_paymentReceiptStars(_ reader: BufferReader) -> PaymentReceipt? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int64?
_3 = reader.readInt64()
var _4: String?
_4 = parseString(reader)
var _5: String?
_5 = parseString(reader)
var _6: Api.WebDocument?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.WebDocument
} }
var _7: Api.Invoice?
if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.Invoice
}
var _8: String?
_8 = parseString(reader)
var _9: Int64?
_9 = reader.readInt64()
var _10: [Api.User]?
if let _ = reader.readInt32() {
_10 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
let _c9 = _9 != nil
let _c10 = _10 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
return Api.payments.PaymentReceipt.paymentReceiptStars(flags: _1!, date: _2!, botId: _3!, title: _4!, description: _5!, photo: _6, invoice: _7!, currency: _8!, totalAmount: _9!, users: _10!)
}
else {
return nil
}
}
} }
} }
@ -1612,67 +1678,3 @@ public extension Api.photos {
} }
} }
public extension Api.premium {
enum BoostsList: TypeConstructorDescription {
case boostsList(flags: Int32, count: Int32, boosts: [Api.Boost], nextOffset: String?, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .boostsList(let flags, let count, let boosts, let nextOffset, let users):
if boxed {
buffer.appendInt32(-2030542532)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(boosts.count))
for item in boosts {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .boostsList(let flags, let count, let boosts, let nextOffset, let users):
return ("boostsList", [("flags", flags as Any), ("count", count as Any), ("boosts", boosts as Any), ("nextOffset", nextOffset as Any), ("users", users as Any)])
}
}
public static func parse_boostsList(_ reader: BufferReader) -> BoostsList? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: [Api.Boost]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Boost.self)
}
var _4: String?
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) }
var _5: [Api.User]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
let _c5 = _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.premium.BoostsList.boostsList(flags: _1!, count: _2!, boosts: _3!, nextOffset: _4, users: _5!)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,67 @@
public extension Api.premium {
enum BoostsList: TypeConstructorDescription {
case boostsList(flags: Int32, count: Int32, boosts: [Api.Boost], nextOffset: String?, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .boostsList(let flags, let count, let boosts, let nextOffset, let users):
if boxed {
buffer.appendInt32(-2030542532)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(boosts.count))
for item in boosts {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .boostsList(let flags, let count, let boosts, let nextOffset, let users):
return ("boostsList", [("flags", flags as Any), ("count", count as Any), ("boosts", boosts as Any), ("nextOffset", nextOffset as Any), ("users", users as Any)])
}
}
public static func parse_boostsList(_ reader: BufferReader) -> BoostsList? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: [Api.Boost]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Boost.self)
}
var _4: String?
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) }
var _5: [Api.User]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
let _c5 = _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.premium.BoostsList.boostsList(flags: _1!, count: _2!, boosts: _3!, nextOffset: _4, users: _5!)
}
else {
return nil
}
}
}
}
public extension Api.premium { public extension Api.premium {
enum BoostsStatus: TypeConstructorDescription { enum BoostsStatus: TypeConstructorDescription {
case boostsStatus(flags: Int32, level: Int32, currentLevelBoosts: Int32, boosts: Int32, giftBoosts: Int32?, nextLevelBoosts: Int32?, premiumAudience: Api.StatsPercentValue?, boostUrl: String, prepaidGiveaways: [Api.PrepaidGiveaway]?, myBoostSlots: [Int32]?) case boostsStatus(flags: Int32, level: Int32, currentLevelBoosts: Int32, boosts: Int32, giftBoosts: Int32?, nextLevelBoosts: Int32?, premiumAudience: Api.StatsPercentValue?, boostUrl: String, prepaidGiveaways: [Api.PrepaidGiveaway]?, myBoostSlots: [Int32]?)

View File

@ -8794,6 +8794,23 @@ public extension Api.functions.payments {
}) })
} }
} }
public extension Api.functions.payments {
static func refundStarsCharge(userId: Api.InputUser, msgId: Int32, chargeId: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(-258950164)
userId.serialize(buffer, true)
serializeInt32(msgId, buffer: buffer, boxed: false)
serializeString(chargeId, buffer: buffer, boxed: false)
return (FunctionDescription(name: "payments.refundStarsCharge", parameters: [("userId", String(describing: userId)), ("msgId", String(describing: msgId)), ("chargeId", String(describing: chargeId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer)
var result: Api.Updates?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Updates
}
return result
})
}
}
public extension Api.functions.payments { public extension Api.functions.payments {
static func sendPaymentForm(flags: Int32, formId: Int64, invoice: Api.InputInvoice, requestedInfoId: String?, shippingOptionId: String?, credentials: Api.InputPaymentCredentials, tipAmount: Int64?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.PaymentResult>) { static func sendPaymentForm(flags: Int32, formId: Int64, invoice: Api.InputInvoice, requestedInfoId: String?, shippingOptionId: String?, credentials: Api.InputPaymentCredentials, tipAmount: Int64?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.PaymentResult>) {
let buffer = Buffer() let buffer = Buffer()

View File

@ -693,6 +693,27 @@ func _internal_requestBotPaymentReceipt(account: Account, messageId: MessageId)
let botPaymentId = PeerId.init(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)) let botPaymentId = PeerId.init(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId))
return BotPaymentReceipt(invoice: parsedInvoice, info: parsedInfo, shippingOption: shippingOption, credentialsTitle: credentialsTitle, invoiceMedia: invoiceMedia, tipAmount: tipAmount, botPaymentId: botPaymentId) return BotPaymentReceipt(invoice: parsedInvoice, info: parsedInfo, shippingOption: shippingOption, credentialsTitle: credentialsTitle, invoiceMedia: invoiceMedia, tipAmount: tipAmount, botPaymentId: botPaymentId)
case let .paymentReceiptStars(_, _, botId, title, description, photo, invoice, currency, totalAmount, users: users):
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: [], users: users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
let parsedInvoice = BotPaymentInvoice(apiInvoice: invoice)
let invoiceMedia = TelegramMediaInvoice(
title: title,
description: description,
photo: photo.flatMap(TelegramMediaWebFile.init),
receiptMessageId: nil,
currency: currency,
totalAmount: totalAmount,
startParam: "",
extendedMedia: nil,
flags: [],
version: TelegramMediaInvoice.lastVersion
)
let botPaymentId = PeerId.init(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId))
return BotPaymentReceipt(invoice: parsedInvoice, info: nil, shippingOption: nil, credentialsTitle: "", invoiceMedia: invoiceMedia, tipAmount: nil, botPaymentId: botPaymentId)
} }
} }
|> castError(RequestBotPaymentReceiptError.self) |> castError(RequestBotPaymentReceiptError.self)

View File

@ -183,7 +183,7 @@ private final class StarsContextImpl {
func add(balance: Int64) { func add(balance: Int64) {
if var state = self._state { if var state = self._state {
var transactions = state.transactions var transactions = state.transactions
transactions.insert(.init(id: "\(arc4random())", count: balance, date: Int32(Date().timeIntervalSince1970), peer: .appStore), at: 0) transactions.insert(.init(id: "\(arc4random())", count: balance, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil), at: 0)
state.balance = state.balance + balance state.balance = state.balance + balance
self._state = state self._state = state
@ -216,7 +216,7 @@ private final class StarsContextImpl {
private extension StarsContext.State.Transaction { private extension StarsContext.State.Transaction {
init?(apiTransaction: Api.StarsTransaction, transaction: Transaction) { init?(apiTransaction: Api.StarsTransaction, transaction: Transaction) {
switch apiTransaction { switch apiTransaction {
case let .starsTransaction(id, stars, date, transactionPeer): case let .starsTransaction(_, id, stars, date, transactionPeer, title, description, photo):
let parsedPeer: StarsContext.State.Transaction.Peer let parsedPeer: StarsContext.State.Transaction.Peer
switch transactionPeer { switch transactionPeer {
case .starsTransactionPeerAppStore: case .starsTransactionPeerAppStore:
@ -235,7 +235,7 @@ private extension StarsContext.State.Transaction {
} }
parsedPeer = .peer(EnginePeer(peer)) parsedPeer = .peer(EnginePeer(peer))
} }
self.init(id: id, count: stars, date: date, peer: parsedPeer) self.init(id: id, count: stars, date: date, peer: parsedPeer, title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init))
} }
} }
} }
@ -256,12 +256,26 @@ public final class StarsContext {
public let count: Int64 public let count: Int64
public let date: Int32 public let date: Int32
public let peer: Peer public let peer: Peer
public let title: String?
public let description: String?
public let photo: TelegramMediaWebFile?
init(id: String, count: Int64, date: Int32, peer: Peer) { init(
id: String,
count: Int64,
date: Int32,
peer: Peer,
title: String?,
description: String?,
photo: TelegramMediaWebFile?
) {
self.id = id self.id = id
self.count = count self.count = count
self.date = date self.date = date
self.peer = peer self.peer = peer
self.title = title
self.description = description
self.photo = photo
} }
} }

View File

@ -175,7 +175,7 @@ public final class ChatBotInfoItemNode: ListViewItemNode {
break break
case .ignore: case .ignore:
return .fail return .fail
case .url, .phone, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji, .customEmoji: case .url, .phone, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji, .customEmoji, .custom:
return .waitForSingleTap return .waitForSingleTap
} }
} }

View File

@ -172,6 +172,7 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
let incoming = message.effectivelyIncoming(context.account.peerId) let incoming = message.effectivelyIncoming(context.account.peerId)
let graphics = PresentationResourcesChat.additionalGraphics(theme.theme, wallpaper: theme.wallpaper, bubbleCorners: bubbleCorners) let graphics = PresentationResourcesChat.additionalGraphics(theme.theme, wallpaper: theme.wallpaper, bubbleCorners: bubbleCorners)
var isStarsPayment = false
let iconImage: UIImage? let iconImage: UIImage?
switch button.action { switch button.action {
case .text: case .text:
@ -191,7 +192,8 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
case .switchInline: case .switchInline:
iconImage = incoming ? graphics.chatBubbleActionButtonIncomingShareIconImage : graphics.chatBubbleActionButtonOutgoingShareIconImage iconImage = incoming ? graphics.chatBubbleActionButtonIncomingShareIconImage : graphics.chatBubbleActionButtonOutgoingShareIconImage
case .payment: case .payment:
if button.title.contains("Pay XTR") { if button.title.contains("⭐️") {
isStarsPayment = true
iconImage = nil iconImage = nil
} else { } else {
iconImage = incoming ? graphics.chatBubbleActionButtonIncomingPaymentIconImage : graphics.chatBubbleActionButtonOutgoingPaymentIconImage iconImage = incoming ? graphics.chatBubbleActionButtonIncomingPaymentIconImage : graphics.chatBubbleActionButtonOutgoingPaymentIconImage
@ -222,10 +224,10 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
let titleColor = bubbleVariableColor(variableColor: messageTheme.actionButtonsTextColor, wallpaper: theme.wallpaper) let titleColor = bubbleVariableColor(variableColor: messageTheme.actionButtonsTextColor, wallpaper: theme.wallpaper)
let attributedTitle: NSAttributedString let attributedTitle: NSAttributedString
if title.contains("Pay XTR") { if isStarsPayment {
let stars = title.replacingOccurrences(of: "Pay XTR", with: "") let updatedTitle = title.replacingOccurrences(of: "⭐️", with: " # ")
let buttonAttributedString = NSMutableAttributedString(string: "Pay > \(stars)", font: titleFont, textColor: titleColor, paragraphAlignment: .center) let buttonAttributedString = NSMutableAttributedString(string: updatedTitle, font: titleFont, textColor: titleColor, paragraphAlignment: .center)
if let range = buttonAttributedString.string.range(of: ">"), let starImage = UIImage(bundleImageName: "Item List/PremiumIcon") { if let range = buttonAttributedString.string.range(of: "#"), let starImage = UIImage(bundleImageName: "Item List/PremiumIcon") {
buttonAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: buttonAttributedString.string)) buttonAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: buttonAttributedString.string))
buttonAttributedString.addAttribute(.foregroundColor, value: titleColor, range: NSRange(range, in: buttonAttributedString.string)) buttonAttributedString.addAttribute(.foregroundColor, value: titleColor, range: NSRange(range, in: buttonAttributedString.string))
buttonAttributedString.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: buttonAttributedString.string)) buttonAttributedString.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: buttonAttributedString.string))

View File

@ -159,6 +159,7 @@ public struct ChatMessageBubbleContentTapAction {
case copy(String) case copy(String)
case largeEmoji(String, String?, TelegramMediaFile) case largeEmoji(String, String?, TelegramMediaFile)
case customEmoji(TelegramMediaFile) case customEmoji(TelegramMediaFile)
case custom(() -> Void)
} }
public var content: Content public var content: Content

View File

@ -1178,7 +1178,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
break break
case .ignore: case .ignore:
return .fail return .fail
case .url, .phone, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji, .customEmoji: case .url, .phone, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji, .customEmoji, .custom:
return .waitForSingleTap return .waitForSingleTap
} }
} }
@ -4623,6 +4623,10 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
return .action(InternalBubbleTapAction.Action { return .action(InternalBubbleTapAction.Action {
}) })
} }
case let .custom(action):
return .action(InternalBubbleTapAction.Action({
action()
}, contextMenuOnLongPress: !tapAction.hasLongTapAction))
case let .url(url): case let .url(url):
if case .longTap = gesture, !tapAction.hasLongTapAction, let item = self.item { if case .longTap = gesture, !tapAction.hasLongTapAction, let item = self.item {
let tapMessage = item.content.firstMessage let tapMessage = item.content.firstMessage
@ -4872,6 +4876,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
break break
case .customEmoji: case .customEmoji:
break break
case .custom:
break
} }
} }
if let tapMessage = tapMessage { if let tapMessage = tapMessage {

View File

@ -24,6 +24,7 @@ swift_library(
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode", "//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon", "//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
"//submodules/TelegramUI/Components/Chat/MessageInlineBlockBackgroundView", "//submodules/TelegramUI/Components/Chat/MessageInlineBlockBackgroundView",
"//submodules/TextSelectionNode",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -12,6 +12,7 @@ import ChatMessageDateAndStatusNode
import ChatMessageBubbleContentNode import ChatMessageBubbleContentNode
import ChatMessageItemCommon import ChatMessageItemCommon
import MessageInlineBlockBackgroundView import MessageInlineBlockBackgroundView
import TextSelectionNode
import Geocoding import Geocoding
import UrlEscaping import UrlEscaping
@ -44,6 +45,7 @@ public class ChatMessageFactCheckBubbleContentNode: ChatMessageBubbleContentNode
private let textNode: TextNode private let textNode: TextNode
private let additionalTextNode: TextNode private let additionalTextNode: TextNode
private var linkHighlightingNode: LinkHighlightingNode? private var linkHighlightingNode: LinkHighlightingNode?
private var textSelectionNode: TextSelectionNode?
private let lineNode: ASDisplayNode private let lineNode: ASDisplayNode
@ -51,7 +53,6 @@ public class ChatMessageFactCheckBubbleContentNode: ChatMessageBubbleContentNode
private var maskOverlayView: UIView? private var maskOverlayView: UIView?
private var expandIcon: ASImageNode private var expandIcon: ASImageNode
private var expandButton: HighlightTrackingButtonNode?
private let statusNode: ChatMessageDateAndStatusNode private let statusNode: ChatMessageDateAndStatusNode
@ -136,10 +137,58 @@ public class ChatMessageFactCheckBubbleContentNode: ChatMessageBubbleContentNode
let _ = item.controllerInteraction.requestMessageUpdate(item.message.id, false) let _ = item.controllerInteraction.requestMessageUpdate(item.message.id, false)
} }
public override func tapActionAtPoint(_ point: CGPoint, gesture: TapLongTapOrDoubleTapGesture, isEstimating: Bool) -> ChatMessageBubbleContentTapAction { public override func willUpdateIsExtractedToContextPreview(_ value: Bool) {
if let expandButton = self.expandButton, expandButton.frame.contains(point) { if !value {
return ChatMessageBubbleContentTapAction(content: .ignore) if let textSelectionNode = self.textSelectionNode {
self.textSelectionNode = nil
textSelectionNode.highlightAreaNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
textSelectionNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak textSelectionNode] _ in
textSelectionNode?.highlightAreaNode.removeFromSupernode()
textSelectionNode?.removeFromSupernode()
})
}
} }
}
public override func updateIsExtractedToContextPreview(_ value: Bool) {
if value {
if self.textSelectionNode == nil, let item = self.item, let rootNode = item.controllerInteraction.chatControllerNode() {
let selectionColor: UIColor = item.presentationData.theme.theme.chat.message.incoming.textSelectionColor
let knobColor: UIColor = item.presentationData.theme.theme.chat.message.incoming.textSelectionKnobColor
let textSelectionNode = TextSelectionNode(theme: TextSelectionTheme(selection: selectionColor, knob: knobColor, isDark: item.presentationData.theme.theme.overallDarkAppearance), strings: item.presentationData.strings, textNode: self.textNode, updateIsActive: { [weak self] value in
self?.updateIsTextSelectionActive?(value)
}, present: { [weak self] c, a in
self?.item?.controllerInteraction.presentGlobalOverlayController(c, a)
}, rootNode: { [weak rootNode] in
return rootNode
}, performAction: { [weak self] text, action in
guard let strongSelf = self, let item = strongSelf.item else {
return
}
item.controllerInteraction.performTextSelectionAction(item.message, true, text, action)
})
textSelectionNode.enableQuote = false
self.textSelectionNode = textSelectionNode
self.addSubnode(textSelectionNode)
self.insertSubnode(textSelectionNode.highlightAreaNode, belowSubnode: self.textClippingNode)
textSelectionNode.frame = self.textClippingNode.view.convert(self.textNode.frame, to: self.view)
textSelectionNode.highlightAreaNode.frame = textSelectionNode.frame
}
} else {
if let textSelectionNode = self.textSelectionNode {
self.textSelectionNode = nil
self.updateIsTextSelectionActive?(false)
textSelectionNode.highlightAreaNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
textSelectionNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak textSelectionNode] _ in
textSelectionNode?.highlightAreaNode.removeFromSupernode()
textSelectionNode?.removeFromSupernode()
})
}
}
}
public override func tapActionAtPoint(_ point: CGPoint, gesture: TapLongTapOrDoubleTapGesture, isEstimating: Bool) -> ChatMessageBubbleContentTapAction {
if let titleBadgeButton = self.titleBadgeButton, titleBadgeButton.frame.contains(point) { if let titleBadgeButton = self.titleBadgeButton, titleBadgeButton.frame.contains(point) {
return ChatMessageBubbleContentTapAction(content: .ignore) return ChatMessageBubbleContentTapAction(content: .ignore)
} }
@ -162,6 +211,11 @@ public class ChatMessageFactCheckBubbleContentNode: ChatMessageBubbleContentNode
return ChatMessageBubbleContentTapAction(content: .hashtag(hashtag.peerName, hashtag.hashtag)) return ChatMessageBubbleContentTapAction(content: .hashtag(hashtag.peerName, hashtag.hashtag))
} }
} }
if let backgroundView = self.backgroundView, backgroundView.frame.contains(point), case .tap = gesture {
return ChatMessageBubbleContentTapAction(content: .custom({ [weak self] in
self?.expandPressed()
}), hasLongTapAction: false)
}
return ChatMessageBubbleContentTapAction(content: .none) return ChatMessageBubbleContentTapAction(content: .none)
} }
@ -585,35 +639,21 @@ public class ChatMessageFactCheckBubbleContentNode: ChatMessageBubbleContentNode
} }
strongSelf.expandIcon.bounds = CGRect(origin: .zero, size: expandIconFrame.size) strongSelf.expandIcon.bounds = CGRect(origin: .zero, size: expandIconFrame.size)
} }
let expandButtonFrame = expandIconFrame.insetBy(dx: -8.0, dy: -8.0)
let expandButton: HighlightTrackingButtonNode
if let current = strongSelf.expandButton {
expandButton = current
} else {
expandButton = HighlightTrackingButtonNode()
expandButton.addTarget(self, action: #selector(strongSelf.expandPressed), forControlEvents: .touchUpInside)
expandButton.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
strongSelf.expandIcon.layer.removeAnimation(forKey: "opacity")
strongSelf.expandIcon.alpha = 0.4
} else {
strongSelf.expandIcon.alpha = 1.0
strongSelf.expandIcon.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
strongSelf.expandButton = expandButton
strongSelf.addSubnode(expandButton)
}
expandButton.frame = expandButtonFrame
} else { } else {
strongSelf.expandIcon.isHidden = true strongSelf.expandIcon.isHidden = true
strongSelf.textClippingNode.view.mask = nil strongSelf.textClippingNode.view.mask = nil
} }
if let textSelectionNode = strongSelf.textSelectionNode {
let shouldUpdateLayout = textSelectionNode.frame.size != textFrame.size
textSelectionNode.frame = strongSelf.textClippingNode.view.convert(strongSelf.textNode.frame, to: strongSelf.view)
textSelectionNode.highlightAreaNode.frame = textSelectionNode.frame
if shouldUpdateLayout {
textSelectionNode.updateLayout()
}
}
if let statusSizeAndApply = statusSizeAndApply { if let statusSizeAndApply = statusSizeAndApply {
strongSelf.statusNode.reactionSelected = { [weak strongSelf] _, value, sourceView in strongSelf.statusNode.reactionSelected = { [weak strongSelf] _, value, sourceView in
guard let strongSelf, let item = strongSelf.item else { guard let strongSelf, let item = strongSelf.item else {

View File

@ -494,7 +494,12 @@ public class ChatMessageThreadInfoNode: ASDisplayNode {
node.contentNode.addSubnode(avatarNode) node.contentNode.addSubnode(avatarNode)
} }
avatarNode.frame = CGRect(origin: CGPoint(x: -1.0, y: -3.0), size: CGSize(width: 26.0, height: 26.0)) avatarNode.frame = CGRect(origin: CGPoint(x: -1.0, y: -3.0), size: CGSize(width: 26.0, height: 26.0))
avatarNode.setPeer(context: arguments.context, theme: arguments.presentationData.theme.theme, peer: peer)
var overrideImage: AvatarNodeImageOverride?
if peer.id.isReplies {
overrideImage = .repliesIcon
}
avatarNode.setPeer(context: arguments.context, theme: arguments.presentationData.theme.theme, peer: peer, overrideImage: overrideImage)
} else { } else {
let titleTopicIconView: ComponentHostView<Empty> let titleTopicIconView: ComponentHostView<Empty>
if let current = node.titleTopicIconView { if let current = node.titleTopicIconView {

View File

@ -222,7 +222,7 @@ private final class FactCheckAlertContentNode: AlertContentNode {
characterLimit: 1024, characterLimit: 1024,
emptyLineHandling: .oneConsecutive, emptyLineHandling: .oneConsecutive,
formatMenuAvailability: .available([.bold, .italic, .link]), formatMenuAvailability: .available([.bold, .italic, .link]),
returnKeyType: .done, returnKeyType: .default,
lockedFormatAction: { lockedFormatAction: {
}, },
present: { [weak self] c in present: { [weak self] c in

View File

@ -33,7 +33,11 @@ private func generateShineTexture() -> UIImage {
private func generateDiffuseTexture(colors: [UIColor]) -> UIImage { private func generateDiffuseTexture(colors: [UIColor]) -> UIImage {
return generateImage(CGSize(width: 256, height: 256), rotatedContext: { size, context in return generateImage(CGSize(width: 256, height: 256), rotatedContext: { size, context in
let colorsArray: [CGColor] = colors.map { $0.cgColor } let colorsArray: [CGColor] = colors.map { $0.cgColor }
var locations: [CGFloat] = [0.0, 0.25, 0.5, 0.75, 1.0] var locations: [CGFloat] = []
for i in 0 ..< colors.count {
let t = CGFloat(i) / CGFloat(colors.count - 1)
locations.append(t)
}
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)! let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: size.height), end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions()) context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: size.height), end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions())
@ -281,7 +285,7 @@ public final class PremiumStarComponent: Component {
private var didSetup = false private var didSetup = false
private func setup() { private func setup() {
guard !self.didSetup, let scene = loadCompressedScene(name: "star", version: sceneVersion) else { guard !self.didSetup, let scene = loadCompressedScene(name: "star2", version: sceneVersion) else {
return return
} }
@ -289,23 +293,23 @@ public final class PremiumStarComponent: Component {
self.sceneView.scene = scene self.sceneView.scene = scene
self.sceneView.delegate = self self.sceneView.delegate = self
if let node = scene.rootNode.childNode(withName: "star", recursively: false), let colors = self.component?.colors, let color = colors.first { if let node = scene.rootNode.childNode(withName: "star", recursively: false), let colors = self.component?.colors, let _ = colors.first {
node.geometry?.materials.first?.diffuse.contents = generateDiffuseTexture(colors: colors) node.geometry?.materials.first?.diffuse.contents = generateDiffuseTexture(colors: colors)
let names: [String] = [ // let names: [String] = [
"particles_left", // "particles_left",
"particles_right", // "particles_right",
"particles_left_bottom", // "particles_left_bottom",
"particles_right_bottom", // "particles_right_bottom",
"particles_center" // "particles_center"
] // ]
//
for name in names { // for name in names {
if let node = scene.rootNode.childNode(withName: name, recursively: false), let particleSystem = node.particleSystems?.first { // if let node = scene.rootNode.childNode(withName: name, recursively: false), let particleSystem = node.particleSystems?.first {
particleSystem.particleColor = color // particleSystem.particleColor = color
particleSystem.particleColorVariation = SCNVector4Make(0, 0, 0, 0) // particleSystem.particleColorVariation = SCNVector4Make(0, 0, 0, 0)
} // }
} // }
} }
if self.animateFrom != nil { if self.animateFrom != nil {
@ -450,9 +454,9 @@ public final class PremiumStarComponent: Component {
return return
} }
if #available(iOS 17.0, *), let material = node.geometry?.materials.first { // if let material = node.geometry?.materials.first {
material.metalness.intensity = 0.2 // material.metalness.intensity = 0.4
} // }
let animation = CABasicAnimation(keyPath: "contentsTransform") let animation = CABasicAnimation(keyPath: "contentsTransform")
animation.fillMode = .forwards animation.fillMode = .forwards

View File

@ -696,10 +696,10 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
isVisible: starIsVisible, isVisible: starIsVisible,
hasIdleAnimations: state.hasIdleAnimations, hasIdleAnimations: state.hasIdleAnimations,
colors: [ colors: [
UIColor(rgb: 0xea8904), UIColor(rgb: 0xe57d02),
UIColor(rgb: 0xf09903), UIColor(rgb: 0xf09903),
UIColor(rgb: 0xfec209), UIColor(rgb: 0xf9b004),
UIColor(rgb: 0xfed31a) UIColor(rgb: 0xfdd219)
] ]
), ),
availableSize: CGSize(width: min(414.0, context.availableSize.width), height: 220.0), availableSize: CGSize(width: min(414.0, context.availableSize.width), height: 220.0),

View File

@ -371,10 +371,10 @@ final class StarsTransactionsScreenComponent: Component {
isVisible: true, isVisible: true,
hasIdleAnimations: true, hasIdleAnimations: true,
colors: [ colors: [
UIColor(rgb: 0xea8904), UIColor(rgb: 0xe57d02),
UIColor(rgb: 0xf09903), UIColor(rgb: 0xf09903),
UIColor(rgb: 0xfec209), UIColor(rgb: 0xf9b004),
UIColor(rgb: 0xfed31a) UIColor(rgb: 0xfdd219)
] ]
)), )),
environment: {}, environment: {},

View File

@ -216,7 +216,8 @@ private final class SheetContent: CombinedComponent {
let constrainedTitleWidth = context.availableSize.width - 16.0 * 2.0 let constrainedTitleWidth = context.availableSize.width - 16.0 * 2.0
contentSize.height += 130.0 contentSize.height += 126.0
let title = title.update( let title = title.update(
component: Text(text: strings.Stars_Transfer_Title, font: Font.bold(24.0), color: theme.list.itemPrimaryTextColor), component: Text(text: strings.Stars_Transfer_Title, font: Font.bold(24.0), color: theme.list.itemPrimaryTextColor),
availableSize: CGSize(width: constrainedTitleWidth, height: context.availableSize.height), availableSize: CGSize(width: constrainedTitleWidth, height: context.availableSize.height),
@ -258,13 +259,14 @@ private final class SheetContent: CombinedComponent {
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + text.size.height / 2.0)) .position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + text.size.height / 2.0))
) )
contentSize.height += text.size.height contentSize.height += text.size.height
contentSize.height += 24.0 contentSize.height += 28.0
if state.cachedChevronImage == nil || state.cachedChevronImage?.1 !== theme { if state.cachedChevronImage == nil || state.cachedChevronImage?.1 !== theme {
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Premium/Stars/Star"), color: UIColor(rgb: 0xf09903))!, theme) state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Premium/Stars/Star"), color: UIColor(rgb: 0xf09903))!, theme)
} }
let balanceAttributedString = parseMarkdownIntoAttributedString("\(strings.Stars_Transfer_Balance)\n # **\(state.balance ?? 0)**", attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString let balanceAttributedString = NSMutableAttributedString(string: strings.Stars_Transfer_Balance, font: Font.regular(14.0), textColor: textColor)
balanceAttributedString.append(NSMutableAttributedString(string: "\n # \(state.balance ?? 0)", font: Font.semibold(16.0), textColor: textColor))
if let range = balanceAttributedString.string.range(of: "#"), let chevronImage = state.cachedChevronImage?.0 { if let range = balanceAttributedString.string.range(of: "#"), let chevronImage = state.cachedChevronImage?.0 {
balanceAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: balanceAttributedString.string)) balanceAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: balanceAttributedString.string))
balanceAttributedString.addAttribute(.foregroundColor, value: UIColor(rgb: 0xf09903), range: NSRange(range, in: balanceAttributedString.string)) balanceAttributedString.addAttribute(.foregroundColor, value: UIColor(rgb: 0xf09903), range: NSRange(range, in: balanceAttributedString.string))
@ -274,13 +276,14 @@ private final class SheetContent: CombinedComponent {
component: MultilineTextComponent( component: MultilineTextComponent(
text: .plain(balanceAttributedString), text: .plain(balanceAttributedString),
horizontalAlignment: .left, horizontalAlignment: .left,
maximumNumberOfLines: 0 maximumNumberOfLines: 0,
lineSpacing: 0.25
), ),
availableSize: CGSize(width: constrainedTitleWidth, height: context.availableSize.height), availableSize: CGSize(width: constrainedTitleWidth, height: context.availableSize.height),
transition: .immediate transition: .immediate
) )
context.add(balanceText context.add(balanceText
.position(CGPoint(x: 16.0 + balanceText.size.width / 2.0, y: 29.0)) .position(CGPoint(x: 16.0 + balanceText.size.width / 2.0, y: 31.0))
) )
if state.cachedStarImage == nil || state.cachedStarImage?.1 !== theme { if state.cachedStarImage == nil || state.cachedStarImage?.1 !== theme {
@ -315,14 +318,17 @@ private final class SheetContent: CombinedComponent {
isEnabled: true, isEnabled: true,
displaysProgress: state.inProgress, displaysProgress: state.inProgress,
action: { [weak state, weak controller] in action: { [weak state, weak controller] in
state?.buy(requestTopUp: { [weak controller] _ in state?.buy(requestTopUp: { [weak controller] completion in
let purchaseController = accountContext.sharedContext.makeStarsPurchaseScreen( let purchaseController = accountContext.sharedContext.makeStarsPurchaseScreen(
context: accountContext, context: accountContext,
starsContext: starsContext, starsContext: starsContext,
options: state?.options ?? [], options: state?.options ?? [],
peerId: state?.peer?.id, peerId: state?.peer?.id,
requiredStars: invoice.totalAmount, requiredStars: invoice.totalAmount,
completion: { _ in } completion: { [weak starsContext] stars in
starsContext?.add(balance: stars)
completion()
}
) )
controller?.push(purchaseController) controller?.push(purchaseController)
}, completion: { [weak controller] in }, completion: { [weak controller] in