SPB Git forge

spb/admin-ka-ios

Public
5commits 1branches 0releases
204.0 KBsize
maindefault branch
1 mo agolast push
Swift 100%
6.5 KB · 145 lines swift
Raw Blame History
1import SwiftUI2import WebKit3import UIKit45// État partagé entre le WKWebView et l'interface SwiftUI6final class WebModel: ObservableObject {7    @Published var progress: Double = 08    @Published var loaded = false9    @Published var failed = false10    var reloadRequested = false11    var webView: WKWebView?1213    func reload() {14        failed = false15        loaded = false16        progress = 017        if let wv = webView {18            if wv.url == nil { wv.load(URLRequest(url: Ka.url)) } else { wv.reload() }19        }20    }21}2223struct WebView: UIViewRepresentable {24    @ObservedObject var model: WebModel2526    func makeCoordinator() -> Coordinator { Coordinator(model: model) }2728    func makeUIView(context: Context) -> WKWebView {29        let cfg = WKWebViewConfiguration()30        cfg.websiteDataStore = .default() // persiste le cookie de session (reste connecté)31        cfg.allowsInlineMediaPlayback = true32        cfg.defaultWebpagePreferences.allowsContentJavaScript = true3334        let wv = WKWebView(frame: .zero, configuration: cfg)35        wv.navigationDelegate = context.coordinator36        wv.uiDelegate = context.coordinator37        wv.allowsBackForwardNavigationGestures = false38        wv.scrollView.bounces = true39        wv.scrollView.contentInsetAdjustmentBehavior = .never40        wv.isOpaque = false41        wv.backgroundColor = UIColor(Ka.bg)42        wv.scrollView.backgroundColor = UIColor(Ka.bg)43        wv.customUserAgent = "AdminKa-iOS/1.0 (Groupe KA console)"4445        // pull-to-refresh natif46        let rc = UIRefreshControl()47        rc.tintColor = UIColor(Ka.orange)48        rc.addTarget(context.coordinator, action: #selector(Coordinator.onRefresh(_:)), for: .valueChanged)49        wv.scrollView.refreshControl = rc5051        context.coordinator.observe(wv)52        model.webView = wv53        wv.load(URLRequest(url: Ka.url))54        return wv55    }5657    func updateUIView(_ uiView: WKWebView, context: Context) {}5859    final class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate {60        let model: WebModel61        private var obs: NSKeyValueObservation?62        init(model: WebModel) { self.model = model }6364        func observe(_ wv: WKWebView) {65            obs = wv.observe(\.estimatedProgress, options: [.new]) { [weak self] wv, _ in66                DispatchQueue.main.async { self?.model.progress = wv.estimatedProgress }67            }68        }6970        @objc func onRefresh(_ sender: UIRefreshControl) {71            model.webView?.reload()72        }7374        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {75            webView.scrollView.refreshControl?.endRefreshing()76            DispatchQueue.main.async {77                withAnimation(.easeOut(duration: 0.35)) { self.model.loaded = true }78                self.model.failed = false79            }80        }8182        func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { fail(error) }83        func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { fail(error) }84        private func fail(_ error: Error) {85            let ns = error as NSError86            if ns.code == NSURLErrorCancelled { return }87            DispatchQueue.main.async {88                self.model.webView?.scrollView.refreshControl?.endRefreshing()89                self.model.failed = true90            }91        }9293        // liens externes (target=_blank / http externes) → Safari94        func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration,95                     for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {96            if let url = navigationAction.request.url { UIApplication.shared.open(url) }97            return nil98        }99100        // --- Panneaux JavaScript natifs (indispensables : sans eux confirm()101        // --- ne s'affiche pas → le mode BYPASS et les confirmations restent morts) ---102        private func topVC(_ webView: WKWebView) -> UIViewController? {103            var vc = webView.window?.rootViewController104            while let p = vc?.presentedViewController { vc = p }105            return vc106        }107        func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String,108                     initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {109            let a = UIAlertController(title: nil, message: message, preferredStyle: .alert)110            a.addAction(UIAlertAction(title: "OK", style: .default) { _ in completionHandler() })111            guard let vc = topVC(webView) else { completionHandler(); return }112            vc.present(a, animated: true)113        }114        func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String,115                     initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {116            let a = UIAlertController(title: nil, message: message, preferredStyle: .alert)117            a.addAction(UIAlertAction(title: "Annuler", style: .cancel) { _ in completionHandler(false) })118            a.addAction(UIAlertAction(title: "OK", style: .default) { _ in completionHandler(true) })119            guard let vc = topVC(webView) else { completionHandler(false); return }120            vc.present(a, animated: true)121        }122        func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String,123                     defaultText: String?, initiatedByFrame frame: WKFrameInfo,124                     completionHandler: @escaping (String?) -> Void) {125            let a = UIAlertController(title: nil, message: prompt, preferredStyle: .alert)126            a.addTextField { $0.text = defaultText }127            a.addAction(UIAlertAction(title: "Annuler", style: .cancel) { _ in completionHandler(nil) })128            a.addAction(UIAlertAction(title: "OK", style: .default) { _ in completionHandler(a.textFields?.first?.text) })129            guard let vc = topVC(webView) else { completionHandler(nil); return }130            vc.present(a, animated: true)131        }132        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,133                     decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {134            if let url = navigationAction.request.url, let host = url.host,135               navigationAction.navigationType == .linkActivated,136               host != Ka.url.host {137                UIApplication.shared.open(url)138                decisionHandler(.cancel)139                return140            }141            decisionHandler(.allow)142        }143    }144}145