Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gimp/app/dialogs/   (Gimp Bildeditor Version 3.2.0©)  Datei vom 14.2.2026 mit Größe 2 kB image not shown  

SSL SettingsWebViewViewController.swift  Sprache: unbekannt

 
import CocoaLumberjackSwift
import JDStatusBarNotification
import MBProgressHUD
import SafariServices
import ThreemaFramework
import ThreemaMacros
import UIKit
@preconcurrency import WebKit

class SettingsWebViewViewController: ThemedViewController {
    
    // MARK: - Public property

    private(set) lazy var webView: WKWebView = {
        let webPagePreferences = WKWebpagePreferences()
        webPagePreferences.allowsContentJavaScript = allowsContentJavaScript
        
        let webConfiguration = WKWebViewConfiguration()
        webConfiguration.defaultWebpagePreferences = webPagePreferences
        let webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.allowsLinkPreview = false
        webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        webView.isOpaque = false
        
        return webView
    }()
    
    // MARK: - Private properties

    private var url: URL?
    private var isSetupWizard = false
    private var allowsContentJavaScript = false
    private var loadingPresenter: NotificationPresenter?

    // MARK: - Lifecycle
    
    /// Show content of a website in a webView
    /// - Parameters:
    ///   - url: URL of the content
    ///   - title: Title of the controller
    ///   - allowsContentJavaScript: The default value of this property is false. If you change the value to true, the
    ///                              web view execute JavaScript code referenced by the web content.
    ///   - isSetupWizard: If true, it will set all to dark mode
    @objc init(
        url: URL? = nil,
        title: String,
        allowsContentJavaScript: Bool = false,
        isSetupWizard: Bool = false
    ) {
        self.url = url
        self.allowsContentJavaScript = allowsContentJavaScript
        self.isSetupWizard = isSetupWizard
        
        super.init(nibName: nil, bundle: nil)
        
        self.title = title
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.largeTitleDisplayMode = .never
        view.backgroundColor = Colors.backgroundViewController
        webView.navigationDelegate = self
        view = webView
        setupTraitRegistration()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        webView.backgroundColor = isSetupWizard ? Colors.backgroundWizard : Colors.backgroundViewController
        loadURL()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        loadingPresenter?.dismiss(animated: false)
    }

    // MARK: Configurations
    
    override var shouldAutorotate: Bool {
        true
    }
    
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        .allButUpsideDown
    }
    
    // MARK: - Private functions
    
    /// Begin loading the URL if it has been set. If the loading process takes more than 0.8 seconds, a loading
    /// indicator will be displayed.
    private func loadURL() {
        guard let url,
              let combinedURL = appendQueryItems(to: url) else {
            DDLogError("Can't load url, because url is empty")
            return
        }
        
        Task.detached {
            try? await Task.sleep(seconds: 0.8)
            
            Task { @MainActor in
                if self.webView.isLoading {
                    NotificationPresenterWrapper.shared.presentIndefinitely(type: .loadingWebSite) { presenter in
                        if self.webView.isLoading {
                            self.loadingPresenter = presenter
                        }
                        else {
                            presenter.dismiss()
                        }
                    }
                }
            }
        }
        
        let request = URLRequest(url: combinedURL, cachePolicy: .reloadIgnoringCacheData)
        webView.load(request)
    }
    
    /// Append the query parameters ‘lang’, ‘version’, ‘platform’, and ‘theme’.
    /// If the ‘isSetupWizard’ parameter is true, the dark theme will always be selected.
    /// - Parameter url: URL to append the items
    /// - Returns: URL?
    private func appendQueryItems(to url: URL) -> URL? {
        let theme: String = {
            guard !self.isSetupWizard else {
                return "dark"
            }
            switch Colors.theme {
            case .dark:
                return "dark"
            case .light:
                return "light"
            }
        }()
        
        return url.appending(queryItems: [
            URLQueryItem(name: "lang", value: Bundle.main.preferredLocalizations.first ?? "en"),
            URLQueryItem(name: "version", value: AppVersionInfo.appVersion.version ?? "-"),
            URLQueryItem(name: "platform", value: "ios"),
            URLQueryItem(name: "theme", value: theme),
        ])
    }
    
    /// Check and add SUPPORT as contact and open the chat with it.
    private func addSupportContactAndOpenChat() {
        ContactStore.shared()
            .addContact(
                with: "*SUPPORT",
                verificationLevel: Int32(ContactEntity.VerificationLevel.fullyVerified.rawValue)
            ) { contact, _ in
                let message = "My app version: \(ThreemaUtility.clientVersionWithMDM)"
                let info = [
                    kKeyContact: contact as Any,
                    kKeyForceCompose: NSNumber(value: true),
                    kKeyText: message,
                ] as [String: Any]
                
                DispatchQueue.main.async {
                    NotificationCenter.default.post(
                        name: NSNotification.Name(rawValue: kNotificationShowConversation),
                        object: nil,
                        userInfo: info
                    )
                }
            }
            onError: { error in
                DDLogError("\(error)")
            }
    }
}

