spb/admin-ka-macos
Public
Swift 100%
1import SwiftUI2import WebKit3import AppKit45final class WebModel: ObservableObject {6 @Published var progress: Double = 07 @Published var loaded = false8 @Published var failed = false9 var webView: WKWebView?10 func reload() {11 failed = false; loaded = false; progress = 012 if let wv = webView { if wv.url == nil { wv.load(URLRequest(url: Ka.url)) } else { wv.reload() } }13 }14}1516struct WebView: NSViewRepresentable {17 @ObservedObject var model: WebModel1819 func makeCoordinator() -> Coordinator { Coordinator(model: model) }2021 func makeNSView(context: Context) -> WKWebView {22 let cfg = WKWebViewConfiguration()23 cfg.websiteDataStore = .default() // cookie de session persistant24 cfg.defaultWebpagePreferences.allowsContentJavaScript = true25 let wv = WKWebView(frame: .zero, configuration: cfg)26 wv.navigationDelegate = context.coordinator27 wv.uiDelegate = context.coordinator28 wv.setValue(false, forKey: "drawsBackground") // fond transparent → crème29 wv.customUserAgent = "AdminKa-macOS/1.0 (Groupe KA console)"30 context.coordinator.observe(wv)31 model.webView = wv32 wv.load(URLRequest(url: Ka.url))33 return wv34 }3536 func updateNSView(_ nsView: WKWebView, context: Context) {}3738 final class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate {39 let model: WebModel40 private var obs: NSKeyValueObservation?41 init(model: WebModel) { self.model = model }4243 func observe(_ wv: WKWebView) {44 obs = wv.observe(\.estimatedProgress, options: [.new]) { [weak self] wv, _ in45 DispatchQueue.main.async { self?.model.progress = wv.estimatedProgress }46 }47 }48 func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {49 DispatchQueue.main.async {50 withAnimation(.easeOut(duration: 0.35)) { self.model.loaded = true }51 self.model.failed = false52 }53 }54 func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { fail(error) }55 func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { fail(error) }56 private func fail(_ error: Error) {57 if (error as NSError).code == NSURLErrorCancelled { return }58 DispatchQueue.main.async { self.model.failed = true }59 }6061 // liens externes → navigateur par défaut62 func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,63 decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {64 if let url = navigationAction.request.url, let host = url.host,65 navigationAction.navigationType == .linkActivated, host != Ka.url.host {66 NSWorkspace.shared.open(url); decisionHandler(.cancel); return67 }68 decisionHandler(.allow)69 }70 func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration,71 for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {72 if let url = navigationAction.request.url { NSWorkspace.shared.open(url) }73 return nil74 }7576 // --- Panneaux JS natifs (confirm() indispensable pour le mode BYPASS) ---77 func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String,78 initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {79 let a = NSAlert(); a.messageText = "Admin-Ka"; a.informativeText = message; a.addButton(withTitle: "OK")80 a.runModal(); completionHandler()81 }82 func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String,83 initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {84 let a = NSAlert(); a.messageText = "Admin-Ka"; a.informativeText = message85 a.addButton(withTitle: "OK"); a.addButton(withTitle: "Annuler")86 completionHandler(a.runModal() == .alertFirstButtonReturn)87 }88 func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String,89 defaultText: String?, initiatedByFrame frame: WKFrameInfo,90 completionHandler: @escaping (String?) -> Void) {91 let a = NSAlert(); a.messageText = "Admin-Ka"; a.informativeText = prompt92 a.addButton(withTitle: "OK"); a.addButton(withTitle: "Annuler")93 let tf = NSTextField(frame: NSRect(x: 0, y: 0, width: 260, height: 24)); tf.stringValue = defaultText ?? ""94 a.accessoryView = tf95 completionHandler(a.runModal() == .alertFirstButtonReturn ? tf.stringValue : nil)96 }97 }98}99