Collect Card Information

Getting Started

To create a Card Form using the MoneyHash Payment SDK for Android, you will use the CardFormBuilder class to configure the card form's fields and set up listeners to monitor changes in their states. This setup allows you to handle events such as when a user updates the card number, CVV, cardholder name, expiry month, or expiry year fields.

The CardFormBuilder provides methods to set listeners (handlers) for each card input field. These listeners are lambda functions that will be called every time the user updates the respective field. The listener function receives a CardInputFieldState object, which contains information about the field’s validity, error message (if any), and the input length.


CardInputFieldState

Each time the user updates a field, the corresponding listener will be invoked with a CardInputFieldState object. The CardInputFieldState model represents the current state of a card input field, such as the card number, CVV, or expiration date. It includes information about whether the field is valid, any error message associated with it, whether the field is currently focused, and the length of the input entered by the user.

data class CardInputFieldState(
    val isValid: Boolean? = null,
    val errorMessage: String? = null,
    val isOnFocused: Boolean = false,
    val inputLength: Int = 0
)

Properties:

  • isValid: A Boolean indicating whether the current input in the field is valid. If the input has not been validated yet, this can be null.
  • errorMessage: An optional string containing an error message if the input is invalid. If the input is valid or no validation has occurred yet, this will be null.
  • isOnFocused: A Boolean indicating whether the input field is currently focused (i.e., the user is actively entering or editing the field).
  • inputLength: An integer representing the length of the input currently entered in the field.

Example Usage:

val cardInputState = CardInputFieldState(
    isValid = true,
    errorMessage = null,
    isOnFocused = true,
    inputLength = 16
)
println("Card Number is valid: ${cardInputState.isValid}")

Default State:

The default state of the card input field can be accessed using:

val defaultState = CardInputFieldState()

In the default state, the field is not focused, and the input length is 0, with no validation performed (isValid and errorMessage are null).


Creating the CardForm

To collect card details, you will use the CardFormBuilder to configure the card input fields and their respective listeners. These listeners handle state changes for each field, such as card number, CVV, cardholder name, expiry month, and expiry year, allowing you to monitor user input and validation in real-time.

Example:

class CardFormViewModel : ViewModel() {
    lateinit var cardForm: CardForm

    init {
        setupCardForm()
    }

    private fun setupCardForm() {
        cardForm = createCardForm()
    }

    private fun createCardForm(): CardForm {
       return CardFormBuilder()
        .setCardNumberField { state ->
          println("Card Number State: $state")
        }
        .setCVVField { state ->
          println("CVV State: $state")
        }
        .setCardHolderNameField { state ->
          println("Card Holder Name State: $state")
        }
        .setExpireMonthField { state ->
          println("Expiry Month State: $state")
        }
        .setExpireYearField { state ->
          println("Expiry Year State: $state")
        }
        .setCardBrandChangeListener { brand ->
          println("Card Brand Changed: $brand")
        }
        .build()
    }
}

Explanation:

  • Listeners for Input Fields: Each field—such as card number, CVV, cardholder name, expiry month, and expiry year—has a listener associated with it. These listeners use closures to receive the updated state (CardInputFieldState) whenever the user modifies the respective field.

    • For instance, in the setCardNumberField closure, the state of the card number input is printed, and this state includes information such as whether the input is valid, the formatted value, and any error messages.

    • The setCardBrandChangeHandler closure listens for changes to the card brand, allowing you to track when the card type (e.g., Visa, MasterCard) changes based on the user's input.

  • build() Method: After configuring the field listeners, the build() method finalizes the creation of the CardForm instance, which is then assigned to the cardForm property. This form can now be used in your UI to display secure card input fields and manage the payment process.


Integrating SecureTextField

The SecureTextField is a Jetpack Compose @Composable function that represents a secure input field for card data. You can integrate it into your Compose-based UI by placing it within your composable layouts. Below is an example of how to integrate SecureTextField into your Android application using Jetpack Compose.

Example:

class CardFormActivity : ComponentActivity() {
    private val viewModel: CardFormViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            CardFormScreen(cardForm = viewModel.cardForm)
        }
    }
}

@Composable
fun CardFormScreen(cardForm: CardForm) {
    val coroutineScope = rememberCoroutineScope()

    Scaffold(
        topBar = {
            TopAppBar(title = { Text("Payment Form") })
        },
        content = { padding ->
            Column(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(padding)
                    .padding(16.dp),
                verticalArrangement = Arrangement.spacedBy(16.dp)
            ) {
                SecureTextField(
                    cardForm = cardForm,
                    type = FieldType.CARD_HOLDER_NAME,
                    placeholder = { Text("Cardholder Name") },
                    label = { Text("Cardholder Name") }
                )

                SecureTextField(
                    cardForm = cardForm,
                    type = FieldType.CARD_NUMBER,
                    placeholder = { Text("Card Number") },
                    label = { Text("Card Number") }
                )

                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.spacedBy(8.dp)
                ) {
                    SecureTextField(
                        cardForm = cardForm,
                        type = FieldType.EXPIRE_MONTH,
                        placeholder = { Text("MM") },
                        label = { Text("Expiry Month") },
                        modifier = Modifier.weight(1f)
                    )

                    SecureTextField(
                        cardForm = cardForm,
                        type = FieldType.EXPIRE_YEAR,
                        placeholder = { Text("YY") },
                        label = { Text("Expiry Year") },
                        modifier = Modifier.weight(1f)
                    )

                    SecureTextField(
                        cardForm = cardForm,
                        type = FieldType.CVV,
                        placeholder = { Text("CVV") },
                        label = { Text("CVV") },
                        modifier = Modifier.weight(1f)
                    )
                }

                Button(
                    onClick = { processPayment(cardForm) },
                    modifier = Modifier.fillMaxWidth()
                ) {
                    Text("Process Payment")
                }
            }
        }
    )
}

Explanation:

  • ViewModel (CardFormViewModel): Initializes the CardForm using CardFormBuilder and sets up listeners for each card input field and card brand changes. Each listener handles state changes, such as displaying error messages when input is invalid.

  • Composable Function (CardFormScreen): Utilizes Jetpack Compose to create the UI for the card form. It integrates the SecureTextField composable for each card input field and includes a button to process the payment.

  • Processing Payment (processPayment): Demonstrates how to collect the card data and process the payment using the pay method of CardForm . It handles success and error scenarios, providing feedback via println statements (which can be replaced with appropriate UI feedback mechanisms like Toast or dialog messages).