Skip to content

Commit f31cad4

Browse files
Merge pull request #72 from woocommerce/issue/22-woo-epilogue
Login Epilogue: Mark I
2 parents e36e801 + 092250a commit f31cad4

File tree

16 files changed

+665
-74
lines changed

16 files changed

+665
-74
lines changed

WooCommerce/Classes/Authentication/AuthenticationManager.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ extension AuthenticationManager: WordPressAuthenticatorDelegate {
136136
/// Presents the Login Epilogue, in the specified NavigationController.
137137
///
138138
func presentLoginEpilogue(in navigationController: UINavigationController, for credentials: WordPressCredentials, onDismiss: @escaping () -> Void) {
139-
// TODO: Wire Store Picker
139+
let pickerViewController = StorePickerViewController()
140+
navigationController.pushViewController(pickerViewController, animated: true)
140141
}
141142

142143
/// Presents the Signup Epilogue, in the specified NavigationController.
@@ -145,11 +146,10 @@ extension AuthenticationManager: WordPressAuthenticatorDelegate {
145146
// NO-OP: The current WC version does not support Signup.
146147
}
147148

148-
/// Indicates if the Login Epilogue should be presented. This is false only when we're doing a Jetpack Connect, and the new
149-
/// WordPress.com account has no sites. Capicci?
149+
/// Indicates if the Login Epilogue should be presented.
150150
///
151151
func shouldPresentLoginEpilogue(isJetpackLogin: Bool) -> Bool {
152-
return false
152+
return true
153153
}
154154

155155
/// Indicates if the Signup Epilogue should be displayed.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import Foundation
2+
import UIKit
3+
4+
5+
6+
/// AccountHeaderView: Displays an Account's Details: [Gravatar + Name + Username]
7+
///
8+
class AccountHeaderView: UIView {
9+
10+
/// Account's Gravatar.
11+
///
12+
@IBOutlet private var gravatarImageView: UIImageView! {
13+
didSet {
14+
gravatarImageView.image = .gravatarPlaceholderImage
15+
}
16+
}
17+
18+
/// Account's Full Name.
19+
///
20+
@IBOutlet private var fullnameLabel: UILabel!
21+
22+
/// Account's Username.
23+
///
24+
@IBOutlet private var usernameLabel: UILabel! {
25+
didSet {
26+
usernameLabel.textColor = StyleManager.wooGreyTextMin
27+
}
28+
}
29+
}
30+
31+
32+
// MARK: - Public Methods
33+
//
34+
extension AccountHeaderView {
35+
36+
/// Account's Username.
37+
///
38+
var username: String? {
39+
set {
40+
usernameLabel.text = newValue
41+
}
42+
get {
43+
return usernameLabel.text
44+
}
45+
}
46+
47+
/// Account's Full Name
48+
///
49+
var fullname: String? {
50+
set {
51+
fullnameLabel.text = newValue
52+
}
53+
get {
54+
return fullnameLabel.text
55+
}
56+
}
57+
58+
/// Downloads (and displays) the Gravatar associated with the specified Email.
59+
///
60+
func downloadGravatar(with email: String) {
61+
gravatarImageView.downloadGravatarWithEmail(email)
62+
}
63+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+
<device id="retina4_7" orientation="portrait">
4+
<adaptation id="fullscreen"/>
5+
</device>
6+
<dependencies>
7+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
8+
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
9+
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10+
</dependencies>
11+
<objects>
12+
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
13+
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
14+
<view contentMode="scaleToFill" id="wsJ-iY-FyE" customClass="AccountHeaderView" customModule="WooCommerce" customModuleProvider="target">
15+
<rect key="frame" x="0.0" y="0.0" width="375" height="174"/>
16+
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
17+
<subviews>
18+
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" verticalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="vOQ-CP-fZ1" customClass="CircularImageView" customModule="WooCommerce" customModuleProvider="target">
19+
<rect key="frame" x="157.5" y="29" width="60" height="60"/>
20+
<constraints>
21+
<constraint firstAttribute="height" constant="60" id="IcJ-wJ-Tra"/>
22+
<constraint firstAttribute="width" constant="60" id="cwR-2d-T4e"/>
23+
</constraints>
24+
</imageView>
25+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="252" horizontalCompressionResistancePriority="1000" verticalCompressionResistancePriority="1000" text="Full Name" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xHF-gJ-reo">
26+
<rect key="frame" x="10" y="97" width="355" height="20.5"/>
27+
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
28+
<nil key="textColor"/>
29+
<nil key="highlightedColor"/>
30+
</label>
31+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="253" verticalCompressionResistancePriority="1000" text="@username" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LiJ-G2-nZS">
32+
<rect key="frame" x="10" y="125.5" width="355" height="18"/>
33+
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
34+
<color key="textColor" cocoaTouchSystemColor="scrollViewTexturedBackgroundColor"/>
35+
<nil key="highlightedColor"/>
36+
</label>
37+
</subviews>
38+
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
39+
<constraints>
40+
<constraint firstItem="LiJ-G2-nZS" firstAttribute="leading" secondItem="DAy-rN-ump" secondAttribute="leading" constant="10" id="4a0-8q-Z34"/>
41+
<constraint firstItem="xHF-gJ-reo" firstAttribute="top" secondItem="vOQ-CP-fZ1" secondAttribute="bottom" constant="8" id="BTx-oz-REg"/>
42+
<constraint firstItem="DAy-rN-ump" firstAttribute="trailing" secondItem="xHF-gJ-reo" secondAttribute="trailing" constant="10" id="JKO-gN-oNe"/>
43+
<constraint firstItem="vOQ-CP-fZ1" firstAttribute="centerX" secondItem="wsJ-iY-FyE" secondAttribute="centerX" id="NgM-Yn-gMx"/>
44+
<constraint firstItem="DAy-rN-ump" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="LiJ-G2-nZS" secondAttribute="bottom" constant="29" id="Ved-ir-LoS"/>
45+
<constraint firstItem="xHF-gJ-reo" firstAttribute="leading" secondItem="DAy-rN-ump" secondAttribute="leading" constant="10" id="bvI-bc-8La"/>
46+
<constraint firstItem="LiJ-G2-nZS" firstAttribute="top" secondItem="xHF-gJ-reo" secondAttribute="bottom" constant="8" id="gOl-k9-naS"/>
47+
<constraint firstItem="DAy-rN-ump" firstAttribute="trailing" secondItem="LiJ-G2-nZS" secondAttribute="trailing" constant="10" id="je2-Uv-FAR"/>
48+
<constraint firstItem="vOQ-CP-fZ1" firstAttribute="top" secondItem="DAy-rN-ump" secondAttribute="top" constant="29" id="yHD-B7-H48"/>
49+
</constraints>
50+
<nil key="simulatedTopBarMetrics"/>
51+
<nil key="simulatedBottomBarMetrics"/>
52+
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
53+
<viewLayoutGuide key="safeArea" id="DAy-rN-ump"/>
54+
<connections>
55+
<outlet property="fullnameLabel" destination="xHF-gJ-reo" id="ba9-Sw-RJO"/>
56+
<outlet property="gravatarImageView" destination="vOQ-CP-fZ1" id="K0E-fC-gY9"/>
57+
<outlet property="usernameLabel" destination="LiJ-G2-nZS" id="SiG-bv-eTM"/>
58+
</connections>
59+
<point key="canvasLocation" x="-6.5" y="-323"/>
60+
</view>
61+
</objects>
62+
</document>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Foundation
2+
import UIKit
3+
4+
5+
/// EmptyStores: Displayed whenever there are no available WooCommerce Stores associated with the active account.
6+
///
7+
class EmptyStoresTableViewCell: UITableViewCell {
8+
9+
/// UITableView's Reuse Identifier.
10+
///
11+
static let reuseIdentifier = EmptyStoresTableViewCell.classNameWithoutNamespaces
12+
13+
/// LegendLabel: To be displayed below the ImageView.
14+
///
15+
@IBOutlet private var legendLabel: UILabel! {
16+
didSet {
17+
legendLabel.textColor = StyleManager.wooGreyTextMin
18+
legendLabel.font = .subheadline
19+
legendLabel.text = NSLocalizedString("Unable to find WooCommerce stores connected to this account",
20+
comment: "Displayed during the Login flow, whenever the user has no woo stores associated.")
21+
}
22+
}
23+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+
<device id="retina4_7" orientation="portrait">
4+
<adaptation id="fullscreen"/>
5+
</device>
6+
<dependencies>
7+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
8+
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
9+
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10+
</dependencies>
11+
<objects>
12+
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
13+
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
14+
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" rowHeight="242" id="qMv-Pb-lgn" customClass="EmptyStoresTableViewCell" customModule="WooCommerce" customModuleProvider="target">
15+
<rect key="frame" x="0.0" y="0.0" width="375" height="242"/>
16+
<autoresizingMask key="autoresizingMask"/>
17+
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="qMv-Pb-lgn" id="gcY-Gg-DvR">
18+
<rect key="frame" x="0.0" y="0.0" width="375" height="241.5"/>
19+
<autoresizingMask key="autoresizingMask"/>
20+
<subviews>
21+
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="woo-no-store" translatesAutoresizingMaskIntoConstraints="NO" id="uuh-xp-DA5">
22+
<rect key="frame" x="0.0" y="0.0" width="375" height="180"/>
23+
</imageView>
24+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bPV-bJ-GBz">
25+
<rect key="frame" x="26" y="200.5" width="323" height="20.5"/>
26+
<fontDescription key="fontDescription" type="system" pointSize="17"/>
27+
<nil key="textColor"/>
28+
<nil key="highlightedColor"/>
29+
</label>
30+
</subviews>
31+
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
32+
<constraints>
33+
<constraint firstItem="bPV-bJ-GBz" firstAttribute="leading" secondItem="gcY-Gg-DvR" secondAttribute="leadingMargin" constant="10" id="02T-fd-amz"/>
34+
<constraint firstAttribute="trailingMargin" secondItem="bPV-bJ-GBz" secondAttribute="trailing" constant="10" id="4v0-dU-uL0"/>
35+
<constraint firstItem="uuh-xp-DA5" firstAttribute="top" secondItem="gcY-Gg-DvR" secondAttribute="top" id="AXH-sZ-i9m"/>
36+
<constraint firstItem="uuh-xp-DA5" firstAttribute="leading" secondItem="gcY-Gg-DvR" secondAttribute="leading" id="QK4-JX-5Z1"/>
37+
<constraint firstItem="bPV-bJ-GBz" firstAttribute="top" relation="greaterThanOrEqual" secondItem="uuh-xp-DA5" secondAttribute="bottom" constant="10" id="YHi-MJ-ZFK"/>
38+
<constraint firstAttribute="bottomMargin" secondItem="bPV-bJ-GBz" secondAttribute="bottom" constant="10" id="Zyf-Uq-D8M"/>
39+
<constraint firstAttribute="trailing" secondItem="uuh-xp-DA5" secondAttribute="trailing" id="egs-Ij-2lL"/>
40+
</constraints>
41+
</tableViewCellContentView>
42+
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
43+
<connections>
44+
<outlet property="legendLabel" destination="bPV-bJ-GBz" id="sQX-ir-ghQ"/>
45+
</connections>
46+
<point key="canvasLocation" x="-162.5" y="-12"/>
47+
</tableViewCell>
48+
</objects>
49+
<resources>
50+
<image name="woo-no-store" width="320" height="180"/>
51+
</resources>
52+
</document>
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import Foundation
2+
import UIKit
3+
import WordPressAuthenticator
4+
import WordPressUI
5+
6+
7+
/// Allows the user to pick which WordPress.com (OR) Jetpack-Connected-Store we should set up as the Main Store.
8+
///
9+
class StorePickerViewController: UIViewController {
10+
11+
/// No Results Placeholder Image
12+
///
13+
@IBOutlet private var noResultsImageView: UIImageView!
14+
15+
/// No Results Placeholder Text
16+
///
17+
@IBOutlet private var noResultsLabel: UILabel! {
18+
didSet {
19+
noResultsLabel.font = StyleManager.subheadlineFont
20+
noResultsLabel.textColor = StyleManager.wooGreyTextMin
21+
}
22+
}
23+
24+
/// Header View: Displays all of the Account Details
25+
///
26+
private let accountHeaderView: AccountHeaderView = {
27+
return AccountHeaderView.instantiateFromNib()
28+
}()
29+
30+
/// Main tableView
31+
///
32+
@IBOutlet private var tableView: UITableView! {
33+
didSet {
34+
tableView.tableHeaderView = accountHeaderView
35+
}
36+
}
37+
38+
/// White-Background View, to be placed surrounding the bottom area.
39+
///
40+
@IBOutlet private var actionBackgroundView: UIView! {
41+
didSet {
42+
actionBackgroundView.layer.masksToBounds = false
43+
actionBackgroundView.layer.shadowOpacity = StorePickerConstants.backgroundShadowOpacity
44+
}
45+
}
46+
47+
/// Default Action Button.
48+
///
49+
@IBOutlet private var actionButton: UIButton! {
50+
didSet {
51+
actionButton.backgroundColor = .clear
52+
}
53+
}
54+
55+
/// Closure to be executed upon dismissal.
56+
///
57+
var onDismiss: (() -> Void)?
58+
59+
60+
61+
// MARK: - Overridden Methods
62+
63+
override func viewDidLoad() {
64+
super.viewDidLoad()
65+
66+
setup(mainView: view)
67+
registerTableViewCells()
68+
displayAccountDetails(in: accountHeaderView)
69+
}
70+
71+
override func viewWillAppear(_ animated: Bool) {
72+
super.viewWillAppear(animated)
73+
navigationController?.setNavigationBarHidden(true, animated: animated)
74+
}
75+
76+
override func viewWillDisappear(_ animated: Bool) {
77+
super.viewWillDisappear(animated)
78+
onDismiss?()
79+
}
80+
}
81+
82+
83+
// MARK: - Initialization Methods
84+
//
85+
private extension StorePickerViewController {
86+
87+
func setup(mainView: UIView) {
88+
mainView.backgroundColor = StyleManager.tableViewBackgroundColor
89+
}
90+
91+
func registerTableViewCells() {
92+
let cells = [
93+
EmptyStoresTableViewCell.reuseIdentifier: EmptyStoresTableViewCell.loadNib()
94+
]
95+
96+
for (reuseIdentifier, nib) in cells {
97+
tableView.register(nib, forCellReuseIdentifier: reuseIdentifier)
98+
}
99+
}
100+
101+
func displayAccountDetails(in headerView: AccountHeaderView) {
102+
guard let defaultAccount = StoresManager.shared.sessionManager.defaultAccount else {
103+
return
104+
}
105+
106+
headerView.username = "@" + defaultAccount.username
107+
headerView.fullname = defaultAccount.displayName
108+
headerView.downloadGravatar(with: defaultAccount.email)
109+
}
110+
}
111+
112+
113+
// MARK: - Action Handlers
114+
//
115+
extension StorePickerViewController {
116+
117+
/// Proceeds with the Login Flow.
118+
///
119+
@IBAction func continueWasPressed() {
120+
dismiss(animated: true, completion: nil)
121+
}
122+
}
123+
124+
125+
// MARK: - Action Handlers
126+
//
127+
extension StorePickerViewController: UITableViewDataSource {
128+
129+
func numberOfSections(in tableView: UITableView) -> Int {
130+
return 1
131+
}
132+
133+
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
134+
return 1
135+
}
136+
137+
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
138+
return tableView.dequeueReusableCell(withIdentifier: EmptyStoresTableViewCell.reuseIdentifier, for: indexPath)
139+
}
140+
}
141+
142+
143+
// MARK: - StorePickerConstants: Contains all of the constants required by the Picker.
144+
//
145+
private enum StorePickerConstants {
146+
static let backgroundShadowOpacity = Float(0.2)
147+
}
148+
149+
150+
// MARK: - Represents the StorePickerViewController's Internal State.
151+
//
152+
private enum StorePickerState {
153+
case empty
154+
case single
155+
case multiple
156+
}

0 commit comments

Comments
 (0)