From 9999575533aa9478571b5fdad4267915ca7d3da6 Mon Sep 17 00:00:00 2001 From: Jineun Jeong Date: Sat, 14 Jan 2023 10:37:41 +0900 Subject: [PATCH 1/3] feat(): add function that store url for deferred handling - separate protocol file - add store test codes --- Sources/Deeplinker/Deeplinkable.swift | 22 +++++++++++ Sources/Deeplinker/Deeplinker.swift | 38 ++++++++----------- Tests/DeeplinkerTests/DeeplinkerTests.swift | 41 +++++++++++++++++++++ 3 files changed, 78 insertions(+), 23 deletions(-) create mode 100644 Sources/Deeplinker/Deeplinkable.swift diff --git a/Sources/Deeplinker/Deeplinkable.swift b/Sources/Deeplinker/Deeplinkable.swift new file mode 100644 index 0000000..044c080 --- /dev/null +++ b/Sources/Deeplinker/Deeplinkable.swift @@ -0,0 +1,22 @@ +// +// Deeplinkable.swift +// +// +// Created by JSilver on 2023/01/14. +// + +import Foundation + +public protocol Deeplinkable { + /// Handle deeplink url. + @discardableResult + func handle(url: URL) -> Bool +} + +public protocol DeferredDeeplinkable: Deeplinkable { + /// Handle deferred deeplink url. + @discardableResult + func handle() -> Bool + /// Store deeplink url to handle after. + func store(url: URL) +} diff --git a/Sources/Deeplinker/Deeplinker.swift b/Sources/Deeplinker/Deeplinker.swift index c2b3e8e..dcefddd 100644 --- a/Sources/Deeplinker/Deeplinker.swift +++ b/Sources/Deeplinker/Deeplinker.swift @@ -7,18 +7,6 @@ import Foundation -public protocol Deeplinkable { - /// Handle deeplink url. - @discardableResult - func handle(url: URL) -> Bool -} - -public protocol DeferredDeeplinkable: Deeplinkable { - /// Handle deferred deeplink url. - @discardableResult - func handle() -> Bool -} - public class Deeplinker: DeferredDeeplinkable { // MARK: - Property private var deeplinks: [Deeplink] = [] @@ -33,24 +21,16 @@ public class Deeplinker: DeferredDeeplinkable { } // MARK: - Public - public func handle() -> Bool { - canHandle = true - - guard let url = deferredURL else { return false } - deferredURL = nil - - // Handle deferred url. - return handle(url: url) - } - @discardableResult public func handle(url: URL) -> Bool { guard canHandle else { // Store url until to can handle. - deferredURL = url + store(url: url) return false } + // Reset deferred url. + deferredURL = nil // Handle first matched deeplink with url. let deeplink = deeplinks.first { $0.matches(url: url) } @@ -59,6 +39,18 @@ public class Deeplinker: DeferredDeeplinkable { ?? false } + public func handle() -> Bool { + canHandle = true + + guard let url = deferredURL else { return false } + // Handle deferred url. + return handle(url: url) + } + + public func store(url: URL) { + deferredURL = url + } + public func addDefault(action: @escaping Action) { self.defaultDeeplink = Deeplink(pattern: ".*", action: action) } diff --git a/Tests/DeeplinkerTests/DeeplinkerTests.swift b/Tests/DeeplinkerTests/DeeplinkerTests.swift index 5487491..045cc37 100644 --- a/Tests/DeeplinkerTests/DeeplinkerTests.swift +++ b/Tests/DeeplinkerTests/DeeplinkerTests.swift @@ -215,4 +215,45 @@ final class DeeplinkerTests: XCTestCase { "Deferred \(url.absoluteString) was not reset." ) } + + func test_that_deeplinker_should_handle_stored_deeplink() { + // Given + let sut = Deeplinker() + sut.addURL("deeplinker://a/b") { _, _, _ in true } + + let url = URL(string: "deeplinker://a/b")! + + // When + sut.store(url: url) + let result = sut.handle() + + // Then + XCTAssertTrue( + result, + "Deferred \(url.absoluteString) was not handled." + ) + } + + func test_that_deeplinker_should_reset_stored_deeplink_after_handle_new_deeplink() { + // Given + let sut = Deeplinker() + sut.addURL("deeplinker://a/b") { _, _, _ in true } + + let storeURL = URL(string: "deeplinker://a/b")! + let newURL = URL(string: "deeplinker://a/c")! + + // When + // Store first deeplink. + sut.store(url: storeURL) + // Handle new deeplink. + sut.handle(url: newURL) + // Try to handle stored deeplink. + let result = sut.handle() + + // Then + XCTAssertFalse( + result, + "Deferred \(storeURL.absoluteString) was not reset." + ) + } } From 41711b4811db8da50b7af54ebf9f3fefe7a6750b Mon Sep 17 00:00:00 2001 From: Jineun Jeong Date: Sat, 14 Jan 2023 10:38:35 +0900 Subject: [PATCH 2/3] feat(): add `DeeplinkerDelegate` - add `DeeplinkerDelegate` test codes --- Sources/Deeplinker/Deeplinker.swift | 4 ++ Sources/Deeplinker/DeeplinkerDelegate.swift | 24 +++++++++++ Tests/DeeplinkerTests/DeeplinkerTests.swift | 43 +++++++++++++++++++ .../Model/DeeplinkerDelegater.swift | 33 ++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 Sources/Deeplinker/DeeplinkerDelegate.swift create mode 100644 Tests/DeeplinkerTests/Model/DeeplinkerDelegater.swift diff --git a/Sources/Deeplinker/Deeplinker.swift b/Sources/Deeplinker/Deeplinker.swift index dcefddd..04587da 100644 --- a/Sources/Deeplinker/Deeplinker.swift +++ b/Sources/Deeplinker/Deeplinker.swift @@ -15,6 +15,8 @@ public class Deeplinker: DeferredDeeplinkable { private var canHandle: Bool private var deferredURL: URL? + weak var delegate: DeeplinkerDelegate? + // MARK: - Initializer public init(canHandle: Bool = true) { self.canHandle = canHandle @@ -34,6 +36,8 @@ public class Deeplinker: DeferredDeeplinkable { // Handle first matched deeplink with url. let deeplink = deeplinks.first { $0.matches(url: url) } + guard delegate?.deeplinker(self, shouldHandle: url) ?? true else { return false } + return deeplink?.action(url: url) ?? defaultDeeplink?.action(url: url) ?? false diff --git a/Sources/Deeplinker/DeeplinkerDelegate.swift b/Sources/Deeplinker/DeeplinkerDelegate.swift new file mode 100644 index 0000000..f1a1359 --- /dev/null +++ b/Sources/Deeplinker/DeeplinkerDelegate.swift @@ -0,0 +1,24 @@ +// +// DeeplinkerDelegate.swift +// +// +// Created by JSilver on 2023/01/14. +// + +import Foundation + +public protocol DeeplinkerDelegate: AnyObject { + func deeplinker( + _ deeplinker: Deeplinker, + shouldHandle url: URL + ) -> Bool +} + +public extension DeeplinkerDelegate { + func deeplinker( + _ deeplinker: Deeplinker, + shouldHandle url: URL + ) -> Bool { + true + } +} diff --git a/Tests/DeeplinkerTests/DeeplinkerTests.swift b/Tests/DeeplinkerTests/DeeplinkerTests.swift index 045cc37..1757ad6 100644 --- a/Tests/DeeplinkerTests/DeeplinkerTests.swift +++ b/Tests/DeeplinkerTests/DeeplinkerTests.swift @@ -256,4 +256,47 @@ final class DeeplinkerTests: XCTestCase { "Deferred \(storeURL.absoluteString) was not reset." ) } + + func test_that_deeplinker_should_handle_deeplink_when_set_delegate_with_default_implementation() { + // Given + let sut = Deeplinker() + sut.addURL("deeplinker://a/b") { _, _, _ in true } + + let delegater = DeeplinkerDefaultDelegater() + sut.delegate = delegater + + let url = URL(string: "deeplinker://a/b")! + + // When + let result = sut.handle(url: url) + + // Then + XCTAssertTrue( + result, + "\(url.absoluteString) was not handled." + ) + } + + func test_that_deeplinker_should_not_handle_deeplink_when_delegate_should_handle_return_false() { + // Given + let sut = Deeplinker() + sut.addURL("deeplinker://a/b") { _, _, _ in true } + + let delegater = DeeplinkerDelegater { _ in + false + } + + sut.delegate = delegater + + let url = URL(string: "deeplinker://a/b")! + + // When + let result = sut.handle(url: url) + + // Then + XCTAssertFalse( + result, + "\(url.absoluteString) was handled." + ) + } } diff --git a/Tests/DeeplinkerTests/Model/DeeplinkerDelegater.swift b/Tests/DeeplinkerTests/Model/DeeplinkerDelegater.swift new file mode 100644 index 0000000..b912aef --- /dev/null +++ b/Tests/DeeplinkerTests/Model/DeeplinkerDelegater.swift @@ -0,0 +1,33 @@ +// +// DeeplinkerDelegater.swift +// +// +// Created by JSilver on 2023/01/14. +// + +import Foundation +import Deeplinker + +class DeeplinkerDefaultDelegater: DeeplinkerDelegate { } + +class DeeplinkerDelegater: DeeplinkerDelegate { + // MARK: - Property + private let shouldHandle: (URL) -> Bool + + // MARK: - Initializer + init(shouldHandle: @escaping (URL) -> Bool) { + self.shouldHandle = shouldHandle + } + + // MARK: - Lifecycle + func deeplinker( + _ deeplinker: Deeplinker, + shouldHandle url: URL + ) -> Bool { + shouldHandle(url) + } + + // MARK: - Public + + // MARK: - Private +} From eb231b6b116ff1bf90dcffa561e523f41e81b7d2 Mon Sep 17 00:00:00 2001 From: Jineun Jeong Date: Sat, 14 Jan 2023 10:46:46 +0900 Subject: [PATCH 3/3] feat(): add annotation about delegate method --- Sources/Deeplinker/DeeplinkerDelegate.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/Deeplinker/DeeplinkerDelegate.swift b/Sources/Deeplinker/DeeplinkerDelegate.swift index f1a1359..ea88f3e 100644 --- a/Sources/Deeplinker/DeeplinkerDelegate.swift +++ b/Sources/Deeplinker/DeeplinkerDelegate.swift @@ -8,6 +8,7 @@ import Foundation public protocol DeeplinkerDelegate: AnyObject { + /// Asks the delegate if the deeplinker should handle an deeplink with url. func deeplinker( _ deeplinker: Deeplinker, shouldHandle url: URL