Skip to content

[Woo POS] Start card reader connection flow and adapt to return result of connection to pos #11616

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

Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
415f42f
Attempt to open acitvity with card reader
kidinov May 27, 2024
a9f776b
Add redirect to card reader tutorial
samiuelson May 27, 2024
14ea468
Remove unnecessary navigate
samiuelson May 27, 2024
f06dea9
Fix start destination
samiuelson May 27, 2024
01d931f
Facade
kidinov May 29, 2024
b469387
Merge branch 'pos-card-reader-2' into 11608-woo-pos-start-cr-connecti…
kidinov May 29, 2024
932e47c
Removed unused imports
kidinov May 29, 2024
ab3485e
Start card reader activity from facade
kidinov May 29, 2024
cafa957
Intent to start activity in connection mode
kidinov May 29, 2024
750b210
Fixed transparent theme
kidinov May 29, 2024
c1bef0e
Extracted connection flow and start it via new activity
kidinov May 29, 2024
07575e1
Fixed compilation errors caused by extracting connection nav graph
kidinov May 29, 2024
c3d6853
Renamed card reader connect flow id to exclude duplicate
kidinov May 29, 2024
714d050
Reverted extraction of the connection nav graph as that causes a lot …
kidinov May 29, 2024
8ae6ca5
pass params from VM
kidinov May 29, 2024
6575e38
pass params from VM
kidinov May 29, 2024
0355768
Figuring out how if tehre is a way to send explicite result from nav …
kidinov May 29, 2024
d5f30c5
Removed attempts to handle cancelation
kidinov May 30, 2024
b058315
Fixed detekt complains
kidinov May 30, 2024
26e18db
Pop back stack instead of going up to handle cancelation/not connecte…
kidinov May 30, 2024
ed38b02
In select payment method screen
kidinov May 30, 2024
b6a99d5
Collect paymnt button and test order creation
kidinov May 30, 2024
ccdc8b4
Small refactoring of the events. Setting the correct graph
kidinov May 30, 2024
d3cee29
Hack to hide ui of select payment method fragment
kidinov May 30, 2024
62c7f6c
Fixed detekt complains
kidinov May 30, 2024
7f3fd8e
Pass result of the payment flow
kidinov May 31, 2024
fc88cbf
Return result to the root activity via suspend function
kidinov May 31, 2024
30de778
Crash if activity is null
kidinov May 31, 2024
8dfeb55
Finish activity after the flow is finished
kidinov May 31, 2024
352ef95
Merge pull request #11629 from woocommerce/11609-woo-pos-start-cr-ful…
backwardstruck May 31, 2024
81ccc3a
Merge branch 'trunk' into 11608-woo-pos-start-cr-connection-flow-and-…
kidinov Jun 3, 2024
b736ee9
Fixed naming and simplified the condition
kidinov Jun 3, 2024
60a3f10
View is not nullable
kidinov Jun 3, 2024
fe06a4e
Removed redundant super call
kidinov Jun 3, 2024
f56268a
Reader status to the up pf the class
kidinov Jun 3, 2024
e23660a
Merge remote-tracking branch 'origin/11608-woo-pos-start-cr-connectio…
kidinov Jun 3, 2024
e0dbb5b
Fixed broken back navigation from tutorial fragment
kidinov Jun 3, 2024
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
2 changes: 2 additions & 0 deletions WooCommerce/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@
<activity
android:name="com.woocommerce.android.ui.woopos.root.WooPosActivity"
android:exported="false" />
<activity android:name="com.woocommerce.android.ui.woopos.cardreader.WooPosCardReaderActivity"
android:theme="@style/Theme.Woo.Transparent" />

