From 1c8dc6f77b6fc1ce1b0dd40f91902f30e53d12e4 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 20 Jun 2025 10:33:37 -0400 Subject: [PATCH 1/4] Remove BackupListViewController and use ActivityLogsViewController instead - Delete BackupListViewController.swift and its extension - Update showBackup() to use ActivityLogsViewController with isBackupMode - Remove BackupListViewController reference from ActivityDetailViewController - Implement displayBackupWithSiteID using ActivityLogsViewController - Add WPAnalytics tracking to ContentCoordinator backup display --- .../Classes/Utility/ContentCoordinator.swift | 10 ++-- .../ActivityDetailViewController.swift | 2 - ...ntroller+JetpackBannerViewController.swift | 19 ------- .../Backup/BackupListViewController.swift | 52 ------------------- .../BlogDetailsViewController+Swift.swift | 13 +---- 5 files changed, 9 insertions(+), 87 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Activity/Backup/BackupListViewController+JetpackBannerViewController.swift delete mode 100644 WordPress/Classes/ViewRelated/Activity/Backup/BackupListViewController.swift diff --git a/WordPress/Classes/Utility/ContentCoordinator.swift b/WordPress/Classes/Utility/ContentCoordinator.swift index 3abf0f4f4658..bbc5259ef6cf 100644 --- a/WordPress/Classes/Utility/ContentCoordinator.swift +++ b/WordPress/Classes/Utility/ContentCoordinator.swift @@ -1,4 +1,5 @@ import UIKit +import WordPressShared protocol ContentCoordinator { func displayReaderWithPostId(_ postID: NSNumber?, siteID: NSNumber?) throws @@ -84,13 +85,16 @@ struct DefaultContentCoordinator: ContentCoordinator { func displayBackupWithSiteID(_ siteID: NSNumber?) throws { guard let siteID, - let blog = Blog.lookup(withID: siteID, in: mainContext), - let backupListViewController = BackupListViewController.withJPBannerForBlog(blog) + let blog = Blog.lookup(withID: siteID, in: mainContext) else { throw DisplayError.missingParameter } - controller?.navigationController?.pushViewController(backupListViewController, animated: true) + let backupViewController = ActivityLogsViewController(blog: blog, isBackupMode: true) + backupViewController.navigationItem.largeTitleDisplayMode = .never + controller?.navigationController?.pushViewController(backupViewController, animated: true) + + WPAnalytics.track(.backupListOpened) } func displayScanWithSiteID(_ siteID: NSNumber?) throws { diff --git a/WordPress/Classes/ViewRelated/Activity/ActivityDetailViewController.swift b/WordPress/Classes/ViewRelated/Activity/ActivityDetailViewController.swift index ea57c336dcd2..b1f2bd77f961 100644 --- a/WordPress/Classes/ViewRelated/Activity/ActivityDetailViewController.swift +++ b/WordPress/Classes/ViewRelated/Activity/ActivityDetailViewController.swift @@ -286,8 +286,6 @@ class ActivityDetailViewController: UIViewController, StoryboardLoadable { private func presentedFrom() -> String { if presenter is JetpackActivityLogViewController { return "activity_log" - } else if presenter is BackupListViewController { - return "backup" } else if presenter is DashboardActivityLogCardCell { return "dashboard" } else { diff --git a/WordPress/Classes/ViewRelated/Activity/Backup/BackupListViewController+JetpackBannerViewController.swift b/WordPress/Classes/ViewRelated/Activity/Backup/BackupListViewController+JetpackBannerViewController.swift deleted file mode 100644 index da57ead27822..000000000000 --- a/WordPress/Classes/ViewRelated/Activity/Backup/BackupListViewController+JetpackBannerViewController.swift +++ /dev/null @@ -1,19 +0,0 @@ -import UIKit - -extension BackupListViewController { - @objc - static func withJPBannerForBlog(_ blog: Blog) -> UIViewController? { - guard let backupListVC = BackupListViewController(blog: blog) else { - return nil - } - backupListVC.navigationItem.largeTitleDisplayMode = .never - return JetpackBannerWrapperViewController(childVC: backupListVC, screen: .backup) - } - - override func scrollViewDidScroll(_ scrollView: UIScrollView) { - super.scrollViewDidScroll(scrollView) - if let jetpackBannerWrapper = parent as? JetpackBannerWrapperViewController { - jetpackBannerWrapper.processJetpackBannerVisibility(scrollView) - } - } -} diff --git a/WordPress/Classes/ViewRelated/Activity/Backup/BackupListViewController.swift b/WordPress/Classes/ViewRelated/Activity/Backup/BackupListViewController.swift deleted file mode 100644 index b14533ba8b5f..000000000000 --- a/WordPress/Classes/ViewRelated/Activity/Backup/BackupListViewController.swift +++ /dev/null @@ -1,52 +0,0 @@ -import Foundation -import Combine -import WordPressShared - -class BackupListViewController: BaseActivityListViewController { - - override init(site: JetpackSiteRef, store: ActivityStore, isFreeWPCom: Bool = false) { - store.onlyRestorableItems = true - - let activityListConfiguration = ActivityListConfiguration( - identifier: "backup", - title: NSLocalizedString("Backup", comment: "Title for the Jetpack's backup list"), - loadingTitle: NSLocalizedString("Loading Backups...", comment: "Text displayed while loading the activity feed for a site"), - noActivitiesTitle: NSLocalizedString("Your first backup will be ready soon", comment: "Title for the view when there aren't any Backups to display"), - noActivitiesSubtitle: NSLocalizedString("Your first backup will appear here within 24 hours and you will receive a notification once the backup has been completed", comment: "Text displayed in the view when there aren't any Backups to display"), - noMatchingTitle: NSLocalizedString("No matching backups found", comment: "Title for the view when there aren't any backups to display for a given filter."), - noMatchingSubtitle: NSLocalizedString("Try adjusting your date range filter", comment: "Text displayed in the view when there aren't any backups to display for a given filter."), - filterbarRangeButtonTapped: .backupFilterbarRangeButtonTapped, - filterbarSelectRange: .backupFilterbarSelectRange, - filterbarResetRange: .backupFilterbarResetRange, - numberOfItemsPerPage: 100 - ) - - super.init(site: site, store: store, configuration: activityListConfiguration, isFreeWPCom: isFreeWPCom) - - activityTypeFilterChip.isHidden = true - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - @objc convenience init?(blog: Blog) { - precondition(blog.dotComID != nil) - guard let siteRef = JetpackSiteRef(blog: blog) else { - return nil - } - - let isFreeWPCom = blog.isHostedAtWPcom && !blog.hasPaidPlan - self.init(site: siteRef, store: StoreContainer.shared.activity, isFreeWPCom: isFreeWPCom) - } - - // MARK: - View lifecycle - - override func viewDidLoad() { - super.viewDidLoad() - - tableView.accessibilityIdentifier = "jetpack-backup-table" - - WPAnalytics.track(.backupListOpened) - } -} diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift index 88687d8a0329..420707edda15 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift @@ -182,17 +182,8 @@ extension BlogDetailsViewController { } @objc public func showBackup() { - let controller: UIViewController - - if FeatureFlag.dataViews.enabled { - controller = ActivityLogsViewController(blog: blog, isBackupMode: true) - controller.navigationItem.largeTitleDisplayMode = .never - } else { - guard let backupListVC = BackupListViewController.withJPBannerForBlog(blog) else { - return wpAssertionFailure("failed to instantiate") - } - controller = backupListVC - } + let controller = ActivityLogsViewController(blog: blog, isBackupMode: true) + controller.navigationItem.largeTitleDisplayMode = .never presentationDelegate?.presentBlogDetailsViewController(controller) From 10e878ac7a1645cf28a5c697393d303e1b2449c6 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 20 Jun 2025 10:36:32 -0400 Subject: [PATCH 2/4] Remove JetpackActivityLogViewController and use ActivityLogsViewController - Delete JetpackActivityLogViewController.swift - Update showActivity() methods to use ActivityLogsViewController directly - Update ActivityDetailViewController to check for ActivityLogsViewController - Simplify DashboardActivityLogCardCell to use ActivityLogsViewController --- .../ActivityDetailViewController.swift | 2 +- .../JetpackActivityLogViewController.swift | 63 ------------------- .../DashboardActivityLogCardCell.swift | 11 +--- .../BlogDetailsViewController+Swift.swift | 11 +--- 4 files changed, 3 insertions(+), 84 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Activity/JetpackActivityLogViewController.swift diff --git a/WordPress/Classes/ViewRelated/Activity/ActivityDetailViewController.swift b/WordPress/Classes/ViewRelated/Activity/ActivityDetailViewController.swift index b1f2bd77f961..23cb6f7eaad2 100644 --- a/WordPress/Classes/ViewRelated/Activity/ActivityDetailViewController.swift +++ b/WordPress/Classes/ViewRelated/Activity/ActivityDetailViewController.swift @@ -284,7 +284,7 @@ class ActivityDetailViewController: UIViewController, StoryboardLoadable { } private func presentedFrom() -> String { - if presenter is JetpackActivityLogViewController { + if presenter is ActivityLogsViewController { return "activity_log" } else if presenter is DashboardActivityLogCardCell { return "dashboard" diff --git a/WordPress/Classes/ViewRelated/Activity/JetpackActivityLogViewController.swift b/WordPress/Classes/ViewRelated/Activity/JetpackActivityLogViewController.swift deleted file mode 100644 index eef433e3fa7b..000000000000 --- a/WordPress/Classes/ViewRelated/Activity/JetpackActivityLogViewController.swift +++ /dev/null @@ -1,63 +0,0 @@ -import UIKit -import Combine - -class JetpackActivityLogViewController: BaseActivityListViewController { - private let jetpackBannerView = JetpackBannerView() - let scrollViewTranslationPublisher = PassthroughSubject() - - override init(site: JetpackSiteRef, store: ActivityStore, isFreeWPCom: Bool = false) { - store.onlyRestorableItems = false - - let activityListConfiguration = ActivityListConfiguration( - identifier: "activity_log", - title: NSLocalizedString("Activity", comment: "Title for the activity list"), - loadingTitle: NSLocalizedString("Loading Activities...", comment: "Text displayed while loading the activity feed for a site"), - noActivitiesTitle: NSLocalizedString("No activity yet", comment: "Title for the view when there aren't any Activities to display in the Activity Log"), - noActivitiesSubtitle: NSLocalizedString("When you make changes to your site you'll be able to see your activity history here.", comment: "Text display when the view when there aren't any Activities to display in the Activity Log"), - noMatchingTitle: NSLocalizedString("No matching events found.", comment: "Title for the view when there aren't any Activities to display in the Activity Log for a given filter."), - noMatchingSubtitle: NSLocalizedString("Try adjusting your date range or activity type filters", comment: "Text display when the view when there aren't any Activities to display in the Activity Log for a given filter."), - filterbarRangeButtonTapped: .activitylogFilterbarRangeButtonTapped, - filterbarSelectRange: .activitylogFilterbarSelectRange, - filterbarResetRange: .activitylogFilterbarResetRange, - numberOfItemsPerPage: 20 - ) - - super.init(site: site, store: store, configuration: activityListConfiguration, isFreeWPCom: isFreeWPCom) - - if JetpackBrandingVisibility.all.enabled { - configureBanner() - } - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - @objc convenience init?(blog: Blog) { - precondition(blog.dotComID != nil) - guard let siteRef = JetpackSiteRef(blog: blog) else { - return nil - } - let isFreeWPCom = blog.isHostedAtWPcom && !blog.hasPaidPlan - self.init(site: siteRef, store: StoreContainer.shared.activity, isFreeWPCom: isFreeWPCom) - } - - // MARK: - View lifecycle - - private func configureBanner() { - containerStackView.addArrangedSubview(jetpackBannerView) - addTranslationObserver(jetpackBannerView) - let textProvider = JetpackBrandingTextProvider(screen: JetpackBannerScreen.activityLog) - jetpackBannerView.configure(title: textProvider.brandingText()) { [unowned self] in - JetpackBrandingCoordinator.presentOverlay(from: self) - JetpackBrandingAnalyticsHelper.trackJetpackPoweredBannerTapped(screen: .activityLog) - } - } -} - -extension JetpackActivityLogViewController: JPScrollViewDelegate { - override func scrollViewDidScroll(_ scrollView: UIScrollView) { - super.scrollViewDidScroll(scrollView) - processJetpackBannerVisibility(scrollView) - } -} diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Activity Log/DashboardActivityLogCardCell.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Activity Log/DashboardActivityLogCardCell.swift index 7af6e6a902e0..07d230a3a635 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Activity Log/DashboardActivityLogCardCell.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Activity Log/DashboardActivityLogCardCell.swift @@ -144,16 +144,7 @@ final class DashboardActivityLogCardCell: DashboardCollectionViewCell { // MARK: - Navigation private func showActivityLog(for blog: Blog, tapSource: String) { - let activityLogController: UIViewController - - if FeatureFlag.dataViews.enabled { - activityLogController = ActivityLogsViewController(blog: blog) - } else if let jetpackController = JetpackActivityLogViewController(blog: blog) { - activityLogController = jetpackController - } else { - return - } - + let activityLogController = ActivityLogsViewController(blog: blog) presentingViewController?.navigationController?.pushViewController(activityLogController, animated: true) WPAnalytics.track(.activityLogViewed, withProperties: [WPAppAnalyticsKeyTapSource: tapSource]) diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift index 420707edda15..61c4494166ca 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift @@ -149,16 +149,7 @@ extension BlogDetailsViewController { } @objc public func showActivity() { - let controller: UIViewController - - if FeatureFlag.dataViews.enabled { - controller = ActivityLogsViewController(blog: blog) - } else if let jetpackController = JetpackActivityLogViewController(blog: blog) { - controller = jetpackController - } else { - return wpAssertionFailure("failed to instantiate") - } - + let controller = ActivityLogsViewController(blog: blog) controller.navigationItem.largeTitleDisplayMode = .never presentationDelegate?.presentBlogDetailsViewController(controller) From cedbc2cb6f0e516ee503de9a8045217dcc765d56 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 20 Jun 2025 10:39:18 -0400 Subject: [PATCH 3/4] Remove dataViews feature flag - Remove dataViews case from FeatureFlag enum - Remove dataViews from enabled property switch statement - Remove dataViews description The feature flag was already removed from usage in previous commits where we removed JetpackActivityLogViewController and BackupListViewController. --- WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift b/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift index 2712f8ca9f3a..79fce8ba652b 100644 --- a/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift +++ b/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift @@ -25,7 +25,6 @@ public enum FeatureFlag: Int, CaseIterable { case pluginManagementOverhaul case nativeJetpackConnection case newsletterSubscribers - case dataViews /// Returns a boolean indicating if the feature is enabled. /// @@ -82,8 +81,6 @@ public enum FeatureFlag: Int, CaseIterable { return BuildConfiguration.current == .debug case .newsletterSubscribers: return true - case .dataViews: - return BuildConfiguration.current == .debug } } @@ -127,7 +124,6 @@ extension FeatureFlag { case .readerGutenbergCommentComposer: "Gutenberg Comment Composer" case .nativeJetpackConnection: "Native Jetpack Connection" case .newsletterSubscribers: "Newsletter Subscribers" - case .dataViews: "Data Views" } } } From cc1719cadb10dc77eeef827bf1ae6d97e17400d0 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 20 Jun 2025 10:45:55 -0400 Subject: [PATCH 4/4] Create separate BackupsViewController and remove isBackupMode from ActivityLogsViewController - Create new BackupsViewController and BackupsView that reuses ActivityLogsView - Remove isBackupMode parameter from ActivityLogsViewController - Update all usages to use BackupsViewController for backups - Update ActivityDetailViewController to recognize BackupsViewController presenter - Keep ActivityLogsView and ActivityLogsViewModel unchanged as implementation details --- .../Classes/Utility/ContentCoordinator.swift | 2 +- .../ActivityDetailViewController.swift | 2 ++ .../List/ActivityLogsViewController.swift | 13 +++++------ .../Activity/List/BackupsViewController.swift | 22 +++++++++++++++++++ .../BlogDetailsViewController+Swift.swift | 2 +- 5 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 WordPress/Classes/ViewRelated/Activity/List/BackupsViewController.swift diff --git a/WordPress/Classes/Utility/ContentCoordinator.swift b/WordPress/Classes/Utility/ContentCoordinator.swift index bbc5259ef6cf..abe1de9b61ae 100644 --- a/WordPress/Classes/Utility/ContentCoordinator.swift +++ b/WordPress/Classes/Utility/ContentCoordinator.swift @@ -90,7 +90,7 @@ struct DefaultContentCoordinator: ContentCoordinator { throw DisplayError.missingParameter } - let backupViewController = ActivityLogsViewController(blog: blog, isBackupMode: true) + let backupViewController = BackupsViewController(blog: blog) backupViewController.navigationItem.largeTitleDisplayMode = .never controller?.navigationController?.pushViewController(backupViewController, animated: true) diff --git a/WordPress/Classes/ViewRelated/Activity/ActivityDetailViewController.swift b/WordPress/Classes/ViewRelated/Activity/ActivityDetailViewController.swift index 23cb6f7eaad2..e3c60142123c 100644 --- a/WordPress/Classes/ViewRelated/Activity/ActivityDetailViewController.swift +++ b/WordPress/Classes/ViewRelated/Activity/ActivityDetailViewController.swift @@ -286,6 +286,8 @@ class ActivityDetailViewController: UIViewController, StoryboardLoadable { private func presentedFrom() -> String { if presenter is ActivityLogsViewController { return "activity_log" + } else if presenter is BackupsViewController { + return "backup" } else if presenter is DashboardActivityLogCardCell { return "dashboard" } else { diff --git a/WordPress/Classes/ViewRelated/Activity/List/ActivityLogsViewController.swift b/WordPress/Classes/ViewRelated/Activity/List/ActivityLogsViewController.swift index 7356e25aab23..b80b8cb1b367 100644 --- a/WordPress/Classes/ViewRelated/Activity/List/ActivityLogsViewController.swift +++ b/WordPress/Classes/ViewRelated/Activity/List/ActivityLogsViewController.swift @@ -3,13 +3,13 @@ import SwiftUI import WordPressUI import WordPressKit -final class ActivityLogsViewController: UIHostingController { +final class ActivityLogsViewController: UIHostingController { private let viewModel: ActivityLogsViewModel - init(blog: Blog, isBackupMode: Bool = false) { - self.viewModel = ActivityLogsViewModel(blog: blog, isBackupMode: isBackupMode) - super.init(rootView: AnyView(ActivityLogsView(viewModel: viewModel))) - self.title = isBackupMode ? Strings.backupsTitle : Strings.activityTitle + init(blog: Blog) { + self.viewModel = ActivityLogsViewModel(blog: blog) + super.init(rootView: ActivityLogsView(viewModel: viewModel)) + self.title = Strings.title } required dynamic init?(coder aDecoder: NSCoder) { @@ -18,6 +18,5 @@ final class ActivityLogsViewController: UIHostingController { } private enum Strings { - static let activityTitle = NSLocalizedString("activity.logs.title", value: "Activity", comment: "Title for the activity logs screen") - static let backupsTitle = NSLocalizedString("backups.title", value: "Backups", comment: "Title for the backups screen") + static let title = NSLocalizedString("activityLogs.title", value: "Activity", comment: "Title for the activity logs screen") } diff --git a/WordPress/Classes/ViewRelated/Activity/List/BackupsViewController.swift b/WordPress/Classes/ViewRelated/Activity/List/BackupsViewController.swift new file mode 100644 index 000000000000..f45e40570fa0 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Activity/List/BackupsViewController.swift @@ -0,0 +1,22 @@ +import UIKit +import SwiftUI +import WordPressUI +import WordPressKit + +final class BackupsViewController: UIHostingController { + private let viewModel: ActivityLogsViewModel + + init(blog: Blog) { + self.viewModel = ActivityLogsViewModel(blog: blog, isBackupMode: true) + super.init(rootView: ActivityLogsView(viewModel: viewModel)) + self.title = Strings.title + } + + required dynamic init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private enum Strings { + static let title = NSLocalizedString("backups.title", value: "Backups", comment: "Title for the backups screen") +} diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift index 61c4494166ca..9c9d6a9c58ae 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+Swift.swift @@ -173,7 +173,7 @@ extension BlogDetailsViewController { } @objc public func showBackup() { - let controller = ActivityLogsViewController(blog: blog, isBackupMode: true) + let controller = BackupsViewController(blog: blog) controller.navigationItem.largeTitleDisplayMode = .never presentationDelegate?.presentBlogDetailsViewController(controller)