Skip to content

Commit e64a372

Browse files
committed
Add new ReaderPostHeaderView
1 parent 133a907 commit e64a372

2 files changed

Lines changed: 657 additions & 0 deletions

File tree

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import UIKit
2+
3+
/// A mock post content view used in previews to simulate real article content
4+
/// below the `ReaderPostHeaderView`.
5+
@available(iOS 17, *)
6+
final class ReaderMockPostContentView: UIView {
7+
8+
private let textView = UITextView()
9+
10+
override init(frame: CGRect) {
11+
super.init(frame: frame)
12+
13+
textView.isEditable = false
14+
textView.isScrollEnabled = false
15+
textView.backgroundColor = .clear
16+
textView.adjustsFontForContentSizeCategory = true
17+
textView.textContainerInset = UIEdgeInsets(top: 8, left: 12, bottom: 16, right: 12)
18+
19+
addSubview(textView)
20+
textView.pinEdges()
21+
}
22+
23+
required init?(coder: NSCoder) {
24+
fatalError("init(coder:) has not been implemented")
25+
}
26+
27+
func apply(_ setting: ReaderDisplaySettings) {
28+
textView.attributedText = Self.makePostContent(with: setting)
29+
}
30+
31+
private static func makePostContent(with setting: ReaderDisplaySettings) -> NSAttributedString {
32+
let colors = setting.color
33+
let bodyFont = setting.font(with: .body)
34+
let headingFont = setting.font(with: .title3, weight: .bold)
35+
36+
let bodyParagraph = NSMutableParagraphStyle()
37+
bodyParagraph.lineSpacing = 4
38+
bodyParagraph.paragraphSpacing = 12
39+
40+
let headingParagraph = NSMutableParagraphStyle()
41+
headingParagraph.lineSpacing = 4
42+
headingParagraph.paragraphSpacing = 4
43+
headingParagraph.paragraphSpacingBefore = 8
44+
45+
let body: [NSAttributedString.Key: Any] = [
46+
.font: bodyFont,
47+
.foregroundColor: colors.foreground,
48+
.paragraphStyle: bodyParagraph
49+
]
50+
let heading: [NSAttributedString.Key: Any] = [
51+
.font: headingFont,
52+
.foregroundColor: colors.foreground,
53+
.paragraphStyle: headingParagraph
54+
]
55+
56+
let result = NSMutableAttributedString()
57+
result.append(NSAttributedString(string: "We love working with talented artists from around the world, and this year, we invited Cinta to capture Automattic's holiday spirit in an illustration for our holiday card. We're excited to introduce Cinta and share her wonderful work with you!\n", attributes: body))
58+
result.append(NSAttributedString(string: "How would you describe your artistic style in three words, and why those three?\n", attributes: heading))
59+
result.append(NSAttributedString(string: "Colorful, conceptual, and playful. I like combining strong visual impact with ideas that invite interpretation and a sense of joy.\n", attributes: body))
60+
result.append(NSAttributedString(string: "What draws you to your medium?\n", attributes: heading))
61+
result.append(NSAttributedString(string: "I'm drawn to traditional techniques such as ink on paper because drawing with brushes and a fluid medium like ink allows me to give the line a strong sense of expressiveness and texture. I enjoy working with the imperfections and unexpected accidents of analog processes, as they add a sense of soul and authenticity to the final illustration. I then apply color digitally, combining the warmth of traditional media with the flexibility of digital tools.", attributes: body))
62+
return result
63+
}
64+
}
65+
66+
// MARK: - ReaderPostHeaderPreviewController
67+
68+
@available(iOS 17, *)
69+
final class ReaderPostHeaderPreviewController: UIViewController {
70+
private let scrollView = UIScrollView()
71+
private let headerView = ReaderPostHeaderView()
72+
private let contentView = ReaderMockPostContentView()
73+
private let viewModel: ReaderPostHeaderView.ViewModel
74+
private var currentSetting = ReaderDisplaySettings.standard
75+
76+
init(viewModel: ReaderPostHeaderView.ViewModel) {
77+
self.viewModel = viewModel
78+
super.init(nibName: nil, bundle: nil)
79+
}
80+
81+
required init?(coder: NSCoder) {
82+
fatalError("init(coder:) has not been implemented")
83+
}
84+
85+
override func viewDidLoad() {
86+
super.viewDidLoad()
87+
88+
let stack = UIStackView(arrangedSubviews: [headerView, contentView])
89+
stack.axis = .vertical
90+
91+
view.addSubview(scrollView)
92+
scrollView.pinEdges()
93+
94+
scrollView.addSubview(stack)
95+
stack.pinEdges()
96+
stack.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
97+
98+
headerView.configure(with: viewModel)
99+
applyDisplaySetting(.standard)
100+
101+
navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "chevron.backward"), style: .plain, target: nil, action: nil)
102+
navigationItem.rightBarButtonItems = [
103+
UIBarButtonItem(image: UIImage(systemName: "ellipsis"), style: .plain, target: nil, action: nil),
104+
UIBarButtonItem(image: UIImage(systemName: "square.and.arrow.up"), style: .plain, target: nil, action: nil),
105+
]
106+
107+
toolbarItems = [
108+
UIBarButtonItem(systemItem: .flexibleSpace),
109+
UIBarButtonItem(title: currentSetting.color.label, menu: makeThemeMenu()),
110+
]
111+
}
112+
113+
override func viewWillAppear(_ animated: Bool) {
114+
super.viewWillAppear(animated)
115+
navigationController?.setToolbarHidden(false, animated: false)
116+
}
117+
118+
private func applyDisplaySetting(_ setting: ReaderDisplaySettings) {
119+
currentSetting = setting
120+
headerView.apply(setting)
121+
contentView.apply(setting)
122+
view.backgroundColor = setting.color.background
123+
scrollView.backgroundColor = setting.color.background
124+
}
125+
126+
private func makeThemeMenu() -> UIMenu {
127+
let colorActions = ReaderDisplaySettings.Color.allCases.map { color in
128+
UIAction(title: color.label, state: currentSetting.color == color ? .on : .off) { [weak self] _ in
129+
guard let self else { return }
130+
let setting = ReaderDisplaySettings(color: color, font: self.currentSetting.font, size: self.currentSetting.size)
131+
self.applyDisplaySetting(setting)
132+
self.toolbarItems?[1] = UIBarButtonItem(title: "Theme", menu: self.makeThemeMenu())
133+
}
134+
}
135+
return UIMenu(title: "Theme", children: colorActions)
136+
}
137+
}

0 commit comments

Comments
 (0)