feat: experiments with deeplink generics

This commit is contained in:
Ivan Smolin 2023-03-31 20:49:47 +03:00
parent 270ac1a4d5
commit 06b687c47e
6 changed files with 129 additions and 76 deletions

View File

@ -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 }
// }
//}

View File

@ -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
}
}

View File

@ -23,5 +23,7 @@
import Foundation
public protocol DeeplinkHandler {
associatedtype Deeplink
func handle(deeplink: Deeplink) -> Operation?
}

View File

@ -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
}
}

View File

@ -23,5 +23,7 @@
import Foundation
public protocol DeeplinkMapper {
associatedtype Deeplink
func map(url: URL) -> Deeplink?
}

View File

@ -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
}