<!-- Stats today app widget -->
<meta-data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ class CardReaderConnectDialogFragment : PaymentsBaseDialogFragment(R.layout.card
result = event.data as Boolean,
)
}
is CardReaderConnectEvent.PopBackStackForWooPOS -> findNavController().popBackStack()
is CardReaderConnectEvent.ShowToast ->
ToastUtils.showToast(requireContext(), getString(event.message))
is CardReaderConnectEvent.ShowToastString ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ sealed class CardReaderConnectEvent : MultiLiveEvent.Event() {
data class OpenWPComWebView(val url: String) : CardReaderConnectEvent()

data class OpenGenericWebView(val url: String) : CardReaderConnectEvent()

data object PopBackStackForWooPOS : CardReaderConnectEvent()
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.woocommerce.android.ui.payments.cardreader.connect.CardReaderConnectE
import com.woocommerce.android.ui.payments.cardreader.connect.CardReaderConnectEvent.OpenLocationSettings
import com.woocommerce.android.ui.payments.cardreader.connect.CardReaderConnectEvent.OpenPermissionsSettings
import com.woocommerce.android.ui.payments.cardreader.connect.CardReaderConnectEvent.OpenWPComWebView
import com.woocommerce.android.ui.payments.cardreader.connect.CardReaderConnectEvent.PopBackStackForWooPOS
import com.woocommerce.android.ui.payments.cardreader.connect.CardReaderConnectEvent.RequestBluetoothRuntimePermissions
import com.woocommerce.android.ui.payments.cardreader.connect.CardReaderConnectEvent.RequestEnableBluetooth
import com.woocommerce.android.ui.payments.cardreader.connect.CardReaderConnectEvent.RequestLocationPermissions
Expand All @@ -57,6 +58,7 @@ import com.woocommerce.android.ui.payments.cardreader.connect.CardReaderConnectV
import com.woocommerce.android.ui.payments.cardreader.connect.CardReaderConnectViewState.MissingMerchantAddressError
import com.woocommerce.android.ui.payments.cardreader.connect.CardReaderConnectViewState.MultipleExternalReadersFoundState
import com.woocommerce.android.ui.payments.cardreader.connect.CardReaderConnectViewState.ScanningFailedState
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderType.BUILT_IN
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderType.EXTERNAL
Expand Down Expand Up @@ -281,6 +283,7 @@ class CardReaderConnectViewModel @Inject constructor(
Unit
}
}

CardReaderStatus.Connecting -> {
connectionStarted = true
viewState.value = provideConnectingState()
Expand Down Expand Up @@ -309,13 +312,16 @@ class CardReaderConnectViewModel @Inject constructor(
viewState.value = provideScanningState()
}
}

is ReadersFound -> {
tracker.trackReadersDiscovered(discoveryEvent.list.size)
onReadersFound(discoveryEvent)
}

Succeeded -> {
// noop
}

is Failed -> {
tracker.trackReaderDiscoveryFailed(discoveryEvent.msg)
WooLog.e(WooLog.T.CARD_READER, "Scanning failed: ${discoveryEvent.msg}")
Expand All @@ -330,6 +336,7 @@ class CardReaderConnectViewModel @Inject constructor(
triggerEvent(ShowToast(R.string.card_reader_detail_connected_update_failed))
exitFlow(connected = false)
}

CardReaderUpdateViewModel.UpdateResult.SUCCESS -> {
// noop
}
Expand Down Expand Up @@ -400,6 +407,7 @@ class CardReaderConnectViewModel @Inject constructor(
::onCancelClicked,
::onLearnMoreClicked
)

EXTERNAL -> ExternalReaderScanningState(
::onCancelClicked,
::onLearnMoreClicked
Expand All @@ -424,6 +432,7 @@ class CardReaderConnectViewModel @Inject constructor(
tracker.trackFetchingLocationSucceeded()
cardReaderManager.startConnectionToReader(cardReader, result.locationId)
}

is CardReaderLocationRepository.LocationIdFetchingResult.Error -> {
handleLocationFetchingError(result)
}
Expand Down Expand Up @@ -453,10 +462,12 @@ class CardReaderConnectViewModel @Inject constructor(
}
)
}

is CardReaderLocationRepository.LocationIdFetchingResult.Error.InvalidPostalCode -> {
trackLocationFailureFetching("Invalid Postal Code")
viewState.value = InvalidMerchantAddressPostCodeError(::restartFlow)
}

