diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 160c0d7e31..c221b32def 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -13146,13 +13146,21 @@ Sorry for the inconvenience."; "TopApps.Info.Text" = "This catalogue ranks mini apps based on their daily revenue, measured in Stars. To be listed, developers must set their main mini app in [@botfather]() (as described [here](https://core.telegram.org/bots/webapps#launching-the-main-mini-app)), have over **1,000** daily users, and earn a daily revenue above **1,000** Stars, based on weekly average."; "TopApps.Info.Done" = "Understood"; -"Stars.Intro.Transaction.TelegramBotApi.Title" = "Paid Limit Extension"; -"Stars.Intro.Transaction.TelegramBotApi.Subtitle" = "Bot API"; +"Stars.Intro.Transaction.TelegramBotApi.Title" = "Paid Broadcast"; +"Stars.Intro.Transaction.TelegramBotApi.Messages_1" = "%@ Message"; +"Stars.Intro.Transaction.TelegramBotApi.Messages_any" = "%@ Messages"; -"Stars.Transaction.TelegramBotApi.Title" = "Paid Limit Extension"; -"Stars.Transaction.TelegramBotApi.Subtitle" = "Bot API"; +"Stars.Transaction.TelegramBotApi.Title" = "Paid Broadcast"; +"Stars.Transaction.TelegramBotApi.Messages_1" = "%@ Message"; +"Stars.Transaction.TelegramBotApi.Messages_any" = "%@ Messages"; "Monetization.Bot.Header" = "Telegram shares 50% of the revenue from ads displayed in your bot. [Learn More >]()"; "Monetization.Bot.BalanceTitle" = "AVAILABLE BALANCE"; "Resolve.ChannelErrorNotFound" = "Sorry, this channel doesn't seem to exist."; + +"Stats.TonBotRevenue.Title" = "TON Balance"; + +"PeerInfo.BotBalance.Title" = "BALANCE"; +"PeerInfo.BotBalance.Ton" = "Ton"; +"PeerInfo.BotBalance.Stars" = "Stars"; diff --git a/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift b/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift index a782b777fd..d15bf6e006 100644 --- a/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift +++ b/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift @@ -1438,6 +1438,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode { verifiedIconView.removeFromSuperview() } + var additionalRightInset: CGFloat = 0.0 if let (titleLayout, titleApply) = actionButtonTitleLayoutAndApply { let actionButtonTitleNode = titleApply() let actionButtonBackgroundNode: ASImageNode @@ -1487,6 +1488,8 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode { let actionTitleFrame = CGRect(origin: CGPoint(x: actionButtonFrame.minX + 13.0, y: actionButtonFrame.minY + floorToScreenPixels((actionButtonFrame.height - titleLayout.size.height) / 2.0) + 1.0), size: titleLayout.size) actionButtonTitleNode.frame = actionTitleFrame + + additionalRightInset += actionButtonSize.width + 16.0 } else { if let actionButtonTitleNode = strongSelf.actionButtonTitleNode { strongSelf.actionButtonTitleNode = nil @@ -1588,7 +1591,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode { badgeBackgroundNode.image = currentBadgeBackgroundImage badgeBackgroundWidth = max(badgeTextLayout.size.width + 10.0, currentBadgeBackgroundImage.size.width) - var badgeBackgroundFrame = CGRect(x: revealOffset + params.width - params.rightInset - badgeBackgroundWidth - 6.0, y: floor((nodeLayout.contentSize.height - currentBadgeBackgroundImage.size.height) / 2.0), width: badgeBackgroundWidth, height: currentBadgeBackgroundImage.size.height) + var badgeBackgroundFrame = CGRect(x: revealOffset + params.width - params.rightInset - badgeBackgroundWidth - additionalRightInset - 6.0, y: floor((nodeLayout.contentSize.height - currentBadgeBackgroundImage.size.height) / 2.0), width: badgeBackgroundWidth, height: currentBadgeBackgroundImage.size.height) if let arrowButtonImage = arrowButtonImage { badgeBackgroundFrame.origin.x -= arrowButtonImage.size.width + 6.0 diff --git a/submodules/StatisticsUI/Sources/ChannelStatsController.swift b/submodules/StatisticsUI/Sources/ChannelStatsController.swift index 975536e4d8..11e1485338 100644 --- a/submodules/StatisticsUI/Sources/ChannelStatsController.swift +++ b/submodules/StatisticsUI/Sources/ChannelStatsController.swift @@ -2182,8 +2182,7 @@ public func channelStatsController( var leftNavigationButton: ItemListNavigationButton? var boostsOnly = false if existingRevenueContext != nil { - //TODO:localize - title = .text("TON Balance") + title = .text(presentationData.strings.Stats_TonBotRevenue_Title) canViewRevenue = true } else if section == .boosts { title = .text("") diff --git a/submodules/StatisticsUI/Sources/StarsTransactionItem.swift b/submodules/StatisticsUI/Sources/StarsTransactionItem.swift index f7dbc7fac1..c09d2b238e 100644 --- a/submodules/StatisticsUI/Sources/StarsTransactionItem.swift +++ b/submodules/StatisticsUI/Sources/StarsTransactionItem.swift @@ -264,7 +264,11 @@ final class StarsTransactionItemNode: ListViewItemNode, ItemListItemNode { itemSubtitle = item.presentationData.strings.Stars_Intro_Transaction_TelegramAds_Subtitle case .apiLimitExtension: itemTitle = item.presentationData.strings.Stars_Intro_Transaction_TelegramBotApi_Title - itemSubtitle = item.presentationData.strings.Stars_Intro_Transaction_TelegramBotApi_Subtitle + if let floodskipNumber = item.transaction.floodskipNumber { + itemSubtitle = item.presentationData.strings.Stars_Intro_Transaction_TelegramBotApi_Messages(floodskipNumber) + } else { + itemSubtitle = nil + } case .unsupported: itemTitle = item.presentationData.strings.Stars_Intro_Transaction_Unsupported_Title itemSubtitle = nil diff --git a/submodules/TabBarUI/Sources/TabBarController.swift b/submodules/TabBarUI/Sources/TabBarController.swift index a2438aab2c..13b171ace0 100644 --- a/submodules/TabBarUI/Sources/TabBarController.swift +++ b/submodules/TabBarUI/Sources/TabBarController.swift @@ -364,7 +364,7 @@ open class TabBarControllerImpl: ViewController, TabBarController { } self.tabBarControllerNode.tabBarNode.selectedIndex = tabBarSelectedIndex - var transitionSale: CGFloat = 0.995 + var transitionSale: CGFloat = 0.998 if let currentView = self.currentController?.view { transitionSale = (currentView.frame.height - 3.0) / currentView.frame.height } @@ -373,7 +373,7 @@ open class TabBarControllerImpl: ViewController, TabBarController { //self.tabBarControllerNode.currentControllerNode = nil if animated { - currentController.view.layer.animateScale(from: 1.0, to: transitionSale, duration: 0.15, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { completed in + currentController.view.layer.animateScale(from: 1.0, to: transitionSale, duration: 0.12, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { completed in if completed { currentController.view.layer.removeAllAnimations() } @@ -395,9 +395,9 @@ open class TabBarControllerImpl: ViewController, TabBarController { let commit = self.tabBarControllerNode.setCurrentControllerNode(currentController.displayNode) if animated { - currentController.view.layer.animateScale(from: transitionSale, to: 1.0, duration: 0.15, delay: 0.15, timingFunction: kCAMediaTimingFunctionSpring) + currentController.view.layer.animateScale(from: transitionSale, to: 1.0, duration: 0.15, delay: 0.1, timingFunction: kCAMediaTimingFunctionSpring) currentController.view.layer.allowsGroupOpacity = true - currentController.view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, completion: { completed in + currentController.view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1, completion: { completed in if completed { currentController.view.layer.allowsGroupOpacity = false } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift index d6b1a54276..ecd4e581fb 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift @@ -468,7 +468,7 @@ 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), at: 0) + 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), at: 0) } self.updateState(StarsContext.State(flags: [.isPendingBalance], balance: max(0, state.balance + balance), subscriptions: state.subscriptions, canLoadMoreSubscriptions: state.canLoadMoreSubscriptions, transactions: transactions, canLoadMoreTransactions: state.canLoadMoreTransactions, isLoading: state.isLoading)) @@ -491,8 +491,6 @@ private extension StarsContext.State.Transaction { init?(apiTransaction: Api.StarsTransaction, peerId: EnginePeer.Id?, transaction: Transaction) { switch apiTransaction { case let .starsTransaction(apiFlags, id, stars, date, transactionPeer, title, description, photo, transactionDate, transactionUrl, _, messageId, extendedMedia, subscriptionPeriod, giveawayPostId, starGift, floodskipNumber): - let _ = floodskipNumber - let parsedPeer: StarsContext.State.Transaction.Peer var paidMessageId: MessageId? var giveawayMessageId: MessageId? @@ -548,7 +546,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: 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) }) + self.init(flags: flags, id: id, count: 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) } } } @@ -619,6 +617,7 @@ public final class StarsContext { public let media: [Media] public let subscriptionPeriod: Int32? public let starGift: StarGift? + public let floodskipNumber: Int32? public init( flags: Flags, @@ -635,7 +634,8 @@ public final class StarsContext { giveawayMessageId: MessageId?, media: [Media], subscriptionPeriod: Int32?, - starGift: StarGift? + starGift: StarGift?, + floodskipNumber: Int32? ) { self.flags = flags self.id = id @@ -652,6 +652,7 @@ public final class StarsContext { self.media = media self.subscriptionPeriod = subscriptionPeriod self.starGift = starGift + self.floodskipNumber = floodskipNumber } public static func == (lhs: Transaction, rhs: Transaction) -> Bool { @@ -700,6 +701,9 @@ public final class StarsContext { if lhs.starGift != rhs.starGift { return false } + if lhs.floodskipNumber != rhs.floodskipNumber { + return false + } return true } } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index 88243dae3e..bc1736a2d2 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -5125,12 +5125,16 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI } item.controllerInteraction.longTap(.command(command), ChatControllerInteraction.LongTapParams(message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?())) }) - case let .hashtag(_, hashtag): + case let .hashtag(peerName, hashtag): + var fullHashtag = hashtag + if let peerName { + fullHashtag += "@\(peerName)" + } return .action(InternalBubbleTapAction.Action { [weak self] in - guard let self, let contentNode = self.contextContentNodeForLink(hashtag, rects: rects) else { + guard let self, let contentNode = self.contextContentNodeForLink(fullHashtag, rects: rects) else { return } - item.controllerInteraction.longTap(.hashtag(hashtag), ChatControllerInteraction.LongTapParams(message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?())) + item.controllerInteraction.longTap(.hashtag(fullHashtag), ChatControllerInteraction.LongTapParams(message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?())) }) case .instantPage: break diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 28d1a02749..61e90e92b7 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -1514,7 +1514,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese if overallRevenueBalance > 0 || overallStarsBalance > 0 { //TODO:localize - items[.balances]!.append(PeerInfoScreenHeaderItem(id: 20, text: "BALANCE")) + items[.balances]!.append(PeerInfoScreenHeaderItem(id: 20, text: presentationData.strings.PeerInfo_BotBalance_Title)) if overallRevenueBalance > 0 { let string = "*\(formatTonAmountText(revenueBalance, dateTimeFormat: presentationData.dateTimeFormat))" let attributedString = NSMutableAttributedString(string: string, font: Font.regular(presentationData.listsFontSize.itemListBaseFontSize), textColor: presentationData.theme.list.itemSecondaryTextColor) @@ -1522,7 +1522,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese attributedString.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .ton), range: NSRange(range, in: attributedString.string)) attributedString.addAttribute(.baselineOffset, value: 1.5, range: NSRange(range, in: attributedString.string)) } - items[.balances]!.append(PeerInfoScreenDisclosureItem(id: 21, label: .attributedText(attributedString), text: "Toncoin", icon: PresentationResourcesSettings.ton, action: { + items[.balances]!.append(PeerInfoScreenDisclosureItem(id: 21, label: .attributedText(attributedString), text: presentationData.strings.PeerInfo_BotBalance_Ton, icon: PresentationResourcesSettings.ton, action: { interaction.editingOpenRevenue() })) } @@ -1534,7 +1534,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese attributedString.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: false)), range: NSRange(range, in: attributedString.string)) attributedString.addAttribute(.baselineOffset, value: 1.5, range: NSRange(range, in: attributedString.string)) } - items[.balances]!.append(PeerInfoScreenDisclosureItem(id: 22, label: .attributedText(attributedString), text: "Stars", icon: PresentationResourcesSettings.stars, action: { + items[.balances]!.append(PeerInfoScreenDisclosureItem(id: 22, label: .attributedText(attributedString), text: presentationData.strings.PeerInfo_BotBalance_Stars, icon: PresentationResourcesSettings.stars, action: { interaction.editingOpenStars() })) } diff --git a/submodules/TelegramUI/Components/Stars/StarsAvatarComponent/Sources/StarsAvatarComponent.swift b/submodules/TelegramUI/Components/Stars/StarsAvatarComponent/Sources/StarsAvatarComponent.swift index 73f748e91b..5a01234637 100644 --- a/submodules/TelegramUI/Components/Stars/StarsAvatarComponent/Sources/StarsAvatarComponent.swift +++ b/submodules/TelegramUI/Components/Stars/StarsAvatarComponent/Sources/StarsAvatarComponent.swift @@ -274,7 +274,20 @@ public final class StarsAvatarComponent: Component { self.iconView.isHidden = false self.avatarNode.isHidden = true self.iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/EntityInputPremiumIcon"), color: .white) - case .unsupported, .apiLimitExtension: + 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, diff --git a/submodules/TelegramUI/Components/Stars/StarsImageComponent/Sources/StarsImageComponent.swift b/submodules/TelegramUI/Components/Stars/StarsImageComponent/Sources/StarsImageComponent.swift index 50544f7399..fc2a18c3aa 100644 --- a/submodules/TelegramUI/Components/Stars/StarsImageComponent/Sources/StarsImageComponent.swift +++ b/submodules/TelegramUI/Components/Stars/StarsImageComponent/Sources/StarsImageComponent.swift @@ -788,7 +788,17 @@ public final class StarsImageComponent: Component { direction: .mirroredDiagonal ) iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/EntityInputPremiumIcon"), color: .white) - case .peer, .unsupported, .apiLimitExtension: + case .apiLimitExtension: + iconBackgroundView.image = generateGradientFilledCircleImage( + diameter: imageSize.width, + colors: [ + UIColor(rgb: 0x32b83b).cgColor, + UIColor(rgb: 0x87d93b).cgColor + ], + direction: .vertical + ) + iconView.image = UIImage(bundleImageName: "Premium/Stars/PaidBroadcast") + case .peer, .unsupported: iconInset = 15.0 iconBackgroundView.image = generateGradientFilledCircleImage( diameter: imageSize.width, diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift index c5ecb26401..ba8cdc8397 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift @@ -412,11 +412,13 @@ private final class StarsTransactionSheetContent: CombinedComponent { via = strings.Stars_Transaction_TelegramAds_Subtitle case .apiLimitExtension: titleText = strings.Stars_Transaction_TelegramBotApi_Title - via = strings.Stars_Transaction_TelegramBotApi_Subtitle case .unsupported: titleText = strings.Stars_Transaction_Unsupported_Title } - if !transaction.media.isEmpty { + + if let floodskipNumber = transaction.floodskipNumber { + descriptionText = strings.Stars_Transaction_TelegramBotApi_Messages(floodskipNumber) + } else if !transaction.media.isEmpty { var description: String = "" var photoCount: Int32 = 0 var videoCount: Int32 = 0 diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsListPanelComponent.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsListPanelComponent.swift index d159370a9d..88612faaa5 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsListPanelComponent.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsListPanelComponent.swift @@ -360,7 +360,11 @@ final class StarsTransactionsListPanelComponent: Component { itemSubtitle = environment.strings.Stars_Intro_Transaction_TelegramAds_Subtitle case .apiLimitExtension: itemTitle = environment.strings.Stars_Intro_Transaction_TelegramBotApi_Title - itemSubtitle = environment.strings.Stars_Intro_Transaction_TelegramBotApi_Subtitle + if let floodskipNumber = item.floodskipNumber { + itemSubtitle = environment.strings.Stars_Intro_Transaction_TelegramBotApi_Messages(floodskipNumber) + } else { + itemSubtitle = nil + } case .unsupported: itemTitle = environment.strings.Stars_Intro_Transaction_Unsupported_Title itemSubtitle = nil diff --git a/submodules/TelegramUI/Images.xcassets/Premium/Stars/PaidBroadcast.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Premium/Stars/PaidBroadcast.imageset/Contents.json new file mode 100644 index 0000000000..84dca5328a --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Premium/Stars/PaidBroadcast.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "paidbroadcast.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Premium/Stars/PaidBroadcast.imageset/paidbroadcast.pdf b/submodules/TelegramUI/Images.xcassets/Premium/Stars/PaidBroadcast.imageset/paidbroadcast.pdf new file mode 100644 index 0000000000..49f4200193 Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Premium/Stars/PaidBroadcast.imageset/paidbroadcast.pdf differ