Updated on 2026-08-14

This commit is contained in:
Tangem 2026-04-28 17:32:04 +05:00
parent ace91fb278
commit 596cbb40cb
29 changed files with 364 additions and 635 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

View file

@ -1,14 +0,0 @@
package com.tangem.features.tangempay.components
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.pay.TangemPayDetailsConfig
interface TangemPayCardPageComponent : ComposableContentComponent {
data class Params(
val userWalletId: UserWalletId,
val config: TangemPayDetailsConfig,
)
interface Factory : ComponentFactory<Params, TangemPayCardPageComponent>
}

View file

@ -16,9 +16,7 @@ import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.tangempay.components.express.ExpressTransactionsComponentProvider
import com.tangem.features.tangempay.limit.setup.TangemPayCardLimitSetupComponent
import com.tangem.features.tangempay.limit.setup.TangemPayCardLimitSetupSuccessComponent
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
import com.tangem.features.tangempay.navigation.TangemPayAccountDetailsInnerRoute
import com.tangem.features.tokenreceive.TokenReceiveComponent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@ -27,13 +25,14 @@ import dagger.assisted.AssistedInject
internal class DefaultTangemPayDetailsContainerComponent @AssistedInject constructor(
@Assisted private val appComponentContext: AppComponentContext,
@Assisted private val params: TangemPayDetailsContainerComponent.Params,
private val tangemPayCardPageFactory: TangemPayCardPageComponent.Factory,
private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
private val expressTransactionsComponentProvider: ExpressTransactionsComponentProvider,
) : AppComponentContext by appComponentContext, TangemPayDetailsContainerComponent {
private val stackNavigation = StackNavigation<TangemPayDetailsInnerRoute>()
private val stackNavigation = StackNavigation<TangemPayAccountDetailsInnerRoute>()
private val innerRouter = InnerRouter<TangemPayDetailsInnerRoute>(
private val innerRouter = InnerRouter<TangemPayAccountDetailsInnerRoute>(
stackNavigation = stackNavigation,
popCallback = { onChildBack() },
)
@ -41,8 +40,8 @@ internal class DefaultTangemPayDetailsContainerComponent @AssistedInject constru
private val childStack = childStack(
key = "tangemPayDetailsInnerStack",
source = stackNavigation,
serializer = TangemPayDetailsInnerRoute.serializer(),
initialConfiguration = TangemPayDetailsInnerRoute.Details,
serializer = TangemPayAccountDetailsInnerRoute.serializer(),
initialConfiguration = TangemPayAccountDetailsInnerRoute.AccountDetails,
childFactory = ::screenChild,
)
@ -57,39 +56,18 @@ internal class DefaultTangemPayDetailsContainerComponent @AssistedInject constru
}
private fun screenChild(
config: TangemPayDetailsInnerRoute,
config: TangemPayAccountDetailsInnerRoute,
componentContext: ComponentContext,
): ComposableContentComponent = when (config) {
TangemPayDetailsInnerRoute.Details -> TangemPayDetailsComponent(
TangemPayAccountDetailsInnerRoute.AccountDetails -> TangemPayDetailsComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
params = params,
tokenReceiveComponentFactory = tokenReceiveComponentFactory,
expressTransactionsComponentProvider = expressTransactionsComponentProvider,
)
TangemPayDetailsInnerRoute.ChangePIN -> TangemPayChangePinComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
params = params,
)
TangemPayDetailsInnerRoute.ChangePINSuccess -> TangemPayChangePinSuccessComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
)
TangemPayDetailsInnerRoute.AddToWallet -> TangemPayAddToWalletComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
params = params,
)
TangemPayDetailsInnerRoute.EditCardDisplayName -> TangemPayEditDisplayNameComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
params = TangemPayDetailsContainerComponent.Params(
userWalletId = params.userWalletId,
config = params.config,
),
)
TangemPayDetailsInnerRoute.LimitSetup -> TangemPayCardLimitSetupComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
params = params,
)
TangemPayDetailsInnerRoute.LimitSetupSuccess -> TangemPayCardLimitSetupSuccessComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
TangemPayAccountDetailsInnerRoute.CardDetails -> tangemPayCardPageFactory.create(
context = childByContext(componentContext = componentContext, router = innerRouter),
params = TangemPayCardPageComponent.Params(userWalletId = params.userWalletId, config = params.config),
)
}

View file