is CardReaderLocationRepository.LocationIdFetchingResult.Error.Other -> {
trackLocationFailureFetching(result.error)
onReaderConnectionFailed()
Expand Down Expand Up @@ -510,7 +521,13 @@ class CardReaderConnectViewModel @Inject constructor(

private fun exitFlow(connected: Boolean) {
if (!connected) {
triggerEvent(ExitWithResult(false))
when (arguments.cardReaderFlowParam) {
is CardReaderFlowParam.CardReadersHub,
is CardReaderFlowParam.PaymentOrRefund.Payment,
is CardReaderFlowParam.PaymentOrRefund.Refund -> triggerEvent(ExitWithResult(false))

CardReaderFlowParam.WooPosConnection -> triggerEvent(PopBackStackForWooPOS)
}
} else {
triggerEvent(ShowCardReaderTutorial(arguments.cardReaderFlowParam, arguments.cardReaderType))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ sealed class CardReaderFlowParam : Parcelable {
}
}

@Parcelize
data object WooPosConnection : CardReaderFlowParam()

sealed class PaymentOrRefund : CardReaderFlowParam() {
abstract val orderId: Long

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,9 @@ class CardReaderOnboardingViewModel @Inject constructor(
CardReaderOnboardingEvent.ContinueToConnection(params, requireNotNull(arguments.cardReaderType))
)
}
is CardReaderFlowParam.WooPosConnection -> {
error("Unsupported flow param: $params")
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class CardReaderStatusCheckerViewModel
handleOnboardingStatus(param)
}
}
is CardReaderFlowParam.WooPosConnection -> handleOnboardingStatus(param)
}
}

Expand All @@ -87,6 +88,7 @@ class CardReaderStatusCheckerViewModel
triggerEvent(StatusCheckerEvent.NavigateToWelcome(param, arguments.cardReaderType))
}
}

