diff --git a/IceCubesApp/App/SafariRouter.swift b/IceCubesApp/App/SafariRouter.swift index 9f07762a..5e5a67a2 100644 --- a/IceCubesApp/App/SafariRouter.swift +++ b/IceCubesApp/App/SafariRouter.swift @@ -31,7 +31,7 @@ private struct SafariRouter: ViewModifier { // Open external URL (from icecubesapp://) let urlString = url.absoluteString.replacingOccurrences(of: AppInfo.scheme, with: "https://") guard let url = URL(string: urlString), url.host != nil else { return } - _ = routerPath.handle(url: url) + _ = routerPath.handleDeepLink(url: url) } .onAppear { routerPath.urlHandler = { url in diff --git a/Packages/Env/Sources/Env/Router.swift b/Packages/Env/Sources/Env/Router.swift index 2c282ae0..d653940a 100644 --- a/Packages/Env/Sources/Env/Router.swift +++ b/Packages/Env/Sources/Env/Router.swift @@ -171,20 +171,59 @@ public enum SheetDestination: Identifiable, Hashable { await navigateToAccountFrom(acct: acct, url: url) } return .handled - } else if let 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 } + + public func handleDeepLink(url: URL) -> OpenURLAction.Result { + guard let client, + client.isAuth, + let id = Int(url.lastPathComponent) else { + return urlHandler?(url) ?? .systemAction + } + // First check whether we already know that the client's server federates with the server this post is on + if client.hasConnection(with: url) { + navigateToStatus(url: url, id: id) + return .handled + } + Task { + // Client does not currently report a federation relationship, but that doesn't mean none exists + // Ensure client is aware of all peers its server federates with so it can give a meaningful answer to hasConnection(with:) + do { + let connections: [String] = try await client.get(endpoint: Instances.peers) + client.addConnections(connections) + } catch { + handlerOrDefault(url: url) + return + } + + guard client.hasConnection(with: url) else { + handlerOrDefault(url: url) + return + } + + navigateToStatus(url: url, id: id) + } + + return .handled + } + + private func navigateToStatus(url: URL, id: Int) { + guard let client else { return } + if url.absoluteString.contains(client.server) { + navigate(to: .statusDetail(id: String(id))) + } else { + navigate(to: .remoteStatusDetail(url: url)) + } + } + + private func handlerOrDefault(url: URL) { + if let urlHandler { + _ = urlHandler(url) + } else { + UIApplication.shared.open(url) + } + } public func navigateToAccountFrom(acct: String, url: URL) async { guard let client else { return }