diff --git a/submodules/BotPaymentsUI/BUILD b/submodules/BotPaymentsUI/BUILD index f7213427bf..d828ebcc6f 100644 --- a/submodules/BotPaymentsUI/BUILD +++ b/submodules/BotPaymentsUI/BUILD @@ -22,6 +22,7 @@ swift_library( "//submodules/CountrySelectionUI:CountrySelectionUI", "//submodules/AppBundle:AppBundle", "//submodules/PresentationDataUtils:PresentationDataUtils", + "//submodules/OverlayStatusController:OverlayStatusController", ], visibility = [ "//visibility:public", diff --git a/submodules/BotPaymentsUI/Sources/BotCheckoutActionButton.swift b/submodules/BotPaymentsUI/Sources/BotCheckoutActionButton.swift index f62ab94796..f356ce752b 100644 --- a/submodules/BotPaymentsUI/Sources/BotCheckoutActionButton.swift +++ b/submodules/BotPaymentsUI/Sources/BotCheckoutActionButton.swift @@ -138,6 +138,11 @@ final class BotCheckoutActionButton: HighlightableButtonNode { self.progressBackgroundNode.layer.add(basicAnimation, forKey: "progressRotation") case let .active(title): + if let applePayButton = self.applePayButton { + self.applePayButton = nil + applePayButton.removeFromSuperview() + } + if case .active = previousState { 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())) diff --git a/submodules/BotPaymentsUI/Sources/BotCheckoutController.swift b/submodules/BotPaymentsUI/Sources/BotCheckoutController.swift index c79efa6d0a..2b44c92e2d 100644 --- a/submodules/BotPaymentsUI/Sources/BotCheckoutController.swift +++ b/submodules/BotPaymentsUI/Sources/BotCheckoutController.swift @@ -52,7 +52,7 @@ public final class BotCheckoutController: ViewController { } 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 { strongSelf.navigationOffset = offset } diff --git a/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift b/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift index 769e802cf8..a83fee8c2c 100644 --- a/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift +++ b/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift @@ -18,6 +18,7 @@ import TelegramStringFormatting import PasswordSetupUI import Stripe import LocalAuth +import OverlayStatusController final class BotCheckoutControllerArguments { fileprivate let account: Account @@ -25,13 +26,15 @@ final class BotCheckoutControllerArguments { fileprivate let openPaymentMethod: () -> Void fileprivate let openShippingMethod: () -> 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.openInfo = openInfo self.openPaymentMethod = openPaymentMethod self.openShippingMethod = openShippingMethod self.updateTip = updateTip + self.ensureTipInputVisible = ensureTipInputVisible } } @@ -197,6 +200,10 @@ enum BotCheckoutEntry: ItemListNodeEntry { 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 arguments.updateTip(value) + }, updatedFocus: { isFocused in + if isFocused { + arguments.ensureTipInputVisible() + } }) case let .paymentMethod(_, text, value): 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 { + private weak var controller: BotCheckoutController? private let context: AccountContext private let messageId: MessageId private let present: (ViewController, Any?) -> Void @@ -452,13 +460,15 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz private let actionButtonPanelSeparator: ASDisplayNode private let actionButton: BotCheckoutActionButton private let inProgressDimNode: ASDisplayNode + private var statusController: ViewController? private let payDisposable = MetaDisposable() private let paymentAuthDisposable = MetaDisposable() private var applePayAuthrorizationCompletion: ((PKPaymentAuthorizationStatus) -> Void)? 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.messageId = messageId self.present = present @@ -470,6 +480,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz var updateTipImpl: ((Int64) -> Void)? var openPaymentMethodImpl: (() -> Void)? var openShippingMethodImpl: (() -> Void)? + var ensureTipInputVisibleImpl: (() -> Void)? let arguments = BotCheckoutControllerArguments(account: context.account, openInfo: { item in openInfoImpl?(item) @@ -479,6 +490,8 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz openShippingMethodImpl?() }, updateTip: { value in 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)) @@ -503,7 +516,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz self.inProgressDimNode.isUserInteractionEnabled = false 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 @@ -519,8 +532,9 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz updatedCurrentShippingOptionId = currentShippingOptionId } } + strongSelf.paymentFormAndInfo.set(.single((paymentFormValue, formInfo, validatedInfo, updatedCurrentShippingOptionId, strongSelf.currentPaymentMethod, strongSelf.currentTipAmount))) - + strongSelf.updateActionButton() } }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) @@ -762,6 +776,23 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz 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 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 if let strongSelf = self { + UIView.transition(with: strongSelf.view, duration: 0.25, options: UIView.AnimationOptions.transitionCrossDissolve, animations: { + }, completion: nil) + let savedInfo: BotPaymentRequestedInfo if let current = form.savedInfo { savedInfo = current @@ -868,13 +902,26 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz } 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) { var updatedInsets = layout.intrinsicInsets let bottomPanelHorizontalInset: 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.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.actionButton.isEnabled = false 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 { strongSelf.inProgressDimNode.isUserInteractionEnabled = false strongSelf.inProgressDimNode.alpha = 0.0 strongSelf.actionButton.isEnabled = true + strongSelf.updateIsInProgress(false) if let applePayAuthrorizationCompletion = strongSelf.applePayAuthrorizationCompletion { strongSelf.applePayAuthrorizationCompletion = nil applePayAuthrorizationCompletion(.success) @@ -1124,6 +1179,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz strongSelf.inProgressDimNode.alpha = 0.0 strongSelf.actionButton.isEnabled = true strongSelf.updateActionButton() + strongSelf.updateIsInProgress(false) if let applePayAuthrorizationCompletion = strongSelf.applePayAuthrorizationCompletion { strongSelf.applePayAuthrorizationCompletion = nil applePayAuthrorizationCompletion(.failure) diff --git a/submodules/BotPaymentsUI/Sources/BotCheckoutTipItem.swift b/submodules/BotPaymentsUI/Sources/BotCheckoutTipItem.swift index 10a99ff846..a01ba0a76c 100644 --- a/submodules/BotPaymentsUI/Sources/BotCheckoutTipItem.swift +++ b/submodules/BotPaymentsUI/Sources/BotCheckoutTipItem.swift @@ -18,12 +18,13 @@ class BotCheckoutTipItem: ListViewItem, ItemListItem { let maxValue: Int64 let availableVariants: [(String, Int64)] let updateValue: (Int64) -> Void + let updatedFocus: (Bool) -> Void let sectionId: ItemListSectionId 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.strings = strings self.title = title @@ -33,6 +34,7 @@ class BotCheckoutTipItem: ListViewItem, ItemListItem { self.maxValue = maxValue self.availableVariants = availableVariants self.updateValue = updateValue + self.updatedFocus = updatedFocus self.sectionId = sectionId } @@ -264,6 +266,18 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate { strongSelf.textNode.clipsToBounds = true 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] @@ -273,6 +287,7 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate { strongSelf.textNode.textField.textAlignment = .right strongSelf.textNode.textField.keyboardAppearance = item.theme.rootController.keyboardColor.keyboardAppearance strongSelf.textNode.textField.keyboardType = .decimalPad + strongSelf.textNode.textField.returnKeyType = .next 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)) @@ -370,6 +385,10 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate { } } + @objc private func dismissKeyboard() { + self.textNode.textField.resignFirstResponder() + } + @objc private func textFieldTextChanged(_ textField: UITextField) { let text = textField.text ?? "" self.labelNode.isHidden = !text.isEmpty @@ -419,6 +438,8 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate { @objc public func textFieldDidBeginEditing(_ textField: UITextField) { textField.selectedTextRange = textField.textRange(from: textField.endOfDocument, to: textField.endOfDocument) + + self.item?.updatedFocus(true) } @objc public func textFieldDidChangeSelection(_ textField: UITextField) { diff --git a/submodules/BotPaymentsUI/Sources/BotReceiptControllerNode.swift b/submodules/BotPaymentsUI/Sources/BotReceiptControllerNode.swift index d667482776..031f1f7251 100644 --- a/submodules/BotPaymentsUI/Sources/BotReceiptControllerNode.swift +++ b/submodules/BotPaymentsUI/Sources/BotReceiptControllerNode.swift @@ -276,7 +276,9 @@ final class BotReceiptControllerNode: ItemListControllerNode { private let receiptData = Promise<(BotPaymentInvoice, BotPaymentRequestedInfo?, BotPaymentShippingOption?, String?, TelegramMediaInvoice, Int64?)?>(nil) private var dataRequestDisposable: Disposable? - + + private let actionButtonPanelNode: ASDisplayNode + private let actionButtonPanelSeparator: ASDisplayNode private let actionButton: BotCheckoutActionButton 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)) } + + 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.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 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))) } }) 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 { @@ -315,13 +329,21 @@ final class BotReceiptControllerNode: ItemListControllerNode { override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition, additionalInsets: UIEdgeInsets) { 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 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 bottomPanelHorizontalInset: CGFloat = 16.0 + let bottomPanelVerticalInset: CGFloat = 16.0 + 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) 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() { diff --git a/submodules/Display/Source/ListView.swift b/submodules/Display/Source/ListView.swift index 5b28121d9b..ffbae84226 100644 --- a/submodules/Display/Source/ListView.swift +++ b/submodules/Display/Source/ListView.swift @@ -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 node.apparentHeight > self.visibleSize.height - self.insets.top - self.insets.bottom { - 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 }) + if atTop { + if node.frame.maxY > self.visibleSize.height - self.insets.bottom { + 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 }) + } 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 { if self.experimentalSnapScrollToItem { diff --git a/submodules/TelegramCore/Sources/GroupCalls.swift b/submodules/TelegramCore/Sources/GroupCalls.swift index 11df8dc596..301b45c904 100644 --- a/submodules/TelegramCore/Sources/GroupCalls.swift +++ b/submodules/TelegramCore/Sources/GroupCalls.swift @@ -79,7 +79,7 @@ public enum GetCurrentGroupCallError { case generic } -public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int64) -> Signal { +public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int64, peerId: PeerId? = nil) -> Signal { return account.network.request(Api.functions.phone.getGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash))) |> mapError { _ -> GetCurrentGroupCallError in return .generic @@ -92,6 +92,7 @@ public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int return nil } + var peers: [Peer] = [] var peerPresences: [PeerId: PeerPresence] = [:] @@ -108,6 +109,17 @@ public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int 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 return updated