feat: experiments with deeplink generics
This commit is contained in:
parent
270ac1a4d5
commit
06b687c47e
|
|
@ -22,25 +22,25 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
open class Deeplink: Equatable, Hashable {
|
||||
|
||||
public var rawValue: String
|
||||
|
||||
required public init(rawValue: String) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
public static func == (lhs: Deeplink, rhs: Deeplink) -> Bool {
|
||||
lhs.rawValue == rhs.rawValue
|
||||
}
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
public extension Array where Element: Deeplink {
|
||||
func find(byRawValue rawValue: String) -> Deeplink? {
|
||||
first { $0.rawValue == rawValue }
|
||||
}
|
||||
}
|
||||
//open class Deeplink: Equatable, Hashable {
|
||||
//
|
||||
// public var rawValue: String
|
||||
//
|
||||
// required public init(rawValue: String) {
|
||||
// self.rawValue = rawValue
|
||||
// }
|
||||
//
|
||||
// public static func == (lhs: Deeplink, rhs: Deeplink) -> Bool {
|
||||
// lhs.rawValue == rhs.rawValue
|
||||
// }
|
||||
//
|
||||
// public func hash(into hasher: inout Hasher) {
|
||||
// hasher.combine(rawValue)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//public extension Array where Element: Deeplink {
|
||||
// func find(byRawValue rawValue: String) -> Deeplink? {
|
||||
// first { $0.rawValue == rawValue }
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -22,24 +22,57 @@
|
|||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import TISwiftUtils
|
||||
|
||||
open class BaseNavigationStackDeeplinkHandler: DeeplinkHandler {
|
||||
open class BaseNavigationStackDeeplinkHandler<Deeplink>: DeeplinkHandler {
|
||||
|
||||
public var rootViewControllerKeeper: UIViewController
|
||||
public var asAnyHandlerClosure: Closure<UIViewController, AnyDeeplinkHandler<Deeplink>?>
|
||||
|
||||
public init(rootViewControllerKeeper: UIViewController,
|
||||
asAnyHandlerClosure: @escaping Closure<UIViewController, AnyDeeplinkHandler<Deeplink>?>) {
|
||||
|
||||
public init(rootViewControllerKeeper: UIViewController) {
|
||||
self.rootViewControllerKeeper = rootViewControllerKeeper
|
||||
self.asAnyHandlerClosure = asAnyHandlerClosure
|
||||
}
|
||||
// MARK: - DeeplinkHandler
|
||||
|
||||
open func handle(deeplink: Deeplink) -> Operation? {
|
||||
let handler = findHandler(for: deeplink)
|
||||
let handler = asAnyHandlerClosure(rootViewControllerKeeper) ?? findHandler(for: deeplink, in: rootViewControllerKeeper)
|
||||
|
||||
return handler?.handle(deeplink: deeplink)
|
||||
}
|
||||
|
||||
// MARK: - Open methods
|
||||
|
||||
open func findHandler(for deeplink: Deeplink) -> DeeplinkHandler? {
|
||||
rootViewControllerKeeper.findHandler(for: deeplink)
|
||||
open func findHandler(for deeplink: Deeplink, in viewController: UIViewController) -> AnyDeeplinkHandler<Deeplink>? {
|
||||
switch viewController {
|
||||
case let navController as UINavigationController:
|
||||
for controllerInNavigationStack in navController.viewControllers.reversed() {
|
||||
if let handler = asAnyHandlerClosure(controllerInNavigationStack) {
|
||||
return handler
|
||||
}
|
||||
}
|
||||
|
||||
case let tabController as UITabBarController:
|
||||
if let selectedController = tabController.selectedViewController, let handler = asAnyHandlerClosure(selectedController) {
|
||||
return handler
|
||||
} else if var tabControllers = tabController.viewControllers {
|
||||
if tabController.selectedIndex != NSNotFound {
|
||||
tabControllers.remove(at: tabController.selectedIndex)
|
||||
}
|
||||
|
||||
for tabController in tabControllers {
|
||||
if let handler = asAnyHandlerClosure(tabController) {
|
||||
return handler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return asAnyHandlerClosure(viewController)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,5 +23,7 @@
|
|||
import Foundation
|
||||
|
||||
public protocol DeeplinkHandler {
|
||||
associatedtype Deeplink
|
||||
|
||||
func handle(deeplink: Deeplink) -> Operation?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,54 +22,30 @@
|
|||
|
||||
import UIKit
|
||||
|
||||
public extension UIViewController {
|
||||
func findHandler(for deeplink: Deeplink) -> DeeplinkHandler? {
|
||||
if let deeplinksHandler = self as? DeeplinkHandler,
|
||||
let _ = deeplinksHandler.handle(deeplink: deeplink) {
|
||||
return deeplinksHandler
|
||||
}
|
||||
enum ProjectDeeplink: Hashable {
|
||||
case promoList
|
||||
case promoDetails(String)
|
||||
}
|
||||
|
||||
if let deeplinksHandler: DeeplinkHandler = presentedViewController?.findHandler(for: deeplink) {
|
||||
return deeplinksHandler
|
||||
}
|
||||
protocol ProjectDeeplinkHandler: DeeplinkHandler where Deeplink == ProjectDeeplink {}
|
||||
|
||||
return findHandlerInViewHierarchy(for: deeplink)
|
||||
}
|
||||
final class ProjectDeeplinkService: TIDeeplinksService<ProjectDeeplink> {
|
||||
}
|
||||
|
||||
private func findHandlerInViewHierarchy(for deeplink: Deeplink) -> DeeplinkHandler? {
|
||||
switch self {
|
||||
case let navController as UINavigationController:
|
||||
let deeplinksHandler = navController.viewControllers.reversed().findHandler(for: deeplink)
|
||||
return deeplinksHandler
|
||||
|
||||
case let tabController as UITabBarController:
|
||||
if let deeplinksHandler = tabController.selectedViewController?.findHandler(for: deeplink) {
|
||||
return deeplinksHandler
|
||||
} else if var tabControllers = tabController.viewControllers {
|
||||
if tabController.selectedIndex != NSNotFound {
|
||||
tabControllers.remove(at: tabController.selectedIndex)
|
||||
}
|
||||
|
||||
if let deeplinksHandler = tabControllers.findHandler(for: deeplink) {
|
||||
return deeplinksHandler
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
final class ProjectVC: UIViewController, DeeplinkHandler {
|
||||
func handle(deeplink: ProjectDeeplink) -> Operation? {
|
||||
BlockOperation()
|
||||
}
|
||||
}
|
||||
|
||||
private extension Sequence where Element: UIViewController {
|
||||
func findHandler(for deeplink: Deeplink) -> DeeplinkHandler? {
|
||||
for controller in self {
|
||||
if let deeplinksHandler = controller.findHandler(for: deeplink) {
|
||||
return deeplinksHandler
|
||||
final class ProjectNavigationHandler: BaseNavigationStackDeeplinkHandler<ProjectDeeplink> {
|
||||
convenience init() {
|
||||
self.init(rootViewControllerKeeper: UIViewController()) {
|
||||
guard let projectHandler = $0 as? (any ProjectDeeplinkHandler) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return projectHandler.eraseToAnyDeeplinkHandler()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,5 +23,7 @@
|
|||
import Foundation
|
||||
|
||||
public protocol DeeplinkMapper {
|
||||
associatedtype Deeplink
|
||||
|
||||
func map(url: URL) -> Deeplink?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,46 @@
|
|||
import Foundation
|
||||
import TIFoundationUtils
|
||||
|
||||
open class TIDeeplinksService {
|
||||
import TISwiftUtils
|
||||
|
||||
public struct AnyDeeplinkMapper<Deeplink>: DeeplinkMapper {
|
||||
private let mappingClosure: Closure<URL, Deeplink?>
|
||||
|
||||
public init<Mapper: DeeplinkMapper>(mapper: Mapper) where Mapper.Deeplink == Deeplink {
|
||||
self.mappingClosure = mapper.map
|
||||
}
|
||||
|
||||
public func map(url: URL) -> Deeplink? {
|
||||
mappingClosure(url)
|
||||
}
|
||||
}
|
||||
|
||||
public extension DeeplinkMapper {
|
||||
func eraseToAnyDeeplinkMapper() -> AnyDeeplinkMapper<Deeplink> {
|
||||
AnyDeeplinkMapper(mapper: self)
|
||||
}
|
||||
}
|
||||
|
||||
public struct AnyDeeplinkHandler<Deeplink>: DeeplinkHandler {
|
||||
private let handlerClosure: Closure<Deeplink, Operation?>
|
||||
|
||||
public init<Handler: DeeplinkHandler>(handler: Handler) where Handler.Deeplink == Deeplink {
|
||||
self.handlerClosure = handler.handle
|
||||
}
|
||||
|
||||
public func handle(deeplink: Deeplink) -> Operation? {
|
||||
handlerClosure(deeplink)
|
||||
}
|
||||
}
|
||||
|
||||
public extension DeeplinkHandler {
|
||||
func eraseToAnyDeeplinkHandler() -> AnyDeeplinkHandler<Deeplink> {
|
||||
AnyDeeplinkHandler(handler: self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open class TIDeeplinksService<Deeplink: Hashable> {
|
||||
|
||||
// MARK: - Private properties
|
||||
|
||||
|
|
@ -34,17 +73,18 @@ open class TIDeeplinksService {
|
|||
|
||||
// MARK: - Public properties
|
||||
|
||||
public var deeplinkMapper: DeeplinkMapper?
|
||||
public var deeplinkHandler: DeeplinkHandler?
|
||||
public var deeplinkMapper: AnyDeeplinkMapper<Deeplink>?
|
||||
public var deeplinkHandler: AnyDeeplinkHandler<Deeplink>?
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
public init(mapper: DeeplinkMapper? = nil,
|
||||
handler: DeeplinkHandler? = nil,
|
||||
operationQueue: OperationQueue = .main) {
|
||||
public init<Mapper: DeeplinkMapper, Handler: DeeplinkHandler>(mapper: Mapper? = nil,
|
||||
handler: Handler? = nil,
|
||||
operationQueue: OperationQueue = .main)
|
||||
where Mapper.Deeplink == Deeplink, Handler.Deeplink == Deeplink {
|
||||
|
||||
self.deeplinkMapper = mapper
|
||||
self.deeplinkHandler = handler
|
||||
self.deeplinkMapper = mapper?.eraseToAnyDeeplinkMapper()
|
||||
self.deeplinkHandler = handler?.eraseToAnyDeeplinkHandler()
|
||||
self.operationQueue = operationQueue
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue