diff --git a/Podfile b/Podfile
index a5dda3b97bfc..93dd406677a9 100644
--- a/Podfile
+++ b/Podfile
@@ -56,7 +56,7 @@ end
def wordpress_kit
# pod 'WordPressKit', '~> 17.0.0'
- pod 'WordPressKit', git: 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', commit: '14aa53a2e1cfa764e3e9e3e91d1f39f4ef09e098'
+ pod 'WordPressKit', git: 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', commit: '77aee91d607cb8b86d4356c0aebfb3977ff1fcc7'
# pod 'WordPressKit', git: 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', branch: ''
# pod 'WordPressKit', git: 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', tag: ''
# pod 'WordPressKit', path: '../WordPressKit-iOS'
diff --git a/Podfile.lock b/Podfile.lock
index 84ba5bea8268..fa52f0297ff6 100644
--- a/Podfile.lock
+++ b/Podfile.lock
@@ -121,7 +121,7 @@ DEPENDENCIES:
- SwiftLint (= 0.54.0)
- WordPress-Editor-iOS (~> 1.19.11)
- WordPressAuthenticator (>= 9.0.8, ~> 9.0)
- - WordPressKit (from `https://github.com/wordpress-mobile/WordPressKit-iOS.git`, commit `14aa53a2e1cfa764e3e9e3e91d1f39f4ef09e098`)
+ - WordPressKit (from `https://github.com/wordpress-mobile/WordPressKit-iOS.git`, commit `77aee91d607cb8b86d4356c0aebfb3977ff1fcc7`)
- WordPressShared (from `https://github.com/wordpress-mobile/WordPress-iOS-Shared.git`, commit `688ee5e4efddc1fc23626626ef17b7e929bdafb0`)
- WordPressUI (~> 1.16)
- ZendeskSupportSDK (= 5.3.0)
@@ -177,7 +177,7 @@ EXTERNAL SOURCES:
Gutenberg:
:podspec: https://cdn.a8c-ci.services/gutenberg-mobile/Gutenberg-v1.117.0.podspec
WordPressKit:
- :commit: 14aa53a2e1cfa764e3e9e3e91d1f39f4ef09e098
+ :commit: 77aee91d607cb8b86d4356c0aebfb3977ff1fcc7
:git: https://github.com/wordpress-mobile/WordPressKit-iOS.git
WordPressShared:
:commit: 688ee5e4efddc1fc23626626ef17b7e929bdafb0
@@ -188,7 +188,7 @@ CHECKOUT OPTIONS:
:git: https://github.com/wordpress-mobile/FSInteractiveMap.git
:tag: 0.2.0
WordPressKit:
- :commit: 14aa53a2e1cfa764e3e9e3e91d1f39f4ef09e098
+ :commit: 77aee91d607cb8b86d4356c0aebfb3977ff1fcc7
:git: https://github.com/wordpress-mobile/WordPressKit-iOS.git
WordPressShared:
:commit: 688ee5e4efddc1fc23626626ef17b7e929bdafb0
@@ -239,6 +239,6 @@ SPEC CHECKSUMS:
ZendeskSupportSDK: 3a8e508ab1d9dd22dc038df6c694466414e037ba
ZIPFoundation: d170fa8e270b2a32bef9dcdcabff5b8f1a5deced
-PODFILE CHECKSUM: 4ac1d35f8415bdc8d4c8e39d6aa7a9f6dab5933d
+PODFILE CHECKSUM: 4bbf2ae7c80a5f39db237e7c3514872e9f7eb3ca
COCOAPODS: 1.15.2
diff --git a/WordPress/Classes/ViewRelated/Stats/Helpers/StatSection.swift b/WordPress/Classes/ViewRelated/Stats/Helpers/StatSection.swift
index 6c0c00c7ab24..5ae03b926140 100644
--- a/WordPress/Classes/ViewRelated/Stats/Helpers/StatSection.swift
+++ b/WordPress/Classes/ViewRelated/Stats/Helpers/StatSection.swift
@@ -34,6 +34,7 @@
case postStatsMonthsYears
case postStatsAverageViews
case postStatsRecentWeeks
+ case subscribersChart
case subscribersEmailsSummary
case subscribersList
@@ -144,6 +145,8 @@
return PostStatsHeaders.averageViewsPerDay
case .postStatsRecentWeeks:
return PostStatsHeaders.recentWeeks
+ case .subscribersChart:
+ return SubscribersHeaders.chart
case .subscribersEmailsSummary:
return SubscribersHeaders.emailsSummaryStats
case .subscribersList:
@@ -433,6 +436,7 @@
}
struct SubscribersHeaders {
+ static let chart = NSLocalizedString("stats.subscribers.chart.title", value: "Subscribers", comment: "Stats 'Subscribers' card header, contains chart")
static let emailsSummaryStats = NSLocalizedString("stats.subscribers.emailsSummaryCard.title", value: "Emails", comment: "Stats 'Emails' card header")
static let subscribersList = NSLocalizedString("stats.subscribers.subscribersListCard.title", value: "Subscribers", comment: "Stats 'Subscribers' card header")
}
diff --git a/WordPress/Classes/ViewRelated/Stats/SiteStatsTableViewCells.swift b/WordPress/Classes/ViewRelated/Stats/SiteStatsTableViewCells.swift
index 8c494c8c3052..0a1fa9fd74c1 100644
--- a/WordPress/Classes/ViewRelated/Stats/SiteStatsTableViewCells.swift
+++ b/WordPress/Classes/ViewRelated/Stats/SiteStatsTableViewCells.swift
@@ -77,6 +77,35 @@ struct ViewsVisitorsRow: StatsHashableImmuTableRow {
}
}
+struct SubscriberChartRow: StatsHashableImmuTableRow {
+ typealias CellType = StatsSubscribersChartCell
+
+ static let cell: ImmuTableCell = {
+ return ImmuTableCell.nib(CellType.defaultNib, CellType.self)
+ }()
+
+ let action: ImmuTableAction? = nil
+ let history: [StatsSubscribersSummaryData.SubscriberData]
+ let chartData: LineChartDataConvertible
+ let chartStyling: LineChartStyling
+ let xAxisDates: [Date]
+ let statSection: StatSection?
+
+ static func == (lhs: SubscriberChartRow, rhs: SubscriberChartRow) -> Bool {
+ return lhs.xAxisDates == rhs.xAxisDates &&
+ lhs.history == rhs.history
+ }
+
+ func configureCell(_ cell: UITableViewCell) {
+
+ guard let cell = cell as? CellType else {
+ return
+ }
+
+ cell.configure(row: self)
+ }
+}
+
struct CellHeaderRow: StatsHashableImmuTableRow {
typealias CellType = StatsCellHeader
diff --git a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersCache.swift b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersCache.swift
index 850b04af9197..c313a21efe7b 100644
--- a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersCache.swift
+++ b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersCache.swift
@@ -27,6 +27,10 @@ final class StatsSubscribersCache {
return .init(record: .subscribersEmailsSummary, key: "\(quantity) \(sortField) \(sortOrder)", siteID: siteId)
}
+ static func chartSummary(unit: String, siteId: NSNumber) -> CacheKey {
+ return .init(record: .subscribersChart, key: unit, siteID: siteId)
+ }
+
static func subscribersList(quantity: Int, siteId: NSNumber) -> CacheKey {
return .init(record: .subscribersList, key: "\(quantity)", siteID: siteId)
}
diff --git a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersChartCell.swift b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersChartCell.swift
new file mode 100644
index 000000000000..728d1cf49cd2
--- /dev/null
+++ b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersChartCell.swift
@@ -0,0 +1,57 @@
+
+import UIKit
+
+class StatsSubscribersChartCell: StatsBaseCell, NibLoadable {
+ private typealias Style = WPStyleGuide.Stats
+
+ @IBOutlet weak var chartView: UIView!
+
+ private var chartData: LineChartDataConvertible!
+ private var chartStyling: LineChartStyling!
+ private var xAxisDates: [Date]!
+
+ override func awakeFromNib() {
+ super.awakeFromNib()
+
+ Style.configureCell(self)
+ }
+
+ func configure(row: SubscriberChartRow) {
+ statSection = row.statSection
+
+ self.chartData = row.chartData
+ self.chartStyling = row.chartStyling
+ self.xAxisDates = row.xAxisDates
+
+ configureChartView()
+ }
+}
+
+private extension StatsSubscribersChartCell {
+
+ func configureChartView() {
+ let configuration = StatsLineChartConfiguration(data: chartData,
+ styling: chartStyling,
+ analyticsGranularity: .days,
+ indexToHighlight: 0,
+ xAxisDates: xAxisDates)
+ let lineChartView = StatsLineChartView(configuration: configuration)
+
+ resetChartContainerView()
+ chartView.addSubview(lineChartView)
+ chartView.accessibilityElements = [lineChartView]
+
+ NSLayoutConstraint.activate([
+ lineChartView.leadingAnchor.constraint(equalTo: chartView.leadingAnchor),
+ lineChartView.trailingAnchor.constraint(equalTo: chartView.trailingAnchor),
+ lineChartView.topAnchor.constraint(equalTo: chartView.topAnchor),
+ lineChartView.bottomAnchor.constraint(equalTo: chartView.bottomAnchor)
+ ])
+ }
+
+ func resetChartContainerView() {
+ for subview in chartView.subviews {
+ subview.removeFromSuperview()
+ }
+ }
+}
diff --git a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersChartCell.xib b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersChartCell.xib
new file mode 100644
index 000000000000..255292322f4a
--- /dev/null
+++ b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersChartCell.xib
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersLineChart.swift b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersLineChart.swift
new file mode 100644
index 000000000000..5a0eb66dcdda
--- /dev/null
+++ b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersLineChart.swift
@@ -0,0 +1,36 @@
+import Foundation
+import DGCharts
+
+private struct SubscriberLineChartData: LineChartDataConvertible {
+ let accessibilityDescription: String
+ let lineChartData: LineChartData
+}
+
+class StatsSubscribersLineChart {
+
+ let lineChartData: LineChartDataConvertible
+ let lineChartStyling: LineChartStyling
+
+ init(counts: [Int]) {
+ let chartEntries = counts.enumerated().map { index, count in
+ ChartDataEntry(x: Double(index), y: Double(count))
+ }
+ let dataSet = LineChartDataSet(entries: chartEntries)
+ let chartData = LineChartData(dataSets: [dataSet])
+ lineChartData = SubscriberLineChartData(accessibilityDescription: "Subscriber Charts", lineChartData: chartData)
+ lineChartStyling = SubscribersLineChartStyling()
+ }
+}
+
+// MARK: - StatsSubscribersLineChartStyling
+
+private struct SubscribersLineChartStyling: LineChartStyling {
+ let primaryLineColor: UIColor = UIColor(light: .muriel(name: .blue, .shade50), dark: .muriel(name: .blue, .shade50))
+ let secondaryLineColor: UIColor? = nil
+ let primaryHighlightColor: UIColor? = UIColor(red: 209.0/255.0, green: 209.0/255.0, blue: 214.0/255.0, alpha: 1.0)
+ let labelColor: UIColor = UIColor(light: .secondaryLabel, dark: .tertiaryLabel)
+ let legendColor: UIColor? = nil
+ let legendTitle: String? = nil
+ let lineColor: UIColor = .neutral(.shade5)
+ let yAxisValueFormatter: AxisValueFormatter = VerticalAxisFormatter()
+}
diff --git a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersStore.swift b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersStore.swift
index 119e6b9da308..f6eb8c0c521a 100644
--- a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersStore.swift
+++ b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersStore.swift
@@ -4,9 +4,11 @@ import WordPressKit
protocol StatsSubscribersStoreProtocol {
var emailsSummary: CurrentValueSubject, Never> { get }
+ var chartSummary: CurrentValueSubject, Never> { get }
var subscribersList: CurrentValueSubject, Never> { get }
func updateEmailsSummary(quantity: Int, sortField: StatsEmailsSummaryData.SortField)
+ func updateChartSummary()
func updateSubscribersList(quantity: Int)
}
@@ -16,6 +18,7 @@ struct StatsSubscribersStore: StatsSubscribersStoreProtocol {
private let statsService: StatsServiceRemoteV2
var emailsSummary: CurrentValueSubject, Never> = .init(.idle)
+ var chartSummary: CurrentValueSubject, Never> = .init(.idle)
var subscribersList: CurrentValueSubject, Never> = .init(.idle)
init() {
@@ -55,6 +58,34 @@ struct StatsSubscribersStore: StatsSubscribersStoreProtocol {
}
}
+ func updateChartSummary() {
+ guard chartSummary.value != .loading else { return }
+
+ let unit = StatsPeriodUnit.day
+ let cacheKey = StatsSubscribersCache.CacheKey.chartSummary(unit: unit.stringValue, siteId: siteID)
+ let cachedData: StatsSubscribersSummaryData? = cache.getValue(key: cacheKey)
+
+ if let cachedData = cachedData {
+ self.chartSummary.send(.success(cachedData))
+ } else {
+ chartSummary.send(.loading)
+ }
+
+ statsService.getData(for: unit, endingOn: StatsDataHelper.currentDateForSite(), limit: 30) { (data: StatsSubscribersSummaryData?, error: Error?) in
+ DispatchQueue.main.async {
+ if let data = data {
+ cache.setValue(data, key: cacheKey)
+ self.chartSummary.send(.success(data))
+ }
+ else {
+ if cachedData == nil {
+ self.chartSummary.send(.error)
+ }
+ }
+ }
+ }
+ }
+
// MARK: - Subscribers List
func updateSubscribersList(quantity: Int) {
diff --git a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersViewController.swift b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersViewController.swift
index ef38c88f60a6..d3dcef8bb80b 100644
--- a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersViewController.swift
+++ b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersViewController.swift
@@ -69,6 +69,7 @@ final class StatsSubscribersViewController: SiteStatsBaseTableViewController {
func tableRowTypes() -> [ImmuTableRow.Type] {
return [
+ SubscriberChartRow.self,
TopTotalsPeriodStatsRow.self,
StatsGhostTopImmutableRow.self,
StatsErrorRow.self
diff --git a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersViewModel.swift b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersViewModel.swift
index bfd93b4a5a36..59b3a9330319 100644
--- a/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersViewModel.swift
+++ b/WordPress/Classes/ViewRelated/Stats/Subscribers/StatsSubscribersViewModel.swift
@@ -14,6 +14,7 @@ final class StatsSubscribersViewModel {
}
func refreshData() {
+ store.updateChartSummary()
store.updateEmailsSummary(quantity: 10, sortField: .postId)
store.updateSubscribersList(quantity: 10)
}
@@ -21,7 +22,8 @@ final class StatsSubscribersViewModel {
// MARK: - Lifecycle
func addObservers() {
- Publishers.CombineLatest(
+ Publishers.CombineLatest3(
+ store.chartSummary.removeDuplicates(),
store.emailsSummary.removeDuplicates(),
store.subscribersList.removeDuplicates()
)
@@ -41,6 +43,7 @@ final class StatsSubscribersViewModel {
private extension StatsSubscribersViewModel {
func updateTableViewSnapshot() {
var snapshot = ImmuTableDiffableDataSourceSnapshot()
+ snapshot.addSection(chartRows())
snapshot.addSection(subscribersListRows())
snapshot.addSection(emailsSummaryRows())
tableViewSnapshot.send(snapshot)
@@ -55,6 +58,31 @@ private extension StatsSubscribersViewModel {
}
}
+// MARK: - Chart
+
+private extension StatsSubscribersViewModel {
+ func chartRows() -> [any StatsHashableImmuTableRow] {
+ switch store.chartSummary.value {
+ case .loading, .idle:
+ return loadingRows(.subscribersChart)
+ case .success(let chartSummary):
+ let xAxisDates = chartSummary.history.map { $0.date }
+ let viewsChart = StatsSubscribersLineChart(counts: chartSummary.history.map { $0.count })
+ return [
+ SubscriberChartRow(
+ history: chartSummary.history,
+ chartData: viewsChart.lineChartData,
+ chartStyling: viewsChart.lineChartStyling,
+ xAxisDates: xAxisDates,
+ statSection: .subscribersChart
+ )
+ ]
+ case .error:
+ return errorRows(.subscribersChart)
+ }
+ }
+}
+
// MARK: - Emails Summary
private extension StatsSubscribersViewModel {
diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj
index 92ef494bfe41..3b6955648276 100644
--- a/WordPress/WordPress.xcodeproj/project.pbxproj
+++ b/WordPress/WordPress.xcodeproj/project.pbxproj
@@ -2801,6 +2801,12 @@
B026DAB02A96D9E900995410 /* support_chat_error_handler.js in Resources */ = {isa = PBXBuildFile; fileRef = B026DAAF2A96D9E900995410 /* support_chat_error_handler.js */; };
B026DAB12A96D9E900995410 /* support_chat_error_handler.js in Resources */ = {isa = PBXBuildFile; fileRef = B026DAAF2A96D9E900995410 /* support_chat_error_handler.js */; };
B030FE0A27EBF0BC000F6F5E /* SiteCreationIntentTracksEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B030FE0927EBF0BC000F6F5E /* SiteCreationIntentTracksEventTests.swift */; };
+ B038A81C2BD70FCA00763731 /* StatsSubscribersChartCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B038A81B2BD70FCA00763731 /* StatsSubscribersChartCell.xib */; };
+ B038A81D2BD70FCA00763731 /* StatsSubscribersChartCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B038A81A2BD70FCA00763731 /* StatsSubscribersChartCell.swift */; };
+ B038A81E2BD70FCA00763731 /* StatsSubscribersChartCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B038A81A2BD70FCA00763731 /* StatsSubscribersChartCell.swift */; };
+ B038A81F2BD70FCA00763731 /* StatsSubscribersChartCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B038A81B2BD70FCA00763731 /* StatsSubscribersChartCell.xib */; };
+ B038A8212BD7164F00763731 /* StatsSubscribersLineChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = B038A8202BD7164F00763731 /* StatsSubscribersLineChart.swift */; };
+ B038A8222BD7164F00763731 /* StatsSubscribersLineChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = B038A8202BD7164F00763731 /* StatsSubscribersLineChart.swift */; };
B03B9234250BC593000A40AF /* SuggestionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B03B9233250BC593000A40AF /* SuggestionService.swift */; };
B03B9236250BC5FD000A40AF /* Suggestion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B03B9235250BC5FD000A40AF /* Suggestion.swift */; };
B0637527253E7CEC00FD45D2 /* SuggestionsTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0637526253E7CEB00FD45D2 /* SuggestionsTableView.swift */; };
@@ -8177,6 +8183,9 @@
AEE082892681C23C00DCF54B /* GutenbergRefactoredGalleryUploadProcessorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GutenbergRefactoredGalleryUploadProcessorTests.swift; sourceTree = ""; };
B026DAAF2A96D9E900995410 /* support_chat_error_handler.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = support_chat_error_handler.js; sourceTree = ""; };
B030FE0927EBF0BC000F6F5E /* SiteCreationIntentTracksEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteCreationIntentTracksEventTests.swift; sourceTree = ""; };
+ B038A81A2BD70FCA00763731 /* StatsSubscribersChartCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsSubscribersChartCell.swift; sourceTree = ""; };
+ B038A81B2BD70FCA00763731 /* StatsSubscribersChartCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StatsSubscribersChartCell.xib; sourceTree = ""; };
+ B038A8202BD7164F00763731 /* StatsSubscribersLineChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsSubscribersLineChart.swift; sourceTree = ""; };
B03B9233250BC593000A40AF /* SuggestionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionService.swift; sourceTree = ""; };
B03B9235250BC5FD000A40AF /* Suggestion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Suggestion.swift; sourceTree = ""; };
B0637526253E7CEB00FD45D2 /* SuggestionsTableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SuggestionsTableView.swift; path = Suggestions/SuggestionsTableView.swift; sourceTree = ""; };
@@ -9927,6 +9936,9 @@
01011E842BD27E47003B5C2B /* StatsSubscribersViewModel.swift */,
019C5B8C2BD6570D00A69DB0 /* StatsSubscribersStore.swift */,
019C5B932BD6917600A69DB0 /* StatsSubscribersCache.swift */,
+ B038A81A2BD70FCA00763731 /* StatsSubscribersChartCell.swift */,
+ B038A81B2BD70FCA00763731 /* StatsSubscribersChartCell.xib */,
+ B038A8202BD7164F00763731 /* StatsSubscribersLineChart.swift */,
);
path = Subscribers;
sourceTree = "";
@@ -19827,6 +19839,7 @@
1761F18226209AEE000815EF /* jetpack-green-icon-app-60x60@3x.png in Resources */,
83317ED92BC71CEB001AD2F4 /* ReaderTagCardCell.xib in Resources */,
FE3E83E626A58646008CE851 /* ListSimpleOverlayView.xib in Resources */,
+ B038A81C2BD70FCA00763731 /* StatsSubscribersChartCell.xib in Resources */,
401A3D022027DBD80099A127 /* PluginListCell.xib in Resources */,
17222D83261DDDF90047B163 /* celadon-classic-icon-app-60x60@2x.png in Resources */,
981C34912183871200FC2683 /* SiteStatsDashboard.storyboard in Resources */,
@@ -20309,6 +20322,7 @@
F46597B128E6605E00D5F49A /* neu-green-icon-app-76@2x.png in Resources */,
F41E4E9728F20802001880C6 /* white-on-pink-icon-app-76@2x.png in Resources */,
F41E4EB828F225DB001880C6 /* stroke-dark-icon-app-60@3x.png in Resources */,
+ B038A81F2BD70FCA00763731 /* StatsSubscribersChartCell.xib in Resources */,
F46597EA28E6698D00D5F49A /* spectrum-on-black-icon-app-76.png in Resources */,
98A047762821D069001B4E2D /* BloggingPromptsViewController.storyboard in Resources */,
F41E4ECF28F23E00001880C6 /* green-on-white-icon-app-83.5@2x.png in Resources */,
@@ -21955,6 +21969,7 @@
C7AFF87C283D5CF4000E01DF /* QRLoginVerifyCoordinator.swift in Sources */,
FA25FA212609AA9C0005E08F /* AppConfiguration.swift in Sources */,
83EF3D7B2937D703000AF9BF /* SharedDataIssueSolver.swift in Sources */,
+ B038A81D2BD70FCA00763731 /* StatsSubscribersChartCell.swift in Sources */,
436D55DB210F862A00CEAA33 /* NibReusable.swift in Sources */,
F49B9A09293A3243000CEFCE /* MigrationEvent.swift in Sources */,
98563DDD21BF30C40006F5E9 /* TabbedTotalsCell.swift in Sources */,
@@ -23288,6 +23303,7 @@
98E14A3C27C9712D007B0896 /* NotificationCommentDetailViewController.swift in Sources */,
9A8ECE122254A3260043C8DA /* JetpackRemoteInstallState.swift in Sources */,
40D7823A206AEA880015A3A1 /* Scheduler.swift in Sources */,
+ B038A8212BD7164F00763731 /* StatsSubscribersLineChart.swift in Sources */,
436D562E2117347C00CEAA33 /* RegisterDomainDetailsViewModel+RowDefinitions.swift in Sources */,
E6FACB1E1EC675E300284AC7 /* GravatarProfile.swift in Sources */,
D8212CB720AA7703008E8AE8 /* ReaderShareAction.swift in Sources */,
@@ -25017,6 +25033,7 @@
FABB22CF2602FC2C00C8785C /* AssembledSiteView.swift in Sources */,
FABB22D02602FC2C00C8785C /* ReaderTopicService+FollowedInterests.swift in Sources */,
FABB22D12602FC2C00C8785C /* ReaderRecommendedSiteCardCell.swift in Sources */,
+ B038A8222BD7164F00763731 /* StatsSubscribersLineChart.swift in Sources */,
FABB22D22602FC2C00C8785C /* PostEditorState.swift in Sources */,
FABB22D32602FC2C00C8785C /* UICollectionViewCell+Tint.swift in Sources */,
FABB22D42602FC2C00C8785C /* ManagedPerson+CoreDataProperties.swift in Sources */,
@@ -25637,6 +25654,7 @@
0CED200D2B68425A00E6DD52 /* WebKitView.swift in Sources */,
FABB247F2602FC2C00C8785C /* StockPhotosPageable.swift in Sources */,
FABB24802602FC2C00C8785C /* JetpackRestoreStatusViewController.swift in Sources */,
+ B038A81E2BD70FCA00763731 /* StatsSubscribersChartCell.swift in Sources */,
FABB24812602FC2C00C8785C /* BindableTapGestureRecognizer.swift in Sources */,
FABB24822602FC2C00C8785C /* ReaderSearchSuggestion.swift in Sources */,
DCF892CA282FA37100BB71E1 /* SiteStatsBaseTableViewController.swift in Sources */,
diff --git a/WordPress/WordPressTest/StatsSubscribersViewModelTests.swift b/WordPress/WordPressTest/StatsSubscribersViewModelTests.swift
index b31ef5ea41db..1d5e02906c62 100644
--- a/WordPress/WordPressTest/StatsSubscribersViewModelTests.swift
+++ b/WordPress/WordPressTest/StatsSubscribersViewModelTests.swift
@@ -24,17 +24,38 @@ final class StatsSubscribersViewModelTests: XCTestCase {
})
.store(in: &cancellables)
- store.emailsSummary.send(.loading)
+ store.chartSummary.send(.loading)
wait(for: [expectation], timeout: 1)
}
+ func testTableViewSnapshot_chartSummaryLoaded() throws {
+ let expectation = expectation(description: "Chart section should be loading")
+ var subscriberChartRow: SubscriberChartRow?
+ sut.tableViewSnapshot
+ .sink(receiveValue: { snapshot in
+ if let row = snapshot.itemIdentifiers[0].immuTableRow as? SubscriberChartRow {
+ subscriberChartRow = row
+ expectation.fulfill()
+ }
+ })
+ .store(in: &cancellables)
+ let chartSummary = StatsSubscribersSummaryData(history: [
+ .init(date: Date(), count: 1),
+ .init(date: Date(), count: 2),
+ ], period: .day, periodEndDate: Date())
+ store.chartSummary.send(.success(chartSummary))
+
+ wait(for: [expectation], timeout: 1)
+ XCTAssertNotNil(subscriberChartRow?.chartData)
+ }
+
func testTableViewSnapshot_subscribersListLoaded() throws {
let expectation = expectation(description: "First section should be TopTotalsPeriodStatsRow")
var subscribersListRow: TopTotalsPeriodStatsRow?
sut.tableViewSnapshot
.sink(receiveValue: { snapshot in
- if let row = snapshot.itemIdentifiers[0].immuTableRow as? TopTotalsPeriodStatsRow {
+ if let row = snapshot.itemIdentifiers[1].immuTableRow as? TopTotalsPeriodStatsRow {
subscribersListRow = row
expectation.fulfill()
}
@@ -59,7 +80,7 @@ final class StatsSubscribersViewModelTests: XCTestCase {
var emailsSummaryRow: TopTotalsPeriodStatsRow?
sut.tableViewSnapshot
.sink(receiveValue: { snapshot in
- if let row = snapshot.itemIdentifiers[1].immuTableRow as? TopTotalsPeriodStatsRow {
+ if let row = snapshot.itemIdentifiers[2].immuTableRow as? TopTotalsPeriodStatsRow {
emailsSummaryRow = row
expectation.fulfill()
}
@@ -82,14 +103,20 @@ final class StatsSubscribersViewModelTests: XCTestCase {
private class StatsSubscribersStoreMock: StatsSubscribersStoreProtocol {
var emailsSummary: CurrentValueSubject, Never> = .init(.idle)
+ var chartSummary: CurrentValueSubject, Never> = .init(.idle)
var subscribersList: CurrentValueSubject, Never> = .init(.idle)
var updateEmailsSummaryCalled = false
+ var updateChartSummaryCalled = false
var updateSubscribersListCalled = false
func updateEmailsSummary(quantity: Int, sortField: StatsEmailsSummaryData.SortField) {
updateEmailsSummaryCalled = true
}
+ func updateChartSummary() {
+ updateChartSummaryCalled = false
+ }
+
func updateSubscribersList(quantity: Int) {
updateSubscribersListCalled = true
}