From 76056e4fef8f555470a7c27fdf089675af236d6f Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Thu, 19 Sep 2019 17:25:36 -0500 Subject: [PATCH] Add menu and keyboard shortcut to Reader --- Mac/Base.lproj/Main.storyboard | 11 ++- Mac/Base.lproj/MainWindow.storyboard | 1 - Mac/MainWindow/MainWindowController.swift | 83 +++++++++++-------- .../Article Extractor/ArticleExtractor.swift | 14 +++- 4 files changed, 69 insertions(+), 40 deletions(-) diff --git a/Mac/Base.lproj/Main.storyboard b/Mac/Base.lproj/Main.storyboard index 6912abb0f..3ee5e633b 100644 --- a/Mac/Base.lproj/Main.storyboard +++ b/Mac/Base.lproj/Main.storyboard @@ -1,8 +1,8 @@ - + - + @@ -440,6 +440,11 @@ + + + + + @@ -595,8 +600,8 @@ - + diff --git a/Mac/Base.lproj/MainWindow.storyboard b/Mac/Base.lproj/MainWindow.storyboard index 6bb6f36f2..cec644190 100644 --- a/Mac/Base.lproj/MainWindow.storyboard +++ b/Mac/Base.lproj/MainWindow.storyboard @@ -208,7 +208,6 @@ - diff --git a/Mac/MainWindow/MainWindowController.swift b/Mac/MainWindow/MainWindowController.swift index e7454de3a..21cf866ff 100644 --- a/Mac/MainWindow/MainWindowController.swift +++ b/Mac/MainWindow/MainWindowController.swift @@ -17,8 +17,7 @@ enum TimelineSourceMode { class MainWindowController : NSWindowController, NSUserInterfaceValidations { - @IBOutlet weak var articleExtractorButton: ArticleExtractorButton! - + private var isShowingExtractedArticle = false private var articleExtractor: ArticleExtractor? = nil private var sharingServicePickerDelegate: NSSharingServicePickerDelegate? @@ -304,15 +303,28 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations { guard let currentLink = currentLink, let article = oneSelectedArticle else { return } + + defer { + makeToolbarValidate() + } - guard articleExtractorButton.state == .on else { - let detailState = DetailState.article(article) - detailViewController?.setState(detailState, mode: timelineSourceMode) + guard articleExtractor?.state != .processing else { + articleExtractor?.cancel() + articleExtractor = nil + isShowingExtractedArticle = false + detailViewController?.setState(DetailState.article(article), mode: timelineSourceMode) + return + } + + guard !isShowingExtractedArticle else { + isShowingExtractedArticle = false + detailViewController?.setState(DetailState.article(article), mode: timelineSourceMode) return } if let articleExtractor = articleExtractor, let extractedArticle = articleExtractor.article { if currentLink == articleExtractor.articleLink { + isShowingExtractedArticle = true let detailState = DetailState.extracted(article, extractedArticle) detailViewController?.setState(detailState, mode: timelineSourceMode) } @@ -322,7 +334,6 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations { extractor.process() articleExtractor = extractor } - makeToolbarValidate() } } @@ -442,11 +453,13 @@ extension MainWindowController: SidebarDelegate { extension MainWindowController: TimelineContainerViewControllerDelegate { func timelineSelectionDidChange(_: TimelineContainerViewController, articles: [Article]?, mode: TimelineSourceMode) { - articleExtractorButton.isError = false - articleExtractorButton.isInProgress = false - articleExtractorButton.state = .off - articleExtractor = nil + articleExtractor?.cancel() + articleExtractor = nil + isShowingExtractedArticle = false + + makeToolbarValidate() + let detailState: DetailState if let articles = articles { detailState = articles.count == 1 ? .article(articles.first!) : .multipleSelection @@ -531,10 +544,11 @@ extension MainWindowController: ArticleExtractorDelegate { } func articleExtractionDidComplete(extractedArticle: ExtractedArticle) { - makeToolbarValidate() - if articleExtractorButton.state == .on, let article = oneSelectedArticle { + if let article = oneSelectedArticle, articleExtractor?.state != .cancelled { + isShowingExtractedArticle = true let detailState = DetailState.extracted(article, extractedArticle) detailViewController?.setState(detailState, mode: timelineSourceMode) + makeToolbarValidate() } } @@ -692,32 +706,35 @@ private extension MainWindowController { } func validateToggleArticleExtractor(_ item: NSValidatedUserInterfaceItem) -> Bool { - guard let articleExtractorState = articleExtractor?.state else { - articleExtractorButton.isError = false - articleExtractorButton.isInProgress = false - articleExtractorButton.state = .off + guard let toolbarItem = item as? NSToolbarItem, let toolbarButton = toolbarItem.view as? ArticleExtractorButton else { + if let menuItem = item as? NSMenuItem { + menuItem.state = isShowingExtractedArticle ? .on : .off + } return currentLink != nil } - switch articleExtractorState { - case .ready: - articleExtractorButton.isError = false - articleExtractorButton.isInProgress = false - return currentLink != nil - case .processing: - articleExtractorButton.isError = false - articleExtractorButton.isInProgress = true - return true - case .failedToParse: - articleExtractorButton.isError = true - articleExtractorButton.isInProgress = false - articleExtractorButton.state = .off - return true - case .complete: - articleExtractorButton.isError = false - articleExtractorButton.isInProgress = false + toolbarButton.state = isShowingExtractedArticle ? .on : .off + + guard let state = articleExtractor?.state else { + toolbarButton.isError = false + toolbarButton.isInProgress = false + toolbarButton.state = .off return currentLink != nil } + + switch state { + case .processing: + toolbarButton.isError = false + toolbarButton.isInProgress = true + case .failedToParse: + toolbarButton.isError = true + toolbarButton.isInProgress = false + case .ready, .cancelled, .complete: + toolbarButton.isError = false + toolbarButton.isInProgress = false + } + + return true } func canMarkOlderArticlesAsRead() -> Bool { diff --git a/Shared/Article Extractor/ArticleExtractor.swift b/Shared/Article Extractor/ArticleExtractor.swift index 02ed1429c..ea1d64c67 100644 --- a/Shared/Article Extractor/ArticleExtractor.swift +++ b/Shared/Article Extractor/ArticleExtractor.swift @@ -13,6 +13,7 @@ public enum ArticleExtractorState { case processing case failedToParse case complete + case cancelled } protocol ArticleExtractorDelegate { @@ -27,6 +28,8 @@ enum ArticleExtractorError: Error { } class ArticleExtractor { + + private var dataTask: URLSessionDataTask? = nil var state: ArticleExtractorState! var article: ExtractedArticle? @@ -57,7 +60,7 @@ class ArticleExtractor { state = .processing - let dataTask = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in + dataTask = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in guard let self = self else { return } @@ -95,8 +98,13 @@ class ArticleExtractor { } - dataTask.resume() - + dataTask!.resume() + } + + public func cancel() { + state = .cancelled + dataTask?.cancel() + } }