NetNewsWire/iOS/MasterTimeline/Cell/MasterTimelineTableViewCell...

251 lines
6.3 KiB
Swift

//
// MasterTimelineTableViewCell.swift
// NetNewsWire
//
// Created by Brent Simmons on 8/31/15.
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
//
import UIKit
import RSCore
class MasterTimelineTableViewCell: NNWTableViewCell {
private let titleView = MasterTimelineTableViewCell.multiLineUILabel()
private let summaryView = MasterTimelineTableViewCell.multiLineUILabel()
private let unreadIndicatorView = MasterUnreadIndicatorView(frame: CGRect.zero)
private let dateView = MasterTimelineTableViewCell.singleLineUILabel()
private let feedNameView = MasterTimelineTableViewCell.singleLineUILabel()
private lazy var avatarView = MasterTimelineAvatarView()
private lazy var starView = {
return NonIntrinsicImageView(image: AppAssets.timelineStarImage)
}()
var cellData: MasterTimelineCellData! {
didSet {
updateSubviews()
}
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
override func applyThemeProperties() {
super.applyThemeProperties()
let highlightedTextColor = AppAssets.tableViewCellHighlightedTextColor
titleView.highlightedTextColor = highlightedTextColor
summaryView.highlightedTextColor = highlightedTextColor
dateView.highlightedTextColor = highlightedTextColor
feedNameView.highlightedTextColor = highlightedTextColor
}
override var frame: CGRect {
didSet {
setNeedsLayout()
}
}
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
super.setHighlighted(highlighted, animated: animated)
unreadIndicatorView.isSelected = isHighlighted || isSelected
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
unreadIndicatorView.isSelected = isHighlighted || isSelected
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
let layout = updatedLayout(width: size.width)
return CGSize(width: size.width, height: layout.height)
}
override func layoutSubviews() {
super.layoutSubviews()
let layout = updatedLayout(width: bounds.width)
unreadIndicatorView.setFrameIfNotEqual(layout.unreadIndicatorRect)
starView.setFrameIfNotEqual(layout.starRect)
avatarView.setFrameIfNotEqual(layout.avatarImageRect)
setFrame(for: titleView, rect: layout.titleRect)
setFrame(for: summaryView, rect: layout.summaryRect)
feedNameView.setFrameIfNotEqual(layout.feedNameRect)
dateView.setFrameIfNotEqual(layout.dateRect)
separatorInset = layout.separatorInsets
}
func setAvatarImage(_ image: UIImage) {
avatarView.image = image
}
}
// MARK: - Private
private extension MasterTimelineTableViewCell {
static func singleLineUILabel() -> UILabel {
let label = NonIntrinsicLabel()
label.lineBreakMode = .byTruncatingTail
label.allowsDefaultTighteningForTruncation = false
label.adjustsFontForContentSizeCategory = true
return label
}
static func multiLineUILabel() -> UILabel {
let label = NonIntrinsicLabel()
label.numberOfLines = 0
label.lineBreakMode = .byTruncatingTail
label.allowsDefaultTighteningForTruncation = false
label.adjustsFontForContentSizeCategory = true
return label
}
func setFrame(for label: UILabel, rect: CGRect) {
if Int(floor(rect.height)) == 0 || Int(floor(rect.width)) == 0 {
hideView(label)
} else {
showView(label)
label.setFrameIfNotEqual(rect)
}
}
func addSubviewAtInit(_ view: UIView, hidden: Bool) {
addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
view.isHidden = hidden
}
func commonInit() {
addSubviewAtInit(titleView, hidden: false)
addSubviewAtInit(summaryView, hidden: true)
addSubviewAtInit(unreadIndicatorView, hidden: true)
addSubviewAtInit(dateView, hidden: false)
addSubviewAtInit(feedNameView, hidden: true)
addSubviewAtInit(avatarView, hidden: true)
addSubviewAtInit(starView, hidden: true)
}
func updatedLayout(width: CGFloat) -> MasterTimelineCellLayout {
if UIApplication.shared.preferredContentSizeCategory.isAccessibilityCategory {
return MasterTimelineAccessibilityCellLayout(width: width, insets: safeAreaInsets, cellData: cellData)
} else {
return MasterTimelineDefaultCellLayout(width: width, insets: safeAreaInsets, cellData: cellData)
}
}
func updateTitleView() {
titleView.font = MasterTimelineDefaultCellLayout.titleFont
titleView.textColor = .label
updateTextFieldText(titleView, cellData?.title)
}
func updateSummaryView() {
summaryView.font = MasterTimelineDefaultCellLayout.summaryFont
summaryView.textColor = .label
updateTextFieldText(summaryView, cellData?.summary)
}
func updateDateView() {
dateView.font = MasterTimelineDefaultCellLayout.dateFont
dateView.textColor = .secondaryLabel
updateTextFieldText(dateView, cellData.dateString)
}
func updateTextFieldText(_ label: UILabel, _ text: String?) {
let s = text ?? ""
if label.text != s {
label.text = s
setNeedsLayout()
}
}
func updateFeedNameView() {
if cellData.showFeedName {
showView(feedNameView)
feedNameView.font = MasterTimelineDefaultCellLayout.feedNameFont
feedNameView.textColor = .secondaryLabel
updateTextFieldText(feedNameView, cellData.feedName)
} else {
hideView(feedNameView)
}
}
func updateUnreadIndicator() {
showOrHideView(unreadIndicatorView, cellData.read || cellData.starred)
unreadIndicatorView.setNeedsDisplay()
}
func updateStarView() {
showOrHideView(starView, !cellData.starred)
}
func updateAvatar() {
guard let image = cellData.avatar, cellData.showAvatar else {
makeAvatarEmpty()
return
}
showView(avatarView)
avatarView.layer.cornerRadius = MasterTimelineDefaultCellLayout.avatarCornerRadius
avatarView.clipsToBounds = true
if avatarView.image !== cellData.avatar {
avatarView.image = image
setNeedsLayout()
}
}
func makeAvatarEmpty() {
if avatarView.image != nil {
avatarView.image = nil
setNeedsLayout()
}
hideView(avatarView)
}
func hideView(_ view: UIView) {
if !view.isHidden {
view.isHidden = true
}
}
func showView(_ view: UIView) {
if view.isHidden {
view.isHidden = false
}
}
func showOrHideView(_ view: UIView, _ shouldHide: Bool) {
shouldHide ? hideView(view) : showView(view)
}
func updateSubviews() {
updateTitleView()
updateSummaryView()
updateDateView()
updateFeedNameView()
updateUnreadIndicator()
updateStarView()
updateAvatar()
}
}