Reload the web view every 10 renderings to clean it up. Issue #1487

This commit is contained in:
Maurice Parker 2020-01-18 11:59:24 -07:00
parent 0d7046adf1
commit f0d8a9038d

View File

@ -28,6 +28,7 @@ class WebViewController: UIViewController {
private var topShowBarsViewConstraint: NSLayoutConstraint!
private var bottomShowBarsViewConstraint: NSLayoutConstraint!
private var renderingTracker = 0
private var webView: WKWebView!
private lazy var contextMenuInteraction = UIContextMenuInteraction(delegate: self)
private var isFullScreenAvailable: Bool {
@ -41,7 +42,7 @@ class WebViewController: UIViewController {
private var isShowingExtractedArticle = false {
didSet {
if isShowingExtractedArticle != oldValue {
reloadHTML()
renderPage()
}
}
}
@ -62,7 +63,7 @@ class WebViewController: UIViewController {
startArticleExtractor()
}
if article != oldValue {
reloadHTML()
renderPage()
}
}
}
@ -101,6 +102,7 @@ class WebViewController: UIViewController {
self.view.bottomAnchor.constraint(equalTo: webView.bottomAnchor)
])
// Configure the tap zones
self.configureTopShowBarsView()
self.configureBottomShowBarsView()
@ -114,53 +116,13 @@ class WebViewController: UIViewController {
// Even though page.html should be loaded into this webview, we have to do it again
// to work around this bug: http://www.openradar.me/22855188
let url = Bundle.main.url(forResource: "page", withExtension: "html")!
webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
self.reloadHTML()
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
}
}
func reloadHTML() {
guard let webView = webView else { return }
let style = ArticleStylesManager.shared.currentStyle
let rendering: ArticleRenderer.Rendering
if let articleExtractor = articleExtractor, articleExtractor.state == .processing {
rendering = ArticleRenderer.loadingHTML(style: style)
} else if let articleExtractor = articleExtractor, articleExtractor.state == .failedToParse, let article = article {
rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true)
} else if let article = article, let extractedArticle = extractedArticle {
if isShowingExtractedArticle {
rendering = ArticleRenderer.articleHTML(article: article, extractedArticle: extractedArticle, style: style, useImageIcon: true)
} else {
rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true)
}
} else if let article = article {
rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true)
} else {
rendering = ArticleRenderer.noSelectionHTML(style: style)
}
let templateData = TemplateData(style: rendering.style, body: rendering.html)
let encoder = JSONEncoder()
var render = "error();"
if let data = try? encoder.encode(templateData) {
let json = String(data: data, encoding: .utf8)!
render = "render(\(json), \(restoreOffset));"
}
restoreOffset = 0
WebViewProvider.shared.articleIconSchemeHandler.currentArticle = article
webView.scrollView.setZoomScale(1.0, animated: false)
webView.evaluateJavaScript(render)
}
// MARK: Notifications
@ -293,7 +255,7 @@ extension WebViewController: ArticleExtractorDelegate {
func articleExtractionDidFail(with: Error) {
stopArticleExtractor()
articleExtractorButtonState = .error
reloadHTML()
renderPage()
}
func articleExtractionDidComplete(extractedArticle: ExtractedArticle) {
@ -377,7 +339,7 @@ extension WebViewController: WKNavigationDelegate {
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.reloadHTML()
self.renderPage()
}
}
@ -460,6 +422,59 @@ private struct ImageClickMessage: Codable {
private extension WebViewController {
func reloadHTML() {
let url = Bundle.main.url(forResource: "page", withExtension: "html")!
webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
renderingTracker = 0
}
func renderPage() {
guard let webView = webView else { return }
// It looks like we need to clean up the webview every once in a while by reloading it from scratch
// Otherwise it will stop responding or cause rendering artifacts. This typically only comes into
// play on the iPad where we aren't constantly pushing and popping this controller.
if (renderingTracker > 10) {
reloadHTML()
}
renderingTracker += 1
let style = ArticleStylesManager.shared.currentStyle
let rendering: ArticleRenderer.Rendering
if let articleExtractor = articleExtractor, articleExtractor.state == .processing {
rendering = ArticleRenderer.loadingHTML(style: style)
} else if let articleExtractor = articleExtractor, articleExtractor.state == .failedToParse, let article = article {
rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true)
} else if let article = article, let extractedArticle = extractedArticle {
if isShowingExtractedArticle {
rendering = ArticleRenderer.articleHTML(article: article, extractedArticle: extractedArticle, style: style, useImageIcon: true)
} else {
rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true)
}
} else if let article = article {
rendering = ArticleRenderer.articleHTML(article: article, style: style, useImageIcon: true)
} else {
rendering = ArticleRenderer.noSelectionHTML(style: style)
}
let templateData = TemplateData(style: rendering.style, body: rendering.html)
let encoder = JSONEncoder()
var render = "error();"
if let data = try? encoder.encode(templateData) {
let json = String(data: data, encoding: .utf8)!
render = "render(\(json), \(restoreOffset));"
}
restoreOffset = 0
WebViewProvider.shared.articleIconSchemeHandler.currentArticle = article
webView.scrollView.setZoomScale(1.0, animated: false)
webView.evaluateJavaScript(render)
}
func finalScrollPosition() -> CGFloat {
return webView.scrollView.contentSize.height - webView.scrollView.bounds.height + webView.scrollView.safeAreaInsets.bottom
}