Skip to content

Commit 63e9df7

Browse files
authored
Merge pull request #5475 from woocommerce/issue/5365-install-jetpack-initial-UI
JCP: Install Jetpack intro screen
2 parents 584e72d + 85276ab commit 63e9df7

File tree

9 files changed

+171
-6
lines changed

9 files changed

+171
-6
lines changed

WooCommerce/Classes/Extensions/UIImage+Woo.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,10 @@ extension UIImage {
336336
return UIImage(named: "icon-jetpack-gray")!
337337
}
338338

339+
static var jetpackGreenLogoImage: UIImage {
340+
return UIImage(named: "icon-jetpack-green")!
341+
}
342+
339343
/// Info Icon
340344
///
341345
static var infoImage: UIImage {

WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewController.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,17 @@ private extension DashboardViewController {
223223
bottomJetpackBenefitsBannerController.setActions { [weak self] in
224224
guard let self = self else { return }
225225
let benefitsController = JetpackBenefitsHostingController()
226-
benefitsController.setActions {
227-
// TODO: 5370 - Navigate to install Jetpack
226+
benefitsController.setActions { [weak self] in
227+
self?.dismiss(animated: true, completion: { [weak self] in
228+
guard let siteURL = ServiceLocator.stores.sessionManager.defaultSite?.url else {
229+
return
230+
}
231+
let installController = JetpackInstallHostingController(siteURL: siteURL)
232+
installController.setDismissAction { [weak self] in
233+
self?.dismiss(animated: true, completion: nil)
234+
}
235+
self?.present(installController, animated: true, completion: nil)
236+
})
228237
} dismissAction: { [weak self] in
229238
self?.dismiss(animated: true, completion: nil)
230239
}

WooCommerce/Classes/ViewRelated/Dashboard/JetpackConnectionPackageSites/JetpackBenefitsBanner.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,8 @@ struct JetpackBenefitsBanner: View {
6363
var body: some View {
6464
Group {
6565
HStack(spacing: Layout.horizontalSpacing) {
66-
Image(uiImage: .jetpackLogoImage)
66+
Image(uiImage: .jetpackGreenLogoImage)
6767
.resizable()
68-
.renderingMode(.template)
69-
.foregroundColor(Color(.jetpackGreen))
7068
.frame(width: Layout.iconDimension * scale, height: Layout.iconDimension * scale)
7169
VStack(alignment: .leading, spacing: Layout.verticalTextSpacing) {
7270
Text(Localization.title)
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import SwiftUI
2+
3+
/// Hosting controller wrapper for `JetpackInstallIntroView`
4+
///
5+
final class JetpackInstallHostingController: UIHostingController<JetpackInstallIntroView> {
6+
init(siteURL: String) {
7+
super.init(rootView: JetpackInstallIntroView(siteURL: siteURL))
8+
}
9+
10+
required dynamic init?(coder aDecoder: NSCoder) {
11+
fatalError("init(coder:) has not been implemented")
12+
}
13+
14+
func setDismissAction(_ dismissAction: @escaping () -> Void) {
15+
rootView.dismissAction = dismissAction
16+
}
17+
}
18+
19+
/// Displays the intro view for the Jetpack install flow.
20+
///
21+
struct JetpackInstallIntroView: View {
22+
// Closure invoked when Close button is tapped
23+
var dismissAction: () -> Void = {}
24+
25+
private let siteURL: String
26+
27+
init(siteURL: String) {
28+
self.siteURL = siteURL
29+
}
30+
31+
private var descriptionAttributedString: NSAttributedString {
32+
let font: UIFont = .body
33+
let boldFont: UIFont = font.bold
34+
let siteName = siteURL.trimHTTPScheme()
35+
36+
let paragraphStyle = NSMutableParagraphStyle()
37+
paragraphStyle.alignment = .center
38+
39+
let attributedString = NSMutableAttributedString(
40+
string: String(format: Localization.installDescription, siteName),
41+
attributes: [.font: font,
42+
.foregroundColor: UIColor.text.withAlphaComponent(0.8),
43+
.paragraphStyle: paragraphStyle,
44+
]
45+
)
46+
let boldSiteAddress = NSAttributedString(string: siteName, attributes: [.font: boldFont, .foregroundColor: UIColor.text])
47+
attributedString.replaceFirstOccurrence(of: siteName, with: boldSiteAddress)
48+
return attributedString
49+
}
50+
51+
@ScaledMetric private var scale: CGFloat = 1.0
52+
53+
var body: some View {
54+
VStack {
55+
HStack {
56+
Button(Localization.closeButton, action: dismissAction)
57+
.buttonStyle(LinkButtonStyle())
58+
.fixedSize(horizontal: true, vertical: true)
59+
.padding(.top, Constants.cancelButtonTopMargin)
60+
Spacer()
61+
}
62+
63+
Spacer()
64+
65+
// Install Jetpack description
66+
VStack(spacing: Constants.contentSpacing) {
67+
Image(uiImage: .jetpackGreenLogoImage)
68+
.resizable()
69+
.frame(width: Constants.jetpackLogoSize * scale, height: Constants.jetpackLogoSize * scale)
70+
.padding(.bottom, Constants.jetpackLogoBottomMargin)
71+
72+
Text(Localization.installTitle)
73+
.font(.largeTitle)
74+
.bold()
75+
.foregroundColor(.primary)
76+
77+
AttributedText(descriptionAttributedString)
78+
}
79+
.padding(.horizontal, Constants.contentHorizontalMargin)
80+
.scrollVerticallyIfNeeded()
81+
82+
Spacer()
83+
84+
// Primary Button to install Jetpack
85+
Button(Localization.installAction, action: {
86+
// TODO: Show main install screen
87+
})
88+
.buttonStyle(PrimaryButtonStyle())
89+
.fixedSize(horizontal: false, vertical: true)
90+
.padding(.horizontal, Constants.actionButtonMargin)
91+
.padding(.bottom, Constants.actionButtonMargin)
92+
}
93+
}
94+
}
95+
96+
private extension JetpackInstallIntroView {
97+
enum Constants {
98+
static let cancelButtonTopMargin: CGFloat = 8
99+
static let jetpackLogoSize: CGFloat = 120
100+
static let jetpackLogoBottomMargin: CGFloat = 24
101+
static let actionButtonMargin: CGFloat = 16
102+
static let contentHorizontalMargin: CGFloat = 40
103+
static let contentSpacing: CGFloat = 8
104+
}
105+
106+
enum Localization {
107+
static let closeButton = NSLocalizedString("Close", comment: "Title of the Close action on the Jetpack Install view")
108+
static let installAction = NSLocalizedString("Get Started", comment: "Title of install action in the Jetpack Install view.")
109+
static let installTitle = NSLocalizedString("Install Jetpack", comment: "Title of the Install Jetpack intro view")
110+
static let installDescription = NSLocalizedString("Install the free Jetpack plugin to %1$@ and experience the best mobile experience.",
111+
comment: "Description of the Jetpack Install flow for the specified site. " +
112+
"The %1$@ is the site address.")
113+
}
114+
}
115+
116+
struct JetpackInstallIntroView_Previews: PreviewProvider {
117+
static var previews: some View {
118+
JetpackInstallIntroView(siteURL: "automattic.com")
119+
.preferredColorScheme(.light)
120+
.previewLayout(.fixed(width: 414, height: 780))
121+
122+
JetpackInstallIntroView(siteURL: "automattic.com")
123+
.preferredColorScheme(.dark)
124+
.previewLayout(.fixed(width: 800, height: 400))
125+
}
126+
}

WooCommerce/Classes/ViewRelated/ReusableViews/SwiftUI Components/AttributedText.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ private struct TextViewWrapper: UIViewRepresentable {
132132
}
133133

134134
func updateUIView(_ uiView: View, context: Context) {
135-
uiView.attributedText = attributedText
136135
uiView.maxLayoutWidth = maxLayoutWidth
137136
uiView.font = context.environment.font?.uiFont ?? UIFont.preferredFont(forTextStyle: .body)
138137
uiView.textColor = context.environment.foregroundColor.map(UIColor.init)
138+
uiView.attributedText = attributedText
139139

140140
var linkTextAttributes = uiView.linkTextAttributes ?? [:]
141141
linkTextAttributes[.underlineColor] = UIColor.clear
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"images" : [
3+
{
4+
"filename" : "icon-jetpack-green.pdf",
5+
"idiom" : "universal"
6+
}
7+
],
8+
"info" : {
9+
"author" : "xcode",
10+
"version" : 1
11+
}
12+
}
Binary file not shown.

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,6 +1336,7 @@
13361336
DE1B030D268DD01A00804330 /* ReviewOrderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1B030B268DD01A00804330 /* ReviewOrderViewController.swift */; };
13371337
DE1B030E268DD01A00804330 /* ReviewOrderViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = DE1B030C268DD01A00804330 /* ReviewOrderViewController.xib */; };
13381338
DE1B0310268EB2FB00804330 /* ReviewOrderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1B030F268EB2FB00804330 /* ReviewOrderViewModel.swift */; };
1339+
DE23CFFA27462D8F003BE54E /* JetpackInstallIntroView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE23CFF927462D8F003BE54E /* JetpackInstallIntroView.swift */; };
13391340
DE279BA426E9C4DC002BA963 /* ShippingLabelPackagesForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE279BA326E9C4DC002BA963 /* ShippingLabelPackagesForm.swift */; };
13401341
DE279BA626E9C582002BA963 /* ShippingLabelPackagesFormViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE279BA526E9C582002BA963 /* ShippingLabelPackagesFormViewModel.swift */; };
13411342
DE279BA826E9C8E3002BA963 /* ShippingLabelSinglePackage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE279BA726E9C8E3002BA963 /* ShippingLabelSinglePackage.swift */; };
@@ -2823,6 +2824,7 @@
28232824
DE1B030B268DD01A00804330 /* ReviewOrderViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewOrderViewController.swift; sourceTree = "<group>"; };
28242825
DE1B030C268DD01A00804330 /* ReviewOrderViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReviewOrderViewController.xib; sourceTree = "<group>"; };
28252826
DE1B030F268EB2FB00804330 /* ReviewOrderViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewOrderViewModel.swift; sourceTree = "<group>"; };
2827+
DE23CFF927462D8F003BE54E /* JetpackInstallIntroView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackInstallIntroView.swift; sourceTree = "<group>"; };
28262828
DE279BA326E9C4DC002BA963 /* ShippingLabelPackagesForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPackagesForm.swift; sourceTree = "<group>"; };
28272829
DE279BA526E9C582002BA963 /* ShippingLabelPackagesFormViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPackagesFormViewModel.swift; sourceTree = "<group>"; };
28282830
DE279BA726E9C8E3002BA963 /* ShippingLabelSinglePackage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelSinglePackage.swift; sourceTree = "<group>"; };
@@ -6234,6 +6236,7 @@
62346236
CE85FD5120F677460080B73E /* Dashboard */ = {
62356237
isa = PBXGroup;
62366238
children = (
6239+
DE23CFF827462CD2003BE54E /* JetpackInstall */,
62376240
02F843D8273646190017FE12 /* JetpackConnectionPackageSites */,
62386241
028BAC4322F3AE3B008BB4AF /* Stats v4 */,
62396242
029D444B22F1417400DEFA8A /* Stats v3 */,
@@ -6673,6 +6676,14 @@
66736676
path = "Review Order";
66746677
sourceTree = "<group>";
66756678
};
6679+
DE23CFF827462CD2003BE54E /* JetpackInstall */ = {
6680+
isa = PBXGroup;
6681+
children = (
6682+
DE23CFF927462D8F003BE54E /* JetpackInstallIntroView.swift */,
6683+
);
6684+
path = JetpackInstall;
6685+
sourceTree = "<group>";
6686+
};
66766687
DE279BA226E9C3BF002BA963 /* Multi-package */ = {
66776688
isa = PBXGroup;
66786689
children = (
@@ -8186,6 +8197,7 @@
81868197
450C2CBA24D3127500D570DD /* ProductReviewsTableViewCell.swift in Sources */,
81878198
029D444922F13F8A00DEFA8A /* DashboardUIFactory.swift in Sources */,
81888199
D8C2A28F231BD00500F503E9 /* ReviewsViewModel.swift in Sources */,
8200+
DE23CFFA27462D8F003BE54E /* JetpackInstallIntroView.swift in Sources */,
81898201
021AEF9E2407F55C00029D28 /* PHAssetImageLoader.swift in Sources */,
81908202
26E0AE1926335AA900A5EB3B /* Survey.swift in Sources */,
81918203
0298430C259351F100979CAE /* ShippingLabelsTopBannerFactory.swift in Sources */,

WooCommerce/WooCommerceTests/Extensions/IconsTests.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ final class IconsTests: XCTestCase {
172172
XCTAssertNotNil(UIImage.jetpackLogoImage)
173173
}
174174

175+
func testJetpackGreenLogoImageIconIsNotNil() {
176+
XCTAssertNotNil(UIImage.jetpackGreenLogoImage)
177+
}
178+
175179
func testInfoOutlineImageIconIsNotNil() {
176180
XCTAssertNotNil(UIImage.infoOutlineImage)
177181
}

0 commit comments

Comments
 (0)