// MARK: - Notifications

extension SettingsWebViewViewController {
    private func setupTraitRegistration() {
        let traits: [UITrait] = [UITraitUserInterfaceStyle.self]
        registerForTraitChanges(traits) { [weak self] (_: Self, previous) in
            guard let self else {
                return
            }
            if previous.userInterfaceStyle != traitCollection.userInterfaceStyle {
                loadURL()
            }
        }
    }
}

// MARK: - WKNavigationDelegate

extension SettingsWebViewViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation?) {
        loadingPresenter?.dismiss()
    }
    
    func webView(
        _ webView: WKWebView,
        decidePolicyFor navigationAction: WKNavigationAction,
        decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
    ) {
        if navigationAction.navigationType == .linkActivated, let url = navigationAction.request.url {
            // In-page anchor: let WebKit scroll to it natively
            if url.fragment != nil, isSameDocument(url, as: webView.url) {
                decisionHandler(.allow)
                return
            }

            if let scheme = url.scheme, scheme.hasPrefix("http") || scheme.hasPrefix("https") {
                let config = SFSafariViewController.Configuration()
                let safariView = SFSafariViewController(url: url, configuration: config)
                present(safariView, animated: true)
            }
            else if let host = url.host,
                    host == "compose",
                    let query = url.query,
                    query.hasPrefix("id=*SUPPORT") {
                addSupportContactAndOpenChat()
            }
            else {
                UIApplication.shared.open(url, options: [:], completionHandler: nil)
            }
            
            decisionHandler(.cancel)
            return
        }
        decisionHandler(.allow)
    }
    
    /// Whether `url` points into the currently loaded document, i.e. only the fragment differs
    private func isSameDocument(_ url: URL, as currentURL: URL?) -> Bool {
        guard let currentURL,
              var target = URLComponents(url: url, resolvingAgainstBaseURL: true),
              var current = URLComponents(url: currentURL, resolvingAgainstBaseURL: true) else {
            return false
        }
        target.fragment = nil
        current.fragment = nil
        return target == current
    }

    func webView(_ webView: WKWebView, didFail navigation: WKNavigation?, withError error: Error) {
        loadingPresenter?.dismiss()
        NotificationPresenterWrapper.shared.present(type: .noConnection)
    }
    
    func webView(
        _ webView: WKWebView,
        didFailProvisionalNavigation navigation: WKNavigation?,
        withError error: any Error
    ) {
        loadingPresenter?.dismiss()
        if (error as NSError).code == URLError.Code.notConnectedToInternet.rawValue {
            NotificationPresenterWrapper.shared.present(type: .noConnection)
        }
    }
}

Messung
CHZG
829610092

[Verzeichnis aufwärts0.104unsichere VerbindungÜbersetzung europäischer Sprachen durch Browser2026-11-04]