2019-04-15 22:03:05 +02:00
|
|
|
//
|
|
|
|
// MasterTimelineTableViewCell.swift
|
|
|
|
// NetNewsWire
|
|
|
|
//
|
|
|
|
// Created by Brent Simmons on 8/31/15.
|
|
|
|
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
import RSCore
|
|
|
|
|
2019-10-22 09:35:47 +02:00
|
|
|
class MasterTimelineTableViewCell: VibrantTableViewCell {
|
2019-04-15 22:03:05 +02:00
|
|
|
|
|
|
|
private let titleView = MasterTimelineTableViewCell.multiLineUILabel()
|
2019-04-29 21:40:14 +02:00
|
|
|
private let summaryView = MasterTimelineTableViewCell.multiLineUILabel()
|
2019-04-15 22:03:05 +02:00
|
|
|
private let unreadIndicatorView = MasterUnreadIndicatorView(frame: CGRect.zero)
|
|
|
|
private let dateView = MasterTimelineTableViewCell.singleLineUILabel()
|
|
|
|
private let feedNameView = MasterTimelineTableViewCell.singleLineUILabel()
|
|
|
|
|
2019-09-18 00:00:23 +02:00
|
|
|
private lazy var avatarView = MasterTimelineAvatarView()
|
2019-04-15 22:03:05 +02:00
|
|
|
|
|
|
|
private lazy var starView = {
|
2019-04-26 13:30:00 +02:00
|
|
|
return NonIntrinsicImageView(image: AppAssets.timelineStarImage)
|
2019-04-15 22:03:05 +02:00
|
|
|
}()
|
|
|
|
|
2019-10-25 22:52:32 +02:00
|
|
|
private let separatorAccent: UIView = {
|
|
|
|
let view = UIView()
|
|
|
|
view.backgroundColor = UIColor.white
|
|
|
|
return view
|
|
|
|
}()
|
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
var cellData: MasterTimelineCellData! {
|
|
|
|
didSet {
|
|
|
|
updateSubviews()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
required init?(coder: NSCoder) {
|
|
|
|
super.init(coder: coder)
|
|
|
|
commonInit()
|
|
|
|
}
|
|
|
|
|
2019-09-03 07:39:01 +02:00
|
|
|
override func applyThemeProperties() {
|
|
|
|
super.applyThemeProperties()
|
|
|
|
|
2019-10-22 10:31:25 +02:00
|
|
|
let highlightedTextColor = AppAssets.vibrantTextColor
|
2019-09-03 07:39:01 +02:00
|
|
|
|
|
|
|
titleView.highlightedTextColor = highlightedTextColor
|
|
|
|
summaryView.highlightedTextColor = highlightedTextColor
|
|
|
|
dateView.highlightedTextColor = highlightedTextColor
|
|
|
|
feedNameView.highlightedTextColor = highlightedTextColor
|
2019-10-25 22:52:32 +02:00
|
|
|
|
|
|
|
backgroundColor = AppAssets.timelineBackgroundColor
|
2019-09-03 07:39:01 +02:00
|
|
|
}
|
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
override var frame: CGRect {
|
|
|
|
didSet {
|
|
|
|
setNeedsLayout()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-03 07:39:01 +02:00
|
|
|
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
|
|
|
|
super.setHighlighted(highlighted, animated: animated)
|
|
|
|
unreadIndicatorView.isSelected = isHighlighted || isSelected
|
|
|
|
}
|
|
|
|
|
2019-08-03 23:25:35 +02:00
|
|
|
override func setSelected(_ selected: Bool, animated: Bool) {
|
|
|
|
super.setSelected(selected, animated: animated)
|
2019-09-03 07:39:01 +02:00
|
|
|
unreadIndicatorView.isSelected = isHighlighted || isSelected
|
2019-08-03 23:25:35 +02:00
|
|
|
}
|
|
|
|
|
2019-04-29 21:40:14 +02:00
|
|
|
override func sizeThatFits(_ size: CGSize) -> CGSize {
|
2019-05-31 23:59:02 +02:00
|
|
|
let layout = updatedLayout(width: size.width)
|
|
|
|
return CGSize(width: size.width, height: layout.height)
|
2019-04-29 21:40:14 +02:00
|
|
|
}
|
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
override func layoutSubviews() {
|
|
|
|
|
|
|
|
super.layoutSubviews()
|
|
|
|
|
2019-05-31 23:59:02 +02:00
|
|
|
let layout = updatedLayout(width: bounds.width)
|
2019-04-30 00:45:12 +02:00
|
|
|
|
2019-05-31 23:59:02 +02:00
|
|
|
unreadIndicatorView.setFrameIfNotEqual(layout.unreadIndicatorRect)
|
|
|
|
starView.setFrameIfNotEqual(layout.starRect)
|
2019-09-18 00:00:23 +02:00
|
|
|
avatarView.setFrameIfNotEqual(layout.avatarImageRect)
|
2019-05-31 23:59:02 +02:00
|
|
|
setFrame(for: titleView, rect: layout.titleRect)
|
|
|
|
setFrame(for: summaryView, rect: layout.summaryRect)
|
|
|
|
feedNameView.setFrameIfNotEqual(layout.feedNameRect)
|
|
|
|
dateView.setFrameIfNotEqual(layout.dateRect)
|
2019-04-29 21:40:14 +02:00
|
|
|
|
2019-05-31 23:59:02 +02:00
|
|
|
separatorInset = layout.separatorInsets
|
2019-04-15 22:03:05 +02:00
|
|
|
|
2019-10-25 22:52:32 +02:00
|
|
|
if traitCollection.userInterfaceStyle == .light {
|
|
|
|
let separatorAccentRect = CGRect(x: safeAreaInsets.left, y: frame.height - 2, width: frame.width - safeAreaInsets.right - safeAreaInsets.left, height: 1)
|
|
|
|
separatorAccent.setFrameIfNotEqual(separatorAccentRect)
|
2019-10-25 22:56:09 +02:00
|
|
|
} else {
|
|
|
|
separatorAccent.setFrameIfNotEqual(.zero)
|
2019-10-25 22:52:32 +02:00
|
|
|
}
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
2019-08-26 22:37:15 +02:00
|
|
|
func setAvatarImage(_ image: UIImage) {
|
2019-09-18 00:00:23 +02:00
|
|
|
avatarView.image = image
|
2019-08-26 22:37:15 +02:00
|
|
|
}
|
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Private
|
|
|
|
|
|
|
|
private extension MasterTimelineTableViewCell {
|
|
|
|
|
|
|
|
static func singleLineUILabel() -> UILabel {
|
2019-04-22 18:49:22 +02:00
|
|
|
let label = NonIntrinsicLabel()
|
2019-04-15 22:03:05 +02:00
|
|
|
label.lineBreakMode = .byTruncatingTail
|
|
|
|
label.allowsDefaultTighteningForTruncation = false
|
2019-04-29 21:40:14 +02:00
|
|
|
label.adjustsFontForContentSizeCategory = true
|
2019-04-15 22:03:05 +02:00
|
|
|
return label
|
|
|
|
}
|
|
|
|
|
|
|
|
static func multiLineUILabel() -> UILabel {
|
2019-04-22 18:49:22 +02:00
|
|
|
let label = NonIntrinsicLabel()
|
2019-04-15 22:03:05 +02:00
|
|
|
label.numberOfLines = 0
|
2019-09-29 21:07:33 +02:00
|
|
|
label.lineBreakMode = .byTruncatingTail
|
2019-04-15 22:03:05 +02:00
|
|
|
label.allowsDefaultTighteningForTruncation = false
|
2019-04-29 21:40:14 +02:00
|
|
|
label.adjustsFontForContentSizeCategory = true
|
2019-04-15 22:03:05 +02:00
|
|
|
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)
|
2019-04-20 16:50:44 +02:00
|
|
|
label.setFrameIfNotEqual(rect)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2019-09-18 00:00:23 +02:00
|
|
|
addSubviewAtInit(avatarView, hidden: true)
|
2019-04-15 22:03:05 +02:00
|
|
|
addSubviewAtInit(starView, hidden: true)
|
2019-10-25 22:52:32 +02:00
|
|
|
addSubviewAtInit(separatorAccent, hidden: false)
|
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
2019-04-21 00:12:39 +02:00
|
|
|
|
2019-05-31 23:59:02 +02:00
|
|
|
func updatedLayout(width: CGFloat) -> MasterTimelineCellLayout {
|
2019-04-30 00:19:08 +02:00
|
|
|
if UIApplication.shared.preferredContentSizeCategory.isAccessibilityCategory {
|
2019-05-31 23:59:02 +02:00
|
|
|
return MasterTimelineAccessibilityCellLayout(width: width, insets: safeAreaInsets, cellData: cellData)
|
2019-04-30 00:19:08 +02:00
|
|
|
} else {
|
2019-05-31 23:59:02 +02:00
|
|
|
return MasterTimelineDefaultCellLayout(width: width, insets: safeAreaInsets, cellData: cellData)
|
2019-04-30 00:19:08 +02:00
|
|
|
}
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func updateTitleView() {
|
2019-04-30 00:19:08 +02:00
|
|
|
titleView.font = MasterTimelineDefaultCellLayout.titleFont
|
2019-06-19 00:47:13 +02:00
|
|
|
titleView.textColor = .label
|
2019-04-15 22:03:05 +02:00
|
|
|
updateTextFieldText(titleView, cellData?.title)
|
|
|
|
}
|
|
|
|
|
|
|
|
func updateSummaryView() {
|
2019-04-30 00:19:08 +02:00
|
|
|
summaryView.font = MasterTimelineDefaultCellLayout.summaryFont
|
2019-06-19 00:47:13 +02:00
|
|
|
summaryView.textColor = .label
|
2019-04-29 21:40:14 +02:00
|
|
|
updateTextFieldText(summaryView, cellData?.summary)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func updateDateView() {
|
2019-04-30 00:19:08 +02:00
|
|
|
dateView.font = MasterTimelineDefaultCellLayout.dateFont
|
2019-06-19 00:47:13 +02:00
|
|
|
dateView.textColor = .secondaryLabel
|
2019-04-15 22:03:05 +02:00
|
|
|
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)
|
2019-04-30 00:19:08 +02:00
|
|
|
feedNameView.font = MasterTimelineDefaultCellLayout.feedNameFont
|
2019-06-19 00:47:13 +02:00
|
|
|
feedNameView.textColor = .secondaryLabel
|
2019-04-15 22:03:05 +02:00
|
|
|
updateTextFieldText(feedNameView, cellData.feedName)
|
|
|
|
} else {
|
|
|
|
hideView(feedNameView)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func updateUnreadIndicator() {
|
2019-10-23 18:08:34 +02:00
|
|
|
showOrHideView(unreadIndicatorView, cellData.read || cellData.starred)
|
|
|
|
unreadIndicatorView.setNeedsDisplay()
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func updateStarView() {
|
2019-10-23 18:08:34 +02:00
|
|
|
showOrHideView(starView, !cellData.starred)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func updateAvatar() {
|
|
|
|
|
2019-04-29 12:51:47 +02:00
|
|
|
guard let image = cellData.avatar, cellData.showAvatar else {
|
2019-04-15 22:03:05 +02:00
|
|
|
makeAvatarEmpty()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-09-18 00:00:23 +02:00
|
|
|
showView(avatarView)
|
|
|
|
avatarView.layer.cornerRadius = MasterTimelineDefaultCellLayout.avatarCornerRadius
|
|
|
|
avatarView.clipsToBounds = true
|
2019-04-15 22:03:05 +02:00
|
|
|
|
2019-09-18 00:00:23 +02:00
|
|
|
if avatarView.image !== cellData.avatar {
|
|
|
|
avatarView.image = image
|
2019-04-15 22:03:05 +02:00
|
|
|
setNeedsLayout()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeAvatarEmpty() {
|
|
|
|
|
2019-09-18 00:00:23 +02:00
|
|
|
if avatarView.image != nil {
|
|
|
|
avatarView.image = nil
|
2019-04-15 22:03:05 +02:00
|
|
|
setNeedsLayout()
|
|
|
|
}
|
2019-09-18 00:00:23 +02:00
|
|
|
hideView(avatarView)
|
2019-04-15 22:03:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func hideView(_ view: UIView) {
|
|
|
|
if !view.isHidden {
|
|
|
|
view.isHidden = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func showView(_ view: UIView) {
|
|
|
|
if view.isHidden {
|
|
|
|
view.isHidden = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-23 18:08:34 +02:00
|
|
|
func showOrHideView(_ view: UIView, _ shouldHide: Bool) {
|
|
|
|
shouldHide ? hideView(view) : showView(view)
|
|
|
|
}
|
|
|
|
|
2019-04-15 22:03:05 +02:00
|
|
|
func updateSubviews() {
|
|
|
|
updateTitleView()
|
|
|
|
updateSummaryView()
|
|
|
|
updateDateView()
|
|
|
|
updateFeedNameView()
|
|
|
|
updateUnreadIndicator()
|
|
|
|
updateStarView()
|
|
|
|
updateAvatar()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|