mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Various improvements
This commit is contained in:
parent
cefc76d4fc
commit
72c58813a8
@ -14870,3 +14870,9 @@ Sorry for the inconvenience.";
|
||||
"Stories.Post.AlbumCount_any" = "%@ Albums";
|
||||
|
||||
"Gift.Options.Gift.Premium" = "premium";
|
||||
|
||||
"Stars.Transaction.FragmentTopUpTon.Title" = "TON Top-Up";
|
||||
"Stars.Transaction.FragmentWithdrawalTon.Title" = "TON Withdrawal";
|
||||
|
||||
"Stars.Transaction.SearchFee.Title" = "Extra Search Fee";
|
||||
"Stars.Intro.Transaction.SearchFee" = "Extra Search Fee";
|
||||
|
@ -277,7 +277,7 @@ final class ChatListNoticeItemNode: ItemListRevealOptionsItemNode {
|
||||
case let .starsSubscriptionLowBalance(amount, peers):
|
||||
let title: String
|
||||
let text: String
|
||||
let starsValue = item.strings.ChatList_SubscriptionsLowBalance_Stars(Int32(amount.value))
|
||||
let starsValue = item.strings.ChatList_SubscriptionsLowBalance_Stars(Int32(clamping: amount.value))
|
||||
if let peer = peers.first, peers.count == 1 {
|
||||
title = item.strings.ChatList_SubscriptionsLowBalance_Single_Title(starsValue, peer.compactDisplayTitle).string
|
||||
text = item.strings.ChatList_SubscriptionsLowBalance_Single_Text
|
||||
|
@ -592,7 +592,7 @@ final class ChatSendMessageContextScreenComponent: Component {
|
||||
let titleLayout: ContextMenuActionItemTextLayout
|
||||
if let currentPrice {
|
||||
title = environment.strings.Attachment_Paid_EditPrice
|
||||
titleLayout = .secondLineWithValue(environment.strings.Attachment_Paid_EditPrice_Stars(Int32(currentPrice)))
|
||||
titleLayout = .secondLineWithValue(environment.strings.Attachment_Paid_EditPrice_Stars(Int32(clamping: currentPrice)))
|
||||
} else {
|
||||
title = environment.strings.Attachment_Paid_Create
|
||||
titleLayout = .twoLinesMax
|
||||
|
@ -2799,7 +2799,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
||||
let titleLayout: ContextMenuActionItemTextLayout
|
||||
if let price {
|
||||
title = strings.Attachment_Paid_EditPrice
|
||||
titleLayout = .secondLineWithValue(strings.Attachment_Paid_EditPrice_Stars(Int32(price)))
|
||||
titleLayout = .secondLineWithValue(strings.Attachment_Paid_EditPrice_Stars(Int32(clamping: price)))
|
||||
} else {
|
||||
title = strings.Attachment_Paid_Create
|
||||
titleLayout = .twoLinesMax
|
||||
|
@ -793,7 +793,7 @@ private func createGiveawayControllerEntries(
|
||||
if !state.starsExpanded && product.giveawayOption.isExtended {
|
||||
continue
|
||||
}
|
||||
let giftTitle: String = presentationData.strings.BoostGift_Stars_Stars(Int32(product.giveawayOption.count))
|
||||
let giftTitle: String = presentationData.strings.BoostGift_Stars_Stars(Int32(clamping: product.giveawayOption.count))
|
||||
let maxWinners = product.giveawayOption.winners.sorted(by: { $0.users < $1.users }).last?.users ?? 1
|
||||
|
||||
let starsPerUser: Int64
|
||||
@ -951,7 +951,7 @@ private func createGiveawayControllerEntries(
|
||||
entries.append(.prizeDescriptionText(presentationData.theme, presentationData.strings.BoostGift_AdditionalPrizesPlaceholder, state.prizeDescription, state.subscriptions))
|
||||
|
||||
if state.mode == .starsGiveaway {
|
||||
let starsString = presentationData.strings.BoostGift_AdditionalPrizesInfoStars(Int32(state.stars))
|
||||
let starsString = presentationData.strings.BoostGift_AdditionalPrizesInfoStars(Int32(clamping: state.stars))
|
||||
if state.prizeDescription.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
prizeDescriptionInfoText = presentationData.strings.BoostGift_AdditionalPrizesInfoStarsOn(starsString, "").string
|
||||
} else {
|
||||
|
@ -154,7 +154,7 @@ public func presentGiveawayInfoController(
|
||||
|
||||
let intro: String
|
||||
if stars > 0 {
|
||||
let starsString = presentationData.strings.Chat_Giveaway_Info_Stars_Stars(Int32(stars))
|
||||
let starsString = presentationData.strings.Chat_Giveaway_Info_Stars_Stars(Int32(clamping: stars))
|
||||
if case .almostOver = status {
|
||||
if isGroup {
|
||||
intro = presentationData.strings.Chat_Giveaway_Info_Stars_Group_EndedIntro(peerName, starsString).string
|
||||
@ -280,7 +280,7 @@ public func presentGiveawayInfoController(
|
||||
|
||||
let intro: String
|
||||
if stars > 0 {
|
||||
let starsString = presentationData.strings.Chat_Giveaway_Info_Stars_Stars(Int32(stars))
|
||||
let starsString = presentationData.strings.Chat_Giveaway_Info_Stars_Stars(Int32(clamping: stars))
|
||||
if isGroup {
|
||||
intro = presentationData.strings.Chat_Giveaway_Info_Stars_Group_EndedIntro(peerName, starsString).string
|
||||
} else {
|
||||
|
@ -931,10 +931,10 @@ struct PremiumIntroConfiguration {
|
||||
|
||||
private struct PremiumProduct: Equatable {
|
||||
let option: PremiumPromoConfiguration.PremiumProductOption
|
||||
let storeProduct: InAppPurchaseManager.Product
|
||||
let storeProduct: InAppPurchaseManager.Product?
|
||||
|
||||
var id: String {
|
||||
return self.option.storeProductId ?? self.storeProduct.id
|
||||
return self.storeProduct?.id ?? self.option.botUrl
|
||||
}
|
||||
|
||||
var months: Int32 {
|
||||
@ -942,11 +942,39 @@ private struct PremiumProduct: Equatable {
|
||||
}
|
||||
|
||||
var price: String {
|
||||
return self.storeProduct.price
|
||||
if let storeProduct = self.storeProduct {
|
||||
return storeProduct.price
|
||||
} else {
|
||||
return formatCurrencyAmount(self.option.amount, currency: self.option.currency)
|
||||
}
|
||||
}
|
||||
|
||||
var pricePerMonth: String {
|
||||
return self.storeProduct.pricePerMonth(Int(self.months))
|
||||
if let storeProduct = self.storeProduct {
|
||||
return storeProduct.pricePerMonth(Int(self.months))
|
||||
} else {
|
||||
return formatCurrencyAmount(self.option.amount / Int64(self.months), currency: self.option.currency)
|
||||
}
|
||||
}
|
||||
|
||||
var priceCurrencyAndAmount: (currency: String, amount: Int64) {
|
||||
if let priceCurrencyAndAmount = self.storeProduct?.priceCurrencyAndAmount {
|
||||
return priceCurrencyAndAmount
|
||||
} else {
|
||||
return (self.option.currency, self.option.amount)
|
||||
}
|
||||
}
|
||||
|
||||
var priceValue: NSDecimalNumber {
|
||||
if let priceValue = self.storeProduct?.priceValue {
|
||||
return priceValue
|
||||
} else {
|
||||
return self.optionPriceValue
|
||||
}
|
||||
}
|
||||
|
||||
var optionPriceValue: NSDecimalNumber {
|
||||
return currencyToFractionalAmount(value: self.option.amount, currency: self.option.currency).flatMap { NSDecimalNumber(floatLiteral: $0) } ?? 0.0
|
||||
}
|
||||
|
||||
var isCurrent: Bool {
|
||||
@ -1552,7 +1580,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
}
|
||||
|
||||
var isBiannual: Bool {
|
||||
return self.products?.first(where: { $0.id == self.selectedProductId })?.id.hasSuffix(".biannual") ?? false
|
||||
return self.products?.first(where: { $0.id == self.selectedProductId })?.months == 24
|
||||
}
|
||||
|
||||
var canUpgrade: Bool {
|
||||
@ -1957,15 +1985,23 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
if let products = state.products, products.count > 1, state.isPremium == false || (!context.component.justBought && state.canUpgrade) {
|
||||
var optionsItems: [SectionGroupComponent.Item] = []
|
||||
|
||||
let shortestOptionPrice: (Int64, NSDecimalNumber)
|
||||
let shortestProductPrice: (Int64, NSDecimalNumber)
|
||||
if let product = products.first(where: { $0.id.hasSuffix(".monthly") }) {
|
||||
shortestOptionPrice = (Int64(Float(product.storeProduct.priceCurrencyAndAmount.amount)), product.storeProduct.priceValue)
|
||||
shortestProductPrice = (Int64(Float(product.priceCurrencyAndAmount.amount)), product.priceValue)
|
||||
} else {
|
||||
shortestOptionPrice = (1, NSDecimalNumber(decimal: 1))
|
||||
shortestProductPrice = (1, NSDecimalNumber(decimal: 1))
|
||||
}
|
||||
|
||||
let currentProductMonths = state.products?.first(where: { $0.isCurrent })?.months ?? 0
|
||||
|
||||
var referenceProduct: InAppPurchaseManager.Product?
|
||||
for product in products {
|
||||
if let storeProduct = product.storeProduct {
|
||||
referenceProduct = storeProduct
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var i = 0
|
||||
for product in products {
|
||||
let giftTitle: String
|
||||
@ -1973,13 +2009,13 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
giftTitle = strings.Premium_Monthly
|
||||
} else if product.id.hasSuffix(".semiannual") {
|
||||
giftTitle = strings.Premium_Semiannual
|
||||
} else if product.id.hasSuffix(".biannual") {
|
||||
} else if product.months == 24 {
|
||||
giftTitle = strings.Premium_Biannual
|
||||
} else {
|
||||
giftTitle = strings.Premium_Annual
|
||||
}
|
||||
|
||||
let fraction = Float(product.storeProduct.priceCurrencyAndAmount.amount) / Float(product.months) / Float(shortestOptionPrice.0)
|
||||
let fraction = Float(product.priceCurrencyAndAmount.amount) / Float(product.months) / Float(shortestProductPrice.0)
|
||||
let discountValue = Int(round((1.0 - fraction) * 20.0) * 5.0)
|
||||
let discount: String
|
||||
if discountValue > 0 {
|
||||
@ -1988,13 +2024,16 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
discount = ""
|
||||
}
|
||||
|
||||
let defaultPrice = product.storeProduct.defaultPrice(shortestOptionPrice.1, monthsCount: Int(product.months))
|
||||
var defaultPrice: String = ""
|
||||
if let referenceProduct {
|
||||
defaultPrice = referenceProduct.defaultPrice(shortestProductPrice.1, monthsCount: Int(product.months))
|
||||
}
|
||||
|
||||
var subtitle = ""
|
||||
var accessibilitySubtitle = ""
|
||||
var pricePerMonth = product.price
|
||||
if product.months > 1 {
|
||||
pricePerMonth = product.storeProduct.pricePerMonth(Int(product.months))
|
||||
pricePerMonth = product.pricePerMonth
|
||||
|
||||
if discountValue > 0 {
|
||||
subtitle = "**\(defaultPrice)** \(product.price)"
|
||||
@ -2964,6 +3003,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
private let source: PremiumSource
|
||||
private let updateInProgress: (Bool) -> Void
|
||||
private let present: (ViewController) -> Void
|
||||
var navigationController: (() -> NavigationController?)?
|
||||
private let completion: () -> Void
|
||||
|
||||
var topContentOffset: CGFloat?
|
||||
@ -2987,7 +3027,6 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
var emojiPackTitle: String?
|
||||
private var emojiFileDisposable: Disposable?
|
||||
|
||||
|
||||
private var disposable: Disposable?
|
||||
private var paymentDisposable = MetaDisposable()
|
||||
private var activationDisposable = MetaDisposable()
|
||||
@ -3002,7 +3041,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
}
|
||||
|
||||
var isBiannual: Bool {
|
||||
return self.products?.first(where: { $0.id == self.selectedProductId })?.id.hasSuffix(".biannual") ?? false
|
||||
return self.products?.first(where: { $0.id == self.selectedProductId })?.months == 24
|
||||
}
|
||||
|
||||
var canUpgrade: Bool {
|
||||
@ -3017,7 +3056,14 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
}
|
||||
}
|
||||
|
||||
init(screenContext: PremiumIntroScreen.ScreenContext, source: PremiumSource, forceHasPremium: Bool, updateInProgress: @escaping (Bool) -> Void, present: @escaping (ViewController) -> Void, completion: @escaping () -> Void) {
|
||||
init(
|
||||
screenContext: PremiumIntroScreen.ScreenContext,
|
||||
source: PremiumSource,
|
||||
forceHasPremium: Bool,
|
||||
updateInProgress: @escaping (Bool) -> Void,
|
||||
present: @escaping (ViewController) -> Void,
|
||||
completion: @escaping () -> Void
|
||||
) {
|
||||
self.screenContext = screenContext
|
||||
self.source = source
|
||||
self.updateInProgress = updateInProgress
|
||||
@ -3093,6 +3139,8 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
for option in promoConfiguration.premiumProductOptions {
|
||||
if let product = availableProducts.first(where: { $0.id == option.storeProductId }), product.isSubscription {
|
||||
products.append(PremiumProduct(option: option, storeProduct: product))
|
||||
} else {
|
||||
products.append(PremiumProduct(option: option, storeProduct: nil))
|
||||
}
|
||||
}
|
||||
|
||||
@ -3219,117 +3267,127 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
self.updateInProgress(true)
|
||||
self.updated(transition: .immediate)
|
||||
|
||||
let purpose: AppStoreTransactionPurpose = isUpgrade ? .upgrade : .subscription
|
||||
if let storeProduct = premiumProduct.storeProduct {
|
||||
let purpose: AppStoreTransactionPurpose = isUpgrade ? .upgrade : .subscription
|
||||
|
||||
let canPurchasePremium: Signal<Bool, NoError>
|
||||
switch self.screenContext {
|
||||
case let .accountContext(context):
|
||||
canPurchasePremium = context.engine.payments.canPurchasePremium(purpose: purpose)
|
||||
case let .sharedContext(_, engine, _):
|
||||
canPurchasePremium = engine.payments.canPurchasePremium(purpose: purpose)
|
||||
}
|
||||
let _ = (canPurchasePremium
|
||||
|> deliverOnMainQueue).start(next: { [weak self] available in
|
||||
guard let self else {
|
||||
return
|
||||
let canPurchasePremium: Signal<Bool, NoError>
|
||||
switch self.screenContext {
|
||||
case let .accountContext(context):
|
||||
canPurchasePremium = context.engine.payments.canPurchasePremium(purpose: purpose)
|
||||
case let .sharedContext(_, engine, _):
|
||||
canPurchasePremium = engine.payments.canPurchasePremium(purpose: purpose)
|
||||
}
|
||||
if available {
|
||||
self.paymentDisposable.set((inAppPurchaseManager.buyProduct(premiumProduct.storeProduct, purpose: purpose)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
if let self, case .purchased = status {
|
||||
let activation: Signal<Never, AssignAppStoreTransactionError>
|
||||
if let context = self.screenContext.context {
|
||||
activation = context.account.postbox.peerView(id: context.account.peerId)
|
||||
|> castError(AssignAppStoreTransactionError.self)
|
||||
|> take(until: { view in
|
||||
if let peer = view.peers[view.peerId], peer.isPremium {
|
||||
return SignalTakeAction(passthrough: false, complete: true)
|
||||
} else {
|
||||
return SignalTakeAction(passthrough: false, complete: false)
|
||||
let _ = (canPurchasePremium
|
||||
|> deliverOnMainQueue).start(next: { [weak self] available in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if available {
|
||||
self.paymentDisposable.set((inAppPurchaseManager.buyProduct(storeProduct, purpose: purpose)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
if let self, case .purchased = status {
|
||||
let activation: Signal<Never, AssignAppStoreTransactionError>
|
||||
if let context = self.screenContext.context {
|
||||
activation = context.account.postbox.peerView(id: context.account.peerId)
|
||||
|> castError(AssignAppStoreTransactionError.self)
|
||||
|> take(until: { view in
|
||||
if let peer = view.peers[view.peerId], peer.isPremium {
|
||||
return SignalTakeAction(passthrough: false, complete: true)
|
||||
} else {
|
||||
return SignalTakeAction(passthrough: false, complete: false)
|
||||
}
|
||||
})
|
||||
|> mapToSignal { _ -> Signal<Never, AssignAppStoreTransactionError> in
|
||||
return .never()
|
||||
}
|
||||
})
|
||||
|> mapToSignal { _ -> Signal<Never, AssignAppStoreTransactionError> in
|
||||
return .never()
|
||||
|> timeout(15.0, queue: Queue.mainQueue(), alternate: .fail(.timeout))
|
||||
} else {
|
||||
activation = .complete()
|
||||
}
|
||||
|> timeout(15.0, queue: Queue.mainQueue(), alternate: .fail(.timeout))
|
||||
} else {
|
||||
activation = .complete()
|
||||
}
|
||||
|
||||
self.activationDisposable.set((activation
|
||||
|> deliverOnMainQueue).start(error: { [weak self] _ in
|
||||
if let self {
|
||||
self.activationDisposable.set((activation
|
||||
|> deliverOnMainQueue).start(error: { [weak self] _ in
|
||||
if let self {
|
||||
self.inProgress = false
|
||||
self.updateInProgress(false)
|
||||
|
||||
self.updated(transition: .immediate)
|
||||
|
||||
if let context = self.screenContext.context {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "premium.promo_screen_fail")
|
||||
}
|
||||
|
||||
let errorText = presentationData.strings.Premium_Purchase_ErrorUnknown
|
||||
let alertController = textAlertController(sharedContext: self.screenContext.sharedContext, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
|
||||
self.present(alertController)
|
||||
}
|
||||
}, completed: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let context = self.screenContext.context {
|
||||
let _ = updatePremiumPromoConfigurationOnce(account: context.account).start()
|
||||
}
|
||||
self.inProgress = false
|
||||
self.updateInProgress(false)
|
||||
|
||||
self.updated(transition: .immediate)
|
||||
self.isPremium = true
|
||||
self.justBought = true
|
||||
|
||||
if let context = self.screenContext.context {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "premium.promo_screen_fail")
|
||||
}
|
||||
self.updated(transition: .easeInOut(duration: 0.25))
|
||||
self.completion()
|
||||
}))
|
||||
}
|
||||
}, error: { [weak self] error in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.inProgress = false
|
||||
self.updateInProgress(false)
|
||||
self.updated(transition: .immediate)
|
||||
|
||||
let errorText = presentationData.strings.Premium_Purchase_ErrorUnknown
|
||||
let alertController = textAlertController(sharedContext: self.screenContext.sharedContext, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
|
||||
self.present(alertController)
|
||||
}
|
||||
}, completed: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
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 = errorText {
|
||||
if let context = self.screenContext.context {
|
||||
let _ = updatePremiumPromoConfigurationOnce(account: context.account).start()
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "premium.promo_screen_fail")
|
||||
}
|
||||
self.inProgress = false
|
||||
self.updateInProgress(false)
|
||||
|
||||
self.isPremium = true
|
||||
self.justBought = true
|
||||
|
||||
self.updated(transition: .easeInOut(duration: 0.25))
|
||||
self.completion()
|
||||
}))
|
||||
}
|
||||
}, error: { [weak self] error in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let alertController = textAlertController(sharedContext: self.screenContext.sharedContext, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
|
||||
self.present(alertController)
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
self.inProgress = false
|
||||
self.updateInProgress(false)
|
||||
self.updated(transition: .immediate)
|
||||
}
|
||||
})
|
||||
} else if case let .accountContext(context) = self.screenContext, let navigationController = self.navigationController?() {
|
||||
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: premiumProduct.option.botUrl, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {})
|
||||
|
||||
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 = errorText {
|
||||
if let context = self.screenContext.context {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "premium.promo_screen_fail")
|
||||
}
|
||||
|
||||
let alertController = textAlertController(sharedContext: self.screenContext.sharedContext, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
|
||||
self.present(alertController)
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
Queue.mainQueue().after(3.0) {
|
||||
self.inProgress = false
|
||||
self.updateInProgress(false)
|
||||
self.updated(transition: .immediate)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func updateIsFocused(_ isFocused: Bool) {
|
||||
@ -3366,6 +3424,9 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
return { context in
|
||||
let environment = context.environment[EnvironmentType.self].value
|
||||
let state = context.state
|
||||
state.navigationController = { [weak environment] in
|
||||
return environment?.controller()?.navigationController as? NavigationController
|
||||
}
|
||||
|
||||
let background = background.update(component: Rectangle(color: environment.theme.list.blocksBackgroundColor), environment: {}, availableSize: context.availableSize, transition: context.transition)
|
||||
|
||||
|
@ -1019,7 +1019,7 @@ private enum StatsEntry: ItemListNodeEntry {
|
||||
icon = .image(color: color, name: "Premium/Unclaimed")
|
||||
} else if boost.flags.contains(.isGiveaway) {
|
||||
if let stars = boost.stars {
|
||||
title = presentationData.strings.Stats_Boosts_Stars(Int32(stars))
|
||||
title = presentationData.strings.Stats_Boosts_Stars(Int32(clamping: stars))
|
||||
icon = .image(color: .stars, name: "Premium/PremiumStar")
|
||||
expiresString = expiresValue
|
||||
} else {
|
||||
@ -1476,7 +1476,7 @@ private func boostsEntries(
|
||||
title = presentationData.strings.Stats_Boosts_PrepaidGiveawayCount(giveaway.quantity)
|
||||
text = presentationData.strings.Stats_Boosts_PrepaidGiveawayMonths("\(months)").string
|
||||
case let .stars(stars, _):
|
||||
title = presentationData.strings.Stats_Boosts_Stars(Int32(stars))
|
||||
title = presentationData.strings.Stats_Boosts_Stars(Int32(clamping: stars))
|
||||
text = presentationData.strings.Stats_Boosts_StarsWinners(giveaway.quantity)
|
||||
}
|
||||
entries.append(.boostPrepaid(i, presentationData.theme, title, text, giveaway))
|
||||
|
@ -347,7 +347,7 @@ final class StarsTransactionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
theme: item.presentationData.theme,
|
||||
title: AnyComponent(VStack(titleComponents, alignment: .left, spacing: 2.0)),
|
||||
contentInsets: UIEdgeInsets(top: 9.0, left: 0.0, bottom: 8.0, right: 0.0),
|
||||
leftIcon: .custom(AnyComponentWithIdentity(id: "avatar", component: AnyComponent(StarsAvatarComponent(context: item.context, theme: item.presentationData.theme, peer: item.transaction.peer, photo: nil, media: [], uniqueGift: nil, backgroundColor: item.presentationData.theme.list.itemBlocksBackgroundColor))), false),
|
||||
leftIcon: .custom(AnyComponentWithIdentity(id: "avatar", component: AnyComponent(StarsAvatarComponent(context: item.context, theme: item.presentationData.theme, peer: .transactionPeer(item.transaction.peer), photo: nil, media: [], uniqueGift: nil, backgroundColor: item.presentationData.theme.list.itemBlocksBackgroundColor))), false),
|
||||
icon: nil,
|
||||
accessory: .custom(ListActionItemComponent.CustomAccessory(component: AnyComponentWithIdentity(id: "label", component: AnyComponent(StarsLabelComponent(text: itemLabel, iconName: itemIconName, iconColor: itemIconColor))), insets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 16.0))),
|
||||
action: { [weak self] _ in
|
||||
|
@ -720,6 +720,9 @@ private extension StarsContext.State.Transaction {
|
||||
if (apiFlags & (1 << 22)) != 0 {
|
||||
flags.insert(.isStarGiftResale)
|
||||
}
|
||||
if (apiFlags & (1 << 24)) != 0 {
|
||||
flags.insert(.isPostsSearch)
|
||||
}
|
||||
|
||||
let media = extendedMedia.flatMap({ $0.compactMap { textMediaAndExpirationTimerFromApiMedia($0, PeerId(0)).media } }) ?? []
|
||||
let _ = subscriptionPeriod
|
||||
@ -774,6 +777,7 @@ public final class StarsContext {
|
||||
public static let isPaidMessage = Flags(rawValue: 1 << 7)
|
||||
public static let isBusinessTransfer = Flags(rawValue: 1 << 8)
|
||||
public static let isStarGiftResale = Flags(rawValue: 1 << 9)
|
||||
public static let isPostsSearch = Flags(rawValue: 1 << 10)
|
||||
}
|
||||
|
||||
public enum Peer: Equatable {
|
||||
|
@ -96,7 +96,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? PaidStarsMessageAttribute {
|
||||
let messageCount = Int32(messageCount ?? 1)
|
||||
let price = strings.Notification_PaidMessage_Stars(Int32(attribute.stars.value) * messageCount)
|
||||
let price = strings.Notification_PaidMessage_Stars(Int32(clamping: attribute.stars.value) * messageCount)
|
||||
if message.author?.id == accountPeerId {
|
||||
if messageCount > 1 {
|
||||
let messagesString = strings.Notification_PaidMessage_Messages(messageCount)
|
||||
@ -1048,7 +1048,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
}
|
||||
let resultTitleString: PresentationStrings.FormattedString
|
||||
if let stars {
|
||||
let starsString = strings.Notification_StarsGiveawayStarted_Stars(Int32(stars))
|
||||
let starsString = strings.Notification_StarsGiveawayStarted_Stars(Int32(clamping: stars))
|
||||
resultTitleString = isGroup ? strings.Notification_StarsGiveawayStartedGroup(compactAuthorName, starsString) : strings.Notification_StarsGiveawayStarted(compactAuthorName, starsString)
|
||||
} else {
|
||||
resultTitleString = isGroup ? strings.Notification_GiveawayStartedGroup(compactAuthorName) : strings.Notification_GiveawayStarted(compactAuthorName)
|
||||
@ -1146,7 +1146,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
if let upgradeStars {
|
||||
finalPrice += upgradeStars
|
||||
}
|
||||
let starsPrice = strings.Notification_StarsGift_Stars(Int32(finalPrice))
|
||||
let starsPrice = strings.Notification_StarsGift_Stars(Int32(clamping: finalPrice))
|
||||
var authorName = compactAuthorName
|
||||
var peerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)]
|
||||
if message.id.peerId.namespace == Namespaces.Peer.CloudUser && message.id.peerId.id._internalGetInt64Value() == 777000 {
|
||||
@ -1207,7 +1207,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
let starsString: String
|
||||
switch resaleStars.currency {
|
||||
case .stars:
|
||||
starsString = strings.Notification_StarsGift_Bought_Stars(Int32(resaleStars.amount.value))
|
||||
starsString = strings.Notification_StarsGift_Bought_Stars(Int32(clamping: resaleStars.amount.value))
|
||||
case .ton:
|
||||
starsString = formatTonAmountText(resaleStars.amount.value, dateTimeFormat: dateTimeFormat) + " TON"
|
||||
}
|
||||
@ -1246,7 +1246,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
let starsString: String
|
||||
switch resaleStars.currency {
|
||||
case .stars:
|
||||
starsString = strings.Notification_StarsGift_Bought_Stars(Int32(resaleStars.amount.value))
|
||||
starsString = strings.Notification_StarsGift_Bought_Stars(Int32(clamping: resaleStars.amount.value))
|
||||
case .ton:
|
||||
starsString = formatTonAmountText(resaleStars.amount.value, dateTimeFormat: dateTimeFormat) + " TON"
|
||||
}
|
||||
@ -1262,7 +1262,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
}
|
||||
}
|
||||
case let .paidMessagesRefunded(_, stars):
|
||||
let starsString = strings.Notification_PaidMessageRefund_Stars(Int32(stars))
|
||||
let starsString = strings.Notification_PaidMessageRefund_Stars(Int32(clamping: stars))
|
||||
|
||||
var isOutgoing = false
|
||||
var messagePeer: EnginePeer?
|
||||
@ -1306,7 +1306,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: attributes)
|
||||
}
|
||||
case let .paidMessagesPriceEdited(stars, broadcastMessagesAllowed):
|
||||
let starsString = strings.Notification_PaidMessagePriceChanged_Stars(Int32(stars))
|
||||
let starsString = strings.Notification_PaidMessagePriceChanged_Stars(Int32(clamping: stars))
|
||||
if message.author?.id == accountPeerId {
|
||||
let resultString: PresentationStrings.FormattedString
|
||||
resultString = strings.Notification_PaidMessagePriceChangedYou(starsString)
|
||||
|
@ -503,7 +503,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
peerName = EnginePeer(channel).compactDisplayTitle
|
||||
}
|
||||
title = item.presentationData.strings.Notification_StarsGiveaway_Title
|
||||
let starsString = item.presentationData.strings.Notification_StarsGiveaway_Subtitle_Stars(Int32(count)).replacingOccurrences(of: " ", with: "\u{00A0}")
|
||||
let starsString = item.presentationData.strings.Notification_StarsGiveaway_Subtitle_Stars(Int32(clamping: count)).replacingOccurrences(of: " ", with: "\u{00A0}")
|
||||
text = item.presentationData.strings.Notification_StarsGiveaway_Subtitle(peerName, starsString).string
|
||||
case let .giftCode(_, fromGiveaway, unclaimed, channelId, monthsValue, _, _, _, _, giftText, giftEntities):
|
||||
if channelId == nil {
|
||||
@ -576,23 +576,23 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Upgraded
|
||||
} else if incoming {
|
||||
if converted {
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Converted(item.presentationData.strings.Notification_StarGift_Subtitle_Converted_Stars(Int32(convertStars ?? 0))).string
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Converted(item.presentationData.strings.Notification_StarGift_Subtitle_Converted_Stars(Int32(clamping: convertStars ?? 0))).string
|
||||
} else if upgradeStars != nil {
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Upgrade
|
||||
} else if isSelfGift && canUpgrade {
|
||||
text = item.presentationData.strings.Notification_StarsGift_Subtitle_Self
|
||||
} else if savedToProfile {
|
||||
if let convertStars {
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Displaying(item.presentationData.strings.Notification_StarGift_Subtitle_Displaying_Stars(Int32(convertStars))).string
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Displaying(item.presentationData.strings.Notification_StarGift_Subtitle_Displaying_Stars(Int32(clamping: convertStars))).string
|
||||
} else {
|
||||
text = item.presentationData.strings.Notification_StarGift_Bot_Subtitle_Displaying
|
||||
}
|
||||
} else {
|
||||
if let convertStars, convertStars > 0 {
|
||||
if isChannelGift {
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Channel(item.presentationData.strings.Notification_StarGift_Subtitle_Stars(Int32(convertStars))).string
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Channel(item.presentationData.strings.Notification_StarGift_Subtitle_Stars(Int32(clamping: convertStars))).string
|
||||
} else {
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle(item.presentationData.strings.Notification_StarGift_Subtitle_Stars(Int32(convertStars))).string
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle(item.presentationData.strings.Notification_StarGift_Subtitle_Stars(Int32(clamping: convertStars))).string
|
||||
}
|
||||
} else {
|
||||
text = item.presentationData.strings.Notification_StarGift_Bot_Subtitle
|
||||
@ -605,7 +605,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
if peerName.isEmpty {
|
||||
if let convertStars, convertStars > 0 {
|
||||
let starsString = item.presentationData.strings.Notification_StarGift_Subtitle_Stars(Int32(convertStars)).replacingOccurrences(of: " ", with: "\u{00A0}")
|
||||
let starsString = item.presentationData.strings.Notification_StarGift_Subtitle_Stars(Int32(clamping: convertStars)).replacingOccurrences(of: " ", with: "\u{00A0}")
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle(starsString).string
|
||||
} else {
|
||||
text = item.presentationData.strings.Notification_StarGift_Bot_Subtitle
|
||||
@ -614,7 +614,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
if upgradeStars != nil {
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Upgrade_Other(peerName).string
|
||||
} else if let convertStars, convertStars > 0 {
|
||||
let starsString = item.presentationData.strings.Notification_StarGift_Subtitle_Other_Stars(Int32(convertStars)).replacingOccurrences(of: " ", with: "\u{00A0}")
|
||||
let starsString = item.presentationData.strings.Notification_StarGift_Subtitle_Other_Stars(Int32(clamping: convertStars)).replacingOccurrences(of: " ", with: "\u{00A0}")
|
||||
let formattedString = item.presentationData.strings.Notification_StarGift_Subtitle_Other(peerName, starsString)
|
||||
text = formattedString.string
|
||||
if let starsRange = formattedString.ranges.last {
|
||||
|
@ -350,7 +350,7 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode,
|
||||
}
|
||||
), textAlignment: .center)
|
||||
case let .stars(amount):
|
||||
let starsString = item.presentationData.strings.Chat_Giveaway_Message_Stars_Stars(Int32(amount))
|
||||
let starsString = item.presentationData.strings.Chat_Giveaway_Message_Stars_Stars(Int32(clamping: amount))
|
||||
prizeTextString = parseMarkdownIntoAttributedString(item.presentationData.strings.Chat_Giveaway_Message_Stars_PrizeText(
|
||||
starsString,
|
||||
item.presentationData.strings.Chat_Giveaway_Message_Stars_Winners(giveaway.quantity)
|
||||
@ -468,7 +468,7 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode,
|
||||
dateTextString = NSAttributedString(string: stringForFullDate(timestamp: giveaway.untilDate, strings: item.presentationData.strings, dateTimeFormat: item.presentationData.dateTimeFormat), font: textFont, textColor: textColor)
|
||||
} else if let giveawayResults {
|
||||
if case let .stars(stars) = giveawayResults.prize {
|
||||
let starsString = item.presentationData.strings.Chat_Giveaway_Message_WinnersInfo_Stars(Int32(stars))
|
||||
let starsString = item.presentationData.strings.Chat_Giveaway_Message_WinnersInfo_Stars(Int32(clamping: stars))
|
||||
dateTextString = parseMarkdownIntoAttributedString(giveawayResults.winnersCount > 1 ? item.presentationData.strings.Chat_Giveaway_Message_WinnersInfo_Stars_Many(starsString).string : item.presentationData.strings.Chat_Giveaway_Message_WinnersInfo_Stars_One(starsString).string, attributes: MarkdownAttributes(
|
||||
body: MarkdownAttributeSet(font: textFont, textColor: textColor),
|
||||
bold: MarkdownAttributeSet(font: boldTextFont, textColor: textColor),
|
||||
|
@ -505,8 +505,8 @@ public func chatMessagePaymentAlertController(
|
||||
|
||||
let text: String
|
||||
if peers.count == 1, let peer = peers.first {
|
||||
let amountString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Stars(Int32(amount.value))
|
||||
let totalString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Stars(Int32(amount.value * Int64(count)))
|
||||
let amountString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Stars(Int32(clamping: amount.value))
|
||||
let totalString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Stars(Int32(clamping: amount.value * Int64(count)))
|
||||
if case let .channel(channel) = peer.chatOrMonoforumMainPeer, case .broadcast = channel.info {
|
||||
text = presentationData.strings.Chat_PaidMessage_Confirm_SingleComment_Text(EnginePeer(channel).compactDisplayTitle, amountString, totalString, messagesString).string
|
||||
} else {
|
||||
@ -515,7 +515,7 @@ public func chatMessagePaymentAlertController(
|
||||
} else {
|
||||
let amount = totalAmount ?? amount
|
||||
let usersString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Users(Int32(peers.count))
|
||||
let totalString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Stars(Int32(amount.value * Int64(count)))
|
||||
let totalString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Stars(Int32(clamping: amount.value * Int64(count)))
|
||||
text = presentationData.strings.Chat_PaidMessage_Confirm_Multiple_Text(usersString, totalString, messagesString).string
|
||||
}
|
||||
|
||||
@ -573,7 +573,7 @@ public func chatMessageRemovePaymentAlertController(
|
||||
text = strings.Chat_PaidMessage_RemoveFee_Text(peer.compactDisplayTitle).string
|
||||
}
|
||||
|
||||
let optionText = amount.flatMap { strings.Chat_PaidMessage_RemoveFee_Refund(strings.Chat_PaidMessage_RemoveFee_Refund_Stars(Int32($0.value))).string }
|
||||
let optionText = amount.flatMap { strings.Chat_PaidMessage_RemoveFee_Refund(strings.Chat_PaidMessage_RemoveFee_Refund_Stars(Int32(clamping: $0.value))).string }
|
||||
|
||||
let contentNode = ChatMessagePaymentAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, title: title, text: text, optionText: optionText, actions: actions, alignment: .horizontal)
|
||||
|
||||
|
@ -1866,7 +1866,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
switch component.initialData.subjectInitialData {
|
||||
case let .react(reactData):
|
||||
if let currentSentAmount = reactData.currentSentAmount {
|
||||
text = environment.strings.SendStarReactions_TextSentStars(Int32(currentSentAmount))
|
||||
text = environment.strings.SendStarReactions_TextSentStars(Int32(clamping: currentSentAmount))
|
||||
} else {
|
||||
text = environment.strings.SendStarReactions_TextGeneric(reactData.peer.debugDisplayTitle).string
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ final class GiftSetupScreenComponent: Component {
|
||||
title: environment.strings.Gift_Send_Premium_Confirmation_Title,
|
||||
text: environment.strings.Gift_Send_Premium_Confirmation_Text(
|
||||
peer.compactDisplayTitle,
|
||||
environment.strings.Gift_Send_Premium_Confirmation_Text_Stars(Int32(starsPrice))
|
||||
environment.strings.Gift_Send_Premium_Confirmation_Text_Stars(Int32(clamping: starsPrice))
|
||||
).string,
|
||||
actions: [
|
||||
TextAlertAction(type: .genericAction, title: environment.strings.Common_Cancel, action: {}),
|
||||
@ -427,7 +427,7 @@ final class GiftSetupScreenComponent: Component {
|
||||
file: starGift.file,
|
||||
loop: true,
|
||||
title: nil,
|
||||
text: presentationData.strings.Gift_Send_Success(self.peerMap[peerId]?.compactDisplayTitle ?? "", presentationData.strings.Gift_Send_Success_Stars(Int32(starGift.price))).string,
|
||||
text: presentationData.strings.Gift_Send_Success(self.peerMap[peerId]?.compactDisplayTitle ?? "", presentationData.strings.Gift_Send_Success_Stars(Int32(clamping: starGift.price))).string,
|
||||
undoText: nil,
|
||||
customAction: nil
|
||||
),
|
||||
|
@ -310,7 +310,7 @@ private final class GiftPurchaseAlertContentNode: AlertContentNode {
|
||||
if let resellPrice {
|
||||
switch resellPrice.currency {
|
||||
case .stars:
|
||||
priceString = self.strings.Gift_Buy_Confirm_Text_Stars(Int32(resellPrice.amount.value))
|
||||
priceString = self.strings.Gift_Buy_Confirm_Text_Stars(Int32(clamping: resellPrice.amount.value))
|
||||
case .ton:
|
||||
priceString = "**\(formatTonAmountText(resellPrice.amount.value, dateTimeFormat: presentationData.dateTimeFormat)) TON**"
|
||||
}
|
||||
|
@ -297,7 +297,7 @@ public func giftTransferAlertController(
|
||||
let text: String
|
||||
let buttonText: String
|
||||
if transferStars > 0 {
|
||||
text = strings.Gift_Transfer_Confirmation_Text("\(gift.title) #\(presentationStringsFormattedNumber(gift.number, presentationData.dateTimeFormat.groupingSeparator))", peer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), strings.Gift_Transfer_Confirmation_Text_Stars(Int32(transferStars))).string
|
||||
text = strings.Gift_Transfer_Confirmation_Text("\(gift.title) #\(presentationStringsFormattedNumber(gift.number, presentationData.dateTimeFormat.groupingSeparator))", peer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), strings.Gift_Transfer_Confirmation_Text_Stars(Int32(clamping: transferStars))).string
|
||||
buttonText = "\(strings.Gift_Transfer_Confirmation_Transfer) $ \(transferStars)"
|
||||
} else {
|
||||
text = strings.Gift_Transfer_Confirmation_TextFree("\(gift.title) #\(presentationStringsFormattedNumber(gift.number, presentationData.dateTimeFormat.groupingSeparator))", peer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder)).string
|
||||
|
@ -548,7 +548,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
|
||||
let text = presentationData.strings.Gift_Convert_Period_Text(
|
||||
fromPeerName,
|
||||
presentationData.strings.Gift_Convert_Period_Stars(Int32(convertStars)),
|
||||
presentationData.strings.Gift_Convert_Period_Stars(Int32(clamping: convertStars)),
|
||||
presentationData.strings.Gift_Convert_Period_Days(days)
|
||||
).string
|
||||
|
||||
@ -579,11 +579,11 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
let text: String
|
||||
if isChannelGift {
|
||||
text = presentationData.strings.Gift_Convert_Success_ChannelText(
|
||||
presentationData.strings.Gift_Convert_Success_ChannelText_Stars(Int32(convertStars))
|
||||
presentationData.strings.Gift_Convert_Success_ChannelText_Stars(Int32(clamping: convertStars))
|
||||
).string
|
||||
} else {
|
||||
text = presentationData.strings.Gift_Convert_Success_Text(
|
||||
presentationData.strings.Gift_Convert_Success_Text_Stars(Int32(convertStars))
|
||||
presentationData.strings.Gift_Convert_Success_Text_Stars(Int32(clamping: convertStars))
|
||||
).string
|
||||
if let starsContext = self.context.starsContext {
|
||||
navigationController.pushViewController(
|
||||
@ -932,7 +932,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
let priceString: String
|
||||
switch price.currency {
|
||||
case .stars:
|
||||
priceString = presentationData.strings.Gift_View_Resale_Relist_Success_Stars(Int32(price.amount.value))
|
||||
priceString = presentationData.strings.Gift_View_Resale_Relist_Success_Stars(Int32(clamping: price.amount.value))
|
||||
case .ton:
|
||||
priceString = formatTonAmountText(price.amount.value, dateTimeFormat: presentationData.dateTimeFormat, maxDecimalPositions: nil) + " TON"
|
||||
}
|
||||
@ -1257,7 +1257,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
let originalPriceString: String
|
||||
switch resellAmount.currency {
|
||||
case .stars:
|
||||
originalPriceString = presentationData.strings.Gift_Buy_ErrorPriceChanged_Text_Stars(Int32(resellAmount.amount.value))
|
||||
originalPriceString = presentationData.strings.Gift_Buy_ErrorPriceChanged_Text_Stars(Int32(clamping: resellAmount.amount.value))
|
||||
case .ton:
|
||||
originalPriceString = formatTonAmountText(resellAmount.amount.value, dateTimeFormat: presentationData.dateTimeFormat, maxDecimalPositions: nil) + " TON"
|
||||
}
|
||||
@ -1266,7 +1266,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
let buttonText: String
|
||||
switch newPrice.currency {
|
||||
case .stars:
|
||||
newPriceString = presentationData.strings.Gift_Buy_ErrorPriceChanged_Text_Stars(Int32(newPrice.amount.value))
|
||||
newPriceString = presentationData.strings.Gift_Buy_ErrorPriceChanged_Text_Stars(Int32(clamping: newPrice.amount.value))
|
||||
buttonText = presentationData.strings.Gift_Buy_Confirm_BuyFor(Int32(newPrice.amount.value))
|
||||
case .ton:
|
||||
let tonValueString = formatTonAmountText(newPrice.amount.value, dateTimeFormat: presentationData.dateTimeFormat, maxDecimalPositions: nil)
|
||||
@ -2246,10 +2246,10 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
descriptionText = strings.Gift_View_UpgradeDescription
|
||||
}
|
||||
} else {
|
||||
descriptionText = isChannelGift ? strings.Gift_View_KeepOrConvertDescription_Channel(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(convertStars))).string : strings.Gift_View_KeepOrConvertDescription(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(convertStars))).string
|
||||
descriptionText = isChannelGift ? strings.Gift_View_KeepOrConvertDescription_Channel(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(clamping: convertStars))).string : strings.Gift_View_KeepOrConvertDescription(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(clamping: convertStars))).string
|
||||
}
|
||||
} else {
|
||||
descriptionText = strings.Gift_View_ConvertedDescription(strings.Gift_View_ConvertedDescription_Stars(Int32(convertStars))).string
|
||||
descriptionText = strings.Gift_View_ConvertedDescription(strings.Gift_View_ConvertedDescription_Stars(Int32(clamping: convertStars))).string
|
||||
}
|
||||
} else {
|
||||
descriptionText = strings.Gift_View_BotDescription
|
||||
@ -2258,7 +2258,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
if let _ = upgradeStars {
|
||||
descriptionText = strings.Gift_View_FreeUpgradeOtherDescription(peer.compactDisplayTitle).string
|
||||
} else if case .message = subject, let convertStars {
|
||||
descriptionText = strings.Gift_View_OtherDescription(peer.compactDisplayTitle, strings.Gift_View_OtherDescription_Stars(Int32(convertStars))).string
|
||||
descriptionText = strings.Gift_View_OtherDescription(peer.compactDisplayTitle, strings.Gift_View_OtherDescription_Stars(Int32(clamping: convertStars))).string
|
||||
} else {
|
||||
descriptionText = ""
|
||||
}
|
||||
@ -3085,7 +3085,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
component: AnyComponent(Button(
|
||||
content: AnyComponent(ButtonContentComponent(
|
||||
context: component.context,
|
||||
text: strings.Gift_View_Sale(strings.Gift_View_Sale_Stars(Int32(convertStars))).string,
|
||||
text: strings.Gift_View_Sale(strings.Gift_View_Sale_Stars(Int32(clamping: convertStars))).string,
|
||||
color: theme.list.itemAccentColor
|
||||
)),
|
||||
action: { [weak state] in
|
||||
|
@ -174,7 +174,7 @@ private final class GiftWithdrawAlertContentNode: AlertContentNode {
|
||||
StarsAvatarComponent(
|
||||
context: self.context,
|
||||
theme: self.presentationTheme,
|
||||
peer: .fragment,
|
||||
peer: .transactionPeer(.fragment),
|
||||
photo: nil,
|
||||
media: [],
|
||||
uniqueGift: nil,
|
||||
|
@ -368,7 +368,7 @@ private class MessagePriceItemNode: ListViewItemNode {
|
||||
strongSelf.leftTextNode.attributedText = NSAttributedString(string: "\(item.minValue)", font: Font.regular(13.0), textColor: item.theme.list.itemSecondaryTextColor)
|
||||
strongSelf.rightTextNode.attributedText = NSAttributedString(string: "\(item.maxValue)", font: Font.regular(13.0), textColor: item.theme.list.itemSecondaryTextColor)
|
||||
|
||||
let centralLeftText = item.value == 0 ? item.strings.Stars_SendMessage_PriceFree : item.strings.Privacy_Messages_Stars(Int32(item.value))
|
||||
let centralLeftText = item.value == 0 ? item.strings.Stars_SendMessage_PriceFree : item.strings.Privacy_Messages_Stars(Int32(clamping: item.value))
|
||||
|
||||
strongSelf.centerLeftTextNode.attributedText = NSAttributedString(string: centralLeftText, font: textFont, textColor: item.openSetCustom != nil ? item.theme.list.itemAccentColor : item.theme.list.itemPrimaryTextColor)
|
||||
strongSelf.centerRightTextNode.attributedText = NSAttributedString(string: item.price, font: smallTextFont, textColor: item.openSetCustom != nil ? item.theme.list.itemAccentColor.withMultipliedAlpha(0.5) : item.theme.list.itemSecondaryTextColor)
|
||||
|
@ -14,9 +14,14 @@ import MultilineTextComponent
|
||||
import GiftItemComponent
|
||||
|
||||
public final class StarsAvatarComponent: Component {
|
||||
public enum Peer: Equatable {
|
||||
case transactionPeer(StarsContext.State.Transaction.Peer)
|
||||
case search
|
||||
}
|
||||
|
||||
let context: AccountContext
|
||||
let theme: PresentationTheme
|
||||
let peer: StarsContext.State.Transaction.Peer?
|
||||
let peer: StarsAvatarComponent.Peer?
|
||||
let photo: TelegramMediaWebFile?
|
||||
let media: [Media]
|
||||
let uniqueGift: StarGift.UniqueGift?
|
||||
@ -26,7 +31,7 @@ public final class StarsAvatarComponent: Component {
|
||||
public init(
|
||||
context: AccountContext,
|
||||
theme: PresentationTheme,
|
||||
peer: StarsContext.State.Transaction.Peer?,
|
||||
peer: StarsAvatarComponent.Peer?,
|
||||
photo: TelegramMediaWebFile?,
|
||||
media: [Media],
|
||||
uniqueGift: StarGift.UniqueGift?,
|
||||
@ -250,108 +255,125 @@ public final class StarsAvatarComponent: Component {
|
||||
switch component.peer {
|
||||
case .none:
|
||||
break
|
||||
case let .peer(peer):
|
||||
if !didSetup {
|
||||
self.avatarNode.setPeer(
|
||||
context: component.context,
|
||||
theme: component.theme,
|
||||
peer: peer,
|
||||
synchronousLoad: true
|
||||
case let .transactionPeer(peer):
|
||||
switch peer {
|
||||
case let .peer(peer):
|
||||
if !didSetup {
|
||||
self.avatarNode.setPeer(
|
||||
context: component.context,
|
||||
theme: component.theme,
|
||||
peer: peer,
|
||||
synchronousLoad: true
|
||||
)
|
||||
self.backgroundView.isHidden = true
|
||||
self.iconView.isHidden = true
|
||||
self.avatarNode.isHidden = false
|
||||
}
|
||||
case .appStore:
|
||||
self.backgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: size.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0x2a9ef1).cgColor,
|
||||
UIColor(rgb: 0x72d5fd).cgColor
|
||||
],
|
||||
direction: .mirroredDiagonal
|
||||
)
|
||||
self.backgroundView.isHidden = true
|
||||
self.iconView.isHidden = true
|
||||
self.avatarNode.isHidden = false
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = UIImage(bundleImageName: "Premium/Stars/Apple")
|
||||
case .playMarket:
|
||||
self.backgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: size.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0x54cb68).cgColor,
|
||||
UIColor(rgb: 0xa0de7e).cgColor
|
||||
],
|
||||
direction: .mirroredDiagonal
|
||||
)
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = UIImage(bundleImageName: "Premium/Stars/Google")
|
||||
case .fragment:
|
||||
self.backgroundView.image = generateFilledCircleImage(diameter: size.width, color: UIColor(rgb: 0x1b1f24))
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = UIImage(bundleImageName: "Premium/Stars/Fragment")
|
||||
iconOffset = 2.0
|
||||
case .ads:
|
||||
self.backgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: size.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0xffa85c).cgColor,
|
||||
UIColor(rgb: 0xffcd6a).cgColor
|
||||
],
|
||||
direction: .mirroredDiagonal
|
||||
)
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/Filters/Channel"), color: .white)
|
||||
case .premiumBot:
|
||||
iconInset = 7.0
|
||||
self.backgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: size.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0x6b93ff).cgColor,
|
||||
UIColor(rgb: 0x6b93ff).cgColor,
|
||||
UIColor(rgb: 0x8d77ff).cgColor,
|
||||
UIColor(rgb: 0xb56eec).cgColor,
|
||||
UIColor(rgb: 0xb56eec).cgColor
|
||||
],
|
||||
direction: .mirroredDiagonal
|
||||
)
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/EntityInputPremiumIcon"), color: .white)
|
||||
case .apiLimitExtension:
|
||||
self.backgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: size.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0x32b83b).cgColor,
|
||||
UIColor(rgb: 0x87d93b).cgColor
|
||||
],
|
||||
direction: .vertical
|
||||
)
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = UIImage(bundleImageName: "Premium/Stars/PaidBroadcast")
|
||||
case .unsupported:
|
||||
iconInset = 7.0
|
||||
self.backgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: size.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0xb1b1b1).cgColor,
|
||||
UIColor(rgb: 0xcdcdcd).cgColor
|
||||
],
|
||||
direction: .mirroredDiagonal
|
||||
)
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/EntityInputPremiumIcon"), color: .white)
|
||||
}
|
||||
case .appStore:
|
||||
case .search:
|
||||
iconInset = 6.0
|
||||
self.backgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: size.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0x2a9ef1).cgColor,
|
||||
UIColor(rgb: 0x72d5fd).cgColor
|
||||
],
|
||||
direction: .mirroredDiagonal
|
||||
)
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = UIImage(bundleImageName: "Premium/Stars/Apple")
|
||||
case .playMarket:
|
||||
self.backgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: size.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0x54cb68).cgColor,
|
||||
UIColor(rgb: 0xa0de7e).cgColor
|
||||
],
|
||||
direction: .mirroredDiagonal
|
||||
)
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = UIImage(bundleImageName: "Premium/Stars/Google")
|
||||
case .fragment:
|
||||
self.backgroundView.image = generateFilledCircleImage(diameter: size.width, color: UIColor(rgb: 0x1b1f24))
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = UIImage(bundleImageName: "Premium/Stars/Fragment")
|
||||
iconOffset = 2.0
|
||||
case .ads:
|
||||
self.backgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: size.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0xffa85c).cgColor,
|
||||
UIColor(rgb: 0xffcd6a).cgColor
|
||||
],
|
||||
direction: .mirroredDiagonal
|
||||
)
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/Filters/Channel"), color: .white)
|
||||
case .premiumBot:
|
||||
iconInset = 7.0
|
||||
self.backgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: size.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0x6b93ff).cgColor,
|
||||
UIColor(rgb: 0x6b93ff).cgColor,
|
||||
UIColor(rgb: 0x8d77ff).cgColor,
|
||||
UIColor(rgb: 0xb56eec).cgColor,
|
||||
UIColor(rgb: 0xb56eec).cgColor
|
||||
],
|
||||
direction: .mirroredDiagonal
|
||||
)
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/EntityInputPremiumIcon"), color: .white)
|
||||
case .apiLimitExtension:
|
||||
self.backgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: size.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0x32b83b).cgColor,
|
||||
UIColor(rgb: 0x87d93b).cgColor
|
||||
],
|
||||
direction: .vertical
|
||||
)
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = UIImage(bundleImageName: "Premium/Stars/PaidBroadcast")
|
||||
case .unsupported:
|
||||
iconInset = 7.0
|
||||
self.backgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: size.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0xb1b1b1).cgColor,
|
||||
UIColor(rgb: 0xcdcdcd).cgColor
|
||||
],
|
||||
direction: .mirroredDiagonal
|
||||
)
|
||||
self.backgroundView.isHidden = false
|
||||
self.iconView.isHidden = false
|
||||
self.avatarNode.isHidden = true
|
||||
self.iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/EntityInputPremiumIcon"), color: .white)
|
||||
self.iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/SearchInlineButtonIcon"), color: .white)
|
||||
}
|
||||
|
||||
self.avatarNode.frame = CGRect(origin: .zero, size: size)
|
||||
|
@ -255,6 +255,7 @@ public final class StarsImageComponent: Component {
|
||||
case transactionPeer(StarsContext.State.Transaction.Peer)
|
||||
case gift(Int32)
|
||||
case color(UIColor)
|
||||
case search
|
||||
|
||||
public static func == (lhs: StarsImageComponent.Subject, rhs: StarsImageComponent.Subject) -> Bool {
|
||||
switch lhs {
|
||||
@ -300,6 +301,12 @@ public final class StarsImageComponent: Component {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case .search:
|
||||
if case .search = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -880,6 +887,36 @@ public final class StarsImageComponent: Component {
|
||||
let animationFrame = imageFrame.insetBy(dx: -imageFrame.width * 0.19, dy: -imageFrame.height * 0.19).offsetBy(dx: 0.0, dy: -14.0)
|
||||
animationNode.frame = animationFrame
|
||||
animationNode.updateLayout(size: animationFrame.size)
|
||||
case .search:
|
||||
let iconBackgroundView: UIImageView
|
||||
let iconView: UIImageView
|
||||
if let currentBackground = self.iconBackgroundView, let current = self.iconView {
|
||||
iconBackgroundView = currentBackground
|
||||
iconView = current
|
||||
} else {
|
||||
iconBackgroundView = UIImageView()
|
||||
iconView = UIImageView()
|
||||
|
||||
containerNode.view.addSubview(iconBackgroundView)
|
||||
containerNode.view.addSubview(iconView)
|
||||
|
||||
self.iconBackgroundView = iconBackgroundView
|
||||
self.iconView = iconView
|
||||
}
|
||||
|
||||
let iconInset: CGFloat = 11.0
|
||||
let iconOffset: CGFloat = 0.0
|
||||
iconBackgroundView.image = generateGradientFilledCircleImage(
|
||||
diameter: imageSize.width,
|
||||
colors: [
|
||||
UIColor(rgb: 0x2a9ef1).cgColor,
|
||||
UIColor(rgb: 0x72d5fd).cgColor
|
||||
],
|
||||
direction: .vertical
|
||||
)
|
||||
iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/SearchInlineButtonIcon"), color: .white)
|
||||
iconBackgroundView.frame = imageFrame
|
||||
iconView.frame = imageFrame.insetBy(dx: iconInset, dy: iconInset).offsetBy(dx: 0.0, dy: iconOffset)
|
||||
}
|
||||
|
||||
if let icon = component.icon {
|
||||
|
@ -331,7 +331,7 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
|
||||
continue
|
||||
}
|
||||
|
||||
let title = strings.Stars_Purchase_Stars(Int32(product.count))
|
||||
let title = strings.Stars_Purchase_Stars(Int32(clamping: product.count))
|
||||
let price = product.price
|
||||
|
||||
let titleComponent = AnyComponent(MultilineTextComponent(
|
||||
|
@ -245,6 +245,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
var giftAvailability: StarGift.Gift.Availability?
|
||||
var isRefProgram = false
|
||||
var isPaidMessage = false
|
||||
var isPostsSearch = false
|
||||
var premiumGiftMonths: Int32?
|
||||
|
||||
var delayedCloseOnOpenPeer = true
|
||||
@ -254,7 +255,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
fatalError()
|
||||
}
|
||||
let boosts = boost.multiplier
|
||||
titleText = strings.Stars_Transaction_Giveaway_Boost_Stars(Int32(stars))
|
||||
titleText = strings.Stars_Transaction_Giveaway_Boost_Stars(Int32(clamping: stars))
|
||||
descriptionText = ""
|
||||
boostsText = strings.Stars_Transaction_Giveaway_Boost_Boosts(boosts)
|
||||
count = CurrencyAmount(amount: StarsAmount(value: stars, nanos: 0), currency: .stars)
|
||||
@ -471,6 +472,13 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
}
|
||||
transactionPeer = transaction.peer
|
||||
isReaction = true
|
||||
} else if transaction.flags.contains(.isPostsSearch) {
|
||||
titleText = strings.Stars_Transaction_SearchFee_Title
|
||||
descriptionText = ""
|
||||
count = transaction.count
|
||||
transactionId = transaction.id
|
||||
date = transaction.date
|
||||
isPostsSearch = true
|
||||
} else {
|
||||
switch transaction.peer {
|
||||
case let .peer(peer):
|
||||
@ -497,14 +505,29 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
case .fragment:
|
||||
if parentPeer.id == component.context.account.peerId {
|
||||
if (transaction.count.amount.value < 0 && !transaction.flags.contains(.isRefund)) || (transaction.count.amount.value > 0 && transaction.flags.contains(.isRefund)) {
|
||||
titleText = strings.Stars_Transaction_FragmentWithdrawal_Title
|
||||
switch transaction.count.currency {
|
||||
case .stars:
|
||||
titleText = strings.Stars_Transaction_FragmentWithdrawal_Title
|
||||
case .ton:
|
||||
titleText = strings.Stars_Transaction_FragmentWithdrawalTon_Title
|
||||
}
|
||||
via = strings.Stars_Transaction_FragmentWithdrawal_Subtitle
|
||||
} else {
|
||||
titleText = strings.Stars_Transaction_FragmentTopUp_Title
|
||||
switch transaction.count.currency {
|
||||
case .stars:
|
||||
titleText = strings.Stars_Transaction_FragmentTopUp_Title
|
||||
case .ton:
|
||||
titleText = strings.Stars_Transaction_FragmentTopUpTon_Title
|
||||
}
|
||||
via = strings.Stars_Transaction_FragmentTopUp_Subtitle
|
||||
}
|
||||
} else {
|
||||
titleText = strings.Stars_Transaction_FragmentWithdrawal_Title
|
||||
switch transaction.count.currency {
|
||||
case .stars:
|
||||
titleText = strings.Stars_Transaction_FragmentWithdrawal_Title
|
||||
case .ton:
|
||||
titleText = strings.Stars_Transaction_FragmentWithdrawalTon_Title
|
||||
}
|
||||
via = strings.Stars_Transaction_FragmentWithdrawal_Subtitle
|
||||
}
|
||||
case .ads:
|
||||
@ -718,7 +741,9 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
|
||||
let imageSubject: StarsImageComponent.Subject
|
||||
var imageIcon: StarsImageComponent.Icon?
|
||||
if let premiumGiftMonths {
|
||||
if isPostsSearch {
|
||||
imageSubject = .search
|
||||
} else if let premiumGiftMonths {
|
||||
imageSubject = .gift(premiumGiftMonths)
|
||||
} else if isGift {
|
||||
var value: Int32 = 3
|
||||
@ -1034,7 +1059,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
id: "prize",
|
||||
title: strings.Stars_Transaction_Giveaway_Prize,
|
||||
component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Stars_Transaction_Giveaway_Stars(Int32(count.amount.value)), font: tableFont, textColor: tableTextColor)))
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Stars_Transaction_Giveaway_Stars(Int32(clamping: count.amount.value)), font: tableFont, textColor: tableTextColor)))
|
||||
)
|
||||
))
|
||||
|
||||
@ -2379,7 +2404,7 @@ private final class PeerCellComponent: Component {
|
||||
let avatarNaturalSize = self.avatar.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(
|
||||
StarsAvatarComponent(context: component.context, theme: component.theme, peer: peer, photo: nil, media: [], uniqueGift: nil, backgroundColor: .clear)
|
||||
StarsAvatarComponent(context: component.context, theme: component.theme, peer: .transactionPeer(peer), photo: nil, media: [], uniqueGift: nil, backgroundColor: .clear)
|
||||
),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 40.0, height: 40.0)
|
||||
|
@ -924,7 +924,7 @@ public final class StarsStatisticsScreen: ViewControllerComponentContainer {
|
||||
scale: 0.066,
|
||||
colors: [:],
|
||||
title: presentationData.strings.Stars_Intro_PurchasedTitle,
|
||||
text: presentationData.strings.Stars_Intro_PurchasedText(presentationData.strings.Stars_Intro_PurchasedText_Stars(Int32(stars))).string,
|
||||
text: presentationData.strings.Stars_Intro_PurchasedText(presentationData.strings.Stars_Intro_PurchasedText_Stars(Int32(clamping: stars))).string,
|
||||
customUndoText: nil,
|
||||
timeout: nil
|
||||
),
|
||||
|
@ -299,7 +299,7 @@ final class StarsTransactionsListPanelComponent: Component {
|
||||
var itemTitle: String
|
||||
let itemSubtitle: String?
|
||||
var itemDate: String
|
||||
var itemPeer = item.peer
|
||||
var itemPeer: StarsAvatarComponent.Peer = .transactionPeer(item.peer)
|
||||
var itemFile: TelegramMediaFile?
|
||||
var uniqueGift: StarGift.UniqueGift?
|
||||
switch item.peer {
|
||||
@ -307,6 +307,10 @@ final class StarsTransactionsListPanelComponent: Component {
|
||||
if let months = item.premiumGiftMonths {
|
||||
itemTitle = peer.displayTitle(strings: environment.strings, displayOrder: .firstLast)
|
||||
itemSubtitle = environment.strings.Stars_Intro_Transaction_TelegramPremium(months)
|
||||
} else if item.flags.contains(.isPostsSearch) {
|
||||
itemTitle = environment.strings.Stars_Intro_Transaction_SearchFee
|
||||
itemSubtitle = ""
|
||||
itemPeer = .search
|
||||
} else if item.flags.contains(.isPaidMessage) {
|
||||
itemTitle = peer.displayTitle(strings: environment.strings, displayOrder: .firstLast)
|
||||
itemSubtitle = environment.strings.Stars_Intro_Transaction_PaidMessage(item.paidMessageCount ?? 1)
|
||||
@ -371,7 +375,7 @@ final class StarsTransactionsListPanelComponent: Component {
|
||||
if item.flags.contains(.isGift) {
|
||||
itemTitle = environment.strings.Stars_Intro_Transaction_Gift_UnknownUser
|
||||
itemSubtitle = environment.strings.Stars_Intro_Transaction_Gift_Title
|
||||
itemPeer = .fragment
|
||||
itemPeer = .transactionPeer(.fragment)
|
||||
} else {
|
||||
if (item.count.amount.value < 0 && !item.flags.contains(.isRefund)) || (item.count.amount.value > 0 && item.flags.contains(.isRefund)) {
|
||||
itemTitle = environment.strings.Stars_Intro_Transaction_FragmentWithdrawal_Title
|
||||
|
@ -969,7 +969,7 @@ final class StarsTransactionsScreenComponent: Component {
|
||||
theme: environment.theme,
|
||||
title: AnyComponent(VStack(titleComponents, alignment: .left, spacing: 2.0)),
|
||||
contentInsets: UIEdgeInsets(top: 9.0, left: 0.0, bottom: 8.0, right: 0.0),
|
||||
leftIcon: .custom(AnyComponentWithIdentity(id: "avatar", component: AnyComponent(StarsAvatarComponent(context: component.context, theme: environment.theme, peer: .peer(subscription.peer), photo: nil, media: [], uniqueGift: nil, backgroundColor: environment.theme.list.plainBackgroundColor))), false),
|
||||
leftIcon: .custom(AnyComponentWithIdentity(id: "avatar", component: AnyComponent(StarsAvatarComponent(context: component.context, theme: environment.theme, peer: .transactionPeer(.peer(subscription.peer)), photo: nil, media: [], uniqueGift: nil, backgroundColor: environment.theme.list.plainBackgroundColor))), false),
|
||||
icon: nil,
|
||||
accessory: .custom(ListActionItemComponent.CustomAccessory(component: labelComponent, insets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 16.0))),
|
||||
action: { [weak self] _ in
|
||||
@ -1336,7 +1336,7 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer {
|
||||
scale: 0.066,
|
||||
colors: [:],
|
||||
title: presentationData.strings.Stars_Intro_PurchasedTitle,
|
||||
text: presentationData.strings.Stars_Intro_PurchasedText(presentationData.strings.Stars_Intro_PurchasedText_Stars(Int32(stars))).string,
|
||||
text: presentationData.strings.Stars_Intro_PurchasedText(presentationData.strings.Stars_Intro_PurchasedText_Stars(Int32(clamping: stars))).string,
|
||||
customUndoText: nil,
|
||||
timeout: nil
|
||||
),
|
||||
|
@ -413,9 +413,9 @@ private final class SheetContent: CombinedComponent {
|
||||
let amount = component.invoice.totalAmount
|
||||
let infoText: String
|
||||
if case .starsChatSubscription = context.component.source {
|
||||
infoText = strings.Stars_Transfer_SubscribeInfo(state.botPeer?.compactDisplayTitle ?? "", strings.Stars_Transfer_Info_Stars(Int32(amount))).string
|
||||
infoText = strings.Stars_Transfer_SubscribeInfo(state.botPeer?.compactDisplayTitle ?? "", strings.Stars_Transfer_Info_Stars(Int32(clamping: amount))).string
|
||||
} else if let _ = component.invoice.subscriptionPeriod {
|
||||
infoText = strings.Stars_Transfer_BotSubscribeInfo(component.invoice.title, state.botPeer?.compactDisplayTitle ?? "", strings.Stars_Transfer_BotSubscribeInfo_Stars(Int32(amount))).string
|
||||
infoText = strings.Stars_Transfer_BotSubscribeInfo(component.invoice.title, state.botPeer?.compactDisplayTitle ?? "", strings.Stars_Transfer_BotSubscribeInfo_Stars(Int32(clamping: amount))).string
|
||||
} else if !component.extendedMedia.isEmpty {
|
||||
var description: String = ""
|
||||
var photoCount: Int32 = 0
|
||||
@ -447,26 +447,26 @@ private final class SheetContent: CombinedComponent {
|
||||
infoText = strings.Stars_Transfer_UnlockBotInfo(
|
||||
description,
|
||||
authorPeerName,
|
||||
strings.Stars_Transfer_Info_Stars(Int32(amount))
|
||||
strings.Stars_Transfer_Info_Stars(Int32(clamping: amount))
|
||||
).string
|
||||
} else if let botPeerName = state.botPeer?.compactDisplayTitle {
|
||||
infoText = strings.Stars_Transfer_UnlockBotInfo(
|
||||
description,
|
||||
botPeerName,
|
||||
strings.Stars_Transfer_Info_Stars(Int32(amount))
|
||||
strings.Stars_Transfer_Info_Stars(Int32(clamping: amount))
|
||||
).string
|
||||
} else {
|
||||
infoText = strings.Stars_Transfer_UnlockInfo(
|
||||
description,
|
||||
state.chatPeer?.compactDisplayTitle ?? "",
|
||||
strings.Stars_Transfer_Info_Stars(Int32(amount))
|
||||
strings.Stars_Transfer_Info_Stars(Int32(clamping: amount))
|
||||
).string
|
||||
}
|
||||
} else {
|
||||
infoText = strings.Stars_Transfer_Info(
|
||||
component.invoice.title,
|
||||
state.botPeer?.compactDisplayTitle ?? "",
|
||||
strings.Stars_Transfer_Info_Stars(Int32(amount))
|
||||
strings.Stars_Transfer_Info_Stars(Int32(clamping: amount))
|
||||
).string
|
||||
}
|
||||
|
||||
@ -611,11 +611,11 @@ private final class SheetContent: CombinedComponent {
|
||||
let text: String
|
||||
if isSubscription {
|
||||
title = presentationData.strings.Stars_Transfer_Subscribe_Successful_Title
|
||||
text = presentationData.strings.Stars_Transfer_Subscribe_Successful_Text(presentationData.strings.Stars_Transfer_Purchased_Stars(Int32(invoice.totalAmount)), botTitle).string
|
||||
text = presentationData.strings.Stars_Transfer_Subscribe_Successful_Text(presentationData.strings.Stars_Transfer_Purchased_Stars(Int32(clamping: invoice.totalAmount)), botTitle).string
|
||||
} else if let _ = component.invoice.extendedMedia {
|
||||
text = presentationData.strings.Stars_Transfer_UnlockedText( presentationData.strings.Stars_Transfer_Purchased_Stars(Int32(invoice.totalAmount))).string
|
||||
text = presentationData.strings.Stars_Transfer_UnlockedText( presentationData.strings.Stars_Transfer_Purchased_Stars(Int32(clamping: invoice.totalAmount))).string
|
||||
} else {
|
||||
text = presentationData.strings.Stars_Transfer_PurchasedText(invoice.title, botTitle, presentationData.strings.Stars_Transfer_Purchased_Stars(Int32(invoice.totalAmount))).string
|
||||
text = presentationData.strings.Stars_Transfer_PurchasedText(invoice.title, botTitle, presentationData.strings.Stars_Transfer_Purchased_Stars(Int32(clamping: invoice.totalAmount))).string
|
||||
}
|
||||
|
||||
if let navigationController = controller?.navigationController {
|
||||
|
@ -1228,9 +1228,9 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer {
|
||||
|
||||
func presentMinAmountTooltip(_ minAmount: Int64, currency: CurrencyAmount.Currency) {
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
var text = presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount))).string
|
||||
var text = presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(clamping: minAmount))).string
|
||||
if case .starGiftResell = self.mode {
|
||||
text = presentationData.strings.Stars_SellGiftMinAmountToast_Text("\(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount)))").string
|
||||
text = presentationData.strings.Stars_SellGiftMinAmountToast_Text("\(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(clamping: minAmount)))").string
|
||||
} else if case let .suggestedPost(mode, _, _, _) = self.mode {
|
||||
let resaleConfiguration = StarsSubscriptionConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
|
||||
switch currency {
|
||||
|
@ -111,7 +111,7 @@ extension ChatControllerImpl {
|
||||
}
|
||||
|
||||
let title = self.presentationData.strings.Chat_PaidMessage_Sent_Title(count)
|
||||
let text = self.presentationData.strings.Chat_PaidMessage_Sent_Text(self.presentationData.strings.Chat_PaidMessage_Sent_Text_Stars(Int32(amount.value * Int64(count)))).string
|
||||
let text = self.presentationData.strings.Chat_PaidMessage_Sent_Text(self.presentationData.strings.Chat_PaidMessage_Sent_Text_Stars(Int32(clamping: amount.value * Int64(count)))).string
|
||||
let textItems: [AnimatedTextComponent.Item] = [
|
||||
AnimatedTextComponent.Item(id: 0, content: .text(text))
|
||||
]
|
||||
|
@ -756,6 +756,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
var profile: Bool = false
|
||||
var referrer: String?
|
||||
var albumId: Int64?
|
||||
var collectionId: Int64?
|
||||
if let queryItems = components.queryItems {
|
||||
for queryItem in queryItems {
|
||||
if let value = queryItem.value {
|
||||
@ -793,6 +794,8 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
referrer = value
|
||||
} else if queryItem.name == "album" {
|
||||
albumId = Int64(value)
|
||||
} else if queryItem.name == "collection" {
|
||||
collectionId = Int64(value)
|
||||
}
|
||||
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
|
||||
voiceChat = ""
|
||||
@ -866,6 +869,8 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
result += "?attach=\(attach)"
|
||||
} else if let albumId {
|
||||
result += "/a/\(albumId)"
|
||||
} else if let collectionId {
|
||||
result += "/c/\(collectionId)"
|
||||
}
|
||||
if let startAttach = startAttach {
|
||||
if attach == nil {
|
||||
|
Loading…
x
Reference in New Issue
Block a user