From 8bbc1e6cb2f16312bba808a41fd52a064d2b061d Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Fri, 16 Dec 2022 03:09:29 +0200 Subject: [PATCH 01/15] Add: `JetpackBrandingMenuCardPresenter` with basic implementation --- .../JetpackBrandingMenuCardCoordinator.swift | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift index 3428b88ec7fc..b8283a9ef68d 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift @@ -32,3 +32,68 @@ private extension JetpackBrandingMenuCardCoordinator { comment: "Description inside a menu card communicating that features are moving to the Jetpack app.") } } + +class JetpackBrandingMenuCardPresenter { + + // MARK: Private Variables + + private let remoteConfigStore: RemoteConfigStore + private let persistenceStore: UserPersistentRepository + private let featureFlagStore: RemoteFeatureFlagStore + + // MARK: Initializers + + init(remoteConfigStore: RemoteConfigStore = RemoteConfigStore(), + featureFlagStore: RemoteFeatureFlagStore = RemoteFeatureFlagStore(), + persistenceStore: UserPersistentRepository = UserDefaults.standard) { + self.remoteConfigStore = remoteConfigStore + self.featureFlagStore = featureFlagStore + self.persistenceStore = persistenceStore + } + + // MARK: Public Functions + + func shouldShowCard() -> Bool { + return false + } + + func remindLaterTapped() { + let now = Date() + let duration = Constants.remindLaterDurationInDays * Constants.secondInDay + let newDate = now.addingTimeInterval(TimeInterval(duration)) + showCardOnDate = newDate + } + + func hideThisTapped() { + shouldHideCard = true + } +} + +private extension JetpackBrandingMenuCardPresenter { + enum Constants { + static let secondInDay = 86_400 + static let remindLaterDurationInDays = 7 + static let shouldHideCardKey = "JetpackBrandingShouldHideCardKey" + static let showCardOnDateKey = "JetpackBrandingShowCardOnDateKey" + } + + var shouldHideCard: Bool { + get { + persistenceStore.bool(forKey: Constants.shouldHideCardKey) + } + + set { + persistenceStore.set(newValue, forKey: Constants.shouldHideCardKey) + } + } + + var showCardOnDate: Date? { + get { + persistenceStore.object(forKey: Constants.showCardOnDateKey) as? Date + } + + set { + persistenceStore.set(newValue, forKey: Constants.showCardOnDateKey) + } + } +} From f5595b932b5b18f129ad2ebbbe47753b30160f8b Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Fri, 16 Dec 2022 03:26:49 +0200 Subject: [PATCH 02/15] Add: Only show card for phase three --- .../JetpackBrandingMenuCardCoordinator.swift | 41 ++++++++--- WordPress/WordPress.xcodeproj/project.pbxproj | 4 ++ ...etpackBrandingMenuCardPresenterTests.swift | 71 +++++++++++++++++++ 3 files changed, 108 insertions(+), 8 deletions(-) create mode 100644 WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift index b8283a9ef68d..df77e9207dd6 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift @@ -35,6 +35,11 @@ private extension JetpackBrandingMenuCardCoordinator { class JetpackBrandingMenuCardPresenter { + struct Config { + let description: String + let learnMoreButtonURL: String? + } + // MARK: Private Variables private let remoteConfigStore: RemoteConfigStore @@ -53,8 +58,20 @@ class JetpackBrandingMenuCardPresenter { // MARK: Public Functions + func cardConfig() -> Config? { + let phase = JetpackFeaturesRemovalCoordinator.generalPhase(featureFlagStore: featureFlagStore) + switch phase { + case .three: + let description = Strings.phaseThreeDescription + let url = RemoteConfig(store: remoteConfigStore).phaseThreeBlogPostUrl.value + return .init(description: description, learnMoreButtonURL: url) + default: + return nil + } + } + func shouldShowCard() -> Bool { - return false + return cardConfig() != nil } func remindLaterTapped() { @@ -70,13 +87,6 @@ class JetpackBrandingMenuCardPresenter { } private extension JetpackBrandingMenuCardPresenter { - enum Constants { - static let secondInDay = 86_400 - static let remindLaterDurationInDays = 7 - static let shouldHideCardKey = "JetpackBrandingShouldHideCardKey" - static let showCardOnDateKey = "JetpackBrandingShowCardOnDateKey" - } - var shouldHideCard: Bool { get { persistenceStore.bool(forKey: Constants.shouldHideCardKey) @@ -97,3 +107,18 @@ private extension JetpackBrandingMenuCardPresenter { } } } + +private extension JetpackBrandingMenuCardPresenter { + enum Constants { + static let secondInDay = 86_400 + static let remindLaterDurationInDays = 7 + static let shouldHideCardKey = "JetpackBrandingShouldHideCardKey" + static let showCardOnDateKey = "JetpackBrandingShowCardOnDateKey" + } + + enum Strings { + static let phaseThreeDescription = NSLocalizedString("jetpack.menuCard.description", + value: "Stats, Reader, Notifications and other features will soon move to the Jetpack mobile app.", + comment: "Description inside a menu card communicating that features are moving to the Jetpack app.") + } +} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 65b7c025b294..15159151408f 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -1582,6 +1582,7 @@ 80535DC1294BDE1900873161 /* JetpackBrandingMenuCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DB72946C79700873161 /* JetpackBrandingMenuCardCell.swift */; }; 80535DC2294BDE2500873161 /* JetpackBrandingMenuCardCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DBD294AC89200873161 /* JetpackBrandingMenuCardCoordinator.swift */; }; 80535DC3294BDE2B00873161 /* BlogDetailsViewController+JetpackBrandingMenuCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DBF294B7D3200873161 /* BlogDetailsViewController+JetpackBrandingMenuCard.swift */; }; + 80535DC5294BF4BE00873161 /* JetpackBrandingMenuCardPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DC4294BF4BE00873161 /* JetpackBrandingMenuCardPresenterTests.swift */; }; 8058730B28F7B70B00340C11 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8058730D28F7B70B00340C11 /* InfoPlist.strings */; }; 8067340A27E3A50900ABC95E /* UIViewController+RemoveQuickStart.m in Sources */ = {isa = PBXBuildFile; fileRef = 8067340927E3A50900ABC95E /* UIViewController+RemoveQuickStart.m */; }; 8067340B27E3A50900ABC95E /* UIViewController+RemoveQuickStart.m in Sources */ = {isa = PBXBuildFile; fileRef = 8067340927E3A50900ABC95E /* UIViewController+RemoveQuickStart.m */; }; @@ -6892,6 +6893,7 @@ 80535DBA294ABBEF00873161 /* JetpackAllFeaturesLogosAnimation_ltr.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = JetpackAllFeaturesLogosAnimation_ltr.json; sourceTree = ""; }; 80535DBD294AC89200873161 /* JetpackBrandingMenuCardCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackBrandingMenuCardCoordinator.swift; sourceTree = ""; }; 80535DBF294B7D3200873161 /* BlogDetailsViewController+JetpackBrandingMenuCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BlogDetailsViewController+JetpackBrandingMenuCard.swift"; sourceTree = ""; }; + 80535DC4294BF4BE00873161 /* JetpackBrandingMenuCardPresenterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackBrandingMenuCardPresenterTests.swift; sourceTree = ""; }; 8058730C28F7B70B00340C11 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 8067340827E3A50900ABC95E /* UIViewController+RemoveQuickStart.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIViewController+RemoveQuickStart.h"; sourceTree = ""; }; 8067340927E3A50900ABC95E /* UIViewController+RemoveQuickStart.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+RemoveQuickStart.m"; sourceTree = ""; }; @@ -12510,6 +12512,7 @@ 8332DD2629259B9700802F7D /* Utility */, 803DE81E290636A4007D4E9C /* JetpackFeaturesRemovalCoordinatorTests.swift */, 801D951C291ADB7E0051993E /* JetpackOverlayFrequencyTrackerTests.swift */, + 80535DC4294BF4BE00873161 /* JetpackBrandingMenuCardPresenterTests.swift */, ); name = Jetpack; sourceTree = ""; @@ -22524,6 +22527,7 @@ 80EF9284280CFEB60064A971 /* DashboardPostsSyncManagerTests.swift in Sources */, 7EC9FE0B22C627DB00C5A888 /* PostEditorAnalyticsSessionTests.swift in Sources */, D88A64A0208D8B7D008AE9BC /* StockPhotosMediaGroupTests.swift in Sources */, + 80535DC5294BF4BE00873161 /* JetpackBrandingMenuCardPresenterTests.swift in Sources */, 7EAA66EF22CB36FD00869038 /* TestAnalyticsTracker.swift in Sources */, 931D26F619ED7F7000114F17 /* BlogServiceTest.m in Sources */, B5882C471D5297D1008E0EAA /* NotificationTests.swift in Sources */, diff --git a/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift b/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift new file mode 100644 index 000000000000..1a71f04c2dcb --- /dev/null +++ b/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift @@ -0,0 +1,71 @@ +import XCTest +@testable import WordPress + +final class JetpackBrandingMenuCardPresenterTests: XCTestCase { + + private var mockUserDefaults: InMemoryUserDefaults! + private var remoteFeatureFlagsStore = RemoteFeatureFlagStoreMock() + + override func setUp() { + mockUserDefaults = InMemoryUserDefaults() + } + + func testShouldShowCardBasedOnPhase() { + // Given + let presenter = JetpackBrandingMenuCardPresenter( + featureFlagStore: remoteFeatureFlagsStore, + persistenceStore: mockUserDefaults) + + // Normal phase + XCTAssertFalse(presenter.shouldShowCard()) + + // Phase One + remoteFeatureFlagsStore.removalPhaseOne = true + XCTAssertFalse(presenter.shouldShowCard()) + + // Phase Two + remoteFeatureFlagsStore.removalPhaseTwo = true + XCTAssertFalse(presenter.shouldShowCard()) + + // Phase Three + remoteFeatureFlagsStore.removalPhaseThree = true + XCTAssertTrue(presenter.shouldShowCard()) + + // Phase Four + remoteFeatureFlagsStore.removalPhaseFour = true + XCTAssertFalse(presenter.shouldShowCard()) + + // Phase New Users + remoteFeatureFlagsStore.removalPhaseNewUsers = true + XCTAssertFalse(presenter.shouldShowCard()) + } +} + +private class RemoteFeatureFlagStoreMock: RemoteFeatureFlagStore { + + var removalPhaseOne = false + var removalPhaseTwo = false + var removalPhaseThree = false + var removalPhaseFour = false + var removalPhaseNewUsers = false + + override func value(for flag: OverrideableFlag) -> Bool { + guard let flag = flag as? WordPress.FeatureFlag else { + return false + } + switch flag { + case .jetpackFeaturesRemovalPhaseOne: + return removalPhaseOne + case .jetpackFeaturesRemovalPhaseTwo: + return removalPhaseTwo + case .jetpackFeaturesRemovalPhaseThree: + return removalPhaseThree + case .jetpackFeaturesRemovalPhaseFour: + return removalPhaseFour + case .jetpackFeaturesRemovalPhaseNewUsers: + return removalPhaseNewUsers + default: + return super.value(for: flag) + } + } +} From 15856648ea3820113765d2ba2bcdbb91c5a5bfe2 Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Fri, 16 Dec 2022 03:35:59 +0200 Subject: [PATCH 03/15] Refactor: make `RemoteConfigStore` properly overridable --- WordPress/Classes/Stores/RemoteConfigStore.swift | 9 ++++++++- .../Utility/BuildInformation/RemoteConfigParameter.swift | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/Stores/RemoteConfigStore.swift b/WordPress/Classes/Stores/RemoteConfigStore.swift index c7d183b79d70..22542735bffe 100644 --- a/WordPress/Classes/Stores/RemoteConfigStore.swift +++ b/WordPress/Classes/Stores/RemoteConfigStore.swift @@ -25,6 +25,13 @@ class RemoteConfigStore { // MARK: Public Functions + /// Looks up the value for a remote config parameter. + /// - Parameters: + /// - key: The key associated with a remote config parameter + public func value(for key: String) -> Any? { + return cache[key] + } + /// Fetches remote config values from the server. /// - Parameter callback: An optional callback that can be used to update UI following the fetch. It is not called on the UI thread. public func update(then callback: FetchCallback? = nil) { @@ -49,7 +56,7 @@ extension RemoteConfigStore { typealias FetchCallback = () -> Void /// The local cache stores remote config values between runs so that the most recently fetched set are ready to go as soon as this object is instantiated. - private(set) var cache: [String: Any] { + private var cache: [String: Any] { get { // Read from the cache in a thread-safe way queue.sync { diff --git a/WordPress/Classes/Utility/BuildInformation/RemoteConfigParameter.swift b/WordPress/Classes/Utility/BuildInformation/RemoteConfigParameter.swift index 6d80e4d123e4..4d114b253695 100644 --- a/WordPress/Classes/Utility/BuildInformation/RemoteConfigParameter.swift +++ b/WordPress/Classes/Utility/BuildInformation/RemoteConfigParameter.swift @@ -12,7 +12,7 @@ struct RemoteConfigParameter { private let store: RemoteConfigStore private var serverValue: T? { - return store.cache[key] as? T + return store.value(for: key) as? T } // MARK: Initializer From c49dfa0e943b7f6312b18a8e7d2aea735f2c54fb Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Fri, 16 Dec 2022 03:46:30 +0200 Subject: [PATCH 04/15] Add: test for phase three config --- ...etpackBrandingMenuCardPresenterTests.swift | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift b/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift index 1a71f04c2dcb..a4b8737c9465 100644 --- a/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift +++ b/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift @@ -5,6 +5,7 @@ final class JetpackBrandingMenuCardPresenterTests: XCTestCase { private var mockUserDefaults: InMemoryUserDefaults! private var remoteFeatureFlagsStore = RemoteFeatureFlagStoreMock() + private var remoteConfigStore = RemoteConfigStoreMock() override func setUp() { mockUserDefaults = InMemoryUserDefaults() @@ -39,6 +40,24 @@ final class JetpackBrandingMenuCardPresenterTests: XCTestCase { remoteFeatureFlagsStore.removalPhaseNewUsers = true XCTAssertFalse(presenter.shouldShowCard()) } + + func testPhaseThreeCardConfig() throws { + // Given + let presenter = JetpackBrandingMenuCardPresenter( + remoteConfigStore: remoteConfigStore, + featureFlagStore: remoteFeatureFlagsStore, + persistenceStore: mockUserDefaults) + remoteFeatureFlagsStore.removalPhaseThree = true + remoteConfigStore.phaseThreeBlogPostUrl = "example.com" + + // When + let config = try XCTUnwrap(presenter.cardConfig()) + + // Then + XCTAssertEqual(config.description, "Stats, Reader, Notifications and other features will soon move to the Jetpack mobile app.") + XCTAssertEqual(config.learnMoreButtonURL, "example.com") + } + } private class RemoteFeatureFlagStoreMock: RemoteFeatureFlagStore { @@ -69,3 +88,15 @@ private class RemoteFeatureFlagStoreMock: RemoteFeatureFlagStore { } } } + +private class RemoteConfigStoreMock: RemoteConfigStore { + + var phaseThreeBlogPostUrl: String? + + override func value(for key: String) -> Any? { + if key == "phase-three-blog-post" { + return phaseThreeBlogPostUrl + } + return super.value(for: key) + } +} From b14149792b8509a95eb0ac738f66a06d889de39a Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Fri, 16 Dec 2022 04:20:17 +0200 Subject: [PATCH 05/15] Add: tests for hiding the menu card --- ...etpackBrandingMenuCardPresenterTests.swift | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift b/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift index a4b8737c9465..e192614e0acd 100644 --- a/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift +++ b/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift @@ -6,9 +6,11 @@ final class JetpackBrandingMenuCardPresenterTests: XCTestCase { private var mockUserDefaults: InMemoryUserDefaults! private var remoteFeatureFlagsStore = RemoteFeatureFlagStoreMock() private var remoteConfigStore = RemoteConfigStoreMock() + private var currentDateProvider: MockCurrentDateProvider! override func setUp() { mockUserDefaults = InMemoryUserDefaults() + currentDateProvider = MockCurrentDateProvider() } func testShouldShowCardBasedOnPhase() { @@ -58,6 +60,58 @@ final class JetpackBrandingMenuCardPresenterTests: XCTestCase { XCTAssertEqual(config.learnMoreButtonURL, "example.com") } + func testHidingTheMenuCard() { + // Given + let presenter = JetpackBrandingMenuCardPresenter( + featureFlagStore: remoteFeatureFlagsStore, + persistenceStore: mockUserDefaults) + remoteFeatureFlagsStore.removalPhaseThree = true + + // When + presenter.hideThisTapped() + + // Then + XCTAssertFalse(presenter.shouldShowCard()) + } + + func testRemindMeLaterTappedRecently() { + // Given + let secondsInDay = TimeInterval(86_400) + let currentDate = Date() + let presenter = JetpackBrandingMenuCardPresenter( + featureFlagStore: remoteFeatureFlagsStore, + persistenceStore: mockUserDefaults, + currentDateProvider: currentDateProvider) + remoteFeatureFlagsStore.removalPhaseThree = true + currentDateProvider.dateToReturn = currentDate + + // When + presenter.remindLaterTapped() + currentDateProvider.dateToReturn = currentDate.addingTimeInterval(secondsInDay) + + // Then + XCTAssertFalse(presenter.shouldShowCard()) + } + + func testRemindMeLaterTappedAndIntervalPassed() { + // Given + let secondsInSevenDays = TimeInterval(86_400 * 7) + let currentDate = Date() + let presenter = JetpackBrandingMenuCardPresenter( + featureFlagStore: remoteFeatureFlagsStore, + persistenceStore: mockUserDefaults, + currentDateProvider: currentDateProvider) + remoteFeatureFlagsStore.removalPhaseThree = true + currentDateProvider.dateToReturn = currentDate + + // When + presenter.remindLaterTapped() + currentDateProvider.dateToReturn = currentDate.addingTimeInterval(secondsInSevenDays + 1) + + // Then + XCTAssertTrue(presenter.shouldShowCard()) + } + } private class RemoteFeatureFlagStoreMock: RemoteFeatureFlagStore { @@ -100,3 +154,11 @@ private class RemoteConfigStoreMock: RemoteConfigStore { return super.value(for: key) } } + +private class MockCurrentDateProvider: CurrentDateProvider { + var dateToReturn: Date? + + func date() -> Date { + return dateToReturn ?? Date() + } +} From df9b3c788fe3c207898d8ab824ed5a7302acfb78 Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Fri, 16 Dec 2022 04:20:53 +0200 Subject: [PATCH 06/15] Add: implement hiding the menu card logic --- .../JetpackBrandingMenuCardCoordinator.swift | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift index df77e9207dd6..661675fd4e9d 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift @@ -45,15 +45,18 @@ class JetpackBrandingMenuCardPresenter { private let remoteConfigStore: RemoteConfigStore private let persistenceStore: UserPersistentRepository private let featureFlagStore: RemoteFeatureFlagStore + private let currentDateProvider: CurrentDateProvider // MARK: Initializers init(remoteConfigStore: RemoteConfigStore = RemoteConfigStore(), featureFlagStore: RemoteFeatureFlagStore = RemoteFeatureFlagStore(), - persistenceStore: UserPersistentRepository = UserDefaults.standard) { + persistenceStore: UserPersistentRepository = UserDefaults.standard, + currentDateProvider: CurrentDateProvider = DefaultCurrentDateProvider()) { self.remoteConfigStore = remoteConfigStore self.featureFlagStore = featureFlagStore self.persistenceStore = persistenceStore + self.currentDateProvider = currentDateProvider } // MARK: Public Functions @@ -71,11 +74,17 @@ class JetpackBrandingMenuCardPresenter { } func shouldShowCard() -> Bool { - return cardConfig() != nil + let showCardOnDate = showCardOnDate ?? .distantPast // If not set, then return distant past so that the condition below always succeeds + guard shouldHideCard == false, // Card not hidden + showCardOnDate < currentDateProvider.date(), // Interval has passed if temporarily hidden + let _ = cardConfig() else { // Card is enabled in the current phase + return false + } + return true } func remindLaterTapped() { - let now = Date() + let now = currentDateProvider.date() let duration = Constants.remindLaterDurationInDays * Constants.secondInDay let newDate = now.addingTimeInterval(TimeInterval(duration)) showCardOnDate = newDate From 9daf52c26c7d935cd7a4524b1836933c21329668 Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Fri, 16 Dec 2022 04:29:28 +0200 Subject: [PATCH 07/15] Refactor: replace usage of `JetpackBrandingMenuCardCoordinator` with presenter instances --- .../Blog/Blog Details/BlogDetailsViewController.m | 2 +- ...BlogDetailsViewController+JetpackBrandingMenuCard.swift | 5 +++++ .../Branding/Menu Card/JetpackBrandingMenuCardCell.swift | 7 +++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m index 95624eb5ad41..319f02525b3d 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m @@ -742,7 +742,7 @@ - (void)configureTableViewData if (MigrationSuccessCardView.shouldShowMigrationSuccessCard == YES) { [marr addObject:[self migrationSuccessSectionViewModel]]; } - if (JetpackBrandingMenuCardCoordinator.shouldShowCard == YES) { + if (self.shouldShowJetpackBrandingMenuCard == YES) { [marr addObject:[self jetpackCardSectionViewModel]]; } diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift index 3d25446ab765..9e69869be23a 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift @@ -2,6 +2,11 @@ import Foundation extension BlogDetailsViewController { + @objc var shouldShowJetpackBrandingMenuCard: Bool { + let presenter = JetpackBrandingMenuCardPresenter() + return presenter.shouldShowCard() + } + @objc func jetpackCardSectionViewModel() -> BlogDetailsSection { let row = BlogDetailsRow() row.callback = {} diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCell.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCell.swift index e221834e9d6e..d772bde1afde 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCell.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCell.swift @@ -6,6 +6,7 @@ class JetpackBrandingMenuCardCell: UITableViewCell { // MARK: Private Variables private weak var viewController: UIViewController? + private var presenter: JetpackBrandingMenuCardPresenter /// Sets the animation based on the language orientation private var animation: Animation? { @@ -119,11 +120,13 @@ class JetpackBrandingMenuCardCell: UITableViewCell { // MARK: Initializers override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + presenter = JetpackBrandingMenuCardPresenter() super.init(style: style, reuseIdentifier: reuseIdentifier) commonInit() } required init?(coder: NSCoder) { + presenter = JetpackBrandingMenuCardPresenter() super.init(coder: coder) commonInit() } @@ -144,7 +147,7 @@ class JetpackBrandingMenuCardCell: UITableViewCell { private func setupContent() { logosAnimationView.play() - let config = JetpackBrandingMenuCardCoordinator.cardConfig + let config = presenter.cardConfig() descriptionLabel.text = config?.description learnMoreSuperview.isHidden = config?.learnMoreButtonURL == nil } @@ -152,7 +155,7 @@ class JetpackBrandingMenuCardCell: UITableViewCell { // MARK: Actions @objc private func learnMoreButtonTapped() { - guard let config = JetpackBrandingMenuCardCoordinator.cardConfig, + guard let config = presenter.cardConfig(), let urlString = config.learnMoreButtonURL, let url = URL(string: urlString) else { return From 580fca2cf63a199104fe40ed93b9e21a8a0dd21e Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Fri, 16 Dec 2022 04:30:43 +0200 Subject: [PATCH 08/15] Refactor: remove `JetpackBrandingMenuCardCoordinator` --- ...=> JetpackBrandingMenuCardPresenter.swift} | 33 ------------------- WordPress/WordPress.xcodeproj/project.pbxproj | 12 +++---- 2 files changed, 6 insertions(+), 39 deletions(-) rename WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/{JetpackBrandingMenuCardCoordinator.swift => JetpackBrandingMenuCardPresenter.swift} (75%) diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift similarity index 75% rename from WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift rename to WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift index 661675fd4e9d..09cace64c2af 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCoordinator.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift @@ -1,38 +1,5 @@ import Foundation -@objc -class JetpackBrandingMenuCardCoordinator: NSObject { - - struct Config { - let description: String - let learnMoreButtonURL: String? - } - - static var cardConfig: Config? { - let phase = JetpackFeaturesRemovalCoordinator.generalPhase() - switch phase { - case .three: - let description = Strings.phaseThreeDescription - let url = RemoteConfig().phaseThreeBlogPostUrl.value - return .init(description: description, learnMoreButtonURL: url) - default: - return nil - } - } - - @objc static var shouldShowCard: Bool { - return cardConfig != nil - } -} - -private extension JetpackBrandingMenuCardCoordinator { - enum Strings { - static let phaseThreeDescription = NSLocalizedString("jetpack.menuCard.description", - value: "Stats, Reader, Notifications and other features will soon move to the Jetpack mobile app.", - comment: "Description inside a menu card communicating that features are moving to the Jetpack app.") - } -} - class JetpackBrandingMenuCardPresenter { struct Config { diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 15159151408f..e0ae137d4a65 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -1577,10 +1577,10 @@ 80535DB82946C79700873161 /* JetpackBrandingMenuCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DB72946C79700873161 /* JetpackBrandingMenuCardCell.swift */; }; 80535DBB294ABBF000873161 /* JetpackAllFeaturesLogosAnimation_rtl.json in Resources */ = {isa = PBXBuildFile; fileRef = 80535DB9294ABBEF00873161 /* JetpackAllFeaturesLogosAnimation_rtl.json */; }; 80535DBC294ABBF000873161 /* JetpackAllFeaturesLogosAnimation_ltr.json in Resources */ = {isa = PBXBuildFile; fileRef = 80535DBA294ABBEF00873161 /* JetpackAllFeaturesLogosAnimation_ltr.json */; }; - 80535DBE294AC89200873161 /* JetpackBrandingMenuCardCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DBD294AC89200873161 /* JetpackBrandingMenuCardCoordinator.swift */; }; + 80535DBE294AC89200873161 /* JetpackBrandingMenuCardPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DBD294AC89200873161 /* JetpackBrandingMenuCardPresenter.swift */; }; 80535DC0294B7D3200873161 /* BlogDetailsViewController+JetpackBrandingMenuCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DBF294B7D3200873161 /* BlogDetailsViewController+JetpackBrandingMenuCard.swift */; }; 80535DC1294BDE1900873161 /* JetpackBrandingMenuCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DB72946C79700873161 /* JetpackBrandingMenuCardCell.swift */; }; - 80535DC2294BDE2500873161 /* JetpackBrandingMenuCardCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DBD294AC89200873161 /* JetpackBrandingMenuCardCoordinator.swift */; }; + 80535DC2294BDE2500873161 /* JetpackBrandingMenuCardPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DBD294AC89200873161 /* JetpackBrandingMenuCardPresenter.swift */; }; 80535DC3294BDE2B00873161 /* BlogDetailsViewController+JetpackBrandingMenuCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DBF294B7D3200873161 /* BlogDetailsViewController+JetpackBrandingMenuCard.swift */; }; 80535DC5294BF4BE00873161 /* JetpackBrandingMenuCardPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80535DC4294BF4BE00873161 /* JetpackBrandingMenuCardPresenterTests.swift */; }; 8058730B28F7B70B00340C11 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8058730D28F7B70B00340C11 /* InfoPlist.strings */; }; @@ -6891,7 +6891,7 @@ 80535DB72946C79700873161 /* JetpackBrandingMenuCardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackBrandingMenuCardCell.swift; sourceTree = ""; }; 80535DB9294ABBEF00873161 /* JetpackAllFeaturesLogosAnimation_rtl.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = JetpackAllFeaturesLogosAnimation_rtl.json; sourceTree = ""; }; 80535DBA294ABBEF00873161 /* JetpackAllFeaturesLogosAnimation_ltr.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = JetpackAllFeaturesLogosAnimation_ltr.json; sourceTree = ""; }; - 80535DBD294AC89200873161 /* JetpackBrandingMenuCardCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackBrandingMenuCardCoordinator.swift; sourceTree = ""; }; + 80535DBD294AC89200873161 /* JetpackBrandingMenuCardPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackBrandingMenuCardPresenter.swift; sourceTree = ""; }; 80535DBF294B7D3200873161 /* BlogDetailsViewController+JetpackBrandingMenuCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BlogDetailsViewController+JetpackBrandingMenuCard.swift"; sourceTree = ""; }; 80535DC4294BF4BE00873161 /* JetpackBrandingMenuCardPresenterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackBrandingMenuCardPresenterTests.swift; sourceTree = ""; }; 8058730C28F7B70B00340C11 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -12521,7 +12521,7 @@ isa = PBXGroup; children = ( 80535DB72946C79700873161 /* JetpackBrandingMenuCardCell.swift */, - 80535DBD294AC89200873161 /* JetpackBrandingMenuCardCoordinator.swift */, + 80535DBD294AC89200873161 /* JetpackBrandingMenuCardPresenter.swift */, 80535DBF294B7D3200873161 /* BlogDetailsViewController+JetpackBrandingMenuCard.swift */, ); path = "Menu Card"; @@ -21203,7 +21203,7 @@ 171096CB270F01EA001BCDD6 /* DomainSuggestionsTableViewController.swift in Sources */, 469CE07124BCFB04003BDC8B /* CollapsableHeaderCollectionViewCell.swift in Sources */, 7EB5824720EC41B200002702 /* NotificationContentFactory.swift in Sources */, - 80535DBE294AC89200873161 /* JetpackBrandingMenuCardCoordinator.swift in Sources */, + 80535DBE294AC89200873161 /* JetpackBrandingMenuCardPresenter.swift in Sources */, F53FF3AA23EA725C001AD596 /* SiteIconView.swift in Sources */, FA3536F525B01A2C0005A3A0 /* JetpackRestoreCompleteViewController.swift in Sources */, 7E7947AD210BAC7B005BB851 /* FormattableNoticonRange.swift in Sources */, @@ -23017,7 +23017,7 @@ 98622EA0274C59A400061A5F /* ReaderDetailCommentsTableViewDelegate.swift in Sources */, FABB21EA2602FC2C00C8785C /* RestoreWarningView.swift in Sources */, 17039225282E6D2800F602E9 /* ViewsVisitorsLineChartCell.swift in Sources */, - 80535DC2294BDE2500873161 /* JetpackBrandingMenuCardCoordinator.swift in Sources */, + 80535DC2294BDE2500873161 /* JetpackBrandingMenuCardPresenter.swift in Sources */, C7D30C652638B07A00A1695B /* JetpackPrologueStyleGuide.swift in Sources */, FABB21EB2602FC2C00C8785C /* GutenbergWebNavigationViewController.swift in Sources */, F4F9D5EC29096CF500502576 /* MigrationHeaderView.swift in Sources */, From cac92b35136e85daa87ae4dccd5ee3100ca06b54 Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Fri, 16 Dec 2022 05:00:05 +0200 Subject: [PATCH 09/15] Update: hook up context menu actions --- ...tailsViewController+JetpackBrandingMenuCard.swift | 5 +++++ .../Menu Card/JetpackBrandingMenuCardCell.swift | 12 ++++++++---- .../Menu Card/JetpackBrandingMenuCardPresenter.swift | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift index 9e69869be23a..4f2d831c63b5 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift @@ -17,4 +17,9 @@ extension BlogDetailsViewController { category: .jetpackBrandingCard) return section } + + func reloadTableView() { + configureTableViewData() + reloadTableViewPreservingSelection() + } } diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCell.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCell.swift index d772bde1afde..25ea813e53e6 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCell.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardCell.swift @@ -5,7 +5,7 @@ class JetpackBrandingMenuCardCell: UITableViewCell { // MARK: Private Variables - private weak var viewController: UIViewController? + private weak var viewController: BlogDetailsViewController? private var presenter: JetpackBrandingMenuCardPresenter /// Sets the animation based on the language orientation @@ -189,11 +189,15 @@ private extension JetpackBrandingMenuCardCell { // MARK: Actions private func remindMeLaterTapped() { - // TODO: Implement this + presenter.remindLaterTapped() + viewController?.reloadTableView() + // TODO: Track button tapped } private func hideThisTapped() { - // TODO: Implement this + presenter.hideThisTapped() + viewController?.reloadTableView() + // TODO: Track button tapped } } @@ -279,7 +283,7 @@ private extension JetpackBrandingMenuCardCell { extension JetpackBrandingMenuCardCell { @objc(configureWithViewController:) - func configure(with viewController: UIViewController) { + func configure(with viewController: BlogDetailsViewController) { self.viewController = viewController } } diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift index 09cace64c2af..60ccfe40332f 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift @@ -52,7 +52,7 @@ class JetpackBrandingMenuCardPresenter { func remindLaterTapped() { let now = currentDateProvider.date() - let duration = Constants.remindLaterDurationInDays * Constants.secondInDay + let duration = Constants.remindLaterDurationInDays * Constants.secondsInDay let newDate = now.addingTimeInterval(TimeInterval(duration)) showCardOnDate = newDate } @@ -86,7 +86,7 @@ private extension JetpackBrandingMenuCardPresenter { private extension JetpackBrandingMenuCardPresenter { enum Constants { - static let secondInDay = 86_400 + static let secondsInDay = 86_400 static let remindLaterDurationInDays = 7 static let shouldHideCardKey = "JetpackBrandingShouldHideCardKey" static let showCardOnDateKey = "JetpackBrandingShowCardOnDateKey" From f237459e02cd1ce4179f54ad3ff09c5dc8624b23 Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Fri, 16 Dec 2022 05:18:57 +0200 Subject: [PATCH 10/15] Add: display overlay when card is tapped --- .../BlogDetailsViewController+JetpackBrandingMenuCard.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift index 4f2d831c63b5..7ba3fce59236 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/BlogDetailsViewController+JetpackBrandingMenuCard.swift @@ -9,7 +9,9 @@ extension BlogDetailsViewController { @objc func jetpackCardSectionViewModel() -> BlogDetailsSection { let row = BlogDetailsRow() - row.callback = {} + row.callback = { + JetpackFeaturesRemovalCoordinator.presentOverlayIfNeeded(from: .card, in: self) + } let section = BlogDetailsSection(title: nil, rows: [row], From a654c46bc799bd7819f8f82120d8d6df225fffae Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Fri, 16 Dec 2022 05:19:23 +0200 Subject: [PATCH 11/15] Update: fix menu restorable reload logic --- .../ViewRelated/Blog/Blog Details/BlogDetailsViewController.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m index 319f02525b3d..65f0e60f164b 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m @@ -615,6 +615,7 @@ - (void)setRestorableSelectedIndexPath:(NSIndexPath *)restorableSelectedIndexPat switch (section.category) { case BlogDetailsSectionCategoryQuickAction: case BlogDetailsSectionCategoryQuickStart: + case BlogDetailsSectionCategoryJetpackBrandingCard: case BlogDetailsSectionCategoryDomainCredit: { _restorableSelectedIndexPath = nil; } @@ -700,6 +701,7 @@ - (void)reloadTableViewPreservingSelection switch (section.category) { case BlogDetailsSectionCategoryQuickAction: case BlogDetailsSectionCategoryQuickStart: + case BlogDetailsSectionCategoryJetpackBrandingCard: case BlogDetailsSectionCategoryDomainCredit: { BlogDetailsSubsection subsection = [self shouldShowDashboard] ? BlogDetailsSubsectionHome : BlogDetailsSubsectionStats; BlogDetailsSectionCategory category = [self sectionCategoryWithSubsection:subsection blog: self.blog]; From 5523bd05392ba8057af6d85867b759d05e65ffd6 Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Fri, 16 Dec 2022 05:54:06 +0200 Subject: [PATCH 12/15] Update: configure card overlay for phase three --- ...ackFullscreenOverlayGeneralViewModel.swift | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Fullscreen Overlay/JetpackFullscreenOverlayGeneralViewModel.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Fullscreen Overlay/JetpackFullscreenOverlayGeneralViewModel.swift index c57d8950ddf5..f63bdd55aeba 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Fullscreen Overlay/JetpackFullscreenOverlayGeneralViewModel.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Fullscreen Overlay/JetpackFullscreenOverlayGeneralViewModel.swift @@ -70,6 +70,8 @@ struct JetpackFullscreenOverlayGeneralViewModel: JetpackFullscreenOverlayViewMod return Strings.PhaseTwoAndThree.notificationsTitle case (.three, .reader): return Strings.PhaseTwoAndThree.readerTitle + case (.three, _): + return Strings.PhaseThree.generalTitle default: return "" } @@ -110,7 +112,7 @@ struct JetpackFullscreenOverlayGeneralViewModel: JetpackFullscreenOverlayViewMod case .login: fallthrough case .appOpen: - return "" // TODO: Add new animation when ready + return Constants.allFeaturesLogosAnimationLtr } } @@ -127,7 +129,7 @@ struct JetpackFullscreenOverlayGeneralViewModel: JetpackFullscreenOverlayViewMod case .login: fallthrough case .appOpen: - return "" // TODO: Add new animation when ready + return Constants.allFeaturesLogosAnimationRtl } } @@ -175,13 +177,15 @@ struct JetpackFullscreenOverlayGeneralViewModel: JetpackFullscreenOverlayViewMod } var continueButtonText: String? { - switch source { - case .stats: + switch (source, phase) { + case (.stats, _): return Strings.General.statsContinueButtonTitle - case .notifications: + case (.notifications, _): return Strings.General.notificationsContinueButtonTitle - case .reader: + case (.reader, _): return Strings.General.readerContinueButtonTitle + case (_, .three): + return Strings.PhaseThree.generalContinueButtonTitle default: return nil } @@ -242,6 +246,8 @@ private extension JetpackFullscreenOverlayGeneralViewModel { static let readerLogoAnimationRtl = "JetpackReaderLogoAnimation_rtl" static let notificationsLogoAnimationLtr = "JetpackNotificationsLogoAnimation_ltr" static let notificationsLogoAnimationRtl = "JetpackNotificationsLogoAnimation_rtl" + static let allFeaturesLogosAnimationLtr = "JetpackAllFeaturesLogosAnimation_ltr" + static let allFeaturesLogosAnimationRtl = "JetpackAllFeaturesLogosAnimation_rtl" } enum Strings { @@ -314,5 +320,15 @@ private extension JetpackFullscreenOverlayGeneralViewModel { value: "Switching is free and only takes a minute.", comment: "A footnote in a screen displayed when the user accesses a Jetpack powered feature from the WordPress app. The screen showcases the Jetpack app.") } + + enum PhaseThree { + static let generalTitle = NSLocalizedString("jetpack.fullscreen.overlay.phaseThree.general.title", + value: "Jetpack features are moving soon.", + comment: "Title of a screen that showcases the Jetpack app.") + + static let generalContinueButtonTitle = NSLocalizedString("jetpack.fullscreen.overlay.phaseThree.general.continue.title", + value: "Continue without Jetpack", + comment: "Title of a button that dismisses an overlay that showcases the Jetpack app.") + } } } From bbb35183fea8009d5054957ed4bd6dc10fdcd1be Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Mon, 19 Dec 2022 19:34:39 +0200 Subject: [PATCH 13/15] Update: the copy for the phase three card --- .../Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift index 60ccfe40332f..f8673f624221 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift @@ -94,7 +94,7 @@ private extension JetpackBrandingMenuCardPresenter { enum Strings { static let phaseThreeDescription = NSLocalizedString("jetpack.menuCard.description", - value: "Stats, Reader, Notifications and other features will soon move to the Jetpack mobile app.", + value: "Stats, Reader, Notifications and other features will move to the Jetpack mobile app soon.", comment: "Description inside a menu card communicating that features are moving to the Jetpack app.") } } From 1c99095fbac860c701008b372d10909f38917ccf Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Mon, 19 Dec 2022 19:36:05 +0200 Subject: [PATCH 14/15] Update: Change the remind me later duration to 4 days --- .../Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift index f8673f624221..230f9b46cb41 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Branding/Menu Card/JetpackBrandingMenuCardPresenter.swift @@ -87,7 +87,7 @@ private extension JetpackBrandingMenuCardPresenter { private extension JetpackBrandingMenuCardPresenter { enum Constants { static let secondsInDay = 86_400 - static let remindLaterDurationInDays = 7 + static let remindLaterDurationInDays = 4 static let shouldHideCardKey = "JetpackBrandingShouldHideCardKey" static let showCardOnDateKey = "JetpackBrandingShowCardOnDateKey" } From c7bfa99994f64472e79cb9d9781653f2c3d925ed Mon Sep 17 00:00:00 2001 From: Hassaan El-Garem Date: Mon, 19 Dec 2022 20:57:58 +0200 Subject: [PATCH 15/15] Fix: Card presenter tests --- .../WordPressTest/JetpackBrandingMenuCardPresenterTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift b/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift index e192614e0acd..9c54b20b52ed 100644 --- a/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift +++ b/WordPress/WordPressTest/JetpackBrandingMenuCardPresenterTests.swift @@ -56,7 +56,7 @@ final class JetpackBrandingMenuCardPresenterTests: XCTestCase { let config = try XCTUnwrap(presenter.cardConfig()) // Then - XCTAssertEqual(config.description, "Stats, Reader, Notifications and other features will soon move to the Jetpack mobile app.") + XCTAssertEqual(config.description, "Stats, Reader, Notifications and other features will move to the Jetpack mobile app soon.") XCTAssertEqual(config.learnMoreButtonURL, "example.com") } @@ -95,7 +95,7 @@ final class JetpackBrandingMenuCardPresenterTests: XCTestCase { func testRemindMeLaterTappedAndIntervalPassed() { // Given - let secondsInSevenDays = TimeInterval(86_400 * 7) + let secondsInSevenDays = TimeInterval(86_400 * 4) let currentDate = Date() let presenter = JetpackBrandingMenuCardPresenter( featureFlagStore: remoteFeatureFlagsStore,