mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-05 05:51:42 +00:00
Gift improvements
This commit is contained in:
parent
bbf127b806
commit
a2ff1313ca
@ -12950,7 +12950,7 @@ Sorry for the inconvenience.";
|
|||||||
"SharedMedia.GiftCount_any" = "%@ gifts";
|
"SharedMedia.GiftCount_any" = "%@ gifts";
|
||||||
|
|
||||||
"Stars.Info.Title" = "What are Stars?";
|
"Stars.Info.Title" = "What are Stars?";
|
||||||
"Stars.Info.Description" = "Buy packages of Stars on Telegram that let you do following:";
|
"Stars.Info.Description" = "Telegram Stars allow users to:";
|
||||||
"Stars.Info.Gift.Title" = "Send Gifts to Friends";
|
"Stars.Info.Gift.Title" = "Send Gifts to Friends";
|
||||||
"Stars.Info.Gift.Text" = "Give your friends gifts that can be kept on their profiles or converted to Stars.";
|
"Stars.Info.Gift.Text" = "Give your friends gifts that can be kept on their profiles or converted to Stars.";
|
||||||
"Stars.Info.Miniapp.Title" = "Use Stars in Miniapps";
|
"Stars.Info.Miniapp.Title" = "Use Stars in Miniapps";
|
||||||
@ -12976,6 +12976,7 @@ Sorry for the inconvenience.";
|
|||||||
"Gift.View.HiddenName" = "Hidden Name";
|
"Gift.View.HiddenName" = "Hidden Name";
|
||||||
"Gift.View.Date" = "Date";
|
"Gift.View.Date" = "Date";
|
||||||
"Gift.View.Availability" = "Availability";
|
"Gift.View.Availability" = "Availability";
|
||||||
|
"Gift.View.Availability.Of" = "%1$@ of %2$@";
|
||||||
"Gift.View.Hide" = "Hide from My Page";
|
"Gift.View.Hide" = "Hide from My Page";
|
||||||
"Gift.View.Display" = "Display on My Page";
|
"Gift.View.Display" = "Display on My Page";
|
||||||
"Gift.View.Convert" = "Convert to %@";
|
"Gift.View.Convert" = "Convert to %@";
|
||||||
@ -12986,7 +12987,7 @@ Sorry for the inconvenience.";
|
|||||||
"Gift.Hidden.Title" = "Gift Removed from Profile";
|
"Gift.Hidden.Title" = "Gift Removed from Profile";
|
||||||
"Gift.Hidden.Text" = "The gift is no longer displayed in [your profile]().";
|
"Gift.Hidden.Text" = "The gift is no longer displayed in [your profile]().";
|
||||||
"Gift.Convert.Title" = "Convert Gift to Stars";
|
"Gift.Convert.Title" = "Convert Gift to Stars";
|
||||||
"Gift.Convert.Text" = "Do you want to convert this gift from **%1$@** to **%2$@**?\n\nThis action cannot be undone.";
|
"Gift.Convert.Text" = "Do you want to convert this gift from **%1$@** to **%2$@**?\n\nThis will permanently destroy the gift.";
|
||||||
"Gift.Convert.Stars_1" = "%@ Star";
|
"Gift.Convert.Stars_1" = "%@ Star";
|
||||||
"Gift.Convert.Stars_any" = "%@ Stars";
|
"Gift.Convert.Stars_any" = "%@ Stars";
|
||||||
"Gift.Convert.Convert" = "Convert";
|
"Gift.Convert.Convert" = "Convert";
|
||||||
@ -13032,7 +13033,8 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Gift.Send.Title" = "Send a Gift";
|
"Gift.Send.Title" = "Send a Gift";
|
||||||
"Gift.Send.Customize.Title" = "CUSTOMIZE YOUR GIFT";
|
"Gift.Send.Customize.Title" = "CUSTOMIZE YOUR GIFT";
|
||||||
"Gift.Send.Customize.MessagePlaceholder" = "Enter Message";
|
"Gift.Send.Customize.MessagePlaceholder" = "Enter Message (Optional)";
|
||||||
|
"Gift.Send.Customize.Info" = "Only %@ will see your message.";
|
||||||
"Gift.Send.HideMyName" = "Hide My Name";
|
"Gift.Send.HideMyName" = "Hide My Name";
|
||||||
"Gift.Send.HideMyName.Info" = "Hide my name and message from visitors to %1$@'s profile. %2$@ will still see your name and message.";
|
"Gift.Send.HideMyName.Info" = "Hide my name and message from visitors to %1$@'s profile. %2$@ will still see your name and message.";
|
||||||
"Gift.Send.Send" = "Send a Gift for";
|
"Gift.Send.Send" = "Send a Gift for";
|
||||||
@ -13051,3 +13053,14 @@ Sorry for the inconvenience.";
|
|||||||
"Report.Comment.Placeholder.Optional" = "Add Comment (Optional)";
|
"Report.Comment.Placeholder.Optional" = "Add Comment (Optional)";
|
||||||
"Report.Comment.Info" = "Please help us by telling what is wrong with the message you have selected.";
|
"Report.Comment.Info" = "Please help us by telling what is wrong with the message you have selected.";
|
||||||
"Report.Send" = "Send Report";
|
"Report.Send" = "Send Report";
|
||||||
|
|
||||||
|
"Notification.PremiumGift.MonthsTitle_1" = "%@ Month Premium";
|
||||||
|
"Notification.PremiumGift.MonthsTitle_any" = "%@ Months Premium";
|
||||||
|
|
||||||
|
"Notification.PremiumGift.YearsTitle_1" = "%@ Year Premium";
|
||||||
|
"Notification.PremiumGift.YearsTitle_any" = "%@ Years Premium";
|
||||||
|
|
||||||
|
"Notification.PremiumGift.SubscriptionDescription" = "Subscription for exclusive Telegram features.";
|
||||||
|
|
||||||
|
"Notification.StarsGift.Stars_1" = "%@ Star";
|
||||||
|
"Notification.StarsGift.Stars_any" = "%@ Stars";
|
||||||
|
|||||||
@ -143,6 +143,7 @@ public struct PremiumConfiguration {
|
|||||||
showPremiumGiftInTextField: false,
|
showPremiumGiftInTextField: false,
|
||||||
giveawayGiftsPurchaseAvailable: false,
|
giveawayGiftsPurchaseAvailable: false,
|
||||||
starsGiftsPurchaseAvailable: false,
|
starsGiftsPurchaseAvailable: false,
|
||||||
|
starGiftsPurchaseBlocked: true,
|
||||||
boostsPerGiftCount: 3,
|
boostsPerGiftCount: 3,
|
||||||
audioTransciptionTrialMaxDuration: 300,
|
audioTransciptionTrialMaxDuration: 300,
|
||||||
audioTransciptionTrialCount: 2,
|
audioTransciptionTrialCount: 2,
|
||||||
@ -170,6 +171,7 @@ public struct PremiumConfiguration {
|
|||||||
public let showPremiumGiftInTextField: Bool
|
public let showPremiumGiftInTextField: Bool
|
||||||
public let giveawayGiftsPurchaseAvailable: Bool
|
public let giveawayGiftsPurchaseAvailable: Bool
|
||||||
public let starsGiftsPurchaseAvailable: Bool
|
public let starsGiftsPurchaseAvailable: Bool
|
||||||
|
public let starGiftsPurchaseBlocked: Bool
|
||||||
public let boostsPerGiftCount: Int32
|
public let boostsPerGiftCount: Int32
|
||||||
public let audioTransciptionTrialMaxDuration: Int32
|
public let audioTransciptionTrialMaxDuration: Int32
|
||||||
public let audioTransciptionTrialCount: Int32
|
public let audioTransciptionTrialCount: Int32
|
||||||
@ -196,6 +198,7 @@ public struct PremiumConfiguration {
|
|||||||
showPremiumGiftInTextField: Bool,
|
showPremiumGiftInTextField: Bool,
|
||||||
giveawayGiftsPurchaseAvailable: Bool,
|
giveawayGiftsPurchaseAvailable: Bool,
|
||||||
starsGiftsPurchaseAvailable: Bool,
|
starsGiftsPurchaseAvailable: Bool,
|
||||||
|
starGiftsPurchaseBlocked: Bool,
|
||||||
boostsPerGiftCount: Int32,
|
boostsPerGiftCount: Int32,
|
||||||
audioTransciptionTrialMaxDuration: Int32,
|
audioTransciptionTrialMaxDuration: Int32,
|
||||||
audioTransciptionTrialCount: Int32,
|
audioTransciptionTrialCount: Int32,
|
||||||
@ -221,6 +224,7 @@ public struct PremiumConfiguration {
|
|||||||
self.showPremiumGiftInTextField = showPremiumGiftInTextField
|
self.showPremiumGiftInTextField = showPremiumGiftInTextField
|
||||||
self.giveawayGiftsPurchaseAvailable = giveawayGiftsPurchaseAvailable
|
self.giveawayGiftsPurchaseAvailable = giveawayGiftsPurchaseAvailable
|
||||||
self.starsGiftsPurchaseAvailable = starsGiftsPurchaseAvailable
|
self.starsGiftsPurchaseAvailable = starsGiftsPurchaseAvailable
|
||||||
|
self.starGiftsPurchaseBlocked = starGiftsPurchaseBlocked
|
||||||
self.boostsPerGiftCount = boostsPerGiftCount
|
self.boostsPerGiftCount = boostsPerGiftCount
|
||||||
self.audioTransciptionTrialMaxDuration = audioTransciptionTrialMaxDuration
|
self.audioTransciptionTrialMaxDuration = audioTransciptionTrialMaxDuration
|
||||||
self.audioTransciptionTrialCount = audioTransciptionTrialCount
|
self.audioTransciptionTrialCount = audioTransciptionTrialCount
|
||||||
@ -254,6 +258,7 @@ public struct PremiumConfiguration {
|
|||||||
showPremiumGiftInTextField: data["premium_gift_text_field_icon"] as? Bool ?? defaultValue.showPremiumGiftInTextField,
|
showPremiumGiftInTextField: data["premium_gift_text_field_icon"] as? Bool ?? defaultValue.showPremiumGiftInTextField,
|
||||||
giveawayGiftsPurchaseAvailable: data["giveaway_gifts_purchase_available"] as? Bool ?? defaultValue.giveawayGiftsPurchaseAvailable,
|
giveawayGiftsPurchaseAvailable: data["giveaway_gifts_purchase_available"] as? Bool ?? defaultValue.giveawayGiftsPurchaseAvailable,
|
||||||
starsGiftsPurchaseAvailable: data["stars_gifts_enabled"] as? Bool ?? defaultValue.starsGiftsPurchaseAvailable,
|
starsGiftsPurchaseAvailable: data["stars_gifts_enabled"] as? Bool ?? defaultValue.starsGiftsPurchaseAvailable,
|
||||||
|
starGiftsPurchaseBlocked: data["stargifts_blocked"] as? Bool ?? defaultValue.starGiftsPurchaseBlocked,
|
||||||
boostsPerGiftCount: get(data["boosts_per_sent_gift"]) ?? defaultValue.boostsPerGiftCount,
|
boostsPerGiftCount: get(data["boosts_per_sent_gift"]) ?? defaultValue.boostsPerGiftCount,
|
||||||
audioTransciptionTrialMaxDuration: get(data["transcribe_audio_trial_duration_max"]) ?? defaultValue.audioTransciptionTrialMaxDuration,
|
audioTransciptionTrialMaxDuration: get(data["transcribe_audio_trial_duration_max"]) ?? defaultValue.audioTransciptionTrialMaxDuration,
|
||||||
audioTransciptionTrialCount: get(data["transcribe_audio_trial_weekly_number"]) ?? defaultValue.audioTransciptionTrialCount,
|
audioTransciptionTrialCount: get(data["transcribe_audio_trial_weekly_number"]) ?? defaultValue.audioTransciptionTrialCount,
|
||||||
|
|||||||
@ -623,6 +623,8 @@ private final class PendingInAppPurchaseState: Codable {
|
|||||||
case untilDate
|
case untilDate
|
||||||
case stars
|
case stars
|
||||||
case users
|
case users
|
||||||
|
case text
|
||||||
|
case entities
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PurposeType: Int32 {
|
enum PurposeType: Int32 {
|
||||||
@ -641,7 +643,7 @@ private final class PendingInAppPurchaseState: Codable {
|
|||||||
case upgrade
|
case upgrade
|
||||||
case restore
|
case restore
|
||||||
case gift(peerId: EnginePeer.Id)
|
case gift(peerId: EnginePeer.Id)
|
||||||
case giftCode(peerIds: [EnginePeer.Id], boostPeer: EnginePeer.Id?)
|
case giftCode(peerIds: [EnginePeer.Id], boostPeer: EnginePeer.Id?, text: String?, entities: [MessageTextEntity]?)
|
||||||
case giveaway(boostPeer: EnginePeer.Id, additionalPeerIds: [EnginePeer.Id], countries: [String], onlyNewSubscribers: Bool, showWinners: Bool, prizeDescription: String?, randomId: Int64, untilDate: Int32)
|
case giveaway(boostPeer: EnginePeer.Id, additionalPeerIds: [EnginePeer.Id], countries: [String], onlyNewSubscribers: Bool, showWinners: Bool, prizeDescription: String?, randomId: Int64, untilDate: Int32)
|
||||||
case stars(count: Int64)
|
case stars(count: Int64)
|
||||||
case starsGift(peerId: EnginePeer.Id, count: Int64)
|
case starsGift(peerId: EnginePeer.Id, count: Int64)
|
||||||
@ -665,7 +667,9 @@ private final class PendingInAppPurchaseState: Codable {
|
|||||||
case .giftCode:
|
case .giftCode:
|
||||||
self = .giftCode(
|
self = .giftCode(
|
||||||
peerIds: try container.decode([Int64].self, forKey: .peers).map { EnginePeer.Id($0) },
|
peerIds: try container.decode([Int64].self, forKey: .peers).map { EnginePeer.Id($0) },
|
||||||
boostPeer: try container.decodeIfPresent(Int64.self, forKey: .boostPeer).flatMap({ EnginePeer.Id($0) })
|
boostPeer: try container.decodeIfPresent(Int64.self, forKey: .boostPeer).flatMap({ EnginePeer.Id($0) }),
|
||||||
|
text: try container.decodeIfPresent(String.self, forKey: .text),
|
||||||
|
entities: try container.decodeIfPresent([MessageTextEntity].self, forKey: .entities)
|
||||||
)
|
)
|
||||||
case .giveaway:
|
case .giveaway:
|
||||||
self = .giveaway(
|
self = .giveaway(
|
||||||
@ -718,10 +722,12 @@ private final class PendingInAppPurchaseState: Codable {
|
|||||||
case let .gift(peerId):
|
case let .gift(peerId):
|
||||||
try container.encode(PurposeType.gift.rawValue, forKey: .type)
|
try container.encode(PurposeType.gift.rawValue, forKey: .type)
|
||||||
try container.encode(peerId.toInt64(), forKey: .peer)
|
try container.encode(peerId.toInt64(), forKey: .peer)
|
||||||
case let .giftCode(peerIds, boostPeer):
|
case let .giftCode(peerIds, boostPeer, text, entities):
|
||||||
try container.encode(PurposeType.giftCode.rawValue, forKey: .type)
|
try container.encode(PurposeType.giftCode.rawValue, forKey: .type)
|
||||||
try container.encode(peerIds.map { $0.toInt64() }, forKey: .peers)
|
try container.encode(peerIds.map { $0.toInt64() }, forKey: .peers)
|
||||||
try container.encodeIfPresent(boostPeer?.toInt64(), forKey: .boostPeer)
|
try container.encodeIfPresent(boostPeer?.toInt64(), forKey: .boostPeer)
|
||||||
|
try container.encodeIfPresent(text, forKey: .text)
|
||||||
|
try container.encodeIfPresent(entities, forKey: .entities)
|
||||||
case let .giveaway(boostPeer, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate):
|
case let .giveaway(boostPeer, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate):
|
||||||
try container.encode(PurposeType.giveaway.rawValue, forKey: .type)
|
try container.encode(PurposeType.giveaway.rawValue, forKey: .type)
|
||||||
try container.encode(boostPeer.toInt64(), forKey: .boostPeer)
|
try container.encode(boostPeer.toInt64(), forKey: .boostPeer)
|
||||||
@ -764,8 +770,8 @@ private final class PendingInAppPurchaseState: Codable {
|
|||||||
self = .restore
|
self = .restore
|
||||||
case let .gift(peerId, _, _):
|
case let .gift(peerId, _, _):
|
||||||
self = .gift(peerId: peerId)
|
self = .gift(peerId: peerId)
|
||||||
case let .giftCode(peerIds, boostPeer, _, _):
|
case let .giftCode(peerIds, boostPeer, _, _, text, entities):
|
||||||
self = .giftCode(peerIds: peerIds, boostPeer: boostPeer)
|
self = .giftCode(peerIds: peerIds, boostPeer: boostPeer, text: text, entities: entities)
|
||||||
case let .giveaway(boostPeer, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate, _, _):
|
case let .giveaway(boostPeer, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate, _, _):
|
||||||
self = .giveaway(boostPeer: boostPeer, additionalPeerIds: additionalPeerIds, countries: countries, onlyNewSubscribers: onlyNewSubscribers, showWinners: showWinners, prizeDescription: prizeDescription, randomId: randomId, untilDate: untilDate)
|
self = .giveaway(boostPeer: boostPeer, additionalPeerIds: additionalPeerIds, countries: countries, onlyNewSubscribers: onlyNewSubscribers, showWinners: showWinners, prizeDescription: prizeDescription, randomId: randomId, untilDate: untilDate)
|
||||||
case let .stars(count, _, _):
|
case let .stars(count, _, _):
|
||||||
@ -788,8 +794,8 @@ private final class PendingInAppPurchaseState: Codable {
|
|||||||
return .restore
|
return .restore
|
||||||
case let .gift(peerId):
|
case let .gift(peerId):
|
||||||
return .gift(peerId: peerId, currency: currency, amount: amount)
|
return .gift(peerId: peerId, currency: currency, amount: amount)
|
||||||
case let .giftCode(peerIds, boostPeer):
|
case let .giftCode(peerIds, boostPeer, text, entities):
|
||||||
return .giftCode(peerIds: peerIds, boostPeer: boostPeer, currency: currency, amount: amount)
|
return .giftCode(peerIds: peerIds, boostPeer: boostPeer, currency: currency, amount: amount, text: text, entities: entities)
|
||||||
case let .giveaway(boostPeer, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate):
|
case let .giveaway(boostPeer, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate):
|
||||||
return .giveaway(boostPeer: boostPeer, additionalPeerIds: additionalPeerIds, countries: countries, onlyNewSubscribers: onlyNewSubscribers, showWinners: showWinners, prizeDescription: prizeDescription, randomId: randomId, untilDate: untilDate, currency: currency, amount: amount)
|
return .giveaway(boostPeer: boostPeer, additionalPeerIds: additionalPeerIds, countries: countries, onlyNewSubscribers: onlyNewSubscribers, showWinners: showWinners, prizeDescription: prizeDescription, randomId: randomId, untilDate: untilDate, currency: currency, amount: amount)
|
||||||
case let .stars(count):
|
case let .stars(count):
|
||||||
|
|||||||
@ -1356,7 +1356,7 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let (currency, amount) = selectedProduct.storeProduct.priceCurrencyAndAmount
|
let (currency, amount) = selectedProduct.storeProduct.priceCurrencyAndAmount
|
||||||
purpose = .giftCode(peerIds: state.peers, boostPeer: peerId, currency: currency, amount: amount)
|
purpose = .giftCode(peerIds: state.peers, boostPeer: peerId, currency: currency, amount: amount, text: nil, entities: nil)
|
||||||
quantity = Int32(state.peers.count)
|
quantity = Int32(state.peers.count)
|
||||||
storeProduct = selectedProduct.storeProduct
|
storeProduct = selectedProduct.storeProduct
|
||||||
case .starsGiveaway:
|
case .starsGiveaway:
|
||||||
|
|||||||
@ -910,7 +910,7 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
|
|||||||
if self.source == .profile || self.source == .attachMenu, let peerId = self.peerIds.first {
|
if self.source == .profile || self.source == .attachMenu, let peerId = self.peerIds.first {
|
||||||
purpose = .gift(peerId: peerId, currency: currency, amount: amount)
|
purpose = .gift(peerId: peerId, currency: currency, amount: amount)
|
||||||
} else {
|
} else {
|
||||||
purpose = .giftCode(peerIds: self.peerIds, boostPeer: nil, currency: currency, amount: amount)
|
purpose = .giftCode(peerIds: self.peerIds, boostPeer: nil, currency: currency, amount: amount, text: nil, entities: nil)
|
||||||
quantity = Int32(self.peerIds.count)
|
quantity = Int32(self.peerIds.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -467,7 +467,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) }
|
dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) }
|
||||||
dict[1251549527] = { return Api.InputStickeredMedia.parse_inputStickeredMediaPhoto($0) }
|
dict[1251549527] = { return Api.InputStickeredMedia.parse_inputStickeredMediaPhoto($0) }
|
||||||
dict[1634697192] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentGiftPremium($0) }
|
dict[1634697192] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentGiftPremium($0) }
|
||||||
dict[-1551868097] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentPremiumGiftCode($0) }
|
dict[-75955309] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentPremiumGiftCode($0) }
|
||||||
dict[369444042] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentPremiumGiveaway($0) }
|
dict[369444042] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentPremiumGiveaway($0) }
|
||||||
dict[-1502273946] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentPremiumSubscription($0) }
|
dict[-1502273946] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentPremiumSubscription($0) }
|
||||||
dict[494149367] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentStarsGift($0) }
|
dict[494149367] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentStarsGift($0) }
|
||||||
@ -551,8 +551,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1230047312] = { return Api.MessageAction.parse_messageActionEmpty($0) }
|
dict[-1230047312] = { return Api.MessageAction.parse_messageActionEmpty($0) }
|
||||||
dict[-1834538890] = { return Api.MessageAction.parse_messageActionGameScore($0) }
|
dict[-1834538890] = { return Api.MessageAction.parse_messageActionGameScore($0) }
|
||||||
dict[-1730095465] = { return Api.MessageAction.parse_messageActionGeoProximityReached($0) }
|
dict[-1730095465] = { return Api.MessageAction.parse_messageActionGeoProximityReached($0) }
|
||||||
dict[1737240073] = { return Api.MessageAction.parse_messageActionGiftCode($0) }
|
dict[1456486804] = { return Api.MessageAction.parse_messageActionGiftCode($0) }
|
||||||
dict[-935499028] = { return Api.MessageAction.parse_messageActionGiftPremium($0) }
|
dict[1818391802] = { return Api.MessageAction.parse_messageActionGiftPremium($0) }
|
||||||
dict[1171632161] = { return Api.MessageAction.parse_messageActionGiftStars($0) }
|
dict[1171632161] = { return Api.MessageAction.parse_messageActionGiftStars($0) }
|
||||||
dict[-1475391004] = { return Api.MessageAction.parse_messageActionGiveawayLaunch($0) }
|
dict[-1475391004] = { return Api.MessageAction.parse_messageActionGiveawayLaunch($0) }
|
||||||
dict[-2015170219] = { return Api.MessageAction.parse_messageActionGiveawayResults($0) }
|
dict[-2015170219] = { return Api.MessageAction.parse_messageActionGiveawayResults($0) }
|
||||||
|
|||||||
@ -711,7 +711,7 @@ public extension Api {
|
|||||||
public extension Api {
|
public extension Api {
|
||||||
indirect enum InputStorePaymentPurpose: TypeConstructorDescription {
|
indirect enum InputStorePaymentPurpose: TypeConstructorDescription {
|
||||||
case inputStorePaymentGiftPremium(userId: Api.InputUser, currency: String, amount: Int64)
|
case inputStorePaymentGiftPremium(userId: Api.InputUser, currency: String, amount: Int64)
|
||||||
case inputStorePaymentPremiumGiftCode(flags: Int32, users: [Api.InputUser], boostPeer: Api.InputPeer?, currency: String, amount: Int64)
|
case inputStorePaymentPremiumGiftCode(flags: Int32, users: [Api.InputUser], boostPeer: Api.InputPeer?, currency: String, amount: Int64, message: Api.TextWithEntities?)
|
||||||
case inputStorePaymentPremiumGiveaway(flags: Int32, boostPeer: Api.InputPeer, additionalPeers: [Api.InputPeer]?, countriesIso2: [String]?, prizeDescription: String?, randomId: Int64, untilDate: Int32, currency: String, amount: Int64)
|
case inputStorePaymentPremiumGiveaway(flags: Int32, boostPeer: Api.InputPeer, additionalPeers: [Api.InputPeer]?, countriesIso2: [String]?, prizeDescription: String?, randomId: Int64, untilDate: Int32, currency: String, amount: Int64)
|
||||||
case inputStorePaymentPremiumSubscription(flags: Int32)
|
case inputStorePaymentPremiumSubscription(flags: Int32)
|
||||||
case inputStorePaymentStarsGift(userId: Api.InputUser, stars: Int64, currency: String, amount: Int64)
|
case inputStorePaymentStarsGift(userId: Api.InputUser, stars: Int64, currency: String, amount: Int64)
|
||||||
@ -728,9 +728,9 @@ public extension Api {
|
|||||||
serializeString(currency, buffer: buffer, boxed: false)
|
serializeString(currency, buffer: buffer, boxed: false)
|
||||||
serializeInt64(amount, buffer: buffer, boxed: false)
|
serializeInt64(amount, buffer: buffer, boxed: false)
|
||||||
break
|
break
|
||||||
case .inputStorePaymentPremiumGiftCode(let flags, let users, let boostPeer, let currency, let amount):
|
case .inputStorePaymentPremiumGiftCode(let flags, let users, let boostPeer, let currency, let amount, let message):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-1551868097)
|
buffer.appendInt32(-75955309)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
buffer.appendInt32(481674261)
|
buffer.appendInt32(481674261)
|
||||||
@ -741,6 +741,7 @@ public extension Api {
|
|||||||
if Int(flags) & Int(1 << 0) != 0 {boostPeer!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 0) != 0 {boostPeer!.serialize(buffer, true)}
|
||||||
serializeString(currency, buffer: buffer, boxed: false)
|
serializeString(currency, buffer: buffer, boxed: false)
|
||||||
serializeInt64(amount, buffer: buffer, boxed: false)
|
serializeInt64(amount, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 1) != 0 {message!.serialize(buffer, true)}
|
||||||
break
|
break
|
||||||
case .inputStorePaymentPremiumGiveaway(let flags, let boostPeer, let additionalPeers, let countriesIso2, let prizeDescription, let randomId, let untilDate, let currency, let amount):
|
case .inputStorePaymentPremiumGiveaway(let flags, let boostPeer, let additionalPeers, let countriesIso2, let prizeDescription, let randomId, let untilDate, let currency, let amount):
|
||||||
if boxed {
|
if boxed {
|
||||||
@ -818,8 +819,8 @@ public extension Api {
|
|||||||
switch self {
|
switch self {
|
||||||
case .inputStorePaymentGiftPremium(let userId, let currency, let amount):
|
case .inputStorePaymentGiftPremium(let userId, let currency, let amount):
|
||||||
return ("inputStorePaymentGiftPremium", [("userId", userId as Any), ("currency", currency as Any), ("amount", amount as Any)])
|
return ("inputStorePaymentGiftPremium", [("userId", userId as Any), ("currency", currency as Any), ("amount", amount as Any)])
|
||||||
case .inputStorePaymentPremiumGiftCode(let flags, let users, let boostPeer, let currency, let amount):
|
case .inputStorePaymentPremiumGiftCode(let flags, let users, let boostPeer, let currency, let amount, let message):
|
||||||
return ("inputStorePaymentPremiumGiftCode", [("flags", flags as Any), ("users", users as Any), ("boostPeer", boostPeer as Any), ("currency", currency as Any), ("amount", amount as Any)])
|
return ("inputStorePaymentPremiumGiftCode", [("flags", flags as Any), ("users", users as Any), ("boostPeer", boostPeer as Any), ("currency", currency as Any), ("amount", amount as Any), ("message", message as Any)])
|
||||||
case .inputStorePaymentPremiumGiveaway(let flags, let boostPeer, let additionalPeers, let countriesIso2, let prizeDescription, let randomId, let untilDate, let currency, let amount):
|
case .inputStorePaymentPremiumGiveaway(let flags, let boostPeer, let additionalPeers, let countriesIso2, let prizeDescription, let randomId, let untilDate, let currency, let amount):
|
||||||
return ("inputStorePaymentPremiumGiveaway", [("flags", flags as Any), ("boostPeer", boostPeer as Any), ("additionalPeers", additionalPeers as Any), ("countriesIso2", countriesIso2 as Any), ("prizeDescription", prizeDescription as Any), ("randomId", randomId as Any), ("untilDate", untilDate as Any), ("currency", currency as Any), ("amount", amount as Any)])
|
return ("inputStorePaymentPremiumGiveaway", [("flags", flags as Any), ("boostPeer", boostPeer as Any), ("additionalPeers", additionalPeers as Any), ("countriesIso2", countriesIso2 as Any), ("prizeDescription", prizeDescription as Any), ("randomId", randomId as Any), ("untilDate", untilDate as Any), ("currency", currency as Any), ("amount", amount as Any)])
|
||||||
case .inputStorePaymentPremiumSubscription(let flags):
|
case .inputStorePaymentPremiumSubscription(let flags):
|
||||||
@ -867,13 +868,18 @@ public extension Api {
|
|||||||
_4 = parseString(reader)
|
_4 = parseString(reader)
|
||||||
var _5: Int64?
|
var _5: Int64?
|
||||||
_5 = reader.readInt64()
|
_5 = reader.readInt64()
|
||||||
|
var _6: Api.TextWithEntities?
|
||||||
|
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_6 = Api.parse(reader, signature: signature) as? Api.TextWithEntities
|
||||||
|
} }
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
|
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
|
||||||
let _c4 = _4 != nil
|
let _c4 = _4 != nil
|
||||||
let _c5 = _5 != nil
|
let _c5 = _5 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil
|
||||||
return Api.InputStorePaymentPurpose.inputStorePaymentPremiumGiftCode(flags: _1!, users: _2!, boostPeer: _3, currency: _4!, amount: _5!)
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||||
|
return Api.InputStorePaymentPurpose.inputStorePaymentPremiumGiftCode(flags: _1!, users: _2!, boostPeer: _3, currency: _4!, amount: _5!, message: _6)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -986,8 +986,8 @@ public extension Api {
|
|||||||
case messageActionEmpty
|
case messageActionEmpty
|
||||||
case messageActionGameScore(gameId: Int64, score: Int32)
|
case messageActionGameScore(gameId: Int64, score: Int32)
|
||||||
case messageActionGeoProximityReached(fromId: Api.Peer, toId: Api.Peer, distance: Int32)
|
case messageActionGeoProximityReached(fromId: Api.Peer, toId: Api.Peer, distance: Int32)
|
||||||
case messageActionGiftCode(flags: Int32, boostPeer: Api.Peer?, months: Int32, slug: String, currency: String?, amount: Int64?, cryptoCurrency: String?, cryptoAmount: Int64?)
|
case messageActionGiftCode(flags: Int32, boostPeer: Api.Peer?, months: Int32, slug: String, currency: String?, amount: Int64?, cryptoCurrency: String?, cryptoAmount: Int64?, message: Api.TextWithEntities?)
|
||||||
case messageActionGiftPremium(flags: Int32, currency: String, amount: Int64, months: Int32, cryptoCurrency: String?, cryptoAmount: Int64?)
|
case messageActionGiftPremium(flags: Int32, currency: String, amount: Int64, months: Int32, cryptoCurrency: String?, cryptoAmount: Int64?, message: Api.TextWithEntities?)
|
||||||
case messageActionGiftStars(flags: Int32, currency: String, amount: Int64, stars: Int64, cryptoCurrency: String?, cryptoAmount: Int64?, transactionId: String?)
|
case messageActionGiftStars(flags: Int32, currency: String, amount: Int64, stars: Int64, cryptoCurrency: String?, cryptoAmount: Int64?, transactionId: String?)
|
||||||
case messageActionGiveawayLaunch(flags: Int32, stars: Int64?)
|
case messageActionGiveawayLaunch(flags: Int32, stars: Int64?)
|
||||||
case messageActionGiveawayResults(flags: Int32, winnersCount: Int32, unclaimedCount: Int32)
|
case messageActionGiveawayResults(flags: Int32, winnersCount: Int32, unclaimedCount: Int32)
|
||||||
@ -1141,9 +1141,9 @@ public extension Api {
|
|||||||
toId.serialize(buffer, true)
|
toId.serialize(buffer, true)
|
||||||
serializeInt32(distance, buffer: buffer, boxed: false)
|
serializeInt32(distance, buffer: buffer, boxed: false)
|
||||||
break
|
break
|
||||||
case .messageActionGiftCode(let flags, let boostPeer, let months, let slug, let currency, let amount, let cryptoCurrency, let cryptoAmount):
|
case .messageActionGiftCode(let flags, let boostPeer, let months, let slug, let currency, let amount, let cryptoCurrency, let cryptoAmount, let message):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(1737240073)
|
buffer.appendInt32(1456486804)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
if Int(flags) & Int(1 << 1) != 0 {boostPeer!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 1) != 0 {boostPeer!.serialize(buffer, true)}
|
||||||
@ -1153,10 +1153,11 @@ public extension Api {
|
|||||||
if Int(flags) & Int(1 << 2) != 0 {serializeInt64(amount!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 2) != 0 {serializeInt64(amount!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags) & Int(1 << 3) != 0 {serializeString(cryptoCurrency!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 3) != 0 {serializeString(cryptoCurrency!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags) & Int(1 << 3) != 0 {serializeInt64(cryptoAmount!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 3) != 0 {serializeInt64(cryptoAmount!, buffer: buffer, boxed: false)}
|
||||||
|
if Int(flags) & Int(1 << 4) != 0 {message!.serialize(buffer, true)}
|
||||||
break
|
break
|
||||||
case .messageActionGiftPremium(let flags, let currency, let amount, let months, let cryptoCurrency, let cryptoAmount):
|
case .messageActionGiftPremium(let flags, let currency, let amount, let months, let cryptoCurrency, let cryptoAmount, let message):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-935499028)
|
buffer.appendInt32(1818391802)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeString(currency, buffer: buffer, boxed: false)
|
serializeString(currency, buffer: buffer, boxed: false)
|
||||||
@ -1164,6 +1165,7 @@ public extension Api {
|
|||||||
serializeInt32(months, buffer: buffer, boxed: false)
|
serializeInt32(months, buffer: buffer, boxed: false)
|
||||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(cryptoCurrency!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 0) != 0 {serializeString(cryptoCurrency!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(cryptoAmount!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(cryptoAmount!, buffer: buffer, boxed: false)}
|
||||||
|
if Int(flags) & Int(1 << 1) != 0 {message!.serialize(buffer, true)}
|
||||||
break
|
break
|
||||||
case .messageActionGiftStars(let flags, let currency, let amount, let stars, let cryptoCurrency, let cryptoAmount, let transactionId):
|
case .messageActionGiftStars(let flags, let currency, let amount, let stars, let cryptoCurrency, let cryptoAmount, let transactionId):
|
||||||
if boxed {
|
if boxed {
|
||||||
@ -1439,10 +1441,10 @@ public extension Api {
|
|||||||
return ("messageActionGameScore", [("gameId", gameId as Any), ("score", score as Any)])
|
return ("messageActionGameScore", [("gameId", gameId as Any), ("score", score as Any)])
|
||||||
case .messageActionGeoProximityReached(let fromId, let toId, let distance):
|
case .messageActionGeoProximityReached(let fromId, let toId, let distance):
|
||||||
return ("messageActionGeoProximityReached", [("fromId", fromId as Any), ("toId", toId as Any), ("distance", distance as Any)])
|
return ("messageActionGeoProximityReached", [("fromId", fromId as Any), ("toId", toId as Any), ("distance", distance as Any)])
|
||||||
case .messageActionGiftCode(let flags, let boostPeer, let months, let slug, let currency, let amount, let cryptoCurrency, let cryptoAmount):
|
case .messageActionGiftCode(let flags, let boostPeer, let months, let slug, let currency, let amount, let cryptoCurrency, let cryptoAmount, let message):
|
||||||
return ("messageActionGiftCode", [("flags", flags as Any), ("boostPeer", boostPeer as Any), ("months", months as Any), ("slug", slug as Any), ("currency", currency as Any), ("amount", amount as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any)])
|
return ("messageActionGiftCode", [("flags", flags as Any), ("boostPeer", boostPeer as Any), ("months", months as Any), ("slug", slug as Any), ("currency", currency as Any), ("amount", amount as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any), ("message", message as Any)])
|
||||||
case .messageActionGiftPremium(let flags, let currency, let amount, let months, let cryptoCurrency, let cryptoAmount):
|
case .messageActionGiftPremium(let flags, let currency, let amount, let months, let cryptoCurrency, let cryptoAmount, let message):
|
||||||
return ("messageActionGiftPremium", [("flags", flags as Any), ("currency", currency as Any), ("amount", amount as Any), ("months", months as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any)])
|
return ("messageActionGiftPremium", [("flags", flags as Any), ("currency", currency as Any), ("amount", amount as Any), ("months", months as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any), ("message", message as Any)])
|
||||||
case .messageActionGiftStars(let flags, let currency, let amount, let stars, let cryptoCurrency, let cryptoAmount, let transactionId):
|
case .messageActionGiftStars(let flags, let currency, let amount, let stars, let cryptoCurrency, let cryptoAmount, let transactionId):
|
||||||
return ("messageActionGiftStars", [("flags", flags as Any), ("currency", currency as Any), ("amount", amount as Any), ("stars", stars as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any), ("transactionId", transactionId as Any)])
|
return ("messageActionGiftStars", [("flags", flags as Any), ("currency", currency as Any), ("amount", amount as Any), ("stars", stars as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any), ("transactionId", transactionId as Any)])
|
||||||
case .messageActionGiveawayLaunch(let flags, let stars):
|
case .messageActionGiveawayLaunch(let flags, let stars):
|
||||||
@ -1718,6 +1720,10 @@ public extension Api {
|
|||||||
if Int(_1!) & Int(1 << 3) != 0 {_7 = parseString(reader) }
|
if Int(_1!) & Int(1 << 3) != 0 {_7 = parseString(reader) }
|
||||||
var _8: Int64?
|
var _8: Int64?
|
||||||
if Int(_1!) & Int(1 << 3) != 0 {_8 = reader.readInt64() }
|
if Int(_1!) & Int(1 << 3) != 0 {_8 = reader.readInt64() }
|
||||||
|
var _9: Api.TextWithEntities?
|
||||||
|
if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_9 = Api.parse(reader, signature: signature) as? Api.TextWithEntities
|
||||||
|
} }
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = (Int(_1!) & Int(1 << 1) == 0) || _2 != nil
|
let _c2 = (Int(_1!) & Int(1 << 1) == 0) || _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
@ -1726,8 +1732,9 @@ public extension Api {
|
|||||||
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
|
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
|
||||||
let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil
|
let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil
|
||||||
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
|
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
|
let _c9 = (Int(_1!) & Int(1 << 4) == 0) || _9 != nil
|
||||||
return Api.MessageAction.messageActionGiftCode(flags: _1!, boostPeer: _2, months: _3!, slug: _4!, currency: _5, amount: _6, cryptoCurrency: _7, cryptoAmount: _8)
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
|
||||||
|
return Api.MessageAction.messageActionGiftCode(flags: _1!, boostPeer: _2, months: _3!, slug: _4!, currency: _5, amount: _6, cryptoCurrency: _7, cryptoAmount: _8, message: _9)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
@ -1746,14 +1753,19 @@ public extension Api {
|
|||||||
if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) }
|
if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) }
|
||||||
var _6: Int64?
|
var _6: Int64?
|
||||||
if Int(_1!) & Int(1 << 0) != 0 {_6 = reader.readInt64() }
|
if Int(_1!) & Int(1 << 0) != 0 {_6 = reader.readInt64() }
|
||||||
|
var _7: Api.TextWithEntities?
|
||||||
|
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_7 = Api.parse(reader, signature: signature) as? Api.TextWithEntities
|
||||||
|
} }
|
||||||
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
|
||||||
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
|
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
|
||||||
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
|
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil
|
||||||
return Api.MessageAction.messageActionGiftPremium(flags: _1!, currency: _2!, amount: _3!, months: _4!, cryptoCurrency: _5, cryptoAmount: _6)
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
|
||||||
|
return Api.MessageAction.messageActionGiftPremium(flags: _1!, currency: _2!, amount: _3!, months: _4!, cryptoCurrency: _5, cryptoAmount: _6, message: _7)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -254,7 +254,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
|
|||||||
}
|
}
|
||||||
case let .messageActionRequestedPeer(_, peers):
|
case let .messageActionRequestedPeer(_, peers):
|
||||||
result.append(contentsOf: peers.map(\.peerId))
|
result.append(contentsOf: peers.map(\.peerId))
|
||||||
case let .messageActionGiftCode(_, boostPeer, _, _, _, _, _, _):
|
case let .messageActionGiftCode(_, boostPeer, _, _, _, _, _, _, _):
|
||||||
if let boostPeer = boostPeer {
|
if let boostPeer = boostPeer {
|
||||||
result.append(boostPeer.peerId)
|
result.append(boostPeer.peerId)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,8 +100,18 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
|||||||
return TelegramMediaAction(action: .joinedByRequest)
|
return TelegramMediaAction(action: .joinedByRequest)
|
||||||
case let .messageActionWebViewDataSentMe(text, _), let .messageActionWebViewDataSent(text):
|
case let .messageActionWebViewDataSentMe(text, _), let .messageActionWebViewDataSent(text):
|
||||||
return TelegramMediaAction(action: .webViewData(text))
|
return TelegramMediaAction(action: .webViewData(text))
|
||||||
case let .messageActionGiftPremium(_, currency, amount, months, cryptoCurrency, cryptoAmount):
|
case let .messageActionGiftPremium(_, currency, amount, months, cryptoCurrency, cryptoAmount, message):
|
||||||
return TelegramMediaAction(action: .giftPremium(currency: currency, amount: amount, months: months, cryptoCurrency: cryptoCurrency, cryptoAmount: cryptoAmount))
|
let text: String?
|
||||||
|
let entities: [MessageTextEntity]?
|
||||||
|
switch message {
|
||||||
|
case let .textWithEntities(textValue, entitiesValue):
|
||||||
|
text = textValue
|
||||||
|
entities = messageTextEntitiesFromApiEntities(entitiesValue)
|
||||||
|
default:
|
||||||
|
text = nil
|
||||||
|
entities = nil
|
||||||
|
}
|
||||||
|
return TelegramMediaAction(action: .giftPremium(currency: currency, amount: amount, months: months, cryptoCurrency: cryptoCurrency, cryptoAmount: cryptoAmount, text: text, entities: entities))
|
||||||
case let .messageActionGiftStars(_, currency, amount, stars, cryptoCurrency, cryptoAmount, transactionId):
|
case let .messageActionGiftStars(_, currency, amount, stars, cryptoCurrency, cryptoAmount, transactionId):
|
||||||
return TelegramMediaAction(action: .giftStars(currency: currency, amount: amount, count: stars, cryptoCurrency: cryptoCurrency, cryptoAmount: cryptoAmount, transactionId: transactionId))
|
return TelegramMediaAction(action: .giftStars(currency: currency, amount: amount, count: stars, cryptoCurrency: cryptoCurrency, cryptoAmount: cryptoAmount, transactionId: transactionId))
|
||||||
case let .messageActionTopicCreate(_, title, iconColor, iconEmojiId):
|
case let .messageActionTopicCreate(_, title, iconColor, iconEmojiId):
|
||||||
@ -133,8 +143,18 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
|||||||
} else {
|
} else {
|
||||||
return TelegramMediaAction(action: .setChatWallpaper(wallpaper: TelegramWallpaper(apiWallpaper: wallpaper), forBoth: (flags & (1 << 1)) != 0))
|
return TelegramMediaAction(action: .setChatWallpaper(wallpaper: TelegramWallpaper(apiWallpaper: wallpaper), forBoth: (flags & (1 << 1)) != 0))
|
||||||
}
|
}
|
||||||
case let .messageActionGiftCode(flags, boostPeer, months, slug, currency, amount, cryptoCurrency, cryptoAmount):
|
case let .messageActionGiftCode(flags, boostPeer, months, slug, currency, amount, cryptoCurrency, cryptoAmount, message):
|
||||||
return TelegramMediaAction(action: .giftCode(slug: slug, fromGiveaway: (flags & (1 << 0)) != 0, isUnclaimed: (flags & (1 << 2)) != 0, boostPeerId: boostPeer?.peerId, months: months, currency: currency, amount: amount, cryptoCurrency: cryptoCurrency, cryptoAmount: cryptoAmount))
|
let text: String?
|
||||||
|
let entities: [MessageTextEntity]?
|
||||||
|
switch message {
|
||||||
|
case let .textWithEntities(textValue, entitiesValue):
|
||||||
|
text = textValue
|
||||||
|
entities = messageTextEntitiesFromApiEntities(entitiesValue)
|
||||||
|
default:
|
||||||
|
text = nil
|
||||||
|
entities = nil
|
||||||
|
}
|
||||||
|
return TelegramMediaAction(action: .giftCode(slug: slug, fromGiveaway: (flags & (1 << 0)) != 0, isUnclaimed: (flags & (1 << 2)) != 0, boostPeerId: boostPeer?.peerId, months: months, currency: currency, amount: amount, cryptoCurrency: cryptoCurrency, cryptoAmount: cryptoAmount, text: text, entities: entities))
|
||||||
case let .messageActionGiveawayLaunch(_, stars):
|
case let .messageActionGiveawayLaunch(_, stars):
|
||||||
return TelegramMediaAction(action: .giveawayLaunched(stars: stars))
|
return TelegramMediaAction(action: .giveawayLaunched(stars: stars))
|
||||||
case let .messageActionGiveawayResults(flags, winners, unclaimed):
|
case let .messageActionGiveawayResults(flags, winners, unclaimed):
|
||||||
|
|||||||
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
|||||||
|
|
||||||
public class Serialization: NSObject, MTSerialization {
|
public class Serialization: NSObject, MTSerialization {
|
||||||
public func currentLayer() -> UInt {
|
public func currentLayer() -> UInt {
|
||||||
return 189
|
return 190
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseMessage(_ data: Data!) -> Any! {
|
public func parseMessage(_ data: Data!) -> Any! {
|
||||||
|
|||||||
@ -114,7 +114,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
|||||||
case setChatTheme(emoji: String)
|
case setChatTheme(emoji: String)
|
||||||
case joinedByRequest
|
case joinedByRequest
|
||||||
case webViewData(String)
|
case webViewData(String)
|
||||||
case giftPremium(currency: String, amount: Int64, months: Int32, cryptoCurrency: String?, cryptoAmount: Int64?)
|
case giftPremium(currency: String, amount: Int64, months: Int32, cryptoCurrency: String?, cryptoAmount: Int64?, text: String?, entities: [MessageTextEntity]?)
|
||||||
case topicCreated(title: String, iconColor: Int32, iconFileId: Int64?)
|
case topicCreated(title: String, iconColor: Int32, iconFileId: Int64?)
|
||||||
case topicEdited(components: [ForumTopicEditComponent])
|
case topicEdited(components: [ForumTopicEditComponent])
|
||||||
case suggestedProfilePhoto(image: TelegramMediaImage?)
|
case suggestedProfilePhoto(image: TelegramMediaImage?)
|
||||||
@ -122,7 +122,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
|||||||
case requestedPeer(buttonId: Int32, peerIds: [PeerId])
|
case requestedPeer(buttonId: Int32, peerIds: [PeerId])
|
||||||
case setChatWallpaper(wallpaper: TelegramWallpaper, forBoth: Bool)
|
case setChatWallpaper(wallpaper: TelegramWallpaper, forBoth: Bool)
|
||||||
case setSameChatWallpaper(wallpaper: TelegramWallpaper)
|
case setSameChatWallpaper(wallpaper: TelegramWallpaper)
|
||||||
case giftCode(slug: String, fromGiveaway: Bool, isUnclaimed: Bool, boostPeerId: PeerId?, months: Int32, currency: String?, amount: Int64?, cryptoCurrency: String?, cryptoAmount: Int64?)
|
case giftCode(slug: String, fromGiveaway: Bool, isUnclaimed: Bool, boostPeerId: PeerId?, months: Int32, currency: String?, amount: Int64?, cryptoCurrency: String?, cryptoAmount: Int64?, text: String?, entities: [MessageTextEntity]?)
|
||||||
case giveawayLaunched(stars: Int64?)
|
case giveawayLaunched(stars: Int64?)
|
||||||
case joinedChannel
|
case joinedChannel
|
||||||
case giveawayResults(winners: Int32, unclaimed: Int32, stars: Bool)
|
case giveawayResults(winners: Int32, unclaimed: Int32, stars: Bool)
|
||||||
@ -200,7 +200,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
|||||||
case 26:
|
case 26:
|
||||||
self = .webViewData(decoder.decodeStringForKey("t", orElse: ""))
|
self = .webViewData(decoder.decodeStringForKey("t", orElse: ""))
|
||||||
case 27:
|
case 27:
|
||||||
self = .giftPremium(currency: decoder.decodeStringForKey("currency", orElse: ""), amount: decoder.decodeInt64ForKey("amount", orElse: 0), months: decoder.decodeInt32ForKey("months", orElse: 0), cryptoCurrency: decoder.decodeOptionalStringForKey("cryptoCurrency"), cryptoAmount: decoder.decodeOptionalInt64ForKey("cryptoAmount"))
|
self = .giftPremium(currency: decoder.decodeStringForKey("currency", orElse: ""), amount: decoder.decodeInt64ForKey("amount", orElse: 0), months: decoder.decodeInt32ForKey("months", orElse: 0), cryptoCurrency: decoder.decodeOptionalStringForKey("cryptoCurrency"), cryptoAmount: decoder.decodeOptionalInt64ForKey("cryptoAmount"), text: decoder.decodeOptionalStringForKey("text"), entities: decoder.decodeOptionalObjectArrayWithDecoderForKey("entities"))
|
||||||
case 28:
|
case 28:
|
||||||
self = .topicCreated(title: decoder.decodeStringForKey("title", orElse: ""), iconColor: decoder.decodeInt32ForKey("iconColor", orElse: 0), iconFileId: decoder.decodeOptionalInt64ForKey("iconFileId"))
|
self = .topicCreated(title: decoder.decodeStringForKey("title", orElse: ""), iconColor: decoder.decodeInt32ForKey("iconColor", orElse: 0), iconFileId: decoder.decodeOptionalInt64ForKey("iconFileId"))
|
||||||
case 29:
|
case 29:
|
||||||
@ -230,7 +230,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
|||||||
case 35:
|
case 35:
|
||||||
self = .botAppAccessGranted(appName: decoder.decodeOptionalStringForKey("app"), type: decoder.decodeOptionalInt32ForKey("atp").flatMap { BotSendMessageAccessGrantedType(rawValue: $0) })
|
self = .botAppAccessGranted(appName: decoder.decodeOptionalStringForKey("app"), type: decoder.decodeOptionalInt32ForKey("atp").flatMap { BotSendMessageAccessGrantedType(rawValue: $0) })
|
||||||
case 36:
|
case 36:
|
||||||
self = .giftCode(slug: decoder.decodeStringForKey("slug", orElse: ""), fromGiveaway: decoder.decodeBoolForKey("give", orElse: false), isUnclaimed: decoder.decodeBoolForKey("unclaimed", orElse: false), boostPeerId: decoder.decodeOptionalInt64ForKey("pi").flatMap { PeerId($0) }, months: decoder.decodeInt32ForKey("months", orElse: 0), currency: decoder.decodeOptionalStringForKey("currency"), amount: decoder.decodeOptionalInt64ForKey("amount"), cryptoCurrency: decoder.decodeOptionalStringForKey("cryptoCurrency"), cryptoAmount: decoder.decodeOptionalInt64ForKey("cryptoAmount"))
|
self = .giftCode(slug: decoder.decodeStringForKey("slug", orElse: ""), fromGiveaway: decoder.decodeBoolForKey("give", orElse: false), isUnclaimed: decoder.decodeBoolForKey("unclaimed", orElse: false), boostPeerId: decoder.decodeOptionalInt64ForKey("pi").flatMap { PeerId($0) }, months: decoder.decodeInt32ForKey("months", orElse: 0), currency: decoder.decodeOptionalStringForKey("currency"), amount: decoder.decodeOptionalInt64ForKey("amount"), cryptoCurrency: decoder.decodeOptionalStringForKey("cryptoCurrency"), cryptoAmount: decoder.decodeOptionalInt64ForKey("cryptoAmount"), text: decoder.decodeOptionalStringForKey("text"), entities: decoder.decodeOptionalObjectArrayWithDecoderForKey("entities"))
|
||||||
case 37:
|
case 37:
|
||||||
self = .giveawayLaunched(stars: decoder.decodeOptionalInt64ForKey("stars"))
|
self = .giveawayLaunched(stars: decoder.decodeOptionalInt64ForKey("stars"))
|
||||||
case 38:
|
case 38:
|
||||||
@ -382,7 +382,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
|||||||
case let .webViewData(text):
|
case let .webViewData(text):
|
||||||
encoder.encodeInt32(26, forKey: "_rawValue")
|
encoder.encodeInt32(26, forKey: "_rawValue")
|
||||||
encoder.encodeString(text, forKey: "t")
|
encoder.encodeString(text, forKey: "t")
|
||||||
case let .giftPremium(currency, amount, months, cryptoCurrency, cryptoAmount):
|
case let .giftPremium(currency, amount, months, cryptoCurrency, cryptoAmount, text, entities):
|
||||||
encoder.encodeInt32(27, forKey: "_rawValue")
|
encoder.encodeInt32(27, forKey: "_rawValue")
|
||||||
encoder.encodeString(currency, forKey: "currency")
|
encoder.encodeString(currency, forKey: "currency")
|
||||||
encoder.encodeInt64(amount, forKey: "amount")
|
encoder.encodeInt64(amount, forKey: "amount")
|
||||||
@ -390,6 +390,16 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
|||||||
if let cryptoCurrency = cryptoCurrency, let cryptoAmount = cryptoAmount {
|
if let cryptoCurrency = cryptoCurrency, let cryptoAmount = cryptoAmount {
|
||||||
encoder.encodeString(cryptoCurrency, forKey: "cryptoCurrency")
|
encoder.encodeString(cryptoCurrency, forKey: "cryptoCurrency")
|
||||||
encoder.encodeInt64(cryptoAmount, forKey: "cryptoAmount")
|
encoder.encodeInt64(cryptoAmount, forKey: "cryptoAmount")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "cryptoCurrency")
|
||||||
|
encoder.encodeNil(forKey: "cryptoAmount")
|
||||||
|
}
|
||||||
|
if let text, let entities {
|
||||||
|
encoder.encodeString(text, forKey: "text")
|
||||||
|
encoder.encodeObjectArray(entities, forKey: "entities")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "text")
|
||||||
|
encoder.encodeNil(forKey: "entities")
|
||||||
}
|
}
|
||||||
case let .topicCreated(title, iconColor, iconFileId):
|
case let .topicCreated(title, iconColor, iconFileId):
|
||||||
encoder.encodeInt32(28, forKey: "_rawValue")
|
encoder.encodeInt32(28, forKey: "_rawValue")
|
||||||
@ -433,7 +443,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
|||||||
} else {
|
} else {
|
||||||
encoder.encodeNil(forKey: "atp")
|
encoder.encodeNil(forKey: "atp")
|
||||||
}
|
}
|
||||||
case let .giftCode(slug, fromGiveaway, unclaimed, boostPeerId, months, currency, amount, cryptoCurrency, cryptoAmount):
|
case let .giftCode(slug, fromGiveaway, unclaimed, boostPeerId, months, currency, amount, cryptoCurrency, cryptoAmount, text, entities):
|
||||||
encoder.encodeInt32(36, forKey: "_rawValue")
|
encoder.encodeInt32(36, forKey: "_rawValue")
|
||||||
encoder.encodeString(slug, forKey: "slug")
|
encoder.encodeString(slug, forKey: "slug")
|
||||||
encoder.encodeBool(fromGiveaway, forKey: "give")
|
encoder.encodeBool(fromGiveaway, forKey: "give")
|
||||||
@ -464,6 +474,13 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
|||||||
} else {
|
} else {
|
||||||
encoder.encodeNil(forKey: "cryptoAmount")
|
encoder.encodeNil(forKey: "cryptoAmount")
|
||||||
}
|
}
|
||||||
|
if let text, let entities {
|
||||||
|
encoder.encodeString(text, forKey: "text")
|
||||||
|
encoder.encodeObjectArray(entities, forKey: "entities")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "text")
|
||||||
|
encoder.encodeNil(forKey: "entities")
|
||||||
|
}
|
||||||
case let .giveawayLaunched(stars):
|
case let .giveawayLaunched(stars):
|
||||||
encoder.encodeInt32(37, forKey: "_rawValue")
|
encoder.encodeInt32(37, forKey: "_rawValue")
|
||||||
if let stars = stars {
|
if let stars = stars {
|
||||||
@ -563,7 +580,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
|||||||
return peerIds
|
return peerIds
|
||||||
case let .requestedPeer(_, peerIds):
|
case let .requestedPeer(_, peerIds):
|
||||||
return peerIds
|
return peerIds
|
||||||
case let .giftCode(_, _, _, boostPeerId, _, _, _, _, _):
|
case let .giftCode(_, _, _, boostPeerId, _, _, _, _, _, _, _):
|
||||||
return boostPeerId.flatMap { [$0] } ?? []
|
return boostPeerId.flatMap { [$0] } ?? []
|
||||||
case let .paymentRefunded(peerId, _, _, _, _):
|
case let .paymentRefunded(peerId, _, _, _, _):
|
||||||
return [peerId]
|
return [peerId]
|
||||||
|
|||||||
@ -15,7 +15,7 @@ public enum AppStoreTransactionPurpose {
|
|||||||
case upgrade
|
case upgrade
|
||||||
case restore
|
case restore
|
||||||
case gift(peerId: EnginePeer.Id, currency: String, amount: Int64)
|
case gift(peerId: EnginePeer.Id, currency: String, amount: Int64)
|
||||||
case giftCode(peerIds: [EnginePeer.Id], boostPeer: EnginePeer.Id?, currency: String, amount: Int64)
|
case giftCode(peerIds: [EnginePeer.Id], boostPeer: EnginePeer.Id?, currency: String, amount: Int64, text: String?, entities: [MessageTextEntity]?)
|
||||||
case giveaway(boostPeer: EnginePeer.Id, additionalPeerIds: [EnginePeer.Id], countries: [String], onlyNewSubscribers: Bool, showWinners: Bool, prizeDescription: String?, randomId: Int64, untilDate: Int32, currency: String, amount: Int64)
|
case giveaway(boostPeer: EnginePeer.Id, additionalPeerIds: [EnginePeer.Id], countries: [String], onlyNewSubscribers: Bool, showWinners: Bool, prizeDescription: String?, randomId: Int64, untilDate: Int32, currency: String, amount: Int64)
|
||||||
case stars(count: Int64, currency: String, amount: Int64)
|
case stars(count: Int64, currency: String, amount: Int64)
|
||||||
case starsGift(peerId: EnginePeer.Id, count: Int64, currency: String, amount: Int64)
|
case starsGift(peerId: EnginePeer.Id, count: Int64, currency: String, amount: Int64)
|
||||||
@ -43,7 +43,7 @@ private func apiInputStorePaymentPurpose(account: Account, purpose: AppStoreTran
|
|||||||
}
|
}
|
||||||
return .single(.inputStorePaymentGiftPremium(userId: inputUser, currency: currency, amount: amount))
|
return .single(.inputStorePaymentGiftPremium(userId: inputUser, currency: currency, amount: amount))
|
||||||
}
|
}
|
||||||
case let .giftCode(peerIds, boostPeerId, currency, amount):
|
case let .giftCode(peerIds, boostPeerId, currency, amount, text, entities):
|
||||||
return account.postbox.transaction { transaction -> Api.InputStorePaymentPurpose in
|
return account.postbox.transaction { transaction -> Api.InputStorePaymentPurpose in
|
||||||
var flags: Int32 = 0
|
var flags: Int32 = 0
|
||||||
var apiBoostPeer: Api.InputPeer?
|
var apiBoostPeer: Api.InputPeer?
|
||||||
@ -60,7 +60,12 @@ private func apiInputStorePaymentPurpose(account: Account, purpose: AppStoreTran
|
|||||||
flags |= (1 << 0)
|
flags |= (1 << 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
return .inputStorePaymentPremiumGiftCode(flags: flags, users: apiInputUsers, boostPeer: apiBoostPeer, currency: currency, amount: amount)
|
var message: Api.TextWithEntities?
|
||||||
|
if let text {
|
||||||
|
flags |= (1 << 1)
|
||||||
|
message = .textWithEntities(text: text, entities: apiEntitiesFromMessageTextEntities(entities ?? [], associatedPeers: SimpleDictionary()))
|
||||||
|
}
|
||||||
|
return .inputStorePaymentPremiumGiftCode(flags: flags, users: apiInputUsers, boostPeer: apiBoostPeer, currency: currency, amount: amount, message: message)
|
||||||
}
|
}
|
||||||
case let .giveaway(boostPeerId, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate, currency, amount):
|
case let .giveaway(boostPeerId, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate, currency, amount):
|
||||||
return account.postbox.transaction { transaction -> Signal<Api.InputStorePaymentPurpose, NoError> in
|
return account.postbox.transaction { transaction -> Signal<Api.InputStorePaymentPurpose, NoError> in
|
||||||
|
|||||||
@ -293,7 +293,7 @@ func _internal_parseInputInvoice(transaction: Transaction, source: BotPaymentInv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let inputPurpose: Api.InputStorePaymentPurpose = .inputStorePaymentPremiumGiftCode(flags: 0, users: inputUsers, boostPeer: nil, currency: currency, amount: amount)
|
let inputPurpose: Api.InputStorePaymentPurpose = .inputStorePaymentPremiumGiftCode(flags: 0, users: inputUsers, boostPeer: nil, currency: currency, amount: amount, message: nil)
|
||||||
|
|
||||||
var flags: Int32 = 0
|
var flags: Int32 = 0
|
||||||
if let _ = option.storeProductId {
|
if let _ = option.storeProductId {
|
||||||
|
|||||||
@ -735,7 +735,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
}
|
}
|
||||||
case let .webViewData(text):
|
case let .webViewData(text):
|
||||||
attributedString = NSAttributedString(string: strings.Notification_WebAppSentData(text).string, font: titleFont, textColor: primaryTextColor)
|
attributedString = NSAttributedString(string: strings.Notification_WebAppSentData(text).string, font: titleFont, textColor: primaryTextColor)
|
||||||
case let .giftPremium(currency, amount, _, _, _):
|
case let .giftPremium(currency, amount, _, _, _, _, _):
|
||||||
let price = formatCurrencyAmount(amount, currency: currency)
|
let price = formatCurrencyAmount(amount, currency: currency)
|
||||||
if message.author?.id == accountPeerId {
|
if message.author?.id == accountPeerId {
|
||||||
attributedString = addAttributesToStringWithRanges(strings.Notification_PremiumGift_SentYou(price)._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
|
attributedString = addAttributesToStringWithRanges(strings.Notification_PremiumGift_SentYou(price)._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
|
||||||
@ -952,7 +952,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
let resultTitleString = strings.Notification_ChangedToSameWallpaper(compactAuthorName)
|
let resultTitleString = strings.Notification_ChangedToSameWallpaper(compactAuthorName)
|
||||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
|
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
|
||||||
}
|
}
|
||||||
case let .giftCode(_, _, _, boostPeerId, _, currency, amount, _, _):
|
case let .giftCode(_, _, _, boostPeerId, _, currency, amount, _, _, _, _):
|
||||||
if boostPeerId == nil, let currency, let amount {
|
if boostPeerId == nil, let currency, let amount {
|
||||||
let price = formatCurrencyAmount(amount, currency: currency)
|
let price = formatCurrencyAmount(amount, currency: currency)
|
||||||
if message.author?.id == accountPeerId {
|
if message.author?.id == accountPeerId {
|
||||||
@ -1058,7 +1058,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
let _ = text
|
let _ = text
|
||||||
let _ = entities
|
let _ = entities
|
||||||
|
|
||||||
let starsPrice = "\(gift.price) Stars"
|
let starsPrice = strings.Notification_StarsGift_Stars(Int32(gift.price))
|
||||||
var authorName = compactAuthorName
|
var authorName = compactAuthorName
|
||||||
var peerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)]
|
var peerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)]
|
||||||
if message.id.peerId.namespace == Namespaces.Peer.CloudUser && message.id.peerId.id._internalGetInt64Value() == 777000 {
|
if message.id.peerId.namespace == Namespaces.Peer.CloudUser && message.id.peerId.id._internalGetInt64Value() == 777000 {
|
||||||
|
|||||||
@ -37,6 +37,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
private var mediaBackgroundContent: WallpaperBubbleBackgroundNode?
|
private var mediaBackgroundContent: WallpaperBubbleBackgroundNode?
|
||||||
private let titleNode: TextNode
|
private let titleNode: TextNode
|
||||||
private let subtitleNode: TextNodeWithEntities
|
private let subtitleNode: TextNodeWithEntities
|
||||||
|
private let textClippingNode: ASDisplayNode
|
||||||
private var dustNode: InvisibleInkDustNode?
|
private var dustNode: InvisibleInkDustNode?
|
||||||
private let placeholderNode: StickerShimmerEffectNode
|
private let placeholderNode: StickerShimmerEffectNode
|
||||||
private let animationNode: AnimatedStickerNode
|
private let animationNode: AnimatedStickerNode
|
||||||
@ -49,11 +50,17 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
private let buttonStarsNode: PremiumStarsNode
|
private let buttonStarsNode: PremiumStarsNode
|
||||||
private let buttonTitleNode: TextNode
|
private let buttonTitleNode: TextNode
|
||||||
|
|
||||||
|
private var maskView: UIImageView?
|
||||||
|
private var maskOverlayView: UIView?
|
||||||
|
|
||||||
private var cachedMaskBackgroundImage: (CGPoint, UIImage, [CGRect])?
|
private var cachedMaskBackgroundImage: (CGPoint, UIImage, [CGRect])?
|
||||||
private var absoluteRect: (CGRect, CGSize)?
|
private var absoluteRect: (CGRect, CGSize)?
|
||||||
|
|
||||||
private var isPlaying: Bool = false
|
private var isPlaying: Bool = false
|
||||||
|
|
||||||
|
private var isExpanded: Bool = false
|
||||||
|
private var appliedIsExpanded: Bool = false
|
||||||
|
|
||||||
private var currentProgressDisposable: Disposable?
|
private var currentProgressDisposable: Disposable?
|
||||||
|
|
||||||
override public var visibility: ListViewItemNodeVisibility {
|
override public var visibility: ListViewItemNodeVisibility {
|
||||||
@ -105,6 +112,9 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
self.subtitleNode.textNode.isUserInteractionEnabled = false
|
self.subtitleNode.textNode.isUserInteractionEnabled = false
|
||||||
self.subtitleNode.textNode.displaysAsynchronously = false
|
self.subtitleNode.textNode.displaysAsynchronously = false
|
||||||
|
|
||||||
|
self.textClippingNode = ASDisplayNode()
|
||||||
|
self.textClippingNode.clipsToBounds = true
|
||||||
|
|
||||||
self.buttonNode = HighlightTrackingButtonNode()
|
self.buttonNode = HighlightTrackingButtonNode()
|
||||||
self.buttonNode.clipsToBounds = true
|
self.buttonNode.clipsToBounds = true
|
||||||
self.buttonNode.cornerRadius = 17.0
|
self.buttonNode.cornerRadius = 17.0
|
||||||
@ -133,7 +143,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
self.addSubnode(self.labelNode)
|
self.addSubnode(self.labelNode)
|
||||||
|
|
||||||
self.addSubnode(self.titleNode)
|
self.addSubnode(self.titleNode)
|
||||||
self.addSubnode(self.subtitleNode.textNode)
|
self.addSubnode(self.textClippingNode)
|
||||||
|
self.textClippingNode.addSubnode(self.subtitleNode.textNode)
|
||||||
self.addSubnode(self.placeholderNode)
|
self.addSubnode(self.placeholderNode)
|
||||||
self.addSubnode(self.animationNode)
|
self.addSubnode(self.animationNode)
|
||||||
|
|
||||||
@ -251,9 +262,12 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
let makeSubtitleLayout = TextNodeWithEntities.asyncLayout(self.subtitleNode)
|
let makeSubtitleLayout = TextNodeWithEntities.asyncLayout(self.subtitleNode)
|
||||||
let makeButtonTitleLayout = TextNode.asyncLayout(self.buttonTitleNode)
|
let makeButtonTitleLayout = TextNode.asyncLayout(self.buttonTitleNode)
|
||||||
let makeRibbonTextLayout = TextNode.asyncLayout(self.ribbonTextNode)
|
let makeRibbonTextLayout = TextNode.asyncLayout(self.ribbonTextNode)
|
||||||
|
let makeMeasureTextLayout = TextNode.asyncLayout(nil)
|
||||||
|
|
||||||
let cachedMaskBackgroundImage = self.cachedMaskBackgroundImage
|
let cachedMaskBackgroundImage = self.cachedMaskBackgroundImage
|
||||||
|
|
||||||
|
let currentIsExpanded = self.isExpanded
|
||||||
|
|
||||||
return { item, layoutConstants, _, _, _, _ in
|
return { item, layoutConstants, _, _, _, _ in
|
||||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: true, headerSpacing: 0.0, hidesBackground: .always, forceFullCorners: false, forceAlignment: .center)
|
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: true, headerSpacing: 0.0, hidesBackground: .always, forceFullCorners: false, forceAlignment: .center)
|
||||||
|
|
||||||
@ -279,9 +293,19 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
for media in item.message.media {
|
for media in item.message.media {
|
||||||
if let action = media as? TelegramMediaAction {
|
if let action = media as? TelegramMediaAction {
|
||||||
switch action.action {
|
switch action.action {
|
||||||
case let .giftPremium(_, _, monthsValue, _, _):
|
case let .giftPremium(_, _, monthsValue, _, _, giftText, giftEntities):
|
||||||
months = monthsValue
|
months = monthsValue
|
||||||
text = item.presentationData.strings.Notification_PremiumGift_Subtitle(item.presentationData.strings.Notification_PremiumGift_Months(months)).string
|
if months == 12 {
|
||||||
|
title = item.presentationData.strings.Notification_PremiumGift_YearsTitle(1)
|
||||||
|
} else {
|
||||||
|
title = item.presentationData.strings.Notification_PremiumGift_MonthsTitle(months)
|
||||||
|
}
|
||||||
|
if let giftText, !giftText.isEmpty {
|
||||||
|
text = giftText
|
||||||
|
entities = giftEntities ?? []
|
||||||
|
} else {
|
||||||
|
text = item.presentationData.strings.Notification_PremiumGift_SubscriptionDescription
|
||||||
|
}
|
||||||
case let .giftStars(_, _, count, _, _, _):
|
case let .giftStars(_, _, count, _, _, _):
|
||||||
if count <= 1000 {
|
if count <= 1000 {
|
||||||
months = 3
|
months = 3
|
||||||
@ -310,10 +334,20 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
title = item.presentationData.strings.Notification_StarsGiveaway_Title
|
title = item.presentationData.strings.Notification_StarsGiveaway_Title
|
||||||
text = item.presentationData.strings.Notification_StarsGiveaway_Subtitle(peerName, item.presentationData.strings.Notification_StarsGiveaway_Subtitle_Stars(Int32(count))).string
|
text = item.presentationData.strings.Notification_StarsGiveaway_Subtitle(peerName, item.presentationData.strings.Notification_StarsGiveaway_Subtitle_Stars(Int32(count))).string
|
||||||
case let .giftCode(_, fromGiveaway, unclaimed, channelId, monthsValue, _, _, _, _):
|
case let .giftCode(_, fromGiveaway, unclaimed, channelId, monthsValue, _, _, _, _, giftText, giftEntities):
|
||||||
if channelId == nil {
|
if channelId == nil {
|
||||||
months = monthsValue
|
months = monthsValue
|
||||||
text = item.presentationData.strings.Notification_PremiumGift_Subtitle(item.presentationData.strings.Notification_PremiumGift_Months(months)).string
|
if months == 12 {
|
||||||
|
title = item.presentationData.strings.Notification_PremiumGift_YearsTitle(1)
|
||||||
|
} else {
|
||||||
|
title = item.presentationData.strings.Notification_PremiumGift_MonthsTitle(months)
|
||||||
|
}
|
||||||
|
if let giftText, !giftText.isEmpty {
|
||||||
|
text = giftText
|
||||||
|
entities = giftEntities ?? []
|
||||||
|
} else {
|
||||||
|
text = item.presentationData.strings.Notification_PremiumGift_SubscriptionDescription
|
||||||
|
}
|
||||||
if item.message.author?.id != item.context.account.peerId {
|
if item.message.author?.id != item.context.account.peerId {
|
||||||
buttonTitle = item.presentationData.strings.Notification_PremiumGift_UseGift
|
buttonTitle = item.presentationData.strings.Notification_PremiumGift_UseGift
|
||||||
}
|
}
|
||||||
@ -419,13 +453,24 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
), textAlignment: .center)
|
), textAlignment: .center)
|
||||||
}
|
}
|
||||||
|
|
||||||
let (subtitleLayout, subtitleApply) = makeSubtitleLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
let textConstrainedSize = CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude)
|
||||||
|
let (subtitleLayout, subtitleApply) = makeSubtitleLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
var canExpand = false
|
||||||
|
var clippedTextHeight: CGFloat = subtitleLayout.size.height
|
||||||
|
if subtitleLayout.numberOfLines > 4 {
|
||||||
|
let (measuredTextLayout, _) = makeMeasureTextLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 4, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
canExpand = true
|
||||||
|
if !currentIsExpanded {
|
||||||
|
clippedTextHeight = measuredTextLayout.size.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (buttonTitleLayout, buttonTitleApply) = makeButtonTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: buttonTitle, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
let (buttonTitleLayout, buttonTitleApply) = makeButtonTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: buttonTitle, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
let (ribbonTextLayout, ribbonTextApply) = makeRibbonTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: ribbonTitle, font: Font.semibold(11.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
let (ribbonTextLayout, ribbonTextApply) = makeRibbonTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: ribbonTitle, font: Font.semibold(11.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
giftSize.height = titleLayout.size.height + textSpacing + subtitleLayout.size.height + 164.0
|
giftSize.height = titleLayout.size.height + textSpacing + clippedTextHeight + 164.0
|
||||||
if !buttonTitle.isEmpty {
|
if !buttonTitle.isEmpty {
|
||||||
giftSize.height += 48.0
|
giftSize.height += 48.0
|
||||||
}
|
}
|
||||||
@ -472,8 +517,18 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (backgroundSize.width, { boundingWidth in
|
return (backgroundSize.width, { boundingWidth in
|
||||||
return (backgroundSize, { [weak self] animation, synchronousLoads, _ in
|
return (backgroundSize, { [weak self] animation, synchronousLoads, info in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
let isFirstTime = strongSelf.item == nil
|
||||||
|
|
||||||
|
var isExpandedUpdated = false
|
||||||
|
if strongSelf.appliedIsExpanded != currentIsExpanded {
|
||||||
|
strongSelf.appliedIsExpanded = currentIsExpanded
|
||||||
|
info?.setInvertOffsetDirection()
|
||||||
|
isExpandedUpdated = true
|
||||||
|
}
|
||||||
|
let _ = isExpandedUpdated
|
||||||
|
|
||||||
let overlayColor = item.presentationData.theme.theme.overallDarkAppearance ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12)
|
let overlayColor = item.presentationData.theme.theme.overallDarkAppearance ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12)
|
||||||
|
|
||||||
let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - giftSize.width) / 2.0), y: hasServiceMessage ? labelLayout.size.height + 16.0 : 0.0), size: giftSize)
|
let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - giftSize.width) / 2.0), y: hasServiceMessage ? labelLayout.size.height + 16.0 : 0.0), size: giftSize)
|
||||||
@ -551,8 +606,21 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
let titleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - titleLayout.size.width) / 2.0) , y: mediaBackgroundFrame.minY + 151.0), size: titleLayout.size)
|
let titleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - titleLayout.size.width) / 2.0) , y: mediaBackgroundFrame.minY + 151.0), size: titleLayout.size)
|
||||||
strongSelf.titleNode.frame = titleFrame
|
strongSelf.titleNode.frame = titleFrame
|
||||||
|
|
||||||
|
let clippingTextFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - subtitleLayout.size.width) / 2.0) , y: titleFrame.maxY + textSpacing), size: CGSize(width: boundingWidth, height: clippedTextHeight))
|
||||||
|
|
||||||
let subtitleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - subtitleLayout.size.width) / 2.0) , y: titleFrame.maxY + textSpacing), size: subtitleLayout.size)
|
let subtitleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - subtitleLayout.size.width) / 2.0) , y: titleFrame.maxY + textSpacing), size: subtitleLayout.size)
|
||||||
strongSelf.subtitleNode.textNode.frame = subtitleFrame
|
strongSelf.subtitleNode.textNode.frame = CGRect(origin: .zero, size: subtitleLayout.size)
|
||||||
|
|
||||||
|
if isFirstTime {
|
||||||
|
strongSelf.textClippingNode.frame = clippingTextFrame
|
||||||
|
} else {
|
||||||
|
animation.animator.updateFrame(layer: strongSelf.textClippingNode.layer, frame: clippingTextFrame, completion: nil)
|
||||||
|
}
|
||||||
|
if let maskView = strongSelf.maskView, let maskOverlayView = strongSelf.maskOverlayView {
|
||||||
|
animation.animator.updateFrame(layer: maskView.layer, frame: CGRect(origin: .zero, size: CGSize(width: boundingWidth, height: clippingTextFrame.size.height)), completion: nil)
|
||||||
|
animation.animator.updateFrame(layer: maskOverlayView.layer, frame: CGRect(origin: .zero, size: CGSize(width: boundingWidth, height: clippingTextFrame.size.height)), completion: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if !subtitleLayout.spoilers.isEmpty {
|
if !subtitleLayout.spoilers.isEmpty {
|
||||||
let dustColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText
|
let dustColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText
|
||||||
@ -573,11 +641,11 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
strongSelf.dustNode = nil
|
strongSelf.dustNode = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let buttonTitleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - buttonTitleLayout.size.width) / 2.0), y: subtitleFrame.maxY + 18.0), size: buttonTitleLayout.size)
|
let buttonTitleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - buttonTitleLayout.size.width) / 2.0), y: clippingTextFrame.maxY + 18.0), size: buttonTitleLayout.size)
|
||||||
strongSelf.buttonTitleNode.frame = buttonTitleFrame
|
strongSelf.buttonTitleNode.frame = buttonTitleFrame
|
||||||
|
|
||||||
let buttonSize = CGSize(width: buttonTitleLayout.size.width + 38.0, height: 34.0)
|
let buttonSize = CGSize(width: buttonTitleLayout.size.width + 38.0, height: 34.0)
|
||||||
strongSelf.buttonNode.frame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - buttonSize.width) / 2.0), y: subtitleFrame.maxY + 10.0), size: buttonSize)
|
strongSelf.buttonNode.frame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - buttonSize.width) / 2.0), y: clippingTextFrame.maxY + 10.0), size: buttonSize)
|
||||||
strongSelf.buttonStarsNode.frame = CGRect(origin: .zero, size: buttonSize)
|
strongSelf.buttonStarsNode.frame = CGRect(origin: .zero, size: buttonSize)
|
||||||
|
|
||||||
if ribbonTextLayout.size.width > 0.0 {
|
if ribbonTextLayout.size.width > 0.0 {
|
||||||
@ -666,6 +734,26 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
strongSelf.updateAbsoluteRect(rect, within: size)
|
strongSelf.updateAbsoluteRect(rect, within: size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if canExpand {
|
||||||
|
if strongSelf.maskView?.image == nil {
|
||||||
|
strongSelf.maskView?.image = generateMaskImage()
|
||||||
|
}
|
||||||
|
strongSelf.textClippingNode.view.mask = strongSelf.maskView
|
||||||
|
|
||||||
|
// var expandIconFrame: CGRect = .zero
|
||||||
|
// if let icon = strongSelf.expandIcon.image {
|
||||||
|
// expandIconFrame = CGRect(origin: CGPoint(x: boundingWidth - icon.size.width - 19.0, y: backgroundFrame.maxY - icon.size.height - 6.0), size: icon.size)
|
||||||
|
// if wasHidden || isFirstTime {
|
||||||
|
// strongSelf.expandIcon.position = expandIconFrame.center
|
||||||
|
// } else {
|
||||||
|
// animation.animator.updatePosition(layer: strongSelf.expandIcon.layer, position: expandIconFrame.center, completion: nil)
|
||||||
|
// }
|
||||||
|
// strongSelf.expandIcon.bounds = CGRect(origin: .zero, size: expandIconFrame.size)
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
strongSelf.textClippingNode.view.mask = nil
|
||||||
|
}
|
||||||
|
|
||||||
switch strongSelf.visibility {
|
switch strongSelf.visibility {
|
||||||
case .none:
|
case .none:
|
||||||
strongSelf.subtitleNode.visibilityRect = nil
|
strongSelf.subtitleNode.visibilityRect = nil
|
||||||
@ -853,3 +941,22 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func generateMaskImage() -> UIImage? {
|
||||||
|
return generateImage(CGSize(width: 140, height: 30), rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: .zero, size: size))
|
||||||
|
|
||||||
|
context.setFillColor(UIColor.white.cgColor)
|
||||||
|
context.fill(CGRect(origin: .zero, size: size))
|
||||||
|
|
||||||
|
var locations: [CGFloat] = [0.0, 0.5, 1.0]
|
||||||
|
let colors: [CGColor] = [UIColor.white.cgColor, UIColor.white.withAlphaComponent(0.0).cgColor, UIColor.white.withAlphaComponent(0.0).cgColor]
|
||||||
|
|
||||||
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||||
|
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
|
||||||
|
|
||||||
|
context.setBlendMode(.copy)
|
||||||
|
context.clip(to: CGRect(origin: CGPoint(x: 10.0, y: 8.0), size: CGSize(width: 130.0, height: 22.0)))
|
||||||
|
context.drawLinearGradient(gradient, start: CGPoint(x: 10.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions())
|
||||||
|
})?.resizableImage(withCapInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 22.0, right: 130.0))
|
||||||
|
}
|
||||||
|
|||||||
@ -306,7 +306,7 @@ final class GiftOptionsScreenComponent: Component {
|
|||||||
let giftController = GiftSetupScreen(
|
let giftController = GiftSetupScreen(
|
||||||
context: component.context,
|
context: component.context,
|
||||||
peerId: component.peerId,
|
peerId: component.peerId,
|
||||||
gift: gift,
|
subject: .starGift(gift),
|
||||||
completion: component.completion
|
completion: component.completion
|
||||||
)
|
)
|
||||||
mainController.push(giftController)
|
mainController.push(giftController)
|
||||||
@ -359,94 +359,6 @@ final class GiftOptionsScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func buyPremium(_ product: PremiumGiftProduct) {
|
|
||||||
guard let component = self.component, let inAppPurchaseManager = self.component?.context.inAppPurchaseManager, self.inProgressPremiumGift == nil else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
self.inProgressPremiumGift = product.id
|
|
||||||
self.state?.updated()
|
|
||||||
|
|
||||||
let (currency, amount) = product.storeProduct.priceCurrencyAndAmount
|
|
||||||
|
|
||||||
addAppLogEvent(postbox: component.context.account.postbox, type: "premium_gift.promo_screen_accept")
|
|
||||||
|
|
||||||
let purpose: AppStoreTransactionPurpose = .giftCode(peerIds: [component.peerId], boostPeer: nil, currency: currency, amount: amount)
|
|
||||||
let quantity: Int32 = 1
|
|
||||||
|
|
||||||
let completion = component.completion
|
|
||||||
|
|
||||||
let _ = (component.context.engine.payments.canPurchasePremium(purpose: purpose)
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] available in
|
|
||||||
if let strongSelf = self {
|
|
||||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
|
||||||
if available {
|
|
||||||
strongSelf.purchaseDisposable.set((inAppPurchaseManager.buyProduct(product.storeProduct, quantity: quantity, purpose: purpose)
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
|
||||||
if let completion {
|
|
||||||
completion()
|
|
||||||
} else {
|
|
||||||
guard let self, case .purchased = status, let controller = self.environment?.controller(), let navigationController = controller.navigationController as? NavigationController else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var controllers = navigationController.viewControllers
|
|
||||||
controllers = controllers.filter { !($0 is GiftOptionsScreen) && !($0 is PeerInfoScreen) && !($0 is ContactSelectionController) }
|
|
||||||
var foundController = false
|
|
||||||
for controller in controllers.reversed() {
|
|
||||||
if let chatController = controller as? ChatController, case .peer(id: component.peerId) = chatController.chatLocation {
|
|
||||||
chatController.hintPlayNextOutgoingGift()
|
|
||||||
foundController = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !foundController {
|
|
||||||
let chatController = component.context.sharedContext.makeChatController(context: component.context, chatLocation: .peer(id: component.peerId), subject: nil, botStart: nil, mode: .standard(.default), params: nil)
|
|
||||||
chatController.hintPlayNextOutgoingGift()
|
|
||||||
controllers.append(chatController)
|
|
||||||
}
|
|
||||||
navigationController.setViewControllers(controllers, animated: true)
|
|
||||||
}
|
|
||||||
}, error: { [weak self] error in
|
|
||||||
guard let self, let controller = self.environment?.controller() else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.inProgressPremiumGift = nil
|
|
||||||
self.state?.updated(transition: .immediate)
|
|
||||||
|
|
||||||
var errorText: String?
|
|
||||||
switch error {
|
|
||||||
case .generic:
|
|
||||||
errorText = presentationData.strings.Premium_Purchase_ErrorUnknown
|
|
||||||
case .network:
|
|
||||||
errorText = presentationData.strings.Premium_Purchase_ErrorNetwork
|
|
||||||
case .notAllowed:
|
|
||||||
errorText = presentationData.strings.Premium_Purchase_ErrorNotAllowed
|
|
||||||
case .cantMakePayments:
|
|
||||||
errorText = presentationData.strings.Premium_Purchase_ErrorCantMakePayments
|
|
||||||
case .assignFailed:
|
|
||||||
errorText = presentationData.strings.Premium_Purchase_ErrorUnknown
|
|
||||||
case .tryLater:
|
|
||||||
errorText = presentationData.strings.Premium_Purchase_ErrorUnknown
|
|
||||||
case .cancelled:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if let errorText {
|
|
||||||
addAppLogEvent(postbox: component.context.account.postbox, type: "premium_gift.promo_screen_fail")
|
|
||||||
|
|
||||||
let alertController = textAlertController(context: component.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
|
|
||||||
controller.present(alertController, in: .window(.root))
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
self?.inProgressPremiumGift = nil
|
|
||||||
self?.state?.updated(transition: .immediate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func update(component: GiftOptionsScreenComponent, availableSize: CGSize, state: State, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
func update(component: GiftOptionsScreenComponent, availableSize: CGSize, state: State, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||||
self.isUpdating = true
|
self.isUpdating = true
|
||||||
defer {
|
defer {
|
||||||
@ -707,7 +619,7 @@ final class GiftOptionsScreenComponent: Component {
|
|||||||
var validIds: [AnyHashable] = []
|
var validIds: [AnyHashable] = []
|
||||||
var itemFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: premiumOptionSize)
|
var itemFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: premiumOptionSize)
|
||||||
for product in premiumProducts {
|
for product in premiumProducts {
|
||||||
let itemId = AnyHashable(product.storeProduct.id)
|
let itemId = AnyHashable(product.id)
|
||||||
validIds.append(itemId)
|
validIds.append(itemId)
|
||||||
|
|
||||||
var itemTransition = transition
|
var itemTransition = transition
|
||||||
@ -756,7 +668,23 @@ final class GiftOptionsScreenComponent: Component {
|
|||||||
),
|
),
|
||||||
effectAlignment: .center,
|
effectAlignment: .center,
|
||||||
action: { [weak self] in
|
action: { [weak self] in
|
||||||
self?.buyPremium(product)
|
if let self, let component = self.component {
|
||||||
|
if let controller = controller() as? GiftOptionsScreen {
|
||||||
|
let mainController: ViewController
|
||||||
|
if let parentController = controller.parentController() {
|
||||||
|
mainController = parentController
|
||||||
|
} else {
|
||||||
|
mainController = controller
|
||||||
|
}
|
||||||
|
let giftController = GiftSetupScreen(
|
||||||
|
context: component.context,
|
||||||
|
peerId: component.peerId,
|
||||||
|
subject: .premium(product),
|
||||||
|
completion: component.completion
|
||||||
|
)
|
||||||
|
mainController.push(giftController)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
animateAlpha: false
|
animateAlpha: false
|
||||||
)
|
)
|
||||||
@ -1019,22 +947,42 @@ final class GiftOptionsScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
|
|
||||||
let shortestOptionPrice: (Int64, NSDecimalNumber)
|
if availableProducts.isEmpty {
|
||||||
if let product = availableProducts.first(where: { $0.id.hasSuffix(".monthly") }) {
|
var premiumProducts: [PremiumGiftProduct] = []
|
||||||
shortestOptionPrice = (Int64(Float(product.priceCurrencyAndAmount.amount)), product.priceValue)
|
for option in premiumOptions {
|
||||||
} else {
|
premiumProducts.append(
|
||||||
shortestOptionPrice = (1, NSDecimalNumber(decimal: 1))
|
PremiumGiftProduct(
|
||||||
}
|
giftOption: CachedPremiumGiftOption(
|
||||||
|
months: option.months,
|
||||||
var premiumProducts: [PremiumGiftProduct] = []
|
currency: option.currency,
|
||||||
for option in premiumOptions {
|
amount: option.amount,
|
||||||
if let product = availableProducts.first(where: { $0.id == option.storeProductId }), !product.isSubscription {
|
botUrl: "",
|
||||||
let fraction = Float(product.priceCurrencyAndAmount.amount) / Float(option.months) / Float(shortestOptionPrice.0)
|
storeProductId: option.storeProductId
|
||||||
let discountValue = Int(round((1.0 - fraction) * 20.0) * 5.0)
|
),
|
||||||
premiumProducts.append(PremiumGiftProduct(giftOption: option, storeProduct: product, discount: discountValue > 0 ? discountValue : nil))
|
storeProduct: nil,
|
||||||
|
discount: nil
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
self.premiumProducts = premiumProducts.sorted(by: { $0.months < $1.months })
|
||||||
|
} else {
|
||||||
|
let shortestOptionPrice: (Int64, NSDecimalNumber)
|
||||||
|
if let product = availableProducts.first(where: { $0.id.hasSuffix(".monthly") }) {
|
||||||
|
shortestOptionPrice = (Int64(Float(product.priceCurrencyAndAmount.amount)), product.priceValue)
|
||||||
|
} else {
|
||||||
|
shortestOptionPrice = (1, NSDecimalNumber(decimal: 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
var premiumProducts: [PremiumGiftProduct] = []
|
||||||
|
for option in premiumOptions {
|
||||||
|
if let product = availableProducts.first(where: { $0.id == option.storeProductId }), !product.isSubscription {
|
||||||
|
let fraction = Float(product.priceCurrencyAndAmount.amount) / Float(option.months) / Float(shortestOptionPrice.0)
|
||||||
|
let discountValue = Int(round((1.0 - fraction) * 20.0) * 5.0)
|
||||||
|
premiumProducts.append(PremiumGiftProduct(giftOption: option, storeProduct: product, discount: discountValue > 0 ? discountValue : nil))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.premiumProducts = premiumProducts.sorted(by: { $0.months < $1.months })
|
||||||
}
|
}
|
||||||
self.premiumProducts = premiumProducts.sorted(by: { $0.months < $1.months })
|
|
||||||
|
|
||||||
self.starGifts = starGifts
|
self.starGifts = starGifts
|
||||||
|
|
||||||
@ -1105,25 +1053,3 @@ open class GiftOptionsScreen: ViewControllerComponentContainer, GiftOptionsScree
|
|||||||
super.containerLayoutUpdated(layout, transition: transition)
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct PremiumGiftProduct: Equatable {
|
|
||||||
let giftOption: CachedPremiumGiftOption
|
|
||||||
let storeProduct: InAppPurchaseManager.Product
|
|
||||||
let discount: Int?
|
|
||||||
|
|
||||||
var id: String {
|
|
||||||
return self.storeProduct.id
|
|
||||||
}
|
|
||||||
|
|
||||||
var months: Int32 {
|
|
||||||
return self.giftOption.months
|
|
||||||
}
|
|
||||||
|
|
||||||
var price: String {
|
|
||||||
return self.storeProduct.price
|
|
||||||
}
|
|
||||||
|
|
||||||
var pricePerMonth: String {
|
|
||||||
return self.storeProduct.pricePerMonth(Int(self.months))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -17,6 +17,7 @@ swift_library(
|
|||||||
"//submodules/SSignalKit/SwiftSignalKit",
|
"//submodules/SSignalKit/SwiftSignalKit",
|
||||||
"//submodules/TelegramPresentationData",
|
"//submodules/TelegramPresentationData",
|
||||||
"//submodules/TelegramUIPreferences",
|
"//submodules/TelegramUIPreferences",
|
||||||
|
"//submodules/TelegramStringFormatting",
|
||||||
"//submodules/AccountContext",
|
"//submodules/AccountContext",
|
||||||
"//submodules/PresentationDataUtils",
|
"//submodules/PresentationDataUtils",
|
||||||
"//submodules/Markdown",
|
"//submodules/Markdown",
|
||||||
@ -41,6 +42,7 @@ swift_library(
|
|||||||
"//submodules/BotPaymentsUI",
|
"//submodules/BotPaymentsUI",
|
||||||
"//submodules/TelegramUI/Components/EmojiSuggestionsComponent",
|
"//submodules/TelegramUI/Components/EmojiSuggestionsComponent",
|
||||||
"//submodules/TelegramUI/Components/ChatEntityKeyboardInputNode",
|
"//submodules/TelegramUI/Components/ChatEntityKeyboardInputNode",
|
||||||
|
"//submodules/InAppPurchaseManager",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|||||||
@ -14,6 +14,10 @@ import WallpaperBackgroundNode
|
|||||||
import ListItemComponentAdaptor
|
import ListItemComponentAdaptor
|
||||||
|
|
||||||
final class ChatGiftPreviewItem: ListViewItem, ItemListItem, ListItemComponentAdaptor.ItemGenerator {
|
final class ChatGiftPreviewItem: ListViewItem, ItemListItem, ListItemComponentAdaptor.ItemGenerator {
|
||||||
|
enum Subject: Equatable {
|
||||||
|
case premium(months: Int32, amount: Int64, currency: String)
|
||||||
|
case starGift(gift: StarGift)
|
||||||
|
}
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let componentTheme: PresentationTheme
|
let componentTheme: PresentationTheme
|
||||||
@ -26,7 +30,7 @@ final class ChatGiftPreviewItem: ListViewItem, ItemListItem, ListItemComponentAd
|
|||||||
let nameDisplayOrder: PresentationPersonNameOrder
|
let nameDisplayOrder: PresentationPersonNameOrder
|
||||||
|
|
||||||
let accountPeer: EnginePeer?
|
let accountPeer: EnginePeer?
|
||||||
let gift: StarGift
|
let subject: ChatGiftPreviewItem.Subject
|
||||||
let text: String
|
let text: String
|
||||||
let entities: [MessageTextEntity]
|
let entities: [MessageTextEntity]
|
||||||
|
|
||||||
@ -42,7 +46,7 @@ final class ChatGiftPreviewItem: ListViewItem, ItemListItem, ListItemComponentAd
|
|||||||
dateTimeFormat: PresentationDateTimeFormat,
|
dateTimeFormat: PresentationDateTimeFormat,
|
||||||
nameDisplayOrder: PresentationPersonNameOrder,
|
nameDisplayOrder: PresentationPersonNameOrder,
|
||||||
accountPeer: EnginePeer?,
|
accountPeer: EnginePeer?,
|
||||||
gift: StarGift,
|
subject: ChatGiftPreviewItem.Subject,
|
||||||
text: String,
|
text: String,
|
||||||
entities: [MessageTextEntity]
|
entities: [MessageTextEntity]
|
||||||
) {
|
) {
|
||||||
@ -57,7 +61,7 @@ final class ChatGiftPreviewItem: ListViewItem, ItemListItem, ListItemComponentAd
|
|||||||
self.dateTimeFormat = dateTimeFormat
|
self.dateTimeFormat = dateTimeFormat
|
||||||
self.nameDisplayOrder = nameDisplayOrder
|
self.nameDisplayOrder = nameDisplayOrder
|
||||||
self.accountPeer = accountPeer
|
self.accountPeer = accountPeer
|
||||||
self.gift = gift
|
self.subject = subject
|
||||||
self.text = text
|
self.text = text
|
||||||
self.entities = entities
|
self.entities = entities
|
||||||
}
|
}
|
||||||
@ -206,9 +210,22 @@ final class ChatGiftPreviewItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
peers[authorPeerId] = item.accountPeer?._asPeer()
|
peers[authorPeerId] = item.accountPeer?._asPeer()
|
||||||
|
|
||||||
let media: [Media] = [
|
let media: [Media]
|
||||||
TelegramMediaAction(action: .starGift(gift: item.gift, convertStars: item.gift.convertStars, text: item.text, entities: item.entities, nameHidden: false, savedToProfile: false, converted: false))
|
switch item.subject {
|
||||||
]
|
case let .premium(months, amount, currency):
|
||||||
|
media = [
|
||||||
|
TelegramMediaAction(
|
||||||
|
action: .giftPremium(currency: currency, amount: amount, months: months, cryptoCurrency: nil, cryptoAmount: nil, text: item.text, entities: item.entities)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
case let .starGift(gift):
|
||||||
|
media = [
|
||||||
|
TelegramMediaAction(
|
||||||
|
action: .starGift(gift: gift, convertStars: gift.convertStars, text: item.text, entities: item.entities, nameHidden: false, savedToProfile: false, converted: false)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
let message = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: peers[authorPeerId], text: "", attributes: [], media: media, peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
let message = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: peers[authorPeerId], text: "", attributes: [], media: media, peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||||
items.append(item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [message], theme: item.componentTheme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: currentBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false, isPreview: true, isStandalone: false))
|
items.append(item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [message], theme: item.componentTheme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: currentBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false, isPreview: true, isStandalone: false))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import Postbox
|
|||||||
import TelegramCore
|
import TelegramCore
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
|
import TelegramStringFormatting
|
||||||
import PresentationDataUtils
|
import PresentationDataUtils
|
||||||
import AccountContext
|
import AccountContext
|
||||||
import ComponentFlow
|
import ComponentFlow
|
||||||
@ -27,24 +28,25 @@ import EmojiSuggestionsComponent
|
|||||||
import ChatPresentationInterfaceState
|
import ChatPresentationInterfaceState
|
||||||
import AudioToolbox
|
import AudioToolbox
|
||||||
import TextFormat
|
import TextFormat
|
||||||
|
import InAppPurchaseManager
|
||||||
|
|
||||||
final class GiftSetupScreenComponent: Component {
|
final class GiftSetupScreenComponent: Component {
|
||||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||||
|
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let peerId: EnginePeer.Id
|
let peerId: EnginePeer.Id
|
||||||
let gift: StarGift
|
let subject: GiftSetupScreen.Subject
|
||||||
let completion: (() -> Void)?
|
let completion: (() -> Void)?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
peerId: EnginePeer.Id,
|
peerId: EnginePeer.Id,
|
||||||
gift: StarGift,
|
subject: GiftSetupScreen.Subject,
|
||||||
completion: (() -> Void)? = nil
|
completion: (() -> Void)? = nil
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.gift = gift
|
self.subject = subject
|
||||||
self.completion = completion
|
self.completion = completion
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +57,7 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
if lhs.peerId != rhs.peerId {
|
if lhs.peerId != rhs.peerId {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if lhs.gift != rhs.gift {
|
if lhs.subject != rhs.subject {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -103,6 +105,7 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
private var currentEmojiSuggestionView: ComponentHostView<Empty>?
|
private var currentEmojiSuggestionView: ComponentHostView<Empty>?
|
||||||
|
|
||||||
private var hideName = false
|
private var hideName = false
|
||||||
|
private var inProgress = false
|
||||||
|
|
||||||
private var previousHadInputHeight: Bool = false
|
private var previousHadInputHeight: Bool = false
|
||||||
private var previousInputHeight: CGFloat?
|
private var previousInputHeight: CGFloat?
|
||||||
@ -189,7 +192,108 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func proceed() {
|
func proceed() {
|
||||||
guard let component = self.component, let starsContext = component.context.starsContext, let starsState = starsContext.currentState else {
|
guard let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch component.subject {
|
||||||
|
case .premium:
|
||||||
|
self.proceedWithPremiumGift()
|
||||||
|
case .starGift:
|
||||||
|
self.proceedWithStarGift()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func proceedWithPremiumGift() {
|
||||||
|
guard let component = self.component, case let .premium(product) = component.subject, let storeProduct = product.storeProduct, let inAppPurchaseManager = component.context.inAppPurchaseManager else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.inProgress = true
|
||||||
|
self.state?.updated()
|
||||||
|
|
||||||
|
let (currency, amount) = storeProduct.priceCurrencyAndAmount
|
||||||
|
|
||||||
|
addAppLogEvent(postbox: component.context.account.postbox, type: "premium_gift.promo_screen_accept")
|
||||||
|
|
||||||
|
let entities = generateChatInputTextEntities(self.textInputState.text)
|
||||||
|
let purpose: AppStoreTransactionPurpose = .giftCode(peerIds: [component.peerId], boostPeer: nil, currency: currency, amount: amount, text: self.textInputState.text.string, entities: entities)
|
||||||
|
let quantity: Int32 = 1
|
||||||
|
|
||||||
|
let completion = component.completion
|
||||||
|
|
||||||
|
let _ = (component.context.engine.payments.canPurchasePremium(purpose: purpose)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] available in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
if available {
|
||||||
|
let _ = (inAppPurchaseManager.buyProduct(storeProduct, quantity: quantity, purpose: purpose)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||||
|
if let completion {
|
||||||
|
completion()
|
||||||
|
} else {
|
||||||
|
guard let self, case .purchased = status, let controller = self.environment?.controller(), let navigationController = controller.navigationController as? NavigationController else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var controllers = navigationController.viewControllers
|
||||||
|
controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) && !($0 is PeerInfoScreen) && !($0 is ContactSelectionController) }
|
||||||
|
var foundController = false
|
||||||
|
for controller in controllers.reversed() {
|
||||||
|
if let chatController = controller as? ChatController, case .peer(id: component.peerId) = chatController.chatLocation {
|
||||||
|
chatController.hintPlayNextOutgoingGift()
|
||||||
|
foundController = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !foundController {
|
||||||
|
let chatController = component.context.sharedContext.makeChatController(context: component.context, chatLocation: .peer(id: component.peerId), subject: nil, botStart: nil, mode: .standard(.default), params: nil)
|
||||||
|
chatController.hintPlayNextOutgoingGift()
|
||||||
|
controllers.append(chatController)
|
||||||
|
}
|
||||||
|
navigationController.setViewControllers(controllers, animated: true)
|
||||||
|
}
|
||||||
|
}, error: { [weak self] error in
|
||||||
|
guard let self, let controller = self.environment?.controller() else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.state?.updated(transition: .immediate)
|
||||||
|
|
||||||
|
var errorText: String?
|
||||||
|
switch error {
|
||||||
|
case .generic:
|
||||||
|
errorText = presentationData.strings.Premium_Purchase_ErrorUnknown
|
||||||
|
case .network:
|
||||||
|
errorText = presentationData.strings.Premium_Purchase_ErrorNetwork
|
||||||
|
case .notAllowed:
|
||||||
|
errorText = presentationData.strings.Premium_Purchase_ErrorNotAllowed
|
||||||
|
case .cantMakePayments:
|
||||||
|
errorText = presentationData.strings.Premium_Purchase_ErrorCantMakePayments
|
||||||
|
case .assignFailed:
|
||||||
|
errorText = presentationData.strings.Premium_Purchase_ErrorUnknown
|
||||||
|
case .tryLater:
|
||||||
|
errorText = presentationData.strings.Premium_Purchase_ErrorUnknown
|
||||||
|
case .cancelled:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if let errorText {
|
||||||
|
addAppLogEvent(postbox: component.context.account.postbox, type: "premium_gift.promo_screen_fail")
|
||||||
|
|
||||||
|
let alertController = textAlertController(context: component.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
|
||||||
|
controller.present(alertController, in: .window(.root))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.inProgress = false
|
||||||
|
self.state?.updated(transition: .immediate)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func proceedWithStarGift() {
|
||||||
|
guard let component = self.component, case let .starGift(starGift) = component.subject, let starsContext = component.context.starsContext, let starsState = starsContext.currentState else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +302,8 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let entities = generateChatInputTextEntities(self.textInputState.text)
|
let entities = generateChatInputTextEntities(self.textInputState.text)
|
||||||
let source: BotPaymentInvoiceSource = .starGift(hideName: self.hideName, peerId: component.peerId, giftId: component.gift.id, text: self.textInputState.text.string, entities: entities)
|
let source: BotPaymentInvoiceSource = .starGift(hideName: self.hideName, peerId: component.peerId, giftId: starGift.id, text: self.textInputState.text.string, entities: entities)
|
||||||
|
|
||||||
let inputData = BotCheckoutController.InputData.fetch(context: component.context, source: source)
|
let inputData = BotCheckoutController.InputData.fetch(context: component.context, source: source)
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<BotCheckoutController.InputData?, NoError> in
|
|> `catch` { _ -> Signal<BotCheckoutController.InputData?, NoError> in
|
||||||
@ -246,7 +351,7 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if starsState.balance < component.gift.price {
|
if starsState.balance < starGift.price {
|
||||||
let _ = (self.optionsPromise.get()
|
let _ = (self.optionsPromise.get()
|
||||||
|> filter { $0 != nil }
|
|> filter { $0 != nil }
|
||||||
|> take(1)
|
|> take(1)
|
||||||
@ -258,7 +363,7 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
context: component.context,
|
context: component.context,
|
||||||
starsContext: starsContext,
|
starsContext: starsContext,
|
||||||
options: options ?? [],
|
options: options ?? [],
|
||||||
purpose: .starGift(peerId: component.peerId, requiredStars: component.gift.price),
|
purpose: .starGift(peerId: component.peerId, requiredStars: starGift.price),
|
||||||
completion: { [weak starsContext] stars in
|
completion: { [weak starsContext] stars in
|
||||||
starsContext?.add(balance: stars)
|
starsContext?.add(balance: stars)
|
||||||
Queue.mainQueue().after(0.1) {
|
Queue.mainQueue().after(0.1) {
|
||||||
@ -522,6 +627,23 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let peerName = self.peerMap[component.peerId]?.compactDisplayTitle ?? ""
|
||||||
|
|
||||||
|
let introFooter: AnyComponent<Empty>?
|
||||||
|
switch component.subject {
|
||||||
|
case .premium:
|
||||||
|
introFooter = AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(
|
||||||
|
string: environment.strings.Gift_Send_Customize_Info(peerName).string,
|
||||||
|
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
||||||
|
textColor: environment.theme.list.freeTextColor
|
||||||
|
)),
|
||||||
|
maximumNumberOfLines: 0
|
||||||
|
))
|
||||||
|
case .starGift:
|
||||||
|
introFooter = nil
|
||||||
|
}
|
||||||
|
|
||||||
let introSectionSize = self.introSection.update(
|
let introSectionSize = self.introSection.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(ListSectionComponent(
|
component: AnyComponent(ListSectionComponent(
|
||||||
@ -534,7 +656,7 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
)),
|
)),
|
||||||
maximumNumberOfLines: 0
|
maximumNumberOfLines: 0
|
||||||
)),
|
)),
|
||||||
footer: nil,
|
footer: introFooter,
|
||||||
items: introSectionItems
|
items: introSectionItems
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
@ -553,6 +675,15 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
|
|
||||||
let listItemParams = ListViewItemLayoutParams(width: availableSize.width - sideInset * 2.0, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true)
|
let listItemParams = ListViewItemLayoutParams(width: availableSize.width - sideInset * 2.0, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true)
|
||||||
if let accountPeer = self.peerMap[component.context.account.peerId] {
|
if let accountPeer = self.peerMap[component.context.account.peerId] {
|
||||||
|
let subject: ChatGiftPreviewItem.Subject
|
||||||
|
switch component.subject {
|
||||||
|
case let .premium(product):
|
||||||
|
let (currency, amount) = product.storeProduct?.priceCurrencyAndAmount ?? ("USD", 1)
|
||||||
|
subject = .premium(months: product.months, amount: amount, currency: currency)
|
||||||
|
case let .starGift(gift):
|
||||||
|
subject = .starGift(gift: gift)
|
||||||
|
}
|
||||||
|
|
||||||
let introContentSize = self.introContent.update(
|
let introContentSize = self.introContent.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(
|
component: AnyComponent(
|
||||||
@ -569,7 +700,7 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
dateTimeFormat: environment.dateTimeFormat,
|
dateTimeFormat: environment.dateTimeFormat,
|
||||||
nameDisplayOrder: presentationData.nameDisplayOrder,
|
nameDisplayOrder: presentationData.nameDisplayOrder,
|
||||||
accountPeer: accountPeer,
|
accountPeer: accountPeer,
|
||||||
gift: component.gift,
|
subject: subject,
|
||||||
text: self.textInputState.text.string,
|
text: self.textInputState.text.string,
|
||||||
entities: generateChatInputTextEntities(self.textInputState.text)
|
entities: generateChatInputTextEntities(self.textInputState.text)
|
||||||
),
|
),
|
||||||
@ -589,55 +720,56 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let peerName = self.peerMap[component.peerId]?.compactDisplayTitle ?? ""
|
if case .starGift = component.subject {
|
||||||
let hideSectionSize = self.hideSection.update(
|
let hideSectionSize = self.hideSection.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(ListSectionComponent(
|
component: AnyComponent(ListSectionComponent(
|
||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
header: nil,
|
header: nil,
|
||||||
footer: AnyComponent(MultilineTextComponent(
|
footer: AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(
|
text: .plain(NSAttributedString(
|
||||||
string: environment.strings.Gift_Send_HideMyName_Info(peerName, peerName).string,
|
string: environment.strings.Gift_Send_HideMyName_Info(peerName, peerName).string,
|
||||||
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
||||||
textColor: environment.theme.list.freeTextColor
|
textColor: environment.theme.list.freeTextColor
|
||||||
|
)),
|
||||||
|
maximumNumberOfLines: 0
|
||||||
)),
|
)),
|
||||||
maximumNumberOfLines: 0
|
items: [
|
||||||
|
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent(
|
||||||
|
theme: environment.theme,
|
||||||
|
title: AnyComponent(VStack([
|
||||||
|
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(
|
||||||
|
string: environment.strings.Gift_Send_HideMyName,
|
||||||
|
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||||
|
textColor: environment.theme.list.itemPrimaryTextColor
|
||||||
|
)),
|
||||||
|
maximumNumberOfLines: 1
|
||||||
|
))),
|
||||||
|
], alignment: .left, spacing: 2.0)),
|
||||||
|
accessory: .toggle(ListActionItemComponent.Toggle(style: .regular, isOn: self.hideName, action: { [weak self] _ in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.hideName = !self.hideName
|
||||||
|
self.state?.updated(transition: .spring(duration: 0.4))
|
||||||
|
})),
|
||||||
|
action: nil
|
||||||
|
)))
|
||||||
|
]
|
||||||
)),
|
)),
|
||||||
items: [
|
environment: {},
|
||||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent(
|
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
||||||
theme: environment.theme,
|
)
|
||||||
title: AnyComponent(VStack([
|
let hideSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: hideSectionSize)
|
||||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
if let hideSectionView = self.hideSection.view {
|
||||||
text: .plain(NSAttributedString(
|
if hideSectionView.superview == nil {
|
||||||
string: environment.strings.Gift_Send_HideMyName,
|
self.scrollView.addSubview(hideSectionView)
|
||||||
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
}
|
||||||
textColor: environment.theme.list.itemPrimaryTextColor
|
transition.setFrame(view: hideSectionView, frame: hideSectionFrame)
|
||||||
)),
|
|
||||||
maximumNumberOfLines: 1
|
|
||||||
))),
|
|
||||||
], alignment: .left, spacing: 2.0)),
|
|
||||||
accessory: .toggle(ListActionItemComponent.Toggle(style: .regular, isOn: self.hideName, action: { [weak self] _ in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.hideName = !self.hideName
|
|
||||||
self.state?.updated(transition: .spring(duration: 0.4))
|
|
||||||
})),
|
|
||||||
action: nil
|
|
||||||
)))
|
|
||||||
]
|
|
||||||
)),
|
|
||||||
environment: {},
|
|
||||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
|
||||||
)
|
|
||||||
let hideSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: hideSectionSize)
|
|
||||||
if let hideSectionView = self.hideSection.view {
|
|
||||||
if hideSectionView.superview == nil {
|
|
||||||
self.scrollView.addSubview(hideSectionView)
|
|
||||||
}
|
}
|
||||||
transition.setFrame(view: hideSectionView, frame: hideSectionFrame)
|
contentHeight += hideSectionSize.height
|
||||||
}
|
}
|
||||||
contentHeight += hideSectionSize.height
|
|
||||||
|
|
||||||
contentHeight += bottomContentInset
|
contentHeight += bottomContentInset
|
||||||
|
|
||||||
@ -647,8 +779,18 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
if self.starImage == nil || self.starImage?.1 !== environment.theme {
|
if self.starImage == nil || self.starImage?.1 !== environment.theme {
|
||||||
self.starImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/PremiumIcon"), color: environment.theme.list.itemCheckColors.foregroundColor)!, environment.theme)
|
self.starImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/PremiumIcon"), color: environment.theme.list.itemCheckColors.foregroundColor)!, environment.theme)
|
||||||
}
|
}
|
||||||
let amountString = presentationStringsFormattedNumber(Int32(component.gift.price), presentationData.dateTimeFormat.groupingSeparator)
|
|
||||||
let buttonAttributedString = NSMutableAttributedString(string: "\(environment.strings.Gift_Send_Send) # \(amountString)", font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
let buttonString: String
|
||||||
|
switch component.subject {
|
||||||
|
case let .premium(product):
|
||||||
|
let amountString = product.price
|
||||||
|
buttonString = "\(environment.strings.Gift_Send_Send) \(amountString)"
|
||||||
|
case let .starGift(starGift):
|
||||||
|
let amountString = presentationStringsFormattedNumber(Int32(starGift.price), presentationData.dateTimeFormat.groupingSeparator)
|
||||||
|
buttonString = "\(environment.strings.Gift_Send_Send) # \(amountString)"
|
||||||
|
}
|
||||||
|
|
||||||
|
let buttonAttributedString = NSMutableAttributedString(string: buttonString, font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
||||||
if let range = buttonAttributedString.string.range(of: "#"), let starImage = self.starImage?.0 {
|
if let range = buttonAttributedString.string.range(of: "#"), let starImage = self.starImage?.0 {
|
||||||
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: environment.theme.list.itemCheckColors.foregroundColor, range: NSRange(range, in: buttonAttributedString.string))
|
buttonAttributedString.addAttribute(.foregroundColor, value: environment.theme.list.itemCheckColors.foregroundColor, range: NSRange(range, in: buttonAttributedString.string))
|
||||||
@ -669,7 +811,7 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))
|
component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))
|
||||||
),
|
),
|
||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
displaysProgress: false,
|
displaysProgress: self.inProgress,
|
||||||
action: { [weak self] in
|
action: { [weak self] in
|
||||||
self?.proceed()
|
self?.proceed()
|
||||||
}
|
}
|
||||||
@ -1039,12 +1181,17 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class GiftSetupScreen: ViewControllerComponentContainer {
|
public final class GiftSetupScreen: ViewControllerComponentContainer {
|
||||||
|
public enum Subject: Equatable {
|
||||||
|
case premium(PremiumGiftProduct)
|
||||||
|
case starGift(StarGift)
|
||||||
|
}
|
||||||
|
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
peerId: EnginePeer.Id,
|
peerId: EnginePeer.Id,
|
||||||
gift: StarGift,
|
subject: Subject,
|
||||||
completion: (() -> Void)? = nil
|
completion: (() -> Void)? = nil
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -1052,7 +1199,7 @@ public final class GiftSetupScreen: ViewControllerComponentContainer {
|
|||||||
super.init(context: context, component: GiftSetupScreenComponent(
|
super.init(context: context, component: GiftSetupScreenComponent(
|
||||||
context: context,
|
context: context,
|
||||||
peerId: peerId,
|
peerId: peerId,
|
||||||
gift: gift,
|
subject: subject,
|
||||||
completion: completion
|
completion: completion
|
||||||
), navigationBarAppearance: .default, theme: .default, updatedPresentationData: nil)
|
), navigationBarAppearance: .default, theme: .default, updatedPresentationData: nil)
|
||||||
|
|
||||||
@ -1105,3 +1252,31 @@ private struct GiftConfiguration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct PremiumGiftProduct: Equatable {
|
||||||
|
public let giftOption: CachedPremiumGiftOption
|
||||||
|
public let storeProduct: InAppPurchaseManager.Product?
|
||||||
|
public let discount: Int?
|
||||||
|
|
||||||
|
public var id: String {
|
||||||
|
return self.storeProduct?.id ?? (self.giftOption.storeProductId ?? "")
|
||||||
|
}
|
||||||
|
|
||||||
|
public var months: Int32 {
|
||||||
|
return self.giftOption.months
|
||||||
|
}
|
||||||
|
|
||||||
|
public var price: String {
|
||||||
|
return self.storeProduct?.price ?? formatCurrencyAmount(self.giftOption.amount, currency: self.giftOption.currency)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var pricePerMonth: String {
|
||||||
|
return self.storeProduct?.pricePerMonth(Int(self.months)) ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(giftOption: CachedPremiumGiftOption, storeProduct: InAppPurchaseManager.Product?, discount: Int?) {
|
||||||
|
self.giftOption = giftOption
|
||||||
|
self.storeProduct = storeProduct
|
||||||
|
self.discount = discount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -235,11 +235,13 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
descriptionText = modifiedString
|
descriptionText = modifiedString
|
||||||
}
|
}
|
||||||
|
|
||||||
let formattedAmount = presentationStringsFormattedNumber(abs(Int32(stars)), dateTimeFormat.groupingSeparator)
|
var formattedAmount = presentationStringsFormattedNumber(abs(Int32(stars)), dateTimeFormat.groupingSeparator)
|
||||||
|
if !incoming && stars > 0 {
|
||||||
|
formattedAmount = "- \(formattedAmount)"
|
||||||
|
}
|
||||||
let countFont: UIFont = Font.semibold(17.0)
|
let countFont: UIFont = Font.semibold(17.0)
|
||||||
let amountText = formattedAmount
|
let amountText = formattedAmount
|
||||||
let countColor = theme.list.itemDisclosureActions.constructive.fillColor
|
let countColor = incoming ? theme.list.itemDisclosureActions.constructive.fillColor : theme.list.itemDestructiveColor
|
||||||
|
|
||||||
|
|
||||||
let title = title.update(
|
let title = title.update(
|
||||||
component: MultilineTextComponent(
|
component: MultilineTextComponent(
|
||||||
@ -344,7 +346,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
id: "availability",
|
id: "availability",
|
||||||
title: strings.Gift_View_Availability,
|
title: strings.Gift_View_Availability,
|
||||||
component: AnyComponent(
|
component: AnyComponent(
|
||||||
MultilineTextComponent(text: .plain(NSAttributedString(string: "\(remains) of \(limitTotal)", font: tableFont, textColor: tableTextColor)))
|
MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Gift_View_Availability_Of("\(remains)", "\(limitTotal)").string, font: tableFont, textColor: tableTextColor)))
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import TelegramPresentationData
|
|||||||
import AnimationUI
|
import AnimationUI
|
||||||
import Display
|
import Display
|
||||||
|
|
||||||
class DynamicIslandMaskNode: ASDisplayNode {
|
final class DynamicIslandMaskNode: ASDisplayNode {
|
||||||
var animationNode: AnimationNode?
|
var animationNode: AnimationNode?
|
||||||
|
|
||||||
var isForum = false {
|
var isForum = false {
|
||||||
@ -39,7 +39,7 @@ class DynamicIslandMaskNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DynamicIslandBlurNode: ASDisplayNode {
|
final class DynamicIslandBlurNode: ASDisplayNode {
|
||||||
private var effectView: UIVisualEffectView?
|
private var effectView: UIVisualEffectView?
|
||||||
private let fadeNode = ASDisplayNode()
|
private let fadeNode = ASDisplayNode()
|
||||||
let gradientNode = ASImageNode()
|
let gradientNode = ASImageNode()
|
||||||
|
|||||||
@ -1172,7 +1172,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
strongSelf.push(wallpaperPreviewController)
|
strongSelf.push(wallpaperPreviewController)
|
||||||
return true
|
return true
|
||||||
case let .giftPremium(_, _, duration, _, _):
|
case let .giftPremium(_, _, duration, _, _, _, _):
|
||||||
strongSelf.chatDisplayNode.dismissInput()
|
strongSelf.chatDisplayNode.dismissInput()
|
||||||
let fromPeerId: PeerId = message.author?.id == strongSelf.context.account.peerId ? strongSelf.context.account.peerId : message.id.peerId
|
let fromPeerId: PeerId = message.author?.id == strongSelf.context.account.peerId ? strongSelf.context.account.peerId : message.id.peerId
|
||||||
let toPeerId: PeerId = message.author?.id == strongSelf.context.account.peerId ? message.id.peerId : strongSelf.context.account.peerId
|
let toPeerId: PeerId = message.author?.id == strongSelf.context.account.peerId ? message.id.peerId : strongSelf.context.account.peerId
|
||||||
@ -1187,7 +1187,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let controller = strongSelf.context.sharedContext.makeStarsGiftScreen(context: strongSelf.context, message: EngineMessage(message))
|
let controller = strongSelf.context.sharedContext.makeStarsGiftScreen(context: strongSelf.context, message: EngineMessage(message))
|
||||||
strongSelf.push(controller)
|
strongSelf.push(controller)
|
||||||
return true
|
return true
|
||||||
case let .giftCode(slug, _, _, _, _, _, _, _, _):
|
case let .giftCode(slug, _, _, _, _, _, _, _, _, _, _):
|
||||||
strongSelf.openResolved(result: .premiumGiftCode(slug: slug), sourceMessageId: message.id, progress: params.progress)
|
strongSelf.openResolved(result: .premiumGiftCode(slug: slug), sourceMessageId: message.id, progress: params.progress)
|
||||||
return true
|
return true
|
||||||
case .prizeStars:
|
case .prizeStars:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user