Implement new timeline layout.

This commit is contained in:
Maurice Parker 2019-04-29 14:40:14 -05:00
parent 2efbd44811
commit e37d4ddd2f
5 changed files with 167 additions and 246 deletions

View File

@ -12,13 +12,13 @@ extension String {
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
let boundingBox = self.boundingRect(with: constraintRect, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [NSAttributedString.Key.font: font], context: nil)
return ceil(boundingBox.height)
}
func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
let boundingBox = self.boundingRect(with: constraintRect, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [NSAttributedString.Key.font: font], context: nil)
return ceil(boundingBox.width)
}

View File

@ -12,7 +12,7 @@ import Articles
struct MasterTimelineCellData {
let title: String
let text: String
let summary: String
let dateString: String
let feedName: String
let showFeedName: Bool
@ -25,7 +25,7 @@ struct MasterTimelineCellData {
init(article: Article, showFeedName: Bool, feedName: String?, avatar: UIImage?, showAvatar: Bool, featuredImage: UIImage?) {
self.title = TimelineStringFormatter.truncatedTitle(article)
self.text = TimelineStringFormatter.truncatedSummary(article)
self.summary = TimelineStringFormatter.truncatedSummary(article)
self.dateString = TimelineStringFormatter.dateString(article.logicalDatePublished)
@ -48,7 +48,7 @@ struct MasterTimelineCellData {
init() { //Empty
self.title = ""
self.text = ""
self.summary = ""
self.dateString = ""
self.feedName = ""
self.showFeedName = false

View File

@ -11,114 +11,100 @@ import RSCore
struct MasterTimelineCellLayout {
static let maxNumberOfLines = 2
static let cellPadding = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
static let feedColor = AppAssets.timelineTextSecondaryColor
static let feedNameFont = UIFont.systemFont(ofSize: UIFont.systemFontSize)
static let dateColor = AppAssets.timelineTextSecondaryColor
static let dateFont = UIFont.systemFont(ofSize: UIFont.systemFontSize, weight: UIFont.Weight.bold)
static let dateMarginBottom = CGFloat(integerLiteral: 1)
static let titleColor = AppAssets.timelineTextPrimaryColor
static let titleFont = UIFont.systemFont(ofSize: UIFont.systemFontSize, weight: .semibold)
static let titleBottomMargin = CGFloat(integerLiteral: 1)
static let titleNumberOfLines = 2
static let textColor = AppAssets.timelineTextPrimaryColor
static let textFont = UIFont.systemFont(ofSize: UIFont.systemFontSize)
static let textOnlyFont = UIFont.systemFont(ofSize: UIFont.systemFontSize)
static let unreadCircleMarginLeft = CGFloat(integerLiteral: 8)
static let unreadCircleDimension = CGFloat(integerLiteral: 8)
static let unreadCircleMarginRight = CGFloat(integerLiteral: 8)
static let starDimension = CGFloat(integerLiteral: 13)
static let avatarSize = CGSize(width: 48.0, height: 48.0)
static let avatarMarginLeft = CGFloat(integerLiteral: 8)
static let avatarMarginRight = CGFloat(integerLiteral: 8)
static let avatarCornerRadius = CGFloat(integerLiteral: 4)
static let titleColor = AppAssets.timelineTextPrimaryColor
static let titleFont = UIFont.preferredFont(forTextStyle: .headline)
static let titleBottomMargin = CGFloat(integerLiteral: 1)
static let feedColor = AppAssets.timelineTextSecondaryColor
static let feedNameFont = UIFont.preferredFont(forTextStyle: .footnote)
static let feedRightMargin = CGFloat(integerLiteral: 8)
static let dateColor = AppAssets.timelineTextSecondaryColor
static let dateFont = UIFont.preferredFont(forTextStyle: .footnote)
static let dateMarginBottom = CGFloat(integerLiteral: 1)
static let summaryColor = AppAssets.timelineTextPrimaryColor
static let summaryFont = UIFont.preferredFont(forTextStyle: .body)
static let chevronWidth = CGFloat(integerLiteral: 28)
let width: CGFloat
let insets: UIEdgeInsets
let height: CGFloat
let feedNameRect: CGRect
let dateRect: CGRect
let titleRect: CGRect
let numberOfLinesForTitle: Int
let summaryRect: CGRect
let textRect: CGRect
let unreadIndicatorRect: CGRect
let starRect: CGRect
let avatarImageRect: CGRect
let paddingBottom: CGFloat
let titleRect: CGRect
let summaryRect: CGRect
let feedNameRect: CGRect
let dateRect: CGRect
let separatorInsets: UIEdgeInsets
init(width: CGFloat, height: CGFloat, feedNameRect: CGRect, dateRect: CGRect, titleRect: CGRect, numberOfLinesForTitle: Int, summaryRect: CGRect, textRect: CGRect, unreadIndicatorRect: CGRect, starRect: CGRect, avatarImageRect: CGRect, paddingBottom: CGFloat, separatorInsets: UIEdgeInsets) {
self.width = width - MasterTimelineCellLayout.chevronWidth
self.feedNameRect = feedNameRect
self.dateRect = dateRect
self.titleRect = titleRect
self.numberOfLinesForTitle = numberOfLinesForTitle
self.summaryRect = summaryRect
self.textRect = textRect
self.unreadIndicatorRect = unreadIndicatorRect
self.starRect = starRect
self.avatarImageRect = avatarImageRect
self.paddingBottom = paddingBottom
self.separatorInsets = separatorInsets
if height > 0.1 {
self.height = height
init(width: CGFloat, insets: UIEdgeInsets, cellData: MasterTimelineCellData, showAvatar: Bool) {
self.width = width
self.insets = insets
var currentPoint = CGPoint.zero
currentPoint.x = MasterTimelineCellLayout.cellPadding.left + insets.left + MasterTimelineCellLayout.unreadCircleMarginLeft
currentPoint.y = MasterTimelineCellLayout.cellPadding.top
// Unread Indicator and Star
self.unreadIndicatorRect = MasterTimelineCellLayout.rectForUnreadIndicator(currentPoint)
self.starRect = MasterTimelineCellLayout.rectForStar(currentPoint)
// Start the point at the beginning position of the main block
currentPoint.x += MasterTimelineCellLayout.unreadCircleDimension + MasterTimelineCellLayout.unreadCircleMarginRight
// Separator Insets
self.separatorInsets = UIEdgeInsets(top: 0, left: currentPoint.x, bottom: 0, right: 0)
// Avatar
if showAvatar {
self.avatarImageRect = MasterTimelineCellLayout.rectForAvatar(currentPoint)
currentPoint.x = self.avatarImageRect.maxX + MasterTimelineCellLayout.avatarMarginRight
} else {
self.height = [feedNameRect, dateRect, titleRect, summaryRect, textRect, unreadIndicatorRect, avatarImageRect].maxY() + paddingBottom
self.avatarImageRect = CGRect.zero
}
}
init(width: CGFloat, height: CGFloat, cellData: MasterTimelineCellData, hasAvatar: Bool) {
let width = width - MasterTimelineCellLayout.chevronWidth
let textAreaWidth = width - (currentPoint.x + MasterTimelineCellLayout.chevronWidth + MasterTimelineCellLayout.cellPadding.right + insets.right)
// If height == 0.0, then height is calculated.
let showAvatar = hasAvatar && cellData.showAvatar
var textBoxRect = MasterTimelineCellLayout.rectForTextBox(cellData, showAvatar, width)
let (titleRect, numberOfLinesForTitle) = MasterTimelineCellLayout.rectForTitle(textBoxRect, cellData)
let summaryRect = numberOfLinesForTitle > 0 ? MasterTimelineCellLayout.rectForSummary(textBoxRect, titleRect, numberOfLinesForTitle, cellData) : CGRect.zero
let textRect = numberOfLinesForTitle > 0 ? CGRect.zero : MasterTimelineCellLayout.rectForText(textBoxRect, cellData)
var lastTextRect = titleRect
if numberOfLinesForTitle == 0 {
lastTextRect = textRect
} else if numberOfLinesForTitle == 1 {
if summaryRect.height > 0.1 {
lastTextRect = summaryRect
}
// Title Text Block
let (titleRect, numberOfLinesForTitle) = MasterTimelineCellLayout.rectForTitle(cellData, currentPoint, textAreaWidth)
self.titleRect = titleRect
// Summary Text Block
if self.titleRect != CGRect.zero {
currentPoint.y = self.titleRect.maxY + MasterTimelineCellLayout.titleBottomMargin
}
self.summaryRect = MasterTimelineCellLayout.rectForSummary(cellData, currentPoint, textAreaWidth, numberOfLinesForTitle)
let dateRect = MasterTimelineCellLayout.rectForDate(textBoxRect, lastTextRect, cellData)
let feedNameRect = MasterTimelineCellLayout.rectForFeedName(textBoxRect, dateRect, cellData)
textBoxRect.size.height = ceil([titleRect, summaryRect, textRect, dateRect, feedNameRect].maxY() - textBoxRect.origin.y)
let avatarImageRect = MasterTimelineCellLayout.rectForAvatar(cellData, showAvatar, textBoxRect, width, height)
let unreadIndicatorRect = MasterTimelineCellLayout.rectForUnreadIndicator(textBoxRect)
let starRect = MasterTimelineCellLayout.rectForStar(unreadIndicatorRect)
let paddingBottom = MasterTimelineCellLayout.cellPadding.bottom
let separatorInsets = UIEdgeInsets(top: 0, left: unreadIndicatorRect.maxX + MasterTimelineCellLayout.unreadCircleMarginRight, bottom: 0, right: 0)
currentPoint.y = [self.titleRect, self.summaryRect].maxY()
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, separatorInsets: separatorInsets)
// Feed Name and Pub Date
self.dateRect = MasterTimelineCellLayout.rectForDate(cellData, currentPoint, textAreaWidth)
}
let feedNameWidth = textAreaWidth - (MasterTimelineCellLayout.feedRightMargin + self.dateRect.size.width)
self.feedNameRect = MasterTimelineCellLayout.rectForFeedName(cellData, currentPoint, feedNameWidth)
self.height = [self.avatarImageRect, self.feedNameRect].maxY() + MasterTimelineCellLayout.cellPadding.bottom
static func height(for width: CGFloat, cellData: MasterTimelineCellData) -> CGFloat {
let layout = MasterTimelineCellLayout(width: width, height: 0.0, cellData: cellData, hasAvatar: true)
return layout.height
}
}
@ -127,123 +113,102 @@ struct MasterTimelineCellLayout {
private extension MasterTimelineCellLayout {
static func rectForTextBox(_ cellData: MasterTimelineCellData, _ showAvatar: Bool, _ width: CGFloat) -> CGRect {
// Returned height is a placeholder. Not needed when this is calculated.
let textBoxOriginX = MasterTimelineCellLayout.cellPadding.left + MasterTimelineCellLayout.unreadCircleDimension + MasterTimelineCellLayout.unreadCircleMarginRight
let textBoxMaxX = floor((width - MasterTimelineCellLayout.cellPadding.right) - (showAvatar ? MasterTimelineCellLayout.avatarSize.width + MasterTimelineCellLayout.avatarMarginLeft : 0.0))
let textBoxWidth = floor(textBoxMaxX - textBoxOriginX)
let textBoxRect = CGRect(x: textBoxOriginX, y: MasterTimelineCellLayout.cellPadding.top, width: textBoxWidth, height: 1000000)
return textBoxRect
}
static func rectForTitle(_ textBoxRect: CGRect, _ cellData: MasterTimelineCellData) -> (CGRect, Int) {
var r = textBoxRect
if cellData.title.isEmpty {
r.size.height = 0
return (r, 0)
}
let sizeInfo = MultilineUILabelSizer.size(for: cellData.title, font: MasterTimelineCellLayout.titleFont, numberOfLines: MasterTimelineCellLayout.titleNumberOfLines, width: Int(textBoxRect.width))
r.size.height = sizeInfo.size.height
if sizeInfo.numberOfLinesUsed < 1 {
r.size.height = 0
}
return (r, sizeInfo.numberOfLinesUsed)
}
static func rectForSummary(_ textBoxRect: CGRect, _ titleRect: CGRect, _ titleNumberOfLines: Int, _ cellData: MasterTimelineCellData) -> CGRect {
if titleNumberOfLines >= MasterTimelineCellLayout.titleNumberOfLines || cellData.text.isEmpty {
return CGRect.zero
}
return rectOfLineBelow(titleRect, titleRect, 0, cellData.text, MasterTimelineCellLayout.textFont)
}
static func rectForText(_ textBoxRect: CGRect, _ cellData: MasterTimelineCellData) -> CGRect {
var r = textBoxRect
if cellData.text.isEmpty {
r.size.height = 0
return r
}
let sizeInfo = MultilineUILabelSizer.size(for: cellData.text, font: MasterTimelineCellLayout.textOnlyFont, numberOfLines: MasterTimelineCellLayout.titleNumberOfLines, width: Int(textBoxRect.width))
r.size.height = sizeInfo.size.height
if sizeInfo.numberOfLinesUsed < 1 {
r.size.height = 0
}
return r
}
static func rectForDate(_ textBoxRect: CGRect, _ rectAbove: CGRect, _ cellData: MasterTimelineCellData) -> CGRect {
return rectOfLineBelow(textBoxRect, rectAbove, MasterTimelineCellLayout.titleBottomMargin, cellData.dateString, MasterTimelineCellLayout.dateFont)
}
static func rectForFeedName(_ textBoxRect: CGRect, _ dateRect: CGRect, _ cellData: MasterTimelineCellData) -> CGRect {
if !cellData.showFeedName {
return CGRect.zero
}
return rectOfLineBelow(textBoxRect, dateRect, MasterTimelineCellLayout.dateMarginBottom, cellData.feedName, MasterTimelineCellLayout.feedNameFont)
}
static func rectOfLineBelow(_ textBoxRect: CGRect, _ rectAbove: CGRect, _ topMargin: CGFloat, _ value: String, _ font: UIFont) -> CGRect {
let textFieldSize = SingleLineUILabelSizer.size(for: value, font: font)
var r = CGRect.zero
r.size = textFieldSize
r.origin.y = rectAbove.maxY + topMargin
r.origin.x = textBoxRect.origin.x
var width = textFieldSize.width
width = min(width, textBoxRect.size.width)
width = max(width, 0.0)
r.size.width = width
return r
}
static func rectForUnreadIndicator(_ titleRect: CGRect) -> CGRect {
static func rectForUnreadIndicator(_ point: CGPoint) -> CGRect {
var r = CGRect.zero
r.size = CGSize(width: MasterTimelineCellLayout.unreadCircleDimension, height: MasterTimelineCellLayout.unreadCircleDimension)
r.origin.x = MasterTimelineCellLayout.cellPadding.left
r.origin.y = titleRect.minY + 6
r.origin.x = point.x
r.origin.y = point.y + 9
return r
}
static func rectForStar(_ unreadIndicatorRect: CGRect) -> CGRect {
static func rectForStar(_ point: CGPoint) -> CGRect {
var r = CGRect.zero
r.size.width = MasterTimelineCellLayout.starDimension
r.size.height = MasterTimelineCellLayout.starDimension
r.origin.x = floor(unreadIndicatorRect.origin.x - ((MasterTimelineCellLayout.starDimension - MasterTimelineCellLayout.unreadCircleDimension) / 2.0))
r.origin.y = unreadIndicatorRect.origin.y - 4.0
r.origin.x = floor(point.x - ((MasterTimelineCellLayout.starDimension - MasterTimelineCellLayout.unreadCircleDimension) / 2.0))
r.origin.y = point.y + 5
return r
}
static func rectForAvatar(_ cellData: MasterTimelineCellData, _ showAvatar: Bool, _ textBoxRect: CGRect, _ width: CGFloat, _ height: CGFloat) -> CGRect {
static func rectForAvatar(_ point: CGPoint) -> CGRect {
var r = CGRect.zero
if !showAvatar {
r.size = MasterTimelineCellLayout.avatarSize
r.origin = point
return r
}
static func rectForTitle(_ cellData: MasterTimelineCellData, _ point: CGPoint, _ textAreaWidth: CGFloat) -> (CGRect, Int) {
var r = CGRect.zero
if cellData.title.isEmpty {
return (r, 0)
}
r.origin = point
let sizeInfo = MultilineUILabelSizer.size(for: cellData.title, font: MasterTimelineCellLayout.titleFont, numberOfLines: MasterTimelineCellLayout.maxNumberOfLines, width: Int(textAreaWidth))
r.size.width = textAreaWidth
r.size.height = sizeInfo.size.height
if sizeInfo.numberOfLinesUsed < 1 {
r.size.height = 0
}
return (r, sizeInfo.numberOfLinesUsed)
}
static func rectForSummary(_ cellData: MasterTimelineCellData, _ point: CGPoint, _ textAreaWidth: CGFloat, _ linesUsed: Int) -> CGRect {
let linesLeft = MasterTimelineCellLayout.maxNumberOfLines - linesUsed
var r = CGRect.zero
if cellData.summary.isEmpty || linesLeft < 1 {
return r
}
r.size = MasterTimelineCellLayout.avatarSize
r.origin.x = (width - MasterTimelineCellLayout.cellPadding.right) - r.size.width
r.origin.y = textBoxRect.origin.y + 4.0
r.origin = point
let sizeInfo = MultilineUILabelSizer.size(for: cellData.summary, font: MasterTimelineCellLayout.summaryFont, numberOfLines: linesLeft, width: Int(textAreaWidth))
r.size.width = textAreaWidth
r.size.height = sizeInfo.size.height
if sizeInfo.numberOfLinesUsed < 1 {
r.size.height = 0
}
return r
}
static func rectForDate(_ cellData: MasterTimelineCellData, _ point: CGPoint, _ textAreaWidth: CGFloat) -> CGRect {
var r = CGRect.zero
let size = SingleLineUILabelSizer.size(for: cellData.dateString, font: MasterTimelineCellLayout.dateFont)
r.size = size
r.origin.x = (point.x + textAreaWidth) - size.width
r.origin.y = point.y
return r
}
static func rectForFeedName(_ cellData: MasterTimelineCellData, _ point: CGPoint, _ textAreaWidth: CGFloat) -> CGRect {
var r = CGRect.zero
r.origin = point
let size = SingleLineUILabelSizer.size(for: cellData.feedName, font: MasterTimelineCellLayout.feedNameFont)
r.size = size
if r.size.width > textAreaWidth {
r.size.width = textAreaWidth
}
return r
}
}

View File

@ -12,8 +12,7 @@ import RSCore
class MasterTimelineTableViewCell: UITableViewCell {
private let titleView = MasterTimelineTableViewCell.multiLineUILabel()
private let summaryView = MasterTimelineTableViewCell.singleLineUILabel()
private let textView = MasterTimelineTableViewCell.multiLineUILabel()
private let summaryView = MasterTimelineTableViewCell.multiLineUILabel()
private let unreadIndicatorView = MasterUnreadIndicatorView(frame: CGRect.zero)
private let dateView = MasterTimelineTableViewCell.singleLineUILabel()
private let feedNameView = MasterTimelineTableViewCell.singleLineUILabel()
@ -28,10 +27,6 @@ class MasterTimelineTableViewCell: UITableViewCell {
return NonIntrinsicImageView(image: AppAssets.timelineStarImage)
}()
private lazy var textFields = {
return [self.dateView, self.feedNameView, self.titleView, self.summaryView, self.textView]
}()
var cellData: MasterTimelineCellData! {
didSet {
updateSubviews()
@ -49,22 +44,25 @@ class MasterTimelineTableViewCell: UITableViewCell {
}
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
let layout = updatedLayout()
return CGSize(width: bounds.width, height: layout.height)
}
override func layoutSubviews() {
super.layoutSubviews()
let layout = updatedLayout()
unreadIndicatorView.setFrameIfNotEqual(layout.unreadIndicatorRect)
starView.setFrameIfNotEqual(layout.starRect)
avatarImageView.setFrameIfNotEqual(layout.avatarImageRect)
setFrame(for: titleView, rect: layout.titleRect)
setFrame(for: summaryView, rect: layout.summaryRect)
setFrame(for: textView, rect: layout.textRect)
dateView.setFrameIfNotEqual(layout.dateRect)
unreadIndicatorView.setFrameIfNotEqual(layout.unreadIndicatorRect)
feedNameView.setFrameIfNotEqual(layout.feedNameRect)
avatarImageView.setFrameIfNotEqual(layout.avatarImageRect)
starView.setFrameIfNotEqual(layout.starRect)
dateView.setFrameIfNotEqual(layout.dateRect)
separatorInset = layout.separatorInsets
}
@ -79,6 +77,7 @@ private extension MasterTimelineTableViewCell {
let label = NonIntrinsicLabel()
label.lineBreakMode = .byTruncatingTail
label.allowsDefaultTighteningForTruncation = false
label.adjustsFontForContentSizeCategory = true
return label
}
@ -87,6 +86,7 @@ private extension MasterTimelineTableViewCell {
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.allowsDefaultTighteningForTruncation = false
label.adjustsFontForContentSizeCategory = true
return label
}
@ -113,7 +113,6 @@ private extension MasterTimelineTableViewCell {
addAccessoryView()
addSubviewAtInit(titleView, hidden: false)
addSubviewAtInit(summaryView, hidden: true)
addSubviewAtInit(textView, hidden: true)
addSubviewAtInit(unreadIndicatorView, hidden: true)
addSubviewAtInit(dateView, hidden: false)
addSubviewAtInit(feedNameView, hidden: true)
@ -133,8 +132,7 @@ private extension MasterTimelineTableViewCell {
}
func updatedLayout() -> MasterTimelineCellLayout {
return MasterTimelineCellLayout(width: bounds.width, height: bounds.height, cellData: cellData, hasAvatar: avatarImageView.image != nil)
return MasterTimelineCellLayout(width: bounds.width, insets: safeAreaInsets, cellData: cellData, showAvatar: avatarImageView.image != nil)
}
func updateTitleView() {
@ -144,15 +142,9 @@ private extension MasterTimelineTableViewCell {
}
func updateSummaryView() {
summaryView.font = MasterTimelineCellLayout.textFont
summaryView.textColor = MasterTimelineCellLayout.textColor
updateTextFieldText(summaryView, cellData?.text)
}
func updateTextView() {
textView.font = MasterTimelineCellLayout.textFont
textView.textColor = MasterTimelineCellLayout.textColor
updateTextFieldText(textView, cellData?.text)
summaryView.font = MasterTimelineCellLayout.summaryFont
summaryView.textColor = MasterTimelineCellLayout.summaryColor
updateTextFieldText(summaryView, cellData?.summary)
}
func updateDateView() {
@ -234,7 +226,6 @@ private extension MasterTimelineTableViewCell {
func updateSubviews() {
updateTitleView()
updateSummaryView()
updateTextView()
updateDateView()
updateFeedNameView()
updateUnreadIndicator()

View File

@ -14,13 +14,7 @@ import Articles
class MasterTimelineViewController: ProgressTableViewController, UndoableCommandRunner {
private static var minAvatarDimension: CGFloat = 20.0
private var rowHeightWithFeedName: CGFloat = 0.0
private var rowHeightWithoutFeedName: CGFloat = 0.0
private var currentRowHeight: CGFloat {
return navState?.showFeedNames ?? false ? rowHeightWithFeedName : rowHeightWithoutFeedName
}
@IBOutlet weak var markAllAsReadButton: UIBarButtonItem!
@IBOutlet weak var firstUnreadButton: UIBarButtonItem!
@ -34,7 +28,6 @@ class MasterTimelineViewController: ProgressTableViewController, UndoableCommand
override func viewDidLoad() {
super.viewDidLoad()
updateRowHeights()
NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
@ -312,28 +305,6 @@ class MasterTimelineViewController: ProgressTableViewController, UndoableCommand
}
}
// MARK: Cell Configuring
private func calculateRowHeight(showingFeedNames: Bool) -> CGFloat {
let longTitle = "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"
let prototypeID = "prototype"
let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, userDeleted: false, dateArrived: Date())
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, feedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, attachments: nil, status: status)
let prototypeCellData = MasterTimelineCellData(article: prototypeArticle, showFeedName: showingFeedNames, feedName: "Prototype Feed Name", avatar: nil, showAvatar: false, featuredImage: nil)
let height = MasterTimelineCellLayout.height(for: 100, cellData: prototypeCellData)
return height
}
private func updateRowHeights() {
rowHeightWithFeedName = calculateRowHeight(showingFeedNames: true)
rowHeightWithoutFeedName = calculateRowHeight(showingFeedNames: false)
updateTableViewRowHeight()
}
}
// MARK: Private
@ -347,7 +318,6 @@ private extension MasterTimelineViewController {
func resetUI() {
updateTableViewRowHeight()
title = navState?.timelineName
navigationController?.title = navState?.timelineName
@ -431,11 +401,6 @@ private extension MasterTimelineViewController {
CoalescingQueue.standard.add(self, #selector(reloadAllVisibleCells))
}
func updateTableViewRowHeight() {
tableView.rowHeight = currentRowHeight
tableView.estimatedRowHeight = currentRowHeight
}
func performBlockAndRestoreSelection(_ block: (() -> Void)) {
let indexPaths = tableView.indexPathsForSelectedRows
block()