Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2024-11-30 00:59:10 +04:00
commit b8b0836d75
9 changed files with 264 additions and 138 deletions

View File

@ -13312,3 +13312,131 @@ Sorry for the inconvenience.";
"MediaPicker.InvertCaption.Updated.Up.Text" = "Text will be shown above the media.";
"MediaPicker.InvertCaption.Updated.Down.Title" = "Caption moved down";
"MediaPicker.InvertCaption.Updated.Down.Text" = "Text will be shown below the media.";
"AffiliateSetup.AlertTerminate.Title" = "Warning";
"AffiliateSetup.AlertTerminate.Text" = "If you end your affiliate program:\n\n• Any referral links already shared will be disabled in 24 hours.\n\n• All participating affiliates will be notified.\n\n• You will be able to start a new affiliate program only in 24 hours.";
"AffiliateSetup.AlertTerminate.Action" = "End Anyway";
"AffiliateSetup.AlertApply.Title" = "Warning";
"AffiliateSetup.AlertApply.Text" = "Once you start the affiliate program, you won't be able to decrease its commission or duration. You can only increase these parameters or end the program, whuch will disable all previously distributed referral links.";
"AffiliateSetup.AlertApply.SectionCommission" = "Commission";
"AffiliateSetup.AlertApply.SectionDuration" = "Duration";
"AffiliateSetup.AlertApply.Action" = "Start";
"AffiliateSetup.ToastTerminated.Title" = "Affiliate Program Ended";
"AffiliateSetup.ToastTerminated.Text" = "Participating affiliates have been notified. All referral links will be disabled in 24 hours.";
"AffiliateSetup.SectionDuration" = "DURATION";
"AffiliateSetup.SectionDurationFooter" = "Set the duration for which affiliates will earn commissions from referred users.";
"AffiliateSetup.SectionCommission" = "COMMISSION";
"AffiliateSetup.SectionCommissionFooter" = "Define the percentage of star revenue your affiliates earn for referring users to your bot.";
"AffiliateSetup.ExistingPrograms.Action" = "View Existing Programs";
"AffiliateSetup.ExistingPrograms.Footer" = "Explore what other mini apps offer.";
"AffiliateSetup.EndAction" = "End Affiliate Program";
"AffiliateSetup.StartTitle" = "Start Affiliate Program";
"AffiliateSetup.UpdateTitle" = "Update Affiliate Program";
"AffiliateSetup.TermsFooter" = "By creating an affiliate program, you afree to the [terms and conditions](https://telegram.org/terms) of Affiliate Programs.";
"AffiliateSetup.ProgramMenu.OpenBot" = "Open Bot";
"AffiliateSetup.ProgramMenu.OpenApp" = "Open App";
"AffiliateSetup.ProgramMenu.CopyLink" = "Copy Link";
"AffiliateSetup.ProgramMenu.Leave" = "Leave";
"AffiliateSetup.ProgramLeave" = "Leave";
"AffiliateSetup.ConnectedSectionTitle" = "MY PROGRAMS";
"AffiliateSetup.SuggestedSectionTitle" = "PROGRAMS";
"AffiliateSetup.SuggestedSectionEmpty" = "No available programs yet.\nPlease check the page later.";
"AffiliateSetup.TitleNew" = "Affiliate Program";
"AffiliateSetup.TextNew" = "Affiliate Program";
"AffiliateSetup.TitleJoin" = "Affiliate Programs";
"AffiliateSetup.TextJoin" = "Earn a commission each time a user who first accessed a mini app through your referral link spends **Stars** within it.";
"AffiliateSetup.IntroNew.Title1" = "Share revenue with affiliates";
"AffiliateSetup.IntroNew.Text1" = "Set the commission for revenue generated by users referred to you.";
"AffiliateSetup.IntroNew.Title2" = "Launch your affiliate program";
"AffiliateSetup.IntroNew.Text2" = "Telegram will feature your program for millions of potential affiliates.";
"AffiliateSetup.IntroNew.Title3" = "Let affiliates promote you";
"AffiliateSetup.IntroNew.Text3" = "Affiliates will share your referral link with their audience.";
"AffiliateSetup.IntroJoin.Title1" = "Reliable";
"AffiliateSetup.IntroJoin.Text1" = "Receive guaranteed commissions for spending by users you refer.";
"AffiliateSetup.IntroJoin.Title2" = "Transparent";
"AffiliateSetup.IntroJoin.Text2" = "Track your commissions from referred users in real time.";
"AffiliateSetup.IntroJoin.Title3" = "Simple";
"AffiliateSetup.IntroJoin.Text3" = "Choose a mini app below, get your referral link, and start earning Stars.";
"AffiliateProgram.ToastLinkCopied.Title" = "Link copied to clipboard";
"AffiliateProgram.ToastLinkCopied.Text" = "Share this link and earn **%1$@** of what people who use it spend in **%2$@!";
"AffiliateProgram.DurationLifetime" = "Lifetime";
"AffiliateProgram.SortSelectorProfitability" = "Profitability";
"AffiliateProgram.SortSelectorRevenue" = "Revenue";
"AffiliateProgram.SortSelectorDate" = "Date";
"AffiliateProgram.ValueShortMonths_1" = "%@m";
"AffiliateProgram.ValueShortMonths_any" = "%@m";
"AffiliateProgram.ValueShortYears_1" = "%@y";
"AffiliateProgram.ValueShortYears_any" = "%@y";
"AffiliateProgram.ValueLongMonths_1" = "%@ MONTH";
"AffiliateProgram.ValueLongMonths_any" = "%@ MONTHS";
"AffiliateProgram.ValueLongYears_1" = "%@ YEAR";
"AffiliateProgram.ValueLongYears_any" = "%@ YEARS";
"AffiliateProgram.PeerTypeSelf" = "personal account";
"AffiliateProgram.JoinTitle" = "Affiliate Program";
"AffiliateProgram.JoinTerms" = "By joining this program, you afree to the [terms and conditions](https://telegram.org/terms) of Affiliate Programs.";
"AffiliateProgram.DailyRevenueText" = "The average daily revenue per user: #**%@**";
"AffiliateProgram.LinkTitle" = "Referral Link";
"AffiliateProgram.LinkSubtitleLifetime" = "Share this link with your users to earn a **{commission}** commission on their spending in **{bot}** **forever** after they follow your link.";
"AffiliateProgram.LinkSubtitleMonths_1" = "Share this link with your users to earn a **{commission}** commission on their spending in **{bot}** for **1 month** after they follow your link.";
"AffiliateProgram.LinkSubtitleMonths_any" = "Share this link with your users to earn a **{commission}** commission on their spending in **{bot}** for **%d months** after they follow your link.";
"AffiliateProgram.LinkSubtitleYears_1" = "Share this link with your users to earn a **{commission}** commission on their spending in **{bot}** for **1 year** after they follow your link.";
"AffiliateProgram.LinkSubtitleYears_any" = "Share this link with your users to earn a **{commission}** commission on their spending in **{bot}** for **%d years** after they follow your link.";
"AffiliateProgram.JoinSubtitleLifetime" = "**{bot}** will share **{commission}** of the revenue from each user you refer to it **forever**.";
"AffiliateProgram.JoinSubtitleMonths_1" = "**{bot}** will share **{commission}** of the revenue from each user you refer to it for **1 month.**";
"AffiliateProgram.JoinSubtitleMonths_any" = "**{bot}** will share **{commission}** of the revenue from each user you refer to it for **%d months.**";
"AffiliateProgram.JoinSubtitleYears_1" = "**{bot}** will share **{commission}** of the revenue from each user you refer to it for **1 month.**";
"AffiliateProgram.JoinSubtitleYears_any" = "**{bot}** will share **{commission}** of the revenue from each user you refer to it for **%d months.**";
"AffiliateProgram.CommistionDestinationText" = "Commission will be sent to:";
"AffiliateProgram.ActionJoin" = "Join Program";
"AffiliateProgram.ActionCopyLink" = "Copy Link";
"AffiliateProgram.ToastJoined.Title" = "Program joined";
"AffiliateProgram.ToastJoined.Text" = "You can now copy the referral link.";
"AffiliateSetup.SortSectionHeader.Date" = "SORT BY [DATE]()";
"AffiliateSetup.SortSectionHeader.Profitability" = "SORT BY [PROFITABILITY]()";
"AffiliateSetup.SortSectionHeader.Revenue" = "SORT BY [REVENUE]()";
"AffiliateProgram.UserCountFooter_0" = "No one opened {bot} through this link yet.";
"AffiliateProgram.UserCountFooter_1" = "1 user opened {bot} through this link.";
"AffiliateProgram.UserCountFooter_any" = "%d users opened {bot} through this link.";
"ChatList.InlineButtonOpenApp" = "OPEN";
"Monetization.EarnStarsInfo.Title" = "Earn Stars";
"Monetization.EarnStarsInfo.Text" = "Distribute links to mini apps and earn a share of their revenue in Stars.";
"PeerInfo.ItemAffiliateProgram.Title" = "Affiliate Program";
"PeerInfo.ItemAffiliatePrograms.Title" = "Affiliate Programs";
"PeerInfo.ItemAffiliateProgram.Footer" = "Share a link to %1$@ with your friends and and earn %2$@% of their spending there.";
"PeerInfo.ItemAffiliateProgram.ValueOff" = "Off";
"StarsTransaction.TitleCommission" = "%@% Commission";
"StarsTransaction.StarRefReason.Title" = "Reason";
"StarsTransaction.StarRefReason.Program" = "Affiliate Program";
"StarsTransaction.StarRefReason.Miniapp" = "Mini App";
"StarsTransaction.StarRefReason.Affiliate" = "Affiliate";
"StarsTransaction.StarRefReason.Referred" = "Referred User";

