Merge pull request #1 from Ranchero-Software/ios-release

Ios release
This commit is contained in:
Stuart Breckenridge 2020-05-13 07:30:28 +08:00 committed by GitHub
commit 1f7d40a537
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 123 additions and 48 deletions

View File

@ -202,12 +202,7 @@ class ArticleViewController: UIViewController {
}
@objc func contentSizeCategoryDidChange(_ note: Notification) {
coordinator.webViewProvider.flushQueue()
coordinator.webViewProvider.replenishQueueIfNeeded()
if let controller = currentWebViewController {
controller.fullReload()
self.pageViewController.setViewControllers([controller], direction: .forward, animated: false, completion: nil)
}
resetWebViewController()
}
@objc func willEnterForeground(_ note: Notification) {
@ -215,6 +210,7 @@ class ArticleViewController: UIViewController {
if AppDefaults.articleFullscreenEnabled {
currentWebViewController?.hideBars()
}
resetWebViewController()
}
// MARK: Actions
@ -274,10 +270,6 @@ class ArticleViewController: UIViewController {
currentWebViewController?.scrollPageDown()
}
func fullReload() {
currentWebViewController?.fullReload()
}
func stopArticleExtractorIfProcessing() {
currentWebViewController?.stopArticleExtractorIfProcessing()
}
@ -366,4 +358,13 @@ private extension ArticleViewController {
return controller
}
func resetWebViewController() {
coordinator.webViewProvider.flushQueue()
coordinator.webViewProvider.replenishQueueIfNeeded()
if let controller = currentWebViewController {
controller.fullReload()
self.pageViewController.setViewControllers([controller], direction: .forward, animated: false, completion: nil)
}
}
}

View File

