From a7e44a3d9a429a211f089992085f4f8ef2de3d4e Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Fri, 6 Jan 2023 07:20:10 +0700 Subject: [PATCH 1/7] feat: initial deep link settings --- LeadKit.podspec | 2 +- Package.swift | 2 ++ TIAppleMapUtils/TIAppleMapUtils.podspec | 2 +- TIAuth/TIAuth.podspec | 2 +- TIDeepLink/Sources/TIDeepLinkService.swift | 9 +++++++++ TIDeepLink/TIDeepLink.podspec | 15 +++++++++++++++ TIEcommerce/TIEcommerce.podspec | 2 +- TIFoundationUtils/TIFoundationUtils.podspec | 2 +- TIGoogleMapUtils/TIGoogleMapUtils.podspec | 2 +- TIKeychainUtils/TIKeychainUtils.podspec | 2 +- TILogging/TILogging.podspec | 2 +- TIMapUtils/TIMapUtils.podspec | 2 +- TIMoyaNetworking/TIMoyaNetworking.podspec | 2 +- TINetworking/TINetworking.podspec | 2 +- TINetworkingCache/TINetworkingCache.podspec | 2 +- TIPagination/TIPagination.podspec | 2 +- TISwiftUICore/TISwiftUICore.podspec | 2 +- TISwiftUtils/TISwiftUtils.podspec | 2 +- TITableKitUtils/TITableKitUtils.podspec | 2 +- TITransitions/TITransitions.podspec | 2 +- TIUIElements/TIUIElements.podspec | 2 +- TIUIKitCore/TIUIKitCore.podspec | 2 +- TIYandexMapUtils/TIYandexMapUtils.podspec | 2 +- 23 files changed, 46 insertions(+), 20 deletions(-) create mode 100644 TIDeepLink/Sources/TIDeepLinkService.swift create mode 100644 TIDeepLink/TIDeepLink.podspec diff --git a/LeadKit.podspec b/LeadKit.podspec index 77369e54..badd9a00 100644 --- a/LeadKit.podspec +++ b/LeadKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "LeadKit" - s.version = "1.30.0" + s.version = "1.33.0" s.summary = "iOS framework with a bunch of tools for rapid development" s.homepage = "https://github.com/TouchInstinct/LeadKit" s.license = "Apache License, Version 2.0" diff --git a/Package.swift b/Package.swift index 87950b8c..d77d173e 100644 --- a/Package.swift +++ b/Package.swift @@ -21,6 +21,7 @@ let package = Package( .library(name: "TIKeychainUtils", targets: ["TIKeychainUtils"]), .library(name: "TITableKitUtils", targets: ["TITableKitUtils"]), .library(name: "TILogging", targets: ["TILogging"]), + .library(name: "TIDeepLink", targets: ["TIDeepLink"]), // MARK: - Networking @@ -65,6 +66,7 @@ let package = Package( .target(name: "TIKeychainUtils", dependencies: ["TIFoundationUtils", "KeychainAccess"], path: "TIKeychainUtils/Sources"), .target(name: "TITableKitUtils", dependencies: ["TIUIElements", "TableKit"], path: "TITableKitUtils/Sources"), .target(name: "TILogging", dependencies: ["TIUIElements", "TISwiftUtils", "TIUIKitCore"], path: "TILogging/Sources"), + .target(name: "TIDeepLink", dependencies: [], path: "TIDeepLink/Sources"), // MARK: - Networking .target(name: "TINetworking", dependencies: ["TIFoundationUtils", "Alamofire"], path: "TINetworking/Sources"), diff --git a/TIAppleMapUtils/TIAppleMapUtils.podspec b/TIAppleMapUtils/TIAppleMapUtils.podspec index 80a3f947..5bf8344d 100644 --- a/TIAppleMapUtils/TIAppleMapUtils.podspec +++ b/TIAppleMapUtils/TIAppleMapUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIAppleMapUtils' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Set of helpers for map objects clustering and interacting using Apple MapKit.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIAuth/TIAuth.podspec b/TIAuth/TIAuth.podspec index 75915749..387253f9 100644 --- a/TIAuth/TIAuth.podspec +++ b/TIAuth/TIAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIAuth' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Login, registration, confirmation and other related actions' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIDeepLink/Sources/TIDeepLinkService.swift b/TIDeepLink/Sources/TIDeepLinkService.swift new file mode 100644 index 00000000..e3b71823 --- /dev/null +++ b/TIDeepLink/Sources/TIDeepLinkService.swift @@ -0,0 +1,9 @@ +final class DeeplinksService { + + static let shared = DeeplinksService() + + private init() { + + } +} + diff --git a/TIDeepLink/TIDeepLink.podspec b/TIDeepLink/TIDeepLink.podspec new file mode 100644 index 00000000..0e35e6dd --- /dev/null +++ b/TIDeepLink/TIDeepLink.podspec @@ -0,0 +1,15 @@ +Pod::Spec.new do |s| + s.name = 'TIDeepLink' + s.version = '1.33.0' + s.summary = 'Deep link service API' + s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name + s.license = { :type => 'MIT', :file => 'LICENSE' } + s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru', + 'castlele' => 'nikita.semenov@touchin.ru' } + s.source = { :git => 'https://github.com/TouchInstinct/LeadKit.git', :tag => s.version.to_s } + + s.ios.deployment_target = '11.0' + s.swift_versions = ['5.3'] + + s.source_files = s.name + '/Sources/**/*' +end diff --git a/TIEcommerce/TIEcommerce.podspec b/TIEcommerce/TIEcommerce.podspec index e65a3a19..c752fd0c 100644 --- a/TIEcommerce/TIEcommerce.podspec +++ b/TIEcommerce/TIEcommerce.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIEcommerce' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Cart, products, promocodes, bonuses and other related actions' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIFoundationUtils/TIFoundationUtils.podspec b/TIFoundationUtils/TIFoundationUtils.podspec index 63f45a58..de560ec2 100644 --- a/TIFoundationUtils/TIFoundationUtils.podspec +++ b/TIFoundationUtils/TIFoundationUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIFoundationUtils' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Set of helpers for Foundation framework classes.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIGoogleMapUtils/TIGoogleMapUtils.podspec b/TIGoogleMapUtils/TIGoogleMapUtils.podspec index 99e30625..e3deb218 100644 --- a/TIGoogleMapUtils/TIGoogleMapUtils.podspec +++ b/TIGoogleMapUtils/TIGoogleMapUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIGoogleMapUtils' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Set of helpers for map objects clustering and interacting using Google Maps SDK.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIKeychainUtils/TIKeychainUtils.podspec b/TIKeychainUtils/TIKeychainUtils.podspec index b0a6525e..321365d7 100644 --- a/TIKeychainUtils/TIKeychainUtils.podspec +++ b/TIKeychainUtils/TIKeychainUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIKeychainUtils' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Set of helpers for Keychain classes.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TILogging/TILogging.podspec b/TILogging/TILogging.podspec index 20b9d4b6..b0376aac 100644 --- a/TILogging/TILogging.podspec +++ b/TILogging/TILogging.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TILogging' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Logging API' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIMapUtils/TIMapUtils.podspec b/TIMapUtils/TIMapUtils.podspec index 578a4eb3..b91c2ed7 100644 --- a/TIMapUtils/TIMapUtils.podspec +++ b/TIMapUtils/TIMapUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIMapUtils' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Set of helpers for map objects clustering and interacting.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIMoyaNetworking/TIMoyaNetworking.podspec b/TIMoyaNetworking/TIMoyaNetworking.podspec index 867865d6..d394f56f 100644 --- a/TIMoyaNetworking/TIMoyaNetworking.podspec +++ b/TIMoyaNetworking/TIMoyaNetworking.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIMoyaNetworking' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Moya + Swagger network service.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TINetworking/TINetworking.podspec b/TINetworking/TINetworking.podspec index 8f92f73a..0aa168f9 100644 --- a/TINetworking/TINetworking.podspec +++ b/TINetworking/TINetworking.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TINetworking' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Swagger-frendly networking layer helpers.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TINetworkingCache/TINetworkingCache.podspec b/TINetworkingCache/TINetworkingCache.podspec index 3131de4f..e9be3cd8 100644 --- a/TINetworkingCache/TINetworkingCache.podspec +++ b/TINetworkingCache/TINetworkingCache.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TINetworkingCache' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Caching results of EndpointRequests.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIPagination/TIPagination.podspec b/TIPagination/TIPagination.podspec index 1df31c1f..c8ff1597 100644 --- a/TIPagination/TIPagination.podspec +++ b/TIPagination/TIPagination.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIPagination' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Generic pagination component.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TISwiftUICore/TISwiftUICore.podspec b/TISwiftUICore/TISwiftUICore.podspec index f9a4a99a..76ae3c2d 100644 --- a/TISwiftUICore/TISwiftUICore.podspec +++ b/TISwiftUICore/TISwiftUICore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TISwiftUICore' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Core UI elements: protocols, views and helpers.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TISwiftUtils/TISwiftUtils.podspec b/TISwiftUtils/TISwiftUtils.podspec index fc9189e6..f9b76474 100644 --- a/TISwiftUtils/TISwiftUtils.podspec +++ b/TISwiftUtils/TISwiftUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TISwiftUtils' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Bunch of useful helpers for Swift development.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TITableKitUtils/TITableKitUtils.podspec b/TITableKitUtils/TITableKitUtils.podspec index fe06f081..73456a50 100644 --- a/TITableKitUtils/TITableKitUtils.podspec +++ b/TITableKitUtils/TITableKitUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TITableKitUtils' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Set of helpers for TableKit classes.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TITransitions/TITransitions.podspec b/TITransitions/TITransitions.podspec index e27da747..e20b753a 100644 --- a/TITransitions/TITransitions.podspec +++ b/TITransitions/TITransitions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TITransitions' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Set of custom transitions to present controller. ' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIUIElements/TIUIElements.podspec b/TIUIElements/TIUIElements.podspec index bb4eadba..842543e0 100644 --- a/TIUIElements/TIUIElements.podspec +++ b/TIUIElements/TIUIElements.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIUIElements' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Bunch of useful protocols and views.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIUIKitCore/TIUIKitCore.podspec b/TIUIKitCore/TIUIKitCore.podspec index 533371cd..978a6563 100644 --- a/TIUIKitCore/TIUIKitCore.podspec +++ b/TIUIKitCore/TIUIKitCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIUIKitCore' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Core UI elements: protocols, views and helpers.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIYandexMapUtils/TIYandexMapUtils.podspec b/TIYandexMapUtils/TIYandexMapUtils.podspec index ff7ea34a..755a8280 100644 --- a/TIYandexMapUtils/TIYandexMapUtils.podspec +++ b/TIYandexMapUtils/TIYandexMapUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIYandexMapUtils' - s.version = '1.30.0' + s.version = '1.33.0' s.summary = 'Set of helpers for map objects clustering and interacting using Yandex Maps SDK.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } From aff54859eb34d4e0560573aac9f3684a198a4d4f Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Tue, 10 Jan 2023 19:26:46 +0300 Subject: [PATCH 2/7] feat: complete deeplink api --- Package.swift | 8 +- .../BaseNavigationStackDeeplinkHandler.swift | 48 +++++++++++ .../DeeplinkHandler/DeeplinkHandler.swift | 28 ++++++ .../UIViewController+DeeplinkHandler.swift | 37 ++++++++ TIDeepLink/Sources/DeeplinkMapper.swift | 27 ++++++ TIDeepLink/Sources/DeeplinkType.swift | 24 ++++++ TIDeepLink/Sources/TIDeepLinkService.swift | 85 ++++++++++++++++++- TIDeepLink/TIDeepLink.podspec | 7 +- 8 files changed, 255 insertions(+), 9 deletions(-) create mode 100644 TIDeepLink/Sources/DeeplinkHandler/BaseNavigationStackDeeplinkHandler.swift create mode 100644 TIDeepLink/Sources/DeeplinkHandler/DeeplinkHandler.swift create mode 100644 TIDeepLink/Sources/DeeplinkHandler/Helpers/UIViewController+DeeplinkHandler.swift create mode 100644 TIDeepLink/Sources/DeeplinkMapper.swift create mode 100644 TIDeepLink/Sources/DeeplinkType.swift diff --git a/Package.swift b/Package.swift index d77d173e..b892c9e9 100644 --- a/Package.swift +++ b/Package.swift @@ -21,7 +21,7 @@ let package = Package( .library(name: "TIKeychainUtils", targets: ["TIKeychainUtils"]), .library(name: "TITableKitUtils", targets: ["TITableKitUtils"]), .library(name: "TILogging", targets: ["TILogging"]), - .library(name: "TIDeepLink", targets: ["TIDeepLink"]), + .library(name: "TIDeeplink", targets: ["TIDeeplink"]), // MARK: - Networking @@ -33,7 +33,7 @@ let package = Package( .library(name: "TIMapUtils", targets: ["TIMapUtils"]), .library(name: "TIAppleMapUtils", targets: ["TIAppleMapUtils"]), - + // MARK: - Elements .library(name: "OTPSwiftView", targets: ["OTPSwiftView"]), .library(name: "TITransitions", targets: ["TITransitions"]), @@ -66,7 +66,7 @@ let package = Package( .target(name: "TIKeychainUtils", dependencies: ["TIFoundationUtils", "KeychainAccess"], path: "TIKeychainUtils/Sources"), .target(name: "TITableKitUtils", dependencies: ["TIUIElements", "TableKit"], path: "TITableKitUtils/Sources"), .target(name: "TILogging", dependencies: ["TIUIElements", "TISwiftUtils", "TIUIKitCore"], path: "TILogging/Sources"), - .target(name: "TIDeepLink", dependencies: [], path: "TIDeepLink/Sources"), + .target(name: "TIDeeplink", dependencies: ["TIFoundationUtils"], path: "TIDeeplink/Sources"), // MARK: - Networking .target(name: "TINetworking", dependencies: ["TIFoundationUtils", "Alamofire"], path: "TINetworking/Sources"), @@ -76,7 +76,7 @@ let package = Package( // MARK: - Maps .target(name: "TIMapUtils", dependencies: [], path: "TIMapUtils/Sources"), .target(name: "TIAppleMapUtils", dependencies: ["TIMapUtils"], path: "TIAppleMapUtils/Sources"), - + // MARK: - Elements .target(name: "OTPSwiftView", dependencies: ["TIUIElements"], path: "OTPSwiftView/Sources"), .target(name: "TITransitions", path: "TITransitions/Sources"), diff --git a/TIDeepLink/Sources/DeeplinkHandler/BaseNavigationStackDeeplinkHandler.swift b/TIDeepLink/Sources/DeeplinkHandler/BaseNavigationStackDeeplinkHandler.swift new file mode 100644 index 00000000..db7f8671 --- /dev/null +++ b/TIDeepLink/Sources/DeeplinkHandler/BaseNavigationStackDeeplinkHandler.swift @@ -0,0 +1,48 @@ +// +// Copyright (c) 2023 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation +import UIKit + +open class BaseNavigationStackDeeplinkHandler: DeeplinkHandler { + + // MARK: - DeeplinkHandler + + open func canHandle(deeplink: DeeplinkType) -> Bool { + findHandler(for: deeplink) != nil + } + + open func handle(deeplink: DeeplinkType) -> Operation? { + let handler = findHandler(for: deeplink) + return handler?.handle(deeplink: deeplink) + } + + // MARK: - Open methods + + open func findHandler(for deeplink: DeeplinkType) -> DeeplinkHandler? { + guard let rootController = UIApplication.shared.keyWindow?.rootViewController else { + return nil + } + + return rootController.findHandler(for: deeplink) + } +} diff --git a/TIDeepLink/Sources/DeeplinkHandler/DeeplinkHandler.swift b/TIDeepLink/Sources/DeeplinkHandler/DeeplinkHandler.swift new file mode 100644 index 00000000..bb874296 --- /dev/null +++ b/TIDeepLink/Sources/DeeplinkHandler/DeeplinkHandler.swift @@ -0,0 +1,28 @@ +// +// Copyright (c) 2023 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +public protocol DeeplinkHandler { + func canHandle(deeplink: DeeplinkType) -> Bool + func handle(deeplink: DeeplinkType) -> Operation? +} diff --git a/TIDeepLink/Sources/DeeplinkHandler/Helpers/UIViewController+DeeplinkHandler.swift b/TIDeepLink/Sources/DeeplinkHandler/Helpers/UIViewController+DeeplinkHandler.swift new file mode 100644 index 00000000..aba552c3 --- /dev/null +++ b/TIDeepLink/Sources/DeeplinkHandler/Helpers/UIViewController+DeeplinkHandler.swift @@ -0,0 +1,37 @@ +// +// Copyright (c) 2023 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import UIKit + +public typealias DeeplinkHandlerViewController = DeeplinkHandler & UIViewController + +public extension UIViewController { + func findHandler(for deeplink: DeeplinkType) -> DeeplinkHandlerViewController? { + if let deeplinksHandler = self as? DeeplinkHandlerViewController, + deeplinksHandler.canHandle(deeplink: deeplink) { + return deeplinksHandler + } + + let deeplinksHandler = presentedViewController?.findHandler(for: deeplink) + return deeplinksHandler + } +} diff --git a/TIDeepLink/Sources/DeeplinkMapper.swift b/TIDeepLink/Sources/DeeplinkMapper.swift new file mode 100644 index 00000000..60f3262e --- /dev/null +++ b/TIDeepLink/Sources/DeeplinkMapper.swift @@ -0,0 +1,27 @@ +// +// Copyright (c) 2023 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +public protocol DeeplinkMapper { + func map(url: URL) -> DeeplinkType? +} diff --git a/TIDeepLink/Sources/DeeplinkType.swift b/TIDeepLink/Sources/DeeplinkType.swift new file mode 100644 index 00000000..1d317f71 --- /dev/null +++ b/TIDeepLink/Sources/DeeplinkType.swift @@ -0,0 +1,24 @@ +// +// Copyright (c) 2023 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +public protocol DeeplinkType { +} diff --git a/TIDeepLink/Sources/TIDeepLinkService.swift b/TIDeepLink/Sources/TIDeepLinkService.swift index e3b71823..c4d1fcf2 100644 --- a/TIDeepLink/Sources/TIDeepLinkService.swift +++ b/TIDeepLink/Sources/TIDeepLinkService.swift @@ -1,9 +1,88 @@ -final class DeeplinksService { +// +// Copyright (c) 2023 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// - static let shared = DeeplinksService() +import Foundation +import TIFoundationUtils + +public final class TIDeeplinksService { + + public static let shared = TIDeeplinksService() + + // MARK: - Private properties + + private let operationQueue = OperationQueue.main + + private var pendingDeeplink: DeeplinkType? + + private(set) var isProcessDeeplink = false + + // MARK: - Public properties + + public var deeplinkMapper: DeeplinkMapper? + public var deeplinkHandler = BaseNavigationStackDeeplinkHandler() + + // MARK: - Init private init() { } -} + // MARK: - Public methods + + @discardableResult + public func deferredHandle(url: URL) -> Bool { + pendingDeeplink = deeplinkMapper?.map(url: url) + return pendingDeeplink != nil + } + + public func reset() { + operationQueue.cancelAllOperations() + pendingDeeplink = nil + isProcessDeeplink = false + } + + public func tryHandle() { + guard let deeplink = pendingDeeplink, + deeplinkHandler.canHandle(deeplink: deeplink) else { + return + } + + handle() + } + + public func handle() { + guard let deeplink = pendingDeeplink, + let lastOperation = deeplinkHandler.handle(deeplink: deeplink) else { + return + } + + operationQueue.addOperation { [weak self] in + self?.isProcessDeeplink = true + self?.pendingDeeplink = nil + } + operationQueue.addOperations(lastOperation.flattenDependencies + [lastOperation], + waitUntilFinished: false) + operationQueue.addOperation { [weak self] in + self?.isProcessDeeplink = false + } + } +} diff --git a/TIDeepLink/TIDeepLink.podspec b/TIDeepLink/TIDeepLink.podspec index 0e35e6dd..7f8d4b4a 100644 --- a/TIDeepLink/TIDeepLink.podspec +++ b/TIDeepLink/TIDeepLink.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| - s.name = 'TIDeepLink' + s.name = 'TIDeeplink' s.version = '1.33.0' - s.summary = 'Deep link service API' + s.summary = 'Deeplink service API' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru', @@ -12,4 +12,7 @@ Pod::Spec.new do |s| s.swift_versions = ['5.3'] s.source_files = s.name + '/Sources/**/*' + + s.dependency 'TIFoundationUtils', s.version.to_s + end From f885183499292b066de6ab3142ed71713a387187 Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Tue, 10 Jan 2023 19:27:53 +0300 Subject: [PATCH 3/7] fix: updated push to podspecs script --- project-scripts/push_to_podspecs.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/project-scripts/push_to_podspecs.sh b/project-scripts/push_to_podspecs.sh index 217d9687..9dcf2183 100755 --- a/project-scripts/push_to_podspecs.sh +++ b/project-scripts/push_to_podspecs.sh @@ -8,6 +8,7 @@ cd "$DIR" ORDERED_PODSPECS="../TISwiftUtils/TISwiftUtils.podspec ../TIPagination/TIPagination.podspec ../TIFoundationUtils/TIFoundationUtils.podspec +../TIDeeplink/TIDeeplink.podspec ../TIKeychainUtils/TIKeychainUtils.podspec ../TIUIKitCore/TIUIKitCore.podspec ../TISwiftUICore/TISwiftUICore.podspec From 3d5aa7a41df8a9b0db8227c9f23213143cfbf029 Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Wed, 11 Jan 2023 12:02:07 +0300 Subject: [PATCH 4/7] fix: remove default implementation of deeplink handler in service object --- TIDeepLink/Sources/TIDeepLinkService.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TIDeepLink/Sources/TIDeepLinkService.swift b/TIDeepLink/Sources/TIDeepLinkService.swift index c4d1fcf2..eaf18322 100644 --- a/TIDeepLink/Sources/TIDeepLinkService.swift +++ b/TIDeepLink/Sources/TIDeepLinkService.swift @@ -38,7 +38,7 @@ public final class TIDeeplinksService { // MARK: - Public properties public var deeplinkMapper: DeeplinkMapper? - public var deeplinkHandler = BaseNavigationStackDeeplinkHandler() + public var deeplinkHandler: DeeplinkHandler? // MARK: - Init @@ -62,7 +62,7 @@ public final class TIDeeplinksService { public func tryHandle() { guard let deeplink = pendingDeeplink, - deeplinkHandler.canHandle(deeplink: deeplink) else { + deeplinkHandler?.canHandle(deeplink: deeplink) ?? false else { return } @@ -71,7 +71,7 @@ public final class TIDeeplinksService { public func handle() { guard let deeplink = pendingDeeplink, - let lastOperation = deeplinkHandler.handle(deeplink: deeplink) else { + let lastOperation = deeplinkHandler?.handle(deeplink: deeplink) else { return } From caeded9561866446b56f8088368a9caf2448203b Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Wed, 11 Jan 2023 13:25:20 +0300 Subject: [PATCH 5/7] fix: searching deeplink handler in navigation stack --- .../UIViewController+DeeplinkHandler.swift | 44 ++++++++++++++++++- .../Sources/TIDeeplinkService.swift | 13 ++++-- .../TIDeeplink.podspec | 0 3 files changed, 51 insertions(+), 6 deletions(-) rename TIDeepLink/Sources/TIDeepLinkService.swift => TIDeeplink/Sources/TIDeeplinkService.swift (88%) rename TIDeepLink/TIDeepLink.podspec => TIDeeplink/TIDeeplink.podspec (100%) diff --git a/TIDeepLink/Sources/DeeplinkHandler/Helpers/UIViewController+DeeplinkHandler.swift b/TIDeepLink/Sources/DeeplinkHandler/Helpers/UIViewController+DeeplinkHandler.swift index aba552c3..9c15d0fd 100644 --- a/TIDeepLink/Sources/DeeplinkHandler/Helpers/UIViewController+DeeplinkHandler.swift +++ b/TIDeepLink/Sources/DeeplinkHandler/Helpers/UIViewController+DeeplinkHandler.swift @@ -25,13 +25,53 @@ import UIKit public typealias DeeplinkHandlerViewController = DeeplinkHandler & UIViewController public extension UIViewController { + func findHandler(for deeplink: DeeplinkType) -> DeeplinkHandlerViewController? { if let deeplinksHandler = self as? DeeplinkHandlerViewController, deeplinksHandler.canHandle(deeplink: deeplink) { return deeplinksHandler } - let deeplinksHandler = presentedViewController?.findHandler(for: deeplink) - return deeplinksHandler + if let deeplinksHandler = presentedViewController?.findHandler(for: deeplink) { + return deeplinksHandler + } + + return findHandlerInViewHierarchy(for: deeplink) + } + + private func findHandlerInViewHierarchy(for deeplink: DeeplinkType) -> DeeplinkHandlerViewController? { + switch self { + case let navController as UINavigationController: + return navController.viewControllers.reversed().findHadler(for: deeplink) + + 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.findHadler(for: deeplink) { + return deeplinksHandler + } + } + + default: + return nil + } + + return nil + } +} + +private extension Sequence where Element: UIViewController { + func findHadler(for deeplink: DeeplinkType) -> DeeplinkHandlerViewController? { + for controller in self { + if let deeplinksHandler = controller.findHandler(for: deeplink) { + return deeplinksHandler + } + } + return nil } } diff --git a/TIDeepLink/Sources/TIDeepLinkService.swift b/TIDeeplink/Sources/TIDeeplinkService.swift similarity index 88% rename from TIDeepLink/Sources/TIDeepLinkService.swift rename to TIDeeplink/Sources/TIDeeplinkService.swift index eaf18322..7aa6503b 100644 --- a/TIDeepLink/Sources/TIDeepLinkService.swift +++ b/TIDeeplink/Sources/TIDeeplinkService.swift @@ -33,7 +33,7 @@ public final class TIDeeplinksService { private var pendingDeeplink: DeeplinkType? - private(set) var isProcessDeeplink = false + private(set) var isProcessingDeeplink = false // MARK: - Public properties @@ -48,6 +48,11 @@ public final class TIDeeplinksService { // MARK: - Public methods + public func configure(mapper: DeeplinkMapper, handler: DeeplinkHandler) { + deeplinkMapper = mapper + deeplinkHandler = handler + } + @discardableResult public func deferredHandle(url: URL) -> Bool { pendingDeeplink = deeplinkMapper?.map(url: url) @@ -57,7 +62,7 @@ public final class TIDeeplinksService { public func reset() { operationQueue.cancelAllOperations() pendingDeeplink = nil - isProcessDeeplink = false + isProcessingDeeplink = false } public func tryHandle() { @@ -76,13 +81,13 @@ public final class TIDeeplinksService { } operationQueue.addOperation { [weak self] in - self?.isProcessDeeplink = true + self?.isProcessingDeeplink = true self?.pendingDeeplink = nil } operationQueue.addOperations(lastOperation.flattenDependencies + [lastOperation], waitUntilFinished: false) operationQueue.addOperation { [weak self] in - self?.isProcessDeeplink = false + self?.isProcessingDeeplink = false } } } diff --git a/TIDeepLink/TIDeepLink.podspec b/TIDeeplink/TIDeeplink.podspec similarity index 100% rename from TIDeepLink/TIDeepLink.podspec rename to TIDeeplink/TIDeeplink.podspec From 63777fef993373f9ed773f357e4eba4a28c5183c Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Sun, 22 Jan 2023 20:09:24 +0300 Subject: [PATCH 6/7] fix: update an approach to handling operation in TIDeeplinkService --- .../BaseNavigationStackDeeplinkHandler.swift | 16 ++-- .../DeeplinkHandler/DeeplinkHandler.swift | 3 +- .../UIViewController+DeeplinkHandler.swift | 30 +++++--- .../RootViewControllerKeeper.swift} | 7 +- TIDeepLink/Sources/DeeplinkMapper.swift | 2 + TIDeeplink/Sources/TIDeeplinkService.swift | 76 +++++++++++-------- 6 files changed, 83 insertions(+), 51 deletions(-) rename TIDeepLink/Sources/{DeeplinkType.swift => DeeplinkHandler/RootViewControllerKeeper.swift} (85%) diff --git a/TIDeepLink/Sources/DeeplinkHandler/BaseNavigationStackDeeplinkHandler.swift b/TIDeepLink/Sources/DeeplinkHandler/BaseNavigationStackDeeplinkHandler.swift index db7f8671..fd8e4831 100644 --- a/TIDeepLink/Sources/DeeplinkHandler/BaseNavigationStackDeeplinkHandler.swift +++ b/TIDeepLink/Sources/DeeplinkHandler/BaseNavigationStackDeeplinkHandler.swift @@ -23,13 +23,14 @@ import Foundation import UIKit -open class BaseNavigationStackDeeplinkHandler: DeeplinkHandler { +open class BaseNavigationStackDeeplinkHandler: DeeplinkHandler { - // MARK: - DeeplinkHandler + public typealias DeeplinkType = ControllerKeeper.DeeplinkHandler.DeeplinkType + public typealias Handler = ControllerKeeper.DeeplinkHandler - open func canHandle(deeplink: DeeplinkType) -> Bool { - findHandler(for: deeplink) != nil - } + public var rootViewControllerKeeper: ControllerKeeper? + + // MARK: - DeeplinkHandler open func handle(deeplink: DeeplinkType) -> Operation? { let handler = findHandler(for: deeplink) @@ -38,8 +39,9 @@ open class BaseNavigationStackDeeplinkHandler: DeeplinkHandler { // MARK: - Open methods - open func findHandler(for deeplink: DeeplinkType) -> DeeplinkHandler? { - guard let rootController = UIApplication.shared.keyWindow?.rootViewController else { + open func findHandler(for deeplink: DeeplinkType) -> Handler? { + + guard let rootController = rootViewControllerKeeper?.rootDeeplinkHandlerController else { return nil } diff --git a/TIDeepLink/Sources/DeeplinkHandler/DeeplinkHandler.swift b/TIDeepLink/Sources/DeeplinkHandler/DeeplinkHandler.swift index bb874296..cebab7c8 100644 --- a/TIDeepLink/Sources/DeeplinkHandler/DeeplinkHandler.swift +++ b/TIDeepLink/Sources/DeeplinkHandler/DeeplinkHandler.swift @@ -23,6 +23,7 @@ import Foundation public protocol DeeplinkHandler { - func canHandle(deeplink: DeeplinkType) -> Bool + associatedtype DeeplinkType: Hashable + func handle(deeplink: DeeplinkType) -> Operation? } diff --git a/TIDeepLink/Sources/DeeplinkHandler/Helpers/UIViewController+DeeplinkHandler.swift b/TIDeepLink/Sources/DeeplinkHandler/Helpers/UIViewController+DeeplinkHandler.swift index 9c15d0fd..c8bbd46f 100644 --- a/TIDeepLink/Sources/DeeplinkHandler/Helpers/UIViewController+DeeplinkHandler.swift +++ b/TIDeepLink/Sources/DeeplinkHandler/Helpers/UIViewController+DeeplinkHandler.swift @@ -26,33 +26,40 @@ public typealias DeeplinkHandlerViewController = DeeplinkHandler & UIViewControl public extension UIViewController { - func findHandler(for deeplink: DeeplinkType) -> DeeplinkHandlerViewController? { - if let deeplinksHandler = self as? DeeplinkHandlerViewController, - deeplinksHandler.canHandle(deeplink: deeplink) { + func findHandler( + for deeplink: DeeplinkHandler.DeeplinkType + ) -> DeeplinkHandler? { + + if let deeplinksHandler = self as? DeeplinkHandler, + let _ = deeplinksHandler.handle(deeplink: deeplink) { return deeplinksHandler } - if let deeplinksHandler = presentedViewController?.findHandler(for: deeplink) { + if let deeplinksHandler: DeeplinkHandler = presentedViewController?.findHandler(for: deeplink) { return deeplinksHandler } return findHandlerInViewHierarchy(for: deeplink) } - private func findHandlerInViewHierarchy(for deeplink: DeeplinkType) -> DeeplinkHandlerViewController? { + private func findHandlerInViewHierarchy( + for deeplink: DeeplinkHandler.DeeplinkType + ) -> DeeplinkHandler? { + switch self { case let navController as UINavigationController: - return navController.viewControllers.reversed().findHadler(for: deeplink) + let deeplinksHandler: DeeplinkHandler? = navController.viewControllers.reversed().findHandler(for: deeplink) + return deeplinksHandler case let tabController as UITabBarController: - if let deeplinksHandler = tabController.selectedViewController?.findHandler(for: deeplink) { + if let deeplinksHandler: DeeplinkHandler = 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.findHadler(for: deeplink) { + if let deeplinksHandler: DeeplinkHandler = tabControllers.findHandler(for: deeplink) { return deeplinksHandler } } @@ -66,9 +73,12 @@ public extension UIViewController { } private extension Sequence where Element: UIViewController { - func findHadler(for deeplink: DeeplinkType) -> DeeplinkHandlerViewController? { + func findHandler( + for deeplink: DeeplinkHandler.DeeplinkType + ) -> DeeplinkHandler? { + for controller in self { - if let deeplinksHandler = controller.findHandler(for: deeplink) { + if let deeplinksHandler: DeeplinkHandler = controller.findHandler(for: deeplink) { return deeplinksHandler } } diff --git a/TIDeepLink/Sources/DeeplinkType.swift b/TIDeepLink/Sources/DeeplinkHandler/RootViewControllerKeeper.swift similarity index 85% rename from TIDeepLink/Sources/DeeplinkType.swift rename to TIDeepLink/Sources/DeeplinkHandler/RootViewControllerKeeper.swift index 1d317f71..acbd1864 100644 --- a/TIDeepLink/Sources/DeeplinkType.swift +++ b/TIDeepLink/Sources/DeeplinkHandler/RootViewControllerKeeper.swift @@ -20,5 +20,10 @@ // THE SOFTWARE. // -public protocol DeeplinkType { +import UIKit + +public protocol RootViewControllerKeeper { + associatedtype DeeplinkHandler: DeeplinkHandlerViewController + + var rootDeeplinkHandlerController: DeeplinkHandler { get } } diff --git a/TIDeepLink/Sources/DeeplinkMapper.swift b/TIDeepLink/Sources/DeeplinkMapper.swift index 60f3262e..9ad21cf3 100644 --- a/TIDeepLink/Sources/DeeplinkMapper.swift +++ b/TIDeepLink/Sources/DeeplinkMapper.swift @@ -23,5 +23,7 @@ import Foundation public protocol DeeplinkMapper { + associatedtype DeeplinkType + func map(url: URL) -> DeeplinkType? } diff --git a/TIDeeplink/Sources/TIDeeplinkService.swift b/TIDeeplink/Sources/TIDeeplinkService.swift index 7aa6503b..c8099fe4 100644 --- a/TIDeeplink/Sources/TIDeeplinkService.swift +++ b/TIDeeplink/Sources/TIDeeplinkService.swift @@ -23,71 +23,83 @@ import Foundation import TIFoundationUtils -public final class TIDeeplinksService { - - public static let shared = TIDeeplinksService() +open class TIDeeplinksService where Mapper.DeeplinkType == Handler.DeeplinkType, + Mapper.DeeplinkType == DeeplinkType { // MARK: - Private properties - private let operationQueue = OperationQueue.main - - private var pendingDeeplink: DeeplinkType? + private var operationQueue: OperationQueue - private(set) var isProcessingDeeplink = false + private var deeplinkQueue: [DeeplinkType] = [] + private var inProcessingSet: Set = [] // MARK: - Public properties - public var deeplinkMapper: DeeplinkMapper? - public var deeplinkHandler: DeeplinkHandler? + public var deeplinkMapper: Mapper? + public var deeplinkHandler: Handler? // MARK: - Init - private init() { - + public init(operationQueue: OperationQueue = .main) { + self.operationQueue = operationQueue } - // MARK: - Public methods + // MARK: - Open methods - public func configure(mapper: DeeplinkMapper, handler: DeeplinkHandler) { + open func configure(mapper: Mapper, handler: Handler) { deeplinkMapper = mapper deeplinkHandler = handler } @discardableResult - public func deferredHandle(url: URL) -> Bool { - pendingDeeplink = deeplinkMapper?.map(url: url) - return pendingDeeplink != nil + open func deferredHandle(url: URL) -> Bool { + let deeplink = deeplinkMapper?.map(url: url) + + guard let deeplink = deeplink else { + return false + } + + deeplinkQueue.append(deeplink) + + return true } - public func reset() { + open func reset() { operationQueue.cancelAllOperations() - pendingDeeplink = nil - isProcessingDeeplink = false + deeplinkQueue.removeAll() + inProcessingSet.removeAll() } - public func tryHandle() { - guard let deeplink = pendingDeeplink, - deeplinkHandler?.canHandle(deeplink: deeplink) ?? false else { + open func tryHandle() { + guard !deeplinkQueue.isEmpty else { return } handle() } - public func handle() { - guard let deeplink = pendingDeeplink, - let lastOperation = deeplinkHandler?.handle(deeplink: deeplink) else { + open func handle() { + guard let deeplink = deeplinkQueue.first else { return } - operationQueue.addOperation { [weak self] in - self?.isProcessingDeeplink = true - self?.pendingDeeplink = nil + deeplinkQueue.remove(at: .zero) + + guard !inProcessingSet.contains(deeplink), + let operation = deeplinkHandler?.handle(deeplink: deeplink) else { + return } - operationQueue.addOperations(lastOperation.flattenDependencies + [lastOperation], - waitUntilFinished: false) - operationQueue.addOperation { [weak self] in - self?.isProcessingDeeplink = false + + inProcessingSet.formUnion([deeplink]) + + let competionOperation = BlockOperation { [weak self] in + self?.inProcessingSet.subtract([deeplink]) } + + competionOperation.addDependency(operation) + + competionOperation.add(to: operationQueue) } } From 7765c01074d46f3ce2bbd8dd97b8a025934e44aa Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Sun, 12 Feb 2023 18:35:28 +0300 Subject: [PATCH 7/7] fix: code review notes --- TIDeeplink/Sources/TIDeeplinkService.swift | 27 ++++++++-------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/TIDeeplink/Sources/TIDeeplinkService.swift b/TIDeeplink/Sources/TIDeeplinkService.swift index c8099fe4..dd2e5e98 100644 --- a/TIDeeplink/Sources/TIDeeplinkService.swift +++ b/TIDeeplink/Sources/TIDeeplinkService.swift @@ -42,17 +42,17 @@ open class TIDeeplinksService Bool { let deeplink = deeplinkMapper?.map(url: url) @@ -72,23 +72,16 @@ open class TIDeeplinksService