View File

@ -1186,7 +1186,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
guard let self else {
return
}
//TODO:localize
self.context.sharedContext.openWebApp(
context: self.context,
parentController: self,

View File

@ -3098,8 +3098,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
var actionButtonTitleNodeLayoutAndApply: (TextNodeLayout, () -> TextNode)?
if case .none = badgeContent, case .none = mentionBadgeContent, case let .chat(itemPeer) = contentPeer, case let .user(user) = itemPeer.chatMainPeer, let botInfo = user.botInfo, botInfo.flags.contains(.hasWebApp) {
//TODO:localize
actionButtonTitleNodeLayoutAndApply = makeActionButtonTitleNodeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "OPEN", font: Font.semibold(15.0), textColor: theme.unreadBadgeActiveTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: rawContentWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
actionButtonTitleNodeLayoutAndApply = makeActionButtonTitleNodeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.ChatList_InlineButtonOpenApp, font: Font.semibold(15.0), textColor: theme.unreadBadgeActiveTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: rawContentWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
}
var badgeSize: CGFloat = 0.0

View File

@ -1219,8 +1219,7 @@ private enum StatsEntry: ItemListNodeEntry {
arguments.presentCpmLocked()
})
case .earnStarsInfo:
//TODO:localize
return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.earnStars, title: "Earn Stars", titleBadge: presentationData.strings.Settings_New, label: "Distribute links to mini apps and earn a share of their revenue in Stars.", labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, action: {
return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.earnStars, title: presentationData.strings.Monetization_EarnStarsInfo_Title, titleBadge: presentationData.strings.Settings_New, label: presentationData.strings.Monetization_EarnStarsInfo_Text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, action: {
arguments.openEarnStars()
})
}
@ -1702,7 +1701,6 @@ private func monetizationEntries(
if displayStarsTransactions {
if !addedTransactionsTabs {
if canJoinRefPrograms {
//TODO:localize
entries.append(.earnStarsInfo)
}

View File

@ -43,6 +43,23 @@ private func textForTimeout(value: Int32) -> String {
}
}
private func textForDurationMonths(strings: PresentationStrings, value: Int) -> (short: String, full: String) {
if value >= Int(Int32.max) {
return ("", strings.AffiliateProgram_DurationLifetime.uppercased())
}
if value > 12 {
return (
strings.AffiliateProgram_ValueShortYears(Int32(value / 12)),
strings.AffiliateProgram_ValueLongYears(Int32(value / 12))
)
} else {
return (
strings.AffiliateProgram_ValueShortMonths(Int32(value)),
strings.AffiliateProgram_ValueLongMonths(Int32(value))
)
}
}
final class AffiliateProgramSetupScreenComponent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
@ -181,25 +198,25 @@ final class AffiliateProgramSetupScreenComponent: Component {
if let durationMonths = programDuration {
durationTitle = timeIntervalString(strings: environment.strings, value: durationMonths * (30 * 24 * 60 * 60))
} else {
durationTitle = "Lifetime"
durationTitle = environment.strings.AffiliateProgram_DurationLifetime
}
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
self.environment?.controller()?.present(tableAlert(
theme: presentationData.theme,
title: "Warning",
text: "Once you start the affiliate program, you won't be able to decrease its commission or duration. You can only increase these parameters or end the program, whuch will disable all previously distributed referral links.",
title: environment.strings.AffiliateSetup_AlertApply_Title,
text: environment.strings.AffiliateSetup_AlertApply_Text,
table: TableComponent(theme: environment.theme, items: [
TableComponent.Item(id: 0, title: "Commission", component: AnyComponent(MultilineTextComponent(
TableComponent.Item(id: 0, title: environment.strings.AffiliateSetup_AlertApply_SectionCommission, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: commissionTitle, font: Font.regular(17.0), textColor: environment.theme.actionSheet.primaryTextColor))
))),
TableComponent.Item(id: 1, title: "Duration", component: AnyComponent(MultilineTextComponent(
TableComponent.Item(id: 1, title: environment.strings.AffiliateSetup_AlertApply_SectionDuration, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: durationTitle, font: Font.regular(17.0), textColor: environment.theme.actionSheet.primaryTextColor))
)))
]),
actions: [
ComponentAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}),
ComponentAlertAction(type: .defaultAction, title: "Start", action: { [weak self] in
ComponentAlertAction(type: .genericAction, title: environment.strings.Common_Cancel, action: {}),
ComponentAlertAction(type: .defaultAction, title: environment.strings.AffiliateSetup_AlertApply_Action, action: { [weak self] in
guard let self else {
return
}
@ -210,26 +227,17 @@ final class AffiliateProgramSetupScreenComponent: Component {
}
private func requestApplyEndProgram() {
guard let component = self.component else {
guard let component = self.component, let environment = self.environment else {
return
}
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
self.environment?.controller()?.present(standardTextAlertController(
theme: AlertControllerTheme(presentationData: presentationData),
title: "Warning",
text:
"""
If you end your affiliate program:
Any referral links already shared will be disabled in 24 hours.
All participating affiliates will be notified.
You will be able to start a new affiliate program only in 24 hours.
""",
title: environment.strings.AffiliateSetup_AlertTerminate_Title,
text: environment.strings.AffiliateSetup_AlertTerminate_Text,
actions: [
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}),
TextAlertAction(type: .defaultDestructiveAction, title: "End Anyway", action: { [weak self] in
TextAlertAction(type: .defaultDestructiveAction, title: environment.strings.AffiliateSetup_AlertTerminate_Action, action: { [weak self] in
guard let self else {
return
}
@ -291,7 +299,7 @@ If you end your affiliate program:
program: nil
)
|> deliverOnMainQueue).startStrict(completed: { [weak self] in
guard let self, let component = self.component, let controller = self.environment?.controller() else {
guard let self, let component = self.component, let environment = self.environment, let controller = self.environment?.controller() else {
return
}
self.isApplying = false
@ -300,7 +308,7 @@ If you end your affiliate program:
if let navigationController = controller.navigationController, let index = navigationController.viewControllers.firstIndex(where: { $0 === controller }), index != 0 {
if let previousController = navigationController.viewControllers[index - 1] as? ViewController {
previousController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_link_broken", scale: 0.065, colors: [:], title: "Affiliate Program Ended", text: "Participating affiliates have been notified. All referral links will be disabled in 24 hours.", customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
previousController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_link_broken", scale: 0.065, colors: [:], title: environment.strings.AffiliateSetup_ToastTerminated_Title, text: environment.strings.AffiliateSetup_ToastTerminated_Text, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}
}
controller.dismiss()
@ -378,7 +386,7 @@ If you end your affiliate program:
}
UIPasteboard.general.string = bot.url
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
self.environment?.controller()?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: "Link copied to clipboard", text: "Share this link and earn **\(formatPermille(bot.commissionPermille))%** of what people who use it spend in **\(bot.peer.compactDisplayTitle)**!"), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
self.environment?.controller()?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: presentationData.strings.AffiliateProgram_ToastLinkCopied_Title, text: presentationData.strings.AffiliateProgram_ToastLinkCopied_Text(formatPermille(bot.commissionPermille), bot.peer.compactDisplayTitle).string), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}
))
))
@ -417,9 +425,9 @@ If you end your affiliate program:
var items: [ContextMenuItem] = []
let availableModes: [(TelegramSuggestedStarRefBotList.SortMode, String)] = [
(.profitability, "Profitability"),
(.revenue, "Revenue"),
(.date, "Date")
(.profitability, environment.strings.AffiliateProgram_SortSelectorProfitability),
(.revenue, environment.strings.AffiliateProgram_SortSelectorRevenue),
(.date, environment.strings.AffiliateProgram_SortSelectorDate)
]
for (mode, title) in availableModes {
let isSelected = mode == self.suggestedSortMode
@ -483,14 +491,14 @@ If you end your affiliate program:
self.isUpdating = false
}
let durationItems: [(months: Int32, title: String, selectedTitle: String)] = [
(1, "1m", "1 MONTH"),
(3, "3m", "3 MONTHS"),
(6, "6m", "6 MONTHS"),
(12, "1y", "1 YEAR"),
(2 * 12, "2y", "2 YEARS"),
(3 * 12, "3y", "3 YEARS"),
(Int32.max, "", "LIFETIME")
let durationItems: [Int32] = [
1,
3,
6,
12,
2 * 12,
3 * 12,
Int32.max
]
let environment = environment[EnvironmentType.self].value
@ -630,11 +638,11 @@ If you end your affiliate program:
let subtitleValue: String
switch component.initialContent.mode {
case .editProgram:
titleValue = "Affiliate Program"
subtitleValue = "Reward those who help grow your userbase."
titleValue = environment.strings.AffiliateSetup_TitleNew
subtitleValue = environment.strings.AffiliateSetup_TextNew
case .connectedPrograms:
titleValue = "Affiliate Programs"
subtitleValue = "Earn a commission each time a user who first accessed a mini app through your referral link spends **Stars** within it."
titleValue = environment.strings.AffiliateSetup_TitleJoin
subtitleValue = environment.strings.AffiliateSetup_TextJoin
}
let titleSize = self.title.update(
transition: .immediate,
@ -696,36 +704,36 @@ If you end your affiliate program:
introItems = [
(
"Chat/Context Menu/Smile",
"Share revenue with affiliates",
"Set the commission for revenue generated by users referred to you."
environment.strings.AffiliateSetup_IntroNew_Title1,
environment.strings.AffiliateSetup_IntroNew_Text1
),
(
"Chat/Context Menu/Channels",
"Launch your affiliate program",
"Telegram will feature your program for millions of potential affiliates."
environment.strings.AffiliateSetup_IntroNew_Title2,
environment.strings.AffiliateSetup_IntroNew_Text2
),
(
"Chat/Context Menu/Link",
"Let affiliates promote you",
"Affiliates will share your referral link with their audience."
environment.strings.AffiliateSetup_IntroNew_Title3,
environment.strings.AffiliateSetup_IntroNew_Text3
)
]
case .connectedPrograms:
introItems = [
(
"Peer Info/RefProgram/IntroListSecure",
"Reliable",
"Receive guaranteed commissions for spending by users you refer."
environment.strings.AffiliateSetup_IntroJoin_Title1,
environment.strings.AffiliateSetup_IntroJoin_Text1
),
(
"Peer Info/RefProgram/IntroListEye",
"Transparent",
"Track your commissions from referred users in real time."
environment.strings.AffiliateSetup_IntroJoin_Title2,
environment.strings.AffiliateSetup_IntroJoin_Text2
),
(
"Peer Info/RefProgram/IntroListLike",
"Simple",
"Choose a mini app below, get your referral link, and start earning Stars."
environment.strings.AffiliateSetup_IntroJoin_Title3,
environment.strings.AffiliateSetup_IntroJoin_Text3
)
]
}
@ -855,7 +863,7 @@ If you end your affiliate program:
theme: environment.theme,
header: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "COMMISSION",
string: environment.strings.AffiliateSetup_SectionCommission,
font: Font.regular(13.0),
textColor: environment.theme.list.freeTextColor
)),
@ -863,7 +871,7 @@ If you end your affiliate program:
)),
footer: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Define the percentage of star revenue your affiliates earn for referring users to your bot.",
string: environment.strings.AffiliateSetup_SectionCommissionFooter,
font: Font.regular(13.0),
textColor: environment.theme.list.freeTextColor
)),
@ -911,10 +919,10 @@ If you end your affiliate program:
var selectedDurationIndex = 0
var durationMinValueIndex = 0
for i in 0 ..< durationItems.count {
if self.durationValue == Int(durationItems[i].months) {
if self.durationValue == Int(durationItems[i]) {
selectedDurationIndex = i
}
if self.durationMinValue == Int(durationItems[i].months) {
if self.durationMinValue == Int(durationItems[i]) {
durationMinValueIndex = i
}
}
@ -925,7 +933,7 @@ If you end your affiliate program:
header: AnyComponent(HStack([
AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "DURATION",
string: environment.strings.AffiliateSetup_SectionDuration,
font: Font.regular(13.0),
textColor: environment.theme.list.freeTextColor
)),
@ -933,7 +941,7 @@ If you end your affiliate program:
))),
AnyComponentWithIdentity(id: 1, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: durationItems[selectedDurationIndex].selectedTitle,
string: textForDurationMonths(strings: environment.strings, value: Int(durationItems[selectedDurationIndex])).full,
font: Font.regular(13.0),
textColor: environment.theme.list.freeTextColor
)),
@ -942,7 +950,7 @@ If you end your affiliate program:
], spacing: 4.0, alignment: .alternatingLeftRight)),
footer: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Set the duration for which affiliates will earn commissions from referred users.",
string: environment.strings.AffiliateSetup_SectionDurationFooter,
font: Font.regular(13.0),
textColor: environment.theme.list.freeTextColor
)),
@ -952,7 +960,9 @@ If you end your affiliate program:
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemSliderSelectorComponent(
theme: environment.theme,
content: .discrete(ListItemSliderSelectorComponent.Discrete(
values: durationItems.map(\.title),
values: durationItems.map {
textForDurationMonths(strings: environment.strings, value: Int($0)).short
},
markPositions: true,
selectedIndex: max(durationMinValueIndex, selectedDurationIndex),
minSelectedIndex: durationMinValueIndex,
@ -961,7 +971,7 @@ If you end your affiliate program:
guard let self else {
return
}
self.durationValue = Int(durationItems[value].months)
self.durationValue = Int(durationItems[value])
self.state?.updated(transition: .immediate)
}
))
@ -990,7 +1000,7 @@ If you end your affiliate program:
header: nil,
footer: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Explore what other mini apps offer.",
string: environment.strings.AffiliateSetup_ExistingPrograms_Footer,
font: Font.regular(13.0),
textColor: environment.theme.list.freeTextColor
)),
@ -1002,7 +1012,7 @@ If you end your affiliate program:
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "View Existing Programs",
string: environment.strings.AffiliateSetup_ExistingPrograms_Action,
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemPrimaryTextColor
)),
@ -1045,7 +1055,7 @@ If you end your affiliate program:
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "End Affiliate Program",
string: environment.strings.AffiliateSetup_EndAction,
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemDestructiveColor
)),
@ -1086,7 +1096,7 @@ If you end your affiliate program:
transition: .immediate,
component: AnyComponent(MultilineTextComponent(
text: .markdown(
text: "By creating an affiliate program, you afree to the [terms and conditions](https://telegram.org/terms) of Affiliate Programs.",
text: environment.strings.AffiliateSetup_TermsFooter,
attributes: MarkdownAttributes(
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.itemSecondaryTextColor),
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: environment.theme.list.itemSecondaryTextColor),
@ -1111,9 +1121,9 @@ If you end your affiliate program:
let remainingTime: Int32 = max(0, endDate - timestamp)
buttonText = textForTimeout(value: remainingTime)
} else if self.currentProgram != nil {
buttonText = "Update Affiliate Program"
buttonText = environment.strings.AffiliateSetup_UpdateTitle
} else {
buttonText = "Start Affiliate Program"
buttonText = environment.strings.AffiliateSetup_StartTitle
}
let bottomPanelButtonSize = self.bottomPanelButton.update(
transition: transition,
@ -1187,7 +1197,7 @@ If you end your affiliate program:
if let durationMonths = item.durationMonths {
durationTitle = timeIntervalString(strings: environment.strings, value: durationMonths * (30 * 24 * 60 * 60))
} else {
durationTitle = "Lifetime"
durationTitle = environment.strings.AffiliateProgram_DurationLifetime
}
let commissionTitle = "\(formatPermille(item.commissionPermille))%"
@ -1201,9 +1211,9 @@ If you end your affiliate program:
let openTitle: String
if case let .user(user) = item.peer, let botInfo = user.botInfo, botInfo.flags.contains(.hasWebApp) {
openTitle = "Open App"
openTitle = environment.strings.AffiliateSetup_ProgramMenu_OpenApp
} else {
openTitle = "Open Bot"
openTitle = environment.strings.AffiliateSetup_ProgramMenu_OpenBot
}
itemList.append(.action(ContextMenuActionItem(text: openTitle, textColor: .primary, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Bots"), color: theme.contextMenu.primaryColor)
@ -1239,7 +1249,7 @@ If you end your affiliate program:
})
})))
itemList.append(.action(ContextMenuActionItem(text: "Copy Link", textColor: .primary, icon: { theme in
itemList.append(.action(ContextMenuActionItem(text: environment.strings.AffiliateSetup_ProgramMenu_CopyLink, textColor: .primary, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.default)
@ -1251,10 +1261,10 @@ If you end your affiliate program:
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
UIPasteboard.general.string = item.url
environment.controller()?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: "Link copied to clipboard", text: "Share this link and earn **\(formatPermille(item.commissionPermille))%** of what people who use it spend in **\(item.peer.compactDisplayTitle)**!"), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
environment.controller()?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: environment.strings.AffiliateProgram_ToastLinkCopied_Title, text: environment.strings.AffiliateProgram_ToastLinkCopied_Text(formatPermille(item.commissionPermille), item.peer.compactDisplayTitle ).string), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
})))
itemList.append(.action(ContextMenuActionItem(text: "Leave", textColor: .destructive, icon: { theme in
itemList.append(.action(ContextMenuActionItem(text: environment.strings.AffiliateSetup_ProgramMenu_Leave, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
}, action: { [weak self] c, _ in
c?.dismiss(completion: {
@ -1314,7 +1324,7 @@ If you end your affiliate program:
self.openConnectedBot(bot: item)
},
inlineActions: PeerListItemComponent.InlineActionsState(actions: [
PeerListItemComponent.InlineAction(id: 0, title: "Leave", color: .destructive, action: { [weak self] in
PeerListItemComponent.InlineAction(id: 0, title: environment.strings.AffiliateSetup_ProgramLeave, color: .destructive, action: { [weak self] in
guard let self else {
return
}
@ -1333,7 +1343,7 @@ If you end your affiliate program:
theme: environment.theme,
header: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "MY PROGRAMS",
string: environment.strings.AffiliateSetup_ConnectedSectionTitle,
font: Font.regular(13.0),
textColor: environment.theme.list.freeTextColor
)),
@ -1369,7 +1379,7 @@ If you end your affiliate program:
suggestedSectionItems.append(AnyComponentWithIdentity(id: "empty", component: AnyComponent(ZStack([
AnyComponentWithIdentity(id: 0, component: AnyComponent(Rectangle(color: .clear, width: nil, height: 100.0))),
AnyComponentWithIdentity(id: 1, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "No available programs yet.\nPlease check the page later.", font: Font.regular(15.0), textColor: environment.theme.list.itemSecondaryTextColor)),
text: .plain(NSAttributedString(string: environment.strings.AffiliateSetup_SuggestedSectionEmpty, font: Font.regular(15.0), textColor: environment.theme.list.itemSecondaryTextColor)),
horizontalAlignment: .center,
maximumNumberOfLines: 0,
lineSpacing: 0.2
@ -1382,7 +1392,7 @@ If you end your affiliate program:
if let durationMonths = item.program.durationMonths {
durationTitle = timeIntervalString(strings: environment.strings, value: durationMonths * (30 * 24 * 60 * 60))
} else {
durationTitle = "Lifetime"
durationTitle = environment.strings.AffiliateProgram_DurationLifetime
}
suggestedSectionItems.append(AnyComponentWithIdentity(id: item.peer.id, component: AnyComponent(PeerListItemComponent(
@ -1476,7 +1486,7 @@ If you end your affiliate program:
var suggestedHeaderItems: [AnyComponentWithIdentity<Empty>] = []
suggestedHeaderItems.append(AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "PROGRAMS",
string: environment.strings.AffiliateSetup_SuggestedSectionTitle,
font: Font.regular(13.0),
textColor: environment.theme.list.freeTextColor
)),

View File

@ -365,11 +365,11 @@ private final class JoinAffiliateProgramScreenComponent: Component {
for peer in peers {
let peerLabel: String
if peer.id == component.context.account.peerId {
peerLabel = "personal account"
peerLabel = environment.strings.AffiliateProgram_PeerTypeSelf
} else if case .channel = peer {
peerLabel = "channel"
peerLabel = environment.strings.Channel_Status
} else {
peerLabel = "bot"
peerLabel = environment.strings.Bot_GenericBotStatus
}
let isSelected = peer.id == self.currentTargetPeer?.id
let accentColor = environment.theme.list.itemAccentColor
@ -767,12 +767,6 @@ private final class JoinAffiliateProgramScreenComponent: Component {
}
let commissionTitle = "\(formatPermille(component.commissionPermille))%"
let durationTitle: String
if let durationMonths = component.programDuration {
durationTitle = timeIntervalString(strings: environment.strings, value: durationMonths * (24 * 60 * 60))
} else {
durationTitle = "lifetime"
}
let titleString: String
var subtitleString: String
@ -780,34 +774,40 @@ private final class JoinAffiliateProgramScreenComponent: Component {
let termsString: String
switch currentMode {
case .join:
titleString = "Affiliate Program"
subtitleString = "**\(component.sourcePeer.compactDisplayTitle)** will share **\(commissionTitle)** of the revenue from each user you refer to it for **\(durationTitle)**."
titleString = environment.strings.AffiliateProgram_JoinTitle
if let programDuration = component.programDuration {
if programDuration < 12 {
subtitleString = environment.strings.AffiliateProgram_JoinSubtitleMonths(Int32(programDuration)).replacingOccurrences(of: "{bot}", with: component.sourcePeer.compactDisplayTitle).replacingOccurrences(of: "{commission}", with: commissionTitle)
} else {
subtitleString = environment.strings.AffiliateProgram_JoinSubtitleYears(Int32(programDuration / 12)).replacingOccurrences(of: "{bot}", with: component.sourcePeer.compactDisplayTitle).replacingOccurrences(of: "{commission}", with: commissionTitle)
}
} else {
subtitleString = environment.strings.AffiliateProgram_JoinSubtitleLifetime.replacingOccurrences(of: "{bot}", with: component.sourcePeer.compactDisplayTitle).replacingOccurrences(of: "{commission}", with: commissionTitle)
}
if component.revenuePerUser != 0.0 {
var revenueString = String(format: "%.1f", component.revenuePerUser)
if revenueString.hasSuffix(".0") {
revenueString = String(revenueString[revenueString.startIndex ..< revenueString.index(revenueString.endIndex, offsetBy: -2)])
}
dailyRevenueString = "Daily revenue per user: #**\(revenueString)**"
dailyRevenueString = environment.strings.AffiliateProgram_DailyRevenueText(revenueString).string
}
termsString = "By joining this program, you afree to the [terms and conditions](https://telegram.org/terms) of Affiliate Programs."
termsString = environment.strings.AffiliateProgram_JoinTerms
case let .active(active):
titleString = "Referral Link"
let timeString: String
if component.programDuration == nil {
timeString = "**forever** after they follow your link."
titleString = environment.strings.AffiliateProgram_LinkTitle
if let programDuration = component.programDuration {
if programDuration < 12 {
subtitleString = environment.strings.AffiliateProgram_LinkSubtitleMonths(Int32(programDuration)).replacingOccurrences(of: "{bot}", with: component.sourcePeer.compactDisplayTitle).replacingOccurrences(of: "{commission}", with: commissionTitle)
} else {
subtitleString = environment.strings.AffiliateProgram_LinkSubtitleYears(Int32(programDuration / 12)).replacingOccurrences(of: "{bot}", with: component.sourcePeer.compactDisplayTitle).replacingOccurrences(of: "{commission}", with: commissionTitle)
}
} else {
timeString = "for **\(durationTitle)** after they follow your link."
}
subtitleString = "Share this link with your users to earn a **\(commissionTitle)** commission on their spending in **\(component.sourcePeer.compactDisplayTitle)** \(timeString)."
if active.bot.participants == 0 {
termsString = "No one opened \(component.sourcePeer.compactDisplayTitle) through this link yet."
} else if active.bot.participants == 1 {
termsString = "1 user opened \(component.sourcePeer.compactDisplayTitle) through this link."
} else {
termsString = "\(active.bot.participants) users opened \(component.sourcePeer.compactDisplayTitle) through this link."
subtitleString = environment.strings.AffiliateProgram_LinkSubtitleLifetime.replacingOccurrences(of: "{bot}", with: component.sourcePeer.compactDisplayTitle).replacingOccurrences(of: "{commission}", with: commissionTitle)
}
termsString = environment.strings.AffiliateProgram_UserCountFooter(Int32(active.bot.participants)).replacingOccurrences(of: "{bot}", with: component.sourcePeer.compactDisplayTitle)
}
let titleSize = self.title.update(
transition: .immediate,
@ -986,7 +986,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
let targetTextSize = self.targetText.update(
transition: .immediate,
component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "Commission will be sent to:", font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor)),
text: .plain(NSAttributedString(string: environment.strings.AffiliateProgram_CommistionDestinationText, font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor)),
horizontalAlignment: .center,
maximumNumberOfLines: 0,
lineSpacing: 0.2
@ -1087,9 +1087,9 @@ private final class JoinAffiliateProgramScreenComponent: Component {
let actionButtonTitle: String
switch currentMode {
case .join:
actionButtonTitle = "Join Program"
actionButtonTitle = environment.strings.AffiliateProgram_ActionJoin
case .active:
actionButtonTitle = "Copy Link"
actionButtonTitle = environment.strings.AffiliateProgram_ActionCopyLink
}
let actionButtonSize = self.actionButton.update(
transition: transition,
@ -1207,11 +1207,11 @@ private final class JoinAffiliateProgramScreenComponent: Component {
)),
content: AnyComponent(VStack([
AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
text: .markdown(text: "Program joined", attributes: MarkdownAttributes(body: bold, bold: bold, link: body, linkAttribute: { _ in nil })),
text: .markdown(text: environment.strings.AffiliateProgram_ToastJoined_Title, attributes: MarkdownAttributes(body: bold, bold: bold, link: body, linkAttribute: { _ in nil })),
maximumNumberOfLines: 0
))),
AnyComponentWithIdentity(id: 1, component: AnyComponent(MultilineTextComponent(
text: .markdown(text: "You can now copy the referral link.", attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil })),
text: .markdown(text: environment.strings.AffiliateProgram_ToastJoined_Text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil })),
maximumNumberOfLines: 0
)))
], alignment: .left, spacing: 6.0)),
@ -1920,11 +1920,11 @@ final class BotSectionSortButtonComponent: Component {
let sortByString: String
switch component.sortMode {
case .date:
sortByString = "SORT BY [DATE]()"
sortByString = component.strings.AffiliateSetup_SortSectionHeader_Date
case .profitability:
sortByString = "SORT BY [PROFITABILITY]()"
sortByString = component.strings.AffiliateSetup_SortSectionHeader_Profitability
case .revenue:
sortByString = "SORT BY [REVENUE]()"
sortByString = component.strings.AffiliateSetup_SortSectionHeader_Revenue
}
let textSize = self.text.update(
transition: .immediate,

View File

@ -1443,14 +1443,12 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
if items[.botAffiliateProgram] == nil {
items[.botAffiliateProgram] = []
}
//TODO:localize
let programTitleValue: String
programTitleValue = "\(formatPermille(starRefProgram.commissionPermille))%"
//TODO:localize
items[.botAffiliateProgram]!.append(PeerInfoScreenDisclosureItem(id: 0, label: .labelBadge(programTitleValue), additionalBadgeLabel: nil, text: "Affiliate Program", icon: PresentationResourcesSettings.affiliateProgram, action: {
items[.botAffiliateProgram]!.append(PeerInfoScreenDisclosureItem(id: 0, label: .labelBadge(programTitleValue), additionalBadgeLabel: nil, text: presentationData.strings.PeerInfo_ItemAffiliateProgram_Title, icon: PresentationResourcesSettings.affiliateProgram, action: {
interaction.editingOpenAffiliateProgram()
}))
items[.botAffiliateProgram]!.append(PeerInfoScreenCommentItem(id: 1, text: "Share a link to \(EnginePeer.user(user).compactDisplayTitle) with your friends and and earn \(formatPermille(starRefProgram.commissionPermille))% of their spending there."))
items[.botAffiliateProgram]!.append(PeerInfoScreenCommentItem(id: 1, text: presentationData.strings.PeerInfo_ItemAffiliateProgram_Footer(EnginePeer.user(user).compactDisplayTitle, formatPermille(starRefProgram.commissionPermille)).string))
}
}
}
@ -1960,14 +1958,13 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
}
if canSetupRefProgram {
//TODO:localize
let programTitleValue: PeerInfoScreenDisclosureItem.Label
if let cachedData = data.cachedData as? CachedUserData, let starRefProgram = cachedData.starRefProgram, starRefProgram.endDate == nil {
programTitleValue = .labelBadge("\(formatPermille(starRefProgram.commissionPermille))%")
} else {
programTitleValue = .text("Off")
programTitleValue = .text(presentationData.strings.PeerInfo_ItemAffiliateProgram_ValueOff)
}
items[.peerDataSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAffiliateProgram, label: programTitleValue, additionalBadgeLabel: presentationData.strings.Settings_New, text: "Affiliate Program", icon: PresentationResourcesSettings.affiliateProgram, action: {
items[.peerDataSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAffiliateProgram, label: programTitleValue, additionalBadgeLabel: presentationData.strings.Settings_New, text: presentationData.strings.PeerInfo_ItemAffiliateProgram_Title, icon: PresentationResourcesSettings.affiliateProgram, action: {
interaction.editingOpenAffiliateProgram()
}))
}
@ -2232,7 +2229,7 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
}
if canJoinRefProgram {
items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAffiliatePrograms, label: .text(""), additionalBadgeLabel: presentationData.strings.Settings_New, text: "Affiliate Programs", icon: PresentationResourcesSettings.affiliateProgram, action: {
items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAffiliatePrograms, label: .text(""), additionalBadgeLabel: presentationData.strings.Settings_New, text: presentationData.strings.PeerInfo_ItemAffiliatePrograms_Title, icon: PresentationResourcesSettings.affiliateProgram, action: {
interaction.editingOpenAffiliateProgram()
}))
}
@ -8659,10 +8656,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
guard let self else {
return
}
//TODO:localize
UIPasteboard.general.string = result.url
let presentationData = self.context.sharedContext.currentPresentationData.with({ $0 })
self.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: "Link copied to clipboard", text: "Share this link and earn **\(formatPermille(result.commissionPermille))%** of what people who use it spend in **\(result.peer.compactDisplayTitle)**!"), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
self.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: presentationData.strings.AffiliateProgram_ToastLinkCopied_Title, text: presentationData.strings.AffiliateProgram_ToastLinkCopied_Text(formatPermille(result.commissionPermille), result.peer.compactDisplayTitle).string), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}
))
} else {

View File

@ -404,12 +404,11 @@ private final class StarsTransactionSheetContent: CombinedComponent {
transactionPeer = transaction.peer
isGift = true
} else if let starrefCommissionPermille = transaction.starrefCommissionPermille {
//TODO:localize
isRefProgram = true
if transaction.starrefPeerId == nil {
titleText = "\(formatPermille(starrefCommissionPermille))% Commission"
titleText = strings.StarsTransaction_TitleCommission(formatPermille(starrefCommissionPermille)).string
} else {
titleText = transaction.title ?? "Product"
titleText = transaction.title ?? " "
}
descriptionText = ""
count = transaction.count
@ -868,15 +867,14 @@ private final class StarsTransactionSheetContent: CombinedComponent {
}
if case let .transaction(transaction, _) = subject {
//TODO:localize
if transaction.starrefCommissionPermille != nil {
if transaction.starrefPeerId == nil {
tableItems.append(.init(
id: "reason",
title: "Reason",
title: strings.StarsTransaction_StarRefReason_Title,
component: AnyComponent(
Button(
content: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: "Affiliate Program", font: tableFont, textColor: tableLinkColor))
content: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: strings.StarsTransaction_StarRefReason_Program, font: tableFont, textColor: tableLinkColor))
)),
action: {
if let toPeer {
@ -894,7 +892,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
if let toPeer, transaction.starrefPeerId == nil {
tableItems.append(.init(
id: "miniapp",
title: "Mini App",
title: strings.StarsTransaction_StarRefReason_Miniapp,
component: AnyComponent(
Button(
content: AnyComponent(
@ -923,10 +921,9 @@ private final class StarsTransactionSheetContent: CombinedComponent {
}
}
if let starRefPeerId = transaction.starrefPeerId, let starRefPeer = state.peerMap[starRefPeerId] {
//TODO:localize
tableItems.append(.init(
id: "to",
title: "Affiliate",
title: strings.StarsTransaction_StarRefReason_Affiliate,
component: AnyComponent(
Button(
content: AnyComponent(
@ -955,7 +952,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
if let toPeer {
tableItems.append(.init(
id: "referred",
title: "Referred User",
title: strings.StarsTransaction_StarRefReason_Referred,
component: AnyComponent(
Button(
content: AnyComponent(

View File

@ -679,9 +679,8 @@ final class StarsTransactionsScreenComponent: Component {
header: nil,
footer: nil,
items: [
//TODO:localize
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemComponentAdaptor(
itemGenerator: ItemListDisclosureItem(presentationData: ItemListPresentationData(presentationData), icon: PresentationResourcesSettings.earnStars, title: "Earn Stars", titleBadge: presentationData.strings.Settings_New, label: "Distribute links to mini apps and earn a share of their revenue in Stars.", labelStyle: .multilineDetailText, sectionId: 0, style: .blocks, action: {
itemGenerator: ItemListDisclosureItem(presentationData: ItemListPresentationData(presentationData), icon: PresentationResourcesSettings.earnStars, title: environment.strings.Monetization_EarnStarsInfo_Title, titleBadge: presentationData.strings.Settings_New, label: environment.strings.Monetization_EarnStarsInfo_Text, labelStyle: .multilineDetailText, sectionId: 0, style: .blocks, action: {
}),
params: ListViewItemLayoutParams(width: availableSize.width, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true),
action: { [weak self] in