mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-06 17:00:13 +00:00
Various improvements
This commit is contained in:
parent
15c9af3ab2
commit
73218834ff
@ -1501,13 +1501,15 @@ public struct StarsSubscriptionConfiguration {
|
||||
return StarsSubscriptionConfiguration(
|
||||
maxFee: 2500,
|
||||
usdWithdrawRate: 1200,
|
||||
tonUsdRate: 0,
|
||||
paidMessageMaxAmount: 10000,
|
||||
paidMessageCommissionPermille: 850,
|
||||
paidMessagesAvailable: false,
|
||||
starGiftResaleMinAmount: 125,
|
||||
starGiftResaleMaxAmount: 3500,
|
||||
starGiftCommissionPermille: 80,
|
||||
channelMessageSuggestionCommissionPermille: 850,
|
||||
channelMessageSuggestionStarsCommissionPermille: 850,
|
||||
channelMessageSuggestionTonCommissionPermille: 850,
|
||||
channelMessageSuggestionMaxStarsAmount: 10000,
|
||||
channelMessageSuggestionMaxTonAmount: 10000000000000
|
||||
)
|
||||
@ -1515,38 +1517,44 @@ public struct StarsSubscriptionConfiguration {
|
||||
|
||||
public let maxFee: Int64
|
||||
public let usdWithdrawRate: Int64
|
||||
public let tonUsdRate: Int64
|
||||
public let paidMessageMaxAmount: Int64
|
||||
public let paidMessageCommissionPermille: Int32
|
||||
public let paidMessagesAvailable: Bool
|
||||
public let starGiftResaleMinAmount: Int64
|
||||
public let starGiftResaleMaxAmount: Int64
|
||||
public let starGiftCommissionPermille: Int32
|
||||
public let channelMessageSuggestionCommissionPermille: Int32
|
||||
public let channelMessageSuggestionStarsCommissionPermille: Int32
|
||||
public let channelMessageSuggestionTonCommissionPermille: Int32
|
||||
public let channelMessageSuggestionMaxStarsAmount: Int64
|
||||
public let channelMessageSuggestionMaxTonAmount: Int64
|
||||
|
||||
fileprivate init(
|
||||
maxFee: Int64,
|
||||
usdWithdrawRate: Int64,
|
||||
tonUsdRate: Int64,
|
||||
paidMessageMaxAmount: Int64,
|
||||
paidMessageCommissionPermille: Int32,
|
||||
paidMessagesAvailable: Bool,
|
||||
starGiftResaleMinAmount: Int64,
|
||||
starGiftResaleMaxAmount: Int64,
|
||||
starGiftCommissionPermille: Int32,
|
||||
channelMessageSuggestionCommissionPermille: Int32,
|
||||
channelMessageSuggestionStarsCommissionPermille: Int32,
|
||||
channelMessageSuggestionTonCommissionPermille: Int32,
|
||||
channelMessageSuggestionMaxStarsAmount: Int64,
|
||||
channelMessageSuggestionMaxTonAmount: Int64
|
||||
) {
|
||||
self.maxFee = maxFee
|
||||
self.usdWithdrawRate = usdWithdrawRate
|
||||
self.tonUsdRate = tonUsdRate
|
||||
self.paidMessageMaxAmount = paidMessageMaxAmount
|
||||
self.paidMessageCommissionPermille = paidMessageCommissionPermille
|
||||
self.paidMessagesAvailable = paidMessagesAvailable
|
||||
self.starGiftResaleMinAmount = starGiftResaleMinAmount
|
||||
self.starGiftResaleMaxAmount = starGiftResaleMaxAmount
|
||||
self.starGiftCommissionPermille = starGiftCommissionPermille
|
||||
self.channelMessageSuggestionCommissionPermille = channelMessageSuggestionCommissionPermille
|
||||
self.channelMessageSuggestionStarsCommissionPermille = channelMessageSuggestionStarsCommissionPermille
|
||||
self.channelMessageSuggestionTonCommissionPermille = channelMessageSuggestionTonCommissionPermille
|
||||
self.channelMessageSuggestionMaxStarsAmount = channelMessageSuggestionMaxStarsAmount
|
||||
self.channelMessageSuggestionMaxTonAmount = channelMessageSuggestionMaxTonAmount
|
||||
}
|
||||
@ -1555,6 +1563,7 @@ public struct StarsSubscriptionConfiguration {
|
||||
if let data = appConfiguration.data {
|
||||
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 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 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
|
||||
@ -1562,20 +1571,23 @@ public struct StarsSubscriptionConfiguration {
|
||||
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 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 channelMessageSuggestionMaxTonAmount = (data["ton_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxTonAmount
|
||||
|
||||
return StarsSubscriptionConfiguration(
|
||||
maxFee: maxFee,
|
||||
usdWithdrawRate: usdWithdrawRate,
|
||||
tonUsdRate: tonUsdRate,
|
||||
paidMessageMaxAmount: paidMessageMaxAmount,
|
||||
paidMessageCommissionPermille: paidMessageCommissionPermille,
|
||||
paidMessagesAvailable: paidMessagesAvailable,
|
||||
starGiftResaleMinAmount: starGiftResaleMinAmount,
|
||||
starGiftResaleMaxAmount: starGiftResaleMaxAmount,
|
||||
starGiftCommissionPermille: starGiftCommissionPermille,
|
||||
channelMessageSuggestionCommissionPermille: channelMessageSuggestionCommissionPermille,
|
||||
channelMessageSuggestionStarsCommissionPermille: channelMessageSuggestionStarsCommissionPermille,
|
||||
channelMessageSuggestionTonCommissionPermille: channelMessageSuggestionTonCommissionPermille,
|
||||
channelMessageSuggestionMaxStarsAmount: channelMessageSuggestionMaxStarsAmount,
|
||||
channelMessageSuggestionMaxTonAmount: channelMessageSuggestionMaxTonAmount
|
||||
)
|
||||
|
||||
@ -1487,7 +1487,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
amountString = "\(amount.amount.value) Stars"
|
||||
}
|
||||
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 }))
|
||||
case let .suggestedPostRefund(info):
|
||||
|
||||
@ -28,7 +28,7 @@ public func formatTonUsdValue(_ value: Int64, divide: Bool = true, rate: Double
|
||||
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))"
|
||||
while balanceText.count < 10 {
|
||||
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 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])
|
||||
} else {
|
||||
balanceText = String(balanceText[balanceText.startIndex..<balanceText.endIndex])
|
||||
|
||||
@ -480,6 +480,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/GifVideoLayer",
|
||||
"//submodules/TelegramUI/Components/BatchVideoRendering",
|
||||
"//submodules/TelegramUI/Components/ComposeTodoScreen",
|
||||
"//submodules/TelegramUI/Components/SuggestedPostApproveAlert",
|
||||
] + select({
|
||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||
"//build-system:ios_sim_arm64": [],
|
||||
|
||||
@ -21,6 +21,12 @@ swift_library(
|
||||
"//submodules/SolidRoundedButtonNode",
|
||||
"//submodules/PresentationDataUtils",
|
||||
"//submodules/UIKitRuntimeUtils",
|
||||
"//submodules/ComponentFlow",
|
||||
"//submodules/TelegramUI/Components/ToastComponent",
|
||||
"//submodules/Markdown",
|
||||
"//submodules/TelegramUI/Components/LottieComponent",
|
||||
"//submodules/Components/MultilineTextComponent",
|
||||
"//submodules/Components/ComponentDisplayAdapters",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
||||
@ -11,7 +11,7 @@ import TelegramPresentationData
|
||||
public enum ChatScheduleTimeControllerMode {
|
||||
case scheduledMessages(sendWhenOnlineAvailable: Bool)
|
||||
case reminders
|
||||
case suggestPost(needsTime: Bool)
|
||||
case suggestPost(needsTime: Bool, isAdmin: Bool, funds: (amount: CurrencyAmount, commissionPermille: Int)?)
|
||||
}
|
||||
|
||||
public enum ChatScheduleTimeControllerStyle {
|
||||
|
||||
@ -10,6 +10,12 @@ import AccountContext
|
||||
import SolidRoundedButtonNode
|
||||
import PresentationDataUtils
|
||||
import UIKitRuntimeUtils
|
||||
import ComponentFlow
|
||||
import ToastComponent
|
||||
import Markdown
|
||||
import LottieComponent
|
||||
import MultilineTextComponent
|
||||
import ComponentDisplayAdapters
|
||||
|
||||
class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDelegate {
|
||||
private let context: AccountContext
|
||||
@ -26,6 +32,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let contentBackgroundNode: ASDisplayNode
|
||||
private let titleNode: ASTextNode
|
||||
private let subtitleNode: ASTextNode?
|
||||
private let textNode: ASTextNode?
|
||||
private let cancelButton: HighlightableButtonNode
|
||||
private let doneButton: SolidRoundedButtonNode
|
||||
@ -36,6 +43,8 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
||||
|
||||
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
private var toast: ComponentView<Empty>?
|
||||
|
||||
var completion: ((Int32) -> Void)?
|
||||
var dismiss: (() -> Void)?
|
||||
var cancel: (() -> Void)?
|
||||
@ -94,22 +103,43 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
||||
self.contentBackgroundNode.backgroundColor = backgroundColor
|
||||
|
||||
let title: String
|
||||
var subtitle: String?
|
||||
var text: String?
|
||||
switch mode {
|
||||
case .scheduledMessages:
|
||||
title = self.presentationData.strings.Conversation_ScheduleMessage_Title
|
||||
case .reminders:
|
||||
title = self.presentationData.strings.Conversation_SetReminder_Title
|
||||
case let .suggestPost(needsTime):
|
||||
case let .suggestPost(needsTime, isAdmin, funds):
|
||||
if needsTime {
|
||||
//TODO:localize
|
||||
title = "Time"
|
||||
title = "Accept Terms"
|
||||
text = "Set the date and time you want\nthis message to be published."
|
||||
} else {
|
||||
//TODO:localize
|
||||
title = "Time"
|
||||
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()
|
||||
@ -130,6 +160,19 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
||||
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.setTitle(self.presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: accentColor, for: .normal)
|
||||
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)
|
||||
switch mode {
|
||||
case let .suggestPost(needsTime):
|
||||
case let .suggestPost(needsTime, _, _):
|
||||
//TODO:localize
|
||||
if needsTime {
|
||||
self.onlineButton.title = "Post Now"
|
||||
@ -172,6 +215,9 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
||||
self.backgroundNode.addSubnode(self.effectNode)
|
||||
self.backgroundNode.addSubnode(self.contentBackgroundNode)
|
||||
self.contentContainerNode.addSubnode(self.titleNode)
|
||||
if let subtitleNode = self.subtitleNode {
|
||||
self.contentContainerNode.addSubnode(subtitleNode)
|
||||
}
|
||||
if let textNode = self.textNode {
|
||||
self.contentContainerNode.addSubnode(textNode)
|
||||
}
|
||||
@ -334,7 +380,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
||||
} else {
|
||||
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 calendar.isDateInToday(date) {
|
||||
self.doneButton.title = self.presentationData.strings.SuggestPost_Time_SendToday(time).string
|
||||
@ -386,10 +432,14 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
||||
let targetBounds = self.bounds
|
||||
self.bounds = self.bounds.offsetBy(dx: 0.0, dy: -offset)
|
||||
self.dimNode.position = CGPoint(x: dimPosition.x, y: dimPosition.y - offset)
|
||||
transition.animateView({
|
||||
self.bounds = targetBounds
|
||||
self.dimNode.position = dimPosition
|
||||
})
|
||||
|
||||
transition.updateBounds(layer: self.layer, bounds: targetBounds)
|
||||
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) {
|
||||
@ -415,6 +465,12 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
||||
offsetCompleted = true
|
||||
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? {
|
||||
@ -463,6 +519,17 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
|
||||
|
||||
let textControlSpacing: CGFloat = -8.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))
|
||||
if let textSize {
|
||||
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)
|
||||
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 cancelFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: cancelSize)
|
||||
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)
|
||||
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)
|
||||
|
||||
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(
|
||||
context: context,
|
||||
usdWithdrawRate: configuration.usdWithdrawRate,
|
||||
channelMessageSuggestionCommissionPermille: Int(configuration.channelMessageSuggestionCommissionPermille),
|
||||
channelMessageSuggestionCommissionPermille: Int(configuration.paidMessageCommissionPermille),
|
||||
peer: peer,
|
||||
initialPrice: initialPrice,
|
||||
completion: completion
|
||||
|
||||
@ -22,6 +22,7 @@ swift_library(
|
||||
"//submodules/Components/SheetComponent",
|
||||
"//submodules/TelegramUI/Components/ButtonComponent",
|
||||
"//submodules/TelegramUI/Components/LottieComponent",
|
||||
"//submodules/TelegramCore",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
||||
@ -12,17 +12,25 @@ import BalancedTextComponent
|
||||
import Markdown
|
||||
import TelegramStringFormatting
|
||||
import BundleIconComponent
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
|
||||
private final class BalanceNeededSheetContentComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let amount: StarsAmount
|
||||
let action: () -> Void
|
||||
let dismiss: () -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
amount: StarsAmount,
|
||||
action: @escaping () -> Void,
|
||||
dismiss: @escaping () -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.amount = amount
|
||||
self.action = action
|
||||
self.dismiss = dismiss
|
||||
}
|
||||
@ -37,11 +45,13 @@ private final class BalanceNeededSheetContentComponent: Component {
|
||||
private let text = ComponentView<Empty>()
|
||||
private let button = ComponentView<Empty>()
|
||||
|
||||
private var cancelButton: ComponentView<Empty>?
|
||||
private let closeButton = ComponentView<Empty>()
|
||||
|
||||
private var component: BalanceNeededSheetContentComponent?
|
||||
private weak var state: EmptyComponentState?
|
||||
|
||||
private var cachedCloseImage: (UIImage, PresentationTheme)?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
@ -61,61 +71,64 @@ private final class BalanceNeededSheetContentComponent: Component {
|
||||
|
||||
let sideInset: CGFloat = 16.0
|
||||
|
||||
let cancelButton: ComponentView<Empty>
|
||||
if let current = self.cancelButton {
|
||||
cancelButton = current
|
||||
let closeImage: UIImage
|
||||
if let (image, theme) = self.cachedCloseImage, theme === environment.theme {
|
||||
closeImage = image
|
||||
} else {
|
||||
cancelButton = ComponentView()
|
||||
self.cancelButton = cancelButton
|
||||
closeImage = generateCloseButtonImage(backgroundColor: UIColor(rgb: 0x808084, alpha: 0.1), foregroundColor: environment.theme.actionSheet.inputClearButtonColor)!
|
||||
self.cachedCloseImage = (closeImage, environment.theme)
|
||||
}
|
||||
let cancelButtonSize = cancelButton.update(
|
||||
transition: transition,
|
||||
let closeButtonSize = self.closeButton.update(
|
||||
transition: .immediate,
|
||||
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
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.dismiss()
|
||||
}
|
||||
).minSize(CGSize(width: 8.0, height: 44.0))),
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 200.0, height: 100.0)
|
||||
containerSize: CGSize(width: 30.0, height: 30.0)
|
||||
)
|
||||
if let cancelButtonView = cancelButton.view {
|
||||
if cancelButtonView.superview == nil {
|
||||
self.addSubview(cancelButtonView)
|
||||
let closeButtonFrame = CGRect(origin: CGPoint(x: availableSize.width - closeButtonSize.width - 16.0, y: 12.0), size: closeButtonSize)
|
||||
if let closeButtonView = self.closeButton.view {
|
||||
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
|
||||
contentHeight += 32.0
|
||||
|
||||
let iconSize = self.icon.update(
|
||||
let iconSize = CGSize(width: 120.0, height: 120.0)
|
||||
let _ = self.icon.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(LottieComponent(
|
||||
content: LottieComponent.AppBundleContent(name: "StoryUpgradeSheet"),
|
||||
content: LottieComponent.AppBundleContent(name: "TonLogo"),
|
||||
color: nil,
|
||||
startingPosition: .begin,
|
||||
size: CGSize(width: 100.0, height: 100.0)
|
||||
size: iconSize,
|
||||
loop: true
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||
containerSize: iconSize
|
||||
)
|
||||
if let iconView = self.icon.view {
|
||||
if iconView.superview == nil {
|
||||
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(
|
||||
transition: transition,
|
||||
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,
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
@ -131,10 +144,11 @@ private final class BalanceNeededSheetContentComponent: Component {
|
||||
contentHeight += titleSize.height
|
||||
contentHeight += 14.0
|
||||
|
||||
//TODO:localize
|
||||
let textSize = self.text.update(
|
||||
transition: transition,
|
||||
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,
|
||||
maximumNumberOfLines: 0,
|
||||
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))
|
||||
}
|
||||
contentHeight += textSize.height
|
||||
contentHeight += 12.0
|
||||
|
||||
contentHeight += 32.0
|
||||
contentHeight += 24.0
|
||||
|
||||
//TODO:localize
|
||||
let buttonSize = self.button.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(ButtonComponent(
|
||||
@ -162,7 +175,7 @@ private final class BalanceNeededSheetContentComponent: Component {
|
||||
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8)
|
||||
),
|
||||
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,
|
||||
allowActionWhenDisabled: true,
|
||||
@ -190,7 +203,7 @@ private final class BalanceNeededSheetContentComponent: Component {
|
||||
if environment.safeInsets.bottom.isZero {
|
||||
contentHeight += 16.0
|
||||
} else {
|
||||
contentHeight += environment.safeInsets.bottom + 14.0
|
||||
contentHeight += environment.safeInsets.bottom + 8.0
|
||||
}
|
||||
|
||||
return CGSize(width: availableSize.width, height: contentHeight)
|
||||
@ -210,13 +223,16 @@ private final class BalanceNeededScreenComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let amount: StarsAmount
|
||||
let buttonAction: (() -> Void)?
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
amount: StarsAmount,
|
||||
buttonAction: (() -> Void)?
|
||||
) {
|
||||
self.context = context
|
||||
self.amount = amount
|
||||
self.buttonAction = buttonAction
|
||||
}
|
||||
|
||||
@ -268,6 +284,8 @@ private final class BalanceNeededScreenComponent: Component {
|
||||
transition: transition,
|
||||
component: AnyComponent(SheetComponent(
|
||||
content: AnyComponent(BalanceNeededSheetContentComponent(
|
||||
context: component.context,
|
||||
amount: component.amount,
|
||||
action: { [weak self] in
|
||||
guard let self else {
|
||||
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
|
||||
)),
|
||||
environment: {
|
||||
@ -323,10 +341,12 @@ private final class BalanceNeededScreenComponent: Component {
|
||||
public class BalanceNeededScreen: ViewControllerComponentContainer {
|
||||
public init(
|
||||
context: AccountContext,
|
||||
amount: StarsAmount,
|
||||
buttonAction: (() -> Void)? = nil
|
||||
) {
|
||||
super.init(context: context, component: BalanceNeededScreenComponent(
|
||||
context: context,
|
||||
amount: amount,
|
||||
buttonAction: buttonAction
|
||||
), navigationBarAppearance: .none)
|
||||
|
||||
@ -359,3 +379,24 @@ public class BalanceNeededScreen: ViewControllerComponentContainer {
|
||||
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"
|
||||
|
||||
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(
|
||||
@ -634,7 +645,7 @@ private final class SheetContent: CombinedComponent {
|
||||
let theme = environment.theme
|
||||
|
||||
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 {
|
||||
return
|
||||
}
|
||||
@ -789,8 +800,20 @@ private final class SheetContent: CombinedComponent {
|
||||
}
|
||||
case .ton:
|
||||
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(
|
||||
context: state.context
|
||||
context: state.context,
|
||||
amount: needed,
|
||||
buttonAction: { [weak state] in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
state.context.sharedContext.applicationBindings.openUrl(fragmentUrl)
|
||||
}
|
||||
))
|
||||
return
|
||||
}
|
||||
@ -1641,17 +1664,19 @@ func generateCloseButtonImage(backgroundColor: UIColor, foregroundColor: UIColor
|
||||
|
||||
private struct 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 maxPaidMediaAmount: Int64?
|
||||
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.maxPaidMediaAmount = maxPaidMediaAmount
|
||||
self.usdWithdrawRate = usdWithdrawRate
|
||||
self.tonUsdRate = tonUsdRate
|
||||
}
|
||||
|
||||
static func with(appConfiguration: AppConfiguration) -> StarsWithdrawConfiguration {
|
||||
@ -1668,8 +1693,12 @@ private struct StarsWithdrawConfiguration {
|
||||
if let value = data["stars_usd_withdraw_rate_x1000"] as? Double {
|
||||
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 {
|
||||
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 PostSuggestionsSettingsScreen
|
||||
import PromptUI
|
||||
import SuggestedPostApproveAlert
|
||||
|
||||
public final class ChatControllerOverlayPresentationData {
|
||||
public let expandData: (ASDisplayNode?, () -> Void)
|
||||
@ -2362,8 +2363,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.present(promptController, in: .window(.root))
|
||||
case 1:
|
||||
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 {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
@ -2378,16 +2390,43 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
timestamp = Int32(Date().timeIntervalSince1970) + 1 * 60 * 60
|
||||
} else {
|
||||
//TODO:localize
|
||||
let textString = "Publish this message now?"
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: textString, actions: [
|
||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}),
|
||||
var textString: String
|
||||
if isAdmin {
|
||||
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
|
||||
guard let strongSelf else {
|
||||
return
|
||||
}
|
||||
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:
|
||||
strongSelf.interfaceInteraction?.openSuggestPost(message, .default)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user