diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 882377e5e5..1603427b46 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -310,4 +310,8 @@
+
+
+
+
diff --git a/app/src/main/java/com/tangem/tap/data/DefaultTangemPayStorage.kt b/app/src/main/java/com/tangem/tap/data/DefaultTangemPayStorage.kt
index e615d85d62..ec16f63f50 100644
--- a/app/src/main/java/com/tangem/tap/data/DefaultTangemPayStorage.kt
+++ b/app/src/main/java/com/tangem/tap/data/DefaultTangemPayStorage.kt
@@ -3,6 +3,10 @@ package com.tangem.tap.data
import android.content.Context
import com.squareup.moshi.Moshi
import com.tangem.datasource.di.NetworkMoshi
+import com.tangem.datasource.local.preferences.AppPreferencesStore
+import com.tangem.datasource.local.preferences.PreferencesKeys
+import com.tangem.datasource.local.preferences.utils.getSyncOrNull
+import com.tangem.datasource.local.preferences.utils.store
import com.tangem.datasource.local.visa.TangemPayStorage
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.visa.model.VisaAuthTokens
@@ -21,6 +25,7 @@ internal class DefaultTangemPayStorage @Inject constructor(
@ApplicationContext applicationContext: Context,
@NetworkMoshi moshi: Moshi,
private val dispatcherProvider: CoroutineDispatcherProvider,
+ private val appPreferencesStore: AppPreferencesStore,
) : TangemPayStorage {
private val secureStorage by lazy {
@@ -75,6 +80,20 @@ internal class DefaultTangemPayStorage @Inject constructor(
secureStorage.get(createOrderIdKey(customerWalletAddress))?.decodeToString(throwOnInvalidSequence = true)
}
+ override suspend fun getAddToWalletDone(customerWalletAddress: String): Boolean {
+ return withContext(dispatcherProvider.io) {
+ appPreferencesStore.getSyncOrNull(
+ key = PreferencesKeys.getTangemPayAddToWalletKey(customerWalletAddress),
+ ) == true
+ }
+ }
+
+ override suspend fun storeAddToWalletDone(customerWalletAddress: String, isDone: Boolean) {
+ withContext(dispatcherProvider.io) {
+ appPreferencesStore.store(PreferencesKeys.getTangemPayAddToWalletKey(customerWalletAddress), isDone)
+ }
+ }
+
override suspend fun clearOrderId(customerWalletAddress: String) = withContext(dispatcherProvider.io) {
secureStorage.delete(createOrderIdKey(customerWalletAddress))
}
@@ -84,6 +103,7 @@ internal class DefaultTangemPayStorage @Inject constructor(
secureStorage.delete(createCustomerAddressKey(userWalletId))
secureStorage.delete(createKey(customerWalletAddress))
secureStorage.delete(createOrderIdKey(customerWalletAddress))
+ appPreferencesStore.store(PreferencesKeys.getTangemPayAddToWalletKey(customerWalletAddress), false)
}
private fun createCustomerAddressKey(userWalletId: UserWalletId): String = userWalletId.stringValue
diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt
index a91cb3cf09..f7da1d83cf 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt
@@ -181,6 +181,9 @@ object PreferencesKeys {
fun getHotWalletUnlockDeadlineKey(attemptId: String) =
longPreferencesKey(name = "hotWalletUnlockDeadline_$attemptId")
+ fun getTangemPayAddToWalletKey(customerWalletAddress: String) =
+ booleanPreferencesKey("tangem_pay_add_to_wallet_done_key_$customerWalletAddress")
+
// endregion
}
diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayStorage.kt b/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayStorage.kt
index 3d9558f45e..d74074f011 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayStorage.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/local/visa/TangemPayStorage.kt
@@ -18,5 +18,9 @@ interface TangemPayStorage {
suspend fun clearOrderId(customerWalletAddress: String)
+ suspend fun getAddToWalletDone(customerWalletAddress: String): Boolean
+
+ suspend fun storeAddToWalletDone(customerWalletAddress: String, isDone: Boolean)
+
suspend fun clearAll(userWalletId: UserWalletId, customerWalletAddress: String)
}
\ No newline at end of file
diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml
index 8c6ab60718..c1aa707042 100644
--- a/core/res/src/main/res/values-fr/strings.xml
+++ b/core/res/src/main/res/values-fr/strings.xml
@@ -1523,9 +1523,11 @@
Les frais de réseau seront déduits du montant que vous retirez.
Rendement annuel brut (APY)
APY
+ Les intérêts sont cumulés automatiquement.
Les intérêts sont cumulés automatiquement.
Mode de rendement
Traitement de votre dépôt
+ Mode Rendement
Automatique
Déposez %1$s %2$s pour couvrir les frais de réseau liés aux transactions.
Impossible de couvrir les frais %s
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 51c96443a0..8e7c5ebd52 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -1338,6 +1338,15 @@
Failed to load data. Try again later.
Freeze Card
Hide
+ Open Google Wallet
+ Set up Tangem Pay in a few taps and start paying with Google Pay.
+ Add your card to Google Pay
+ Open Google Wallet
+ Tap “Add a card”
+ Enter the card details manually
+ Verify card using the OTP sent to your device.
+ All set! Your card is ready to use.
+ Add card to Google Pay
Technical issues detected. Please try again later or contact support.
Receive unavailable now
Reveal
diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultCardDetailsRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultCardDetailsRepository.kt
index 6c820d0bd1..3478231e55 100644
--- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultCardDetailsRepository.kt
+++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultCardDetailsRepository.kt
@@ -10,6 +10,7 @@ import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
import com.tangem.datasource.api.pay.TangemPayApi
import com.tangem.datasource.api.pay.models.request.CardDetailsRequest
import com.tangem.datasource.api.pay.models.request.SetPinRequest
+import com.tangem.datasource.local.visa.TangemPayStorage
import com.tangem.domain.pay.model.SetPinResult
import com.tangem.domain.pay.model.TangemPayCardBalance
import com.tangem.domain.pay.model.TangemPayCardDetails
@@ -24,6 +25,7 @@ internal class DefaultCardDetailsRepository @Inject constructor(
private val visaLibLoader: VisaLibLoader,
private val apiConfigsManager: ApiConfigsManager,
private val rainCryptoUtil: RainCryptoUtil,
+ private val storage: TangemPayStorage,
) : CardDetailsRepository {
override suspend fun getCardBalance(): Either {
@@ -98,6 +100,18 @@ internal class DefaultCardDetailsRepository @Inject constructor(
}
}
+ override suspend fun isAddToWalletDone(): Either {
+ return requestHelper.runWithErrorLogs(TAG) {
+ storage.getAddToWalletDone(requestHelper.getCustomerWalletAddress())
+ }
+ }
+
+ override suspend fun setAddToWalletAsDone(): Either {
+ return requestHelper.runWithErrorLogs(TAG) {
+ storage.storeAddToWalletDone(requestHelper.getCustomerWalletAddress(), isDone = true)
+ }
+ }
+
private suspend fun getPublicKeyBase64(): String {
val env = apiConfigsManager.getEnvironmentConfig(ApiConfig.ID.TangemPay).environment
return when (env) {
diff --git a/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/CardDetailsRepository.kt b/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/CardDetailsRepository.kt
index 63211bc2c1..426b1814a8 100644
--- a/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/CardDetailsRepository.kt
+++ b/domain/visa/src/main/kotlin/com/tangem/domain/pay/repository/CardDetailsRepository.kt
@@ -13,4 +13,8 @@ interface CardDetailsRepository {
suspend fun revealCardDetails(): Either
suspend fun setPin(pin: String): Either
+
+ suspend fun isAddToWalletDone(): Either
+
+ suspend fun setAddToWalletAsDone(): Either
}
\ 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 28d4475d31..b1f3fb02be 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
@@ -67,6 +67,10 @@ class DefaultTangemPayDetailsContainerComponent @AssistedInject constructor(
TangemPayDetailsInnerRoute.ChangePINSuccess -> TangemPayChangePinSuccessComponent(
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
)
+ TangemPayDetailsInnerRoute.AddToWallet -> TangemPayAddToWalletComponent(
+ appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
+ params = params,
+ )
}
private fun onChildBack() {
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayAddToWalletComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayAddToWalletComponent.kt
new file mode 100644
index 0000000000..561ef1f9cf
--- /dev/null
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayAddToWalletComponent.kt
@@ -0,0 +1,38 @@
+package com.tangem.features.tangempay.components
+
+import androidx.activity.compose.BackHandler
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.tangem.core.decompose.context.AppComponentContext
+import com.tangem.core.decompose.context.child
+import com.tangem.core.decompose.model.getOrCreateModel
+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.model.TangemPayAddToWalletModel
+import com.tangem.features.tangempay.ui.TangemPayAddToWalletScreen
+
+internal class TangemPayAddToWalletComponent(
+ private val appComponentContext: AppComponentContext,
+ private val params: TangemPayDetailsContainerComponent.Params,
+) : AppComponentContext by appComponentContext, ComposableContentComponent {
+
+ private val model: TangemPayAddToWalletModel = getOrCreateModel()
+
+ private val cardDetailsBlockComponent = DefaultTangemPayCardDetailsBlockComponent(
+ appComponentContext = child("cardDetailsBlockComponent"),
+ params = TangemPayCardDetailsBlockComponent.Params(params = params),
+ )
+
+ @Composable
+ override fun Content(modifier: Modifier) {
+ val state by model.uiState.collectAsStateWithLifecycle()
+ BackHandler(onBack = router::pop)
+ TangemPayAddToWalletScreen(
+ state = state,
+ cardDetailsBlockComponent = cardDetailsBlockComponent,
+ )
+ }
+}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayModelModule.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayModelModule.kt
index 65f28a6405..912654abc7 100644
--- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayModelModule.kt
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/di/TangemPayModelModule.kt
@@ -2,6 +2,7 @@ package com.tangem.features.tangempay.di
import com.tangem.core.decompose.di.ModelComponent
import com.tangem.core.decompose.model.Model
+import com.tangem.features.tangempay.model.TangemPayAddToWalletModel
import com.tangem.features.tangempay.model.TangemPayCardDetailsBlockModel
import com.tangem.features.tangempay.model.TangemPayChangePinModel
import com.tangem.features.tangempay.model.TangemPayDetailsModel
@@ -41,4 +42,9 @@ internal interface TangemPayModelModule {
@IntoMap
@ClassKey(TangemPayCardDetailsBlockModel::class)
fun bindTangemPayCardDetailsBlockModel(model: TangemPayCardDetailsBlockModel): Model
+
+ @Binds
+ @IntoMap
+ @ClassKey(TangemPayAddToWalletModel::class)
+ fun bindTangemPayAddToWalletModel(model: TangemPayAddToWalletModel): Model
}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayAddToWalletUM.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayAddToWalletUM.kt
new file mode 100644
index 0000000000..c5aa65d1c5
--- /dev/null
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/entity/TangemPayAddToWalletUM.kt
@@ -0,0 +1,16 @@
+package com.tangem.features.tangempay.entity
+
+import com.tangem.core.ui.extensions.TextReference
+import kotlinx.collections.immutable.ImmutableList
+
+internal data class TangemPayAddToWalletUM(
+ val steps: ImmutableList,
+ val showAddToWalletButton: Boolean,
+ val onBackClick: () -> Unit,
+ val onClickOpenWallet: () -> Unit,
+)
+
+internal data class TangemPayAddToWalletStepItemUM(
+ val count: Int,
+ val text: TextReference,
+)
\ 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 baae7769b7..16de26202e 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
@@ -45,6 +45,7 @@ internal class TangemPayDetailsStateFactory(
),
),
),
+ addToWalletBlockState = null,
isBalanceHidden = false,
)
}
\ 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 a762ed7fdd..9ab8efa762 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
@@ -9,6 +9,7 @@ internal data class TangemPayDetailsUM(
val topBarConfig: TangemPayDetailsTopBarConfig,
val pullToRefreshConfig: PullToRefreshConfig,
val balanceBlockState: TangemPayDetailsBalanceBlockState,
+ val addToWalletBlockState: AddToWalletBlockState?,
val isBalanceHidden: Boolean,
)
@@ -41,4 +42,9 @@ internal sealed class TangemPayDetailsBalanceBlockState {
data class Error(
override val actionButtons: ImmutableList,
) : TangemPayDetailsBalanceBlockState()
-}
\ No newline at end of file
+}
+
+internal data class AddToWalletBlockState(
+ val onClick: () -> Unit,
+ val onClickClose: () -> Unit,
+)
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayAddToWalletModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayAddToWalletModel.kt
new file mode 100644
index 0000000000..0920d736e8
--- /dev/null
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayAddToWalletModel.kt
@@ -0,0 +1,59 @@
+package com.tangem.features.tangempay.model
+
+import androidx.compose.runtime.Stable
+import com.tangem.core.decompose.di.ModelScoped
+import com.tangem.core.decompose.model.Model
+import com.tangem.core.decompose.navigation.Router
+import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.features.tangempay.details.impl.R
+import com.tangem.features.tangempay.entity.TangemPayAddToWalletStepItemUM
+import com.tangem.features.tangempay.entity.TangemPayAddToWalletUM
+import com.tangem.features.tangempay.utils.GoogleWalletUtil
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.collections.immutable.persistentListOf
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import javax.inject.Inject
+
+@Stable
+@ModelScoped
+internal class TangemPayAddToWalletModel @Inject constructor(
+ override val dispatchers: CoroutineDispatcherProvider,
+ private val router: Router,
+ private val googleWalletUtil: GoogleWalletUtil,
+) : Model() {
+
+ val uiState: StateFlow
+ field = MutableStateFlow(getInitialState())
+
+ @Suppress("MagicNumber")
+ private fun getInitialState(): TangemPayAddToWalletUM {
+ return TangemPayAddToWalletUM(
+ steps = persistentListOf(
+ TangemPayAddToWalletStepItemUM(
+ count = 1,
+ text = resourceReference(R.string.tangempay_card_details_open_wallet_step_1),
+ ),
+ TangemPayAddToWalletStepItemUM(
+ count = 2,
+ text = resourceReference(R.string.tangempay_card_details_open_wallet_step_2),
+ ),
+ TangemPayAddToWalletStepItemUM(
+ count = 3,
+ text = resourceReference(R.string.tangempay_card_details_open_wallet_step_3),
+ ),
+ TangemPayAddToWalletStepItemUM(
+ count = 4,
+ text = resourceReference(R.string.tangempay_card_details_open_wallet_step_4),
+ ),
+ TangemPayAddToWalletStepItemUM(
+ count = 5,
+ text = resourceReference(R.string.tangempay_card_details_open_wallet_step_5),
+ ),
+ ),
+ showAddToWalletButton = googleWalletUtil.isWalletAvailable(),
+ onBackClick = router::pop,
+ onClickOpenWallet = googleWalletUtil::openWallet,
+ )
+ }
+}
\ No newline at end of file
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 fd80a9a75f..3b4c752852 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
@@ -20,6 +20,7 @@ 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.DetailsAddToWalletBannerTransformer
import com.tangem.features.tangempay.model.transformers.DetailsBalanceTransformer
import com.tangem.features.tangempay.model.transformers.TangemPayDetailsRefreshTransformer
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
@@ -63,10 +64,12 @@ internal class TangemPayDetailsModel @Inject constructor(
private val refreshStateJobHolder = JobHolder()
private val fetchBalanceJobHolder = JobHolder()
+ private val addToWalletBannerJobHolder = JobHolder()
val bottomSheetNavigation: SlotNavigation = SlotNavigation()
init {
+ fetchAddToWalletBanner()
fetchBalance()
}
@@ -105,6 +108,19 @@ internal class TangemPayDetailsModel @Inject constructor(
}.saveIn(fetchBalanceJobHolder)
}
+ private fun fetchAddToWalletBanner() {
+ modelScope.launch {
+ val isDone = cardDetailsRepository.isAddToWalletDone().getOrNull() ?: false
+ uiState.update(
+ transformer = DetailsAddToWalletBannerTransformer(
+ onClickBanner = ::onClickAddToWalletBlock,
+ onClickCloseBanner = ::onClickCloseAddToWalletBlock,
+ isDone = isDone,
+ ),
+ )
+ }.saveIn(addToWalletBannerJobHolder)
+ }
+
private fun onRefreshSwipe(refreshState: ShowRefreshState) {
modelScope.launch {
cardDetailsEventListener.send(CardDetailsEvent.Hide)
@@ -114,6 +130,23 @@ internal class TangemPayDetailsModel @Inject constructor(
}.saveIn(refreshStateJobHolder)
}
+ private fun onClickAddToWalletBlock() {
+ router.push(TangemPayDetailsInnerRoute.AddToWallet)
+ }
+
+ private fun onClickCloseAddToWalletBlock() {
+ modelScope.launch {
+ cardDetailsRepository.setAddToWalletAsDone()
+ uiState.update(
+ transformer = DetailsAddToWalletBannerTransformer(
+ onClickBanner = ::onClickAddToWalletBlock,
+ onClickCloseBanner = ::onClickCloseAddToWalletBlock,
+ isDone = true,
+ ),
+ )
+ }.saveIn(addToWalletBannerJobHolder)
+ }
+
override fun onTransactionClick(item: TangemPayTxHistoryItem) {
bottomSheetNavigation.activate(TangemPayDetailsNavigation.TransactionDetails(item))
}
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
new file mode 100644
index 0000000000..3fe7bddbf8
--- /dev/null
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/transformers/DetailsAddToWalletBannerTransformer.kt
@@ -0,0 +1,22 @@
+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/navigation/TangemPayDetailsInnerRoute.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/navigation/TangemPayDetailsInnerRoute.kt
index 9aabeac0cd..7bc24c9979 100644
--- 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
@@ -13,4 +13,7 @@ internal sealed class TangemPayDetailsInnerRoute : Route {
@Serializable
data object ChangePINSuccess : TangemPayDetailsInnerRoute()
+
+ @Serializable
+ data object AddToWallet : TangemPayDetailsInnerRoute()
}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayAddToWalletBlock.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayAddToWalletBlock.kt
new file mode 100644
index 0000000000..50c72f534f
--- /dev/null
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayAddToWalletBlock.kt
@@ -0,0 +1,107 @@
+package com.tangem.features.tangempay.ui
+
+import android.content.res.Configuration
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.tangem.core.ui.extensions.stringResourceSafe
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreview
+import com.tangem.features.tangempay.details.impl.R
+import com.tangem.features.tangempay.entity.AddToWalletBlockState
+
+private const val GRADIENT_START_COLOR = 0xFF252934
+private const val GRADIENT_END_COLOR = 0xFF12141E
+private const val GRADIENT_OFFSET_X = 0f
+private const val GRADIENT_OFFSET_Y = 80F
+private const val GRADIENT_RADIUS = 200F
+
+@Composable
+internal fun TangemPayAddToWalletBlock(state: AddToWalletBlockState, modifier: Modifier = Modifier) {
+ Box(
+ modifier = modifier
+ .fillMaxWidth()
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .background(
+ brush = Brush.radialGradient(
+ colors = listOf(Color(GRADIENT_START_COLOR), Color(GRADIENT_END_COLOR)),
+ center = Offset(GRADIENT_OFFSET_X, GRADIENT_OFFSET_Y),
+ radius = GRADIENT_RADIUS,
+ ),
+ )
+ .clickable(onClick = state.onClick),
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(IntrinsicSize.Min)
+ .padding(horizontal = 16.dp, vertical = 12.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Image(
+ painter = painterResource(R.drawable.img_google_wallet_48),
+ contentDescription = null,
+ modifier = Modifier.size(36.dp).clip(CircleShape),
+ )
+
+ Spacer(Modifier.width(12.dp))
+
+ Column(
+ modifier = Modifier.weight(1f),
+ verticalArrangement = Arrangement.Center,
+ ) {
+ Text(
+ text = stringResourceSafe(R.string.tangempay_card_details_open_wallet_notification_title),
+ style = TangemTheme.typography.subtitle2,
+ color = TangemTheme.colors.text.constantWhite,
+ )
+
+ Spacer(Modifier.height(6.dp))
+
+ Text(
+ text = stringResourceSafe(R.string.tangempay_card_details_open_wallet_notification_subtitle),
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+ }
+ Box(
+ modifier = Modifier.fillMaxHeight(),
+ contentAlignment = Alignment.TopEnd,
+ ) {
+ Image(
+ modifier = Modifier
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .clickable(onClick = state.onClickClose)
+ .padding(4.dp)
+ .size(12.dp),
+ painter = painterResource(id = R.drawable.ic_close_24),
+ colorFilter = ColorFilter.tint(TangemTheme.colors.icon.inactive),
+ contentDescription = null,
+ )
+ }
+ }
+ }
+}
+
+@Preview(showBackground = true)
+@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+private fun PreviewTangemPayAddToWalletBlock() {
+ TangemThemePreview {
+ TangemPayAddToWalletBlock(AddToWalletBlockState({}, {}))
+ }
+}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayAddToWalletScreen.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayAddToWalletScreen.kt
new file mode 100644
index 0000000000..249aee7ace
--- /dev/null
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayAddToWalletScreen.kt
@@ -0,0 +1,192 @@
+package com.tangem.features.tangempay.ui
+
+import android.content.res.Configuration
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.itemsIndexed
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.tangem.core.ui.components.PrimaryButton
+import com.tangem.core.ui.components.SecondaryButton
+import com.tangem.core.ui.components.appbar.AppBarWithBackButton
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.extensions.resolveReference
+import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.core.ui.extensions.stringResourceSafe
+import com.tangem.core.ui.res.TangemColorPalette
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreview
+import com.tangem.features.tangempay.components.cardDetails.PreviewTangemPayCardDetailsBlockComponent
+import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent
+import com.tangem.features.tangempay.details.impl.R
+import com.tangem.features.tangempay.entity.TangemPayAddToWalletStepItemUM
+import com.tangem.features.tangempay.entity.TangemPayAddToWalletUM
+import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM
+import kotlinx.collections.immutable.persistentListOf
+
+@Composable
+internal fun TangemPayAddToWalletScreen(
+ state: TangemPayAddToWalletUM,
+ cardDetailsBlockComponent: TangemPayCardDetailsBlockComponent,
+ modifier: Modifier = Modifier,
+) {
+ val listState = rememberLazyListState()
+ val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
+ val cardDetailsState by cardDetailsBlockComponent.state.collectAsStateWithLifecycle()
+
+ Column(
+ modifier = modifier
+ .fillMaxSize()
+ .navigationBarsPadding(),
+ ) {
+ AppBarWithBackButton(
+ modifier = Modifier.statusBarsPadding(),
+ iconRes = R.drawable.ic_close_24,
+ onBackClick = state.onBackClick,
+ )
+
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxSize()
+ .weight(1f),
+ state = listState,
+ contentPadding = PaddingValues(bottom = TangemTheme.dimens.spacing16 + bottomBarHeight),
+ ) {
+ item(key = TangemPayCardDetailsUM::class.java) {
+ TangemPayCardDetailsBlockItem(component = cardDetailsBlockComponent, state = cardDetailsState)
+ }
+
+ item(key = TangemPayAddToWalletUM::class.java) {
+ Text(
+ modifier = Modifier
+ .padding(horizontal = 16.dp, vertical = 24.dp)
+ .fillMaxWidth(),
+ text = stringResourceSafe(R.string.tangempay_card_details_open_wallet_title),
+ style = TangemTheme.typography.h2,
+ color = TangemTheme.colors.text.primary1,
+ textAlign = TextAlign.Center,
+ )
+ }
+ itemsIndexed(
+ items = state.steps,
+ key = { _, step -> "${TangemPayAddToWalletStepItemUM::class.java}${step.count}" },
+ ) { idx, step ->
+ StepItem(
+ modifier = Modifier.padding(bottom = if (idx < state.steps.lastIndex) 16.dp else 0.dp),
+ stepNumber = step.count,
+ title = step.text,
+ )
+ }
+ }
+
+ SecondaryButton(
+ modifier = Modifier
+ .imePadding()
+ .padding(start = 16.dp, end = 16.dp, bottom = 8.dp)
+ .fillMaxWidth(),
+ text = resourceReference(R.string.common_got_it).resolveReference(),
+ onClick = state.onBackClick,
+
+ )
+ if (state.showAddToWalletButton) {
+ PrimaryButton(
+ modifier = Modifier
+ .imePadding()
+ .padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
+ .fillMaxWidth(),
+ text = resourceReference(R.string.tangempay_card_details_open_wallet_button).resolveReference(),
+ onClick = state.onClickOpenWallet,
+ )
+ }
+ }
+}
+
+@Composable
+private fun StepItem(stepNumber: Int, title: TextReference, modifier: Modifier = Modifier) {
+ Row(
+ modifier = modifier
+ .background(color = Color.Transparent, shape = TangemTheme.shapes.roundedCorners8)
+ .padding(horizontal = 24.dp),
+ verticalAlignment = Alignment.Top,
+ ) {
+ Box(
+ modifier = Modifier
+ .size(24.dp)
+ .background(color = TangemColorPalette.Azure, shape = CircleShape),
+ contentAlignment = Alignment.Center,
+ ) {
+ Text(
+ text = stepNumber.toString(),
+ style = TangemTheme.typography.subtitle2,
+ color = TangemTheme.colors.text.primary2,
+ )
+ }
+
+ Spacer(modifier = Modifier.width(12.dp))
+
+ Text(
+ text = title.resolveReference(),
+ style = TangemTheme.typography.subtitle1,
+ color = TangemTheme.colors.text.primary1,
+ )
+ }
+}
+
+@Preview(showBackground = true)
+@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+private fun PreviewTangemPayAddToWalletScreen() {
+ TangemThemePreview {
+ TangemPayAddToWalletScreen(
+ state = TangemPayAddToWalletUM(
+ steps = persistentListOf(
+ TangemPayAddToWalletStepItemUM(
+ count = 1,
+ text = resourceReference(R.string.tangempay_card_details_open_wallet_step_1),
+ ),
+ TangemPayAddToWalletStepItemUM(
+ count = 2,
+ text = resourceReference(R.string.tangempay_card_details_open_wallet_step_2),
+ ),
+ TangemPayAddToWalletStepItemUM(
+ count = 3,
+ text = resourceReference(R.string.tangempay_card_details_open_wallet_step_3),
+ ),
+ TangemPayAddToWalletStepItemUM(
+ count = 4,
+ text = resourceReference(R.string.tangempay_card_details_open_wallet_step_4),
+ ),
+ TangemPayAddToWalletStepItemUM(
+ count = 5,
+ text = resourceReference(R.string.tangempay_card_details_open_wallet_step_5),
+ ),
+ ),
+ showAddToWalletButton = true,
+ onBackClick = {},
+ onClickOpenWallet = {},
+ ),
+ cardDetailsBlockComponent = PreviewTangemPayCardDetailsBlockComponent(
+ TangemPayCardDetailsUM(
+ number = "•••• •••• •••• 1245",
+ expiry = "••/••",
+ cvv = "•••",
+ onCopy = {},
+ onClick = {},
+ buttonText = TextReference.Res(R.string.tangempay_card_details_hide_text),
+ ),
+ ),
+ )
+ }
+}
\ No newline at end of file
diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlockItem.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlockItem.kt
new file mode 100644
index 0000000000..01e3a91379
--- /dev/null
+++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlockItem.kt
@@ -0,0 +1,15 @@
+package com.tangem.features.tangempay.ui
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent
+import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM
+
+@Composable
+internal fun TangemPayCardDetailsBlockItem(
+ component: TangemPayCardDetailsBlockComponent,
+ state: TangemPayCardDetailsUM,
+ modifier: Modifier = Modifier,
+) {
+ component.CardDetailsBlockContent(state = state, modifier = modifier)
+}
\ 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 47de0ecf3b..3cf7c2e7a6 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
@@ -90,10 +90,21 @@ internal fun TangemPayDetailsScreen(
)
},
)
- with(cardDetailsBlockComponent) {
- item(TangemPayCardDetailsUM::class.java) {
- CardDetailsBlockContent(state = cardDetailsState)
- }
+ 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),
+ )
+ },
+ )
+ }
+ item(TangemPayCardDetailsUM::class.java) {
+ TangemPayCardDetailsBlockItem(component = cardDetailsBlockComponent, state = cardDetailsState)
}
with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryState) }
}
@@ -300,12 +311,14 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider
+
+
+
+
+
+