Updated on 2026-08-14
This commit is contained in:
parent
52925902c2
commit
1ac0556dc8
19 changed files with 491 additions and 264 deletions
|
|
@ -15,6 +15,8 @@ import com.tangem.core.decompose.model.getOrCreateModel
|
|||
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.tangempay.components.cardDetails.DefaultTangemPayCardDetailsBlockComponent
|
||||
import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent
|
||||
import com.tangem.features.tangempay.components.txHistory.DefaultTangemPayTxHistoryComponent
|
||||
import com.tangem.features.tangempay.components.txHistory.TangemPayTxHistoryDetailsComponent
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsNavigation
|
||||
|
|
@ -44,6 +46,11 @@ internal class TangemPayDetailsComponent(
|
|||
),
|
||||
)
|
||||
|
||||
private val cardDetailsBlockComponent = DefaultTangemPayCardDetailsBlockComponent(
|
||||
appComponentContext = child("cardDetailsBlockComponent"),
|
||||
params = TangemPayCardDetailsBlockComponent.Params(params = params),
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
|
@ -53,6 +60,7 @@ internal class TangemPayDetailsComponent(
|
|||
TangemPayDetailsScreen(
|
||||
state = state,
|
||||
txHistoryComponent = txHistoryComponent,
|
||||
cardDetailsBlockComponent = cardDetailsBlockComponent,
|
||||
modifier = modifier,
|
||||
)
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.features.tangempay.components.cardDetails
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM
|
||||
import com.tangem.features.tangempay.model.TangemPayCardDetailsBlockModel
|
||||
import com.tangem.features.tangempay.ui.CardDetailsItem
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
internal class DefaultTangemPayCardDetailsBlockComponent(
|
||||
appComponentContext: AppComponentContext,
|
||||
params: TangemPayCardDetailsBlockComponent.Params,
|
||||
) : AppComponentContext by appComponentContext, TangemPayCardDetailsBlockComponent {
|
||||
|
||||
private val model: TangemPayCardDetailsBlockModel = getOrCreateModel(params = params)
|
||||
override val state: StateFlow<TangemPayCardDetailsUM> = model.uiState
|
||||
|
||||
@Composable
|
||||
override fun CardDetailsBlockContent(state: TangemPayCardDetailsUM, modifier: Modifier) {
|
||||
CardDetailsItem(state, modifier)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.tangempay.components.cardDetails
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM
|
||||
import com.tangem.features.tangempay.ui.CardDetailsItem
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
internal class PreviewTangemPayCardDetailsBlockComponent(
|
||||
state: TangemPayCardDetailsUM,
|
||||
) : TangemPayCardDetailsBlockComponent {
|
||||
|
||||
override val state: StateFlow<TangemPayCardDetailsUM> = MutableStateFlow(state)
|
||||
|
||||
@Composable
|
||||
override fun CardDetailsBlockContent(state: TangemPayCardDetailsUM, modifier: Modifier) {
|
||||
CardDetailsItem(state, modifier)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.features.tangempay.components.cardDetails
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
internal interface TangemPayCardDetailsBlockComponent {
|
||||
val state: StateFlow<TangemPayCardDetailsUM>
|
||||
|
||||
@Composable
|
||||
fun CardDetailsBlockContent(state: TangemPayCardDetailsUM, modifier: Modifier = Modifier)
|
||||
|
||||
data class Params(val params: TangemPayDetailsContainerComponent.Params)
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@ package com.tangem.features.tangempay.di
|
|||
|
||||
import com.tangem.features.tangempay.components.DefaultTangemPayDetailsContainerComponent
|
||||
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
|
||||
import com.tangem.features.tangempay.model.listener.CardDetailsEventListener
|
||||
import com.tangem.features.tangempay.model.listener.DefaultCardDetailsEventListener
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -17,4 +19,8 @@ internal interface TangemPayDetailsFeatureModule {
|
|||
fun bindTangemPayDetailsContainerComponentFactory(
|
||||
factory: DefaultTangemPayDetailsContainerComponent.Factory,
|
||||
): TangemPayDetailsContainerComponent.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindCardDetailsEventListener(impl: DefaultCardDetailsEventListener): CardDetailsEventListener
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.tangempay.di
|
|||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.tangempay.model.TangemPayCardDetailsBlockModel
|
||||
import com.tangem.features.tangempay.model.TangemPayChangePinModel
|
||||
import com.tangem.features.tangempay.model.TangemPayDetailsModel
|
||||
import com.tangem.features.tangempay.model.TangemPayTxHistoryDetailsModel
|
||||
|
|
@ -35,4 +36,9 @@ internal interface TangemPayModelModule {
|
|||
@IntoMap
|
||||
@ClassKey(TangemPayChangePinModel::class)
|
||||
fun bindTangemPayChangePinModel(model: TangemPayChangePinModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(TangemPayCardDetailsBlockModel::class)
|
||||
fun bindTangemPayCardDetailsBlockModel(model: TangemPayCardDetailsBlockModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.features.tangempay.entity
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.utils.CardDetailsFormatUtil
|
||||
import com.tangem.utils.StringsSigns
|
||||
|
||||
private const val CARD_NUMBER_SART_DIGITS_COUNT = 12
|
||||
private const val DATE_PART_LENGTH = 2
|
||||
private const val CVV_LENGTH = 3
|
||||
|
||||
internal class TangemPayCardDetailsBlockStateFactory(
|
||||
private val cardNumberEnd: String,
|
||||
private val onReveal: () -> Unit,
|
||||
private val onCopy: (String) -> Unit,
|
||||
) {
|
||||
|
||||
private val cardStartMasked = maskedBlock(CARD_NUMBER_SART_DIGITS_COUNT)
|
||||
private val dateMasked = maskedBlock(DATE_PART_LENGTH)
|
||||
private val cvvMasked = maskedBlock(CVV_LENGTH)
|
||||
|
||||
fun getInitialState() = TangemPayCardDetailsUM(
|
||||
number = CardDetailsFormatUtil.formatCardNumber(cardNumber = "$cardStartMasked$cardNumberEnd"),
|
||||
expiry = CardDetailsFormatUtil.formatDate(month = dateMasked, year = dateMasked),
|
||||
cvv = cvvMasked,
|
||||
buttonText = TextReference.Res(R.string.tangempay_card_details_reveal_text),
|
||||
onClick = onReveal,
|
||||
onCopy = onCopy,
|
||||
isHidden = true,
|
||||
)
|
||||
|
||||
private fun maskedBlock(count: Int) = StringsSigns.DOT.repeat(count)
|
||||
}
|
||||
|
|
@ -8,30 +8,16 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.utils.CardDetailsFormatUtil
|
||||
import com.tangem.utils.StringsSigns
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
private const val CARD_NUMBER_SART_DIGITS_COUNT = 12
|
||||
private const val DATE_PART_LENGTH = 2
|
||||
private const val CVV_LENGTH = 3
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class TangemPayDetailsStateFactory(
|
||||
private val cardNumberEnd: String,
|
||||
private val onBack: () -> Unit,
|
||||
private val onRefresh: (ShowRefreshState) -> Unit,
|
||||
private val onReceive: () -> Unit,
|
||||
private val onReveal: () -> Unit,
|
||||
private val onCopy: (String) -> Unit,
|
||||
private val onClickChangePin: () -> Unit,
|
||||
private val onClickFreezeCard: () -> Unit,
|
||||
) {
|
||||
|
||||
private val cardStartMasked = maskedBlock(CARD_NUMBER_SART_DIGITS_COUNT)
|
||||
private val dateMasked = maskedBlock(DATE_PART_LENGTH)
|
||||
private val cvvMasked = maskedBlock(CVV_LENGTH)
|
||||
|
||||
fun getInitialState() = TangemPayDetailsUM(
|
||||
topBarConfig = TangemPayDetailsTopBarConfig(
|
||||
onBackClick = onBack,
|
||||
|
|
@ -58,18 +44,6 @@ internal class TangemPayDetailsStateFactory(
|
|||
),
|
||||
),
|
||||
),
|
||||
cardDetailsUM = TangemPayCardDetailsUM(
|
||||
number = CardDetailsFormatUtil.formatCardNumber(cardNumber = "$cardStartMasked$cardNumberEnd"),
|
||||
expiry = CardDetailsFormatUtil.formatDate(month = dateMasked, year = dateMasked),
|
||||
cvv = cvvMasked,
|
||||
buttonText = TextReference.Res(R.string.tangempay_card_details_reveal_text),
|
||||
onClick = onReveal,
|
||||
onCopy = onCopy,
|
||||
isHidden = true,
|
||||
),
|
||||
isBalanceHidden = false,
|
||||
|
||||
)
|
||||
|
||||
private fun maskedBlock(count: Int) = StringsSigns.DOT.repeat(count)
|
||||
}
|
||||
|
|
@ -9,11 +9,10 @@ internal data class TangemPayDetailsUM(
|
|||
val topBarConfig: TangemPayDetailsTopBarConfig,
|
||||
val pullToRefreshConfig: PullToRefreshConfig,
|
||||
val balanceBlockState: TangemPayDetailsBalanceBlockState,
|
||||
val cardDetailsUM: TangemPayCardDetailsUM,
|
||||
val isBalanceHidden: Boolean,
|
||||
)
|
||||
|
||||
data class TangemPayCardDetailsUM(
|
||||
internal data class TangemPayCardDetailsUM(
|
||||
val number: String = "",
|
||||
val expiry: String = "",
|
||||
val cvv: String = "",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
package com.tangem.features.tangempay.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.pay.repository.CardDetailsRepository
|
||||
import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardDetailsBlockStateFactory
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM
|
||||
import com.tangem.features.tangempay.model.listener.CardDetailsEvent
|
||||
import com.tangem.features.tangempay.model.listener.CardDetailsEventListener
|
||||
import com.tangem.features.tangempay.model.transformers.DetailsHiddenStateTransformer
|
||||
import com.tangem.features.tangempay.model.transformers.DetailsRevealProgressStateTransformer
|
||||
import com.tangem.features.tangempay.model.transformers.DetailsRevealedStateTransformer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import com.tangem.utils.transformer.update
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class TangemPayCardDetailsBlockModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val cardDetailsRepository: CardDetailsRepository,
|
||||
private val clipboardManager: ClipboardManager,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val cardDetailsEventListener: CardDetailsEventListener,
|
||||
) : Model() {
|
||||
|
||||
private val params: TangemPayCardDetailsBlockComponent.Params = paramsContainer.require()
|
||||
|
||||
private val stateFactory = TangemPayCardDetailsBlockStateFactory(
|
||||
cardNumberEnd = params.params.config.cardNumberEnd,
|
||||
onReveal = ::revealCardDetails,
|
||||
onCopy = ::copyData,
|
||||
)
|
||||
|
||||
val uiState: StateFlow<TangemPayCardDetailsUM>
|
||||
field = MutableStateFlow(stateFactory.getInitialState())
|
||||
|
||||
private val revealCardDetailsJobHolder = JobHolder()
|
||||
|
||||
init {
|
||||
modelScope.launch {
|
||||
cardDetailsEventListener.event.collectLatest { event ->
|
||||
when (event) {
|
||||
CardDetailsEvent.Hide -> hideCardDetails()
|
||||
CardDetailsEvent.Show -> revealCardDetails()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun revealCardDetails() {
|
||||
modelScope.launch {
|
||||
uiState.update(
|
||||
transformer = DetailsRevealProgressStateTransformer(onClickHide = ::hideCardDetails),
|
||||
)
|
||||
cardDetailsRepository.revealCardDetails()
|
||||
.onRight {
|
||||
uiState.update(
|
||||
transformer = DetailsRevealedStateTransformer(
|
||||
details = it,
|
||||
onClickHide = ::hideCardDetails,
|
||||
),
|
||||
)
|
||||
}
|
||||
.onLeft {
|
||||
uiState.update(transformer = DetailsHiddenStateTransformer(stateFactory))
|
||||
showError()
|
||||
}
|
||||
}.saveIn(revealCardDetailsJobHolder)
|
||||
}
|
||||
|
||||
fun hideCardDetails() {
|
||||
modelScope.launch {
|
||||
revealCardDetailsJobHolder.cancel()
|
||||
uiState.update(transformer = DetailsHiddenStateTransformer(stateFactory))
|
||||
}
|
||||
}
|
||||
|
||||
private fun showError() {
|
||||
uiMessageSender.send(
|
||||
SnackbarMessage(TextReference.Res(R.string.tangempay_card_details_error_text)),
|
||||
)
|
||||
}
|
||||
|
||||
private fun copyData(text: String) {
|
||||
clipboardManager.setText(text = text.filterNot { it.isWhitespace() }, isSensitive = true)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,21 +8,20 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig.ShowRefreshState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.pay.DataForReceiveFactory
|
||||
import com.tangem.domain.pay.repository.CardDetailsRepository
|
||||
import com.tangem.domain.visa.model.TangemPayTxHistoryItem
|
||||
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsErrorType
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsNavigation
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsStateFactory
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
|
||||
import com.tangem.features.tangempay.model.transformers.*
|
||||
import com.tangem.features.tangempay.model.listener.CardDetailsEvent
|
||||
import com.tangem.features.tangempay.model.listener.CardDetailsEventListener
|
||||
import com.tangem.features.tangempay.model.transformers.DetailsBalanceTransformer
|
||||
import com.tangem.features.tangempay.model.transformers.TangemPayDetailsRefreshTransformer
|
||||
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
|
||||
import com.tangem.features.tangempay.utils.TangemPayErrorMessageFactory
|
||||
import com.tangem.features.tangempay.utils.TangemPayTxHistoryUiActions
|
||||
|
|
@ -45,19 +44,16 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
private val router: Router,
|
||||
private val cardDetailsRepository: CardDetailsRepository,
|
||||
private val dataForReceiveFactory: DataForReceiveFactory,
|
||||
private val clipboardManager: ClipboardManager,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val cardDetailsEventListener: CardDetailsEventListener,
|
||||
) : Model(), TangemPayTxHistoryUiActions {
|
||||
|
||||
private val params: TangemPayDetailsContainerComponent.Params = paramsContainer.require()
|
||||
|
||||
private val stateFactory = TangemPayDetailsStateFactory(
|
||||
cardNumberEnd = params.config.cardNumberEnd,
|
||||
onBack = router::pop,
|
||||
onRefresh = ::onRefreshSwipe,
|
||||
onReceive = ::onClickReceive,
|
||||
onReveal = ::revealCardDetails,
|
||||
onCopy = ::copyData,
|
||||
onClickChangePin = ::onClickChangePin,
|
||||
onClickFreezeCard = ::onClickFreezeCard,
|
||||
)
|
||||
|
|
@ -67,7 +63,6 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
|
||||
private val refreshStateJobHolder = JobHolder()
|
||||
private val fetchBalanceJobHolder = JobHolder()
|
||||
private val revealCardDetailsJobHolder = JobHolder()
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<TangemPayDetailsNavigation> = SlotNavigation()
|
||||
|
||||
|
|
@ -112,50 +107,13 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
|
||||
private fun onRefreshSwipe(refreshState: ShowRefreshState) {
|
||||
modelScope.launch {
|
||||
hideCardDetails()
|
||||
cardDetailsEventListener.send(CardDetailsEvent.Hide)
|
||||
uiState.update(TangemPayDetailsRefreshTransformer(isRefreshing = refreshState.value))
|
||||
fetchBalance().join()
|
||||
uiState.update(TangemPayDetailsRefreshTransformer(isRefreshing = false))
|
||||
}.saveIn(refreshStateJobHolder)
|
||||
}
|
||||
|
||||
private fun revealCardDetails() {
|
||||
modelScope.launch {
|
||||
uiState.update(
|
||||
transformer = DetailsRevealProgressStateTransformer(onClickHide = ::hideCardDetails),
|
||||
)
|
||||
cardDetailsRepository.revealCardDetails()
|
||||
.onRight {
|
||||
uiState.update(
|
||||
transformer = DetailsRevealedStateTransformer(
|
||||
details = it,
|
||||
onClickHide = ::hideCardDetails,
|
||||
),
|
||||
)
|
||||
}
|
||||
.onLeft {
|
||||
uiState.update(transformer = DetailsHiddenStateTransformer(stateFactory))
|
||||
showError()
|
||||
}
|
||||
}.saveIn(revealCardDetailsJobHolder)
|
||||
}
|
||||
|
||||
private fun hideCardDetails() {
|
||||
modelScope.launch {
|
||||
revealCardDetailsJobHolder.cancel()
|
||||
uiState.update(transformer = DetailsHiddenStateTransformer(stateFactory))
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyData(text: String) {
|
||||
clipboardManager.setText(text = text.filterNot { it.isWhitespace() }, isSensitive = true)
|
||||
}
|
||||
private fun showError() {
|
||||
uiMessageSender.send(
|
||||
SnackbarMessage(TextReference.Res(R.string.tangempay_card_details_error_text)),
|
||||
)
|
||||
}
|
||||
|
||||
override fun onTransactionClick(item: TangemPayTxHistoryItem) {
|
||||
bottomSheetNavigation.activate(TangemPayDetailsNavigation.TransactionDetails(item))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.features.tangempay.model.listener
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* Card details must be hidden after some UI actions from the external component
|
||||
*/
|
||||
internal interface CardDetailsEventListener {
|
||||
|
||||
val event: Flow<CardDetailsEvent>
|
||||
|
||||
suspend fun send(event: CardDetailsEvent)
|
||||
}
|
||||
|
||||
internal enum class CardDetailsEvent {
|
||||
Hide, Show
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.features.tangempay.model.listener
|
||||
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
internal class DefaultCardDetailsEventListener @Inject constructor() : CardDetailsEventListener {
|
||||
|
||||
private val _event = MutableSharedFlow<CardDetailsEvent>(
|
||||
replay = 1,
|
||||
extraBufferCapacity = 0,
|
||||
onBufferOverflow = BufferOverflow.DROP_OLDEST,
|
||||
)
|
||||
override val event: Flow<CardDetailsEvent> = _event
|
||||
|
||||
override suspend fun send(event: CardDetailsEvent) {
|
||||
_event.emit(event)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
package com.tangem.features.tangempay.model.transformers
|
||||
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsStateFactory
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardDetailsBlockStateFactory
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class DetailsHiddenStateTransformer(
|
||||
private val stateFactory: TangemPayDetailsStateFactory,
|
||||
) : Transformer<TangemPayDetailsUM> {
|
||||
private val stateFactory: TangemPayCardDetailsBlockStateFactory,
|
||||
) : Transformer<TangemPayCardDetailsUM> {
|
||||
|
||||
override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM {
|
||||
return prevState.copy(cardDetailsUM = stateFactory.getInitialState().cardDetailsUM)
|
||||
override fun transform(prevState: TangemPayCardDetailsUM): TangemPayCardDetailsUM {
|
||||
return stateFactory.getInitialState()
|
||||
}
|
||||
}
|
||||
|
|
@ -2,21 +2,19 @@ package com.tangem.features.tangempay.model.transformers
|
|||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class DetailsRevealProgressStateTransformer(
|
||||
private val onClickHide: (() -> Unit),
|
||||
) : Transformer<TangemPayDetailsUM> {
|
||||
) : Transformer<TangemPayCardDetailsUM> {
|
||||
|
||||
override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM {
|
||||
override fun transform(prevState: TangemPayCardDetailsUM): TangemPayCardDetailsUM {
|
||||
return prevState.copy(
|
||||
cardDetailsUM = prevState.cardDetailsUM.copy(
|
||||
buttonText = TextReference.Res(R.string.tangempay_card_details_hide_text),
|
||||
onClick = onClickHide,
|
||||
isLoading = true,
|
||||
isHidden = true,
|
||||
),
|
||||
buttonText = TextReference.Res(R.string.tangempay_card_details_hide_text),
|
||||
onClick = onClickHide,
|
||||
isLoading = true,
|
||||
isHidden = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,25 +4,23 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
import com.tangem.domain.pay.model.TangemPayCardDetails
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
|
||||
import com.tangem.features.tangempay.utils.CardDetailsFormatUtil
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class DetailsRevealedStateTransformer(
|
||||
private val details: TangemPayCardDetails,
|
||||
private val onClickHide: (() -> Unit),
|
||||
) : Transformer<TangemPayDetailsUM> {
|
||||
) : Transformer<TangemPayCardDetailsUM> {
|
||||
|
||||
override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM {
|
||||
val cardDetailsUM = TangemPayCardDetailsUM(
|
||||
override fun transform(prevState: TangemPayCardDetailsUM): TangemPayCardDetailsUM {
|
||||
return TangemPayCardDetailsUM(
|
||||
number = CardDetailsFormatUtil.formatCardNumber(cardNumber = details.pan),
|
||||
expiry = CardDetailsFormatUtil.formatDate(month = details.expirationMonth, year = details.expirationYear),
|
||||
cvv = details.cvv,
|
||||
onClick = onClickHide,
|
||||
buttonText = TextReference.Res(R.string.tangempay_card_details_hide_text),
|
||||
onCopy = prevState.cardDetailsUM.onCopy,
|
||||
onCopy = prevState.onCopy,
|
||||
isHidden = false,
|
||||
)
|
||||
return prevState.copy(cardDetailsUM = cardDetailsUM)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.features.tangempay.ui
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM
|
||||
|
||||
@Composable
|
||||
internal fun CardDetailsItem(state: TangemPayCardDetailsUM, modifier: Modifier = Modifier) {
|
||||
TangemPayCardDetailsBlock(
|
||||
modifier = modifier
|
||||
.padding(top = TangemTheme.dimens.spacing12)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
state = state,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
package com.tangem.features.tangempay.ui
|
||||
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.RepeatMode
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.infiniteRepeatable
|
||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM
|
||||
|
||||
private const val REVEAL_ANIMATION_MILLIS = 500
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayCardDetailsBlock(state: TangemPayCardDetailsUM, modifier: Modifier = Modifier) {
|
||||
val alpha = if (state.isLoading) {
|
||||
val infiniteTransition = rememberInfiniteTransition()
|
||||
val animation by infiniteTransition.animateFloat(
|
||||
initialValue = 1f,
|
||||
targetValue = 0.3f,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(REVEAL_ANIMATION_MILLIS, easing = LinearEasing),
|
||||
repeatMode = RepeatMode.Reverse,
|
||||
),
|
||||
)
|
||||
animation
|
||||
} else {
|
||||
1f
|
||||
}
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(
|
||||
color = TangemTheme.colors.background.primary,
|
||||
shape = TangemTheme.shapes.roundedCornersMedium,
|
||||
),
|
||||
) {
|
||||
CardDetailsBlockHeader(state)
|
||||
CardDetailsTextContainer(
|
||||
modifier = Modifier
|
||||
.graphicsLayer { this.alpha = alpha }
|
||||
.fillMaxWidth()
|
||||
.padding(start = 12.dp, end = 12.dp, top = 4.dp),
|
||||
text = state.number,
|
||||
onCopy = { state.onCopy(state.number) },
|
||||
isHidden = state.isHidden,
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 12.dp, end = 12.dp, bottom = 12.dp, top = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
CardDetailsTextContainer(
|
||||
modifier = Modifier
|
||||
.graphicsLayer { this.alpha = alpha }
|
||||
.weight(1f),
|
||||
text = state.expiry,
|
||||
onCopy = { state.onCopy(state.expiry) },
|
||||
isHidden = state.isHidden,
|
||||
)
|
||||
CardDetailsTextContainer(
|
||||
modifier = Modifier
|
||||
.graphicsLayer { this.alpha = alpha }
|
||||
.weight(1f),
|
||||
text = state.cvv,
|
||||
onCopy = { state.onCopy(state.cvv) },
|
||||
isHidden = state.isHidden,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CardDetailsBlockHeader(state: TangemPayCardDetailsUM, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(start = 12.dp, top = 12.dp),
|
||||
text = stringResourceSafe(R.string.tangempay_card_details_title),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(top = 8.dp, end = 4.dp)
|
||||
.clip(TangemTheme.shapes.roundedCornersMedium)
|
||||
.clickable(onClick = state.onClick)
|
||||
.padding(horizontal = 8.dp, vertical = 4.dp),
|
||||
text = state.buttonText.resolveReference(),
|
||||
color = TangemTheme.colors.text.accent,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CardDetailsTextContainer(
|
||||
text: String,
|
||||
isHidden: Boolean,
|
||||
onCopy: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.heightIn(min = 48.dp)
|
||||
.background(color = TangemTheme.colors.field.primary, shape = RoundedCornerShape(16.dp)),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 4.dp, horizontal = 12.dp),
|
||||
text = text,
|
||||
maxLines = 1,
|
||||
color = if (isHidden) TangemTheme.colors.text.disabled else TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
|
||||
if (!isHidden) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.padding(end = TangemTheme.dimens.spacing8)
|
||||
.size(TangemTheme.dimens.size32),
|
||||
onClick = onCopy,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size24),
|
||||
painter = painterResource(id = R.drawable.ic_copy_new_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,20 +2,14 @@ package com.tangem.features.tangempay.ui
|
|||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
|
|
@ -39,6 +33,8 @@ import com.tangem.core.ui.extensions.*
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.TokenDetailsTopBarTestTags
|
||||
import com.tangem.features.tangempay.components.cardDetails.PreviewTangemPayCardDetailsBlockComponent
|
||||
import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent
|
||||
import com.tangem.features.tangempay.components.txHistory.PreviewTangemPayTxHistoryComponent
|
||||
import com.tangem.features.tangempay.components.txHistory.TangemPayTxHistoryComponent
|
||||
import com.tangem.features.tangempay.details.impl.R
|
||||
|
|
@ -46,12 +42,11 @@ import com.tangem.features.tangempay.entity.*
|
|||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
private const val REVEAL_ANIMATION_MILLIS = 500
|
||||
|
||||
@Composable
|
||||
internal fun TangemPayDetailsScreen(
|
||||
state: TangemPayDetailsUM,
|
||||
txHistoryComponent: TangemPayTxHistoryComponent,
|
||||
cardDetailsBlockComponent: TangemPayCardDetailsBlockComponent,
|
||||
modifier: Modifier = Modifier,
|
||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||
) {
|
||||
|
|
@ -70,6 +65,7 @@ internal fun TangemPayDetailsScreen(
|
|||
val listState = rememberLazyListState()
|
||||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
val txHistoryState by txHistoryComponent.state.collectAsStateWithLifecycle()
|
||||
val cardDetailsState by cardDetailsBlockComponent.state.collectAsStateWithLifecycle()
|
||||
|
||||
TangemPullToRefreshContainer(
|
||||
config = state.pullToRefreshConfig,
|
||||
|
|
@ -94,19 +90,11 @@ internal fun TangemPayDetailsScreen(
|
|||
)
|
||||
},
|
||||
)
|
||||
item(
|
||||
key = TangemPayCardDetailsUM::class.java,
|
||||
content = {
|
||||
TangemPayCardDetailsBlock(
|
||||
modifier = modifier
|
||||
.padding(top = TangemTheme.dimens.spacing12)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
state = state.cardDetailsUM,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
with(cardDetailsBlockComponent) {
|
||||
item(TangemPayCardDetailsUM::class.java) {
|
||||
CardDetailsBlockContent(state = cardDetailsState)
|
||||
}
|
||||
}
|
||||
with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryState) }
|
||||
}
|
||||
}
|
||||
|
|
@ -218,136 +206,6 @@ private fun CryptoBalance(
|
|||
}
|
||||
// endregion
|
||||
|
||||
// region Card details block
|
||||
@Composable
|
||||
private fun TangemPayCardDetailsBlock(state: TangemPayCardDetailsUM, modifier: Modifier = Modifier) {
|
||||
val alpha = if (state.isLoading) {
|
||||
val infiniteTransition = rememberInfiniteTransition()
|
||||
val animation by infiniteTransition.animateFloat(
|
||||
initialValue = 1f,
|
||||
targetValue = 0.3f,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(REVEAL_ANIMATION_MILLIS, easing = LinearEasing),
|
||||
repeatMode = RepeatMode.Reverse,
|
||||
),
|
||||
)
|
||||
animation
|
||||
} else {
|
||||
1f
|
||||
}
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(
|
||||
color = TangemTheme.colors.background.primary,
|
||||
shape = TangemTheme.shapes.roundedCornersMedium,
|
||||
),
|
||||
) {
|
||||
CardDetailsBlockHeader(state)
|
||||
CardDetailsTextContainer(
|
||||
modifier = Modifier
|
||||
.graphicsLayer { this.alpha = alpha }
|
||||
.fillMaxWidth()
|
||||
.padding(start = 12.dp, end = 12.dp, top = 4.dp),
|
||||
text = state.number,
|
||||
onCopy = { state.onCopy(state.number) },
|
||||
isHidden = state.isHidden,
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 12.dp, end = 12.dp, bottom = 12.dp, top = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
CardDetailsTextContainer(
|
||||
modifier = Modifier
|
||||
.graphicsLayer { this.alpha = alpha }
|
||||
.weight(1f),
|
||||
text = state.expiry,
|
||||
onCopy = { state.onCopy(state.expiry) },
|
||||
isHidden = state.isHidden,
|
||||
)
|
||||
CardDetailsTextContainer(
|
||||
modifier = Modifier
|
||||
.graphicsLayer { this.alpha = alpha }
|
||||
.weight(1f),
|
||||
text = state.cvv,
|
||||
onCopy = { state.onCopy(state.cvv) },
|
||||
isHidden = state.isHidden,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CardDetailsBlockHeader(state: TangemPayCardDetailsUM, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(start = 12.dp, top = 12.dp),
|
||||
text = stringResourceSafe(R.string.tangempay_card_details_title),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(top = 8.dp, end = 4.dp)
|
||||
.clip(TangemTheme.shapes.roundedCornersMedium)
|
||||
.clickable(onClick = state.onClick)
|
||||
.padding(horizontal = 8.dp, vertical = 4.dp),
|
||||
text = state.buttonText.resolveReference(),
|
||||
color = TangemTheme.colors.text.accent,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CardDetailsTextContainer(
|
||||
text: String,
|
||||
isHidden: Boolean,
|
||||
onCopy: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.heightIn(min = 48.dp)
|
||||
.background(color = TangemTheme.colors.field.primary, shape = RoundedCornerShape(16.dp)),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 4.dp, horizontal = 12.dp),
|
||||
text = text,
|
||||
maxLines = 1,
|
||||
color = if (isHidden) TangemTheme.colors.text.disabled else TangemTheme.colors.text.primary1,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
|
||||
if (!isHidden) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.padding(end = TangemTheme.dimens.spacing8)
|
||||
.size(TangemTheme.dimens.size32),
|
||||
onClick = onCopy,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size24),
|
||||
painter = painterResource(id = R.drawable.ic_copy_new_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun TangemPayDetailsTopAppBar(config: TangemPayDetailsTopBarConfig, modifier: Modifier = Modifier) {
|
||||
|
|
@ -411,6 +269,16 @@ private fun TangemPayDetailsScreenPreview(
|
|||
txHistoryComponent = PreviewTangemPayTxHistoryComponent(
|
||||
txHistoryUM = PreviewTangemPayTxHistoryComponent.contentUM,
|
||||
),
|
||||
cardDetailsBlockComponent = PreviewTangemPayCardDetailsBlockComponent(
|
||||
TangemPayCardDetailsUM(
|
||||
number = "•••• •••• •••• 1245",
|
||||
expiry = "••/••",
|
||||
cvv = "•••",
|
||||
onCopy = {},
|
||||
onClick = {},
|
||||
buttonText = TextReference.Res(R.string.tangempay_card_details_hide_text),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -432,28 +300,12 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<Ta
|
|||
fiatBalance = "$1234.56",
|
||||
isBalanceFlickering = false,
|
||||
),
|
||||
cardDetailsUM = TangemPayCardDetailsUM(
|
||||
number = "•••• •••• •••• 1245",
|
||||
expiry = "••/••",
|
||||
cvv = "•••",
|
||||
onCopy = {},
|
||||
onClick = {},
|
||||
buttonText = TextReference.Res(R.string.tangempay_card_details_reveal_text),
|
||||
),
|
||||
isBalanceHidden = false,
|
||||
),
|
||||
TangemPayDetailsUM(
|
||||
topBarConfig = TangemPayDetailsTopBarConfig(onBackClick = {}, items = null),
|
||||
pullToRefreshConfig = PullToRefreshConfig(isRefreshing = false, onRefresh = {}),
|
||||
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(actionButtons = persistentListOf()),
|
||||
cardDetailsUM = TangemPayCardDetailsUM(
|
||||
number = "•••• •••• •••• 1245",
|
||||
expiry = "••/••",
|
||||
cvv = "•••",
|
||||
onCopy = {},
|
||||
onClick = {},
|
||||
buttonText = TextReference.Res(R.string.tangempay_card_details_hide_text),
|
||||
),
|
||||
isBalanceHidden = false,
|
||||
),
|
||||
),
|
||||
|
|
@ -468,6 +320,16 @@ private fun TangemPayDetailsTxHistoryScreenPreview(
|
|||
TangemPayDetailsScreen(
|
||||
state = TangemPayDetailsUMProvider().values.first(),
|
||||
txHistoryComponent = PreviewTangemPayTxHistoryComponent(txHistoryUM = state),
|
||||
cardDetailsBlockComponent = PreviewTangemPayCardDetailsBlockComponent(
|
||||
TangemPayCardDetailsUM(
|
||||
number = "•••• •••• •••• 1245",
|
||||
expiry = "••/••",
|
||||
cvv = "•••",
|
||||
onCopy = {},
|
||||
onClick = {},
|
||||
buttonText = TextReference.Res(R.string.tangempay_card_details_hide_text),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue