Skip to content

Commit bcd4a8f

Browse files
authored
Merge pull request #7451 from woocommerce/issue/7362-run-ipp-onboarding-background
[Mobile Payments] Run onboarding check on the IPP hub screen asynchronously
2 parents 3da9580 + e84b53d commit bcd4a8f

File tree

10 files changed

+386
-36
lines changed

10 files changed

+386
-36
lines changed

WooCommerce/Classes/Analytics/WooAnalyticsStat.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ public enum WooAnalyticsStat: String {
140140
case settingsTapped = "main_menu_settings_tapped"
141141
case settingsSelectedStoreTapped = "settings_selected_site_tapped"
142142
case settingsContactSupportTapped = "main_menu_contact_support_tapped"
143-
case settingsCardReadersTapped = "settings_card_readers_tapped"
144-
case settingsCardPresentSelectedPaymentGatewayTapped = "settings_card_present_select_payment_gateway_tapped"
145143

146144
case settingsBetaFeaturesButtonTapped = "settings_beta_features_button_tapped"
147145
case settingsBetaFeaturesProductsToggled = "settings_beta_features_products_toggled"
@@ -651,6 +649,14 @@ public enum WooAnalyticsStat: String {
651649
case loginWooCommerceSetupButtonTapped = "login_woocommerce_setup_button_tapped"
652650
case loginWooCommerceSetupDismissed = "login_woocommerce_setup_dismissed"
653651
case loginWooCommerceSetupCompleted = "login_woocommerce_setup_completed"
652+
653+
// MARK: Payments Menu
654+
case paymentsMenuCollectPaymentTapped = "payments_hub_collect_payment_tapped"
655+
case paymentsMenuOnboardingErrorTapped = "payments_hub_onboarding_error_tapped"
656+
case paymentsMenuOrderCardReaderTapped = "payments_hub_order_card_reader_tapped"
657+
case paymentsMenuCardReadersManualsTapped = "payments_hub_card_readers_manuals_tapped"
658+
case paymentsMenuManageCardReadersTapped = "payments_hub_manage_card_readers_tapped"
659+
case paymentsMenuPaymentProviderTapped = "settings_card_present_select_payment_gateway_tapped"
654660
}
655661

656662
public extension WooAnalyticsStat {
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import Foundation
2+
import UIKit
3+
import SwiftUI
4+
5+
/// This struct encapsulates the content to displayed in a Permanent Notice
6+
///
7+
struct PermanentNotice {
8+
let message: String
9+
let callToActionTitle: String
10+
let callToActionHandler: () -> Void
11+
}
12+
13+
/// Presents a banner permanently, that is, will remain until it is called to dismiss, unlike `DefaultNoticePresenter`, which dismiss the notice after a delay.
14+
/// The design also differs with the latter to represent a more permanent air.
15+
///
16+
final class PermanentNoticePresenter {
17+
private var hostingController: UIHostingController<PermanentNoticeView>?
18+
19+
/// Presents the given notice into the passed view controller with an animation
20+
///
21+
func presentNotice(notice: PermanentNotice, from viewController: UIViewController) {
22+
let permanentNoticeView = PermanentNoticeView(notice: notice)
23+
let newHostingController = ConstraintsUpdatingHostingController(rootView: permanentNoticeView)
24+
25+
guard let hostingView = newHostingController.view else {
26+
return
27+
}
28+
29+
viewController.addChild(newHostingController)
30+
viewController.view.addSubview(hostingView)
31+
32+
setupConstraints(in: viewController, hostingView: hostingView)
33+
animatePresentation(of: newHostingController, in: viewController)
34+
35+
self.hostingController = newHostingController
36+
}
37+
38+
/// Dismiss the permanent notice presented by calling `presentNotice`. If there is no one presented this method does nothing.
39+
///
40+
func dismiss() {
41+
animateDismiss()
42+
}
43+
}
44+
45+
private extension PermanentNoticePresenter {
46+
func setupConstraints(in viewController: UIViewController, hostingView: UIView) {
47+
hostingView.translatesAutoresizingMaskIntoConstraints = false
48+
49+
NSLayoutConstraint.activate([
50+
viewController.view.leadingAnchor.constraint(equalTo: hostingView.leadingAnchor, constant: 0),
51+
viewController.view.trailingAnchor.constraint(equalTo: hostingView.trailingAnchor, constant: 0),
52+
viewController.view.bottomAnchor.constraint(equalTo: hostingView.bottomAnchor, constant: 0),
53+
])
54+
}
55+
56+
func animatePresentation(of hostingController: UIViewController, in viewController: UIViewController) {
57+
guard let hostingView = hostingController.view else {
58+
return
59+
}
60+
61+
hostingView.alpha = 0
62+
63+
UIView.animate(withDuration: Animations.appearanceDuration,
64+
delay: 0,
65+
options: .transitionFlipFromLeft, animations: {
66+
hostingView.alpha = 1
67+
}) { _ in
68+
hostingController.didMove(toParent: viewController)
69+
}
70+
}
71+
72+
func animateDismiss() {
73+
guard let hostingController = hostingController else {
74+
return
75+
}
76+
77+
UIView.animate(withDuration: Animations.appearanceDuration,
78+
delay: 0,
79+
options: .transitionFlipFromLeft, animations: {
80+
hostingController.view.alpha = 0
81+
}) { _ in
82+
hostingController.willMove(toParent: nil)
83+
hostingController.view.removeFromSuperview()
84+
}
85+
}
86+
}
87+
88+
private extension PermanentNoticePresenter {
89+
private enum Animations {
90+
static let appearanceDuration: TimeInterval = 0.5
91+
}
92+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import Foundation
2+
import SwiftUI
3+
4+
/// Renders a permanent notice with a separator line on top
5+
///
6+
struct PermanentNoticeView: View {
7+
let notice: PermanentNotice
8+
9+
var body: some View {
10+
PermanentNoticeContentView(notice: notice)
11+
.background(Color(.listForeground))
12+
.overlay(Rectangle()
13+
.frame(width: nil, height: 0.5, alignment: .top)
14+
.foregroundColor(Color(UIColor.systemColor(.separator))), alignment: .top)
15+
}
16+
}
17+
18+
private struct PermanentNoticeContentView: View {
19+
let notice: PermanentNotice
20+
21+
var body: some View {
22+
HStack(alignment: .top, spacing: Layout.hStackSpacing) {
23+
Image(uiImage: .infoOutlineImage)
24+
.foregroundColor(Color(.gray(.shade40)))
25+
26+
VStack(alignment: .leading, spacing: Layout.vStackSpacing) {
27+
Text(notice.message)
28+
.bodyStyle()
29+
Button(action: notice.callToActionHandler, label: {
30+
Text(notice.callToActionTitle)
31+
.underline()
32+
.font(.body)
33+
.foregroundColor(Color(.accent))
34+
})
35+
}.padding(.top, Layout.vStackTopPadding)
36+
}
37+
.frame(maxWidth: .infinity, alignment: .topLeading)
38+
.padding(Layout.hStackPadding)
39+
}
40+
}
41+
42+
private extension PermanentNoticeContentView {
43+
enum Layout {
44+
static let hStackSpacing: CGFloat = 15
45+
static let hStackPadding: CGFloat = 10
46+
static let vStackSpacing: CGFloat = 10
47+
static let vStackTopPadding: CGFloat = 2
48+
}
49+
}

0 commit comments

Comments
 (0)