Payments and more

This commit is contained in:
Ali 2021-04-09 01:30:50 +04:00
parent bfcb7e6e10
commit aa7a568197
24 changed files with 397 additions and 136 deletions

View File

@ -43,7 +43,7 @@ enum BotCheckoutActionButtonState: Equatable {
private let titleFont = Font.semibold(17.0)
final class BotCheckoutActionButton: HighlightableButtonNode {
static var diameter: CGFloat = 48.0
static var height: CGFloat = 52.0
private var inactiveFillColor: UIColor
private var activeFillColor: UIColor
@ -62,12 +62,14 @@ final class BotCheckoutActionButton: HighlightableButtonNode {
self.inactiveFillColor = inactiveFillColor
self.activeFillColor = activeFillColor
self.foregroundColor = foregroundColor
let diameter: CGFloat = 20.0
self.progressBackgroundNode = ASImageNode()
self.progressBackgroundNode.displaysAsynchronously = false
self.progressBackgroundNode.displayWithoutProcessing = true
self.progressBackgroundNode.isLayerBacked = true
self.progressBackgroundNode.image = generateImage(CGSize(width: BotCheckoutActionButton.diameter, height: BotCheckoutActionButton.diameter), rotatedContext: { size, context in
self.progressBackgroundNode.image = generateImage(CGSize(width: diameter, height: diameter), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
let strokeWidth: CGFloat = 2.0
context.setFillColor(activeFillColor.cgColor)
@ -75,7 +77,7 @@ final class BotCheckoutActionButton: HighlightableButtonNode {
context.setFillColor(inactiveFillColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(x: strokeWidth, y: strokeWidth), size: CGSize(width: size.width - strokeWidth * 2.0, height: size.height - strokeWidth * 2.0)))
let cutout: CGFloat = 10.0
let cutout: CGFloat = diameter
context.fill(CGRect(origin: CGPoint(x: floor((size.width - cutout) / 2.0), y: 0.0), size: CGSize(width: cutout, height: cutout)))
})
@ -83,14 +85,14 @@ final class BotCheckoutActionButton: HighlightableButtonNode {
self.inactiveBackgroundNode.displaysAsynchronously = false
self.inactiveBackgroundNode.displayWithoutProcessing = true
self.inactiveBackgroundNode.isLayerBacked = true
self.inactiveBackgroundNode.image = generateStretchableFilledCircleImage(diameter: BotCheckoutActionButton.diameter, color: self.foregroundColor, strokeColor: activeFillColor, strokeWidth: 2.0)
self.inactiveBackgroundNode.image = generateStretchableFilledCircleImage(diameter: diameter, color: self.foregroundColor, strokeColor: activeFillColor, strokeWidth: 2.0)
self.inactiveBackgroundNode.alpha = 0.0
self.activeBackgroundNode = ASImageNode()
self.activeBackgroundNode.displaysAsynchronously = false
self.activeBackgroundNode.displayWithoutProcessing = true
self.activeBackgroundNode.isLayerBacked = true
self.activeBackgroundNode.image = generateStretchableFilledCircleImage(diameter: BotCheckoutActionButton.diameter, color: activeFillColor)
self.activeBackgroundNode.image = generateStretchableFilledCircleImage(diameter: diameter, color: activeFillColor)
self.labelNode = TextNode()
self.labelNode.displaysAsynchronously = false
@ -178,10 +180,21 @@ final class BotCheckoutActionButton: HighlightableButtonNode {
self.labelNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
}
case .applePay:
if case .applePay = previousState {
} else {
if self.applePayButton == nil {
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
let applePayButton: PKPaymentButton
if #available(iOS 14.0, *) {
applePayButton = PKPaymentButton(paymentButtonType: .buy, paymentButtonStyle: .black)
} else {
applePayButton = PKPaymentButton(paymentButtonType: .buy, paymentButtonStyle: .black)
}
applePayButton.addTarget(self, action: #selector(self.applePayButtonPressed), for: .touchUpInside)
self.view.addSubview(applePayButton)
self.applePayButton = applePayButton
}
}
if let applePayButton = self.applePayButton {
applePayButton.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: validLayout.width, height: BotCheckoutActionButton.height))
}
}
} else {
@ -226,15 +239,19 @@ final class BotCheckoutActionButton: HighlightableButtonNode {
}
}
}
@objc private func applePayButtonPressed() {
self.sendActions(forControlEvents: .touchUpInside, with: nil)
}
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
self.validLayout = size
transition.updateFrame(node: self.progressBackgroundNode, frame: CGRect(origin: CGPoint(x: floor((size.width - BotCheckoutActionButton.diameter) / 2.0), y: 0.0), size: CGSize(width: BotCheckoutActionButton.diameter, height: BotCheckoutActionButton.diameter)))
transition.updateFrame(node: self.inactiveBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: BotCheckoutActionButton.diameter)))
transition.updateFrame(node: self.activeBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: BotCheckoutActionButton.diameter)))
transition.updateFrame(node: self.progressBackgroundNode, frame: CGRect(origin: CGPoint(x: floor((size.width - BotCheckoutActionButton.height) / 2.0), y: 0.0), size: CGSize(width: BotCheckoutActionButton.height, height: BotCheckoutActionButton.height)))
transition.updateFrame(node: self.inactiveBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: BotCheckoutActionButton.height)))
transition.updateFrame(node: self.activeBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: BotCheckoutActionButton.height)))
if let applePayButton = self.applePayButton {
applePayButton.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: BotCheckoutActionButton.diameter))
applePayButton.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: BotCheckoutActionButton.height))
}
var labelSize = self.labelNode.bounds.size

View File

@ -55,7 +55,7 @@ enum BotCheckoutEntry: ItemListNodeEntry {
var section: ItemListSectionId {
switch self {
case .header:
return BotCheckoutSection.header.rawValue
return BotCheckoutSection.prices.rawValue
case .price, .tip:
return BotCheckoutSection.prices.rawValue
default:
@ -286,7 +286,7 @@ private func botCheckoutControllerEntries(presentationData: PresentationData, st
var index = 0
for price in paymentForm.invoice.prices {
entries.append(.price(index, presentationData.theme, price.label, formatCurrencyAmount(price.amount, currency: paymentForm.invoice.currency), false, false))
entries.append(.price(index, presentationData.theme, price.label, formatCurrencyAmount(price.amount, currency: paymentForm.invoice.currency), false, index == 0))
totalPrice += price.amount
index += 1
}
@ -447,7 +447,9 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
private var currentPaymentMethod: BotCheckoutPaymentMethod?
private var currentTipAmount: Int64?
private var formRequestDisposable: Disposable?
private let actionButtonPanelNode: ASDisplayNode
private let actionButtonPanelSeparator: ASDisplayNode
private let actionButton: BotCheckoutActionButton
private let inProgressDimNode: ASDisplayNode
@ -481,13 +483,20 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
let signal: Signal<(ItemListPresentationData, (ItemListNodeState, Any)), NoError> = combineLatest(context.sharedContext.presentationData, self.state.get(), paymentFormAndInfo.get(), context.account.postbox.loadedPeerWithId(messageId.peerId))
|> map { presentationData, state, paymentFormAndInfo, botPeer -> (ItemListPresentationData, (ItemListNodeState, Any)) in
let nodeState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: botCheckoutControllerEntries(presentationData: presentationData, state: state, invoice: invoice, paymentForm: paymentFormAndInfo?.0, formInfo: paymentFormAndInfo?.1, validatedFormInfo: paymentFormAndInfo?.2, currentShippingOptionId: paymentFormAndInfo?.3, currentPaymentMethod: paymentFormAndInfo?.4, currentTip: paymentFormAndInfo?.5, botPeer: botPeer), style: .plain, focusItemTag: nil, emptyStateItem: nil, animateChanges: false)
let nodeState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: botCheckoutControllerEntries(presentationData: presentationData, state: state, invoice: invoice, paymentForm: paymentFormAndInfo?.0, formInfo: paymentFormAndInfo?.1, validatedFormInfo: paymentFormAndInfo?.2, currentShippingOptionId: paymentFormAndInfo?.3, currentPaymentMethod: paymentFormAndInfo?.4, currentTip: paymentFormAndInfo?.5, botPeer: botPeer), style: .blocks, focusItemTag: nil, emptyStateItem: nil, animateChanges: false)
return (ItemListPresentationData(presentationData), (nodeState, arguments))
}
self.actionButtonPanelNode = ASDisplayNode()
self.actionButtonPanelNode.backgroundColor = self.presentationData.theme.rootController.navigationBar.backgroundColor
self.actionButtonPanelSeparator = ASDisplayNode()
self.actionButtonPanelSeparator.backgroundColor = self.presentationData.theme.rootController.navigationBar.separatorColor
self.actionButton = BotCheckoutActionButton(inactiveFillColor: self.presentationData.theme.list.plainBackgroundColor, activeFillColor: self.presentationData.theme.list.itemAccentColor, foregroundColor: self.presentationData.theme.list.itemCheckColors.foregroundColor)
self.actionButton.setState(.loading)
self.actionButton.setState(.active(""))
self.actionButtonPanelNode.isHidden = true
self.inProgressDimNode = ASDisplayNode()
self.inProgressDimNode.alpha = 0.0
@ -522,6 +531,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
if let strongSelf = self, let paymentFormValue = strongSelf.paymentFormValue, let currentFormInfo = strongSelf.currentFormInfo {
strongSelf.currentPaymentMethod = method
strongSelf.paymentFormAndInfo.set(.single((paymentFormValue, currentFormInfo, strongSelf.currentValidatedFormInfo, strongSelf.currentShippingOptionId, strongSelf.currentPaymentMethod, strongSelf.currentTipAmount)))
strongSelf.updateActionButton()
}
}
@ -753,10 +763,13 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
}, error: { _ in
})
self.addSubnode(self.actionButtonPanelNode)
self.actionButtonPanelNode.addSubnode(self.actionButtonPanelSeparator)
self.actionButtonPanelNode.addSubnode(self.actionButton)
self.actionButton.addTarget(self, action: #selector(self.actionButtonPressed), forControlEvents: .touchUpInside)
self.actionButton.isEnabled = false
self.addSubnode(self.actionButton)
self.listNode.supernode?.insertSubnode(self.inProgressDimNode, aboveSubnode: self.listNode)
}
@ -775,21 +788,36 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
} else {
payString = self.presentationData.strings.CheckoutInfo_Pay
}
if self.actionButton.isEnabled {
self.actionButton.setState(.active(payString))
if let currentPaymentMethod = self.currentPaymentMethod {
switch currentPaymentMethod {
case .applePay:
self.actionButton.setState(.applePay)
default:
self.actionButton.setState(.active(payString))
}
} else {
self.actionButton.setState(.loading)
self.actionButton.setState(.active(payString))
}
self.actionButtonPanelNode.isHidden = false
}
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition, additionalInsets: UIEdgeInsets) {
var updatedInsets = layout.intrinsicInsets
updatedInsets.bottom += BotCheckoutActionButton.diameter + 20.0
super.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, intrinsicInsets: updatedInsets, safeInsets: layout.safeInsets, additionalInsets: layout.additionalInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), navigationBarHeight: navigationBarHeight, transition: transition, additionalInsets: additionalInsets)
let actionButtonFrame = CGRect(origin: CGPoint(x: 10.0, y: layout.size.height - 10.0 - BotCheckoutActionButton.diameter - layout.intrinsicInsets.bottom), size: CGSize(width: layout.size.width - 20.0, height: BotCheckoutActionButton.diameter))
let bottomPanelHorizontalInset: CGFloat = 16.0
let bottomPanelVerticalInset: CGFloat = 16.0
let bottomPanelHeight = updatedInsets.bottom + bottomPanelVerticalInset * 2.0 + BotCheckoutActionButton.height
transition.updateFrame(node: self.actionButtonPanelNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - bottomPanelHeight), size: CGSize(width: layout.size.width, height: bottomPanelHeight)))
transition.updateFrame(node: self.actionButtonPanelSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
let actionButtonFrame = CGRect(origin: CGPoint(x: bottomPanelHorizontalInset, y: bottomPanelVerticalInset), size: CGSize(width: layout.size.width - bottomPanelHorizontalInset * 2.0, height: BotCheckoutActionButton.height))
transition.updateFrame(node: self.actionButton, frame: actionButtonFrame)
self.actionButton.updateLayout(size: actionButtonFrame.size, transition: transition)
updatedInsets.bottom = bottomPanelHeight
super.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, intrinsicInsets: updatedInsets, safeInsets: layout.safeInsets, additionalInsets: layout.additionalInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), navigationBarHeight: navigationBarHeight, transition: transition, additionalInsets: additionalInsets)
transition.updateFrame(node: self.inProgressDimNode, frame: self.listNode.frame)
}

