Files
Yuvomi-App/legacy/ios/AuthenticationView.swift
T
Yuvomi Mobile Contributors 97570b7fdf feat(ios): replace embedded website with initial native SwiftUI API client
Introduce real SwiftUI auth/dashboard/task/note/shopping screens, a bounded origin-bound URLSession transport and Keychain-backed native sessions. Archive the rejected WebKit renderer rather than embedding it for unfinished modules. Sixteen portable URL/contract/transport tests and Swift format/parsing pass on Linux; Apple SDK application and UI validation remains mandatory. This is an incomplete native slice, not full PWA parity or a release.
2026-10-21 08:57:31 +02:00

78 lines
3.3 KiB
Swift

import SwiftUI
import WebKit
struct AuthenticationView: View {
let destination: URL
@ObservedObject var model: BrowserModel
var body: some View {
NavigationStack {
IsolatedAuthentication(url: destination, model: model)
.navigationTitle(model.authenticationHost)
.navigationBarTitleDisplayMode(.inline)
.toolbar { Button("Close") { model.authentication = nil } }
}
}
}
struct IsolatedAuthentication: UIViewRepresentable {
let url: URL
let model: BrowserModel
func makeCoordinator() -> Coordinator { Coordinator(model) }
func makeUIView(context: Context) -> WKWebView {
let configuration = WKWebViewConfiguration()
// Same cookie store as the initiating Yuvomi handshake; no manual cookie export.
configuration.websiteDataStore = model.web.configuration.websiteDataStore
configuration.preferences.javaScriptCanOpenWindowsAutomatically = false
configuration.mediaTypesRequiringUserActionForPlayback = .all
let view = WKWebView(frame: .zero, configuration: configuration)
view.navigationDelegate = context.coordinator
view.uiDelegate = context.coordinator
if #available(iOS 16.4, *) { view.isInspectable = false }
view.load(URLRequest(url: url))
return view
}
func updateUIView(_ uiView: WKWebView, context: Context) {}
static func dismantleUIView(_ uiView: WKWebView, coordinator: Coordinator) {
uiView.stopLoading()
uiView.navigationDelegate = nil
uiView.uiDelegate = nil
}
final class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate {
let model: BrowserModel
init(_ model: BrowserModel) { self.model = model }
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
model.authenticationHost = webView.url?.host ?? "Sign in"
}
func webView(
_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
) {
guard let url = navigationAction.request.url, url.scheme == "https",
url.user == nil, url.password == nil
else {
decisionHandler(.cancel)
return
}
decisionHandler(.allow)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
if let url = webView.url, model.server?.owns(url) == true, !url.path.hasPrefix("/api/") {
model.authentication = nil
model.web.load(URLRequest(url: url))
}
}
func webView(
_ webView: WKWebView, requestMediaCapturePermissionFor origin: WKSecurityOrigin,
initiatedByFrame frame: WKFrameInfo, type: WKMediaCaptureType,
decisionHandler: @escaping (WKPermissionDecision) -> Void
) { decisionHandler(.deny) }
func webView(
_ webView: WKWebView, runOpenPanelWith parameters: WKOpenPanelParameters,
initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping @MainActor @Sendable ([URL]?) -> Void
) {
completionHandler(nil)
}
}
}