bugger/Sources/Views/Web/FeishuWebView.swift

60 lines
2.1 KiB
Swift

import AppKit
import SwiftUI
import WebKit
/// Embeds the Feishu record page inside the app. Uses the default persistent
/// data store, so the Feishu login survives app restarts. Workflow (流程)
/// fields can't be reached via the API — this is the in-app way to advance them.
struct FeishuWebView: NSViewRepresentable {
let url: URL
func makeNSView(context: Context) -> WKWebView {
let configuration = WKWebViewConfiguration()
configuration.websiteDataStore = .default()
let webView = WKWebView(frame: .zero, configuration: configuration)
webView.navigationDelegate = context.coordinator
webView.allowsBackForwardNavigationGestures = true
webView.load(URLRequest(url: url))
return webView
}
func updateNSView(_ webView: WKWebView, context: Context) {
if webView.url?.absoluteString != url.absoluteString {
webView.load(URLRequest(url: url))
}
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
final class Coordinator: NSObject, WKNavigationDelegate {
// Only http(s) navigates inside the webview. Custom schemes the page
// may try (e.g. feishu:// to hand off to the desktop client) are
// routed to the system instead of failing silently.
func webView(
_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction
) async -> WKNavigationActionPolicy {
guard let url = navigationAction.request.url,
let scheme = url.scheme else { return .allow }
if scheme == "http" || scheme == "https" {
return .allow
}
NSWorkspace.shared.open(url)
return .cancel
}
}
}
/// Window content wrapper: WKWebView has no intrinsic size, so a bare hosting
/// controller collapses the window to ~1px — pin a minimum size here.
struct FeishuWebWindowContent: View {
let url: URL
var body: some View {
FeishuWebView(url: url)
.frame(minWidth: 900, minHeight: 600)
}
}