11import Foundation
22import Yosemite
33import Combine
4+ #if !targetEnvironment(simulator)
5+ import ProximityReader
6+ #endif
47
58enum CardReaderConnectionResult {
69 case connected( CardReader )
@@ -20,9 +23,9 @@ final class CardPresentPaymentPreflightController {
2023 ///
2124 private let configuration : CardPresentPaymentsConfiguration
2225
23- /// View Controller used to present alerts.
26+ /// Alerts presenter to send alert view models
2427 ///
25- private var rootViewController : UIViewController
28+ private var alertsPresenter : CardPresentPaymentAlertsPresenting
2629
2730 /// Stores manager.
2831 ///
@@ -40,30 +43,43 @@ final class CardPresentPaymentPreflightController {
4043 ///
4144 private var connectionController : CardReaderConnectionController
4245
46+ /// Controller to connect a card reader.
47+ ///
48+ private var builtInConnectionController : CardReaderConnectionController
49+
4350
4451 private( set) var readerConnection = CurrentValueSubject < CardReaderConnectionResult ? , Never > ( nil )
4552
4653 init ( siteID: Int64 ,
4754 paymentGatewayAccount: PaymentGatewayAccount ,
4855 configuration: CardPresentPaymentsConfiguration ,
49- rootViewController : UIViewController ,
56+ alertsPresenter : CardPresentPaymentAlertsPresenting ,
5057 stores: StoresManager = ServiceLocator . stores,
5158 analytics: Analytics = ServiceLocator . analytics) {
5259 self . siteID = siteID
5360 self . paymentGatewayAccount = paymentGatewayAccount
5461 self . configuration = configuration
55- self . rootViewController = rootViewController
62+ self . alertsPresenter = alertsPresenter
5663 self . stores = stores
5764 self . analytics = analytics
5865 self . connectedReader = nil
5966 let analyticsTracker = CardReaderConnectionAnalyticsTracker ( configuration: configuration,
6067 stores: stores,
6168 analytics: analytics)
62- // TODO: Replace this with a refactored (New)CardReaderConnectionController
69+ // TODO: Replace this with a refactored (New)LegacyCardReaderConnectionController
6370 self . connectionController = CardReaderConnectionController (
6471 forSiteID: siteID,
72+ discoveryMethod: . bluetoothProximity,
6573 knownReaderProvider: CardReaderSettingsKnownReaderStorage ( ) ,
66- alertsProvider: CardReaderSettingsAlerts ( ) ,
74+ alertsPresenter: alertsPresenter,
75+ configuration: configuration,
76+ analyticsTracker: analyticsTracker)
77+
78+ self . builtInConnectionController = CardReaderConnectionController (
79+ forSiteID: siteID,
80+ discoveryMethod: . localMobile,
81+ knownReaderProvider: CardReaderSettingsKnownReaderStorage ( ) ,
82+ alertsPresenter: alertsPresenter,
6783 configuration: configuration,
6884 analyticsTracker: analyticsTracker)
6985 }
@@ -78,31 +94,63 @@ final class CardPresentPaymentPreflightController {
7894
7995 // TODO: Run onboarding if needed
8096
81- // TODO: Ask for a Reader type if supported by device
82-
83- // Attempt to find a reader and connect
84- connectionController. searchAndConnect ( from: rootViewController) { result in
85- let connectionResult = result. map { connection in
86- switch connection {
87- case . connected:
88- // TODO: pass the reader from the (New)CardReaderConnectionController
89- guard let connectedReader = self . connectedReader else { return CardReaderConnectionResult . canceled }
90- return CardReaderConnectionResult . connected ( connectedReader)
91- case . canceled:
92- return CardReaderConnectionResult . canceled
93- }
94- }
97+ // Ask for a Reader type if supported by device/in country
98+ guard localMobileReaderSupported ( ) ,
99+ configuration. supportedReaders. contains ( . appleBuiltIn)
100+ else {
101+ // Attempt to find a bluetooth reader and connect
102+ connectionController. searchAndConnect ( onCompletion: handleConnectionResult)
103+ return
104+ }
95105
96- switch connectionResult {
97- case . success( let unwrapped) :
98- self . readerConnection. send ( unwrapped)
99- default :
100- break
101- }
106+ alertsPresenter. present ( viewModel: CardPresentModalSelectSearchType (
107+ tapOnIPhoneAction: { [ weak self] in
108+ guard let self = self else { return }
109+ self . builtInConnectionController. searchAndConnect (
110+ onCompletion: self . handleConnectionResult)
111+ } ,
112+ bluetoothAction: { [ weak self] in
113+ guard let self = self else { return }
114+ self . connectionController. searchAndConnect (
115+ onCompletion: self . handleConnectionResult)
116+ } ,
117+ cancelAction: { [ weak self] in
118+ guard let self = self else { return }
119+ self . alertsPresenter. dismiss ( )
120+ self . handleConnectionResult ( . success( . canceled) )
121+ } ) )
122+ }
123+
124+ private func localMobileReaderSupported( ) -> Bool {
125+ #if !targetEnvironment(simulator)
126+ if #available( iOS 15 . 4 , * ) {
127+ return PaymentCardReader . isSupported
128+ } else {
129+ return false
102130 }
131+ #endif
132+ return true
103133 }
104134
135+ private func handleConnectionResult( _ result: Result < CardReaderConnectionController . ConnectionResult , Error > ) {
136+ let connectionResult = result. map { connection in
137+ switch connection {
138+ case . connected:
139+ // TODO: pass the reader from the (New)CardReaderConnectionController
140+ guard let connectedReader = self . connectedReader else { return CardReaderConnectionResult . canceled }
141+ return CardReaderConnectionResult . connected ( connectedReader)
142+ case . canceled:
143+ return CardReaderConnectionResult . canceled
144+ }
145+ }
105146
147+ switch connectionResult {
148+ case . success( let unwrapped) :
149+ self . readerConnection. send ( unwrapped)
150+ default :
151+ break
152+ }
153+ }
106154
107155 /// Configure the CardPresentPaymentStore to use the appropriate backend
108156 ///
0 commit comments