Skip to content

WIP: Extract card reader connection state management from App to Yosemite #12723

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 1 addition & 16 deletions WooCommerce/Classes/Analytics/WooAnalyticsEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1769,7 +1769,7 @@ extension WooAnalyticsEvent {
static func collectPaymentCanceled(forGatewayID: String?,
countryCode: CountryCode,
cardReaderModel: String?,
cancellationSource: CancellationSource,
cancellationSource: CardReaderConnectionCancellationSource,
siteID: Int64) -> WooAnalyticsEvent {
WooAnalyticsEvent(statName: .collectPaymentCanceled,
properties: [
Expand All @@ -1782,21 +1782,6 @@ extension WooAnalyticsEvent {
)
}

enum CancellationSource: String {
case appleTOSAcceptance = "apple_tap_to_pay_terms_acceptance"
case reader = "card_reader"
case selectReaderType = "preflight_select_reader_type"
case searchingForReader = "searching_for_reader"
case foundReader = "found_reader"
case foundSeveralReaders = "found_several_readers"
case paymentValidatingOrder = "payment_validating_order"
case paymentPreparingReader = "payment_preparing_reader"
case paymentWaitingForInput = "payment_waiting_for_input"
case connectionError = "connection_error"
case readerSoftwareUpdate = "reader_software_update"
case other = "unknown"
}

/// Tracked when payment collection succeeds
///
/// - Parameters:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ final class BuiltInCardReaderConnectionController: BuiltInCardReaderConnectionCo
/// will be called with a `success` `Bool` `False` result. The view controller passed to `searchAndConnect` will be
/// dereferenced and the state set to `idle`
///
case cancel(WooAnalyticsEvent.InPersonPayments.CancellationSource)
case cancel(CardReaderConnectionCancellationSource)

/// A failure occurred. The completion passed to `searchAndConnect`
/// will be called with a `failure` result. The view controller passed to `searchAndConnect` will be
Expand Down Expand Up @@ -320,7 +320,7 @@ private extension BuiltInCardReaderConnectionController {

/// End the search for a card reader
///
func onCancel(from cancellationSource: WooAnalyticsEvent.InPersonPayments.CancellationSource) {
func onCancel(from cancellationSource: CardReaderConnectionCancellationSource) {
let action = CardPresentPaymentAction.cancelCardReaderDiscovery() { [weak self] _ in
self?.returnSuccess(result: .canceled(cancellationSource))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,7 @@ import protocol WooFoundation.Analytics

enum CardReaderPreflightResult {
case completed(CardReader, PaymentGatewayAccount)
case canceled(WooAnalyticsEvent.InPersonPayments.CancellationSource, PaymentGatewayAccount)
}

enum CardReaderConnectionResult {
case connected(CardReader)
case canceled(WooAnalyticsEvent.InPersonPayments.CancellationSource)
case canceled(CardReaderConnectionCancellationSource, PaymentGatewayAccount)
}

protocol CardPresentPaymentPreflightControllerProtocol {
Expand Down Expand Up @@ -98,12 +93,12 @@ final class CardPresentPaymentPreflightController: CardPresentPaymentPreflightCo
stores: stores,
analytics: analytics)
self.connectionController = CardReaderConnectionController(
forSiteID: siteID,
siteID: siteID,
storageManager: ServiceLocator.storageManager,
stores: stores,
knownReaderProvider: CardReaderSettingsKnownReaderStorage(),
alertsPresenter: alertsPresenter,
alertsProvider: BluetoothReaderConnectionAlertsProvider(),
configuration: configuration,
analyticsTracker: analyticsTracker)
configuration: configuration
)

self.builtInConnectionController = BuiltInCardReaderConnectionController(
forSiteID: siteID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ final class BluetoothCardReaderSettingsConnectedViewModel: PaymentSettingsFlowPr
/// The datasource that will be used to help render the related screens
///
private(set) lazy var dataSource: CardReaderSettingsDataSource = {
return CardReaderSettingsDataSource(siteID: siteID)
return CardReaderSettingsDataSource(siteID: siteID, storageManager: ServiceLocator.storageManager)
}()

private let analyticsTracker: CardReaderConnectionAnalyticsTracker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,43 +9,6 @@ final class CardReaderSettingsAlerts: CardReaderSettingsAlertsProvider {
private var modalController: CardPresentPaymentsModalViewController?
private var severalFoundController: SeveralReadersFoundViewController?

func scanningForReader(from: UIViewController, cancel: @escaping () -> Void) {
setViewModelAndPresent(from: from, viewModel: scanningForReader(cancel: cancel))
}

func scanningFailed(from: UIViewController, error: Error, close: @escaping () -> Void) {
setViewModelAndPresent(from: from, viewModel: scanningFailed(error: error, close: close))
}

func connectingToReader(from: UIViewController) {
setViewModelAndPresent(from: from, viewModel: connectingToReader())
}

func connectingFailed(from: UIViewController, error: Error, continueSearch: @escaping () -> Void, cancelSearch: @escaping () -> Void) {
setViewModelAndPresent(from: from,
viewModel: connectingFailed(error: error,
continueSearch: continueSearch,
cancelSearch: cancelSearch))
}

func connectingFailedIncompleteAddress(from: UIViewController,
openWCSettings: ((UIViewController) -> Void)?,
retrySearch: @escaping () -> Void,
cancelSearch: @escaping () -> Void) {
setViewModelAndPresent(from: from,
viewModel: connectingFailedUpdateAddress(openWCSettings: openWCSettings,
retrySearch: retrySearch,
cancelSearch: cancelSearch))
}

func connectingFailedInvalidPostalCode(from: UIViewController, retrySearch: @escaping () -> Void, cancelSearch: @escaping () -> Void) {
setViewModelAndPresent(from: from, viewModel: connectingFailedUpdatePostalCode(retrySearch: retrySearch, cancelSearch: cancelSearch))
}

func connectingFailedCriticallyLowBattery(from: UIViewController, retrySearch: @escaping () -> Void, cancelSearch: @escaping () -> Void) {
setViewModelAndPresent(from: from, viewModel: connectingFailedCriticallyLowBattery(retrySearch: retrySearch, cancelSearch: cancelSearch))
}

func updatingFailedLowBattery(from: UIViewController, batteryLevel: Double?, close: @escaping () -> Void) {
setViewModelAndPresent(from: from, viewModel: updatingFailedLowBattery(from: from, batteryLevel: batteryLevel, close: close))
}
Expand All @@ -54,47 +17,6 @@ final class CardReaderSettingsAlerts: CardReaderSettingsAlertsProvider {
setViewModelAndPresent(from: from, viewModel: updatingFailed(from: from, tryAgain: tryAgain, close: close))
}

func foundReader(from: UIViewController,
name: String,
connect: @escaping () -> Void,
continueSearch: @escaping () -> Void,
cancelSearch: @escaping () -> Void) {
setViewModelAndPresent(from: from,
viewModel: foundReader(name: name,
connect: connect,
continueSearch: continueSearch,
cancel: {
cancelSearch()
from.dismiss(animated: true)
})
)
}

/// Note: `foundSeveralReaders` uses a view controller distinct from the common
/// `CardPresentPaymentsModalViewController` to avoid further
/// overloading `CardPresentPaymentsModalViewModel`
///
/// This will dismiss any view controllers using the common view model first before
/// presenting the several readers found modal
///
func foundSeveralReaders(from: UIViewController,
readerIDs: [String],
connect: @escaping (String) -> Void,
cancelSearch: @escaping () -> Void) {
severalFoundController = SeveralReadersFoundViewController()

if let severalFoundController = severalFoundController {
severalFoundController.configureController(
readerIDs: readerIDs,
connect: connect,
cancelSearch: cancelSearch
)
severalFoundController.prepareForCardReaderModalFlow()
}

dismissCommonAndPresent(animated: false, from: from, present: severalFoundController)
}

/// Used to update the readers list in the several readers found view
///
func updateSeveralReadersList(readerIDs: [String]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,69 +7,10 @@ import Yosemite
/// and connecting to a reader
///
protocol CardReaderSettingsAlertsProvider {
/// Defines a cancellable alert indicating we are searching for a reader
///
func scanningForReader(from: UIViewController, cancel: @escaping () -> Void)

/// Defines a cancellable (closeable) alert indicating the search failed
///
func scanningFailed(from: UIViewController, error: Error, close: @escaping () -> Void)

/// Defines an interactive alert indicating a reader has been found. The user must
/// choose to connect to that reader or continue searching
///
func foundReader(from: UIViewController,
name: String,
connect: @escaping () -> Void,
continueSearch: @escaping () -> Void,
cancelSearch: @escaping () -> Void)

/// Defines an interactive alert indicating more than one reader has been found. The user must
/// choose to connect to that reader or cancel searching
///
func foundSeveralReaders(from: UIViewController,
readerIDs: [String],
connect: @escaping (String) -> Void,
cancelSearch: @escaping () -> Void)

/// Allows updating the list of readers found in the several readers alert
///
func updateSeveralReadersList(readerIDs: [String])

/// Defines a non-interactive alert indicating a connection is in progress to a particular reader
///
func connectingToReader(from: UIViewController)

/// Defines an alert indicating connecting failed. The user may continue the search
/// or cancel
///
func connectingFailed(from: UIViewController,
error: Error,
continueSearch: @escaping () -> Void,
cancelSearch: @escaping () -> Void)

/// Defines an alert indicating connecting failed because their address needs updating.
/// The user may try again or cancel
///
func connectingFailedIncompleteAddress(from: UIViewController,
openWCSettings: ((UIViewController) -> Void)?,
retrySearch: @escaping () -> Void,
cancelSearch: @escaping () -> Void)

/// Defines an alert indicating connecting failed because their postal code needs updating.
/// The user may try again or cancel
///
func connectingFailedInvalidPostalCode(from: UIViewController,
retrySearch: @escaping () -> Void,
cancelSearch: @escaping () -> Void)

/// Defines an alert indicating connecting failed because the reader battery is critically low.
/// The user may try searching again (i.e. for a different reader) or cancel
///
func connectingFailedCriticallyLowBattery(from: UIViewController,
retrySearch: @escaping () -> Void,
cancelSearch: @escaping () -> Void)

/// Defines an alert indicating an update couldn't be installed because the reader is low on battery.
///
func updatingFailedLowBattery(from: UIViewController,
Expand Down
Loading