Skip to content

Commit

Permalink
Merge pull request #1 from Ranchero-Software/ios-release
Browse files Browse the repository at this point in the history
Ios release
  • Loading branch information
stuartbreckenridge committed May 12, 2020
2 parents d09541a + e648623 commit 1f7d40a
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 46 deletions.
21 changes: 11 additions & 10 deletions iOS/Article/ArticleViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -202,19 +202,15 @@ 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) {
// The toolbar will come back on you if you don't hide it again
if AppDefaults.articleFullscreenEnabled {
currentWebViewController?.hideBars()
}
resetWebViewController()
}

// MARK: Actions
Expand Down Expand Up @@ -274,10 +270,6 @@ class ArticleViewController: UIViewController {
currentWebViewController?.scrollPageDown()
}

func fullReload() {
currentWebViewController?.fullReload()
}

func stopArticleExtractorIfProcessing() {
currentWebViewController?.stopArticleExtractorIfProcessing()
}
Expand Down Expand Up @@ -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)
}
}

}
22 changes: 14 additions & 8 deletions iOS/Article/WebViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ class WebViewController: UIViewController {
}

func fullReload() {
self.loadWebView()
loadWebView(replaceExistingWebView: true)
}

func showBars() {
Expand Down Expand Up @@ -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
Expand All @@ -313,13 +319,13 @@ extension WebViewController: WKNavigationDelegate {
} else {
decisionHandler(.allow)
}

} else {

decisionHandler(.allow)

}

}

func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
fullReload()
}

}
Expand Down Expand Up @@ -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
}
Expand Down
107 changes: 87 additions & 20 deletions iOS/Article/WebViewProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,128 @@
//

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() {
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 {
enqueueWebView(PreloadedWebView(articleIconSchemeHandler: articleIconSchemeHandler))
let webView = PreloadedWebView(articleIconSchemeHandler: articleIconSchemeHandler)
queue.insertSubview(webView, at: 0)
webView.preload()
}
self.operationDelegate?.operationDidComplete(self)
}

func dequeueWebView(completion: @escaping (PreloadedWebView) -> ()) {
}

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
}

assertionFailure("Creating PreloadedWebView in \(#function); queue has run dry.")

let webView = PreloadedWebView(articleIconSchemeHandler: articleIconSchemeHandler)
webView.preload()
webView.ready { preloadedWebView in
self.replenishQueueIfNeeded()
completion(preloadedWebView)
self.completion(preloadedWebView)
self.operationDelegate?.operationDidComplete(self)
}
}

func enqueueWebView(_ webView: PreloadedWebView) {
guard queue.subviews.count < maximumQueueDepth else {
return
}
queue.insertSubview(webView, at: 0)
webView.preload()
}

}
5 changes: 1 addition & 4 deletions iOS/MasterFeed/Cell/MasterFeedTableViewSectionHeader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions iOS/Resources/main_ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion xcconfig/common/NetNewsWire_ios_target_common.xcconfig
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit 1f7d40a

Please sign in to comment.