mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Payments and more
This commit is contained in:
parent
bfcb7e6e10
commit
aa7a568197
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
})
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
})
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user