mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-17 08:41:10 +00:00
Various improvements
This commit is contained in:
parent
9a14b076c6
commit
d166e32b3e
@ -1213,6 +1213,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||
func makeStoryStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: EnginePeer.Id, storyId: Int32, storyItem: EngineStoryItem, fromStory: Bool) -> ViewController
|
||||
|
||||
func makeStarsTransactionsScreen(context: AccountContext, starsContext: StarsContext) -> ViewController
|
||||
func makeTonTransactionsScreen(context: AccountContext, tonContext: StarsContext) -> ViewController
|
||||
func makeStarsPurchaseScreen(context: AccountContext, starsContext: StarsContext, options: [Any], purpose: StarsPurchasePurpose, completion: @escaping (Int64) -> Void) -> ViewController
|
||||
func makeStarsTransferScreen(context: AccountContext, starsContext: StarsContext, invoice: TelegramMediaInvoice, source: BotPaymentInvoiceSource, extendedMedia: [TelegramExtendedMedia], inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?, EnginePeer?)?, NoError>, completion: @escaping (Bool) -> Void) -> ViewController
|
||||
func makeStarsSubscriptionTransferScreen(context: AccountContext, starsContext: StarsContext, invoice: TelegramMediaInvoice, link: String, inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?, EnginePeer?)?, NoError>, navigateToPeer: @escaping (EnginePeer) -> Void) -> ViewController
|
||||
|
BIN
submodules/PremiumUI/Resources/diamond.scn
Normal file
BIN
submodules/PremiumUI/Resources/diamond.scn
Normal file
Binary file not shown.
@ -280,9 +280,9 @@ final class StarsTransactionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
let itemLabel: NSAttributedString
|
||||
let labelString: String
|
||||
|
||||
let absCount = StarsAmount(value: abs(item.transaction.count.value), nanos: abs(item.transaction.count.nanos))
|
||||
let absCount = StarsAmount(value: abs(item.transaction.count.amount.value), nanos: abs(item.transaction.count.amount.nanos))
|
||||
let formattedLabel = presentationStringsFormattedNumber(absCount, item.presentationData.dateTimeFormat.groupingSeparator)
|
||||
if item.transaction.count < StarsAmount.zero {
|
||||
if item.transaction.count.amount < StarsAmount.zero {
|
||||
labelString = "- \(formattedLabel)"
|
||||
} else {
|
||||
labelString = "+ \(formattedLabel)"
|
||||
|
@ -618,9 +618,9 @@ private final class StarsContextImpl {
|
||||
}
|
||||
var transactions = state.transactions
|
||||
if addTransaction {
|
||||
transactions.insert(.init(flags: [.isLocal], id: "\(arc4random())", count: balance, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil, transactionDate: nil, transactionUrl: nil, paidMessageId: nil, giveawayMessageId: nil, media: [], subscriptionPeriod: nil, starGift: nil, floodskipNumber: nil, starrefCommissionPermille: nil, starrefPeerId: nil, starrefAmount: nil, paidMessageCount: nil, premiumGiftMonths: nil), at: 0)
|
||||
let count = CurrencyAmount(amount: balance, currency: self.ton ? .ton : .stars)
|
||||
transactions.insert(.init(flags: [.isLocal], id: "\(arc4random())", count: count, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil, transactionDate: nil, transactionUrl: nil, paidMessageId: nil, giveawayMessageId: nil, media: [], subscriptionPeriod: nil, starGift: nil, floodskipNumber: nil, starrefCommissionPermille: nil, starrefPeerId: nil, starrefAmount: nil, paidMessageCount: nil, premiumGiftMonths: nil), at: 0)
|
||||
}
|
||||
|
||||
self.updateState(StarsContext.State(flags: [.isPendingBalance], balance: max(StarsAmount(value: 0, nanos: 0), state.balance + balance), subscriptions: state.subscriptions, canLoadMoreSubscriptions: state.canLoadMoreSubscriptions, transactions: transactions, canLoadMoreTransactions: state.canLoadMoreTransactions, isLoading: state.isLoading))
|
||||
}
|
||||
|
||||
@ -724,7 +724,7 @@ private extension StarsContext.State.Transaction {
|
||||
let media = extendedMedia.flatMap({ $0.compactMap { textMediaAndExpirationTimerFromApiMedia($0, PeerId(0)).media } }) ?? []
|
||||
let _ = subscriptionPeriod
|
||||
|
||||
self.init(flags: flags, id: id, count: StarsAmount(apiAmount: stars), date: date, peer: parsedPeer, title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), transactionDate: transactionDate, transactionUrl: transactionUrl, paidMessageId: paidMessageId, giveawayMessageId: giveawayMessageId, media: media, subscriptionPeriod: subscriptionPeriod, starGift: starGift.flatMap { StarGift(apiStarGift: $0) }, floodskipNumber: floodskipNumber, starrefCommissionPermille: starrefCommissionPermille, starrefPeerId: starrefPeer?.peerId, starrefAmount: starrefAmount.flatMap(StarsAmount.init(apiAmount:)), paidMessageCount: paidMessageCount, premiumGiftMonths: premiumGiftMonths)
|
||||
self.init(flags: flags, id: id, count: CurrencyAmount(apiAmount: stars), date: date, peer: parsedPeer, title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), transactionDate: transactionDate, transactionUrl: transactionUrl, paidMessageId: paidMessageId, giveawayMessageId: giveawayMessageId, media: media, subscriptionPeriod: subscriptionPeriod, starGift: starGift.flatMap { StarGift(apiStarGift: $0) }, floodskipNumber: floodskipNumber, starrefCommissionPermille: starrefCommissionPermille, starrefPeerId: starrefPeer?.peerId, starrefAmount: starrefAmount.flatMap(StarsAmount.init(apiAmount:)), paidMessageCount: paidMessageCount, premiumGiftMonths: premiumGiftMonths)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -789,7 +789,7 @@ public final class StarsContext {
|
||||
|
||||
public let flags: Flags
|
||||
public let id: String
|
||||
public let count: StarsAmount
|
||||
public let count: CurrencyAmount
|
||||
public let date: Int32
|
||||
public let peer: Peer
|
||||
public let title: String?
|
||||
@ -812,7 +812,7 @@ public final class StarsContext {
|
||||
public init(
|
||||
flags: Flags,
|
||||
id: String,
|
||||
count: StarsAmount,
|
||||
count: CurrencyAmount,
|
||||
date: Int32,
|
||||
peer: Peer,
|
||||
title: String?,
|
||||
@ -1173,9 +1173,9 @@ private final class StarsTransactionsContextImpl {
|
||||
case .all:
|
||||
initialTransactions = currentTransactions
|
||||
case .incoming:
|
||||
initialTransactions = currentTransactions.filter { $0.count > StarsAmount.zero }
|
||||
initialTransactions = currentTransactions.filter { $0.count.amount > StarsAmount.zero }
|
||||
case .outgoing:
|
||||
initialTransactions = currentTransactions.filter { $0.count < StarsAmount.zero }
|
||||
initialTransactions = currentTransactions.filter { $0.count.amount < StarsAmount.zero }
|
||||
}
|
||||
|
||||
self._state = StarsTransactionsContext.State(transactions: initialTransactions, canLoadMore: true, isLoading: false)
|
||||
@ -1193,9 +1193,9 @@ private final class StarsTransactionsContextImpl {
|
||||
case .all:
|
||||
filteredTransactions = currentTransactions
|
||||
case .incoming:
|
||||
filteredTransactions = currentTransactions.filter { $0.count > StarsAmount.zero }
|
||||
filteredTransactions = currentTransactions.filter { $0.count.amount > StarsAmount.zero }
|
||||
case .outgoing:
|
||||
filteredTransactions = currentTransactions.filter { $0.count < StarsAmount.zero }
|
||||
filteredTransactions = currentTransactions.filter { $0.count.amount < StarsAmount.zero }
|
||||
}
|
||||
|
||||
if !filteredTransactions.isEmpty && self._state.transactions.isEmpty && filteredTransactions != initialTransactions {
|
||||
@ -1220,9 +1220,9 @@ private final class StarsTransactionsContextImpl {
|
||||
case .all:
|
||||
filteredTransactions = currentTransactions
|
||||
case .incoming:
|
||||
filteredTransactions = currentTransactions.filter { $0.count > StarsAmount.zero }
|
||||
filteredTransactions = currentTransactions.filter { $0.count.amount > StarsAmount.zero }
|
||||
case .outgoing:
|
||||
filteredTransactions = currentTransactions.filter { $0.count < StarsAmount.zero }
|
||||
filteredTransactions = currentTransactions.filter { $0.count.amount < StarsAmount.zero }
|
||||
}
|
||||
|
||||
if filteredTransactions != initialTransactions {
|
||||
|
@ -93,6 +93,15 @@ public func formatStarsAmountText(_ amount: StarsAmount, dateTimeFormat: Present
|
||||
return balanceText
|
||||
}
|
||||
|
||||
public func formatCurrencyAmountText(_ amount: CurrencyAmount, dateTimeFormat: PresentationDateTimeFormat, showPlus: Bool = false) -> String {
|
||||
switch amount.currency {
|
||||
case .stars:
|
||||
return formatStarsAmountText(amount.amount, dateTimeFormat: dateTimeFormat, showPlus: showPlus)
|
||||
case .ton:
|
||||
return formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat, showPlus: showPlus)
|
||||
}
|
||||
}
|
||||
|
||||
private let invalidAddressCharacters = CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=").inverted
|
||||
public func isValidTonAddress(_ address: String, exactLength: Bool = false) -> Bool {
|
||||
if address.count > walletAddressLength || address.rangeOfCharacter(from: invalidAddressCharacters) != nil {
|
||||
|
@ -381,6 +381,7 @@ final class PeerInfoScreenData {
|
||||
let hasBotPreviewItems: Bool
|
||||
let isPremiumRequiredForStoryPosting: Bool
|
||||
let personalChannel: PeerInfoPersonalChannelData?
|
||||
let tonState: StarsContext.State?
|
||||
let starsState: StarsContext.State?
|
||||
let starsRevenueStatsState: StarsRevenueStats?
|
||||
let starsRevenueStatsContext: StarsRevenueStatsContext?
|
||||
@ -432,6 +433,7 @@ final class PeerInfoScreenData {
|
||||
hasBotPreviewItems: Bool,
|
||||
isPremiumRequiredForStoryPosting: Bool,
|
||||
personalChannel: PeerInfoPersonalChannelData?,
|
||||
tonState: StarsContext.State?,
|
||||
starsState: StarsContext.State?,
|
||||
starsRevenueStatsState: StarsRevenueStats?,
|
||||
starsRevenueStatsContext: StarsRevenueStatsContext?,
|
||||
@ -471,6 +473,7 @@ final class PeerInfoScreenData {
|
||||
self.hasBotPreviewItems = hasBotPreviewItems
|
||||
self.isPremiumRequiredForStoryPosting = isPremiumRequiredForStoryPosting
|
||||
self.personalChannel = personalChannel
|
||||
self.tonState = tonState
|
||||
self.starsState = starsState
|
||||
self.starsRevenueStatsState = starsRevenueStatsState
|
||||
self.starsRevenueStatsContext = starsRevenueStatsContext
|
||||
@ -752,7 +755,7 @@ private func peerInfoPersonalOrLinkedChannel(context: AccountContext, peerId: En
|
||||
|> distinctUntilChanged
|
||||
}
|
||||
|
||||
func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, accountsAndPeers: Signal<[(AccountContext, EnginePeer, Int32)], NoError>, activeSessionsContextAndCount: Signal<(ActiveSessionsContext, Int, WebSessionsContext)?, NoError>, notificationExceptions: Signal<NotificationExceptionsList?, NoError>, privacySettings: Signal<AccountPrivacySettings?, NoError>, archivedStickerPacks: Signal<[ArchivedStickerPackItem]?, NoError>, hasPassport: Signal<Bool, NoError>, starsContext: StarsContext?) -> Signal<PeerInfoScreenData, NoError> {
|
||||
func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, accountsAndPeers: Signal<[(AccountContext, EnginePeer, Int32)], NoError>, activeSessionsContextAndCount: Signal<(ActiveSessionsContext, Int, WebSessionsContext)?, NoError>, notificationExceptions: Signal<NotificationExceptionsList?, NoError>, privacySettings: Signal<AccountPrivacySettings?, NoError>, archivedStickerPacks: Signal<[ArchivedStickerPackItem]?, NoError>, hasPassport: Signal<Bool, NoError>, starsContext: StarsContext?, tonContext: StarsContext?) -> Signal<PeerInfoScreenData, NoError> {
|
||||
let preferences = context.sharedContext.accountManager.sharedData(keys: [
|
||||
SharedDataKeys.proxySettings,
|
||||
ApplicationSpecificSharedDataKeys.inAppNotificationSettings,
|
||||
@ -845,6 +848,13 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
|> distinctUntilChanged
|
||||
}
|
||||
}
|
||||
|
||||
let tonState: Signal<StarsContext.State?, NoError>
|
||||
if let tonContext {
|
||||
tonState = tonContext.state
|
||||
} else {
|
||||
tonState = .single(nil)
|
||||
}
|
||||
|
||||
let starsState: Signal<StarsContext.State?, NoError>
|
||||
if let starsContext {
|
||||
@ -879,9 +889,10 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
hasStories,
|
||||
bots,
|
||||
peerInfoPersonalOrLinkedChannel(context: context, peerId: peerId, isSettings: true),
|
||||
starsState
|
||||
starsState,
|
||||
tonState
|
||||
)
|
||||
|> map { peerView, accountsAndPeers, accountSessions, privacySettings, sharedPreferences, notifications, stickerPacks, hasPassport, accountPreferences, suggestions, limits, hasPassword, isPowerSavingEnabled, hasStories, bots, personalChannel, starsState -> PeerInfoScreenData in
|
||||
|> map { peerView, accountsAndPeers, accountSessions, privacySettings, sharedPreferences, notifications, stickerPacks, hasPassport, accountPreferences, suggestions, limits, hasPassword, isPowerSavingEnabled, hasStories, bots, personalChannel, starsState, tonState -> PeerInfoScreenData in
|
||||
let (notificationExceptions, notificationsAuthorizationStatus, notificationsWarningSuppressed) = notifications
|
||||
let (featuredStickerPacks, archivedStickerPacks) = stickerPacks
|
||||
|
||||
@ -959,6 +970,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
hasBotPreviewItems: false,
|
||||
isPremiumRequiredForStoryPosting: true,
|
||||
personalChannel: personalChannel,
|
||||
tonState: tonState,
|
||||
starsState: starsState,
|
||||
starsRevenueStatsState: nil,
|
||||
starsRevenueStatsContext: nil,
|
||||
@ -1009,6 +1021,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
hasBotPreviewItems: false,
|
||||
isPremiumRequiredForStoryPosting: true,
|
||||
personalChannel: nil,
|
||||
tonState: nil,
|
||||
starsState: nil,
|
||||
starsRevenueStatsState: nil,
|
||||
starsRevenueStatsContext: nil,
|
||||
@ -1468,6 +1481,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
hasBotPreviewItems: hasBotPreviewItems,
|
||||
isPremiumRequiredForStoryPosting: false,
|
||||
personalChannel: personalChannel,
|
||||
tonState: nil,
|
||||
starsState: nil,
|
||||
starsRevenueStatsState: starsRevenueContextAndState.1,
|
||||
starsRevenueStatsContext: starsRevenueContextAndState.0,
|
||||
@ -1699,6 +1713,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
hasBotPreviewItems: false,
|
||||
isPremiumRequiredForStoryPosting: isPremiumRequiredForStoryPosting,
|
||||
personalChannel: personalChannel,
|
||||
tonState: nil,
|
||||
starsState: nil,
|
||||
starsRevenueStatsState: starsRevenueContextAndState.1,
|
||||
starsRevenueStatsContext: starsRevenueContextAndState.0,
|
||||
@ -2031,6 +2046,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
hasBotPreviewItems: false,
|
||||
isPremiumRequiredForStoryPosting: isPremiumRequiredForStoryPosting,
|
||||
personalChannel: nil,
|
||||
tonState: nil,
|
||||
starsState: nil,
|
||||
starsRevenueStatsState: starsRevenueContextAndState.1,
|
||||
starsRevenueStatsContext: starsRevenueContextAndState.0,
|
||||
|
@ -538,6 +538,7 @@ private enum PeerInfoSettingsSection {
|
||||
case profile
|
||||
case premiumManagement
|
||||
case stars
|
||||
case ton
|
||||
}
|
||||
|
||||
private enum PeerInfoReportType {
|
||||
@ -1035,14 +1036,31 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
|
||||
}))
|
||||
}
|
||||
}
|
||||
if let tonState = data.tonState {
|
||||
if abs(tonState.balance.value) > 0 {
|
||||
let balanceText: NSAttributedString
|
||||
if abs(tonState.balance.value) > 0 {
|
||||
let formattedLabel = formatTonAmountText(tonState.balance.value, dateTimeFormat: presentationData.dateTimeFormat)
|
||||
let smallLabelFont = Font.regular(floor(presentationData.listsFontSize.itemListBaseFontSize / 17.0 * 13.0))
|
||||
let labelFont = Font.regular(presentationData.listsFontSize.itemListBaseFontSize)
|
||||
let labelColor = presentationData.theme.list.itemSecondaryTextColor
|
||||
balanceText = tonAmountAttributedString(formattedLabel, integralFont: labelFont, fractionalFont: smallLabelFont, color: labelColor, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator)
|
||||
} else {
|
||||
balanceText = NSAttributedString()
|
||||
}
|
||||
items[.payment]!.append(PeerInfoScreenDisclosureItem(id: 103, label: .attributedText(balanceText), text: "My TON", icon: PresentationResourcesSettings.ton, action: {
|
||||
interaction.openSettings(.ton)
|
||||
}))
|
||||
}
|
||||
}
|
||||
if !isPremiumDisabled || context.isPremium {
|
||||
items[.payment]!.append(PeerInfoScreenDisclosureItem(id: 103, label: .text(""), additionalBadgeLabel: nil, text: presentationData.strings.Settings_Business, icon: PresentationResourcesSettings.business, action: {
|
||||
items[.payment]!.append(PeerInfoScreenDisclosureItem(id: 104, label: .text(""), additionalBadgeLabel: nil, text: presentationData.strings.Settings_Business, icon: PresentationResourcesSettings.business, action: {
|
||||
interaction.openSettings(.businessSetup)
|
||||
}))
|
||||
}
|
||||
if let starsState = data.starsState {
|
||||
if !isPremiumDisabled || starsState.balance > StarsAmount.zero {
|
||||
items[.payment]!.append(PeerInfoScreenDisclosureItem(id: 104, label: .text(""), text: presentationData.strings.Settings_SendGift, icon: PresentationResourcesSettings.premiumGift, action: {
|
||||
items[.payment]!.append(PeerInfoScreenDisclosureItem(id: 105, label: .text(""), text: presentationData.strings.Settings_SendGift, icon: PresentationResourcesSettings.premiumGift, action: {
|
||||
interaction.openSettings(.premiumGift)
|
||||
}))
|
||||
}
|
||||
@ -3011,7 +3029,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
private var didSetReady = false
|
||||
|
||||
init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, isMyProfile: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?, profileGiftsContext: ProfileGiftsContext?, starsContext: StarsContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, initialPaneKey: PeerInfoPaneKey?) {
|
||||
init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, isMyProfile: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?, profileGiftsContext: ProfileGiftsContext?, starsContext: StarsContext?, tonContext: StarsContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, initialPaneKey: PeerInfoPaneKey?) {
|
||||
self.controller = controller
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
@ -4676,7 +4694,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
self.cachedFaq.set(.single(nil) |> then(cachedFaqInstantPage(context: self.context) |> map(Optional.init)))
|
||||
|
||||
screenData = peerInfoScreenSettingsData(context: context, peerId: peerId, accountsAndPeers: self.accountsAndPeers.get(), activeSessionsContextAndCount: self.activeSessionsContextAndCount.get(), notificationExceptions: self.notificationExceptions.get(), privacySettings: self.privacySettings.get(), archivedStickerPacks: self.archivedPacks.get(), hasPassport: hasPassport, starsContext: starsContext)
|
||||
screenData = peerInfoScreenSettingsData(context: context, peerId: peerId, accountsAndPeers: self.accountsAndPeers.get(), activeSessionsContextAndCount: self.activeSessionsContextAndCount.get(), notificationExceptions: self.notificationExceptions.get(), privacySettings: self.privacySettings.get(), archivedStickerPacks: self.archivedPacks.get(), hasPassport: hasPassport, starsContext: starsContext, tonContext: tonContext)
|
||||
|
||||
|
||||
self.headerNode.displayCopyContextMenu = { [weak self] node, copyPhone, copyUsername in
|
||||
@ -10649,6 +10667,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
if let starsContext = self.controller?.starsContext {
|
||||
push(self.context.sharedContext.makeStarsTransactionsScreen(context: self.context, starsContext: starsContext))
|
||||
}
|
||||
case .ton:
|
||||
if let tonContext = self.controller?.tonContext {
|
||||
push(self.context.sharedContext.makeTonTransactionsScreen(context: self.context, tonContext: tonContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12846,6 +12868,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
private weak var requestsContext: PeerInvitationImportersContext?
|
||||
private weak var profileGiftsContext: ProfileGiftsContext?
|
||||
fileprivate let starsContext: StarsContext?
|
||||
fileprivate let tonContext: StarsContext?
|
||||
private let switchToRecommendedChannels: Bool
|
||||
private let switchToGifts: Bool
|
||||
private let switchToGroupsInCommon: Bool
|
||||
@ -12947,11 +12970,22 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
self.chatLocation = .peer(id: peerId)
|
||||
}
|
||||
|
||||
if isSettings, let starsContext = context.starsContext {
|
||||
self.starsContext = starsContext
|
||||
starsContext.load(force: true)
|
||||
if isSettings {
|
||||
if let starsContext = context.starsContext {
|
||||
self.starsContext = starsContext
|
||||
starsContext.load(force: true)
|
||||
} else {
|
||||
self.starsContext = nil
|
||||
}
|
||||
if let tonContext = context.tonContext {
|
||||
self.tonContext = tonContext
|
||||
tonContext.load(force: true)
|
||||
} else {
|
||||
self.tonContext = nil
|
||||
}
|
||||
} else {
|
||||
self.starsContext = nil
|
||||
self.tonContext = nil
|
||||
}
|
||||
|
||||
if isMyProfile, let profileGiftsContext {
|
||||
@ -13294,7 +13328,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
} else if self.switchToGroupsInCommon {
|
||||
initialPaneKey = .groupsInCommon
|
||||
}
|
||||
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, profileGiftsContext: self.profileGiftsContext, starsContext: self.starsContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, initialPaneKey: initialPaneKey)
|
||||
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, profileGiftsContext: self.profileGiftsContext, starsContext: self.starsContext, tonContext: self.tonContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, initialPaneKey: initialPaneKey)
|
||||
self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 })
|
||||
self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get())
|
||||
self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get())
|
||||
|
@ -0,0 +1,27 @@
|
||||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "PremiumDiamondComponent",
|
||||
module_name = "PremiumDiamondComponent",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit",
|
||||
"//submodules/Display",
|
||||
"//submodules/SSignalKit/SwiftSignalKit",
|
||||
"//submodules/ComponentFlow",
|
||||
"//submodules/AccountContext",
|
||||
"//submodules/AppBundle",
|
||||
"//submodules/GZip",
|
||||
"//submodules/LegacyComponents",
|
||||
"//submodules/Components/MultilineTextComponent:MultilineTextComponent",
|
||||
"//submodules/TelegramUI/Components/Premium/PremiumStarComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
@ -0,0 +1,309 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import ComponentFlow
|
||||
import SwiftSignalKit
|
||||
import SceneKit
|
||||
import GZip
|
||||
import AppBundle
|
||||
import LegacyComponents
|
||||
import PremiumStarComponent
|
||||
|
||||
private let sceneVersion: Int = 5
|
||||
|
||||
private func deg2rad(_ number: Float) -> Float {
|
||||
return number * .pi / 180
|
||||
}
|
||||
|
||||
private func rad2deg(_ number: Float) -> Float {
|
||||
return number * 180.0 / .pi
|
||||
}
|
||||
|
||||
public final class PremiumDiamondComponent: Component {
|
||||
public init() {
|
||||
}
|
||||
|
||||
public static func ==(lhs: PremiumDiamondComponent, rhs: PremiumDiamondComponent) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
public final class View: UIView, SCNSceneRendererDelegate, ComponentTaggedView {
|
||||
public final class Tag {
|
||||
public init() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public func matches(tag: Any) -> Bool {
|
||||
if let _ = tag as? Tag {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private var _ready = Promise<Bool>()
|
||||
public var ready: Signal<Bool, NoError> {
|
||||
return self._ready.get()
|
||||
}
|
||||
|
||||
weak var animateFrom: UIView?
|
||||
weak var containerView: UIView?
|
||||
|
||||
private let sceneView: SCNView
|
||||
|
||||
private var timer: SwiftSignalKit.Timer?
|
||||
|
||||
private var component: PremiumDiamondComponent?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.sceneView = SCNView(frame: CGRect(origin: .zero, size: CGSize(width: 64.0, height: 64.0)))
|
||||
self.sceneView.backgroundColor = .clear
|
||||
self.sceneView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
|
||||
self.sceneView.isUserInteractionEnabled = false
|
||||
self.sceneView.preferredFramesPerSecond = 60
|
||||
self.sceneView.isJitteringEnabled = true
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.addSubview(self.sceneView)
|
||||
|
||||
self.setup()
|
||||
|
||||
let panGestureRecoginzer = UIPanGestureRecognizer(target: self, action: #selector(self.handlePan(_:)))
|
||||
self.addGestureRecognizer(panGestureRecoginzer)
|
||||
|
||||
self.disablesInteractiveModalDismiss = true
|
||||
self.disablesInteractiveTransitionGestureRecognizer = true
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.timer?.invalidate()
|
||||
}
|
||||
|
||||
private var previousYaw: Float = 0.0
|
||||
@objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
|
||||
guard let scene = self.sceneView.scene, let node = scene.rootNode.childNode(withName: "star", recursively: false) else {
|
||||
return
|
||||
}
|
||||
|
||||
let keys = [
|
||||
"rotate",
|
||||
"tapRotate",
|
||||
"continuousRotation"
|
||||
]
|
||||
|
||||
for key in keys {
|
||||
node.removeAnimation(forKey: key)
|
||||
}
|
||||
|
||||
switch gesture.state {
|
||||
case .began:
|
||||
self.previousYaw = 0.0
|
||||
case .changed:
|
||||
let translation = gesture.translation(in: gesture.view)
|
||||
let yawPan = deg2rad(Float(translation.x))
|
||||
|
||||
func rubberBandingOffset(offset: CGFloat, bandingStart: CGFloat) -> CGFloat {
|
||||
let bandedOffset = offset - bandingStart
|
||||
let range: CGFloat = 60.0
|
||||
let coefficient: CGFloat = 0.4
|
||||
return bandingStart + (1.0 - (1.0 / ((bandedOffset * coefficient / range) + 1.0))) * range
|
||||
}
|
||||
|
||||
var pitchTranslation = rubberBandingOffset(offset: abs(translation.y), bandingStart: 0.0)
|
||||
if translation.y < 0.0 {
|
||||
pitchTranslation *= -1.0
|
||||
}
|
||||
let pitchPan = deg2rad(Float(pitchTranslation))
|
||||
|
||||
self.previousYaw = yawPan
|
||||
// Maintain the initial tilt while adding pan gestures
|
||||
let initialTiltX: Float = deg2rad(-15.0)
|
||||
let initialTiltZ: Float = deg2rad(5.0)
|
||||
node.eulerAngles = SCNVector3(initialTiltX + pitchPan, yawPan, initialTiltZ)
|
||||
case .ended:
|
||||
let velocity = gesture.velocity(in: gesture.view)
|
||||
|
||||
var smallAngle = false
|
||||
if (self.previousYaw < .pi / 2 && self.previousYaw > -.pi / 2) && abs(velocity.x) < 200 {
|
||||
smallAngle = true
|
||||
}
|
||||
|
||||
self.playAppearanceAnimation(velocity: velocity.x, smallAngle: smallAngle, explode: !smallAngle && abs(velocity.x) > 600)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func setup() {
|
||||
guard let scene = loadCompressedScene(name: "diamond", version: sceneVersion) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.sceneView.scene = scene
|
||||
self.sceneView.delegate = self
|
||||
|
||||
let _ = self.sceneView.snapshot()
|
||||
}
|
||||
|
||||
private var didSetReady = false
|
||||
public func renderer(_ renderer: SCNSceneRenderer, didRenderScene scene: SCNScene, atTime time: TimeInterval) {
|
||||
if !self.didSetReady {
|
||||
self.didSetReady = true
|
||||
|
||||
Queue.mainQueue().justDispatch {
|
||||
self._ready.set(.single(true))
|
||||
self.onReady()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func onReady() {
|
||||
self.playAppearanceAnimation(mirror: true, explode: true)
|
||||
}
|
||||
|
||||
private func playAppearanceAnimation(velocity: CGFloat? = nil, smallAngle: Bool = false, mirror: Bool = false, explode: Bool = false) {
|
||||
guard let scene = self.sceneView.scene else {
|
||||
return
|
||||
}
|
||||
|
||||
if explode, let node = scene.rootNode.childNode(withName: "swirl", recursively: false), let particlesLeft = scene.rootNode.childNode(withName: "particles_left", recursively: false), let particlesRight = scene.rootNode.childNode(withName: "particles_right", recursively: false), let particlesBottomLeft = scene.rootNode.childNode(withName: "particles_left_bottom", recursively: false), let particlesBottomRight = scene.rootNode.childNode(withName: "particles_right_bottom", recursively: false) {
|
||||
if let leftParticleSystem = particlesLeft.particleSystems?.first, let rightParticleSystem = particlesRight.particleSystems?.first, let leftBottomParticleSystem = particlesBottomLeft.particleSystems?.first, let rightBottomParticleSystem = particlesBottomRight.particleSystems?.first {
|
||||
leftParticleSystem.speedFactor = 2.0
|
||||
leftParticleSystem.particleVelocity = 1.6
|
||||
leftParticleSystem.birthRate = 60.0
|
||||
leftParticleSystem.particleLifeSpan = 4.0
|
||||
|
||||
rightParticleSystem.speedFactor = 2.0
|
||||
rightParticleSystem.particleVelocity = 1.6
|
||||
rightParticleSystem.birthRate = 60.0
|
||||
rightParticleSystem.particleLifeSpan = 4.0
|
||||
|
||||
leftBottomParticleSystem.particleVelocity = 1.6
|
||||
leftBottomParticleSystem.birthRate = 24.0
|
||||
leftBottomParticleSystem.particleLifeSpan = 7.0
|
||||
|
||||
rightBottomParticleSystem.particleVelocity = 1.6
|
||||
rightBottomParticleSystem.birthRate = 24.0
|
||||
rightBottomParticleSystem.particleLifeSpan = 7.0
|
||||
|
||||
node.physicsField?.isActive = true
|
||||
Queue.mainQueue().after(1.0) {
|
||||
node.physicsField?.isActive = false
|
||||
|
||||
leftParticleSystem.birthRate = 15.0
|
||||
leftParticleSystem.particleVelocity = 1.0
|
||||
leftParticleSystem.particleLifeSpan = 3.0
|
||||
|
||||
rightParticleSystem.birthRate = 15.0
|
||||
rightParticleSystem.particleVelocity = 1.0
|
||||
rightParticleSystem.particleLifeSpan = 3.0
|
||||
|
||||
leftBottomParticleSystem.particleVelocity = 1.0
|
||||
leftBottomParticleSystem.birthRate = 10.0
|
||||
leftBottomParticleSystem.particleLifeSpan = 5.0
|
||||
|
||||
rightBottomParticleSystem.particleVelocity = 1.0
|
||||
rightBottomParticleSystem.birthRate = 10.0
|
||||
rightBottomParticleSystem.particleLifeSpan = 5.0
|
||||
|
||||
let leftAnimation = POPBasicAnimation()
|
||||
leftAnimation.property = (POPAnimatableProperty.property(withName: "speedFactor", initializer: { property in
|
||||
property?.readBlock = { particleSystem, values in
|
||||
values?.pointee = (particleSystem as! SCNParticleSystem).speedFactor
|
||||
}
|
||||
property?.writeBlock = { particleSystem, values in
|
||||
(particleSystem as! SCNParticleSystem).speedFactor = values!.pointee
|
||||
}
|
||||
property?.threshold = 0.01
|
||||
}) as! POPAnimatableProperty)
|
||||
leftAnimation.fromValue = 1.2 as NSNumber
|
||||
leftAnimation.toValue = 0.85 as NSNumber
|
||||
leftAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
|
||||
leftAnimation.duration = 0.5
|
||||
leftParticleSystem.pop_add(leftAnimation, forKey: "speedFactor")
|
||||
|
||||
let rightAnimation = POPBasicAnimation()
|
||||
rightAnimation.property = (POPAnimatableProperty.property(withName: "speedFactor", initializer: { property in
|
||||
property?.readBlock = { particleSystem, values in
|
||||
values?.pointee = (particleSystem as! SCNParticleSystem).speedFactor
|
||||
}
|
||||
property?.writeBlock = { particleSystem, values in
|
||||
(particleSystem as! SCNParticleSystem).speedFactor = values!.pointee
|
||||
}
|
||||
property?.threshold = 0.01
|
||||
}) as! POPAnimatableProperty)
|
||||
rightAnimation.fromValue = 1.2 as NSNumber
|
||||
rightAnimation.toValue = 0.85 as NSNumber
|
||||
rightAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
|
||||
rightAnimation.duration = 0.5
|
||||
rightParticleSystem.pop_add(rightAnimation, forKey: "speedFactor")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// var from = node.presentation.eulerAngles
|
||||
// if abs(from.y - .pi * 2.0) < 0.001 {
|
||||
// from.y = 0.0
|
||||
// }
|
||||
// node.removeAnimation(forKey: "tapRotate")
|
||||
//
|
||||
// var toValue: Float = smallAngle ? 0.0 : .pi * 2.0
|
||||
// if let velocity = velocity, !smallAngle && abs(velocity) > 200 && velocity < 0.0 {
|
||||
// toValue *= -1
|
||||
// }
|
||||
// if mirror {
|
||||
// toValue *= -1
|
||||
// }
|
||||
//
|
||||
//
|
||||
// let to = SCNVector3(x: from.x, y: toValue, z: from.z)
|
||||
// let distance = rad2deg(to.y - from.y)
|
||||
//
|
||||
// guard !distance.isZero else {
|
||||
// Queue.mainQueue().after(0.1) { [weak self] in
|
||||
// self?.setupContinuousRotation()
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// let springAnimation = CASpringAnimation(keyPath: "eulerAngles")
|
||||
// springAnimation.fromValue = NSValue(scnVector3: from)
|
||||
// springAnimation.toValue = NSValue(scnVector3: to)
|
||||
// springAnimation.mass = 1.0
|
||||
// springAnimation.stiffness = 21.0
|
||||
// springAnimation.damping = 5.8
|
||||
// springAnimation.duration = springAnimation.settlingDuration * 0.75
|
||||
// springAnimation.initialVelocity = velocity.flatMap { abs($0 / CGFloat(distance)) } ?? 1.7
|
||||
// springAnimation.completion = { [weak self] finished in
|
||||
// if finished {
|
||||
// self?.setupContinuousRotation()
|
||||
// }
|
||||
// }
|
||||
// node.addAnimation(springAnimation, forKey: "rotate")
|
||||
}
|
||||
|
||||
func update(component: PremiumDiamondComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
|
||||
self.component = component
|
||||
|
||||
self.sceneView.bounds = CGRect(origin: .zero, size: CGSize(width: availableSize.width * 2.0, height: availableSize.height * 2.0))
|
||||
if self.sceneView.superview == self {
|
||||
self.sceneView.center = CGPoint(x: availableSize.width / 2.0, y: availableSize.height / 2.0)
|
||||
}
|
||||
|
||||
return availableSize
|
||||
}
|
||||
}
|
||||
|
||||
public func makeView() -> View {
|
||||
return View(frame: CGRect())
|
||||
}
|
||||
|
||||
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||
return view.update(component: self, availableSize: availableSize, transition: transition)
|
||||
}
|
||||
}
|
@ -376,7 +376,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
titleText = gift.title
|
||||
descriptionText = "\(strings.Gift_Unique_Collectible) #\(presentationStringsFormattedNumber(gift.number, dateTimeFormat.groupingSeparator))"
|
||||
}
|
||||
count = transaction.count
|
||||
count = transaction.count.amount
|
||||
transactionId = transaction.id
|
||||
date = transaction.date
|
||||
if case let .peer(peer) = transaction.peer {
|
||||
@ -395,7 +395,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
} else if let giveawayMessageIdValue = transaction.giveawayMessageId {
|
||||
titleText = strings.Stars_Transaction_Giveaway_Title
|
||||
descriptionText = ""
|
||||
count = transaction.count
|
||||
count = transaction.count.amount
|
||||
transactionId = transaction.id
|
||||
date = transaction.date
|
||||
giveawayMessageId = giveawayMessageIdValue
|
||||
@ -406,7 +406,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
} else if let _ = transaction.subscriptionPeriod {
|
||||
titleText = strings.Stars_Transaction_SubscriptionFee
|
||||
descriptionText = ""
|
||||
count = transaction.count
|
||||
count = transaction.count.amount
|
||||
transactionId = transaction.id
|
||||
date = transaction.date
|
||||
if case let .peer(peer) = transaction.peer {
|
||||
@ -417,7 +417,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
} else if transaction.flags.contains(.isGift) {
|
||||
titleText = strings.Stars_Gift_Received_Title
|
||||
descriptionText = strings.Stars_Gift_Received_Text
|
||||
count = transaction.count
|
||||
count = transaction.count.amount
|
||||
countOnTop = true
|
||||
transactionId = transaction.id
|
||||
date = transaction.date
|
||||
@ -446,7 +446,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
countOnTop = false
|
||||
descriptionText = ""
|
||||
}
|
||||
count = transaction.count
|
||||
count = transaction.count.amount
|
||||
transactionId = transaction.id
|
||||
date = transaction.date
|
||||
transactionPeer = transaction.peer
|
||||
@ -457,7 +457,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
titleText = strings.Stars_Transaction_Reaction_Title
|
||||
descriptionText = ""
|
||||
messageId = transaction.paidMessageId
|
||||
count = transaction.count
|
||||
count = transaction.count.amount
|
||||
transactionId = transaction.id
|
||||
date = transaction.date
|
||||
if case let .peer(peer) = transaction.peer {
|
||||
@ -490,7 +490,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
via = strings.Stars_Transaction_PremiumBotTopUp_Subtitle
|
||||
case .fragment:
|
||||
if parentPeer.id == component.context.account.peerId {
|
||||
if (transaction.count.value < 0 && !transaction.flags.contains(.isRefund)) || (transaction.count.value > 0 && transaction.flags.contains(.isRefund)) {
|
||||
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
|
||||
via = strings.Stars_Transaction_FragmentWithdrawal_Subtitle
|
||||
} else {
|
||||
@ -545,7 +545,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
|
||||
messageId = transaction.paidMessageId
|
||||
|
||||
count = transaction.count
|
||||
count = transaction.count.amount
|
||||
transactionId = transaction.id
|
||||
date = transaction.date
|
||||
if case let .peer(peer) = transaction.peer {
|
||||
@ -1173,7 +1173,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
}
|
||||
if let starrefCommissionPermille = transaction.starrefCommissionPermille, transaction.starrefPeerId != nil {
|
||||
if transaction.flags.contains(.isPaidMessage) || transaction.flags.contains(.isStarGiftResale) {
|
||||
var totalStars = transaction.count
|
||||
var totalStars = transaction.count.amount
|
||||
if let starrefCount = transaction.starrefAmount {
|
||||
totalStars = totalStars + starrefCount
|
||||
}
|
||||
|
@ -50,6 +50,8 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/LottieComponent",
|
||||
"//submodules/TelegramUI/Components/LottieComponentResourceContent",
|
||||
"//submodules/TelegramUI/Components/Gifts/GiftAnimationComponent",
|
||||
"//submodules/TelegramUI/Components/Premium/PremiumCoinComponent",
|
||||
"//submodules/TelegramUI/Components/Premium/PremiumDiamondComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -17,6 +17,7 @@ final class StarsBalanceComponent: Component {
|
||||
let strings: PresentationStrings
|
||||
let dateTimeFormat: PresentationDateTimeFormat
|
||||
let count: StarsAmount
|
||||
let isTon: Bool
|
||||
let rate: Double?
|
||||
let actionTitle: String
|
||||
let actionAvailable: Bool
|
||||
@ -35,6 +36,7 @@ final class StarsBalanceComponent: Component {
|
||||
strings: PresentationStrings,
|
||||
dateTimeFormat: PresentationDateTimeFormat,
|
||||
count: StarsAmount,
|
||||
isTon: Bool = false,
|
||||
rate: Double?,
|
||||
actionTitle: String,
|
||||
actionAvailable: Bool,
|
||||
@ -52,6 +54,7 @@ final class StarsBalanceComponent: Component {
|
||||
self.strings = strings
|
||||
self.dateTimeFormat = dateTimeFormat
|
||||
self.count = count
|
||||
self.isTon = isTon
|
||||
self.rate = rate
|
||||
self.actionTitle = actionTitle
|
||||
self.actionAvailable = actionAvailable
|
||||
@ -97,6 +100,9 @@ final class StarsBalanceComponent: Component {
|
||||
if lhs.count != rhs.count {
|
||||
return false
|
||||
}
|
||||
if lhs.isTon != rhs.isTon {
|
||||
return false
|
||||
}
|
||||
if lhs.rate != rhs.rate {
|
||||
return false
|
||||
}
|
||||
@ -120,8 +126,6 @@ final class StarsBalanceComponent: Component {
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
self.icon.image = UIImage(bundleImageName: "Premium/Stars/BalanceStar")
|
||||
|
||||
self.addSubview(self.icon)
|
||||
}
|
||||
|
||||
@ -130,6 +134,14 @@ final class StarsBalanceComponent: Component {
|
||||
}
|
||||
|
||||
func update(component: StarsBalanceComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||
if self.component == nil {
|
||||
if component.isTon {
|
||||
self.icon.image = generateTintedImage(image: UIImage(bundleImageName: "Ads/TonBig"), color: component.theme.list.itemAccentColor)
|
||||
} else {
|
||||
self.icon.image = UIImage(bundleImageName: "Premium/Stars/BalanceStar")
|
||||
}
|
||||
}
|
||||
|
||||
self.component = component
|
||||
self.state = state
|
||||
|
||||
@ -164,7 +176,12 @@ final class StarsBalanceComponent: Component {
|
||||
let sideInset: CGFloat = 16.0
|
||||
var contentHeight: CGFloat = sideInset
|
||||
|
||||
let formattedLabel = formatStarsAmountText(component.count, dateTimeFormat: component.dateTimeFormat)
|
||||
let formattedLabel: String
|
||||
if component.isTon {
|
||||
formattedLabel = formatTonAmountText(component.count.value, dateTimeFormat: component.dateTimeFormat)
|
||||
} else {
|
||||
formattedLabel = formatStarsAmountText(component.count, dateTimeFormat: component.dateTimeFormat)
|
||||
}
|
||||
let labelFont: UIFont
|
||||
if formattedLabel.contains(component.dateTimeFormat.decimalSeparator) {
|
||||
labelFont = Font.with(size: 48.0, design: .round, weight: .semibold)
|
||||
@ -188,13 +205,13 @@ final class StarsBalanceComponent: Component {
|
||||
self.addSubview(titleView)
|
||||
}
|
||||
if let icon = self.icon.image {
|
||||
let spacing: CGFloat = 3.0
|
||||
let spacing: CGFloat = 4.0
|
||||
let totalWidth = titleSize.width + icon.size.width + spacing
|
||||
let origin = floorToScreenPixels((availableSize.width - totalWidth) / 2.0)
|
||||
let titleFrame = CGRect(origin: CGPoint(x: origin + icon.size.width + spacing, y: contentHeight - 3.0), size: titleSize)
|
||||
titleView.frame = titleFrame
|
||||
|
||||
self.icon.frame = CGRect(origin: CGPoint(x: origin, y: contentHeight), size: icon.size)
|
||||
|
||||
self.icon.frame = CGRect(origin: CGPoint(x: origin, y: floorToScreenPixels(titleFrame.midY - icon.size.height / 2.0)), size: icon.size)
|
||||
}
|
||||
}
|
||||
contentHeight += titleSize.height
|
||||
|
@ -21,7 +21,7 @@ import TelegramStringFormatting
|
||||
|
||||
private extension StarsContext.State.Transaction {
|
||||
var extendedId: String {
|
||||
if self.count > StarsAmount.zero {
|
||||
if self.count.amount > StarsAmount.zero {
|
||||
return "\(id)_in"
|
||||
} else {
|
||||
return "\(id)_out"
|
||||
@ -320,7 +320,7 @@ final class StarsTransactionsListPanelComponent: Component {
|
||||
switch starGift {
|
||||
case let .generic(gift):
|
||||
itemFile = gift.file
|
||||
itemSubtitle = item.count > StarsAmount.zero ? environment.strings.Stars_Intro_Transaction_ConvertedGift : environment.strings.Stars_Intro_Transaction_Gift
|
||||
itemSubtitle = item.count.amount > StarsAmount.zero ? environment.strings.Stars_Intro_Transaction_ConvertedGift : environment.strings.Stars_Intro_Transaction_Gift
|
||||
case let .unique(gift):
|
||||
for attribute in gift.attributes {
|
||||
if case let .model(_, file, _) = attribute {
|
||||
@ -328,7 +328,7 @@ final class StarsTransactionsListPanelComponent: Component {
|
||||
break
|
||||
}
|
||||
}
|
||||
if item.count > StarsAmount.zero {
|
||||
if item.count.amount > StarsAmount.zero {
|
||||
itemSubtitle = environment.strings.Stars_Intro_Transaction_GiftSale
|
||||
} else {
|
||||
if item.flags.contains(.isStarGiftResale) {
|
||||
@ -373,7 +373,7 @@ final class StarsTransactionsListPanelComponent: Component {
|
||||
itemSubtitle = environment.strings.Stars_Intro_Transaction_Gift_Title
|
||||
itemPeer = .fragment
|
||||
} else {
|
||||
if (item.count.value < 0 && !item.flags.contains(.isRefund)) || (item.count.value > 0 && item.flags.contains(.isRefund)) {
|
||||
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
|
||||
itemSubtitle = environment.strings.Stars_Intro_Transaction_FragmentWithdrawal_Subtitle
|
||||
} else {
|
||||
@ -382,7 +382,7 @@ final class StarsTransactionsListPanelComponent: Component {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if item.count > StarsAmount.zero && !item.flags.contains(.isRefund) {
|
||||
if item.count.amount > StarsAmount.zero && !item.flags.contains(.isRefund) {
|
||||
itemTitle = environment.strings.Stars_Intro_Transaction_FragmentTopUp_Title
|
||||
itemSubtitle = environment.strings.Stars_Intro_Transaction_FragmentTopUp_Subtitle
|
||||
} else {
|
||||
@ -409,13 +409,24 @@ final class StarsTransactionsListPanelComponent: Component {
|
||||
}
|
||||
|
||||
let itemLabel: NSAttributedString
|
||||
let formattedLabel = formatStarsAmountText(item.count, dateTimeFormat: environment.dateTimeFormat, showPlus: true)
|
||||
let formattedLabel = formatCurrencyAmountText(item.count, dateTimeFormat: environment.dateTimeFormat, showPlus: true)
|
||||
|
||||
let smallLabelFont = Font.with(size: floor(fontBaseDisplaySize / 17.0 * 13.0))
|
||||
let labelFont = Font.medium(fontBaseDisplaySize)
|
||||
let labelColor = formattedLabel.hasPrefix("-") ? environment.theme.list.itemDestructiveColor : environment.theme.list.itemDisclosureActions.constructive.fillColor
|
||||
itemLabel = tonAmountAttributedString(formattedLabel, integralFont: labelFont, fractionalFont: smallLabelFont, color: labelColor, decimalSeparator: environment.dateTimeFormat.decimalSeparator)
|
||||
|
||||
let itemIconName: String
|
||||
let itemIconColor: UIColor?
|
||||
switch item.count.currency {
|
||||
case .stars:
|
||||
itemIconName = "Premium/Stars/StarMedium"
|
||||
itemIconColor = nil
|
||||
case .ton:
|
||||
itemIconName = "Ads/TonAbout"
|
||||
itemIconColor = labelColor
|
||||
}
|
||||
|
||||
var itemDateColor = environment.theme.list.itemSecondaryTextColor
|
||||
itemDate = stringForMediumCompactDate(timestamp: item.date, strings: environment.strings, dateTimeFormat: environment.dateTimeFormat)
|
||||
if item.flags.contains(.isRefund) {
|
||||
@ -496,7 +507,7 @@ final class StarsTransactionsListPanelComponent: Component {
|
||||
contentInsets: UIEdgeInsets(top: 9.0, left: environment.containerInsets.left, bottom: 8.0, right: environment.containerInsets.right),
|
||||
leftIcon: .custom(AnyComponentWithIdentity(id: "avatar", component: AnyComponent(StarsAvatarComponent(context: component.context, theme: environment.theme, peer: itemPeer, photo: item.photo, media: item.media, uniqueGift: uniqueGift, backgroundColor: environment.theme.list.plainBackgroundColor))), false),
|
||||
icon: nil,
|
||||
accessory: .custom(ListActionItemComponent.CustomAccessory(component: AnyComponentWithIdentity(id: "label", component: AnyComponent(StarsLabelComponent(text: itemLabel))), insets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 16.0))),
|
||||
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
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,11 @@ func openWebAppImpl(
|
||||
skipTermsOfService: Bool,
|
||||
payload: String?
|
||||
) {
|
||||
if context.isFrozen {
|
||||
parentController.push(context.sharedContext.makeAccountFreezeInfoScreen(context: context))
|
||||
return
|
||||
}
|
||||
|
||||
let presentationData: PresentationData
|
||||
if let parentController = parentController as? ChatControllerImpl {
|
||||
presentationData = parentController.presentationData
|
||||
|
@ -3687,6 +3687,10 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
return StarsTransactionsScreen(context: context, starsContext: starsContext)
|
||||
}
|
||||
|
||||
public func makeTonTransactionsScreen(context: AccountContext, tonContext: StarsContext) -> ViewController {
|
||||
return TonTransactionsScreen(context: context, tonContext: tonContext)
|
||||
}
|
||||
|
||||
public func makeStarsPurchaseScreen(context: AccountContext, starsContext: StarsContext, options: [Any], purpose: StarsPurchasePurpose, completion: @escaping (Int64) -> Void) -> ViewController {
|
||||
return StarsPurchaseScreen(context: context, starsContext: starsContext, options: options, purpose: purpose, completion: completion)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user