mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Upgraded navigation
This commit is contained in:
parent
99c6240172
commit
538e3dbe70
@ -432,7 +432,7 @@ public protocol SharedAccountContext: class {
|
|||||||
func resolveUrl(account: Account, url: String) -> Signal<ResolvedUrl, NoError>
|
func resolveUrl(account: Account, url: String) -> Signal<ResolvedUrl, NoError>
|
||||||
func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void)
|
func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void)
|
||||||
func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)
|
func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)
|
||||||
func openAddPersonContact(context: AccountContext, peerId: PeerId, present: @escaping (ViewController, Any?) -> Void)
|
func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void)
|
||||||
func presentContactsWarningSuppression(context: AccountContext, present: (ViewController, Any?) -> Void)
|
func presentContactsWarningSuppression(context: AccountContext, present: (ViewController, Any?) -> Void)
|
||||||
|
|
||||||
func navigateToCurrentCall()
|
func navigateToCurrentCall()
|
||||||
|
@ -194,6 +194,7 @@ public final class CallListController: ViewController {
|
|||||||
|
|
||||||
@objc func callPressed() {
|
@objc func callPressed() {
|
||||||
let controller = self.context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(context: self.context, title: { $0.Calls_NewCall }))
|
let controller = self.context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(context: self.context, title: { $0.Calls_NewCall }))
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
self.createActionDisposable.set((controller.result
|
self.createActionDisposable.set((controller.result
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { [weak controller, weak self] peer in
|
|> deliverOnMainQueue).start(next: { [weak controller, weak self] peer in
|
||||||
|
@ -84,9 +84,13 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, source: ChatC
|
|||||||
if !isSavedMessages, let peer = peer as? TelegramUser {
|
if !isSavedMessages, let peer = peer as? TelegramUser {
|
||||||
if !transaction.isPeerContact(peerId: peer.id) {
|
if !transaction.isPeerContact(peerId: peer.id) {
|
||||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToContacts, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToContacts, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||||
context.sharedContext.openAddPersonContact(context: context, peerId: peerId, present: { controller, arguments in
|
context.sharedContext.openAddPersonContact(context: context, peerId: peerId, pushController: { controller in
|
||||||
|
if let navigationController = chatListController?.navigationController as? NavigationController {
|
||||||
|
navigationController.pushViewController(controller)
|
||||||
|
}
|
||||||
|
}, present: { c, a in
|
||||||
if let chatListController = chatListController {
|
if let chatListController = chatListController {
|
||||||
chatListController.present(controller, in: .window(.root), with: arguments)
|
chatListController.present(c, in: .window(.root), with: a)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
f(.default)
|
f(.default)
|
||||||
@ -224,6 +228,10 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, source: ChatC
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let item = items.last, case .separator = item {
|
||||||
|
items.removeLast()
|
||||||
|
}
|
||||||
|
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1020,8 +1020,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
|||||||
|
|
||||||
@objc private func composePressed() {
|
@objc private func composePressed() {
|
||||||
let controller = self.context.sharedContext.makeComposeController(context: self.context)
|
let controller = self.context.sharedContext.makeComposeController(context: self.context)
|
||||||
self.present(controller, in: .window(.root))
|
(self.navigationController as? NavigationController)?.pushViewController(controller)
|
||||||
//(self.navigationController as? NavigationController)?.replaceAllButRootController(self.context.sharedContext.makeComposeController(context: self.context), animated: true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
|
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
|
||||||
|
@ -387,6 +387,7 @@ public func createPollController(context: AccountContext, peerId: PeerId, comple
|
|||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(context: context, state: signal)
|
let controller = ItemListController(context: context, state: signal)
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
presentControllerImpl = { [weak controller] c, a in
|
presentControllerImpl = { [weak controller] c, a in
|
||||||
controller?.present(c, in: .window(.root), with: a)
|
controller?.present(c, in: .window(.root), with: a)
|
||||||
}
|
}
|
||||||
|
@ -523,7 +523,7 @@ public class ContactsController: ViewController {
|
|||||||
switch status {
|
switch status {
|
||||||
case .allowed:
|
case .allowed:
|
||||||
let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: "+")]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [])
|
let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: "+")]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [])
|
||||||
strongSelf.present(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
(strongSelf.navigationController as? NavigationController)?.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -534,7 +534,7 @@ public class ContactsController: ViewController {
|
|||||||
} else {
|
} else {
|
||||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil))
|
(strongSelf.navigationController as? NavigationController)?.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil))
|
||||||
}
|
}
|
||||||
}), completed: nil, cancelled: nil), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}), completed: nil, cancelled: nil))
|
||||||
case .notDetermined:
|
case .notDetermined:
|
||||||
DeviceAccess.authorizeAccess(to: .contacts)
|
DeviceAccess.authorizeAccess(to: .contacts)
|
||||||
default:
|
default:
|
||||||
|
@ -38,6 +38,8 @@ public class InviteContactsController: ViewController, MFMessageComposeViewContr
|
|||||||
|
|
||||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||||
|
|
||||||
|
self.navigationPresentation = .modal
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||||
|
|
||||||
self.title = self.presentationData.strings.Contacts_InviteFriends
|
self.title = self.presentationData.strings.Contacts_InviteFriends
|
||||||
|
@ -575,6 +575,7 @@ public extension ContainedViewLayoutTransition {
|
|||||||
func updateSublayerTransformScale(node: ASDisplayNode, scale: CGFloat, completion: ((Bool) -> Void)? = nil) {
|
func updateSublayerTransformScale(node: ASDisplayNode, scale: CGFloat, completion: ((Bool) -> Void)? = nil) {
|
||||||
if !node.isNodeLoaded {
|
if !node.isNodeLoaded {
|
||||||
node.subnodeTransform = CATransform3DMakeScale(scale, scale, 1.0)
|
node.subnodeTransform = CATransform3DMakeScale(scale, scale, 1.0)
|
||||||
|
completion?(true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let t = node.layer.sublayerTransform
|
let t = node.layer.sublayerTransform
|
||||||
@ -606,12 +607,13 @@ public extension ContainedViewLayoutTransition {
|
|||||||
func updateSublayerTransformScaleAndOffset(node: ASDisplayNode, scale: CGFloat, offset: CGPoint, beginWithCurrentState: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
func updateSublayerTransformScaleAndOffset(node: ASDisplayNode, scale: CGFloat, offset: CGPoint, beginWithCurrentState: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||||
if !node.isNodeLoaded {
|
if !node.isNodeLoaded {
|
||||||
node.subnodeTransform = CATransform3DMakeScale(scale, scale, 1.0)
|
node.subnodeTransform = CATransform3DMakeScale(scale, scale, 1.0)
|
||||||
|
completion?(true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let t = node.layer.sublayerTransform
|
let t = node.layer.sublayerTransform
|
||||||
let currentScale = sqrt((t.m11 * t.m11) + (t.m12 * t.m12) + (t.m13 * t.m13))
|
let currentScale = sqrt((t.m11 * t.m11) + (t.m12 * t.m12) + (t.m13 * t.m13))
|
||||||
let currentOffset = CGPoint(x: t.m41, y: t.m42)
|
let currentOffset = CGPoint(x: t.m41 / currentScale, y: t.m42 / currentScale)
|
||||||
if currentScale.isEqual(to: scale) && currentOffset == offset {
|
if abs(currentScale - scale) <= CGFloat.ulpOfOne && abs(currentOffset.x - offset.x) <= CGFloat.ulpOfOne && abs(currentOffset.y - offset.y) <= CGFloat.ulpOfOne {
|
||||||
if let completion = completion {
|
if let completion = completion {
|
||||||
completion(true)
|
completion(true)
|
||||||
}
|
}
|
||||||
@ -647,6 +649,7 @@ public extension ContainedViewLayoutTransition {
|
|||||||
func updateSublayerTransformScale(node: ASDisplayNode, scale: CGPoint, completion: ((Bool) -> Void)? = nil) {
|
func updateSublayerTransformScale(node: ASDisplayNode, scale: CGPoint, completion: ((Bool) -> Void)? = nil) {
|
||||||
if !node.isNodeLoaded {
|
if !node.isNodeLoaded {
|
||||||
node.subnodeTransform = CATransform3DMakeScale(scale.x, scale.y, 1.0)
|
node.subnodeTransform = CATransform3DMakeScale(scale.x, scale.y, 1.0)
|
||||||
|
completion?(true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let t = node.layer.sublayerTransform
|
let t = node.layer.sublayerTransform
|
||||||
@ -713,6 +716,7 @@ public extension ContainedViewLayoutTransition {
|
|||||||
func updateTransformScale(node: ASDisplayNode, scale: CGPoint, completion: ((Bool) -> Void)? = nil) {
|
func updateTransformScale(node: ASDisplayNode, scale: CGPoint, completion: ((Bool) -> Void)? = nil) {
|
||||||
if !node.isNodeLoaded {
|
if !node.isNodeLoaded {
|
||||||
node.subnodeTransform = CATransform3DMakeScale(scale.x, scale.y, 1.0)
|
node.subnodeTransform = CATransform3DMakeScale(scale.x, scale.y, 1.0)
|
||||||
|
completion?(true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let t = node.layer.transform
|
let t = node.layer.transform
|
||||||
|
@ -759,7 +759,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func lowestSectionNode() -> ASDisplayNode? {
|
public func lowestSectionNode() -> ASDisplayNode? {
|
||||||
var lowestHeaderNode: ASDisplayNode?
|
var lowestHeaderNode: ASDisplayNode?
|
||||||
var lowestHeaderNodeIndex: Int?
|
var lowestHeaderNodeIndex: Int?
|
||||||
for (_, headerNode) in self.sectionNodes {
|
for (_, headerNode) in self.sectionNodes {
|
||||||
|
377
submodules/Display/Display/Navigation/NavigationContainer.swift
Normal file
377
submodules/Display/Display/Navigation/NavigationContainer.swift
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
|
final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||||
|
private final class Child {
|
||||||
|
let value: ViewController
|
||||||
|
var layout: ContainerViewLayout
|
||||||
|
|
||||||
|
init(value: ViewController, layout: ContainerViewLayout) {
|
||||||
|
self.value = value
|
||||||
|
self.layout = layout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class PendingChild {
|
||||||
|
enum TransitionType {
|
||||||
|
case push
|
||||||
|
case pop
|
||||||
|
}
|
||||||
|
|
||||||
|
let value: Child
|
||||||
|
let transitionType: TransitionType
|
||||||
|
let transition: ContainedViewLayoutTransition
|
||||||
|
let disposable: MetaDisposable = MetaDisposable()
|
||||||
|
var isReady: Bool = false
|
||||||
|
|
||||||
|
init(value: Child, transitionType: TransitionType, transition: ContainedViewLayoutTransition, update: @escaping (PendingChild) -> Void) {
|
||||||
|
self.value = value
|
||||||
|
self.transitionType = transitionType
|
||||||
|
self.transition = transition
|
||||||
|
var localIsReady: Bool?
|
||||||
|
self.disposable.set((value.value.ready.get()
|
||||||
|
|> filter { $0 }
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] _ in
|
||||||
|
if localIsReady == nil {
|
||||||
|
localIsReady = true
|
||||||
|
} else if let strongSelf = self {
|
||||||
|
update(strongSelf)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
if let localIsReady = localIsReady {
|
||||||
|
self.isReady = true
|
||||||
|
} else {
|
||||||
|
localIsReady = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.disposable.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class TopTransition {
|
||||||
|
let previous: Child
|
||||||
|
let coordinator: NavigationTransitionCoordinator
|
||||||
|
|
||||||
|
init(previous: Child, coordinator: NavigationTransitionCoordinator) {
|
||||||
|
self.previous = previous
|
||||||
|
self.coordinator = coordinator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct State {
|
||||||
|
var layout: ContainerViewLayout?
|
||||||
|
var canBeClosed: Bool?
|
||||||
|
var top: Child?
|
||||||
|
var transition: TopTransition?
|
||||||
|
var pending: PendingChild?
|
||||||
|
}
|
||||||
|
|
||||||
|
private(set) var controllers: [ViewController] = []
|
||||||
|
private var state: State = State(layout: nil, canBeClosed: nil, top: nil, transition: nil, pending: nil)
|
||||||
|
|
||||||
|
private(set) var isReady: Bool = false
|
||||||
|
var isReadyUpdated: (() -> Void)?
|
||||||
|
var controllerRemoved: (ViewController) -> Void
|
||||||
|
var keyboardManager: KeyboardManager? {
|
||||||
|
didSet {
|
||||||
|
if self.keyboardManager !== oldValue {
|
||||||
|
self.keyboardManager?.surfaces = self.state.top?.value.view.flatMap({ [KeyboardSurface(host: $0)] }) ?? []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(controllerRemoved: @escaping (ViewController) -> Void) {
|
||||||
|
self.controllerRemoved = controllerRemoved
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func didLoad() {
|
||||||
|
super.didLoad()
|
||||||
|
|
||||||
|
let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
||||||
|
panRecognizer.delegate = self
|
||||||
|
panRecognizer.delaysTouchesBegan = false
|
||||||
|
panRecognizer.cancelsTouchesInView = true
|
||||||
|
self.view.addGestureRecognizer(panRecognizer)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
|
if let _ = otherGestureRecognizer as? UIPanGestureRecognizer {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func panGesture(_ recognizer: UIPanGestureRecognizer) {
|
||||||
|
switch recognizer.state {
|
||||||
|
case .began:
|
||||||
|
guard let layout = self.state.layout else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard self.state.transition == nil else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let beginGesture = self.controllers.count > 1
|
||||||
|
|
||||||
|
if beginGesture {
|
||||||
|
let topController = self.controllers[self.controllers.count - 1]
|
||||||
|
let bottomController = self.controllers[self.controllers.count - 2]
|
||||||
|
|
||||||
|
if let topController = topController as? ViewController {
|
||||||
|
if !topController.attemptNavigation({ [weak self] in
|
||||||
|
//let _ = self?.popViewController(animated: true)
|
||||||
|
}) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
topController.viewWillDisappear(true)
|
||||||
|
let topView = topController.view!
|
||||||
|
bottomController.containerLayoutUpdated(layout, transition: .immediate)
|
||||||
|
bottomController.viewWillAppear(true)
|
||||||
|
let bottomView = bottomController.view!
|
||||||
|
|
||||||
|
let navigationTransitionCoordinator = NavigationTransitionCoordinator(transition: .Pop, container: self.view, topView: topView, topNavigationBar: topController.navigationBar, bottomView: bottomView, bottomNavigationBar: bottomController.navigationBar, didUpdateProgress: { [weak self] progress, transition in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.keyboardManager?.surfaces = strongSelf.state.top?.value.view.flatMap({ [KeyboardSurface(host: $0)] }) ?? []
|
||||||
|
/*for i in 0 ..< strongSelf._viewControllers.count {
|
||||||
|
if let controller = strongSelf._viewControllers[i].controller as? ViewController {
|
||||||
|
if i < strongSelf._viewControllers.count - 1 {
|
||||||
|
controller.updateNavigationCustomData((strongSelf.viewControllers[i + 1] as? ViewController)?.customData, progress: 1.0 - progress, transition: transition)
|
||||||
|
} else {
|
||||||
|
controller.updateNavigationCustomData(nil, progress: 1.0 - progress, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
})
|
||||||
|
bottomController.displayNode.recursivelyEnsureDisplaySynchronously(true)
|
||||||
|
self.state.transition = TopTransition(previous: Child(value: bottomController, layout: layout), coordinator: navigationTransitionCoordinator)
|
||||||
|
}
|
||||||
|
case .changed:
|
||||||
|
if let navigationTransitionCoordinator = self.state.transition?.coordinator, !navigationTransitionCoordinator.animatingCompletion {
|
||||||
|
let translation = recognizer.translation(in: self.view).x
|
||||||
|
let progress = max(0.0, min(1.0, translation / self.view.frame.width))
|
||||||
|
navigationTransitionCoordinator.progress = progress
|
||||||
|
}
|
||||||
|
case .ended, .cancelled:
|
||||||
|
if let navigationTransitionCoordinator = self.state.transition?.coordinator, !navigationTransitionCoordinator.animatingCompletion {
|
||||||
|
let velocity = recognizer.velocity(in: self.view).x
|
||||||
|
|
||||||
|
if velocity > 1000 || navigationTransitionCoordinator.progress > 0.2 {
|
||||||
|
//(self.view as! NavigationControllerView).inTransition = true
|
||||||
|
navigationTransitionCoordinator.animateCompletion(velocity, completion: { [weak self] in
|
||||||
|
guard let strongSelf = self, let layout = strongSelf.state.layout, let transition = strongSelf.state.transition, let top = strongSelf.state.top else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//(self.view as! NavigationControllerView).inTransition = false
|
||||||
|
|
||||||
|
let topController = top.value
|
||||||
|
let bottomController = transition.previous.value
|
||||||
|
strongSelf.keyboardManager?.updateInteractiveInputOffset(layout.size.height, transition: .immediate, completion: {})
|
||||||
|
topController.view.endEditing(true)
|
||||||
|
|
||||||
|
strongSelf.state.transition = nil
|
||||||
|
|
||||||
|
strongSelf.controllerRemoved(top.value)
|
||||||
|
|
||||||
|
//topController.viewDidDisappear(true)
|
||||||
|
//bottomController.viewDidAppear(true)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
/*if self.viewControllers.count >= 2 {
|
||||||
|
let topController = self.viewControllers[self.viewControllers.count - 1] as UIViewController
|
||||||
|
let bottomController = self.viewControllers[self.viewControllers.count - 2] as UIViewController
|
||||||
|
|
||||||
|
topController.viewWillAppear(true)
|
||||||
|
bottomController.viewWillDisappear(true)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//(self.view as! NavigationControllerView).inTransition = true
|
||||||
|
navigationTransitionCoordinator.animateCancel({ [weak self] in
|
||||||
|
guard let strongSelf = self, let top = strongSelf.state.top, let transition = strongSelf.state.transition else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//(self.view as! NavigationControllerView).inTransition = false
|
||||||
|
strongSelf.state.transition = nil
|
||||||
|
|
||||||
|
top.value.viewDidAppear(true)
|
||||||
|
transition.previous.value.viewDidDisappear(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(layout: ContainerViewLayout, canBeClosed: Bool, controllers: [ViewController], transition: ContainedViewLayoutTransition) {
|
||||||
|
let previousControllers = self.controllers
|
||||||
|
self.controllers = controllers
|
||||||
|
|
||||||
|
for i in 0 ..< controllers.count {
|
||||||
|
if i == 0 {
|
||||||
|
if canBeClosed {
|
||||||
|
controllers[i].navigationBar?.previousItem = .close
|
||||||
|
} else {
|
||||||
|
controllers[i].navigationBar?.previousItem = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
controllers[i].navigationBar?.previousItem = .item(controllers[i - 1].navigationItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state.layout = layout
|
||||||
|
self.state.canBeClosed = canBeClosed
|
||||||
|
|
||||||
|
if controllers.last !== self.state.top?.value {
|
||||||
|
if controllers.last !== self.state.pending?.value.value {
|
||||||
|
self.state.pending = nil
|
||||||
|
if let last = controllers.last {
|
||||||
|
let transitionType: PendingChild.TransitionType
|
||||||
|
if !previousControllers.contains(where: { $0 === last }) {
|
||||||
|
transitionType = .push
|
||||||
|
} else {
|
||||||
|
transitionType = .pop
|
||||||
|
}
|
||||||
|
self.state.pending = PendingChild(value: self.makeChild(layout: layout, value: last), transitionType: transitionType, transition: transition, update: { [weak self] pendingChild in
|
||||||
|
self?.pendingChildIsReady(pendingChild)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let pending = self.state.pending {
|
||||||
|
if pending.isReady {
|
||||||
|
self.state.pending = nil
|
||||||
|
let previous = self.state.top
|
||||||
|
self.state.top = pending.value
|
||||||
|
self.topTransition(from: previous, to: pending.value, transitionType: pending.transitionType, layout: layout, transition: pending.transition)
|
||||||
|
if !self.isReady {
|
||||||
|
self.isReady = true
|
||||||
|
self.isReadyUpdated?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if controllers.isEmpty && self.state.top != nil {
|
||||||
|
let previous = self.state.top
|
||||||
|
self.state.top = nil
|
||||||
|
self.topTransition(from: previous, to: nil, transitionType: .pop, layout: layout, transition: .immediate)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let top = self.state.top {
|
||||||
|
self.applyLayout(layout: layout, to: top, transition: transition)
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.state.transition == nil {
|
||||||
|
self.keyboardManager?.surfaces = self.state.top?.value.view.flatMap({ [KeyboardSurface(host: $0)] }) ?? []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func topTransition(from fromValue: Child?, to toValue: Child?, transitionType: PendingChild.TransitionType, layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
|
if case .animated = transition, let fromValue = fromValue, let toValue = toValue {
|
||||||
|
self.keyboardManager?.surfaces = fromValue.value.view.flatMap({ [KeyboardSurface(host: $0)] }) ?? []
|
||||||
|
if let currentTransition = self.state.transition {
|
||||||
|
assertionFailure()
|
||||||
|
}
|
||||||
|
|
||||||
|
fromValue.value.viewWillDisappear(true)
|
||||||
|
toValue.value.viewWillAppear(true)
|
||||||
|
toValue.value.setIgnoreAppearanceMethodInvocations(true)
|
||||||
|
if let layout = self.state.layout {
|
||||||
|
toValue.value.displayNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
|
}
|
||||||
|
let mappedTransitionType: NavigationTransition
|
||||||
|
let topController: ViewController
|
||||||
|
let bottomController: ViewController
|
||||||
|
switch transitionType {
|
||||||
|
case .push:
|
||||||
|
mappedTransitionType = .Push
|
||||||
|
self.addSubnode(toValue.value.displayNode)
|
||||||
|
topController = toValue.value
|
||||||
|
bottomController = fromValue.value
|
||||||
|
case .pop:
|
||||||
|
mappedTransitionType = .Pop
|
||||||
|
self.insertSubnode(toValue.value.displayNode, belowSubnode: fromValue.value.displayNode)
|
||||||
|
topController = fromValue.value
|
||||||
|
bottomController = toValue.value
|
||||||
|
}
|
||||||
|
toValue.value.setIgnoreAppearanceMethodInvocations(false)
|
||||||
|
|
||||||
|
let topTransition = TopTransition(previous: fromValue, coordinator: NavigationTransitionCoordinator(transition: mappedTransitionType, container: self.view, topView: topController.view, topNavigationBar: topController.navigationBar, bottomView: bottomController.view, bottomNavigationBar: bottomController.navigationBar, didUpdateProgress: nil))
|
||||||
|
self.state.transition = topTransition
|
||||||
|
|
||||||
|
topTransition.coordinator.animateCompletion(0.0, completion: { [weak self, weak topTransition] in
|
||||||
|
guard let strongSelf = self, let topTransition = topTransition, strongSelf.state.transition === topTransition else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.state.transition = nil
|
||||||
|
|
||||||
|
topTransition.previous.value.setIgnoreAppearanceMethodInvocations(true)
|
||||||
|
topTransition.previous.value.displayNode.removeFromSupernode()
|
||||||
|
topTransition.previous.value.setIgnoreAppearanceMethodInvocations(false)
|
||||||
|
topTransition.previous.value.viewDidDisappear(true)
|
||||||
|
if let toValue = strongSelf.state.top, let layout = strongSelf.state.layout {
|
||||||
|
toValue.value.displayNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
|
strongSelf.applyLayout(layout: layout, to: toValue, transition: .immediate)
|
||||||
|
toValue.value.viewDidAppear(true)
|
||||||
|
strongSelf.keyboardManager?.surfaces = toValue.value.view.flatMap({ [KeyboardSurface(host: $0)] }) ?? []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.keyboardManager?.surfaces = toValue?.value.view.flatMap({ [KeyboardSurface(host: $0)] }) ?? []
|
||||||
|
if let fromValue = fromValue {
|
||||||
|
fromValue.value.viewWillDisappear(false)
|
||||||
|
fromValue.value.setIgnoreAppearanceMethodInvocations(true)
|
||||||
|
fromValue.value.displayNode.removeFromSupernode()
|
||||||
|
fromValue.value.setIgnoreAppearanceMethodInvocations(false)
|
||||||
|
fromValue.value.viewDidDisappear(false)
|
||||||
|
}
|
||||||
|
if let toValue = toValue {
|
||||||
|
self.applyLayout(layout: layout, to: toValue, transition: .immediate)
|
||||||
|
toValue.value.displayNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
|
toValue.value.viewWillAppear(false)
|
||||||
|
toValue.value.setIgnoreAppearanceMethodInvocations(true)
|
||||||
|
self.addSubnode(toValue.value.displayNode)
|
||||||
|
toValue.value.setIgnoreAppearanceMethodInvocations(false)
|
||||||
|
toValue.value.viewDidAppear(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func makeChild(layout: ContainerViewLayout, value: ViewController) -> Child {
|
||||||
|
value.containerLayoutUpdated(layout, transition: .immediate)
|
||||||
|
return Child(value: value, layout: layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func applyLayout(layout: ContainerViewLayout, to child: Child, transition: ContainedViewLayoutTransition) {
|
||||||
|
if child.layout != layout {
|
||||||
|
child.layout = layout
|
||||||
|
child.value.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func pendingChildIsReady(_ child: PendingChild) {
|
||||||
|
if let pending = self.state.pending, pending === child {
|
||||||
|
pending.isReady = true
|
||||||
|
self.performUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func performUpdate() {
|
||||||
|
if let layout = self.state.layout, let canBeClosed = self.state.canBeClosed {
|
||||||
|
self.update(layout: layout, canBeClosed: canBeClosed, controllers: self.controllers, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
793
submodules/Display/Display/Navigation/NavigationController.swift
Normal file
793
submodules/Display/Display/Navigation/NavigationController.swift
Normal file
@ -0,0 +1,793 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
|
public enum NavigationStatusBarStyle {
|
||||||
|
case black
|
||||||
|
case white
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class NavigationControllerTheme {
|
||||||
|
public let statusBar: NavigationStatusBarStyle
|
||||||
|
public let navigationBar: NavigationBarTheme
|
||||||
|
public let emptyAreaColor: UIColor
|
||||||
|
|
||||||
|
public init(statusBar: NavigationStatusBarStyle, navigationBar: NavigationBarTheme, emptyAreaColor: UIColor) {
|
||||||
|
self.statusBar = statusBar
|
||||||
|
self.navigationBar = navigationBar
|
||||||
|
self.emptyAreaColor = emptyAreaColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct NavigationAnimationOptions : OptionSet {
|
||||||
|
public let rawValue: Int
|
||||||
|
|
||||||
|
public init(rawValue: Int) {
|
||||||
|
self.rawValue = rawValue
|
||||||
|
}
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
self.rawValue = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
public static let removeOnMasterDetails = NavigationAnimationOptions(rawValue: 1 << 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class NavigationControllerContainerView: UIView {
|
||||||
|
override class var layerClass: AnyClass {
|
||||||
|
return CATracingLayer.self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum NavigationEmptyDetailsBackgoundMode {
|
||||||
|
case image(UIImage)
|
||||||
|
case wallpaper(UIImage)
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class NavigationControllerView: UITracingLayerView {
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder aDecoder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override class var layerClass: AnyClass {
|
||||||
|
return CATracingLayer.self
|
||||||
|
}
|
||||||
|
|
||||||
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
|
return super.hitTest(point, with: event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum ControllerTransition {
|
||||||
|
case none
|
||||||
|
case appearance
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class ControllerRecord {
|
||||||
|
let controller: UIViewController
|
||||||
|
var transition: ControllerTransition = .none
|
||||||
|
|
||||||
|
init(controller: UIViewController) {
|
||||||
|
self.controller = controller
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum NavigationControllerMode {
|
||||||
|
case single
|
||||||
|
case automaticMasterDetail
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MasterDetailLayoutBlackout : Equatable {
|
||||||
|
case master
|
||||||
|
case details
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum RootContainer {
|
||||||
|
case flat(NavigationContainer)
|
||||||
|
case split(NavigationSplitContainer)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class NavigationController: UINavigationController, ContainableController, UIGestureRecognizerDelegate {
|
||||||
|
public var isOpaqueWhenInOverlay: Bool = true
|
||||||
|
public var blocksBackgroundWhenInOverlay: Bool = true
|
||||||
|
public var isModalWhenInOverlay: Bool = false
|
||||||
|
public var updateTransitionWhenPresentedAsModal: ((CGFloat, ContainedViewLayoutTransition) -> Void)?
|
||||||
|
|
||||||
|
private let _ready = Promise<Bool>(true)
|
||||||
|
open var ready: Promise<Bool> {
|
||||||
|
return self._ready
|
||||||
|
}
|
||||||
|
|
||||||
|
private var masterDetailsBlackout: MasterDetailLayoutBlackout?
|
||||||
|
private var backgroundDetailsMode: NavigationEmptyDetailsBackgoundMode?
|
||||||
|
|
||||||
|
public var lockOrientation: Bool = false
|
||||||
|
|
||||||
|
public var deferScreenEdgeGestures: UIRectEdge = UIRectEdge()
|
||||||
|
|
||||||
|
private let mode: NavigationControllerMode
|
||||||
|
private var theme: NavigationControllerTheme
|
||||||
|
|
||||||
|
public private(set) weak var overlayPresentingController: ViewController?
|
||||||
|
|
||||||
|
private var controllerView: NavigationControllerView {
|
||||||
|
return self.view as! NavigationControllerView
|
||||||
|
}
|
||||||
|
|
||||||
|
private var rootContainer: RootContainer?
|
||||||
|
private var rootModalFrame: NavigationModalFrame?
|
||||||
|
private var modalContainers: [NavigationModalContainer] = []
|
||||||
|
private var validLayout: ContainerViewLayout?
|
||||||
|
private var validStatusBarStyle: NavigationStatusBarStyle?
|
||||||
|
|
||||||
|
private var scheduledLayoutTransitionRequestId: Int = 0
|
||||||
|
private var scheduledLayoutTransitionRequest: (Int, ContainedViewLayoutTransition)?
|
||||||
|
|
||||||
|
private var _presentedViewController: UIViewController?
|
||||||
|
open override var presentedViewController: UIViewController? {
|
||||||
|
return self._presentedViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _viewControllers: [ViewController] = []
|
||||||
|
override open var viewControllers: [UIViewController] {
|
||||||
|
get {
|
||||||
|
return self._viewControllers.map { $0 as! ViewController }
|
||||||
|
} set(value) {
|
||||||
|
self.setViewControllers(value, animated: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override open var topViewController: UIViewController? {
|
||||||
|
return self._viewControllers.last
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _displayNode: ASDisplayNode?
|
||||||
|
public var displayNode: ASDisplayNode {
|
||||||
|
return self._displayNode!
|
||||||
|
}
|
||||||
|
|
||||||
|
var statusBarHost: StatusBarHost?
|
||||||
|
var keyboardManager: KeyboardManager?
|
||||||
|
|
||||||
|
public func updateMasterDetailsBlackout(_ blackout: MasterDetailLayoutBlackout?, transition: ContainedViewLayoutTransition) {
|
||||||
|
self.masterDetailsBlackout = blackout
|
||||||
|
if isViewLoaded {
|
||||||
|
self.view.endEditing(true)
|
||||||
|
}
|
||||||
|
self.requestLayout(transition: transition)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateBackgroundDetailsMode(_ mode: NavigationEmptyDetailsBackgoundMode?, transition: ContainedViewLayoutTransition) {
|
||||||
|
self.backgroundDetailsMode = mode
|
||||||
|
self.requestLayout(transition: transition)
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(mode: NavigationControllerMode, theme: NavigationControllerTheme, backgroundDetailsMode: NavigationEmptyDetailsBackgoundMode? = nil) {
|
||||||
|
self.mode = mode
|
||||||
|
self.theme = theme
|
||||||
|
self.backgroundDetailsMode = backgroundDetailsMode
|
||||||
|
|
||||||
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
|
||||||
|
preconditionFailure()
|
||||||
|
}
|
||||||
|
|
||||||
|
public required init(coder aDecoder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
}
|
||||||
|
|
||||||
|
public func combinedSupportedOrientations(currentOrientationToLock: UIInterfaceOrientationMask) -> ViewControllerSupportedOrientations {
|
||||||
|
var supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .allButUpsideDown)
|
||||||
|
if let controller = self.viewControllers.last {
|
||||||
|
if let controller = controller as? ViewController {
|
||||||
|
if controller.lockOrientation {
|
||||||
|
if let lockedOrientation = controller.lockedOrientation {
|
||||||
|
supportedOrientations = supportedOrientations.intersection(ViewControllerSupportedOrientations(regularSize: lockedOrientation, compactSize: lockedOrientation))
|
||||||
|
} else {
|
||||||
|
supportedOrientations = supportedOrientations.intersection(ViewControllerSupportedOrientations(regularSize: currentOrientationToLock, compactSize: currentOrientationToLock))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
supportedOrientations = supportedOrientations.intersection(controller.supportedOrientations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return supportedOrientations
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateTheme(_ theme: NavigationControllerTheme) {
|
||||||
|
let statusBarStyleUpdated = self.theme.statusBar != theme.statusBar
|
||||||
|
self.theme = theme
|
||||||
|
if self.isViewLoaded {
|
||||||
|
if statusBarStyleUpdated {
|
||||||
|
self.validStatusBarStyle = self.theme.statusBar
|
||||||
|
let normalStatusBarStyle: UIStatusBarStyle
|
||||||
|
switch self.theme.statusBar {
|
||||||
|
case .black:
|
||||||
|
normalStatusBarStyle = .default
|
||||||
|
case .white:
|
||||||
|
normalStatusBarStyle = .lightContent
|
||||||
|
}
|
||||||
|
self.statusBarHost?.setStatusBarStyle(normalStatusBarStyle, animated: false)
|
||||||
|
}
|
||||||
|
self.controllerView.backgroundColor = theme.emptyAreaColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open func preferredContentSizeForLayout(_ layout: ContainerViewLayout) -> CGSize? {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
|
if !self.isViewLoaded {
|
||||||
|
self.loadView()
|
||||||
|
}
|
||||||
|
self.validLayout = layout
|
||||||
|
transition.updateFrame(view: self.view, frame: CGRect(origin: self.view.frame.origin, size: layout.size))
|
||||||
|
self.updateContainers(layout: layout, transition: transition)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateContainers(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
|
let navigationLayout = makeNavigationLayout(layout: layout, controllers: self._viewControllers)
|
||||||
|
|
||||||
|
var transition = transition
|
||||||
|
|
||||||
|
var modalContainers: [NavigationModalContainer] = []
|
||||||
|
for i in 0 ..< navigationLayout.modal.count {
|
||||||
|
var existingModalContainer: NavigationModalContainer?
|
||||||
|
loop: for currentModalContainer in self.modalContainers {
|
||||||
|
for controller in navigationLayout.modal[i].controllers {
|
||||||
|
if currentModalContainer.container.controllers.contains(where: { $0 === controller }) {
|
||||||
|
existingModalContainer = currentModalContainer
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let modalContainer: NavigationModalContainer
|
||||||
|
let containerTransition: ContainedViewLayoutTransition
|
||||||
|
if let existingModalContainer = existingModalContainer {
|
||||||
|
modalContainer = existingModalContainer
|
||||||
|
containerTransition = transition
|
||||||
|
} else {
|
||||||
|
modalContainer = NavigationModalContainer(theme: self.theme, controllerRemoved: { [weak self] controller in
|
||||||
|
self?.controllerRemoved(controller)
|
||||||
|
})
|
||||||
|
self.modalContainers.append(modalContainer)
|
||||||
|
if !modalContainer.isReady {
|
||||||
|
modalContainer.isReadyUpdated = { [weak self, weak modalContainer] in
|
||||||
|
guard let strongSelf = self, let modalContainer = modalContainer else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let layout = strongSelf.validLayout {
|
||||||
|
strongSelf.updateContainers(layout: layout, transition: .animated(duration: 0.5, curve: .spring))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modalContainer.updateDismissProgress = { [weak self, weak modalContainer] _ in
|
||||||
|
guard let strongSelf = self, let modalContainer = modalContainer else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let layout = strongSelf.validLayout {
|
||||||
|
strongSelf.updateContainers(layout: layout, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modalContainer.interactivelyDismissed = { [weak self, weak modalContainer] in
|
||||||
|
guard let strongSelf = self, let modalContainer = modalContainer else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let controllers = strongSelf._viewControllers.filter { controller in
|
||||||
|
return !modalContainer.container.controllers.contains(where: { $0 === controller })
|
||||||
|
}
|
||||||
|
strongSelf.setViewControllers(controllers, animated: false)
|
||||||
|
}
|
||||||
|
containerTransition = .immediate
|
||||||
|
}
|
||||||
|
|
||||||
|
containerTransition.updateFrame(node: modalContainer, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
modalContainer.update(layout: layout, controllers: navigationLayout.modal[i].controllers, transition: containerTransition)
|
||||||
|
modalContainers.append(modalContainer)
|
||||||
|
}
|
||||||
|
|
||||||
|
for container in self.modalContainers {
|
||||||
|
if !modalContainers.contains(where: { $0 === container }) {
|
||||||
|
transition = container.dismiss(transition: transition, completion: { [weak container] in
|
||||||
|
container?.removeFromSupernode()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.modalContainers = modalContainers
|
||||||
|
|
||||||
|
var previousModalContainer: NavigationModalContainer?
|
||||||
|
var visibleModalCount = 0
|
||||||
|
var topModalDismissProgress: CGFloat = 0.0
|
||||||
|
|
||||||
|
for i in (0 ..< navigationLayout.modal.count).reversed() {
|
||||||
|
let modalContainer = self.modalContainers[i]
|
||||||
|
if modalContainer.supernode == nil && modalContainer.isReady {
|
||||||
|
if let previousModalContainer = previousModalContainer {
|
||||||
|
self.displayNode.insertSubnode(modalContainer, belowSubnode: previousModalContainer)
|
||||||
|
} else {
|
||||||
|
self.displayNode.addSubnode(modalContainer)
|
||||||
|
}
|
||||||
|
modalContainer.animateIn(transition: transition)
|
||||||
|
}
|
||||||
|
if modalContainer.supernode != nil {
|
||||||
|
visibleModalCount += 1
|
||||||
|
if previousModalContainer == nil {
|
||||||
|
topModalDismissProgress = modalContainer.dismissProgress
|
||||||
|
modalContainer.container.keyboardManager = self.keyboardManager
|
||||||
|
} else {
|
||||||
|
modalContainer.container.keyboardManager = nil
|
||||||
|
}
|
||||||
|
previousModalContainer = modalContainer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch navigationLayout.root {
|
||||||
|
case let .flat(controllers):
|
||||||
|
if let rootContainer = self.rootContainer {
|
||||||
|
switch rootContainer {
|
||||||
|
case let .flat(flatContainer):
|
||||||
|
if previousModalContainer == nil {
|
||||||
|
flatContainer.keyboardManager = self.keyboardManager
|
||||||
|
} else {
|
||||||
|
flatContainer.keyboardManager = nil
|
||||||
|
}
|
||||||
|
transition.updateFrame(node: flatContainer, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
flatContainer.update(layout: layout, canBeClosed: false, controllers: controllers, transition: transition)
|
||||||
|
case let .split(splitContainer):
|
||||||
|
let flatContainer = NavigationContainer(controllerRemoved: { [weak self] controller in
|
||||||
|
self?.controllerRemoved(controller)
|
||||||
|
})
|
||||||
|
self.displayNode.insertSubnode(flatContainer, at: 0)
|
||||||
|
self.rootContainer = .flat(flatContainer)
|
||||||
|
flatContainer.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
|
flatContainer.update(layout: layout, canBeClosed: false, controllers: controllers, transition: .immediate)
|
||||||
|
splitContainer.removeFromSupernode()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let flatContainer = NavigationContainer(controllerRemoved: { [weak self] controller in
|
||||||
|
self?.controllerRemoved(controller)
|
||||||
|
})
|
||||||
|
self.displayNode.insertSubnode(flatContainer, at: 0)
|
||||||
|
self.rootContainer = .flat(flatContainer)
|
||||||
|
flatContainer.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
|
flatContainer.update(layout: layout, canBeClosed: false, controllers: controllers, transition: .immediate)
|
||||||
|
}
|
||||||
|
case let .split(masterControllers, detailControllers):
|
||||||
|
if let rootContainer = self.rootContainer {
|
||||||
|
switch rootContainer {
|
||||||
|
case let .flat(flatContainer):
|
||||||
|
let splitContainer = NavigationSplitContainer(theme: self.theme, controllerRemoved: { [weak self] controller in
|
||||||
|
self?.controllerRemoved(controller)
|
||||||
|
})
|
||||||
|
self.displayNode.insertSubnode(splitContainer, at: 0)
|
||||||
|
self.rootContainer = .split(splitContainer)
|
||||||
|
splitContainer.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
|
splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, transition: .immediate)
|
||||||
|
flatContainer.removeFromSupernode()
|
||||||
|
case let .split(splitContainer):
|
||||||
|
transition.updateFrame(node: splitContainer, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, transition: transition)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let splitContainer = NavigationSplitContainer(theme: self.theme, controllerRemoved: { [weak self] controller in
|
||||||
|
self?.controllerRemoved(controller)
|
||||||
|
})
|
||||||
|
self.displayNode.insertSubnode(splitContainer, at: 0)
|
||||||
|
self.rootContainer = .split(splitContainer)
|
||||||
|
splitContainer.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
|
splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch layout.metrics.widthClass {
|
||||||
|
case .compact:
|
||||||
|
if visibleModalCount != 0 {
|
||||||
|
let rootModalFrame: NavigationModalFrame
|
||||||
|
var modalFrameTransition: ContainedViewLayoutTransition = transition
|
||||||
|
var forceStatusBarAnimation = false
|
||||||
|
if let current = self.rootModalFrame {
|
||||||
|
rootModalFrame = current
|
||||||
|
transition.updateFrame(node: rootModalFrame, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
rootModalFrame.update(layout: layout, transition: modalFrameTransition)
|
||||||
|
rootModalFrame.updateDismissal(transition: transition, progress: topModalDismissProgress, completion: {})
|
||||||
|
forceStatusBarAnimation = true
|
||||||
|
} else {
|
||||||
|
rootModalFrame = NavigationModalFrame(theme: self.theme)
|
||||||
|
self.rootModalFrame = rootModalFrame
|
||||||
|
rootModalFrame.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
|
rootModalFrame.update(layout: layout, transition: .immediate)
|
||||||
|
rootModalFrame.animateIn(transition: transition)
|
||||||
|
if let rootContainer = self.rootContainer {
|
||||||
|
var rootContainerNode: ASDisplayNode
|
||||||
|
switch rootContainer {
|
||||||
|
case let .flat(container):
|
||||||
|
rootContainerNode = container
|
||||||
|
case let .split(container):
|
||||||
|
rootContainerNode = container
|
||||||
|
}
|
||||||
|
self.displayNode.insertSubnode(rootModalFrame, aboveSubnode: rootContainerNode)
|
||||||
|
}
|
||||||
|
rootModalFrame.updateDismissal(transition: transition, progress: topModalDismissProgress, completion: {})
|
||||||
|
}
|
||||||
|
if topModalDismissProgress < 0.5 {
|
||||||
|
self.statusBarHost?.setStatusBarStyle(.lightContent, animated: transition.isAnimated || forceStatusBarAnimation)
|
||||||
|
} else {
|
||||||
|
let normalStatusBarStyle: UIStatusBarStyle
|
||||||
|
switch self.theme.statusBar {
|
||||||
|
case .black:
|
||||||
|
normalStatusBarStyle = .default
|
||||||
|
case .white:
|
||||||
|
normalStatusBarStyle = .lightContent
|
||||||
|
}
|
||||||
|
self.statusBarHost?.setStatusBarStyle(normalStatusBarStyle, animated: transition.isAnimated || forceStatusBarAnimation)
|
||||||
|
}
|
||||||
|
if let rootContainer = self.rootContainer {
|
||||||
|
var rootContainerNode: ASDisplayNode
|
||||||
|
switch rootContainer {
|
||||||
|
case let .flat(container):
|
||||||
|
rootContainerNode = container
|
||||||
|
case let .split(container):
|
||||||
|
rootContainerNode = container
|
||||||
|
}
|
||||||
|
let maxScale = (layout.size.width - 16.0 * 2.0) / layout.size.width
|
||||||
|
var topInset: CGFloat = 0.0
|
||||||
|
if let statusBarHeight = layout.statusBarHeight {
|
||||||
|
topInset += statusBarHeight
|
||||||
|
}
|
||||||
|
let maxOffset: CGFloat = (topInset - (layout.size.height - layout.size.height * maxScale) / 2.0)
|
||||||
|
|
||||||
|
let scale = 1.0 * topModalDismissProgress + (1.0 - topModalDismissProgress) * maxScale
|
||||||
|
let offset = (1.0 - topModalDismissProgress) * maxOffset
|
||||||
|
transition.updateSublayerTransformScaleAndOffset(node: rootContainerNode, scale: scale, offset: CGPoint(x: 0.0, y: offset))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let rootModalFrame = self.rootModalFrame {
|
||||||
|
self.rootModalFrame = nil
|
||||||
|
rootModalFrame.updateDismissal(transition: transition, progress: 1.0, completion: { [weak rootModalFrame] in
|
||||||
|
rootModalFrame?.removeFromSupernode()
|
||||||
|
})
|
||||||
|
let normalStatusBarStyle: UIStatusBarStyle
|
||||||
|
switch self.theme.statusBar {
|
||||||
|
case .black:
|
||||||
|
normalStatusBarStyle = .default
|
||||||
|
case .white:
|
||||||
|
normalStatusBarStyle = .lightContent
|
||||||
|
}
|
||||||
|
self.statusBarHost?.setStatusBarStyle(normalStatusBarStyle, animated: transition.isAnimated)
|
||||||
|
}
|
||||||
|
if let rootContainer = self.rootContainer {
|
||||||
|
var rootContainerNode: ASDisplayNode
|
||||||
|
switch rootContainer {
|
||||||
|
case let .flat(container):
|
||||||
|
rootContainerNode = container
|
||||||
|
case let .split(container):
|
||||||
|
rootContainerNode = container
|
||||||
|
}
|
||||||
|
transition.updateSublayerTransformScaleAndOffset(node: rootContainerNode, scale: 1.0, offset: CGPoint())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .regular:
|
||||||
|
if let rootModalFrame = self.rootModalFrame {
|
||||||
|
self.rootModalFrame = nil
|
||||||
|
rootModalFrame.updateDismissal(transition: .immediate, progress: 1.0, completion: { [weak rootModalFrame] in
|
||||||
|
rootModalFrame?.removeFromSupernode()
|
||||||
|
})
|
||||||
|
let normalStatusBarStyle: UIStatusBarStyle
|
||||||
|
switch self.theme.statusBar {
|
||||||
|
case .black:
|
||||||
|
normalStatusBarStyle = .default
|
||||||
|
case .white:
|
||||||
|
normalStatusBarStyle = .lightContent
|
||||||
|
}
|
||||||
|
self.statusBarHost?.setStatusBarStyle(normalStatusBarStyle, animated: false)
|
||||||
|
}
|
||||||
|
if let rootContainer = self.rootContainer {
|
||||||
|
var rootContainerNode: ASDisplayNode
|
||||||
|
switch rootContainer {
|
||||||
|
case let .flat(container):
|
||||||
|
rootContainerNode = container
|
||||||
|
case let .split(container):
|
||||||
|
rootContainerNode = container
|
||||||
|
}
|
||||||
|
ContainedViewLayoutTransition.immediate.updateSublayerTransformScaleAndOffset(node: rootContainerNode, scale: 1.0, offset: CGPoint())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.validStatusBarStyle != self.theme.statusBar {
|
||||||
|
self.validStatusBarStyle = self.theme.statusBar
|
||||||
|
let normalStatusBarStyle: UIStatusBarStyle
|
||||||
|
switch self.theme.statusBar {
|
||||||
|
case .black:
|
||||||
|
normalStatusBarStyle = .default
|
||||||
|
case .white:
|
||||||
|
normalStatusBarStyle = .lightContent
|
||||||
|
}
|
||||||
|
self.statusBarHost?.setStatusBarStyle(normalStatusBarStyle, animated: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func controllerRemoved(_ controller: ViewController) {
|
||||||
|
self.filterController(controller, animated: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateModalTransition(_ value: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateToInterfaceOrientation(_ orientation: UIInterfaceOrientation) {
|
||||||
|
/*for record in self._viewControllers {
|
||||||
|
if let controller = record.controller as? ContainableController {
|
||||||
|
controller.updateToInterfaceOrientation(orientation)
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func loadView() {
|
||||||
|
self._displayNode = ASDisplayNode(viewBlock: {
|
||||||
|
return NavigationControllerView()
|
||||||
|
}, didLoad: nil)
|
||||||
|
|
||||||
|
self.view = self.displayNode.view
|
||||||
|
self.view.clipsToBounds = true
|
||||||
|
self.view.autoresizingMask = []
|
||||||
|
|
||||||
|
self.controllerView.backgroundColor = self.theme.emptyAreaColor
|
||||||
|
|
||||||
|
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
||||||
|
self.navigationBar.prefersLargeTitles = false
|
||||||
|
}
|
||||||
|
self.navigationBar.removeFromSuperview()
|
||||||
|
|
||||||
|
/*let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
||||||
|
panRecognizer.delegate = self
|
||||||
|
panRecognizer.delaysTouchesBegan = false
|
||||||
|
panRecognizer.cancelsTouchesInView = true
|
||||||
|
self.view.addGestureRecognizer(panRecognizer)*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public func pushViewController(_ controller: ViewController) {
|
||||||
|
self.pushViewController(controller, completion: {})
|
||||||
|
}
|
||||||
|
|
||||||
|
public func pushViewController(_ controller: ViewController, animated: Bool = true, completion: @escaping () -> Void) {
|
||||||
|
let navigateAction: () -> Void = { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !controller.hasActiveInput {
|
||||||
|
//strongSelf.view.endEditing(true)
|
||||||
|
}
|
||||||
|
/*strongSelf.scheduleAfterLayout({
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}*/
|
||||||
|
strongSelf.pushViewController(controller, animated: animated)
|
||||||
|
completion()
|
||||||
|
//})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if let lastController = self.viewControllers.last as? ViewController, !lastController.attemptNavigation(navigateAction) {
|
||||||
|
} else {*/
|
||||||
|
navigateAction()
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func pushViewController(_ viewController: UIViewController, animated: Bool) {
|
||||||
|
var controllers = self.viewControllers
|
||||||
|
controllers.append(viewController)
|
||||||
|
self.setViewControllers(controllers, animated: animated)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func replaceTopController(_ controller: ViewController, animated: Bool, ready: ValuePromise<Bool>? = nil) {
|
||||||
|
ready?.set(true)
|
||||||
|
var controllers = self.viewControllers
|
||||||
|
controllers.removeLast()
|
||||||
|
controllers.append(controller)
|
||||||
|
self.setViewControllers(controllers, animated: animated)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func filterController(_ controller: ViewController, animated: Bool) {
|
||||||
|
let controllers = self.viewControllers.filter({ $0 !== controller })
|
||||||
|
if controllers.count != self.viewControllers.count {
|
||||||
|
self.setViewControllers(controllers, animated: animated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func replaceControllersAndPush(controllers: [UIViewController], controller: ViewController, animated: Bool, options: NavigationAnimationOptions = [], ready: ValuePromise<Bool>? = nil, completion: @escaping () -> Void = {}) {
|
||||||
|
ready?.set(true)
|
||||||
|
var controllers = controllers
|
||||||
|
controllers.append(controller)
|
||||||
|
self.setViewControllers(controllers, animated: animated)
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func replaceAllButRootController(_ controller: ViewController, animated: Bool, animationOptions: NavigationAnimationOptions = [], ready: ValuePromise<Bool>? = nil, completion: @escaping () -> Void = {}) {
|
||||||
|
ready?.set(true)
|
||||||
|
var controllers = self.viewControllers
|
||||||
|
while controllers.count > 1 {
|
||||||
|
controllers.removeLast()
|
||||||
|
}
|
||||||
|
controllers.append(controller)
|
||||||
|
self.setViewControllers(controllers, animated: animated)
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func popToRoot(animated: Bool) {
|
||||||
|
var controllers = self.viewControllers
|
||||||
|
while controllers.count > 1 {
|
||||||
|
controllers.removeLast()
|
||||||
|
}
|
||||||
|
self.setViewControllers(controllers, animated: animated)
|
||||||
|
}
|
||||||
|
|
||||||
|
override open func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? {
|
||||||
|
var poppedControllers: [UIViewController] = []
|
||||||
|
var found = false
|
||||||
|
var controllers = self.viewControllers
|
||||||
|
if !controllers.contains(where: { $0 === viewController }) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
while !controllers.isEmpty {
|
||||||
|
if controllers[controllers.count - 1] === viewController {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
poppedControllers.insert(controllers[controllers.count - 1], at: 0)
|
||||||
|
controllers.removeLast()
|
||||||
|
}
|
||||||
|
if found {
|
||||||
|
self.setViewControllers(controllers, animated: animated)
|
||||||
|
return poppedControllers
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func popViewController(animated: Bool) -> UIViewController? {
|
||||||
|
var controller: UIViewController?
|
||||||
|
var controllers = self.viewControllers
|
||||||
|
if controllers.count != 0 {
|
||||||
|
controller = controllers[controllers.count - 1] as UIViewController
|
||||||
|
controllers.remove(at: controllers.count - 1)
|
||||||
|
self.setViewControllers(controllers, animated: animated)
|
||||||
|
}
|
||||||
|
return controller
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func setViewControllers(_ viewControllers: [UIViewController], animated: Bool) {
|
||||||
|
self._viewControllers = viewControllers.map { controller in
|
||||||
|
let controller = controller as! ViewController
|
||||||
|
controller.navigation_setNavigationController(self)
|
||||||
|
return controller
|
||||||
|
}
|
||||||
|
if let layout = self.validLayout {
|
||||||
|
self.updateContainers(layout: layout, transition: animated ? .animated(duration: 0.5, curve: .spring) : .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override open func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||||
|
preconditionFailure()
|
||||||
|
/*if let controller = viewControllerToPresent as? NavigationController {
|
||||||
|
controller.navigation_setDismiss({ [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.dismiss(animated: false, completion: nil)
|
||||||
|
}
|
||||||
|
}, rootController: self.view!.window!.rootViewController)
|
||||||
|
self._presentedViewController = controller
|
||||||
|
|
||||||
|
self.view.endEditing(true)
|
||||||
|
if let validLayout = self.validLayout {
|
||||||
|
controller.containerLayoutUpdated(validLayout, transition: .immediate)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ready: Signal<Bool, NoError> = .single(true)
|
||||||
|
|
||||||
|
if let controller = controller.topViewController as? ViewController {
|
||||||
|
ready = controller.ready.get()
|
||||||
|
|> filter { $0 }
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue
|
||||||
|
}
|
||||||
|
|
||||||
|
self.currentPresentDisposable.set(ready.start(next: { [weak self] _ in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if flag {
|
||||||
|
controller.view.frame = strongSelf.view.bounds.offsetBy(dx: 0.0, dy: strongSelf.view.bounds.height)
|
||||||
|
strongSelf.view.addSubview(controller.view)
|
||||||
|
UIView.animate(withDuration: 0.3, delay: 0.0, options: UIView.AnimationOptions(rawValue: 7 << 16), animations: {
|
||||||
|
controller.view.frame = strongSelf.view.bounds
|
||||||
|
}, completion: { _ in
|
||||||
|
if let completion = completion {
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
controller.view.frame = strongSelf.view.bounds
|
||||||
|
strongSelf.view.addSubview(controller.view)
|
||||||
|
|
||||||
|
if let completion = completion {
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
preconditionFailure("NavigationController can't present \(viewControllerToPresent). Only subclasses of NavigationController are allowed.")
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
override open func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||||
|
if let controller = self.presentedViewController {
|
||||||
|
if flag {
|
||||||
|
UIView.animate(withDuration: 0.3, delay: 0.0, options: UIView.AnimationOptions(rawValue: 7 << 16), animations: {
|
||||||
|
controller.view.frame = self.view.bounds.offsetBy(dx: 0.0, dy: self.view.bounds.height)
|
||||||
|
}, completion: { _ in
|
||||||
|
controller.view.removeFromSuperview()
|
||||||
|
self._presentedViewController = nil
|
||||||
|
if let completion = completion {
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
controller.view.removeFromSuperview()
|
||||||
|
self._presentedViewController = nil
|
||||||
|
if let completion = completion {
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final var currentWindow: WindowHost? {
|
||||||
|
if let window = self.view.window as? WindowHost {
|
||||||
|
return window
|
||||||
|
} else if let superwindow = self.view.window {
|
||||||
|
for subview in superwindow.subviews {
|
||||||
|
if let subview = subview as? WindowHost {
|
||||||
|
return subview
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func scheduleAfterLayout(_ f: @escaping () -> Void) {
|
||||||
|
(self.view as? UITracingLayerView)?.schedule(layout: {
|
||||||
|
f()
|
||||||
|
})
|
||||||
|
self.view.setNeedsLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func scheduleLayoutTransitionRequest(_ transition: ContainedViewLayoutTransition) {
|
||||||
|
let requestId = self.scheduledLayoutTransitionRequestId
|
||||||
|
self.scheduledLayoutTransitionRequestId += 1
|
||||||
|
self.scheduledLayoutTransitionRequest = (requestId, transition)
|
||||||
|
(self.view as? UITracingLayerView)?.schedule(layout: { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if let (currentRequestId, currentRequestTransition) = strongSelf.scheduledLayoutTransitionRequest, currentRequestId == requestId {
|
||||||
|
strongSelf.scheduledLayoutTransitionRequest = nil
|
||||||
|
strongSelf.requestLayout(transition: currentRequestTransition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.view.setNeedsLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func requestLayout(transition: ContainedViewLayoutTransition) {
|
||||||
|
if self.isViewLoaded, let validLayout = self.validLayout {
|
||||||
|
self.containerLayoutUpdated(validLayout, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
76
submodules/Display/Display/Navigation/NavigationLayout.swift
Normal file
76
submodules/Display/Display/Navigation/NavigationLayout.swift
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
|
enum RootNavigationLayout {
|
||||||
|
case split([ViewController], [ViewController])
|
||||||
|
case flat([ViewController])
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ModalContainerLayout {
|
||||||
|
var controllers: [ViewController]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NavigationLayout {
|
||||||
|
var root: RootNavigationLayout
|
||||||
|
var modal: [ModalContainerLayout]
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeNavigationLayout(layout: ContainerViewLayout, controllers: [ViewController]) -> NavigationLayout {
|
||||||
|
var rootControllers: [ViewController] = []
|
||||||
|
var modalStack: [ModalContainerLayout] = []
|
||||||
|
for controller in controllers {
|
||||||
|
let requiresModal: Bool
|
||||||
|
var beginsModal: Bool = false
|
||||||
|
switch controller.navigationPresentation {
|
||||||
|
case .default:
|
||||||
|
requiresModal = false
|
||||||
|
case .master:
|
||||||
|
requiresModal = false
|
||||||
|
case .modal:
|
||||||
|
requiresModal = true
|
||||||
|
beginsModal = true
|
||||||
|
case .modalInLargeLayout:
|
||||||
|
switch layout.metrics.widthClass {
|
||||||
|
case .compact:
|
||||||
|
requiresModal = false
|
||||||
|
case .regular:
|
||||||
|
requiresModal = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if requiresModal {
|
||||||
|
if beginsModal || modalStack.isEmpty {
|
||||||
|
modalStack.append(ModalContainerLayout(controllers: [controller]))
|
||||||
|
} else {
|
||||||
|
modalStack[modalStack.count - 1].controllers.append(controller)
|
||||||
|
}
|
||||||
|
} else if !modalStack.isEmpty {
|
||||||
|
modalStack[modalStack.count - 1].controllers.append(controller)
|
||||||
|
} else {
|
||||||
|
rootControllers.append(controller)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let rootLayout: RootNavigationLayout
|
||||||
|
switch layout.metrics.widthClass {
|
||||||
|
case .compact:
|
||||||
|
rootLayout = .flat(rootControllers)
|
||||||
|
case .regular:
|
||||||
|
let masterControllers = rootControllers.filter {
|
||||||
|
if case .master = $0.navigationPresentation {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let detailControllers = rootControllers.filter {
|
||||||
|
if case .master = $0.navigationPresentation {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rootLayout = .split(masterControllers, detailControllers)
|
||||||
|
}
|
||||||
|
return NavigationLayout(root: rootLayout, modal: modalStack)
|
||||||
|
}
|
@ -0,0 +1,196 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
|
final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate {
|
||||||
|
private var theme: NavigationControllerTheme
|
||||||
|
|
||||||
|
private let dim: ASDisplayNode
|
||||||
|
private let scrollNode: ASScrollNode
|
||||||
|
let container: NavigationContainer
|
||||||
|
|
||||||
|
private(set) var isReady: Bool = false
|
||||||
|
private(set) var dismissProgress: CGFloat = 0.0
|
||||||
|
var isReadyUpdated: (() -> Void)?
|
||||||
|
var updateDismissProgress: ((CGFloat) -> Void)?
|
||||||
|
var interactivelyDismissed: (() -> Void)?
|
||||||
|
|
||||||
|
private var ignoreScrolling = false
|
||||||
|
private var animator: DisplayLinkAnimator?
|
||||||
|
|
||||||
|
init(theme: NavigationControllerTheme, controllerRemoved: @escaping (ViewController) -> Void) {
|
||||||
|
self.theme = theme
|
||||||
|
|
||||||
|
self.dim = ASDisplayNode()
|
||||||
|
self.dim.backgroundColor = UIColor(white: 0.0, alpha: 0.4)
|
||||||
|
self.dim.alpha = 0.0
|
||||||
|
|
||||||
|
self.scrollNode = ASScrollNode()
|
||||||
|
|
||||||
|
self.container = NavigationContainer(controllerRemoved: controllerRemoved)
|
||||||
|
self.container.clipsToBounds = true
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.addSubnode(self.dim)
|
||||||
|
self.addSubnode(self.scrollNode)
|
||||||
|
self.scrollNode.addSubnode(self.container)
|
||||||
|
|
||||||
|
self.isReady = self.container.isReady
|
||||||
|
self.container.isReadyUpdated = { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !strongSelf.isReady {
|
||||||
|
strongSelf.isReady = true
|
||||||
|
strongSelf.isReadyUpdated?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.animator?.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func didLoad() {
|
||||||
|
super.didLoad()
|
||||||
|
|
||||||
|
self.scrollNode.view.alwaysBounceVertical = false
|
||||||
|
self.scrollNode.view.alwaysBounceHorizontal = false
|
||||||
|
self.scrollNode.view.bounces = false
|
||||||
|
self.scrollNode.view.showsVerticalScrollIndicator = false
|
||||||
|
self.scrollNode.view.showsHorizontalScrollIndicator = false
|
||||||
|
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
||||||
|
self.scrollNode.view.contentInsetAdjustmentBehavior = .never
|
||||||
|
}
|
||||||
|
self.scrollNode.view.delaysContentTouches = false
|
||||||
|
self.scrollNode.view.delegate = self
|
||||||
|
}
|
||||||
|
|
||||||
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
|
if self.ignoreScrolling {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var progress = (self.bounds.height - scrollView.bounds.origin.y) / self.bounds.height
|
||||||
|
progress = max(0.0, min(1.0, progress))
|
||||||
|
self.dismissProgress = progress
|
||||||
|
self.dim.alpha = 1.0 - progress
|
||||||
|
self.updateDismissProgress?(progress)
|
||||||
|
}
|
||||||
|
|
||||||
|
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
||||||
|
var progress = (self.bounds.height - scrollView.bounds.origin.y) / self.bounds.height
|
||||||
|
progress = max(0.0, min(1.0, progress))
|
||||||
|
|
||||||
|
self.ignoreScrolling = true
|
||||||
|
targetContentOffset.pointee = scrollView.contentOffset
|
||||||
|
scrollView.setContentOffset(scrollView.contentOffset, animated: false)
|
||||||
|
self.ignoreScrolling = false
|
||||||
|
self.animator?.invalidate()
|
||||||
|
let targetOffset: CGFloat
|
||||||
|
if velocity.y < -0.5 || progress >= 0.5 {
|
||||||
|
targetOffset = 0.0
|
||||||
|
} else {
|
||||||
|
targetOffset = self.bounds.height
|
||||||
|
}
|
||||||
|
let velocityFactor: CGFloat = 0.4 / max(1.0, abs(velocity.y))
|
||||||
|
self.animator = DisplayLinkAnimator(duration: Double(min(0.3, velocityFactor)), from: scrollView.contentOffset.y, to: targetOffset, update: { [weak self] value in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.scrollNode.view.contentOffset = CGPoint(x: 0.0, y: value)
|
||||||
|
}, completion: { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.animator = nil
|
||||||
|
if targetOffset == 0.0 {
|
||||||
|
strongSelf.interactivelyDismissed?()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(layout: ContainerViewLayout, controllers: [ViewController], transition: ContainedViewLayoutTransition) {
|
||||||
|
transition.updateFrame(node: self.dim, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: layout.size.height * 2.0)
|
||||||
|
if !self.scrollNode.view.isDecelerating && !self.scrollNode.view.isDragging && self.animator == nil {
|
||||||
|
transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height), size: layout.size))
|
||||||
|
}
|
||||||
|
|
||||||
|
let containerLayout: ContainerViewLayout
|
||||||
|
let containerFrame: CGRect
|
||||||
|
switch layout.metrics.widthClass {
|
||||||
|
case .compact:
|
||||||
|
self.dim.isHidden = true
|
||||||
|
self.container.clipsToBounds = true
|
||||||
|
self.container.cornerRadius = 10.0
|
||||||
|
if #available(iOS 11.0, *) {
|
||||||
|
self.container.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
|
||||||
|
}
|
||||||
|
|
||||||
|
var topInset: CGFloat = 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)
|
||||||
|
containerFrame = CGRect(origin: CGPoint(x: 0.0, y: topInset), size: containerLayout.size)
|
||||||
|
case .regular:
|
||||||
|
self.dim.isHidden = false
|
||||||
|
self.container.clipsToBounds = true
|
||||||
|
self.container.cornerRadius = 10.0
|
||||||
|
if #available(iOS 11.0, *) {
|
||||||
|
self.container.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
|
||||||
|
}
|
||||||
|
|
||||||
|
let verticalInset: CGFloat = 44.0
|
||||||
|
|
||||||
|
let maxSide = max(layout.size.width, layout.size.height)
|
||||||
|
let containerSize = CGSize(width: max(layout.size.width - 20.0, floor(maxSide / 2.0)), height: layout.size.height - verticalInset * 2.0)
|
||||||
|
containerFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - containerSize.width) / 2.0), y: floor((layout.size.height - containerSize.height) / 2.0)), size: containerSize)
|
||||||
|
|
||||||
|
var inputHeight: CGFloat?
|
||||||
|
if let inputHeightValue = layout.inputHeight {
|
||||||
|
inputHeight = max(0.0, inputHeightValue - (layout.size.height - containerFrame.maxY))
|
||||||
|
}
|
||||||
|
containerLayout = ContainerViewLayout(size: containerSize, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: inputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver)
|
||||||
|
}
|
||||||
|
transition.updateFrame(node: self.container, frame: containerFrame.offsetBy(dx: 0.0, dy: layout.size.height))
|
||||||
|
self.container.update(layout: containerLayout, canBeClosed: true, controllers: controllers, transition: transition)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func dismiss(transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) -> ContainedViewLayoutTransition {
|
||||||
|
for controller in self.container.controllers {
|
||||||
|
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 {
|
||||||
|
for controller in self.container.controllers {
|
||||||
|
controller.setIgnoreAppearanceMethodInvocations(true)
|
||||||
|
controller.displayNode.removeFromSupernode()
|
||||||
|
controller.setIgnoreAppearanceMethodInvocations(false)
|
||||||
|
controller.viewDidDisappear(transition.isAnimated)
|
||||||
|
}
|
||||||
|
completion()
|
||||||
|
return transition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
113
submodules/Display/Display/Navigation/NavigationModalFrame.swift
Normal file
113
submodules/Display/Display/Navigation/NavigationModalFrame.swift
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
|
private func generateCornerImage(radius: CGFloat, mirror: Bool) -> UIImage? {
|
||||||
|
return generateImage(CGSize(width: radius, height: radius), rotatedContext: { size, context in
|
||||||
|
context.setFillColor(UIColor.black.cgColor)
|
||||||
|
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||||
|
context.setBlendMode(.copy)
|
||||||
|
context.setFillColor(UIColor.clear.cgColor)
|
||||||
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: mirror ? (-radius) : 0.0, y: 0.0), size: CGSize(width: radius * 2.0, height: radius * 2.0)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
final class NavigationModalFrame: ASDisplayNode {
|
||||||
|
private let dim: ASDisplayNode
|
||||||
|
private let topShade: ASDisplayNode
|
||||||
|
private let leftShade: ASDisplayNode
|
||||||
|
private let rightShade: ASDisplayNode
|
||||||
|
private let topLeftCorner: ASImageNode
|
||||||
|
private let topRightCorner: ASImageNode
|
||||||
|
|
||||||
|
private var currentMaxCornerRadius: CGFloat?
|
||||||
|
|
||||||
|
private var progress: CGFloat = 0.0
|
||||||
|
private var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
|
init(theme: NavigationControllerTheme) {
|
||||||
|
self.dim = ASDisplayNode()
|
||||||
|
self.dim.backgroundColor = UIColor(white: 0.0, alpha: 0.4)
|
||||||
|
self.dim.alpha = 0.0
|
||||||
|
|
||||||
|
self.topShade = ASDisplayNode()
|
||||||
|
self.topShade.backgroundColor = .black
|
||||||
|
self.leftShade = ASDisplayNode()
|
||||||
|
self.leftShade.backgroundColor = .black
|
||||||
|
self.rightShade = ASDisplayNode()
|
||||||
|
self.rightShade.backgroundColor = .black
|
||||||
|
|
||||||
|
self.topLeftCorner = ASImageNode()
|
||||||
|
self.topLeftCorner.displaysAsynchronously = false
|
||||||
|
self.topLeftCorner.displayWithoutProcessing = true
|
||||||
|
self.topRightCorner = ASImageNode()
|
||||||
|
self.topRightCorner.displaysAsynchronously = false
|
||||||
|
self.topRightCorner.displayWithoutProcessing = true
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.addSubnode(self.dim)
|
||||||
|
self.addSubnode(self.topShade)
|
||||||
|
self.addSubnode(self.leftShade)
|
||||||
|
self.addSubnode(self.rightShade)
|
||||||
|
self.addSubnode(self.topLeftCorner)
|
||||||
|
self.addSubnode(self.topRightCorner)
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
|
self.validLayout = layout
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.dim, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
|
||||||
|
self.updateShades(layout: layout, progress: 1.0 - self.progress, transition: transition)
|
||||||
|
}
|
||||||
|
|
||||||
|
func animateIn(transition: ContainedViewLayoutTransition) {
|
||||||
|
transition.updateAlpha(node: self.dim, alpha: 1.0)
|
||||||
|
|
||||||
|
if let layout = self.validLayout {
|
||||||
|
self.updateShades(layout: layout, progress: 0.0, transition: .immediate)
|
||||||
|
self.updateShades(layout: layout, progress: 1.0, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateDismissal(transition: ContainedViewLayoutTransition, progress: CGFloat, completion: @escaping () -> Void) {
|
||||||
|
self.progress = progress
|
||||||
|
|
||||||
|
transition.updateAlpha(node: self.dim, alpha: 1.0 - progress, completion: { _ in
|
||||||
|
completion()
|
||||||
|
})
|
||||||
|
if let layout = self.validLayout {
|
||||||
|
self.updateShades(layout: layout, progress: 1.0 - progress, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateShades(layout: ContainerViewLayout, progress: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
let sideInset: CGFloat = 16.0
|
||||||
|
var topInset: CGFloat = 0.0
|
||||||
|
if let statusBarHeight = layout.statusBarHeight {
|
||||||
|
topInset += statusBarHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
let cornerRadius: CGFloat = 8.0
|
||||||
|
let initialCornerRadius: CGFloat
|
||||||
|
if !layout.safeInsets.top.isZero {
|
||||||
|
initialCornerRadius = 40.0
|
||||||
|
} else {
|
||||||
|
initialCornerRadius = 0.0
|
||||||
|
}
|
||||||
|
if self.currentMaxCornerRadius != cornerRadius {
|
||||||
|
self.topLeftCorner.image = generateCornerImage(radius: max(initialCornerRadius, cornerRadius), mirror: false)
|
||||||
|
self.topRightCorner.image = generateCornerImage(radius: max(initialCornerRadius, cornerRadius), mirror: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
let cornerSize = progress * cornerRadius + (1.0 - progress) * initialCornerRadius
|
||||||
|
transition.updateFrame(node: self.topLeftCorner, frame: CGRect(origin: CGPoint(x: progress * sideInset, y: progress * topInset), size: CGSize(width: cornerSize, height: cornerSize)))
|
||||||
|
transition.updateFrame(node: self.topRightCorner, frame: CGRect(origin: CGPoint(x: layout.size.width - progress * sideInset - cornerSize, y: progress * topInset), size: CGSize(width: cornerSize, height: cornerSize)))
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.topShade, frame: CGRect(origin: CGPoint(x: 0.0, y: (1.0 - progress) * (-topInset)), size: CGSize(width: layout.size.width, height: topInset)))
|
||||||
|
transition.updateFrame(node: self.leftShade, frame: CGRect(origin: CGPoint(x: (1.0 - progress) * (-sideInset), y: 0.0), size: CGSize(width: sideInset, height: layout.size.height)))
|
||||||
|
transition.updateFrame(node: self.rightShade, frame: CGRect(origin: CGPoint(x: layout.size.width - sideInset * progress, y: 0.0), size: CGSize(width: sideInset, height: layout.size.height)))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
|
final class NavigationSplitContainer: ASDisplayNode {
|
||||||
|
private var theme: NavigationControllerTheme
|
||||||
|
|
||||||
|
private let masterContainer: NavigationContainer
|
||||||
|
private let detailContainer: NavigationContainer
|
||||||
|
private let separator: ASDisplayNode
|
||||||
|
|
||||||
|
init(theme: NavigationControllerTheme, controllerRemoved: @escaping (ViewController) -> Void) {
|
||||||
|
self.theme = theme
|
||||||
|
|
||||||
|
self.masterContainer = NavigationContainer(controllerRemoved: controllerRemoved)
|
||||||
|
self.masterContainer.clipsToBounds = true
|
||||||
|
|
||||||
|
self.detailContainer = NavigationContainer(controllerRemoved: controllerRemoved)
|
||||||
|
self.detailContainer.clipsToBounds = true
|
||||||
|
|
||||||
|
self.separator = ASDisplayNode()
|
||||||
|
self.separator.backgroundColor = theme.navigationBar.separatorColor
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.addSubnode(self.masterContainer)
|
||||||
|
self.addSubnode(self.detailContainer)
|
||||||
|
self.addSubnode(self.separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(layout: ContainerViewLayout, masterControllers: [ViewController], detailControllers: [ViewController], transition: ContainedViewLayoutTransition) {
|
||||||
|
let masterWidth = min(max(320.0, floor(layout.size.width / 3.0)), floor(layout.size.width / 2.0))
|
||||||
|
let detailWidth = layout.size.width - masterWidth
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.masterContainer, frame: CGRect(origin: CGPoint(), size: CGSize(width: masterWidth, height: layout.size.height)))
|
||||||
|
transition.updateFrame(node: self.detailContainer, frame: CGRect(origin: CGPoint(x: masterWidth, y: 0.0), size: CGSize(width: detailWidth, height: layout.size.height)))
|
||||||
|
transition.updateFrame(node: self.separator, frame: CGRect(origin: CGPoint(x: masterWidth, y: 0.0), size: CGSize(width: UIScreenPixel, height: layout.size.height)))
|
||||||
|
|
||||||
|
self.masterContainer.update(layout: ContainerViewLayout(size: CGSize(width: masterWidth, height: layout.size.height), metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), canBeClosed: false, controllers: masterControllers, transition: transition)
|
||||||
|
self.detailContainer.update(layout: ContainerViewLayout(size: CGSize(width: detailWidth, height: layout.size.height), metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), canBeClosed: true, controllers: detailControllers, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -6,6 +6,8 @@ class ScrollToTopView: UIScrollView, UIScrollViewDelegate {
|
|||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
self.isOpaque = false
|
||||||
|
self.backgroundColor = .clear
|
||||||
self.delegate = self
|
self.delegate = self
|
||||||
self.scrollsToTop = true
|
self.scrollsToTop = true
|
||||||
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
||||||
|
@ -11,4 +11,6 @@ public protocol StatusBarHost {
|
|||||||
var keyboardView: UIView? { get }
|
var keyboardView: UIView? { get }
|
||||||
|
|
||||||
var handleVolumeControl: Signal<Bool, NoError> { get }
|
var handleVolumeControl: Signal<Bool, NoError> { get }
|
||||||
|
|
||||||
|
func setStatusBarStyle(_ style: UIStatusBarStyle, animated: Bool)
|
||||||
}
|
}
|
||||||
|
@ -278,7 +278,7 @@ class StatusBarManager {
|
|||||||
}
|
}
|
||||||
self.volumeControlStatusBarNode.isDark = isDark
|
self.volumeControlStatusBarNode.isDark = isDark
|
||||||
|
|
||||||
if let globalStatusBar = globalStatusBar, !forceHiddenBySystemWindows {
|
/*if let globalStatusBar = globalStatusBar, !forceHiddenBySystemWindows {
|
||||||
let statusBarStyle: UIStatusBarStyle
|
let statusBarStyle: UIStatusBarStyle
|
||||||
if forceInCallStatusBarText != nil {
|
if forceInCallStatusBarText != nil {
|
||||||
statusBarStyle = .lightContent
|
statusBarStyle = .lightContent
|
||||||
@ -298,6 +298,6 @@ class StatusBarManager {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
statusBarView.alpha = 0.0
|
statusBarView.alpha = 0.0
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,8 @@ open class ViewControllerPresentationArguments {
|
|||||||
public enum ViewControllerNavigationPresentation {
|
public enum ViewControllerNavigationPresentation {
|
||||||
case `default`
|
case `default`
|
||||||
case master
|
case master
|
||||||
|
case modal
|
||||||
|
case modalInLargeLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc open class ViewController: UIViewController, ContainableController {
|
@objc open class ViewController: UIViewController, ContainableController {
|
||||||
@ -446,9 +448,9 @@ public enum ViewControllerNavigationPresentation {
|
|||||||
|
|
||||||
override open func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
|
override open func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||||
if let navigationController = self.navigationController as? NavigationController {
|
if let navigationController = self.navigationController as? NavigationController {
|
||||||
navigationController.dismiss(animated: flag, completion: completion)
|
navigationController.filterController(self, animated: flag)
|
||||||
} else {
|
} else {
|
||||||
super.dismiss(animated: flag, completion: completion)
|
assertionFailure()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,6 +509,7 @@ public enum ViewControllerNavigationPresentation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open func dismiss(completion: (() -> Void)? = nil) {
|
open func dismiss(completion: (() -> Void)? = nil) {
|
||||||
|
(self.navigationController as? NavigationController)?.filterController(self, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOSApplicationExtension 9.0, iOS 9.0, *)
|
@available(iOSApplicationExtension 9.0, iOS 9.0, *)
|
||||||
|
@ -692,6 +692,10 @@ public class Window1 {
|
|||||||
self._rootController = value
|
self._rootController = value
|
||||||
|
|
||||||
if let rootController = self._rootController {
|
if let rootController = self._rootController {
|
||||||
|
if let rootController = rootController as? NavigationController {
|
||||||
|
rootController.statusBarHost = self.statusBarHost
|
||||||
|
rootController.keyboardManager = self.keyboardManager
|
||||||
|
}
|
||||||
if !self.windowLayout.size.width.isZero && !self.windowLayout.size.height.isZero {
|
if !self.windowLayout.size.width.isZero && !self.windowLayout.size.height.isZero {
|
||||||
rootController.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout, deviceMetrics: self.deviceMetrics), transition: .immediate)
|
rootController.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout, deviceMetrics: self.deviceMetrics), transition: .immediate)
|
||||||
}
|
}
|
||||||
@ -803,7 +807,7 @@ public class Window1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keyboardManager.surfaces = keyboardSurfaces
|
//keyboardManager.surfaces = keyboardSurfaces
|
||||||
|
|
||||||
var supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .all)
|
var supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .all)
|
||||||
let orientationToLock: UIInterfaceOrientationMask
|
let orientationToLock: UIInterfaceOrientationMask
|
||||||
|
@ -62,7 +62,6 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
var currentAccessibilityAreas: [AccessibilityAreaNode] = []
|
var currentAccessibilityAreas: [AccessibilityAreaNode] = []
|
||||||
|
|
||||||
private var previousContentOffset: CGPoint?
|
|
||||||
private var isDeceleratingBecauseOfDragging = false
|
private var isDeceleratingBecauseOfDragging = false
|
||||||
|
|
||||||
private let hiddenMediaDisposable = MetaDisposable()
|
private let hiddenMediaDisposable = MetaDisposable()
|
||||||
@ -372,7 +371,6 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
self.scrollNode.view.contentOffset = contentOffset
|
self.scrollNode.view.contentOffset = contentOffset
|
||||||
if didSetScrollOffset {
|
if didSetScrollOffset {
|
||||||
self.previousContentOffset = contentOffset
|
|
||||||
self.updateNavigationBar()
|
self.updateNavigationBar()
|
||||||
if self.currentLayout != nil {
|
if self.currentLayout != nil {
|
||||||
self.setupScrollOffsetOnLayout = false
|
self.setupScrollOffsetOnLayout = false
|
||||||
@ -660,8 +658,6 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
self.updateVisibleItems(visibleBounds: self.scrollNode.view.bounds)
|
self.updateVisibleItems(visibleBounds: self.scrollNode.view.bounds)
|
||||||
self.updateNavigationBar()
|
|
||||||
self.previousContentOffset = self.scrollNode.view.contentOffset
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||||||
@ -694,50 +690,14 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
minBarHeight = 20.0
|
minBarHeight = 20.0
|
||||||
}
|
}
|
||||||
|
|
||||||
var pageProgress: CGFloat = 0.0
|
|
||||||
if !self.scrollNode.view.contentSize.height.isZero {
|
|
||||||
let value = (contentOffset.y + self.scrollNode.view.contentInset.top) / (self.scrollNode.view.contentSize.height - bounds.size.height + self.scrollNode.view.contentInset.top)
|
|
||||||
pageProgress = max(0.0, min(1.0, value))
|
|
||||||
}
|
|
||||||
|
|
||||||
let delta: CGFloat
|
|
||||||
if self.setupScrollOffsetOnLayout {
|
|
||||||
delta = 0.0
|
|
||||||
} else if let previousContentOffset = self.previousContentOffset {
|
|
||||||
delta = contentOffset.y - previousContentOffset.y
|
|
||||||
} else {
|
|
||||||
delta = 0.0
|
|
||||||
}
|
|
||||||
self.previousContentOffset = contentOffset
|
|
||||||
|
|
||||||
var transition: ContainedViewLayoutTransition = .immediate
|
var transition: ContainedViewLayoutTransition = .immediate
|
||||||
var navigationBarFrame = self.navigationBar.frame
|
var navigationBarFrame = self.navigationBar.frame
|
||||||
navigationBarFrame.size.width = bounds.size.width
|
navigationBarFrame.size.width = bounds.size.width
|
||||||
if navigationBarFrame.size.height.isZero {
|
if navigationBarFrame.size.height.isZero {
|
||||||
navigationBarFrame.size.height = maxBarHeight
|
navigationBarFrame.size.height = maxBarHeight
|
||||||
}
|
}
|
||||||
if forceState {
|
|
||||||
transition = .animated(duration: 0.3, curve: .spring)
|
|
||||||
|
|
||||||
let transitionFactor = (navigationBarFrame.size.height - minBarHeight) / (maxBarHeight - minBarHeight)
|
|
||||||
|
|
||||||
if contentOffset.y <= -self.scrollNode.view.contentInset.top || transitionFactor > 0.4 {
|
|
||||||
navigationBarFrame.size.height = maxBarHeight
|
navigationBarFrame.size.height = maxBarHeight
|
||||||
} else {
|
|
||||||
navigationBarFrame.size.height = minBarHeight
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if contentOffset.y <= -self.scrollNode.view.contentInset.top {
|
|
||||||
navigationBarFrame.size.height = maxBarHeight
|
|
||||||
} else {
|
|
||||||
navigationBarFrame.size.height -= delta
|
|
||||||
}
|
|
||||||
navigationBarFrame.size.height = max(minBarHeight, min(maxBarHeight, navigationBarFrame.size.height))
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.setupScrollOffsetOnLayout {
|
|
||||||
navigationBarFrame.size.height = maxBarHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
let transitionFactor = (navigationBarFrame.size.height - minBarHeight) / (maxBarHeight - minBarHeight)
|
let transitionFactor = (navigationBarFrame.size.height - minBarHeight) / (maxBarHeight - minBarHeight)
|
||||||
|
|
||||||
@ -756,7 +716,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
transition.updateFrame(node: self.navigationBar, frame: navigationBarFrame)
|
transition.updateFrame(node: self.navigationBar, frame: navigationBarFrame)
|
||||||
self.navigationBar.updateLayout(size: navigationBarFrame.size, minHeight: minBarHeight, maxHeight: maxBarHeight, topInset: containerLayout.safeInsets.top, leftInset: containerLayout.safeInsets.left, rightInset: containerLayout.safeInsets.right, title: title, pageProgress: pageProgress, transition: transition)
|
self.navigationBar.updateLayout(size: navigationBarFrame.size, minHeight: minBarHeight, maxHeight: maxBarHeight, topInset: containerLayout.safeInsets.top, leftInset: containerLayout.safeInsets.left, rightInset: containerLayout.safeInsets.right, title: title, pageProgress: 0.0, transition: transition)
|
||||||
|
|
||||||
transition.animateView {
|
transition.animateView {
|
||||||
self.scrollNode.view.scrollIndicatorInsets = UIEdgeInsets(top: navigationBarFrame.size.height, left: 0.0, bottom: containerLayout.intrinsicInsets.bottom, right: 0.0)
|
self.scrollNode.view.scrollIndicatorInsets = UIEdgeInsets(top: navigationBarFrame.size.height, left: 0.0, bottom: containerLayout.intrinsicInsets.bottom, right: 0.0)
|
||||||
|
@ -505,14 +505,6 @@ open class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShor
|
|||||||
self.didDisappear?(animated)
|
self.didDisappear?(animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func dismiss(completion: (() -> Void)? = nil) {
|
|
||||||
if !self.isDismissed {
|
|
||||||
self.isDismissed = true
|
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).animateOut(completion: completion)
|
|
||||||
self.updateTransitionWhenPresentedAsModal?(0.0, .animated(duration: 0.2, curve: .easeInOut))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func frameForItemNode(_ predicate: (ListViewItemNode) -> Bool) -> CGRect? {
|
public func frameForItemNode(_ predicate: (ListViewItemNode) -> Bool) -> CGRect? {
|
||||||
var result: CGRect?
|
var result: CGRect?
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).listNode.forEachItemNode { itemNode in
|
(self.displayNode as! ItemListControllerNode<Entry>).listNode.forEachItemNode { itemNode in
|
||||||
|
@ -508,7 +508,7 @@ open class LegacyController: ViewController, PresentableController {
|
|||||||
case .custom:
|
case .custom:
|
||||||
self.presentingViewController?.dismiss(animated: false, completion: completion)
|
self.presentingViewController?.dismiss(animated: false, completion: completion)
|
||||||
case .navigation:
|
case .navigation:
|
||||||
break
|
(self.navigationController as? NavigationController)?.filterController(self, animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,8 @@ private func generateClearIcon(color: UIColor) -> UIImage? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func legacyLocationPickerController(context: AccountContext, selfPeer: Peer, peer: Peer, sendLocation: @escaping (CLLocationCoordinate2D, MapVenue?, String?) -> Void, sendLiveLocation: @escaping (CLLocationCoordinate2D, Int32) -> Void, theme: PresentationTheme, customLocationPicker: Bool = false, hasLiveLocation: Bool = true, presentationCompleted: @escaping () -> Void = {}) -> ViewController {
|
public func legacyLocationPickerController(context: AccountContext, selfPeer: Peer, peer: Peer, sendLocation: @escaping (CLLocationCoordinate2D, MapVenue?, String?) -> Void, sendLiveLocation: @escaping (CLLocationCoordinate2D, Int32) -> Void, theme: PresentationTheme, customLocationPicker: Bool = false, hasLiveLocation: Bool = true, presentationCompleted: @escaping () -> Void = {}) -> ViewController {
|
||||||
let legacyController = LegacyController(presentation: .modal(animateIn: true), theme: theme)
|
let legacyController = LegacyController(presentation: .navigation, theme: theme)
|
||||||
|
legacyController.navigationPresentation = .modal
|
||||||
legacyController.presentationCompleted = {
|
legacyController.presentationCompleted = {
|
||||||
presentationCompleted()
|
presentationCompleted()
|
||||||
}
|
}
|
||||||
|
@ -1105,6 +1105,7 @@ public func channelAdminController(context: AccountContext, peerId: PeerId, admi
|
|||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(context: context, state: signal)
|
let controller = ItemListController(context: context, state: signal)
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
controller.experimentalSnapScrollToItem = true
|
controller.experimentalSnapScrollToItem = true
|
||||||
dismissImpl = { [weak controller] in
|
dismissImpl = { [weak controller] in
|
||||||
controller?.view.endEditing(true)
|
controller?.view.endEditing(true)
|
||||||
|
@ -600,20 +600,20 @@ public func channelAdminsController(context: AccountContext, peerId: PeerId, loa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
presentControllerImpl?(channelAdminController(context: context, peerId: peerId, adminId: peer.id, initialParticipant: participant?.participant, updated: { _ in
|
pushControllerImpl?(channelAdminController(context: context, peerId: peerId, adminId: peer.id, initialParticipant: participant?.participant, updated: { _ in
|
||||||
}, upgradedToSupergroup: upgradedToSupergroup, transferedOwnership: transferedOwnership), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}, upgradedToSupergroup: upgradedToSupergroup, transferedOwnership: transferedOwnership))
|
||||||
})
|
})
|
||||||
dismissController = { [weak controller] in
|
dismissController = { [weak controller] in
|
||||||
controller?.dismiss()
|
controller?.dismiss()
|
||||||
}
|
}
|
||||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
pushControllerImpl?(controller)
|
||||||
|
|
||||||
return current
|
return current
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, openAdmin: { participant in
|
}, openAdmin: { participant in
|
||||||
presentControllerImpl?(channelAdminController(context: context, peerId: peerId, adminId: participant.peerId, initialParticipant: participant, updated: { _ in
|
pushControllerImpl?(channelAdminController(context: context, peerId: peerId, adminId: participant.peerId, initialParticipant: participant, updated: { _ in
|
||||||
}, upgradedToSupergroup: upgradedToSupergroup, transferedOwnership: transferedOwnership), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}, upgradedToSupergroup: upgradedToSupergroup, transferedOwnership: transferedOwnership))
|
||||||
})
|
})
|
||||||
|
|
||||||
let membersAndLoadMoreControl: (Disposable, PeerChannelMemberCategoryControl?)
|
let membersAndLoadMoreControl: (Disposable, PeerChannelMemberCategoryControl?)
|
||||||
@ -734,14 +734,14 @@ public func channelAdminsController(context: AccountContext, peerId: PeerId, loa
|
|||||||
}
|
}
|
||||||
}, openPeer: { _, participant in
|
}, openPeer: { _, participant in
|
||||||
if let participant = participant?.participant, case .member = participant {
|
if let participant = participant?.participant, case .member = participant {
|
||||||
presentControllerImpl?(channelAdminController(context: context, peerId: peerId, adminId: participant.peerId, initialParticipant: participant, updated: { _ in
|
pushControllerImpl?(channelAdminController(context: context, peerId: peerId, adminId: participant.peerId, initialParticipant: participant, updated: { _ in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
return state.withUpdatedSearchingMembers(false)
|
return state.withUpdatedSearchingMembers(false)
|
||||||
}
|
}
|
||||||
}, upgradedToSupergroup: upgradedToSupergroup, transferedOwnership: transferedOwnership), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}, upgradedToSupergroup: upgradedToSupergroup, transferedOwnership: transferedOwnership))
|
||||||
}
|
}
|
||||||
}, present: { c, a in
|
}, pushController: { c in
|
||||||
presentControllerImpl?(c, a)
|
pushControllerImpl?(c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,8 +486,8 @@ public func channelBlacklistController(context: AccountContext, peerId: PeerId)
|
|||||||
if let rendered = rendered, case .member = rendered.participant {
|
if let rendered = rendered, case .member = rendered.participant {
|
||||||
arguments.openPeer(rendered)
|
arguments.openPeer(rendered)
|
||||||
}
|
}
|
||||||
}, present: { c, a in
|
}, pushController: { c in
|
||||||
presentControllerImpl?(c, a)
|
pushControllerImpl?(c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,8 +403,8 @@ public func channelMembersController(context: AccountContext, peerId: PeerId) ->
|
|||||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Channel_AddBotErrorHaveRights, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Channel_AddBotAsAdmin, action: {
|
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Channel_AddBotErrorHaveRights, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Channel_AddBotAsAdmin, action: {
|
||||||
contactsController?.dismiss()
|
contactsController?.dismiss()
|
||||||
|
|
||||||
presentControllerImpl?(channelAdminController(context: context, peerId: peerId, adminId: memberId, initialParticipant: nil, updated: { _ in
|
pushControllerImpl?(channelAdminController(context: context, peerId: peerId, adminId: memberId, initialParticipant: nil, updated: { _ in
|
||||||
}, upgradedToSupergroup: { _, f in f () }, transferedOwnership: { _ in }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}, upgradedToSupergroup: { _, f in f () }, transferedOwnership: { _ in }))
|
||||||
})]), nil)
|
})]), nil)
|
||||||
} else {
|
} else {
|
||||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Channel_AddBotErrorHaveRights, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Channel_AddBotErrorHaveRights, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||||
@ -500,8 +500,8 @@ public func channelMembersController(context: AccountContext, peerId: PeerId) ->
|
|||||||
if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) {
|
if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) {
|
||||||
pushControllerImpl?(infoController)
|
pushControllerImpl?(infoController)
|
||||||
}
|
}
|
||||||
}, present: { c, a in
|
}, pushController: { c in
|
||||||
presentControllerImpl?(c, a)
|
pushControllerImpl?(c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,7 +296,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
|
|||||||
|
|
||||||
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, PresentationDateTimeFormat)>
|
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, PresentationDateTimeFormat)>
|
||||||
|
|
||||||
init(context: AccountContext, peerId: PeerId, mode: ChannelMembersSearchMode, filters: [ChannelMembersSearchFilter], searchContext: GroupMembersSearchContext?, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, updateActivity: @escaping (Bool) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
init(context: AccountContext, peerId: PeerId, mode: ChannelMembersSearchMode, filters: [ChannelMembersSearchFilter], searchContext: GroupMembersSearchContext?, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, updateActivity: @escaping (Bool) -> Void, pushController: @escaping (ViewController) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.openPeer = openPeer
|
self.openPeer = openPeer
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
@ -341,16 +341,16 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
|
|||||||
state.revealedPeerId = nil
|
state.revealedPeerId = nil
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
present(channelAdminController(context: context, peerId: peerId, adminId: participant.peer.id, initialParticipant: participant.participant, updated: { _ in
|
pushController(channelAdminController(context: context, peerId: peerId, adminId: participant.peer.id, initialParticipant: participant.participant, updated: { _ in
|
||||||
}, upgradedToSupergroup: { _, f in f() }, transferedOwnership: { _ in }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}, upgradedToSupergroup: { _, f in f() }, transferedOwnership: { _ in }))
|
||||||
}, restrictPeer: { participant in
|
}, restrictPeer: { participant in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var state = state
|
var state = state
|
||||||
state.revealedPeerId = nil
|
state.revealedPeerId = nil
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
present(channelBannedMemberController(context: context, peerId: peerId, memberId: participant.peer.id, initialParticipant: participant.participant, updated: { _ in
|
pushController(channelBannedMemberController(context: context, peerId: peerId, memberId: participant.peer.id, initialParticipant: participant.participant, updated: { _ in
|
||||||
}, upgradedToSupergroup: { _, f in f() }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}, upgradedToSupergroup: { _, f in f() }))
|
||||||
}, removePeer: { memberId in
|
}, removePeer: { memberId in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var state = state
|
var state = state
|
||||||
|
@ -47,6 +47,8 @@ final class ChannelMembersSearchController: ViewController {
|
|||||||
|
|
||||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||||
|
|
||||||
|
self.navigationPresentation = .modal
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||||
|
|
||||||
self.title = self.presentationData.strings.Channel_Members_Title
|
self.title = self.presentationData.strings.Channel_Members_Title
|
||||||
@ -83,8 +85,8 @@ final class ChannelMembersSearchController: ViewController {
|
|||||||
self.controllerNode.requestOpenPeerFromSearch = { [weak self] peer, participant in
|
self.controllerNode.requestOpenPeerFromSearch = { [weak self] peer, participant in
|
||||||
self?.openPeer(peer, participant)
|
self?.openPeer(peer, participant)
|
||||||
}
|
}
|
||||||
self.controllerNode.present = { [weak self] c, a in
|
self.controllerNode.pushController = { [weak self] c in
|
||||||
self?.present(c, in: .window(.root), with: a)
|
(self?.navigationController as? NavigationController)?.pushViewController(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.displayNodeDidLoad()
|
self.displayNodeDidLoad()
|
||||||
@ -113,14 +115,6 @@ final class ChannelMembersSearchController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func dismiss(completion: (() -> Void)? = nil) {
|
|
||||||
self.view.endEditing(true)
|
|
||||||
self.controllerNode.animateOut(completion: { [weak self] in
|
|
||||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
|
||||||
completion?()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
super.containerLayoutUpdated(layout, transition: transition)
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ class ChannelMembersSearchControllerNode: ASDisplayNode {
|
|||||||
var requestActivateSearch: (() -> Void)?
|
var requestActivateSearch: (() -> Void)?
|
||||||
var requestDeactivateSearch: (() -> Void)?
|
var requestDeactivateSearch: (() -> Void)?
|
||||||
var requestOpenPeerFromSearch: ((Peer, RenderedChannelParticipant?) -> Void)?
|
var requestOpenPeerFromSearch: ((Peer, RenderedChannelParticipant?) -> Void)?
|
||||||
var present: ((ViewController, Any?) -> Void)?
|
var pushController: ((ViewController) -> Void)?
|
||||||
|
|
||||||
var presentationData: PresentationData
|
var presentationData: PresentationData
|
||||||
|
|
||||||
@ -362,8 +362,8 @@ class ChannelMembersSearchControllerNode: ASDisplayNode {
|
|||||||
self?.requestOpenPeerFromSearch?(peer, participant)
|
self?.requestOpenPeerFromSearch?(peer, participant)
|
||||||
}, updateActivity: { value in
|
}, updateActivity: { value in
|
||||||
|
|
||||||
}, present: { [weak self] c, a in
|
}, pushController: { [weak self] c in
|
||||||
self?.present?(c, a)
|
self?.pushController?(c)
|
||||||
}), cancel: { [weak self] in
|
}), cancel: { [weak self] in
|
||||||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||||
requestDeactivateSearch()
|
requestDeactivateSearch()
|
||||||
|
@ -797,8 +797,8 @@ public func channelPermissionsController(context: AccountContext, peerId origina
|
|||||||
upgradedToSupergroupImpl?(upgradedPeerId, f)
|
upgradedToSupergroupImpl?(upgradedPeerId, f)
|
||||||
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
}
|
}
|
||||||
}, present: { c, a in
|
}, pushController: { c in
|
||||||
presentControllerImpl?(c, a)
|
pushControllerImpl?(c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -811,6 +811,7 @@ public func deviceContactInfoController(context: AccountContext, subject: Device
|
|||||||
var addToExistingImpl: (() -> Void)?
|
var addToExistingImpl: (() -> Void)?
|
||||||
var openChatImpl: ((PeerId) -> Void)?
|
var openChatImpl: ((PeerId) -> Void)?
|
||||||
var replaceControllerImpl: ((ViewController) -> Void)?
|
var replaceControllerImpl: ((ViewController) -> Void)?
|
||||||
|
var pushControllerImpl: ((ViewController) -> Void)?
|
||||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||||
var openUrlImpl: ((String) -> Void)?
|
var openUrlImpl: ((String) -> Void)?
|
||||||
var openAddressImpl: ((DeviceContactAddressData) -> Void)?
|
var openAddressImpl: ((DeviceContactAddressData) -> Void)?
|
||||||
@ -908,7 +909,7 @@ public func deviceContactInfoController(context: AccountContext, subject: Device
|
|||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
}, updatePhoneLabel: { id, currentLabel in
|
}, updatePhoneLabel: { id, currentLabel in
|
||||||
presentControllerImpl?(phoneLabelController(context: context, currentLabel: currentLabel, completion: { value in
|
pushControllerImpl?(phoneLabelController(context: context, currentLabel: currentLabel, completion: { value in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var state = state
|
var state = state
|
||||||
for i in 0 ..< state.phoneNumbers.count {
|
for i in 0 ..< state.phoneNumbers.count {
|
||||||
@ -919,7 +920,7 @@ public func deviceContactInfoController(context: AccountContext, subject: Device
|
|||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}))
|
||||||
}, deletePhone: { id in
|
}, deletePhone: { id in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var state = state
|
var state = state
|
||||||
@ -976,14 +977,14 @@ public func deviceContactInfoController(context: AccountContext, subject: Device
|
|||||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
}
|
}
|
||||||
case .createContact:
|
case .createContact:
|
||||||
presentControllerImpl?(deviceContactInfoController(context: context, subject: .create(peer: subject.peer, contactData: subject.contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
pushControllerImpl?(deviceContactInfoController(context: context, subject: .create(peer: subject.peer, contactData: subject.contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
||||||
dismissImpl?(false)
|
dismissImpl?(false)
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
}), completed: nil, cancelled: nil), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}), completed: nil, cancelled: nil))
|
||||||
case .addToExisting:
|
case .addToExisting:
|
||||||
addToExistingImpl?()
|
addToExistingImpl?()
|
||||||
case .sendMessage:
|
case .sendMessage:
|
||||||
@ -1210,6 +1211,7 @@ public func deviceContactInfoController(context: AccountContext, subject: Device
|
|||||||
}
|
}
|
||||||
|
|
||||||
let controller = DeviceContactInfoController(context: context, state: signal)
|
let controller = DeviceContactInfoController(context: context, state: signal)
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
addToExistingImpl = { [weak controller] in
|
addToExistingImpl = { [weak controller] in
|
||||||
guard let controller = controller else {
|
guard let controller = controller else {
|
||||||
return
|
return
|
||||||
@ -1226,6 +1228,9 @@ public func deviceContactInfoController(context: AccountContext, subject: Device
|
|||||||
replaceControllerImpl = { [weak controller] value in
|
replaceControllerImpl = { [weak controller] value in
|
||||||
(controller?.navigationController as? NavigationController)?.replaceTopController(value, animated: true)
|
(controller?.navigationController as? NavigationController)?.replaceTopController(value, animated: true)
|
||||||
}
|
}
|
||||||
|
pushControllerImpl = { [weak controller] c in
|
||||||
|
(controller?.navigationController as? NavigationController)?.pushViewController(c)
|
||||||
|
}
|
||||||
presentControllerImpl = { [weak controller] value, presentationArguments in
|
presentControllerImpl = { [weak controller] value, presentationArguments in
|
||||||
controller?.present(value, in: .window(.root), with: presentationArguments)
|
controller?.present(value, in: .window(.root), with: presentationArguments)
|
||||||
}
|
}
|
||||||
@ -1293,7 +1298,8 @@ public func deviceContactInfoController(context: AccountContext, subject: Device
|
|||||||
|
|
||||||
private func addContactToExisting(context: AccountContext, parentController: ViewController, contactData: DeviceContactExtendedData, completion: @escaping (Peer?, DeviceContactStableId, DeviceContactExtendedData) -> Void) {
|
private func addContactToExisting(context: AccountContext, parentController: ViewController, contactData: DeviceContactExtendedData, completion: @escaping (Peer?, DeviceContactStableId, DeviceContactExtendedData) -> Void) {
|
||||||
let contactsController = context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(context: context, title: { $0.Contacts_Title }, displayDeviceContacts: true))
|
let contactsController = context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(context: context, title: { $0.Contacts_Title }, displayDeviceContacts: true))
|
||||||
parentController.present(contactsController, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
contactsController.navigationPresentation = .modal
|
||||||
|
(parentController.navigationController as? NavigationController)?.pushViewController(contactsController)
|
||||||
let _ = (contactsController.result
|
let _ = (contactsController.result
|
||||||
|> deliverOnMainQueue).start(next: { peer in
|
|> deliverOnMainQueue).start(next: { peer in
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
|
@ -1868,10 +1868,10 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
|
|||||||
let _ = (peerView.get()
|
let _ = (peerView.get()
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { peerView in
|
|> deliverOnMainQueue).start(next: { peerView in
|
||||||
presentControllerImpl?(channelAdminController(context: context, peerId: peerView.peerId, adminId: participant.peer.id, initialParticipant: participant.participant, updated: { _ in
|
pushControllerImpl?(channelAdminController(context: context, peerId: peerView.peerId, adminId: participant.peer.id, initialParticipant: participant.participant, updated: { _ in
|
||||||
}, upgradedToSupergroup: { upgradedPeerId, f in
|
}, upgradedToSupergroup: { upgradedPeerId, f in
|
||||||
upgradedToSupergroupImpl?(upgradedPeerId, f)
|
upgradedToSupergroupImpl?(upgradedPeerId, f)
|
||||||
}, transferedOwnership: { _ in }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}, transferedOwnership: { _ in }))
|
||||||
})
|
})
|
||||||
}, restrictPeer: { participant in
|
}, restrictPeer: { participant in
|
||||||
let _ = (peerView.get()
|
let _ = (peerView.get()
|
||||||
@ -2257,8 +2257,8 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
|
|||||||
if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) {
|
if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) {
|
||||||
arguments.pushController(infoController)
|
arguments.pushController(infoController)
|
||||||
}
|
}
|
||||||
}, present: { c, a in
|
}, pushController: { c in
|
||||||
presentControllerImpl?(c, a)
|
pushControllerImpl?(c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,20 +14,20 @@ final class ChannelMembersSearchItem: ItemListControllerSearch {
|
|||||||
let searchContext: GroupMembersSearchContext?
|
let searchContext: GroupMembersSearchContext?
|
||||||
let cancel: () -> Void
|
let cancel: () -> Void
|
||||||
let openPeer: (Peer, RenderedChannelParticipant?) -> Void
|
let openPeer: (Peer, RenderedChannelParticipant?) -> Void
|
||||||
let present: (ViewController, Any?) -> Void
|
let pushController: (ViewController) -> Void
|
||||||
let searchMode: ChannelMembersSearchMode
|
let searchMode: ChannelMembersSearchMode
|
||||||
|
|
||||||
private var updateActivity: ((Bool) -> Void)?
|
private var updateActivity: ((Bool) -> Void)?
|
||||||
private var activity: ValuePromise<Bool> = ValuePromise(ignoreRepeated: false)
|
private var activity: ValuePromise<Bool> = ValuePromise(ignoreRepeated: false)
|
||||||
private let activityDisposable = MetaDisposable()
|
private let activityDisposable = MetaDisposable()
|
||||||
|
|
||||||
init(context: AccountContext, peerId: PeerId, searchContext: GroupMembersSearchContext?, searchMode: ChannelMembersSearchMode = .searchMembers, cancel: @escaping () -> Void, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
init(context: AccountContext, peerId: PeerId, searchContext: GroupMembersSearchContext?, searchMode: ChannelMembersSearchMode = .searchMembers, cancel: @escaping () -> Void, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, pushController: @escaping (ViewController) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.searchContext = searchContext
|
self.searchContext = searchContext
|
||||||
self.cancel = cancel
|
self.cancel = cancel
|
||||||
self.openPeer = openPeer
|
self.openPeer = openPeer
|
||||||
self.present = present
|
self.pushController = pushController
|
||||||
self.searchMode = searchMode
|
self.searchMode = searchMode
|
||||||
activityDisposable.set((activity.get() |> mapToSignal { value -> Signal<Bool, NoError> in
|
activityDisposable.set((activity.get() |> mapToSignal { value -> Signal<Bool, NoError> in
|
||||||
if value {
|
if value {
|
||||||
@ -73,8 +73,8 @@ final class ChannelMembersSearchItem: ItemListControllerSearch {
|
|||||||
func node(current: ItemListControllerSearchNode?, titleContentNode: (NavigationBarContentNode & ItemListControllerSearchNavigationContentNode)?) -> ItemListControllerSearchNode {
|
func node(current: ItemListControllerSearchNode?, titleContentNode: (NavigationBarContentNode & ItemListControllerSearchNavigationContentNode)?) -> ItemListControllerSearchNode {
|
||||||
return ChannelMembersSearchItemNode(context: self.context, peerId: self.peerId, searchMode: self.searchMode, searchContext: self.searchContext, openPeer: self.openPeer, cancel: self.cancel, updateActivity: { [weak self] value in
|
return ChannelMembersSearchItemNode(context: self.context, peerId: self.peerId, searchMode: self.searchMode, searchContext: self.searchContext, openPeer: self.openPeer, cancel: self.cancel, updateActivity: { [weak self] value in
|
||||||
self?.activity.set(value)
|
self?.activity.set(value)
|
||||||
}, present: { [weak self] c, a in
|
}, pushController: { [weak self] c in
|
||||||
self?.present(c, a)
|
self?.pushController(c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,10 +82,10 @@ final class ChannelMembersSearchItem: ItemListControllerSearch {
|
|||||||
private final class ChannelMembersSearchItemNode: ItemListControllerSearchNode {
|
private final class ChannelMembersSearchItemNode: ItemListControllerSearchNode {
|
||||||
private let containerNode: ChannelMembersSearchContainerNode
|
private let containerNode: ChannelMembersSearchContainerNode
|
||||||
|
|
||||||
init(context: AccountContext, peerId: PeerId, searchMode: ChannelMembersSearchMode, searchContext: GroupMembersSearchContext?, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, cancel: @escaping () -> Void, updateActivity: @escaping(Bool) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
init(context: AccountContext, peerId: PeerId, searchMode: ChannelMembersSearchMode, searchContext: GroupMembersSearchContext?, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, cancel: @escaping () -> Void, updateActivity: @escaping(Bool) -> Void, pushController: @escaping (ViewController) -> Void) {
|
||||||
self.containerNode = ChannelMembersSearchContainerNode(context: context, peerId: peerId, mode: searchMode, filters: [], searchContext: searchContext, openPeer: { peer, participant in
|
self.containerNode = ChannelMembersSearchContainerNode(context: context, peerId: peerId, mode: searchMode, filters: [], searchContext: searchContext, openPeer: { peer, participant in
|
||||||
openPeer(peer, participant)
|
openPeer(peer, participant)
|
||||||
}, updateActivity: updateActivity, present: present)
|
}, updateActivity: updateActivity, pushController: pushController)
|
||||||
self.containerNode.cancel = {
|
self.containerNode.cancel = {
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,7 @@ public func phoneLabelController(context: AccountContext, currentLabel: String,
|
|||||||
let controller = ItemListController(context: context, state: signal
|
let controller = ItemListController(context: context, state: signal
|
||||||
|> afterDisposed {
|
|> afterDisposed {
|
||||||
})
|
})
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
controller.enableInteractiveDismiss = true
|
controller.enableInteractiveDismiss = true
|
||||||
|
|
||||||
completeImpl = { [weak controller] in
|
completeImpl = { [weak controller] in
|
||||||
|
@ -766,7 +766,7 @@ private func getUserPeer(postbox: Postbox, peerId: PeerId) -> Signal<(Peer?, Cac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func openAddPersonContactImpl(context: AccountContext, peerId: PeerId, present: @escaping (ViewController, Any?) -> Void) {
|
public func openAddPersonContactImpl(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||||
let _ = (getUserPeer(postbox: context.account.postbox, peerId: peerId)
|
let _ = (getUserPeer(postbox: context.account.postbox, peerId: peerId)
|
||||||
|> deliverOnMainQueue).start(next: { peer, cachedData in
|
|> deliverOnMainQueue).start(next: { peer, cachedData in
|
||||||
guard let user = peer as? TelegramUser, let contactData = DeviceContactExtendedData(peer: user) else {
|
guard let user = peer as? TelegramUser, let contactData = DeviceContactExtendedData(peer: user) else {
|
||||||
@ -778,7 +778,7 @@ public func openAddPersonContactImpl(context: AccountContext, peerId: PeerId, pr
|
|||||||
shareViaException = peerStatusSettings.contains(.addExceptionWhenAddingContact)
|
shareViaException = peerStatusSettings.contains(.addExceptionWhenAddingContact)
|
||||||
}
|
}
|
||||||
|
|
||||||
present(deviceContactInfoController(context: context, subject: .create(peer: user, contactData: contactData, isSharing: true, shareViaException: shareViaException, completion: { peer, stableId, contactData in
|
pushController(deviceContactInfoController(context: context, subject: .create(peer: user, contactData: contactData, isSharing: true, shareViaException: shareViaException, completion: { peer, stableId, contactData in
|
||||||
if let peer = peer as? TelegramUser {
|
if let peer = peer as? TelegramUser {
|
||||||
if let phone = peer.phone, !phone.isEmpty {
|
if let phone = peer.phone, !phone.isEmpty {
|
||||||
}
|
}
|
||||||
@ -786,7 +786,7 @@ public func openAddPersonContactImpl(context: AccountContext, peerId: PeerId, pr
|
|||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
present(OverlayStatusController(theme: presentationData.theme, strings: presentationData.strings, type: .genericSuccess(presentationData.strings.AddContact_StatusSuccess(peer.compactDisplayTitle).0, true)), nil)
|
present(OverlayStatusController(theme: presentationData.theme, strings: presentationData.strings, type: .genericSuccess(presentationData.strings.AddContact_StatusSuccess(peer.compactDisplayTitle).0, true)), nil)
|
||||||
}
|
}
|
||||||
}), completed: nil, cancelled: nil), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}), completed: nil, cancelled: nil))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -916,7 +916,9 @@ public func userInfoController(context: AccountContext, peerId: PeerId, mode: Pe
|
|||||||
}, openChat: {
|
}, openChat: {
|
||||||
openChatImpl?()
|
openChatImpl?()
|
||||||
}, addContact: {
|
}, addContact: {
|
||||||
openAddPersonContactImpl(context: context, peerId: peerId, present: { c, a in
|
openAddPersonContactImpl(context: context, peerId: peerId, pushController: { c in
|
||||||
|
pushControllerImpl?(c)
|
||||||
|
}, present: { c, a in
|
||||||
presentControllerImpl?(c, a)
|
presentControllerImpl?(c, a)
|
||||||
})
|
})
|
||||||
}, shareContact: {
|
}, shareContact: {
|
||||||
|
@ -315,7 +315,7 @@ public func proxySettingsController(context: AccountContext, mode: ProxySettings
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func proxySettingsController(accountManager: AccountManager, postbox: Postbox, network: Network, mode: ProxySettingsControllerMode, theme: PresentationTheme, strings: PresentationStrings, updatedPresentationData: Signal<(theme: PresentationTheme, strings: PresentationStrings), NoError>) -> ViewController {
|
public func proxySettingsController(accountManager: AccountManager, postbox: Postbox, network: Network, mode: ProxySettingsControllerMode, theme: PresentationTheme, strings: PresentationStrings, updatedPresentationData: Signal<(theme: PresentationTheme, strings: PresentationStrings), NoError>) -> ViewController {
|
||||||
var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
|
var pushControllerImpl: ((ViewController) -> Void)?
|
||||||
var dismissImpl: (() -> Void)?
|
var dismissImpl: (() -> Void)?
|
||||||
let stateValue = Atomic(value: ProxySettingsControllerState())
|
let stateValue = Atomic(value: ProxySettingsControllerState())
|
||||||
let statePromise = ValuePromise<ProxySettingsControllerState>(stateValue.with { $0 })
|
let statePromise = ValuePromise<ProxySettingsControllerState>(stateValue.with { $0 })
|
||||||
@ -342,7 +342,7 @@ public func proxySettingsController(accountManager: AccountManager, postbox: Pos
|
|||||||
return current
|
return current
|
||||||
}).start()
|
}).start()
|
||||||
}, addNewServer: {
|
}, addNewServer: {
|
||||||
presentControllerImpl?(proxyServerSettingsController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, accountManager: accountManager, postbox: postbox, network: network, currentSettings: nil), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
pushControllerImpl?(proxyServerSettingsController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, accountManager: accountManager, postbox: postbox, network: network, currentSettings: nil))
|
||||||
}, activateServer: { server in
|
}, activateServer: { server in
|
||||||
let _ = updateProxySettingsInteractively(accountManager: accountManager, { current in
|
let _ = updateProxySettingsInteractively(accountManager: accountManager, { current in
|
||||||
var current = current
|
var current = current
|
||||||
@ -355,7 +355,7 @@ public func proxySettingsController(accountManager: AccountManager, postbox: Pos
|
|||||||
return current
|
return current
|
||||||
}).start()
|
}).start()
|
||||||
}, editServer: { server in
|
}, editServer: { server in
|
||||||
presentControllerImpl?(proxyServerSettingsController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, accountManager: accountManager, postbox: postbox, network: network, currentSettings: server), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
pushControllerImpl?(proxyServerSettingsController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, accountManager: accountManager, postbox: postbox, network: network, currentSettings: server))
|
||||||
}, removeServer: { server in
|
}, removeServer: { server in
|
||||||
let _ = updateProxySettingsInteractively(accountManager: accountManager, { current in
|
let _ = updateProxySettingsInteractively(accountManager: accountManager, { current in
|
||||||
var current = current
|
var current = current
|
||||||
@ -438,8 +438,9 @@ public func proxySettingsController(accountManager: AccountManager, postbox: Pos
|
|||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, state: signal, tabBarItem: nil)
|
let controller = ItemListController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, state: signal, tabBarItem: nil)
|
||||||
presentControllerImpl = { [weak controller] c, a in
|
controller.navigationPresentation = .modal
|
||||||
controller?.present(c, in: .window(.root), with: a)
|
pushControllerImpl = { [weak controller] c in
|
||||||
|
(controller?.navigationController as? NavigationController)?.pushViewController(c)
|
||||||
}
|
}
|
||||||
dismissImpl = { [weak controller] in
|
dismissImpl = { [weak controller] in
|
||||||
controller?.dismiss()
|
controller?.dismiss()
|
||||||
|
@ -369,6 +369,7 @@ func proxyServerSettingsController(theme: PresentationTheme, strings: Presentati
|
|||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, state: signal, tabBarItem: nil)
|
let controller = ItemListController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, state: signal, tabBarItem: nil)
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
presentImpl = { [weak controller] c, d in
|
presentImpl = { [weak controller] c, d in
|
||||||
controller?.present(c, in: .window(.root), with: d)
|
controller?.present(c, in: .window(.root), with: d)
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||||||
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: messages).start()
|
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: messages).start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arguments.presentController(controller, ViewControllerPresentationArguments(presentationAnimation: ViewControllerPresentationAnimation.modalSheet))
|
arguments.pushController(controller)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
items.append(ActionSheetButtonItem(title: "Via Email", color: .accent, action: { [weak actionSheet] in
|
items.append(ActionSheetButtonItem(title: "Via Email", color: .accent, action: { [weak actionSheet] in
|
||||||
@ -225,7 +225,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||||||
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: messages).start()
|
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: messages).start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arguments.presentController(controller, ViewControllerPresentationArguments(presentationAnimation: ViewControllerPresentationAnimation.modalSheet))
|
arguments.pushController(controller)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,7 +272,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||||||
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: messages).start()
|
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: messages).start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arguments.presentController(controller, ViewControllerPresentationArguments(presentationAnimation: ViewControllerPresentationAnimation.modalSheet))
|
arguments.pushController(controller)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
case let .sendCriticalLogs(theme):
|
case let .sendCriticalLogs(theme):
|
||||||
@ -301,7 +301,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||||||
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: messages).start()
|
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: messages).start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arguments.presentController(controller, ViewControllerPresentationArguments(presentationAnimation: ViewControllerPresentationAnimation.modalSheet))
|
arguments.pushController(controller)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ private enum SettingsEntry: ItemListNodeEntry {
|
|||||||
})
|
})
|
||||||
case let .username(theme, text, address):
|
case let .username(theme, text, address):
|
||||||
return ItemListDisclosureItem(theme: theme, title: text, label: address, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
|
return ItemListDisclosureItem(theme: theme, title: text, label: address, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
|
||||||
arguments.presentController(usernameSetupController(context: arguments.context))
|
arguments.pushController(usernameSetupController(context: arguments.context))
|
||||||
})
|
})
|
||||||
case let .addAccount(theme, text):
|
case let .addAccount(theme, text):
|
||||||
return ItemListActionItem(theme: theme, title: text, kind: .generic, alignment: .center, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
|
return ItemListActionItem(theme: theme, title: text, kind: .generic, alignment: .center, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
|
||||||
|
@ -894,7 +894,7 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
dismissInputImpl?()
|
dismissInputImpl?()
|
||||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
pushController(controller)
|
||||||
}, updateRevealedPeerId: { peerId in
|
}, updateRevealedPeerId: { peerId in
|
||||||
updateState { current in
|
updateState { current in
|
||||||
return current.withUpdatedRevealedPeerId(peerId)
|
return current.withUpdatedRevealedPeerId(peerId)
|
||||||
|
@ -239,7 +239,7 @@ public func blockedPeersController(context: AccountContext, blockedPeersContext:
|
|||||||
strongController.dismiss()
|
strongController.dismiss()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
presentControllerImpl?(controller, nil)
|
pushControllerImpl?(controller)
|
||||||
}, removePeer: { memberId in
|
}, removePeer: { memberId in
|
||||||
updateState {
|
updateState {
|
||||||
return $0.withUpdatedRemovingPeerId(memberId)
|
return $0.withUpdatedRemovingPeerId(memberId)
|
||||||
|
@ -50,6 +50,8 @@ public final class ThemePreviewController: ViewController {
|
|||||||
|
|
||||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationTheme: self.previewTheme, presentationStrings: self.presentationData.strings))
|
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationTheme: self.previewTheme, presentationStrings: self.presentationData.strings))
|
||||||
|
|
||||||
|
self.navigationPresentation = .modal
|
||||||
|
|
||||||
self.isModalWhenInOverlay = true
|
self.isModalWhenInOverlay = true
|
||||||
|
|
||||||
let themeName: String
|
let themeName: String
|
||||||
@ -333,13 +335,6 @@ public final class ThemePreviewController: ViewController {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func dismiss(completion: (() -> Void)? = nil) {
|
|
||||||
self.controllerNode.animateOut(completion: { [weak self] in
|
|
||||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
|
||||||
completion?()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
super.containerLayoutUpdated(layout, transition: transition)
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
|
||||||
|
@ -345,6 +345,7 @@ public func usernameSetupController(context: AccountContext) -> ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(context: context, state: signal)
|
let controller = ItemListController(context: context, state: signal)
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
controller.enableInteractiveDismiss = true
|
controller.enableInteractiveDismiss = true
|
||||||
dismissImpl = { [weak controller] in
|
dismissImpl = { [weak controller] in
|
||||||
controller?.view.endEditing(true)
|
controller?.view.endEditing(true)
|
||||||
|
@ -61,6 +61,13 @@ extension PeekControllerTheme {
|
|||||||
|
|
||||||
public extension NavigationControllerTheme {
|
public extension NavigationControllerTheme {
|
||||||
convenience init(presentationTheme: PresentationTheme) {
|
convenience init(presentationTheme: PresentationTheme) {
|
||||||
self.init(navigationBar: NavigationBarTheme(rootControllerTheme: presentationTheme), emptyAreaColor: presentationTheme.chatList.backgroundColor)
|
let navigationStatusBar: NavigationStatusBarStyle
|
||||||
|
switch presentationTheme.rootController.statusBarStyle {
|
||||||
|
case .black:
|
||||||
|
navigationStatusBar = .black
|
||||||
|
case .white:
|
||||||
|
navigationStatusBar = .white
|
||||||
|
}
|
||||||
|
self.init(statusBar: navigationStatusBar, navigationBar: NavigationBarTheme(rootControllerTheme: presentationTheme), emptyAreaColor: presentationTheme.chatList.backgroundColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,15 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
|||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.openUrl = openUrl
|
self.openUrl = openUrl
|
||||||
|
|
||||||
super.init(mode: .single, theme: NavigationControllerTheme(navigationBar: AuthorizationSequenceController.navigationBarTheme(theme), emptyAreaColor: .black))
|
let navigationStatusBar: NavigationStatusBarStyle
|
||||||
|
switch theme.rootController.statusBarStyle {
|
||||||
|
case .black:
|
||||||
|
navigationStatusBar = .black
|
||||||
|
case .white:
|
||||||
|
navigationStatusBar = .white
|
||||||
|
}
|
||||||
|
|
||||||
|
super.init(mode: .single, theme: NavigationControllerTheme(statusBar: navigationStatusBar, navigationBar: AuthorizationSequenceController.navigationBarTheme(theme), emptyAreaColor: .black))
|
||||||
|
|
||||||
self.stateDisposable = (account.postbox.stateView()
|
self.stateDisposable = (account.postbox.stateView()
|
||||||
|> map { view -> InnerState in
|
|> map { view -> InnerState in
|
||||||
|
@ -987,7 +987,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}, openTheme: { [weak self] message in
|
}, openTheme: { [weak self] message in
|
||||||
if let strongSelf = self, strongSelf.isNodeLoaded, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) {
|
if let strongSelf = self, strongSelf.isNodeLoaded, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) {
|
||||||
strongSelf.chatDisplayNode.dismissInput()
|
strongSelf.chatDisplayNode.dismissInput()
|
||||||
openChatTheme(context: strongSelf.context, message: message, present: { [weak self] c, a in
|
openChatTheme(context: strongSelf.context, message: message, pushController: { [weak self] c in
|
||||||
|
(self?.navigationController as? NavigationController)?.pushViewController(c)
|
||||||
|
}, present: { [weak self] c, a in
|
||||||
self?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
self?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -5265,7 +5267,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
let _ = legacyAssetPicker(context: strongSelf.context, presentationData: strongSelf.presentationData, editingMedia: editingMedia, fileMode: fileMode, peer: peer, saveEditedPhotos: settings.storeEditedPhotos, allowGrouping: true, selectionLimit: selectionLimit).start(next: { generator in
|
let _ = legacyAssetPicker(context: strongSelf.context, presentationData: strongSelf.presentationData, editingMedia: editingMedia, fileMode: fileMode, peer: peer, saveEditedPhotos: settings.storeEditedPhotos, allowGrouping: true, selectionLimit: selectionLimit).start(next: { generator in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let legacyController = LegacyController(presentation: .modal(animateIn: true), theme: strongSelf.presentationData.theme, initialLayout: strongSelf.validLayout)
|
let legacyController = LegacyController(presentation: .navigation, theme: strongSelf.presentationData.theme, initialLayout: strongSelf.validLayout)
|
||||||
|
legacyController.navigationPresentation = .modal
|
||||||
legacyController.statusBar.statusBarStyle = strongSelf.presentationData.theme.rootController.statusBarStyle.style
|
legacyController.statusBar.statusBarStyle = strongSelf.presentationData.theme.rootController.statusBarStyle.style
|
||||||
legacyController.controllerLoaded = { [weak legacyController] in
|
legacyController.controllerLoaded = { [weak legacyController] in
|
||||||
legacyController?.view.disablesInteractiveTransitionGestureRecognizer = true
|
legacyController?.view.disablesInteractiveTransitionGestureRecognizer = true
|
||||||
@ -5290,7 +5293,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
(strongSelf.navigationController as? NavigationController)?.pushViewController(controller)
|
||||||
}
|
}
|
||||||
}, presentSelectionLimitExceeded: {
|
}, presentSelectionLimitExceeded: {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
@ -5330,7 +5333,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
strongSelf.chatDisplayNode.dismissInput()
|
strongSelf.chatDisplayNode.dismissInput()
|
||||||
strongSelf.present(legacyController, in: .window(.root))
|
legacyController.navigationPresentation = .modal
|
||||||
|
(strongSelf.navigationController as? NavigationController)?.pushViewController(legacyController)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -5385,7 +5389,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.chatDisplayNode.dismissInput()
|
strongSelf.chatDisplayNode.dismissInput()
|
||||||
strongSelf.present(legacyLocationPickerController(context: strongSelf.context, selfPeer: selfPeer, peer: peer, sendLocation: { coordinate, venue, _ in
|
(strongSelf.navigationController as? NavigationController)?.pushViewController(legacyLocationPickerController(context: strongSelf.context, selfPeer: selfPeer, peer: peer, sendLocation: { coordinate, venue, _ in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -5422,15 +5426,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
})
|
})
|
||||||
strongSelf.sendMessages([message])
|
strongSelf.sendMessages([message])
|
||||||
}
|
}
|
||||||
}, theme: strongSelf.presentationData.theme, hasLiveLocation: !strongSelf.presentationInterfaceState.isScheduledMessages), in: .window(.root))
|
}, theme: strongSelf.presentationData.theme, hasLiveLocation: !strongSelf.presentationInterfaceState.isScheduledMessages))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private func presentContactPicker() {
|
private func presentContactPicker() {
|
||||||
let contactsController = ContactSelectionControllerImpl(ContactSelectionControllerParams(context: self.context, title: { $0.Contacts_Title }, displayDeviceContacts: true))
|
let contactsController = ContactSelectionControllerImpl(ContactSelectionControllerParams(context: self.context, title: { $0.Contacts_Title }, displayDeviceContacts: true))
|
||||||
|
contactsController.navigationPresentation = .modal
|
||||||
self.chatDisplayNode.dismissInput()
|
self.chatDisplayNode.dismissInput()
|
||||||
self.present(contactsController, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
(self.navigationController as? NavigationController)?.pushViewController(contactsController)
|
||||||
self.controllerNavigationDisposable.set((contactsController.result |> deliverOnMainQueue).start(next: { [weak self] peer in
|
self.controllerNavigationDisposable.set((contactsController.result
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||||
if let strongSelf = self, let peer = peer {
|
if let strongSelf = self, let peer = peer {
|
||||||
let dataSignal: Signal<(Peer?, DeviceContactExtendedData?), NoError>
|
let dataSignal: Signal<(Peer?, DeviceContactExtendedData?), NoError>
|
||||||
switch peer {
|
switch peer {
|
||||||
@ -5488,7 +5494,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil)
|
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil)
|
||||||
strongSelf.sendMessages([message])
|
strongSelf.sendMessages([message])
|
||||||
} else {
|
} else {
|
||||||
strongSelf.present(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .filter(peer: peerAndContactData.0, contactId: nil, contactData: contactData, completion: { peer, contactData in
|
let contactController = strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .filter(peer: peerAndContactData.0, contactId: nil, contactData: contactData, completion: { peer, contactData in
|
||||||
guard let strongSelf = self, !contactData.basicData.phoneNumbers.isEmpty else {
|
guard let strongSelf = self, !contactData.basicData.phoneNumbers.isEmpty else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -5506,7 +5512,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil)
|
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil)
|
||||||
strongSelf.sendMessages([message])
|
strongSelf.sendMessages([message])
|
||||||
}
|
}
|
||||||
}), completed: nil, cancelled: nil), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}), completed: nil, cancelled: nil)
|
||||||
|
(strongSelf.navigationController as? NavigationController)?.pushViewController(contactController)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
@ -5516,7 +5523,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
private func presentPollCreation() {
|
private func presentPollCreation() {
|
||||||
if case let .peer(peerId) = self.chatLocation {
|
if case let .peer(peerId) = self.chatLocation {
|
||||||
self.present(createPollController(context: self.context, peerId: peerId, completion: { [weak self] message in
|
(self.navigationController as? NavigationController)?.pushViewController(createPollController(context: self.context, peerId: peerId, completion: { [weak self] message in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -5529,7 +5536,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
strongSelf.sendMessages([message.withUpdatedReplyToMessageId(replyMessageId)])
|
strongSelf.sendMessages([message.withUpdatedReplyToMessageId(replyMessageId)])
|
||||||
}), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6345,7 +6352,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.chatDisplayNode.dismissInput()
|
self.chatDisplayNode.dismissInput()
|
||||||
self.present(controller, in: .window(.root), blockInteraction: true)
|
(self.navigationController as? NavigationController)?.pushViewController(controller)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func openPeer(peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer, fromMessage: Message?) {
|
private func openPeer(peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer, fromMessage: Message?) {
|
||||||
@ -6462,7 +6469,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.chatDisplayNode.dismissInput()
|
self.chatDisplayNode.dismissInput()
|
||||||
self.present(controller, in: .window(.root))
|
(self.navigationController as? NavigationController)?.pushViewController(controller)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
@ -7698,17 +7705,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
private func openScheduledMessages() {
|
private func openScheduledMessages() {
|
||||||
let controller = ChatControllerImpl(context: self.context, chatLocation: self.chatLocation, subject: .scheduledMessages)
|
let controller = ChatControllerImpl(context: self.context, chatLocation: self.chatLocation, subject: .scheduledMessages)
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
(self.navigationController as? NavigationController)?.pushViewController(controller)
|
(self.navigationController as? NavigationController)?.pushViewController(controller)
|
||||||
//self.present(controller, in: .window(.root))
|
|
||||||
}
|
|
||||||
|
|
||||||
override public func dismiss(completion: (() -> Void)? = nil) {
|
|
||||||
if !self.isDismissed {
|
|
||||||
self.isDismissed = true
|
|
||||||
self.chatDisplayNode.animateOut(completion: { [weak self] in
|
|
||||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
|
||||||
})
|
|
||||||
self.updateTransitionWhenPresentedAsModal?(0.0, .animated(duration: 0.2, curve: .easeInOut))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,13 +40,15 @@ public class ComposeController: ViewController {
|
|||||||
|
|
||||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||||
|
|
||||||
|
self.navigationPresentation = .modal
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||||
|
|
||||||
self.title = self.presentationData.strings.Compose_NewMessage
|
self.title = self.presentationData.strings.Compose_NewMessage
|
||||||
|
|
||||||
self.isModalWhenInOverlay = true
|
self.isModalWhenInOverlay = true
|
||||||
|
|
||||||
//self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||||
|
|
||||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(cancelPressed))
|
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(cancelPressed))
|
||||||
|
|
||||||
@ -263,6 +265,6 @@ public class ComposeController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc private func cancelPressed() {
|
@objc private func cancelPressed() {
|
||||||
self.presentingViewController?.dismiss(animated: true, completion: nil)
|
(self.navigationController as? NavigationController)?.filterController(self, animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,19 +271,6 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func dismiss(completion: (() -> Void)? = nil) {
|
|
||||||
if let presentationArguments = self.presentationArguments as? ViewControllerPresentationArguments {
|
|
||||||
switch presentationArguments.presentationAnimation {
|
|
||||||
case .modalSheet:
|
|
||||||
self.dismissed?()
|
|
||||||
self.contactsNode.animateOut(completion: completion)
|
|
||||||
case .none:
|
|
||||||
self.dismissed?()
|
|
||||||
completion?()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func dismissSearch() {
|
func dismissSearch() {
|
||||||
self.deactivateSearch()
|
self.deactivateSearch()
|
||||||
}
|
}
|
||||||
|
@ -261,12 +261,8 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
|
|||||||
}, stopLiveLocation: {
|
}, stopLiveLocation: {
|
||||||
params.context.liveLocationManager?.cancelLiveLocation(peerId: params.message.id.peerId)
|
params.context.liveLocationManager?.cancelLiveLocation(peerId: params.message.id.peerId)
|
||||||
}, openUrl: params.openUrl)
|
}, openUrl: params.openUrl)
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
if params.modal {
|
|
||||||
params.present(controller, nil)
|
|
||||||
} else {
|
|
||||||
params.navigationController?.pushViewController(controller)
|
params.navigationController?.pushViewController(controller)
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
case let .stickerPack(reference):
|
case let .stickerPack(reference):
|
||||||
let controller = StickerPackPreviewController(context: params.context, stickerPack: reference, parentNavigationController: params.navigationController)
|
let controller = StickerPackPreviewController(context: params.context, stickerPack: reference, parentNavigationController: params.navigationController)
|
||||||
@ -381,7 +377,7 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
let controller = ThemePreviewController(context: params.context, previewTheme: theme, source: .media(.message(message: MessageReference(params.message), media: media)))
|
let controller = ThemePreviewController(context: params.context, previewTheme: theme, source: .media(.message(message: MessageReference(params.message), media: media)))
|
||||||
params.present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
params.navigationController?.pushViewController(controller)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -430,6 +426,7 @@ func openChatInstantPage(context: AccountContext, message: Message, sourcePeerTy
|
|||||||
}
|
}
|
||||||
|
|
||||||
let pageController = InstantPageController(context: context, webPage: webpage, sourcePeerType: sourcePeerType ?? .channel, anchor: anchor)
|
let pageController = InstantPageController(context: context, webPage: webpage, sourcePeerType: sourcePeerType ?? .channel, anchor: anchor)
|
||||||
|
pageController.navigationPresentation = .modal
|
||||||
navigationController.pushViewController(pageController)
|
navigationController.pushViewController(pageController)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@ -459,7 +456,7 @@ func openChatWallpaper(context: AccountContext, message: Message, present: @esca
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func openChatTheme(context: AccountContext, message: Message, present: @escaping (ViewController, Any?) -> Void) {
|
func openChatTheme(context: AccountContext, message: Message, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
|
if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
|
||||||
let _ = (context.sharedContext.resolveUrl(account: context.account, url: content.url)
|
let _ = (context.sharedContext.resolveUrl(account: context.account, url: content.url)
|
||||||
@ -474,7 +471,7 @@ func openChatTheme(context: AccountContext, message: Message, present: @escaping
|
|||||||
if case let .theme(slug) = resolvedUrl, let file = file {
|
if case let .theme(slug) = resolvedUrl, let file = file {
|
||||||
if let path = context.sharedContext.accountManager.mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead), let theme = makePresentationTheme(data: data) {
|
if let path = context.sharedContext.accountManager.mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead), let theme = makePresentationTheme(data: data) {
|
||||||
let controller = ThemePreviewController(context: context, previewTheme: theme, source: .slug(slug, file))
|
let controller = ThemePreviewController(context: context, previewTheme: theme, source: .slug(slug, file))
|
||||||
present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
pushController(controller)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
@ -81,7 +81,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dismissInput()
|
dismissInput()
|
||||||
present(controller, ViewControllerPresentationArguments(presentationAnimation: ViewControllerPresentationAnimation.modalSheet))
|
navigationController?.pushViewController(controller)
|
||||||
case let .channelMessage(peerId, messageId):
|
case let .channelMessage(peerId, messageId):
|
||||||
openPeer(peerId, .chat(textInputState: nil, subject: .message(messageId)))
|
openPeer(peerId, .chat(textInputState: nil, subject: .message(messageId)))
|
||||||
case let .stickerPack(name):
|
case let .stickerPack(name):
|
||||||
@ -203,10 +203,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
|||||||
continueWithPeer(peerId)
|
continueWithPeer(peerId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let navigationController = navigationController {
|
navigationController?.pushViewController(controller)
|
||||||
context.sharedContext.applicationBindings.dismissNativeController()
|
|
||||||
(navigationController.viewControllers.last as? ViewController)?.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: ViewControllerPresentationAnimation.modalSheet))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case let .wallpaper(parameter):
|
case let .wallpaper(parameter):
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
@ -59,6 +59,8 @@ public class PeerMediaCollectionController: TelegramBaseController {
|
|||||||
|
|
||||||
super.init(context: context, navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: self.presentationData.theme).withUpdatedSeparatorColor(self.presentationData.theme.rootController.navigationBar.backgroundColor), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)), mediaAccessoryPanelVisibility: .specific(size: .compact), locationBroadcastPanelSource: .none)
|
super.init(context: context, navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: self.presentationData.theme).withUpdatedSeparatorColor(self.presentationData.theme.rootController.navigationBar.backgroundColor), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)), mediaAccessoryPanelVisibility: .specific(size: .compact), locationBroadcastPanelSource: .none)
|
||||||
|
|
||||||
|
self.navigationPresentation = .modalInLargeLayout
|
||||||
|
|
||||||
self.title = self.presentationData.strings.SharedMedia_TitleAll
|
self.title = self.presentationData.strings.SharedMedia_TitleAll
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||||
@ -105,7 +107,18 @@ public class PeerMediaCollectionController: TelegramBaseController {
|
|||||||
return nil
|
return nil
|
||||||
}, addToTransitionSurface: { view in
|
}, addToTransitionSurface: { view in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.mediaCollectionDisplayNode.view.insertSubview(view, aboveSubview: strongSelf.mediaCollectionDisplayNode.historyNode.view)
|
var belowSubview: UIView?
|
||||||
|
if let historyNode = strongSelf.mediaCollectionDisplayNode.historyNode as? ChatHistoryGridNode {
|
||||||
|
if let lowestSectionNode = historyNode.lowestSectionNode() {
|
||||||
|
belowSubview = lowestSectionNode.view
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strongSelf.mediaCollectionDisplayNode.historyNode
|
||||||
|
if let belowSubview = belowSubview {
|
||||||
|
strongSelf.mediaCollectionDisplayNode.historyNode.view.insertSubview(view, belowSubview: belowSubview)
|
||||||
|
} else {
|
||||||
|
strongSelf.mediaCollectionDisplayNode.historyNode.view.addSubview(view)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, openUrl: { url in
|
}, openUrl: { url in
|
||||||
self?.openUrl(url)
|
self?.openUrl(url)
|
||||||
@ -823,7 +836,7 @@ public class PeerMediaCollectionController: TelegramBaseController {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strongSelf.present(controller, in: .window(.root))
|
(strongSelf.navigationController as? NavigationController)?.pushViewController(controller)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,9 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
|||||||
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||||
|
|
||||||
|
self.navigationPresentation = .modal
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||||
|
|
||||||
self.customTitle = params.title
|
self.customTitle = params.title
|
||||||
@ -178,7 +181,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
|||||||
override public func viewDidAppear(_ animated: Bool) {
|
override public func viewDidAppear(_ animated: Bool) {
|
||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
self.peerSelectionNode.animateIn()
|
//self.peerSelectionNode.animateIn()
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func viewDidDisappear(_ animated: Bool) {
|
override public func viewDidDisappear(_ animated: Bool) {
|
||||||
@ -215,9 +218,4 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func dismiss(completion: (() -> Void)? = nil) {
|
|
||||||
self.peerSelectionNode.view.endEditing(true)
|
|
||||||
self.peerSelectionNode.animateOut(completion: completion)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -924,7 +924,9 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func makePeerInfoController(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode) -> ViewController? {
|
public func makePeerInfoController(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode) -> ViewController? {
|
||||||
return peerInfoControllerImpl(context: context, peer: peer, mode: mode)
|
let controller = peerInfoControllerImpl(context: context, peer: peer, mode: mode)
|
||||||
|
controller?.navigationPresentation = .modalInLargeLayout
|
||||||
|
return controller
|
||||||
}
|
}
|
||||||
|
|
||||||
public func openExternalUrl(context: AccountContext, urlContext: OpenURLContext, url: String, forceExternal: Bool, presentationData: PresentationData, navigationController: NavigationController?, dismissInput: @escaping () -> Void) {
|
public func openExternalUrl(context: AccountContext, urlContext: OpenURLContext, url: String, forceExternal: Bool, presentationData: PresentationData, navigationController: NavigationController?, dismissInput: @escaping () -> Void) {
|
||||||
@ -995,8 +997,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
openAddContactImpl(context: context, firstName: firstName, lastName: lastName, phoneNumber: phoneNumber, label: label, present: present, pushController: pushController, completed: completed)
|
openAddContactImpl(context: context, firstName: firstName, lastName: lastName, phoneNumber: phoneNumber, label: label, present: present, pushController: pushController, completed: completed)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func openAddPersonContact(context: AccountContext, peerId: PeerId, present: @escaping (ViewController, Any?) -> Void) {
|
public func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||||
openAddPersonContactImpl(context: context, peerId: peerId, present: present)
|
openAddPersonContactImpl(context: context, peerId: peerId, pushController: pushController, present: present)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeCreateGroupController(context: AccountContext, peerIds: [PeerId], initialTitle: String?, mode: CreateGroupMode, completion: ((PeerId, @escaping () -> Void) -> Void)?) -> ViewController {
|
public func makeCreateGroupController(context: AccountContext, peerIds: [PeerId], initialTitle: String?, mode: CreateGroupMode, completion: ((PeerId, @escaping () -> Void) -> Void)?) -> ViewController {
|
||||||
|
@ -472,12 +472,4 @@ public final class WebSearchController: ViewController {
|
|||||||
|
|
||||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
|
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func dismiss(completion: (() -> Void)? = nil) {
|
|
||||||
self.navigationContentNode?.deactivate()
|
|
||||||
self.controllerNode.animateOut(completion: { [weak self] in
|
|
||||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
|
||||||
completion?()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user