else -> triggerEvent(
StatusCheckerEvent.NavigateToOnboarding(
CardReaderOnboardingParams.Failed(param, state),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ class CardReaderTutorialDialogFragment : PaymentsBaseDialogFragment(R.layout.car

private fun navigateNext() {
when (val param = args.cardReaderFlowParam) {
is CardReaderFlowParam.CardReadersHub -> findNavController().popBackStack()
is CardReaderFlowParam.CardReadersHub,
is CardReaderFlowParam.WooPosConnection -> findNavController().popBackStack()
is CardReaderFlowParam.PaymentOrRefund -> {
val action = CardReaderTutorialDialogFragmentDirections
.actionCardReaderTutorialDialogFragmentToCardReaderPaymentDialogFragment(param, args.cardReaderType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ class PaymentsHubViewModel @Inject constructor(
is PaymentOrRefund -> {
// no-op
}
is CardReaderFlowParam.WooPosConnection -> error("Unsupported card reader flow param $params")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowP
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.SIMPLE
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.TRY_TAP_TO_PAY
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Refund
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.WooPosConnection
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderType.BUILT_IN
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderType.EXTERNAL
import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker
Expand Down Expand Up @@ -120,6 +121,7 @@ class SelectPaymentMethodViewModel @Inject constructor(
is Refund -> triggerEvent(NavigateToCardReaderRefundFlow(param, EXTERNAL))
}
}
is WooPosConnection -> error("Unsupported card reader flow param: $param")
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.woocommerce.android.ui.woopos.cardreader

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.fragment.NavHostFragment
import com.woocommerce.android.R
import com.woocommerce.android.ui.payments.cardreader.statuschecker.CardReaderStatusCheckerDialogFragmentArgs
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class WooPosCardReaderActivity : AppCompatActivity(R.layout.activity_woo_pos_card_reader) {
val viewModel: WooPosCardReaderViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val navHostFragment = supportFragmentManager.findFragmentById(
R.id.woopos_card_reader_nav_host_fragment
) as NavHostFragment

observeEvents(navHostFragment)
}

private fun observeEvents(navHostFragment: NavHostFragment) {
viewModel.event.observe(this) { event ->
when (event) {
is WooPosCardReaderActivityEvent -> {
val navController = navHostFragment.navController
val graph = navController.navInflater.inflate(R.navigation.nav_graph_payment_flow).apply {
setStartDestination(R.id.cardReaderStatusCheckerDialogFragment)
}
navController.setGraph(
graph,
CardReaderStatusCheckerDialogFragmentArgs(
cardReaderFlowParam = event.cardReaderFlowParam,
cardReaderType = event.cardReaderType,
).toBundle()
)
}
}
}
}

companion object {
internal const val WOO_POS_CARD_READER_MODE_KEY = "card_reader_connection_mode"

fun buildIntentForCardReaderConnection(context: Context) =
Intent(context, WooPosCardReaderActivity::class.java).apply {
putExtra(WOO_POS_CARD_READER_MODE_KEY, WooPosCardReaderMode.Connection)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.woocommerce.android.ui.woopos.cardreader

import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderType
import com.woocommerce.android.viewmodel.MultiLiveEvent

data class WooPosCardReaderActivityEvent(
val cardReaderFlowParam: CardReaderFlowParam,
val cardReaderType: CardReaderType,
) : MultiLiveEvent.Event()
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.woocommerce.android.ui.woopos.cardreader

import android.content.Context
import com.woocommerce.android.cardreader.CardReaderManager
import com.woocommerce.android.cardreader.connection.CardReaderStatus
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject

class WooPosCardReaderFacade @Inject constructor(
cardReaderManager: CardReaderManager,
) {
val readerStatus: Flow<CardReaderStatus> = cardReaderManager.readerStatus

fun connectToReader(context: Context) {
context.startActivity(WooPosCardReaderActivity.buildIntentForCardReaderConnection(context))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.woocommerce.android.ui.woopos.cardreader

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
internal sealed class WooPosCardReaderMode : Parcelable {
data object Connection : WooPosCardReaderMode()
data class Payment(val orderId: Long) : WooPosCardReaderMode()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.woocommerce.android.ui.woopos.cardreader

import androidx.lifecycle.SavedStateHandle
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam
import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderType
import com.woocommerce.android.ui.woopos.cardreader.WooPosCardReaderActivity.Companion.WOO_POS_CARD_READER_MODE_KEY
import com.woocommerce.android.viewmodel.ScopedViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class WooPosCardReaderViewModel @Inject constructor(
savedStateHandle: SavedStateHandle
) : ScopedViewModel(savedStateHandle) {
init {
when (savedStateHandle.get<WooPosCardReaderMode>(WOO_POS_CARD_READER_MODE_KEY)) {
is WooPosCardReaderMode.Connection -> {
triggerEvent(
WooPosCardReaderActivityEvent(
cardReaderFlowParam = CardReaderFlowParam.WooPosConnection,
cardReaderType = CardReaderType.EXTERNAL
)
)
}

is WooPosCardReaderMode.Payment -> error("Payment mode not implemented yet")

null -> error("WooPosCardReaderMode not found in savedStateHandle")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ import androidx.navigation.compose.composable
internal const val CART_ROUTE = "cart"

internal fun NavGraphBuilder.cartScreen(
onCheckoutClick: () -> Unit
onCheckoutClick: () -> Unit,
onConnectToCardReaderClicked: () -> Unit
) {
composable(CART_ROUTE) {
val viewModel: WooPosCartViewModel = hiltViewModel()

WooPosCartScreen(
viewModel = viewModel,
onCheckoutClick = onCheckoutClick
onCheckoutClick = onCheckoutClick,
onConnectToCardReaderClicked = onConnectToCardReaderClicked
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,36 @@ package com.woocommerce.android.ui.woopos.cart

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.woocommerce.android.ui.woopos.util.WooPosPreview

@Composable
@Suppress("UNUSED_PARAMETER")
fun WooPosCartScreen(
viewModel: WooPosCartViewModel,
onCheckoutClick: () -> Unit,
onConnectToCardReaderClicked: () -> Unit
) {
WooPosCartScreen(
onButtonClicked = onCheckoutClick
onCheckoutClick = onCheckoutClick,
onConnectToCardReaderClicked = onConnectToCardReaderClicked,
)
}

@Composable
private fun WooPosCartScreen(onButtonClicked: () -> Unit) {
private fun WooPosCartScreen(
onCheckoutClick: () -> Unit,
onConnectToCardReaderClicked: () -> Unit,
) {
Box(
Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
Expand All @@ -34,15 +42,21 @@ private fun WooPosCartScreen(onButtonClicked: () -> Unit) {
style = MaterialTheme.typography.h3,
color = MaterialTheme.colors.primary,
)
Button(onClick = onButtonClicked) {
Button(onClick = onCheckoutClick) {
Text("Checkout")
}

Spacer(modifier = Modifier.height(16.dp))

Button(onClick = onConnectToCardReaderClicked) {
Text("Connect to Card Reader")
}
}
}
}

@Composable
@WooPosPreview
fun WooPosCartScreenPreview() {
WooPosCartScreen(onButtonClicked = {})
WooPosCartScreen(onCheckoutClick = {}, onConnectToCardReaderClicked = {})
}
Loading
Loading