| 1 |
//
|
|
| 2 |
// RouteComposer
|
|
| 3 |
// UIViewController+Extension.swift
|
|
| 4 |
// https://github.com/ekazaev/route-composer
|
|
| 5 |
//
|
|
| 6 |
// Created by Eugene Kazaev in 2018-2022.
|
|
| 7 |
// Distributed under the MIT license.
|
|
| 8 |
//
|
|
| 9 |
// Become a sponsor:
|
|
| 10 |
// https://github.com/sponsors/ekazaev
|
|
| 11 |
//
|
|
| 12 |
|
|
| 13 |
import UIKit
|
|
| 14 |
|
|
| 15 |
public extension UIViewController {
|
|
| 16 |
|
|
| 17 |
/// Iterates through the view controller stack to finds a `UIViewController` instance.
|
|
| 18 |
///
|
|
| 19 |
/// - Parameters:
|
|
| 20 |
/// - viewController: A `UIViewController` instance to start from.
|
|
| 21 |
/// - options: A combination of `SearchOptions`.
|
|
| 22 |
/// - containerAdapterLocator: A `ContainerAdapterLocator` instance.
|
|
| 23 |
/// - predicate: A block that should return `true` if the `UIViewController` instance provided is the
|
|
| 24 |
/// one that is being searched for.
|
|
| 25 |
/// - Returns: A `UIViewController` instance if found, `nil` otherwise.
|
|
| 26 |
static func findViewController(in viewController: UIViewController,
|
|
| 27 |
options: SearchOptions = .currentAndUp,
|
|
| 28 |
containerAdapterLocator: ContainerAdapterLocator = RouteComposerDefaults.shared.containerAdapterLocator,
|
|
| 29 |
using predicate: (UIViewController) -> Bool) throws -> UIViewController? {
|
1360x |
| 30 |
guard !viewController.isBeingDismissed else {
|
1360x |
| 31 |
return nil
|
2x |
| 32 |
}
|
1350x |
| 33 |
|
1350x |
| 34 |
if options.contains(.current), predicate(viewController) {
|
1350x |
| 35 |
return viewController
|
322x |
| 36 |
}
|
1030x |
| 37 |
|
1030x |
| 38 |
if options.contains(.parent),
|
1030x |
| 39 |
let parentViewController = viewController.parentViewController,
|
1030x |
| 40 |
let foundViewController = try findViewController(in: parentViewController,
|
1030x |
| 41 |
options: [.current, .parent],
|
1030x |
| 42 |
containerAdapterLocator: containerAdapterLocator,
|
1030x |
| 43 |
using: predicate) {
|
1030x |
| 44 |
return foundViewController
|
6x |
| 45 |
}
|
1030x |
| 46 |
|
1030x |
| 47 |
if let container = viewController as? ContainerViewController, options.contains(.visible) || options.contains(.contained) {
|
1030x |
| 48 |
var viewControllers: [[UIViewController]] = []
|
660x |
| 49 |
let containerAdapter = try containerAdapterLocator.getAdapter(for: container)
|
660x |
| 50 |
viewControllers.append(containerAdapter.visibleViewControllers)
|
660x |
| 51 |
if options.contains(.contained) {
|
660x |
| 52 |
viewControllers.append(containerAdapter.containedViewControllers)
|
336x |
| 53 |
}
|
660x |
| 54 |
for currentViewController in Array(viewControllers.joined()).uniqueElements() {
|
809x |
| 55 |
var internalOptions: SearchOptions = options.contains(.visible) ? .currentVisibleOnly : [.current, .contained]
|
809x |
| 56 |
if options.contains(.presented) {
|
809x |
| 57 |
internalOptions.insert(.presented)
|
320x |
| 58 |
}
|
809x |
| 59 |
if let foundViewController = try findViewController(in: currentViewController,
|
809x |
| 60 |
options: internalOptions,
|
809x |
| 61 |
containerAdapterLocator: containerAdapterLocator,
|
809x |
| 62 |
using: predicate) {
|
809x |
| 63 |
return foundViewController
|
412x |
| 64 |
}
|
412x |
| 65 |
}
|
397x |
| 66 |
}
|
619x |
| 67 |
|
619x |
| 68 |
if options.contains(.presented),
|
619x |
| 69 |
let presentedViewController = viewController.presentedViewController {
|
619x |
| 70 |
let presentedOptions = options.subtracting(.presenting)
|
18x |
| 71 |
if let foundViewController = try findViewController(in: presentedViewController,
|
18x |
| 72 |
options: presentedOptions,
|
18x |
| 73 |
containerAdapterLocator: containerAdapterLocator,
|
18x |
| 74 |
using: predicate) {
|
18x |
| 75 |
return foundViewController
|
3x |
| 76 |
}
|
15x |
| 77 |
}
|
616x |
| 78 |
|
616x |
| 79 |
if options.contains(.presenting),
|
616x |
| 80 |
let presentingViewController = viewController.presentingViewController {
|
616x |
| 81 |
let presentingOptions = options.subtracting(.presented)
|
52x |
| 82 |
if let foundViewController = try findViewController(in: presentingViewController,
|
52x |
| 83 |
options: presentingOptions,
|
52x |
| 84 |
containerAdapterLocator: containerAdapterLocator,
|
52x |
| 85 |
using: predicate) {
|
52x |
| 86 |
return foundViewController
|
6x |
| 87 |
}
|
46x |
| 88 |
}
|
610x |
| 89 |
|
610x |
| 90 |
return nil
|
610x |
| 91 |
}
|
616x |
| 92 |
|
|
| 93 |
}
|
|