diff --git a/Evergreen/Base.lproj/MainWindow.storyboard b/Evergreen/Base.lproj/MainWindow.storyboard index 315e19190..ee93da7a0 100644 --- a/Evergreen/Base.lproj/MainWindow.storyboard +++ b/Evergreen/Base.lproj/MainWindow.storyboard @@ -2,7 +2,9 @@ + + @@ -699,11 +701,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/Evergreen/MainWindow/Detail/DetailViewController.swift b/Evergreen/MainWindow/Detail/DetailViewController.swift index 94b331637..5e0e70e9e 100644 --- a/Evergreen/MainWindow/Detail/DetailViewController.swift +++ b/Evergreen/MainWindow/Detail/DetailViewController.swift @@ -12,14 +12,30 @@ import RSCore import Data import RSWeb -final class DetailViewController: NSViewController, WKNavigationDelegate, WKUIDelegate { +final class DetailViewController: NSViewController, WKUIDelegate { @IBOutlet var containerView: DetailContainerView! + @IBOutlet var noSelectionView: NoSelectionView! var webview: DetailWebView! - var noSelectionView: NoSelectionView! - var article: Article? { + var articles: [Article]? { + didSet { + if let articles = articles, articles.count == 1 { + article = articles.first! + return + } + article = nil + if let _ = articles { + noSelectionView.showMultipleSelection() + } + else { + noSelectionView.showNoSelection() + } + } + } + + private var article: Article? { didSet { reloadHTML() showOrHideWebView() @@ -62,8 +78,6 @@ final class DetailViewController: NSViewController, WKNavigationDelegate, WKUIDe webview.customUserAgent = userAgent } - noSelectionView = NoSelectionView(frame: self.view.bounds) - containerView.viewController = self showOrHideWebView() @@ -91,7 +105,7 @@ final class DetailViewController: NSViewController, WKNavigationDelegate, WKUIDe webview.scrollPageDown(sender) } - // MARK: Notifications + // MARK: - Notifications @objc func timelineSelectionDidChange(_ notification: Notification) { @@ -102,8 +116,8 @@ final class DetailViewController: NSViewController, WKNavigationDelegate, WKUIDe return } - let timelineArticle = userInfo[UserInfoKey.article] as? Article - article = timelineArticle + let timelineArticles = userInfo[UserInfoKey.articles] as? ArticleArray + articles = timelineArticles } func viewWillStartLiveResize() { @@ -115,56 +129,30 @@ final class DetailViewController: NSViewController, WKNavigationDelegate, WKUIDe webview.evaluateJavaScript("document.body.style.overflow = 'visible';", completionHandler: nil) } - - // MARK: Private +} - private func reloadHTML() { +// MARK: - WKNavigationDelegate - if let article = article { - let articleRenderer = ArticleRenderer(article: article, style: ArticleStylesManager.shared.currentStyle) - webview.loadHTMLString(articleRenderer.html, baseURL: articleRenderer.baseURL) - } - else { - webview.loadHTMLString("", baseURL: nil) - } - } +extension DetailViewController: WKNavigationDelegate { - private func showOrHideWebView() { - - if let _ = article { - switchToView(webview) - } - else { - switchToView(noSelectionView) - } - } - - private func switchToView(_ view: NSView) { - - if containerView.contentView == view { - return - } - containerView.contentView = view - } - - // MARK: WKNavigationDelegate - public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { - + if navigationAction.navigationType == .linkActivated { - + if let url = navigationAction.request.url { Browser.open(url.absoluteString) } - + decisionHandler(.cancel) return } - + decisionHandler(.allow) } } +// MARK: - WKScriptMessageHandler + extension DetailViewController: WKScriptMessageHandler { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { @@ -200,8 +188,39 @@ extension DetailViewController: WKScriptMessageHandler { } } +// MARK: - Private + private extension DetailViewController { + func reloadHTML() { + + if let article = article { + let articleRenderer = ArticleRenderer(article: article, style: ArticleStylesManager.shared.currentStyle) + webview.loadHTMLString(articleRenderer.html, baseURL: articleRenderer.baseURL) + } + else { + webview.loadHTMLString("", baseURL: nil) + } + } + + func showOrHideWebView() { + + if let _ = article { + switchToView(webview) + } + else { + switchToView(noSelectionView) + } + } + + func switchToView(_ view: NSView) { + + if containerView.contentView == view { + return + } + containerView.contentView = view + } + func fetchScrollInfo(_ callback: @escaping (ScrollInfo?) -> Void) { let javascriptString = "var x = {contentHeight: document.body.scrollHeight, offsetY: document.body.scrollTop}; x" @@ -222,6 +241,8 @@ private extension DetailViewController { } } +// MARK: - + final class DetailContainerView: NSView { @IBOutlet var detailStatusBarView: DetailStatusBarView! @@ -270,28 +291,28 @@ final class DetailContainerView: NSView { } } +// MARK: - + final class NoSelectionView: NSView { - private var didConfigureLayer = false + @IBOutlet var noSelectionLabel: NSTextField! + @IBOutlet var multipleSelectionLabel: NSTextField! - override var wantsUpdateLayer: Bool { - return true + func showMultipleSelection() { + + noSelectionLabel.isHidden = true + multipleSelectionLabel.isHidden = false } - override func updateLayer() { + func showNoSelection() { - guard !didConfigureLayer else { - return - } - if let layer = layer { -// let color = appDelegate.currentTheme.color(forKey: "MainWindow.Detail.noSelectionView.backgroundColor") - let color = NSColor(calibratedWhite: 0.96, alpha: 1.0) - layer.backgroundColor = color.cgColor - didConfigureLayer = true - } + noSelectionLabel.isHidden = false + multipleSelectionLabel.isHidden = true } } +// MARK: - + private struct ScrollInfo { let contentHeight: CGFloat diff --git a/Evergreen/MainWindow/Timeline/ArticleArray.swift b/Evergreen/MainWindow/Timeline/ArticleArray.swift index b1a8d7512..67192fb94 100644 --- a/Evergreen/MainWindow/Timeline/ArticleArray.swift +++ b/Evergreen/MainWindow/Timeline/ArticleArray.swift @@ -110,6 +110,12 @@ extension Array where Element == Article { return anyArticlePassesTest { !$0.status.starred } } + + func unreadArticles() -> [Article]? { + + let articles = self.filter{ !$0.status.read } + return articles.isEmpty ? nil : articles + } } private extension Array where Element == Article { diff --git a/Evergreen/MainWindow/Timeline/TimelineViewController.swift b/Evergreen/MainWindow/Timeline/TimelineViewController.swift index 531f4f7ed..2d1ea4635 100644 --- a/Evergreen/MainWindow/Timeline/TimelineViewController.swift +++ b/Evergreen/MainWindow/Timeline/TimelineViewController.swift @@ -516,30 +516,28 @@ extension TimelineViewController: NSTableViewDelegate { func tableViewSelectionDidChange(_ notification: Notification) { - tableView.redrawGrid() + // tableView.redrawGrid() - let selectedRow = tableView.selectedRow - if selectedRow < 0 || selectedRow == NSNotFound || tableView.numberOfSelectedRows != 1 { + if selectedArticles.isEmpty { postTimelineSelectionDidChangeNotification(nil) return } - if let selectedArticle = articles.articleAtRow(selectedRow) { - if (!selectedArticle.status.read) { - markArticles(Set([selectedArticle]), statusKey: .read, flag: true) + if selectedArticles.count == 1 { + let article = selectedArticles.first! + if !article.status.read { + markArticles(Set([article]), statusKey: .read, flag: true) } - postTimelineSelectionDidChangeNotification(selectedArticle) - } - else { - postTimelineSelectionDidChangeNotification(nil) } + + postTimelineSelectionDidChangeNotification(selectedArticles) } - private func postTimelineSelectionDidChangeNotification(_ selectedArticle: Article?) { + private func postTimelineSelectionDidChangeNotification(_ selectedArticles: ArticleArray?) { var userInfo = UserInfoDictionary() - if let article = selectedArticle { - userInfo[UserInfoKey.article] = article + if let selectedArticles = selectedArticles { + userInfo[UserInfoKey.articles] = selectedArticles } userInfo[UserInfoKey.view] = tableView