View File

@ -80,7 +80,6 @@ class BotCheckoutHeaderItemNode: ListViewItemNode {
init() {
self.backgroundNode = ASDisplayNode()
self.backgroundNode.isLayerBacked = true
self.backgroundNode.backgroundColor = .white
self.topStripeNode = ASDisplayNode()
self.topStripeNode.isLayerBacked = true
@ -109,7 +108,8 @@ class BotCheckoutHeaderItemNode: ListViewItemNode {
self.highlightedBackgroundNode.isLayerBacked = true
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.backgroundNode)
self.addSubnode(self.imageNode)
self.addSubnode(self.titleNode)
self.addSubnode(self.textNode)
@ -209,9 +209,9 @@ class BotCheckoutHeaderItemNode: ListViewItemNode {
}
strongSelf.imageNode.frame = CGRect(origin: CGPoint(x: contentInsets.left, y: contentInsets.top), size: imageSize)
if strongSelf.backgroundNode.supernode != nil {
/*if strongSelf.backgroundNode.supernode != nil {
strongSelf.backgroundNode.removeFromSupernode()
}
}*/
if strongSelf.topStripeNode.supernode != nil {
strongSelf.topStripeNode.removeFromSupernode()
}
@ -231,7 +231,8 @@ class BotCheckoutHeaderItemNode: ListViewItemNode {
strongSelf.textNode.frame = textFrame
strongSelf.botNameNode.frame = CGRect(origin: CGPoint(x: textFrame.minX, y: textFrame.maxY + textBotNameSpacing), size: botNameLayout.size)
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -1000.0), size: CGSize(width: params.width, height: contentSize.height + 1000.0))
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: 44.0 + UIScreenPixel + UIScreenPixel))
}
})

View File

@ -29,7 +29,7 @@ class BotCheckoutPriceItem: ListViewItem, ItemListItem {
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
async {
let node = BotCheckoutPriceItemNode()
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem), previousItem, nextItem)
node.contentSize = layout.contentSize
node.insets = layout.insets
@ -48,7 +48,7 @@ class BotCheckoutPriceItem: ListViewItem, ItemListItem {
let makeLayout = nodeValue.asyncLayout()
async {
let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem), previousItem, nextItem)
Queue.mainQueue().async {
completion(layout, { _ in
apply()
@ -69,13 +69,13 @@ private func priceItemInsets(_ neighbors: ItemListNeighbors) -> UIEdgeInsets {
var insets = UIEdgeInsets()
switch neighbors.top {
case .otherSection:
insets.top += 8.0
insets.top += 24.0
case .none, .sameSection:
break
}
switch neighbors.bottom {
case .none, .otherSection:
insets.bottom += 8.0
insets.bottom += 24.0
case .sameSection:
break
}
@ -86,9 +86,9 @@ class BotCheckoutPriceItemNode: ListViewItemNode {
let titleNode: TextNode
let labelNode: TextNode
let backgroundNode: ASDisplayNode
let separatorNode: ASDisplayNode
let bottomSeparatorNode: ASDisplayNode
let spacerNode: ASDisplayNode
private var item: BotCheckoutPriceItem?
@ -99,37 +99,44 @@ class BotCheckoutPriceItemNode: ListViewItemNode {
self.labelNode = TextNode()
self.labelNode.isUserInteractionEnabled = false
self.backgroundNode = ASDisplayNode()
self.separatorNode = ASDisplayNode()
self.bottomSeparatorNode = ASDisplayNode()
self.spacerNode = ASDisplayNode()
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.spacerNode)
self.addSubnode(self.backgroundNode)
self.addSubnode(self.titleNode)
self.addSubnode(self.labelNode)
self.addSubnode(self.separatorNode)
self.addSubnode(self.bottomSeparatorNode)
}
func asyncLayout() -> (_ item: BotCheckoutPriceItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
func asyncLayout() -> (_ item: BotCheckoutPriceItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors, _ previousItem: ListViewItem?, _ nextItem: ListViewItem?) -> (ListViewItemNodeLayout, () -> Void) {
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
return { item, params, neighbors in
return { item, params, neighbors, previousItem, nextItem in
let rightInset: CGFloat = 16.0 + params.rightInset
let naturalContentHeight: CGFloat = 34.0
var contentSize = CGSize(width: params.width, height: naturalContentHeight)
var insets = priceItemInsets(neighbors)
if item.hasSeparator {
insets.top += 5.0
}
let naturalContentHeight: CGFloat
var verticalOffset: CGFloat = 0.0
if item.isFinal {
contentSize.height += 34.0
naturalContentHeight = 44.0
} else {
naturalContentHeight = 34.0
}
if let _ = previousItem as? BotCheckoutHeaderItem {
verticalOffset += 8.0
}
var contentSize = CGSize(width: params.width, height: naturalContentHeight + verticalOffset)
if let nextItem = nextItem as? BotCheckoutPriceItem {
if nextItem.isFinal {
contentSize.height += 8.0
}
}
let insets = priceItemInsets(neighbors)
let textFont: UIFont
let textColor: UIColor
@ -154,21 +161,15 @@ class BotCheckoutPriceItemNode: ListViewItemNode {
let leftInset: CGFloat = 16.0 + params.leftInset
strongSelf.separatorNode.isHidden = !item.hasSeparator
strongSelf.separatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor
strongSelf.separatorNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
strongSelf.separatorNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: params.width - leftInset, height: UIScreenPixel))
strongSelf.bottomSeparatorNode.isHidden = !item.isFinal
strongSelf.bottomSeparatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor
strongSelf.bottomSeparatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: naturalContentHeight + 10.0), size: CGSize(width: params.width, height: UIScreenPixel))
strongSelf.bottomSeparatorNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
strongSelf.bottomSeparatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: contentSize.height), size: CGSize(width: params.width, height: UIScreenPixel))
strongSelf.spacerNode.isHidden = !item.isFinal
strongSelf.spacerNode.backgroundColor = item.theme.list.blocksBackgroundColor
strongSelf.spacerNode.frame = CGRect(origin: CGPoint(x: 0.0, y: naturalContentHeight + 10.0 + UIScreenPixel), size: CGSize(width: params.width, height: max(0.0, contentSize.height - naturalContentHeight - UIScreenPixel)))
var verticalOffset: CGFloat = 0.0
if item.hasSeparator {
verticalOffset += 5.0
}
strongSelf.backgroundNode.backgroundColor = item.theme.list.itemBlocksBackgroundColor
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: params.width, height: contentSize.height))
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: verticalOffset + floor((naturalContentHeight - titleLayout.size.height) / 2.0)), size: titleLayout.size)
strongSelf.labelNode.frame = CGRect(origin: CGPoint(x: params.width - rightInset - labelLayout.size.width, y: verticalOffset + floor((naturalContentHeight - labelLayout.size.height) / 2.0)), size: labelLayout.size)

