Skip to content

Commit 79cbec0

Browse files
authored
Refactor: Rework PostCompactCell (#23893)
* Rework PostCompactCell * Remove obsolete tests
1 parent bb5191d commit 79cbec0

File tree

7 files changed

+45
-478
lines changed

7 files changed

+45
-478
lines changed

WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/DashboardPostsListCardCell.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ class DashboardPostsListCardCell: UICollectionViewCell, Reusable {
2323
tableView.translatesAutoresizingMaskIntoConstraints = false
2424
tableView.isScrollEnabled = false
2525
tableView.backgroundColor = nil
26-
let postCompactCellNib = PostCompactCell.defaultNib
27-
tableView.register(postCompactCellNib, forCellReuseIdentifier: PostCompactCell.defaultReuseID)
26+
tableView.register(PostCompactCell.self, forCellReuseIdentifier: PostCompactCell.defaultReuseID)
2827
let ghostCellNib = BlogDashboardPostCardGhostCell.defaultNib
2928
tableView.register(ghostCellNib, forCellReuseIdentifier: BlogDashboardPostCardGhostCell.defaultReuseID)
3029
tableView.register(DashboardPostListErrorCell.self, forCellReuseIdentifier: DashboardPostListErrorCell.defaultReuseID)

WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,7 @@ private extension PostsCardViewModel {
127127

128128
let cell = tableView.dequeueReusableCell(withIdentifier: PostCompactCell.defaultReuseID, for: indexPath) as? PostCompactCell
129129

130-
cell?.accessoryType = .none
131-
cell?.configureForDashboard(with: post)
130+
cell?.configure(with: post)
132131

133132
return cell ?? UITableViewCell()
134133
}
Lines changed: 43 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,79 @@
11
import AutomatticTracks
22
import UIKit
3-
import Gridicons
43
import WordPressShared
54
import WordPressUI
65

7-
class PostCompactCell: UITableViewCell {
8-
@IBOutlet weak var titleLabel: UILabel!
9-
@IBOutlet weak var timestampLabel: UILabel!
10-
@IBOutlet weak var badgesLabel: UILabel!
11-
@IBOutlet weak var menuButton: UIButton!
12-
@IBOutlet weak var featuredImageView: CachedAnimatedImageView!
13-
@IBOutlet weak var headerStackView: UIStackView!
14-
@IBOutlet weak var innerView: UIView!
15-
@IBOutlet weak var contentStackView: UIStackView!
16-
@IBOutlet weak var ghostView: UIView!
17-
@IBOutlet weak var separator: UIView!
18-
19-
@IBOutlet weak var trailingContentConstraint: NSLayoutConstraint!
20-
21-
private var iPadReadableLeadingAnchor: NSLayoutConstraint?
22-
private var iPadReadableTrailingAnchor: NSLayoutConstraint?
23-
24-
lazy var imageLoader: ImageLoader = {
25-
return ImageLoader(imageView: featuredImageView, gifStrategy: .mediumGIFs)
26-
}()
6+
final class PostCompactCell: UITableViewCell, Reusable {
7+
private let titleLabel = UILabel()
8+
private let detailsLabel = UILabel()
9+
private let featuredImageView = AsyncImageView()
2710

2811
private var post: Post? {
2912
didSet {
30-
guard let post, post != oldValue else {
31-
return
32-
}
33-
13+
guard let post, post != oldValue else { return }
3414
viewModel = PostCardStatusViewModel(post: post)
3515
}
3616
}
3717

3818
private var viewModel: PostCardStatusViewModel?
3919

40-
func configure(with post: Post) {
41-
self.post = post
20+
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
21+
super.init(style: style, reuseIdentifier: reuseIdentifier)
4222

43-
resetGhostStyles()
44-
configureTitle()
45-
configureDate()
46-
configureStatus()
47-
configureFeaturedImage()
48-
configureMenuInteraction()
23+
setupStyles()
24+
setupLayout()
4925
}
5026

51-
@IBAction func more(_ sender: Any) {
52-
// Do nothing. The compact cell is only shown in the dashboard, where the more button is hidden.
27+
required init?(coder: NSCoder) {
28+
fatalError("init(coder:) has not been implemented")
5329
}
5430

55-
override func awakeFromNib() {
56-
super.awakeFromNib()
57-
applyStyles()
58-
setupReadableGuideForiPad()
59-
setupSeparator()
60-
setupAccessibility()
61-
}
31+
func configure(with post: Post) {
32+
self.post = post
6233

63-
private func resetGhostStyles() {
64-
toggleGhost(visible: false)
65-
menuButton.layer.opacity = Constants.opacity
34+
titleLabel.text = post.titleForDisplay()
35+
detailsLabel.text = post.contentPreviewForDisplay()
36+
configureFeaturedImage()
6637
}
6738

68-
private func applyStyles() {
39+
private func setupStyles() {
6940
WPStyleGuide.configureTableViewCell(self)
7041
WPStyleGuide.applyPostCardStyle(self)
71-
WPStyleGuide.configureLabel(timestampLabel, textStyle: .subheadline)
72-
WPStyleGuide.configureLabel(badgesLabel, textStyle: .subheadline)
7342

74-
titleLabel.font = AppStyleGuide.prominentFont(textStyle: .headline, weight: .bold)
43+
titleLabel.font = .preferredFont(forTextStyle: .headline)
7544
titleLabel.adjustsFontForContentSizeCategory = true
76-
7745
titleLabel.textColor = .label
78-
timestampLabel.textColor = .secondaryLabel
79-
menuButton.tintColor = .secondaryLabel
46+
titleLabel.numberOfLines = 1
8047

81-
menuButton.setImage(.gridicon(.ellipsis), for: .normal)
48+
detailsLabel.font = .preferredFont(forTextStyle: .subheadline)
49+
detailsLabel.textColor = .secondaryLabel
50+
detailsLabel.numberOfLines = 1
8251

8352
featuredImageView.layer.cornerRadius = Constants.imageRadius
53+
featuredImageView.layer.masksToBounds = true
8454

85-
innerView.backgroundColor = .secondarySystemGroupedBackground
86-
backgroundColor = .secondarySystemGroupedBackground
87-
contentView.backgroundColor = .secondarySystemGroupedBackground
88-
}
89-
90-
private func setupSeparator() {
91-
WPStyleGuide.applyBorderStyle(separator)
55+
contentView.backgroundColor = .systemBackground
9256
}
9357

94-
private func setupReadableGuideForiPad() {
95-
guard WPDeviceIdentification.isiPad() else { return }
96-
97-
iPadReadableLeadingAnchor = innerView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor)
98-
iPadReadableTrailingAnchor = innerView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor)
58+
private func setupLayout() {
59+
let stackView = UIStackView(alignment: .top, spacing: 8, [
60+
UIStackView(axis: .vertical, alignment: .leading, spacing: 2, [
61+
titleLabel, detailsLabel
62+
]),
63+
featuredImageView
64+
])
65+
contentView.addSubview(stackView)
66+
stackView.pinEdges(insets: UIEdgeInsets(horizontal: 16, vertical: 8))
9967

100-
iPadReadableLeadingAnchor?.isActive = true
101-
iPadReadableTrailingAnchor?.isActive = true
68+
NSLayoutConstraint.activate([
69+
featuredImageView.widthAnchor.constraint(equalToConstant: Constants.imageSize.width),
70+
featuredImageView.heightAnchor.constraint(equalToConstant: Constants.imageSize.height),
71+
])
10272
}
10373

10474
private func configureFeaturedImage() {
75+
featuredImageView.prepareForReuse()
76+
10577
if let post, let url = post.featuredImageURL {
10678
featuredImageView.isHidden = false
10779

@@ -110,108 +82,15 @@ class PostCompactCell: UITableViewCell {
11082
WordPressAppDelegate.crashLogging?.logError(error)
11183
})
11284

113-
imageLoader.loadImage(with: url, from: host, preferredSize: CGSize(width: featuredImageView.frame.width, height: featuredImageView.frame.height))
85+
let targetSize = Constants.imageSize.scaled(by: traitCollection.displayScale)
86+
featuredImageView.setImage(with: url, host: host, size: targetSize)
11487
} else {
11588
featuredImageView.isHidden = true
11689
}
11790
}
11891

119-
private func configureTitle() {
120-
titleLabel.text = post?.titleForDisplay()
121-
}
122-
123-
private func configureDate() {
124-
guard let post else {
125-
return
126-
}
127-
128-
timestampLabel.text = post.latest().dateStringForDisplay()
129-
timestampLabel.isHidden = false
130-
}
131-
132-
private func configureExcerpt() {
133-
guard let post else {
134-
return
135-
}
136-
137-
timestampLabel.text = post.contentPreviewForDisplay()
138-
timestampLabel.isHidden = false
139-
}
140-
141-
private func configureStatus() {
142-
guard let viewModel else {
143-
return
144-
}
145-
badgesLabel.textColor = viewModel.statusColor
146-
badgesLabel.text = viewModel.statusAndBadges(separatedBy: Constants.separator)
147-
if badgesLabel.text?.isEmpty ?? true {
148-
badgesLabel.isHidden = true
149-
} else {
150-
badgesLabel.isHidden = false
151-
}
152-
}
153-
154-
private func configureMenuInteraction() {
155-
menuButton.isEnabled = true
156-
menuButton.alpha = 1.0
157-
}
158-
159-
private func setupAccessibility() {
160-
menuButton.accessibilityLabel =
161-
NSLocalizedString("More", comment: "Accessibility label for the More button in Post List (compact view).")
162-
}
163-
16492
private enum Constants {
165-
static let separator = " · "
166-
static let imageRadius: CGFloat = 2
167-
static let opacity: Float = 1
168-
static let margin: CGFloat = 16
169-
}
170-
}
171-
172-
extension PostCompactCell: GhostableView {
173-
func ghostAnimationWillStart() {
174-
toggleGhost(visible: true)
175-
menuButton.layer.opacity = GhostConstants.opacity
176-
}
177-
178-
private func toggleGhost(visible: Bool) {
179-
isUserInteractionEnabled = !visible
180-
menuButton.isGhostableDisabled = true
181-
separator.isGhostableDisabled = true
182-
ghostView.isHidden = !visible
183-
ghostView.backgroundColor = .secondarySystemGroupedBackground
184-
contentStackView.isHidden = visible
185-
}
186-
187-
private enum GhostConstants {
188-
static let opacity: Float = 0.5
189-
}
190-
}
191-
192-
extension PostCompactCell: NibReusable { }
193-
194-
// MARK: - For display on the Posts Card (Dashboard)
195-
196-
extension PostCompactCell {
197-
/// Configure the cell to be displayed in the Posts Card
198-
/// No "more" button and show a description, instead of a date
199-
func configureForDashboard(with post: Post) {
200-
configure(with: post)
201-
separator.isHidden = true
202-
menuButton.isHidden = true
203-
trailingContentConstraint.constant = Constants.margin
204-
headerStackView.spacing = Constants.margin
205-
206-
disableiPadReadableMargin()
207-
208-
if !post.isScheduled() {
209-
configureExcerpt()
210-
}
211-
}
212-
213-
func disableiPadReadableMargin() {
214-
iPadReadableLeadingAnchor?.isActive = false
215-
iPadReadableTrailingAnchor?.isActive = false
93+
static let imageRadius: CGFloat = 4
94+
static let imageSize = CGSize(width: 40, height: 40)
21695
}
21796
}

0 commit comments

Comments
 (0)