Skip to content

Commit ae4e4d1

Browse files
authored
Reader: Improve stream headers (#23730)
* Improve stream headers * Remove leading inset for channels on iPhone * Enable accessibility for Reader headers * Fix background for channels in dark mode * Fix an issue with Reader menu not using large titles
1 parent 643bca2 commit ae4e4d1

File tree

10 files changed

+187
-86
lines changed

10 files changed

+187
-86
lines changed

WordPress/Classes/System/Root View/ReaderPresenter.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@ final class ReaderPresenter: NSObject, SplitViewDisplayable {
4040
sidebar.onViewDidLoad = { [weak self] in
4141
self?.showInitialSelection()
4242
}
43+
4344
sidebarViewModel.isCompact = true
4445
sidebarViewModel.restoreSelection(defaultValue: nil)
45-
mainNavigationController.navigationBar.prefersLargeTitles = true
4646
mainNavigationController = UINavigationController(rootViewController: sidebar) // Loads sidebar lazily
47+
mainNavigationController.navigationBar.prefersLargeTitles = true
4748
sidebar.navigationItem.backButtonDisplayMode = .minimal
4849
return mainNavigationController
4950
}

WordPress/Classes/ViewRelated/Reader/Cards/ReaderPostCell.swift

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,7 @@ final class ReaderPostCell: ReaderStreamBaseCell {
5151

5252
override func updateConstraints() {
5353
NSLayoutConstraint.deactivate(contentViewConstraints)
54-
contentViewConstraints = [
55-
view.leadingAnchor.constraint(equalTo: isCompact ? contentView.leadingAnchor : contentView.readableContentGuide.leadingAnchor),
56-
view.trailingAnchor.constraint(equalTo: isCompact ? contentView.trailingAnchor : contentView.readableContentGuide.trailingAnchor)
57-
]
58-
NSLayoutConstraint.activate(contentViewConstraints)
59-
54+
contentViewConstraints = view.pinEdges(.horizontal, to: isCompact ? contentView : contentView.readableContentGuide)
6055
super.updateConstraints()
6156
}
6257
}

WordPress/Classes/ViewRelated/Reader/Controllers/ReaderStreamViewController+Helper.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ extension ReaderStreamViewController {
1212

1313
func headerForStream(_ topic: ReaderAbstractTopic?, isLoggedIn: Bool, container: UITableViewController) -> UIView? {
1414
if let topic, ReaderHelpers.topicIsFollowing(topic) {
15-
return ReaderStreamTitleView.makeForFollowing()
15+
return ReaderHeaderView.makeForFollowing()
1616
}
1717
if let topic,
1818
let header = headerForStream(topic) {

WordPress/Classes/ViewRelated/Reader/Controllers/ReaderStreamViewController.swift

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,13 @@ import AutomatticTracks
198198

199199
var isEmbeddedInDiscover = false
200200

201+
private var isCompact = true {
202+
didSet {
203+
guard oldValue != isCompact else { return }
204+
didChangeIsCompact(isCompact)
205+
}
206+
}
207+
201208
// MARK: - Init
202209

203210
/// Convenience method for instantiating an instance of ReaderStreamViewController
@@ -275,6 +282,8 @@ import AutomatticTracks
275282
override func viewDidLoad() {
276283
super.viewDidLoad()
277284

285+
isCompact = traitCollection.horizontalSizeClass == .compact
286+
278287
// Setup Site Blocking Controller
279288
self.siteBlockingController.delegate = self
280289

@@ -353,6 +362,17 @@ import AutomatticTracks
353362
}
354363
}
355364

365+
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
366+
super.traitCollectionDidChange(previousTraitCollection)
367+
368+
isCompact = traitCollection.horizontalSizeClass == .compact
369+
}
370+
371+
private func didChangeIsCompact(_ isCompact: Bool) {
372+
(tableView.tableHeaderView as? ReaderBaseHeaderView)?.isCompact = isCompact
373+
tableView.reloadData()
374+
}
375+
356376
// MARK: - Topic acquisition
357377

358378
/// Fetches a site topic for the value of the `siteID` property.
@@ -471,6 +491,7 @@ import AutomatticTracks
471491
headerView.isHidden = tableHeaderView.isHidden
472492
}
473493

494+
(headerView as? ReaderBaseHeaderView)?.isCompact = isCompact
474495
tableView.tableHeaderView = headerView
475496
streamHeader = headerView as? ReaderStreamHeader
476497

@@ -1398,8 +1419,6 @@ extension ReaderStreamViewController: WPTableViewHandlerDelegate {
13981419
return cell
13991420
}
14001421

1401-
let isCompact = traitCollection.horizontalSizeClass == .compact
1402-
14031422
if post.isCross() {
14041423
let cell = tableConfiguration.crossPostCell(tableView)
14051424
cell.isCompact = isCompact

WordPress/Classes/ViewRelated/Reader/Headers/ReaderDiscoverHeaderView.swift

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ protocol ReaderDiscoverHeaderViewDelegate: AnyObject {
44
func readerDiscoverHeaderView(_ view: ReaderDiscoverHeaderView, didChangeSelection selection: ReaderDiscoverChannel)
55
}
66

7-
final class ReaderDiscoverHeaderView: UIView, UITextViewDelegate {
8-
private let titleView = ReaderStreamTitleView(insets: nil)
7+
final class ReaderDiscoverHeaderView: ReaderBaseHeaderView, UITextViewDelegate {
8+
private let titleView = ReaderTitleView()
99
private let channelsStackView = UIStackView(spacing: 8, [])
10+
private let scrollView = UIScrollView()
1011
private var channelViews: [ReaderDiscoverChannelView] = []
1112

1213
private var selectedChannel: ReaderDiscoverChannel?
@@ -16,16 +17,15 @@ final class ReaderDiscoverHeaderView: UIView, UITextViewDelegate {
1617
override init(frame: CGRect) {
1718
super.init(frame: frame)
1819

19-
let scrollView = UIScrollView()
2020
scrollView.addSubview(channelsStackView)
2121
scrollView.showsHorizontalScrollIndicator = false
2222
scrollView.clipsToBounds = false
2323
channelsStackView.pinEdges()
2424
scrollView.heightAnchor.constraint(equalTo: channelsStackView.heightAnchor).isActive = true
2525

2626
let stackView = UIStackView(axis: .vertical, spacing: 8, [titleView, scrollView])
27-
addSubview(stackView)
28-
stackView.pinEdges(insets: ReaderStreamTitleView.preferredInsets)
27+
contentView.addSubview(stackView)
28+
stackView.pinEdges()
2929

3030
titleView.titleLabel.text = SharedStrings.Reader.discover
3131
titleView.detailsTextView.attributedText = {
@@ -39,6 +39,8 @@ final class ReaderDiscoverHeaderView: UIView, UITextViewDelegate {
3939
return details
4040
}()
4141
titleView.detailsTextView.delegate = self
42+
43+
updateStyle()
4244
}
4345

4446
required init?(coder: NSCoder) {
@@ -60,6 +62,17 @@ final class ReaderDiscoverHeaderView: UIView, UITextViewDelegate {
6062
refreshChannelViews()
6163
}
6264

65+
override func didUpdateIsCompact(_ isCompact: Bool) {
66+
super.didUpdateIsCompact(isCompact)
67+
updateStyle()
68+
}
69+
70+
private func updateStyle() {
71+
scrollView.contentInset = UIEdgeInsets(.leading, isCompact ? 0 : -10) // Align the "channels"
72+
}
73+
74+
// MARK: Channels
75+
6376
private func makeChannelView(_ channel: ReaderDiscoverChannel) -> ReaderDiscoverChannelView {
6477
let view = ReaderDiscoverChannelView(channel: channel)
6578
view.button.addAction(UIAction { [weak self] _ in
@@ -119,6 +132,8 @@ private final class ReaderDiscoverChannelView: UIView {
119132

120133
textLabel.font = UIFont.preferredFont(forTextStyle: .subheadline).withWeight(.medium)
121134
textLabel.text = channel.localizedTitle
135+
textLabel.adjustsFontForContentSizeCategory = true
136+
textLabel.maximumContentSizeCategory = .accessibilityMedium
122137

123138
backgroundView.clipsToBounds = true
124139

@@ -138,7 +153,7 @@ private final class ReaderDiscoverChannelView: UIView {
138153
backgroundView.backgroundColor = UIColor.label
139154
textLabel.textColor = UIColor.systemBackground
140155
} else {
141-
backgroundView.backgroundColor = UIColor.opaqueSeparator.withAlphaComponent(0.33)
156+
backgroundView.backgroundColor = UIColor(light: UIColor.opaqueSeparator.withAlphaComponent(0.33), dark: UIColor.opaqueSeparator)
142157
textLabel.textColor = UIColor.label
143158
}
144159
}

WordPress/Classes/ViewRelated/Reader/Headers/ReaderStreamTitleView.swift

Lines changed: 0 additions & 70 deletions
This file was deleted.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import UIKit
2+
import WordPressUI
3+
4+
// A container view for stream headers.
5+
class ReaderBaseHeaderView: UIView {
6+
let contentView = UIView()
7+
8+
var isCompact: Bool = true {
9+
didSet {
10+
guard oldValue != isCompact else { return }
11+
didUpdateIsCompact(isCompact)
12+
}
13+
}
14+
15+
private var contentViewConstraints: [NSLayoutConstraint] = []
16+
17+
override init(frame: CGRect) {
18+
super.init(frame: frame)
19+
20+
addSubview(contentView)
21+
}
22+
23+
required init?(coder: NSCoder) {
24+
fatalError("init(coder:) has not been implemented")
25+
}
26+
27+
override func updateConstraints() {
28+
NSLayoutConstraint.deactivate(contentViewConstraints)
29+
contentViewConstraints = []
30+
31+
let insets = Self.makeInsets(isCompact: isCompact)
32+
contentViewConstraints += contentView.pinEdges(.horizontal, to: isCompact ? self : readableContentGuide, insets: insets)
33+
contentViewConstraints += contentView.pinEdges(.vertical, insets: insets)
34+
35+
super.updateConstraints()
36+
}
37+
38+
func didUpdateIsCompact(_ isCompact: Bool) {
39+
setNeedsUpdateConstraints()
40+
}
41+
42+
static func makeInsets(isCompact: Bool) -> UIEdgeInsets {
43+
UIEdgeInsets(
44+
top: 4, // To align with the large title on iPad
45+
left: isCompact ? 16 : ReaderStreamBaseCell.insets.left, // Align with the text in the feed
46+
bottom: 12, // Add spacing below
47+
right: 0
48+
)
49+
}
50+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import UIKit
2+
import WordPressUI
3+
4+
final class ReaderHeaderView: ReaderBaseHeaderView {
5+
let titleView = ReaderTitleView()
6+
7+
override init(frame: CGRect) {
8+
super.init(frame: frame)
9+
10+
contentView.addSubview(titleView)
11+
titleView.pinEdges()
12+
}
13+
14+
required init?(coder: NSCoder) {
15+
fatalError("init(coder:) has not been implemented")
16+
}
17+
}
18+
19+
extension ReaderHeaderView {
20+
static func makeForFollowing() -> ReaderHeaderView {
21+
let view = ReaderHeaderView()
22+
view.titleView.titleLabel.text = SharedStrings.Reader.recent
23+
view.titleView.detailsTextView.text = Strings.followingDetails
24+
return view
25+
}
26+
}
27+
28+
private enum Strings {
29+
static let followingDetails = NSLocalizedString("reader.following.header.details", value: "Stay current with the blogs you've subscribed to.", comment: "Screen header details")
30+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import UIKit
2+
import WordPressUI
3+
4+
/// A custom replacement for a navigation bar title view.
5+
final class ReaderNavigationCustomTitleView: UIView {
6+
let textLabel = UILabel()
7+
8+
override init(frame: CGRect) {
9+
super.init(frame: frame)
10+
11+
textLabel.font = WPStyleGuide.navigationBarStandardFont
12+
textLabel.alpha = 0
13+
14+
// The label has to be a subview of the title view because
15+
// navigation bar doesn't seem to allow you to change the alpha
16+
// of `navigationItem.titleView` itself.
17+
addSubview(textLabel)
18+
textLabel.pinEdges()
19+
}
20+
21+
required init?(coder: NSCoder) {
22+
fatalError("init(coder:) has not been implemented")
23+
}
24+
25+
func updateAlpha(in scrollView: UIScrollView) {
26+
let offsetY = scrollView.contentOffset.y
27+
if offsetY < 16 {
28+
textLabel.alpha = 0
29+
} else {
30+
let alpha = (offsetY - 16) / 24
31+
textLabel.alpha = max(0, min(1, alpha))
32+
}
33+
}
34+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import UIKit
2+
import WordPressUI
3+
4+
/// A Reader stream header with a large title and a description.
5+
final class ReaderTitleView: UIView {
6+
let titleLabel = UILabel()
7+
let detailsTextView = UITextView.makeLabel()
8+
9+
init() {
10+
super.init(frame: .zero)
11+
12+
titleLabel.font = UIFont.preferredFont(forTextStyle: .largeTitle).withWeight(.bold)
13+
titleLabel.adjustsFontForContentSizeCategory = true
14+
15+
detailsTextView.font = UIFont.preferredFont(forTextStyle: .subheadline)
16+
detailsTextView.textColor = .secondaryLabel
17+
detailsTextView.adjustsFontForContentSizeCategory = true
18+
19+
let stackView = UIStackView(axis: .vertical, alignment: .leading, [titleLabel, detailsTextView])
20+
addSubview(stackView)
21+
stackView.pinEdges()
22+
}
23+
24+
required init?(coder: NSCoder) {
25+
fatalError("init(coder:) has not been implemented")
26+
}
27+
}

0 commit comments

Comments
 (0)