Skip to content

Commit 2bfb8ee

Browse files
Merge pull request #18412 from wordpress-mobile/task/18388-qs-create-tour-2
Quick Start for Existing Users: Add new tasks collection for existing users
2 parents 3869aa9 + f1a81ad commit 2bfb8ee

16 files changed

Lines changed: 254 additions & 90 deletions

File tree

WordPress/Classes/Models/Blog+QuickStart.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,22 @@ extension Blog {
99
return quickStartTours?.filter { $0.skipped }
1010
}
1111

12+
var quickStartType: QuickStartType {
13+
get {
14+
guard let value = quickStartTypeValue?.intValue,
15+
let type = QuickStartType(rawValue: value) else {
16+
return .undefined
17+
}
18+
return type
19+
}
20+
21+
set {
22+
quickStartTypeValue = NSNumber(value: newValue.rawValue)
23+
let context = managedObjectContext ?? ContextManager.sharedInstance().mainContext
24+
ContextManager.sharedInstance().saveContextAndWait(context)
25+
}
26+
}
27+
1228
public func skipTour(_ tourID: String) {
1329
let tourState = findOrCreate(tour: tourID)
1430
tourState.skipped = true

WordPress/Classes/Models/Blog.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ typedef NS_ENUM(NSInteger, SiteVisibility) {
156156
@property (nonatomic, strong, readwrite, nullable) NSSet *sharingButtons;
157157
@property (nonatomic, strong, readwrite, nullable) NSDictionary *capabilities;
158158
@property (nonatomic, strong, readwrite, nullable) NSSet<QuickStartTourState *> *quickStartTours;
159+
@property (nonatomic, strong, readwrite, nullable) NSNumber *quickStartTypeValue;
159160
/// The blog's user ID for the current user
160161
@property (nonatomic, strong, readwrite, nullable) NSNumber *userID;
161162
/// Disk quota for site, this is only available for WP.com sites

WordPress/Classes/Models/Blog.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ @implementation Blog
8787
@dynamic sharingButtons;
8888
@dynamic capabilities;
8989
@dynamic quickStartTours;
90+
@dynamic quickStartTypeValue;
9091
@dynamic userID;
9192
@dynamic quotaSpaceAllowed;
9293
@dynamic quotaSpaceUsed;

WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ enum FeatureFlag: Int, CaseIterable, OverrideableFlag {
2727
case statsNewAppearance
2828
case statsNewInsights
2929
case siteName
30+
case quickStartForExistingUsers
3031

3132
/// Returns a boolean indicating if the feature is enabled
3233
var enabled: Bool {
@@ -86,6 +87,8 @@ enum FeatureFlag: Int, CaseIterable, OverrideableFlag {
8687
return false
8788
case .siteName:
8889
return true
90+
case .quickStartForExistingUsers:
91+
return BuildConfiguration.current == .localDeveloper
8992
}
9093
}
9194

@@ -166,6 +169,8 @@ extension FeatureFlag {
166169
return "New Cards for Stats Insights"
167170
case .siteName:
168171
return "Site Name"
172+
case .quickStartForExistingUsers:
173+
return "Quick Start For Existing Users"
169174
}
170175
}
171176

WordPress/Classes/ViewRelated/Blog/Blog Dashboard/DashboardCard.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ enum DashboardCard: String, CaseIterable {
4545
func shouldShow(for blog: Blog, apiResponse: BlogDashboardRemoteEntity? = nil, mySiteSettings: DefaultSectionProvider = MySiteSettings()) -> Bool {
4646
switch self {
4747
case .quickStart:
48-
return QuickStartTourGuide.shouldShowChecklist(for: blog) && mySiteSettings.defaultSection == .dashboard
48+
return QuickStartTourGuide.quickStartEnabled(for: blog) && mySiteSettings.defaultSection == .dashboard
4949
case .draftPosts:
5050
fallthrough
5151
case .scheduledPosts:

WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+FancyAlerts.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,10 @@ extension BlogDetailsViewController {
9393
return false
9494
}
9595

96-
return QuickStartTourGuide.shouldShowChecklist(for: blog) && parentVC.mySiteSettings.defaultSection == .siteMenu
96+
return QuickStartTourGuide.quickStartEnabled(for: blog) && parentVC.mySiteSettings.defaultSection == .siteMenu
9797
}
9898

99-
return QuickStartTourGuide.shouldShowChecklist(for: blog)
99+
return QuickStartTourGuide.quickStartEnabled(for: blog)
100100
}
101101

102102
@objc func showQuickStart() {
Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
11
import Foundation
22

3-
enum QuickStartType {
4-
case newUser
5-
case existingUser
3+
enum QuickStartType: Int {
4+
case undefined
5+
case newSite
6+
case existingSite
67
}
78

89
class QuickStartFactory {
910
static func collections(for blog: Blog) -> [QuickStartToursCollection] {
10-
// TODO: Save QuickStartType in blog. Retrieve it here and return collections accordingly
11-
return [QuickStartCustomizeToursCollection(blog: blog), QuickStartGrowToursCollection(blog: blog)]
11+
switch blog.quickStartType {
12+
case .undefined:
13+
guard let completedTours = blog.completedQuickStartTours, completedTours.count > 0 else {
14+
return []
15+
}
16+
// This is to support tours started before quickStartType was added.
17+
fallthrough
18+
case .newSite:
19+
return [QuickStartCustomizeToursCollection(blog: blog), QuickStartGrowToursCollection(blog: blog)]
20+
case .existingSite:
21+
return [QuickStartGetToKnowAppCollection(blog: blog)]
22+
}
23+
}
24+
25+
static func allTours(for blog: Blog) -> [QuickStartTour] {
26+
collections(for: blog).flatMap { $0.tours }
1227
}
1328
}

WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift

Lines changed: 15 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -30,35 +30,37 @@ open class QuickStartTourGuide: NSObject {
3030

3131
private override init() {}
3232

33-
func setup(for blog: Blog, withCompletedSteps steps: [QuickStartTour] = []) {
34-
35-
let createTour = QuickStartCreateTour()
36-
completed(tour: createTour, for: blog)
33+
func setup(for blog: Blog, type: QuickStartType, withCompletedSteps steps: [QuickStartTour] = []) {
34+
if type == .newSite {
35+
let createTour = QuickStartCreateTour()
36+
completed(tour: createTour, for: blog)
37+
}
3738

3839
steps.forEach { (tour) in
3940
completed(tour: tour, for: blog)
4041
}
4142
tourInProgress = false
43+
blog.quickStartType = type
4244

45+
NotificationCenter.default.post(name: .QuickStartTourElementChangedNotification, object: self)
4346
WPAnalytics.track(.quickStartStarted)
4447
}
4548

46-
func setupWithDelay(for blog: Blog, withCompletedSteps steps: [QuickStartTour] = []) {
49+
func setupWithDelay(for blog: Blog, type: QuickStartType, withCompletedSteps steps: [QuickStartTour] = []) {
4750
DispatchQueue.main.asyncAfter(deadline: .now() + Constants.quickStartDelay) {
48-
self.setup(for: blog, withCompletedSteps: steps)
51+
self.setup(for: blog, type: type, withCompletedSteps: steps)
4952
}
5053
}
5154

5255
@objc func remove(from blog: Blog) {
5356
blog.removeAllTours()
57+
blog.quickStartType = .undefined
5458
endCurrentTour()
5559
NotificationCenter.default.post(name: .QuickStartTourElementChangedNotification, object: self)
5660
}
5761

58-
@objc static func shouldShowChecklist(for blog: Blog) -> Bool {
59-
let list = QuickStartTourGuide.customizeListTours(for: blog) + QuickStartTourGuide.growListTours
60-
let checklistCompletedCount = countChecklistCompleted(in: list, for: blog)
61-
return checklistCompletedCount > 0
62+
@objc static func quickStartEnabled(for blog: Blog) -> Bool {
63+
QuickStartFactory.collections(for: blog).isEmpty == false
6264
}
6365

6466
/// Provides a tour to suggest to the user
@@ -69,9 +71,9 @@ open class QuickStartTourGuide: NSObject {
6971
let completedTours: [QuickStartTourState] = blog.completedQuickStartTours ?? []
7072
let skippedTours: [QuickStartTourState] = blog.skippedQuickStartTours ?? []
7173
let unavailableTours = Array(Set(completedTours + skippedTours))
72-
let allTours = QuickStartTourGuide.customizeListTours(for: blog) + QuickStartTourGuide.growListTours
74+
let allTours = QuickStartFactory.allTours(for: blog)
7375

74-
guard isQuickStartEnabled(for: blog),
76+
guard QuickStartTourGuide.quickStartEnabled(for: blog),
7577
recentlyTouredBlog == blog else {
7678
return nil
7779
}
@@ -281,39 +283,9 @@ open class QuickStartTourGuide: NSObject {
281283
dismissCurrentNotice()
282284
currentTourState = nil
283285
}
284-
285-
static func customizeListTours(for blog: Blog) -> [QuickStartTour] {
286-
return [
287-
QuickStartCreateTour(),
288-
QuickStartSiteTitleTour(blog: blog),
289-
QuickStartSiteIconTour(),
290-
QuickStartEditHomepageTour(),
291-
QuickStartReviewPagesTour(),
292-
QuickStartViewTour(blog: blog)
293-
]
294-
}
295-
296-
static var growListTours: [QuickStartTour] {
297-
return [
298-
QuickStartShareTour(),
299-
QuickStartPublishTour(),
300-
QuickStartFollowTour(),
301-
QuickStartCheckStatsTour()
302-
// Temporarily disabled
303-
// QuickStartExplorePlansTour()
304-
]
305-
}
306286
}
307287

308288
private extension QuickStartTourGuide {
309-
func isQuickStartEnabled(for blog: Blog) -> Bool {
310-
// there must be at least one completed tour for quick start to have been enabled
311-
guard let completedTours = blog.completedQuickStartTours else {
312-
return false
313-
}
314-
315-
return completedTours.count > 0
316-
}
317289

318290
func completed(tour: QuickStartTour, for blog: Blog, postNotification: Bool = true) {
319291
let completedTourIDs = (blog.completedQuickStartTours ?? []).map { $0.tourID }
@@ -357,7 +329,7 @@ private extension QuickStartTourGuide {
357329
/// - Parameter blog: blog to check
358330
/// - Returns: boolean, true if all tours have been completed
359331
func allToursCompleted(for blog: Blog) -> Bool {
360-
let list = QuickStartTourGuide.customizeListTours(for: blog) + QuickStartTourGuide.growListTours
332+
let list = QuickStartFactory.allTours(for: blog)
361333
return countChecklistCompleted(in: list, for: blog) >= list.count
362334
}
363335

WordPress/Classes/ViewRelated/Blog/QuickStartToursCollection.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,25 @@ struct QuickStartGrowToursCollection: QuickStartToursCollection {
5959
]
6060
}
6161
}
62+
63+
struct QuickStartGetToKnowAppCollection: QuickStartToursCollection {
64+
let title: String
65+
let hint: String
66+
let completedImageName: String
67+
let analyticsKey: String
68+
let tours: [QuickStartTour]
69+
70+
init(blog: Blog) {
71+
self.title = NSLocalizedString("Get to know the WordPress app",
72+
comment: "Name of the Quick Start list that guides users through a few tasks to explore the WordPress app.")
73+
self.hint = NSLocalizedString("A series of steps helping you to explore the app.",
74+
comment: "A VoiceOver hint to explain what the user gets when they select the 'Get to know the WordPress app' button.")
75+
self.completedImageName = "wp-illustration-tasks-complete-site"
76+
self.analyticsKey = "get-to-know"
77+
self.tours = [
78+
QuickStartCheckStatsTour(),
79+
QuickStartViewTour(blog: blog),
80+
QuickStartFollowTour()
81+
]
82+
}
83+
}

WordPress/Classes/ViewRelated/Me/App Settings/DebugMenuViewController.swift

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,11 @@ class DebugMenuViewController: UITableViewController {
6868

6969
private var toolsRows: [ImmuTableRow] {
7070
var toolsRows = [
71-
ButtonRow(title: Strings.quickStartRow, action: { [weak self] _ in
72-
self?.displayBlogPickerForQuickStart()
71+
ButtonRow(title: Strings.quickStartForNewSiteRow, action: { [weak self] _ in
72+
self?.displayBlogPickerForQuickStart(type: .newSite)
73+
}),
74+
ButtonRow(title: Strings.quickStartForExistingSiteRow, action: { [weak self] _ in
75+
self?.displayBlogPickerForQuickStart(type: .existingSite)
7376
}),
7477
ButtonRow(title: Strings.sandboxStoreCookieSecretRow, action: { [weak self] _ in
7578
self?.displayStoreSandboxSecretInserter()
@@ -117,14 +120,14 @@ class DebugMenuViewController: UITableViewController {
117120
return rows
118121
}
119122

120-
private func displayBlogPickerForQuickStart() {
123+
private func displayBlogPickerForQuickStart(type: QuickStartType) {
121124
let successHandler: BlogSelectorSuccessHandler = { [weak self] selectedObjectID in
122125
guard let blog = self?.blogService.managedObjectContext.object(with: selectedObjectID) as? Blog else {
123126
return
124127
}
125128

126129
self?.dismiss(animated: true) { [weak self] in
127-
self?.enableQuickStart(for: blog)
130+
self?.enableQuickStart(for: blog, type: type)
128131
}
129132
}
130133

@@ -154,8 +157,8 @@ class DebugMenuViewController: UITableViewController {
154157
self.navigationController?.pushViewController(viewController, animated: true)
155158
}
156159

157-
private func enableQuickStart(for blog: Blog) {
158-
QuickStartTourGuide.shared.setup(for: blog)
160+
private func enableQuickStart(for blog: Blog, type: QuickStartType) {
161+
QuickStartTourGuide.shared.setup(for: blog, type: type)
159162
}
160163

161164
// MARK: Reader
@@ -181,7 +184,8 @@ class DebugMenuViewController: UITableViewController {
181184
static let featureFlags = NSLocalizedString("Feature flags", comment: "Title of the Feature Flags screen used in debug builds of the app")
182185
static let tools = NSLocalizedString("Tools", comment: "Title of the Tools section of the debug screen used in debug builds of the app")
183186
static let sandboxStoreCookieSecretRow = NSLocalizedString("Use Sandbox Store", comment: "Title of a row displayed on the debug screen used to configure the sandbox store use in the App.")
184-
static let quickStartRow = NSLocalizedString("Enable Quick Start for Site", comment: "Title of a row displayed on the debug screen used in debug builds of the app")
187+
static let quickStartForNewSiteRow = NSLocalizedString("Enable Quick Start for New Site", comment: "Title of a row displayed on the debug screen used in debug builds of the app")
188+
static let quickStartForExistingSiteRow = NSLocalizedString("Enable Quick Start for Existing Site", comment: "Title of a row displayed on the debug screen used in debug builds of the app")
185189
static let sendTestCrash = NSLocalizedString("Send Test Crash", comment: "Title of a row displayed on the debug screen used to crash the app and send a crash report to the crash logging provider to ensure everything is working correctly")
186190
static let sendLogMessage = NSLocalizedString("Send Log Message", comment: "Title of a row displayed on the debug screen used to send a pretend error message to the crash logging provider to ensure everything is working correctly")
187191
static let alwaysSendLogs = NSLocalizedString("Always Send Crash Logs", comment: "Title of a row displayed on the debug screen used to indicate whether crash logs should be forced to send, even if they otherwise wouldn't")

0 commit comments

Comments
 (0)