diff --git a/Mail/Views/Thread/MessageBodyView.swift b/Mail/Views/Thread/MessageBodyView.swift
index 9099fa36b..0876a0fed 100644
--- a/Mail/Views/Thread/MessageBodyView.swift
+++ b/Mail/Views/Thread/MessageBodyView.swift
@@ -29,47 +29,54 @@ struct MessageBodyView: View {
@State private var webViewCompleteHeight: CGFloat = .zero
@State private var showBlockQuote = false
+ @State private var contentLoading = true
var body: some View {
- VStack {
- if let body = presentableBody.body {
- if body.type == "text/plain" {
- SelectableTextView(text: body.value)
- .padding(.horizontal, 16)
- } else {
- GeometryReader { proxy in
+ ZStack {
+ VStack {
+ if let body = presentableBody.body {
+ if body.type == "text/plain" {
+ SelectableTextView(text: body.value)
+ .padding(.horizontal, 16)
+ .onAppear {
+ withAnimation {
+ contentLoading = false
+ }
+ }
+ } else {
WebView(
model: $model,
shortHeight: $webViewShortHeight,
completeHeight: $webViewCompleteHeight,
- withQuote: $showBlockQuote,
- proxy: proxy
+ loading: $contentLoading,
+ withQuote: $showBlockQuote
)
- }
- .frame(height: showBlockQuote ? webViewCompleteHeight : webViewShortHeight)
- .onAppear {
- loadBody()
- }
- .onChange(of: presentableBody) { _ in
- loadBody()
- }
- .onChange(of: showBlockQuote) { _ in
- loadBody()
- }
+ .frame(minHeight: showBlockQuote ? webViewCompleteHeight : webViewShortHeight)
+ .onAppear {
+ loadBody()
+ }
+ .onChange(of: presentableBody) { _ in
+ loadBody()
+ }
+ .onChange(of: showBlockQuote) { _ in
+ loadBody()
+ }
- if presentableBody.quote != nil {
- MailButton(label: showBlockQuote
- ? MailResourcesStrings.Localizable.messageHideQuotedText
- : MailResourcesStrings.Localizable.messageShowQuotedText) {
- showBlockQuote.toggle()
- }
- .mailButtonStyle(.smallLink)
- .frame(maxWidth: .infinity, alignment: .leading)
- .padding(.horizontal, 16)
+ if presentableBody.quote != nil {
+ MailButton(label: showBlockQuote
+ ? MailResourcesStrings.Localizable.messageHideQuotedText
+ : MailResourcesStrings.Localizable.messageShowQuotedText) {
+ showBlockQuote.toggle()
+ }
+ .mailButtonStyle(.smallLink)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .padding(.horizontal, 16)
+ }
}
}
- } else {
- // Display a shimmer while the body is loading
+ }
+ .opacity(contentLoading ? 0 : 1)
+ if contentLoading {
ShimmerView()
}
}
diff --git a/Mail/Views/Thread/WebViewModel.swift b/Mail/Views/Thread/WebViewModel.swift
index e01e5bff2..0d981ce48 100644
--- a/Mail/Views/Thread/WebViewModel.swift
+++ b/Mail/Views/Thread/WebViewModel.swift
@@ -28,8 +28,8 @@ struct WebView: UIViewRepresentable {
@Binding var model: WebViewModel
@Binding var shortHeight: CGFloat
@Binding var completeHeight: CGFloat
+ @Binding var loading: Bool
@Binding var withQuote: Bool
- var proxy: GeometryProxy
var webView: WKWebView {
return model.webView
@@ -40,15 +40,15 @@ struct WebView: UIViewRepresentable {
init(_ parent: WebView) {
self.parent = parent
- parent.model.proxy = parent.proxy
}
private func updateHeight(height: CGFloat) {
if !parent.withQuote {
if parent.shortHeight < height {
+ parent.shortHeight = height
+ parent.completeHeight = height
withAnimation {
- parent.shortHeight = height
- parent.completeHeight = height
+ parent.loading = false
}
}
} else if parent.completeHeight < height {
@@ -57,17 +57,13 @@ struct WebView: UIViewRepresentable {
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
- webView.evaluateJavaScript("document.readyState") { complete, _ in
- if complete != nil {
- webView.evaluateJavaScript("document.documentElement.scrollHeight") { height, _ in
- guard let height = height as? CGFloat else { return }
- DispatchQueue.main.async { [weak self] in
- self?.updateHeight(height: height)
- }
- }
- }
- }
+ Task { @MainActor in
+ let readyState = try await webView.evaluateJavaScript("document.readyState") as? String
+ guard readyState == "complete" else { return }
+
+ let scrollHeight = try await webView.evaluateJavaScript("document.documentElement.scrollHeight") as? CGFloat
+ guard let scrollHeight else { return }
+ updateHeight(height: scrollHeight)
}
}
@@ -107,17 +103,14 @@ struct WebView: UIViewRepresentable {
}
}
-class WebViewModel: ObservableObject {
+class WebViewModel {
let webView: WKWebView
- var proxy: GeometryProxy?
- let css: String? = try? String(contentsOfFile: Bundle.main.path(forResource: "style", ofType: "css") ?? "", encoding: .utf8)
- .replacingOccurrences(of: "\n", with: "")
var viewport: String {
- return ""
+ return ""
}
var style: String {
- return ""
+ return ""
}
init() {
@@ -144,6 +137,17 @@ class WebViewModel: ObservableObject {
head = try parsedHtml.appendElement("head")
}
+ let allImages = try parsedHtml.select("img[width]").array()
+ let maxWidth = webView.frame.width
+ for image in allImages {
+ if let widthString = image.getAttributes()?.get(key: "width"),
+ let width = Double(widthString),
+ width > maxWidth {
+ try image.attr("width", "\(maxWidth)")
+ try image.attr("height", "auto")
+ }
+ }
+
try head.append(viewport)
try head.append(style)
diff --git a/MailCore/Utils/Constants.swift b/MailCore/Utils/Constants.swift
index cc7d945d7..2bfb3c84c 100644
--- a/MailCore/Utils/Constants.swift
+++ b/MailCore/Utils/Constants.swift
@@ -66,6 +66,8 @@ public enum Constants {
}()
public static let extendedWhitelist = Whitelist.extendedWhitelist
+ public static let customCss = (try? String(contentsOfFile: Bundle.main.path(forResource: "style", ofType: "css") ?? "",
+ encoding: .utf8).replacingOccurrences(of: "\n", with: "")) ?? ""
public static func forwardQuote(message: Message) -> String {
let date = DateFormatter.localizedString(from: message.date, dateStyle: .medium, timeStyle: .short)