2023-01-08 19:56:16 +01:00
|
|
|
import DesignSystem
|
2023-01-17 11:36:01 +01:00
|
|
|
import Env
|
|
|
|
import SafariServices
|
|
|
|
import SwiftUI
|
2023-01-08 19:56:16 +01:00
|
|
|
|
|
|
|
extension View {
|
2023-01-17 15:14:50 +01:00
|
|
|
func withSafariRouter() -> some View {
|
|
|
|
modifier(SafariRouter())
|
2023-01-17 11:36:01 +01:00
|
|
|
}
|
2023-01-08 19:56:16 +01:00
|
|
|
}
|
|
|
|
|
2023-01-17 15:14:50 +01:00
|
|
|
private struct SafariRouter: ViewModifier {
|
2023-01-17 11:36:01 +01:00
|
|
|
@EnvironmentObject private var theme: Theme
|
|
|
|
@EnvironmentObject private var preferences: UserPreferences
|
2023-01-17 15:14:50 +01:00
|
|
|
@EnvironmentObject private var routerPath: RouterPath
|
2023-01-17 11:36:01 +01:00
|
|
|
|
|
|
|
@State private var safari: SFSafariViewController?
|
|
|
|
|
|
|
|
func body(content: Content) -> some View {
|
|
|
|
content
|
|
|
|
.environment(\.openURL, OpenURLAction { url in
|
2023-01-27 20:35:16 +01:00
|
|
|
// Open internal URL.
|
2023-01-17 15:14:50 +01:00
|
|
|
routerPath.handle(url: url)
|
2023-01-17 11:36:01 +01:00
|
|
|
})
|
2023-01-27 20:35:16 +01:00
|
|
|
.onOpenURL(perform: { url in
|
|
|
|
// Open external URL (from icecubesapp://)
|
|
|
|
let urlString = url.absoluteString.replacingOccurrences(of: "icecubesapp://", with: "https://")
|
2023-01-29 07:36:20 +01:00
|
|
|
guard let url = URL(string: urlString), url.host != nil else { return }
|
2023-01-27 20:35:16 +01:00
|
|
|
_ = routerPath.handle(url: url)
|
|
|
|
})
|
2023-01-17 11:36:01 +01:00
|
|
|
.onAppear {
|
2023-01-17 15:14:50 +01:00
|
|
|
routerPath.urlHandler = { url in
|
2023-01-23 21:34:45 +01:00
|
|
|
if url.absoluteString.contains("@twitter.com"), url.absoluteString.hasPrefix("mailto:") {
|
|
|
|
let username = url.absoluteString
|
|
|
|
.replacingOccurrences(of: "@twitter.com", with: "")
|
|
|
|
.replacingOccurrences(of: "mailto:", with: "")
|
|
|
|
let twitterLink = "https://twitter.com/\(username)"
|
|
|
|
if let url = URL(string: twitterLink) {
|
|
|
|
UIApplication.shared.open(url)
|
|
|
|
return .handled
|
|
|
|
}
|
|
|
|
}
|
2023-01-19 11:59:12 +01:00
|
|
|
guard preferences.preferredBrowser == .inAppSafari, !ProcessInfo.processInfo.isiOSAppOnMac else { return .systemAction }
|
2023-01-17 11:36:01 +01:00
|
|
|
// SFSafariViewController only supports initial URLs with http:// or https:// schemes.
|
|
|
|
guard let scheme = url.scheme, ["https", "http"].contains(scheme.lowercased()) else {
|
|
|
|
return .systemAction
|
|
|
|
}
|
|
|
|
|
|
|
|
let safari = SFSafariViewController(url: url)
|
|
|
|
safari.preferredBarTintColor = UIColor(theme.primaryBackgroundColor)
|
|
|
|
safari.preferredControlTintColor = UIColor(theme.tintColor)
|
|
|
|
|
|
|
|
self.safari = safari
|
|
|
|
return .handled
|
2023-01-08 19:56:16 +01:00
|
|
|
}
|
2023-01-17 11:36:01 +01:00
|
|
|
}
|
|
|
|
.background {
|
|
|
|
SafariPresenter(safari: safari)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct SafariPresenter: UIViewRepresentable {
|
|
|
|
var safari: SFSafariViewController?
|
|
|
|
|
|
|
|
func makeUIView(context _: Context) -> UIView {
|
|
|
|
let view = UIView(frame: .zero)
|
|
|
|
view.isHidden = true
|
|
|
|
view.isUserInteractionEnabled = false
|
|
|
|
return view
|
2023-01-08 19:56:16 +01:00
|
|
|
}
|
2023-01-17 11:36:01 +01:00
|
|
|
|
|
|
|
func updateUIView(_ uiView: UIView, context _: Context) {
|
|
|
|
guard let safari = safari, let viewController = uiView.findTopViewController() else { return }
|
|
|
|
viewController.present(safari, animated: true)
|
|
|
|
}
|
|
|
|
}
|
2023-01-08 19:56:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private extension UIView {
|
2023-01-17 11:36:01 +01:00
|
|
|
func findTopViewController() -> UIViewController? {
|
|
|
|
if let nextResponder = next as? UIViewController {
|
|
|
|
return nextResponder.topViewController()
|
|
|
|
} else if let nextResponder = next as? UIView {
|
|
|
|
return nextResponder.findTopViewController()
|
|
|
|
} else {
|
|
|
|
return nil
|
2023-01-08 19:56:16 +01:00
|
|
|
}
|
2023-01-17 11:36:01 +01:00
|
|
|
}
|
2023-01-08 19:56:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private extension UIViewController {
|
2023-01-17 11:36:01 +01:00
|
|
|
func topViewController() -> UIViewController? {
|
|
|
|
if let nvc = self as? UINavigationController {
|
|
|
|
return nvc.visibleViewController?.topViewController()
|
|
|
|
} else if let tbc = self as? UITabBarController, let selected = tbc.selectedViewController {
|
|
|
|
return selected.topViewController()
|
|
|
|
} else if let presented = presentedViewController {
|
|
|
|
return presented.topViewController()
|
2023-01-08 19:56:16 +01:00
|
|
|
}
|
2023-01-17 11:36:01 +01:00
|
|
|
return self
|
|
|
|
}
|
2023-01-08 19:56:16 +01:00
|
|
|
}
|