mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-25 12:40:36 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
f362ce9fc6
@ -22,6 +22,7 @@ swift_library(
|
|||||||
"//submodules/CountrySelectionUI:CountrySelectionUI",
|
"//submodules/CountrySelectionUI:CountrySelectionUI",
|
||||||
"//submodules/AppBundle:AppBundle",
|
"//submodules/AppBundle:AppBundle",
|
||||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||||
|
"//submodules/OverlayStatusController:OverlayStatusController",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -138,6 +138,11 @@ final class BotCheckoutActionButton: HighlightableButtonNode {
|
|||||||
|
|
||||||
self.progressBackgroundNode.layer.add(basicAnimation, forKey: "progressRotation")
|
self.progressBackgroundNode.layer.add(basicAnimation, forKey: "progressRotation")
|
||||||
case let .active(title):
|
case let .active(title):
|
||||||
|
if let applePayButton = self.applePayButton {
|
||||||
|
self.applePayButton = nil
|
||||||
|
applePayButton.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
if case .active = previousState {
|
if case .active = previousState {
|
||||||
let makeLayout = TextNode.asyncLayout(self.labelNode)
|
let makeLayout = TextNode.asyncLayout(self.labelNode)
|
||||||
let (labelLayout, labelApply) = makeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: title, font: titleFont, textColor: self.foregroundColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: validLayout, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
let (labelLayout, labelApply) = makeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: title, font: titleFont, textColor: self.foregroundColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: validLayout, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
@ -52,7 +52,7 @@ public final class BotCheckoutController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
let displayNode = BotCheckoutControllerNode(controller: nil, navigationBar: self.navigationBar!, updateNavigationOffset: { [weak self] offset in
|
let displayNode = BotCheckoutControllerNode(controller: self, navigationBar: self.navigationBar!, updateNavigationOffset: { [weak self] offset in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.navigationOffset = offset
|
strongSelf.navigationOffset = offset
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import TelegramStringFormatting
|
|||||||
import PasswordSetupUI
|
import PasswordSetupUI
|
||||||
import Stripe
|
import Stripe
|
||||||
import LocalAuth
|
import LocalAuth
|
||||||
|
import OverlayStatusController
|
||||||
|
|
||||||
final class BotCheckoutControllerArguments {
|
final class BotCheckoutControllerArguments {
|
||||||
fileprivate let account: Account
|
fileprivate let account: Account
|
||||||
@ -25,13 +26,15 @@ final class BotCheckoutControllerArguments {
|
|||||||
fileprivate let openPaymentMethod: () -> Void
|
fileprivate let openPaymentMethod: () -> Void
|
||||||
fileprivate let openShippingMethod: () -> Void
|
fileprivate let openShippingMethod: () -> Void
|
||||||
fileprivate let updateTip: (Int64) -> Void
|
fileprivate let updateTip: (Int64) -> Void
|
||||||
|
fileprivate let ensureTipInputVisible: () -> Void
|
||||||
|
|
||||||
fileprivate init(account: Account, openInfo: @escaping (BotCheckoutInfoControllerFocus) -> Void, openPaymentMethod: @escaping () -> Void, openShippingMethod: @escaping () -> Void, updateTip: @escaping (Int64) -> Void) {
|
fileprivate init(account: Account, openInfo: @escaping (BotCheckoutInfoControllerFocus) -> Void, openPaymentMethod: @escaping () -> Void, openShippingMethod: @escaping () -> Void, updateTip: @escaping (Int64) -> Void, ensureTipInputVisible: @escaping () -> Void) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.openInfo = openInfo
|
self.openInfo = openInfo
|
||||||
self.openPaymentMethod = openPaymentMethod
|
self.openPaymentMethod = openPaymentMethod
|
||||||
self.openShippingMethod = openShippingMethod
|
self.openShippingMethod = openShippingMethod
|
||||||
self.updateTip = updateTip
|
self.updateTip = updateTip
|
||||||
|
self.ensureTipInputVisible = ensureTipInputVisible
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,6 +200,10 @@ enum BotCheckoutEntry: ItemListNodeEntry {
|
|||||||
case let .tip(_, _, text, currency, value, numericValue, maxValue, variants):
|
case let .tip(_, _, text, currency, value, numericValue, maxValue, variants):
|
||||||
return BotCheckoutTipItem(theme: presentationData.theme, strings: presentationData.strings, title: text, currency: currency, value: value, numericValue: numericValue, maxValue: maxValue, availableVariants: variants, sectionId: self.section, updateValue: { value in
|
return BotCheckoutTipItem(theme: presentationData.theme, strings: presentationData.strings, title: text, currency: currency, value: value, numericValue: numericValue, maxValue: maxValue, availableVariants: variants, sectionId: self.section, updateValue: { value in
|
||||||
arguments.updateTip(value)
|
arguments.updateTip(value)
|
||||||
|
}, updatedFocus: { isFocused in
|
||||||
|
if isFocused {
|
||||||
|
arguments.ensureTipInputVisible()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
case let .paymentMethod(_, text, value):
|
case let .paymentMethod(_, text, value):
|
||||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||||
@ -428,6 +435,7 @@ private func availablePaymentMethods(form: BotPaymentForm, current: BotCheckoutP
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthorizationViewControllerDelegate {
|
final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthorizationViewControllerDelegate {
|
||||||
|
private weak var controller: BotCheckoutController?
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let messageId: MessageId
|
private let messageId: MessageId
|
||||||
private let present: (ViewController, Any?) -> Void
|
private let present: (ViewController, Any?) -> Void
|
||||||
@ -452,13 +460,15 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||||||
private let actionButtonPanelSeparator: ASDisplayNode
|
private let actionButtonPanelSeparator: ASDisplayNode
|
||||||
private let actionButton: BotCheckoutActionButton
|
private let actionButton: BotCheckoutActionButton
|
||||||
private let inProgressDimNode: ASDisplayNode
|
private let inProgressDimNode: ASDisplayNode
|
||||||
|
private var statusController: ViewController?
|
||||||
|
|
||||||
private let payDisposable = MetaDisposable()
|
private let payDisposable = MetaDisposable()
|
||||||
private let paymentAuthDisposable = MetaDisposable()
|
private let paymentAuthDisposable = MetaDisposable()
|
||||||
private var applePayAuthrorizationCompletion: ((PKPaymentAuthorizationStatus) -> Void)?
|
private var applePayAuthrorizationCompletion: ((PKPaymentAuthorizationStatus) -> Void)?
|
||||||
private var applePayController: PKPaymentAuthorizationViewController?
|
private var applePayController: PKPaymentAuthorizationViewController?
|
||||||
|
|
||||||
init(controller: ItemListController?, navigationBar: NavigationBar, updateNavigationOffset: @escaping (CGFloat) -> Void, context: AccountContext, invoice: TelegramMediaInvoice, messageId: MessageId, present: @escaping (ViewController, Any?) -> Void, dismissAnimated: @escaping () -> Void) {
|
init(controller: BotCheckoutController?, navigationBar: NavigationBar, updateNavigationOffset: @escaping (CGFloat) -> Void, context: AccountContext, invoice: TelegramMediaInvoice, messageId: MessageId, present: @escaping (ViewController, Any?) -> Void, dismissAnimated: @escaping () -> Void) {
|
||||||
|
self.controller = controller
|
||||||
self.context = context
|
self.context = context
|
||||||
self.messageId = messageId
|
self.messageId = messageId
|
||||||
self.present = present
|
self.present = present
|
||||||
@ -470,6 +480,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||||||
var updateTipImpl: ((Int64) -> Void)?
|
var updateTipImpl: ((Int64) -> Void)?
|
||||||
var openPaymentMethodImpl: (() -> Void)?
|
var openPaymentMethodImpl: (() -> Void)?
|
||||||
var openShippingMethodImpl: (() -> Void)?
|
var openShippingMethodImpl: (() -> Void)?
|
||||||
|
var ensureTipInputVisibleImpl: (() -> Void)?
|
||||||
|
|
||||||
let arguments = BotCheckoutControllerArguments(account: context.account, openInfo: { item in
|
let arguments = BotCheckoutControllerArguments(account: context.account, openInfo: { item in
|
||||||
openInfoImpl?(item)
|
openInfoImpl?(item)
|
||||||
@ -479,6 +490,8 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||||||
openShippingMethodImpl?()
|
openShippingMethodImpl?()
|
||||||
}, updateTip: { value in
|
}, updateTip: { value in
|
||||||
updateTipImpl?(value)
|
updateTipImpl?(value)
|
||||||
|
}, ensureTipInputVisible: {
|
||||||
|
ensureTipInputVisibleImpl?()
|
||||||
})
|
})
|
||||||
|
|
||||||
let signal: Signal<(ItemListPresentationData, (ItemListNodeState, Any)), NoError> = combineLatest(context.sharedContext.presentationData, self.state.get(), paymentFormAndInfo.get(), context.account.postbox.loadedPeerWithId(messageId.peerId))
|
let signal: Signal<(ItemListPresentationData, (ItemListNodeState, Any)), NoError> = combineLatest(context.sharedContext.presentationData, self.state.get(), paymentFormAndInfo.get(), context.account.postbox.loadedPeerWithId(messageId.peerId))
|
||||||
@ -503,7 +516,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||||||
self.inProgressDimNode.isUserInteractionEnabled = false
|
self.inProgressDimNode.isUserInteractionEnabled = false
|
||||||
self.inProgressDimNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor.withAlphaComponent(0.5)
|
self.inProgressDimNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor.withAlphaComponent(0.5)
|
||||||
|
|
||||||
super.init(controller: controller, navigationBar: navigationBar, updateNavigationOffset: updateNavigationOffset, state: signal)
|
super.init(controller: nil, navigationBar: navigationBar, updateNavigationOffset: updateNavigationOffset, state: signal)
|
||||||
|
|
||||||
self.arguments = arguments
|
self.arguments = arguments
|
||||||
|
|
||||||
@ -519,8 +532,9 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||||||
updatedCurrentShippingOptionId = currentShippingOptionId
|
updatedCurrentShippingOptionId = currentShippingOptionId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.paymentFormAndInfo.set(.single((paymentFormValue, formInfo, validatedInfo, updatedCurrentShippingOptionId, strongSelf.currentPaymentMethod, strongSelf.currentTipAmount)))
|
strongSelf.paymentFormAndInfo.set(.single((paymentFormValue, formInfo, validatedInfo, updatedCurrentShippingOptionId, strongSelf.currentPaymentMethod, strongSelf.currentTipAmount)))
|
||||||
|
|
||||||
strongSelf.updateActionButton()
|
strongSelf.updateActionButton()
|
||||||
}
|
}
|
||||||
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
@ -762,6 +776,23 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||||||
|
|
||||||
strongSelf.updateActionButton()
|
strongSelf.updateActionButton()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensureTipInputVisibleImpl = { [weak self] in
|
||||||
|
self?.afterLayout({
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var selectedItemNode: ListViewItemNode?
|
||||||
|
strongSelf.listNode.forEachItemNode { itemNode in
|
||||||
|
if let itemNode = itemNode as? BotCheckoutTipItemNode {
|
||||||
|
selectedItemNode = itemNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let selectedItemNode = selectedItemNode {
|
||||||
|
strongSelf.listNode.ensureItemNodeVisible(selectedItemNode, atTop: true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
openPaymentMethodImpl = { [weak self] in
|
openPaymentMethodImpl = { [weak self] in
|
||||||
if let strongSelf = self, let paymentForm = strongSelf.paymentFormValue {
|
if let strongSelf = self, let paymentForm = strongSelf.paymentFormValue {
|
||||||
@ -811,6 +842,9 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||||||
|
|
||||||
self.formRequestDisposable = (formAndMaybeValidatedInfo |> deliverOnMainQueue).start(next: { [weak self] form, validatedInfo in
|
self.formRequestDisposable = (formAndMaybeValidatedInfo |> deliverOnMainQueue).start(next: { [weak self] form, validatedInfo in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
UIView.transition(with: strongSelf.view, duration: 0.25, options: UIView.AnimationOptions.transitionCrossDissolve, animations: {
|
||||||
|
}, completion: nil)
|
||||||
|
|
||||||
let savedInfo: BotPaymentRequestedInfo
|
let savedInfo: BotPaymentRequestedInfo
|
||||||
if let current = form.savedInfo {
|
if let current = form.savedInfo {
|
||||||
savedInfo = current
|
savedInfo = current
|
||||||
@ -868,13 +902,26 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||||||
}
|
}
|
||||||
self.actionButtonPanelNode.isHidden = false
|
self.actionButtonPanelNode.isHidden = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func updateIsInProgress(_ value: Bool) {
|
||||||
|
if value {
|
||||||
|
if self.statusController == nil {
|
||||||
|
let statusController = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
||||||
|
self.statusController = statusController
|
||||||
|
self.controller?.present(statusController, in: .window(.root))
|
||||||
|
}
|
||||||
|
} else if let statusController = self.statusController {
|
||||||
|
self.statusController = nil
|
||||||
|
statusController.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition, additionalInsets: UIEdgeInsets) {
|
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition, additionalInsets: UIEdgeInsets) {
|
||||||
var updatedInsets = layout.intrinsicInsets
|
var updatedInsets = layout.intrinsicInsets
|
||||||
|
|
||||||
let bottomPanelHorizontalInset: CGFloat = 16.0
|
let bottomPanelHorizontalInset: CGFloat = 16.0
|
||||||
let bottomPanelVerticalInset: CGFloat = 16.0
|
let bottomPanelVerticalInset: CGFloat = 16.0
|
||||||
let bottomPanelHeight = updatedInsets.bottom + bottomPanelVerticalInset * 2.0 + BotCheckoutActionButton.height
|
let bottomPanelHeight = max(updatedInsets.bottom, layout.inputHeight ?? 0.0) + 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.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)))
|
transition.updateFrame(node: self.actionButtonPanelSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
||||||
@ -1088,11 +1135,19 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||||||
self.inProgressDimNode.alpha = 1.0
|
self.inProgressDimNode.alpha = 1.0
|
||||||
self.actionButton.isEnabled = false
|
self.actionButton.isEnabled = false
|
||||||
self.updateActionButton()
|
self.updateActionButton()
|
||||||
self.payDisposable.set((sendBotPaymentForm(account: self.context.account, messageId: self.messageId, formId: paymentForm.id, validatedInfoId: self.currentValidatedFormInfo?.id, shippingOptionId: self.currentShippingOptionId, tipAmount: self.currentTipAmount, credentials: credentials) |> deliverOnMainQueue).start(next: { [weak self] result in
|
self.updateIsInProgress(true)
|
||||||
|
|
||||||
|
var tipAmount = self.currentTipAmount
|
||||||
|
if tipAmount == nil, let _ = paymentForm.invoice.tip {
|
||||||
|
tipAmount = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
self.payDisposable.set((sendBotPaymentForm(account: self.context.account, messageId: self.messageId, formId: paymentForm.id, validatedInfoId: self.currentValidatedFormInfo?.id, shippingOptionId: self.currentShippingOptionId, tipAmount: tipAmount, credentials: credentials) |> deliverOnMainQueue).start(next: { [weak self] result in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.inProgressDimNode.isUserInteractionEnabled = false
|
strongSelf.inProgressDimNode.isUserInteractionEnabled = false
|
||||||
strongSelf.inProgressDimNode.alpha = 0.0
|
strongSelf.inProgressDimNode.alpha = 0.0
|
||||||
strongSelf.actionButton.isEnabled = true
|
strongSelf.actionButton.isEnabled = true
|
||||||
|
strongSelf.updateIsInProgress(false)
|
||||||
if let applePayAuthrorizationCompletion = strongSelf.applePayAuthrorizationCompletion {
|
if let applePayAuthrorizationCompletion = strongSelf.applePayAuthrorizationCompletion {
|
||||||
strongSelf.applePayAuthrorizationCompletion = nil
|
strongSelf.applePayAuthrorizationCompletion = nil
|
||||||
applePayAuthrorizationCompletion(.success)
|
applePayAuthrorizationCompletion(.success)
|
||||||
@ -1124,6 +1179,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||||||
strongSelf.inProgressDimNode.alpha = 0.0
|
strongSelf.inProgressDimNode.alpha = 0.0
|
||||||
strongSelf.actionButton.isEnabled = true
|
strongSelf.actionButton.isEnabled = true
|
||||||
strongSelf.updateActionButton()
|
strongSelf.updateActionButton()
|
||||||
|
strongSelf.updateIsInProgress(false)
|
||||||
if let applePayAuthrorizationCompletion = strongSelf.applePayAuthrorizationCompletion {
|
if let applePayAuthrorizationCompletion = strongSelf.applePayAuthrorizationCompletion {
|
||||||
strongSelf.applePayAuthrorizationCompletion = nil
|
strongSelf.applePayAuthrorizationCompletion = nil
|
||||||
applePayAuthrorizationCompletion(.failure)
|
applePayAuthrorizationCompletion(.failure)
|
||||||
|
@ -18,12 +18,13 @@ class BotCheckoutTipItem: ListViewItem, ItemListItem {
|
|||||||
let maxValue: Int64
|
let maxValue: Int64
|
||||||
let availableVariants: [(String, Int64)]
|
let availableVariants: [(String, Int64)]
|
||||||
let updateValue: (Int64) -> Void
|
let updateValue: (Int64) -> Void
|
||||||
|
let updatedFocus: (Bool) -> Void
|
||||||
|
|
||||||
let sectionId: ItemListSectionId
|
let sectionId: ItemListSectionId
|
||||||
|
|
||||||
let requestsNoInset: Bool = true
|
let requestsNoInset: Bool = true
|
||||||
|
|
||||||
init(theme: PresentationTheme, strings: PresentationStrings, title: String, currency: String, value: String, numericValue: Int64, maxValue: Int64, availableVariants: [(String, Int64)], sectionId: ItemListSectionId, updateValue: @escaping (Int64) -> Void) {
|
init(theme: PresentationTheme, strings: PresentationStrings, title: String, currency: String, value: String, numericValue: Int64, maxValue: Int64, availableVariants: [(String, Int64)], sectionId: ItemListSectionId, updateValue: @escaping (Int64) -> Void, updatedFocus: @escaping (Bool) -> Void) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.title = title
|
self.title = title
|
||||||
@ -33,6 +34,7 @@ class BotCheckoutTipItem: ListViewItem, ItemListItem {
|
|||||||
self.maxValue = maxValue
|
self.maxValue = maxValue
|
||||||
self.availableVariants = availableVariants
|
self.availableVariants = availableVariants
|
||||||
self.updateValue = updateValue
|
self.updateValue = updateValue
|
||||||
|
self.updatedFocus = updatedFocus
|
||||||
self.sectionId = sectionId
|
self.sectionId = sectionId
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,6 +266,18 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate {
|
|||||||
|
|
||||||
strongSelf.textNode.clipsToBounds = true
|
strongSelf.textNode.clipsToBounds = true
|
||||||
strongSelf.textNode.textField.delegate = strongSelf.formatterDelegate
|
strongSelf.textNode.textField.delegate = strongSelf.formatterDelegate
|
||||||
|
|
||||||
|
/*let toolbar: UIToolbar = UIToolbar()
|
||||||
|
toolbar.tintColor = item.theme.rootController.navigationBar.accentTextColor
|
||||||
|
toolbar.barTintColor = item.theme.rootController.navigationBar.backgroundColor
|
||||||
|
toolbar.barStyle = .default
|
||||||
|
toolbar.items = [
|
||||||
|
UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil),
|
||||||
|
UIBarButtonItem(title: item.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.dismissKeyboard))
|
||||||
|
]
|
||||||
|
toolbar.sizeToFit()
|
||||||
|
|
||||||
|
strongSelf.textNode.textField.inputAccessoryView = toolbar*/
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.textNode.textField.typingAttributes = [NSAttributedString.Key.font: titleFont]
|
strongSelf.textNode.textField.typingAttributes = [NSAttributedString.Key.font: titleFont]
|
||||||
@ -273,6 +287,7 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate {
|
|||||||
strongSelf.textNode.textField.textAlignment = .right
|
strongSelf.textNode.textField.textAlignment = .right
|
||||||
strongSelf.textNode.textField.keyboardAppearance = item.theme.rootController.keyboardColor.keyboardAppearance
|
strongSelf.textNode.textField.keyboardAppearance = item.theme.rootController.keyboardColor.keyboardAppearance
|
||||||
strongSelf.textNode.textField.keyboardType = .decimalPad
|
strongSelf.textNode.textField.keyboardType = .decimalPad
|
||||||
|
strongSelf.textNode.textField.returnKeyType = .next
|
||||||
strongSelf.textNode.textField.tintColor = item.theme.list.itemAccentColor
|
strongSelf.textNode.textField.tintColor = item.theme.list.itemAccentColor
|
||||||
|
|
||||||
var textInputFrame = CGRect(origin: CGPoint(x: params.width - leftInset - 150.0, y: -2.0), size: CGSize(width: 150.0, height: labelsContentHeight))
|
var textInputFrame = CGRect(origin: CGPoint(x: params.width - leftInset - 150.0, y: -2.0), size: CGSize(width: 150.0, height: labelsContentHeight))
|
||||||
@ -370,6 +385,10 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func dismissKeyboard() {
|
||||||
|
self.textNode.textField.resignFirstResponder()
|
||||||
|
}
|
||||||
|
|
||||||
@objc private func textFieldTextChanged(_ textField: UITextField) {
|
@objc private func textFieldTextChanged(_ textField: UITextField) {
|
||||||
let text = textField.text ?? ""
|
let text = textField.text ?? ""
|
||||||
self.labelNode.isHidden = !text.isEmpty
|
self.labelNode.isHidden = !text.isEmpty
|
||||||
@ -419,6 +438,8 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate {
|
|||||||
|
|
||||||
@objc public func textFieldDidBeginEditing(_ textField: UITextField) {
|
@objc public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||||
textField.selectedTextRange = textField.textRange(from: textField.endOfDocument, to: textField.endOfDocument)
|
textField.selectedTextRange = textField.textRange(from: textField.endOfDocument, to: textField.endOfDocument)
|
||||||
|
|
||||||
|
self.item?.updatedFocus(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func textFieldDidChangeSelection(_ textField: UITextField) {
|
@objc public func textFieldDidChangeSelection(_ textField: UITextField) {
|
||||||
|
@ -276,7 +276,9 @@ final class BotReceiptControllerNode: ItemListControllerNode {
|
|||||||
|
|
||||||
private let receiptData = Promise<(BotPaymentInvoice, BotPaymentRequestedInfo?, BotPaymentShippingOption?, String?, TelegramMediaInvoice, Int64?)?>(nil)
|
private let receiptData = Promise<(BotPaymentInvoice, BotPaymentRequestedInfo?, BotPaymentShippingOption?, String?, TelegramMediaInvoice, Int64?)?>(nil)
|
||||||
private var dataRequestDisposable: Disposable?
|
private var dataRequestDisposable: Disposable?
|
||||||
|
|
||||||
|
private let actionButtonPanelNode: ASDisplayNode
|
||||||
|
private let actionButtonPanelSeparator: ASDisplayNode
|
||||||
private let actionButton: BotCheckoutActionButton
|
private let actionButton: BotCheckoutActionButton
|
||||||
|
|
||||||
init(controller: ItemListController?, navigationBar: NavigationBar, updateNavigationOffset: @escaping (CGFloat) -> Void, context: AccountContext, messageId: MessageId, dismissAnimated: @escaping () -> Void) {
|
init(controller: ItemListController?, navigationBar: NavigationBar, updateNavigationOffset: @escaping (CGFloat) -> Void, context: AccountContext, messageId: MessageId, dismissAnimated: @escaping () -> Void) {
|
||||||
@ -293,6 +295,12 @@ final class BotReceiptControllerNode: ItemListControllerNode {
|
|||||||
|
|
||||||
return (ItemListPresentationData(presentationData), (nodeState, arguments))
|
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.plainBackgroundColor)
|
self.actionButton = BotCheckoutActionButton(inactiveFillColor: self.presentationData.theme.list.plainBackgroundColor, activeFillColor: self.presentationData.theme.list.itemAccentColor, foregroundColor: self.presentationData.theme.list.plainBackgroundColor)
|
||||||
self.actionButton.setState(.active(self.presentationData.strings.Common_Done))
|
self.actionButton.setState(.active(self.presentationData.strings.Common_Done))
|
||||||
@ -301,12 +309,18 @@ final class BotReceiptControllerNode: ItemListControllerNode {
|
|||||||
|
|
||||||
self.dataRequestDisposable = (requestBotPaymentReceipt(account: context.account, messageId: messageId) |> deliverOnMainQueue).start(next: { [weak self] receipt in
|
self.dataRequestDisposable = (requestBotPaymentReceipt(account: context.account, messageId: messageId) |> deliverOnMainQueue).start(next: { [weak self] receipt in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
UIView.transition(with: strongSelf.view, duration: 0.25, options: UIView.AnimationOptions.transitionCrossDissolve, animations: {
|
||||||
|
}, completion: nil)
|
||||||
|
|
||||||
strongSelf.receiptData.set(.single((receipt.invoice, receipt.info, receipt.shippingOption, receipt.credentialsTitle, receipt.invoiceMedia, receipt.tipAmount)))
|
strongSelf.receiptData.set(.single((receipt.invoice, receipt.info, receipt.shippingOption, receipt.credentialsTitle, receipt.invoiceMedia, receipt.tipAmount)))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.actionButton.addTarget(self, action: #selector(self.actionButtonPressed), forControlEvents: .touchUpInside)
|
self.actionButton.addTarget(self, action: #selector(self.actionButtonPressed), forControlEvents: .touchUpInside)
|
||||||
self.addSubnode(self.actionButton)
|
|
||||||
|
self.addSubnode(self.actionButtonPanelNode)
|
||||||
|
self.actionButtonPanelNode.addSubnode(self.actionButtonPanelSeparator)
|
||||||
|
self.actionButtonPanelNode.addSubnode(self.actionButton)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
@ -315,13 +329,21 @@ final class BotReceiptControllerNode: ItemListControllerNode {
|
|||||||
|
|
||||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition, additionalInsets: UIEdgeInsets) {
|
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition, additionalInsets: UIEdgeInsets) {
|
||||||
var updatedInsets = layout.intrinsicInsets
|
var updatedInsets = layout.intrinsicInsets
|
||||||
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 bottomPanelHorizontalInset: CGFloat = 16.0
|
||||||
|
let bottomPanelVerticalInset: CGFloat = 16.0
|
||||||
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))
|
let bottomPanelHeight = max(updatedInsets.bottom, layout.inputHeight ?? 0.0) + 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)
|
transition.updateFrame(node: self.actionButton, frame: actionButtonFrame)
|
||||||
self.actionButton.updateLayout(size: actionButtonFrame.size, transition: transition)
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func actionButtonPressed() {
|
@objc func actionButtonPressed() {
|
||||||
|
@ -4024,13 +4024,21 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func ensureItemNodeVisible(_ node: ListViewItemNode, animated: Bool = true, overflow: CGFloat = 0.0, allowIntersection: Bool = false, curve: ListViewAnimationCurve = .Default(duration: 0.25)) {
|
public func ensureItemNodeVisible(_ node: ListViewItemNode, animated: Bool = true, overflow: CGFloat = 0.0, allowIntersection: Bool = false, atTop: Bool = false, curve: ListViewAnimationCurve = .Default(duration: 0.25)) {
|
||||||
if let index = node.index {
|
if let index = node.index {
|
||||||
if node.apparentHeight > self.visibleSize.height - self.insets.top - self.insets.bottom {
|
if node.apparentHeight > self.visibleSize.height - self.insets.top - self.insets.bottom {
|
||||||
if node.frame.maxY > self.visibleSize.height - self.insets.bottom {
|
if atTop {
|
||||||
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: ListViewDeleteAndInsertOptions(), scrollToItem: ListViewScrollToItem(index: index, position: ListViewScrollPosition.bottom(-overflow), animated: animated, curve: curve, directionHint: ListViewScrollToItemDirectionHint.Down), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
if node.frame.maxY > self.visibleSize.height - self.insets.bottom {
|
||||||
} else if node.frame.minY < self.insets.top && overflow > 0.0 {
|
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: ListViewDeleteAndInsertOptions(), scrollToItem: ListViewScrollToItem(index: index, position: ListViewScrollPosition.top(-overflow), animated: animated, curve: curve, directionHint: ListViewScrollToItemDirectionHint.Down), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: ListViewDeleteAndInsertOptions(), scrollToItem: ListViewScrollToItem(index: index, position: ListViewScrollPosition.top(-overflow), animated: animated, curve: curve, directionHint: ListViewScrollToItemDirectionHint.Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
} else if node.frame.minY < self.insets.top && overflow > 0.0 {
|
||||||
|
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: ListViewDeleteAndInsertOptions(), scrollToItem: ListViewScrollToItem(index: index, position: ListViewScrollPosition.top(-overflow), animated: animated, curve: curve, directionHint: ListViewScrollToItemDirectionHint.Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if node.frame.maxY > self.visibleSize.height - self.insets.bottom {
|
||||||
|
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: ListViewDeleteAndInsertOptions(), scrollToItem: ListViewScrollToItem(index: index, position: ListViewScrollPosition.bottom(-overflow), animated: animated, curve: curve, directionHint: ListViewScrollToItemDirectionHint.Down), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
} else if node.frame.minY < self.insets.top && overflow > 0.0 {
|
||||||
|
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: ListViewDeleteAndInsertOptions(), scrollToItem: ListViewScrollToItem(index: index, position: ListViewScrollPosition.top(-overflow), animated: animated, curve: curve, directionHint: ListViewScrollToItemDirectionHint.Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if self.experimentalSnapScrollToItem {
|
if self.experimentalSnapScrollToItem {
|
||||||
|
@ -79,7 +79,7 @@ public enum GetCurrentGroupCallError {
|
|||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int64) -> Signal<GroupCallSummary?, GetCurrentGroupCallError> {
|
public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int64, peerId: PeerId? = nil) -> Signal<GroupCallSummary?, GetCurrentGroupCallError> {
|
||||||
return account.network.request(Api.functions.phone.getGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash)))
|
return account.network.request(Api.functions.phone.getGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash)))
|
||||||
|> mapError { _ -> GetCurrentGroupCallError in
|
|> mapError { _ -> GetCurrentGroupCallError in
|
||||||
return .generic
|
return .generic
|
||||||
@ -92,6 +92,7 @@ public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: PeerPresence] = [:]
|
||||||
|
|
||||||
@ -108,6 +109,17 @@ public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int
|
|||||||
peers.append(peer)
|
peers.append(peer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let peerId = peerId {
|
||||||
|
transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current in
|
||||||
|
if let cachedData = current as? CachedChannelData {
|
||||||
|
return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall.init(id: info.id, accessHash: info.accessHash, title: info.title, scheduleTimestamp: info.scheduleTimestamp, subscribedToScheduled: cachedData.activeCall?.subscribedToScheduled ?? false))
|
||||||
|
} else if let cachedData = current as? CachedGroupData {
|
||||||
|
return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash, title: info.title, scheduleTimestamp: info.scheduleTimestamp, subscribedToScheduled: cachedData.activeCall?.subscribedToScheduled ?? false))
|
||||||
|
} else {
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
||||||
return updated
|
return updated
|
||||||
|
Loading…
x
Reference in New Issue
Block a user