From 51a16c711078fab6940623bf1de0ec85516ba699 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 24 Jun 2025 00:16:00 +0200 Subject: [PATCH] [WIP] Stars [skip ci] --- .../TelegramEngine/Payments/Stars.swift | 9 +---- .../Sources/ServiceMessageStrings.swift | 38 +++++++++---------- .../ChatMessageActionBubbleContentNode.swift | 34 ++++++++++++----- .../Sources/ChatMessageBubbleItemNode.swift | 2 + .../ChatMessageGiftBubbleContentNode.swift | 14 +++++++ .../ChatMessageSuggestedPostInfoNode.swift | 8 ++-- .../SuggestPostAccessoryPanelNode.swift | 9 ++++- .../PeerInfoScreen/Sources/PeerInfoData.swift | 21 ++++++++-- .../Sources/PeerInfoScreen.swift | 36 ++++++++++++++++-- .../Sources/StarsWithdrawalScreen.swift | 2 +- 10 files changed, 123 insertions(+), 50 deletions(-) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift index 967cfe9ac8..a0c94370ed 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift @@ -1074,13 +1074,7 @@ public final class StarsContext { return peerId! } - var ton: Bool { - var ton = false - self.impl.syncWith { impl in - ton = impl.ton - } - return ton - } + let ton: Bool public var currentState: StarsContext.State? { var state: StarsContext.State? @@ -1122,6 +1116,7 @@ public final class StarsContext { } init(account: Account, ton: Bool) { + self.ton = ton self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: { return StarsContextImpl(account: account, ton: ton) }) diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index 93ef4adda8..459dde1f40 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -1444,27 +1444,25 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, } attributedString = NSAttributedString(string: string, font: titleFont, textColor: primaryTextColor) case let .giftTon(currency, amount, _, _, _): - let _ = currency - let _ = amount attributedString = nil -// if !forAdditionalServiceMessage { -// attributedString = NSAttributedString(string: strings.Notification_Gift, font: titleFont, textColor: primaryTextColor) -// } else { -// let price = formatCurrencyAmount(amount, currency: currency) -// if message.author?.id == accountPeerId { -// attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGift_SentYou(price)._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes]) -// } else { -// 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 { -// authorName = strings.Notification_StarsGift_UnknownUser -// peerIds = [] -// } -// var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: peerIds) -// attributes[1] = boldAttributes -// attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGift_Sent(authorName, price)._tuple, body: bodyAttributes, argumentAttributes: attributes) -// } -// } + if !forAdditionalServiceMessage { + attributedString = NSAttributedString(string: strings.Notification_Gift, font: titleFont, textColor: primaryTextColor) + } else { + let price = formatCurrencyAmount(amount, currency: currency) + if message.author?.id == accountPeerId { + attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGift_SentYou(price)._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes]) + } else { + 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 { + authorName = strings.Notification_StarsGift_UnknownUser + peerIds = [] + } + var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: peerIds) + attributes[1] = boldAttributes + attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGift_Sent(authorName, price)._tuple, body: bodyAttributes, argumentAttributes: attributes) + } + } case .unknown: attributedString = nil } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift index f8f16fe098..c6673ec321 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift @@ -258,38 +258,52 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { } )).string - let amountString: String + var pricePart = "" if let amount, amount.amount != .zero { + let amountString: String switch amount.currency { case .stars: amountString = amount.amount.value == 1 ? "\(amount.amount) Star" : "\(amount.amount) Stars" case .ton: - amountString = "\(amount.amount) TON" + amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat)) TON" + } + + switch amount.currency { + case .stars: + if !item.message.effectivelyIncoming(item.context.account.peerId) { + pricePart = "\n\nšŸ’° The user have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive the Stars once the post has been live for 24 hours.\n\nšŸ”„ If your remove the post before it has been live for 24 hours, the user's Stars will be refunded." + } else { + pricePart = "\n\nšŸ’° You have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive your Stars once the post has been live for 24 hours.\n\nšŸ”„ If **\(channelName)** removes the post before it has been live for 24 hours, your Stars will be refunded." + } + case .ton: + if !item.message.effectivelyIncoming(item.context.account.peerId) { + pricePart = "\n\nšŸ’° The user have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive TON once the post has been live for 24 hours.\n\nšŸ”„ If your remove the post before it has been live for 24 hours, the user's TON will be refunded." + } else { + pricePart = "\n\nšŸ’° You have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive your TON once the post has been live for 24 hours.\n\nšŸ”„ If **\(channelName)** removes the post before it has been live for 24 hours, your TON will be refunded." + } } - } else { - amountString = "0 Stars" } let rawString: String if let timestamp { if Int32(Date().timeIntervalSince1970) >= timestamp { if !item.message.effectivelyIncoming(item.context.account.peerId) { - rawString = "šŸ“… The post has been automatically published in **\(channelName)** **\(timeString)**.\n\nšŸ’° The user have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive the Stars once the post has been live for 24 hours.\n\nšŸ”„ If your remove the post before it has been live for 24 hours, the user's Stars will be refunded." + rawString = "šŸ“… The post has been automatically published in **\(channelName)** **\(timeString)**." + pricePart } else { - rawString = "šŸ“… Your post has been automatically published in **\(channelName)** **\(timeString)**.\n\nšŸ’° You have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive your Stars once the post has been live for 24 hours.\n\nšŸ”„ If **\(channelName)** removes the post before it has been live for 24 hours, your Stars will be refunded." + rawString = "šŸ“… Your post has been automatically published in **\(channelName)** **\(timeString)**." + pricePart } } else { if !item.message.effectivelyIncoming(item.context.account.peerId) { - rawString = "šŸ“… The post will be automatically published in **\(channelName)** **\(timeString)**.\n\nšŸ’° The user have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive the Stars once the post has been live for 24 hours.\n\nšŸ”„ If your remove the post before it has been live for 24 hours, the user's Stars will be refunded." + rawString = "šŸ“… The post will be automatically published in **\(channelName)** **\(timeString)**." + pricePart } else { - rawString = "šŸ“… Your post will be automatically published in **\(channelName)** **\(timeString)**.\n\nšŸ’° You have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive your Stars once the post has been live for 24 hours.\n\nšŸ”„ If **\(channelName)** removes the post before it has been live for 24 hours, your Stars will be refunded." + rawString = "šŸ“… Your post will be automatically published in **\(channelName)** **\(timeString)**." + pricePart } } } else { if !item.message.effectivelyIncoming(item.context.account.peerId) { - rawString = "šŸ“… The post has been automatically published in **\(channelName)**.\n\nšŸ’° The user have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive the Stars once the post has been live for 24 hours.\n\nšŸ”„ If your remove the post before it has been live for 24 hours, the user's Stars will be refunded." + rawString = "šŸ“… The post has been automatically published in **\(channelName)**." + pricePart } else { - rawString = "šŸ“… Your post has been automatically published in **\(channelName)**.\n\nšŸ’° You have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive your Stars once the post has been live for 24 hours.\n\nšŸ”„ If **\(channelName)** removes the post before it has been live for 24 hours, your Stars will be refunded." + rawString = "šŸ“… Your post has been automatically published in **\(channelName)**." + pricePart } } updatedAttributedString = parseMarkdownIntoAttributedString(rawString, attributes: MarkdownAttributes( diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index 89a6a75df0..cf5fa73d75 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -222,6 +222,8 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([ result.append((message, ChatMessageGiftBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default))) } else if case .giftStars = action.action { result.append((message, ChatMessageGiftBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default))) + } else if case .giftTon = action.action { + result.append((message, ChatMessageGiftBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default))) } else if case .starGift = action.action { result.append((message, ChatMessageGiftBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default))) skipText = true diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift index e71506cdcd..14cdf5eb20 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift @@ -413,6 +413,20 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { } title = item.presentationData.strings.Notification_StarsGift_Title(Int32(count)) text = incoming ? item.presentationData.strings.Notification_StarsGift_Subtitle : item.presentationData.strings.Notification_StarsGift_SubtitleYou(peerName).string + case let .giftTon(currency, amount, cryptoCurrency, cryptoAmount, _): + var peerName = "" + if let peer = item.message.peers[item.message.id.peerId] { + peerName = EnginePeer(peer).compactDisplayTitle + } + //TODO:localize + let _ = currency + let _ = amount + let _ = cryptoCurrency + + let cryptoAmount = cryptoAmount ?? 0 + + title = item.presentationData.strings.Notification_StarsGift_Title(Int32(cryptoAmount)) + text = incoming ? item.presentationData.strings.Notification_StarsGift_Subtitle : item.presentationData.strings.Notification_StarsGift_SubtitleYou(peerName).string case let .prizeStars(count, _, channelId, _, _): if count <= 1000 { months = 3 diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode/Sources/ChatMessageSuggestedPostInfoNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode/Sources/ChatMessageSuggestedPostInfoNode.swift index fc63b1a8eb..1dc6273fdd 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode/Sources/ChatMessageSuggestedPostInfoNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode/Sources/ChatMessageSuggestedPostInfoNode.swift @@ -60,19 +60,19 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode { //TODO:localize let amountString: String - if let amount, amount.amount.value != 0, amount.amount.nanos != 0 { + if let amount, amount.amount != .zero { switch amount.currency { case .stars: if amount.amount.value == 1 { amountString = "1 Star" } else { - amountString = "\(amount) Stars" + amountString = "\(amount.amount) Stars" } case .ton: if amount.amount.value == 1 { amountString = "1 TON" } else { - amountString = "\(amount) TON" + amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat)) TON" } } } else { @@ -81,7 +81,7 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode { var timestampString: String if let timestamp { - timestampString = humanReadableStringForTimestamp(strings: item.presentationData.strings, dateTimeFormat: PresentationDateTimeFormat(), timestamp: timestamp, alwaysShowTime: true).string + timestampString = humanReadableStringForTimestamp(strings: item.presentationData.strings, dateTimeFormat: item.presentationData.dateTimeFormat, timestamp: timestamp, alwaysShowTime: true).string if timestampString.count > 1 { timestampString = String(timestampString[timestampString.startIndex]).capitalized + timestampString[timestampString.index(after: timestampString.startIndex)...] } diff --git a/submodules/TelegramUI/Components/Chat/SuggestPostAccessoryPanelNode/Sources/SuggestPostAccessoryPanelNode.swift b/submodules/TelegramUI/Components/Chat/SuggestPostAccessoryPanelNode/Sources/SuggestPostAccessoryPanelNode.swift index 9f200cd6e0..ba2b0ba756 100644 --- a/submodules/TelegramUI/Components/Chat/SuggestPostAccessoryPanelNode/Sources/SuggestPostAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/SuggestPostAccessoryPanelNode/Sources/SuggestPostAccessoryPanelNode.swift @@ -35,6 +35,7 @@ public final class SuggestPostAccessoryPanelNode: AccessoryPanelNode { private let context: AccountContext public var theme: PresentationTheme public var strings: PresentationStrings + private let dateTimeFormat: PresentationDateTimeFormat private var textIsOptions: Bool = false @@ -47,6 +48,7 @@ public final class SuggestPostAccessoryPanelNode: AccessoryPanelNode { self.context = context self.theme = theme self.strings = strings + self.dateTimeFormat = dateTimeFormat self.closeButton = HighlightableButtonNode() self.closeButton.accessibilityLabel = strings.VoiceOver_DiscardPreparedContent @@ -241,11 +243,14 @@ public final class SuggestPostAccessoryPanelNode: AccessoryPanelNode { let textString: NSAttributedString if let postSuggestionState = interfaceState.interfaceState.postSuggestionState, let price = postSuggestionState.price, price.amount != .zero { let currencySymbol: String + let amountString: String switch price.currency { case .stars: currencySymbol = "#" + amountString = "\(price.amount)" case .ton: currencySymbol = "$" + amountString = formatTonAmountText(price.amount.value, dateTimeFormat: self.dateTimeFormat) } if let timestamp = postSuggestionState.timestamp { let timeString = humanReadableStringForTimestamp(strings: interfaceState.strings, dateTimeFormat: interfaceState.dateTimeFormat, timestamp: timestamp, alwaysShowTime: true, allowYesterday: false, format: HumanReadableStringFormat( @@ -262,9 +267,9 @@ public final class SuggestPostAccessoryPanelNode: AccessoryPanelNode { return PresentationStrings.FormattedString(string: interfaceState.strings.SuggestPost_SetTimeFormat_TodayAt(value).string, ranges: []) } )).string - textString = NSAttributedString(string: "\(currencySymbol)\(price.amount) šŸ“… \(timeString)", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor) + textString = NSAttributedString(string: "\(currencySymbol)\(amountString) šŸ“… \(timeString)", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor) } else { - textString = NSAttributedString(string: "\(currencySymbol)\(price.amount) for publishing anytime", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor) + textString = NSAttributedString(string: "\(currencySymbol)\(amountString) for publishing anytime", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor) } } else { textString = NSAttributedString(string: "Tap to offer a price for publishing", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift index a09cd2413b..cb03111948 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift @@ -382,6 +382,7 @@ final class PeerInfoScreenData { let isPremiumRequiredForStoryPosting: Bool let personalChannel: PeerInfoPersonalChannelData? let starsState: StarsContext.State? + let tonState: StarsContext.State? let starsRevenueStatsState: StarsRevenueStats? let starsRevenueStatsContext: StarsRevenueStatsContext? let revenueStatsState: RevenueStats? @@ -433,6 +434,7 @@ final class PeerInfoScreenData { isPremiumRequiredForStoryPosting: Bool, personalChannel: PeerInfoPersonalChannelData?, starsState: StarsContext.State?, + tonState: StarsContext.State?, starsRevenueStatsState: StarsRevenueStats?, starsRevenueStatsContext: StarsRevenueStatsContext?, revenueStatsState: RevenueStats?, @@ -472,6 +474,7 @@ final class PeerInfoScreenData { self.isPremiumRequiredForStoryPosting = isPremiumRequiredForStoryPosting self.personalChannel = personalChannel self.starsState = starsState + self.tonState = tonState self.starsRevenueStatsState = starsRevenueStatsState self.starsRevenueStatsContext = starsRevenueStatsContext self.revenueStatsState = revenueStatsState @@ -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, privacySettings: Signal, archivedStickerPacks: Signal<[ArchivedStickerPackItem]?, NoError>, hasPassport: Signal, starsContext: StarsContext?) -> Signal { +func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, accountsAndPeers: Signal<[(AccountContext, EnginePeer, Int32)], NoError>, activeSessionsContextAndCount: Signal<(ActiveSessionsContext, Int, WebSessionsContext)?, NoError>, notificationExceptions: Signal, privacySettings: Signal, archivedStickerPacks: Signal<[ArchivedStickerPackItem]?, NoError>, hasPassport: Signal, starsContext: StarsContext?, tonContext: StarsContext?) -> Signal { let preferences = context.sharedContext.accountManager.sharedData(keys: [ SharedDataKeys.proxySettings, ApplicationSpecificSharedDataKeys.inAppNotificationSettings, @@ -852,6 +855,12 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, } else { starsState = .single(nil) } + let tonState: Signal + if let tonContext { + tonState = tonContext.state + } else { + tonState = .single(nil) + } let profileGiftsContext = ProfileGiftsContext(account: context.account, peerId: peerId) @@ -879,9 +888,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 @@ -960,6 +970,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, isPremiumRequiredForStoryPosting: true, personalChannel: personalChannel, starsState: starsState, + tonState: tonState, starsRevenueStatsState: nil, starsRevenueStatsContext: nil, revenueStatsState: nil, @@ -1010,6 +1021,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen isPremiumRequiredForStoryPosting: true, personalChannel: nil, starsState: nil, + tonState: nil, starsRevenueStatsState: nil, starsRevenueStatsContext: nil, revenueStatsState: nil, @@ -1469,6 +1481,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen isPremiumRequiredForStoryPosting: false, personalChannel: personalChannel, starsState: nil, + tonState: nil, starsRevenueStatsState: starsRevenueContextAndState.1, starsRevenueStatsContext: starsRevenueContextAndState.0, revenueStatsState: revenueContextAndState.1, @@ -1700,6 +1713,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen isPremiumRequiredForStoryPosting: isPremiumRequiredForStoryPosting, personalChannel: personalChannel, starsState: nil, + tonState: nil, starsRevenueStatsState: starsRevenueContextAndState.1, starsRevenueStatsContext: starsRevenueContextAndState.0, revenueStatsState: revenueContextAndState.1, @@ -2032,6 +2046,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen isPremiumRequiredForStoryPosting: isPremiumRequiredForStoryPosting, personalChannel: nil, starsState: nil, + tonState: nil, starsRevenueStatsState: starsRevenueContextAndState.1, starsRevenueStatsContext: starsRevenueContextAndState.0, revenueStatsState: nil, diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 26a7cd4b7d..ffd4026643 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -538,6 +538,7 @@ private enum PeerInfoSettingsSection { case profile case premiumManagement case stars + case ton } private enum PeerInfoReportType { @@ -1035,6 +1036,24 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p })) } } + if let tonState = data.tonState { + if !isPremiumDisabled || tonState.balance != .zero { + let balanceText: NSAttributedString + if tonState.balance != .zero { + 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() + } + //TODO:localize + items[.payment]!.append(PeerInfoScreenDisclosureItem(id: 105, label: .attributedText(balanceText), text: "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: { interaction.openSettings(.businessSetup) @@ -3011,7 +3030,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, 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, initialPaneKey: PeerInfoPaneKey?) { self.controller = controller self.context = context self.peerId = peerId @@ -4676,7 +4695,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 +10668,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.makeStarsTransactionsScreen(context: self.context, starsContext: tonContext)) + } } } @@ -12846,6 +12869,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 @@ -12953,6 +12977,12 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc } else { self.starsContext = nil } + if isSettings, let tonContext = context.tonContext { + self.tonContext = tonContext + tonContext.load(force: true) + } else { + self.tonContext = nil + } if isMyProfile, let profileGiftsContext { profileGiftsContext.updateFilter(.All) @@ -13294,7 +13324,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()) diff --git a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift index 3657d23258..231d091348 100644 --- a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift @@ -481,7 +481,7 @@ private final class SheetContent: CombinedComponent { accentColor: theme.list.itemAccentColor, value: state.amount?.value, minValue: minAmount?.value, - maxValue: maxAmount?.value, + maxValue: state.currency == .ton ? nil : maxAmount?.value, placeholderText: amountPlaceholder, labelText: amountLabel, currency: state.currency,