mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Make the article icon code specify the desired article so that it can't pull the wrong one by mistake. Issue #1707
This commit is contained in:
@@ -58,8 +58,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
||||
super.init()
|
||||
appDelegate = self
|
||||
|
||||
// Force lazy initialization of the web view provider so that it can warm up the queue of prepared web views
|
||||
let _ = WebViewProvider.shared
|
||||
AccountManager.shared = AccountManager()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
|
||||
|
||||
58
iOS/Article/ArticleIconSchemeHandler.swift
Normal file
58
iOS/Article/ArticleIconSchemeHandler.swift
Normal file
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// ArticleIconSchemeHandler.swift
|
||||
// NetNewsWire-iOS
|
||||
//
|
||||
// Created by Maurice Parker on 1/27/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import WebKit
|
||||
import Articles
|
||||
|
||||
class ArticleIconSchemeHandler: NSObject, WKURLSchemeHandler {
|
||||
|
||||
let coordinator: SceneCoordinator
|
||||
|
||||
init(coordinator: SceneCoordinator) {
|
||||
self.coordinator = coordinator
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
|
||||
|
||||
guard let url = urlSchemeTask.request.url else {
|
||||
urlSchemeTask.didFailWithError(URLError(.fileDoesNotExist))
|
||||
return
|
||||
}
|
||||
|
||||
let articleID = url.absoluteString.stripping(prefix: "\(ArticleRenderer.imageIconScheme)://")
|
||||
|
||||
guard let iconImage = coordinator.articleFor(articleID)?.iconImage() else {
|
||||
urlSchemeTask.didFailWithError(URLError(.fileDoesNotExist))
|
||||
return
|
||||
}
|
||||
|
||||
let iconView = IconView(frame: CGRect(x: 0, y: 0, width: 48, height: 48))
|
||||
iconView.iconImage = iconImage
|
||||
let renderedImage = iconView.asImage()
|
||||
|
||||
guard let data = renderedImage.dataRepresentation() else {
|
||||
urlSchemeTask.didFailWithError(URLError(.fileDoesNotExist))
|
||||
return
|
||||
}
|
||||
|
||||
let headerFields = ["Cache-Control": "no-cache"]
|
||||
if let response = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: headerFields) {
|
||||
urlSchemeTask.didReceive(response)
|
||||
urlSchemeTask.didReceive(data)
|
||||
urlSchemeTask.didFinish()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
|
||||
urlSchemeTask.didFailWithError(URLError(.unknown))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ class WebViewController: UIViewController {
|
||||
webView.configuration.userContentController.removeScriptMessageHandler(forName: MessageName.imageWasClicked)
|
||||
webView.configuration.userContentController.removeScriptMessageHandler(forName: MessageName.imageWasShown)
|
||||
webView.removeFromSuperview()
|
||||
WebViewProvider.shared.enqueueWebView(webView)
|
||||
coordinator.webViewProvider.enqueueWebView(webView)
|
||||
webView = nil
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ class WebViewController: UIViewController {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(faviconDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil)
|
||||
|
||||
WebViewProvider.shared.dequeueWebView() { webView in
|
||||
coordinator.webViewProvider.dequeueWebView() { webView in
|
||||
|
||||
// Add the webview
|
||||
self.webView = webView
|
||||
@@ -486,7 +486,6 @@ private extension WebViewController {
|
||||
|
||||
restoreWindowScrollY = 0
|
||||
|
||||
WebViewProvider.shared.articleIconSchemeHandler.currentArticle = article
|
||||
webView.scrollView.setZoomScale(1.0, animated: false)
|
||||
webView.evaluateJavaScript(render)
|
||||
|
||||
|
||||
@@ -13,9 +13,7 @@ import WebKit
|
||||
/// Keep a queue of WebViews where we've already done a trivial load so that by the time we need them in the UI, they're past the flash-to-shite part of their lifecycle.
|
||||
class WebViewProvider: NSObject, WKNavigationDelegate {
|
||||
|
||||
static let shared = WebViewProvider()
|
||||
|
||||
let articleIconSchemeHandler = ArticleIconSchemeHandler()
|
||||
let articleIconSchemeHandler: ArticleIconSchemeHandler
|
||||
|
||||
private let minimumQueueDepth = 3
|
||||
private let maximumQueueDepth = 6
|
||||
@@ -24,6 +22,12 @@ class WebViewProvider: NSObject, WKNavigationDelegate {
|
||||
private var waitingForFirstLoad = true
|
||||
private var waitingCompletionHandler: ((WKWebView) -> ())?
|
||||
|
||||
init(coordinator: SceneCoordinator) {
|
||||
articleIconSchemeHandler = ArticleIconSchemeHandler(coordinator: coordinator)
|
||||
super.init()
|
||||
replenishQueueIfNeeded()
|
||||
}
|
||||
|
||||
func dequeueWebView(completion: @escaping (WKWebView) -> ()) {
|
||||
if waitingForFirstLoad {
|
||||
waitingCompletionHandler = completion
|
||||
@@ -58,11 +62,6 @@ class WebViewProvider: NSObject, WKNavigationDelegate {
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private override init() {
|
||||
super.init()
|
||||
replenishQueueIfNeeded()
|
||||
}
|
||||
|
||||
private func replenishQueueIfNeeded() {
|
||||
while queue.count < minimumQueueDepth {
|
||||
let preferences = WKPreferences()
|
||||
|
||||
@@ -30,6 +30,8 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
||||
return rootSplitViewController.undoManager
|
||||
}
|
||||
|
||||
lazy var webViewProvider = WebViewProvider(coordinator: self)
|
||||
|
||||
private var panelMode: PanelMode = .unset
|
||||
|
||||
private var activityManager = ActivityManager()
|
||||
@@ -255,9 +257,19 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
||||
private(set) var articles = ArticleArray() {
|
||||
didSet {
|
||||
timelineMiddleIndexPath = nil
|
||||
articleDictionaryNeedsUpdate = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private var articleDictionaryNeedsUpdate = true
|
||||
private var _idToArticleDictionary = [String: Article]()
|
||||
private var idToAticleDictionary: [String: Article] {
|
||||
if articleDictionaryNeedsUpdate {
|
||||
rebuildArticleDictionaries()
|
||||
}
|
||||
return _idToArticleDictionary
|
||||
}
|
||||
|
||||
private var currentArticleRow: Int? {
|
||||
guard let article = currentArticle else { return nil }
|
||||
return articles.firstIndex(of: article)
|
||||
@@ -572,6 +584,10 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
||||
return shadowTable[section]
|
||||
}
|
||||
|
||||
func articleFor(_ articleID: String) -> Article? {
|
||||
return idToAticleDictionary[articleID]
|
||||
}
|
||||
|
||||
func cappedIndexPath(_ indexPath: IndexPath) -> IndexPath {
|
||||
guard indexPath.section < shadowTable.count && indexPath.row < shadowTable[indexPath.section].count else {
|
||||
return IndexPath(row: shadowTable[shadowTable.count - 1].count - 1, section: shadowTable.count - 1)
|
||||
@@ -1222,6 +1238,17 @@ private extension SceneCoordinator {
|
||||
unreadCount = count
|
||||
}
|
||||
|
||||
func rebuildArticleDictionaries() {
|
||||
var idDictionary = [String: Article]()
|
||||
|
||||
articles.forEach { article in
|
||||
idDictionary[article.articleID] = article
|
||||
}
|
||||
|
||||
_idToArticleDictionary = idDictionary
|
||||
articleDictionaryNeedsUpdate = false
|
||||
}
|
||||
|
||||
func rebuildBackingStores(initialLoad: Bool = false, updateExpandedNodes: (() -> Void)? = nil) {
|
||||
if !animatingChanges && !BatchUpdate.shared.isPerforming {
|
||||
treeController.rebuild()
|
||||
|
||||
Reference in New Issue
Block a user