Store more article view controller state when destroying and recreating them. Issue #1729
This commit is contained in:
parent
e9989d6f24
commit
f96bb9c3e0
@ -14,6 +14,11 @@ import SafariServices
|
|||||||
|
|
||||||
class ArticleViewController: UIViewController {
|
class ArticleViewController: UIViewController {
|
||||||
|
|
||||||
|
typealias State = (extractedArticle: ExtractedArticle?,
|
||||||
|
isShowingExtractedArticle: Bool,
|
||||||
|
articleExtractorButtonState: ArticleExtractorButtonState,
|
||||||
|
windowScrollY: Int)
|
||||||
|
|
||||||
@IBOutlet private weak var nextUnreadBarButtonItem: UIBarButtonItem!
|
@IBOutlet private weak var nextUnreadBarButtonItem: UIBarButtonItem!
|
||||||
@IBOutlet private weak var prevArticleBarButtonItem: UIBarButtonItem!
|
@IBOutlet private weak var prevArticleBarButtonItem: UIBarButtonItem!
|
||||||
@IBOutlet private weak var nextArticleBarButtonItem: UIBarButtonItem!
|
@IBOutlet private weak var nextArticleBarButtonItem: UIBarButtonItem!
|
||||||
@ -49,7 +54,16 @@ class ArticleViewController: UIViewController {
|
|||||||
updateUI()
|
updateUI()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var restoreWindowScrollY = 0
|
|
||||||
|
var currentState: State? {
|
||||||
|
guard let controller = currentWebViewController else { return nil}
|
||||||
|
return State(extractedArticle: controller.extractedArticle,
|
||||||
|
isShowingExtractedArticle: controller.isShowingExtractedArticle,
|
||||||
|
articleExtractorButtonState: controller.articleExtractorButtonState,
|
||||||
|
windowScrollY: controller.windowScrollY)
|
||||||
|
}
|
||||||
|
|
||||||
|
var restoreState: State?
|
||||||
|
|
||||||
private let keyboardManager = KeyboardManager(type: .detail)
|
private let keyboardManager = KeyboardManager(type: .detail)
|
||||||
override var keyCommands: [UIKeyCommand]? {
|
override var keyCommands: [UIKeyCommand]? {
|
||||||
@ -89,7 +103,12 @@ class ArticleViewController: UIViewController {
|
|||||||
])
|
])
|
||||||
|
|
||||||
let controller = createWebViewController(article)
|
let controller = createWebViewController(article)
|
||||||
controller.restoreWindowScrollY = restoreWindowScrollY
|
if let state = restoreState {
|
||||||
|
controller.extractedArticle = state.extractedArticle
|
||||||
|
controller.isShowingExtractedArticle = state.isShowingExtractedArticle
|
||||||
|
controller.articleExtractorButtonState = state.articleExtractorButtonState
|
||||||
|
controller.windowScrollY = state.windowScrollY
|
||||||
|
}
|
||||||
articleExtractorButton.buttonState = controller.articleExtractorButtonState
|
articleExtractorButton.buttonState = controller.articleExtractorButtonState
|
||||||
pageViewController.setViewControllers([controller], direction: .forward, animated: false, completion: nil)
|
pageViewController.setViewControllers([controller], direction: .forward, animated: false, completion: nil)
|
||||||
|
|
||||||
@ -239,18 +258,16 @@ class ArticleViewController: UIViewController {
|
|||||||
currentWebViewController?.fullReload()
|
currentWebViewController?.fullReload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stopArticleExtractorIfProcessing() {
|
||||||
|
currentWebViewController?.stopArticleExtractorIfProcessing()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: WebViewControllerDelegate
|
// MARK: WebViewControllerDelegate
|
||||||
|
|
||||||
extension ArticleViewController: WebViewControllerDelegate {
|
extension ArticleViewController: WebViewControllerDelegate {
|
||||||
|
|
||||||
func webViewController(_ webViewController: WebViewController, restoreWindowScrollYDidUpdate restoreWindowScrollY: Int) {
|
|
||||||
if webViewController === currentWebViewController {
|
|
||||||
self.restoreWindowScrollY = restoreWindowScrollY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func webViewController(_ webViewController: WebViewController, articleExtractorButtonStateDidUpdate buttonState: ArticleExtractorButtonState) {
|
func webViewController(_ webViewController: WebViewController, articleExtractorButtonStateDidUpdate buttonState: ArticleExtractorButtonState) {
|
||||||
if webViewController === currentWebViewController {
|
if webViewController === currentWebViewController {
|
||||||
articleExtractorButton.buttonState = buttonState
|
articleExtractorButton.buttonState = buttonState
|
||||||
|
@ -14,7 +14,6 @@ import Articles
|
|||||||
import SafariServices
|
import SafariServices
|
||||||
|
|
||||||
protocol WebViewControllerDelegate: class {
|
protocol WebViewControllerDelegate: class {
|
||||||
func webViewController(_: WebViewController, restoreWindowScrollYDidUpdate: Int)
|
|
||||||
func webViewController(_: WebViewController, articleExtractorButtonStateDidUpdate: ArticleExtractorButtonState)
|
func webViewController(_: WebViewController, articleExtractorButtonStateDidUpdate: ArticleExtractorButtonState)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,8 +38,12 @@ class WebViewController: UIViewController {
|
|||||||
private var clickedImageCompletion: (() -> Void)?
|
private var clickedImageCompletion: (() -> Void)?
|
||||||
|
|
||||||
private var articleExtractor: ArticleExtractor? = nil
|
private var articleExtractor: ArticleExtractor? = nil
|
||||||
private var extractedArticle: ExtractedArticle?
|
var extractedArticle: ExtractedArticle? {
|
||||||
private var isShowingExtractedArticle = false {
|
didSet {
|
||||||
|
windowScrollY = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var isShowingExtractedArticle = false {
|
||||||
didSet {
|
didSet {
|
||||||
if isShowingExtractedArticle != oldValue {
|
if isShowingExtractedArticle != oldValue {
|
||||||
reloadHTML()
|
reloadHTML()
|
||||||
@ -64,18 +67,14 @@ class WebViewController: UIViewController {
|
|||||||
startArticleExtractor()
|
startArticleExtractor()
|
||||||
}
|
}
|
||||||
if article != oldValue {
|
if article != oldValue {
|
||||||
restoreWindowScrollY = 0
|
windowScrollY = 0
|
||||||
reloadHTML()
|
reloadHTML()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let scrollPositionQueue = CoalescingQueue(name: "Article Scroll Position", interval: 0.3, maxInterval: 1.0)
|
let scrollPositionQueue = CoalescingQueue(name: "Article Scroll Position", interval: 0.3, maxInterval: 1.0)
|
||||||
var restoreWindowScrollY = 0 {
|
var windowScrollY = 0
|
||||||
didSet {
|
|
||||||
delegate?.webViewController(self, restoreWindowScrollYDidUpdate: restoreWindowScrollY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
if webView != nil {
|
if webView != nil {
|
||||||
@ -247,6 +246,12 @@ class WebViewController: UIViewController {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stopArticleExtractorIfProcessing() {
|
||||||
|
if articleExtractor?.state == .processing {
|
||||||
|
stopArticleExtractor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func showActivityDialog(popOverBarButtonItem: UIBarButtonItem? = nil) {
|
func showActivityDialog(popOverBarButtonItem: UIBarButtonItem? = nil) {
|
||||||
guard let preferredLink = article?.preferredLink, let url = URL(string: preferredLink) else {
|
guard let preferredLink = article?.preferredLink, let url = URL(string: preferredLink) else {
|
||||||
return
|
return
|
||||||
@ -423,7 +428,7 @@ extension WebViewController: UIScrollViewDelegate {
|
|||||||
|
|
||||||
@objc func scrollPositionDidChange() {
|
@objc func scrollPositionDidChange() {
|
||||||
webView?.evaluateJavaScript("window.scrollY") { (scrollY, _) in
|
webView?.evaluateJavaScript("window.scrollY") { (scrollY, _) in
|
||||||
self.restoreWindowScrollY = scrollY as? Int ?? 0
|
self.windowScrollY = scrollY as? Int ?? 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,10 +486,10 @@ private extension WebViewController {
|
|||||||
var render = "error();"
|
var render = "error();"
|
||||||
if let data = try? encoder.encode(templateData) {
|
if let data = try? encoder.encode(templateData) {
|
||||||
let json = String(data: data, encoding: .utf8)!
|
let json = String(data: data, encoding: .utf8)!
|
||||||
render = "render(\(json), \(restoreWindowScrollY));"
|
render = "render(\(json), \(windowScrollY));"
|
||||||
}
|
}
|
||||||
|
|
||||||
restoreWindowScrollY = 0
|
windowScrollY = 0
|
||||||
|
|
||||||
webView.scrollView.setZoomScale(1.0, animated: false)
|
webView.scrollView.setZoomScale(1.0, animated: false)
|
||||||
webView.evaluateJavaScript(render)
|
webView.evaluateJavaScript(render)
|
||||||
|
@ -1778,14 +1778,14 @@ private extension SceneCoordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
func installArticleController(restoreWindowScrollY: Int = 0, animated: Bool) -> ArticleViewController {
|
func installArticleController(state: ArticleViewController.State? = nil, animated: Bool) -> ArticleViewController {
|
||||||
|
|
||||||
isArticleViewControllerPending = true
|
isArticleViewControllerPending = true
|
||||||
|
|
||||||
let articleController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self)
|
let articleController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self)
|
||||||
articleController.coordinator = self
|
articleController.coordinator = self
|
||||||
articleController.article = currentArticle
|
articleController.article = currentArticle
|
||||||
articleController.restoreWindowScrollY = restoreWindowScrollY
|
articleController.restoreState = state
|
||||||
|
|
||||||
if let subSplit = subSplitViewController {
|
if let subSplit = subSplitViewController {
|
||||||
let controller = addNavControllerIfNecessary(articleController, showButton: false)
|
let controller = addNavControllerIfNecessary(articleController, showButton: false)
|
||||||
@ -1848,12 +1848,12 @@ private extension SceneCoordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func configureThreePanelMode() {
|
func configureThreePanelMode() {
|
||||||
let articleRestoreWindowScrollY = articleViewController?.restoreWindowScrollY ?? 0
|
articleViewController?.stopArticleExtractorIfProcessing()
|
||||||
|
let articleViewControllerState = articleViewController?.currentState
|
||||||
defer {
|
defer {
|
||||||
masterNavigationController.viewControllers = [masterFeedViewController]
|
masterNavigationController.viewControllers = [masterFeedViewController]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if rootSplitViewController.viewControllers.last is InteractiveNavigationController {
|
if rootSplitViewController.viewControllers.last is InteractiveNavigationController {
|
||||||
_ = rootSplitViewController.viewControllers.popLast()
|
_ = rootSplitViewController.viewControllers.popLast()
|
||||||
}
|
}
|
||||||
@ -1863,14 +1863,15 @@ private extension SceneCoordinator {
|
|||||||
masterTimelineViewController?.navigationItem.leftBarButtonItem = rootSplitViewController.displayModeButtonItem
|
masterTimelineViewController?.navigationItem.leftBarButtonItem = rootSplitViewController.displayModeButtonItem
|
||||||
masterTimelineViewController?.navigationItem.leftItemsSupplementBackButton = true
|
masterTimelineViewController?.navigationItem.leftItemsSupplementBackButton = true
|
||||||
|
|
||||||
installArticleController(restoreWindowScrollY: articleRestoreWindowScrollY, animated: false)
|
installArticleController(state: articleViewControllerState, animated: false)
|
||||||
|
|
||||||
masterFeedViewController.restoreSelectionIfNecessary(adjustScroll: true)
|
masterFeedViewController.restoreSelectionIfNecessary(adjustScroll: true)
|
||||||
masterTimelineViewController!.restoreSelectionIfNecessary(adjustScroll: false)
|
masterTimelineViewController!.restoreSelectionIfNecessary(adjustScroll: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureStandardPanelMode() {
|
func configureStandardPanelMode() {
|
||||||
let articleRestoreWindowScrollY = articleViewController?.restoreWindowScrollY ?? 0
|
articleViewController?.stopArticleExtractorIfProcessing()
|
||||||
|
let articleViewControllerState = articleViewController?.currentState
|
||||||
rootSplitViewController.preferredPrimaryColumnWidthFraction = UISplitViewController.automaticDimension
|
rootSplitViewController.preferredPrimaryColumnWidthFraction = UISplitViewController.automaticDimension
|
||||||
|
|
||||||
// Set the is Pending flags early to prevent the navigation controller delegate from thinking that we
|
// Set the is Pending flags early to prevent the navigation controller delegate from thinking that we
|
||||||
@ -1890,7 +1891,7 @@ private extension SceneCoordinator {
|
|||||||
masterNavigationController.pushViewController(masterTimelineViewController!, animated: false)
|
masterNavigationController.pushViewController(masterTimelineViewController!, animated: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
installArticleController(restoreWindowScrollY: articleRestoreWindowScrollY, animated: false)
|
installArticleController(state: articleViewControllerState, animated: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: NSUserActivity
|
// MARK: NSUserActivity
|
||||||
|
Loading…
x
Reference in New Issue
Block a user