mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Various improvements
This commit is contained in:
parent
3d6c9b1745
commit
54a90be1f4
@ -11683,6 +11683,7 @@ Sorry for the inconvenience.";
|
|||||||
"Monetization.OverviewTitle" = "PROCEEDS OVERVIEW";
|
"Monetization.OverviewTitle" = "PROCEEDS OVERVIEW";
|
||||||
"Monetization.BalanceTitle" = "AVAILABLE BALANCE";
|
"Monetization.BalanceTitle" = "AVAILABLE BALANCE";
|
||||||
"Monetization.BalanceInfo" = "You will be able to collect rewards using Fragment, a third-party platform used by the advertizer to pay for the ad. [Learn More >]()";
|
"Monetization.BalanceInfo" = "You will be able to collect rewards using Fragment, a third-party platform used by the advertizer to pay for the ad. [Learn More >]()";
|
||||||
|
"Monetization.BalanceInfo_URL" = "https://telegram.org";
|
||||||
"Monetization.BalanceWithdraw" = "Withdraw via Fragment";
|
"Monetization.BalanceWithdraw" = "Withdraw via Fragment";
|
||||||
"Monetization.TransactionsTitle" = "TRANSACTION HISTORY";
|
"Monetization.TransactionsTitle" = "TRANSACTION HISTORY";
|
||||||
|
|
||||||
@ -11695,6 +11696,8 @@ Sorry for the inconvenience.";
|
|||||||
"Monetization.Transaction.Refund" = "Refund";
|
"Monetization.Transaction.Refund" = "Refund";
|
||||||
"Monetization.Transaction.Pending" = "Pending";
|
"Monetization.Transaction.Pending" = "Pending";
|
||||||
"Monetization.Transaction.Failed" = "Not Completed";
|
"Monetization.Transaction.Failed" = "Not Completed";
|
||||||
|
"Monetization.Transaction.ShowMoreTransactions_1" = "Show %@ More Transaction";
|
||||||
|
"Monetization.Transaction.ShowMoreTransactions_any" = "Show %@ More Transactions";
|
||||||
|
|
||||||
"Monetization.SwitchOffAds" = "Switch off Ads";
|
"Monetization.SwitchOffAds" = "Switch off Ads";
|
||||||
"Monetization.SwitchOffAdsInfo" = "You will not be eligible for any rewards if you switch off ads.";
|
"Monetization.SwitchOffAdsInfo" = "You will not be eligible for any rewards if you switch off ads.";
|
||||||
@ -11723,4 +11726,6 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Monetization.Intro.Info.Title" = "What's #TON?";
|
"Monetization.Intro.Info.Title" = "What's #TON?";
|
||||||
"Monetization.Intro.Info.Text" = "TON is a blockchain platform and cryptocurrency that Telegram uses for its record scalability and ultra low commissions on transactions. [Learn More >]()";
|
"Monetization.Intro.Info.Text" = "TON is a blockchain platform and cryptocurrency that Telegram uses for its record scalability and ultra low commissions on transactions. [Learn More >]()";
|
||||||
|
"Monetization.Intro.Info.Text_URL" = "https://ton.org";
|
||||||
|
|
||||||
"Monetization.Intro.Understood" = "Understood";
|
"Monetization.Intro.Understood" = "Understood";
|
||||||
|
@ -6,6 +6,7 @@ import SwiftSignalKit
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import SwitchNode
|
import SwitchNode
|
||||||
import AppBundle
|
import AppBundle
|
||||||
|
import ComponentFlow
|
||||||
|
|
||||||
public enum ItemListSwitchItemNodeType {
|
public enum ItemListSwitchItemNodeType {
|
||||||
case regular
|
case regular
|
||||||
@ -17,6 +18,7 @@ public class ItemListSwitchItem: ListViewItem, ItemListItem {
|
|||||||
let icon: UIImage?
|
let icon: UIImage?
|
||||||
let title: String
|
let title: String
|
||||||
let text: String?
|
let text: String?
|
||||||
|
let titleBadgeComponent: AnyComponent<Empty>?
|
||||||
let value: Bool
|
let value: Bool
|
||||||
let type: ItemListSwitchItemNodeType
|
let type: ItemListSwitchItemNodeType
|
||||||
let enableInteractiveChanges: Bool
|
let enableInteractiveChanges: Bool
|
||||||
@ -31,11 +33,12 @@ public class ItemListSwitchItem: ListViewItem, ItemListItem {
|
|||||||
let activatedWhileDisabled: () -> Void
|
let activatedWhileDisabled: () -> Void
|
||||||
public let tag: ItemListItemTag?
|
public let tag: ItemListItemTag?
|
||||||
|
|
||||||
public init(presentationData: ItemListPresentationData, icon: UIImage? = nil, title: String, text: String? = nil, value: Bool, type: ItemListSwitchItemNodeType = .regular, enableInteractiveChanges: Bool = true, enabled: Bool = true, displayLocked: Bool = false, disableLeadingInset: Bool = false, maximumNumberOfLines: Int = 1, noCorners: Bool = false, sectionId: ItemListSectionId, style: ItemListStyle, updated: @escaping (Bool) -> Void, activatedWhileDisabled: @escaping () -> Void = {}, tag: ItemListItemTag? = nil) {
|
public init(presentationData: ItemListPresentationData, icon: UIImage? = nil, title: String, text: String? = nil, titleBadgeComponent: AnyComponent<Empty>? = nil, value: Bool, type: ItemListSwitchItemNodeType = .regular, enableInteractiveChanges: Bool = true, enabled: Bool = true, displayLocked: Bool = false, disableLeadingInset: Bool = false, maximumNumberOfLines: Int = 1, noCorners: Bool = false, sectionId: ItemListSectionId, style: ItemListStyle, updated: @escaping (Bool) -> Void, activatedWhileDisabled: @escaping () -> Void = {}, tag: ItemListItemTag? = nil) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.title = title
|
self.title = title
|
||||||
self.text = text
|
self.text = text
|
||||||
|
self.titleBadgeComponent = titleBadgeComponent
|
||||||
self.value = value
|
self.value = value
|
||||||
self.type = type
|
self.type = type
|
||||||
self.enableInteractiveChanges = enableInteractiveChanges
|
self.enableInteractiveChanges = enableInteractiveChanges
|
||||||
@ -134,6 +137,8 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
private let switchGestureNode: ASDisplayNode
|
private let switchGestureNode: ASDisplayNode
|
||||||
private var disabledOverlayNode: ASDisplayNode?
|
private var disabledOverlayNode: ASDisplayNode?
|
||||||
|
|
||||||
|
private var titleBadgeComponentView: ComponentView<Empty>?
|
||||||
|
|
||||||
private var lockedIconNode: ASImageNode?
|
private var lockedIconNode: ASImageNode?
|
||||||
|
|
||||||
private let activateArea: AccessibilityAreaNode
|
private let activateArea: AccessibilityAreaNode
|
||||||
@ -471,6 +476,32 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
lockedIconNode.removeFromSupernode()
|
lockedIconNode.removeFromSupernode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let component = item.titleBadgeComponent {
|
||||||
|
let componentView: ComponentView<Empty>
|
||||||
|
if let current = strongSelf.titleBadgeComponentView {
|
||||||
|
componentView = current
|
||||||
|
} else {
|
||||||
|
componentView = ComponentView<Empty>()
|
||||||
|
strongSelf.titleBadgeComponentView = componentView
|
||||||
|
}
|
||||||
|
|
||||||
|
let badgeSize = componentView.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: component,
|
||||||
|
environment: {},
|
||||||
|
containerSize: contentSize
|
||||||
|
)
|
||||||
|
if let view = componentView.view {
|
||||||
|
if view.superview == nil {
|
||||||
|
strongSelf.view.addSubview(view)
|
||||||
|
}
|
||||||
|
view.frame = CGRect(origin: CGPoint(x: strongSelf.titleNode.frame.maxX + 7.0, y: floor((contentSize.height - badgeSize.height) / 2.0)), size: badgeSize)
|
||||||
|
}
|
||||||
|
} else if let componentView = strongSelf.titleBadgeComponentView {
|
||||||
|
strongSelf.titleBadgeComponentView = nil
|
||||||
|
componentView.view?.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: 44.0 + UIScreenPixel + UIScreenPixel))
|
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: 44.0 + UIScreenPixel + UIScreenPixel))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -39,6 +39,7 @@ swift_library(
|
|||||||
"//submodules/TextFormat",
|
"//submodules/TextFormat",
|
||||||
"//submodules/TelegramUI/Components/Stories/AvatarStoryIndicatorComponent",
|
"//submodules/TelegramUI/Components/Stories/AvatarStoryIndicatorComponent",
|
||||||
"//submodules/TelegramUI/Components/Stories/StoryContainerScreen",
|
"//submodules/TelegramUI/Components/Stories/StoryContainerScreen",
|
||||||
|
"//submodules/TelegramUI/Components/Settings/BoostLevelIconComponent",
|
||||||
"//submodules/TelegramUI/Components/PlainButtonComponent",
|
"//submodules/TelegramUI/Components/PlainButtonComponent",
|
||||||
"//submodules/TelegramUI/Components/EmojiTextAttachmentView",
|
"//submodules/TelegramUI/Components/EmojiTextAttachmentView",
|
||||||
"//submodules/Components/SheetComponent",
|
"//submodules/Components/SheetComponent",
|
||||||
|
@ -23,8 +23,11 @@ import ItemListPeerActionItem
|
|||||||
import PremiumUI
|
import PremiumUI
|
||||||
import StoryContainerScreen
|
import StoryContainerScreen
|
||||||
import TelegramNotices
|
import TelegramNotices
|
||||||
|
import ComponentFlow
|
||||||
|
import BoostLevelIconComponent
|
||||||
|
|
||||||
private let initialBoostersDisplayedLimit: Int32 = 5
|
private let initialBoostersDisplayedLimit: Int32 = 5
|
||||||
|
private let initialTransactionsDisplayedLimit: Int32 = 5
|
||||||
|
|
||||||
private final class ChannelStatsControllerArguments {
|
private final class ChannelStatsControllerArguments {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
@ -42,13 +45,14 @@ private final class ChannelStatsControllerArguments {
|
|||||||
|
|
||||||
let requestWithdraw: () -> Void
|
let requestWithdraw: () -> Void
|
||||||
let openMonetizationIntro: () -> Void
|
let openMonetizationIntro: () -> Void
|
||||||
|
let openMonetizationInfo: () -> Void
|
||||||
let openTransaction: (RevenueStatsTransactionsContext.State.Transaction) -> Void
|
let openTransaction: (RevenueStatsTransactionsContext.State.Transaction) -> Void
|
||||||
let expandTransactions: () -> Void
|
let expandTransactions: () -> Void
|
||||||
let updateCpmEnabled: (Bool) -> Void
|
let updateCpmEnabled: (Bool) -> Void
|
||||||
let presentCpmLocked: () -> Void
|
let presentCpmLocked: () -> Void
|
||||||
let dismissInput: () -> Void
|
let dismissInput: () -> Void
|
||||||
|
|
||||||
init(context: AccountContext, loadDetailedGraph: @escaping (StatsGraph, Int64) -> Signal<StatsGraph?, NoError>, openPostStats: @escaping (EnginePeer, StatsPostItem) -> Void, openStory: @escaping (EngineStoryItem, UIView) -> Void, contextAction: @escaping (MessageId, ASDisplayNode, ContextGesture?) -> Void, copyBoostLink: @escaping (String) -> Void, shareBoostLink: @escaping (String) -> Void, openBoost: @escaping (ChannelBoostersContext.State.Boost) -> Void, expandBoosters: @escaping () -> Void, openGifts: @escaping () -> Void, createPrepaidGiveaway: @escaping (PrepaidGiveaway) -> Void, updateGiftsSelected: @escaping (Bool) -> Void, requestWithdraw: @escaping () -> Void, openMonetizationIntro: @escaping () -> Void, openTransaction: @escaping (RevenueStatsTransactionsContext.State.Transaction) -> Void, expandTransactions: @escaping () -> Void, updateCpmEnabled: @escaping (Bool) -> Void, presentCpmLocked: @escaping () -> Void, dismissInput: @escaping () -> Void) {
|
init(context: AccountContext, loadDetailedGraph: @escaping (StatsGraph, Int64) -> Signal<StatsGraph?, NoError>, openPostStats: @escaping (EnginePeer, StatsPostItem) -> Void, openStory: @escaping (EngineStoryItem, UIView) -> Void, contextAction: @escaping (MessageId, ASDisplayNode, ContextGesture?) -> Void, copyBoostLink: @escaping (String) -> Void, shareBoostLink: @escaping (String) -> Void, openBoost: @escaping (ChannelBoostersContext.State.Boost) -> Void, expandBoosters: @escaping () -> Void, openGifts: @escaping () -> Void, createPrepaidGiveaway: @escaping (PrepaidGiveaway) -> Void, updateGiftsSelected: @escaping (Bool) -> Void, requestWithdraw: @escaping () -> Void, openMonetizationIntro: @escaping () -> Void, openMonetizationInfo: @escaping () -> Void, openTransaction: @escaping (RevenueStatsTransactionsContext.State.Transaction) -> Void, expandTransactions: @escaping () -> Void, updateCpmEnabled: @escaping (Bool) -> Void, presentCpmLocked: @escaping () -> Void, dismissInput: @escaping () -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.loadDetailedGraph = loadDetailedGraph
|
self.loadDetailedGraph = loadDetailedGraph
|
||||||
self.openPostStats = openPostStats
|
self.openPostStats = openPostStats
|
||||||
@ -63,6 +67,7 @@ private final class ChannelStatsControllerArguments {
|
|||||||
self.updateGiftsSelected = updateGiftsSelected
|
self.updateGiftsSelected = updateGiftsSelected
|
||||||
self.requestWithdraw = requestWithdraw
|
self.requestWithdraw = requestWithdraw
|
||||||
self.openMonetizationIntro = openMonetizationIntro
|
self.openMonetizationIntro = openMonetizationIntro
|
||||||
|
self.openMonetizationInfo = openMonetizationInfo
|
||||||
self.openTransaction = openTransaction
|
self.openTransaction = openTransaction
|
||||||
self.expandTransactions = expandTransactions
|
self.expandTransactions = expandTransactions
|
||||||
self.updateCpmEnabled = updateCpmEnabled
|
self.updateCpmEnabled = updateCpmEnabled
|
||||||
@ -225,8 +230,9 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
|
|
||||||
case adsTransactionsTitle(PresentationTheme, String)
|
case adsTransactionsTitle(PresentationTheme, String)
|
||||||
case adsTransaction(Int32, PresentationTheme, RevenueStatsTransactionsContext.State.Transaction)
|
case adsTransaction(Int32, PresentationTheme, RevenueStatsTransactionsContext.State.Transaction)
|
||||||
|
case adsTransactionsExpand(PresentationTheme, String)
|
||||||
|
|
||||||
case adsCpmToggle(PresentationTheme, String, Bool?)
|
case adsCpmToggle(PresentationTheme, String, Int32, Bool?)
|
||||||
case adsCpmInfo(PresentationTheme, String)
|
case adsCpmInfo(PresentationTheme, String)
|
||||||
|
|
||||||
var section: ItemListSectionId {
|
var section: ItemListSectionId {
|
||||||
@ -281,7 +287,7 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
return StatsSection.adsProceeds.rawValue
|
return StatsSection.adsProceeds.rawValue
|
||||||
case .adsBalanceTitle, .adsBalance, .adsBalanceInfo:
|
case .adsBalanceTitle, .adsBalance, .adsBalanceInfo:
|
||||||
return StatsSection.adsBalance.rawValue
|
return StatsSection.adsBalance.rawValue
|
||||||
case .adsTransactionsTitle, .adsTransaction:
|
case .adsTransactionsTitle, .adsTransaction, .adsTransactionsExpand:
|
||||||
return StatsSection.adsTransactions.rawValue
|
return StatsSection.adsTransactions.rawValue
|
||||||
case .adsCpmToggle, .adsCpmInfo:
|
case .adsCpmToggle, .adsCpmInfo:
|
||||||
return StatsSection.adsCpm.rawValue
|
return StatsSection.adsCpm.rawValue
|
||||||
@ -404,10 +410,12 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
return 20010
|
return 20010
|
||||||
case let .adsTransaction(index, _, _):
|
case let .adsTransaction(index, _, _):
|
||||||
return 20011 + index
|
return 20011 + index
|
||||||
|
case .adsTransactionsExpand:
|
||||||
|
return 30000
|
||||||
case .adsCpmToggle:
|
case .adsCpmToggle:
|
||||||
return 21000
|
return 30001
|
||||||
case .adsCpmInfo:
|
case .adsCpmInfo:
|
||||||
return 21002
|
return 30002
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -755,8 +763,14 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .adsCpmToggle(lhsTheme, lhsText, lhsValue):
|
case let .adsTransactionsExpand(lhsTheme, lhsText):
|
||||||
if case let .adsCpmToggle(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
if case let .adsTransactionsExpand(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .adsCpmToggle(lhsTheme, lhsText, lhsMinLevel, lhsValue):
|
||||||
|
if case let .adsCpmToggle(rhsTheme, rhsText, rhsMinLevel, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsMinLevel == rhsMinLevel, lhsValue == rhsValue {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -806,7 +820,6 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
let .boostersInfo(_, text),
|
let .boostersInfo(_, text),
|
||||||
let .boostLinkInfo(_, text),
|
let .boostLinkInfo(_, text),
|
||||||
let .boostGiftsInfo(_, text),
|
let .boostGiftsInfo(_, text),
|
||||||
let .adsBalanceInfo(_, text),
|
|
||||||
let .adsCpmInfo(_, text):
|
let .adsCpmInfo(_, text):
|
||||||
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section)
|
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section)
|
||||||
case let .overview(_, stats):
|
case let .overview(_, stats):
|
||||||
@ -961,6 +974,10 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
sectionId: self.section,
|
sectionId: self.section,
|
||||||
style: .blocks
|
style: .blocks
|
||||||
)
|
)
|
||||||
|
case let .adsBalanceInfo(_, text):
|
||||||
|
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section, linkAction: { _ in
|
||||||
|
arguments.openMonetizationInfo()
|
||||||
|
})
|
||||||
case let .adsTransaction(_, theme, transaction):
|
case let .adsTransaction(_, theme, transaction):
|
||||||
let font = Font.regular(presentationData.fontSize.itemListBaseFontSize)
|
let font = Font.regular(presentationData.fontSize.itemListBaseFontSize)
|
||||||
let smallLabelFont = Font.regular(floor(presentationData.fontSize.itemListBaseFontSize / 17.0 * 13.0))
|
let smallLabelFont = Font.regular(floor(presentationData.fontSize.itemListBaseFontSize / 17.0 * 13.0))
|
||||||
@ -973,22 +990,22 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
switch transaction {
|
switch transaction {
|
||||||
case let .proceeds(_, fromDate, toDate):
|
case let .proceeds(_, fromDate, toDate):
|
||||||
title = NSAttributedString(string: presentationData.strings.Monetization_Transaction_Proceeds, font: font, textColor: theme.list.itemPrimaryTextColor)
|
title = NSAttributedString(string: presentationData.strings.Monetization_Transaction_Proceeds, font: font, textColor: theme.list.itemPrimaryTextColor)
|
||||||
detailText = "\(stringForMediumDate(timestamp: fromDate, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)) – \(stringForMediumDate(timestamp: toDate, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat))"
|
detailText = "\(stringForMediumCompactDate(timestamp: fromDate, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)) – \(stringForMediumCompactDate(timestamp: toDate, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat))"
|
||||||
case let .withdrawal(status, _, date, provider, _, _):
|
case let .withdrawal(status, _, date, provider, _, _):
|
||||||
title = NSAttributedString(string: presentationData.strings.Monetization_Transaction_Withdrawal(provider).string, font: font, textColor: theme.list.itemPrimaryTextColor)
|
title = NSAttributedString(string: presentationData.strings.Monetization_Transaction_Withdrawal(provider).string, font: font, textColor: theme.list.itemPrimaryTextColor)
|
||||||
labelColor = theme.list.itemDestructiveColor
|
labelColor = theme.list.itemDestructiveColor
|
||||||
switch status {
|
switch status {
|
||||||
case .succeed:
|
case .succeed:
|
||||||
detailText = stringForMediumDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)
|
detailText = stringForMediumCompactDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)
|
||||||
case .failed:
|
case .failed:
|
||||||
detailText = stringForMediumDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat) + " – \(presentationData.strings.Monetization_Transaction_Failed)"
|
detailText = stringForMediumCompactDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat) + " – \(presentationData.strings.Monetization_Transaction_Failed)"
|
||||||
detailColor = .destructive
|
detailColor = .destructive
|
||||||
case .pending:
|
case .pending:
|
||||||
detailText = presentationData.strings.Monetization_Transaction_Pending
|
detailText = presentationData.strings.Monetization_Transaction_Pending
|
||||||
}
|
}
|
||||||
case let .refund(_, date, _):
|
case let .refund(_, date, _):
|
||||||
title = NSAttributedString(string: presentationData.strings.Monetization_Transaction_Refund, font: font, textColor: theme.list.itemPrimaryTextColor)
|
title = NSAttributedString(string: presentationData.strings.Monetization_Transaction_Refund, font: font, textColor: theme.list.itemPrimaryTextColor)
|
||||||
detailText = stringForMediumDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)
|
detailText = stringForMediumCompactDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
let label = amountAttributedString(formatBalanceText(transaction.amount, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator, showPlus: true), integralFont: font, fractionalFont: smallLabelFont, color: labelColor).mutableCopy() as! NSMutableAttributedString
|
let label = amountAttributedString(formatBalanceText(transaction.amount, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator, showPlus: true), integralFont: font, fractionalFont: smallLabelFont, color: labelColor).mutableCopy() as! NSMutableAttributedString
|
||||||
@ -997,8 +1014,19 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
return ItemListDisclosureItem(presentationData: presentationData, title: "", attributedTitle: title, label: "", attributedLabel: label, labelStyle: .coloredText(labelColor), additionalDetailLabel: detailText, additionalDetailLabelColor: detailColor, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: {
|
return ItemListDisclosureItem(presentationData: presentationData, title: "", attributedTitle: title, label: "", attributedLabel: label, labelStyle: .coloredText(labelColor), additionalDetailLabel: detailText, additionalDetailLabelColor: detailColor, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: {
|
||||||
arguments.openTransaction(transaction)
|
arguments.openTransaction(transaction)
|
||||||
})
|
})
|
||||||
case let .adsCpmToggle(_, title, value):
|
case let .adsTransactionsExpand(theme, title):
|
||||||
return ItemListSwitchItem(presentationData: presentationData, title: title, value: value == true, enableInteractiveChanges: value != nil, enabled: true, displayLocked: value == nil, sectionId: self.section, style: .blocks, updated: { updatedValue in
|
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: {
|
||||||
|
arguments.expandTransactions()
|
||||||
|
})
|
||||||
|
case let .adsCpmToggle(_, title, minLevel, value):
|
||||||
|
var badgeComponent: AnyComponent<Empty>?
|
||||||
|
if value == nil {
|
||||||
|
badgeComponent = AnyComponent(BoostLevelIconComponent(
|
||||||
|
strings: presentationData.strings,
|
||||||
|
level: Int(minLevel)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
return ItemListSwitchItem(presentationData: presentationData, title: title, titleBadgeComponent: badgeComponent, value: value == true, enableInteractiveChanges: value != nil, enabled: true, displayLocked: value == nil, sectionId: self.section, style: .blocks, updated: { updatedValue in
|
||||||
if value != nil {
|
if value != nil {
|
||||||
arguments.updateCpmEnabled(updatedValue)
|
arguments.updateCpmEnabled(updatedValue)
|
||||||
} else {
|
} else {
|
||||||
@ -1022,19 +1050,25 @@ private struct ChannelStatsControllerState: Equatable {
|
|||||||
let boostersExpanded: Bool
|
let boostersExpanded: Bool
|
||||||
let moreBoostersDisplayed: Int32
|
let moreBoostersDisplayed: Int32
|
||||||
let giftsSelected: Bool
|
let giftsSelected: Bool
|
||||||
|
let transactionsExpanded: Bool
|
||||||
|
let moreTransactionsDisplayed: Int32
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
self.section = .stats
|
self.section = .stats
|
||||||
self.boostersExpanded = false
|
self.boostersExpanded = false
|
||||||
self.moreBoostersDisplayed = 0
|
self.moreBoostersDisplayed = 0
|
||||||
self.giftsSelected = false
|
self.giftsSelected = false
|
||||||
|
self.transactionsExpanded = false
|
||||||
|
self.moreTransactionsDisplayed = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
init(section: ChannelStatsSection, boostersExpanded: Bool, moreBoostersDisplayed: Int32, giftsSelected: Bool) {
|
init(section: ChannelStatsSection, boostersExpanded: Bool, moreBoostersDisplayed: Int32, giftsSelected: Bool, transactionsExpanded: Bool, moreTransactionsDisplayed: Int32) {
|
||||||
self.section = section
|
self.section = section
|
||||||
self.boostersExpanded = boostersExpanded
|
self.boostersExpanded = boostersExpanded
|
||||||
self.moreBoostersDisplayed = moreBoostersDisplayed
|
self.moreBoostersDisplayed = moreBoostersDisplayed
|
||||||
self.giftsSelected = giftsSelected
|
self.giftsSelected = giftsSelected
|
||||||
|
self.transactionsExpanded = transactionsExpanded
|
||||||
|
self.moreTransactionsDisplayed = moreTransactionsDisplayed
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: ChannelStatsControllerState, rhs: ChannelStatsControllerState) -> Bool {
|
static func ==(lhs: ChannelStatsControllerState, rhs: ChannelStatsControllerState) -> Bool {
|
||||||
@ -1050,23 +1084,37 @@ private struct ChannelStatsControllerState: Equatable {
|
|||||||
if lhs.giftsSelected != rhs.giftsSelected {
|
if lhs.giftsSelected != rhs.giftsSelected {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.transactionsExpanded != rhs.transactionsExpanded {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.moreTransactionsDisplayed != rhs.moreTransactionsDisplayed {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedSection(_ section: ChannelStatsSection) -> ChannelStatsControllerState {
|
func withUpdatedSection(_ section: ChannelStatsSection) -> ChannelStatsControllerState {
|
||||||
return ChannelStatsControllerState(section: section, boostersExpanded: self.boostersExpanded, moreBoostersDisplayed: self.moreBoostersDisplayed, giftsSelected: self.giftsSelected)
|
return ChannelStatsControllerState(section: section, boostersExpanded: self.boostersExpanded, moreBoostersDisplayed: self.moreBoostersDisplayed, giftsSelected: self.giftsSelected, transactionsExpanded: self.transactionsExpanded, moreTransactionsDisplayed: self.moreTransactionsDisplayed)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedBoostersExpanded(_ boostersExpanded: Bool) -> ChannelStatsControllerState {
|
func withUpdatedBoostersExpanded(_ boostersExpanded: Bool) -> ChannelStatsControllerState {
|
||||||
return ChannelStatsControllerState(section: self.section, boostersExpanded: boostersExpanded, moreBoostersDisplayed: self.moreBoostersDisplayed, giftsSelected: self.giftsSelected)
|
return ChannelStatsControllerState(section: self.section, boostersExpanded: boostersExpanded, moreBoostersDisplayed: self.moreBoostersDisplayed, giftsSelected: self.giftsSelected, transactionsExpanded: self.transactionsExpanded, moreTransactionsDisplayed: self.moreTransactionsDisplayed)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedMoreBoostersDisplayed(_ moreBoostersDisplayed: Int32) -> ChannelStatsControllerState {
|
func withUpdatedMoreBoostersDisplayed(_ moreBoostersDisplayed: Int32) -> ChannelStatsControllerState {
|
||||||
return ChannelStatsControllerState(section: self.section, boostersExpanded: self.boostersExpanded, moreBoostersDisplayed: moreBoostersDisplayed, giftsSelected: self.giftsSelected)
|
return ChannelStatsControllerState(section: self.section, boostersExpanded: self.boostersExpanded, moreBoostersDisplayed: moreBoostersDisplayed, giftsSelected: self.giftsSelected, transactionsExpanded: self.transactionsExpanded, moreTransactionsDisplayed: self.moreTransactionsDisplayed)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedGiftsSelected(_ giftsSelected: Bool) -> ChannelStatsControllerState {
|
func withUpdatedGiftsSelected(_ giftsSelected: Bool) -> ChannelStatsControllerState {
|
||||||
return ChannelStatsControllerState(section: self.section, boostersExpanded: self.boostersExpanded, moreBoostersDisplayed: self.moreBoostersDisplayed, giftsSelected: giftsSelected)
|
return ChannelStatsControllerState(section: self.section, boostersExpanded: self.boostersExpanded, moreBoostersDisplayed: self.moreBoostersDisplayed, giftsSelected: giftsSelected, transactionsExpanded: self.transactionsExpanded, moreTransactionsDisplayed: self.moreTransactionsDisplayed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withUpdatedTransactionsExpanded(_ transactionsExpanded: Bool) -> ChannelStatsControllerState {
|
||||||
|
return ChannelStatsControllerState(section: self.section, boostersExpanded: self.boostersExpanded, moreBoostersDisplayed: self.moreBoostersDisplayed, giftsSelected: self.giftsSelected, transactionsExpanded: self.transactionsExpanded, moreTransactionsDisplayed: self.moreTransactionsDisplayed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withUpdatedMoreTransactionsDisplayed(_ moreTransactionsDisplayed: Int32) -> ChannelStatsControllerState {
|
||||||
|
return ChannelStatsControllerState(section: self.section, boostersExpanded: self.boostersExpanded, moreBoostersDisplayed: self.moreBoostersDisplayed, giftsSelected: self.giftsSelected, transactionsExpanded: self.transactionsExpanded, moreTransactionsDisplayed: moreTransactionsDisplayed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1309,9 +1357,11 @@ private func boostsEntries(
|
|||||||
private func monetizationEntries(
|
private func monetizationEntries(
|
||||||
presentationData: PresentationData,
|
presentationData: PresentationData,
|
||||||
state: ChannelStatsControllerState,
|
state: ChannelStatsControllerState,
|
||||||
|
peer: EnginePeer?,
|
||||||
data: RevenueStats,
|
data: RevenueStats,
|
||||||
boostData: ChannelBoostStatus?,
|
boostData: ChannelBoostStatus?,
|
||||||
transactions: RevenueStatsTransactionsContext.State,
|
transactionsInfo: RevenueStatsTransactionsContext.State,
|
||||||
|
adsRestricted: Bool,
|
||||||
animatedEmojis: [String: [StickerPackItem]],
|
animatedEmojis: [String: [StickerPackItem]],
|
||||||
premiumConfiguration: PremiumConfiguration
|
premiumConfiguration: PremiumConfiguration
|
||||||
) -> [StatsEntry] {
|
) -> [StatsEntry] {
|
||||||
@ -1333,25 +1383,50 @@ private func monetizationEntries(
|
|||||||
entries.append(.adsProceedsTitle(presentationData.theme, presentationData.strings.Monetization_OverviewTitle))
|
entries.append(.adsProceedsTitle(presentationData.theme, presentationData.strings.Monetization_OverviewTitle))
|
||||||
entries.append(.adsProceedsOverview(presentationData.theme, data, diamond))
|
entries.append(.adsProceedsOverview(presentationData.theme, data, diamond))
|
||||||
|
|
||||||
|
|
||||||
|
var withdrawalAvailable = false
|
||||||
|
if let peer, case let .channel(channel) = peer, channel.flags.contains(.isCreator) && data.availableBalance > 0 {
|
||||||
|
withdrawalAvailable = true
|
||||||
|
}
|
||||||
entries.append(.adsBalanceTitle(presentationData.theme, presentationData.strings.Monetization_BalanceTitle))
|
entries.append(.adsBalanceTitle(presentationData.theme, presentationData.strings.Monetization_BalanceTitle))
|
||||||
entries.append(.adsBalance(presentationData.theme, data, false, diamond))
|
entries.append(.adsBalance(presentationData.theme, data, withdrawalAvailable, diamond))
|
||||||
entries.append(.adsBalanceInfo(presentationData.theme, presentationData.strings.Monetization_BalanceInfo))
|
entries.append(.adsBalanceInfo(presentationData.theme, presentationData.strings.Monetization_BalanceInfo))
|
||||||
|
|
||||||
if !transactions.transactions.isEmpty {
|
if !transactionsInfo.transactions.isEmpty {
|
||||||
entries.append(.adsTransactionsTitle(presentationData.theme, presentationData.strings.Monetization_TransactionsTitle))
|
entries.append(.adsTransactionsTitle(presentationData.theme, presentationData.strings.Monetization_TransactionsTitle))
|
||||||
|
|
||||||
|
var transactions = transactionsInfo.transactions
|
||||||
|
var limit: Int32
|
||||||
|
if state.transactionsExpanded {
|
||||||
|
limit = 25 + state.moreTransactionsDisplayed
|
||||||
|
} else {
|
||||||
|
limit = initialTransactionsDisplayedLimit
|
||||||
|
}
|
||||||
|
transactions = Array(transactions.prefix(Int(limit)))
|
||||||
|
|
||||||
var i: Int32 = 0
|
var i: Int32 = 0
|
||||||
for transaction in transactions.transactions {
|
for transaction in transactions {
|
||||||
entries.append(.adsTransaction(i, presentationData.theme, transaction))
|
entries.append(.adsTransaction(i, presentationData.theme, transaction))
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if transactions.count < transactionsInfo.count {
|
||||||
|
let moreCount: Int32
|
||||||
|
if !state.transactionsExpanded {
|
||||||
|
moreCount = min(20, transactionsInfo.count - Int32(transactions.count))
|
||||||
|
} else {
|
||||||
|
moreCount = min(500, transactionsInfo.count - Int32(transactions.count))
|
||||||
|
}
|
||||||
|
entries.append(.adsTransactionsExpand(presentationData.theme, presentationData.strings.Monetization_Transaction_ShowMoreTransactions(moreCount)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var switchOffAdds: Bool? = nil
|
var switchOffAdds: Bool? = nil
|
||||||
if let boostData, boostData.level >= premiumConfiguration.minChannelRestrictAdsLevel {
|
if let boostData, boostData.level >= premiumConfiguration.minChannelRestrictAdsLevel {
|
||||||
switchOffAdds = false
|
switchOffAdds = adsRestricted
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.append(.adsCpmToggle(presentationData.theme, presentationData.strings.Monetization_SwitchOffAds, switchOffAdds))
|
entries.append(.adsCpmToggle(presentationData.theme, presentationData.strings.Monetization_SwitchOffAds, premiumConfiguration.minChannelRestrictAdsLevel, switchOffAdds))
|
||||||
entries.append(.adsCpmInfo(presentationData.theme, presentationData.strings.Monetization_SwitchOffAdsInfo))
|
entries.append(.adsCpmInfo(presentationData.theme, presentationData.strings.Monetization_SwitchOffAdsInfo))
|
||||||
|
|
||||||
return entries
|
return entries
|
||||||
@ -1374,6 +1449,7 @@ private func channelStatsControllerEntries(
|
|||||||
animatedEmojis: [String: [StickerPackItem]],
|
animatedEmojis: [String: [StickerPackItem]],
|
||||||
revenueState: RevenueStats?,
|
revenueState: RevenueStats?,
|
||||||
revenueTransactions: RevenueStatsTransactionsContext.State,
|
revenueTransactions: RevenueStatsTransactionsContext.State,
|
||||||
|
adsRestricted: Bool,
|
||||||
premiumConfiguration: PremiumConfiguration
|
premiumConfiguration: PremiumConfiguration
|
||||||
) -> [StatsEntry] {
|
) -> [StatsEntry] {
|
||||||
switch state.section {
|
switch state.section {
|
||||||
@ -1406,9 +1482,11 @@ private func channelStatsControllerEntries(
|
|||||||
return monetizationEntries(
|
return monetizationEntries(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
state: state,
|
state: state,
|
||||||
|
peer: peer,
|
||||||
data: revenueState,
|
data: revenueState,
|
||||||
boostData: boostData,
|
boostData: boostData,
|
||||||
transactions: revenueTransactions,
|
transactionsInfo: revenueTransactions,
|
||||||
|
adsRestricted: adsRestricted,
|
||||||
animatedEmojis: animatedEmojis,
|
animatedEmojis: animatedEmojis,
|
||||||
premiumConfiguration: premiumConfiguration
|
premiumConfiguration: premiumConfiguration
|
||||||
)
|
)
|
||||||
@ -1418,8 +1496,8 @@ private func channelStatsControllerEntries(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func channelStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: PeerId, section: ChannelStatsSection = .stats, boostStatus: ChannelBoostStatus? = nil, boostStatusUpdated: ((ChannelBoostStatus) -> Void)? = nil) -> ViewController {
|
public func channelStatsController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: PeerId, section: ChannelStatsSection = .stats, boostStatus: ChannelBoostStatus? = nil, boostStatusUpdated: ((ChannelBoostStatus) -> Void)? = nil) -> ViewController {
|
||||||
let statePromise = ValuePromise(ChannelStatsControllerState(section: section, boostersExpanded: false, moreBoostersDisplayed: 0, giftsSelected: false), ignoreRepeated: true)
|
let statePromise = ValuePromise(ChannelStatsControllerState(section: section, boostersExpanded: false, moreBoostersDisplayed: 0, giftsSelected: false, transactionsExpanded: false, moreTransactionsDisplayed: 0), ignoreRepeated: true)
|
||||||
let stateValue = Atomic(value: ChannelStatsControllerState(section: section, boostersExpanded: false, moreBoostersDisplayed: 0, giftsSelected: false))
|
let stateValue = Atomic(value: ChannelStatsControllerState(section: section, boostersExpanded: false, moreBoostersDisplayed: 0, giftsSelected: false, transactionsExpanded: false, moreTransactionsDisplayed: 0))
|
||||||
let updateState: ((ChannelStatsControllerState) -> ChannelStatsControllerState) -> Void = { f in
|
let updateState: ((ChannelStatsControllerState) -> ChannelStatsControllerState) -> Void = { f in
|
||||||
statePromise.set(stateValue.modify { f($0) })
|
statePromise.set(stateValue.modify { f($0) })
|
||||||
}
|
}
|
||||||
@ -1471,6 +1549,8 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
let boostsContext = ChannelBoostersContext(account: context.account, peerId: peerId, gift: false)
|
let boostsContext = ChannelBoostersContext(account: context.account, peerId: peerId, gift: false)
|
||||||
let giftsContext = ChannelBoostersContext(account: context.account, peerId: peerId, gift: true)
|
let giftsContext = ChannelBoostersContext(account: context.account, peerId: peerId, gift: true)
|
||||||
let revenueContext = RevenueStatsContext(postbox: context.account.postbox, network: context.account.network, peerId: peerId)
|
let revenueContext = RevenueStatsContext(postbox: context.account.postbox, network: context.account.network, peerId: peerId)
|
||||||
|
let revenueState = Promise<RevenueStatsContextState?>()
|
||||||
|
revenueState.set(.single(nil) |> then(revenueContext.state |> map(Optional.init)))
|
||||||
|
|
||||||
let revenueTransactions = RevenueStatsTransactionsContext(account: context.account, peerId: peerId)
|
let revenueTransactions = RevenueStatsTransactionsContext(account: context.account, peerId: peerId)
|
||||||
|
|
||||||
@ -1612,13 +1692,25 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
let controller = MonetizationIntroScreen(context: context, openMore: {})
|
let controller = MonetizationIntroScreen(context: context, openMore: {})
|
||||||
pushImpl?(controller)
|
pushImpl?(controller)
|
||||||
},
|
},
|
||||||
|
openMonetizationInfo: {
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: presentationData.strings.Monetization_BalanceInfo_URL, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
|
||||||
|
},
|
||||||
openTransaction: { transaction in
|
openTransaction: { transaction in
|
||||||
openTransactionImpl?(transaction)
|
openTransactionImpl?(transaction)
|
||||||
},
|
},
|
||||||
expandTransactions: {
|
expandTransactions: {
|
||||||
|
updateState { state in
|
||||||
|
if state.transactionsExpanded {
|
||||||
|
return state.withUpdatedMoreTransactionsDisplayed(state.moreTransactionsDisplayed + 50)
|
||||||
|
} else {
|
||||||
|
return state.withUpdatedTransactionsExpanded(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
revenueTransactions.loadMore()
|
||||||
},
|
},
|
||||||
updateCpmEnabled: { value in
|
updateCpmEnabled: { value in
|
||||||
|
let _ = context.engine.peers.updateChannelRestrictAdMessages(peerId: peerId, value: value ? .restrict(minCpm: nil) : .unrestrict).start()
|
||||||
},
|
},
|
||||||
presentCpmLocked: {
|
presentCpmLocked: {
|
||||||
let _ = combineLatest(
|
let _ = combineLatest(
|
||||||
@ -1658,6 +1750,8 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
let peer = Promise<EnginePeer?>()
|
let peer = Promise<EnginePeer?>()
|
||||||
peer.set(context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)))
|
peer.set(context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)))
|
||||||
|
|
||||||
|
let adsRestricted = context.engine.data.get(TelegramEngine.EngineData.Item.Peer.AdsRestricted(id: peerId))
|
||||||
|
|
||||||
let longLoadingSignal: Signal<Bool, NoError> = .single(false) |> then(.single(true) |> delay(2.0, queue: Queue.mainQueue()))
|
let longLoadingSignal: Signal<Bool, NoError> = .single(false) |> then(.single(true) |> delay(2.0, queue: Queue.mainQueue()))
|
||||||
let previousData = Atomic<ChannelStats?>(value: nil)
|
let previousData = Atomic<ChannelStats?>(value: nil)
|
||||||
|
|
||||||
@ -1672,13 +1766,14 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
boostDataPromise.get(),
|
boostDataPromise.get(),
|
||||||
boostsContext.state,
|
boostsContext.state,
|
||||||
giftsContext.state,
|
giftsContext.state,
|
||||||
revenueContext.state,
|
revenueState.get(),
|
||||||
revenueTransactions.state,
|
revenueTransactions.state,
|
||||||
|
adsRestricted,
|
||||||
longLoadingSignal,
|
longLoadingSignal,
|
||||||
context.animatedEmojiStickers
|
context.animatedEmojiStickers
|
||||||
)
|
)
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> map { presentationData, state, peer, data, messageView, stories, boostData, boostersState, giftsState, revenueState, revenueTransactions, longLoading, animatedEmojiStickers -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
|> map { presentationData, state, peer, data, messageView, stories, boostData, boostersState, giftsState, revenueState, revenueTransactions, adsRestricted, longLoading, animatedEmojiStickers -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||||
var isGroup = false
|
var isGroup = false
|
||||||
if let peer, case let .channel(channel) = peer, case .group = channel.info {
|
if let peer, case let .channel(channel) = peer, case .group = channel.info {
|
||||||
isGroup = true
|
isGroup = true
|
||||||
@ -1700,8 +1795,9 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
emptyStateItem = ItemListLoadingIndicatorEmptyStateItem(theme: presentationData.theme)
|
emptyStateItem = ItemListLoadingIndicatorEmptyStateItem(theme: presentationData.theme)
|
||||||
}
|
}
|
||||||
case .monetization:
|
case .monetization:
|
||||||
emptyStateItem = nil
|
if revenueState == nil {
|
||||||
// emptyStateItem = ItemListLoadingIndicatorEmptyStateItem(theme: presentationData.theme)
|
emptyStateItem = ItemListLoadingIndicatorEmptyStateItem(theme: presentationData.theme)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var existingGroupingKeys = Set<Int64>()
|
var existingGroupingKeys = Set<Int64>()
|
||||||
@ -1762,7 +1858,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
}
|
}
|
||||||
|
|
||||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: title, leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: title, leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
||||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelStatsControllerEntries(presentationData: presentationData, state: state, peer: peer, data: data, messages: messages, stories: stories, interactions: interactions, boostData: boostData, boostersState: boostersState, giftsState: giftsState, giveawayAvailable: premiumConfiguration.giveawayGiftsPurchaseAvailable, isGroup: isGroup, boostsOnly: boostsOnly, animatedEmojis: animatedEmojiStickers, revenueState: revenueState.stats, revenueTransactions: revenueTransactions, premiumConfiguration: premiumConfiguration), style: .blocks, emptyStateItem: emptyStateItem, headerItem: headerItem, crossfadeState: previous == nil, animateChanges: false)
|
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelStatsControllerEntries(presentationData: presentationData, state: state, peer: peer, data: data, messages: messages, stories: stories, interactions: interactions, boostData: boostData, boostersState: boostersState, giftsState: giftsState, giveawayAvailable: premiumConfiguration.giveawayGiftsPurchaseAvailable, isGroup: isGroup, boostsOnly: boostsOnly, animatedEmojis: animatedEmojiStickers, revenueState: revenueState?.stats, revenueTransactions: revenueTransactions, adsRestricted: adsRestricted, premiumConfiguration: premiumConfiguration), style: .blocks, emptyStateItem: emptyStateItem, headerItem: headerItem, crossfadeState: previous == nil, animateChanges: false)
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
return (controllerState, (listState, arguments))
|
||||||
}
|
}
|
||||||
@ -1770,6 +1866,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
actionsDisposable.dispose()
|
actionsDisposable.dispose()
|
||||||
let _ = statsContext.state
|
let _ = statsContext.state
|
||||||
let _ = storyList.state
|
let _ = storyList.state
|
||||||
|
let _ = revenueContext.state
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(context: context, state: signal)
|
let controller = ItemListController(context: context, state: signal)
|
||||||
|
@ -224,6 +224,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: linkColor)!, theme)
|
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: linkColor)!, theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let infoString = strings.Monetization_Intro_Info_Text
|
let infoString = strings.Monetization_Intro_Info_Text
|
||||||
let infoAttributedString = parseMarkdownIntoAttributedString(infoString, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString
|
let infoAttributedString = parseMarkdownIntoAttributedString(infoString, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString
|
||||||
if let range = infoAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 {
|
if let range = infoAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 {
|
||||||
@ -234,7 +235,17 @@ private final class SheetContent: CombinedComponent {
|
|||||||
text: .plain(infoAttributedString),
|
text: .plain(infoAttributedString),
|
||||||
horizontalAlignment: .center,
|
horizontalAlignment: .center,
|
||||||
maximumNumberOfLines: 0,
|
maximumNumberOfLines: 0,
|
||||||
lineSpacing: 0.2
|
lineSpacing: 0.2,
|
||||||
|
highlightAction: { attributes in
|
||||||
|
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] {
|
||||||
|
return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tapAction: { _, _ in
|
||||||
|
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.Monetization_Intro_Info_Text_URL, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
|
||||||
|
}
|
||||||
),
|
),
|
||||||
availableSize: CGSize(width: context.availableSize.width - (textSideInset + sideInset - 2.0) * 2.0, height: context.availableSize.height),
|
availableSize: CGSize(width: context.availableSize.width - (textSideInset + sideInset - 2.0) * 2.0, height: context.availableSize.height),
|
||||||
transition: .immediate
|
transition: .immediate
|
||||||
|
@ -139,7 +139,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
case let .proceeds(amount, fromDate, toDate):
|
case let .proceeds(amount, fromDate, toDate):
|
||||||
amountString = amountAttributedString(formatBalanceText(amount, decimalSeparator: dateTimeFormat.decimalSeparator, showPlus: true), integralFont: integralFont, fractionalFont: fractionalFont, color: theme.list.itemDisclosureActions.constructive.fillColor).mutableCopy() as! NSMutableAttributedString
|
amountString = amountAttributedString(formatBalanceText(amount, decimalSeparator: dateTimeFormat.decimalSeparator, showPlus: true), integralFont: integralFont, fractionalFont: fractionalFont, color: theme.list.itemDisclosureActions.constructive.fillColor).mutableCopy() as! NSMutableAttributedString
|
||||||
amountString.append(NSAttributedString(string: " TON", font: fractionalFont, textColor: theme.list.itemDisclosureActions.constructive.fillColor))
|
amountString.append(NSAttributedString(string: " TON", font: fractionalFont, textColor: theme.list.itemDisclosureActions.constructive.fillColor))
|
||||||
dateString = "\(stringForFullDate(timestamp: fromDate, strings: strings, dateTimeFormat: dateTimeFormat)) – \(stringForFullDate(timestamp: toDate, strings: strings, dateTimeFormat: dateTimeFormat))"
|
dateString = "\(stringForMediumCompactDate(timestamp: fromDate, strings: strings, dateTimeFormat: dateTimeFormat)) – \(stringForMediumCompactDate(timestamp: toDate, strings: strings, dateTimeFormat: dateTimeFormat))"
|
||||||
titleString = strings.Monetization_TransactionInfo_Proceeds
|
titleString = strings.Monetization_TransactionInfo_Proceeds
|
||||||
buttonTitle = strings.Common_OK
|
buttonTitle = strings.Common_OK
|
||||||
explorerUrl = nil
|
explorerUrl = nil
|
||||||
|
@ -240,7 +240,9 @@ private final class RevenueStatsTransactionsContextImpl {
|
|||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
let offset = lastOffset ?? 0
|
let offset = lastOffset ?? 0
|
||||||
let request = Api.functions.stats.getBroadcastRevenueTransactions(channel: inputChannel, offset: offset, limit: 50)
|
let limit: Int32 = lastOffset == nil ? 25 : 50
|
||||||
|
|
||||||
|
let request = Api.functions.stats.getBroadcastRevenueTransactions(channel: inputChannel, offset: offset, limit: limit)
|
||||||
let signal: Signal<Api.stats.BroadcastRevenueTransactions, MTRpcError>
|
let signal: Signal<Api.stats.BroadcastRevenueTransactions, MTRpcError>
|
||||||
if let statsDatacenterId = statsDatacenterId, account.network.datacenterId != statsDatacenterId {
|
if let statsDatacenterId = statsDatacenterId, account.network.datacenterId != statsDatacenterId {
|
||||||
signal = account.network.download(datacenterId: Int(statsDatacenterId), isMedia: false, tag: nil)
|
signal = account.network.download(datacenterId: Int(statsDatacenterId), isMedia: false, tag: nil)
|
||||||
|
@ -1812,5 +1812,33 @@ public extension TelegramEngine.EngineData.Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct AdsRestricted: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||||
|
public typealias Result = Bool
|
||||||
|
|
||||||
|
fileprivate var id: EnginePeer.Id
|
||||||
|
public var mapKey: EnginePeer.Id {
|
||||||
|
return self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(id: EnginePeer.Id) {
|
||||||
|
self.id = id
|
||||||
|
}
|
||||||
|
|
||||||
|
var key: PostboxViewKey {
|
||||||
|
return .cachedPeerData(peerId: self.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extract(view: PostboxView) -> Result {
|
||||||
|
guard let view = view as? CachedPeerDataView else {
|
||||||
|
preconditionFailure()
|
||||||
|
}
|
||||||
|
if let cachedData = view.cachedPeerData as? CachedChannelData {
|
||||||
|
return cachedData.flags.contains(.adsRestricted)
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,26 @@ public func getDateTimeComponents(timestamp: Int32) -> (day: Int32, month: Int32
|
|||||||
return (timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year, timeinfo.tm_hour, timeinfo.tm_min)
|
return (timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year, timeinfo.tm_hour, timeinfo.tm_min)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func stringForMediumCompactDate(timestamp: Int32, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> String {
|
||||||
|
var t: time_t = Int(timestamp)
|
||||||
|
var timeinfo = tm()
|
||||||
|
localtime_r(&t, &timeinfo);
|
||||||
|
|
||||||
|
let day = timeinfo.tm_mday
|
||||||
|
let month = monthAtIndex(Int(timeinfo.tm_mon), strings: strings)
|
||||||
|
|
||||||
|
let timeString = stringForShortTimestamp(hours: Int32(timeinfo.tm_hour), minutes: Int32(timeinfo.tm_min), dateTimeFormat: dateTimeFormat)
|
||||||
|
|
||||||
|
let dateString: String
|
||||||
|
switch dateTimeFormat.dateFormat {
|
||||||
|
case .monthFirst:
|
||||||
|
dateString = String(format: "%@ %02d %@", month, day, timeString)
|
||||||
|
case .dayFirst:
|
||||||
|
dateString = String(format: "%02d %@ %@", day, month, timeString)
|
||||||
|
}
|
||||||
|
return dateString
|
||||||
|
}
|
||||||
|
|
||||||
public func stringForMediumDate(timestamp: Int32, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, withTime: Bool = true) -> String {
|
public func stringForMediumDate(timestamp: Int32, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, withTime: Bool = true) -> String {
|
||||||
var t: time_t = Int(timestamp)
|
var t: time_t = Int(timestamp)
|
||||||
var timeinfo = tm()
|
var timeinfo = tm()
|
||||||
|
@ -107,7 +107,7 @@ public func stringForMonth(strings: PresentationStrings, month: Int32, ofYear ye
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func monthAtIndex(_ index: Int, strings: PresentationStrings) -> String {
|
func monthAtIndex(_ index: Int, strings: PresentationStrings) -> String {
|
||||||
switch index {
|
switch index {
|
||||||
case 0:
|
case 0:
|
||||||
return strings.Month_ShortJanuary
|
return strings.Month_ShortJanuary
|
||||||
|
@ -32,6 +32,7 @@ final class PeerInfoBirthdayOverlay: ASDisplayNode {
|
|||||||
self.setupAnimations(size: size, birthday: birthday, sourceRect: sourceRect)
|
self.setupAnimations(size: size, birthday: birthday, sourceRect: sourceRect)
|
||||||
|
|
||||||
Queue.mainQueue().after(0.1) {
|
Queue.mainQueue().after(0.1) {
|
||||||
|
HapticFeedback().success()
|
||||||
self.view.addSubview(ConfettiView(frame: CGRect(origin: .zero, size: size)))
|
self.view.addSubview(ConfettiView(frame: CGRect(origin: .zero, size: size)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user