Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-05 07:22:30 +02:00
parent 8ede48416d
commit c637c9a194
10 changed files with 607 additions and 8 deletions

View file

@ -1876,6 +1876,8 @@
<string name="tangempay_service_unavailable_title">Service temporarily unavailable</string>
<string name="tangempay_service_unreachable_try_later">The service is currently unreachable. Please try again later.</string>
<string name="tangempay_set_pin_code">Set \nPIN code</string>
<string name="tangempay_set_pin_header">Set up new PIN</string>
<string name="tangempay_set_pin_title">Set PIN</string>
<string name="tangempay_status_deactivated">Account closed</string>
<string name="tangempay_status_replacing">Replacing your card</string>
<string name="tangempay_sync_needed">Use your card or ring to renew session</string>
@ -1888,7 +1890,7 @@
<string name="tangempay_topup_receive_body">Send USDC Polygon to your accounts address </string>
<string name="tangempay_topup_receive_title">From another wallet or exchange</string>
<string name="tangempay_topup_swap_body">Use crypto from your wallet to top up your payment account</string>
<string name="tangempay_topup_swap_title">Swap from Tangem Wallet</string>
<string name="tangempay_topup_swap_title">From your Tangem Wallet</string>
<string name="tangempay_usdc_on_polygon_network">USDC on Polygon network</string>
<string name="tangempay_withdrawal_note_description">Funds from refunded purchases wont be returned your on-chain Polygon balance or be available for withdrawal, but will stay on your card balance for purchases</string>
<string name="tangempay_withdrawal_note_title">Please note</string>

View file

@ -17,6 +17,7 @@ import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.models.account.AccountStatus
import com.tangem.features.tangempay.TangemPayFeatureToggles
import com.tangem.features.tangempay.limit.setup.TangemPayCardLimitSetupComponent
import com.tangem.features.tangempay.limit.setup.TangemPayCardLimitSetupSuccessComponent
import com.tangem.features.tangempay.navigation.TangemPayCardDetailsInnerRoute
@ -29,6 +30,7 @@ internal class TangemPayCardPageComponent @AssistedInject constructor(
@Assisted private val appComponentContext: AppComponentContext,
@Assisted private val params: Params,
private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
) : ComposableContentComponent, AppComponentContext by appComponentContext {
private val stackNavigation = StackNavigation<TangemPayCardDetailsInnerRoute>()
@ -72,7 +74,11 @@ internal class TangemPayCardPageComponent @AssistedInject constructor(
params = TangemPayDetailsContainerComponent.Params(initialStatus = params.initialStatus),
)
TangemPayCardDetailsInnerRoute.ChangePINSuccess -> TangemPayChangePinSuccessComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
appComponentContext = childByContext(
componentContext = componentContext,
router = innerRouter,
),
isRedesignEnabled = tangemPayFeatureToggles.isRedesignEnabled,
)
TangemPayCardDetailsInnerRoute.AddToWallet -> TangemPayAddToWalletComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),

View file

@ -11,6 +11,7 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.security.DisableScreenshotsDisposableEffect
import com.tangem.features.tangempay.model.TangemPayChangePinModel
import com.tangem.features.tangempay.ui.TangemPayChangePinScreen
import com.tangem.features.tangempay.ui.TangemPayChangePinScreenV2
internal class TangemPayChangePinComponent(
private val appComponentContext: AppComponentContext,
@ -24,9 +25,16 @@ internal class TangemPayChangePinComponent(
val state by model.uiState.collectAsStateWithLifecycle()
BackHandler(onBack = router::pop)
DisableScreenshotsDisposableEffect()
TangemPayChangePinScreen(
state = state,
onBackClick = router::pop,
)
if (model.isRedesignEnabled()) {
TangemPayChangePinScreenV2(
state = state,
onBackClick = router::pop,
)
} else {
TangemPayChangePinScreen(
state = state,
onBackClick = router::pop,
)
}
}
}

View file

