mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 01:10:09 +00:00
Various improvements
This commit is contained in:
parent
15c9af3ab2
commit
73218834ff
@ -1501,13 +1501,15 @@ public struct StarsSubscriptionConfiguration {
|
|||||||
return StarsSubscriptionConfiguration(
|
return StarsSubscriptionConfiguration(
|
||||||
maxFee: 2500,
|
maxFee: 2500,
|
||||||
usdWithdrawRate: 1200,
|
usdWithdrawRate: 1200,
|
||||||
|
tonUsdRate: 0,
|
||||||
paidMessageMaxAmount: 10000,
|
paidMessageMaxAmount: 10000,
|
||||||
paidMessageCommissionPermille: 850,
|
paidMessageCommissionPermille: 850,
|
||||||
paidMessagesAvailable: false,
|
paidMessagesAvailable: false,
|
||||||
starGiftResaleMinAmount: 125,
|
starGiftResaleMinAmount: 125,
|
||||||
starGiftResaleMaxAmount: 3500,
|
starGiftResaleMaxAmount: 3500,
|
||||||
starGiftCommissionPermille: 80,
|
starGiftCommissionPermille: 80,
|
||||||
channelMessageSuggestionCommissionPermille: 850,
|
channelMessageSuggestionStarsCommissionPermille: 850,
|
||||||
|
channelMessageSuggestionTonCommissionPermille: 850,
|
||||||
channelMessageSuggestionMaxStarsAmount: 10000,
|
channelMessageSuggestionMaxStarsAmount: 10000,
|
||||||
channelMessageSuggestionMaxTonAmount: 10000000000000
|
channelMessageSuggestionMaxTonAmount: 10000000000000
|
||||||
)
|
)
|
||||||
@ -1515,38 +1517,44 @@ public struct StarsSubscriptionConfiguration {
|
|||||||
|
|
||||||
public let maxFee: Int64
|
public let maxFee: Int64
|
||||||
public let usdWithdrawRate: Int64
|
public let usdWithdrawRate: Int64
|
||||||
|
public let tonUsdRate: Int64
|
||||||
public let paidMessageMaxAmount: Int64
|
public let paidMessageMaxAmount: Int64
|
||||||
public let paidMessageCommissionPermille: Int32
|
public let paidMessageCommissionPermille: Int32
|
||||||
public let paidMessagesAvailable: Bool
|
public let paidMessagesAvailable: Bool
|
||||||
public let starGiftResaleMinAmount: Int64
|
public let starGiftResaleMinAmount: Int64
|
||||||
public let starGiftResaleMaxAmount: Int64
|
public let starGiftResaleMaxAmount: Int64
|
||||||
public let starGiftCommissionPermille: Int32
|
public let starGiftCommissionPermille: Int32
|
||||||
public let channelMessageSuggestionCommissionPermille: Int32
|
public let channelMessageSuggestionStarsCommissionPermille: Int32
|
||||||
|
public let channelMessageSuggestionTonCommissionPermille: Int32
|
||||||
public let channelMessageSuggestionMaxStarsAmount: Int64
|
public let channelMessageSuggestionMaxStarsAmount: Int64
|
||||||
public let channelMessageSuggestionMaxTonAmount: Int64
|
public let channelMessageSuggestionMaxTonAmount: Int64
|
||||||
|
|
||||||
fileprivate init(
|
fileprivate init(
|
||||||
maxFee: Int64,
|
maxFee: Int64,
|
||||||
usdWithdrawRate: Int64,
|
usdWithdrawRate: Int64,
|
||||||
|
tonUsdRate: Int64,
|
||||||
paidMessageMaxAmount: Int64,
|
paidMessageMaxAmount: Int64,
|
||||||
paidMessageCommissionPermille: Int32,
|
paidMessageCommissionPermille: Int32,
|
||||||
paidMessagesAvailable: Bool,
|
paidMessagesAvailable: Bool,
|
||||||
starGiftResaleMinAmount: Int64,
|
starGiftResaleMinAmount: Int64,
|
||||||
starGiftResaleMaxAmount: Int64,
|
starGiftResaleMaxAmount: Int64,
|
||||||
starGiftCommissionPermille: Int32,
|
starGiftCommissionPermille: Int32,
|
||||||
channelMessageSuggestionCommissionPermille: Int32,
|
channelMessageSuggestionStarsCommissionPermille: Int32,
|
||||||
|
channelMessageSuggestionTonCommissionPermille: Int32,
|
||||||
channelMessageSuggestionMaxStarsAmount: Int64,
|
channelMessageSuggestionMaxStarsAmount: Int64,
|
||||||
channelMessageSuggestionMaxTonAmount: Int64
|
channelMessageSuggestionMaxTonAmount: Int64
|
||||||
) {
|
) {
|
||||||
self.maxFee = maxFee
|
self.maxFee = maxFee
|
||||||
self.usdWithdrawRate = usdWithdrawRate
|
self.usdWithdrawRate = usdWithdrawRate
|
||||||
|
self.tonUsdRate = tonUsdRate
|
||||||
self.paidMessageMaxAmount = paidMessageMaxAmount
|
self.paidMessageMaxAmount = paidMessageMaxAmount
|
||||||
self.paidMessageCommissionPermille = paidMessageCommissionPermille
|
self.paidMessageCommissionPermille = paidMessageCommissionPermille
|
||||||
self.paidMessagesAvailable = paidMessagesAvailable
|
self.paidMessagesAvailable = paidMessagesAvailable
|
||||||
self.starGiftResaleMinAmount = starGiftResaleMinAmount
|
self.starGiftResaleMinAmount = starGiftResaleMinAmount
|
||||||
self.starGiftResaleMaxAmount = starGiftResaleMaxAmount
|
self.starGiftResaleMaxAmount = starGiftResaleMaxAmount
|
||||||
self.starGiftCommissionPermille = starGiftCommissionPermille
|
self.starGiftCommissionPermille = starGiftCommissionPermille
|
||||||
self.channelMessageSuggestionCommissionPermille = channelMessageSuggestionCommissionPermille
|
self.channelMessageSuggestionStarsCommissionPermille = channelMessageSuggestionStarsCommissionPermille
|
||||||
|
self.channelMessageSuggestionTonCommissionPermille = channelMessageSuggestionTonCommissionPermille
|
||||||
self.channelMessageSuggestionMaxStarsAmount = channelMessageSuggestionMaxStarsAmount
|
self.channelMessageSuggestionMaxStarsAmount = channelMessageSuggestionMaxStarsAmount
|
||||||
self.channelMessageSuggestionMaxTonAmount = channelMessageSuggestionMaxTonAmount
|
self.channelMessageSuggestionMaxTonAmount = channelMessageSuggestionMaxTonAmount
|
||||||
}
|
}
|
||||||
@ -1555,6 +1563,7 @@ public struct StarsSubscriptionConfiguration {
|
|||||||
if let data = appConfiguration.data {
|
if let data = appConfiguration.data {
|
||||||
let maxFee = (data["stars_subscription_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.maxFee
|
let maxFee = (data["stars_subscription_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.maxFee
|
||||||
let usdWithdrawRate = (data["stars_usd_withdraw_rate_x1000"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.usdWithdrawRate
|
let usdWithdrawRate = (data["stars_usd_withdraw_rate_x1000"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.usdWithdrawRate
|
||||||
|
let tonUsdRate = (data["ton_usd_rate"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.tonUsdRate
|
||||||
let paidMessageMaxAmount = (data["stars_paid_message_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.paidMessageMaxAmount
|
let paidMessageMaxAmount = (data["stars_paid_message_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.paidMessageMaxAmount
|
||||||
let paidMessageCommissionPermille = (data["stars_paid_message_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.paidMessageCommissionPermille
|
let paidMessageCommissionPermille = (data["stars_paid_message_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.paidMessageCommissionPermille
|
||||||
let paidMessagesAvailable = (data["stars_paid_messages_available"] as? Bool) ?? StarsSubscriptionConfiguration.defaultValue.paidMessagesAvailable
|
let paidMessagesAvailable = (data["stars_paid_messages_available"] as? Bool) ?? StarsSubscriptionConfiguration.defaultValue.paidMessagesAvailable
|
||||||
@ -1562,20 +1571,23 @@ public struct StarsSubscriptionConfiguration {
|
|||||||
let starGiftResaleMaxAmount = (data["stars_stargift_resale_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.starGiftResaleMaxAmount
|
let starGiftResaleMaxAmount = (data["stars_stargift_resale_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.starGiftResaleMaxAmount
|
||||||
let starGiftCommissionPermille = (data["stars_stargift_resale_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.starGiftCommissionPermille
|
let starGiftCommissionPermille = (data["stars_stargift_resale_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.starGiftCommissionPermille
|
||||||
|
|
||||||
let channelMessageSuggestionCommissionPermille = (data["stars_suggested_post_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionCommissionPermille
|
let channelMessageSuggestionStarsCommissionPermille = (data["stars_suggested_post_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionStarsCommissionPermille
|
||||||
|
let channelMessageSuggestionTonCommissionPermille = (data["ton_suggested_post_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionTonCommissionPermille
|
||||||
let channelMessageSuggestionMaxStarsAmount = (data["stars_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxStarsAmount
|
let channelMessageSuggestionMaxStarsAmount = (data["stars_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxStarsAmount
|
||||||
let channelMessageSuggestionMaxTonAmount = (data["ton_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxTonAmount
|
let channelMessageSuggestionMaxTonAmount = (data["ton_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxTonAmount
|
||||||
|
|
||||||
return StarsSubscriptionConfiguration(
|
return StarsSubscriptionConfiguration(
|
||||||
maxFee: maxFee,
|
maxFee: maxFee,
|
||||||
usdWithdrawRate: usdWithdrawRate,
|
usdWithdrawRate: usdWithdrawRate,
|
||||||
|
tonUsdRate: tonUsdRate,
|
||||||
paidMessageMaxAmount: paidMessageMaxAmount,
|
paidMessageMaxAmount: paidMessageMaxAmount,
|
||||||
paidMessageCommissionPermille: paidMessageCommissionPermille,
|
paidMessageCommissionPermille: paidMessageCommissionPermille,
|
||||||
paidMessagesAvailable: paidMessagesAvailable,
|
paidMessagesAvailable: paidMessagesAvailable,
|
||||||
starGiftResaleMinAmount: starGiftResaleMinAmount,
|
starGiftResaleMinAmount: starGiftResaleMinAmount,
|
||||||
starGiftResaleMaxAmount: starGiftResaleMaxAmount,
|
starGiftResaleMaxAmount: starGiftResaleMaxAmount,
|
||||||
starGiftCommissionPermille: starGiftCommissionPermille,
|
starGiftCommissionPermille: starGiftCommissionPermille,
|
||||||
channelMessageSuggestionCommissionPermille: channelMessageSuggestionCommissionPermille,
|
channelMessageSuggestionStarsCommissionPermille: channelMessageSuggestionStarsCommissionPermille,
|
||||||
|
channelMessageSuggestionTonCommissionPermille: channelMessageSuggestionTonCommissionPermille,
|
||||||
channelMessageSuggestionMaxStarsAmount: channelMessageSuggestionMaxStarsAmount,
|
channelMessageSuggestionMaxStarsAmount: channelMessageSuggestionMaxStarsAmount,
|
||||||
channelMessageSuggestionMaxTonAmount: channelMessageSuggestionMaxTonAmount
|
channelMessageSuggestionMaxTonAmount: channelMessageSuggestionMaxTonAmount
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1487,7 +1487,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
amountString = "\(amount.amount.value) Stars"
|
amountString = "\(amount.amount.value) Stars"
|
||||||
}
|
}
|
||||||
case .ton:
|
case .ton:
|
||||||
amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat)) TON"
|
amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat, maxDecimalPositions: 3)) TON"
|
||||||
}
|
}
|
||||||
attributedString = parseMarkdownIntoAttributedString("**\(channelName)** received **\(amountString)** for publishing this post", attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }))
|
attributedString = parseMarkdownIntoAttributedString("**\(channelName)** received **\(amountString)** for publishing this post", attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }))
|
||||||
case let .suggestedPostRefund(info):
|
case let .suggestedPostRefund(info):
|
||||||
|
|||||||
@ -28,7 +28,7 @@ public func formatTonUsdValue(_ value: Int64, divide: Bool = true, rate: Double
|
|||||||
return "$\(formattedValue)"
|
return "$\(formattedValue)"
|
||||||
}
|
}
|
||||||
|
|
||||||
public func formatTonAmountText(_ value: Int64, dateTimeFormat: PresentationDateTimeFormat, showPlus: Bool = false) -> String {
|
public func formatTonAmountText(_ value: Int64, dateTimeFormat: PresentationDateTimeFormat, showPlus: Bool = false, maxDecimalPositions: Int = 2) -> String {
|
||||||
var balanceText = "\(abs(value))"
|
var balanceText = "\(abs(value))"
|
||||||
while balanceText.count < 10 {
|
while balanceText.count < 10 {
|
||||||
balanceText.insert("0", at: balanceText.startIndex)
|
balanceText.insert("0", at: balanceText.startIndex)
|
||||||
@ -49,7 +49,7 @@ public func formatTonAmountText(_ value: Int64, dateTimeFormat: PresentationDate
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let dotIndex = balanceText.range(of: dateTimeFormat.decimalSeparator) {
|
if let dotIndex = balanceText.range(of: dateTimeFormat.decimalSeparator) {
|
||||||
if let endIndex = balanceText.index(dotIndex.upperBound, offsetBy: 2, limitedBy: balanceText.endIndex) {
|
if let endIndex = balanceText.index(dotIndex.upperBound, offsetBy: maxDecimalPositions, limitedBy: balanceText.endIndex) {
|
||||||
balanceText = String(balanceText[balanceText.startIndex..<endIndex])
|
balanceText = String(balanceText[balanceText.startIndex..<endIndex])
|
||||||
} else {
|
} else {
|
||||||
balanceText = String(balanceText[balanceText.startIndex..<balanceText.endIndex])
|
balanceText = String(balanceText[balanceText.startIndex..<balanceText.endIndex])
|
||||||
|
|||||||
@ -480,6 +480,7 @@ swift_library(
|
|||||||
"//submodules/TelegramUI/Components/GifVideoLayer",
|
"//submodules/TelegramUI/Components/GifVideoLayer",
|
||||||
"//submodules/TelegramUI/Components/BatchVideoRendering",
|
"//submodules/TelegramUI/Components/BatchVideoRendering",
|
||||||
"//submodules/TelegramUI/Components/ComposeTodoScreen",
|
"//submodules/TelegramUI/Components/ComposeTodoScreen",
|
||||||
|
"//submodules/TelegramUI/Components/SuggestedPostApproveAlert",
|
||||||
] + select({
|
] + select({
|
||||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||||
"//build-system:ios_sim_arm64": [],
|
"//build-system:ios_sim_arm64": [],
|
||||||
|
|||||||
@ -21,6 +21,12 @@ swift_library(
|
|||||||
"//submodules/SolidRoundedButtonNode",
|
"//submodules/SolidRoundedButtonNode",
|
||||||
"//submodules/PresentationDataUtils",
|
"//submodules/PresentationDataUtils",
|
||||||
"//submodules/UIKitRuntimeUtils",
|
"//submodules/UIKitRuntimeUtils",
|
||||||
|
"//submodules/ComponentFlow",
|
||||||
|
"//submodules/TelegramUI/Components/ToastComponent",
|
||||||
|
"//submodules/Markdown",
|
||||||
|
"//submodules/TelegramUI/Components/LottieComponent",
|
||||||
|
"//submodules/Components/MultilineTextComponent",
|
||||||
|
"//submodules/Components/ComponentDisplayAdapters",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import TelegramPresentationData
|
|||||||
public enum ChatScheduleTimeControllerMode {
|
public enum ChatScheduleTimeControllerMode {
|
||||||
case scheduledMessages(sendWhenOnlineAvailable: Bool)
|
case scheduledMessages(sendWhenOnlineAvailable: Bool)
|
||||||
case reminders
|
case reminders
|
||||||
case suggestPost(needsTime: Bool)
|
case suggestPost(needsTime: Bool, isAdmin: Bool, funds: (amount: CurrencyAmount, commissionPermille: Int)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ChatScheduleTimeControllerStyle {
|
public enum ChatScheduleTimeControllerStyle {
|
||||||
|
|||||||
@ -10,6 +10,12 @@ import AccountContext
|
|||||||
import SolidRoundedButtonNode
|
import SolidRoundedButtonNode
|
||||||
import PresentationDataUtils
|
import PresentationDataUtils
|
||||||
import UIKitRuntimeUtils
|
import UIKitRuntimeUtils
|
||||||
|
import ComponentFlow
|
||||||
|
import ToastComponent
|
||||||
|
import Markdown
|
||||||
|
import LottieComponent
|
||||||
|
import MultilineTextComponent
|
||||||
|
import ComponentDisplayAdapters
|
||||||
|
|
||||||
class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDelegate {
|
class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDelegate {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
@ -26,6 +32,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
|||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
private let contentBackgroundNode: ASDisplayNode
|
private let contentBackgroundNode: ASDisplayNode
|
||||||
private let titleNode: ASTextNode
|
private let titleNode: ASTextNode
|
||||||
|
private let subtitleNode: ASTextNode?
|
||||||
private let textNode: ASTextNode?
|
private let textNode: ASTextNode?
|
||||||
private let cancelButton: HighlightableButtonNode
|
private let cancelButton: HighlightableButtonNode
|
||||||
private let doneButton: SolidRoundedButtonNode
|
private let doneButton: SolidRoundedButtonNode
|
||||||
@ -36,6 +43,8 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
|||||||
|
|
||||||
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
||||||
|
|
||||||
|
private var toast: ComponentView<Empty>?
|
||||||
|
|
||||||
var completion: ((Int32) -> Void)?
|
var completion: ((Int32) -> Void)?
|
||||||
var dismiss: (() -> Void)?
|
var dismiss: (() -> Void)?
|
||||||
var cancel: (() -> Void)?
|
var cancel: (() -> Void)?
|
||||||
@ -94,22 +103,43 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
|||||||
self.contentBackgroundNode.backgroundColor = backgroundColor
|
self.contentBackgroundNode.backgroundColor = backgroundColor
|
||||||
|
|
||||||
let title: String
|
let title: String
|
||||||
|
var subtitle: String?
|
||||||
var text: String?
|
var text: String?
|
||||||
switch mode {
|
switch mode {
|
||||||
case .scheduledMessages:
|
case .scheduledMessages:
|
||||||
title = self.presentationData.strings.Conversation_ScheduleMessage_Title
|
title = self.presentationData.strings.Conversation_ScheduleMessage_Title
|
||||||
case .reminders:
|
case .reminders:
|
||||||
title = self.presentationData.strings.Conversation_SetReminder_Title
|
title = self.presentationData.strings.Conversation_SetReminder_Title
|
||||||
case let .suggestPost(needsTime):
|
case let .suggestPost(needsTime, isAdmin, funds):
|
||||||
if needsTime {
|
if needsTime {
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
title = "Time"
|
title = "Accept Terms"
|
||||||
text = "Set the date and time you want\nthis message to be published."
|
text = "Set the date and time you want\nthis message to be published."
|
||||||
} else {
|
} else {
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
title = "Time"
|
title = "Time"
|
||||||
text = "Set the date and time you want\nyour message to be published."
|
text = "Set the date and time you want\nyour message to be published."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
if let funds, isAdmin {
|
||||||
|
var commissionValue: String
|
||||||
|
commissionValue = "\(Double(funds.commissionPermille) * 0.1)"
|
||||||
|
if commissionValue.hasSuffix(".0") {
|
||||||
|
commissionValue = String(commissionValue[commissionValue.startIndex ..< commissionValue.index(commissionValue.endIndex, offsetBy: -2)])
|
||||||
|
} else if commissionValue.hasSuffix(".00") {
|
||||||
|
commissionValue = String(commissionValue[commissionValue.startIndex ..< commissionValue.index(commissionValue.endIndex, offsetBy: -3)])
|
||||||
|
}
|
||||||
|
|
||||||
|
switch funds.amount.currency {
|
||||||
|
case .stars:
|
||||||
|
let displayAmount = funds.amount.amount.totalValue * Double(funds.commissionPermille) / 1000.0
|
||||||
|
subtitle = "You will receive \(displayAmount) Stars (\(commissionValue)%)\nfor publishing this post"
|
||||||
|
case .ton:
|
||||||
|
let displayAmount = Double(funds.amount.amount.value) / 1000000000.0 * Double(funds.commissionPermille) / 1000.0
|
||||||
|
subtitle = "You will receive \(displayAmount) TON (\(commissionValue)%)\nfor publishing this post"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.titleNode = ASTextNode()
|
self.titleNode = ASTextNode()
|
||||||
@ -130,6 +160,19 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
|||||||
self.textNode = nil
|
self.textNode = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let subtitle {
|
||||||
|
let subtitleNode = ASTextNode()
|
||||||
|
subtitleNode.attributedText = NSAttributedString(string: subtitle, font: Font.regular(15.0), textColor: textColor)
|
||||||
|
subtitleNode.maximumNumberOfLines = 0
|
||||||
|
subtitleNode.textAlignment = .center
|
||||||
|
subtitleNode.lineSpacing = 0.2
|
||||||
|
subtitleNode.accessibilityLabel = text
|
||||||
|
subtitleNode.accessibilityTraits = [.staticText]
|
||||||
|
self.subtitleNode = subtitleNode
|
||||||
|
} else {
|
||||||
|
self.subtitleNode = nil
|
||||||
|
}
|
||||||
|
|
||||||
self.cancelButton = HighlightableButtonNode()
|
self.cancelButton = HighlightableButtonNode()
|
||||||
self.cancelButton.setTitle(self.presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: accentColor, for: .normal)
|
self.cancelButton.setTitle(self.presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: accentColor, for: .normal)
|
||||||
self.cancelButton.accessibilityLabel = self.presentationData.strings.Common_Cancel
|
self.cancelButton.accessibilityLabel = self.presentationData.strings.Common_Cancel
|
||||||
@ -139,7 +182,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
|||||||
|
|
||||||
self.onlineButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: buttonColor, foregroundColor: buttonTextColor), font: .regular, height: 52.0, cornerRadius: 11.0, gloss: false)
|
self.onlineButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: buttonColor, foregroundColor: buttonTextColor), font: .regular, height: 52.0, cornerRadius: 11.0, gloss: false)
|
||||||
switch mode {
|
switch mode {
|
||||||
case let .suggestPost(needsTime):
|
case let .suggestPost(needsTime, _, _):
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
if needsTime {
|
if needsTime {
|
||||||
self.onlineButton.title = "Post Now"
|
self.onlineButton.title = "Post Now"
|
||||||
@ -172,6 +215,9 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
|||||||
self.backgroundNode.addSubnode(self.effectNode)
|
self.backgroundNode.addSubnode(self.effectNode)
|
||||||
self.backgroundNode.addSubnode(self.contentBackgroundNode)
|
self.backgroundNode.addSubnode(self.contentBackgroundNode)
|
||||||
self.contentContainerNode.addSubnode(self.titleNode)
|
self.contentContainerNode.addSubnode(self.titleNode)
|
||||||
|
if let subtitleNode = self.subtitleNode {
|
||||||
|
self.contentContainerNode.addSubnode(subtitleNode)
|
||||||
|
}
|
||||||
if let textNode = self.textNode {
|
if let textNode = self.textNode {
|
||||||
self.contentContainerNode.addSubnode(textNode)
|
self.contentContainerNode.addSubnode(textNode)
|
||||||
}
|
}
|
||||||
@ -334,7 +380,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
|||||||
} else {
|
} else {
|
||||||
self.doneButton.title = self.presentationData.strings.Conversation_SetReminder_RemindOn(self.dateFormatter.string(from: date), time).string
|
self.doneButton.title = self.presentationData.strings.Conversation_SetReminder_RemindOn(self.dateFormatter.string(from: date), time).string
|
||||||
}
|
}
|
||||||
case let .suggestPost(needsTime):
|
case let .suggestPost(needsTime, _, _):
|
||||||
if needsTime {
|
if needsTime {
|
||||||
if calendar.isDateInToday(date) {
|
if calendar.isDateInToday(date) {
|
||||||
self.doneButton.title = self.presentationData.strings.SuggestPost_Time_SendToday(time).string
|
self.doneButton.title = self.presentationData.strings.SuggestPost_Time_SendToday(time).string
|
||||||
@ -386,10 +432,14 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
|||||||
let targetBounds = self.bounds
|
let targetBounds = self.bounds
|
||||||
self.bounds = self.bounds.offsetBy(dx: 0.0, dy: -offset)
|
self.bounds = self.bounds.offsetBy(dx: 0.0, dy: -offset)
|
||||||
self.dimNode.position = CGPoint(x: dimPosition.x, y: dimPosition.y - offset)
|
self.dimNode.position = CGPoint(x: dimPosition.x, y: dimPosition.y - offset)
|
||||||
transition.animateView({
|
|
||||||
self.bounds = targetBounds
|
transition.updateBounds(layer: self.layer, bounds: targetBounds)
|
||||||
self.dimNode.position = dimPosition
|
transition.updatePosition(layer: self.dimNode.layer, position: dimPosition)
|
||||||
})
|
|
||||||
|
if let toastView = self.toast?.view {
|
||||||
|
toastView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||||
|
transition.animatePositionAdditive(layer: toastView.layer, offset: CGPoint(x: 0.0, y: -offset))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateOut(completion: (() -> Void)? = nil) {
|
func animateOut(completion: (() -> Void)? = nil) {
|
||||||
@ -415,6 +465,12 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
|||||||
offsetCompleted = true
|
offsetCompleted = true
|
||||||
internalCompletion()
|
internalCompletion()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if let toastView = self.toast?.view {
|
||||||
|
toastView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
|
||||||
|
})
|
||||||
|
toastView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -offset), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
@ -463,6 +519,17 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
|||||||
|
|
||||||
let textControlSpacing: CGFloat = -8.0
|
let textControlSpacing: CGFloat = -8.0
|
||||||
let textDoneSpacing: CGFloat = 21.0
|
let textDoneSpacing: CGFloat = 21.0
|
||||||
|
|
||||||
|
let subtitleTopSpacing: CGFloat = 22.0
|
||||||
|
let subtitleControlSpacing: CGFloat = 8.0
|
||||||
|
|
||||||
|
let subtitleSize = self.subtitleNode?.measure(CGSize(width: width, height: 1000.0))
|
||||||
|
var controlOffset: CGFloat = 0.0
|
||||||
|
if let subtitleSize {
|
||||||
|
contentHeight += subtitleSize.height + subtitleTopSpacing + subtitleControlSpacing
|
||||||
|
controlOffset += subtitleTopSpacing + subtitleControlSpacing + 20.0
|
||||||
|
}
|
||||||
|
|
||||||
let textSize = self.textNode?.measure(CGSize(width: width, height: 1000.0))
|
let textSize = self.textNode?.measure(CGSize(width: width, height: 1000.0))
|
||||||
if let textSize {
|
if let textSize {
|
||||||
contentHeight += textSize.height + textControlSpacing + textDoneSpacing
|
contentHeight += textSize.height + textControlSpacing + textDoneSpacing
|
||||||
@ -486,6 +553,11 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
|||||||
let titleFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - titleSize.width) / 2.0), y: 16.0), size: titleSize)
|
let titleFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - titleSize.width) / 2.0), y: 16.0), size: titleSize)
|
||||||
transition.updateFrame(node: self.titleNode, frame: titleFrame)
|
transition.updateFrame(node: self.titleNode, frame: titleFrame)
|
||||||
|
|
||||||
|
if let subtitleNode = self.subtitleNode, let subtitleSize {
|
||||||
|
let subtitleFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - subtitleSize.width) / 2.0), y: titleFrame.maxY + subtitleTopSpacing), size: subtitleSize)
|
||||||
|
transition.updateFrame(node: subtitleNode, frame: subtitleFrame)
|
||||||
|
}
|
||||||
|
|
||||||
let cancelSize = self.cancelButton.measure(CGSize(width: width, height: titleHeight))
|
let cancelSize = self.cancelButton.measure(CGSize(width: width, height: titleHeight))
|
||||||
let cancelFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: cancelSize)
|
let cancelFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: cancelSize)
|
||||||
transition.updateFrame(node: self.cancelButton, frame: cancelFrame)
|
transition.updateFrame(node: self.cancelButton, frame: cancelFrame)
|
||||||
@ -503,8 +575,52 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
|||||||
let onlineButtonHeight = self.onlineButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition)
|
let onlineButtonHeight = self.onlineButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition)
|
||||||
transition.updateFrame(node: self.onlineButton, frame: CGRect(x: buttonInset, y: contentHeight - onlineButtonHeight - cleanInsets.bottom - 16.0, width: contentFrame.width, height: onlineButtonHeight))
|
transition.updateFrame(node: self.onlineButton, frame: CGRect(x: buttonInset, y: contentHeight - onlineButtonHeight - cleanInsets.bottom - 16.0, width: contentFrame.width, height: onlineButtonHeight))
|
||||||
|
|
||||||
self.pickerView?.frame = CGRect(origin: CGPoint(x: 0.0, y: 54.0), size: CGSize(width: contentFrame.width, height: pickerHeight))
|
self.pickerView?.frame = CGRect(origin: CGPoint(x: 0.0, y: 54.0 + controlOffset), size: CGSize(width: contentFrame.width, height: pickerHeight))
|
||||||
|
|
||||||
transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame)
|
transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame)
|
||||||
|
|
||||||
|
if case let .suggestPost(_, isAdmin, funds) = self.mode, isAdmin, let funds, funds.amount.currency == .stars {
|
||||||
|
let toast: ComponentView<Empty>
|
||||||
|
if let current = self.toast {
|
||||||
|
toast = current
|
||||||
|
} else {
|
||||||
|
toast = ComponentView()
|
||||||
|
self.toast = toast
|
||||||
|
}
|
||||||
|
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||||
|
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||||
|
//TODO:localize
|
||||||
|
let playOnce = ActionSlot<Void>()
|
||||||
|
let toastSize = toast.update(
|
||||||
|
transition: ComponentTransition(transition),
|
||||||
|
component: AnyComponent(ToastContentComponent(
|
||||||
|
icon: AnyComponent(LottieComponent(
|
||||||
|
content: LottieComponent.AppBundleContent(name: "anim_infotip"),
|
||||||
|
startingPosition: .begin,
|
||||||
|
size: CGSize(width: 32.0, height: 32.0),
|
||||||
|
playOnce: playOnce
|
||||||
|
)),
|
||||||
|
content: AnyComponent(VStack([
|
||||||
|
AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .markdown(text: "Transactions in **Stars** may be reversed by the payment provider within **21** days. Only accept Stars from people you trust.", attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil })),
|
||||||
|
maximumNumberOfLines: 0
|
||||||
|
)))
|
||||||
|
], alignment: .left, spacing: 6.0)),
|
||||||
|
insets: UIEdgeInsets(top: 10.0, left: 12.0, bottom: 10.0, right: 10.0),
|
||||||
|
iconSpacing: 12.0
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 12.0 * 2.0, height: 1000.0)
|
||||||
|
)
|
||||||
|
let toastFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left + 12.0, y: layout.insets(options: .statusBar).top + 4.0), size: toastSize)
|
||||||
|
if let toastView = toast.view {
|
||||||
|
if toastView.superview == nil {
|
||||||
|
self.view.addSubview(toastView)
|
||||||
|
playOnce.invoke(())
|
||||||
|
}
|
||||||
|
transition.updatePosition(layer: toastView.layer, position: toastFrame.center)
|
||||||
|
transition.updateBounds(layer: toastView.layer, bounds: CGRect(origin: CGPoint(), size: toastFrame.size))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -503,7 +503,7 @@ public final class PostSuggestionsSettingsScreen: ViewControllerComponentContain
|
|||||||
super.init(context: context, component: PostSuggestionsSettingsScreenComponent(
|
super.init(context: context, component: PostSuggestionsSettingsScreenComponent(
|
||||||
context: context,
|
context: context,
|
||||||
usdWithdrawRate: configuration.usdWithdrawRate,
|
usdWithdrawRate: configuration.usdWithdrawRate,
|
||||||
channelMessageSuggestionCommissionPermille: Int(configuration.channelMessageSuggestionCommissionPermille),
|
channelMessageSuggestionCommissionPermille: Int(configuration.paidMessageCommissionPermille),
|
||||||
peer: peer,
|
peer: peer,
|
||||||
initialPrice: initialPrice,
|
initialPrice: initialPrice,
|
||||||
completion: completion
|
completion: completion
|
||||||
|
|||||||
@ -22,6 +22,7 @@ swift_library(
|
|||||||
"//submodules/Components/SheetComponent",
|
"//submodules/Components/SheetComponent",
|
||||||
"//submodules/TelegramUI/Components/ButtonComponent",
|
"//submodules/TelegramUI/Components/ButtonComponent",
|
||||||
"//submodules/TelegramUI/Components/LottieComponent",
|
"//submodules/TelegramUI/Components/LottieComponent",
|
||||||
|
"//submodules/TelegramCore",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|||||||
@ -12,17 +12,25 @@ import BalancedTextComponent
|
|||||||
import Markdown
|
import Markdown
|
||||||
import TelegramStringFormatting
|
import TelegramStringFormatting
|
||||||
import BundleIconComponent
|
import BundleIconComponent
|
||||||
|
import TelegramCore
|
||||||
|
import TelegramPresentationData
|
||||||
|
|
||||||
private final class BalanceNeededSheetContentComponent: Component {
|
private final class BalanceNeededSheetContentComponent: Component {
|
||||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||||
|
|
||||||
|
let context: AccountContext
|
||||||
|
let amount: StarsAmount
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
let dismiss: () -> Void
|
let dismiss: () -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
|
context: AccountContext,
|
||||||
|
amount: StarsAmount,
|
||||||
action: @escaping () -> Void,
|
action: @escaping () -> Void,
|
||||||
dismiss: @escaping () -> Void
|
dismiss: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
|
self.context = context
|
||||||
|
self.amount = amount
|
||||||
self.action = action
|
self.action = action
|
||||||
self.dismiss = dismiss
|
self.dismiss = dismiss
|
||||||
}
|
}
|
||||||
@ -37,11 +45,13 @@ private final class BalanceNeededSheetContentComponent: Component {
|
|||||||
private let text = ComponentView<Empty>()
|
private let text = ComponentView<Empty>()
|
||||||
private let button = ComponentView<Empty>()
|
private let button = ComponentView<Empty>()
|
||||||
|
|
||||||
private var cancelButton: ComponentView<Empty>?
|
private let closeButton = ComponentView<Empty>()
|
||||||
|
|
||||||
private var component: BalanceNeededSheetContentComponent?
|
private var component: BalanceNeededSheetContentComponent?
|
||||||
private weak var state: EmptyComponentState?
|
private weak var state: EmptyComponentState?
|
||||||
|
|
||||||
|
private var cachedCloseImage: (UIImage, PresentationTheme)?
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
}
|
}
|
||||||
@ -61,61 +71,64 @@ private final class BalanceNeededSheetContentComponent: Component {
|
|||||||
|
|
||||||
let sideInset: CGFloat = 16.0
|
let sideInset: CGFloat = 16.0
|
||||||
|
|
||||||
let cancelButton: ComponentView<Empty>
|
let closeImage: UIImage
|
||||||
if let current = self.cancelButton {
|
if let (image, theme) = self.cachedCloseImage, theme === environment.theme {
|
||||||
cancelButton = current
|
closeImage = image
|
||||||
} else {
|
} else {
|
||||||
cancelButton = ComponentView()
|
closeImage = generateCloseButtonImage(backgroundColor: UIColor(rgb: 0x808084, alpha: 0.1), foregroundColor: environment.theme.actionSheet.inputClearButtonColor)!
|
||||||
self.cancelButton = cancelButton
|
self.cachedCloseImage = (closeImage, environment.theme)
|
||||||
}
|
}
|
||||||
let cancelButtonSize = cancelButton.update(
|
let closeButtonSize = self.closeButton.update(
|
||||||
transition: transition,
|
transition: .immediate,
|
||||||
component: AnyComponent(Button(
|
component: AnyComponent(Button(
|
||||||
content: AnyComponent(Text(text: environment.strings.Common_Cancel, font: Font.regular(17.0), color: environment.theme.list.itemAccentColor)),
|
content: AnyComponent(Image(image: closeImage)),
|
||||||
action: { [weak self] in
|
action: { [weak self] in
|
||||||
guard let self, let component = self.component else {
|
guard let self, let component = self.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
component.dismiss()
|
component.dismiss()
|
||||||
}
|
}
|
||||||
).minSize(CGSize(width: 8.0, height: 44.0))),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: 200.0, height: 100.0)
|
containerSize: CGSize(width: 30.0, height: 30.0)
|
||||||
)
|
)
|
||||||
if let cancelButtonView = cancelButton.view {
|
let closeButtonFrame = CGRect(origin: CGPoint(x: availableSize.width - closeButtonSize.width - 16.0, y: 12.0), size: closeButtonSize)
|
||||||
if cancelButtonView.superview == nil {
|
if let closeButtonView = self.closeButton.view {
|
||||||
self.addSubview(cancelButtonView)
|
if closeButtonView.superview == nil {
|
||||||
|
self.addSubview(closeButtonView)
|
||||||
}
|
}
|
||||||
transition.setFrame(view: cancelButtonView, frame: CGRect(origin: CGPoint(x: 16.0, y: 6.0), size: cancelButtonSize))
|
transition.setFrame(view: closeButtonView, frame: closeButtonFrame)
|
||||||
}
|
}
|
||||||
|
|
||||||
var contentHeight: CGFloat = 0.0
|
var contentHeight: CGFloat = 0.0
|
||||||
contentHeight += 32.0
|
contentHeight += 32.0
|
||||||
|
|
||||||
let iconSize = self.icon.update(
|
let iconSize = CGSize(width: 120.0, height: 120.0)
|
||||||
|
let _ = self.icon.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(LottieComponent(
|
component: AnyComponent(LottieComponent(
|
||||||
content: LottieComponent.AppBundleContent(name: "StoryUpgradeSheet"),
|
content: LottieComponent.AppBundleContent(name: "TonLogo"),
|
||||||
color: nil,
|
color: nil,
|
||||||
startingPosition: .begin,
|
startingPosition: .begin,
|
||||||
size: CGSize(width: 100.0, height: 100.0)
|
size: iconSize,
|
||||||
|
loop: true
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: 100.0, height: 100.0)
|
containerSize: iconSize
|
||||||
)
|
)
|
||||||
if let iconView = self.icon.view {
|
if let iconView = self.icon.view {
|
||||||
if iconView.superview == nil {
|
if iconView.superview == nil {
|
||||||
self.addSubview(iconView)
|
self.addSubview(iconView)
|
||||||
}
|
}
|
||||||
transition.setFrame(view: iconView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - iconSize.width) * 0.5), y: 42.0), size: iconSize))
|
transition.setFrame(view: iconView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - iconSize.width) * 0.5), y: 16.0), size: iconSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
contentHeight += 138.0
|
contentHeight += 110.0
|
||||||
|
|
||||||
let titleSize = self.title.update(
|
let titleSize = self.title.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(MultilineTextComponent(
|
component: AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(string: environment.strings.Story_UpgradeQuality_Title, font: Font.semibold(20.0), textColor: environment.theme.list.itemPrimaryTextColor)),
|
text: .plain(NSAttributedString(string: "\(formatTonAmountText(component.amount.value, dateTimeFormat: component.context.sharedContext.currentPresentationData.with({ $0 }).dateTimeFormat)) TON Needed", font: Font.bold(24.0), textColor: environment.theme.list.itemPrimaryTextColor)),
|
||||||
horizontalAlignment: .center,
|
horizontalAlignment: .center,
|
||||||
maximumNumberOfLines: 0
|
maximumNumberOfLines: 0
|
||||||
)),
|
)),
|
||||||
@ -131,10 +144,11 @@ private final class BalanceNeededSheetContentComponent: Component {
|
|||||||
contentHeight += titleSize.height
|
contentHeight += titleSize.height
|
||||||
contentHeight += 14.0
|
contentHeight += 14.0
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
let textSize = self.text.update(
|
let textSize = self.text.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(BalancedTextComponent(
|
component: AnyComponent(BalancedTextComponent(
|
||||||
text: .plain(NSAttributedString(string: environment.strings.Story_UpgradeQuality_Text, font: Font.regular(14.0), textColor: environment.theme.list.itemSecondaryTextColor)),
|
text: .plain(NSAttributedString(string: "You can add funds to your balance via the third-party platform Fragment.", font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor)),
|
||||||
horizontalAlignment: .center,
|
horizontalAlignment: .center,
|
||||||
maximumNumberOfLines: 0,
|
maximumNumberOfLines: 0,
|
||||||
lineSpacing: 0.18
|
lineSpacing: 0.18
|
||||||
@ -149,10 +163,9 @@ private final class BalanceNeededSheetContentComponent: Component {
|
|||||||
transition.setFrame(view: textView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - textSize.width) * 0.5), y: contentHeight), size: textSize))
|
transition.setFrame(view: textView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - textSize.width) * 0.5), y: contentHeight), size: textSize))
|
||||||
}
|
}
|
||||||
contentHeight += textSize.height
|
contentHeight += textSize.height
|
||||||
contentHeight += 12.0
|
contentHeight += 24.0
|
||||||
|
|
||||||
contentHeight += 32.0
|
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
let buttonSize = self.button.update(
|
let buttonSize = self.button.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(ButtonComponent(
|
component: AnyComponent(ButtonComponent(
|
||||||
@ -162,7 +175,7 @@ private final class BalanceNeededSheetContentComponent: Component {
|
|||||||
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8)
|
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8)
|
||||||
),
|
),
|
||||||
content: AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent(MultilineTextComponent(
|
content: AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(NSAttributedString(string: "Add Funds via Fragment"))
|
text: .plain(NSAttributedString(string: "Add Funds via Fragment", font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor))
|
||||||
))),
|
))),
|
||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
allowActionWhenDisabled: true,
|
allowActionWhenDisabled: true,
|
||||||
@ -190,7 +203,7 @@ private final class BalanceNeededSheetContentComponent: Component {
|
|||||||
if environment.safeInsets.bottom.isZero {
|
if environment.safeInsets.bottom.isZero {
|
||||||
contentHeight += 16.0
|
contentHeight += 16.0
|
||||||
} else {
|
} else {
|
||||||
contentHeight += environment.safeInsets.bottom + 14.0
|
contentHeight += environment.safeInsets.bottom + 8.0
|
||||||
}
|
}
|
||||||
|
|
||||||
return CGSize(width: availableSize.width, height: contentHeight)
|
return CGSize(width: availableSize.width, height: contentHeight)
|
||||||
@ -210,13 +223,16 @@ private final class BalanceNeededScreenComponent: Component {
|
|||||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||||
|
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
|
let amount: StarsAmount
|
||||||
let buttonAction: (() -> Void)?
|
let buttonAction: (() -> Void)?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
|
amount: StarsAmount,
|
||||||
buttonAction: (() -> Void)?
|
buttonAction: (() -> Void)?
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
|
self.amount = amount
|
||||||
self.buttonAction = buttonAction
|
self.buttonAction = buttonAction
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +284,8 @@ private final class BalanceNeededScreenComponent: Component {
|
|||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(SheetComponent(
|
component: AnyComponent(SheetComponent(
|
||||||
content: AnyComponent(BalanceNeededSheetContentComponent(
|
content: AnyComponent(BalanceNeededSheetContentComponent(
|
||||||
|
context: component.context,
|
||||||
|
amount: component.amount,
|
||||||
action: { [weak self] in
|
action: { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
@ -291,7 +309,7 @@ private final class BalanceNeededScreenComponent: Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
backgroundColor: .color(environment.theme.overallDarkAppearance ? environment.theme.list.itemBlocksBackgroundColor : environment.theme.list.blocksBackgroundColor),
|
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
|
||||||
animateOut: self.sheetAnimateOut
|
animateOut: self.sheetAnimateOut
|
||||||
)),
|
)),
|
||||||
environment: {
|
environment: {
|
||||||
@ -323,10 +341,12 @@ private final class BalanceNeededScreenComponent: Component {
|
|||||||
public class BalanceNeededScreen: ViewControllerComponentContainer {
|
public class BalanceNeededScreen: ViewControllerComponentContainer {
|
||||||
public init(
|
public init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
|
amount: StarsAmount,
|
||||||
buttonAction: (() -> Void)? = nil
|
buttonAction: (() -> Void)? = nil
|
||||||
) {
|
) {
|
||||||
super.init(context: context, component: BalanceNeededScreenComponent(
|
super.init(context: context, component: BalanceNeededScreenComponent(
|
||||||
context: context,
|
context: context,
|
||||||
|
amount: amount,
|
||||||
buttonAction: buttonAction
|
buttonAction: buttonAction
|
||||||
), navigationBarAppearance: .none)
|
), navigationBarAppearance: .none)
|
||||||
|
|
||||||
@ -359,3 +379,24 @@ public class BalanceNeededScreen: ViewControllerComponentContainer {
|
|||||||
self.wasDismissed?()
|
self.wasDismissed?()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateCloseButtonImage(backgroundColor: UIColor, foregroundColor: UIColor) -> UIImage? {
|
||||||
|
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
context.setFillColor(backgroundColor.cgColor)
|
||||||
|
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
context.setLineWidth(2.0)
|
||||||
|
context.setLineCap(.round)
|
||||||
|
context.setStrokeColor(foregroundColor.cgColor)
|
||||||
|
|
||||||
|
context.move(to: CGPoint(x: 10.0, y: 10.0))
|
||||||
|
context.addLine(to: CGPoint(x: 20.0, y: 20.0))
|
||||||
|
context.strokePath()
|
||||||
|
|
||||||
|
context.move(to: CGPoint(x: 20.0, y: 10.0))
|
||||||
|
context.addLine(to: CGPoint(x: 10.0, y: 20.0))
|
||||||
|
context.strokePath()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@ -229,6 +229,17 @@ private final class SheetContent: CombinedComponent {
|
|||||||
amountPlaceholder = "Price"
|
amountPlaceholder = "Price"
|
||||||
|
|
||||||
minAmount = StarsAmount(value: 0, nanos: 0)
|
minAmount = StarsAmount(value: 0, nanos: 0)
|
||||||
|
|
||||||
|
if let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate, let tonUsdRate = withdrawConfiguration.tonUsdRate, let amount = state.amount, amount > StarsAmount.zero {
|
||||||
|
switch state.currency {
|
||||||
|
case .stars:
|
||||||
|
let usdRate = Double(usdWithdrawRate) / 1000.0 / 100.0
|
||||||
|
amountLabel = "≈\(formatTonUsdValue(amount.value, divide: false, rate: usdRate, dateTimeFormat: environment.dateTimeFormat))"
|
||||||
|
case .ton:
|
||||||
|
let usdRate = Double(tonUsdRate) / 1000.0 / 1000000.0
|
||||||
|
amountLabel = "≈\(formatTonUsdValue(amount.value, divide: false, rate: usdRate, dateTimeFormat: environment.dateTimeFormat))"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let title = title.update(
|
let title = title.update(
|
||||||
@ -634,7 +645,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
let theme = environment.theme
|
let theme = environment.theme
|
||||||
|
|
||||||
let minimalTime: Int32 = Int32(Date().timeIntervalSince1970) + 5 * 60 + 10
|
let minimalTime: Int32 = Int32(Date().timeIntervalSince1970) + 5 * 60 + 10
|
||||||
let controller = ChatScheduleTimeController(context: state.context, updatedPresentationData: (state.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), state.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) }), mode: .suggestPost(needsTime: false), style: .default, currentTime: state.timestamp, minimalTime: minimalTime, dismissByTapOutside: true, completion: { [weak state] time in
|
let controller = ChatScheduleTimeController(context: state.context, updatedPresentationData: (state.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), state.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) }), mode: .suggestPost(needsTime: false, isAdmin: false, funds: nil), style: .default, currentTime: state.timestamp, minimalTime: minimalTime, dismissByTapOutside: true, completion: { [weak state] time in
|
||||||
guard let state else {
|
guard let state else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -789,8 +800,20 @@ private final class SheetContent: CombinedComponent {
|
|||||||
}
|
}
|
||||||
case .ton:
|
case .ton:
|
||||||
if let balance = state.tonBalance, amount > balance {
|
if let balance = state.tonBalance, amount > balance {
|
||||||
|
let needed = amount - balance
|
||||||
|
var fragmentUrl = "https://fragment.com/ads/topup"
|
||||||
|
if let data = state.context.currentAppConfiguration.with({ $0 }).data, let value = data["ton_topup_url"] as? String {
|
||||||
|
fragmentUrl = value
|
||||||
|
}
|
||||||
controller.push(BalanceNeededScreen(
|
controller.push(BalanceNeededScreen(
|
||||||
context: state.context
|
context: state.context,
|
||||||
|
amount: needed,
|
||||||
|
buttonAction: { [weak state] in
|
||||||
|
guard let state else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state.context.sharedContext.applicationBindings.openUrl(fragmentUrl)
|
||||||
|
}
|
||||||
))
|
))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1641,17 +1664,19 @@ func generateCloseButtonImage(backgroundColor: UIColor, foregroundColor: UIColor
|
|||||||
|
|
||||||
private struct StarsWithdrawConfiguration {
|
private struct StarsWithdrawConfiguration {
|
||||||
static var defaultValue: StarsWithdrawConfiguration {
|
static var defaultValue: StarsWithdrawConfiguration {
|
||||||
return StarsWithdrawConfiguration(minWithdrawAmount: nil, maxPaidMediaAmount: nil, usdWithdrawRate: nil)
|
return StarsWithdrawConfiguration(minWithdrawAmount: nil, maxPaidMediaAmount: nil, usdWithdrawRate: nil, tonUsdRate: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
let minWithdrawAmount: Int64?
|
let minWithdrawAmount: Int64?
|
||||||
let maxPaidMediaAmount: Int64?
|
let maxPaidMediaAmount: Int64?
|
||||||
let usdWithdrawRate: Double?
|
let usdWithdrawRate: Double?
|
||||||
|
let tonUsdRate: Double?
|
||||||
|
|
||||||
fileprivate init(minWithdrawAmount: Int64?, maxPaidMediaAmount: Int64?, usdWithdrawRate: Double?) {
|
fileprivate init(minWithdrawAmount: Int64?, maxPaidMediaAmount: Int64?, usdWithdrawRate: Double?, tonUsdRate: Double?) {
|
||||||
self.minWithdrawAmount = minWithdrawAmount
|
self.minWithdrawAmount = minWithdrawAmount
|
||||||
self.maxPaidMediaAmount = maxPaidMediaAmount
|
self.maxPaidMediaAmount = maxPaidMediaAmount
|
||||||
self.usdWithdrawRate = usdWithdrawRate
|
self.usdWithdrawRate = usdWithdrawRate
|
||||||
|
self.tonUsdRate = tonUsdRate
|
||||||
}
|
}
|
||||||
|
|
||||||
static func with(appConfiguration: AppConfiguration) -> StarsWithdrawConfiguration {
|
static func with(appConfiguration: AppConfiguration) -> StarsWithdrawConfiguration {
|
||||||
@ -1668,8 +1693,12 @@ private struct StarsWithdrawConfiguration {
|
|||||||
if let value = data["stars_usd_withdraw_rate_x1000"] as? Double {
|
if let value = data["stars_usd_withdraw_rate_x1000"] as? Double {
|
||||||
usdWithdrawRate = value
|
usdWithdrawRate = value
|
||||||
}
|
}
|
||||||
|
var tonUsdRate: Double?
|
||||||
|
if let value = data["ton_usd_rate"] as? Double {
|
||||||
|
tonUsdRate = value
|
||||||
|
}
|
||||||
|
|
||||||
return StarsWithdrawConfiguration(minWithdrawAmount: minWithdrawAmount, maxPaidMediaAmount: maxPaidMediaAmount, usdWithdrawRate: usdWithdrawRate)
|
return StarsWithdrawConfiguration(minWithdrawAmount: minWithdrawAmount, maxPaidMediaAmount: maxPaidMediaAmount, usdWithdrawRate: usdWithdrawRate, tonUsdRate: tonUsdRate)
|
||||||
} else {
|
} else {
|
||||||
return .defaultValue
|
return .defaultValue
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "SuggestedPostApproveAlert",
|
||||||
|
module_name = "SuggestedPostApproveAlert",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-warnings-as-errors",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/Display",
|
||||||
|
"//submodules/AsyncDisplayKit",
|
||||||
|
"//submodules/TelegramPresentationData",
|
||||||
|
"//submodules/ComponentFlow",
|
||||||
|
"//submodules/Components/ComponentDisplayAdapters",
|
||||||
|
"//submodules/Markdown",
|
||||||
|
"//submodules/TelegramUI/Components/ToastComponent",
|
||||||
|
"//submodules/TelegramUI/Components/LottieComponent",
|
||||||
|
"//submodules/Components/MultilineTextComponent",
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
||||||
@ -0,0 +1,441 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import Markdown
|
||||||
|
import Display
|
||||||
|
import TelegramPresentationData
|
||||||
|
import ComponentFlow
|
||||||
|
import ToastComponent
|
||||||
|
import Markdown
|
||||||
|
import LottieComponent
|
||||||
|
import MultilineTextComponent
|
||||||
|
import ComponentDisplayAdapters
|
||||||
|
|
||||||
|
private let alertWidth: CGFloat = 270.0
|
||||||
|
|
||||||
|
private final class SuggestedPostApproveAlertContentNode: AlertContentNode {
|
||||||
|
private var theme: AlertControllerTheme
|
||||||
|
private let actionLayout: TextAlertContentActionLayout
|
||||||
|
|
||||||
|
private let titleNode: ImmediateTextNode?
|
||||||
|
private let textNode: ImmediateTextNode
|
||||||
|
|
||||||
|
private let actionNodesSeparator: ASDisplayNode
|
||||||
|
private let actionNodes: [TextAlertContentActionNode]
|
||||||
|
private let actionVerticalSeparators: [ASDisplayNode]
|
||||||
|
|
||||||
|
private var validLayout: CGSize?
|
||||||
|
|
||||||
|
private let _dismissOnOutsideTap: Bool
|
||||||
|
override public var dismissOnOutsideTap: Bool {
|
||||||
|
return self._dismissOnOutsideTap
|
||||||
|
}
|
||||||
|
|
||||||
|
private var highlightedItemIndex: Int? = nil
|
||||||
|
|
||||||
|
public var textAttributeAction: (NSAttributedString.Key, (Any) -> Void)? {
|
||||||
|
didSet {
|
||||||
|
if let (attribute, textAttributeAction) = self.textAttributeAction {
|
||||||
|
self.textNode.highlightAttributeAction = { attributes in
|
||||||
|
if let _ = attributes[attribute] {
|
||||||
|
return attribute
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.textNode.tapAttributeAction = { attributes, _ in
|
||||||
|
if let value = attributes[attribute] {
|
||||||
|
textAttributeAction(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.textNode.linkHighlightColor = self.theme.accentColor.withAlphaComponent(0.5)
|
||||||
|
} else {
|
||||||
|
self.textNode.highlightAttributeAction = nil
|
||||||
|
self.textNode.tapAttributeAction = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(theme: AlertControllerTheme, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout, dismissOnOutsideTap: Bool, linkAction: (([NSAttributedString.Key: Any], Int) -> Void)? = nil) {
|
||||||
|
self.theme = theme
|
||||||
|
self.actionLayout = actionLayout
|
||||||
|
self._dismissOnOutsideTap = dismissOnOutsideTap
|
||||||
|
if let title = title {
|
||||||
|
let titleNode = ImmediateTextNode()
|
||||||
|
titleNode.attributedText = title
|
||||||
|
titleNode.displaysAsynchronously = false
|
||||||
|
titleNode.isUserInteractionEnabled = false
|
||||||
|
titleNode.maximumNumberOfLines = 4
|
||||||
|
titleNode.truncationType = .end
|
||||||
|
titleNode.isAccessibilityElement = true
|
||||||
|
titleNode.accessibilityLabel = title.string
|
||||||
|
self.titleNode = titleNode
|
||||||
|
} else {
|
||||||
|
self.titleNode = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
self.textNode = ImmediateTextNode()
|
||||||
|
self.textNode.maximumNumberOfLines = 0
|
||||||
|
self.textNode.attributedText = text
|
||||||
|
self.textNode.displaysAsynchronously = false
|
||||||
|
self.textNode.isLayerBacked = false
|
||||||
|
self.textNode.isAccessibilityElement = true
|
||||||
|
self.textNode.accessibilityLabel = text.string
|
||||||
|
self.textNode.insets = UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)
|
||||||
|
self.textNode.tapAttributeAction = linkAction
|
||||||
|
self.textNode.highlightAttributeAction = { attributes in
|
||||||
|
if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] {
|
||||||
|
return NSAttributedString.Key(rawValue: "URL")
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.textNode.linkHighlightColor = theme.accentColor.withMultipliedAlpha(0.1)
|
||||||
|
if text.length != 0 {
|
||||||
|
if let paragraphStyle = text.attribute(.paragraphStyle, at: 0, effectiveRange: nil) as? NSParagraphStyle {
|
||||||
|
self.textNode.textAlignment = paragraphStyle.alignment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.actionNodesSeparator = ASDisplayNode()
|
||||||
|
self.actionNodesSeparator.isLayerBacked = true
|
||||||
|
self.actionNodesSeparator.backgroundColor = theme.separatorColor
|
||||||
|
|
||||||
|
self.actionNodes = actions.map { action -> TextAlertContentActionNode in
|
||||||
|
return TextAlertContentActionNode(theme: theme, action: action)
|
||||||
|
}
|
||||||
|
|
||||||
|
var actionVerticalSeparators: [ASDisplayNode] = []
|
||||||
|
if actions.count > 1 {
|
||||||
|
for _ in 0 ..< actions.count - 1 {
|
||||||
|
let separatorNode = ASDisplayNode()
|
||||||
|
separatorNode.isLayerBacked = true
|
||||||
|
separatorNode.backgroundColor = theme.separatorColor
|
||||||
|
actionVerticalSeparators.append(separatorNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.actionVerticalSeparators = actionVerticalSeparators
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
if let titleNode = self.titleNode {
|
||||||
|
self.addSubnode(titleNode)
|
||||||
|
}
|
||||||
|
self.addSubnode(self.textNode)
|
||||||
|
|
||||||
|
self.addSubnode(self.actionNodesSeparator)
|
||||||
|
|
||||||
|
var i = 0
|
||||||
|
for actionNode in self.actionNodes {
|
||||||
|
self.addSubnode(actionNode)
|
||||||
|
|
||||||
|
let index = i
|
||||||
|
actionNode.highlightedUpdated = { [weak self] highlighted in
|
||||||
|
if highlighted {
|
||||||
|
self?.highlightedItemIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for separatorNode in self.actionVerticalSeparators {
|
||||||
|
self.addSubnode(separatorNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setHighlightedItemIndex(_ index: Int?, update: Bool = false) {
|
||||||
|
self.highlightedItemIndex = index
|
||||||
|
|
||||||
|
if update {
|
||||||
|
var i = 0
|
||||||
|
for actionNode in self.actionNodes {
|
||||||
|
if i == index {
|
||||||
|
actionNode.setHighlighted(true, animated: false)
|
||||||
|
} else {
|
||||||
|
actionNode.setHighlighted(false, animated: false)
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func decreaseHighlightedIndex() {
|
||||||
|
let currentHighlightedIndex = self.highlightedItemIndex ?? 0
|
||||||
|
|
||||||
|
self.setHighlightedItemIndex(max(0, currentHighlightedIndex - 1), update: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func increaseHighlightedIndex() {
|
||||||
|
let currentHighlightedIndex = self.highlightedItemIndex ?? -1
|
||||||
|
|
||||||
|
self.setHighlightedItemIndex(min(self.actionNodes.count - 1, currentHighlightedIndex + 1), update: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func performHighlightedAction() {
|
||||||
|
guard let highlightedItemIndex = self.highlightedItemIndex else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = 0
|
||||||
|
for itemNode in self.actionNodes {
|
||||||
|
if i == highlightedItemIndex {
|
||||||
|
itemNode.performAction()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func updateTheme(_ theme: AlertControllerTheme) {
|
||||||
|
self.theme = theme
|
||||||
|
|
||||||
|
if let titleNode = self.titleNode, let attributedText = titleNode.attributedText {
|
||||||
|
let updatedText = NSMutableAttributedString(attributedString: attributedText)
|
||||||
|
updatedText.addAttribute(NSAttributedString.Key.foregroundColor, value: theme.primaryColor, range: NSRange(location: 0, length: updatedText.length))
|
||||||
|
titleNode.attributedText = updatedText
|
||||||
|
}
|
||||||
|
if let attributedText = self.textNode.attributedText {
|
||||||
|
let updatedText = NSMutableAttributedString(attributedString: attributedText)
|
||||||
|
updatedText.addAttribute(NSAttributedString.Key.foregroundColor, value: theme.primaryColor, range: NSRange(location: 0, length: updatedText.length))
|
||||||
|
self.textNode.attributedText = updatedText
|
||||||
|
}
|
||||||
|
|
||||||
|
self.actionNodesSeparator.backgroundColor = theme.separatorColor
|
||||||
|
for actionNode in self.actionNodes {
|
||||||
|
actionNode.updateTheme(theme)
|
||||||
|
}
|
||||||
|
for separatorNode in self.actionVerticalSeparators {
|
||||||
|
separatorNode.backgroundColor = theme.separatorColor
|
||||||
|
}
|
||||||
|
|
||||||
|
if let size = self.validLayout {
|
||||||
|
_ = self.updateLayout(size: size, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||||
|
self.validLayout = size
|
||||||
|
|
||||||
|
let insets = UIEdgeInsets(top: 18.0, left: 18.0, bottom: 18.0, right: 18.0)
|
||||||
|
|
||||||
|
var size = size
|
||||||
|
size.width = min(size.width, alertWidth)
|
||||||
|
|
||||||
|
var titleSize: CGSize?
|
||||||
|
if let titleNode = self.titleNode {
|
||||||
|
titleSize = titleNode.updateLayout(CGSize(width: size.width - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude))
|
||||||
|
}
|
||||||
|
let textSize = self.textNode.updateLayout(CGSize(width: size.width - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude))
|
||||||
|
|
||||||
|
let actionButtonHeight: CGFloat = 44.0
|
||||||
|
|
||||||
|
var minActionsWidth: CGFloat = 0.0
|
||||||
|
let maxActionWidth: CGFloat = floor(size.width / CGFloat(self.actionNodes.count))
|
||||||
|
let actionTitleInsets: CGFloat = 8.0
|
||||||
|
|
||||||
|
var effectiveActionLayout = self.actionLayout
|
||||||
|
for actionNode in self.actionNodes {
|
||||||
|
let actionTitleSize = actionNode.titleNode.updateLayout(CGSize(width: maxActionWidth, height: actionButtonHeight))
|
||||||
|
if case .horizontal = effectiveActionLayout, actionTitleSize.height > actionButtonHeight * 0.6667 {
|
||||||
|
effectiveActionLayout = .vertical
|
||||||
|
}
|
||||||
|
switch effectiveActionLayout {
|
||||||
|
case .horizontal:
|
||||||
|
minActionsWidth += actionTitleSize.width + actionTitleInsets
|
||||||
|
case .vertical:
|
||||||
|
minActionsWidth = max(minActionsWidth, actionTitleSize.width + actionTitleInsets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let resultSize: CGSize
|
||||||
|
|
||||||
|
var actionsHeight: CGFloat = 0.0
|
||||||
|
switch effectiveActionLayout {
|
||||||
|
case .horizontal:
|
||||||
|
actionsHeight = actionButtonHeight
|
||||||
|
case .vertical:
|
||||||
|
actionsHeight = actionButtonHeight * CGFloat(self.actionNodes.count)
|
||||||
|
}
|
||||||
|
|
||||||
|
let contentWidth = alertWidth - insets.left - insets.right
|
||||||
|
if let titleNode = self.titleNode, let titleSize = titleSize {
|
||||||
|
let spacing: CGFloat = 6.0
|
||||||
|
let titleFrame = CGRect(origin: CGPoint(x: insets.left + floor((contentWidth - titleSize.width) / 2.0), y: insets.top), size: titleSize)
|
||||||
|
transition.updateFrame(node: titleNode, frame: titleFrame)
|
||||||
|
|
||||||
|
let textFrame = CGRect(origin: CGPoint(x: insets.left + floor((contentWidth - textSize.width) / 2.0), y: titleFrame.maxY + spacing), size: textSize)
|
||||||
|
transition.updateFrame(node: self.textNode, frame: textFrame.offsetBy(dx: -1.0, dy: -1.0))
|
||||||
|
|
||||||
|
resultSize = CGSize(width: contentWidth + insets.left + insets.right, height: titleSize.height + spacing + textSize.height + actionsHeight + insets.top + insets.bottom)
|
||||||
|
} else {
|
||||||
|
let textFrame = CGRect(origin: CGPoint(x: insets.left + floor((contentWidth - textSize.width) / 2.0), y: insets.top), size: textSize)
|
||||||
|
transition.updateFrame(node: self.textNode, frame: textFrame)
|
||||||
|
|
||||||
|
resultSize = CGSize(width: contentWidth + insets.left + insets.right, height: textSize.height + actionsHeight + insets.top + insets.bottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.actionNodesSeparator.frame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel))
|
||||||
|
|
||||||
|
var actionOffset: CGFloat = 0.0
|
||||||
|
let actionWidth: CGFloat = floor(resultSize.width / CGFloat(self.actionNodes.count))
|
||||||
|
var separatorIndex = -1
|
||||||
|
var nodeIndex = 0
|
||||||
|
for actionNode in self.actionNodes {
|
||||||
|
if separatorIndex >= 0 {
|
||||||
|
let separatorNode = self.actionVerticalSeparators[separatorIndex]
|
||||||
|
switch effectiveActionLayout {
|
||||||
|
case .horizontal:
|
||||||
|
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: actionOffset - UIScreenPixel, y: resultSize.height - actionsHeight), size: CGSize(width: UIScreenPixel, height: actionsHeight - UIScreenPixel)))
|
||||||
|
case .vertical:
|
||||||
|
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
separatorIndex += 1
|
||||||
|
|
||||||
|
let currentActionWidth: CGFloat
|
||||||
|
switch effectiveActionLayout {
|
||||||
|
case .horizontal:
|
||||||
|
if nodeIndex == self.actionNodes.count - 1 {
|
||||||
|
currentActionWidth = resultSize.width - actionOffset
|
||||||
|
} else {
|
||||||
|
currentActionWidth = actionWidth
|
||||||
|
}
|
||||||
|
case .vertical:
|
||||||
|
currentActionWidth = resultSize.width
|
||||||
|
}
|
||||||
|
|
||||||
|
let actionNodeFrame: CGRect
|
||||||
|
switch effectiveActionLayout {
|
||||||
|
case .horizontal:
|
||||||
|
actionNodeFrame = CGRect(origin: CGPoint(x: actionOffset, y: resultSize.height - actionsHeight), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||||
|
actionOffset += currentActionWidth
|
||||||
|
case .vertical:
|
||||||
|
actionNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||||
|
actionOffset += actionButtonHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
transition.updateFrame(node: actionNode, frame: actionNodeFrame)
|
||||||
|
|
||||||
|
nodeIndex += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class SuggestedPostAlertImpl: AlertController {
|
||||||
|
private let toastText: String?
|
||||||
|
private var toast: ComponentView<Empty>?
|
||||||
|
|
||||||
|
init(theme: AlertControllerTheme, contentNode: AlertContentNode, allowInputInset: Bool, toastText: String?) {
|
||||||
|
self.toastText = toastText
|
||||||
|
|
||||||
|
super.init(theme: theme, contentNode: contentNode, allowInputInset: allowInputInset)
|
||||||
|
|
||||||
|
self.willDismiss = { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let toastView = self.toast?.view {
|
||||||
|
toastView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required public init(coder aDecoder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
|
||||||
|
if let toastText = self.toastText {
|
||||||
|
let toast: ComponentView<Empty>
|
||||||
|
if let current = self.toast {
|
||||||
|
toast = current
|
||||||
|
} else {
|
||||||
|
toast = ComponentView()
|
||||||
|
self.toast = toast
|
||||||
|
}
|
||||||
|
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||||
|
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||||
|
//TODO:localize
|
||||||
|
let playOnce = ActionSlot<Void>()
|
||||||
|
let toastSize = toast.update(
|
||||||
|
transition: ComponentTransition(transition),
|
||||||
|
component: AnyComponent(ToastContentComponent(
|
||||||
|
icon: AnyComponent(LottieComponent(
|
||||||
|
content: LottieComponent.AppBundleContent(name: "anim_infotip"),
|
||||||
|
startingPosition: .begin,
|
||||||
|
size: CGSize(width: 32.0, height: 32.0),
|
||||||
|
playOnce: playOnce
|
||||||
|
)),
|
||||||
|
content: AnyComponent(VStack([
|
||||||
|
AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .markdown(text: toastText, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil })),
|
||||||
|
maximumNumberOfLines: 0
|
||||||
|
)))
|
||||||
|
], alignment: .left, spacing: 6.0)),
|
||||||
|
insets: UIEdgeInsets(top: 10.0, left: 12.0, bottom: 10.0, right: 10.0),
|
||||||
|
iconSpacing: 12.0
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 12.0 * 2.0, height: 1000.0)
|
||||||
|
)
|
||||||
|
let toastFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left + 12.0, y: layout.insets(options: .statusBar).top + 4.0), size: toastSize)
|
||||||
|
if let toastView = toast.view {
|
||||||
|
if toastView.superview == nil {
|
||||||
|
self.view.addSubview(toastView)
|
||||||
|
playOnce.invoke(())
|
||||||
|
}
|
||||||
|
transition.updatePosition(layer: toastView.layer, position: toastFrame.center)
|
||||||
|
transition.updateBounds(layer: toastView.layer, bounds: CGRect(origin: CGPoint(), size: toastFrame.size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidAppear(_ animated: Bool) {
|
||||||
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
|
if let toastView = self.toast?.view {
|
||||||
|
toastView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func dismissAnimated() {
|
||||||
|
super.dismissAnimated()
|
||||||
|
|
||||||
|
if let toastView = self.toast?.view {
|
||||||
|
toastView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func SuggestedPostApproveAlert(presentationData: PresentationData, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, parseMarkdown: Bool = false, dismissOnOutsideTap: Bool = true, linkAction: (([NSAttributedString.Key: Any], Int) -> Void)? = nil, toastText: String?) -> AlertController {
|
||||||
|
let theme = AlertControllerTheme(presentationData: presentationData)
|
||||||
|
|
||||||
|
var dismissImpl: (() -> Void)?
|
||||||
|
let attributedText: NSAttributedString
|
||||||
|
if parseMarkdown {
|
||||||
|
let font = title == nil ? Font.semibold(theme.baseFontSize) : Font.regular(floor(theme.baseFontSize * 13.0 / 17.0))
|
||||||
|
let boldFont = title == nil ? Font.bold(theme.baseFontSize) : Font.semibold(floor(theme.baseFontSize * 13.0 / 17.0))
|
||||||
|
let body = MarkdownAttributeSet(font: font, textColor: theme.primaryColor)
|
||||||
|
let bold = MarkdownAttributeSet(font: boldFont, textColor: theme.primaryColor)
|
||||||
|
let link = MarkdownAttributeSet(font: font, textColor: theme.accentColor)
|
||||||
|
attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: link, linkAttribute: { url in
|
||||||
|
return ("URL", url)
|
||||||
|
}), textAlignment: .center)
|
||||||
|
} else {
|
||||||
|
attributedText = NSAttributedString(string: text, font: title == nil ? Font.semibold(theme.baseFontSize) : Font.regular(floor(theme.baseFontSize * 13.0 / 17.0)), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||||
|
}
|
||||||
|
let controller = SuggestedPostAlertImpl(theme: theme, contentNode: TextAlertContentNode(theme: theme, title: title != nil ? NSAttributedString(string: title!, font: Font.semibold(theme.baseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center) : nil, text: attributedText, actions: actions.map { action in
|
||||||
|
return TextAlertAction(type: action.type, title: action.title, action: {
|
||||||
|
dismissImpl?()
|
||||||
|
action.action()
|
||||||
|
})
|
||||||
|
}, actionLayout: actionLayout, dismissOnOutsideTap: dismissOnOutsideTap, linkAction: linkAction), allowInputInset: allowInputInset, toastText: toastText)
|
||||||
|
dismissImpl = { [weak controller] in
|
||||||
|
controller?.dismissAnimated()
|
||||||
|
}
|
||||||
|
return controller
|
||||||
|
}
|
||||||
BIN
submodules/TelegramUI/Resources/Animations/TonLogo.tgs
Normal file
BIN
submodules/TelegramUI/Resources/Animations/TonLogo.tgs
Normal file
Binary file not shown.
@ -137,6 +137,7 @@ import TelegramCallsUI
|
|||||||
import QuickShareScreen
|
import QuickShareScreen
|
||||||
import PostSuggestionsSettingsScreen
|
import PostSuggestionsSettingsScreen
|
||||||
import PromptUI
|
import PromptUI
|
||||||
|
import SuggestedPostApproveAlert
|
||||||
|
|
||||||
public final class ChatControllerOverlayPresentationData {
|
public final class ChatControllerOverlayPresentationData {
|
||||||
public let expandData: (ASDisplayNode?, () -> Void)
|
public let expandData: (ASDisplayNode?, () -> Void)
|
||||||
@ -2362,8 +2363,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
strongSelf.present(promptController, in: .window(.root))
|
strongSelf.present(promptController, in: .window(.root))
|
||||||
case 1:
|
case 1:
|
||||||
var timestamp: Int32?
|
var timestamp: Int32?
|
||||||
|
var funds: (amount: CurrencyAmount, commissionPermille: Int)?
|
||||||
|
if let amount = attribute.amount {
|
||||||
|
let configuration = StarsSubscriptionConfiguration.with(appConfiguration: strongSelf.context.currentAppConfiguration.with { $0 })
|
||||||
|
funds = (amount, amount.currency == .stars ? Int(configuration.channelMessageSuggestionStarsCommissionPermille) : Int(configuration.channelMessageSuggestionTonCommissionPermille))
|
||||||
|
}
|
||||||
|
|
||||||
|
var isAdmin = false
|
||||||
|
if let channel = strongSelf.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.isMonoForum, let linkedMonoforumId = channel.linkedMonoforumId, let mainChannel = strongSelf.presentationInterfaceState.renderedPeer?.peers[linkedMonoforumId] as? TelegramChannel, mainChannel.hasPermission(.manageDirect) {
|
||||||
|
isAdmin = true
|
||||||
|
}
|
||||||
|
|
||||||
if attribute.timestamp == nil {
|
if attribute.timestamp == nil {
|
||||||
let controller = ChatScheduleTimeController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, mode: .suggestPost(needsTime: true), style: .default, currentTime: nil, minimalTime: nil, dismissByTapOutside: true, completion: { [weak strongSelf] time in
|
let controller = ChatScheduleTimeController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, mode: .suggestPost(needsTime: true, isAdmin: isAdmin, funds: funds), style: .default, currentTime: nil, minimalTime: nil, dismissByTapOutside: true, completion: { [weak strongSelf] time in
|
||||||
guard let strongSelf else {
|
guard let strongSelf else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2378,16 +2390,43 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
timestamp = Int32(Date().timeIntervalSince1970) + 1 * 60 * 60
|
timestamp = Int32(Date().timeIntervalSince1970) + 1 * 60 * 60
|
||||||
} else {
|
} else {
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
let textString = "Publish this message now?"
|
var textString: String
|
||||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: textString, actions: [
|
if isAdmin {
|
||||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}),
|
textString = "Do you really want to publish this post from **\((message.author.flatMap(EnginePeer.init))?.compactDisplayTitle ?? "")**?"
|
||||||
|
|
||||||
|
if let funds {
|
||||||
|
var commissionValue: String
|
||||||
|
commissionValue = "\(Double(funds.commissionPermille) * 0.1)"
|
||||||
|
if commissionValue.hasSuffix(".0") {
|
||||||
|
commissionValue = String(commissionValue[commissionValue.startIndex ..< commissionValue.index(commissionValue.endIndex, offsetBy: -2)])
|
||||||
|
} else if commissionValue.hasSuffix(".00") {
|
||||||
|
commissionValue = String(commissionValue[commissionValue.startIndex ..< commissionValue.index(commissionValue.endIndex, offsetBy: -3)])
|
||||||
|
}
|
||||||
|
|
||||||
|
textString += "\n\n"
|
||||||
|
|
||||||
|
switch funds.amount.currency {
|
||||||
|
case .stars:
|
||||||
|
let displayAmount = funds.amount.amount.totalValue * Double(funds.commissionPermille) / 1000.0
|
||||||
|
textString += "You will receive \(displayAmount) Stars (\(commissionValue)%)\nfor publishing this post. It must remain visible for **24** hours after publication."
|
||||||
|
case .ton:
|
||||||
|
let displayAmount = Double(funds.amount.amount.value) / 1000000000.0 * Double(funds.commissionPermille) / 1000.0
|
||||||
|
textString += "You will receive \(displayAmount) TON (\(commissionValue)%)\nfor publishing this post. It must remain visible for **24** hours after publication."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
textString = "Do you really want to publish this post?"
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.present(SuggestedPostApproveAlert(presentationData: strongSelf.presentationData, title: "Accept Terms", text: textString, actions: [
|
||||||
TextAlertAction(type: .defaultAction, title: "Publish", action: { [weak strongSelf] in
|
TextAlertAction(type: .defaultAction, title: "Publish", action: { [weak strongSelf] in
|
||||||
guard let strongSelf else {
|
guard let strongSelf else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, action: .approve(timestamp: timestamp)).startStandalone()
|
let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, action: .approve(timestamp: timestamp)).startStandalone()
|
||||||
})
|
}),
|
||||||
]), in: .window(.root))
|
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {})
|
||||||
|
], actionLayout: .vertical, parseMarkdown: true, toastText: funds?.amount.currency == .ton ? "Transactions in **Stars** may be reversed by the payment provider within **21** days. Only accept Stars from people you trust." : nil), in: .window(.root))
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
strongSelf.interfaceInteraction?.openSuggestPost(message, .default)
|
strongSelf.interfaceInteraction?.openSuggestPost(message, .default)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user