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 topShowBarsViewConstraint: NSLayoutConstraint!
private var bottomShowBarsViewConstraint: NSLayoutConstraint! private var bottomShowBarsViewConstraint: NSLayoutConstraint!
private var renderingTracker = 0
private var webView: WKWebView! private var webView: WKWebView!
private lazy var contextMenuInteraction = UIContextMenuInteraction(delegate: self) private lazy var contextMenuInteraction = UIContextMenuInteraction(delegate: self)
private var isFullScreenAvailable: Bool { private var isFullScreenAvailable: Bool {
@ -41,7 +42,7 @@ class WebViewController: UIViewController {
private var isShowingExtractedArticle = false { private var isShowingExtractedArticle = false {
didSet { didSet {
if isShowingExtractedArticle != oldValue { if isShowingExtractedArticle != oldValue {
reloadHTML() renderPage()
} }
} }
} }
@ -62,7 +63,7 @@ class WebViewController: UIViewController {
startArticleExtractor() startArticleExtractor()
} }
if article != oldValue { if article != oldValue {
reloadHTML() renderPage()
} }
} }
} }
@ -101,6 +102,7 @@ class WebViewController: UIViewController {
self.view.bottomAnchor.constraint(equalTo: webView.bottomAnchor) self.view.bottomAnchor.constraint(equalTo: webView.bottomAnchor)
]) ])
// Configure the tap zones
self.configureTopShowBarsView() self.configureTopShowBarsView()
self.configureBottomShowBarsView() 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 // 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 // to work around this bug: http://www.openradar.me/22855188
let url = Bundle.main.url(forResource: "page", withExtension: "html")! self.reloadHTML()
webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
self.view.setNeedsLayout() self.view.setNeedsLayout()
self.view.layoutIfNeeded() 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 // MARK: Notifications
@ -293,7 +255,7 @@ extension WebViewController: ArticleExtractorDelegate {
func articleExtractionDidFail(with: Error) { func articleExtractionDidFail(with: Error) {
stopArticleExtractor() stopArticleExtractor()
articleExtractorButtonState = .error articleExtractorButtonState = .error
reloadHTML() renderPage()
} }
func articleExtractionDidComplete(extractedArticle: ExtractedArticle) { func articleExtractionDidComplete(extractedArticle: ExtractedArticle) {
@ -377,7 +339,7 @@ extension WebViewController: WKNavigationDelegate {
} }
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.reloadHTML() self.renderPage()
} }
} }
@ -460,6 +422,59 @@ private struct ImageClickMessage: Codable {
private extension WebViewController { 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 { func finalScrollPosition() -> CGFloat {
return webView.scrollView.contentSize.height - webView.scrollView.bounds.height + webView.scrollView.safeAreaInsets.bottom return webView.scrollView.contentSize.height - webView.scrollView.bounds.height + webView.scrollView.safeAreaInsets.bottom
} }