Files
ios-mail/Modules/App/Sources/UI/Views/MessageBodyReaderView.swift
T
2025-04-29 11:07:38 +02:00

104 lines
3.3 KiB
Swift

// Copyright (c) 2024 Proton Technologies AG
//
// This file is part of Proton Mail.
//
// Proton Mail is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail. If not, see https://www.gnu.org/licenses/.
import InboxCore
import InboxDesignSystem
import SwiftUI
import WebKit
struct MessageBodyReaderView: UIViewRepresentable {
@Binding var bodyContentHeight: CGFloat
let body: MessageBody.HTML
let urlOpener: URLOpenerProtocol
let htmlLoaded: () -> Void
func makeUIView(context: Context) -> WKWebView {
let backgroundColor = UIColor(DS.Color.Background.norm)
let config = WKWebViewConfiguration()
config.dataDetectorTypes = [.link]
config.setURLSchemeHandler(
CIDSchemeHandler(embeddedImageProvider: body.embeddedImageProvider),
forURLScheme: CIDSchemeHandler.handlerScheme
)
let webView = WKWebView(frame: .zero, configuration: config)
webView.navigationDelegate = context.coordinator
webView.scrollView.isScrollEnabled = false
webView.scrollView.bounces = false
webView.loadHTMLString(body.rawBody)
webView.isOpaque = false
webView.backgroundColor = backgroundColor
webView.scrollView.backgroundColor = backgroundColor
webView.scrollView.contentInsetAdjustmentBehavior = .never
return webView
}
func updateUIView(_ uiView: WKWebView, context: Context) {
updateUIView(uiView)
}
func updateUIView(_ view: WKWebView) {
view.loadHTMLString(body.rawBody)
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
extension MessageBodyReaderView {
class Coordinator: NSObject, WKNavigationDelegate, @unchecked Sendable {
let parent: MessageBodyReaderView
init(_ parent: MessageBodyReaderView) {
self.parent = parent
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
Task { @MainActor in
try await webView.evaluateJavaScript("document.readyState")
let scrollHeight = try await webView.evaluateJavaScript("document.documentElement.scrollHeight")
parent.bodyContentHeight = scrollHeight as! CGFloat
parent.htmlLoaded()
}
}
func webView(
_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction
) async -> WKNavigationActionPolicy {
guard navigationAction.navigationType == .linkActivated, let url = navigationAction.request.url else {
return .allow
}
parent.urlOpener(url)
return .cancel
}
}
}
private extension WKWebView {
func loadHTMLString(_ string: String) {
loadHTMLString(string, baseURL: nil)
}
}