@ -1,5 +1,7 @@
package com.tangem.features.tangempay.components
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
@ -11,25 +13,28 @@ import com.arkivanov.decompose.router.stack.childStack
import com.arkivanov.decompose.router.stack.pop
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
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.wallet.UserWalletId
import com.tangem.domain.pay.TangemPayDetailsConfig
import com.tangem.features.tangempay.limit.setup.TangemPayCardLimitSetupComponent
import com.tangem.features.tangempay.limit.setup.TangemPayCardLimitSetupSuccessComponent
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
import com.tangem.features.tangempay.navigation.TangemPayCardDetailsInnerRoute
import com.tangem.features.tokenreceive.TokenReceiveComponent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
internal class DefaultTangemPayCardPageComponent @AssistedInject constructor(
internal class TangemPayCardPageComponent @AssistedInject constructor(
@Assisted private val appComponentContext: AppComponentContext,
@Assisted private val params: TangemPayCardPageComponent.Params,
@Assisted private val params: Params,
private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
) : AppComponentContext by appComponentContext, TangemPayCardPageComponent {
) : ComposableContentComponent, AppComponentContext by appComponentContext {
private val stackNavigation = StackNavigation<TangemPayDetailsInnerRoute>()
private val stackNavigation = StackNavigation<TangemPayCardDetailsInnerRoute>()
private val innerRouter = InnerRouter<TangemPayDetailsInnerRoute>(
private val innerRouter = InnerRouter<TangemPayCardDetailsInnerRoute>(
stackNavigation = stackNavigation,
popCallback = { onChildBack() },
)
@ -37,63 +42,64 @@ internal class DefaultTangemPayCardPageComponent @AssistedInject constructor(
private val childStack = childStack(
key = "tangemPayCardPageInnerStack",
source = stackNavigation,
serializer = TangemPayDetailsInnerRoute.serializer(),
initialConfiguration = TangemPayDetailsInnerRoute.Details,
serializer = TangemPayCardDetailsInnerRoute.serializer(),
initialConfiguration = TangemPayCardDetailsInnerRoute.Details,
childFactory = ::screenChild,
)
@Suppress("ReusedModifierInstance")
@Composable
override fun Content(modifier: Modifier) {
val childStack by childStack.subscribeAsState()
BackHandler(onBack = ::onChildBack)
Children(
modifier = modifier,
stack = childStack,
) { child ->
child.instance.Content(modifier = modifier)
child.instance.Content(modifier = Modifier.fillMaxSize())
}
}
private fun screenChild(
config: TangemPayDetailsInnerRoute,
config: TangemPayCardDetailsInnerRoute,
componentContext: ComponentContext,
): ComposableContentComponent = when (config) {
TangemPayDetailsInnerRoute.Details -> TangemPayCardPageScreenComponent(
TangemPayCardDetailsInnerRoute.Details -> TangemPayCardPageScreenComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
params = params,
tokenReceiveComponentFactory = tokenReceiveComponentFactory,
)
TangemPayDetailsInnerRoute.ChangePIN -> TangemPayChangePinComponent(
TangemPayCardDetailsInnerRoute.ChangePIN -> TangemPayChangePinComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
params = TangemPayDetailsContainerComponent.Params(
userWalletId = params.userWalletId,
config = params.config,
),
)
TangemPayDetailsInnerRoute.ChangePINSuccess -> TangemPayChangePinSuccessComponent(
TangemPayCardDetailsInnerRoute.ChangePINSuccess -> TangemPayChangePinSuccessComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
)
TangemPayDetailsInnerRoute.AddToWallet -> TangemPayAddToWalletComponent(
TangemPayCardDetailsInnerRoute.AddToWallet -> TangemPayAddToWalletComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
params = TangemPayDetailsContainerComponent.Params(
userWalletId = params.userWalletId,
config = params.config,
),
)
TangemPayDetailsInnerRoute.EditCardDisplayName -> TangemPayEditDisplayNameComponent(
TangemPayCardDetailsInnerRoute.EditCardDisplayName -> TangemPayEditDisplayNameComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
params = TangemPayDetailsContainerComponent.Params(
userWalletId = params.userWalletId,
config = params.config,
),
)
TangemPayDetailsInnerRoute.LimitSetup -> TangemPayCardLimitSetupComponent(
TangemPayCardDetailsInnerRoute.LimitSetup -> TangemPayCardLimitSetupComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
params = TangemPayDetailsContainerComponent.Params(
userWalletId = params.userWalletId,
config = params.config,
),
)
TangemPayDetailsInnerRoute.LimitSetupSuccess -> TangemPayCardLimitSetupSuccessComponent(
TangemPayCardDetailsInnerRoute.LimitSetupSuccess -> TangemPayCardLimitSetupSuccessComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
)
}
@ -106,11 +112,10 @@ internal class DefaultTangemPayCardPageComponent @AssistedInject constructor(
}
}
data class Params(val userWalletId: UserWalletId, val config: TangemPayDetailsConfig)
@AssistedFactory
interface Factory : TangemPayCardPageComponent.Factory {
override fun create(
context: AppComponentContext,
params: TangemPayCardPageComponent.Params,
): DefaultTangemPayCardPageComponent
interface Factory : ComponentFactory<Params, TangemPayCardPageComponent> {
override fun create(context: AppComponentContext, params: Params): TangemPayCardPageComponent
}
}

View file

@ -17,7 +17,7 @@ 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.entity.TangemPayDetailsNavigation
import com.tangem.features.tangempay.entity.TangemPayCardNavigation
import com.tangem.features.tangempay.model.TangemPayCardPageModel
import com.tangem.features.tangempay.ui.TangemPayCardPageScreen
import com.tangem.features.tokenreceive.TokenReceiveComponent
@ -45,7 +45,7 @@ internal class TangemPayCardPageScreenComponent(
private val bottomSheetSlot = childSlot(
source = model.bottomSheetNavigation,
serializer = TangemPayDetailsNavigation.serializer(),
serializer = TangemPayCardNavigation.serializer(),
handleBackButton = false,
childFactory = ::bottomSheetChild,
)
@ -69,12 +69,12 @@ internal class TangemPayCardPageScreenComponent(
}
private fun bottomSheetChild(
navigation: TangemPayDetailsNavigation,
navigation: TangemPayCardNavigation,
componentContext: ComponentContext,
): ComposableBottomSheetComponent {
val context = childByContext(componentContext)
return when (navigation) {
is TangemPayDetailsNavigation.ViewPinCode -> TangemPayViewPinComponent(
is TangemPayCardNavigation.ViewPinCode -> TangemPayViewPinComponent(
appComponentContext = context,
params = TangemPayViewPinComponent.Params(
walletId = navigation.userWalletId,
@ -82,7 +82,7 @@ internal class TangemPayCardPageScreenComponent(
listener = model,
),
)
is TangemPayDetailsNavigation.ReissueCard -> TangemPayReissueCardComponent(
is TangemPayCardNavigation.ReissueCard -> TangemPayReissueCardComponent(
appComponentContext = context,
params = TangemPayReissueCardComponent.Params(
listener = model,
@ -90,7 +90,7 @@ internal class TangemPayCardPageScreenComponent(
cardId = params.config.cardId,
),
)
is TangemPayDetailsNavigation.AddFunds -> TangemPayAddFundsComponent(
is TangemPayCardNavigation.AddFunds -> TangemPayAddFundsComponent(
appComponentContext = context,
params = TangemPayAddFundsComponent.Params(
listener = model,
@ -101,14 +101,13 @@ internal class TangemPayCardPageScreenComponent(
chainId = navigation.chainId,
),
)
is TangemPayDetailsNavigation.Receive -> tokenReceiveComponentFactory.create(
is TangemPayCardNavigation.Receive -> tokenReceiveComponentFactory.create(
context = context,
params = TokenReceiveComponent.Params(
config = navigation.config,
onDismiss = model.bottomSheetNavigation::dismiss,
),
)
else -> error("Unsupported bottom sheet navigation: $navigation")
}
}
}

View file

@ -2,10 +2,10 @@ package com.tangem.features.tangempay.components
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
import androidx.compose.ui.Modifier
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
internal class TangemPayChangePinSuccessComponent(
@ -19,6 +19,6 @@ internal class TangemPayChangePinSuccessComponent(
}
private fun backToDetails() {
router.popTo(route = TangemPayDetailsInnerRoute.Details)
router.popTo(route = TangemPayCardDetailsInnerRoute.Details)
}
}

View file

@ -16,8 +16,6 @@ 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.express.ExpressTransactionsComponentProvider
import com.tangem.features.tangempay.components.txHistory.DefaultTangemPayTxHistoryComponent
import com.tangem.features.tangempay.components.txHistory.TangemPayTxHistoryDetailsComponent
@ -49,14 +47,6 @@ internal class TangemPayDetailsComponent(
),
)
private val cardDetailsBlockComponent = DefaultTangemPayCardDetailsBlockComponent(
appComponentContext = child("cardDetailsBlockComponent"),
params = TangemPayCardDetailsBlockComponent.Params(
params = params,
isDisplayCardNameEnabled = false,
),
)
private val expressTransactionsComponent by lazy {
expressTransactionsComponentProvider.create(
appComponentContext = child("expressTransactionsComponent"),
@ -81,7 +71,6 @@ internal class TangemPayDetailsComponent(
TangemPayDetailsScreen(
state = state,
txHistoryComponent = txHistoryComponent,
cardDetailsBlockComponent = cardDetailsBlockComponent,
expressTransactionsComponent = expressTransactionsComponent,
modifier = modifier,
)
@ -122,15 +111,6 @@ internal class TangemPayDetailsComponent(
listener = model,
),
)
is TangemPayDetailsNavigation.ViewPinCode -> TangemPayViewPinComponent(
appComponentContext = context,
params = TangemPayViewPinComponent.Params(
walletId = navigation.userWalletId,
cardId = navigation.cardId,
listener = model,
),
)
else -> error("Unsupported bottom sheet navigation: $navigation")
}
}
}

View file

@ -1,8 +1,6 @@
package com.tangem.features.tangempay.di
import com.tangem.features.tangempay.components.DefaultTangemPayCardPageComponent
import com.tangem.features.tangempay.components.DefaultTangemPayDetailsContainerComponent
import com.tangem.features.tangempay.components.TangemPayCardPageComponent
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
import com.tangem.features.tangempay.model.listener.CardDetailsEventListener
import com.tangem.features.tangempay.model.listener.DefaultCardDetailsEventListener
@ -22,12 +20,6 @@ internal interface TangemPayDetailsFeatureModule {
factory: DefaultTangemPayDetailsContainerComponent.Factory,
): TangemPayDetailsContainerComponent.Factory
@Binds
@Singleton
fun bindTangemPayCardPageComponentFactory(
factory: DefaultTangemPayCardPageComponent.Factory,
): TangemPayCardPageComponent.Factory
@Binds
@Singleton
fun bindCardDetailsEventListener(impl: DefaultCardDetailsEventListener): CardDetailsEventListener

View file

@ -0,0 +1,30 @@
package com.tangem.features.tangempay.entity
import com.tangem.domain.models.TokenReceiveConfig
import com.tangem.domain.models.serialization.SerializedBigDecimal
import com.tangem.domain.models.wallet.UserWalletId
import kotlinx.serialization.Serializable
@Serializable
internal sealed class TangemPayCardNavigation {
@Serializable
data class ViewPinCode(
val userWalletId: UserWalletId,
val cardId: String,
) : TangemPayCardNavigation()
@Serializable
data object ReissueCard : TangemPayCardNavigation()
@Serializable
data class AddFunds(
val walletId: UserWalletId,
val cryptoBalance: SerializedBigDecimal,
val fiatBalance: SerializedBigDecimal,
val depositAddress: String,
val chainId: Int,
) : TangemPayCardNavigation()
@Serializable
data class Receive(val config: TokenReceiveConfig) : TangemPayCardNavigation()
}

View file

@ -26,13 +26,4 @@ internal sealed class TangemPayDetailsNavigation {
val transaction: TangemPayTxHistoryItem,
val isBalanceHidden: Boolean,
) : TangemPayDetailsNavigation()
@Serializable
data class ViewPinCode(
val userWalletId: UserWalletId,
val cardId: String,
) : TangemPayDetailsNavigation()
@Serializable
data object ReissueCard : TangemPayDetailsNavigation()
}

View file

@ -1,19 +1,15 @@
package com.tangem.features.tangempay.entity
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.themedColor
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.visa.model.TangemPayCardFrozenState
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.model.transformers.TangemPayCardFrozenStateConverter
import com.tangem.features.tangempay.utils.TangemPayDetailIntents
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
@Suppress("LongParameterList")
internal class TangemPayDetailsStateFactory(
@ -21,53 +17,26 @@ internal class TangemPayDetailsStateFactory(
private val onOpenMenu: () -> Unit,
private val intents: TangemPayDetailIntents,
private val cardFrozenState: TangemPayCardFrozenState,
private val converter: TangemPayCardFrozenStateConverter,
) {
@Suppress("LongMethod")
fun getInitialState(): TangemPayDetailsUM {
val cardFrozenStateItem = when (cardFrozenState) {
is TangemPayCardFrozenState.Pending -> null
is TangemPayCardFrozenState.Frozen -> TangemPayDetailsTopBarMenuItem(
type = TangemPayDetailsTopBarMenuItemType.UnfreezeCard,
dropdownItem = TangemDropdownMenuItem(
title = resourceReference(R.string.tangempay_card_details_unfreeze_card),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = intents::onClickUnfreezeCard,
),
)
is TangemPayCardFrozenState.Unfrozen -> TangemPayDetailsTopBarMenuItem(
type = TangemPayDetailsTopBarMenuItemType.FreezeCard,
dropdownItem = TangemDropdownMenuItem(
title = resourceReference(R.string.tangempay_card_details_freeze_card),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = intents::onClickFreezeCard,
),
)
}
fun getInitialState(cardNumberEnd: String): TangemPayDetailsUM {
return TangemPayDetailsUM(
topBarConfig = TangemPayDetailsTopBarConfig(
onBackClick = onBack,
onOpenMenu = onOpenMenu,
items = listOfNotNull(
TangemPayDetailsTopBarMenuItem(
type = TangemPayDetailsTopBarMenuItemType.ChangePin,
dropdownItem = TangemDropdownMenuItem(
title = resourceReference(R.string.tangempay_card_details_pin_code),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = intents::onClickPinCode,
),
items = persistentListOf(
TangemDropdownMenuItem(
title = resourceReference(R.string.tangem_pay_terms_limits),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = intents::onClickTermsAndLimits,
),
TangemPayDetailsTopBarMenuItem(
type = TangemPayDetailsTopBarMenuItemType.TermsAndLimits,
dropdownItem = TangemDropdownMenuItem(
title = resourceReference(R.string.tangem_pay_terms_limits),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = intents::onClickTermsAndLimits,
),
TangemDropdownMenuItem(
title = resourceReference(R.string.tangempay_pay_support),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = intents::onContactSupportClicked,
),
cardFrozenStateItem,
).toPersistentList(),
),
),
pullToRefreshConfig = PullToRefreshConfig(
isRefreshing = false,
@ -88,21 +57,18 @@ internal class TangemPayDetailsStateFactory(
isEnabled = cardFrozenState == TangemPayCardFrozenState.Unfrozen,
),
),
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
cards = persistentListOf(
TangemPayDetailsBalanceBlockState.Card(
lastDigits = cardNumberEnd,
onClick = intents::onCardClick,
),
),
onAddCardClick = intents::onAddCardClick,
),
),
addToWalletBlockState = null,
isBalanceHidden = false,
addFundsEnabled = true,
cardFrozenState = converter.convert(cardFrozenState),
betaNotificationConfig = NotificationConfig(
title = resourceReference(R.string.tangem_pay_beta_notification_title),
subtitle = resourceReference(R.string.tangem_pay_beta_notification_subtitle),
iconResId = R.drawable.img_visa_notification,
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = resourceReference(R.string.common_contact_support),
onClick = intents::onContactSupportClicked,
),
iconSize = 36.dp,
),
)
}
}

View file

@ -6,17 +6,5 @@ import kotlinx.collections.immutable.ImmutableList
internal data class TangemPayDetailsTopBarConfig(
val onBackClick: () -> Unit,
val onOpenMenu: () -> Unit,
val items: ImmutableList<TangemPayDetailsTopBarMenuItem>?,
)
internal data class TangemPayDetailsTopBarMenuItem(
val type: TangemPayDetailsTopBarMenuItemType,
val dropdownItem: TangemDropdownMenuItem,
)
internal enum class TangemPayDetailsTopBarMenuItemType {
ChangePin,
TermsAndLimits,
FreezeCard,
UnfreezeCard,
}
val items: ImmutableList<TangemDropdownMenuItem>,
)

View file

@ -2,7 +2,6 @@ package com.tangem.features.tangempay.entity
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.visa.model.TangemPayCardFrozenState
import com.tangem.features.tangempay.model.CardDataType
@ -12,11 +11,8 @@ internal data class TangemPayDetailsUM(
val topBarConfig: TangemPayDetailsTopBarConfig,
val pullToRefreshConfig: PullToRefreshConfig,
val balanceBlockState: TangemPayDetailsBalanceBlockState,
val addToWalletBlockState: AddToWalletBlockState?,
val isBalanceHidden: Boolean,
val addFundsEnabled: Boolean,
val cardFrozenState: CardFrozenState,
val betaNotificationConfig: NotificationConfig,
)
internal data class TangemPayCardDetailsUM(
@ -55,26 +51,27 @@ internal sealed interface DisplayNameState {
internal sealed class TangemPayDetailsBalanceBlockState {
abstract val actionButtons: ImmutableList<ActionButtonConfig>
abstract val cardsBlockState: CardsBlockState
data class Loading(
override val actionButtons: ImmutableList<ActionButtonConfig>,
override val cardsBlockState: CardsBlockState,
) : TangemPayDetailsBalanceBlockState()
data class Content(
override val actionButtons: ImmutableList<ActionButtonConfig>,
override val cardsBlockState: CardsBlockState,
val fiatBalance: String,
val isBalanceFlickering: Boolean,
) : TangemPayDetailsBalanceBlockState()
data class Error(
override val actionButtons: ImmutableList<ActionButtonConfig>,
override val cardsBlockState: CardsBlockState,
) : TangemPayDetailsBalanceBlockState()
}
sealed class CardFrozenState {
data object Pending : CardFrozenState()
data class Frozen(val onUnfreeze: () -> Unit) : CardFrozenState()
data object Unfrozen : CardFrozenState()
data class CardsBlockState(val cards: ImmutableList<Card>, val onAddCardClick: () -> Unit)
data class Card(val lastDigits: String, val onClick: () -> Unit)
}
internal data class AddToWalletBlockState(

View file

@ -22,7 +22,7 @@ import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
import com.tangem.domain.pay.usecase.SetTangemPayCardLimitUseCase
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
import com.tangem.features.tangempay.navigation.TangemPayCardDetailsInnerRoute
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
@ -146,7 +146,7 @@ internal class TangemPayCardLimitSetupModel @Inject constructor(
},
ifRight = {
uiState.update { state -> state.copy(isSubmitButtonLoading = false) }
router.push(TangemPayDetailsInnerRoute.LimitSetupSuccess)
router.push(TangemPayCardDetailsInnerRoute.LimitSetupSuccess)
},
)
}

View file

@ -5,7 +5,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
import com.tangem.features.tangempay.navigation.TangemPayCardDetailsInnerRoute
internal class TangemPayCardLimitSetupSuccessComponent(
appComponentContext: AppComponentContext,
@ -21,6 +21,6 @@ internal class TangemPayCardLimitSetupSuccessComponent(
}
private fun backToDetails() {
router.popTo(route = TangemPayDetailsInnerRoute.Details)
router.popTo(route = TangemPayCardDetailsInnerRoute.Details)
}
}

View file

@ -19,8 +19,10 @@ import com.tangem.features.tangempay.entity.TangemPayCardDetailsBlockStateFactor
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.*
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
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.features.tangempay.navigation.TangemPayCardDetailsInnerRoute
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.saveIn
@ -131,7 +133,7 @@ internal class TangemPayCardDetailsBlockModel @Inject constructor(
}
private fun startEditingDisplayName() {
router.push(TangemPayDetailsInnerRoute.EditCardDisplayName)
router.push(TangemPayCardDetailsInnerRoute.EditCardDisplayName)
}
private fun copyData(text: String, type: CardDataType) {

View file

@ -39,7 +39,7 @@ import com.tangem.features.tangempay.components.TangemPayCardPageComponent
import com.tangem.features.tangempay.components.ViewPinListener
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.entity.*
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
import com.tangem.features.tangempay.navigation.TangemPayCardDetailsInnerRoute
import com.tangem.features.tangempay.utils.TangemPayMessagesFactory
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.JobHolder
@ -78,7 +78,7 @@ internal class TangemPayCardPageModel @Inject constructor(
),
)
val bottomSheetNavigation: SlotNavigation<TangemPayDetailsNavigation> = SlotNavigation()
val bottomSheetNavigation: SlotNavigation<TangemPayCardNavigation> = SlotNavigation()
// TODO v_rodionov: #[REDACTED_TASK_KEY] check reissue order state before card details are showed
init {
@ -99,7 +99,7 @@ internal class TangemPayCardPageModel @Inject constructor(
val symbol = getJavaCurrencyByCode(status.currencyCode).symbol
fiat(status.currencyCode, symbol)
},
onChangeClick = { router.push(TangemPayDetailsInnerRoute.LimitSetup) },
onChangeClick = { router.push(TangemPayCardDetailsInnerRoute.LimitSetup) },
)
} else {
TangemPayDailyLimitBlockState.Error
@ -131,10 +131,10 @@ internal class TangemPayCardPageModel @Inject constructor(
private fun onClickChangePIN(isPinSet: Boolean) {
if (!isPinSet) {
router.push(TangemPayDetailsInnerRoute.ChangePIN)
router.push(TangemPayCardDetailsInnerRoute.ChangePIN)
} else {
bottomSheetNavigation.activate(
TangemPayDetailsNavigation.ViewPinCode(
TangemPayCardNavigation.ViewPinCode(
userWalletId = params.userWalletId,
cardId = params.config.cardId,
),
@ -153,7 +153,7 @@ internal class TangemPayCardPageModel @Inject constructor(
private fun onClickReissueCard() {
analytics.send(TangemPayAnalyticsEvents.ReplaceCardClicked())
bottomSheetNavigation.activate(TangemPayDetailsNavigation.ReissueCard)
bottomSheetNavigation.activate(TangemPayCardNavigation.ReissueCard)
}
override fun onReissueOrderCreate(order: TangemPayReissueOrderInfo) {
@ -182,7 +182,7 @@ internal class TangemPayCardPageModel @Inject constructor(
return@launch
}
bottomSheetNavigation.activate(
TangemPayDetailsNavigation.AddFunds(
TangemPayCardNavigation.AddFunds(
walletId = params.userWalletId,
fiatBalance = balance.fiatBalance,
cryptoBalance = balance.cryptoBalance,
@ -202,7 +202,7 @@ internal class TangemPayCardPageModel @Inject constructor(
showMemoDisclaimer = false,
receiveAddress = data.receiveAddress,
)
bottomSheetNavigation.activate(TangemPayDetailsNavigation.Receive(config))
bottomSheetNavigation.activate(TangemPayCardNavigation.Receive(config))
}
override fun onClickSwap(data: TangemPayTopUpData) {
@ -282,7 +282,7 @@ internal class TangemPayCardPageModel @Inject constructor(
}
private fun onClickAddToWallet() {
router.push(TangemPayDetailsInnerRoute.AddToWallet)
router.push(TangemPayCardDetailsInnerRoute.AddToWallet)
}
private fun onClickCloseBanner() {
@ -294,7 +294,7 @@ internal class TangemPayCardPageModel @Inject constructor(
override fun onClickChangePin() {
bottomSheetNavigation.dismiss()
router.push(TangemPayDetailsInnerRoute.ChangePIN)
router.push(TangemPayCardDetailsInnerRoute.ChangePIN)
}
override fun onDismissViewPin() {

View file

@ -16,12 +16,14 @@ import com.tangem.features.tangempay.components.TangemPayDetailsContainerCompone
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.entity.TangemPayChangePinUM
import com.tangem.features.tangempay.model.transformers.PinCodeChangeTransformer
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
import com.tangem.features.tangempay.navigation.TangemPayCardDetailsInnerRoute
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.transformer.update
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import com.tangem.utils.logging.TangemLogger
import com.tangem.utils.transformer.update
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
@Stable
@ -69,7 +71,7 @@ internal class TangemPayChangePinModel @Inject constructor(
}
SetPinResult.SUCCESS -> {
analytics.send(TangemPayAnalyticsEvents.ChangePinSuccessShown())
router.push(TangemPayDetailsInnerRoute.ChangePINSuccess)
router.push(TangemPayCardDetailsInnerRoute.ChangePINSuccess)
}
SetPinResult.DECRYPTION_ERROR,
SetPinResult.UNKNOWN_ERROR,

View file

@ -15,8 +15,6 @@ import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig.ShowRefreshState
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
import com.tangem.domain.feedback.models.FeedbackEmailType
@ -30,22 +28,22 @@ import com.tangem.domain.pay.model.TangemPayTopUpData
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
import com.tangem.domain.pay.repository.TangemPayWithdrawRepository
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
import com.tangem.domain.visa.model.TangemPayCardFrozenState
import com.tangem.domain.visa.model.TangemPayTxHistoryItem
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.tangempay.TangemPayConstants
import com.tangem.features.tangempay.components.AddFundsListener
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
import com.tangem.features.tangempay.components.ViewPinListener
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.listener.CardDetailsEvent
import com.tangem.features.tangempay.model.listener.CardDetailsEventListener
import com.tangem.features.tangempay.model.transformers.*
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
import com.tangem.features.tangempay.model.transformers.DetailBalanceVisibilityTransformer
import com.tangem.features.tangempay.model.transformers.DetailsBalanceTransformer
import com.tangem.features.tangempay.model.transformers.TangemPayDetailsRefreshTransformer
import com.tangem.features.tangempay.model.transformers.TangemPayFreezeUnfreezeStateTransformer
import com.tangem.features.tangempay.navigation.TangemPayAccountDetailsInnerRoute
import com.tangem.features.tangempay.utils.TangemPayDetailIntents
import com.tangem.features.tangempay.utils.TangemPayMessagesFactory
import com.tangem.features.tangempay.utils.TangemPayTxHistoryUiActions
@ -84,25 +82,22 @@ internal class TangemPayDetailsModel @Inject constructor(
private val getUserWalletUseCase: GetUserWalletUseCase,
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
private val expressTransactionsEventListener: ExpressTransactionsEventListener,
) : Model(), TangemPayTxHistoryUiActions, TangemPayDetailIntents, AddFundsListener, ViewPinListener {
) : Model(), TangemPayTxHistoryUiActions, TangemPayDetailIntents, AddFundsListener {
private val params: TangemPayDetailsContainerComponent.Params = paramsContainer.require()
private val cardFrozenStateConverter = TangemPayCardFrozenStateConverter(onUnfreezeClick = ::onClickUnfreezeCard)
private val stateFactory = TangemPayDetailsStateFactory(
onBack = router::pop,
onOpenMenu = ::onOpenMenu,
intents = this,
cardFrozenState = params.config.cardFrozenState,
converter = cardFrozenStateConverter,
)
val uiState: StateFlow<TangemPayDetailsUM>
field = MutableStateFlow(stateFactory.getInitialState())
field = MutableStateFlow(stateFactory.getInitialState(cardNumberEnd = params.config.cardNumberEnd))
private val refreshStateJobHolder = JobHolder()
private val fetchBalanceJobHolder = JobHolder()
private val addToWalletBannerJobHolder = JobHolder()
private var balance: TangemPayCardBalance? = null
@ -116,7 +111,6 @@ internal class TangemPayDetailsModel @Inject constructor(
init {
analytics.send(TangemPayAnalyticsEvents.MainScreenOpened())
handleBalanceHiding()
fetchAddToWalletBanner()
fetchBalance()
subscribeToCardFrozenState()
}
@ -136,123 +130,10 @@ internal class TangemPayDetailsModel @Inject constructor(
private fun subscribeToCardFrozenState() {
cardDetailsRepository
.cardFrozenState(params.config.cardId)
.onEach { state ->
uiState.update(
TangemPayFreezeUnfreezeStateTransformer(
cardFrozenState = state,
onFreezeClick = ::onClickFreezeCard,
onUnfreezeClick = ::onClickUnfreezeCard,
converter = cardFrozenStateConverter,
),
)
}
.onEach { uiState.update(TangemPayFreezeUnfreezeStateTransformer(cardFrozenState = it)) }
.launchIn(modelScope)
}
override fun onClickPinCode() {
analytics.send(TangemPayAnalyticsEvents.PinCodeClicked())
if (!params.config.isPinSet) {
router.push(TangemPayDetailsInnerRoute.ChangePIN)
} else {
bottomSheetNavigation.activate(
TangemPayDetailsNavigation.ViewPinCode(
userWalletId = params.userWalletId,
cardId = params.config.cardId,
),
)
}
}
override fun onClickFreezeCard() {
analytics.send(TangemPayAnalyticsEvents.FreezeCardClicked())
uiMessageSender.send(TangemPayMessagesFactory.createFreezeCardMessage(onFreezeClicked = ::freezeCard))
analytics.send(TangemPayAnalyticsEvents.FreezeCardConfirmShown())
}
override fun onClickUnfreezeCard() {
analytics.send(TangemPayAnalyticsEvents.UnfreezeCardClicked())
uiMessageSender.send(TangemPayMessagesFactory.createUnfreezeCardMessage(onUnfreezeClicked = ::unfreezeCard))
analytics.send(TangemPayAnalyticsEvents.UnfreezeCardConfirmShown())
}
private fun freezeCard() {
analytics.send(TangemPayAnalyticsEvents.FreezeCardConfirmClicked())
modelScope.launch {
val result = try {
cardDetailsRepository.freezeCard(userWalletId = params.userWalletId, cardId = params.config.cardId)
} catch (e: Exception) {
TangemLogger.e("Error", e)
return@launch
}
result
.onLeft {
uiMessageSender.send(SnackbarMessage(resourceReference(R.string.tangem_pay_freeze_card_failed)))
}
.onRight { state ->
when (state) {
TangemPayCardFrozenState.Frozen -> {
uiMessageSender.send(
SnackbarMessage(resourceReference(R.string.tangem_pay_freeze_card_success)),
)
uiState.update(
TangemPayFreezeUnfreezeStateTransformer(
cardFrozenState = state,
onFreezeClick = ::onClickFreezeCard,
onUnfreezeClick = ::onClickUnfreezeCard,
converter = cardFrozenStateConverter,
),
)
}
TangemPayCardFrozenState.Unfrozen -> {
uiMessageSender.send(
SnackbarMessage(resourceReference(R.string.tangem_pay_freeze_card_failed)),
)
}
TangemPayCardFrozenState.Pending -> Unit // TODO [REDACTED_JIRA]
}
}
}
}
private fun unfreezeCard() {
analytics.send(TangemPayAnalyticsEvents.UnfreezeCardConfirmClicked())
modelScope.launch {
val result = try {
cardDetailsRepository.unfreezeCard(userWalletId = params.userWalletId, cardId = params.config.cardId)
} catch (e: Exception) {
TangemLogger.e("Error", e)
return@launch
}
result
.onLeft {
uiMessageSender.send(SnackbarMessage(resourceReference(R.string.tangem_pay_unfreeze_card_failed)))
}
.onRight { state ->
when (state) {
TangemPayCardFrozenState.Unfrozen -> {
uiMessageSender.send(
SnackbarMessage(resourceReference(R.string.tangem_pay_unfreeze_card_success)),
)
uiState.update(
TangemPayFreezeUnfreezeStateTransformer(
cardFrozenState = state,
onFreezeClick = ::onClickFreezeCard,
onUnfreezeClick = ::onClickUnfreezeCard,
converter = cardFrozenStateConverter,
),
)
}
TangemPayCardFrozenState.Frozen -> {
uiMessageSender.send(
SnackbarMessage(resourceReference(R.string.tangem_pay_unfreeze_card_failed)),
)
}
TangemPayCardFrozenState.Pending -> Unit // TODO [REDACTED_JIRA]
}
}
}
}
override fun onClickAddFunds() {
analytics.send(TangemPayAnalyticsEvents.AddFundsClicked())
val currentBalance = balance
@ -352,26 +233,7 @@ internal class TangemPayDetailsModel @Inject constructor(
}.launchIn(modelScope)
}
private fun fetchAddToWalletBanner() {
modelScope.launch {
val isDone = try {
cardDetailsRepository.isAddToWalletDone(params.userWalletId).getOrNull() == true
} catch (e: Exception) {
TangemLogger.e("Error", e)
return@launch
}
uiState.update(
transformer = DetailsAddToWalletBannerTransformer(
onClickBanner = ::onClickAddToWalletBlock,
onClickCloseBanner = ::onClickCloseAddToWalletBlock,
isDone = isDone,
),
)
}.saveIn(addToWalletBannerJobHolder)
}
override fun onContactSupportClicked() {
analytics.send(TangemPayAnalyticsEvents.GoToSupportOnBetaBannerClicked())
analytics.send(Basic.ButtonSupport(source = AnalyticsParam.ScreensSources.TangemPay))
modelScope.launch {
sendFeedbackEmailUseCase.invoke(
@ -394,28 +256,6 @@ internal class TangemPayDetailsModel @Inject constructor(
}.saveIn(refreshStateJobHolder)
}
private fun onClickAddToWalletBlock() {
analytics.send(TangemPayAnalyticsEvents.AddToWalletClicked())
router.push(TangemPayDetailsInnerRoute.AddToWallet)
}
private fun onClickCloseAddToWalletBlock() {
modelScope.launch {
try {
cardDetailsRepository.setAddToWalletAsDone(params.userWalletId)
} catch (e: Exception) {
TangemLogger.e("Error", e)
}
uiState.update(
transformer = DetailsAddToWalletBannerTransformer(
onClickBanner = ::onClickAddToWalletBlock,
onClickCloseBanner = ::onClickCloseAddToWalletBlock,
isDone = true,
),
)
}.saveIn(addToWalletBannerJobHolder)
}
private fun onOpenMenu() {
analytics.send(TangemPayAnalyticsEvents.CardSettingsClicked())
}
@ -456,16 +296,6 @@ internal class TangemPayDetailsModel @Inject constructor(
bottomSheetNavigation.dismiss()
}
override fun onClickChangePin() {
bottomSheetNavigation.dismiss()
analytics.send(TangemPayAnalyticsEvents.ChangePinOnCurrentPinClicked())
router.push(TangemPayDetailsInnerRoute.ChangePIN)
}
override fun onDismissViewPin() {
bottomSheetNavigation.dismiss()
}
override fun onTransactionClick(item: TangemPayTxHistoryItem) {
val (type, status) = when (item) {
is TangemPayTxHistoryItem.Collateral -> "collateral" to "unknown"
@ -487,6 +317,14 @@ internal class TangemPayDetailsModel @Inject constructor(
urlOpener.openUrl(TangemPayConstants.TERMS_AND_LIMITS_LINK)
}
override fun onCardClick() {
router.push(TangemPayAccountDetailsInnerRoute.CardDetails)
}
override fun onAddCardClick() {
uiMessageSender.send(message = TangemPayMessagesFactory.createFutureFeature())
}
private fun showBottomSheetError(type: TangemPayDetailsErrorType) {
uiMessageSender.send(message = TangemPayMessagesFactory.createErrorMessage(errorType = type))
}

View file

@ -1,22 +0,0 @@
package com.tangem.features.tangempay.model.transformers
import com.tangem.features.tangempay.entity.AddToWalletBlockState
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
import com.tangem.utils.transformer.Transformer
internal class DetailsAddToWalletBannerTransformer(
private val onClickBanner: () -> Unit,
private val onClickCloseBanner: () -> Unit,
private val isDone: Boolean,
) : Transformer<TangemPayDetailsUM> {
override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM {
return prevState.copy(
addToWalletBlockState = if (isDone) {
null
} else {
AddToWalletBlockState(onClick = onClickBanner, onClickClose = onClickCloseBanner)
},
)
}
}

View file

@ -22,19 +22,26 @@ internal class DetailsBalanceTransformer(
override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM {
val balance = when (balance) {
is Either.Left<UniversalError> -> {
TangemPayDetailsBalanceBlockState.Error(actionButtons = persistentListOf())
TangemPayDetailsBalanceBlockState.Error(
actionButtons = persistentListOf(),
cardsBlockState = prevState.balanceBlockState.cardsBlockState,
)
}
is Either.Right<TangemPayCardBalance> -> {
val cryptoCurrency = userWallet?.let {
cryptoCurrencyFactory.create(userWallet, balance.value.chainId).getOrNull()
}
if (cryptoCurrency == null) {
TangemPayDetailsBalanceBlockState.Error(actionButtons = persistentListOf())
TangemPayDetailsBalanceBlockState.Error(
actionButtons = persistentListOf(),
cardsBlockState = prevState.balanceBlockState.cardsBlockState,
)
} else {
TangemPayDetailsBalanceBlockState.Content(
isBalanceFlickering = false,
fiatBalance = getFiatBalanceText(balance.value),
actionButtons = prevState.balanceBlockState.actionButtons,
cardsBlockState = prevState.balanceBlockState.cardsBlockState,
)
}
}

View file

@ -1,18 +0,0 @@
package com.tangem.features.tangempay.model.transformers
import com.tangem.domain.visa.model.TangemPayCardFrozenState
import com.tangem.features.tangempay.entity.CardFrozenState
import com.tangem.utils.converter.Converter
internal class TangemPayCardFrozenStateConverter(
private val onUnfreezeClick: () -> Unit,
) : Converter<TangemPayCardFrozenState, CardFrozenState> {
override fun convert(value: TangemPayCardFrozenState): CardFrozenState {
return when (value) {
TangemPayCardFrozenState.Unfrozen -> CardFrozenState.Unfrozen
TangemPayCardFrozenState.Frozen -> CardFrozenState.Frozen(onUnfreezeClick)
TangemPayCardFrozenState.Pending -> CardFrozenState.Pending
}
}
}

View file

@ -1,77 +1,24 @@
package com.tangem.features.tangempay.model.transformers
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.themedColor
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.visa.model.TangemPayCardFrozenState
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.entity.TangemPayDetailsBalanceBlockState
import com.tangem.features.tangempay.entity.TangemPayDetailsTopBarMenuItem
import com.tangem.features.tangempay.entity.TangemPayDetailsTopBarMenuItemType.FreezeCard
import com.tangem.features.tangempay.entity.TangemPayDetailsTopBarMenuItemType.UnfreezeCard
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
import com.tangem.utils.transformer.Transformer
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toPersistentList
internal class TangemPayFreezeUnfreezeStateTransformer(
private val cardFrozenState: TangemPayCardFrozenState,
private val onFreezeClick: () -> Unit,
private val onUnfreezeClick: () -> Unit,
private val converter: TangemPayCardFrozenStateConverter,
) : Transformer<TangemPayDetailsUM> {
private val isCardFrozen: Boolean = when (cardFrozenState) {
is TangemPayCardFrozenState.Frozen -> true
is TangemPayCardFrozenState.Unfrozen, is TangemPayCardFrozenState.Pending -> false
}
override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM {
val filteredItems = prevState.topBarConfig.items?.filterNot {
it.type == FreezeCard || it.type == UnfreezeCard
}
val dropdownMenuItems = createUpdatedMenuItems(filteredItems?.toPersistentList())
val balanceBlockState = if (prevState.balanceBlockState is TangemPayDetailsBalanceBlockState.Content) {
val actionButtons = prevState.balanceBlockState.actionButtons.map {
it.copy(isEnabled = cardFrozenState == TangemPayCardFrozenState.Unfrozen)
}
prevState.balanceBlockState.copy(
actionButtons = actionButtons.toPersistentList(),
)
prevState.balanceBlockState.copy(actionButtons = actionButtons.toPersistentList())
} else {
prevState.balanceBlockState
}
return prevState.copy(
topBarConfig = prevState.topBarConfig.copy(items = dropdownMenuItems),
cardFrozenState = converter.convert(cardFrozenState),
balanceBlockState = balanceBlockState,
)
}
private fun createUpdatedMenuItems(
items: ImmutableList<TangemPayDetailsTopBarMenuItem>?,
): ImmutableList<TangemPayDetailsTopBarMenuItem>? {
return items
?.plus(createMenuItemToAdd(cardFrozenState))
?.toPersistentList()
}
private fun createMenuItemToAdd(cardFrozenState: TangemPayCardFrozenState): TangemPayDetailsTopBarMenuItem {
return TangemPayDetailsTopBarMenuItem(
type = if (isCardFrozen) UnfreezeCard else FreezeCard,
dropdownItem = TangemDropdownMenuItem(
title = resourceReference(
id = if (isCardFrozen) {
R.string.tangempay_card_details_unfreeze_card
} else {
R.string.tangempay_card_details_freeze_card
},
),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = if (isCardFrozen) onUnfreezeClick else onFreezeClick,
isEnabled = cardFrozenState != TangemPayCardFrozenState.Pending,
),
)
return prevState.copy(balanceBlockState = balanceBlockState)
}
}

View file

@ -0,0 +1,13 @@
package com.tangem.features.tangempay.navigation
import com.tangem.core.decompose.navigation.Route
import kotlinx.serialization.Serializable
@Serializable
internal sealed class TangemPayAccountDetailsInnerRoute : Route {
@Serializable
data object AccountDetails : TangemPayAccountDetailsInnerRoute()
@Serializable
data object CardDetails : TangemPayAccountDetailsInnerRoute()
}

View file

@ -0,0 +1,29 @@
package com.tangem.features.tangempay.navigation
import com.tangem.core.decompose.navigation.Route
import kotlinx.serialization.Serializable
@Serializable
internal sealed class TangemPayCardDetailsInnerRoute : Route {
@Serializable
data object Details : TangemPayCardDetailsInnerRoute()
@Serializable
data object ChangePIN : TangemPayCardDetailsInnerRoute()
@Serializable
data object ChangePINSuccess : TangemPayCardDetailsInnerRoute()
@Serializable
data object AddToWallet : TangemPayCardDetailsInnerRoute()
@Serializable
data object EditCardDisplayName : TangemPayCardDetailsInnerRoute()
@Serializable
data object LimitSetup : TangemPayCardDetailsInnerRoute()
@Serializable
data object LimitSetupSuccess : TangemPayCardDetailsInnerRoute()
}

View file

@ -1,28 +0,0 @@
package com.tangem.features.tangempay.navigation
import com.tangem.core.decompose.navigation.Route
import kotlinx.serialization.Serializable
@Serializable
internal sealed class TangemPayDetailsInnerRoute : Route {
@Serializable
data object Details : TangemPayDetailsInnerRoute()
@Serializable
data object ChangePIN : TangemPayDetailsInnerRoute()
@Serializable
data object ChangePINSuccess : TangemPayDetailsInnerRoute()
@Serializable
data object AddToWallet : TangemPayDetailsInnerRoute()
@Serializable
data object EditCardDisplayName : TangemPayDetailsInnerRoute()
@Serializable
data object LimitSetup : TangemPayDetailsInnerRoute()
@Serializable
data object LimitSetupSuccess : TangemPayDetailsInnerRoute()
}

View file

@ -2,17 +2,26 @@ package com.tangem.features.tangempay.ui
import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
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.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
@ -21,34 +30,33 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.util.fastForEach
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.buttons.HorizontalActionChips
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.buttons.small.TangemIconButton
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownItem
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenu
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.components.text.applyBladeBrush
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.orMaskWithStars
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.test.TokenDetailsTopBarTestTags
import com.tangem.domain.visa.model.TangemPayCardFrozenState
import com.tangem.features.tangempay.components.cardDetails.PreviewTangemPayCardDetailsBlockComponent
import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent
import com.tangem.core.ui.test.WalletConnectBottomSheetTestTags
import com.tangem.features.tangempay.components.express.PreviewEmptyExpressTransactionsComponent
import com.tangem.features.tangempay.components.txHistory.PreviewTangemPayTxHistoryComponent
import com.tangem.features.tangempay.components.txHistory.TangemPayTxHistoryComponent
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.entity.*
import com.tangem.features.tangempay.entity.TangemPayDetailsBalanceBlockState
import com.tangem.features.tangempay.entity.TangemPayDetailsTopBarConfig
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
import com.tangem.features.tangempay.entity.TangemPayTxHistoryUM
import com.tangem.features.tokendetails.ExpressTransactionsComponent
import com.tangem.utils.StringsSigns.DASH_SIGN
import kotlinx.collections.immutable.persistentListOf
@ -58,7 +66,6 @@ import kotlinx.collections.immutable.persistentListOf
internal fun TangemPayDetailsScreen(
state: TangemPayDetailsUM,
txHistoryComponent: TangemPayTxHistoryComponent,
cardDetailsBlockComponent: TangemPayCardDetailsBlockComponent,
expressTransactionsComponent: ExpressTransactionsComponent,
modifier: Modifier = Modifier,
) {
@ -71,7 +78,6 @@ 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()
val expressState by expressTransactionsComponent.state.collectAsStateWithLifecycle()
val expressTransactionsBottomSheetState = expressState.bottomSheetSlot
@ -86,39 +92,12 @@ internal fun TangemPayDetailsScreen(
bottom = TangemTheme.dimens.spacing16 + bottomBarHeight,
),
) {
item(TangemPayCardDetailsUM::class.java) {
cardDetailsBlockComponent.CardDetailsBlockContent(
item(key = "title") {
TangemPayTitle(
modifier = Modifier
.padding(horizontal = 16.dp)
.padding(top = 8.dp),
state = cardDetailsState,
)
}
when (state.cardFrozenState) {
is CardFrozenState.Frozen -> item(CardFrozenState.Frozen::class.java) {
PrimaryButton(
modifier = Modifier
.animateItem()
.padding(horizontal = 16.dp)
.padding(top = 12.dp)
.fillMaxWidth(),
text = stringResourceSafe(R.string.tangempay_card_details_unfreeze_card),
onClick = state.cardFrozenState.onUnfreeze,
)
}
else -> Unit
}
if (state.addToWalletBlockState != null) {
item(
key = AddToWalletBlockState::class.java,
content = {
TangemPayAddToWalletBlock(
state = state.addToWalletBlockState,
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing12)
.padding(horizontal = TangemTheme.dimens.spacing16),
)
},
.padding(horizontal = TangemTheme.dimens.spacing16)
.padding(top = 4.dp)
.fillMaxWidth(),
)
}
item(
@ -134,18 +113,6 @@ internal fun TangemPayDetailsScreen(
)
},
)
item(
key = "TANGEM_PAY_IS_IN_BETA",
content = {
TangemPayBetaBlock(
modifier = modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
.padding(top = 12.dp)
.fillMaxWidth(),
config = state.betaNotificationConfig,
)
},
)
with(expressTransactionsComponent) {
expressTransactionsContent(
state = expressState.transactionsToDisplay,
@ -162,8 +129,59 @@ internal fun TangemPayDetailsScreen(
}
@Composable
private fun TangemPayBetaBlock(config: NotificationConfig, modifier: Modifier = Modifier) {
Notification(modifier = modifier, config = config)
private fun TangemPayTitle(modifier: Modifier = Modifier) {
Column(modifier = modifier) {
Text(
text = stringResourceSafe(R.string.tangempay_payment_account),
style = TangemTheme.typography.head,
color = TangemTheme.colors.text.primary1,
maxLines = 1,
)
TangemPaySubtitle()
}
}
@Suppress("MagicNumber")
@Composable
private fun TangemPaySubtitle(modifier: Modifier = Modifier) {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
Box(modifier = Modifier.wrapContentWidth()) {
Icon(
painter = painterResource(id = R.drawable.ic_polygon_22),
contentDescription = null,
tint = TangemTheme.colors.text.constantWhite,
modifier = Modifier
.padding(start = TangemTheme.dimens.spacing12)
.border(width = 2.dp, color = TangemTheme.colors.background.secondary, shape = CircleShape)
.padding(2.dp)
.clip(CircleShape)
.background(Color(0xFF8247E5))
.size(16.dp)
.testTag(WalletConnectBottomSheetTestTags.NETWORKS_ICONS),
)
Image(
painter = painterResource(id = R.drawable.img_usdc_16),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.border(width = 2.dp, color = TangemTheme.colors.background.secondary, shape = CircleShape)
.padding(2.dp)
.clip(CircleShape)
.size(16.dp)
.testTag(WalletConnectBottomSheetTestTags.NETWORKS_ICONS),
)
}
Text(
modifier = Modifier.align(Alignment.CenterVertically),
text = stringResourceSafe(R.string.tangempay_usdc_on_polygon_network),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
maxLines = 1,
)
}
}
// region Balance block
@ -183,7 +201,7 @@ private fun TangemPayDetailsBalanceBlock(
) {
Text(
modifier = Modifier.padding(start = 12.dp),
text = stringResourceSafe(R.string.tangempay_title),
text = stringResourceSafe(R.string.common_balance_title),
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.subtitle2,
)
@ -192,6 +210,12 @@ private fun TangemPayDetailsBalanceBlock(
state = state,
isBalanceHidden = isBalanceHidden,
)
CardsBlockRow(
modifier = Modifier
.wrapContentSize()
.padding(horizontal = 12.dp, vertical = 8.dp),
cardsBlockState = state.cardsBlockState,
)
if (state.actionButtons.isNotEmpty()) {
HorizontalActionChips(
modifier = Modifier.padding(top = 12.dp),
@ -203,6 +227,51 @@ private fun TangemPayDetailsBalanceBlock(
}
}
@Composable
private fun CardsBlockRow(
cardsBlockState: TangemPayDetailsBalanceBlockState.CardsBlockState,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(6.dp),
) {
val itemsModifier = Modifier.size(width = 48.dp, height = 32.dp)
cardsBlockState.cards.fastForEach { card ->
TangemPayCardItem(modifier = itemsModifier, card = card)
}
TangemIconButton(
modifier = itemsModifier,
onClick = cardsBlockState.onAddCardClick,
iconRes = R.drawable.ic_plus_24,
shape = RoundedCornerShape(4.dp),
)
}
}
@Composable
private fun TangemPayCardItem(card: TangemPayDetailsBalanceBlockState.Card, modifier: Modifier = Modifier) {
Box(
modifier = modifier
.clip(RoundedCornerShape(4.dp))
.clickable(onClick = card.onClick),
) {
Image(
modifier = Modifier.fillMaxSize(),
painter = painterResource(R.drawable.img_visa_card_48x32),
contentDescription = null,
)
Text(
modifier = Modifier
.align(Alignment.BottomStart)
.padding(4.dp, bottom = 2.dp),
text = card.lastDigits,
style = TangemTheme.typography.overline.copy(letterSpacing = 0.sp),
color = TangemTheme.colors.text.constantWhite,
)
}
}
@Composable
private fun FiatBalance(
state: TangemPayDetailsBalanceBlockState,
@ -251,7 +320,7 @@ private fun TangemPayDetailsTopAppBar(config: TangemPayDetailsTopBarConfig, modi
},
title = {},
actions = {
AnimatedVisibility(visible = config.items != null && config.items.isNotEmpty()) {
AnimatedVisibility(visible = config.items.isNotEmpty()) {
IconButton(
onClick = {
config.onOpenMenu()
@ -272,9 +341,9 @@ private fun TangemPayDetailsTopAppBar(config: TangemPayDetailsTopBarConfig, modi
modifier = Modifier.background(TangemTheme.colors.background.primary),
onDismissRequest = { showDropdownMenu = false },
content = {
config.items?.fastForEach {
config.items.fastForEach { item ->
TangemDropdownItem(
item = it.dropdownItem,
item = item,
dismissParent = { showDropdownMenu = false },
)
}
@ -302,19 +371,6 @@ private fun TangemPayDetailsScreenPreview(
txHistoryComponent = PreviewTangemPayTxHistoryComponent(
txHistoryUM = PreviewTangemPayTxHistoryComponent.contentUM,
),
cardDetailsBlockComponent = PreviewTangemPayCardDetailsBlockComponent(
TangemPayCardDetailsUM(
number = "•••• •••• •••• 1245",
numberShort = "*1245",
expiry = "••/••",
cvv = "•••",
onCopy = { _, _ -> },
onClick = {},
buttonText = TextReference.Res(R.string.tangempay_card_details_hide_text),
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
displayNameState = null,
),
),
expressTransactionsComponent = PreviewEmptyExpressTransactionsComponent(),
)
}
@ -323,7 +379,7 @@ private fun TangemPayDetailsScreenPreview(
private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<TangemPayDetailsUM>(
collection = listOf(
TangemPayDetailsUM(
topBarConfig = TangemPayDetailsTopBarConfig(onBackClick = {}, onOpenMenu = {}, items = null),
topBarConfig = TangemPayDetailsTopBarConfig(onBackClick = {}, onOpenMenu = {}, items = persistentListOf()),
pullToRefreshConfig = PullToRefreshConfig(isRefreshing = false, onRefresh = {}),
balanceBlockState = TangemPayDetailsBalanceBlockState.Content(
actionButtons = persistentListOf(
@ -335,40 +391,29 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<Ta
),
fiatBalance = "$1234.56",
isBalanceFlickering = false,
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
cards = persistentListOf(
TangemPayDetailsBalanceBlockState.Card(lastDigits = "1234", onClick = {}),
TangemPayDetailsBalanceBlockState.Card(lastDigits = "3456", onClick = {}),
),
onAddCardClick = {},
),
),
addToWalletBlockState = AddToWalletBlockState({}, {}),
isBalanceHidden = false,
addFundsEnabled = true,
cardFrozenState = CardFrozenState.Frozen(onUnfreeze = {}),
betaNotificationConfig = NotificationConfig(
title = resourceReference(R.string.tangem_pay_beta_notification_title),
subtitle = resourceReference(R.string.tangem_pay_beta_notification_subtitle),
iconResId = R.drawable.img_visa_notification,
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = resourceReference(R.string.common_contact_support),
onClick = {},
),
iconSize = 36.dp,
),
),
TangemPayDetailsUM(
topBarConfig = TangemPayDetailsTopBarConfig(onBackClick = {}, onOpenMenu = {}, items = null),
topBarConfig = TangemPayDetailsTopBarConfig(onBackClick = {}, onOpenMenu = {}, items = persistentListOf()),
pullToRefreshConfig = PullToRefreshConfig(isRefreshing = false, onRefresh = {}),
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(actionButtons = persistentListOf()),
addToWalletBlockState = AddToWalletBlockState({}, {}),
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
actionButtons = persistentListOf(),
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
cards = persistentListOf(TangemPayDetailsBalanceBlockState.Card(lastDigits = "1234", onClick = {})),
onAddCardClick = {},
),
),
isBalanceHidden = false,
addFundsEnabled = true,
cardFrozenState = CardFrozenState.Unfrozen,
betaNotificationConfig = NotificationConfig(
title = resourceReference(R.string.tangem_pay_beta_notification_title),
subtitle = resourceReference(R.string.tangem_pay_beta_notification_subtitle),
iconResId = R.drawable.img_visa_notification,
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = resourceReference(R.string.common_contact_support),
onClick = {},
),
iconSize = 36.dp,
),
),
),
)
@ -382,19 +427,6 @@ private fun TangemPayDetailsTxHistoryScreenPreview(
TangemPayDetailsScreen(
state = TangemPayDetailsUMProvider().values.first(),
txHistoryComponent = PreviewTangemPayTxHistoryComponent(txHistoryUM = state),
cardDetailsBlockComponent = PreviewTangemPayCardDetailsBlockComponent(
TangemPayCardDetailsUM(
number = "•••• •••• •••• 1245",
numberShort = "*1245",
expiry = "••/••",
cvv = "•••",
onCopy = { _, _ -> },
onClick = {},
buttonText = TextReference.Res(R.string.tangempay_card_details_hide_text),
cardFrozenState = TangemPayCardFrozenState.Unfrozen,
displayNameState = null,
),
),
expressTransactionsComponent = PreviewEmptyExpressTransactionsComponent(),
)
}

View file

@ -7,8 +7,7 @@ internal interface TangemPayDetailIntents {
fun onRefreshSwipe(refreshState: ShowRefreshState)
fun onClickAddFunds()
fun onClickWithdraw()
fun onClickPinCode()
fun onClickFreezeCard()
fun onClickUnfreezeCard()
fun onClickTermsAndLimits()
fun onCardClick()
fun onAddCardClick()
}

View file

@ -113,4 +113,20 @@ internal object TangemPayMessagesFactory {
}
}
}
fun createFutureFeature(): BottomSheetMessage {
return bottomSheetMessage {
infoBlock {
icon(R.drawable.ic_credit_card_add_24) {
backgroundType = MessageBottomSheetUM.Icon.BackgroundType.Accent
}
title = resourceReference(R.string.tangempay_feature_will_be_available_soon)
body = resourceReference(R.string.tangempay_feature_will_be_available_soon_description)
}
primaryButton {
text = resourceReference(R.string.common_got_it)
onClick { closeBs() }
}
}
}
}