diff --git a/iOS/Article/ArticleViewController.swift b/iOS/Article/ArticleViewController.swift index 536605068..38c51c74f 100644 --- a/iOS/Article/ArticleViewController.swift +++ b/iOS/Article/ArticleViewController.swift @@ -53,6 +53,7 @@ class ArticleViewController: UIViewController { updateUI() } } + var restoreWindowScrollY = 0 private let keyboardManager = KeyboardManager(type: .detail) override var keyCommands: [UIKeyCommand]? { @@ -92,6 +93,7 @@ class ArticleViewController: UIViewController { ]) let controller = createWebViewController(article) + controller.restoreWindowScrollY = restoreWindowScrollY articleExtractorButton.buttonState = controller.articleExtractorButtonState pageViewController.setViewControllers([controller], direction: .forward, animated: false, completion: nil) @@ -246,6 +248,13 @@ class ArticleViewController: UIViewController { // MARK: WebViewControllerDelegate extension ArticleViewController: WebViewControllerDelegate { + + func webViewController(_ webViewController: WebViewController, restoreWindowScrollYDidUpdate restoreWindowScrollY: Int) { + if webViewController === currentWebViewController { + self.restoreWindowScrollY = restoreWindowScrollY + } + } + func webViewController(_ webViewController: WebViewController, articleExtractorButtonStateDidUpdate buttonState: ArticleExtractorButtonState) { if webViewController === currentWebViewController { articleExtractorButton.buttonState = buttonState diff --git a/iOS/Article/WebViewController.swift b/iOS/Article/WebViewController.swift index b3fee9095..7a1a56bc8 100644 --- a/iOS/Article/WebViewController.swift +++ b/iOS/Article/WebViewController.swift @@ -8,11 +8,13 @@ import UIKit import WebKit +import RSCore import Account import Articles import SafariServices protocol WebViewControllerDelegate: class { + func webViewController(_: WebViewController, restoreWindowScrollYDidUpdate: Int) func webViewController(_: WebViewController, articleExtractorButtonStateDidUpdate: ArticleExtractorButtonState) } @@ -68,7 +70,12 @@ class WebViewController: UIViewController { } } - var restoreOffset = 0 + let scrollPositionQueue = CoalescingQueue(name: "Article Scroll Position", interval: 0.3, maxInterval: 1.0) + var restoreWindowScrollY = 0 { + didSet { + delegate?.webViewController(self, restoreWindowScrollYDidUpdate: restoreWindowScrollY) + } + } deinit { if webView != nil { @@ -109,6 +116,7 @@ class WebViewController: UIViewController { // Configure the webview webView.navigationDelegate = self webView.uiDelegate = self + webView.scrollView.delegate = self self.configureContextMenuInteraction() webView.configuration.userContentController.add(WrapperScriptMessageHandler(self), name: MessageName.imageWasClicked) @@ -186,10 +194,7 @@ class WebViewController: UIViewController { } func fullReload() { - webView?.evaluateJavaScript("window.scrollY") { (scrollY, _) in - self.restoreOffset = scrollY as! Int - self.reloadHTML() - } + self.reloadHTML() } func showBars() { @@ -408,6 +413,22 @@ extension WebViewController: UIViewControllerTransitioningDelegate { } } +// MARK: + +extension WebViewController: UIScrollViewDelegate { + + func scrollViewDidScroll(_ scrollView: UIScrollView) { + scrollPositionQueue.add(self, #selector(scrollPositionDidChange)) + } + + @objc func scrollPositionDidChange() { + webView?.evaluateJavaScript("window.scrollY") { (scrollY, _) in + self.restoreWindowScrollY = scrollY as! Int + } + } + +} + // MARK: JSON private struct TemplateData: Codable { @@ -472,10 +493,10 @@ private extension WebViewController { var render = "error();" if let data = try? encoder.encode(templateData) { let json = String(data: data, encoding: .utf8)! - render = "render(\(json), \(restoreOffset));" + render = "render(\(json), \(restoreWindowScrollY));" } - restoreOffset = 0 + restoreWindowScrollY = 0 WebViewProvider.shared.articleIconSchemeHandler.currentArticle = article webView.scrollView.setZoomScale(1.0, animated: false) diff --git a/iOS/MasterTimeline/MasterTimelineViewController.swift b/iOS/MasterTimeline/MasterTimelineViewController.swift index c45568971..2c96b458c 100644 --- a/iOS/MasterTimeline/MasterTimelineViewController.swift +++ b/iOS/MasterTimeline/MasterTimelineViewController.swift @@ -28,7 +28,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner weak var coordinator: SceneCoordinator! var undoableCommands = [UndoableCommand]() - let scrollPositionQueue = CoalescingQueue(name: "Scroll Position", interval: 0.3, maxInterval: 1.0) + let scrollPositionQueue = CoalescingQueue(name: "Timeline Scroll Position", interval: 0.3, maxInterval: 1.0) private let keyboardManager = KeyboardManager(type: .timeline) override var keyCommands: [UIKeyCommand]? { diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index 00f936ebe..99338b401 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -1677,19 +1677,14 @@ private extension SceneCoordinator { } @discardableResult - func installArticleController(_ recycledArticleController: ArticleViewController? = nil, animated: Bool) -> ArticleViewController { + func installArticleController(restoreWindowScrollY: Int = 0, animated: Bool) -> ArticleViewController { isArticleViewControllerPending = true - let articleController: ArticleViewController = { - if let controller = recycledArticleController { - return controller - } else { - let controller = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self) - controller.coordinator = self - return controller - } - }() + let articleController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self) + articleController.coordinator = self + articleController.article = currentArticle + articleController.restoreWindowScrollY = restoreWindowScrollY if let subSplit = subSplitViewController { let controller = addNavControllerIfNecessary(articleController, showButton: false) @@ -1701,12 +1696,6 @@ private extension SceneCoordinator { rootSplitViewController.showDetailViewController(controller, sender: self) } - // We have to do a full reload when installing an article controller. We may have changed color contexts - // and need to update the article colors. An example is in dark mode. Split screen doesn't use true black - // like darkmode usually does. - - // TODO: This should probably only happen to recycled article controllers - articleController.fullReload() return articleController } @@ -1758,7 +1747,7 @@ private extension SceneCoordinator { } func configureThreePanelMode() { - let recycledArticleController = articleViewController + let articleRestoreWindowScrollY = articleViewController?.restoreWindowScrollY ?? 0 defer { masterNavigationController.viewControllers = [masterFeedViewController] } @@ -1773,14 +1762,14 @@ private extension SceneCoordinator { masterTimelineViewController?.navigationItem.leftBarButtonItem = rootSplitViewController.displayModeButtonItem masterTimelineViewController?.navigationItem.leftItemsSupplementBackButton = true - installArticleController(recycledArticleController, animated: false) + installArticleController(restoreWindowScrollY: articleRestoreWindowScrollY, animated: false) masterFeedViewController.restoreSelectionIfNecessary(adjustScroll: true) masterTimelineViewController!.restoreSelectionIfNecessary(adjustScroll: false) } func configureStandardPanelMode() { - let recycledArticleController = articleViewController + let articleRestoreWindowScrollY = articleViewController?.restoreWindowScrollY ?? 0 rootSplitViewController.preferredPrimaryColumnWidthFraction = UISplitViewController.automaticDimension // Set the is Pending flags early to prevent the navigation controller delegate from thinking that we @@ -1800,7 +1789,7 @@ private extension SceneCoordinator { masterNavigationController.pushViewController(masterTimelineViewController!, animated: false) } - installArticleController(recycledArticleController, animated: false) + installArticleController(restoreWindowScrollY: articleRestoreWindowScrollY, animated: false) } // MARK: NSUserActivity