Updated on 2026-08-14
This commit is contained in:
parent
2105360004
commit
d76fcd143c
24 changed files with 645 additions and 5 deletions
|
|
@ -310,4 +310,8 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
</application>
|
</application>
|
||||||
|
<queries>
|
||||||
|
<!-- Needed from Android 11 to open Google Wallet for payment with Visa card -->
|
||||||
|
<package android:name="com.google.android.apps.walletnfcrel" />
|
||||||
|
</queries>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@ package com.tangem.tap.data
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
import com.tangem.datasource.di.NetworkMoshi
|
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.datasource.local.visa.TangemPayStorage
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.visa.model.VisaAuthTokens
|
import com.tangem.domain.visa.model.VisaAuthTokens
|
||||||
|
|
@ -21,6 +25,7 @@ internal class DefaultTangemPayStorage @Inject constructor(
|
||||||
@ApplicationContext applicationContext: Context,
|
@ApplicationContext applicationContext: Context,
|
||||||
@NetworkMoshi moshi: Moshi,
|
@NetworkMoshi moshi: Moshi,
|
||||||
private val dispatcherProvider: CoroutineDispatcherProvider,
|
private val dispatcherProvider: CoroutineDispatcherProvider,
|
||||||
|
private val appPreferencesStore: AppPreferencesStore,
|
||||||
) : TangemPayStorage {
|
) : TangemPayStorage {
|
||||||
|
|
||||||
private val secureStorage by lazy {
|
private val secureStorage by lazy {
|
||||||
|
|
@ -75,6 +80,20 @@ internal class DefaultTangemPayStorage @Inject constructor(
|
||||||
secureStorage.get(createOrderIdKey(customerWalletAddress))?.decodeToString(throwOnInvalidSequence = true)
|
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) {
|
override suspend fun clearOrderId(customerWalletAddress: String) = withContext(dispatcherProvider.io) {
|
||||||
secureStorage.delete(createOrderIdKey(customerWalletAddress))
|
secureStorage.delete(createOrderIdKey(customerWalletAddress))
|
||||||
}
|
}
|
||||||
|
|
@ -84,6 +103,7 @@ internal class DefaultTangemPayStorage @Inject constructor(
|
||||||
secureStorage.delete(createCustomerAddressKey(userWalletId))
|
secureStorage.delete(createCustomerAddressKey(userWalletId))
|
||||||
secureStorage.delete(createKey(customerWalletAddress))
|
secureStorage.delete(createKey(customerWalletAddress))
|
||||||
secureStorage.delete(createOrderIdKey(customerWalletAddress))
|
secureStorage.delete(createOrderIdKey(customerWalletAddress))
|
||||||
|
appPreferencesStore.store(PreferencesKeys.getTangemPayAddToWalletKey(customerWalletAddress), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createCustomerAddressKey(userWalletId: UserWalletId): String = userWalletId.stringValue
|
private fun createCustomerAddressKey(userWalletId: UserWalletId): String = userWalletId.stringValue
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,9 @@ object PreferencesKeys {
|
||||||
fun getHotWalletUnlockDeadlineKey(attemptId: String) =
|
fun getHotWalletUnlockDeadlineKey(attemptId: String) =
|
||||||
longPreferencesKey(name = "hotWalletUnlockDeadline_$attemptId")
|
longPreferencesKey(name = "hotWalletUnlockDeadline_$attemptId")
|
||||||
|
|
||||||
|
fun getTangemPayAddToWalletKey(customerWalletAddress: String) =
|
||||||
|
booleanPreferencesKey("tangem_pay_add_to_wallet_done_key_$customerWalletAddress")
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,5 +18,9 @@ interface TangemPayStorage {
|
||||||
|
|
||||||
suspend fun clearOrderId(customerWalletAddress: String)
|
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)
|
suspend fun clearAll(userWalletId: UserWalletId, customerWalletAddress: String)
|
||||||
}
|
}
|
||||||
|
|
@ -1523,9 +1523,11 @@
|
||||||
<string name="yield_module_stop_earning_sheet_fee_note">Les frais de réseau seront déduits du montant que vous retirez.</string>
|
<string name="yield_module_stop_earning_sheet_fee_note">Les frais de réseau seront déduits du montant que vous retirez.</string>
|
||||||
<string name="yield_module_supply_apr">Rendement annuel brut (APY)</string>
|
<string name="yield_module_supply_apr">Rendement annuel brut (APY)</string>
|
||||||
<string name="yield_module_token_details_earn_notification_apy">APY</string>
|
<string name="yield_module_token_details_earn_notification_apy">APY</string>
|
||||||
|
<string name="yield_module_token_details_earn_notification_description">Les intérêts sont cumulés automatiquement.</string>
|
||||||
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_subtitle">Les intérêts sont cumulés automatiquement.</string>
|
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_subtitle">Les intérêts sont cumulés automatiquement.</string>
|
||||||
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">Mode de rendement</string>
|
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">Mode de rendement</string>
|
||||||
<string name="yield_module_token_details_earn_notification_processing">Traitement de votre dépôt</string>
|
<string name="yield_module_token_details_earn_notification_processing">Traitement de votre dépôt</string>
|
||||||
|
<string name="yield_module_token_details_earn_notification_title">Mode Rendement</string>
|
||||||
<string name="yield_module_transfer_mode_automatic">Automatique</string>
|
<string name="yield_module_transfer_mode_automatic">Automatique</string>
|
||||||
<string name="yield_module_unable_to_cover_fee_description">Déposez %1$s %2$s pour couvrir les frais de réseau liés aux transactions.</string>
|
<string name="yield_module_unable_to_cover_fee_description">Déposez %1$s %2$s pour couvrir les frais de réseau liés aux transactions.</string>
|
||||||
<string name="yield_module_unable_to_cover_fee_title">Impossible de couvrir les frais %s</string>
|
<string name="yield_module_unable_to_cover_fee_title">Impossible de couvrir les frais %s</string>
|
||||||
|
|
|
||||||
|
|
@ -1338,6 +1338,15 @@
|
||||||
<string name="tangempay_card_details_error_text">Failed to load data. Try again later.</string>
|
<string name="tangempay_card_details_error_text">Failed to load data. Try again later.</string>
|
||||||
<string name="tangempay_card_details_freeze_card">Freeze Card</string>
|
<string name="tangempay_card_details_freeze_card">Freeze Card</string>
|
||||||
<string name="tangempay_card_details_hide_text">Hide</string>
|
<string name="tangempay_card_details_hide_text">Hide</string>
|
||||||
|
<string name="tangempay_card_details_open_wallet_button">Open Google Wallet</string>
|
||||||
|
<string name="tangempay_card_details_open_wallet_notification_subtitle">Set up Tangem Pay in a few taps and start paying with Google Pay.</string>
|
||||||
|
<string name="tangempay_card_details_open_wallet_notification_title">Add your card to Google Pay</string>
|
||||||
|
<string name="tangempay_card_details_open_wallet_step_1">Open Google Wallet</string>
|
||||||
|
<string name="tangempay_card_details_open_wallet_step_2">Tap “Add a card”</string>
|
||||||
|
<string name="tangempay_card_details_open_wallet_step_3">Enter the card details manually</string>
|
||||||
|
<string name="tangempay_card_details_open_wallet_step_4">Verify card using the OTP sent to your device.</string>
|
||||||
|
<string name="tangempay_card_details_open_wallet_step_5">All set! Your card is ready to use.</string>
|
||||||
|
<string name="tangempay_card_details_open_wallet_title">Add card to Google Pay</string>
|
||||||
<string name="tangempay_card_details_receive_error_description">Technical issues detected. Please try again later or contact support.</string>
|
<string name="tangempay_card_details_receive_error_description">Technical issues detected. Please try again later or contact support.</string>
|
||||||
<string name="tangempay_card_details_receive_error_title">Receive unavailable now</string>
|
<string name="tangempay_card_details_receive_error_title">Receive unavailable now</string>
|
||||||
<string name="tangempay_card_details_reveal_text">Reveal</string>
|
<string name="tangempay_card_details_reveal_text">Reveal</string>
|
||||||
|
|
|
||||||
|
|
@ -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.TangemPayApi
|
||||||
import com.tangem.datasource.api.pay.models.request.CardDetailsRequest
|
import com.tangem.datasource.api.pay.models.request.CardDetailsRequest
|
||||||
import com.tangem.datasource.api.pay.models.request.SetPinRequest
|
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.SetPinResult
|
||||||
import com.tangem.domain.pay.model.TangemPayCardBalance
|
import com.tangem.domain.pay.model.TangemPayCardBalance
|
||||||
import com.tangem.domain.pay.model.TangemPayCardDetails
|
import com.tangem.domain.pay.model.TangemPayCardDetails
|
||||||
|
|
@ -24,6 +25,7 @@ internal class DefaultCardDetailsRepository @Inject constructor(
|
||||||
private val visaLibLoader: VisaLibLoader,
|
private val visaLibLoader: VisaLibLoader,
|
||||||
private val apiConfigsManager: ApiConfigsManager,
|
private val apiConfigsManager: ApiConfigsManager,
|
||||||
private val rainCryptoUtil: RainCryptoUtil,
|
private val rainCryptoUtil: RainCryptoUtil,
|
||||||
|
private val storage: TangemPayStorage,
|
||||||
) : CardDetailsRepository {
|
) : CardDetailsRepository {
|
||||||
|
|
||||||
override suspend fun getCardBalance(): Either<UniversalError, TangemPayCardBalance> {
|
override suspend fun getCardBalance(): Either<UniversalError, TangemPayCardBalance> {
|
||||||
|
|
@ -98,6 +100,18 @@ internal class DefaultCardDetailsRepository @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun isAddToWalletDone(): Either<UniversalError, Boolean> {
|
||||||
|
return requestHelper.runWithErrorLogs(TAG) {
|
||||||
|
storage.getAddToWalletDone(requestHelper.getCustomerWalletAddress())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun setAddToWalletAsDone(): Either<UniversalError, Unit> {
|
||||||
|
return requestHelper.runWithErrorLogs(TAG) {
|
||||||
|
storage.storeAddToWalletDone(requestHelper.getCustomerWalletAddress(), isDone = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun getPublicKeyBase64(): String {
|
private suspend fun getPublicKeyBase64(): String {
|
||||||
val env = apiConfigsManager.getEnvironmentConfig(ApiConfig.ID.TangemPay).environment
|
val env = apiConfigsManager.getEnvironmentConfig(ApiConfig.ID.TangemPay).environment
|
||||||
return when (env) {
|
return when (env) {
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,8 @@ interface CardDetailsRepository {
|
||||||
suspend fun revealCardDetails(): Either<UniversalError, TangemPayCardDetails>
|
suspend fun revealCardDetails(): Either<UniversalError, TangemPayCardDetails>
|
||||||
|
|
||||||
suspend fun setPin(pin: String): Either<UniversalError, SetPinResult>
|
suspend fun setPin(pin: String): Either<UniversalError, SetPinResult>
|
||||||
|
|
||||||
|
suspend fun isAddToWalletDone(): Either<UniversalError, Boolean>
|
||||||
|
|
||||||
|
suspend fun setAddToWalletAsDone(): Either<UniversalError, Unit>
|
||||||
}
|
}
|
||||||
|
|
@ -67,6 +67,10 @@ class DefaultTangemPayDetailsContainerComponent @AssistedInject constructor(
|
||||||
TangemPayDetailsInnerRoute.ChangePINSuccess -> TangemPayChangePinSuccessComponent(
|
TangemPayDetailsInnerRoute.ChangePINSuccess -> TangemPayChangePinSuccessComponent(
|
||||||
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
|
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
|
||||||
)
|
)
|
||||||
|
TangemPayDetailsInnerRoute.AddToWallet -> TangemPayAddToWalletComponent(
|
||||||
|
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
|
||||||
|
params = params,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onChildBack() {
|
private fun onChildBack() {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.tangempay.di
|
||||||
|
|
||||||
import com.tangem.core.decompose.di.ModelComponent
|
import com.tangem.core.decompose.di.ModelComponent
|
||||||
import com.tangem.core.decompose.model.Model
|
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.TangemPayCardDetailsBlockModel
|
||||||
import com.tangem.features.tangempay.model.TangemPayChangePinModel
|
import com.tangem.features.tangempay.model.TangemPayChangePinModel
|
||||||
import com.tangem.features.tangempay.model.TangemPayDetailsModel
|
import com.tangem.features.tangempay.model.TangemPayDetailsModel
|
||||||
|
|
@ -41,4 +42,9 @@ internal interface TangemPayModelModule {
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@ClassKey(TangemPayCardDetailsBlockModel::class)
|
@ClassKey(TangemPayCardDetailsBlockModel::class)
|
||||||
fun bindTangemPayCardDetailsBlockModel(model: TangemPayCardDetailsBlockModel): Model
|
fun bindTangemPayCardDetailsBlockModel(model: TangemPayCardDetailsBlockModel): Model
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ClassKey(TangemPayAddToWalletModel::class)
|
||||||
|
fun bindTangemPayAddToWalletModel(model: TangemPayAddToWalletModel): Model
|
||||||
}
|
}
|
||||||
|
|
@ -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<TangemPayAddToWalletStepItemUM>,
|
||||||
|
val showAddToWalletButton: Boolean,
|
||||||
|
val onBackClick: () -> Unit,
|
||||||
|
val onClickOpenWallet: () -> Unit,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal data class TangemPayAddToWalletStepItemUM(
|
||||||
|
val count: Int,
|
||||||
|
val text: TextReference,
|
||||||
|
)
|
||||||
|
|
@ -45,6 +45,7 @@ internal class TangemPayDetailsStateFactory(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
addToWalletBlockState = null,
|
||||||
isBalanceHidden = false,
|
isBalanceHidden = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -9,6 +9,7 @@ internal data class TangemPayDetailsUM(
|
||||||
val topBarConfig: TangemPayDetailsTopBarConfig,
|
val topBarConfig: TangemPayDetailsTopBarConfig,
|
||||||
val pullToRefreshConfig: PullToRefreshConfig,
|
val pullToRefreshConfig: PullToRefreshConfig,
|
||||||
val balanceBlockState: TangemPayDetailsBalanceBlockState,
|
val balanceBlockState: TangemPayDetailsBalanceBlockState,
|
||||||
|
val addToWalletBlockState: AddToWalletBlockState?,
|
||||||
val isBalanceHidden: Boolean,
|
val isBalanceHidden: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -41,4 +42,9 @@ internal sealed class TangemPayDetailsBalanceBlockState {
|
||||||
data class Error(
|
data class Error(
|
||||||
override val actionButtons: ImmutableList<ActionButtonConfig>,
|
override val actionButtons: ImmutableList<ActionButtonConfig>,
|
||||||
) : TangemPayDetailsBalanceBlockState()
|
) : TangemPayDetailsBalanceBlockState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal data class AddToWalletBlockState(
|
||||||
|
val onClick: () -> Unit,
|
||||||
|
val onClickClose: () -> Unit,
|
||||||
|
)
|
||||||
|
|
@ -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<TangemPayAddToWalletUM>
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,7 @@ import com.tangem.features.tangempay.entity.TangemPayDetailsStateFactory
|
||||||
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
|
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
|
||||||
import com.tangem.features.tangempay.model.listener.CardDetailsEvent
|
import com.tangem.features.tangempay.model.listener.CardDetailsEvent
|
||||||
import com.tangem.features.tangempay.model.listener.CardDetailsEventListener
|
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.DetailsBalanceTransformer
|
||||||
import com.tangem.features.tangempay.model.transformers.TangemPayDetailsRefreshTransformer
|
import com.tangem.features.tangempay.model.transformers.TangemPayDetailsRefreshTransformer
|
||||||
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
|
import com.tangem.features.tangempay.navigation.TangemPayDetailsInnerRoute
|
||||||
|
|
@ -63,10 +64,12 @@ internal class TangemPayDetailsModel @Inject constructor(
|
||||||
|
|
||||||
private val refreshStateJobHolder = JobHolder()
|
private val refreshStateJobHolder = JobHolder()
|
||||||
private val fetchBalanceJobHolder = JobHolder()
|
private val fetchBalanceJobHolder = JobHolder()
|
||||||
|
private val addToWalletBannerJobHolder = JobHolder()
|
||||||
|
|
||||||
val bottomSheetNavigation: SlotNavigation<TangemPayDetailsNavigation> = SlotNavigation()
|
val bottomSheetNavigation: SlotNavigation<TangemPayDetailsNavigation> = SlotNavigation()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
fetchAddToWalletBanner()
|
||||||
fetchBalance()
|
fetchBalance()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,6 +108,19 @@ internal class TangemPayDetailsModel @Inject constructor(
|
||||||
}.saveIn(fetchBalanceJobHolder)
|
}.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) {
|
private fun onRefreshSwipe(refreshState: ShowRefreshState) {
|
||||||
modelScope.launch {
|
modelScope.launch {
|
||||||
cardDetailsEventListener.send(CardDetailsEvent.Hide)
|
cardDetailsEventListener.send(CardDetailsEvent.Hide)
|
||||||
|
|
@ -114,6 +130,23 @@ internal class TangemPayDetailsModel @Inject constructor(
|
||||||
}.saveIn(refreshStateJobHolder)
|
}.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) {
|
override fun onTransactionClick(item: TangemPayTxHistoryItem) {
|
||||||
bottomSheetNavigation.activate(TangemPayDetailsNavigation.TransactionDetails(item))
|
bottomSheetNavigation.activate(TangemPayDetailsNavigation.TransactionDetails(item))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<TangemPayDetailsUM> {
|
||||||
|
|
||||||
|
override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM {
|
||||||
|
return prevState.copy(
|
||||||
|
addToWalletBlockState = if (isDone) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
AddToWalletBlockState(onClick = onClickBanner, onClickClose = onClickCloseBanner)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,4 +13,7 @@ internal sealed class TangemPayDetailsInnerRoute : Route {
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data object ChangePINSuccess : TangemPayDetailsInnerRoute()
|
data object ChangePINSuccess : TangemPayDetailsInnerRoute()
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data object AddToWallet : TangemPayDetailsInnerRoute()
|
||||||
}
|
}
|
||||||
|
|
@ -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({}, {}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
@ -90,10 +90,21 @@ internal fun TangemPayDetailsScreen(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
with(cardDetailsBlockComponent) {
|
if (state.addToWalletBlockState != null) {
|
||||||
item(TangemPayCardDetailsUM::class.java) {
|
item(
|
||||||
CardDetailsBlockContent(state = cardDetailsState)
|
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) }
|
with(txHistoryComponent) { txHistoryContent(listState = listState, state = txHistoryState) }
|
||||||
}
|
}
|
||||||
|
|
@ -300,12 +311,14 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<Ta
|
||||||
fiatBalance = "$1234.56",
|
fiatBalance = "$1234.56",
|
||||||
isBalanceFlickering = false,
|
isBalanceFlickering = false,
|
||||||
),
|
),
|
||||||
|
addToWalletBlockState = AddToWalletBlockState({}, {}),
|
||||||
isBalanceHidden = false,
|
isBalanceHidden = false,
|
||||||
),
|
),
|
||||||
TangemPayDetailsUM(
|
TangemPayDetailsUM(
|
||||||
topBarConfig = TangemPayDetailsTopBarConfig(onBackClick = {}, items = null),
|
topBarConfig = TangemPayDetailsTopBarConfig(onBackClick = {}, items = null),
|
||||||
pullToRefreshConfig = PullToRefreshConfig(isRefreshing = false, onRefresh = {}),
|
pullToRefreshConfig = PullToRefreshConfig(isRefreshing = false, onRefresh = {}),
|
||||||
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(actionButtons = persistentListOf()),
|
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(actionButtons = persistentListOf()),
|
||||||
|
addToWalletBlockState = AddToWalletBlockState({}, {}),
|
||||||
isBalanceHidden = false,
|
isBalanceHidden = false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.tangem.features.tangempay.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val TAG = "GoogleWalletUtil"
|
||||||
|
private const val WALLET_PACKAGE_NAME = "com.google.android.apps.walletnfcrel"
|
||||||
|
|
||||||
|
internal class GoogleWalletUtil @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
) {
|
||||||
|
private var walletIntent: Intent? = null
|
||||||
|
|
||||||
|
fun isWalletAvailable(): Boolean = getWalletIntent() != null
|
||||||
|
|
||||||
|
fun openWallet() {
|
||||||
|
val intent = getWalletIntent()
|
||||||
|
if (intent != null) {
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getWalletIntent(): Intent? {
|
||||||
|
return if (walletIntent != null) {
|
||||||
|
walletIntent
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
context.packageManager.getLaunchIntentForPackage(WALLET_PACKAGE_NAME)
|
||||||
|
?.apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
|
||||||
|
.also { walletIntent = it }
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
Timber.tag(TAG).e(exception)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="48dp"
|
||||||
|
android:height="48dp"
|
||||||
|
android:viewportWidth="48"
|
||||||
|
android:viewportHeight="48">
|
||||||
|
<path
|
||||||
|
android:pathData="M24,0L24,0A24,24 0,0 1,48 24L48,24A24,24 0,0 1,24 48L24,48A24,24 0,0 1,0 24L0,24A24,24 0,0 1,24 0z"
|
||||||
|
android:fillColor="#393C45"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M34.092,21.69V18.629C34.092,16.861 32.652,15.42 30.884,15.42H17.116C15.348,15.436 13.907,16.877 13.907,18.629V21.69C13.907,22.001 14.153,22.247 14.464,22.247H33.536C33.847,22.247 34.092,22.001 34.092,21.69Z"
|
||||||
|
android:fillColor="#34A853"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M34.092,24.375V21.33C34.092,19.562 32.652,18.121 30.884,18.121H17.116C15.348,18.121 13.907,19.562 13.907,21.33V24.391C13.907,24.702 14.153,24.948 14.464,24.948H33.536C33.847,24.931 34.092,24.686 34.092,24.375Z"
|
||||||
|
android:fillColor="#FBBC04"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M34.092,27.077V24.015C34.092,22.247 32.652,20.807 30.884,20.807H17.116C15.348,20.807 13.907,22.247 13.907,24.015V27.077C13.907,27.388 14.153,27.633 14.464,27.633H33.536C33.847,27.617 34.092,27.371 34.092,27.077Z"
|
||||||
|
android:fillColor="#EA4335"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M26.742,25.603L13.907,22.623V29.368C13.907,31.136 15.348,32.576 17.116,32.576H30.884C32.652,32.576 34.092,31.136 34.092,29.368V22.492L31.031,24.719C29.787,25.619 28.232,25.946 26.742,25.603Z"
|
||||||
|
android:fillColor="#4285F4"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
</vector>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue