mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-22 20:18:36 +00:00
Perform client side checks on name and email for donation flows.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components.settings.app.subscription.donate.transfer
|
||||
|
||||
object BankDetailsValidator {
|
||||
|
||||
private val EMAIL_REGEX: Regex = ".+@.+\\..+".toRegex()
|
||||
|
||||
fun validName(name: String): Boolean {
|
||||
return name.length >= 2
|
||||
}
|
||||
|
||||
fun validEmail(email: String): Boolean {
|
||||
return email.length >= 3 && email.matches(EMAIL_REGEX)
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,7 @@ import org.thoughtcrime.securesms.components.settings.app.subscription.donate.ga
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.stripe.StripePaymentInProgressFragment
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.stripe.StripePaymentInProgressViewModel
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.transfer.BankTransferRequestKeys
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.transfer.details.BankTransferDetailsViewModel.Field
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.errors.DonationErrorSource
|
||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||
import org.thoughtcrime.securesms.payments.FiatMoneyUtil
|
||||
@@ -133,7 +134,7 @@ class BankTransferDetailsFragment : ComposeFragment(), DonationCheckoutDelegate.
|
||||
setDisplayFindAccountInfoSheet = viewModel::setDisplayFindAccountInfoSheet,
|
||||
onLearnMoreClick = this::onLearnMoreClick,
|
||||
onDonateClick = this::onDonateClick,
|
||||
onIBANFocusChanged = viewModel::onIBANFocusChanged,
|
||||
onFocusChanged = viewModel::onFocusChanged,
|
||||
donateLabel = donateLabel
|
||||
)
|
||||
}
|
||||
@@ -186,7 +187,7 @@ private fun BankTransferDetailsContentPreview() {
|
||||
setDisplayFindAccountInfoSheet = {},
|
||||
onLearnMoreClick = {},
|
||||
onDonateClick = {},
|
||||
onIBANFocusChanged = {},
|
||||
onFocusChanged = { _, _ -> },
|
||||
donateLabel = "Donate $5/month"
|
||||
)
|
||||
}
|
||||
@@ -202,7 +203,7 @@ private fun BankTransferDetailsContent(
|
||||
setDisplayFindAccountInfoSheet: (Boolean) -> Unit,
|
||||
onLearnMoreClick: () -> Unit,
|
||||
onDonateClick: () -> Unit,
|
||||
onIBANFocusChanged: (Boolean) -> Unit,
|
||||
onFocusChanged: (Field, Boolean) -> Unit,
|
||||
donateLabel: String
|
||||
) {
|
||||
Scaffolds.Settings(
|
||||
@@ -275,7 +276,7 @@ private fun BankTransferDetailsContent(
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp)
|
||||
.defaultMinSize(minHeight = 78.dp)
|
||||
.onFocusChanged { onIBANFocusChanged(it.hasFocus) }
|
||||
.onFocusChanged { onFocusChanged(Field.IBAN, it.hasFocus) }
|
||||
.focusRequester(focusRequester)
|
||||
)
|
||||
}
|
||||
@@ -294,11 +295,17 @@ private fun BankTransferDetailsContent(
|
||||
keyboardActions = KeyboardActions(
|
||||
onNext = { focusManager.moveFocus(FocusDirection.Down) }
|
||||
),
|
||||
supportingText = {},
|
||||
isError = state.showNameError(),
|
||||
supportingText = {
|
||||
if (state.showNameError()) {
|
||||
Text(text = stringResource(id = R.string.BankTransferDetailsFragment__minimum_2_characters))
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp)
|
||||
.defaultMinSize(minHeight = 78.dp)
|
||||
.onFocusChanged { onFocusChanged(Field.NAME, it.hasFocus) }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -316,11 +323,17 @@ private fun BankTransferDetailsContent(
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = { onDonateClick() }
|
||||
),
|
||||
supportingText = {},
|
||||
isError = state.showEmailError(),
|
||||
supportingText = {
|
||||
if (state.showEmailError()) {
|
||||
Text(text = stringResource(id = R.string.BankTransferDetailsFragment__invalid_email_address))
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp)
|
||||
.defaultMinSize(minHeight = 78.dp)
|
||||
.onFocusChanged { onFocusChanged(Field.EMAIL, it.hasFocus) }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,15 +6,26 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.subscription.donate.transfer.details
|
||||
|
||||
import org.signal.donations.StripeApi
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.transfer.BankDetailsValidator
|
||||
|
||||
data class BankTransferDetailsState(
|
||||
val name: String = "",
|
||||
val nameFocusState: FocusState = FocusState.NOT_FOCUSED,
|
||||
val iban: String = "",
|
||||
val email: String = "",
|
||||
val emailFocusState: FocusState = FocusState.NOT_FOCUSED,
|
||||
val ibanValidity: IBANValidator.Validity = IBANValidator.Validity.POTENTIALLY_VALID,
|
||||
val displayFindAccountInfoSheet: Boolean = false
|
||||
) {
|
||||
val canProceed = name.isNotBlank() && email.isNotBlank() && ibanValidity == IBANValidator.Validity.COMPLETELY_VALID
|
||||
val canProceed = BankDetailsValidator.validName(name) && BankDetailsValidator.validEmail(email) && ibanValidity == IBANValidator.Validity.COMPLETELY_VALID
|
||||
|
||||
fun showNameError(): Boolean {
|
||||
return nameFocusState == FocusState.LOST_FOCUS && !BankDetailsValidator.validName(name)
|
||||
}
|
||||
|
||||
fun showEmailError(): Boolean {
|
||||
return emailFocusState == FocusState.LOST_FOCUS && !BankDetailsValidator.validEmail(email)
|
||||
}
|
||||
|
||||
fun asSEPADebitData(): StripeApi.SEPADebitData {
|
||||
return StripeApi.SEPADebitData(
|
||||
@@ -23,4 +34,10 @@ data class BankTransferDetailsState(
|
||||
email = email.trim()
|
||||
)
|
||||
}
|
||||
|
||||
enum class FocusState {
|
||||
NOT_FOCUSED,
|
||||
FOCUSED,
|
||||
LOST_FOCUS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.thoughtcrime.securesms.components.settings.app.subscription.donate.t
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.transfer.details.BankTransferDetailsState.FocusState
|
||||
|
||||
class BankTransferDetailsViewModel : ViewModel() {
|
||||
|
||||
@@ -30,10 +31,30 @@ class BankTransferDetailsViewModel : ViewModel() {
|
||||
)
|
||||
}
|
||||
|
||||
fun onIBANFocusChanged(isFocused: Boolean) {
|
||||
internalState.value = internalState.value.copy(
|
||||
ibanValidity = IBANValidator.validate(internalState.value.iban, isFocused)
|
||||
)
|
||||
fun onFocusChanged(field: Field, isFocused: Boolean) {
|
||||
when (field) {
|
||||
Field.IBAN -> {
|
||||
internalState.value = internalState.value.copy(
|
||||
ibanValidity = IBANValidator.validate(internalState.value.iban, isFocused)
|
||||
)
|
||||
}
|
||||
|
||||
Field.NAME -> {
|
||||
if (isFocused && internalState.value.nameFocusState == FocusState.NOT_FOCUSED) {
|
||||
internalState.value = internalState.value.copy(nameFocusState = FocusState.FOCUSED)
|
||||
} else if (!isFocused && internalState.value.nameFocusState == FocusState.FOCUSED) {
|
||||
internalState.value = internalState.value.copy(nameFocusState = FocusState.LOST_FOCUS)
|
||||
}
|
||||
}
|
||||
|
||||
Field.EMAIL -> {
|
||||
if (isFocused && internalState.value.emailFocusState == FocusState.NOT_FOCUSED) {
|
||||
internalState.value = internalState.value.copy(emailFocusState = FocusState.FOCUSED)
|
||||
} else if (!isFocused && internalState.value.emailFocusState == FocusState.FOCUSED) {
|
||||
internalState.value = internalState.value.copy(emailFocusState = FocusState.LOST_FOCUS)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onIBANChanged(iban: String) {
|
||||
@@ -48,4 +69,10 @@ class BankTransferDetailsViewModel : ViewModel() {
|
||||
email = email
|
||||
)
|
||||
}
|
||||
|
||||
enum class Field {
|
||||
IBAN,
|
||||
NAME,
|
||||
EMAIL
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.thoughtcrime.securesms.components.settings.app.subscription.donate.t
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -28,6 +29,8 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusDirection
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@@ -41,7 +44,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.navigation.fragment.findNavController
|
||||
@@ -62,12 +64,14 @@ import org.thoughtcrime.securesms.components.settings.app.subscription.donate.ga
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.stripe.StripePaymentInProgressFragment
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.stripe.StripePaymentInProgressViewModel
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.transfer.BankTransferRequestKeys
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.transfer.ideal.IdealTransferDetailsViewModel.Field
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.errors.DonationErrorSource
|
||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||
import org.thoughtcrime.securesms.payments.FiatMoneyUtil
|
||||
import org.thoughtcrime.securesms.util.SpanUtil
|
||||
import org.thoughtcrime.securesms.util.fragments.requireListener
|
||||
import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||
import org.thoughtcrime.securesms.util.viewModel
|
||||
|
||||
/**
|
||||
* Fragment for inputting necessary bank transfer information for iDEAL donation
|
||||
@@ -75,7 +79,9 @@ import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||
class IdealTransferDetailsFragment : ComposeFragment(), DonationCheckoutDelegate.ErrorHandlerCallback {
|
||||
|
||||
private val args: IdealTransferDetailsFragmentArgs by navArgs()
|
||||
private val viewModel: IdealTransferDetailsViewModel by viewModels()
|
||||
private val viewModel: IdealTransferDetailsViewModel by viewModel {
|
||||
IdealTransferDetailsViewModel(args.request.donateToSignalType == DonateToSignalType.MONTHLY)
|
||||
}
|
||||
|
||||
private val stripePaymentViewModel: StripePaymentInProgressViewModel by navGraphViewModels(
|
||||
R.id.donate_to_signal,
|
||||
@@ -127,14 +133,24 @@ class IdealTransferDetailsFragment : ComposeFragment(), DonationCheckoutDelegate
|
||||
}
|
||||
}
|
||||
|
||||
val idealDirections = remember(args.request) {
|
||||
if (args.request.donateToSignalType == DonateToSignalType.MONTHLY) {
|
||||
R.string.IdealTransferDetailsFragment__enter_your_bank
|
||||
} else {
|
||||
R.string.IdealTransferDetailsFragment__enter_your_bank_details_one_time
|
||||
}
|
||||
}
|
||||
|
||||
IdealTransferDetailsContent(
|
||||
state = state,
|
||||
idealDirections = idealDirections,
|
||||
donateLabel = donateLabel,
|
||||
onNavigationClick = { findNavController().popBackStack() },
|
||||
onLearnMoreClick = { findNavController().navigate(IdealTransferDetailsFragmentDirections.actionBankTransferDetailsFragmentToYourInformationIsPrivateBottomSheet()) },
|
||||
onSelectBankClick = { findNavController().navigate(IdealTransferDetailsFragmentDirections.actionIdealTransferDetailsFragmentToIdealTransferBankSelectionDialogFragment()) },
|
||||
onNameChanged = viewModel::onNameChanged,
|
||||
onEmailChanged = viewModel::onEmailChanged,
|
||||
onFocusChanged = viewModel::onFocusChanged,
|
||||
onDonateClick = this::onDonateClick
|
||||
)
|
||||
}
|
||||
@@ -171,13 +187,15 @@ class IdealTransferDetailsFragment : ComposeFragment(), DonationCheckoutDelegate
|
||||
@Composable
|
||||
private fun IdealTransferDetailsContentPreview() {
|
||||
IdealTransferDetailsContent(
|
||||
state = IdealTransferDetailsState(),
|
||||
state = IdealTransferDetailsState(isMonthly = true),
|
||||
idealDirections = R.string.IdealTransferDetailsFragment__enter_your_bank,
|
||||
donateLabel = "Donate $5/month",
|
||||
onNavigationClick = {},
|
||||
onLearnMoreClick = {},
|
||||
onSelectBankClick = {},
|
||||
onNameChanged = {},
|
||||
onEmailChanged = {},
|
||||
onFocusChanged = { _, _ -> },
|
||||
onDonateClick = {}
|
||||
)
|
||||
}
|
||||
@@ -185,12 +203,14 @@ private fun IdealTransferDetailsContentPreview() {
|
||||
@Composable
|
||||
private fun IdealTransferDetailsContent(
|
||||
state: IdealTransferDetailsState,
|
||||
@StringRes idealDirections: Int,
|
||||
donateLabel: String,
|
||||
onNavigationClick: () -> Unit,
|
||||
onLearnMoreClick: () -> Unit,
|
||||
onSelectBankClick: () -> Unit,
|
||||
onNameChanged: (String) -> Unit,
|
||||
onEmailChanged: (String) -> Unit,
|
||||
onFocusChanged: (Field, Boolean) -> Unit,
|
||||
onDonateClick: () -> Unit
|
||||
) {
|
||||
Scaffolds.Settings(
|
||||
@@ -211,7 +231,7 @@ private fun IdealTransferDetailsContent(
|
||||
) {
|
||||
item {
|
||||
val learnMore = stringResource(id = R.string.IdealTransferDetailsFragment__learn_more)
|
||||
val fullString = stringResource(id = R.string.IdealTransferDetailsFragment__enter_your_bank, learnMore)
|
||||
val fullString = stringResource(id = idealDirections, learnMore)
|
||||
|
||||
Texts.LinkifiedText(
|
||||
textWithUrlSpans = SpanUtil.urlSubsequence(fullString, learnMore, stringResource(id = R.string.donate_faq_url)),
|
||||
@@ -248,38 +268,52 @@ private fun IdealTransferDetailsContent(
|
||||
keyboardActions = KeyboardActions(
|
||||
onNext = { focusManager.moveFocus(FocusDirection.Down) }
|
||||
),
|
||||
supportingText = {},
|
||||
isError = state.showNameError(),
|
||||
supportingText = {
|
||||
if (state.showNameError()) {
|
||||
Text(text = stringResource(id = R.string.BankTransferDetailsFragment__minimum_2_characters))
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp)
|
||||
.defaultMinSize(minHeight = 78.dp)
|
||||
.onFocusChanged { onFocusChanged(Field.NAME, it.hasFocus) }
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
TextField(
|
||||
value = state.email,
|
||||
onValueChange = onEmailChanged,
|
||||
label = {
|
||||
Text(text = stringResource(id = R.string.IdealTransferDetailsFragment__email))
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Email,
|
||||
imeAction = ImeAction.Done
|
||||
),
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = {
|
||||
if (state.canProceed()) {
|
||||
onDonateClick()
|
||||
if (state.isMonthly) {
|
||||
item {
|
||||
TextField(
|
||||
value = state.email,
|
||||
onValueChange = onEmailChanged,
|
||||
label = {
|
||||
Text(text = stringResource(id = R.string.IdealTransferDetailsFragment__email))
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Email,
|
||||
imeAction = ImeAction.Done
|
||||
),
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = {
|
||||
if (state.canProceed()) {
|
||||
onDonateClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
supportingText = {},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp)
|
||||
.defaultMinSize(minHeight = 78.dp)
|
||||
)
|
||||
),
|
||||
isError = state.showEmailError(),
|
||||
supportingText = {
|
||||
if (state.showEmailError()) {
|
||||
Text(text = stringResource(id = R.string.BankTransferDetailsFragment__invalid_email_address))
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp)
|
||||
.defaultMinSize(minHeight = 78.dp)
|
||||
.onFocusChanged { onFocusChanged(Field.EMAIL, it.hasFocus) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,6 +358,7 @@ private fun IdealBankSelector(
|
||||
Image(
|
||||
painter = painterResource(id = uiValues?.icon ?: R.drawable.bank_transfer),
|
||||
contentDescription = null,
|
||||
colorFilter = if (uiValues?.icon == null) ColorFilter.tint(MaterialTheme.colorScheme.onSurface) else null,
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 12.dp)
|
||||
.size(32.dp)
|
||||
|
||||
@@ -6,12 +6,25 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.subscription.donate.transfer.ideal
|
||||
|
||||
import org.signal.donations.StripeApi
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.transfer.BankDetailsValidator
|
||||
|
||||
data class IdealTransferDetailsState(
|
||||
val isMonthly: Boolean,
|
||||
val idealBank: IdealBank? = null,
|
||||
val name: String = "",
|
||||
val email: String = ""
|
||||
val nameFocusState: FocusState = FocusState.NOT_FOCUSED,
|
||||
val email: String = "",
|
||||
val emailFocusState: FocusState = FocusState.NOT_FOCUSED
|
||||
) {
|
||||
|
||||
fun showNameError(): Boolean {
|
||||
return nameFocusState == FocusState.LOST_FOCUS && !BankDetailsValidator.validName(name)
|
||||
}
|
||||
|
||||
fun showEmailError(): Boolean {
|
||||
return emailFocusState == FocusState.LOST_FOCUS && !BankDetailsValidator.validEmail(email)
|
||||
}
|
||||
|
||||
fun asIDEALData(): StripeApi.IDEALData {
|
||||
return StripeApi.IDEALData(
|
||||
bank = idealBank!!.code,
|
||||
@@ -21,6 +34,12 @@ data class IdealTransferDetailsState(
|
||||
}
|
||||
|
||||
fun canProceed(): Boolean {
|
||||
return idealBank != null && name.isNotBlank() && email.isNotBlank()
|
||||
return idealBank != null && BankDetailsValidator.validName(name) && (!isMonthly || BankDetailsValidator.validEmail(email))
|
||||
}
|
||||
|
||||
enum class FocusState {
|
||||
NOT_FOCUSED,
|
||||
FOCUSED,
|
||||
LOST_FOCUS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
||||
class IdealTransferDetailsViewModel : ViewModel() {
|
||||
class IdealTransferDetailsViewModel(isMonthly: Boolean) : ViewModel() {
|
||||
|
||||
private val internalState = mutableStateOf(IdealTransferDetailsState())
|
||||
private val internalState = mutableStateOf(IdealTransferDetailsState(isMonthly = isMonthly))
|
||||
var state: State<IdealTransferDetailsState> = internalState
|
||||
|
||||
fun onNameChanged(name: String) {
|
||||
@@ -26,9 +26,34 @@ class IdealTransferDetailsViewModel : ViewModel() {
|
||||
)
|
||||
}
|
||||
|
||||
fun onFocusChanged(field: Field, isFocused: Boolean) {
|
||||
when (field) {
|
||||
Field.NAME -> {
|
||||
if (isFocused && internalState.value.nameFocusState == IdealTransferDetailsState.FocusState.NOT_FOCUSED) {
|
||||
internalState.value = internalState.value.copy(nameFocusState = IdealTransferDetailsState.FocusState.FOCUSED)
|
||||
} else if (!isFocused && internalState.value.nameFocusState == IdealTransferDetailsState.FocusState.FOCUSED) {
|
||||
internalState.value = internalState.value.copy(nameFocusState = IdealTransferDetailsState.FocusState.LOST_FOCUS)
|
||||
}
|
||||
}
|
||||
|
||||
Field.EMAIL -> {
|
||||
if (isFocused && internalState.value.emailFocusState == IdealTransferDetailsState.FocusState.NOT_FOCUSED) {
|
||||
internalState.value = internalState.value.copy(emailFocusState = IdealTransferDetailsState.FocusState.FOCUSED)
|
||||
} else if (!isFocused && internalState.value.emailFocusState == IdealTransferDetailsState.FocusState.FOCUSED) {
|
||||
internalState.value = internalState.value.copy(emailFocusState = IdealTransferDetailsState.FocusState.LOST_FOCUS)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onBankSelected(idealBank: IdealBank) {
|
||||
internalState.value = internalState.value.copy(
|
||||
idealBank = idealBank
|
||||
)
|
||||
}
|
||||
|
||||
enum class Field {
|
||||
NAME,
|
||||
EMAIL
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5966,12 +5966,18 @@
|
||||
<string name="BankTransferDetailsFragment__iban_country_code_is_not_supported">IBAN country code is not supported</string>
|
||||
<!-- Error label for IBAN field when number is invalid -->
|
||||
<string name="BankTransferDetailsFragment__invalid_iban">Invalid IBAN</string>
|
||||
<!-- Error label for name field when name is not at least two characters long -->
|
||||
<string name="BankTransferDetailsFragment__minimum_2_characters">Minimum 2 characters</string>
|
||||
<!-- Error label for email field when email is not valid -->
|
||||
<string name="BankTransferDetailsFragment__invalid_email_address">Invalid email address</string>
|
||||
|
||||
<!-- IdealTransferDetailsFragment -->
|
||||
<!-- Title of the screen, displayed in the toolbar -->
|
||||
<string name="IdealTransferDetailsFragment__ideal">iDEAL</string>
|
||||
<!-- Subtitle of the screen, displayed below the toolbar. Placeholder is for \'learn more\' -->
|
||||
<string name="IdealTransferDetailsFragment__enter_your_bank">Enter your bank, name and email. Stripe uses this email to send you updates about your donation. %1$s</string>
|
||||
<!-- Subtitle of the screen, displayed below the toolbar. Placeholder is for \'learn more\' -->
|
||||
<string name="IdealTransferDetailsFragment__enter_your_bank_details_one_time">Enter your bank details. Signal does not collect or store your personal information. %1$s</string>
|
||||
<!-- Subtitle learn-more button displayed inline with the subtitle text -->
|
||||
<string name="IdealTransferDetailsFragment__learn_more">Learn more</string>
|
||||
<!-- Hint label for text entry box for name on bank account -->
|
||||
|
||||
Reference in New Issue
Block a user