mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
Various fixes
This commit is contained in:
parent
e23c7f2e2b
commit
e348c620fa
@ -160,6 +160,12 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer.description.contains("WKDeferringGesture") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer.description.contains("UIWebTouchEventsGesture") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is UILongPressGestureRecognizer {
|
if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is UILongPressGestureRecognizer {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -263,7 +263,7 @@ public class AttachmentController: ViewController {
|
|||||||
let panel: AttachmentPanel
|
let panel: AttachmentPanel
|
||||||
|
|
||||||
fileprivate var currentType: AttachmentButtonType?
|
fileprivate var currentType: AttachmentButtonType?
|
||||||
private var currentControllers: [AttachmentContainable] = []
|
fileprivate var currentControllers: [AttachmentContainable] = []
|
||||||
|
|
||||||
private var validLayout: ContainerViewLayout?
|
private var validLayout: ContainerViewLayout?
|
||||||
private var modalProgress: CGFloat = 0.0
|
private var modalProgress: CGFloat = 0.0
|
||||||
@ -402,7 +402,7 @@ public class AttachmentController: ViewController {
|
|||||||
if let current = current as? MinimizedContainerImpl {
|
if let current = current as? MinimizedContainerImpl {
|
||||||
minimizedContainer = current
|
minimizedContainer = current
|
||||||
} else if let context = self?.controller?.context {
|
} else if let context = self?.controller?.context {
|
||||||
minimizedContainer = MinimizedContainerImpl(context: context, navigationController: navigationController)
|
minimizedContainer = MinimizedContainerImpl(sharedContext: context.sharedContext)
|
||||||
} else {
|
} else {
|
||||||
minimizedContainer = nil
|
minimizedContainer = nil
|
||||||
}
|
}
|
||||||
@ -954,7 +954,7 @@ public class AttachmentController: ViewController {
|
|||||||
if fromMenu && !hasButton, let inputContainerHeight = self.inputContainerHeight {
|
if fromMenu && !hasButton, let inputContainerHeight = self.inputContainerHeight {
|
||||||
panelHeight = inputContainerHeight
|
panelHeight = inputContainerHeight
|
||||||
}
|
}
|
||||||
if hasPanel || hasButton || (fromMenu && isCompact) {
|
if hasPanel || hasButton {
|
||||||
containerInsets.bottom = panelHeight
|
containerInsets.bottom = panelHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1145,6 +1145,12 @@ public class AttachmentController: ViewController {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override var isMinimized: Bool {
|
||||||
|
didSet {
|
||||||
|
self.mainController.isMinimized = self.isMinimized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var validLayout: ContainerViewLayout?
|
private var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
@ -1160,6 +1166,10 @@ public class AttachmentController: ViewController {
|
|||||||
self.node.containerLayoutUpdated(layout, transition: transition)
|
self.node.containerLayoutUpdated(layout, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var mainController: ViewController {
|
||||||
|
return self.node.currentControllers.first!
|
||||||
|
}
|
||||||
|
|
||||||
public final class InputPanelTransition {
|
public final class InputPanelTransition {
|
||||||
let inputNode: ASDisplayNode
|
let inputNode: ASDisplayNode
|
||||||
let accessoryPanelNode: ASDisplayNode?
|
let accessoryPanelNode: ASDisplayNode?
|
||||||
|
|||||||
@ -2,6 +2,9 @@ import Foundation
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
|
|
||||||
public protocol MinimizedContainer: ASDisplayNode {
|
public protocol MinimizedContainer: ASDisplayNode {
|
||||||
|
var navigationController: NavigationController? { get set }
|
||||||
|
var controllers: [ViewController] { get }
|
||||||
|
|
||||||
var willMaximize: (() -> Void)? { get set }
|
var willMaximize: (() -> Void)? { get set }
|
||||||
|
|
||||||
func addController(_ viewController: ViewController, transition: ContainedViewLayoutTransition)
|
func addController(_ viewController: ViewController, transition: ContainedViewLayoutTransition)
|
||||||
|
|||||||
@ -150,7 +150,11 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||||||
private var rootModalFrame: NavigationModalFrame?
|
private var rootModalFrame: NavigationModalFrame?
|
||||||
private var modalContainers: [NavigationModalContainer] = []
|
private var modalContainers: [NavigationModalContainer] = []
|
||||||
private var overlayContainers: [NavigationOverlayContainer] = []
|
private var overlayContainers: [NavigationOverlayContainer] = []
|
||||||
private var minimizedContainer: MinimizedContainer?
|
open var minimizedContainer: MinimizedContainer? {
|
||||||
|
didSet {
|
||||||
|
self.minimizedContainer?.navigationController = self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var globalOverlayContainers: [NavigationOverlayContainer] = []
|
private var globalOverlayContainers: [NavigationOverlayContainer] = []
|
||||||
private var globalOverlayBelowKeyboardContainerParent: GlobalOverlayContainerParent?
|
private var globalOverlayBelowKeyboardContainerParent: GlobalOverlayContainerParent?
|
||||||
@ -826,6 +830,22 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||||||
layout.additionalInsets.left = max(layout.intrinsicInsets.left, additionalSideInsets.left)
|
layout.additionalInsets.left = max(layout.intrinsicInsets.left, additionalSideInsets.left)
|
||||||
layout.additionalInsets.right = max(layout.intrinsicInsets.right, additionalSideInsets.right)
|
layout.additionalInsets.right = max(layout.intrinsicInsets.right, additionalSideInsets.right)
|
||||||
|
|
||||||
|
var updatedSize = layout.size
|
||||||
|
var updatedIntrinsicInsets = layout.intrinsicInsets
|
||||||
|
if case .flat = navigationLayout.root, let minimizedContainer = self.minimizedContainer {
|
||||||
|
if minimizedContainer.supernode !== self.displayNode {
|
||||||
|
if let rootContainer = self.rootContainer, case let .flat(flatContainer) = rootContainer {
|
||||||
|
self.displayNode.insertSubnode(minimizedContainer, aboveSubnode: flatContainer)
|
||||||
|
} else {
|
||||||
|
self.displayNode.insertSubnode(minimizedContainer, at: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (layout.inputHeight ?? 0.0).isZero {
|
||||||
|
updatedSize.height -= minimizedContainer.collapsedHeight(layout: layout)
|
||||||
|
updatedIntrinsicInsets.bottom = 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch navigationLayout.root {
|
switch navigationLayout.root {
|
||||||
case let .flat(controllers):
|
case let .flat(controllers):
|
||||||
if let rootContainer = self.rootContainer {
|
if let rootContainer = self.rootContainer {
|
||||||
@ -839,12 +859,6 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||||||
flatContainer.canHaveKeyboardFocus = false
|
flatContainer.canHaveKeyboardFocus = false
|
||||||
}
|
}
|
||||||
|
|
||||||
var updatedSize = layout.size
|
|
||||||
var updatedIntrinsicInsets = layout.intrinsicInsets
|
|
||||||
if let minimizedContainer = self.minimizedContainer, (layout.inputHeight ?? 0.0).isZero {
|
|
||||||
updatedSize.height -= minimizedContainer.collapsedHeight(layout: layout)
|
|
||||||
updatedIntrinsicInsets.bottom = 0.0
|
|
||||||
}
|
|
||||||
let updatedLayout = layout.withUpdatedSize(updatedSize).withUpdatedIntrinsicInsets(updatedIntrinsicInsets)
|
let updatedLayout = layout.withUpdatedSize(updatedSize).withUpdatedIntrinsicInsets(updatedIntrinsicInsets)
|
||||||
transition.updateFrame(node: flatContainer, frame: CGRect(origin: CGPoint(), size: updatedSize))
|
transition.updateFrame(node: flatContainer, frame: CGRect(origin: CGPoint(), size: updatedSize))
|
||||||
flatContainer.update(layout: updatedLayout, canBeClosed: false, controllers: controllers, transition: transition)
|
flatContainer.update(layout: updatedLayout, canBeClosed: false, controllers: controllers, transition: transition)
|
||||||
@ -904,8 +918,10 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||||||
self.displayNode.insertSubnode(flatContainer, at: 0)
|
self.displayNode.insertSubnode(flatContainer, at: 0)
|
||||||
}
|
}
|
||||||
self.rootContainer = .flat(flatContainer)
|
self.rootContainer = .flat(flatContainer)
|
||||||
flatContainer.frame = CGRect(origin: CGPoint(), size: layout.size)
|
|
||||||
flatContainer.update(layout: layout, canBeClosed: false, controllers: controllers, transition: .immediate)
|
let updatedLayout = layout.withUpdatedSize(updatedSize).withUpdatedIntrinsicInsets(updatedIntrinsicInsets)
|
||||||
|
flatContainer.frame = CGRect(origin: CGPoint(), size: updatedSize)
|
||||||
|
flatContainer.update(layout: updatedLayout, canBeClosed: false, controllers: controllers, transition: .immediate)
|
||||||
}
|
}
|
||||||
case let .split(masterControllers, detailControllers):
|
case let .split(masterControllers, detailControllers):
|
||||||
if let rootContainer = self.rootContainer {
|
if let rootContainer = self.rootContainer {
|
||||||
@ -931,6 +947,11 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||||||
splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, detailsPlaceholderNode: self.detailsPlaceholderNode, transition: .immediate)
|
splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, detailsPlaceholderNode: self.detailsPlaceholderNode, transition: .immediate)
|
||||||
flatContainer.statusBarStyleUpdated = nil
|
flatContainer.statusBarStyleUpdated = nil
|
||||||
flatContainer.removeFromSupernode()
|
flatContainer.removeFromSupernode()
|
||||||
|
|
||||||
|
if let minimizedContainer = self.minimizedContainer {
|
||||||
|
minimizedContainer.removeFromSupernode()
|
||||||
|
self.minimizedContainer = nil
|
||||||
|
}
|
||||||
case let .split(splitContainer):
|
case let .split(splitContainer):
|
||||||
if previousModalContainer == nil {
|
if previousModalContainer == nil {
|
||||||
splitContainer.canHaveKeyboardFocus = true
|
splitContainer.canHaveKeyboardFocus = true
|
||||||
@ -1554,17 +1575,11 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||||||
self.isMaximizing = true
|
self.isMaximizing = true
|
||||||
self.updateContainersNonReentrant(transition: .animated(duration: 0.4, curve: .spring))
|
self.updateContainersNonReentrant(transition: .animated(duration: 0.4, curve: .spring))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
self.minimizedContainer?.removeFromSupernode()
|
self.minimizedContainer?.removeFromSupernode()
|
||||||
self.minimizedContainer = minimizedContainer
|
self.minimizedContainer = minimizedContainer
|
||||||
|
|
||||||
if let minimizedContainer {
|
|
||||||
if let modalContainer = self.modalContainers.first {
|
|
||||||
self.displayNode.insertSubnode(minimizedContainer, belowSubnode: modalContainer)
|
|
||||||
} else {
|
|
||||||
self.displayNode.addSubnode(minimizedContainer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.updateContainersNonReentrant(transition: transition)
|
self.updateContainersNonReentrant(transition: transition)
|
||||||
}
|
}
|
||||||
viewController.isMinimized = true
|
viewController.isMinimized = true
|
||||||
|
|||||||
@ -1195,7 +1195,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
|
|
||||||
var hintSeekable = false
|
var hintSeekable = false
|
||||||
if let contentInfo = item.contentInfo, case let .message(message, _) = contentInfo {
|
if let contentInfo = item.contentInfo, case let .message(message, _) = contentInfo {
|
||||||
if Namespaces.Message.allNonRegular.contains(message.id.namespace) || message.id.namespace == Namespaces.Message.Local {
|
if message.paidContent != nil {
|
||||||
|
disablePictureInPicture = true
|
||||||
|
} else if Namespaces.Message.allNonRegular.contains(message.id.namespace) || message.id.namespace == Namespaces.Message.Local {
|
||||||
disablePictureInPicture = true
|
disablePictureInPicture = true
|
||||||
} else {
|
} else {
|
||||||
let throttledSignal = videoNode.status
|
let throttledSignal = videoNode.status
|
||||||
|
|||||||
@ -49,6 +49,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
|
|||||||
private let shadowNode: ASImageNode
|
private let shadowNode: ASImageNode
|
||||||
|
|
||||||
private var controllerView: UIView?
|
private var controllerView: UIView?
|
||||||
|
fileprivate var snapshotView: UIView?
|
||||||
|
|
||||||
var tapped: (() -> Void)?
|
var tapped: (() -> Void)?
|
||||||
var highlighted: ((Bool) -> Void)?
|
var highlighted: ((Bool) -> Void)?
|
||||||
@ -97,13 +98,19 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
|
|||||||
self.shadowNode.image = shadowImage
|
self.shadowNode.image = shadowImage
|
||||||
|
|
||||||
self.addSubnode(self.containerNode)
|
self.addSubnode(self.containerNode)
|
||||||
if let snapshotView = self.item.controller.displayNode.view.snapshotView(afterScreenUpdates: false) {
|
self.controllerView = self.item.controller.displayNode.view
|
||||||
self.controllerView = snapshotView
|
self.containerNode.view.addSubview(self.item.controller.displayNode.view)
|
||||||
self.containerNode.view.addSubview(snapshotView)
|
|
||||||
} else {
|
Queue.mainQueue().after(0.45) {
|
||||||
self.controllerView = self.item.controller.displayNode.view
|
if !self.isDismissed, let snapshotView = self.controllerView?.snapshotView(afterScreenUpdates: false) {
|
||||||
self.containerNode.view.addSubview(self.item.controller.displayNode.view)
|
self.snapshotView = snapshotView
|
||||||
|
self.controllerView?.removeFromSuperview()
|
||||||
|
self.controllerView = snapshotView
|
||||||
|
self.containerNode.view.addSubview(snapshotView)
|
||||||
|
self.requestLayout(transition: .immediate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.addSubnode(self.headerNode)
|
self.addSubnode(self.headerNode)
|
||||||
self.addSubnode(self.dimCoverNode)
|
self.addSubnode(self.dimCoverNode)
|
||||||
self.addSubnode(self.shadowNode)
|
self.addSubnode(self.shadowNode)
|
||||||
@ -181,6 +188,13 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func requestLayout(transition: ContainedViewLayoutTransition) {
|
||||||
|
guard let (size, insets, isExpanded) = self.validLayout else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.updateLayout(size: size, insets: insets, isExpanded: isExpanded, transition: transition)
|
||||||
|
}
|
||||||
|
|
||||||
func updateLayout(size: CGSize, insets: UIEdgeInsets, isExpanded: Bool, transition: ContainedViewLayoutTransition) {
|
func updateLayout(size: CGSize, insets: UIEdgeInsets, isExpanded: Bool, transition: ContainedViewLayoutTransition) {
|
||||||
self.validLayout = (size, insets, isExpanded)
|
self.validLayout = (size, insets, isExpanded)
|
||||||
|
|
||||||
@ -203,7 +217,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
|
|||||||
transition.updateFrame(node: self.headerNode, frame: headerFrame)
|
transition.updateFrame(node: self.headerNode, frame: headerFrame)
|
||||||
transition.updateFrame(node: self.dimCoverNode, frame: CGRect(origin: .zero, size: size))
|
transition.updateFrame(node: self.dimCoverNode, frame: CGRect(origin: .zero, size: size))
|
||||||
|
|
||||||
if let controllerView = self.controllerView {
|
if let controllerView = self.snapshotView {
|
||||||
let controllerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - controllerView.bounds.size.width) / 2.0), y: 0.0), size: controllerView.bounds.size)
|
let controllerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - controllerView.bounds.size.width) / 2.0), y: 0.0), size: controllerView.bounds.size)
|
||||||
transition.updateFrame(view: controllerView, frame: controllerFrame)
|
transition.updateFrame(view: controllerView, frame: controllerFrame)
|
||||||
}
|
}
|
||||||
@ -214,8 +228,8 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let context: AccountContext
|
private let sharedContext: SharedAccountContext
|
||||||
private weak var navigationController: NavigationController?
|
public weak var navigationController: NavigationController?
|
||||||
private var items: [Item] = []
|
private var items: [Item] = []
|
||||||
|
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
@ -239,10 +253,13 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
|
|||||||
private var isApplyingTransition = false
|
private var isApplyingTransition = false
|
||||||
private var validLayout: ContainerViewLayout?
|
private var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
public init(context: AccountContext, navigationController: NavigationController) {
|
public var controllers: [ViewController] {
|
||||||
self.context = context
|
return self.items.map { $0.controller }
|
||||||
self.navigationController = navigationController
|
}
|
||||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
||||||
|
public init(sharedContext: SharedAccountContext) {
|
||||||
|
self.sharedContext = sharedContext
|
||||||
|
self.presentationData = sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
self.bottomEdgeView = UIImageView()
|
self.bottomEdgeView = UIImageView()
|
||||||
self.bottomEdgeView.contentMode = .scaleToFill
|
self.bottomEdgeView.contentMode = .scaleToFill
|
||||||
@ -275,7 +292,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
|
|||||||
self.view.addSubview(self.dimView)
|
self.view.addSubview(self.dimView)
|
||||||
self.view.addSubview(self.scrollView)
|
self.view.addSubview(self.scrollView)
|
||||||
|
|
||||||
self.presentationDataDisposable = (self.context.sharedContext.presentationData
|
self.presentationDataDisposable = (self.sharedContext.presentationData
|
||||||
|> deliverOnMainQueue).startStrict(next: { [weak self] presentationData in
|
|> deliverOnMainQueue).startStrict(next: { [weak self] presentationData in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
@ -488,6 +505,13 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.requestUpdate(transition: .immediate)
|
self.requestUpdate(transition: .immediate)
|
||||||
|
|
||||||
|
if scrollView.contentOffset.y < -64.0 {
|
||||||
|
self.isExpanded = false
|
||||||
|
scrollView.panGestureRecognizer.isEnabled = false
|
||||||
|
scrollView.panGestureRecognizer.isEnabled = true
|
||||||
|
self.requestUpdate(transition: .animated(duration: 0.4, curve: .spring))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func requestUpdate(transition: ContainedViewLayoutTransition, completion: @escaping (Transition) -> Void = { _ in }) {
|
private func requestUpdate(transition: ContainedViewLayoutTransition, completion: @escaping (Transition) -> Void = { _ in }) {
|
||||||
@ -773,6 +797,16 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
|
|||||||
if self.currentTransition == currentTransition {
|
if self.currentTransition == currentTransition {
|
||||||
self.currentTransition = nil
|
self.currentTransition = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let snaphotView = itemNode.snapshotView {
|
||||||
|
itemNode.item.controller.displayNode.view.addSubview(snaphotView)
|
||||||
|
Queue.mainQueue().after(0.15, {
|
||||||
|
snaphotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||||
|
snaphotView.removeFromSuperview()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
completion(currentTransition)
|
completion(currentTransition)
|
||||||
self.itemNodes[itemId] = nil
|
self.itemNodes[itemId] = nil
|
||||||
itemNode.removeFromSupernode()
|
itemNode.removeFromSupernode()
|
||||||
|
|||||||
@ -5296,6 +5296,16 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
guard let controller = self.controller else {
|
guard let controller = self.controller else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let navigationController = controller.navigationController as? NavigationController, let minimizedContainer = navigationController.minimizedContainer {
|
||||||
|
for controller in minimizedContainer.controllers {
|
||||||
|
if let controller = controller as? AttachmentController, let mainController = controller.mainController as? WebAppController, mainController.botId == bot.peer.id && mainController.source == .settings {
|
||||||
|
navigationController.maximizeViewController(controller, animated: true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let presentationData = self.presentationData
|
let presentationData = self.presentationData
|
||||||
let proceed: (Bool) -> Void = { [weak self] installed in
|
let proceed: (Bool) -> Void = { [weak self] installed in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
|
|||||||
@ -178,6 +178,7 @@ final class SharedApplicationContext {
|
|||||||
let notificationManager: SharedNotificationManager
|
let notificationManager: SharedNotificationManager
|
||||||
let wakeupManager: SharedWakeupManager
|
let wakeupManager: SharedWakeupManager
|
||||||
let overlayMediaController: ViewController & OverlayMediaController
|
let overlayMediaController: ViewController & OverlayMediaController
|
||||||
|
var minimizedContainer: MinimizedContainer?
|
||||||
|
|
||||||
init(sharedContext: SharedAccountContextImpl, notificationManager: SharedNotificationManager, wakeupManager: SharedWakeupManager) {
|
init(sharedContext: SharedAccountContextImpl, notificationManager: SharedNotificationManager, wakeupManager: SharedWakeupManager) {
|
||||||
self.sharedContext = sharedContext
|
self.sharedContext = sharedContext
|
||||||
|
|||||||
@ -168,6 +168,10 @@ final class AuthorizedApplicationContext {
|
|||||||
self.notificationController = NotificationContainerController(context: context)
|
self.notificationController = NotificationContainerController(context: context)
|
||||||
|
|
||||||
self.rootController = TelegramRootController(context: context)
|
self.rootController = TelegramRootController(context: context)
|
||||||
|
self.rootController.minimizedContainer = self.sharedApplicationContext.minimizedContainer
|
||||||
|
self.rootController.minimizedContainerUpdated = { [weak self] minimizedContainer in
|
||||||
|
self?.sharedApplicationContext.minimizedContainer = minimizedContainer
|
||||||
|
}
|
||||||
|
|
||||||
self.rootController.globalOverlayControllersUpdated = { [weak self] in
|
self.rootController.globalOverlayControllersUpdated = { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
|
|||||||
@ -0,0 +1,253 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
import SwiftSignalKit
|
||||||
|
import TelegramCore
|
||||||
|
import ChatPresentationInterfaceState
|
||||||
|
import ChatControllerInteraction
|
||||||
|
import WebUI
|
||||||
|
import AttachmentUI
|
||||||
|
import AccountContext
|
||||||
|
import TelegramNotices
|
||||||
|
import PresentationDataUtils
|
||||||
|
|
||||||
|
extension ChatControllerImpl {
|
||||||
|
func openWebApp(buttonText: String, url: String, simple: Bool, source: ChatOpenWebViewSource) {
|
||||||
|
guard let peerId = self.chatLocation.peerId, let peer = self.presentationInterfaceState.renderedPeer?.peer else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.chatDisplayNode.dismissInput()
|
||||||
|
|
||||||
|
let botName: String
|
||||||
|
let botAddress: String
|
||||||
|
if case let .inline(bot) = source {
|
||||||
|
botName = bot.compactDisplayTitle
|
||||||
|
botAddress = bot.addressName ?? ""
|
||||||
|
} else {
|
||||||
|
botName = EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)
|
||||||
|
botAddress = peer.addressName ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if source == .generic {
|
||||||
|
self.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||||
|
return $0.updatedTitlePanelContext {
|
||||||
|
if !$0.contains(where: {
|
||||||
|
switch $0 {
|
||||||
|
case .requestInProgress:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
var updatedContexts = $0
|
||||||
|
updatedContexts.append(.requestInProgress)
|
||||||
|
return updatedContexts.sorted()
|
||||||
|
}
|
||||||
|
return $0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let updateProgress = { [weak self] in
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||||
|
return $0.updatedTitlePanelContext {
|
||||||
|
if let index = $0.firstIndex(where: {
|
||||||
|
switch $0 {
|
||||||
|
case .requestInProgress:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
var updatedContexts = $0
|
||||||
|
updatedContexts.remove(at: index)
|
||||||
|
return updatedContexts
|
||||||
|
}
|
||||||
|
return $0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let openWebView = {
|
||||||
|
if source == .menu {
|
||||||
|
self.updateChatPresentationInterfaceState(interactive: false) { state in
|
||||||
|
return state.updatedForceInputCommandsHidden(true)
|
||||||
|
// return state.updatedShowWebView(true).updatedForceInputCommandsHidden(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let currentMenuWebAppController = self.currentMenuWebAppController {
|
||||||
|
if currentMenuWebAppController.isMinimized {
|
||||||
|
(currentMenuWebAppController.navigationController as? NavigationController)?.maximizeViewController(currentMenuWebAppController, animated: true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let navigationController = self.navigationController as? NavigationController, let minimizedContainer = navigationController.minimizedContainer {
|
||||||
|
for controller in minimizedContainer.controllers {
|
||||||
|
if let controller = controller as? AttachmentController, let mainController = controller.mainController as? WebAppController, mainController.botId == peerId && mainController.source == .menu {
|
||||||
|
navigationController.maximizeViewController(controller, animated: true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let context = self.context
|
||||||
|
let params = WebAppParameters(source: .menu, peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false)
|
||||||
|
let controller = standaloneWebAppController(context: self.context, updatedPresentationData: self.updatedPresentationData, params: params, threadId: self.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
|
||||||
|
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
||||||
|
}, requestSwitchInline: { [weak self] query, chatTypes, completion in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if let chatTypes {
|
||||||
|
let controller = strongSelf.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: strongSelf.context, filter: [.excludeRecent, .doNotSearchMessages], requestPeerType: chatTypes, hasContactSelector: false, hasCreation: false))
|
||||||
|
controller.peerSelected = { [weak self, weak controller] peer, _ in
|
||||||
|
if let strongSelf = self {
|
||||||
|
completion()
|
||||||
|
controller?.dismiss()
|
||||||
|
strongSelf.controllerInteraction?.activateSwitchInline(peer.id, "@\(botAddress) \(query)", nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strongSelf.push(controller)
|
||||||
|
} else {
|
||||||
|
strongSelf.controllerInteraction?.activateSwitchInline(peerId, "@\(botAddress) \(query)", nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, getInputContainerNode: { [weak self] in
|
||||||
|
if let strongSelf = self, let layout = strongSelf.validLayout, case .compact = layout.metrics.widthClass {
|
||||||
|
return (strongSelf.chatDisplayNode.getWindowInputAccessoryHeight(), strongSelf.chatDisplayNode.inputPanelContainerNode, {
|
||||||
|
return strongSelf.chatDisplayNode.textInputPanelNode?.makeAttachmentMenuTransition(accessoryPanelNode: nil)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}, completion: { [weak self] in
|
||||||
|
self?.chatDisplayNode.historyNode.scrollToEndOfHistory()
|
||||||
|
}, willDismiss: { [weak self] in
|
||||||
|
self?.interfaceInteraction?.updateShowWebView { _ in
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}, didDismiss: { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
let isFocused = strongSelf.chatDisplayNode.textInputPanelNode?.isFocused ?? false
|
||||||
|
strongSelf.chatDisplayNode.insertSubnode(strongSelf.chatDisplayNode.inputPanelContainerNode, aboveSubnode: strongSelf.chatDisplayNode.inputContextPanelContainer)
|
||||||
|
if isFocused {
|
||||||
|
strongSelf.chatDisplayNode.textInputPanelNode?.ensureFocused()
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.updateChatPresentationInterfaceState(interactive: false) { state in
|
||||||
|
return state.updatedForceInputCommandsHidden(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, getNavigationController: { [weak self] in
|
||||||
|
return self?.effectiveNavigationController ?? context.sharedContext.mainWindow?.viewController as? NavigationController
|
||||||
|
})
|
||||||
|
controller.navigationPresentation = .flatModal
|
||||||
|
self.push(controller)
|
||||||
|
self.currentMenuWebAppController = controller
|
||||||
|
} else if simple {
|
||||||
|
var isInline = false
|
||||||
|
var botId = peerId
|
||||||
|
var botName = botName
|
||||||
|
var botAddress = ""
|
||||||
|
if case let .inline(bot) = source {
|
||||||
|
isInline = true
|
||||||
|
botId = bot.id
|
||||||
|
botName = bot.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)
|
||||||
|
botAddress = bot.addressName ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
|
self.messageActionCallbackDisposable.set(((self.context.engine.messages.requestSimpleWebView(botId: botId, url: url, source: isInline ? .inline : .generic, themeParams: generateWebAppThemeParams(self.presentationData.theme))
|
||||||
|
|> afterDisposed {
|
||||||
|
updateProgress()
|
||||||
|
})
|
||||||
|
|> deliverOnMainQueue).startStrict(next: { [weak self] url in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let context = strongSelf.context
|
||||||
|
let params = WebAppParameters(source: isInline ? .inline : .simple, peerId: peerId, botId: botId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false)
|
||||||
|
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
|
||||||
|
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
||||||
|
}, requestSwitchInline: { [weak self] query, chatTypes, completion in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if let chatTypes {
|
||||||
|
let controller = strongSelf.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: strongSelf.context, filter: [.excludeRecent, .doNotSearchMessages], requestPeerType: chatTypes, hasContactSelector: false, hasCreation: false))
|
||||||
|
controller.peerSelected = { [weak self, weak controller] peer, _ in
|
||||||
|
if let strongSelf = self {
|
||||||
|
completion()
|
||||||
|
controller?.dismiss()
|
||||||
|
strongSelf.controllerInteraction?.activateSwitchInline(peer.id, "@\(botAddress) \(query)", nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strongSelf.push(controller)
|
||||||
|
} else {
|
||||||
|
strongSelf.controllerInteraction?.activateSwitchInline(peerId, "@\(botAddress) \(query)", nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, getNavigationController: { [weak self] in
|
||||||
|
return self?.effectiveNavigationController ?? context.sharedContext.mainWindow?.viewController as? NavigationController
|
||||||
|
})
|
||||||
|
controller.navigationPresentation = .flatModal
|
||||||
|
strongSelf.currentWebAppController = controller
|
||||||
|
strongSelf.push(controller)
|
||||||
|
}, error: { [weak self] error in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
|
||||||
|
})]), in: .window(.root))
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
self.messageActionCallbackDisposable.set(((self.context.engine.messages.requestWebView(peerId: peerId, botId: peerId, url: !url.isEmpty ? url : nil, payload: nil, themeParams: generateWebAppThemeParams(self.presentationData.theme), fromMenu: buttonText == "Menu", replyToMessageId: nil, threadId: self.chatLocation.threadId)
|
||||||
|
|> afterDisposed {
|
||||||
|
updateProgress()
|
||||||
|
})
|
||||||
|
|> deliverOnMainQueue).startStrict(next: { [weak self] result in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let context = strongSelf.context
|
||||||
|
let params = WebAppParameters(source: .generic, peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, forceHasSettings: false)
|
||||||
|
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
|
||||||
|
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
||||||
|
}, completion: { [weak self] in
|
||||||
|
self?.chatDisplayNode.historyNode.scrollToEndOfHistory()
|
||||||
|
}, getNavigationController: { [weak self] in
|
||||||
|
return self?.effectiveNavigationController ?? context.sharedContext.mainWindow?.viewController as? NavigationController
|
||||||
|
})
|
||||||
|
controller.navigationPresentation = .flatModal
|
||||||
|
strongSelf.currentWebAppController = controller
|
||||||
|
strongSelf.push(controller)
|
||||||
|
}, error: { [weak self] error in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
|
||||||
|
})]), in: .window(.root))
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var botPeer = EnginePeer(peer)
|
||||||
|
if case let .inline(bot) = source {
|
||||||
|
botPeer = bot
|
||||||
|
}
|
||||||
|
let _ = (ApplicationSpecificNotice.getBotGameNotice(accountManager: self.context.sharedContext.accountManager, peerId: botPeer.id)
|
||||||
|
|> deliverOnMainQueue).startStandalone(next: { [weak self] value in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if value {
|
||||||
|
openWebView()
|
||||||
|
} else {
|
||||||
|
let controller = webAppLaunchConfirmationController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: botPeer, completion: { _ in
|
||||||
|
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: botPeer.id).startStandalone()
|
||||||
|
openWebView()
|
||||||
|
}, showMore: nil)
|
||||||
|
strongSelf.present(controller, in: .window(.root))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -574,15 +574,7 @@ func updateChatPresentationInterfaceStateImpl(
|
|||||||
controller.updateVisibility()
|
controller.updateVisibility()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let currentMenuWebAppController = selfController.currentMenuWebAppController, !selfController.presentationInterfaceState.showWebView {
|
|
||||||
selfController.currentMenuWebAppController = nil
|
|
||||||
if let currentMenuWebAppController = currentMenuWebAppController as? AttachmentController {
|
|
||||||
currentMenuWebAppController.ensureUnfocused = false
|
|
||||||
}
|
|
||||||
currentMenuWebAppController.dismiss(animated: true, completion: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
selfController.presentationInterfaceStatePromise.set(selfController.presentationInterfaceState)
|
selfController.presentationInterfaceStatePromise.set(selfController.presentationInterfaceState)
|
||||||
|
|
||||||
if case .tag = selfController.chatDisplayNode.historyNode.tag {
|
if case .tag = selfController.chatDisplayNode.historyNode.tag {
|
||||||
|
|||||||
@ -3691,227 +3691,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
strongSelf.openResolved(result: .join(joinHash), sourceMessageId: nil)
|
strongSelf.openResolved(result: .join(joinHash), sourceMessageId: nil)
|
||||||
}, openWebView: { [weak self] buttonText, url, simple, source in
|
}, openWebView: { [weak self] buttonText, url, simple, source in
|
||||||
guard let strongSelf = self, let peerId = strongSelf.chatLocation.peerId, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
self.openWebApp(buttonText: buttonText, url: url, simple: simple, source: source)
|
||||||
strongSelf.chatDisplayNode.dismissInput()
|
|
||||||
|
|
||||||
let botName: String
|
|
||||||
let botAddress: String
|
|
||||||
if case let .inline(bot) = source {
|
|
||||||
botName = bot.compactDisplayTitle
|
|
||||||
botAddress = bot.addressName ?? ""
|
|
||||||
} else {
|
|
||||||
botName = EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)
|
|
||||||
botAddress = peer.addressName ?? ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if source == .generic {
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
|
||||||
return $0.updatedTitlePanelContext {
|
|
||||||
if !$0.contains(where: {
|
|
||||||
switch $0 {
|
|
||||||
case .requestInProgress:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
var updatedContexts = $0
|
|
||||||
updatedContexts.append(.requestInProgress)
|
|
||||||
return updatedContexts.sorted()
|
|
||||||
}
|
|
||||||
return $0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let updateProgress = { [weak self] in
|
|
||||||
Queue.mainQueue().async {
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
|
||||||
return $0.updatedTitlePanelContext {
|
|
||||||
if let index = $0.firstIndex(where: {
|
|
||||||
switch $0 {
|
|
||||||
case .requestInProgress:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
var updatedContexts = $0
|
|
||||||
updatedContexts.remove(at: index)
|
|
||||||
return updatedContexts
|
|
||||||
}
|
|
||||||
return $0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let openWebView = {
|
|
||||||
if source == .menu {
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(interactive: false) { state in
|
|
||||||
return state.updatedForceInputCommandsHidden(true)
|
|
||||||
// return state.updatedShowWebView(true).updatedForceInputCommandsHidden(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
let context = strongSelf.context
|
|
||||||
let params = WebAppParameters(source: .menu, peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false)
|
|
||||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
|
|
||||||
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
|
||||||
}, requestSwitchInline: { [weak self] query, chatTypes, completion in
|
|
||||||
if let strongSelf = self {
|
|
||||||
if let chatTypes {
|
|
||||||
let controller = strongSelf.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: strongSelf.context, filter: [.excludeRecent, .doNotSearchMessages], requestPeerType: chatTypes, hasContactSelector: false, hasCreation: false))
|
|
||||||
controller.peerSelected = { [weak self, weak controller] peer, _ in
|
|
||||||
if let strongSelf = self {
|
|
||||||
completion()
|
|
||||||
controller?.dismiss()
|
|
||||||
strongSelf.controllerInteraction?.activateSwitchInline(peer.id, "@\(botAddress) \(query)", nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strongSelf.push(controller)
|
|
||||||
} else {
|
|
||||||
strongSelf.controllerInteraction?.activateSwitchInline(peerId, "@\(botAddress) \(query)", nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, getInputContainerNode: { [weak self] in
|
|
||||||
if let strongSelf = self, let layout = strongSelf.validLayout, case .compact = layout.metrics.widthClass {
|
|
||||||
return (strongSelf.chatDisplayNode.getWindowInputAccessoryHeight(), strongSelf.chatDisplayNode.inputPanelContainerNode, {
|
|
||||||
return strongSelf.chatDisplayNode.textInputPanelNode?.makeAttachmentMenuTransition(accessoryPanelNode: nil)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}, completion: { [weak self] in
|
|
||||||
self?.chatDisplayNode.historyNode.scrollToEndOfHistory()
|
|
||||||
}, willDismiss: { [weak self] in
|
|
||||||
self?.interfaceInteraction?.updateShowWebView { _ in
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}, didDismiss: { [weak self] in
|
|
||||||
if let strongSelf = self {
|
|
||||||
let isFocused = strongSelf.chatDisplayNode.textInputPanelNode?.isFocused ?? false
|
|
||||||
strongSelf.chatDisplayNode.insertSubnode(strongSelf.chatDisplayNode.inputPanelContainerNode, aboveSubnode: strongSelf.chatDisplayNode.inputContextPanelContainer)
|
|
||||||
if isFocused {
|
|
||||||
strongSelf.chatDisplayNode.textInputPanelNode?.ensureFocused()
|
|
||||||
}
|
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(interactive: false) { state in
|
|
||||||
return state.updatedForceInputCommandsHidden(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, getNavigationController: { [weak self] in
|
|
||||||
return self?.effectiveNavigationController ?? context.sharedContext.mainWindow?.viewController as? NavigationController
|
|
||||||
})
|
|
||||||
controller.navigationPresentation = .flatModal
|
|
||||||
strongSelf.push(controller)
|
|
||||||
strongSelf.currentMenuWebAppController = controller
|
|
||||||
} else if simple {
|
|
||||||
var isInline = false
|
|
||||||
var botId = peerId
|
|
||||||
var botName = botName
|
|
||||||
var botAddress = ""
|
|
||||||
if case let .inline(bot) = source {
|
|
||||||
isInline = true
|
|
||||||
botId = bot.id
|
|
||||||
botName = bot.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)
|
|
||||||
botAddress = bot.addressName ?? ""
|
|
||||||
}
|
|
||||||
|
|
||||||
strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestSimpleWebView(botId: botId, url: url, source: isInline ? .inline : .generic, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme))
|
|
||||||
|> afterDisposed {
|
|
||||||
updateProgress()
|
|
||||||
})
|
|
||||||
|> deliverOnMainQueue).startStrict(next: { [weak self] url in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let context = strongSelf.context
|
|
||||||
let params = WebAppParameters(source: isInline ? .inline : .simple, peerId: peerId, botId: botId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false)
|
|
||||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
|
|
||||||
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
|
||||||
}, requestSwitchInline: { [weak self] query, chatTypes, completion in
|
|
||||||
if let strongSelf = self {
|
|
||||||
if let chatTypes {
|
|
||||||
let controller = strongSelf.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: strongSelf.context, filter: [.excludeRecent, .doNotSearchMessages], requestPeerType: chatTypes, hasContactSelector: false, hasCreation: false))
|
|
||||||
controller.peerSelected = { [weak self, weak controller] peer, _ in
|
|
||||||
if let strongSelf = self {
|
|
||||||
completion()
|
|
||||||
controller?.dismiss()
|
|
||||||
strongSelf.controllerInteraction?.activateSwitchInline(peer.id, "@\(botAddress) \(query)", nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strongSelf.push(controller)
|
|
||||||
} else {
|
|
||||||
strongSelf.controllerInteraction?.activateSwitchInline(peerId, "@\(botAddress) \(query)", nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, getNavigationController: { [weak self] in
|
|
||||||
return self?.effectiveNavigationController ?? context.sharedContext.mainWindow?.viewController as? NavigationController
|
|
||||||
})
|
|
||||||
controller.navigationPresentation = .flatModal
|
|
||||||
strongSelf.currentWebAppController = controller
|
|
||||||
strongSelf.push(controller)
|
|
||||||
}, error: { [weak self] error in
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
|
|
||||||
})]), in: .window(.root))
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestWebView(peerId: peerId, botId: peerId, url: !url.isEmpty ? url : nil, payload: nil, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), fromMenu: buttonText == "Menu", replyToMessageId: nil, threadId: strongSelf.chatLocation.threadId)
|
|
||||||
|> afterDisposed {
|
|
||||||
updateProgress()
|
|
||||||
})
|
|
||||||
|> deliverOnMainQueue).startStrict(next: { [weak self] result in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let context = strongSelf.context
|
|
||||||
let params = WebAppParameters(source: .generic, peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, forceHasSettings: false)
|
|
||||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
|
|
||||||
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
|
||||||
}, completion: { [weak self] in
|
|
||||||
self?.chatDisplayNode.historyNode.scrollToEndOfHistory()
|
|
||||||
}, getNavigationController: { [weak self] in
|
|
||||||
return self?.effectiveNavigationController ?? context.sharedContext.mainWindow?.viewController as? NavigationController
|
|
||||||
})
|
|
||||||
controller.navigationPresentation = .flatModal
|
|
||||||
strongSelf.currentWebAppController = controller
|
|
||||||
strongSelf.push(controller)
|
|
||||||
}, error: { [weak self] error in
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
|
|
||||||
})]), in: .window(.root))
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var botPeer = EnginePeer(peer)
|
|
||||||
if case let .inline(bot) = source {
|
|
||||||
botPeer = bot
|
|
||||||
}
|
|
||||||
let _ = (ApplicationSpecificNotice.getBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: botPeer.id)
|
|
||||||
|> deliverOnMainQueue).startStandalone(next: { value in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if value {
|
|
||||||
openWebView()
|
|
||||||
} else {
|
|
||||||
let controller = webAppLaunchConfirmationController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: botPeer, completion: { _ in
|
|
||||||
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: botPeer.id).startStandalone()
|
|
||||||
openWebView()
|
|
||||||
}, showMore: nil)
|
|
||||||
strongSelf.present(controller, in: .window(.root))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, activateAdAction: { [weak self] messageId, progress in
|
}, activateAdAction: { [weak self] messageId, progress in
|
||||||
guard let self, let message = self.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId), let adAttribute = message.adAttribute else {
|
guard let self, let message = self.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId), let adAttribute = message.adAttribute else {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -88,6 +88,15 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
|||||||
|
|
||||||
private var applicationInFocusDisposable: Disposable?
|
private var applicationInFocusDisposable: Disposable?
|
||||||
private var storyUploadEventsDisposable: Disposable?
|
private var storyUploadEventsDisposable: Disposable?
|
||||||
|
|
||||||
|
override public var minimizedContainer: MinimizedContainer? {
|
||||||
|
didSet {
|
||||||
|
self.minimizedContainer?.navigationController = self
|
||||||
|
self.minimizedContainerUpdated(self.minimizedContainer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var minimizedContainerUpdated: (MinimizedContainer?) -> Void = { _ in }
|
||||||
|
|
||||||
public init(context: AccountContext) {
|
public init(context: AccountContext) {
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|||||||
@ -1771,9 +1771,9 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
fileprivate let moreButtonNode: MoreButtonNode
|
fileprivate let moreButtonNode: MoreButtonNode
|
||||||
|
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let source: WebAppParameters.Source
|
public let source: WebAppParameters.Source
|
||||||
private let peerId: PeerId
|
private let peerId: PeerId
|
||||||
private let botId: PeerId
|
public let botId: PeerId
|
||||||
private let botName: String
|
private let botName: String
|
||||||
private let url: String?
|
private let url: String?
|
||||||
private let queryId: Int64?
|
private let queryId: Int64?
|
||||||
@ -2094,13 +2094,17 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func shouldDismissImmediately() -> Bool {
|
public override var isMinimized: Bool {
|
||||||
if self.controllerNode.needDismissConfirmation {
|
didSet {
|
||||||
return false
|
if self.isMinimized != oldValue && self.isMinimized {
|
||||||
} else {
|
self.controllerNode.webView?.hideScrollIndicators()
|
||||||
return true
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func shouldDismissImmediately() -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class WebAppPickerContext: AttachmentMediaPickerContext {
|
final class WebAppPickerContext: AttachmentMediaPickerContext {
|
||||||
@ -2182,7 +2186,6 @@ public func standaloneWebAppController(
|
|||||||
let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: .peer(id: params.peerId), buttons: [.standalone], initialButton: .standalone, fromMenu: params.source == .menu, hasTextInput: false, makeEntityInputView: {
|
let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: .peer(id: params.peerId), buttons: [.standalone], initialButton: .standalone, fromMenu: params.source == .menu, hasTextInput: false, makeEntityInputView: {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
// controller.getInputContainerNode = getInputContainerNode
|
|
||||||
controller.requestController = { _, present in
|
controller.requestController = { _, present in
|
||||||
let webAppController = WebAppController(context: context, updatedPresentationData: updatedPresentationData, params: params, replyToMessageId: nil, threadId: threadId)
|
let webAppController = WebAppController(context: context, updatedPresentationData: updatedPresentationData, params: params, replyToMessageId: nil, threadId: threadId)
|
||||||
webAppController.openUrl = openUrl
|
webAppController.openUrl = openUrl
|
||||||
|
|||||||
@ -194,6 +194,22 @@ final class WebAppWebView: WKWebView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hideScrollIndicators() {
|
||||||
|
var hiddenViews: [UIView] = []
|
||||||
|
for view in self.scrollView.subviews.reversed() {
|
||||||
|
let minSize = min(view.frame.width, view.frame.height)
|
||||||
|
if minSize < 4.0 {
|
||||||
|
view.isHidden = true
|
||||||
|
hiddenViews.append(view)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Queue.mainQueue().after(2.0) {
|
||||||
|
for view in hiddenViews {
|
||||||
|
view.isHidden = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func sendEvent(name: String, data: String?) {
|
func sendEvent(name: String, data: String?) {
|
||||||
let script = "window.TelegramGameProxy.receiveEvent(\"\(name)\", \(data ?? "null"))"
|
let script = "window.TelegramGameProxy.receiveEvent(\"\(name)\", \(data ?? "null"))"
|
||||||
self.evaluateJavaScript(script, completionHandler: { _, _ in
|
self.evaluateJavaScript(script, completionHandler: { _, _ in
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user