Skip to content

Commit

Permalink
Merge pull request #17564 from wordpress-mobile/epic/onboarding-impro…
Browse files Browse the repository at this point in the history
…vements

Onboarding Improvements: Epilogue (select site / create a new site) + Quick Start prompt
  • Loading branch information
momo-ozawa authored Nov 25, 2021
2 parents 271409a + 9e32d77 commit 2a367e4
Show file tree
Hide file tree
Showing 28 changed files with 1,061 additions and 468 deletions.
1 change: 1 addition & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* [***] Fixes a crasher that was sometimes triggered when seeing the details for like notifications.

* [*] Editor: Show a compact notice when switching between HTML or Visual mode. [https://github.com/wordpress-mobile/WordPress-iOS/pull/17521]
* [*] Onboarding Improvements: Need a little help after login? We're here for you. We've made a few changes to the login flow that will make it easier for you to start managing your site or create a new one. [#17564]
* [***] Fixed crash where uploading image when offline crashes iOS app. [#17488]

18.7
Expand Down
17 changes: 11 additions & 6 deletions WordPress/Classes/System/WindowManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ class WindowManager: NSObject {
/// Shows the initial UI for the App to be shown right after launch. This method will present the sign-in flow if the user is not
/// authenticated, or the actuall App UI if the user is already authenticated.
///
public func showUI() {
public func showUI(for blog: Blog? = nil) {
if AccountHelper.isLoggedIn {
showAppUI()
showAppUI(for: blog)
} else {
showSignInUI()
}
Expand All @@ -45,20 +45,25 @@ class WindowManager: NSObject {
showSignInUI()
}

func dismissFullscreenSignIn(completion: Completion? = nil) {
func dismissFullscreenSignIn(blogToShow: Blog? = nil, completion: Completion? = nil) {
guard isShowingFullscreenSignIn == true && AccountHelper.isLoggedIn == true else {
return
}

showAppUI(completion: completion)
showAppUI(for: blogToShow, completion: completion)
}

/// Shows the UI for authenticated users.
///
func showAppUI(completion: Completion? = nil) {
func showAppUI(for blog: Blog? = nil, completion: Completion? = nil) {
isShowingFullscreenSignIn = false

show(WPTabBarController.sharedInstance(), completion: completion)

guard let blog = blog else {
return
}

WPTabBarController.sharedInstance()?.showBlogDetails(for: blog)
}

/// Shows the initial UI for unauthenticated users.
Expand Down
10 changes: 10 additions & 0 deletions WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@ import Foundation
case privacySettingsOpened
case privacySettingsReportCrashesToggled

// Login: Epilogue
case loginEpilogueChooseSiteTapped
case loginEpilogueCreateNewSiteTapped

/// A String that represents the event
var value: String {
switch self {
Expand Down Expand Up @@ -690,6 +694,12 @@ import Foundation
return "account_close_tapped"
case .accountCloseCompleted:
return "account_close_completed"

// Login: Epilogue
case .loginEpilogueChooseSiteTapped:
return "login_epilogue_choose_site_tapped"
case .loginEpilogueCreateNewSiteTapped:
return "login_epilogue_create_new_site_tapped"
} // END OF SWITCH
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ extension BlogDetailsViewController {
return
}
let newWorkItem = DispatchWorkItem { [weak self] in
self?.showNoticeOrAlertAsNeeded()
self?.showNoticeAsNeeded()
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: newWorkItem)
alertWorkItem = newWorkItem
Expand All @@ -80,13 +80,8 @@ extension BlogDetailsViewController {
return false
}

private func showNoticeOrAlertAsNeeded() {

if QuickStartTourGuide.shared.shouldShowUpgradeToV2Notice(for: blog) {
showUpgradeToV2Alert(for: blog)

QuickStartTourGuide.shared.didShowUpgradeToV2Notice(for: blog)
} else if let tourToSuggest = QuickStartTourGuide.shared.tourToSuggest(for: blog) {
private func showNoticeAsNeeded() {
if let tourToSuggest = QuickStartTourGuide.shared.tourToSuggest(for: blog) {
QuickStartTourGuide.shared.suggest(tourToSuggest, for: blog)
}
}
Expand Down Expand Up @@ -165,17 +160,4 @@ extension BlogDetailsViewController {
section.showQuickStartMenu = true
return section
}

private func showUpgradeToV2Alert(for blog: Blog) {
guard noPresentedViewControllers else {
return
}

let alert = FancyAlertViewController.makeQuickStartUpgradeToV2AlertController(blog: blog)
alert.modalPresentationStyle = .custom
alert.transitioningDelegate = self
tabBarController?.present(alert, animated: true)

WPAnalytics.track(.quickStartMigrationDialogViewed)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import UIKit

final class QuickStartPromptViewController: UIViewController {

// MARK: - IBOutlets

/// Site info
@IBOutlet private weak var siteIconView: UIImageView!
@IBOutlet private weak var siteTitleLabel: UILabel!
@IBOutlet private weak var siteDescriptionLabel: UILabel!

/// Prompt info
@IBOutlet private weak var promptTitleLabel: UILabel!
@IBOutlet private weak var promptDescriptionLabel: UILabel!

/// Buttons
@IBOutlet private weak var showMeAroundButton: FancyButton!
@IBOutlet private weak var noThanksButton: FancyButton!

// MARK: - Properties

private let blog: Blog
private let quickStartSettings: QuickStartSettings

/// Closure to be executed upon dismissal.
///
var onDismiss: ((Blog) -> Void)?

// MARK: - Init

init(blog: Blog, quickStartSettings: QuickStartSettings = QuickStartSettings()) {
self.blog = blog
self.quickStartSettings = quickStartSettings
super.init(nibName: nil, bundle: nil)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// MARK: - Lifecycle

override func viewDidLoad() {
super.viewDidLoad()
applyStyles()
setup()
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIAccessibility.post(notification: .layoutChanged, argument: promptTitleLabel)
}

// MARK: - Styling

private func applyStyles() {
siteTitleLabel.numberOfLines = 0
siteTitleLabel.font = WPStyleGuide.fontForTextStyle(.subheadline)
siteTitleLabel.textColor = .text

siteDescriptionLabel.numberOfLines = 0
siteDescriptionLabel.font = WPStyleGuide.fontForTextStyle(.subheadline)
siteDescriptionLabel.textColor = .textSubtle

promptTitleLabel.numberOfLines = 0
promptTitleLabel.font = WPStyleGuide.fontForTextStyle(.callout, fontWeight: .medium)
promptTitleLabel.textColor = .text

promptDescriptionLabel.numberOfLines = 0
promptDescriptionLabel.font = WPStyleGuide.fontForTextStyle(.subheadline)
promptDescriptionLabel.textColor = .textSubtle

showMeAroundButton.isPrimary = true
noThanksButton.isPrimary = false
}

// MARK: - Setup

private func setup() {
setupSiteInfoViews()
setupPromptInfoViews()
setupButtons()
}

private func setupSiteInfoViews() {
siteIconView.downloadSiteIcon(for: blog)

let displayURL = blog.displayURL as String? ?? ""
if let name = blog.settings?.name?.nonEmptyString() {
siteTitleLabel.text = name
siteDescriptionLabel.text = displayURL
} else {
siteTitleLabel.text = displayURL
siteDescriptionLabel.text = nil
}
}

private func setupPromptInfoViews() {
promptTitleLabel.text = Strings.promptTitle
promptDescriptionLabel.text = Strings.promptDescription
}

private func setupButtons() {
showMeAroundButton.setTitle(Strings.showMeAroundButtonTitle, for: .normal)
noThanksButton.setTitle(Strings.noThanksButtonTitle, for: .normal)
}

// MARK: - IBAction

@IBAction private func showMeAroundButtonTapped(_ sender: Any) {
onDismiss?(blog)
dismiss(animated: true)

WPAnalytics.track(.quickStartRequestAlertButtonTapped, withProperties: ["type": "positive"])
}

@IBAction private func noThanksButtonTapped(_ sender: Any) {
quickStartSettings.setPromptWasDismissed(true, for: blog)
onDismiss?(blog)
dismiss(animated: true)

WPAnalytics.track(.quickStartRequestAlertButtonTapped, withProperties: ["type": "neutral"])
}
}

extension QuickStartPromptViewController {

private enum Strings {
static let promptTitle = NSLocalizedString("Want a little help managing this site with the app?", comment: "Title for a prompt asking if users want to try out the quick start checklist.")
static let promptDescription = NSLocalizedString("Learn the basics with a quick walk through.", comment: "Description for a prompt asking if users want to try out the quick start checklist.")
static let showMeAroundButtonTitle = NSLocalizedString("Show me around", comment: "Button title. When tapped, the quick start checklist will be shown.")
static let noThanksButtonTitle = NSLocalizedString("No thanks", comment: "Button title. When tapped, the quick start checklist will not be shown, and the prompt will be dismissed.")
}

}
124 changes: 124 additions & 0 deletions WordPress/Classes/ViewRelated/Blog/QuickStartPromptViewController.xib
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19455" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19454"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="QuickStartPromptViewController" customModule="WordPress" customModuleProvider="target">
<connections>
<outlet property="noThanksButton" destination="2uc-tK-alt" id="EyT-E0-oLS"/>
<outlet property="promptDescriptionLabel" destination="Kqr-FO-d5M" id="lbG-CU-xOm"/>
<outlet property="promptTitleLabel" destination="doQ-6M-3Uv" id="i5m-E1-5kU"/>
<outlet property="showMeAroundButton" destination="0WF-fO-mti" id="MyR-dp-DjP"/>
<outlet property="siteDescriptionLabel" destination="T6b-Pg-T2k" id="Jbd-bS-EqF"/>
<outlet property="siteIconView" destination="5pl-dB-rPb" id="ovD-LF-JHV"/>
<outlet property="siteTitleLabel" destination="3V2-cy-NN5" id="ool-ZA-cxV"/>
<outlet property="view" destination="i5M-Pr-FkT" id="w2c-2a-ctD"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" layoutMarginsFollowReadableWidth="YES" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="wS6-OQ-uc5">
<rect key="frame" x="20" y="124" width="374" height="110"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="5oK-P9-biU">
<rect key="frame" x="0.0" y="0.0" width="374" height="45"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="5pl-dB-rPb">
<rect key="frame" x="0.0" y="2.5" width="40" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="LBc-8A-qPF"/>
<constraint firstAttribute="width" secondItem="5pl-dB-rPb" secondAttribute="height" id="VjL-ts-OLa"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="lqh-pW-MOV">
<rect key="frame" x="50" y="0.0" width="324" height="45"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3V2-cy-NN5">
<rect key="frame" x="0.0" y="0.0" width="324" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="T6b-Pg-T2k">
<rect key="frame" x="0.0" y="24.5" width="324" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="kWJ-TZ-NYM">
<rect key="frame" x="0.0" y="61" width="374" height="49"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="doQ-6M-3Uv">
<rect key="frame" x="0.0" y="0.0" width="374" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Kqr-FO-d5M">
<rect key="frame" x="0.0" y="28.5" width="374" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="88c-8d-UbI">
<rect key="frame" x="20" y="734" width="374" height="104"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0WF-fO-mti" customClass="FancyButton" customModule="WordPressUI">
<rect key="frame" x="0.0" y="0.0" width="374" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="B3O-Yu-fRo"/>
</constraints>
<state key="normal" title="Button"/>
<connections>
<action selector="showMeAroundButtonTapped:" destination="-1" eventType="touchUpInside" id="mp9-Ig-efP"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2uc-tK-alt" customClass="FancyButton" customModule="WordPressUI">
<rect key="frame" x="0.0" y="60" width="374" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="oud-dv-V6a"/>
</constraints>
<state key="normal" title="Button"/>
<connections>
<action selector="noThanksButtonTapped:" destination="-1" eventType="touchUpInside" id="pO2-el-6ic"/>
</connections>
</button>
</subviews>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="wS6-OQ-uc5" secondAttribute="trailing" id="Ado-d7-g5C"/>
<constraint firstItem="wS6-OQ-uc5" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leadingMargin" id="MFc-W9-00A"/>
<constraint firstAttribute="leadingMargin" secondItem="88c-8d-UbI" secondAttribute="leading" id="Qbc-f2-ZaH"/>
<constraint firstAttribute="trailingMargin" secondItem="88c-8d-UbI" secondAttribute="trailing" id="daa-Gn-9WI"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="88c-8d-UbI" secondAttribute="bottom" constant="24" id="oQS-J2-RXn"/>
<constraint firstItem="wS6-OQ-uc5" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="80" id="vN3-dJ-56h"/>
</constraints>
<point key="canvasLocation" x="132" y="76"/>
</view>
</objects>
<resources>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
Loading

0 comments on commit 2a367e4

Please sign in to comment.