diff --git a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift index 9c90bbd23acb..112477e52f03 100644 --- a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift +++ b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift @@ -237,6 +237,23 @@ import Foundation case readerManageViewDisplayed case readerManageViewDismissed + // App Settings + case settingsDidChange + + // Account Close + case accountCloseTapped + case accountCloseCompleted + + // App Settings + case appSettingsClearMediaCacheTapped + case appSettingsClearSpotlightIndexTapped + case appSettingsClearSiriSuggestionsTapped + case appSettingsOpenDeviceSettingsTapped + + // Privacy Settings + case privacySettingsOpened + case privacySettingsReportCrashesToggled + /// A String that represents the event var value: String { switch self { @@ -628,6 +645,7 @@ import Foundation case .postListShareAction: return "post_list_button_pressed" + // Reader: Filter Sheet case .readerFilterSheetDisplayed: return "reader_filter_sheet_displayed" case .readerFilterSheetDismissed: @@ -636,10 +654,36 @@ import Foundation return "reader_filter_sheet_item_selected" case .readerFilterSheetCleared: return "reader_filter_sheet_cleared" + + // Reader: Manage View case .readerManageViewDisplayed: return "reader_manage_view_displayed" case .readerManageViewDismissed: return "reader_manage_view_dismissed" + + // App Settings + case .settingsDidChange: + return "settings_did_change" + case .appSettingsClearMediaCacheTapped: + return "app_settings_clear_media_cache_tapped" + case .appSettingsClearSpotlightIndexTapped: + return "app_settings_clear_spotlight_index_tapped" + case .appSettingsClearSiriSuggestionsTapped: + return "app_settings_clear_siri_suggestions_tapped" + case .appSettingsOpenDeviceSettingsTapped: + return "app_settings_open_device_settings_tapped" + + // Privacy Settings + case .privacySettingsOpened: + return "privacy_settings_opened" + case .privacySettingsReportCrashesToggled: + return "privacy_settings_report_crashes_toggled" + + // Account Close + case .accountCloseTapped: + return "account_close_tapped" + case .accountCloseCompleted: + return "account_close_completed" } // END OF SWITCH } @@ -803,4 +847,18 @@ extension WPAnalytics { } } + @objc static func trackSettingsChange(_ page: String, fieldName: String) { + Self.trackSettingsChange(page, fieldName: fieldName, value: nil) + } + + @objc static func trackSettingsChange(_ page: String, fieldName: String, value: Any?) { + var properties: [AnyHashable: Any] = ["page": page, "field_name": fieldName] + + if let value = value { + let additionalProperties: [AnyHashable: Any] = ["value": value] + properties.merge(additionalProperties) { (_, new) in new } + } + + WPAnalytics.track(.settingsDidChange, properties: properties) + } } diff --git a/WordPress/Classes/Utility/WPImmuTableRows.swift b/WordPress/Classes/Utility/WPImmuTableRows.swift index d8860d8b9825..31f2fc4678a0 100644 --- a/WordPress/Classes/Utility/WPImmuTableRows.swift +++ b/WordPress/Classes/Utility/WPImmuTableRows.swift @@ -80,12 +80,14 @@ struct EditableTextRow: ImmuTableRow { let value: String let accessoryImage: UIImage? let action: ImmuTableAction? + let fieldName: String? - init(title: String, value: String, accessoryImage: UIImage? = nil, action: ImmuTableAction?) { + init(title: String, value: String, accessoryImage: UIImage? = nil, action: ImmuTableAction?, fieldName: String? = nil) { self.title = title self.value = value self.accessoryImage = accessoryImage self.action = action + self.fieldName = fieldName } func configureCell(_ cell: UITableViewCell) { diff --git a/WordPress/Classes/ViewRelated/Blog/Site Management/SiteTagsViewController.swift b/WordPress/Classes/ViewRelated/Blog/Site Management/SiteTagsViewController.swift index 82591c7be3c9..7f226c051459 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Management/SiteTagsViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Site Management/SiteTagsViewController.swift @@ -1,5 +1,6 @@ import UIKit import Gridicons +import WordPressShared final class SiteTagsViewController: UITableViewController { private struct TableConstants { @@ -309,6 +310,7 @@ extension SiteTagsViewController { newTag.tagDescription = data.subtitle save(newTag) + WPAnalytics.trackSettingsChange("site_tags", fieldName: "add_tag") } private func updateTag(_ tag: PostTag, updatedData: SettingsTitleSubtitleController.Content) { @@ -323,6 +325,7 @@ extension SiteTagsViewController { tag.tagDescription = updatedData.subtitle save(tag) + WPAnalytics.trackSettingsChange("site_tags", fieldName: "edit_tag") } private func existingTagForData(_ data: SettingsTitleSubtitleController.Content) -> PostTag? { diff --git a/WordPress/Classes/ViewRelated/Blog/Site Settings/DateAndTimeFormatSettingsViewController.swift b/WordPress/Classes/ViewRelated/Blog/Site Settings/DateAndTimeFormatSettingsViewController.swift index ea8d2e6a92b2..3e94841d3586 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Settings/DateAndTimeFormatSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Site Settings/DateAndTimeFormatSettingsViewController.swift @@ -135,6 +135,7 @@ open class DateAndTimeFormatSettingsViewController: UITableViewController { if let newDateFormat = selected as? String { self?.settings.dateFormat = newDateFormat self?.saveSettings() + WPAnalytics.trackSettingsChange("date_format", fieldName: "date_format") } } @@ -168,6 +169,8 @@ open class DateAndTimeFormatSettingsViewController: UITableViewController { if let newTimeFormat = selected as? String { self?.settings.timeFormat = newTimeFormat self?.saveSettings() + WPAnalytics.trackSettingsChange("date_format", fieldName: "time_format") + } } @@ -187,6 +190,9 @@ open class DateAndTimeFormatSettingsViewController: UITableViewController { if let newStartOfWeek = selected as? String { self?.settings.startOfWeek = newStartOfWeek self?.saveSettings() + WPAnalytics.trackSettingsChange("date_format", + fieldName: "start_of_week", + value: newStartOfWeek as Any) } } diff --git a/WordPress/Classes/ViewRelated/Blog/Site Settings/DiscussionSettingsViewController.swift b/WordPress/Classes/ViewRelated/Blog/Site Settings/DiscussionSettingsViewController.swift index 9b6e86d5dabe..5ccfebae13fa 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Settings/DiscussionSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Site Settings/DiscussionSettingsViewController.swift @@ -7,6 +7,8 @@ import WordPressShared /// allow the user to tune those settings, as required. /// open class DiscussionSettingsViewController: UITableViewController { + private let tracksDiscussionSettingsKey = "site_settings_discussion" + // MARK: - Initializers / Deinitializers @objc public convenience init(blog: Blog) { self.init(style: .grouped) @@ -183,6 +185,7 @@ open class DiscussionSettingsViewController: UITableViewController { return } + trackSettingsChange(fieldName: "allow_comments", value: enabled as Any) settings.commentsAllowed = enabled } @@ -191,6 +194,7 @@ open class DiscussionSettingsViewController: UITableViewController { return } + trackSettingsChange(fieldName: "receive_pingbacks", value: enabled as Any) settings.pingbackInboundEnabled = enabled } @@ -199,6 +203,7 @@ open class DiscussionSettingsViewController: UITableViewController { return } + trackSettingsChange(fieldName: "send_pingbacks", value: enabled as Any) settings.pingbackOutboundEnabled = enabled } @@ -207,6 +212,7 @@ open class DiscussionSettingsViewController: UITableViewController { return } + trackSettingsChange(fieldName: "require_name_and_email", value: enabled as Any) settings.commentsRequireNameAndEmail = enabled } @@ -215,6 +221,7 @@ open class DiscussionSettingsViewController: UITableViewController { return } + trackSettingsChange(fieldName: "require_registration", value: enabled as Any) settings.commentsRequireRegistration = enabled } @@ -234,6 +241,9 @@ open class DiscussionSettingsViewController: UITableViewController { pickerViewController.onChange = { [weak self] (enabled: Bool, newValue: Int) in self?.settings.commentsCloseAutomatically = enabled self?.settings.commentsCloseAutomaticallyAfterDays = newValue as NSNumber + + let value: Any = enabled ? newValue : "disabled" + self?.trackSettingsChange(fieldName: "close_commenting", value: value) } navigationController?.pushViewController(pickerViewController, animated: true) @@ -250,6 +260,7 @@ open class DiscussionSettingsViewController: UITableViewController { return } + self?.trackSettingsChange(fieldName: "comments_sort_by", value: selected as Any) self?.settings.commentsSorting = newSortOrder } @@ -268,6 +279,7 @@ open class DiscussionSettingsViewController: UITableViewController { } self?.settings.commentsThreading = newThreadingDepth + self?.trackSettingsChange(fieldName: "comments_threading", value: selected as Any) } navigationController?.pushViewController(settingsViewController, animated: true) @@ -287,6 +299,9 @@ open class DiscussionSettingsViewController: UITableViewController { pickerViewController.onChange = { [weak self] (enabled: Bool, newValue: Int) in self?.settings.commentsPagingEnabled = enabled self?.settings.commentsPageSize = newValue as NSNumber + + let value: Any = enabled ? newValue : "disabled" + self?.trackSettingsChange(fieldName: "comments_paging", value: value) } navigationController?.pushViewController(pickerViewController, animated: true) @@ -305,6 +320,7 @@ open class DiscussionSettingsViewController: UITableViewController { } self?.settings.commentsAutoapproval = newApprovalStatus + self?.trackSettingsChange(fieldName: "comments_automatically_approve", value: selected as Any) } navigationController?.pushViewController(settingsViewController, animated: true) @@ -321,6 +337,7 @@ open class DiscussionSettingsViewController: UITableViewController { pickerViewController.pickerSelectedValue = settings.commentsMaximumLinks as? Int pickerViewController.onChange = { [weak self] (enabled: Bool, newValue: Int) in self?.settings.commentsMaximumLinks = newValue as NSNumber + self?.trackSettingsChange(fieldName: "comments_links", value: newValue as Any) } navigationController?.pushViewController(pickerViewController, animated: true) @@ -336,6 +353,7 @@ open class DiscussionSettingsViewController: UITableViewController { comment: "Text rendered at the bottom of the Discussion Moderation Keys editor") settingsViewController.onChange = { [weak self] (updated: Set) in self?.settings.commentsModerationKeys = updated + self?.trackSettingsChange(fieldName: "comments_hold_for_moderation", value: updated.count as Any) } navigationController?.pushViewController(settingsViewController, animated: true) @@ -351,12 +369,18 @@ open class DiscussionSettingsViewController: UITableViewController { comment: "Text rendered at the bottom of the Discussion Blocklist Keys editor") settingsViewController.onChange = { [weak self] (updated: Set) in self?.settings.commentsBlocklistKeys = updated + self?.trackSettingsChange(fieldName: "comments_block_list", value: updated.count as Any) } navigationController?.pushViewController(settingsViewController, animated: true) } + private func trackSettingsChange(fieldName: String, value: Any?) { + WPAnalytics.trackSettingsChange(tracksDiscussionSettingsKey, + fieldName: fieldName, + value: value) + } // MARK: - Computed Properties fileprivate var sections: [Section] { diff --git a/WordPress/Classes/ViewRelated/Blog/Site Settings/HomepageSettingsViewController.swift b/WordPress/Classes/ViewRelated/Blog/Site Settings/HomepageSettingsViewController.swift index 785090da84e9..7f18cc14abda 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Settings/HomepageSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Site Settings/HomepageSettingsViewController.swift @@ -276,6 +276,10 @@ import WordPressShared /// If there is already an in progress change (i.e. bad network), don't push the view controller and deselect the selection immediately. tableView.allowsSelection = false + WPAnalytics.trackSettingsChange("homepage_settings", + fieldName: "homepage_type", + value: (homepageType == .page) ? "page" : "posts") + /// Send the remove service call let service = HomepageSettingsService(blog: blog, context: blog.managedObjectContext!) service?.setHomepageType(homepageType, diff --git a/WordPress/Classes/ViewRelated/Blog/Site Settings/Related Posts/RelatedPostsSettingsViewController.m b/WordPress/Classes/ViewRelated/Blog/Site Settings/Related Posts/RelatedPostsSettingsViewController.m index 10d56dd8a927..cc4d560fb850 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Settings/Related Posts/RelatedPostsSettingsViewController.m +++ b/WordPress/Classes/ViewRelated/Blog/Site Settings/Related Posts/RelatedPostsSettingsViewController.m @@ -190,6 +190,8 @@ - (SwitchTableViewCell *)relatedPostsEnabledCell _relatedPostsEnabledCell.name = NSLocalizedString(@"Show Related Posts", @"Label for configuration switch to enable/disable related posts"); __weak RelatedPostsSettingsViewController *weakSelf = self; _relatedPostsEnabledCell.onChange = ^(BOOL value){ + [WPAnalytics trackSettingsChange:@"related_posts" fieldName:@"show_related_posts" value:@(value)]; + [weakSelf updateRelatedPostsSettings:nil]; }; } @@ -203,6 +205,7 @@ - (SwitchTableViewCell *)relatedPostsShowHeaderCell _relatedPostsShowHeaderCell.name = NSLocalizedString(@"Show Header", @"Label for configuration switch to show/hide the header for the related posts section"); __weak RelatedPostsSettingsViewController *weakSelf = self; _relatedPostsShowHeaderCell.onChange = ^(BOOL value){ + [WPAnalytics trackSettingsChange:@"related_posts" fieldName:@"show_related_posts_header" value:@(value)]; [weakSelf updateRelatedPostsSettings:nil]; }; } @@ -217,6 +220,8 @@ - (SwitchTableViewCell *)relatedPostsShowThumbnailsCell _relatedPostsShowThumbnailsCell.name = NSLocalizedString(@"Show Images", @"Label for configuration switch to show/hide images thumbnail for the related posts"); __weak RelatedPostsSettingsViewController *weakSelf = self; _relatedPostsShowThumbnailsCell.onChange = ^(BOOL value){ + [WPAnalytics trackSettingsChange:@"related_posts" fieldName:@"show_related_posts_thumbnail" value:@(value)]; + [weakSelf updateRelatedPostsSettings:nil]; }; } diff --git a/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController+Swift.swift b/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController+Swift.swift index 9f36f04cf119..665e69a4f48d 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController+Swift.swift +++ b/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController+Swift.swift @@ -79,6 +79,8 @@ extension SiteSettingsViewController { self?.blog.settings?.gmtOffset = newValue.gmtOffset as NSNumber? self?.blog.settings?.timezoneString = newValue.timezoneString self?.saveSettings() + self?.trackSettingsChange(fieldName: "timezone", + value: newValue.value as Any) } navigationController?.pushViewController(controller, animated: true) } @@ -105,6 +107,7 @@ extension SiteSettingsViewController { pickerViewController.onChange = { [weak self] (enabled: Bool, newValue: Int) in self?.blog.settings?.postsPerPage = newValue as NSNumber? self?.saveSettings() + self?.trackSettingsChange(fieldName: "posts_per_page", value: newValue as Any) } navigationController?.pushViewController(pickerViewController, animated: true) @@ -355,6 +358,8 @@ extension SiteSettingsViewController { if value != self.blog.settings?.name { self.blog.settings?.name = value self.saveSettings() + + self.trackSettingsChange(fieldName: "site_title") } } @@ -385,6 +390,8 @@ extension SiteSettingsViewController { if normalizedTagline != self.blog.settings?.tagline { self.blog.settings?.tagline = normalizedTagline self.saveSettings() + + self.trackSettingsChange(fieldName: "tagline") } } @@ -403,4 +410,10 @@ extension SiteSettingsViewController { tableView.deselectRow(at: indexPath, animated: true) } + + func trackSettingsChange(fieldName: String, value: Any? = nil) { + WPAnalytics.trackSettingsChange("site_settings", + fieldName: fieldName, + value: value) + } } diff --git a/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController.m b/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController.m index d2e3f3738c95..89186be40a23 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController.m +++ b/WordPress/Classes/ViewRelated/Blog/Site Settings/SiteSettingsViewController.m @@ -438,6 +438,7 @@ - (SwitchTableViewCell *)ampSettingCell _ampSettingCell.onChange = ^(BOOL value){ weakSelf.blog.settings.ampEnabled = value; [weakSelf saveSettings]; + [WPAnalytics trackSettingsChange:@"site_settings" fieldName:@"amp_enabled" value:@(value)]; }; return _ampSettingCell; @@ -751,6 +752,7 @@ - (void)showPrivacySelector if (weakSelf.blog.siteVisibility != newSiteVisibility) { weakSelf.blog.siteVisibility = newSiteVisibility; [weakSelf saveSettings]; + [WPAnalytics trackSettingsChange:@"site_settings" fieldName:@"privacy" value:status]; } } }; @@ -768,6 +770,7 @@ - (void)showLanguageSelectorForBlog:(Blog *)blog languageViewController.onChange = ^(NSNumber *newLanguageID){ weakSelf.blog.settings.languageID = newLanguageID; [weakSelf saveSettings]; + [WPAnalytics trackSettingsChange:@"site_settings" fieldName:@"language" value:newLanguageID]; }; [self.navigationController pushViewController:languageViewController animated:YES]; @@ -832,7 +835,7 @@ - (void)showPostFormatSelector SettingsSelectionValuesKey : formats, SettingsSelectionCurrentValueKey : currentDefaultPostFormat }; - + SettingsSelectionViewController *vc = [[SettingsSelectionViewController alloc] initWithDictionary:postFormatsDict]; __weak __typeof__(self) weakSelf = self; vc.onItemSelected = ^(NSString *status) { @@ -840,7 +843,10 @@ - (void)showPostFormatSelector if ([status isKindOfClass:[NSString class]]) { if (weakSelf.blog.settings.defaultPostFormat != status) { weakSelf.blog.settings.defaultPostFormat = status; + if ([weakSelf savingWritingDefaultsIsAvailable]) { + [WPAnalytics trackSettingsChange:@"site_settings" fieldName:@"default_post_format"]; + [weakSelf saveSettings]; } } @@ -1149,6 +1155,9 @@ - (void)postCategoriesViewController:(PostCategoriesViewController *)controller self.blog.settings.defaultCategoryID = category.categoryID; self.defaultCategoryCell.detailTextLabel.text = category.categoryName; if ([self savingWritingDefaultsIsAvailable]) { + [WPAnalytics trackSettingsChange:@"site_settings" + fieldName:@"default_category"]; + [self saveSettings]; } } diff --git a/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackSettingsViewController.swift b/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackSettingsViewController.swift index 7e1f409a77f5..1acdeff4aaf0 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackSettingsViewController.swift @@ -187,6 +187,7 @@ open class JetpackSettingsViewController: UITableViewController { fileprivate func jetpackMonitorEnabledValueChanged() -> (_ newValue: Bool) -> Void { return { [unowned self] newValue in + WPAnalytics.trackSettingsChange("jetpack_settings", fieldName: "monitor_enabled", value: newValue as Any) self.settings.jetpackMonitorEnabled = newValue self.reloadViewModel() self.service.updateJetpackSettingsForBlog(self.blog, @@ -199,6 +200,7 @@ open class JetpackSettingsViewController: UITableViewController { fileprivate func sendNotificationsByEmailValueChanged() -> (_ newValue: Bool) -> Void { return { [unowned self] newValue in + WPAnalytics.trackSettingsChange("jetpack_settings", fieldName: "send_notification_by_email", value: newValue as Any) self.settings.jetpackMonitorEmailNotifications = newValue self.service.updateJetpackMonitorSettingsForBlog(self.blog, success: {}, @@ -210,6 +212,7 @@ open class JetpackSettingsViewController: UITableViewController { fileprivate func sendPushNotificationsValueChanged() -> (_ newValue: Bool) -> Void { return { [unowned self] newValue in + WPAnalytics.trackSettingsChange("jetpack_settings", fieldName: "send_push_notifications", value: newValue as Any) self.settings.jetpackMonitorPushNotifications = newValue self.service.updateJetpackMonitorSettingsForBlog(self.blog, success: {}, @@ -221,6 +224,7 @@ open class JetpackSettingsViewController: UITableViewController { fileprivate func blockMaliciousLoginAttemptsValueChanged() -> (_ newValue: Bool) -> Void { return { [unowned self] newValue in + WPAnalytics.trackSettingsChange("jetpack_settings", fieldName: "block_malicious_logins", value: newValue as Any) self.settings.jetpackBlockMaliciousLoginAttempts = newValue self.reloadViewModel() self.service.updateJetpackSettingsForBlog(self.blog, @@ -268,6 +272,7 @@ open class JetpackSettingsViewController: UITableViewController { fileprivate func ssoEnabledChanged() -> (_ newValue: Bool) -> Void { return { [unowned self] newValue in + WPAnalytics.trackSettingsChange("jetpack_settings", fieldName: "wpcom_login_allowed", value: newValue as Any) self.settings.jetpackSSOEnabled = newValue self.reloadViewModel() self.service.updateJetpackSettingsForBlog(self.blog, @@ -280,6 +285,7 @@ open class JetpackSettingsViewController: UITableViewController { fileprivate func matchAccountsUsingEmailChanged() -> (_ newValue: Bool) -> Void { return { [unowned self] newValue in + WPAnalytics.trackSettingsChange("jetpack_settings", fieldName: "match_accounts_using_email", value: newValue as Any) self.settings.jetpackSSOMatchAccountsByEmail = newValue self.service.updateJetpackSettingsForBlog(self.blog, success: {}, @@ -291,6 +297,7 @@ open class JetpackSettingsViewController: UITableViewController { fileprivate func requireTwoStepAuthenticationChanged() -> (_ newValue: Bool) -> Void { return { [unowned self] newValue in + WPAnalytics.trackSettingsChange("jetpack_settings", fieldName: "require_two_step_auth", value: newValue as Any) self.settings.jetpackSSORequireTwoStepAuthentication = newValue self.service.updateJetpackSettingsForBlog(self.blog, success: {}, diff --git a/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackSpeedUpSiteSettingsViewController.swift b/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackSpeedUpSiteSettingsViewController.swift index 1d413d7fc5ef..a680335acef7 100644 --- a/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackSpeedUpSiteSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Jetpack/Jetpack Settings/JetpackSpeedUpSiteSettingsViewController.swift @@ -90,6 +90,8 @@ open class JetpackSpeedUpSiteSettingsViewController: UITableViewController { return { [unowned self] newValue in self.settings.jetpackServeImagesFromOurServers = newValue self.reloadViewModel() + WPAnalytics.trackSettingsChange("jetpack_speed_up_site", fieldName: "serve_images", value: newValue as Any) + self.service.updateJetpackServeImagesFromOurServersModuleSettingForBlog(self.blog, success: {}, failure: { [weak self] (_) in @@ -102,6 +104,7 @@ open class JetpackSpeedUpSiteSettingsViewController: UITableViewController { return { [unowned self] newValue in self.settings.jetpackLazyLoadImages = newValue self.reloadViewModel() + WPAnalytics.trackSettingsChange("jetpack_speed_up_site", fieldName: "lazy_load_images", value: newValue as Any) self.service.updateJetpackLazyImagesModuleSettingForBlog(self.blog, success: {}, failure: { [weak self] (_) in diff --git a/WordPress/Classes/ViewRelated/Me/Account Settings/AccountSettingsViewController.swift b/WordPress/Classes/ViewRelated/Me/Account Settings/AccountSettingsViewController.swift index b51b0c54d71a..364f376b6160 100644 --- a/WordPress/Classes/ViewRelated/Me/Account Settings/AccountSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/Account Settings/AccountSettingsViewController.swift @@ -19,6 +19,10 @@ func AccountSettingsViewController(accountSettingsService: AccountSettingsServic } private class AccountSettingsController: SettingsController { + var trackingKey: String { + return "account_settings" + } + let title = NSLocalizedString("Account Settings", comment: "Account Settings Title") var immuTableRows: [ImmuTableRow.Type] { @@ -91,14 +95,16 @@ private class AccountSettingsController: SettingsController { let editableUsername = EditableTextRow( title: NSLocalizedString("Username", comment: "Account Settings Username label"), value: settings?.username ?? "", - action: presenter.push(changeUsername(with: settings, service: service)) + action: presenter.push(changeUsername(with: settings, service: service)), + fieldName: "username" ) let email = EditableTextRow( title: NSLocalizedString("Email", comment: "Account Settings Email label"), value: settings?.emailForDisplay ?? "", accessoryImage: emailAccessoryImage(), - action: presenter.push(editEmailAddress(settings, service: service)) + action: presenter.push(editEmailAddress(settings, service: service)), + fieldName: "email" ) var primarySiteName = settings.flatMap { service.primarySiteNameForSettings($0) } ?? "" @@ -112,19 +118,22 @@ private class AccountSettingsController: SettingsController { let primarySite = EditableTextRow( title: NSLocalizedString("Primary Site", comment: "Primary Web Site"), value: primarySiteName, - action: presenter.present(insideNavigationController(editPrimarySite(settings, service: service))) + action: presenter.present(insideNavigationController(editPrimarySite(settings, service: service))), + fieldName: "primary_site" ) let webAddress = EditableTextRow( title: NSLocalizedString("Web Address", comment: "Account Settings Web Address label"), value: settings?.webAddress ?? "", - action: presenter.push(editWebAddress(service)) + action: presenter.push(editWebAddress(service)), + fieldName: "web_address" ) let password = EditableTextRow( title: Constants.title, value: "", - action: presenter.push(changePassword(with: settings, service: service)) + action: presenter.push(changePassword(with: settings, service: service)), + fieldName: "password" ) let closeAccount = DestructiveButtonRow( @@ -225,6 +234,8 @@ private class AccountSettingsController: SettingsController { let selectorViewController = BlogSelectorViewController(selectedBlogDotComID: settings?.primarySiteID as NSNumber?, successHandler: { (dotComID: NSNumber?) in if let dotComID = dotComID?.intValue { + WPAnalytics.trackSettingsChange(self.trackingKey, fieldName: "primary_site") + let change = AccountSettingsChange.primarySite(dotComID) service.saveChange(change) } @@ -244,6 +255,8 @@ private class AccountSettingsController: SettingsController { private var closeAccountAction: (ImmuTableRow) -> Void { return { [weak self] _ in guard let self = self else { return } + WPAnalytics.track(.accountCloseTapped, properties: ["has_atomic": self.hasAtomicSite]) + switch self.hasAtomicSite { case true: self.showCloseAccountErrorAlert(message: self.localizedErrorMessageForAtomicSites) @@ -281,10 +294,14 @@ private class AccountSettingsController: SettingsController { guard let self = self else { return } switch $0 { case .success: + WPAnalytics.track(.accountCloseCompleted, properties: ["status": "success"]) let status = NSLocalizedString("Account closed", comment: "Overlay message displayed when account successfully closed") SVProgressHUD.showDismissibleSuccess(withStatus: status) AccountHelper.logOutDefaultWordPressComAccount() case .failure(let error): + let errorCode = self.errorCode(error) ?? "unknown" + WPAnalytics.track(.accountCloseCompleted, properties: ["status": "failure", "error_code": errorCode]) + SVProgressHUD.dismiss() DDLogError("Error closing account: \(error.localizedDescription)") self.showCloseAccountErrorAlert(message: self.generateLocalizedMessage(error)) @@ -306,10 +323,16 @@ private class AccountSettingsController: SettingsController { alert.presentFromRootViewController() } - private func generateLocalizedMessage(_ error: Error) -> String { + private func errorCode(_ error: Error) -> String? { let userInfo = (error as NSError).userInfo let errorCode = userInfo[WordPressComRestApi.ErrorKeyErrorCode] as? String + return errorCode + } + + private func generateLocalizedMessage(_ error: Error) -> String { + let errorCode = errorCode(error) + switch errorCode { case "unauthorized": return NSLocalizedString("You're not authorized to close the account.", diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/AppIconViewController.swift b/WordPress/Classes/ViewRelated/Me/App Settings/AppIconViewController.swift index da5d5743398f..c773a2b81f17 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/AppIconViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/AppIconViewController.swift @@ -114,8 +114,11 @@ open class AppIconViewController: UITableViewController { UIApplication.shared.setAlternateIconName(iconName, completionHandler: { [weak self] error in if error == nil { - let event: WPAnalyticsStat = isOriginalIcon ? .appIconReset : .appIconChanged - WPAppAnalytics.track(event) + if isOriginalIcon { + WPAppAnalytics.track(.appIconReset) + } else { + WPAppAnalytics.track(.appIconChanged, withProperties: ["icon_name": iconName ?? "default"]) + } } self?.tableView.reloadData() diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift index 4a5df4179fe2..0c3245492727 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/AppSettingsViewController.swift @@ -133,6 +133,8 @@ class AppSettingsViewController: UITableViewController { } fileprivate func clearMediaCache() { + WPAnalytics.track(.appSettingsClearMediaCacheTapped) + setMediaCacheRowDescription(status: .clearingCache) MediaFileManager.clearAllMediaCacheFiles(onCompletion: { [weak self] in self?.updateMediaCacheSize() @@ -267,6 +269,8 @@ class AppSettingsViewController: UITableViewController { func openPrivacySettings() -> ImmuTableAction { return { [weak self] _ in + WPAnalytics.track(.privacySettingsOpened) + let controller = PrivacySettingsViewController() self?.navigationController?.pushViewController(controller, animated: true) } @@ -274,6 +278,8 @@ class AppSettingsViewController: UITableViewController { func openApplicationSettings() -> ImmuTableAction { return { [weak self] row in + WPAnalytics.track(.appSettingsOpenDeviceSettingsTapped) + if let targetURL = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(targetURL) @@ -287,6 +293,8 @@ class AppSettingsViewController: UITableViewController { func clearSiriActivityDonations() -> ImmuTableAction { return { [tableView] _ in + WPAnalytics.track(.appSettingsClearSiriSuggestionsTapped) + tableView?.deselectSelectedRowWithAnimation(true) if #available(iOS 12.0, *) { @@ -300,6 +308,8 @@ class AppSettingsViewController: UITableViewController { func clearSpotlightCache() -> ImmuTableAction { return { [weak self] row in + WPAnalytics.track(.appSettingsClearSpotlightIndexTapped) + self?.tableView.deselectSelectedRowWithAnimation(true) SearchManager.shared.deleteAllSearchableItems() let notice = Notice(title: NSLocalizedString("Successfully cleared spotlight index", comment: "Notice displayed to the user after clearing the spotlight index in app settings."), diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/PrivacySettingsViewController.swift b/WordPress/Classes/ViewRelated/Me/App Settings/PrivacySettingsViewController.swift index c87f5d485a03..fc03124b9aba 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/PrivacySettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/PrivacySettingsViewController.swift @@ -160,6 +160,9 @@ class PrivacySettingsViewController: UITableViewController { func crashReportingChanged(_ enabled: Bool) { UserSettings.userHasOptedOutOfCrashLogging = !enabled + + WPAnalytics.track(.privacySettingsReportCrashesToggled, properties: ["enabled": enabled]) + WordPressAppDelegate.crashLogging?.setNeedsDataRefresh() } } diff --git a/WordPress/Classes/ViewRelated/Me/My Profile/MyProfileViewController.swift b/WordPress/Classes/ViewRelated/Me/My Profile/MyProfileViewController.swift index 81788e7bc213..9ba28cd105b9 100644 --- a/WordPress/Classes/ViewRelated/Me/My Profile/MyProfileViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/My Profile/MyProfileViewController.swift @@ -44,6 +44,9 @@ private func makeHeaderView(account: WPAccount) -> MyProfileHeaderView { /// To avoid problems, it's marked private and should only be initialized using the /// `MyProfileViewController` factory functions. private class MyProfileController: SettingsController { + var trackingKey: String { + return "my_profile" + } // MARK: - Private Properties @@ -111,24 +114,28 @@ private class MyProfileController: SettingsController { let firstNameRow = EditableTextRow( title: NSLocalizedString("First Name", comment: "My Profile first name label"), value: settings?.firstName ?? "", - action: presenter.push(editText(AccountSettingsChange.firstName, service: service))) + action: presenter.push(editText(AccountSettingsChange.firstName, service: service)), + fieldName: "first_name") let lastNameRow = EditableTextRow( title: NSLocalizedString("Last Name", comment: "My Profile last name label"), value: settings?.lastName ?? "", - action: presenter.push(editText(AccountSettingsChange.lastName, service: service))) + action: presenter.push(editText(AccountSettingsChange.lastName, service: service)), + fieldName: "last_name") let displayNameRow = EditableTextRow( title: NSLocalizedString("Display Name", comment: "My Profile display name label"), value: settings?.displayName ?? "", - action: presenter.push(editText(AccountSettingsChange.displayName, service: service))) + action: presenter.push(editText(AccountSettingsChange.displayName, service: service)), + fieldName: "display_name") let aboutMeRow = EditableTextRow( title: NSLocalizedString("About Me", comment: "My Profile 'About me' label"), value: settings?.aboutMe ?? "", action: presenter.push(editMultilineText(AccountSettingsChange.aboutMe, hint: NSLocalizedString("Tell us a bit about you.", comment: "My Profile 'About me' hint text"), - service: service))) + service: service)), + fieldName: "about_me") return ImmuTable(sections: [ ImmuTableSection(rows: [ diff --git a/WordPress/Classes/ViewRelated/Post/Scheduling/PublishSettingsViewController.swift b/WordPress/Classes/ViewRelated/Post/Scheduling/PublishSettingsViewController.swift index 5ed89780ce52..ab76864ddeb6 100644 --- a/WordPress/Classes/ViewRelated/Post/Scheduling/PublishSettingsViewController.swift +++ b/WordPress/Classes/ViewRelated/Post/Scheduling/PublishSettingsViewController.swift @@ -123,6 +123,9 @@ private struct DateAndTimeRow: ImmuTableRow { } @objc class PublishSettingsController: NSObject, SettingsController { + var trackingKey: String { + return "publish_settings" + } @objc class func viewController(post: AbstractPost) -> ImmuTableViewController { let controller = PublishSettingsController(post: post) diff --git a/WordPress/Classes/ViewRelated/Tools/SettingsCommon.swift b/WordPress/Classes/ViewRelated/Tools/SettingsCommon.swift index 773b1df955b0..a1dd4c44fb9c 100644 --- a/WordPress/Classes/ViewRelated/Tools/SettingsCommon.swift +++ b/WordPress/Classes/ViewRelated/Tools/SettingsCommon.swift @@ -2,7 +2,9 @@ import UIKit import WordPressKit import CocoaLumberjack -protocol SettingsController: ImmuTableController {} +protocol SettingsController: ImmuTableController { + var trackingKey: String { get } +} // MARK: - Actions extension SettingsController { @@ -55,6 +57,8 @@ extension SettingsController { let change = changeType(value) service.saveChange(change) DDLogDebug("\(title) changed: \(value)") + + trackChangeIfNeeded(row) } return controller @@ -76,8 +80,19 @@ extension SettingsController { let change = changeType(value) service.saveChange(change) DDLogDebug("\(title) changed: \(value)") + + trackChangeIfNeeded(row) } return controller } + + private func trackChangeIfNeeded(_ row: EditableTextRow) { + // Don't track if the field name isn't specified + guard let fieldName = row.fieldName else { + return + } + + WPAnalytics.trackSettingsChange(trackingKey, fieldName: fieldName) + } }