mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-02 00:17:02 +00:00
Support standalone modal controllers
This commit is contained in:
parent
b01c3d9b09
commit
37f28503aa
@ -371,7 +371,11 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
}
|
||||
switch transitionType {
|
||||
case .push:
|
||||
strongSelf.syncKeyboard(leftEdge: topFrame.minX - bottomFrame.width, transition: transition)
|
||||
if let _ = strongSelf.state.transition, let top = strongSelf.state.top, viewTreeContainsFirstResponder(view: top.value.view) {
|
||||
strongSelf.syncKeyboard(leftEdge: topFrame.minX, transition: transition)
|
||||
} else {
|
||||
strongSelf.syncKeyboard(leftEdge: topFrame.minX - bottomFrame.width, transition: transition)
|
||||
}
|
||||
case .pop:
|
||||
strongSelf.syncKeyboard(leftEdge: topFrame.minX, transition: transition)
|
||||
}
|
||||
|
@ -537,6 +537,11 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
for i in (0 ..< navigationLayout.modal.count).reversed() {
|
||||
let modalContainer = self.modalContainers[i]
|
||||
|
||||
var isStandaloneModal = false
|
||||
if case .standaloneModal = modalContainer.container.controllers.first?.navigationPresentation {
|
||||
isStandaloneModal = true
|
||||
}
|
||||
|
||||
let containerTransition: ContainedViewLayoutTransition
|
||||
if modalContainer.supernode == nil {
|
||||
containerTransition = .immediate
|
||||
@ -572,7 +577,9 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
}
|
||||
|
||||
if modalContainer.supernode != nil {
|
||||
visibleModalCount += 1
|
||||
if !isStandaloneModal || visibleModalCount != 0 {
|
||||
visibleModalCount += 1
|
||||
}
|
||||
if previousModalContainer == nil {
|
||||
topModalDismissProgress = modalContainer.dismissProgress
|
||||
if case .compact = layout.metrics.widthClass {
|
||||
@ -587,6 +594,14 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
modalContainer.canHaveKeyboardFocus = false
|
||||
}
|
||||
previousModalContainer = modalContainer
|
||||
if isStandaloneModal {
|
||||
switch modalContainer.container.statusBarStyle {
|
||||
case .Hide:
|
||||
statusBarHidden = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ enum RootNavigationLayout {
|
||||
|
||||
struct ModalContainerLayout {
|
||||
var controllers: [ViewController]
|
||||
var isStandalone: Bool
|
||||
}
|
||||
|
||||
struct NavigationLayout {
|
||||
@ -23,6 +24,7 @@ func makeNavigationLayout(mode: NavigationControllerMode, layout: ContainerViewL
|
||||
for controller in controllers {
|
||||
let requiresModal: Bool
|
||||
var beginsModal: Bool = false
|
||||
var isStandalone: Bool = false
|
||||
switch controller.navigationPresentation {
|
||||
case .default:
|
||||
requiresModal = false
|
||||
@ -31,6 +33,10 @@ func makeNavigationLayout(mode: NavigationControllerMode, layout: ContainerViewL
|
||||
case .modal:
|
||||
requiresModal = true
|
||||
beginsModal = true
|
||||
case .standaloneModal:
|
||||
requiresModal = true
|
||||
beginsModal = true
|
||||
isStandalone = true
|
||||
case .modalInLargeLayout:
|
||||
switch layout.metrics.widthClass {
|
||||
case .compact:
|
||||
@ -40,13 +46,17 @@ func makeNavigationLayout(mode: NavigationControllerMode, layout: ContainerViewL
|
||||
}
|
||||
}
|
||||
if requiresModal {
|
||||
if beginsModal || modalStack.isEmpty {
|
||||
modalStack.append(ModalContainerLayout(controllers: [controller]))
|
||||
if beginsModal || modalStack.isEmpty || modalStack[modalStack.count - 1].isStandalone {
|
||||
modalStack.append(ModalContainerLayout(controllers: [controller], isStandalone: isStandalone))
|
||||
} else {
|
||||
modalStack[modalStack.count - 1].controllers.append(controller)
|
||||
}
|
||||
} else if !modalStack.isEmpty {
|
||||
modalStack[modalStack.count - 1].controllers.append(controller)
|
||||
if modalStack[modalStack.count - 1].isStandalone {
|
||||
modalStack.append(ModalContainerLayout(controllers: [controller], isStandalone: isStandalone))
|
||||
} else {
|
||||
modalStack[modalStack.count - 1].controllers.append(controller)
|
||||
}
|
||||
} else {
|
||||
rootControllers.append(controller)
|
||||
}
|
||||
|
@ -289,6 +289,11 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
|
||||
|
||||
self.validLayout = layout
|
||||
|
||||
var isStandaloneModal = false
|
||||
if case .standaloneModal = controllers.first?.navigationPresentation {
|
||||
isStandaloneModal = true
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.dim, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||
self.ignoreScrolling = true
|
||||
self.scrollNode.view.isScrollEnabled = (layout.inputHeight == nil || layout.inputHeight == 0.0) && self.isInteractiveDimissEnabled
|
||||
@ -302,6 +307,8 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
|
||||
}
|
||||
self.ignoreScrolling = false
|
||||
|
||||
self.scrollNode.view.isScrollEnabled = !isStandaloneModal
|
||||
|
||||
let containerLayout: ContainerViewLayout
|
||||
let containerFrame: CGRect
|
||||
let containerScale: CGFloat
|
||||
@ -310,14 +317,28 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
|
||||
self.panRecognizer?.isEnabled = true
|
||||
self.dim.backgroundColor = UIColor(white: 0.0, alpha: 0.25)
|
||||
self.container.clipsToBounds = true
|
||||
self.container.cornerRadius = 10.0
|
||||
if #available(iOS 11.0, *) {
|
||||
self.container.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
|
||||
if isStandaloneModal {
|
||||
self.container.cornerRadius = 0.0
|
||||
} else {
|
||||
self.container.cornerRadius = 10.0
|
||||
}
|
||||
|
||||
var topInset: CGFloat = 10.0
|
||||
if let statusBarHeight = layout.statusBarHeight {
|
||||
topInset += statusBarHeight
|
||||
if #available(iOS 11.0, *) {
|
||||
if layout.safeInsets.bottom.isZero {
|
||||
self.container.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
|
||||
} else {
|
||||
self.container.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
|
||||
}
|
||||
}
|
||||
|
||||
var topInset: CGFloat
|
||||
if isStandaloneModal {
|
||||
topInset = 0.0
|
||||
} else {
|
||||
topInset = 10.0
|
||||
if let statusBarHeight = layout.statusBarHeight {
|
||||
topInset += statusBarHeight
|
||||
}
|
||||
}
|
||||
|
||||
containerLayout = ContainerViewLayout(size: CGSize(width: layout.size.width, height: layout.size.height - topInset), metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(top: 0.0, left: layout.intrinsicInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.intrinsicInsets.right), safeInsets: UIEdgeInsets(top: 0.0, left: layout.safeInsets.left, bottom: layout.safeInsets.bottom, right: layout.safeInsets.right), statusBarHeight: nil, inputHeight: layout.inputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver)
|
||||
@ -358,8 +379,11 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
|
||||
}
|
||||
|
||||
func animateIn(transition: ContainedViewLayoutTransition) {
|
||||
transition.updateAlpha(node: self.dim, alpha: 1.0)
|
||||
transition.animatePositionAdditive(node: self.container, offset: CGPoint(x: 0.0, y: self.bounds.height + self.container.bounds.height / 2.0 - (self.container.position.y - self.bounds.height)))
|
||||
if case .standaloneModal = self.container.controllers.first?.navigationPresentation {
|
||||
} else {
|
||||
transition.updateAlpha(node: self.dim, alpha: 1.0)
|
||||
transition.animatePositionAdditive(node: self.container, offset: CGPoint(x: 0.0, y: self.bounds.height + self.container.bounds.height / 2.0 - (self.container.position.y - self.bounds.height)))
|
||||
}
|
||||
}
|
||||
|
||||
func dismiss(transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) -> ContainedViewLayoutTransition {
|
||||
@ -367,15 +391,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
|
||||
controller.viewWillDisappear(transition.isAnimated)
|
||||
}
|
||||
|
||||
if transition.isAnimated {
|
||||
let alphaTransition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||
let positionTransition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||
alphaTransition.updateAlpha(node: self.dim, alpha: 0.0, beginWithCurrentState: true)
|
||||
positionTransition.updatePosition(node: self.container, position: CGPoint(x: self.container.position.x, y: self.bounds.height + self.container.bounds.height / 2.0 + self.bounds.height), beginWithCurrentState: true, completion: { [weak self] _ in
|
||||
completion()
|
||||
})
|
||||
return positionTransition
|
||||
} else {
|
||||
if case .standaloneModal = self.container.controllers.first?.navigationPresentation {
|
||||
for controller in self.container.controllers {
|
||||
controller.setIgnoreAppearanceMethodInvocations(true)
|
||||
controller.displayNode.removeFromSupernode()
|
||||
@ -384,6 +400,25 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
|
||||
}
|
||||
completion()
|
||||
return transition
|
||||
} else {
|
||||
if transition.isAnimated {
|
||||
let alphaTransition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||
let positionTransition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||
alphaTransition.updateAlpha(node: self.dim, alpha: 0.0, beginWithCurrentState: true)
|
||||
positionTransition.updatePosition(node: self.container, position: CGPoint(x: self.container.position.x, y: self.bounds.height + self.container.bounds.height / 2.0 + self.bounds.height), beginWithCurrentState: true, completion: { [weak self] _ in
|
||||
completion()
|
||||
})
|
||||
return positionTransition
|
||||
} else {
|
||||
for controller in self.container.controllers {
|
||||
controller.setIgnoreAppearanceMethodInvocations(true)
|
||||
controller.displayNode.removeFromSupernode()
|
||||
controller.setIgnoreAppearanceMethodInvocations(false)
|
||||
controller.viewDidDisappear(transition.isAnimated)
|
||||
}
|
||||
completion()
|
||||
return transition
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,7 @@ public enum ViewControllerNavigationPresentation {
|
||||
case `default`
|
||||
case master
|
||||
case modal
|
||||
case standaloneModal
|
||||
case modalInLargeLayout
|
||||
}
|
||||
|
||||
@ -439,7 +440,11 @@ public enum ViewControllerNavigationPresentation {
|
||||
|
||||
override open func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||
if let navigationController = self.navigationController as? NavigationController {
|
||||
navigationController.filterController(self, animated: flag)
|
||||
var animated = flag
|
||||
if case .standaloneModal = self.navigationPresentation {
|
||||
animated = false
|
||||
}
|
||||
navigationController.filterController(self, animated: animated)
|
||||
} else {
|
||||
assertionFailure()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user