Show byline in timeline for single feed timelines when available.
This commit is contained in:
parent
67434c2d0b
commit
1778a270d6
|
@ -15,14 +15,15 @@ struct TimelineCellData {
|
|||
let text: String
|
||||
let dateString: String
|
||||
let feedName: String
|
||||
let showFeedName: Bool
|
||||
let byline: String
|
||||
let showFeedName: TimelineShowFeedName
|
||||
let iconImage: IconImage? // feed icon, user avatar, or favicon
|
||||
let showIcon: Bool // Make space even when icon is nil
|
||||
let featuredImage: NSImage? // image from within the article
|
||||
let read: Bool
|
||||
let starred: Bool
|
||||
|
||||
init(article: Article, showFeedName: Bool, feedName: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: NSImage?) {
|
||||
init(article: Article, showFeedName: TimelineShowFeedName, feedName: String?, byline: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: NSImage?) {
|
||||
|
||||
self.title = ArticleStringFormatter.truncatedTitle(article)
|
||||
self.text = ArticleStringFormatter.truncatedSummary(article)
|
||||
|
@ -31,10 +32,15 @@ struct TimelineCellData {
|
|||
|
||||
if let feedName = feedName {
|
||||
self.feedName = ArticleStringFormatter.truncatedFeedName(feedName)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
self.feedName = ""
|
||||
}
|
||||
|
||||
if let byline = byline {
|
||||
self.byline = byline
|
||||
} else {
|
||||
self.byline = ""
|
||||
}
|
||||
|
||||
self.showFeedName = showFeedName
|
||||
|
||||
|
@ -51,7 +57,8 @@ struct TimelineCellData {
|
|||
self.text = ""
|
||||
self.dateString = ""
|
||||
self.feedName = ""
|
||||
self.showFeedName = false
|
||||
self.byline = ""
|
||||
self.showFeedName = .none
|
||||
self.showIcon = false
|
||||
self.iconImage = nil
|
||||
self.featuredImage = nil
|
||||
|
|
|
@ -171,7 +171,7 @@ private extension TimelineCellLayout {
|
|||
}
|
||||
|
||||
static func rectForFeedName(_ textBoxRect: NSRect, _ dateRect: NSRect, _ appearance: TimelineCellAppearance, _ cellData: TimelineCellData) -> NSRect {
|
||||
if !cellData.showFeedName {
|
||||
if cellData.showFeedName == .none {
|
||||
return NSZeroRect
|
||||
}
|
||||
|
||||
|
|
|
@ -248,11 +248,14 @@ private extension TimelineTableCellView {
|
|||
}
|
||||
|
||||
func updateFeedNameView() {
|
||||
if cellData.showFeedName {
|
||||
switch cellData.showFeedName {
|
||||
case .byline:
|
||||
showView(feedNameView)
|
||||
updateTextFieldText(feedNameView, cellData.byline)
|
||||
case .feed:
|
||||
showView(feedNameView)
|
||||
updateTextFieldText(feedNameView, cellData.feedName)
|
||||
}
|
||||
else {
|
||||
case .none:
|
||||
hideView(feedNameView)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,12 @@ protocol TimelineDelegate: class {
|
|||
func timelineInvalidatedRestorationState(_: TimelineViewController)
|
||||
}
|
||||
|
||||
enum TimelineShowFeedName {
|
||||
case none
|
||||
case byline
|
||||
case feed
|
||||
}
|
||||
|
||||
final class TimelineViewController: NSViewController, UndoableCommandRunner, UnreadCountProvider {
|
||||
|
||||
@IBOutlet var tableView: TimelineTableView!
|
||||
|
@ -41,23 +47,11 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
|
|||
didSet {
|
||||
if !representedObjectArraysAreEqual(oldValue, representedObjects) {
|
||||
unreadCount = 0
|
||||
if let representedObjects = representedObjects {
|
||||
if representedObjects.count == 1 && representedObjects.first is WebFeed {
|
||||
showFeedNames = false
|
||||
}
|
||||
else {
|
||||
showFeedNames = true
|
||||
}
|
||||
}
|
||||
else {
|
||||
showFeedNames = false
|
||||
}
|
||||
|
||||
selectionDidChange(nil)
|
||||
if showsSearchResults {
|
||||
fetchAndReplaceArticlesAsync()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
fetchAndReplaceArticlesSync()
|
||||
if articles.count > 0 {
|
||||
tableView.scrollRowToVisible(0)
|
||||
|
@ -85,9 +79,11 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
|
|||
defer {
|
||||
updateUnreadCount()
|
||||
}
|
||||
|
||||
if articles == oldValue {
|
||||
return
|
||||
}
|
||||
|
||||
if articles.representSameArticlesInSameOrder(as: oldValue) {
|
||||
// When the array is the same — same articles, same order —
|
||||
// but some data in some of the articles may have changed.
|
||||
|
@ -96,7 +92,20 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
|
|||
reloadVisibleCells()
|
||||
return
|
||||
}
|
||||
updateShowIcons()
|
||||
|
||||
if let representedObjects = representedObjects, representedObjects.count == 1 && representedObjects.first is WebFeed {
|
||||
showFeedNames = {
|
||||
for article in articles {
|
||||
if article.authors?.contains(where: { $0.name != nil }) ?? false {
|
||||
return .byline
|
||||
}
|
||||
}
|
||||
return .none
|
||||
}()
|
||||
} else {
|
||||
showFeedNames = .feed
|
||||
}
|
||||
|
||||
articleRowMap = [String: Int]()
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
@ -117,7 +126,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
|
|||
private var articleRowMap = [String: Int]() // articleID: rowIndex
|
||||
private var cellAppearance: TimelineCellAppearance!
|
||||
private var cellAppearanceWithIcon: TimelineCellAppearance!
|
||||
private var showFeedNames = false {
|
||||
private var showFeedNames: TimelineShowFeedName = .none {
|
||||
didSet {
|
||||
if showFeedNames != oldValue {
|
||||
updateShowIcons()
|
||||
|
@ -663,7 +672,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
|
|||
let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, dateArrived: Date())
|
||||
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, webFeedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, datePublished: nil, dateModified: nil, authors: nil, status: status)
|
||||
|
||||
let prototypeCellData = TimelineCellData(article: prototypeArticle, showFeedName: true, feedName: "Prototype Feed Name", iconImage: nil, showIcon: false, featuredImage: nil)
|
||||
let prototypeCellData = TimelineCellData(article: prototypeArticle, showFeedName: .feed, feedName: "Prototype Feed Name", byline: nil, iconImage: nil, showIcon: false, featuredImage: nil)
|
||||
let height = TimelineCellLayout.height(for: 100, cellData: prototypeCellData, appearance: cellAppearance)
|
||||
return height
|
||||
}
|
||||
|
@ -810,7 +819,7 @@ extension TimelineViewController: NSTableViewDelegate {
|
|||
private func configureTimelineCell(_ cell: TimelineTableCellView, article: Article) {
|
||||
cell.objectValue = article
|
||||
let iconImage = article.iconImage()
|
||||
cell.cellData = TimelineCellData(article: article, showFeedName: showFeedNames, feedName: article.webFeed?.nameForDisplay, iconImage: iconImage, showIcon: showIcons, featuredImage: nil)
|
||||
cell.cellData = TimelineCellData(article: article, showFeedName: showFeedNames, feedName: article.webFeed?.nameForDisplay, byline: article.byline(), iconImage: iconImage, showIcon: showIcons, featuredImage: nil)
|
||||
}
|
||||
|
||||
private func iconFor(_ article: Article) -> IconImage? {
|
||||
|
@ -946,20 +955,20 @@ private extension TimelineViewController {
|
|||
}
|
||||
|
||||
func updateShowIcons() {
|
||||
if showFeedNames {
|
||||
if showFeedNames != .none {
|
||||
self.showIcons = true
|
||||
return
|
||||
}
|
||||
|
||||
for article in articles {
|
||||
if let authors = article.authors {
|
||||
for author in authors {
|
||||
if author.avatarURL != nil {
|
||||
self.showIcons = true
|
||||
return
|
||||
for author in authors {
|
||||
if author.avatarURL != nil {
|
||||
self.showIcons = true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.showIcons = false
|
||||
|
|
|
@ -55,7 +55,7 @@ struct MasterTimelineAccessibilityCellLayout: MasterTimelineCellLayout {
|
|||
|
||||
currentPoint.y = [self.titleRect, self.summaryRect].maxY()
|
||||
|
||||
if cellData.showFeedName {
|
||||
if cellData.showFeedName != .none {
|
||||
self.feedNameRect = MasterTimelineAccessibilityCellLayout.rectForFeedName(cellData, currentPoint, textAreaWidth)
|
||||
currentPoint.y = self.feedNameRect.maxY
|
||||
} else {
|
||||
|
|
|
@ -15,7 +15,8 @@ struct MasterTimelineCellData {
|
|||
let summary: String
|
||||
let dateString: String
|
||||
let feedName: String
|
||||
let showFeedName: Bool
|
||||
let byline: String
|
||||
let showFeedName: ShowFeedName
|
||||
let iconImage: IconImage? // feed icon, user avatar, or favicon
|
||||
let showIcon: Bool // Make space even when icon is nil
|
||||
let featuredImage: UIImage? // image from within the article
|
||||
|
@ -24,7 +25,7 @@ struct MasterTimelineCellData {
|
|||
let numberOfLines: Int
|
||||
let iconSize: IconSize
|
||||
|
||||
init(article: Article, showFeedName: Bool, feedName: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: UIImage?, numberOfLines: Int, iconSize: IconSize) {
|
||||
init(article: Article, showFeedName: ShowFeedName, feedName: String?, byline: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: UIImage?, numberOfLines: Int, iconSize: IconSize) {
|
||||
|
||||
self.title = ArticleStringFormatter.truncatedTitle(article)
|
||||
self.summary = ArticleStringFormatter.truncatedSummary(article)
|
||||
|
@ -37,6 +38,12 @@ struct MasterTimelineCellData {
|
|||
else {
|
||||
self.feedName = ""
|
||||
}
|
||||
|
||||
if let byline = byline {
|
||||
self.byline = byline
|
||||
} else {
|
||||
self.byline = ""
|
||||
}
|
||||
|
||||
self.showFeedName = showFeedName
|
||||
|
||||
|
@ -56,7 +63,8 @@ struct MasterTimelineCellData {
|
|||
self.summary = ""
|
||||
self.dateString = ""
|
||||
self.feedName = ""
|
||||
self.showFeedName = false
|
||||
self.byline = ""
|
||||
self.showFeedName = .none
|
||||
self.showIcon = false
|
||||
self.iconImage = nil
|
||||
self.featuredImage = nil
|
||||
|
|
|
@ -172,12 +172,18 @@ private extension MasterTimelineTableViewCell {
|
|||
}
|
||||
|
||||
func updateFeedNameView() {
|
||||
if cellData.showFeedName {
|
||||
switch cellData.showFeedName {
|
||||
case .feed:
|
||||
showView(feedNameView)
|
||||
feedNameView.font = MasterTimelineDefaultCellLayout.feedNameFont
|
||||
feedNameView.textColor = secondaryLabelColor
|
||||
updateTextFieldText(feedNameView, cellData.feedName)
|
||||
} else {
|
||||
case .byline:
|
||||
showView(feedNameView)
|
||||
feedNameView.font = MasterTimelineDefaultCellLayout.feedNameFont
|
||||
feedNameView.textColor = secondaryLabelColor
|
||||
updateTextFieldText(feedNameView, cellData.byline)
|
||||
case .none:
|
||||
hideView(feedNameView)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -489,7 +489,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
|||
let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, dateArrived: Date())
|
||||
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, webFeedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, datePublished: nil, dateModified: nil, authors: nil, status: status)
|
||||
|
||||
let prototypeCellData = MasterTimelineCellData(article: prototypeArticle, showFeedName: true, feedName: "Prototype Feed Name", iconImage: nil, showIcon: false, featuredImage: nil, numberOfLines: numberOfTextLines, iconSize: iconSize)
|
||||
let prototypeCellData = MasterTimelineCellData(article: prototypeArticle, showFeedName: .feed, feedName: "Prototype Feed Name", byline: nil, iconImage: nil, showIcon: false, featuredImage: nil, numberOfLines: numberOfTextLines, iconSize: iconSize)
|
||||
|
||||
if UIApplication.shared.preferredContentSizeCategory.isAccessibilityCategory {
|
||||
let layout = MasterTimelineAccessibilityCellLayout(width: tableView.bounds.width, insets: tableView.safeAreaInsets, cellData: prototypeCellData)
|
||||
|
@ -649,7 +649,7 @@ private extension MasterTimelineViewController {
|
|||
|
||||
let showFeedNames = coordinator.showFeedNames
|
||||
let showIcon = coordinator.showIcons && iconImage != nil
|
||||
cell.cellData = MasterTimelineCellData(article: article, showFeedName: showFeedNames, feedName: article.webFeed?.nameForDisplay, iconImage: iconImage, showIcon: showIcon, featuredImage: featuredImage, numberOfLines: numberOfTextLines, iconSize: iconSize)
|
||||
cell.cellData = MasterTimelineCellData(article: article, showFeedName: showFeedNames, feedName: article.webFeed?.nameForDisplay, byline: article.byline(), iconImage: iconImage, showIcon: showIcon, featuredImage: featuredImage, numberOfLines: numberOfTextLines, iconSize: iconSize)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,12 @@ enum SearchScope: Int {
|
|||
case global = 1
|
||||
}
|
||||
|
||||
enum ShowFeedName {
|
||||
case none
|
||||
case byline
|
||||
case feed
|
||||
}
|
||||
|
||||
class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
||||
|
||||
var undoableCommands = [UndoableCommand]()
|
||||
|
@ -159,7 +165,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
|||
|
||||
var timelineMiddleIndexPath: IndexPath?
|
||||
|
||||
private(set) var showFeedNames = false
|
||||
private(set) var showFeedNames = ShowFeedName.none
|
||||
private(set) var showIcons = false
|
||||
|
||||
var prevFeedIndexPath: IndexPath? {
|
||||
|
@ -1454,12 +1460,19 @@ private extension SceneCoordinator {
|
|||
func updateShowNamesAndIcons() {
|
||||
|
||||
if timelineFeed is WebFeed {
|
||||
showFeedNames = false
|
||||
showFeedNames = {
|
||||
for article in articles {
|
||||
if article.authors?.contains(where: { $0.name != nil }) ?? false {
|
||||
return .byline
|
||||
}
|
||||
}
|
||||
return .none
|
||||
}()
|
||||
} else {
|
||||
showFeedNames = true
|
||||
showFeedNames = .feed
|
||||
}
|
||||
|
||||
if showFeedNames {
|
||||
if showFeedNames == .feed {
|
||||
self.showIcons = true
|
||||
return
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ private extension TimelinePreviewTableViewController {
|
|||
|
||||
let iconImage = IconImage(AppAssets.faviconTemplateImage.withTintColor(AppAssets.secondaryAccentColor))
|
||||
|
||||
return MasterTimelineCellData(article: prototypeArticle, showFeedName: true, feedName: "Feed Name", iconImage: iconImage, showIcon: true, featuredImage: nil, numberOfLines: AppDefaults.timelineNumberOfLines, iconSize: AppDefaults.timelineIconSize)
|
||||
return MasterTimelineCellData(article: prototypeArticle, showFeedName: .feed, feedName: "Feed Name", byline: nil, iconImage: iconImage, showIcon: true, featuredImage: nil, numberOfLines: AppDefaults.timelineNumberOfLines, iconSize: AppDefaults.timelineIconSize)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue