From dc167a991f556ab97097742a88cbb773cbc0a164 Mon Sep 17 00:00:00 2001 From: Fabian Bender Date: Fri, 26 Jul 2024 15:34:38 +0200 Subject: [PATCH 1/4] add new event with default action --- ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt | 9 ++++++++- ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt | 6 ++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt index 18c129267d..0d3cf993ff 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt @@ -24,12 +24,14 @@ import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_EXTERNAL_BILLING import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_GIROPAY_INPUT import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_PAYMENT_CREDENTIALS_LIST import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_PAYMENT_OPTIONS +import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_PAYMENT_SELECTION_DIALOG import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_PAYONE_INPUT import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_PAYONE_SEPA import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_PROJECT_PAYMENT_OPTIONS import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_SCANNER import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_SEPA_CARD_INPUT import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_SHOPPING_CART +import io.snabble.sdk.ui.cart.PaymentSelectionHelper import io.snabble.sdk.ui.cart.deprecated.ShoppingCartActivity import io.snabble.sdk.ui.checkout.CheckoutActivity import io.snabble.sdk.ui.coupon.CouponDetailActivity @@ -80,7 +82,8 @@ object SnabbleUI { SHOW_COUPON_DETAILS, GO_BACK, EXIT_TOKEN_AVAILABLE, - NOT_CHECKED_IN + NOT_CHECKED_IN, + SHOW_PAYMENT_SELECTION_DIALOG } private class ActivityCallback( @@ -195,12 +198,16 @@ object SnabbleUI { SHOW_COUPON_DETAILS -> startActivity(context, CouponDetailActivity::class.java, args) + SHOW_PAYMENT_SELECTION_DIALOG -> PaymentSelectionHelper.getInstance() + .showDialog(UIUtils.getHostFragmentActivity(context)) + // unhandled actions GO_BACK, SHOW_CHECKOUT_DONE, NOT_CHECKED_IN, EXIT_TOKEN_AVAILABLE, null -> Unit + } } } diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt b/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt index b4b74c97d9..7f0813ad5c 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt @@ -113,11 +113,13 @@ open class CheckoutBar @JvmOverloads constructor( } paymentSelectorButton.setOnClickListener { - paymentSelectionHelper.showDialog(UIUtils.getHostFragmentActivity(context)) + SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_PAYMENT_SELECTION_DIALOG) +// paymentSelectionHelper.showDialog(UIUtils.getHostFragmentActivity(context)) } paymentSelectorButtonBig.setOnClickListener { - paymentSelectionHelper.showDialog(UIUtils.getHostFragmentActivity(context)) + SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_PAYMENT_SELECTION_DIALOG) +// paymentSelectionHelper.showDialog(UIUtils.getHostFragmentActivity(context)) } payButton.setOneShotClickListener { From 27e27a901bc01ddfb223a42439b47e6ee64b36c0 Mon Sep 17 00:00:00 2001 From: Christian Maier Date: Wed, 31 Jul 2024 16:32:40 +0200 Subject: [PATCH 2/4] Make payone token info serializable --- ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt index 742f66efcb..d12580c036 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt @@ -15,11 +15,13 @@ import io.snabble.sdk.utils.Dispatch import io.snabble.sdk.utils.Logger import io.snabble.sdk.utils.SimpleJsonCallback import kotlinx.parcelize.Parcelize +import kotlinx.serialization.Serializable import okhttp3.Callback import okhttp3.Request object Payone { + @Serializable @Parcelize data class PayoneTokenizationData( val merchantID: String, @@ -31,12 +33,14 @@ object Payone { val links: Map ) : Parcelable + @Serializable @Parcelize data class PreAuthInfo( val amount: Int?, val currency: String? ) : Parcelable + @Serializable @Parcelize data class Link( val href: String? From 10cfb6c581078cc3740bbf4f67bfeab9ec82b112 Mon Sep 17 00:00:00 2001 From: Christian Maier Date: Wed, 31 Jul 2024 16:32:55 +0200 Subject: [PATCH 3/4] Create a solo ExternalBillingInputScreen to be used externally --- .../ExternalBillingFragment.kt | 59 +--------------- .../ExternalBillingInputScreen.kt | 68 +++++++++++++++++++ .../ui/ExternalBillingLoginScreen.kt | 4 +- 3 files changed, 72 insertions(+), 59 deletions(-) create mode 100644 ui/src/main/java/io/snabble/sdk/ui/payment/externalbilling/ExternalBillingInputScreen.kt diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/externalbilling/ExternalBillingFragment.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/externalbilling/ExternalBillingFragment.kt index 28c6953c87..0c78ce6616 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/externalbilling/ExternalBillingFragment.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/externalbilling/ExternalBillingFragment.kt @@ -2,81 +2,28 @@ package io.snabble.sdk.ui.payment.externalbilling import android.os.Bundle import android.view.View -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.compose.ui.res.stringResource import androidx.core.os.bundleOf -import androidx.fragment.app.viewModels -import androidx.lifecycle.compose.collectAsStateWithLifecycle +import io.snabble.sdk.config.ProjectId import io.snabble.sdk.ui.BaseFragment import io.snabble.sdk.ui.R -import io.snabble.sdk.ui.SnabbleUI -import io.snabble.sdk.ui.payment.externalbilling.ui.ExternalBillingLoginScreen -import io.snabble.sdk.ui.payment.externalbilling.viewmodel.Error -import io.snabble.sdk.ui.payment.externalbilling.viewmodel.ExternalBillingViewModel -import io.snabble.sdk.ui.payment.externalbilling.viewmodel.Processing -import io.snabble.sdk.ui.payment.externalbilling.viewmodel.Success -import io.snabble.sdk.ui.utils.ThemeWrapper open class ExternalBillingFragment : BaseFragment( layoutResId = R.layout.snabble_fragment_external_billing, waitForProject = false, ) { - private val viewModel: ExternalBillingViewModel by viewModels() - override fun onActualViewCreated(view: View, savedInstanceState: Bundle?) { super.onActualViewCreated(view, savedInstanceState) view.findViewById(R.id.external_billing_compose_view).apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) - val projectId: String? = arguments?.getString(ARG_PROJECT_ID) + val projectId: ProjectId? = arguments?.getString(ARG_PROJECT_ID)?.let(::ProjectId) setContent { - val state = viewModel.uiState.collectAsStateWithLifecycle() - val errorMessage = remember { - mutableStateOf("") - } - - when (val it = state.value) { - is Error -> { - if (it.message == "400" || it.message == "null") { - errorMessage.value = - stringResource(id = R.string.Snabble_Payment_ExternalBilling_Error_badRequest) - } else { - errorMessage.value = - stringResource(id = R.string.Snabble_Payment_ExternalBilling_Error_wrongCredentials) - } - } - - Processing -> { - errorMessage.value = "" - } - - Success -> { - SnabbleUI.executeAction(context, SnabbleUI.Event.GO_BACK) - } - } - - val idDescriptor = stringResource(id = R.string.Snabble_Payment_ExternalBilling_username) - - ThemeWrapper { - ExternalBillingLoginScreen( - onSaveClick = { username, password -> - projectId?.let { - viewModel.login(idDescriptor, username, password, it) - } - }, - isInputValid = false, - errorMessage = errorMessage.value, - onFocusChanged = { - if (state.value != Processing) viewModel.typing() - } - ) - } + PaymentExternalBillingScreen(projectId = projectId) } } } diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/externalbilling/ExternalBillingInputScreen.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/externalbilling/ExternalBillingInputScreen.kt new file mode 100644 index 0000000000..688d56a268 --- /dev/null +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/externalbilling/ExternalBillingInputScreen.kt @@ -0,0 +1,68 @@ +package io.snabble.sdk.ui.payment.externalbilling + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewmodel.compose.viewModel +import io.snabble.sdk.config.ProjectId +import io.snabble.sdk.ui.R +import io.snabble.sdk.ui.SnabbleUI +import io.snabble.sdk.ui.payment.externalbilling.ui.ExternalBillingLoginScreen +import io.snabble.sdk.ui.payment.externalbilling.viewmodel.Error +import io.snabble.sdk.ui.payment.externalbilling.viewmodel.ExternalBillingViewModel +import io.snabble.sdk.ui.payment.externalbilling.viewmodel.Processing +import io.snabble.sdk.ui.payment.externalbilling.viewmodel.Success +import io.snabble.sdk.ui.utils.ThemeWrapper + +@Composable +fun PaymentExternalBillingScreen( + modifier: Modifier = Modifier, + projectId: ProjectId?, + viewModel: ExternalBillingViewModel = viewModel() +) { + val state = viewModel.uiState.collectAsStateWithLifecycle() + val errorMessage = remember { + mutableStateOf("") + } + + when (val it = state.value) { + is Error -> { + if (it.message == "400" || it.message == "null") { + errorMessage.value = + stringResource(id = R.string.Snabble_Payment_ExternalBilling_Error_badRequest) + } else { + errorMessage.value = + stringResource(id = R.string.Snabble_Payment_ExternalBilling_Error_wrongCredentials) + } + } + + Processing -> { + errorMessage.value = "" + } + + Success -> { + SnabbleUI.executeAction(LocalContext.current, SnabbleUI.Event.GO_BACK) + } + } + + val idDescriptor = stringResource(id = R.string.Snabble_Payment_ExternalBilling_username) + + ThemeWrapper { + ExternalBillingLoginScreen( + onSaveClick = { username, password -> + projectId?.let { + viewModel.login(idDescriptor, username, password, it.id) + } + }, + isInputValid = false, + errorMessage = errorMessage.value, + onFocusChanged = { + if (state.value != Processing) viewModel.typing() + } + ) + } +} diff --git a/ui/src/main/java/io/snabble/sdk/ui/payment/externalbilling/ui/ExternalBillingLoginScreen.kt b/ui/src/main/java/io/snabble/sdk/ui/payment/externalbilling/ui/ExternalBillingLoginScreen.kt index 05c6e72235..2adf6fa416 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/payment/externalbilling/ui/ExternalBillingLoginScreen.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/payment/externalbilling/ui/ExternalBillingLoginScreen.kt @@ -17,7 +17,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController @@ -29,9 +28,8 @@ import io.snabble.sdk.ui.R import io.snabble.sdk.ui.payment.externalbilling.ui.widgets.PasswordField import io.snabble.sdk.ui.payment.payone.sepa.form.ui.widget.TextFieldWidget -@OptIn(ExperimentalComposeUiApi::class) @Composable -fun ExternalBillingLoginScreen( +internal fun ExternalBillingLoginScreen( onSaveClick: (username: String, password: String) -> Unit, onFocusChanged: () -> Unit, isInputValid: Boolean, From 8e885ae05027947beac4cbdc8a37ea1157cddcc9 Mon Sep 17 00:00:00 2001 From: Christian Maier Date: Fri, 2 Aug 2024 11:26:25 +0200 Subject: [PATCH 4/4] The new navigation event is not necessary This reverts commit dc167a991f556ab97097742a88cbb773cbc0a164. --- ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt | 9 +-------- ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt | 6 ++---- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt index 0d3cf993ff..18c129267d 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/SnabbleUI.kt @@ -24,14 +24,12 @@ import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_EXTERNAL_BILLING import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_GIROPAY_INPUT import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_PAYMENT_CREDENTIALS_LIST import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_PAYMENT_OPTIONS -import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_PAYMENT_SELECTION_DIALOG import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_PAYONE_INPUT import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_PAYONE_SEPA import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_PROJECT_PAYMENT_OPTIONS import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_SCANNER import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_SEPA_CARD_INPUT import io.snabble.sdk.ui.SnabbleUI.Event.SHOW_SHOPPING_CART -import io.snabble.sdk.ui.cart.PaymentSelectionHelper import io.snabble.sdk.ui.cart.deprecated.ShoppingCartActivity import io.snabble.sdk.ui.checkout.CheckoutActivity import io.snabble.sdk.ui.coupon.CouponDetailActivity @@ -82,8 +80,7 @@ object SnabbleUI { SHOW_COUPON_DETAILS, GO_BACK, EXIT_TOKEN_AVAILABLE, - NOT_CHECKED_IN, - SHOW_PAYMENT_SELECTION_DIALOG + NOT_CHECKED_IN } private class ActivityCallback( @@ -198,16 +195,12 @@ object SnabbleUI { SHOW_COUPON_DETAILS -> startActivity(context, CouponDetailActivity::class.java, args) - SHOW_PAYMENT_SELECTION_DIALOG -> PaymentSelectionHelper.getInstance() - .showDialog(UIUtils.getHostFragmentActivity(context)) - // unhandled actions GO_BACK, SHOW_CHECKOUT_DONE, NOT_CHECKED_IN, EXIT_TOKEN_AVAILABLE, null -> Unit - } } } diff --git a/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt b/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt index 7f0813ad5c..b4b74c97d9 100644 --- a/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt +++ b/ui/src/main/java/io/snabble/sdk/ui/cart/CheckoutBar.kt @@ -113,13 +113,11 @@ open class CheckoutBar @JvmOverloads constructor( } paymentSelectorButton.setOnClickListener { - SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_PAYMENT_SELECTION_DIALOG) -// paymentSelectionHelper.showDialog(UIUtils.getHostFragmentActivity(context)) + paymentSelectionHelper.showDialog(UIUtils.getHostFragmentActivity(context)) } paymentSelectorButtonBig.setOnClickListener { - SnabbleUI.executeAction(context, SnabbleUI.Event.SHOW_PAYMENT_SELECTION_DIALOG) -// paymentSelectionHelper.showDialog(UIUtils.getHostFragmentActivity(context)) + paymentSelectionHelper.showDialog(UIUtils.getHostFragmentActivity(context)) } payButton.setOneShotClickListener {