From 8e2a4c12df1d5efbeb764018ed6e6f2790d8b365 Mon Sep 17 00:00:00 2001 From: Momo Ozawa Date: Tue, 26 Apr 2022 10:48:50 +0100 Subject: [PATCH 1/7] Refactor: update copy for Reader tour --- .../Classes/ViewRelated/Blog/QuickStartTours.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift b/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift index a18a0720a494..f29e3eea4647 100644 --- a/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift +++ b/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift @@ -191,22 +191,22 @@ struct QuickStartPublishTour: QuickStartTour { struct QuickStartFollowTour: QuickStartTour { let key = "quick-start-follow-tour" let analyticsKey = "follow_site" - let title = NSLocalizedString("Follow other sites", comment: "Title of a Quick Start Tour") - let titleMarkedCompleted = NSLocalizedString("Completed: Follow other sites", comment: "The Quick Start Tour title after the user finished the step.") - let description = NSLocalizedString("Find sites that speak to you, and follow them to get updates when they publish.", comment: "Description of a Quick Start Tour") + let title = NSLocalizedString("Connect with other sites", comment: "Title of a Quick Start Tour") + let titleMarkedCompleted = NSLocalizedString("Completed: Connect with other sites", comment: "The Quick Start Tour title after the user finished the step.") + let description = NSLocalizedString("Discover and follow sites that inspire you.", comment: "Description of a Quick Start Tour") let icon = UIImage.gridicon(.readerFollow) let suggestionNoText = Strings.notNow let suggestionYesText = Strings.yesShowMe let possibleEntryPoints: Set = [.blogDetails, .blogDashboard] var waypoints: [WayPoint] = { - let step1DescriptionBase = NSLocalizedString("Select %@ to continue", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") + let step1DescriptionBase = NSLocalizedString("Select %@ to find other sites.", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") let step1DescriptionTarget = NSLocalizedString("Reader", comment: "The menu item to select during a guided tour.") let step1: WayPoint = (element: .readerTab, description: step1DescriptionBase.highlighting(phrase: step1DescriptionTarget, icon: .gridicon(.reader))) - let step2DescriptionBase = NSLocalizedString("Select %@ to look for sites with similar interests", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") - let step2DescriptionTarget = NSLocalizedString("Search", comment: "The menu item to select during a guided tour.") - let step2: WayPoint = (element: .readerSearch, description: step2DescriptionBase.highlighting(phrase: step2DescriptionTarget, icon: .gridicon(.search))) + let step2DescriptionBase = NSLocalizedString("Select %@ to add topics you like.", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") + let step2DescriptionTarget = NSLocalizedString("Settings", comment: "The menu item to select during a guided tour.") + let step2: WayPoint = (element: .readerSearch, description: step2DescriptionBase.highlighting(phrase: step2DescriptionTarget, icon: .gridicon(.cog))) return [step1, step2] }() From fce05d233bb2ddbea29154bb21180d86a7414600 Mon Sep 17 00:00:00 2001 From: Momo Ozawa Date: Tue, 26 Apr 2022 14:51:54 +0100 Subject: [PATCH 2/7] Refactor: make settings button spotlightable --- .../Tab Navigation/ReaderTabViewController.swift | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift index 41b2b2dda557..7ffbad8a1617 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift @@ -11,6 +11,7 @@ class ReaderTabViewController: UIViewController { return makeReaderTabView(viewModel) }() + private let settingsButton: SpotlightableButton = SpotlightableButton(type: .custom) private let searchButton: SpotlightableButton = SpotlightableButton(type: .custom) init(viewModel: ReaderTabViewModel, readerTabViewFactory: @escaping (ReaderTabViewModel) -> ReaderTabView) { @@ -72,18 +73,18 @@ class ReaderTabViewController: UIViewController { func setupNavigationButtons() { // Settings Button - let settingsButton = UIBarButtonItem(image: UIImage.gridicon(.cog), - style: .plain, - target: self, - action: #selector(didTapSettingsButton)) + settingsButton.spotlightOffset = ReaderTabConstants.spotlightOffset + settingsButton.setImage(.gridicon(.cog), for: .normal) + settingsButton.addTarget(self, action: #selector(didTapSettingsButton), for: .touchUpInside) settingsButton.accessibilityIdentifier = ReaderTabConstants.settingsButtonIdentifier // Search Button - searchButton.spotlightOffset = UIOffset(horizontal: 20, vertical: -10) + searchButton.spotlightOffset = ReaderTabConstants.spotlightOffset searchButton.setImage(.gridicon(.search), for: .normal) searchButton.addTarget(self, action: #selector(didTapSearchButton), for: .touchUpInside) searchButton.accessibilityIdentifier = ReaderTabConstants.searchButtonAccessibilityIdentifier + let settingsButton = UIBarButtonItem(customView: settingsButton) let searchBarButton = UIBarButtonItem(customView: searchButton) navigationItem.rightBarButtonItems = [searchBarButton, settingsButton] @@ -172,5 +173,6 @@ extension ReaderTabViewController { static let restorationIdentifier = "WPReaderTabControllerRestorationID" static let encodedIndexKey = "WPReaderTabControllerIndexRestorationKey" static let discoverIndex = 1 + static let spotlightOffset = UIOffset(horizontal: 20, vertical: -10) } } From ecf106d8cb17a4c5e2a836666021d1ebaeb12969 Mon Sep 17 00:00:00 2001 From: Momo Ozawa Date: Tue, 26 Apr 2022 14:53:11 +0100 Subject: [PATCH 3/7] Refactor: switch to discover tab if needed and show spotlight on settings button --- .../Reader/Manage/ReaderManageScenePresenter.swift | 1 + .../Tab Navigation/ReaderTabViewController.swift | 12 +++++++++++- .../WPTabBarController+ReaderTabNavigation.swift | 1 - 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift b/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift index a4661a609dba..c82386627765 100644 --- a/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift +++ b/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift @@ -53,6 +53,7 @@ class ReaderManageScenePresenter: ScenePresenter { presentedViewController = navigationController viewController.present(navigationController, animated: true, completion: nil) + QuickStartTourGuide.shared.visited(.readerSearch) WPAnalytics.track(.readerManageViewDisplayed) } } diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift index 7ffbad8a1617..9ca5f01de9f7 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift @@ -62,7 +62,16 @@ class ReaderTabViewController: UIViewController { } override func viewWillAppear(_ animated: Bool) { - searchButton.shouldShowSpotlight = QuickStartTourGuide.shared.isCurrentElement(.readerSearch) + super.viewWillAppear(animated) + + if QuickStartTourGuide.shared.isCurrentElement(.readerSearch) { + + if viewModel.selectedIndex != ReaderTabConstants.discoverIndex { + viewModel.showTab(at: ReaderTabConstants.discoverIndex) + } + + settingsButton.shouldShowSpotlight = true + } } override func viewWillDisappear(_ animated: Bool) { @@ -116,6 +125,7 @@ class ReaderTabViewController: UIViewController { // MARK: - Navigation Buttons extension ReaderTabViewController { @objc private func didTapSettingsButton() { + settingsButton.shouldShowSpotlight = false viewModel.presentManage(from: self) } diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift index a6a92223ec46..1f18fb510b4e 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift @@ -64,7 +64,6 @@ extension WPTabBarController { func navigateToReaderSearch() { let searchController = ReaderSearchViewController.controller() navigateToReader(searchController) - QuickStartTourGuide.shared.visited(.readerSearch) } func navigateToReaderSite(_ topic: ReaderSiteTopic) { From 84f70980b60603bb8d3e04b127601139269262fe Mon Sep 17 00:00:00 2001 From: Momo Ozawa Date: Tue, 26 Apr 2022 15:41:37 +0100 Subject: [PATCH 4/7] Refactor: rename .readerSearch to .readerDiscoverSettings --- .../ViewRelated/Blog/Blog Details/BlogDetailsViewController.h | 2 +- WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift | 2 +- WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift | 2 +- .../ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift | 2 +- .../Reader/Tab Navigation/ReaderTabViewController.swift | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.h b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.h index 5b9839ed2aee..c78e92876c29 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.h +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.h @@ -60,7 +60,7 @@ typedef NS_ENUM(NSInteger, QuickStartTourElement) { QuickStartTourElementSharing = 8, QuickStartTourElementConnections = 9, QuickStartTourElementReaderTab = 10, - QuickStartTourElementReaderSearch = 12, + QuickStartTourElementReaderDiscoverSettings = 12, QuickStartTourElementTourCompleted = 13, QuickStartTourElementCongratulations = 14, QuickStartTourElementSiteIcon = 15, diff --git a/WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift b/WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift index fc6e7c56fb38..3ef658943687 100644 --- a/WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift +++ b/WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift @@ -253,7 +253,7 @@ open class QuickStartTourGuide: NSObject { } if element != currentElement { let blogDetailEvents: [QuickStartTourElement] = [.blogDetailNavigation, .checklist, .themes, .viewSite, .sharing, .siteMenu] - let readerElements: [QuickStartTourElement] = [.readerTab, .readerSearch] + let readerElements: [QuickStartTourElement] = [.readerTab, .readerDiscoverSettings] if blogDetailEvents.contains(element) { endCurrentTour() diff --git a/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift b/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift index f29e3eea4647..3f1b2ef0e088 100644 --- a/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift +++ b/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift @@ -206,7 +206,7 @@ struct QuickStartFollowTour: QuickStartTour { let step2DescriptionBase = NSLocalizedString("Select %@ to add topics you like.", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") let step2DescriptionTarget = NSLocalizedString("Settings", comment: "The menu item to select during a guided tour.") - let step2: WayPoint = (element: .readerSearch, description: step2DescriptionBase.highlighting(phrase: step2DescriptionTarget, icon: .gridicon(.cog))) + let step2: WayPoint = (element: .readerDiscoverSettings, description: step2DescriptionBase.highlighting(phrase: step2DescriptionTarget, icon: .gridicon(.cog))) return [step1, step2] }() diff --git a/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift b/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift index c82386627765..c15871f9f6b7 100644 --- a/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift +++ b/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift @@ -53,7 +53,7 @@ class ReaderManageScenePresenter: ScenePresenter { presentedViewController = navigationController viewController.present(navigationController, animated: true, completion: nil) - QuickStartTourGuide.shared.visited(.readerSearch) + QuickStartTourGuide.shared.visited(.readerDiscoverSettings) WPAnalytics.track(.readerManageViewDisplayed) } } diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift index 9ca5f01de9f7..d12f4764ef70 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift @@ -64,7 +64,7 @@ class ReaderTabViewController: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - if QuickStartTourGuide.shared.isCurrentElement(.readerSearch) { + if QuickStartTourGuide.shared.isCurrentElement(.readerDiscoverSettings) { if viewModel.selectedIndex != ReaderTabConstants.discoverIndex { viewModel.showTab(at: ReaderTabConstants.discoverIndex) From b6e8f2303d13b82f85d969a1b34e07bab6059649 Mon Sep 17 00:00:00 2001 From: Momo Ozawa Date: Tue, 26 Apr 2022 15:42:42 +0100 Subject: [PATCH 5/7] Update: copy for .readerDiscoverSettings --- .../ViewRelated/Blog/QuickStartTours.swift | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift b/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift index 3f1b2ef0e088..20f0776dd7fe 100644 --- a/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift +++ b/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift @@ -204,9 +204,19 @@ struct QuickStartFollowTour: QuickStartTour { let step1DescriptionTarget = NSLocalizedString("Reader", comment: "The menu item to select during a guided tour.") let step1: WayPoint = (element: .readerTab, description: step1DescriptionBase.highlighting(phrase: step1DescriptionTarget, icon: .gridicon(.reader))) - let step2DescriptionBase = NSLocalizedString("Select %@ to add topics you like.", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") - let step2DescriptionTarget = NSLocalizedString("Settings", comment: "The menu item to select during a guided tour.") - let step2: WayPoint = (element: .readerDiscoverSettings, description: step2DescriptionBase.highlighting(phrase: step2DescriptionTarget, icon: .gridicon(.cog))) + let step2DiscoverDescriptionBase = NSLocalizedString("Use %@ to find sites and tags.", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") + let step2DiscoverDescriptionTarget = NSLocalizedString("Discover", comment: "The menu item to select during a guided tour.") + let step2DiscoverDescription = step2DiscoverDescriptionBase.highlighting(phrase: step2DiscoverDescriptionTarget, icon: nil) + + let step2SettingsDescriptionBase = NSLocalizedString("Try selecting %@ to add topics you like.", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") + let step2SettingsDescriptionTarget = NSLocalizedString("Settings", comment: "The menu item to select during a guided tour.") + let step2SettingsDescription = step2SettingsDescriptionBase.highlighting(phrase: step2SettingsDescriptionTarget, icon: .gridicon(.cog)) + + /// Combined description for step 2 + let step2Format = NSAttributedString(string: "%@ %@") + let step2Description = NSAttributedString(format: step2Format, args: step2DiscoverDescription, step2SettingsDescription) + + let step2: WayPoint = (element: .readerDiscoverSettings, description: step2Description) return [step1, step2] }() @@ -430,3 +440,15 @@ private extension String { } } } + +private extension NSAttributedString { + convenience init(format: NSAttributedString, args: NSAttributedString...) { + let mutableNSAttributedString = NSMutableAttributedString(attributedString: format) + + args.forEach { (attributedString) in + let range = NSString(string: mutableNSAttributedString.string).range(of: "%@") + mutableNSAttributedString.replaceCharacters(in: range, with: attributedString) + } + self.init(attributedString: mutableNSAttributedString) + } +} From 0177e78b460fa4e5aa78e017d18a9035b1151593 Mon Sep 17 00:00:00 2001 From: Momo Ozawa Date: Tue, 26 Apr 2022 16:16:22 +0100 Subject: [PATCH 6/7] Update: release notes --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 729357acc9a7..fd8ed3373784 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -3,6 +3,7 @@ * [**] Self hosted sites are not restricted by video length during media uploads [https://github.com/wordpress-mobile/WordPress-iOS/pull/18414] * [*] [internal] My Site Dashboard: Made some changes to the code architecture of the dashboard. The majority of the changes are related to the posts cards. It should have no visible changes but could cause regressions. Please test it by creating/trashing drafts and scheduled posts and testing that they appear correctly on the dashboard. [#18405] * [*] Quick Start: Updated the Stats tour. The tour can now be accessed from either the dashboard or the menu tab. [#18413] +* [*] Quick Start: Updated the Reader tour. The tour now highlights the Discover tab and guides users to follow topics via the Settings screen. [#18450] * [*] [internal] Quick Start: Refactored some code related to the tasks displayed in the Quick Start Card and the Quick Start modal. It should have no visible changes but could cause regressions. [#18395] 19.7 From 248ece3b9e1c44c9f870afe07537bef5e68cbed2 Mon Sep 17 00:00:00 2001 From: Momo Ozawa Date: Wed, 27 Apr 2022 09:54:52 +0100 Subject: [PATCH 7/7] Refactor: search button no longer needs to be spotlightable --- .../ReaderTabViewController.swift | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift index d12f4764ef70..81e72009ffe6 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift @@ -12,7 +12,6 @@ class ReaderTabViewController: UIViewController { }() private let settingsButton: SpotlightableButton = SpotlightableButton(type: .custom) - private let searchButton: SpotlightableButton = SpotlightableButton(type: .custom) init(viewModel: ReaderTabViewModel, readerTabViewFactory: @escaping (ReaderTabViewModel) -> ReaderTabView) { self.viewModel = viewModel @@ -81,22 +80,21 @@ class ReaderTabViewController: UIViewController { } func setupNavigationButtons() { + // Search Button + let searchButton = UIBarButtonItem(image: UIImage.gridicon(.search), + style: .plain, + target: self, + action: #selector(didTapSearchButton)) + searchButton.accessibilityIdentifier = ReaderTabConstants.searchButtonAccessibilityIdentifier + // Settings Button settingsButton.spotlightOffset = ReaderTabConstants.spotlightOffset settingsButton.setImage(.gridicon(.cog), for: .normal) settingsButton.addTarget(self, action: #selector(didTapSettingsButton), for: .touchUpInside) settingsButton.accessibilityIdentifier = ReaderTabConstants.settingsButtonIdentifier - - // Search Button - searchButton.spotlightOffset = ReaderTabConstants.spotlightOffset - searchButton.setImage(.gridicon(.search), for: .normal) - searchButton.addTarget(self, action: #selector(didTapSearchButton), for: .touchUpInside) - searchButton.accessibilityIdentifier = ReaderTabConstants.searchButtonAccessibilityIdentifier - let settingsButton = UIBarButtonItem(customView: settingsButton) - let searchBarButton = UIBarButtonItem(customView: searchButton) - navigationItem.rightBarButtonItems = [searchBarButton, settingsButton] + navigationItem.rightBarButtonItems = [searchButton, settingsButton] } override func loadView() {