110 lines
3.0 KiB
Swift
110 lines
3.0 KiB
Swift
//
|
|
/*
|
|
* SwiftFin is subject to the terms of the Mozilla Public
|
|
* License, v2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
|
*/
|
|
|
|
import Combine
|
|
import Foundation
|
|
import JellyfinAPI
|
|
import Stinsen
|
|
|
|
final class AppURLHandler {
|
|
static let deepLinkScheme = "jellyfin"
|
|
|
|
enum AppURLState {
|
|
case launched
|
|
case allowedInLogin
|
|
case allowed
|
|
|
|
func allowedScheme(with url: URL) -> Bool {
|
|
switch self {
|
|
case .launched:
|
|
return false
|
|
case .allowed:
|
|
return true
|
|
case .allowedInLogin:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
static let shared = AppURLHandler()
|
|
|
|
var cancellables = Set<AnyCancellable>()
|
|
|
|
var appURLState: AppURLState = .launched
|
|
var launchURL: URL?
|
|
}
|
|
|
|
extension AppURLHandler {
|
|
@discardableResult
|
|
func processDeepLink(url: URL) -> Bool {
|
|
guard url.scheme == Self.deepLinkScheme || url.scheme == "widget-extension" else {
|
|
return false
|
|
}
|
|
if AppURLHandler.shared.appURLState.allowedScheme(with: url) {
|
|
return processURL(url)
|
|
} else {
|
|
launchURL = url
|
|
}
|
|
return true
|
|
}
|
|
|
|
func processLaunchedURLIfNeeded() {
|
|
guard let launchURL = launchURL,
|
|
!launchURL.absoluteString.isEmpty else { return }
|
|
if processDeepLink(url: launchURL) {
|
|
self.launchURL = nil
|
|
}
|
|
}
|
|
|
|
private func processURL(_ url: URL) -> Bool {
|
|
if processURLForUser(url: url) {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
private func processURLForUser(url: URL) -> Bool {
|
|
guard url.host?.lowercased() == "users",
|
|
url.pathComponents[safe: 1]?.isEmpty == false else { return false }
|
|
|
|
// /Users/{UserID}/Items/{ItemID}
|
|
if url.pathComponents[safe: 2]?.lowercased() == "items",
|
|
let userID = url.pathComponents[safe: 1],
|
|
let itemID = url.pathComponents[safe: 3] {
|
|
// It would be nice if the ItemViewModel could be initialized to id later.
|
|
getItem(userID: userID, itemID: itemID) { item in
|
|
guard let item = item else { return }
|
|
SwiftfinNotificationCenter.main.post(name: SwiftfinNotificationCenter.Keys.processDeepLink, object: DeepLink.item(item))
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
}
|
|
|
|
extension AppURLHandler {
|
|
func getItem(userID: String, itemID: String, completion: @escaping (BaseItemDto?) -> Void) {
|
|
UserLibraryAPI.getItem(userId: userID, itemId: itemID)
|
|
.sink(receiveCompletion: { innerCompletion in
|
|
switch innerCompletion {
|
|
case .failure:
|
|
completion(nil)
|
|
default:
|
|
break
|
|
}
|
|
}, receiveValue: { item in
|
|
completion(item)
|
|
})
|
|
.store(in: &cancellables)
|
|
}
|
|
}
|