From 2efcd7ea0c5d691a891cff13f8b96fcb5d3959a6 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Sat, 16 Dec 2017 10:18:02 -0800 Subject: [PATCH] Get rid of the window status bar. Put the current URL at the bottom of the detail view. --- Evergreen.xcodeproj/project.pbxproj | 4 + Evergreen/Base.lproj/MainWindow.storyboard | 130 +++++++--------- .../Detail/DetailStatusBarView.swift | 146 ++++++++++++++++++ .../Detail/DetailViewController.swift | 50 ++++-- .../MainWindow/MainWindowSplitView.swift | 2 +- Evergreen/Resources/DB5.plist | 7 + 6 files changed, 251 insertions(+), 88 deletions(-) create mode 100644 Evergreen/MainWindow/Detail/DetailStatusBarView.swift diff --git a/Evergreen.xcodeproj/project.pbxproj b/Evergreen.xcodeproj/project.pbxproj index fb42cbdbc..a196a79f9 100644 --- a/Evergreen.xcodeproj/project.pbxproj +++ b/Evergreen.xcodeproj/project.pbxproj @@ -99,6 +99,7 @@ 84B99C9D1FAE83C600ECDEDB /* DeleteFromSidebarCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B99C9C1FAE83C600ECDEDB /* DeleteFromSidebarCommand.swift */; }; 84BB4B771F11753300858766 /* Data.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84BB4B681F1174D400858766 /* Data.framework */; }; 84BB4B781F11753300858766 /* Data.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84BB4B681F1174D400858766 /* Data.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 84D52E951FE588BB00D14F5B /* DetailStatusBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D52E941FE588BB00D14F5B /* DetailStatusBarView.swift */; }; 84DAEE301F86CAFE0058304B /* OPMLImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DAEE2F1F86CAFE0058304B /* OPMLImporter.swift */; }; 84DAEE321F870B390058304B /* DockBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DAEE311F870B390058304B /* DockBadge.swift */; }; 84E46C7D1F75EF7B005ECFB3 /* AppDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E46C7C1F75EF7B005ECFB3 /* AppDefaults.swift */; }; @@ -494,6 +495,7 @@ 84B99C9C1FAE83C600ECDEDB /* DeleteFromSidebarCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteFromSidebarCommand.swift; sourceTree = ""; }; 84BB4B611F1174D400858766 /* Data.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Data.xcodeproj; path = Frameworks/Data/Data.xcodeproj; sourceTree = ""; }; 84CBDDAE1FD3674C005A61AA /* Technotes */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Technotes; sourceTree = ""; }; + 84D52E941FE588BB00D14F5B /* DetailStatusBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailStatusBarView.swift; sourceTree = ""; }; 84DAEE2F1F86CAFE0058304B /* OPMLImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OPMLImporter.swift; sourceTree = ""; }; 84DAEE311F870B390058304B /* DockBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DockBadge.swift; path = Evergreen/DockBadge.swift; sourceTree = ""; }; 84E46C7C1F75EF7B005ECFB3 /* AppDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDefaults.swift; path = Evergreen/AppDefaults.swift; sourceTree = ""; }; @@ -715,6 +717,7 @@ children = ( 849A977E1ED9EC42007D329B /* DetailViewController.swift */, 849A977D1ED9EC42007D329B /* ArticleRenderer.swift */, + 84D52E941FE588BB00D14F5B /* DetailStatusBarView.swift */, ); path = Detail; sourceTree = ""; @@ -1402,6 +1405,7 @@ 84B99C9D1FAE83C600ECDEDB /* DeleteFromSidebarCommand.swift in Sources */, 849A97541ED9EAC0007D329B /* AddFeedWindowController.swift in Sources */, 849A976D1ED9EBC8007D329B /* TimelineTableView.swift in Sources */, + 84D52E951FE588BB00D14F5B /* DetailStatusBarView.swift in Sources */, 84B99C671FAE35E600ECDEDB /* FeedListTreeControllerDelegate.swift in Sources */, 84B99C691FAE36B800ECDEDB /* FeedListFolder.swift in Sources */, 84F204DE1FAACB8B0076E152 /* FeedListTimelineViewController.swift in Sources */, diff --git a/Evergreen/Base.lproj/MainWindow.storyboard b/Evergreen/Base.lproj/MainWindow.storyboard index 539a1b098..32de73cd8 100644 --- a/Evergreen/Base.lproj/MainWindow.storyboard +++ b/Evergreen/Base.lproj/MainWindow.storyboard @@ -1,8 +1,7 @@ - + - - + @@ -238,7 +237,6 @@ - @@ -282,12 +280,12 @@ - + - + @@ -297,73 +295,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -637,14 +574,54 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -652,7 +629,6 @@ - diff --git a/Evergreen/MainWindow/Detail/DetailStatusBarView.swift b/Evergreen/MainWindow/Detail/DetailStatusBarView.swift new file mode 100644 index 000000000..a616cb933 --- /dev/null +++ b/Evergreen/MainWindow/Detail/DetailStatusBarView.swift @@ -0,0 +1,146 @@ +// +// DetailStatusBarView.swift +// Evergreen +// +// Created by Brent Simmons on 12/16/17. +// Copyright © 2017 Ranchero Software. All rights reserved. +// + +import Cocoa +import DB5 +import Data + +final class DetailStatusBarView: NSView { + + @IBOutlet var urlLabel: NSTextField! + +// private var didConfigureLayer = false + + private var article: Article? { + didSet { + updateURLLabel() + } + } + private var mouseoverLink: String? { + didSet { + updateURLLabel() + } + } + + private let backgroundColor = appDelegate.currentTheme.color(forKey: "MainWindow.Detail.statusBar.backgroundColor") + + override var isFlipped: Bool { + return true + } + +// override var wantsUpdateLayer: Bool { +// return true +// } +// +// override func updateLayer() { +// +// guard !didConfigureLayer else { +// return +// } +// if let layer = layer { +// let color = appDelegate.currentTheme.color(forKey: "MainWindow.Detail.statusBar.backgroundColor") +// layer.backgroundColor = color.cgColor +// didConfigureLayer = true +// } +// } + + override func awakeFromNib() { + + NotificationCenter.default.addObserver(self, selector: #selector(timelineSelectionDidChange(_:)), name: .TimelineSelectionDidChange, object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(mouseDidEnterLink(_:)), name: .MouseDidEnterLink, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(mouseDidExitLink(_:)), name: .MouseDidExitLink, object: nil) + } + + // MARK: - Notifications + + @objc func mouseDidEnterLink(_ notification: Notification) { + + guard let appInfo = AppInfo.pullFromUserInfo(notification.userInfo) else { + return + } + guard let window = window, let notificationWindow = appInfo.view?.window, window === notificationWindow else { + return + } + guard let link = appInfo.url else { + return + } + mouseoverLink = link + } + + @objc func mouseDidExitLink(_ notification: Notification) { + + guard let appInfo = AppInfo.pullFromUserInfo(notification.userInfo) else { + return + } + guard let window = window, let notificationWindow = appInfo.view?.window, window === notificationWindow else { + return + } + mouseoverLink = nil + } + + @objc func timelineSelectionDidChange(_ note: Notification) { + + let timelineView = note.appInfo?.view + if timelineView?.window === self.window { + mouseoverLink = nil + article = note.appInfo?.article + } + } + + // MARK: Drawing + + private let lineColor = NSColor(calibratedWhite: 0.65, alpha: 1.0) + + override func draw(_ dirtyRect: NSRect) { + + backgroundColor.set() + dirtyRect.fill() + +// let path = NSBezierPath() +// path.lineWidth = 1.0 +// path.move(to: NSPoint(x: NSMinX(bounds), y: NSMinY(bounds) + 0.5)) +// path.line(to: NSPoint(x: NSMaxX(bounds), y: NSMinY(bounds) + 0.5)) +// lineColor.set() +// path.stroke() + } +} + +private extension DetailStatusBarView { + + // MARK: URL Label + + func updateURLLabel() { + + needsLayout = true + + guard let article = article else { + setURLLabel("") + return + } + + if let mouseoverLink = mouseoverLink, !mouseoverLink.isEmpty { + setURLLabel(mouseoverLink) + return + } + + if let s = article.preferredLink { + setURLLabel(s) + } + else { + setURLLabel("") + } + } + + func setURLLabel(_ link: String) { + + urlLabel.stringValue = (link as NSString).rs_stringByStrippingHTTPOrHTTPSScheme() + } +} + + diff --git a/Evergreen/MainWindow/Detail/DetailViewController.swift b/Evergreen/MainWindow/Detail/DetailViewController.swift index 1d17a76f9..240843fe6 100644 --- a/Evergreen/MainWindow/Detail/DetailViewController.swift +++ b/Evergreen/MainWindow/Detail/DetailViewController.swift @@ -14,6 +14,8 @@ import RSWeb final class DetailViewController: NSViewController, WKNavigationDelegate, WKUIDelegate { + @IBOutlet var containerView: DetailContainerView! + var webview: WKWebView! var noSelectionView: NoSelectionView! @@ -58,8 +60,7 @@ final class DetailViewController: NSViewController, WKNavigationDelegate, WKUIDe noSelectionView = NoSelectionView(frame: self.view.bounds) - let boxView = self.view as! DetailBox - boxView.viewController = self + containerView.viewController = self showOrHideWebView() } @@ -109,12 +110,10 @@ final class DetailViewController: NSViewController, WKNavigationDelegate, WKUIDe private func switchToView(_ view: NSView) { - let boxView = self.view as! DetailBox - if boxView.contentView == view { + if containerView.contentView == view { return } - boxView.contentView = view - boxView.rs_addFullSizeConstraints(forSubview: view) + containerView.contentView = view } // MARK: WKNavigationDelegate @@ -170,10 +169,29 @@ extension DetailViewController: WKScriptMessageHandler { } } -final class DetailBox: NSBox { - - weak var viewController: DetailViewController? - +final class DetailContainerView: NSView { + + weak var viewController: DetailViewController? = nil + + private var didConfigureLayer = false + + override var wantsUpdateLayer: Bool { + return true + } + + var contentView: NSView? { + didSet { + if let oldContentView = oldValue { + oldContentView.removeFromSuperviewWithoutNeedingDisplay() + } + if let contentView = contentView { + contentView.translatesAutoresizingMaskIntoConstraints = false + addSubview(contentView) + rs_addFullSizeConstraints(forSubview: contentView) + } + } + } + override func viewWillStartLiveResize() { viewController?.viewWillStartLiveResize() @@ -183,6 +201,18 @@ final class DetailBox: NSBox { viewController?.viewDidEndLiveResize() } + + override func updateLayer() { + + guard !didConfigureLayer else { + return + } + if let layer = layer { + let color = appDelegate.currentTheme.color(forKey: "MainWindow.Detail.backgroundColor") + layer.backgroundColor = color.cgColor + didConfigureLayer = true + } + } } final class NoSelectionView: NSView { diff --git a/Evergreen/MainWindow/MainWindowSplitView.swift b/Evergreen/MainWindow/MainWindowSplitView.swift index cf0236c72..e0b381fa3 100644 --- a/Evergreen/MainWindow/MainWindowSplitView.swift +++ b/Evergreen/MainWindow/MainWindowSplitView.swift @@ -10,7 +10,7 @@ import Cocoa class MainWindowSplitView: NSSplitView { - private let splitViewDividerColor = NSColor(calibratedWhite: 0.75, alpha: 1.0) + private let splitViewDividerColor = NSColor(calibratedWhite: 0.65, alpha: 1.0) override var dividerColor: NSColor { get { diff --git a/Evergreen/Resources/DB5.plist b/Evergreen/Resources/DB5.plist index fd88a1b7e..f01927fe9 100644 --- a/Evergreen/Resources/DB5.plist +++ b/Evergreen/Resources/DB5.plist @@ -115,6 +115,13 @@ backgroundColor FFFFFF + statusBar + + backgroundColor + FFFFFF + + backgroundColor + FFFFFF