Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions Modules/Sources/JetpackStats/Screens/AdsTabView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import SwiftUI

public struct AdsTabView: View {

public init() {}

public var body: some View {
ScrollView {
VStack(spacing: 16) {
Text("Ads")
.font(.largeTitle)
.fontWeight(.bold)
.padding(.top, 20)

Text("Coming Soon")
.font(.headline)
.foregroundColor(.secondary)

Spacer(minLength: 100)
}
.padding()
}
}
}

#Preview {
AdsTabView()
}
7 changes: 2 additions & 5 deletions Modules/Sources/JetpackStats/Screens/StatsMainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,15 @@ public struct StatsMainView: View {
.onAppear {
context.tracker?.send(.trafficTabShown)
}
case .realtime:
RealtimeTabView()
.onAppear {
context.tracker?.send(.realtimeTabShown)
}
case .insights:
InsightsTabView()
case .subscribers:
SubscribersTabView()
.onAppear {
context.tracker?.send(.subscribersTabShown)
}
case .ads:
AdsTabView()
}
}

Expand Down
1 change: 1 addition & 0 deletions Modules/Sources/JetpackStats/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ enum Strings {
static let realtime = AppLocalizedString("jetpackStats.tabs.realtime", value: "Realtime", comment: "Realtime tab")
static let insights = AppLocalizedString("jetpackStats.tabs.insights", value: "Insights", comment: "Insights tab")
static let subscribers = AppLocalizedString("jetpackStats.tabs.subscribers", value: "Subscribers", comment: "Subscribers tab")
static let ads = AppLocalizedString("jetpackStats.tabs.ads", value: "Ads", comment: "Ads tab")
}

