Updated on 2026-08-14
This commit is contained in:
parent
ace91fb278
commit
596cbb40cb
29 changed files with 364 additions and 635 deletions
BIN
core/ui/src/main/res/drawable/img_visa_card_48x32.webp
Normal file
BIN
core/ui/src/main/res/drawable/img_visa_card_48x32.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 772 B |
|
|
@ -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>
|
||||
}
|
||||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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>,
|
||||
)
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue