From 596cbb40cb63d2687ded2d3a95ba6cf77d48c303 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 28 Apr 2026 17:32:04 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../res/drawable/img_visa_card_48x32.webp | Bin 0 -> 772 bytes .../components/TangemPayCardPageComponent.kt | 14 - ...faultTangemPayDetailsContainerComponent.kt | 44 +-- ...onent.kt => TangemPayCardPageComponent.kt} | 51 ++-- .../TangemPayCardPageScreenComponent.kt | 15 +- .../TangemPayChangePinSuccessComponent.kt | 4 +- .../components/TangemPayDetailsComponent.kt | 20 -- .../di/TangemPayDetailsFeatureModule.kt | 8 - .../entity/TangemPayCardNavigation.kt | 30 ++ .../entity/TangemPayDetailsNavigation.kt | 9 - .../entity/TangemPayDetailsStateFactory.kt | 74 ++--- .../entity/TangemPayDetailsTopBarConfig.kt | 16 +- .../tangempay/entity/TangemPayDetailsUM.kt | 15 +- .../setup/TangemPayCardLimitSetupModel.kt | 4 +- ...TangemPayCardLimitSetupSuccessComponent.kt | 4 +- .../model/TangemPayCardDetailsBlockModel.kt | 8 +- .../tangempay/model/TangemPayCardPageModel.kt | 20 +- .../model/TangemPayChangePinModel.kt | 12 +- .../tangempay/model/TangemPayDetailsModel.kt | 194 ++----------- .../DetailsAddToWalletBannerTransformer.kt | 22 -- .../transformers/DetailsBalanceTransformer.kt | 11 +- .../TangemPayCardFrozenStateConverter.kt | 18 -- ...TangemPayFreezeUnfreezeStateTransformer.kt | 57 +--- .../TangemPayAccountDetailsInnerRoute.kt | 13 + .../TangemPayCardDetailsInnerRoute.kt | 29 ++ .../navigation/TangemPayDetailsInnerRoute.kt | 28 -- .../tangempay/ui/TangemPayDetailsScreen.kt | 258 ++++++++++-------- .../tangempay/utils/TangemPayDetailIntents.kt | 5 +- .../utils/TangemPayMessagesFactory.kt | 16 ++ 29 files changed, 364 insertions(+), 635 deletions(-) create mode 100644 core/ui/src/main/res/drawable/img_visa_card_48x32.webp delete mode 100644 features/tangempay/details/api/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageComponent.kt rename features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/{DefaultTangemPayCardPageComponent.kt => TangemPayCardPageComponent.kt} (65%) create mode 100644 features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayCardNavigation.kt delete mode 100644 features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsAddToWalletBannerTransformer.kt delete mode 100644 features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayCardFrozenStateConverter.kt create mode 100644 features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayAccountDetailsInnerRoute.kt create mode 100644 features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayCardDetailsInnerRoute.kt delete mode 100644 features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayDetailsInnerRoute.kt diff --git a/core/ui/src/main/res/drawable/img_visa_card_48x32.webp b/core/ui/src/main/res/drawable/img_visa_card_48x32.webp new file mode 100644 index 0000000000000000000000000000000000000000..8fa2d328ee81dda7bb0e5e2a2a4a132b67911ed3 GIT binary patch literal 772 zcmV+f1N;0^Nk&He0ssJ4MM6+kP&gp)0ssKe5dfV5D!>4M06vjOp-d&DBO)RdSXi(U z32AQKUD~u}Q83MH!LTj~%Fa#9^4tBiGes8(%#3qE2M?kss{HQI?&b3cDerljT>k)E zgAATECY;m|DFQ${N-W2WbD8@`+^n=g0>~j4k@;9W1m{|n5R>TH^TM-E^|$+8;y7bG zA>d24E`t|tg@rAcrsAsq{FN@-fPeu0@eEZ#{0S=@g};Y)Hoc6^jW6P}cTdv(@?Qzi zMD=0jSb|;N4tOKe z_h4V8dTOkOK3K2{xs|=>C9Qf~tkmier#~6-X8O^kQ{pqxQ2~Yu0Mg7aPvflu>CRLctnA=^jfuzDQ!rR%% znZF7)h?bAa8hwx{1l1Dy{pmkz((yOm^14M|x5noz0qy7FGIIZZS09$^2&Xa+;oa$P zTEN?9=B7Bw(K)sgp~qQ7(x+&v9cAR%bwUuj7c`#`vhvc;L}4EWN`6ocmKXL+MT zHR#H=&=!^rD1v&I>)i4)I@)&eIzCWa^zxaIm%U$$|6i<=AT(`^w2XV^oRXPQwz9GR znTa~h_3V!FBTHfaJ71H69^s-JDkMn)qCq~_u_3p<`&DnBdh_l6q1RnnZLK)yUq*`h@O@)%aXm5j_!`s%{eL3k3uZ2<-f*pmRM!rXd%x z{*s?`Y{iBm;;}1=f3iPr+@7JePmeZ!LsRgD;gKIAYj%~Yt+!=`+c7|1s1)+N@6N&L z0|8c&3ncD+M}PY3g%;|t6EptAu-=DkKmmt_43Ku&0R2F7n%e*=c0x6}L&Z39Z~y=f C<%PWf literal 0 HcmV?d00001 diff --git a/features/tangempay/details/api/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageComponent.kt b/features/tangempay/details/api/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageComponent.kt deleted file mode 100644 index 9ec8ddecd1..0000000000 --- a/features/tangempay/details/api/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageComponent.kt +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayDetailsContainerComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayDetailsContainerComponent.kt index 272c8d3b39..52b0069572 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayDetailsContainerComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayDetailsContainerComponent.kt @@ -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() + private val stackNavigation = StackNavigation() - private val innerRouter = InnerRouter( + private val innerRouter = InnerRouter( 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), ) } diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayCardPageComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageComponent.kt similarity index 65% rename from features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayCardPageComponent.kt rename to features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageComponent.kt index 7271f7fd3a..6d2e0dc50b 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/DefaultTangemPayCardPageComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageComponent.kt @@ -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() + private val stackNavigation = StackNavigation() - private val innerRouter = InnerRouter( + private val innerRouter = InnerRouter( 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 { + override fun create(context: AppComponentContext, params: Params): TangemPayCardPageComponent } } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageScreenComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageScreenComponent.kt index 039bcab003..9d3e29f799 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageScreenComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageScreenComponent.kt @@ -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") } } } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayChangePinSuccessComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayChangePinSuccessComponent.kt index d47fcd6737..eccf167f98 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayChangePinSuccessComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayChangePinSuccessComponent.kt @@ -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) } } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt index b59577ebe8..806f7c1980 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayDetailsComponent.kt @@ -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") } } } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayDetailsFeatureModule.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayDetailsFeatureModule.kt index df71114f7c..de293a174d 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayDetailsFeatureModule.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayDetailsFeatureModule.kt @@ -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 diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayCardNavigation.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayCardNavigation.kt new file mode 100644 index 0000000000..7e527748ee --- /dev/null +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayCardNavigation.kt @@ -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() +} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsNavigation.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsNavigation.kt index fdc5357eae..86009f09f0 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsNavigation.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsNavigation.kt @@ -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() } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt index 8fb38c33bc..ca79de1c95 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsStateFactory.kt @@ -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, - ), ) } } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsTopBarConfig.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsTopBarConfig.kt index bd4daa10c9..9675f1b31d 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsTopBarConfig.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsTopBarConfig.kt @@ -6,17 +6,5 @@ import kotlinx.collections.immutable.ImmutableList internal data class TangemPayDetailsTopBarConfig( val onBackClick: () -> Unit, val onOpenMenu: () -> Unit, - val items: ImmutableList?, -) - -internal data class TangemPayDetailsTopBarMenuItem( - val type: TangemPayDetailsTopBarMenuItemType, - val dropdownItem: TangemDropdownMenuItem, -) - -internal enum class TangemPayDetailsTopBarMenuItemType { - ChangePin, - TermsAndLimits, - FreezeCard, - UnfreezeCard, -} \ No newline at end of file + val items: ImmutableList, +) \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsUM.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsUM.kt index 7eb7b01df6..b201d755e3 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsUM.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayDetailsUM.kt @@ -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 + abstract val cardsBlockState: CardsBlockState data class Loading( override val actionButtons: ImmutableList, + override val cardsBlockState: CardsBlockState, ) : TangemPayDetailsBalanceBlockState() data class Content( override val actionButtons: ImmutableList, + override val cardsBlockState: CardsBlockState, val fiatBalance: String, val isBalanceFlickering: Boolean, ) : TangemPayDetailsBalanceBlockState() data class Error( override val actionButtons: ImmutableList, + 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, val onAddCardClick: () -> Unit) + data class Card(val lastDigits: String, val onClick: () -> Unit) } internal data class AddToWalletBlockState( diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/limit/setup/TangemPayCardLimitSetupModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/limit/setup/TangemPayCardLimitSetupModel.kt index 509ea0514e..5f3941838b 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/limit/setup/TangemPayCardLimitSetupModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/limit/setup/TangemPayCardLimitSetupModel.kt @@ -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) }, ) } diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/limit/setup/TangemPayCardLimitSetupSuccessComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/limit/setup/TangemPayCardLimitSetupSuccessComponent.kt index fd424be559..a7c95a2eb2 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/limit/setup/TangemPayCardLimitSetupSuccessComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/limit/setup/TangemPayCardLimitSetupSuccessComponent.kt @@ -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) } } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardDetailsBlockModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardDetailsBlockModel.kt index 13025f10a1..9bcf1fcdd1 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardDetailsBlockModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardDetailsBlockModel.kt @@ -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) { diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt index 2789a75e07..5bee5538b2 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt @@ -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 = SlotNavigation() + val bottomSheetNavigation: SlotNavigation = 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() { diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayChangePinModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayChangePinModel.kt index de7acccebe..01ff0e469d 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayChangePinModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayChangePinModel.kt @@ -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, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt index 9de0999957..6e32517234 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayDetailsModel.kt @@ -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 - 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)) } diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsAddToWalletBannerTransformer.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsAddToWalletBannerTransformer.kt deleted file mode 100644 index 3fe7bddbf8..0000000000 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsAddToWalletBannerTransformer.kt +++ /dev/null @@ -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 { - - override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM { - return prevState.copy( - addToWalletBlockState = if (isDone) { - null - } else { - AddToWalletBlockState(onClick = onClickBanner, onClickClose = onClickCloseBanner) - }, - ) - } -} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsBalanceTransformer.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsBalanceTransformer.kt index d2da85c3d4..af0cec0bd5 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsBalanceTransformer.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsBalanceTransformer.kt @@ -22,19 +22,26 @@ internal class DetailsBalanceTransformer( override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM { val balance = when (balance) { is Either.Left -> { - TangemPayDetailsBalanceBlockState.Error(actionButtons = persistentListOf()) + TangemPayDetailsBalanceBlockState.Error( + actionButtons = persistentListOf(), + cardsBlockState = prevState.balanceBlockState.cardsBlockState, + ) } is Either.Right -> { 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, ) } } diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayCardFrozenStateConverter.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayCardFrozenStateConverter.kt deleted file mode 100644 index 1be3c5e765..0000000000 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayCardFrozenStateConverter.kt +++ /dev/null @@ -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 { - - override fun convert(value: TangemPayCardFrozenState): CardFrozenState { - return when (value) { - TangemPayCardFrozenState.Unfrozen -> CardFrozenState.Unfrozen - TangemPayCardFrozenState.Frozen -> CardFrozenState.Frozen(onUnfreezeClick) - TangemPayCardFrozenState.Pending -> CardFrozenState.Pending - } - } -} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformer.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformer.kt index 7fb2efcb5e..9ba594e731 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformer.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/TangemPayFreezeUnfreezeStateTransformer.kt @@ -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 { - 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?, - ): ImmutableList? { - 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) } } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayAccountDetailsInnerRoute.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayAccountDetailsInnerRoute.kt new file mode 100644 index 0000000000..6bc9172607 --- /dev/null +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayAccountDetailsInnerRoute.kt @@ -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() +} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayCardDetailsInnerRoute.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayCardDetailsInnerRoute.kt new file mode 100644 index 0000000000..38d9fb1d83 --- /dev/null +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayCardDetailsInnerRoute.kt @@ -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() +} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayDetailsInnerRoute.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayDetailsInnerRoute.kt deleted file mode 100644 index 89facef290..0000000000 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayDetailsInnerRoute.kt +++ /dev/null @@ -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() -} \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt index 86e06e7ffe..a2b35908ce 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayDetailsScreen.kt @@ -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( 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 }, - onClick = {}, - buttonText = TextReference.Res(R.string.tangempay_card_details_hide_text), - cardFrozenState = TangemPayCardFrozenState.Unfrozen, - displayNameState = null, - ), - ), expressTransactionsComponent = PreviewEmptyExpressTransactionsComponent(), ) } diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/TangemPayDetailIntents.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/TangemPayDetailIntents.kt index 9e96a75104..731154d2a1 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/TangemPayDetailIntents.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/TangemPayDetailIntents.kt @@ -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() } \ No newline at end of file diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/TangemPayMessagesFactory.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/TangemPayMessagesFactory.kt index 5f8a35fffc..e10ee99a4e 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/TangemPayMessagesFactory.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/TangemPayMessagesFactory.kt @@ -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() } + } + } + } } \ No newline at end of file