Skip to content

Commit 7ea0fb2

Browse files
Merge pull request #18405 from wordpress-mobile/feature/dashboard-arch-refactor/base
My Site Dashboard: Refactor dashboard architecture and data source
2 parents 305202c + 2b86889 commit 7ea0fb2

30 files changed

Lines changed: 1632 additions & 1034 deletions

RELEASE-NOTES.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
19.8
22
-----
3-
3+
* [*] [internal] My Site Dashboard: Made some changes to the code architecture of the dashboard. The majority of the changes are related to the posts cards. It should have no visible changes but could cause regressions. Please test it by creating/trashing drafts and scheduled posts and testing that they appear correctly on the dashboard. [#18405]
44

55
19.7
66
-----
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Foundation
2+
3+
@propertyWrapper
4+
struct Atomic<Value> {
5+
6+
private var value: Value
7+
private let lock = NSLock()
8+
9+
init(wrappedValue value: Value) {
10+
self.value = value
11+
}
12+
13+
var wrappedValue: Value {
14+
get { return load() }
15+
set { store(newValue: newValue) }
16+
}
17+
18+
func load() -> Value {
19+
lock.lock()
20+
defer { lock.unlock() }
21+
return value
22+
}
23+
24+
mutating func store(newValue: Value) {
25+
lock.lock()
26+
defer { lock.unlock() }
27+
value = newValue
28+
}
29+
}

WordPress/Classes/Services/PostCoordinator+Dashboard.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ extension PostCoordinator {
1313
func notifyNewPostCreated() {
1414
NotificationCenter.default.post(name: .newPostCreated, object: nil)
1515
}
16+
17+
func notifyNewPostPublished() {
18+
NotificationCenter.default.post(name: .newPostPublished, object: nil)
19+
}
1620
}
1721

1822
extension NSNotification.Name {
@@ -21,4 +25,7 @@ extension NSNotification.Name {
2125

2226
/// Fired when a draft is saved
2327
static let newPostCreated = NSNotification.Name("NewPostCreated")
28+
29+
/// Fired when a post is published
30+
static let newPostPublished = NSNotification.Name("NewPostPublished")
2431
}

WordPress/Classes/Services/PostCoordinator.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ class PostCoordinator: NSObject {
242242

243243
if uploadedPost.isScheduled() {
244244
self?.notifyNewPostScheduled()
245+
} else if uploadedPost.isPublished() {
246+
self?.notifyNewPostPublished()
245247
}
246248

247249
SearchManager.shared.indexItem(uploadedPost)

WordPress/Classes/ViewRelated/Blog/Blog Dashboard/BlogDashboardViewController.swift

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ protocol BlogDashboardCardConfigurable {
1010
final class BlogDashboardViewController: UIViewController {
1111

1212
var blog: Blog
13+
var presentedPostStatus: String?
14+
1315
private let embeddedInScrollView: Bool
1416

1517
private lazy var viewModel: BlogDashboardViewModel = {
@@ -57,7 +59,6 @@ final class BlogDashboardViewController: UIViewController {
5759
addHeightObservers()
5860
addWillEnterForegroundObserver()
5961
addQuickStartObserver()
60-
addNewPostAvailableObserver()
6162
viewModel.viewDidLoad()
6263

6364
// Force the view to update its layout immediately, so the content size is calculated correctly
@@ -78,6 +79,10 @@ final class BlogDashboardViewController: UIViewController {
7879
stopAlertTimer()
7980
}
8081

82+
func reloadCardsLocally() {
83+
viewModel.loadCardsFromCache()
84+
}
85+
8186
/// If you want to give any feedback when the dashboard
8287
/// started loading just change this method.
8388
/// For not, it will be transparent
@@ -124,6 +129,7 @@ final class BlogDashboardViewController: UIViewController {
124129
private func setupCollectionView() {
125130
collectionView.isScrollEnabled = !embeddedInScrollView
126131
collectionView.backgroundColor = .listBackground
132+
collectionView.register(DashboardQuickActionsCardCell.self, forCellWithReuseIdentifier: DashboardQuickActionsCardCell.self.defaultReuseID)
127133
DashboardCard.allCases.forEach {
128134
collectionView.register($0.cell, forCellWithReuseIdentifier: $0.cell.defaultReuseID)
129135
}
@@ -144,10 +150,6 @@ final class BlogDashboardViewController: UIViewController {
144150
NotificationCenter.default.addObserver(self, selector: #selector(loadCardsFromCache), name: .QuickStartTourElementChangedNotification, object: nil)
145151
}
146152

147-
private func addNewPostAvailableObserver() {
148-
NotificationCenter.default.addObserver(self, selector: #selector(loadCardsFromCache), name: .newPostAvailableForDashboard, object: nil)
149-
}
150-
151153
@objc private func updateCollectionViewHeight(notification: Notification) {
152154
collectionView.collectionViewLayout.invalidateLayout()
153155
}
@@ -195,10 +197,9 @@ extension BlogDashboardViewController {
195197
let group = NSCollectionLayoutGroup.vertical(layoutSize: itemSize, subitems: [item])
196198

197199
let section = NSCollectionLayoutSection(group: group)
198-
let isQuickActionSection = viewModel.card(for: sectionIndex) == .quickActions
199-
let isLastSection = collectionView.numberOfSections == (sectionIndex + 1)
200+
let isQuickActionSection = viewModel.isQuickActionsSection(sectionIndex)
200201
let horizontalInset = isQuickActionSection ? 0 : Constants.horizontalSectionInset
201-
let bottomInset = isLastSection ? Constants.verticalSectionInset : 0
202+
let bottomInset = isQuickActionSection ? 0 : Constants.verticalSectionInset
202203
section.contentInsets = NSDirectionalEdgeInsets(top: Constants.verticalSectionInset,
203204
leading: horizontalInset,
204205
bottom: bottomInset,
@@ -264,7 +265,7 @@ extension BlogDashboardViewController {
264265
static let estimatedHeight: CGFloat = 44
265266
static let horizontalSectionInset: CGFloat = 20
266267
static let verticalSectionInset: CGFloat = 20
267-
static let cellSpacing: CGFloat = 24
268+
static let cellSpacing: CGFloat = 20
268269
}
269270
}
270271

WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/BlogDashboardNextPostView.swift renamed to WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/DashboardEmptyPostsCardCell.swift

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,31 @@
11
import UIKit
22

3-
/// View prompting the user to create their next post
4-
class BlogDashboardNextPostView: UIView {
3+
/// Card cell prompting the user to create their first post
4+
final class DashboardFirstPostCardCell: DashboardEmptyPostsCardCell, BlogDashboardCardConfigurable {
5+
func configure(blog: Blog, viewController: BlogDashboardViewController?, apiResponse: BlogDashboardRemoteEntity?) {
6+
super.configure(blog: blog, viewController: viewController, apiResponse: apiResponse, cardType: .createPost)
7+
}
8+
}
9+
10+
/// Card cell prompting the user to create their next post
11+
final class DashboardNextPostCardCell: DashboardEmptyPostsCardCell, BlogDashboardCardConfigurable {
12+
func configure(blog: Blog, viewController: BlogDashboardViewController?, apiResponse: BlogDashboardRemoteEntity?) {
13+
super.configure(blog: blog, viewController: viewController, apiResponse: apiResponse, cardType: .nextPost)
14+
}
15+
}
16+
17+
/// Card cell used when no posts are available to display
18+
class DashboardEmptyPostsCardCell: UICollectionViewCell, Reusable {
19+
20+
// MARK: Views
21+
22+
private lazy var frameView: BlogDashboardCardFrameView = {
23+
let frameView = BlogDashboardCardFrameView()
24+
frameView.translatesAutoresizingMaskIntoConstraints = false
25+
frameView.hideHeader()
26+
return frameView
27+
}()
28+
529
private lazy var mainStackView: UIStackView = {
630
let mainStackView = UIStackView()
731
mainStackView.translatesAutoresizingMaskIntoConstraints = false
@@ -54,20 +78,21 @@ class BlogDashboardNextPostView: UIView {
5478
return imageView
5579
}()
5680

57-
var onTap: (() -> Void)?
81+
// MARK: Private Variables
5882

59-
var hasPublishedPosts: Bool = true {
60-
didSet {
61-
titleLabel.text = hasPublishedPosts ? Strings.nextPostTitle : Strings.firstPostTitle
62-
descriptionLabel.text = hasPublishedPosts ? Strings.nextPostDescription : Strings.firstPostDescription
63-
}
64-
}
83+
/// The VC presenting this cell
84+
private weak var viewController: BlogDashboardViewController?
85+
private var blog: Blog?
86+
87+
// MARK: Initializers
6588

6689
override init(frame: CGRect) {
6790
super.init(frame: frame)
6891

69-
addSubview(mainStackView)
70-
pinSubviewToAllEdges(mainStackView)
92+
contentView.addSubview(frameView)
93+
contentView.pinSubviewToAllEdges(frameView, priority: Constants.constraintPriority)
94+
95+
frameView.add(subview: mainStackView)
7196

7297
mainStackView.addArrangedSubviews([
7398
contentStackView,
@@ -83,19 +108,58 @@ class BlogDashboardNextPostView: UIView {
83108
addGestureRecognizer(tap)
84109
}
85110

111+
required init?(coder: NSCoder) {
112+
fatalError("init(coder:) has not been implemented")
113+
}
114+
115+
// MARK: Actions
116+
86117
@objc private func promptTapped() {
87-
onTap?()
118+
presentEditor()
88119
}
120+
}
89121

90-
required init?(coder: NSCoder) {
91-
fatalError("init(coder:) has not been implemented")
122+
// MARK: BlogDashboardCardConfigurable
123+
124+
extension DashboardEmptyPostsCardCell {
125+
func configure(blog: Blog, viewController: BlogDashboardViewController?, apiResponse: BlogDashboardRemoteEntity?, cardType: DashboardCard) {
126+
self.blog = blog
127+
self.viewController = viewController
128+
129+
switch cardType {
130+
case .createPost:
131+
titleLabel.text = Strings.firstPostTitle
132+
descriptionLabel.text = Strings.firstPostDescription
133+
case .nextPost:
134+
titleLabel.text = Strings.nextPostTitle
135+
descriptionLabel.text = Strings.nextPostDescription
136+
default:
137+
assertionFailure("Cell used with wrong card type")
138+
return
139+
}
140+
141+
BlogDashboardAnalytics.shared.track(.dashboardCardShown, properties: ["type": "post", "sub_type": cardType.rawValue])
142+
}
143+
}
144+
145+
// MARK: Private Helpers
146+
147+
private extension DashboardEmptyPostsCardCell {
148+
func presentEditor() {
149+
let controller = viewController?.tabBarController as? WPTabBarController
150+
controller?.showPostTab()
92151
}
152+
}
153+
154+
// MARK: Constants
93155

156+
extension DashboardEmptyPostsCardCell {
94157
private enum Constants {
95158
static let horizontalSpacing: CGFloat = 16
96159
static let verticalSpacing: CGFloat = 10
97160
static let padding = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
98161
static let imageSize = CGSize(width: 70, height: 70)
162+
static let constraintPriority = UILayoutPriority(999)
99163
}
100164

101165
private enum Strings {

0 commit comments

Comments
 (0)