mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2025-02-09 00:28:53 +01:00
Merge pull request #945 from correia/correia-separators
Add optional separators in the timeline view.
This commit is contained in:
commit
563b4a8320
@ -32,6 +32,7 @@ struct AppDefaults {
|
|||||||
static let exportOPMLAccountID = "exportOPMLAccountID"
|
static let exportOPMLAccountID = "exportOPMLAccountID"
|
||||||
|
|
||||||
// Hidden prefs
|
// Hidden prefs
|
||||||
|
static let timelineShowsSeparators = "CorreiaSeparators"
|
||||||
static let showTitleOnMainWindow = "KafasisTitleMode"
|
static let showTitleOnMainWindow = "KafasisTitleMode"
|
||||||
static let hideDockUnreadCount = "JustinMillerHideDockUnreadCount"
|
static let hideDockUnreadCount = "JustinMillerHideDockUnreadCount"
|
||||||
}
|
}
|
||||||
@ -136,6 +137,10 @@ struct AppDefaults {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static var timelineShowsSeparators: Bool {
|
||||||
|
return bool(for: Key.timelineShowsSeparators)
|
||||||
|
}
|
||||||
|
|
||||||
static var mainWindowWidths: [Int]? {
|
static var mainWindowWidths: [Int]? {
|
||||||
get {
|
get {
|
||||||
return UserDefaults.standard.object(forKey: Key.mainWindowWidths) as? [Int]
|
return UserDefaults.standard.object(forKey: Key.mainWindowWidths) as? [Int]
|
||||||
@ -268,4 +273,17 @@ private extension AppDefaults {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
|
extension UserDefaults {
|
||||||
|
/// This property exists so that it can conveniently be observed via KVO
|
||||||
|
@objc var CorreiaSeparators: Bool {
|
||||||
|
get {
|
||||||
|
return bool(forKey: AppDefaults.Key.timelineShowsSeparators)
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
set(newValue, forKey: AppDefaults.Key.timelineShowsSeparators)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -22,9 +22,10 @@ struct TimelineCellLayout {
|
|||||||
let unreadIndicatorRect: NSRect
|
let unreadIndicatorRect: NSRect
|
||||||
let starRect: NSRect
|
let starRect: NSRect
|
||||||
let avatarImageRect: NSRect
|
let avatarImageRect: NSRect
|
||||||
|
let separatorRect: NSRect
|
||||||
let paddingBottom: CGFloat
|
let paddingBottom: CGFloat
|
||||||
|
|
||||||
init(width: CGFloat, height: CGFloat, feedNameRect: NSRect, dateRect: NSRect, titleRect: NSRect, numberOfLinesForTitle: Int, summaryRect: NSRect, textRect: NSRect, unreadIndicatorRect: NSRect, starRect: NSRect, avatarImageRect: NSRect, paddingBottom: CGFloat) {
|
init(width: CGFloat, height: CGFloat, feedNameRect: NSRect, dateRect: NSRect, titleRect: NSRect, numberOfLinesForTitle: Int, summaryRect: NSRect, textRect: NSRect, unreadIndicatorRect: NSRect, starRect: NSRect, avatarImageRect: NSRect, separatorRect: NSRect, paddingBottom: CGFloat) {
|
||||||
|
|
||||||
self.width = width
|
self.width = width
|
||||||
self.feedNameRect = feedNameRect
|
self.feedNameRect = feedNameRect
|
||||||
@ -36,6 +37,7 @@ struct TimelineCellLayout {
|
|||||||
self.unreadIndicatorRect = unreadIndicatorRect
|
self.unreadIndicatorRect = unreadIndicatorRect
|
||||||
self.starRect = starRect
|
self.starRect = starRect
|
||||||
self.avatarImageRect = avatarImageRect
|
self.avatarImageRect = avatarImageRect
|
||||||
|
self.separatorRect = separatorRect
|
||||||
self.paddingBottom = paddingBottom
|
self.paddingBottom = paddingBottom
|
||||||
|
|
||||||
if height > 0.1 {
|
if height > 0.1 {
|
||||||
@ -73,10 +75,11 @@ struct TimelineCellLayout {
|
|||||||
let avatarImageRect = TimelineCellLayout.rectForAvatar(cellData, appearance, showAvatar, textBoxRect, width, height)
|
let avatarImageRect = TimelineCellLayout.rectForAvatar(cellData, appearance, showAvatar, textBoxRect, width, height)
|
||||||
let unreadIndicatorRect = TimelineCellLayout.rectForUnreadIndicator(appearance, textBoxRect)
|
let unreadIndicatorRect = TimelineCellLayout.rectForUnreadIndicator(appearance, textBoxRect)
|
||||||
let starRect = TimelineCellLayout.rectForStar(appearance, unreadIndicatorRect)
|
let starRect = TimelineCellLayout.rectForStar(appearance, unreadIndicatorRect)
|
||||||
|
let separatorRect = TimelineCellLayout.rectForSeparator(cellData, appearance, showAvatar ? avatarImageRect : titleRect, width, height)
|
||||||
|
|
||||||
let paddingBottom = appearance.cellPadding.bottom
|
let paddingBottom = appearance.cellPadding.bottom
|
||||||
|
|
||||||
self.init(width: width, height: height, feedNameRect: feedNameRect, dateRect: dateRect, titleRect: titleRect, numberOfLinesForTitle: numberOfLinesForTitle, summaryRect: summaryRect, textRect: textRect, unreadIndicatorRect: unreadIndicatorRect, starRect: starRect, avatarImageRect: avatarImageRect, paddingBottom: paddingBottom)
|
self.init(width: width, height: height, feedNameRect: feedNameRect, dateRect: dateRect, titleRect: titleRect, numberOfLinesForTitle: numberOfLinesForTitle, summaryRect: summaryRect, textRect: textRect, unreadIndicatorRect: unreadIndicatorRect, starRect: starRect, avatarImageRect: avatarImageRect, separatorRect: separatorRect, paddingBottom: paddingBottom)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func height(for width: CGFloat, cellData: TimelineCellData, appearance: TimelineCellAppearance) -> CGFloat {
|
static func height(for width: CGFloat, cellData: TimelineCellData, appearance: TimelineCellAppearance) -> CGFloat {
|
||||||
@ -210,6 +213,10 @@ private extension TimelineCellLayout {
|
|||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func rectForSeparator(_ cellData: TimelineCellData, _ appearance: TimelineCellAppearance, _ alignmentRect: NSRect, _ width: CGFloat, _ height: CGFloat) -> NSRect {
|
||||||
|
return NSRect(x: alignmentRect.minX, y: height - 1, width: width - alignmentRect.minX, height: 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension Array where Element == NSRect {
|
private extension Array where Element == NSRect {
|
||||||
|
@ -27,11 +27,18 @@ class TimelineTableCellView: NSTableCellView {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
private let starView = TimelineTableCellView.imageView(with: AppAssets.timelineStar, scaling: .scaleNone)
|
private let starView = TimelineTableCellView.imageView(with: AppAssets.timelineStar, scaling: .scaleNone)
|
||||||
|
private let separatorView = TimelineTableCellView.separatorView()
|
||||||
|
|
||||||
private lazy var textFields = {
|
private lazy var textFields = {
|
||||||
return [self.dateView, self.feedNameView, self.titleView, self.summaryView, self.textView]
|
return [self.dateView, self.feedNameView, self.titleView, self.summaryView, self.textView]
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private var showsSeparator: Bool = AppDefaults.timelineShowsSeparators {
|
||||||
|
didSet {
|
||||||
|
separatorView.isHidden = !showsSeparator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var cellAppearance: TimelineCellAppearance! {
|
var cellAppearance: TimelineCellAppearance! {
|
||||||
didSet {
|
didSet {
|
||||||
if cellAppearance != oldValue {
|
if cellAppearance != oldValue {
|
||||||
@ -78,6 +85,15 @@ class TimelineTableCellView: NSTableCellView {
|
|||||||
self.init(frame: NSRect.zero)
|
self.init(frame: NSRect.zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func prepareForReuse() {
|
||||||
|
super.prepareForReuse()
|
||||||
|
separatorView.isHidden = !showsSeparator
|
||||||
|
}
|
||||||
|
|
||||||
|
func timelineShowsSeparatorsDefaultDidChange() {
|
||||||
|
showsSeparator = AppDefaults.timelineShowsSeparators
|
||||||
|
}
|
||||||
|
|
||||||
override func setFrameSize(_ newSize: NSSize) {
|
override func setFrameSize(_ newSize: NSSize) {
|
||||||
|
|
||||||
if newSize == self.frame.size {
|
if newSize == self.frame.size {
|
||||||
@ -111,6 +127,7 @@ class TimelineTableCellView: NSTableCellView {
|
|||||||
feedNameView.rs_setFrameIfNotEqual(layoutRects.feedNameRect)
|
feedNameView.rs_setFrameIfNotEqual(layoutRects.feedNameRect)
|
||||||
avatarImageView.rs_setFrameIfNotEqual(layoutRects.avatarImageRect)
|
avatarImageView.rs_setFrameIfNotEqual(layoutRects.avatarImageRect)
|
||||||
starView.rs_setFrameIfNotEqual(layoutRects.starRect)
|
starView.rs_setFrameIfNotEqual(layoutRects.starRect)
|
||||||
|
separatorView.rs_setFrameIfNotEqual(layoutRects.separatorRect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,6 +166,11 @@ private extension TimelineTableCellView {
|
|||||||
return imageView
|
return imageView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func separatorView() -> NSView {
|
||||||
|
|
||||||
|
return TimelineSeparatorView(frame: .zero)
|
||||||
|
}
|
||||||
|
|
||||||
func setFrame(for textField: NSTextField, rect: NSRect) {
|
func setFrame(for textField: NSTextField, rect: NSRect) {
|
||||||
|
|
||||||
if Int(floor(rect.height)) == 0 || Int(floor(rect.width)) == 0 {
|
if Int(floor(rect.height)) == 0 || Int(floor(rect.width)) == 0 {
|
||||||
@ -193,6 +215,7 @@ private extension TimelineTableCellView {
|
|||||||
addSubviewAtInit(feedNameView, hidden: true)
|
addSubviewAtInit(feedNameView, hidden: true)
|
||||||
addSubviewAtInit(avatarImageView, hidden: true)
|
addSubviewAtInit(avatarImageView, hidden: true)
|
||||||
addSubviewAtInit(starView, hidden: true)
|
addSubviewAtInit(starView, hidden: true)
|
||||||
|
addSubviewAtInit(separatorView, hidden: !AppDefaults.timelineShowsSeparators)
|
||||||
|
|
||||||
makeTextFieldColorsNormal()
|
makeTextFieldColorsNormal()
|
||||||
}
|
}
|
||||||
@ -296,3 +319,32 @@ private extension TimelineTableCellView {
|
|||||||
updateAvatar()
|
updateAvatar()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
|
private class TimelineSeparatorView: NSView {
|
||||||
|
private static let backgroundColor = NSColor(named: "timelineSeparatorColor")!
|
||||||
|
|
||||||
|
override init(frame: NSRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
self.wantsLayer = true
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidChangeEffectiveAppearance() {
|
||||||
|
super.viewDidChangeEffectiveAppearance()
|
||||||
|
needsDisplay = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override var wantsUpdateLayer: Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override func updateLayer() {
|
||||||
|
super.updateLayer()
|
||||||
|
layer?.backgroundColor = TimelineSeparatorView.backgroundColor.cgColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -141,10 +141,12 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private let keyboardDelegate = TimelineKeyboardDelegate()
|
private let keyboardDelegate = TimelineKeyboardDelegate()
|
||||||
|
private var timelineShowsSeparatorsObserver: NSKeyValueObservation?
|
||||||
|
|
||||||
convenience init(delegate: TimelineDelegate) {
|
convenience init(delegate: TimelineDelegate) {
|
||||||
self.init(nibName: "TimelineTableView", bundle: nil)
|
self.init(nibName: "TimelineTableView", bundle: nil)
|
||||||
self.delegate = delegate
|
self.delegate = delegate
|
||||||
|
self.startObservingUserDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
@ -846,6 +848,19 @@ extension TimelineViewController: NSTableViewDelegate {
|
|||||||
|
|
||||||
private extension TimelineViewController {
|
private extension TimelineViewController {
|
||||||
|
|
||||||
|
func startObservingUserDefaults() {
|
||||||
|
|
||||||
|
assert(timelineShowsSeparatorsObserver == nil)
|
||||||
|
timelineShowsSeparatorsObserver = UserDefaults.standard.observe(\UserDefaults.CorreiaSeparators) { [weak self] (_, _) in
|
||||||
|
guard let self = self, self.isViewLoaded else { return }
|
||||||
|
self.tableView.enumerateAvailableRowViews { (rowView, index) in
|
||||||
|
if let cellView = rowView.view(atColumn: 0) as? TimelineTableCellView {
|
||||||
|
cellView.timelineShowsSeparatorsDefaultDidChange()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc func reloadAvailableCells() {
|
@objc func reloadAvailableCells() {
|
||||||
|
|
||||||
if let indexesToReload = tableView.indexesOfAvailableRows() {
|
if let indexesToReload = tableView.indexesOfAvailableRows() {
|
||||||
@ -1114,4 +1129,3 @@ private extension TimelineViewController {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
},
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "gray-gamma-22",
|
||||||
|
"components" : {
|
||||||
|
"white" : "0.900",
|
||||||
|
"alpha" : "1.000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"platform" : "osx",
|
||||||
|
"reference" : "gridColor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user