enum Calendar {
Expand Down
9 changes: 5 additions & 4 deletions Modules/Sources/JetpackStats/Views/StatsTabBar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,39 @@ import SwiftUI

enum StatsTab: CaseIterable {
case traffic
case realtime
case insights
case subscribers
case ads

var localizedTitle: String {
switch self {
case .traffic: return Strings.Tabs.traffic
case .realtime: return Strings.Tabs.realtime
case .insights: return Strings.Tabs.insights
case .subscribers: return Strings.Tabs.subscribers
case .ads: return Strings.Tabs.ads
}
}

var analyticsName: String {
switch self {
case .traffic: return "traffic"
case .realtime: return "realtime"
case .insights: return "insights"
case .subscribers: return "subscribers"
case .ads: return "ads"
}
}
}

struct StatsTabBar: View {
@Binding var selectedTab: StatsTab
var tabs: [StatsTab] = StatsTab.allCases
var showBackground: Bool = true

var body: some View {
VStack(spacing: 0) {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 18) {
ForEach(StatsTab.allCases, id: \.self) { tab in
ForEach(tabs, id: \.self) { tab in
tabButton(for: tab)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ import Foundation
"page_for_posts",
"blogging_prompts_settings",
"jetpack_connection_active_plugins",
"can_blaze"
"can_blaze",
"wordads"
]
for key in optionsDirectMapKeys {
if let value = response.value(forKeyPath: "options.\(key)") {
Expand Down
13 changes: 13 additions & 0 deletions Sources/WordPressData/Swift/Blog+Capabilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ extension Blog {
/// Enumeration that contains all of the Blog's available capabilities.
///
public enum Capability: String {
case ActivateWordAds = "activate_wordads"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not using it yet, but I decided to model it anyway since I spent a bit of time discovering it.

case DeleteOthersPosts = "delete_others_posts"
case DeletePosts = "delete_posts"
case EditOthersPages = "edit_others_pages"
Expand Down Expand Up @@ -71,6 +72,18 @@ extension Blog {
return isAdmin || isUserCapableOf(.ViewStats)
}

/// Returns true if the current user is allowed to use WordAds
///
@objc public func isWordAdsAllowed() -> Bool {
return isUserCapableOf(.ActivateWordAds)
}

/// Returns true if WordAds is actually active on the site
///
@objc public func isWordAdsActive() -> Bool {
return getOption(name: "wordads") ?? false
}

private func isUserCapableOf(_ capability: String) -> Bool {
return capabilities?[capability] as? Bool ?? false
}
Expand Down
4 changes: 4 additions & 0 deletions WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public enum FeatureFlag: Int, CaseIterable {
case intelligence
case newSupport
case nativeBlockInserter
case statsAds

/// Returns a boolean indicating if the feature is enabled.
///
Expand Down Expand Up @@ -86,6 +87,8 @@ public enum FeatureFlag: Int, CaseIterable {
return false
case .nativeBlockInserter:
return true
case .statsAds:
return BuildConfiguration.current == .debug
}
}

Expand Down Expand Up @@ -129,6 +132,7 @@ extension FeatureFlag {
case .intelligence: "Intelligence"
case .newSupport: "New Support"
case .nativeBlockInserter: "Native Block Inserter"
case .statsAds: "Stats Ads Tab"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public enum RemoteFeatureFlag: Int, CaseIterable {
case dotComWebLogin
case newGutenberg
case newGutenbergPlugins
case statsAds

var defaultValue: Bool {
let app = BuildSettings.current.brand
Expand Down Expand Up @@ -92,6 +93,8 @@ public enum RemoteFeatureFlag: Int, CaseIterable {
return app == .reader
case .newGutenbergPlugins:
return false
case .statsAds:
return false
}
}

Expand Down Expand Up @@ -154,6 +157,8 @@ public enum RemoteFeatureFlag: Int, CaseIterable {
return "gutenberg_kit"
case .newGutenbergPlugins:
return "gutenberg_kit_plugins"
case .statsAds:
return "stats_ads"
}
}

Expand Down Expand Up @@ -215,6 +220,8 @@ public enum RemoteFeatureFlag: Int, CaseIterable {
return "Experimental Block Editor"
case .newGutenbergPlugins:
return "Experimental Block Editor Plugins"
case .statsAds:
return "Stats Ads Tab"
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import WordPressUI
import Combine
import TipKit
import BuildSettingsKit
import JetpackStats

enum StatsTabType: Int, AdaptiveTabBarItem, CaseIterable {
case insights = 0
case traffic
case subscribers
case ads

var id: StatsTabType { self }

Expand All @@ -19,6 +21,7 @@ enum StatsTabType: Int, AdaptiveTabBarItem, CaseIterable {
case .insights: return NSLocalizedString("Insights", comment: "Title of Insights stats filter.")
case .traffic: return NSLocalizedString("stats.dashboard.tab.traffic", value: "Traffic", comment: "Title of Traffic stats tab.")
case .subscribers: return NSLocalizedString("stats.dashboard.tab.subscribers", value: "Subscribers", comment: "Title of Subscribers stats tab.")
case .ads: return NSLocalizedString("stats.dashboard.tab.ads", value: "Ads", comment: "Title of Ads stats tab.")
}
}

Expand All @@ -30,35 +33,54 @@ enum StatsTabType: Int, AdaptiveTabBarItem, CaseIterable {
self = .traffic
case "subscribers":
self = .subscribers
case "ads":
self = .ads
default:
return nil
}
}
}

fileprivate extension StatsTabType {
static var displayedTabs: [StatsTabType] {
return [.traffic, .insights, .subscribers]
}

var analyticsAccessEvent: WPAnalyticsStat? {
switch self {
case .insights: return .statsInsightsAccessed
case .traffic: return nil
case .traffic: return nil
case .subscribers: return .statsSubscribersAccessed
case .ads: return nil
}
}
}

public class SiteStatsDashboardViewController: UIViewController {
static let lastSelectedStatsDateKey = "LastSelectedStatsDate"

// MARK: - Helpers

/// Returns the current blog from SiteStatsInformation if available
private static func currentBlog() -> Blog? {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not ideal, but this is how this screen operates. I don't want to refactor it in the scope of this PR.

guard let siteID = SiteStatsInformation.sharedInstance.siteID,
let blog = Blog.lookup(withID: siteID, in: ContextManager.shared.mainContext) else {
return nil
}
return blog
}

// MARK: - Properties

private let containerView = UIView()

private var currentChildViewController: UIViewController?
private lazy var displayedTabs: [StatsTabType] = StatsTabType.displayedTabs
private lazy var displayedTabs: [StatsTabType] = {
var tabs: [StatsTabType] = [.traffic, .insights, .subscribers]

// Add Ads tab if feature flag is enabled and WordAds is active on the site
if FeatureFlag.statsAds.enabled,
let blog = Self.currentBlog(),
blog.isWordAdsActive() {
tabs.append(.ads)
}

return tabs
}()
private var tipObserver: TipObserver?
private var isUsingMockData = UITestConfigurator.isEnabled(.useMockData)
private var navigationItemObserver: NSKeyValueObservation?
Expand Down Expand Up @@ -100,8 +122,7 @@ public class SiteStatsDashboardViewController: UIViewController {
// Create with demo context for mock data
return StatsHostingViewController.makeNewTrafficViewController(blog: nil, parentViewController: self, isDemo: true)
} else {
guard let siteID = SiteStatsInformation.sharedInstance.siteID,
let blog = Blog.lookup(withID: siteID, in: ContextManager.shared.mainContext) else {
guard let blog = Self.currentBlog() else {
return nil
}
return StatsHostingViewController.makeNewTrafficViewController(blog: blog, parentViewController: self, isDemo: false)
Expand All @@ -126,6 +147,13 @@ public class SiteStatsDashboardViewController: UIViewController {
return StatsSubscribersViewController(viewModel: viewModel)
}()

private lazy var adsViewController: UIViewController = {
let adsView = AdsTabView()
let hostingController = UIHostingController(rootView: adsView)
hostingController.view.backgroundColor = .systemBackground
return hostingController
}()

// MARK: - View

deinit {
Expand Down Expand Up @@ -183,6 +211,8 @@ public class SiteStatsDashboardViewController: UIViewController {
self.showNewStatsTip()
}
}
case .ads:
parent?.navigationItem.rightBarButtonItem = nil
default:
parent?.navigationItem.rightBarButtonItem = nil
}
Expand Down Expand Up @@ -358,7 +388,7 @@ private extension SiteStatsDashboardViewController {
func setupFilterBar() {
wpAssert(parent != nil)
filterBarController.navigationItem = parent?.navigationItem
filterBarController.configure(StatsTabType.displayedTabs, in: self) { [weak self] in
filterBarController.configure(displayedTabs, in: self) { [weak self] in
self?.selectedFilterDidChange($0)
}
filterBarController.accessibilityIdentifier = "site-stats-dashboard-filter-bar"
Expand Down Expand Up @@ -429,6 +459,10 @@ private extension SiteStatsDashboardViewController {
} else {
subscribersViewController.refreshData()
}
case .ads:
if oldSelectedTab != .ads || containerIsEmpty {
showChildViewController(adsViewController)
}
}
}

Expand Down