Skip to content

Commit 81bc1c5

Browse files
authored
Stats: Improve scrolling performance (#22847)
2 parents 6dc78ec + 465047a commit 81bc1c5

File tree

7 files changed

+126
-42
lines changed

7 files changed

+126
-42
lines changed

RELEASE-NOTES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
25.2
22
-----
3+
4+
* [*] [Jetpack-only] Stats: Made optimizations to enhance scrolling performance. [#22847]
35
* [*] Simplify post list context menu sections [#23356]
46
* [*] Fix an issue with incorrect snackbar shown when saving drafts manually [#23358]
57

WordPress/Classes/ViewRelated/Stats/Extensions/UITableViewCell+Stats.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,4 @@ extension UITableViewCell {
7070
row.configure(statSection: statSection, delegate: delegate)
7171
rowsStackView.addArrangedSubview(row)
7272
}
73-
7473
}

WordPress/Classes/ViewRelated/Stats/Extensions/WPStyleGuide+Stats.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ extension WPStyleGuide {
7373
label.textColor = .DS.Foreground.secondary
7474
label.font = .DS.font(.footnote)
7575
label.adjustsFontSizeToFitWidth = true
76-
label.maximumContentSizeCategory = .accessibilityLarge
76+
label.maximumContentSizeCategory = .extraExtraExtraLarge
7777
}
7878

7979
static func configureLabelAsLink(_ label: UILabel) {

WordPress/Classes/ViewRelated/Stats/Period Stats/Countries/CountriesCell.swift

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import UIKit
22

3-
class CountriesCell: StatsBaseCell, NibLoadable {
3+
final class CountriesCell: StatsRowsCell, NibLoadable {
44

55
// MARK: - Properties
66

77
@IBOutlet weak var topSeparatorLine: UIView!
88
@IBOutlet weak var subtitleStackView: UIStackView!
9-
@IBOutlet weak var rowsStackView: UIStackView!
109
@IBOutlet weak var itemSubtitleLabel: UILabel!
1110
@IBOutlet weak var dataSubtitleLabel: UILabel!
1211
@IBOutlet weak var bottomSeparatorLine: UIView!
@@ -38,21 +37,24 @@ class CountriesCell: StatsBaseCell, NibLoadable {
3837
bottomSeparatorLine.isHidden = forDetails
3938

4039
if !forDetails {
41-
addRows(dataRows,
42-
toStackView: rowsStackView,
40+
configureTotalRows(
41+
dataRows,
42+
inStackView: rowsStackView,
4343
forType: .period,
44-
limitRowsDisplayed: true,
45-
viewMoreDelegate: self)
44+
configuration: .init(
45+
limitRowsDisplayed: true,
46+
rowDelegate: nil,
47+
referrerDelegate: nil,
48+
viewMoreDelegate: self
49+
)
50+
)
51+
} else {
52+
removeRowsFromStackView(rowsStackView)
4653
}
4754

4855
setSubtitleVisibility()
4956
applyStyles()
5057
}
51-
52-
override func prepareForReuse() {
53-
super.prepareForReuse()
54-
removeRowsFromStackView(rowsStackView)
55-
}
5658
}
5759

5860
private extension CountriesCell {
@@ -66,7 +68,6 @@ private extension CountriesCell {
6668
}
6769

6870
func setSubtitleVisibility() {
69-
subtitleStackView.layoutIfNeeded()
7071
let subtitleHeight = subtitlesStackViewTopConstraint.constant * 2 + subtitleStackView.frame.height
7172

7273
if forDetails {
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import Foundation
2+
3+
class StatsRowsCell: StatsBaseCell {
4+
struct StatsTotalRowConfiguration {
5+
let limitRowsDisplayed: Bool
6+
let rowDelegate: StatsTotalRowDelegate?
7+
let referrerDelegate: StatsTotalRowReferrerDelegate?
8+
let viewMoreDelegate: ViewMoreRowDelegate?
9+
}
10+
11+
@IBOutlet weak var rowsStackView: UIStackView!
12+
13+
override func awakeFromNib() {
14+
super.awakeFromNib()
15+
16+
addDefaultTotalRows(toStackView: rowsStackView)
17+
}
18+
19+
func configureTotalRows(_ dataRows: [StatsTotalRowData],
20+
inStackView rowsStackView: UIStackView,
21+
forType statType: StatType,
22+
configuration: StatsTotalRowConfiguration) {
23+
if rowsStackView.arrangedSubviews.isEmpty {
24+
addDefaultTotalRows(toStackView: rowsStackView)
25+
}
26+
27+
guard !dataRows.isEmpty else {
28+
configureForNoData(inStackView: rowsStackView, forType: statType)
29+
return
30+
}
31+
32+
let numberOfRowsToAdd = calculateNumberOfRowsToAdd(from: dataRows, withConfiguration: configuration)
33+
34+
rowsStackView.arrangedSubviews.enumerated().forEach { index, view in
35+
configure(view: view, at: index, in: dataRows, numberOfRowsToAdd: numberOfRowsToAdd, configuration: configuration)
36+
}
37+
}
38+
39+
private func addDefaultTotalRows(toStackView rowsStackView: UIStackView) {
40+
for _ in 0..<StatsDataHelper.maxRowsToDisplay {
41+
let row = StatsTotalRow.loadFromNib()
42+
rowsStackView.addArrangedSubview(row)
43+
}
44+
45+
let emptyRow = StatsNoDataRow.loadFromNib()
46+
rowsStackView.addArrangedSubview(emptyRow)
47+
48+
let viewMoreRow = ViewMoreRow.loadFromNib()
49+
rowsStackView.addArrangedSubview(viewMoreRow)
50+
}
51+
52+
private func configureForNoData(inStackView rowsStackView: UIStackView, forType statType: StatType) {
53+
rowsStackView.arrangedSubviews.forEach { view in
54+
if let emptyRow = view as? StatsNoDataRow {
55+
emptyRow.isHidden = false
56+
emptyRow.configure(forType: statType)
57+
} else {
58+
view.isHidden = true
59+
}
60+
}
61+
}
62+
63+
private func calculateNumberOfRowsToAdd(from dataRows: [StatsTotalRowData], withConfiguration configuration: StatsTotalRowConfiguration) -> Int {
64+
if configuration.limitRowsDisplayed {
65+
return min(dataRows.count, StatsDataHelper.maxRowsToDisplay)
66+
}
67+
return dataRows.count
68+
}
69+
70+
private func configure(view: UIView, at index: Int, in dataRows: [StatsTotalRowData], numberOfRowsToAdd: Int, configuration: StatsTotalRowConfiguration) {
71+
switch view {
72+
case let view as StatsNoDataRow:
73+
view.isHidden = true
74+
case let view as ViewMoreRow:
75+
configureViewMoreRow(view, at: index, in: dataRows, withConfiguration: configuration)
76+
case let view as StatsTotalRow where index < dataRows.count:
77+
view.isHidden = false
78+
let dataRow = dataRows[index]
79+
view.configure(rowData: dataRow, delegate: configuration.rowDelegate, referrerDelegate: configuration.referrerDelegate)
80+
view.showSeparator = index != (numberOfRowsToAdd - 1)
81+
default:
82+
view.isHidden = true
83+
}
84+
}
85+
86+
private func configureViewMoreRow(_ viewMoreRow: ViewMoreRow, at index: Int, in dataRows: [StatsTotalRowData], withConfiguration configuration: StatsTotalRowConfiguration) {
87+
let shouldShowViewMore = configuration.limitRowsDisplayed && dataRows.count > StatsDataHelper.maxRowsToDisplay
88+
viewMoreRow.isHidden = !shouldShowViewMore
89+
if shouldShowViewMore {
90+
viewMoreRow.configure(statSection: dataRows.first?.statSection, delegate: configuration.viewMoreDelegate)
91+
}
92+
}
93+
}

WordPress/Classes/ViewRelated/Stats/Shared Views/TopTotalsCell.swift

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@ import UIKit
77
/// If the row has child rows, those child rows are added to the stack view below the selected row.
88
///
99

10-
class TopTotalsCell: StatsBaseCell, NibLoadable {
10+
final class TopTotalsCell: StatsRowsCell, NibLoadable {
1111

1212
// MARK: - Properties
1313

1414
@IBOutlet weak var outerStackView: UIStackView!
1515
@IBOutlet weak var subtitleStackView: UIStackView!
16-
@IBOutlet weak var rowsStackView: UIStackView!
1716
@IBOutlet weak var itemSubtitleLabel: UILabel!
1817
@IBOutlet weak var dataSubtitleLabel: UILabel!
1918
@IBOutlet weak var dataSubtitleLabelWidthConstraint: NSLayoutConstraint!
@@ -77,41 +76,27 @@ class TopTotalsCell: StatsBaseCell, NibLoadable {
7776
self.forDetails = forDetails
7877

7978
if !forDetails {
80-
addRows(dataRows,
81-
toStackView: rowsStackView,
82-
forType: siteStatsPeriodDelegate != nil ? .period : .insights,
79+
configureTotalRows(
80+
dataRows,
81+
inStackView: rowsStackView,
82+
forType: siteStatsPeriodDelegate != nil ? .period : .insights,
83+
configuration: .init(
8384
limitRowsDisplayed: limitRowsDisplayed,
8485
rowDelegate: self,
8586
referrerDelegate: self,
86-
viewMoreDelegate: self)
87-
87+
viewMoreDelegate: self
88+
)
89+
)
8890
initChildRows()
91+
} else {
92+
rowsStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
8993
}
9094

9195
setSubtitleVisibility()
9296
applyStyles()
9397
prepareForVoiceOver()
9498
}
9599

96-
override func prepareForReuse() {
97-
super.prepareForReuse()
98-
99-
rowsStackView.arrangedSubviews.forEach { subview in
100-
101-
// Remove granchild rows
102-
if let row = subview as? StatsTotalRow {
103-
removeChildRowsForRow(row)
104-
}
105-
106-
// Remove child rows
107-
if let childView = subview as? StatsChildRowsView {
108-
removeRowsFromStackView(childView.rowsStackView)
109-
}
110-
}
111-
112-
removeRowsFromStackView(rowsStackView)
113-
}
114-
115100
private enum Metrics {
116101
static let topAccessoryViewSpacing: CGFloat = 32.0
117102
}
@@ -136,8 +121,6 @@ private extension TopTotalsCell {
136121
/// - Hide the stack view.
137122
///
138123
func setSubtitleVisibility() {
139-
subtitleStackView.layoutIfNeeded()
140-
141124
if forDetails {
142125
bottomSeparatorLine.isHidden = true
143126

WordPress/WordPress.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@
255255
01E70EBC2BB5CCCF000BFE45 /* NumberFormatter+Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E70EBA2BB5CCCF000BFE45 /* NumberFormatter+Stats.swift */; };
256256
01E70EBD2BB5D035000BFE45 /* NumberFormatter+Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E70EBA2BB5CCCF000BFE45 /* NumberFormatter+Stats.swift */; };
257257
01E78D1D296EA54F00FB6863 /* StatsPeriodHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E78D1C296EA54F00FB6863 /* StatsPeriodHelperTests.swift */; };
258+
01FB42F42C25651000F5069E /* StatsRowsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FB42F32C25651000F5069E /* StatsRowsCell.swift */; };
259+
01FB42F52C25651000F5069E /* StatsRowsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FB42F32C25651000F5069E /* StatsRowsCell.swift */; };
258260
02761EC02270072F009BAF0F /* BlogDetailsViewController+SectionHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02761EBF2270072F009BAF0F /* BlogDetailsViewController+SectionHelpers.swift */; };
259261
02761EC222700A9C009BAF0F /* BlogDetailsSubsectionToSectionCategoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02761EC122700A9C009BAF0F /* BlogDetailsSubsectionToSectionCategoryTests.swift */; };
260262
02761EC4227010BC009BAF0F /* BlogDetailsSectionIndexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02761EC3227010BC009BAF0F /* BlogDetailsSectionIndexTests.swift */; };
@@ -6056,6 +6058,7 @@
60566058
01E2580D2ACDC88100F09666 /* PlanWizardContentViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlanWizardContentViewModelTests.swift; sourceTree = "<group>"; };
60576059
01E70EBA2BB5CCCF000BFE45 /* NumberFormatter+Stats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NumberFormatter+Stats.swift"; sourceTree = "<group>"; };
60586060
01E78D1C296EA54F00FB6863 /* StatsPeriodHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsPeriodHelperTests.swift; sourceTree = "<group>"; };
6061+
01FB42F32C25651000F5069E /* StatsRowsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsRowsCell.swift; sourceTree = "<group>"; };
60596062
02761EBF2270072F009BAF0F /* BlogDetailsViewController+SectionHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BlogDetailsViewController+SectionHelpers.swift"; sourceTree = "<group>"; };
60606063
02761EC122700A9C009BAF0F /* BlogDetailsSubsectionToSectionCategoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlogDetailsSubsectionToSectionCategoryTests.swift; sourceTree = "<group>"; };
60616064
02761EC3227010BC009BAF0F /* BlogDetailsSectionIndexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlogDetailsSectionIndexTests.swift; sourceTree = "<group>"; };
@@ -14659,6 +14662,7 @@
1465914662
987535622282682D001661B4 /* DetailDataCell.xib */,
1466014663
DC9AF768285DF8A300EA2A0D /* StatsFollowersChartViewModel.swift */,
1466114664
1762B6DB2845510400F270A5 /* StatsReferrersChartViewModel.swift */,
14665+
01FB42F32C25651000F5069E /* StatsRowsCell.swift */,
1466214666
);
1466314667
path = "Stats Detail";
1466414668
sourceTree = "<group>";
@@ -23344,6 +23348,7 @@
2334423348
01B7590B2B3ED63B00179AE6 /* DomainDetailsWebViewControllerWrapper.swift in Sources */,
2334523349
0CB424F12ADEE52A0080B807 /* PostSearchToken.swift in Sources */,
2334623350
98AA6D1126B8CE7200920C8B /* Comment+CoreDataClass.swift in Sources */,
23351+
01FB42F42C25651000F5069E /* StatsRowsCell.swift in Sources */,
2334723352
7E4A773720F802A8001C706D /* ActivityRangesFactory.swift in Sources */,
2334823353
E1AC282D18282423004D394C /* SFHFKeychainUtils.m in Sources */,
2334923354
7EDAB3F420B046FE002D1A76 /* CircularProgressView+ActivityIndicatorType.swift in Sources */,
@@ -25340,6 +25345,7 @@
2534025345
F41E32FF287B47A500F89082 /* SuggestionsListViewModel.swift in Sources */,
2534125346
F4EDAA5129A795C600622D3D /* BlockedAuthor.swift in Sources */,
2534225347
FABB238E2602FC2C00C8785C /* NotificationSettingsService.swift in Sources */,
25348+
01FB42F52C25651000F5069E /* StatsRowsCell.swift in Sources */,
2534325349
019105872BE8BD6000CDFB16 /* StatsGhostSingleValueCell.swift in Sources */,
2534425350
8091019429078CFE00FCB4EA /* JetpackFullscreenOverlayViewController.swift in Sources */,
2534525351
FA347AEE26EB6E300096604B /* GrowAudienceCell.swift in Sources */,

0 commit comments

Comments
 (0)