// LoopFollow // NightScoutViewController.swift import Combine import UIKit import WebKit class NightscoutViewController: UIViewController { var webView: WKWebView! private var cancellables = Set() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground overrideUserInterfaceStyle = Storage.shared.appearanceMode.value.userInterfaceStyle // Create WKWebView programmatically let webConfiguration = WKWebViewConfiguration() webConfiguration.mediaTypesRequiringUserActionForPlayback = [] webView = WKWebView(frame: .zero, configuration: webConfiguration) webView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(webView) let safeArea = view.safeAreaLayoutGuide NSLayoutConstraint.activate([ webView.topAnchor.constraint(equalTo: safeArea.topAnchor), webView.leadingAnchor.constraint(equalTo: view.leadingAnchor), webView.trailingAnchor.constraint(equalTo: view.trailingAnchor), webView.bottomAnchor.constraint(equalTo: safeArea.bottomAnchor), ]) // Listen for appearance setting changes Storage.shared.appearanceMode.$value .receive(on: DispatchQueue.main) .sink { [weak self] mode in self?.overrideUserInterfaceStyle = mode.userInterfaceStyle } .store(in: &cancellables) var url = Storage.shared.url.value let token = Storage.shared.token.value if token != "" { url = url + "?token=" + token } guard let myUrl = URL(string: url) else { return } let webpagePreferences = WKWebpagePreferences() webpagePreferences.allowsContentJavaScript = true webView.configuration.defaultWebpagePreferences = webpagePreferences webView.navigationDelegate = self webView.uiDelegate = self webView.load(URLRequest(url: myUrl)) let refreshControl = UIRefreshControl() refreshControl.addTarget(self, action: #selector(reloadWebView(_:)), for: .valueChanged) webView.scrollView.addSubview(refreshControl) } @objc func reloadWebView(_ sender: UIRefreshControl) { clearWebCache() webView.reload() sender.endRefreshing() } func clearWebCache() { let dataStore = WKWebsiteDataStore.default() let cacheTypes = Set([WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache]) let date = Date(timeIntervalSince1970: 0) dataStore.removeData(ofTypes: cacheTypes, modifiedSince: date) { print("Web cache cleared.") } } // this handles target=_blank links by opening them in the same view func webView(webView: WKWebView!, createWebViewWithConfiguration _: WKWebViewConfiguration!, forNavigationAction navigationAction: WKNavigationAction!, windowFeatures _: WKWindowFeatures!) -> WKWebView! { if let frame = navigationAction.targetFrame, frame.isMainFrame { return nil } // for _blank target or non-mainFrame target webView.load(navigationAction.request) return nil } } // MARK: - WKUIDelegate implementation extension NightscoutViewController: WKNavigationDelegate, WKUIDelegate { func webView(_: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame _: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { let alertCtrl = UIAlertController(title: nil, message: message, preferredStyle: .alert) alertCtrl.addAction(UIAlertAction(title: "OK", style: .default) { _ in completionHandler(true) }) alertCtrl.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in completionHandler(false) }) present(alertCtrl, animated: true) } func webView(_: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { guard let _ = navigationAction.request.url else { decisionHandler(.cancel) return } decisionHandler(.allow) } func webView(_: WKWebView, shouldStartLoadWith request: URLRequest) -> Bool { guard let url = request.url else { return false } LogManager.shared.log(category: .nightscout, message: "Web shouldStart: \(LogRedactor.url(url.absoluteString))", isDebug: true) return true } func webView(_ webView: WKWebView, createWebViewWith _: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures _: WKWindowFeatures) -> WKWebView? { if navigationAction.targetFrame == nil { webView.load(navigationAction.request) } return nil } func webView(_ webView: WKWebView, didFinish _: WKNavigation!) { let javascript = """ var meta = document.querySelector('meta[name="viewport"]'); if (meta) { meta.setAttribute('content', 'width=device-width, initial-scale=0.9, maximum-scale=5.0, user-scalable=yes'); } """ webView.evaluateJavaScript(javascript) } }