Skip to content

Commit

Permalink
feat(POM-387): Dynamic Checkout ViewModel & Interactor (#208)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitalii-vanziak-cko authored Jul 12, 2024
1 parent c0ac593 commit f544e88
Show file tree
Hide file tree
Showing 25 changed files with 811 additions and 67 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ ext {
mockitoInlineVersion = '5.2.0'
mockitoKotlinVersion = '5.2.1'
robolectricVersion = '4.11.1'
androidxTestCoreVersion = '1.5.0'
androidxTestCoreVersion = '1.6.1'

// Legacy
volleyVersion = '1.2.1'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.processout.sdk.api.model.response

import com.processout.sdk.core.annotation.ProcessOutInternalApi
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

Expand All @@ -25,7 +26,7 @@ data class POInvoice(
@Json(name = "return_url")
val returnUrl: String?,
@Json(name = "payment_methods")
internal val paymentMethods: List<PODynamicCheckoutPaymentMethod>?
@ProcessOutInternalApi val paymentMethods: List<PODynamicCheckoutPaymentMethod>?
)

/**
Expand Down Expand Up @@ -95,19 +96,7 @@ sealed class PODynamicCheckoutPaymentMethod {
val name: String,
val logo: POImageResource,
@Json(name = "brand_color")
val brandColor: BrandColor
)

/**
* Brand color for light/dark themes.
*
* @param[light] Light color HEX.
* @param[dark] Dark color HEX.
*/
@JsonClass(generateAdapter = true)
data class BrandColor(
val light: String,
val dark: String
val brandColor: POColor
)

/**
Expand Down Expand Up @@ -135,7 +124,7 @@ sealed class PODynamicCheckoutPaymentMethod {
*
* @param[collectionMode] Billing address collection mode.
* @param[restrictToCountryCodes] Set of ISO country codes that is supported for the billing address.
* When _null_, all countries are supported.
* When _null_, all countries are provided.
*/
@JsonClass(generateAdapter = true)
data class BillingAddressConfiguration(
Expand Down Expand Up @@ -170,15 +159,12 @@ sealed class PODynamicCheckoutPaymentMethod {
* Alternative payment configuration.
*
* @param[gatewayConfigurationId] Gateway configuration ID.
* @param[gatewayName] Gateway name.
* @param[redirectUrl] Redirect URL. If it's _null_, then payment should go through the native flow.
*/
@JsonClass(generateAdapter = true)
data class AlternativePaymentConfiguration(
@Json(name = "gateway_configuration_uid")
@Json(name = "gateway_configuration_id")
val gatewayConfigurationId: String,
@Json(name = "gateway_name")
val gatewayName: String,
@Json(name = "redirect_url")
val redirectUrl: String?
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.processout.sdk.api.model.response

import com.squareup.moshi.JsonClass

/**
* Color for light/dark themes.
*
* @param[light] Light color HEX.
* @param[dark] Dark color HEX.
*/
@JsonClass(generateAdapter = true)
data class POColor(
val light: String,
val dark: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import android.view.inputmethod.EditorInfo
import androidx.annotation.StringRes
import androidx.core.os.postDelayed
import androidx.core.text.isDigitsOnly
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
Expand Down Expand Up @@ -51,7 +50,7 @@ import java.text.NumberFormat
import java.util.Currency
import java.util.concurrent.TimeUnit

internal class NativeAlternativePaymentMethodViewModel(
internal class NativeAlternativePaymentMethodViewModel private constructor(
private val app: Application,
private val gatewayConfigurationId: String,
private val invoiceId: String,
Expand All @@ -60,7 +59,7 @@ internal class NativeAlternativePaymentMethodViewModel(
private val captureRetryStrategy: PORetryStrategy,
val options: Options,
val logAttributes: Map<String, String>
) : AndroidViewModel(app) {
) : ViewModel() {

class Factory(
private val app: Application,
Expand Down Expand Up @@ -735,7 +734,6 @@ internal class NativeAlternativePaymentMethodViewModel(
}

override fun onCleared() {
super.onCleared()
handler.removeCallbacksAndMessages(null)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import com.processout.sdk.ui.web.customtab.CustomTabAuthorizationActivityContrac
import com.processout.sdk.ui.web.customtab.CustomTabAuthorizationUiState.*
import java.util.concurrent.TimeUnit

internal class CustomTabAuthorizationViewModel(
internal class CustomTabAuthorizationViewModel private constructor(
private val savedState: SavedStateHandle,
private val configuration: CustomTabConfiguration
) : ViewModel() {
Expand Down Expand Up @@ -100,7 +100,6 @@ internal class CustomTabAuthorizationViewModel(
}

override fun onCleared() {
super.onCleared()
timeoutHandler.removeCallbacksAndMessages(null)
}
}
2 changes: 0 additions & 2 deletions sdk/src/main/res/values-ar/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
<!-- Dynamic Checkout -->
<string name="po_dynamic_checkout_button_pay">ادفع</string>
<string name="po_dynamic_checkout_warning_redirect">سيتم إعادة توجيهك لإتمام هذه الدفعة.</string>
<string name="po_dynamic_checkout_warning_unavailable_method">طريقة الدفع هذه غير متاحة.</string>
<string name="po_dynamic_checkout_error_generic">لم نتمكن من إتمام دفعتك. يرجى التحقق من التفاصيل أو تجربة طريقة دفع أخرى.</string>
<string name="po_dynamic_checkout_error_unavailable_method">طريقة الدفع المطلوبة غير متاحة، يرجى تجربة طريقة دفع أخرى.</string>

<!-- Native Alternative Payment Method -->
<string name="po_native_apm_title_format">الدفع بواسطة %s</string>
Expand Down
15 changes: 10 additions & 5 deletions sdk/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@

<string name="po_locale_language_code">fr</string>

<!-- Dynamic Checkout -->
<string name="po_dynamic_checkout_button_pay">Payer</string>
<string name="po_dynamic_checkout_warning_redirect">Vous serez redirigé pour finaliser ce paiement.</string>
<string name="po_dynamic_checkout_error_generic">Nous n\'avons pas pu finaliser votre paiement. Veuillez vérifier vos informations ou essayer un autre mode de paiement.</string>

<!-- Native Alternative Payment Method -->
<string name="po_native_apm_title_format">Payer avec %s</string>
<string name="po_native_apm_submit_button_text_format">Payer %s</string>
Expand All @@ -28,7 +33,7 @@
<string name="po_card_update_button_submit">Envoyer</string>
<string name="po_card_update_button_cancel">Annuler</string>
<string name="po_card_update_error_cvc">Le code CVV de votre carte est incorrect.</string>
<string name="po_card_update_error_generic">Une erreur sest produite, veuillez réessayer.</string>
<string name="po_card_update_error_generic">Une erreur s\'est produite, veuillez réessayer.</string>

<!-- Card Tokenization -->
<string name="po_card_tokenization_title">Ajouter une nouvelle carte</string>
Expand All @@ -40,14 +45,14 @@
<string name="po_card_tokenization_card_details_expiration_placeholder">MM / AA</string>
<string name="po_card_tokenization_card_details_number_placeholder">4242 4242 4242 4242</string>
<string name="po_card_tokenization_billing_address_title">Adresse de Facturation</string>
<string name="po_card_tokenization_billing_address_street">Ligne dadresse %d</string>
<string name="po_card_tokenization_billing_address_street">Ligne d\'adresse %d</string>
<string name="po_card_tokenization_error_card">Les informations de votre carte sont incorrectes.</string>
<string name="po_card_tokenization_error_card_expiration">La date dexpiration de votre carte est incorrecte.</string>
<string name="po_card_tokenization_error_card_expiration">La date d\'expiration de votre carte est incorrecte.</string>
<string name="po_card_tokenization_error_card_number">Votre numéro de carte est incorrect.</string>
<string name="po_card_tokenization_error_cardholder">Le nom du porteur de carte est incorrect.</string>
<string name="po_card_tokenization_error_cvc">Le code CVV de votre carte est incorrect.</string>
<string name="po_card_tokenization_error_generic">Une erreur sest produite, veuillez réessayer.</string>
<string name="po_card_tokenization_error_track_data">La date dexpiration de votre carte ou son code CVV sont incorrects.</string>
<string name="po_card_tokenization_error_generic">Une erreur s\'est produite, veuillez réessayer.</string>
<string name="po_card_tokenization_error_track_data">La date d\'expiration de votre carte ou son code CVV sont incorrects.</string>

<!-- Address Specification -->
<string name="po_address_spec_area">Zone</string>
Expand Down
2 changes: 0 additions & 2 deletions sdk/src/main/res/values-pl/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
<!-- Dynamic Checkout -->
<string name="po_dynamic_checkout_button_pay">Zapłać</string>
<string name="po_dynamic_checkout_warning_redirect">Zostaniesz przekierowany, aby sfinalizować tę płatność.</string>
<string name="po_dynamic_checkout_warning_unavailable_method">Ta metoda płatności nie jest obsługiwana.</string>
<string name="po_dynamic_checkout_error_generic">Nie byliśmy w stanie sfinalizować Twojej płatności. Zweryfikuj swoje dane lub wybierz inną metody płatności.</string>
<string name="po_dynamic_checkout_error_unavailable_method">Wybrana metoda płatności nie jest obsługiwana. Proszę wybierz inną metodę.</string>

<!-- Native Alternative Payment Method -->
<string name="po_native_apm_title_format">Zapłać przy pomocy %s</string>
Expand Down
2 changes: 0 additions & 2 deletions sdk/src/main/res/values-pt/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
<!-- Dynamic Checkout -->
<string name="po_dynamic_checkout_button_pay">Pagar</string>
<string name="po_dynamic_checkout_warning_redirect">Será redireccionado para finalizar este pagamento.</string>
<string name="po_dynamic_checkout_warning_unavailable_method">Este método de pagamento não está disponível.</string>
<string name="po_dynamic_checkout_error_generic">Não foi possível concluir o seu pagamento. Por favor, verifique os detalhes ou tente outro método de pagamento.</string>
<string name="po_dynamic_checkout_error_unavailable_method">O método de pagamento escolhido não está disponível, por favor tente outro método de pagamento.</string>

<!-- Native Alternative Payment Method -->
<string name="po_native_apm_title_format">Pagar com %s</string>
Expand Down
4 changes: 1 addition & 3 deletions sdk/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<resources>

<string name="po_locale_language_code">en</string>

<!-- Dynamic Checkout -->
<string name="po_dynamic_checkout_button_pay">Pay</string>
<string name="po_dynamic_checkout_warning_redirect">You will be redirected to finalise this payment.</string>
<string name="po_dynamic_checkout_warning_unavailable_method">This payment method is unavailable.</string>
<string name="po_dynamic_checkout_error_generic">We were unable to process your payment. Please check your payment details or try another payment method.</string>
<string name="po_dynamic_checkout_error_unavailable_method">The requested payment method is not available, please try another payment method.</string>

<!-- Native Alternative Payment Method -->
<string name="po_native_apm_title_format">Pay with %s</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ internal class CardTokenizationBottomSheet : BaseBottomSheetDialogFragment<POCar
super.onAttach(context)
@Suppress("DEPRECATION")
configuration = arguments?.getParcelable(EXTRA_CONFIGURATION)
viewModel.start()
}

override fun onCreateView(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import com.processout.sdk.ui.shared.provider.address.AddressSpecification
import com.processout.sdk.ui.shared.provider.address.AddressSpecification.AddressUnit
import com.processout.sdk.ui.shared.provider.address.AddressSpecificationProvider
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
Expand All @@ -44,7 +45,7 @@ import java.util.Locale

internal class CardTokenizationInteractor(
private val app: Application,
private val configuration: POCardTokenizationConfiguration,
private var configuration: POCardTokenizationConfiguration,
private val cardsRepository: POCardsRepository,
private val cardSchemeProvider: CardSchemeProvider,
private val addressSpecificationProvider: AddressSpecificationProvider,
Expand Down Expand Up @@ -74,7 +75,7 @@ internal class CardTokenizationInteractor(

//region Initialization

init {
fun start() {
interactorScope.launch {
POLogger.info("Starting card tokenization.")
dispatch(WillStart)
Expand All @@ -87,6 +88,21 @@ internal class CardTokenizationInteractor(
}
}

fun start(configuration: POCardTokenizationConfiguration) {
this.configuration = configuration
_state.update { initState() }
start()
}

fun reset() {
interactorScope.coroutineContext.cancelChildren()
issuerInformationJob = null
latestPreferredSchemeRequest = null
latestShouldContinueRequest = null
_completion.update { Awaiting }
_state.update { initState() }
}

private fun initState() = CardTokenizationInteractorState(
cardFields = cardFields(),
addressFields = emptyList(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ import com.processout.sdk.ui.shared.state.FieldState
import com.processout.sdk.ui.shared.transformation.CardExpirationVisualTransformation
import com.processout.sdk.ui.shared.transformation.CardNumberVisualTransformation

internal class CardTokenizationViewModel(
internal class CardTokenizationViewModel private constructor(
private val app: Application,
private val configuration: POCardTokenizationConfiguration,
configuration: POCardTokenizationConfiguration,
private val interactor: CardTokenizationInteractor
) : ViewModel() {

Expand Down Expand Up @@ -61,6 +61,9 @@ internal class CardTokenizationViewModel(
val actionId: String?
)

var configuration = configuration
private set

val completion = interactor.completion

val state = interactor.state.map(viewModelScope, ::map)
Expand All @@ -69,6 +72,15 @@ internal class CardTokenizationViewModel(
addCloseable(interactor.interactorScope)
}

fun start() = interactor.start()

fun start(configuration: POCardTokenizationConfiguration) {
this.configuration = configuration
interactor.start(configuration)
}

fun reset() = interactor.reset()

fun onEvent(event: CardTokenizationEvent) = interactor.onEvent(event)

private fun map(state: CardTokenizationInteractorState) = with(configuration) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

internal class CardUpdateViewModel(
internal class CardUpdateViewModel private constructor(
private val app: Application,
private val cardId: String,
private val options: POCardUpdateConfiguration.Options,
Expand Down
Loading

0 comments on commit f544e88

Please sign in to comment.