@ -7,15 +7,21 @@ import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.tangempay.navigation.TangemPayCardDetailsInnerRoute
import com.tangem.features.tangempay.ui.TangemPayChangePinCodeSuccessScreen
import com.tangem.features.tangempay.ui.TangemPayChangePinCodeSuccessScreenV2
internal class TangemPayChangePinSuccessComponent(
private val appComponentContext: AppComponentContext,
private val isRedesignEnabled: Boolean,
) : AppComponentContext by appComponentContext, ComposableContentComponent {
@Composable
override fun Content(modifier: Modifier) {
BackHandler(onBack = ::backToDetails)
TangemPayChangePinCodeSuccessScreen(onClick = ::backToDetails)
if (isRedesignEnabled) {
TangemPayChangePinCodeSuccessScreenV2(onClose = ::backToDetails)
} else {
TangemPayChangePinCodeSuccessScreen(onClick = ::backToDetails)
}
}
private fun backToDetails() {

View file

@ -11,6 +11,7 @@ import com.tangem.core.ui.security.DisableScreenshotsDisposableEffect
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.features.tangempay.model.TangemPayViewPinModel
import com.tangem.features.tangempay.ui.TangemPayViewPinContent
import com.tangem.features.tangempay.ui.TangemPayViewPinContentV2
internal class TangemPayViewPinComponent(
appComponentContext: AppComponentContext,
@ -28,7 +29,11 @@ internal class TangemPayViewPinComponent(
val state by model.uiState.collectAsStateWithLifecycle()
BackHandler(onBack = ::dismiss)
DisableScreenshotsDisposableEffect()
TangemPayViewPinContent(state = state)
if (model.isRedesignEnabled()) {
TangemPayViewPinContentV2(state = state)
} else {
TangemPayViewPinContent(state = state)
}
}
data class Params(

View file

@ -12,6 +12,7 @@ import com.tangem.core.ui.message.ToastMessage
import com.tangem.domain.pay.model.SetPinResult
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
import com.tangem.features.tangempay.TangemPayFeatureToggles
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.entity.TangemPayChangePinUM
@ -27,6 +28,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
@Suppress("LongParameterList")
@Stable
@ModelScoped
internal class TangemPayChangePinModel @Inject constructor(
@ -36,6 +38,7 @@ internal class TangemPayChangePinModel @Inject constructor(
private val router: Router,
private val cardDetailsRepository: TangemPayCardDetailsRepository,
private val analytics: AnalyticsEventHandler,
private val featureToggles: TangemPayFeatureToggles,
) : Model() {
private val params: TangemPayDetailsContainerComponent.Params = paramsContainer.require()
@ -46,8 +49,15 @@ internal class TangemPayChangePinModel @Inject constructor(
analytics.send(TangemPayAnalyticsEvents.ChangePinScreenShown())
}
fun isRedesignEnabled(): Boolean = featureToggles.isRedesignEnabled
private fun onPinCodeChange(pin: String) {
uiState.update(transformer = PinCodeChangeTransformer(newPin = pin))
val state = uiState.value
// In the redesign there is no submit button: a valid full PIN is submitted automatically.
if (featureToggles.isRedesignEnabled && state.submitButtonEnabled && !state.submitButtonLoading) {
onClickSubmit()
}
}
private fun onClickSubmit() {

View file

@ -7,6 +7,7 @@ import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
import com.tangem.features.tangempay.TangemPayFeatureToggles
import com.tangem.features.tangempay.components.TangemPayViewPinComponent
import com.tangem.features.tangempay.entity.TangemPayViewPinUM
import com.tangem.features.tangempay.model.transformers.TangemPayViewPinErrorStateTransformer
@ -25,6 +26,7 @@ internal class TangemPayViewPinModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
private val cardDetailsRepository: TangemPayCardDetailsRepository,
private val analytics: AnalyticsEventHandler,
private val featureToggles: TangemPayFeatureToggles,
) : Model() {
private val params = paramsContainer.require<TangemPayViewPinComponent.Params>()
@ -37,6 +39,8 @@ internal class TangemPayViewPinModel @Inject constructor(
getCardPin()
}
fun isRedesignEnabled(): Boolean = featureToggles.isRedesignEnabled
private fun getCardPin() {
modelScope.launch {
cardDetailsRepository.getPin(userWalletId = params.walletId, cardId = params.cardId)

View file

@ -0,0 +1,98 @@
package com.tangem.features.tangempay.ui
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.TileMode
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.SpacerHMax
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.core.ui.res.generated.icons.Icons
import com.tangem.core.ui.res.generated.icons.ic_success_24
import com.tangem.core.ui.test.TangemPayTestTags
import com.tangem.features.tangempay.details.impl.R
private const val BG_YELLOW_COLOR = 0x52DFAF12
@Suppress("MagicNumber")
@Composable
internal fun TangemPayChangePinCodeSuccessScreenV2(onClose: () -> Unit, modifier: Modifier = Modifier) {
Box(modifier = modifier.fillMaxSize()) {
Box(
modifier = Modifier
.matchParentSize()
.blur(192.dp)
.drawBehind {
val w = size.width
drawRect(
brush = Brush.radialGradient(
colors = listOf(
Color(BG_YELLOW_COLOR),
Color.Transparent,
),
center = Offset(w / 2f, -w * .1f),
radius = w + w * .2f,
tileMode = TileMode.Clamp,
),
)
},
)
Column(
modifier = Modifier
.fillMaxSize()
.windowInsetsPadding(WindowInsets.systemBars)
.padding(top = 72.dp, start = 24.dp, end = 24.dp),
) {
Icon(
modifier = Modifier.size(28.dp),
imageVector = Icons.ic_success_24,
tint = TangemTheme.colors3.icon.primary,
contentDescription = null,
)
SpacerH(TangemTheme.dimens2.x4)
Text(
modifier = Modifier.testTag(TangemPayTestTags.PIN_SUCCESS_TITLE),
text = stringResourceSafe(R.string.tangempay_card_details_change_pin_success_title),
style = TangemTheme.typography3.heading.medium,
color = TangemTheme.colors3.text.primary,
)
Text(
modifier = Modifier.testTag(TangemPayTestTags.PIN_SUCCESS_DESCRIPTION),
text = stringResourceSafe(R.string.tangempay_card_details_change_pin_success_description),
style = TangemTheme.typography3.heading.medium,
color = TangemTheme.colors3.text.secondary,
)
SpacerHMax()
TangemButton(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = TangemTheme.dimens2.x3),
onClick = onClose,
size = TangemButton.Size.X12,
text = resourceReference(R.string.common_close),
)
}
}
}
@Preview(showBackground = true)
@Composable
private fun Preview() {
TangemThemePreviewRedesign {
TangemPayChangePinCodeSuccessScreenV2(onClose = {})
}
}

View file

@ -0,0 +1,239 @@
package com.tangem.features.tangempay.ui
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color.Companion.Transparent
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.SpacerH4
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds.topbar.TangemTopBar
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.ds2.loader.TangemLoader
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.res.generated.icons.Icons
import com.tangem.core.ui.res.generated.icons.ic_cross_20
import com.tangem.core.ui.test.TangemPayTestTags
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.entity.TangemPayChangePinUM
import kotlinx.coroutines.delay
@Composable
internal fun TangemPayChangePinScreenV2(
state: TangemPayChangePinUM,
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxSize()
.statusBarsPadding(),
) {
TangemTopBar(
title = resourceReference(R.string.tangempay_set_pin_title),
endContent = {
TangemButton(
iconStart = TangemIconUM.Icon(imageVector = Icons.ic_cross_20),
onClick = onBackClick,
size = TangemButton.Size.X11,
variant = TangemButton.Variant.Material,
)
},
)
SpacerH(TangemTheme.dimens2.x4)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(top = TangemTheme.dimens2.x12)
.padding(horizontal = TangemTheme.dimens2.x9),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResourceSafe(R.string.tangempay_set_pin_header),
style = TangemTheme.typography3.body.medium,
color = TangemTheme.colors3.text.secondary,
textAlign = TextAlign.Center,
modifier = Modifier.testTag(TangemPayTestTags.PIN_SCREEN_TITLE),
)
SpacerH(TangemTheme.dimens2.x6)
PinCodeSection(state)
SpacerH(TangemTheme.dimens2.x6)
AnimatedVisibility(state.submitButtonLoading) {
TangemLoader()
}
}
}
}
@Composable
private fun PinCodeSection(state: TangemPayChangePinUM, modifier: Modifier = Modifier) {
val focusRequester = remember { FocusRequester() }
Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier) {
PinCode(
value = state.pinCode,
onValueChange = state.onPinCodeChange,
focusRequester = focusRequester,
readOnly = state.submitButtonLoading,
)
AnimatedVisibility(
visible = state.error != null,
) {
val error = remember(this) { requireNotNull(state.error) }
Column {
SpacerH4()
Text(
text = error.resolveReference(),
style = TangemTheme.typography3.caption.medium,
color = TangemTheme.colors3.text.status.warning,
textAlign = TextAlign.Center,
modifier = Modifier.testTag(TangemPayTestTags.PIN_ERROR_MESSAGE),
)
}
}
}
LaunchedEffect(Unit) {
delay(timeMillis = 300)
focusRequester.requestFocus()
}
}
@Composable
private fun PinCode(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
numbersCount: Int = 4,
readOnly: Boolean = false,
focusRequester: FocusRequester = remember { FocusRequester() },
) {
val keyboardController = LocalSoftwareKeyboardController.current
// Hide the keyboard while the PIN is being submitted so it can't be edited mid-request.
LaunchedEffect(readOnly) {
if (readOnly) keyboardController?.hide()
}
BasicTextField(
value = value,
onValueChange = { text ->
if (text.length <= numbersCount && !readOnly) {
onValueChange(text)
}
},
readOnly = readOnly,
modifier = modifier
.focusRequester(focusRequester)
.clickable(enabled = !readOnly) {
focusRequester.requestFocus()
keyboardController?.show()
}
.testTag(TangemPayTestTags.PIN_INPUT_FIELD),
textStyle = TangemTheme.typography3.heading.medium.copy(color = Transparent),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.NumberPassword,
imeAction = ImeAction.Done,
),
keyboardActions = KeyboardActions(onDone = { keyboardController?.hide() }),
cursorBrush = SolidColor(Transparent),
decorationBox = { innerTextField ->
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
verticalAlignment = Alignment.CenterVertically,
) {
repeat(numbersCount) { index ->
val digit = value.getOrNull(index)?.toString()
val isActive = !readOnly && index == value.length
PinDigitBox(
modifier = Modifier.size(
width = TangemTheme.dimens2.x14,
height = TangemTheme.dimens2.x16,
),
digit = digit,
backgroundColor = TangemTheme.colors3.bg.opaque.primary,
borderColor = if (isActive) {
TangemTheme.colors3.border.status.info
} else {
TangemTheme.colors3.border.secondary
},
textColor = TangemTheme.colors3.text.primary,
textStyle = TangemTheme.typography3.heading.medium,
)
}
}
innerTextField()
}
},
)
}
@Preview(showBackground = true)
@Composable
private fun TangemPayChangePinScreenV2Preview(
@PreviewParameter(TangemPayChangePinUMPreviewProvider::class) state: TangemPayChangePinUM,
) {
TangemThemePreview {
TangemPayChangePinScreenV2(
state = state,
onBackClick = {},
)
}
}
private class TangemPayChangePinUMPreviewProvider : CollectionPreviewParameterProvider<TangemPayChangePinUM>(
collection = listOf(
TangemPayChangePinUM(
pinCode = "",
error = null,
onPinCodeChange = {},
submitButtonLoading = false,
submitButtonEnabled = false,
onSubmitClick = {},
),
TangemPayChangePinUM(
pinCode = "1111",
error = resourceReference(R.string.visa_onboarding_pin_validation_error_message),
onPinCodeChange = {},
submitButtonLoading = false,
submitButtonEnabled = false,
onSubmitClick = {},
),
TangemPayChangePinUM(
pinCode = "2580",
error = null,
onPinCodeChange = {},
submitButtonLoading = false,
submitButtonEnabled = true,
onSubmitClick = {},
),
),
)

View file

@ -0,0 +1,221 @@
package com.tangem.features.tangempay.ui
import android.content.res.Configuration
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color.Companion.Transparent
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetType
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetContent
import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds.topbar.TangemTopBar
import com.tangem.core.ui.ds.topbar.TangemTopBarType
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.ds2.loader.TangemLoader
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.entity.TangemPayViewPinUM
@Composable
internal fun TangemPayViewPinContentV2(state: TangemPayViewPinUM) {
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
config = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = state.onDismiss,
content = TangemBottomSheetConfigContent.Empty,
),
onBack = state.onDismiss,
type = TangemBottomSheetType.Modal,
containerColor = TangemTheme.colors3.bg.secondary,
title = {
TangemTopBar(
type = TangemTopBarType.BottomSheet,
endContent = {
TangemButton(
iconStart = TangemIconUM.Icon(iconRes = R.drawable.ic_close_24),
onClick = state.onDismiss,
size = TangemButton.Size.X11,
variant = TangemButton.Variant.Material,
)
},
)
},
content = {
AnimatedContent(
targetState = state,
contentKey = { um -> um::class.java },
transitionSpec = { fadeIn() togetherWith fadeOut() },
) { animatedState ->
when (animatedState) {
is TangemPayViewPinUM.Content -> {
PinSuccessContent(animatedState)
}
is TangemPayViewPinUM.Error -> {
MessageBottomSheetContent(animatedState.errorMessage)
}
is TangemPayViewPinUM.Loading -> {
PinLoadingContent()
}
}
}
},
)
}
@Composable
private fun PinSuccessContent(state: TangemPayViewPinUM.Content, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.padding(horizontal = TangemTheme.dimens2.x4)
.padding(top = TangemTheme.dimens2.x12)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResourceSafe(R.string.tangempay_card_details_view_pin_code_title),
style = TangemTheme.typography3.heading.small,
color = TangemTheme.colors3.text.primary,
textAlign = TextAlign.Center,
)
SpacerH(TangemTheme.dimens2.x2)
Text(
text = stringResourceSafe(R.string.tangempay_card_details_view_pin_code_description),
style = TangemTheme.typography3.subheading.medium,
color = TangemTheme.colors3.text.secondary,
textAlign = TextAlign.Center,
)
SpacerH(TangemTheme.dimens2.x8)
PinCode(value = state.pin)
SpacerH(TangemTheme.dimens2.x12)
TangemButton(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = TangemTheme.dimens2.x4),
size = TangemButton.Size.X12,
text = resourceReference(R.string.tangempay_change_pin_code),
onClick = state.onClickChangePin,
)
}
}
@Composable
private fun PinLoadingContent(modifier: Modifier = Modifier) {
Column(
modifier = modifier
.padding(horizontal = TangemTheme.dimens2.x4)
.padding(top = TangemTheme.dimens2.x12)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResourceSafe(R.string.tangempay_card_details_view_pin_code_title),
style = TangemTheme.typography3.heading.small,
color = TangemTheme.colors3.text.primary,
textAlign = TextAlign.Center,
)
SpacerH(TangemTheme.dimens2.x2)
Text(
text = stringResourceSafe(R.string.tangempay_card_details_view_pin_code_description),
style = TangemTheme.typography3.subheading.medium,
color = TangemTheme.colors3.text.secondary,
textAlign = TextAlign.Center,
)
SpacerH(TangemTheme.dimens2.x8)
TangemLoader(
modifier = Modifier.padding(vertical = TangemTheme.dimens2.x5),
)
SpacerH(TangemTheme.dimens2.x12)
TangemButton(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = TangemTheme.dimens2.x4),
size = TangemButton.Size.X12,
text = resourceReference(R.string.tangempay_change_pin_code),
onClick = {},
isEnabled = false,
)
}
}
@Composable
private fun PinCode(value: String, modifier: Modifier = Modifier, numbersCount: Int = 4) {
BasicTextField(
enabled = false,
value = value,
onValueChange = {},
modifier = modifier,
textStyle = TangemTheme.typography3.heading.medium.copy(color = Transparent),
cursorBrush = SolidColor(Transparent),
decorationBox = { innerTextField ->
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
verticalAlignment = Alignment.CenterVertically,
) {
repeat(numbersCount) { index ->
val digit = value.getOrNull(index)?.toString()
PinDigitBox(
modifier = Modifier.size(
width = TangemTheme.dimens2.x14,
height = TangemTheme.dimens2.x16,
),
digit = digit,
backgroundColor = TangemTheme.colors3.bg.opaque.primary,
borderColor = TangemTheme.colors3.border.secondary,
textColor = TangemTheme.colors3.text.primary,
textStyle = TangemTheme.typography3.heading.medium,
)
}
}
innerTextField()
}
},
)
}
@Preview(showBackground = true)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun TangemPayViewPinContentPreview() {
TangemThemePreviewRedesign {
TangemPayViewPinContentV2(
state = TangemPayViewPinUM.Content(
pin = "1234",
onClickChangePin = {},
onDismiss = {},
),
)
}
}