Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[RELEASE] Deeplinker/1.1.0 #2

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Sources/Deeplinker/Deeplinkable.swift
Original file line number Diff line number Diff line change
@@ -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)
}
42 changes: 19 additions & 23 deletions Sources/Deeplinker/Deeplinker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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] = []
Expand All @@ -27,38 +15,46 @@ 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
}

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

guard delegate?.deeplinker(self, shouldHandle: url) ?? true else { return false }

return deeplink?.action(url: url)
?? defaultDeeplink?.action(url: url)
?? 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)
}
Expand Down
25 changes: 25 additions & 0 deletions Sources/Deeplinker/DeeplinkerDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// DeeplinkerDelegate.swift
//
//
// Created by JSilver on 2023/01/14.
//

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
) -> Bool
}

public extension DeeplinkerDelegate {
func deeplinker(
_ deeplinker: Deeplinker,
shouldHandle url: URL
) -> Bool {
true
}
}
84 changes: 84 additions & 0 deletions Tests/DeeplinkerTests/DeeplinkerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,88 @@ 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."
)
}

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."
)
}
}
33 changes: 33 additions & 0 deletions Tests/DeeplinkerTests/Model/DeeplinkerDelegater.swift
Original file line number Diff line number Diff line change
@@ -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
}