IceCubesApp/Packages/Env/Sources/Env/Router.swift

156 lines
5.5 KiB
Swift
Raw Normal View History

2022-11-29 10:46:02 +00:00
import Foundation
2022-12-17 12:37:46 +00:00
import Models
import Network
2023-01-17 10:36:01 +00:00
import SwiftUI
2022-11-29 10:46:02 +00:00
public enum RouterDestinations: Hashable {
2022-11-29 10:46:02 +00:00
case accountDetail(id: String)
2022-12-17 12:37:46 +00:00
case accountDetailWithAccount(account: Account)
case accountSettingsWithAccount(account: Account, appAccount: AppAccount)
2022-11-29 10:46:02 +00:00
case statusDetail(id: String)
2023-01-22 15:55:03 +00:00
case conversationDetail(conversation: Conversation)
case remoteStatusDetail(url: URL)
2022-12-21 19:26:38 +00:00
case hashTag(tag: String, account: String?)
case list(list: Models.List)
2022-12-23 17:47:19 +00:00
case followers(id: String)
case following(id: String)
case favoritedBy(id: String)
2022-12-24 12:41:25 +00:00
case rebloggedBy(id: String)
2022-11-29 10:46:02 +00:00
}
2022-12-20 08:37:07 +00:00
public enum SheetDestinations: Identifiable {
case newStatusEditor(visibility: Models.Visibility)
2022-12-27 12:38:10 +00:00
case editStatusEditor(status: Status)
case replyToStatusEditor(status: Status)
case quoteStatusEditor(status: Status)
2023-01-04 17:37:58 +00:00
case mentionStatusEditor(account: Account, visibility: Models.Visibility)
case listEdit(list: Models.List)
case listAddAccount(account: Account)
case addAccount
2023-01-06 16:14:34 +00:00
case addRemoteLocalTimeline
2023-01-19 20:19:19 +00:00
case statusEditHistory(status: String)
case settings
case accountPushNotficationsSettings
2023-01-17 10:36:01 +00:00
2022-12-20 08:37:07 +00:00
public var id: String {
switch self {
case .editStatusEditor, .newStatusEditor, .replyToStatusEditor, .quoteStatusEditor,
.mentionStatusEditor, .settings, .accountPushNotficationsSettings:
return "statusEditor"
case .listEdit:
return "listEdit"
case .listAddAccount:
return "listAddAccount"
case .addAccount:
return "addAccount"
2023-01-06 16:14:34 +00:00
case .addRemoteLocalTimeline:
return "addRemoteLocalTimeline"
2023-01-19 20:19:19 +00:00
case .statusEditHistory:
return "statusEditHistory"
2022-12-20 08:37:07 +00:00
}
}
}
@MainActor
2022-11-29 10:46:02 +00:00
public class RouterPath: ObservableObject {
public var client: Client?
public var urlHandler: ((URL) -> OpenURLAction.Result)?
2023-01-17 10:36:01 +00:00
@Published public var path: [RouterDestinations] = []
2022-12-20 08:37:07 +00:00
@Published public var presentedSheet: SheetDestinations?
2023-01-17 10:36:01 +00:00
2022-11-29 10:46:02 +00:00
public init() {}
2023-01-17 10:36:01 +00:00
public func navigate(to: RouterDestinations) {
2022-11-29 10:46:02 +00:00
path.append(to)
}
2023-01-17 10:36:01 +00:00
2022-12-19 14:51:25 +00:00
public func handleStatus(status: AnyStatus, url: URL) -> OpenURLAction.Result {
2023-01-25 05:14:55 +00:00
if url.pathComponents.count == 3 && url.pathComponents[1] == "tags" &&
url.host() == status.account.url?.host(),
2023-01-17 10:36:01 +00:00
let tag = url.pathComponents.last
{
2023-01-25 05:14:55 +00:00
// OK this test looks weird but it's
// A 3 component path i.e. ["/", "tags", "tagname"]
// That is on the same host as the person that posted the tag,
// i.e. not a link that matches the pattern but elsewhere on the internet
// In those circumstances, hijack the link and goto the tags page instead
2022-12-21 19:26:38 +00:00
navigate(to: .hashTag(tag: tag, account: nil))
2022-12-20 14:37:51 +00:00
return .handled
} else if let mention = status.mentions.first(where: { $0.url == url }) {
2022-12-19 14:51:25 +00:00
navigate(to: .accountDetail(id: mention.id))
return .handled
} else if let client = client,
2023-01-12 17:25:37 +00:00
client.isAuth,
client.hasConnection(with: url),
2023-01-17 10:36:01 +00:00
let id = Int(url.lastPathComponent)
{
if url.absoluteString.contains(client.server) {
navigate(to: .statusDetail(id: String(id)))
} else {
navigate(to: .remoteStatusDetail(url: url))
}
return .handled
2022-12-19 14:51:25 +00:00
}
return urlHandler?(url) ?? .systemAction
2022-12-19 14:51:25 +00:00
}
2023-01-17 10:36:01 +00:00
public func handle(url: URL) -> OpenURLAction.Result {
if url.pathComponents.contains(where: { $0 == "tags" }),
2023-01-17 10:36:01 +00:00
let tag = url.pathComponents.last
{
navigate(to: .hashTag(tag: tag, account: nil))
return .handled
} else if url.lastPathComponent.first == "@", let host = url.host {
let acct = "\(url.lastPathComponent)@\(host)"
Task {
await navigateToAccountFrom(acct: acct, url: url)
}
return .handled
} else if let client = client,
client.isAuth,
client.hasConnection(with: url),
let id = Int(url.lastPathComponent) {
if url.absoluteString.contains(client.server) {
navigate(to: .statusDetail(id: String(id)))
} else {
navigate(to: .remoteStatusDetail(url: url))
}
return .handled
}
return urlHandler?(url) ?? .systemAction
}
2023-01-17 10:36:01 +00:00
public func navigateToAccountFrom(acct: String, url: URL) async {
2023-01-01 08:19:00 +00:00
guard let client else { return }
Task {
let results: SearchResults? = try? await client.get(endpoint: Search.search(query: acct,
type: "accounts",
2023-01-01 08:19:00 +00:00
offset: nil,
following: nil),
forceVersion: .v2)
if let account = results?.accounts.first {
navigate(to: .accountDetailWithAccount(account: account))
2023-01-01 08:19:00 +00:00
} else {
await UIApplication.shared.open(url)
}
}
}
2023-01-17 10:36:01 +00:00
public func navigateToAccountFrom(url: URL) async {
2023-01-01 08:19:00 +00:00
guard let client else { return }
Task {
let results: SearchResults? = try? await client.get(endpoint: Search.search(query: url.absoluteString,
type: "accounts",
2023-01-01 08:19:00 +00:00
offset: nil,
following: nil),
forceVersion: .v2)
if let account = results?.accounts.first {
navigate(to: .accountDetailWithAccount(account: account))
} else {
await UIApplication.shared.open(url)
2023-01-01 08:19:00 +00:00
}
}
}
2022-11-29 10:46:02 +00:00
}