View File

@ -122,7 +122,7 @@ private final class TipValueNode: ASDisplayNode {
func update(theme: PresentationTheme, text: String, isHighlighted: Bool, height: CGFloat) -> (CGFloat, (CGFloat) -> Void) {
var updateBackground = false
let backgroundColor = isHighlighted ? UIColor(rgb: 0x00A650) : UIColor(rgb: 0xE5F6ED)
let backgroundColor = isHighlighted ? theme.list.paymentOption.activeFillColor : theme.list.paymentOption.inactiveFillColor
if let currentBackgroundColor = self.currentBackgroundColor {
if !currentBackgroundColor.isEqual(backgroundColor) {
updateBackground = true
@ -135,7 +135,7 @@ private final class TipValueNode: ASDisplayNode {
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 20.0, color: backgroundColor)
}
self.titleNode.attributedText = NSAttributedString(string: text, font: Font.semibold(15.0), textColor: isHighlighted ? UIColor(rgb: 0xffffff) : UIColor(rgb: 0x00A650))
self.titleNode.attributedText = NSAttributedString(string: text, font: Font.semibold(15.0), textColor: isHighlighted ? theme.list.paymentOption.activeForegroundColor : theme.list.paymentOption.inactiveForegroundColor)
let titleSize = self.titleNode.updateLayout(CGSize(width: 200.0, height: height))
let minWidth: CGFloat = 80.0
@ -154,20 +154,23 @@ private final class TipValueNode: ASDisplayNode {
}
class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate {
private let backgroundNode: ASDisplayNode
let titleNode: TextNode
let labelNode: TextNode
let tipMeasurementNode: ImmediateTextNode
let tipCurrencyNode: ImmediateTextNode
private let textNode: TextFieldNode
private var formatterDelegate: CurrencyUITextFieldDelegate?
private let scrollNode: ASScrollNode
private var valueNodes: [TipValueNode] = []
private var item: BotCheckoutTipItem?
private var formatterDelegate: CurrencyUITextFieldDelegate?
init() {
self.backgroundNode = ASDisplayNode()
self.titleNode = TextNode()
self.titleNode.isUserInteractionEnabled = false
@ -191,6 +194,8 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate {
}
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.backgroundNode)
self.addSubnode(self.titleNode)
self.addSubnode(self.labelNode)
@ -272,7 +277,11 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate {
var textInputFrame = CGRect(origin: CGPoint(x: params.width - leftInset - 150.0, y: -2.0), size: CGSize(width: 150.0, height: labelsContentHeight))
var currencyText: (String, String) = formatCurrencyAmountCustom(item.numericValue, currency: item.currency)
let currencyText: (String, String, Bool) = formatCurrencyAmountCustom(item.numericValue, currency: item.currency)
let currencySymbolOnTheLeft = currencyText.2
//let currencySymbolOnTheLeft = true
if strongSelf.textNode.textField.text ?? "" != currencyText.0 {
strongSelf.textNode.textField.text = currencyText.0
strongSelf.labelNode.isHidden = !currencyText.0.isEmpty
@ -281,10 +290,16 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate {
strongSelf.tipMeasurementNode.attributedText = NSAttributedString(string: currencyText.0, font: titleFont, textColor: textColor)
let inputTextSize = strongSelf.tipMeasurementNode.updateLayout(textInputFrame.size)
strongSelf.tipCurrencyNode.attributedText = NSAttributedString(string: " \(currencyText.1)", font: titleFont, textColor: textColor)
let spaceRect = NSAttributedString(string: " ", font: titleFont, textColor: textColor).boundingRect(with: CGSize(width: 100.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil)
strongSelf.tipCurrencyNode.attributedText = NSAttributedString(string: "\(currencyText.1)", font: titleFont, textColor: textColor)
let currencySize = strongSelf.tipCurrencyNode.updateLayout(CGSize(width: 100.0, height: .greatestFiniteMagnitude))
strongSelf.tipCurrencyNode.frame = CGRect(origin: CGPoint(x: textInputFrame.maxX - currencySize.width, y: floor((labelsContentHeight - currencySize.height) / 2.0) - 1.0), size: currencySize)
textInputFrame.origin.x -= currencySize.width
if currencySymbolOnTheLeft {
strongSelf.tipCurrencyNode.frame = CGRect(origin: CGPoint(x: textInputFrame.maxX - currencySize.width - inputTextSize.width - spaceRect.width, y: floor((labelsContentHeight - currencySize.height) / 2.0) - 1.0), size: currencySize)
} else {
strongSelf.tipCurrencyNode.frame = CGRect(origin: CGPoint(x: textInputFrame.maxX - currencySize.width, y: floor((labelsContentHeight - currencySize.height) / 2.0) - 1.0), size: currencySize)
textInputFrame.origin.x -= currencySize.width + spaceRect.width
}
strongSelf.textNode.frame = textInputFrame
@ -347,6 +362,9 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate {
strongSelf.scrollNode.frame = CGRect(origin: CGPoint(x: 0.0, y: valueY), size: CGSize(width: params.width, height: max(0.0, contentSize.height - valueY)))
strongSelf.scrollNode.view.contentSize = CGSize(width: variantsOffset, height: strongSelf.scrollNode.frame.height)
strongSelf.backgroundNode.backgroundColor = item.theme.list.itemBlocksBackgroundColor
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: params.width, height: contentSize.height))
}
})
}
@ -382,7 +400,7 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate {
if value > item.maxValue {
value = item.maxValue
let currencyText: (String, String) = formatCurrencyAmountCustom(value, currency: item.currency)
let currencyText = formatCurrencyAmountCustom(value, currency: item.currency)
if self.textNode.textField.text ?? "" != currencyText.0 {
self.textNode.textField.text = currencyText.0
}
@ -400,6 +418,11 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate {
}
@objc public func textFieldDidBeginEditing(_ textField: UITextField) {
textField.selectedTextRange = textField.textRange(from: textField.endOfDocument, to: textField.endOfDocument)
}
@objc public func textFieldDidChangeSelection(_ textField: UITextField) {
textField.selectedTextRange = textField.textRange(from: textField.endOfDocument, to: textField.endOfDocument)
}
@objc public func textFieldDidEndEditing(_ textField: UITextField) {

View File

@ -117,7 +117,7 @@ final class BotPaymentFieldItemNode: BotPaymentItemNode, UITextFieldDelegate {
textInset = max(measuredInset, textInset)
transition.updateFrame(node: self.textField, frame: CGRect(origin: CGPoint(x: textInset, y: 3.0), size: CGSize(width: max(1.0, width - textInset - 8.0), height: 40.0)))
transition.updateFrame(node: self.textField, frame: CGRect(origin: CGPoint(x: textInset, y: 0.0), size: CGSize(width: max(1.0, width - textInset - 8.0), height: 40.0)))
return 44.0
}

View File

@ -20,16 +20,14 @@ public final class BotReceiptController: ViewController {
}
private let context: AccountContext
private let invoice: TelegramMediaInvoice
private let messageId: MessageId
private var presentationData: PresentationData
private var didPlayPresentationAnimation = false
public init(context: AccountContext, invoice: TelegramMediaInvoice, messageId: MessageId) {
public init(context: AccountContext, messageId: MessageId) {
self.context = context
self.invoice = invoice
self.messageId = messageId
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
@ -38,10 +36,10 @@ public final class BotReceiptController: ViewController {
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
var title = self.presentationData.strings.Checkout_Receipt_Title
if invoice.flags.contains(.isTest) {
let title = self.presentationData.strings.Checkout_Receipt_Title
/*if invoice.flags.contains(.isTest) {
title += " (Test)"
}
}*/
self.title = title
}
@ -54,7 +52,7 @@ public final class BotReceiptController: ViewController {
if let strongSelf = self {
strongSelf.navigationOffset = offset
}
}, context: self.context, invoice: self.invoice, messageId: self.messageId, dismissAnimated: { [weak self] in
}, context: self.context, messageId: self.messageId, dismissAnimated: { [weak self] in
self?.dismiss()
})

View File

@ -28,7 +28,7 @@ private enum BotReceiptSection: Int32 {
enum BotReceiptEntry: ItemListNodeEntry {
case header(PresentationTheme, TelegramMediaInvoice, String)
case price(Int, PresentationTheme, String, String, Bool)
case price(Int, PresentationTheme, String, String, Bool, Bool)
case paymentMethod(PresentationTheme, String, String)
case shippingInfo(PresentationTheme, String, String)
case shippingMethod(PresentationTheme, String, String)
@ -39,7 +39,7 @@ enum BotReceiptEntry: ItemListNodeEntry {
var section: ItemListSectionId {
switch self {
case .header:
return BotReceiptSection.header.rawValue
return BotReceiptSection.prices.rawValue
case .price:
return BotReceiptSection.prices.rawValue
default:
@ -51,7 +51,7 @@ enum BotReceiptEntry: ItemListNodeEntry {
switch self {
case .header:
return 0
case let .price(index, _, _, _, _):
case let .price(index, _, _, _, _, _):
return 1 + Int32(index)
case .paymentMethod:
return 10000 + 0
@ -85,8 +85,8 @@ enum BotReceiptEntry: ItemListNodeEntry {
} else {
return false
}
case let .price(lhsIndex, lhsTheme, lhsText, lhsValue, lhsFinal):
if case let .price(rhsIndex, rhsTheme, rhsText, rhsValue, rhsFinal) = rhs {
case let .price(lhsIndex, lhsTheme, lhsText, lhsValue, lhsHasSeparator, lhsFinal):
if case let .price(rhsIndex, rhsTheme, rhsText, rhsValue, rhsHasSeparator, rhsFinal) = rhs {
if lhsIndex != rhsIndex {
return false
}
@ -99,6 +99,9 @@ enum BotReceiptEntry: ItemListNodeEntry {
if lhsValue != rhsValue {
return false
}
if lhsHasSeparator != rhsHasSeparator {
return false
}
if lhsFinal != rhsFinal {
return false
}
@ -154,8 +157,8 @@ enum BotReceiptEntry: ItemListNodeEntry {
switch self {
case let .header(theme, invoice, botName):
return BotCheckoutHeaderItem(account: arguments.account, theme: theme, invoice: invoice, botName: botName, sectionId: self.section)
case let .price(_, theme, text, value, isFinal):
return BotCheckoutPriceItem(theme: theme, title: text, label: value, isFinal: isFinal, hasSeparator: false, sectionId: self.section)
case let .price(_, theme, text, value, hasSeparator, isFinal):
return BotCheckoutPriceItem(theme: theme, title: text, label: value, isFinal: isFinal, hasSeparator: hasSeparator, sectionId: self.section)
case let .paymentMethod(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: nil)
case let .shippingInfo(_, text, value):
@ -172,21 +175,23 @@ enum BotReceiptEntry: ItemListNodeEntry {
}
}
private func botReceiptControllerEntries(presentationData: PresentationData, invoice: TelegramMediaInvoice, formInvoice: BotPaymentInvoice?, formInfo: BotPaymentRequestedInfo?, shippingOption: BotPaymentShippingOption?, paymentMethodTitle: String?, botPeer: Peer?) -> [BotReceiptEntry] {
private func botReceiptControllerEntries(presentationData: PresentationData, invoice: TelegramMediaInvoice?, formInvoice: BotPaymentInvoice?, formInfo: BotPaymentRequestedInfo?, shippingOption: BotPaymentShippingOption?, paymentMethodTitle: String?, botPeer: Peer?, tipAmount: Int64?) -> [BotReceiptEntry] {
var entries: [BotReceiptEntry] = []
var botName = ""
if let botPeer = botPeer {
botName = botPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
}
entries.append(.header(presentationData.theme, invoice, botName))
if let invoice = invoice {
entries.append(.header(presentationData.theme, invoice, botName))
}
if let formInvoice = formInvoice {
var totalPrice: Int64 = 0
var index = 0
for price in formInvoice.prices {
entries.append(.price(index, presentationData.theme, price.label, formatCurrencyAmount(price.amount, currency: formInvoice.currency), false))
entries.append(.price(index, presentationData.theme, price.label, formatCurrencyAmount(price.amount, currency: formInvoice.currency), index == 0, false))
totalPrice += price.amount
index += 1
}
@ -196,13 +201,20 @@ private func botReceiptControllerEntries(presentationData: PresentationData, inv
shippingOptionString = shippingOption.title
for price in shippingOption.prices {
entries.append(.price(index, presentationData.theme, price.label, formatCurrencyAmount(price.amount, currency: formInvoice.currency), false))
entries.append(.price(index, presentationData.theme, price.label, formatCurrencyAmount(price.amount, currency: formInvoice.currency), index == 0, false))
totalPrice += price.amount
index += 1
}
}
if let tipAmount = tipAmount, tipAmount != 0 {
//TODO:localize
entries.append(.price(index, presentationData.theme, "Tip", formatCurrencyAmount(tipAmount, currency: formInvoice.currency), index == 0, false))
totalPrice += tipAmount
index += 1
}
entries.append(.price(index, presentationData.theme, presentationData.strings.Checkout_TotalAmount, formatCurrencyAmount(totalPrice, currency: formInvoice.currency), true))
entries.append(.price(index, presentationData.theme, presentationData.strings.Checkout_TotalAmount, formatCurrencyAmount(totalPrice, currency: formInvoice.currency), true, true))
if let paymentMethodTitle = paymentMethodTitle {
entries.append(.paymentMethod(presentationData.theme, presentationData.strings.Checkout_PaymentMethod, paymentMethodTitle))
@ -262,12 +274,12 @@ final class BotReceiptControllerNode: ItemListControllerNode {
private var presentationData: PresentationData
private let receiptData = Promise<(BotPaymentInvoice, BotPaymentRequestedInfo?, BotPaymentShippingOption?, String?)?>(nil)
private let receiptData = Promise<(BotPaymentInvoice, BotPaymentRequestedInfo?, BotPaymentShippingOption?, String?, TelegramMediaInvoice, Int64?)?>(nil)
private var dataRequestDisposable: Disposable?
private let actionButton: BotCheckoutActionButton
init(controller: ItemListController?, navigationBar: NavigationBar, updateNavigationOffset: @escaping (CGFloat) -> Void, context: AccountContext, invoice: TelegramMediaInvoice, messageId: MessageId, dismissAnimated: @escaping () -> Void) {
init(controller: ItemListController?, navigationBar: NavigationBar, updateNavigationOffset: @escaping (CGFloat) -> Void, context: AccountContext, messageId: MessageId, dismissAnimated: @escaping () -> Void) {
self.context = context
self.dismissAnimated = dismissAnimated
@ -277,19 +289,19 @@ final class BotReceiptControllerNode: ItemListControllerNode {
let signal: Signal<(ItemListPresentationData, (ItemListNodeState, Any)), NoError> = combineLatest(context.sharedContext.presentationData, receiptData.get(), context.account.postbox.loadedPeerWithId(messageId.peerId))
|> map { presentationData, receiptData, botPeer -> (ItemListPresentationData, (ItemListNodeState, Any)) in
let nodeState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: botReceiptControllerEntries(presentationData: presentationData, invoice: invoice, formInvoice: receiptData?.0, formInfo: receiptData?.1, shippingOption: receiptData?.2, paymentMethodTitle: receiptData?.3, botPeer: botPeer), style: .plain, focusItemTag: nil, emptyStateItem: nil, animateChanges: false)
let nodeState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: botReceiptControllerEntries(presentationData: presentationData, invoice: receiptData?.4, formInvoice: receiptData?.0, formInfo: receiptData?.1, shippingOption: receiptData?.2, paymentMethodTitle: receiptData?.3, botPeer: botPeer, tipAmount: receiptData?.5), style: .blocks, focusItemTag: nil, emptyStateItem: nil, animateChanges: false)
return (ItemListPresentationData(presentationData), (nodeState, arguments))
}
self.actionButton = BotCheckoutActionButton(inactiveFillColor: self.presentationData.theme.list.plainBackgroundColor, activeFillColor: self.presentationData.theme.list.itemAccentColor, foregroundColor: self.presentationData.theme.list.plainBackgroundColor)
self.actionButton.setState(.inactive(self.presentationData.strings.Common_Done))
self.actionButton.setState(.active(self.presentationData.strings.Common_Done))
super.init(controller: controller, navigationBar: navigationBar, updateNavigationOffset: updateNavigationOffset, state: signal)
self.dataRequestDisposable = (requestBotPaymentReceipt(account: context.account, messageId: messageId) |> deliverOnMainQueue).start(next: { [weak self] receipt in
if let strongSelf = self {
strongSelf.receiptData.set(.single((receipt.invoice, receipt.info, receipt.shippingOption, receipt.credentialsTitle)))
strongSelf.receiptData.set(.single((receipt.invoice, receipt.info, receipt.shippingOption, receipt.credentialsTitle, receipt.invoiceMedia, receipt.tipAmount)))
}
})
@ -303,10 +315,11 @@ final class BotReceiptControllerNode: ItemListControllerNode {
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition, additionalInsets: UIEdgeInsets) {
var updatedInsets = layout.intrinsicInsets
updatedInsets.bottom += BotCheckoutActionButton.diameter + 20.0
updatedInsets.bottom += BotCheckoutActionButton.height + 16.0 * 2.0
super.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, intrinsicInsets: updatedInsets, safeInsets: layout.safeInsets, additionalInsets: layout.additionalInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), navigationBarHeight: navigationBarHeight, transition: transition, additionalInsets: additionalInsets)
let actionButtonFrame = CGRect(origin: CGPoint(x: 10.0, y: layout.size.height - 10.0 - BotCheckoutActionButton.diameter - layout.intrinsicInsets.bottom), size: CGSize(width: layout.size.width - 20.0, height: BotCheckoutActionButton.diameter))
let actionButtonFrame = CGRect(origin: CGPoint(x: 16.0, y: layout.size.height - 16.0 - BotCheckoutActionButton.height - layout.intrinsicInsets.bottom), size: CGSize(width: layout.size.width - 16.0 * 2.0, height: BotCheckoutActionButton.height))
transition.updateFrame(node: self.actionButton, frame: actionButtonFrame)
self.actionButton.updateLayout(size: actionButtonFrame.size, transition: transition)
}

View File

@ -108,6 +108,12 @@ extension CurrencyUITextFieldDelegate: UITextFieldDelegate {
return false
}
public func textFieldDidChangeSelection(_ textField: UITextField) {
if #available(iOSApplicationExtension 13.0, iOS 13.0, *) {
passthroughDelegate?.textFieldDidChangeSelection?(textField)
}
}
}
// MARK: - Private

View File

@ -74,6 +74,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
case knockoutWallpaper(PresentationTheme, Bool)
case demoVideoChats(Bool)
case experimentalCompatibility(Bool)
case enableNoiseSuppression(Bool)
case playerEmbedding(Bool)
case playlistPlayback(Bool)
case voiceConference
@ -93,7 +94,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return DebugControllerSection.logging.rawValue
case .enableRaiseToSpeak, .keepChatNavigationStack, .skipReadHistory, .crashOnSlowQueries:
return DebugControllerSection.experiments.rawValue
case .clearTips, .reimport, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .demoVideoChats, .experimentalCompatibility, .playerEmbedding, .playlistPlayback, .voiceConference:
case .clearTips, .reimport, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .demoVideoChats, .experimentalCompatibility, .enableNoiseSuppression, .playerEmbedding, .playlistPlayback, .voiceConference:
return DebugControllerSection.experiments.rawValue
case .preferredVideoCodec:
return DebugControllerSection.videoExperiments.rawValue
@ -158,14 +159,16 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return 24
case .experimentalCompatibility:
return 25
case .playerEmbedding:
case .enableNoiseSuppression:
return 26
case .playlistPlayback:
case .playerEmbedding:
return 27
case .voiceConference:
case .playlistPlayback:
return 28
case .voiceConference:
return 29
case let .preferredVideoCodec(index, _, _, _):
return 29 + index
return 30 + index
case .disableVideoAspectScaling:
return 100
case .enableVoipTcp:
@ -725,6 +728,16 @@ private enum DebugControllerEntry: ItemListNodeEntry {
})
}).start()
})
case let .enableNoiseSuppression(value):
return ItemListSwitchItem(presentationData: presentationData, title: "Noise Suppression", value: value, sectionId: self.section, style: .blocks, updated: { value in
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in
var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings
settings.enableNoiseSuppression = value
return settings
})
}).start()
})
case let .playerEmbedding(value):
return ItemListSwitchItem(presentationData: presentationData, title: "Player Embedding", value: value, sectionId: self.section, style: .blocks, updated: { value in
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
@ -834,6 +847,7 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present
entries.append(.knockoutWallpaper(presentationData.theme, experimentalSettings.knockoutWallpaper))
entries.append(.demoVideoChats(experimentalSettings.demoVideoChats))
entries.append(.experimentalCompatibility(experimentalSettings.experimentalCompatibility))
entries.append(.enableNoiseSuppression(experimentalSettings.enableNoiseSuppression))
entries.append(.playerEmbedding(experimentalSettings.playerEmbedding))
entries.append(.playlistPlayback(experimentalSettings.playlistPlayback))
}

View File

@ -1082,6 +1082,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
outgoingAudioBitrateKbit = value
}
let enableNoiseSuppression = accountContext.sharedContext.immediateExperimentalUISettings.enableNoiseSuppression
callContext = OngoingGroupCallContext(video: self.videoCapturer, participantDescriptionsRequired: { [weak self] ssrcs in
Queue.mainQueue().async {
guard let strongSelf = self else {
@ -1098,7 +1100,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
strongSelf.requestCall(movingFromBroadcastToRtc: false)
}
}
}, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit, enableVideo: self.isVideo)
}, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit, enableVideo: self.isVideo, enableNoiseSuppression: enableNoiseSuppression)
self.incomingVideoSourcePromise.set(callContext.videoSources
|> deliverOnMainQueue
|> map { [weak self] sources -> [PeerId: UInt32] in

View File

@ -1994,7 +1994,7 @@ public final class VoiceChatController: ViewController {
}
}
items.append(.action(ContextMenuActionItem(text: strongSelf.isNoiseSuppressionEnabled ? "Disable Noise Suppression" : "Enable Noise Suppression", textColor: .primary, icon: { theme in
/*items.append(.action(ContextMenuActionItem(text: strongSelf.isNoiseSuppressionEnabled ? "Disable Noise Suppression" : "Enable Noise Suppression", textColor: .primary, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Unmute"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
f(.dismissWithoutContent)
@ -2004,7 +2004,7 @@ public final class VoiceChatController: ViewController {
}
strongSelf.call.setIsNoiseSuppressionEnabled(!strongSelf.isNoiseSuppressionEnabled)
})))
})))*/
if let callState = strongSelf.callState, callState.canManageCall {
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_EndVoiceChat, textColor: .destructive, icon: { theme in

View File

@ -393,11 +393,13 @@ public func sendBotPaymentForm(account: Account, messageId: MessageId, formId: I
}
}
public struct BotPaymentReceipt : Equatable {
public struct BotPaymentReceipt {
public let invoice: BotPaymentInvoice
public let info: BotPaymentRequestedInfo?
public let shippingOption: BotPaymentShippingOption?
public let credentialsTitle: String
public let invoiceMedia: TelegramMediaInvoice
public let tipAmount: Int64?
}
public enum RequestBotPaymentReceiptError {
@ -418,14 +420,55 @@ public func requestBotPaymentReceipt(account: Account, messageId: MessageId) ->
|> mapError { _ -> RequestBotPaymentReceiptError in
return .generic
}
|> map { result -> BotPaymentReceipt in
switch result {
case let .paymentReceipt(flags, date, botId, providerId, title, description, photo, invoice, info, shipping, tipAmount, currency, totalAmount, credentialsTitle, users):
let parsedInvoice = BotPaymentInvoice(apiInvoice: invoice)
let parsedInfo = info.flatMap(BotPaymentRequestedInfo.init)
let shippingOption = shipping.flatMap(BotPaymentShippingOption.init)
return BotPaymentReceipt(invoice: parsedInvoice, info: parsedInfo, shippingOption: shippingOption, credentialsTitle: credentialsTitle)
|> mapToSignal { result -> Signal<BotPaymentReceipt, RequestBotPaymentReceiptError> in
return account.postbox.transaction { transaction -> BotPaymentReceipt in
switch result {
case let .paymentReceipt(flags, date, botId, providerId, title, description, photo, invoice, info, shipping, tipAmount, currency, totalAmount, credentialsTitle, users):
var peers: [Peer] = []
for user in users {
peers.append(TelegramUser(user: user))
}
updatePeers(transaction: transaction, peers: peers, update: { _, updated in return updated })
let parsedInvoice = BotPaymentInvoice(apiInvoice: invoice)
let parsedInfo = info.flatMap(BotPaymentRequestedInfo.init)
let shippingOption = shipping.flatMap(BotPaymentShippingOption.init)
/*let fields = BotPaymentInvoiceFields()
let form = BotPaymentForm(
id: 0,
canSaveCredentials: false,
passwordMissing: false,
invoice: BotPaymentInvoice(
isTest: false,
requestedFields: fields,
currency: currency,
prices: [],
tip: nil
),
providerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt32Value(providerId)),
url: "",
nativeProvider: nil,
savedInfo: nil,
savedCredentials: nil
)*/
let invoiceMedia = TelegramMediaInvoice(
title: title,
description: description,
photo: photo.flatMap(TelegramMediaWebFile.init),
receiptMessageId: nil,
currency: currency,
totalAmount: totalAmount,
startParam: "",
flags: []
)
return BotPaymentReceipt(invoice: parsedInvoice, info: parsedInfo, shippingOption: shippingOption, credentialsTitle: credentialsTitle, invoiceMedia: invoiceMedia, tipAmount: tipAmount)
}
}
|> castError(RequestBotPaymentReceiptError.self)
}
}
}

View File

@ -359,7 +359,13 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati
pageIndicatorInactiveColor: UIColor(white: 1.0, alpha: 0.3),
inputClearButtonColor: UIColor(rgb: 0x8b9197),
itemBarChart: PresentationThemeItemBarChart(color1: UIColor(rgb: 0xffffff), color2: UIColor(rgb: 0x929196), color3: UIColor(rgb: 0x333333)),
itemInputField: PresentationInputFieldTheme(backgroundColor: UIColor(rgb: 0x0f0f0f), strokeColor: UIColor(rgb: 0x0f0f0f), placeholderColor: UIColor(rgb: 0x8f8f8f), primaryColor: UIColor(rgb: 0xffffff), controlColor: UIColor(rgb: 0x8f8f8f))
itemInputField: PresentationInputFieldTheme(backgroundColor: UIColor(rgb: 0x0f0f0f), strokeColor: UIColor(rgb: 0x0f0f0f), placeholderColor: UIColor(rgb: 0x8f8f8f), primaryColor: UIColor(rgb: 0xffffff), controlColor: UIColor(rgb: 0x8f8f8f)),
paymentOption: PresentationThemeList.PaymentOption(
inactiveFillColor: UIColor(rgb: 0x00A650).withMultipliedAlpha(0.3),
inactiveForegroundColor: UIColor(rgb: 0x00A650),
activeFillColor: UIColor(rgb: 0x00A650),
activeForegroundColor: UIColor(rgb: 0xffffff)
)
)
let chatList = PresentationThemeChatList(

View File

@ -612,7 +612,13 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres
pageIndicatorInactiveColor: mainSecondaryTextColor.withAlphaComponent(0.4),
inputClearButtonColor: mainSecondaryColor,
itemBarChart: PresentationThemeItemBarChart(color1: accentColor, color2: mainSecondaryTextColor.withAlphaComponent(0.5), color3: accentColor.withMultiplied(hue: 1.038, saturation: 0.329, brightness: 0.33)),
itemInputField: PresentationInputFieldTheme(backgroundColor: mainInputColor, strokeColor: mainInputColor, placeholderColor: mainSecondaryColor, primaryColor: UIColor(rgb: 0xffffff), controlColor: mainSecondaryColor)
itemInputField: PresentationInputFieldTheme(backgroundColor: mainInputColor, strokeColor: mainInputColor, placeholderColor: mainSecondaryColor, primaryColor: UIColor(rgb: 0xffffff), controlColor: mainSecondaryColor),
paymentOption: PresentationThemeList.PaymentOption(
inactiveFillColor: UIColor(rgb: 0x00A650).withMultipliedAlpha(0.3),
inactiveForegroundColor: UIColor(rgb: 0x00A650),
activeFillColor: UIColor(rgb: 0x00A650),
activeForegroundColor: UIColor(rgb: 0xffffff)
)
)
let chatList = PresentationThemeChatList(

View File

@ -448,7 +448,13 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
pageIndicatorInactiveColor: UIColor(rgb: 0xe3e3e7),
inputClearButtonColor: UIColor(rgb: 0xcccccc),
itemBarChart: PresentationThemeItemBarChart(color1: UIColor(rgb: 0x007ee5), color2: UIColor(rgb: 0xc8c7cc), color3: UIColor(rgb: 0xf2f1f7)),
itemInputField: PresentationInputFieldTheme(backgroundColor: UIColor(rgb: 0xf2f2f7), strokeColor: UIColor(rgb: 0xf2f2f7), placeholderColor: UIColor(rgb: 0xb6b6bb), primaryColor: UIColor(rgb: 0x000000), controlColor: UIColor(rgb: 0xb6b6bb))
itemInputField: PresentationInputFieldTheme(backgroundColor: UIColor(rgb: 0xf2f2f7), strokeColor: UIColor(rgb: 0xf2f2f7), placeholderColor: UIColor(rgb: 0xb6b6bb), primaryColor: UIColor(rgb: 0x000000), controlColor: UIColor(rgb: 0xb6b6bb)),
paymentOption: PresentationThemeList.PaymentOption(
inactiveFillColor: UIColor(rgb: 0x00A650).withMultipliedAlpha(0.1),
inactiveForegroundColor: UIColor(rgb: 0x00A650),
activeFillColor: UIColor(rgb: 0x00A650),
activeForegroundColor: UIColor(rgb: 0xffffff)
)
)
let chatList = PresentationThemeChatList(

View File

@ -406,6 +406,25 @@ public final class PresentationInputFieldTheme {
}
public final class PresentationThemeList {
public final class PaymentOption {
public let inactiveFillColor: UIColor
public let inactiveForegroundColor: UIColor
public let activeFillColor: UIColor
public let activeForegroundColor: UIColor
public init(
inactiveFillColor: UIColor,
inactiveForegroundColor: UIColor,
activeFillColor: UIColor,
activeForegroundColor: UIColor
) {
self.inactiveFillColor = inactiveFillColor
self.inactiveForegroundColor = inactiveForegroundColor
self.activeFillColor = activeFillColor
self.activeForegroundColor = activeForegroundColor
}
}
public let blocksBackgroundColor: UIColor
public let plainBackgroundColor: UIColor
public let itemPrimaryTextColor: UIColor
@ -437,8 +456,42 @@ public final class PresentationThemeList {
public let inputClearButtonColor: UIColor
public let itemBarChart: PresentationThemeItemBarChart
public let itemInputField: PresentationInputFieldTheme
public let paymentOption: PaymentOption
public init(blocksBackgroundColor: UIColor, plainBackgroundColor: UIColor, itemPrimaryTextColor: UIColor, itemSecondaryTextColor: UIColor, itemDisabledTextColor: UIColor, itemAccentColor: UIColor, itemHighlightedColor: UIColor, itemDestructiveColor: UIColor, itemPlaceholderTextColor: UIColor, itemBlocksBackgroundColor: UIColor, itemHighlightedBackgroundColor: UIColor, itemBlocksSeparatorColor: UIColor, itemPlainSeparatorColor: UIColor, disclosureArrowColor: UIColor, sectionHeaderTextColor: UIColor, freeTextColor: UIColor, freeTextErrorColor: UIColor, freeTextSuccessColor: UIColor, freeMonoIconColor: UIColor, itemSwitchColors: PresentationThemeSwitch, itemDisclosureActions: PresentationThemeItemDisclosureActions, itemCheckColors: PresentationThemeFillStrokeForeground, controlSecondaryColor: UIColor, freeInputField: PresentationInputFieldTheme, freePlainInputField: PresentationInputFieldTheme, mediaPlaceholderColor: UIColor, scrollIndicatorColor: UIColor, pageIndicatorInactiveColor: UIColor, inputClearButtonColor: UIColor, itemBarChart: PresentationThemeItemBarChart, itemInputField: PresentationInputFieldTheme) {
public init(
blocksBackgroundColor: UIColor,
plainBackgroundColor: UIColor,
itemPrimaryTextColor: UIColor,
itemSecondaryTextColor: UIColor,
itemDisabledTextColor: UIColor,
itemAccentColor: UIColor,
itemHighlightedColor: UIColor,
itemDestructiveColor: UIColor,
itemPlaceholderTextColor: UIColor,
itemBlocksBackgroundColor: UIColor,
itemHighlightedBackgroundColor: UIColor,
itemBlocksSeparatorColor: UIColor,
itemPlainSeparatorColor: UIColor,
disclosureArrowColor: UIColor,
sectionHeaderTextColor: UIColor,
freeTextColor: UIColor,
freeTextErrorColor: UIColor,
freeTextSuccessColor: UIColor,
freeMonoIconColor: UIColor,
itemSwitchColors: PresentationThemeSwitch,
itemDisclosureActions: PresentationThemeItemDisclosureActions,
itemCheckColors: PresentationThemeFillStrokeForeground,
controlSecondaryColor: UIColor,
freeInputField: PresentationInputFieldTheme,
freePlainInputField: PresentationInputFieldTheme,
mediaPlaceholderColor: UIColor,
scrollIndicatorColor: UIColor,
pageIndicatorInactiveColor: UIColor,
inputClearButtonColor: UIColor,
itemBarChart: PresentationThemeItemBarChart,
itemInputField: PresentationInputFieldTheme,
paymentOption: PaymentOption
) {
self.blocksBackgroundColor = blocksBackgroundColor
self.plainBackgroundColor = plainBackgroundColor
self.itemPrimaryTextColor = itemPrimaryTextColor
@ -470,10 +523,11 @@ public final class PresentationThemeList {
self.inputClearButtonColor = inputClearButtonColor
self.itemBarChart = itemBarChart
self.itemInputField = itemInputField
self.paymentOption = paymentOption
}
public func withUpdated(blocksBackgroundColor: UIColor? = nil, plainBackgroundColor: UIColor? = nil, itemPrimaryTextColor: UIColor? = nil, itemSecondaryTextColor: UIColor? = nil, itemDisabledTextColor: UIColor? = nil, itemAccentColor: UIColor? = nil, itemHighlightedColor: UIColor? = nil, itemDestructiveColor: UIColor? = nil, itemPlaceholderTextColor: UIColor? = nil, itemBlocksBackgroundColor: UIColor? = nil, itemHighlightedBackgroundColor: UIColor? = nil, itemBlocksSeparatorColor: UIColor? = nil, itemPlainSeparatorColor: UIColor? = nil, disclosureArrowColor: UIColor? = nil, sectionHeaderTextColor: UIColor? = nil, freeTextColor: UIColor? = nil, freeTextErrorColor: UIColor? = nil, freeTextSuccessColor: UIColor? = nil, freeMonoIconColor: UIColor? = nil, itemSwitchColors: PresentationThemeSwitch? = nil, itemDisclosureActions: PresentationThemeItemDisclosureActions? = nil, itemCheckColors: PresentationThemeFillStrokeForeground? = nil, controlSecondaryColor: UIColor? = nil, freeInputField: PresentationInputFieldTheme? = nil, freePlainInputField: PresentationInputFieldTheme? = nil, mediaPlaceholderColor: UIColor? = nil, scrollIndicatorColor: UIColor? = nil, pageIndicatorInactiveColor: UIColor? = nil, inputClearButtonColor: UIColor? = nil, itemBarChart: PresentationThemeItemBarChart? = nil, itemInputField: PresentationInputFieldTheme? = nil) -> PresentationThemeList {
return PresentationThemeList(blocksBackgroundColor: blocksBackgroundColor ?? self.blocksBackgroundColor, plainBackgroundColor: plainBackgroundColor ?? self.plainBackgroundColor, itemPrimaryTextColor: itemPrimaryTextColor ?? self.itemPrimaryTextColor, itemSecondaryTextColor: itemSecondaryTextColor ?? self.itemSecondaryTextColor, itemDisabledTextColor: itemDisabledTextColor ?? self.itemDisabledTextColor, itemAccentColor: itemAccentColor ?? self.itemAccentColor, itemHighlightedColor: itemHighlightedColor ?? self.itemHighlightedColor, itemDestructiveColor: itemDestructiveColor ?? self.itemDestructiveColor, itemPlaceholderTextColor: itemPlaceholderTextColor ?? self.itemPlaceholderTextColor, itemBlocksBackgroundColor: itemBlocksBackgroundColor ?? self.itemBlocksBackgroundColor, itemHighlightedBackgroundColor: itemHighlightedBackgroundColor ?? self.itemHighlightedBackgroundColor, itemBlocksSeparatorColor: itemBlocksSeparatorColor ?? self.itemBlocksSeparatorColor, itemPlainSeparatorColor: itemPlainSeparatorColor ?? self.itemPlainSeparatorColor, disclosureArrowColor: disclosureArrowColor ?? self.disclosureArrowColor, sectionHeaderTextColor: sectionHeaderTextColor ?? self.sectionHeaderTextColor, freeTextColor: freeTextColor ?? self.freeTextColor, freeTextErrorColor: freeTextErrorColor ?? self.freeTextErrorColor, freeTextSuccessColor: freeTextSuccessColor ?? self.freeTextSuccessColor, freeMonoIconColor: freeMonoIconColor ?? self.freeMonoIconColor, itemSwitchColors: itemSwitchColors ?? self.itemSwitchColors, itemDisclosureActions: itemDisclosureActions ?? self.itemDisclosureActions, itemCheckColors: itemCheckColors ?? self.itemCheckColors, controlSecondaryColor: controlSecondaryColor ?? self.controlSecondaryColor, freeInputField: freeInputField ?? self.freeInputField, freePlainInputField: freePlainInputField ?? self.freePlainInputField, mediaPlaceholderColor: mediaPlaceholderColor ?? self.mediaPlaceholderColor, scrollIndicatorColor: scrollIndicatorColor ?? self.scrollIndicatorColor, pageIndicatorInactiveColor: pageIndicatorInactiveColor ?? self.pageIndicatorInactiveColor, inputClearButtonColor: inputClearButtonColor ?? self.inputClearButtonColor, itemBarChart: itemBarChart ?? self.itemBarChart, itemInputField: itemInputField ?? self.itemInputField)
public func withUpdated(blocksBackgroundColor: UIColor? = nil, plainBackgroundColor: UIColor? = nil, itemPrimaryTextColor: UIColor? = nil, itemSecondaryTextColor: UIColor? = nil, itemDisabledTextColor: UIColor? = nil, itemAccentColor: UIColor? = nil, itemHighlightedColor: UIColor? = nil, itemDestructiveColor: UIColor? = nil, itemPlaceholderTextColor: UIColor? = nil, itemBlocksBackgroundColor: UIColor? = nil, itemHighlightedBackgroundColor: UIColor? = nil, itemBlocksSeparatorColor: UIColor? = nil, itemPlainSeparatorColor: UIColor? = nil, disclosureArrowColor: UIColor? = nil, sectionHeaderTextColor: UIColor? = nil, freeTextColor: UIColor? = nil, freeTextErrorColor: UIColor? = nil, freeTextSuccessColor: UIColor? = nil, freeMonoIconColor: UIColor? = nil, itemSwitchColors: PresentationThemeSwitch? = nil, itemDisclosureActions: PresentationThemeItemDisclosureActions? = nil, itemCheckColors: PresentationThemeFillStrokeForeground? = nil, controlSecondaryColor: UIColor? = nil, freeInputField: PresentationInputFieldTheme? = nil, freePlainInputField: PresentationInputFieldTheme? = nil, mediaPlaceholderColor: UIColor? = nil, scrollIndicatorColor: UIColor? = nil, pageIndicatorInactiveColor: UIColor? = nil, inputClearButtonColor: UIColor? = nil, itemBarChart: PresentationThemeItemBarChart? = nil, itemInputField: PresentationInputFieldTheme? = nil, paymentOption: PaymentOption? = nil) -> PresentationThemeList {
return PresentationThemeList(blocksBackgroundColor: blocksBackgroundColor ?? self.blocksBackgroundColor, plainBackgroundColor: plainBackgroundColor ?? self.plainBackgroundColor, itemPrimaryTextColor: itemPrimaryTextColor ?? self.itemPrimaryTextColor, itemSecondaryTextColor: itemSecondaryTextColor ?? self.itemSecondaryTextColor, itemDisabledTextColor: itemDisabledTextColor ?? self.itemDisabledTextColor, itemAccentColor: itemAccentColor ?? self.itemAccentColor, itemHighlightedColor: itemHighlightedColor ?? self.itemHighlightedColor, itemDestructiveColor: itemDestructiveColor ?? self.itemDestructiveColor, itemPlaceholderTextColor: itemPlaceholderTextColor ?? self.itemPlaceholderTextColor, itemBlocksBackgroundColor: itemBlocksBackgroundColor ?? self.itemBlocksBackgroundColor, itemHighlightedBackgroundColor: itemHighlightedBackgroundColor ?? self.itemHighlightedBackgroundColor, itemBlocksSeparatorColor: itemBlocksSeparatorColor ?? self.itemBlocksSeparatorColor, itemPlainSeparatorColor: itemPlainSeparatorColor ?? self.itemPlainSeparatorColor, disclosureArrowColor: disclosureArrowColor ?? self.disclosureArrowColor, sectionHeaderTextColor: sectionHeaderTextColor ?? self.sectionHeaderTextColor, freeTextColor: freeTextColor ?? self.freeTextColor, freeTextErrorColor: freeTextErrorColor ?? self.freeTextErrorColor, freeTextSuccessColor: freeTextSuccessColor ?? self.freeTextSuccessColor, freeMonoIconColor: freeMonoIconColor ?? self.freeMonoIconColor, itemSwitchColors: itemSwitchColors ?? self.itemSwitchColors, itemDisclosureActions: itemDisclosureActions ?? self.itemDisclosureActions, itemCheckColors: itemCheckColors ?? self.itemCheckColors, controlSecondaryColor: controlSecondaryColor ?? self.controlSecondaryColor, freeInputField: freeInputField ?? self.freeInputField, freePlainInputField: freePlainInputField ?? self.freePlainInputField, mediaPlaceholderColor: mediaPlaceholderColor ?? self.mediaPlaceholderColor, scrollIndicatorColor: scrollIndicatorColor ?? self.scrollIndicatorColor, pageIndicatorInactiveColor: pageIndicatorInactiveColor ?? self.pageIndicatorInactiveColor, inputClearButtonColor: inputClearButtonColor ?? self.inputClearButtonColor, itemBarChart: itemBarChart ?? self.itemBarChart, itemInputField: itemInputField ?? self.itemInputField, paymentOption: paymentOption ?? self.paymentOption)
}
}

View File

@ -745,6 +745,33 @@ extension PresentationInputFieldTheme: Codable {
}
}
extension PresentationThemeList.PaymentOption: Codable {
enum CodingKeys: String, CodingKey {
case inactiveFill
case inactiveForeground
case activeFill
case activeForeground
}
public convenience init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.init(
inactiveFillColor: try decodeColor(values, .inactiveFill),
inactiveForegroundColor: try decodeColor(values, .inactiveForeground),
activeFillColor: try decodeColor(values, .activeFill),
activeForegroundColor: try decodeColor(values, .activeForeground)
)
}
public func encode(to encoder: Encoder) throws {
var values = encoder.container(keyedBy: CodingKeys.self)
try encodeColor(&values, self.activeFillColor, .inactiveFill)
try encodeColor(&values, self.activeForegroundColor, .inactiveForeground)
try encodeColor(&values, self.activeFillColor, .activeFill)
try encodeColor(&values, self.activeForegroundColor, .activeForeground)
}
}
extension PresentationThemeList: Codable {
enum CodingKeys: String, CodingKey {
case blocksBg
@ -778,6 +805,7 @@ extension PresentationThemeList: Codable {
case inputClearButton
case itemBarChart
case itemInputField
case paymentOption
}
public convenience init(from decoder: Decoder) throws {
@ -789,6 +817,8 @@ extension PresentationThemeList: Codable {
} else {
freePlainInputField = try values.decode(PresentationInputFieldTheme.self, forKey: .freeInputField)
}
let freeTextSuccessColor = try decodeColor(values, .freeTextSuccess)
self.init(
blocksBackgroundColor: try decodeColor(values, .blocksBg),
@ -808,7 +838,7 @@ extension PresentationThemeList: Codable {
sectionHeaderTextColor: try decodeColor(values, .sectionHeaderText),
freeTextColor: try decodeColor(values, .freeText),
freeTextErrorColor: try decodeColor(values, .freeTextError),
freeTextSuccessColor: try decodeColor(values, .freeTextSuccess),
freeTextSuccessColor: freeTextSuccessColor,
freeMonoIconColor: try decodeColor(values, .freeMonoIcon),
itemSwitchColors: try values.decode(PresentationThemeSwitch.self, forKey: .switch),
itemDisclosureActions: try values.decode(PresentationThemeItemDisclosureActions.self, forKey: .disclosureActions),
@ -821,7 +851,13 @@ extension PresentationThemeList: Codable {
pageIndicatorInactiveColor: try decodeColor(values, .pageIndicatorInactive),
inputClearButtonColor: try decodeColor(values, .inputClearButton),
itemBarChart: try values.decode(PresentationThemeItemBarChart.self, forKey: .itemBarChart),
itemInputField: try values.decode(PresentationInputFieldTheme.self, forKey: .itemInputField)
itemInputField: try values.decode(PresentationInputFieldTheme.self, forKey: .itemInputField),
paymentOption: (try? values.decode(PresentationThemeList.PaymentOption.self, forKey: .paymentOption)) ?? PresentationThemeList.PaymentOption(
inactiveFillColor: freeTextSuccessColor.withMultipliedAlpha(0.3),
inactiveForegroundColor: freeTextSuccessColor,
activeFillColor: freeTextSuccessColor,
activeForegroundColor: UIColor(rgb: 0xffffff)
)
)
}

View File

@ -165,7 +165,7 @@ public func formatCurrencyAmount(_ amount: Int64, currency: String) -> String {
}
}
public func formatCurrencyAmountCustom(_ amount: Int64, currency: String) -> (String, String) {
public func formatCurrencyAmountCustom(_ amount: Int64, currency: String) -> (String, String, Bool) {
if let entry = currencyFormatterEntries[currency] ?? currencyFormatterEntries["USD"] {
var result = ""
if amount < 0 {
@ -198,8 +198,8 @@ public func formatCurrencyAmountCustom(_ amount: Int64, currency: String) -> (St
result.append(entry.symbol)
}*/
return (result, entry.symbol)
return (result, entry.symbol, entry.symbolOnLeft)
} else {
return ("", "")
return ("", "", false)
}
}

View File

@ -815,14 +815,14 @@ final class SharedApplicationContext {
}
})
self.mainWindow.debugAction = {
/*self.mainWindow.debugAction = {
self.mainWindow.debugAction = nil
let presentationData = sharedContext.currentPresentationData.with { $0 }
let navigationController = NavigationController(mode: .single, theme: NavigationControllerTheme(presentationTheme: presentationData.theme))
navigationController.viewControllers = [debugController(sharedContext: sharedContext, context: nil)]
self.mainWindow.present(navigationController, on: .root)
}
}*/
presentationDataPromise.set(sharedContext.presentationData)

View File

@ -627,12 +627,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.presentAutoremoveSetup()
}
case .paymentSent:
for attribute in message.attributes {
strongSelf.present(BotReceiptController(context: strongSelf.context, messageId: message.id), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
/*for attribute in message.attributes {
if let attribute = attribute as? ReplyMessageAttribute {
strongSelf.navigateToMessage(from: message.id, to: .id(attribute.messageId))
//strongSelf.navigateToMessage(from: message.id, to: .id(attribute.messageId))
break
}
}
}*/
return true
default:
break
@ -1870,7 +1871,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let invoice = media as? TelegramMediaInvoice {
strongSelf.chatDisplayNode.dismissInput()
if let receiptMessageId = invoice.receiptMessageId {
strongSelf.present(BotReceiptController(context: strongSelf.context, invoice: invoice, messageId: receiptMessageId), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
strongSelf.present(BotReceiptController(context: strongSelf.context, messageId: receiptMessageId), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
} else {
strongSelf.present(BotCheckoutController(context: strongSelf.context, invoice: invoice, messageId: messageId), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}

View File

@ -926,7 +926,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
}
videoNode.updateLayout(size: arguments.drawingSize, transition: .immediate)
videoNode.frame = imageFrame
videoNode.frame = CGRect(origin: CGPoint(), size: imageFrame.size)
if strongSelf.visibility {
if !videoNode.canAttachContent {

View File

@ -16,6 +16,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
public var enableVoipTcp: Bool
public var demoVideoChats: Bool
public var experimentalCompatibility: Bool
public var enableNoiseSuppression: Bool
public static var defaultSettings: ExperimentalUISettings {
return ExperimentalUISettings(
@ -31,7 +32,8 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
disableVideoAspectScaling: false,
enableVoipTcp: false,
demoVideoChats: false,
experimentalCompatibility: false
experimentalCompatibility: false,
enableNoiseSuppression: false
)
}
@ -48,7 +50,8 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
disableVideoAspectScaling: Bool,
enableVoipTcp: Bool,
demoVideoChats: Bool,
experimentalCompatibility: Bool
experimentalCompatibility: Bool,
enableNoiseSuppression: Bool
) {
self.keepChatNavigationStack = keepChatNavigationStack
self.skipReadHistory = skipReadHistory
@ -63,6 +66,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
self.enableVoipTcp = enableVoipTcp
self.demoVideoChats = demoVideoChats
self.experimentalCompatibility = experimentalCompatibility
self.enableNoiseSuppression = enableNoiseSuppression
}
public init(decoder: PostboxDecoder) {
@ -79,6 +83,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
self.enableVoipTcp = decoder.decodeInt32ForKey("enableVoipTcp", orElse: 0) != 0
self.demoVideoChats = decoder.decodeInt32ForKey("demoVideoChats", orElse: 0) != 0
self.experimentalCompatibility = decoder.decodeInt32ForKey("experimentalCompatibility", orElse: 0) != 0
self.enableNoiseSuppression = decoder.decodeInt32ForKey("enableNoiseSuppression", orElse: 0) != 0
}
public func encode(_ encoder: PostboxEncoder) {
@ -97,6 +102,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
encoder.encodeInt32(self.enableVoipTcp ? 1 : 0, forKey: "enableVoipTcp")
encoder.encodeInt32(self.demoVideoChats ? 1 : 0, forKey: "demoVideoChats")
encoder.encodeInt32(self.experimentalCompatibility ? 1 : 0, forKey: "experimentalCompatibility")
encoder.encodeInt32(self.enableNoiseSuppression ? 1 : 0, forKey: "enableNoiseSuppression")
}
public func isEqual(to: PreferencesEntry) -> Bool {

View File

@ -180,7 +180,7 @@ public final class OngoingGroupCallContext {
private var broadcastPartsSource: BroadcastPartSource?
init(queue: Queue, inputDeviceId: String, outputDeviceId: String, video: OngoingCallVideoCapturer?, participantDescriptionsRequired: @escaping (Set<UInt32>) -> Void, audioStreamData: AudioStreamData?, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, enableVideo: Bool) {
init(queue: Queue, inputDeviceId: String, outputDeviceId: String, video: OngoingCallVideoCapturer?, participantDescriptionsRequired: @escaping (Set<UInt32>) -> Void, audioStreamData: AudioStreamData?, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, enableVideo: Bool, enableNoiseSuppression: Bool) {
self.queue = queue
var networkStateUpdatedImpl: ((GroupCallNetworkState) -> Void)?
@ -224,7 +224,7 @@ public final class OngoingGroupCallContext {
},
outgoingAudioBitrateKbit: outgoingAudioBitrateKbit ?? 32,
enableVideo: enableVideo,
enableNoiseSuppression: true
enableNoiseSuppression: enableNoiseSuppression
)
let queue = self.queue
@ -529,10 +529,10 @@ public final class OngoingGroupCallContext {
}
}
public init(inputDeviceId: String = "", outputDeviceId: String = "", video: OngoingCallVideoCapturer?, participantDescriptionsRequired: @escaping (Set<UInt32>) -> Void, audioStreamData: AudioStreamData?, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, enableVideo: Bool) {
public init(inputDeviceId: String = "", outputDeviceId: String = "", video: OngoingCallVideoCapturer?, participantDescriptionsRequired: @escaping (Set<UInt32>) -> Void, audioStreamData: AudioStreamData?, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, enableVideo: Bool, enableNoiseSuppression: Bool) {
let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: {
return Impl(queue: queue, inputDeviceId: inputDeviceId, outputDeviceId: outputDeviceId, video: video, participantDescriptionsRequired: participantDescriptionsRequired, audioStreamData: audioStreamData, rejoinNeeded: rejoinNeeded, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit, enableVideo: enableVideo)
return Impl(queue: queue, inputDeviceId: inputDeviceId, outputDeviceId: outputDeviceId, video: video, participantDescriptionsRequired: participantDescriptionsRequired, audioStreamData: audioStreamData, rejoinNeeded: rejoinNeeded, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit, enableVideo: enableVideo, enableNoiseSuppression: enableNoiseSuppression)
})
}