@ -148,7 +148,7 @@ class WebViewController: UIViewController {
}
func fullReload() {
self.loadWebView()
loadWebView(replaceExistingWebView: true)
}
func showBars() {
@ -288,10 +288,16 @@ extension WebViewController: UIContextMenuInteractionDelegate {
// MARK: WKNavigationDelegate
extension WebViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
if view.subviews.count > 1 {
view.subviews.last?.removeFromSuperview()
}
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if navigationAction.navigationType == .linkActivated {
guard let url = navigationAction.request.url else {
decisionHandler(.allow)
return
@ -313,13 +319,13 @@ extension WebViewController: WKNavigationDelegate {
} else {
decisionHandler(.allow)
}
} else {
decisionHandler(.allow)
}
}
func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
fullReload()
}
}
@ -402,10 +408,10 @@ private struct ImageClickMessage: Codable {
private extension WebViewController {
func loadWebView() {
func loadWebView(replaceExistingWebView: Bool = false) {
guard isViewLoaded else { return }
if let webView = webView {
if !replaceExistingWebView, let webView = webView {
self.renderPage(webView)
return
}

View File

@ -7,42 +7,116 @@
//
import Foundation
import RSCore
import WebKit
/// WKWebView has an awful behavior of a flash to white on first load when in dark mode.
/// 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 {
let articleIconSchemeHandler: ArticleIconSchemeHandler
private let minimumQueueDepth = 3
private let maximumQueueDepth = 6
private let articleIconSchemeHandler: ArticleIconSchemeHandler
private let operationQueue = MainThreadOperationQueue()
private var queue = UIView()
init(coordinator: SceneCoordinator, viewController: UIViewController) {
articleIconSchemeHandler = ArticleIconSchemeHandler(coordinator: coordinator)
super.init()
viewController.view.insertSubview(queue, at: 0)
replenishQueueIfNeeded()
}
func flushQueue() {
queue.subviews.forEach { $0.removeFromSuperview() }
operationQueue.add(WebViewProviderFlushQueueOperation(queue: queue))
}
func replenishQueueIfNeeded() {
while queue.subviews.count < minimumQueueDepth {
enqueueWebView(PreloadedWebView(articleIconSchemeHandler: articleIconSchemeHandler))
}
operationQueue.add(WebViewProviderReplenishQueueOperation(queue: queue, articleIconSchemeHandler: articleIconSchemeHandler))
}
func dequeueWebView(completion: @escaping (PreloadedWebView) -> ()) {
operationQueue.add(WebViewProviderDequeueOperation(queue: queue, articleIconSchemeHandler: articleIconSchemeHandler, completion: completion))
operationQueue.add(WebViewProviderReplenishQueueOperation(queue: queue, articleIconSchemeHandler: articleIconSchemeHandler))
}
}
class WebViewProviderFlushQueueOperation: MainThreadOperation {
// MainThreadOperation
public var isCanceled = false
public var id: Int?
public weak var operationDelegate: MainThreadOperationDelegate?
public var name: String? = "WebViewProviderFlushQueueOperation"
public var completionBlock: MainThreadOperation.MainThreadOperationCompletionBlock?
private var queue: UIView
init(queue: UIView) {
self.queue = queue
}
func run() {
queue.subviews.forEach { $0.removeFromSuperview() }
self.operationDelegate?.operationDidComplete(self)
}
}
class WebViewProviderReplenishQueueOperation: MainThreadOperation {
// MainThreadOperation
public var isCanceled = false
public var id: Int?
public weak var operationDelegate: MainThreadOperationDelegate?
public var name: String? = "WebViewProviderReplenishQueueOperation"
public var completionBlock: MainThreadOperation.MainThreadOperationCompletionBlock?
private let minimumQueueDepth = 3
private var queue: UIView
private var articleIconSchemeHandler: ArticleIconSchemeHandler
init(queue: UIView, articleIconSchemeHandler: ArticleIconSchemeHandler) {
self.queue = queue
self.articleIconSchemeHandler = articleIconSchemeHandler
}
func run() {
while queue.subviews.count < minimumQueueDepth {
let webView = PreloadedWebView(articleIconSchemeHandler: articleIconSchemeHandler)
queue.insertSubview(webView, at: 0)
webView.preload()
}
self.operationDelegate?.operationDidComplete(self)
}
}
class WebViewProviderDequeueOperation: MainThreadOperation {
// MainThreadOperation
public var isCanceled = false
public var id: Int?
public weak var operationDelegate: MainThreadOperationDelegate?
public var name: String? = "WebViewProviderFlushQueueOperation"
public var completionBlock: MainThreadOperation.MainThreadOperationCompletionBlock?
private var queue: UIView
private var articleIconSchemeHandler: ArticleIconSchemeHandler
private var completion: (PreloadedWebView) -> ()
init(queue: UIView, articleIconSchemeHandler: ArticleIconSchemeHandler, completion: @escaping (PreloadedWebView) -> ()) {
self.queue = queue
self.articleIconSchemeHandler = articleIconSchemeHandler
self.completion = completion
}
func run() {
if let webView = queue.subviews.last as? PreloadedWebView {
webView.ready { preloadedWebView in
preloadedWebView.removeFromSuperview()
self.replenishQueueIfNeeded()
completion(preloadedWebView)
self.completion(preloadedWebView)
self.operationDelegate?.operationDidComplete(self)
}
return
}
@ -50,18 +124,11 @@ class WebViewProvider: NSObject {
assertionFailure("Creating PreloadedWebView in \(#function); queue has run dry.")
let webView = PreloadedWebView(articleIconSchemeHandler: articleIconSchemeHandler)
webView.ready { preloadedWebView in
self.replenishQueueIfNeeded()
completion(preloadedWebView)
}
}
func enqueueWebView(_ webView: PreloadedWebView) {
guard queue.subviews.count < maximumQueueDepth else {
return
}
queue.insertSubview(webView, at: 0)
webView.preload()
webView.ready { preloadedWebView in
self.completion(preloadedWebView)
self.operationDelegate?.operationDidComplete(self)
}
}
}

View File

@ -73,16 +73,13 @@ class MasterFeedTableViewSectionHeader: UITableViewHeaderFooterView {
private let unreadCountView = MasterFeedUnreadCountView(frame: CGRect.zero)
@available(iOS 13.4, *)
private(set) lazy var disclosurePointerInteraction = UIPointerInteraction()
private lazy var disclosureButton: UIButton = {
let button = NonIntrinsicButton()
button.tintColor = UIColor.tertiaryLabel
button.setImage(AppAssets.disclosureImage, for: .normal)
button.contentMode = .center
if #available(iOS 13.4, *) {
button.addInteraction(disclosurePointerInteraction)
button.addInteraction(UIPointerInteraction())
}
button.addTarget(self, action: #selector(toggleDisclosure), for: .touchUpInside)
return button

View File

@ -35,10 +35,14 @@ class ImageViewer {
this.hideLoadingIndicator();
var canvas = document.createElement("canvas");
canvas.width = this.img.naturalWidth * window.devicePixelRatio;
canvas.height = this.img.naturalHeight * window.devicePixelRatio;
var pixelRatio = window.devicePixelRatio;
do {
canvas.width = this.img.naturalWidth * pixelRatio;
canvas.height = this.img.naturalHeight * pixelRatio;
pixelRatio--;
} while (pixelRatio > 0 && canvas.width * canvas.height > 16777216)
canvas.getContext("2d").drawImage(this.img, 0, 0, canvas.width, canvas.height);
const rect = this.img.getBoundingClientRect();
const message = {
x: rect.x,

View File

@ -1,7 +1,7 @@
// High Level Settings common to both the iOS application and any extensions we bundle with it
MARKETING_VERSION = 5.0.1
CURRENT_PROJECT_VERSION = 44
CURRENT_PROJECT_VERSION = 46
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon