Updated on 2026-08-14
This commit is contained in:
commit
9860ecc4cb
36 changed files with 230 additions and 61 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -10,6 +10,7 @@
|
||||||
**/build/kotlin/**
|
**/build/kotlin/**
|
||||||
**/build/libs/**
|
**/build/libs/**
|
||||||
**/build/outputs/**
|
**/build/outputs/**
|
||||||
|
**/build/reports/**
|
||||||
**/build/tmp/**
|
**/build/tmp/**
|
||||||
|
|
||||||
# Local configuration file (sdk path, etc)
|
# Local configuration file (sdk path, etc)
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit ad46a043f9b98b4f4577f906920532cb370c15d4
|
Subproject commit 5cf863d2ad68d89a111520aca3504fe9db234c82
|
||||||
|
|
@ -143,10 +143,8 @@ internal object TransactionDomainModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideIsUtxoConsolidationAvailableUseCase(
|
fun provideIsSelfSendAvailableUseCase(walletManagersFacade: WalletManagersFacade): IsSelfSendAvailableUseCase {
|
||||||
walletManagersFacade: WalletManagersFacade,
|
return IsSelfSendAvailableUseCase(walletManagersFacade)
|
||||||
): IsUtxoConsolidationAvailableUseCase {
|
|
||||||
return IsUtxoConsolidationAvailableUseCase(walletManagersFacade)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "NEW_ONRAMP_MAIN_ENABLED",
|
"name": "NEW_ONRAMP_MAIN_ENABLED",
|
||||||
"version": "5.29.0"
|
"version": "undefined"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ACCOUNTS_FEATURE_ENABLED",
|
"name": "ACCOUNTS_FEATURE_ENABLED",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class PromotionInfoResponse(
|
data class PromoBannerResponse(
|
||||||
@Json(name = "name") val name: String,
|
@Json(name = "name") val name: String,
|
||||||
@Json(name = "all") val bannerState: BannerState?,
|
@Json(name = "all") val bannerState: BannerState?,
|
||||||
) {
|
) {
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.tangem.datasource.api.tangemTech
|
package com.tangem.datasource.api.tangemTech
|
||||||
|
|
||||||
import com.tangem.datasource.api.common.response.ApiResponse
|
import com.tangem.datasource.api.common.response.ApiResponse
|
||||||
|
import com.tangem.datasource.api.promotion.models.PromoBannerResponse
|
||||||
import com.tangem.datasource.api.promotion.models.StoryContentResponse
|
import com.tangem.datasource.api.promotion.models.StoryContentResponse
|
||||||
import com.tangem.datasource.api.tangemTech.models.*
|
import com.tangem.datasource.api.tangemTech.models.*
|
||||||
import com.tangem.datasource.api.tangemTech.models.account.GetWalletAccountsResponse
|
import com.tangem.datasource.api.tangemTech.models.account.GetWalletAccountsResponse
|
||||||
|
|
@ -163,4 +164,12 @@ interface TangemTechApi {
|
||||||
@Header("If-None-Match") eTag: String? = null,
|
@Header("If-None-Match") eTag: String? = null,
|
||||||
): ApiResponse<GetWalletArchivedAccountsResponse>
|
): ApiResponse<GetWalletArchivedAccountsResponse>
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
// region promo banners
|
||||||
|
@GET("/v1/promotion")
|
||||||
|
suspend fun getPromoBanner(
|
||||||
|
@Query("programName") name: String,
|
||||||
|
@Header("Cache-Control") cacheControl: String = "max-age=600",
|
||||||
|
): ApiResponse<PromoBannerResponse>
|
||||||
|
// endregion
|
||||||
}
|
}
|
||||||
|
|
@ -11,6 +11,10 @@ import com.tangem.datasource.local.onramp.paymentmethods.DefaultOnrampPaymentMet
|
||||||
import com.tangem.datasource.local.onramp.paymentmethods.OnrampPaymentMethodsStore
|
import com.tangem.datasource.local.onramp.paymentmethods.OnrampPaymentMethodsStore
|
||||||
import com.tangem.datasource.local.onramp.quotes.DefaultOnrampQuotesStore
|
import com.tangem.datasource.local.onramp.quotes.DefaultOnrampQuotesStore
|
||||||
import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
|
import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
|
||||||
|
import com.tangem.datasource.local.onramp.sepa.DefaultOnrampCurrentCountryByIPStore
|
||||||
|
import com.tangem.datasource.local.onramp.sepa.DefaultOnrampSepaAvailabilityStore
|
||||||
|
import com.tangem.datasource.local.onramp.sepa.OnrampCurrentCountryByIPStore
|
||||||
|
import com.tangem.datasource.local.onramp.sepa.OnrampSepaAvailabilityStore
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
|
|
@ -50,4 +54,16 @@ internal object OnrampStoreModule {
|
||||||
fun provideOnrampCurrencies(): OnrampCurrenciesStore {
|
fun provideOnrampCurrencies(): OnrampCurrenciesStore {
|
||||||
return DefaultOnrampCurrenciesStore(dataStore = RuntimeDataStore())
|
return DefaultOnrampCurrenciesStore(dataStore = RuntimeDataStore())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideOnrampSepaAvailableStore(): OnrampSepaAvailabilityStore {
|
||||||
|
return DefaultOnrampSepaAvailabilityStore(dataStore = RuntimeDataStore())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideOnrampCurrentCountryByIPStore(): OnrampCurrentCountryByIPStore {
|
||||||
|
return DefaultOnrampCurrentCountryByIPStore(dataStore = RuntimeDataStore())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -44,6 +44,7 @@ internal object BlockchainSDKConfigConverter : Converter<EnvironmentConfigModel,
|
||||||
koinosProApiKey = value.koinosProApiKey,
|
koinosProApiKey = value.koinosProApiKey,
|
||||||
alephiumApiKey = value.alephiumTangemApiKey,
|
alephiumApiKey = value.alephiumTangemApiKey,
|
||||||
moralisApiKey = value.moralisApiKey,
|
moralisApiKey = value.moralisApiKey,
|
||||||
|
etherscanApiKey = value.etherScanApiKey,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ class EnvironmentConfigModel(
|
||||||
@Json(name = "tangemApiKey") val tangemApiKey: String?,
|
@Json(name = "tangemApiKey") val tangemApiKey: String?,
|
||||||
@Json(name = "tangemApiKeyDev") val tangemApiKeyDev: String?,
|
@Json(name = "tangemApiKeyDev") val tangemApiKeyDev: String?,
|
||||||
@Json(name = "tangemApiKeyStage") val tangemApiKeyStage: String?,
|
@Json(name = "tangemApiKeyStage") val tangemApiKeyStage: String?,
|
||||||
|
@Json(name = "etherscanApiKey") val etherScanApiKey: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.tangem.datasource.local.onramp.sepa
|
||||||
|
|
||||||
|
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||||
|
import com.tangem.datasource.local.datastore.core.StringKeyDataStoreDecorator
|
||||||
|
import com.tangem.domain.onramp.model.OnrampCountry
|
||||||
|
|
||||||
|
internal class DefaultOnrampCurrentCountryByIPStore(
|
||||||
|
val dataStore: StringKeyDataStore<OnrampCountry>,
|
||||||
|
) : OnrampCurrentCountryByIPStore, StringKeyDataStoreDecorator<Unit, OnrampCountry>(
|
||||||
|
wrappedDataStore = dataStore,
|
||||||
|
) {
|
||||||
|
|
||||||
|
override suspend fun getSyncOrNull(): OnrampCountry? {
|
||||||
|
return getSyncOrNull(Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun store(value: OnrampCountry) {
|
||||||
|
return store(Unit, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun provideStringKey(key: Unit) = "KEY"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.tangem.datasource.local.onramp.sepa
|
||||||
|
|
||||||
|
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||||
|
import com.tangem.datasource.local.datastore.core.StringKeyDataStoreDecorator
|
||||||
|
|
||||||
|
internal class DefaultOnrampSepaAvailabilityStore(
|
||||||
|
val dataStore: StringKeyDataStore<Boolean>,
|
||||||
|
) : OnrampSepaAvailabilityStore, StringKeyDataStoreDecorator<OnrampSepaAvailabilityStoreKey, Boolean>(
|
||||||
|
wrappedDataStore = dataStore,
|
||||||
|
) {
|
||||||
|
override fun provideStringKey(key: OnrampSepaAvailabilityStoreKey) = with(key) {
|
||||||
|
buildString {
|
||||||
|
append(userWallet.walletId.toString())
|
||||||
|
append("_")
|
||||||
|
append(country.code)
|
||||||
|
append("_")
|
||||||
|
append(cryptoCurrency.id.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.tangem.datasource.local.onramp.sepa
|
||||||
|
|
||||||
|
import com.tangem.domain.onramp.model.OnrampCountry
|
||||||
|
|
||||||
|
interface OnrampCurrentCountryByIPStore {
|
||||||
|
suspend fun getSyncOrNull(): OnrampCountry?
|
||||||
|
suspend fun store(value: OnrampCountry)
|
||||||
|
suspend fun clear()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.tangem.datasource.local.onramp.sepa
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
interface OnrampSepaAvailabilityStore {
|
||||||
|
suspend fun getSyncOrNull(key: OnrampSepaAvailabilityStoreKey): Boolean?
|
||||||
|
fun get(key: OnrampSepaAvailabilityStoreKey): Flow<Boolean>
|
||||||
|
suspend fun store(key: OnrampSepaAvailabilityStoreKey, value: Boolean)
|
||||||
|
suspend fun clear()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.tangem.datasource.local.onramp.sepa
|
||||||
|
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.onramp.model.OnrampCountry
|
||||||
|
|
||||||
|
data class OnrampSepaAvailabilityStoreKey(
|
||||||
|
val userWallet: UserWallet,
|
||||||
|
val country: OnrampCountry,
|
||||||
|
val cryptoCurrency: CryptoCurrency,
|
||||||
|
)
|
||||||
|
|
@ -27,10 +27,12 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import com.tangem.core.ui.R
|
import com.tangem.core.ui.R
|
||||||
import com.tangem.core.ui.components.*
|
import com.tangem.core.ui.components.*
|
||||||
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
|
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
|
import com.tangem.core.ui.extensions.resolveAnnotatedReference
|
||||||
import com.tangem.core.ui.extensions.resolveReference
|
import com.tangem.core.ui.extensions.resolveReference
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
|
@ -216,7 +218,7 @@ internal fun TextsBlock(
|
||||||
SpacerH(height = TangemTheme.dimens.spacing2)
|
SpacerH(height = TangemTheme.dimens.spacing2)
|
||||||
}
|
}
|
||||||
|
|
||||||
val subtitleText = subtitle.resolveReference()
|
val subtitleText = subtitle.resolveAnnotatedReference()
|
||||||
if (subtitleText.isNotEmpty()) {
|
if (subtitleText.isNotEmpty()) {
|
||||||
Text(
|
Text(
|
||||||
text = subtitleText,
|
text = subtitleText,
|
||||||
|
|
@ -459,5 +461,15 @@ private class NotificationConfigProvider : CollectionPreviewParameterProvider<No
|
||||||
subtitle = resourceReference(id = R.string.information_generated_with_ai),
|
subtitle = resourceReference(id = R.string.information_generated_with_ai),
|
||||||
iconResId = R.drawable.ic_magic_28,
|
iconResId = R.drawable.ic_magic_28,
|
||||||
),
|
),
|
||||||
|
NotificationConfig(
|
||||||
|
title = resourceReference(R.string.notification_sepa_title),
|
||||||
|
subtitle = resourceReference(R.string.notification_sepa_text),
|
||||||
|
iconResId = R.drawable.img_notification_sepa,
|
||||||
|
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
||||||
|
text = resourceReference(R.string.notification_sepa_button),
|
||||||
|
onClick = { },
|
||||||
|
),
|
||||||
|
iconSize = 54.dp,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -30,6 +30,9 @@ import com.tangem.datasource.local.onramp.currencies.OnrampCurrenciesStore
|
||||||
import com.tangem.datasource.local.onramp.pairs.OnrampPairsStore
|
import com.tangem.datasource.local.onramp.pairs.OnrampPairsStore
|
||||||
import com.tangem.datasource.local.onramp.paymentmethods.OnrampPaymentMethodsStore
|
import com.tangem.datasource.local.onramp.paymentmethods.OnrampPaymentMethodsStore
|
||||||
import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
|
import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
|
||||||
|
import com.tangem.datasource.local.onramp.sepa.OnrampCurrentCountryByIPStore
|
||||||
|
import com.tangem.datasource.local.onramp.sepa.OnrampSepaAvailabilityStore
|
||||||
|
import com.tangem.datasource.local.onramp.sepa.OnrampSepaAvailabilityStoreKey
|
||||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||||
import com.tangem.datasource.local.preferences.utils.getObject
|
import com.tangem.datasource.local.preferences.utils.getObject
|
||||||
|
|
@ -64,6 +67,8 @@ internal class DefaultOnrampRepository(
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
private val appPreferencesStore: AppPreferencesStore,
|
private val appPreferencesStore: AppPreferencesStore,
|
||||||
private val paymentMethodsStore: OnrampPaymentMethodsStore,
|
private val paymentMethodsStore: OnrampPaymentMethodsStore,
|
||||||
|
private val onrampSepaAvailabilityStore: OnrampSepaAvailabilityStore,
|
||||||
|
private val onrampCurrentCountryByIPStore: OnrampCurrentCountryByIPStore,
|
||||||
private val pairsStore: OnrampPairsStore,
|
private val pairsStore: OnrampPairsStore,
|
||||||
private val quotesStore: OnrampQuotesStore,
|
private val quotesStore: OnrampQuotesStore,
|
||||||
private val countriesStore: OnrampCountriesStore,
|
private val countriesStore: OnrampCountriesStore,
|
||||||
|
|
@ -123,17 +128,30 @@ internal class DefaultOnrampRepository(
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getCountryByIp(userWallet: UserWallet): OnrampCountry = withContext(dispatchers.io) {
|
override suspend fun getCountryByIp(userWallet: UserWallet, fromCache: Boolean): OnrampCountry =
|
||||||
onrampApi.getCountryByIp(
|
withContext(dispatchers.io) {
|
||||||
userWalletId = userWallet.walletId.stringValue,
|
if (fromCache) {
|
||||||
refCode = ExpressUtils.getRefCode(
|
val country = onrampCurrentCountryByIPStore.getSyncOrNull()
|
||||||
userWallet = userWallet,
|
|
||||||
appPreferencesStore = appPreferencesStore,
|
if (country != null) {
|
||||||
),
|
return@withContext country
|
||||||
)
|
}
|
||||||
.getOrThrow()
|
}
|
||||||
.let(countryConverter::convert)
|
|
||||||
}
|
val country = onrampApi.getCountryByIp(
|
||||||
|
userWalletId = userWallet.walletId.stringValue,
|
||||||
|
refCode = ExpressUtils.getRefCode(
|
||||||
|
userWallet = userWallet,
|
||||||
|
appPreferencesStore = appPreferencesStore,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.getOrThrow()
|
||||||
|
.let(countryConverter::convert)
|
||||||
|
|
||||||
|
onrampCurrentCountryByIPStore.store(country)
|
||||||
|
|
||||||
|
country
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getStatus(userWallet: UserWallet, txId: String): OnrampStatus = withContext(dispatchers.io) {
|
override suspend fun getStatus(userWallet: UserWallet, txId: String): OnrampStatus = withContext(dispatchers.io) {
|
||||||
onrampApi.getStatus(
|
onrampApi.getStatus(
|
||||||
|
|
@ -263,11 +281,22 @@ internal class DefaultOnrampRepository(
|
||||||
|
|
||||||
override suspend fun hasSepaMethod(
|
override suspend fun hasSepaMethod(
|
||||||
userWallet: UserWallet,
|
userWallet: UserWallet,
|
||||||
currency: OnrampCurrency,
|
|
||||||
country: OnrampCountry,
|
country: OnrampCountry,
|
||||||
cryptoCurrency: CryptoCurrency,
|
cryptoCurrency: CryptoCurrency,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return withContext(dispatchers.io) {
|
return withContext(dispatchers.io) {
|
||||||
|
val key = OnrampSepaAvailabilityStoreKey(
|
||||||
|
userWallet = userWallet,
|
||||||
|
country = country,
|
||||||
|
cryptoCurrency = cryptoCurrency,
|
||||||
|
)
|
||||||
|
|
||||||
|
val cachedValue = onrampSepaAvailabilityStore.getSyncOrNull(key)
|
||||||
|
|
||||||
|
if (cachedValue != null) {
|
||||||
|
return@withContext cachedValue
|
||||||
|
}
|
||||||
|
|
||||||
val onrampPairs =
|
val onrampPairs =
|
||||||
safeApiCall(
|
safeApiCall(
|
||||||
call = {
|
call = {
|
||||||
|
|
@ -300,6 +329,8 @@ internal class DefaultOnrampRepository(
|
||||||
.flatMap { it.paymentMethods }
|
.flatMap { it.paymentMethods }
|
||||||
.any { it == SEPA_METHOD_ID }
|
.any { it == SEPA_METHOD_ID }
|
||||||
|
|
||||||
|
onrampSepaAvailabilityStore.store(key, hasSepaMethod)
|
||||||
|
|
||||||
hasSepaMethod
|
hasSepaMethod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ import com.tangem.datasource.local.onramp.currencies.OnrampCurrenciesStore
|
||||||
import com.tangem.datasource.local.onramp.pairs.OnrampPairsStore
|
import com.tangem.datasource.local.onramp.pairs.OnrampPairsStore
|
||||||
import com.tangem.datasource.local.onramp.paymentmethods.OnrampPaymentMethodsStore
|
import com.tangem.datasource.local.onramp.paymentmethods.OnrampPaymentMethodsStore
|
||||||
import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
|
import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
|
||||||
|
import com.tangem.datasource.local.onramp.sepa.OnrampCurrentCountryByIPStore
|
||||||
|
import com.tangem.datasource.local.onramp.sepa.OnrampSepaAvailabilityStore
|
||||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||||
import com.tangem.datasource.local.token.UserTokensResponseStore
|
import com.tangem.datasource.local.token.UserTokensResponseStore
|
||||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||||
|
|
@ -52,6 +54,8 @@ internal object OnrampDataModule {
|
||||||
currenciesStore: OnrampCurrenciesStore,
|
currenciesStore: OnrampCurrenciesStore,
|
||||||
walletManagersFacade: WalletManagersFacade,
|
walletManagersFacade: WalletManagersFacade,
|
||||||
dataSignatureVerifier: DataSignatureVerifier,
|
dataSignatureVerifier: DataSignatureVerifier,
|
||||||
|
onrampSepaAvailabilityStore: OnrampSepaAvailabilityStore,
|
||||||
|
onrampCurrentCountryByIPStore: OnrampCurrentCountryByIPStore,
|
||||||
@NetworkMoshi moshi: Moshi,
|
@NetworkMoshi moshi: Moshi,
|
||||||
): OnrampRepository {
|
): OnrampRepository {
|
||||||
return DefaultOnrampRepository(
|
return DefaultOnrampRepository(
|
||||||
|
|
@ -60,6 +64,8 @@ internal object OnrampDataModule {
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
appPreferencesStore = appPreferencesStore,
|
appPreferencesStore = appPreferencesStore,
|
||||||
paymentMethodsStore = paymentMethodsStore,
|
paymentMethodsStore = paymentMethodsStore,
|
||||||
|
onrampSepaAvailabilityStore = onrampSepaAvailabilityStore,
|
||||||
|
onrampCurrentCountryByIPStore = onrampCurrentCountryByIPStore,
|
||||||
pairsStore = pairsStore,
|
pairsStore = pairsStore,
|
||||||
quotesStore = quotesStore,
|
quotesStore = quotesStore,
|
||||||
currenciesStore = currenciesStore,
|
currenciesStore = currenciesStore,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.tangem.data.promo
|
package com.tangem.data.promo
|
||||||
|
|
||||||
|
import com.tangem.data.promo.converters.PromoBannerConverter
|
||||||
import com.tangem.data.promo.converters.StoryContentResponseConverter
|
import com.tangem.data.promo.converters.StoryContentResponseConverter
|
||||||
import com.tangem.datasource.api.common.response.getOrThrow
|
import com.tangem.datasource.api.common.response.getOrThrow
|
||||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||||
|
|
@ -12,6 +13,7 @@ import com.tangem.datasource.local.preferences.utils.store
|
||||||
import com.tangem.datasource.local.promo.PromoStoriesStore
|
import com.tangem.datasource.local.promo.PromoStoriesStore
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.promo.PromoRepository
|
import com.tangem.domain.promo.PromoRepository
|
||||||
|
import com.tangem.domain.promo.models.PromoBanner
|
||||||
import com.tangem.domain.promo.models.PromoId
|
import com.tangem.domain.promo.models.PromoId
|
||||||
import com.tangem.domain.promo.models.StoryContent
|
import com.tangem.domain.promo.models.StoryContent
|
||||||
import com.tangem.feature.referral.domain.ReferralRepository
|
import com.tangem.feature.referral.domain.ReferralRepository
|
||||||
|
|
@ -22,6 +24,7 @@ import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.coroutines.withTimeoutOrNull
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
|
import com.tangem.utils.coroutines.runCatching
|
||||||
|
|
||||||
internal class DefaultPromoRepository(
|
internal class DefaultPromoRepository(
|
||||||
private val tangemApi: TangemTechApi,
|
private val tangemApi: TangemTechApi,
|
||||||
|
|
@ -32,6 +35,7 @@ internal class DefaultPromoRepository(
|
||||||
) : PromoRepository {
|
) : PromoRepository {
|
||||||
|
|
||||||
private val storyContentConverter = StoryContentResponseConverter()
|
private val storyContentConverter = StoryContentResponseConverter()
|
||||||
|
private val promoBannerConverter = PromoBannerConverter()
|
||||||
|
|
||||||
override fun isReadyToShowWalletPromo(userWalletId: UserWalletId, promoId: PromoId): Flow<Boolean> {
|
override fun isReadyToShowWalletPromo(userWalletId: UserWalletId, promoId: PromoId): Flow<Boolean> {
|
||||||
return appPreferencesStore.get(
|
return appPreferencesStore.get(
|
||||||
|
|
@ -42,7 +46,11 @@ internal class DefaultPromoRepository(
|
||||||
PromoId.Referral -> runCatching {
|
PromoId.Referral -> runCatching {
|
||||||
!referralRepository.isReferralParticipant(userWalletId) && shouldShow
|
!referralRepository.isReferralParticipant(userWalletId) && shouldShow
|
||||||
}.getOrDefault(false)
|
}.getOrDefault(false)
|
||||||
PromoId.Sepa -> shouldShow
|
PromoId.Sepa -> {
|
||||||
|
val isActive = getSepaPromoBanner()?.isActive ?: false
|
||||||
|
|
||||||
|
isActive && shouldShow
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +126,16 @@ internal class DefaultPromoRepository(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun getSepaPromoBanner(): PromoBanner? {
|
||||||
|
return runCatching(dispatchers.io) {
|
||||||
|
promoBannerConverter.convert(
|
||||||
|
tangemApi.getPromoBanner(SEPA_NAME).getOrThrow(),
|
||||||
|
)
|
||||||
|
}.getOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
const val SEPA_NAME = "sepa"
|
||||||
const val STORIES_LOAD_DELAY = 1000L
|
const val STORIES_LOAD_DELAY = 1000L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
package com.tangem.data.promo.converters
|
package com.tangem.data.promo.converters
|
||||||
|
|
||||||
import com.tangem.datasource.api.promotion.models.PromotionInfoResponse
|
import com.tangem.datasource.api.promotion.models.PromoBannerResponse
|
||||||
import com.tangem.domain.promo.models.PromoBanner
|
import com.tangem.domain.promo.models.PromoBanner
|
||||||
import com.tangem.utils.converter.Converter
|
import com.tangem.utils.converter.Converter
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
|
||||||
class PromoResponseConverter : Converter<PromotionInfoResponse, PromoBanner?> {
|
class PromoBannerConverter : Converter<PromoBannerResponse, PromoBanner?> {
|
||||||
|
|
||||||
override fun convert(value: PromotionInfoResponse): PromoBanner? {
|
override fun convert(value: PromoBannerResponse): PromoBanner? {
|
||||||
val bannerState = value.bannerState ?: return null
|
val bannerState = value.bannerState ?: return null
|
||||||
return PromoBanner(
|
return PromoBanner(
|
||||||
name = value.name,
|
name = value.name,
|
||||||
|
|
@ -650,7 +650,7 @@ internal class DefaultWalletManagersFacade @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun checkUtxoConsolidationAvailability(userWalletId: UserWalletId, network: Network): Boolean {
|
override suspend fun checkSelfSendAvailability(userWalletId: UserWalletId, network: Network): Boolean {
|
||||||
val blockchain = network.toBlockchain()
|
val blockchain = network.toBlockchain()
|
||||||
val walletManager = getOrCreateWalletManager(
|
val walletManager = getOrCreateWalletManager(
|
||||||
userWalletId = userWalletId,
|
userWalletId = userWalletId,
|
||||||
|
|
@ -658,7 +658,7 @@ internal class DefaultWalletManagersFacade @Inject constructor(
|
||||||
derivationPath = network.derivationPath.value,
|
derivationPath = network.derivationPath.value,
|
||||||
) ?: return false
|
) ?: return false
|
||||||
|
|
||||||
return (walletManager as? UtxoBlockchainManager)?.allowConsolidation == true
|
return walletManager.isSelfSendAvailable
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getNFTCollections(userWalletId: UserWalletId, network: Network): List<NFTCollection> {
|
override suspend fun getNFTCollections(userWalletId: UserWalletId, network: Network): List<NFTCollection> {
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ internal class DefaultYieldSupplyTransactionRepository(
|
||||||
walletManager = walletManager,
|
walletManager = walletManager,
|
||||||
cryptoCurrency = cryptoCurrency,
|
cryptoCurrency = cryptoCurrency,
|
||||||
callData = callData,
|
callData = callData,
|
||||||
destinationAddress = walletManager.getYieldContract(),
|
destinationAddress = walletManager.getYieldModuleAddress(),
|
||||||
amount = BigDecimal.ZERO.convertToSdkAmount(cryptoCurrencyStatus),
|
amount = BigDecimal.ZERO.convertToSdkAmount(cryptoCurrencyStatus),
|
||||||
fee = fee,
|
fee = fee,
|
||||||
)
|
)
|
||||||
|
|
@ -175,7 +175,7 @@ internal class DefaultYieldSupplyTransactionRepository(
|
||||||
blockchain = cryptoCurrency.network.toBlockchain(),
|
blockchain = cryptoCurrency.network.toBlockchain(),
|
||||||
derivationPath = cryptoCurrency.network.derivationPath.value,
|
derivationPath = cryptoCurrency.network.derivationPath.value,
|
||||||
) ?: error("Wallet manager not found")
|
) ?: error("Wallet manager not found")
|
||||||
walletManager.calculateYieldContract()
|
walletManager.calculateYieldModuleAddress()
|
||||||
}.onFailure(Timber::e).getOrNull()
|
}.onFailure(Timber::e).getOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,7 +188,7 @@ internal class DefaultYieldSupplyTransactionRepository(
|
||||||
blockchain = cryptoCurrency.network.toBlockchain(),
|
blockchain = cryptoCurrency.network.toBlockchain(),
|
||||||
derivationPath = cryptoCurrency.network.derivationPath.value,
|
derivationPath = cryptoCurrency.network.derivationPath.value,
|
||||||
) ?: error("Wallet manager not found")
|
) ?: error("Wallet manager not found")
|
||||||
walletManager.getYieldContract()
|
walletManager.getYieldModuleAddress()
|
||||||
}.onFailure(Timber::e).getOrNull()
|
}.onFailure(Timber::e).getOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,12 @@ class GetOnrampCountryUseCase(
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun invokeSync(userWallet: UserWallet): Either<OnrampError, OnrampCountry> {
|
suspend fun invokeSync(userWallet: UserWallet): Either<OnrampError, OnrampCountry> {
|
||||||
return Either.catch { repository.getDefaultCountrySync() ?: repository.getCountryByIp(userWallet) }
|
return Either.catch {
|
||||||
|
repository.getDefaultCountrySync() ?: repository.getCountryByIp(
|
||||||
|
userWallet = userWallet,
|
||||||
|
fromCache = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
.mapLeft(errorResolver::resolve)
|
.mapLeft(errorResolver::resolve)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,7 +6,6 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.onramp.model.OnrampCountry
|
import com.tangem.domain.onramp.model.OnrampCountry
|
||||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
|
||||||
|
|
||||||
class OnrampSepaAvailableUseCase(
|
class OnrampSepaAvailableUseCase(
|
||||||
private val repository: OnrampRepository,
|
private val repository: OnrampRepository,
|
||||||
|
|
@ -14,7 +13,6 @@ class OnrampSepaAvailableUseCase(
|
||||||
|
|
||||||
suspend operator fun invoke(
|
suspend operator fun invoke(
|
||||||
userWallet: UserWallet,
|
userWallet: UserWallet,
|
||||||
currency: OnrampCurrency,
|
|
||||||
country: OnrampCountry,
|
country: OnrampCountry,
|
||||||
cryptoCurrency: CryptoCurrency,
|
cryptoCurrency: CryptoCurrency,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
|
|
@ -25,7 +23,6 @@ class OnrampSepaAvailableUseCase(
|
||||||
return Either.catch {
|
return Either.catch {
|
||||||
repository.hasSepaMethod(
|
repository.hasSepaMethod(
|
||||||
userWallet = userWallet,
|
userWallet = userWallet,
|
||||||
currency = currency,
|
|
||||||
country = country,
|
country = country,
|
||||||
cryptoCurrency = cryptoCurrency,
|
cryptoCurrency = cryptoCurrency,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,9 @@ interface OnrampRepository {
|
||||||
fun getCurrencies(): Flow<List<OnrampCurrency>>
|
fun getCurrencies(): Flow<List<OnrampCurrency>>
|
||||||
fun getCountries(): Flow<List<OnrampCountry>>
|
fun getCountries(): Flow<List<OnrampCountry>>
|
||||||
suspend fun getCountriesSync(): List<OnrampCountry>?
|
suspend fun getCountriesSync(): List<OnrampCountry>?
|
||||||
suspend fun getCountryByIp(userWallet: UserWallet): OnrampCountry
|
suspend fun getCountryByIp(userWallet: UserWallet, fromCache: Boolean = false): OnrampCountry
|
||||||
suspend fun getStatus(userWallet: UserWallet, txId: String): OnrampStatus
|
suspend fun getStatus(userWallet: UserWallet, txId: String): OnrampStatus
|
||||||
suspend fun hasSepaMethod(
|
suspend fun hasSepaMethod(userWallet: UserWallet, country: OnrampCountry, cryptoCurrency: CryptoCurrency): Boolean
|
||||||
userWallet: UserWallet,
|
|
||||||
currency: OnrampCurrency,
|
|
||||||
country: OnrampCountry,
|
|
||||||
cryptoCurrency: CryptoCurrency,
|
|
||||||
): Boolean
|
|
||||||
suspend fun fetchCurrencies(userWallet: UserWallet)
|
suspend fun fetchCurrencies(userWallet: UserWallet)
|
||||||
suspend fun fetchCountries(userWallet: UserWallet): List<OnrampCountry>
|
suspend fun fetchCountries(userWallet: UserWallet): List<OnrampCountry>
|
||||||
suspend fun fetchPaymentMethodsIfAbsent(userWallet: UserWallet)
|
suspend fun fetchPaymentMethodsIfAbsent(userWallet: UserWallet)
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,11 @@ sealed class StakingAnalyticsEvent(
|
||||||
data object TransactionError : StakingAnalyticsEvent(
|
data object TransactionError : StakingAnalyticsEvent(
|
||||||
event = "Error - Transaction Rejected",
|
event = "Error - Transaction Rejected",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class UnitializedAddress(val token: String) : StakingAnalyticsEvent(
|
||||||
|
event = "Notice - Uninitialized Address",
|
||||||
|
params = mapOf(AnalyticsParam.TOKEN_PARAM to token),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class StakeScreenSource {
|
enum class StakeScreenSource {
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,14 @@ import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets UTXO consolidation availability
|
* Gets self send availability
|
||||||
*/
|
*/
|
||||||
class IsUtxoConsolidationAvailableUseCase(
|
class IsSelfSendAvailableUseCase(
|
||||||
private val walletManagersFacade: WalletManagersFacade,
|
private val walletManagersFacade: WalletManagersFacade,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun invokeSync(userWalletId: UserWalletId, network: Network) =
|
suspend fun invokeSync(userWalletId: UserWalletId, network: Network) =
|
||||||
walletManagersFacade.checkUtxoConsolidationAvailability(
|
walletManagersFacade.checkSelfSendAvailability(
|
||||||
userWalletId = userWalletId,
|
userWalletId = userWalletId,
|
||||||
network = network,
|
network = network,
|
||||||
)
|
)
|
||||||
|
|
@ -56,12 +56,11 @@ class ValidateWalletAddressUseCase(
|
||||||
isCurrentAddress: (String) -> Boolean,
|
isCurrentAddress: (String) -> Boolean,
|
||||||
): AddressValidationResult {
|
): AddressValidationResult {
|
||||||
val decodedXAddress = BlockchainUtils.decodeRippleXAddress(address, network.rawId)
|
val decodedXAddress = BlockchainUtils.decodeRippleXAddress(address, network.rawId)
|
||||||
val isUtxoConsolidationAvailable =
|
val isSelfSendAvailable = walletManagersFacade.checkSelfSendAvailability(userWalletId, network)
|
||||||
walletManagersFacade.checkUtxoConsolidationAvailability(userWalletId, network)
|
|
||||||
|
|
||||||
val addressToValidate = decodedXAddress?.address ?: address
|
val addressToValidate = decodedXAddress?.address ?: address
|
||||||
val current = isCurrentAddress(addressToValidate)
|
val current = isCurrentAddress(addressToValidate)
|
||||||
val isForbidSelfSend = current && !isUtxoConsolidationAvailable
|
val isForbidSelfSend = current && !isSelfSendAvailable
|
||||||
val isValidAddress = walletAddressServiceRepository.validateAddress(userWalletId, network, addressToValidate)
|
val isValidAddress = walletAddressServiceRepository.validateAddress(userWalletId, network, addressToValidate)
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
|
|
|
||||||
|
|
@ -243,12 +243,12 @@ interface WalletManagersFacade {
|
||||||
suspend fun discardRequirements(userWalletId: UserWalletId, currency: CryptoCurrency): SimpleResult
|
suspend fun discardRequirements(userWalletId: UserWalletId, currency: CryptoCurrency): SimpleResult
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates UTXO consolidation availability
|
* Indicates self send availability
|
||||||
*
|
*
|
||||||
* @param userWalletId selected user wallet
|
* @param userWalletId selected user wallet
|
||||||
* @param network availability for network
|
* @param network availability for network
|
||||||
*/
|
*/
|
||||||
suspend fun checkUtxoConsolidationAvailability(userWalletId: UserWalletId, network: Network): Boolean
|
suspend fun checkSelfSendAvailability(userWalletId: UserWalletId, network: Network): Boolean
|
||||||
|
|
||||||
suspend fun getNFTCollections(userWalletId: UserWalletId, network: Network): List<NFTCollection>
|
suspend fun getNFTCollections(userWalletId: UserWalletId, network: Network): List<NFTCollection>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,11 @@ internal class ManageTokensUiManager(
|
||||||
|
|
||||||
val updatedBatch = uiBatchToUpdate.copy(
|
val updatedBatch = uiBatchToUpdate.copy(
|
||||||
data = data.mapIndexed { index, item ->
|
data = data.mapIndexed { index, item ->
|
||||||
if (item == currencyBatch.data[index]) {
|
val uiBatch = uiBatchToUpdate.data.getOrNull(index)
|
||||||
return@mapIndexed uiBatchToUpdate.data[index]
|
if (item == currencyBatch.data.getOrNull(index) &&
|
||||||
|
uiBatch != null
|
||||||
|
) {
|
||||||
|
return@mapIndexed uiBatch
|
||||||
}
|
}
|
||||||
|
|
||||||
val previousUiItem = uiBatchToUpdate.data.getOrNull(index)
|
val previousUiItem = uiBatchToUpdate.data.getOrNull(index)
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,6 @@ internal class OnboardingNoteCreateWalletModel @Inject constructor(
|
||||||
when (result) {
|
when (result) {
|
||||||
is CompletionResult.Success -> {
|
is CompletionResult.Success -> {
|
||||||
Analytics.send(OnboardingEvent.CreateWallet.WalletCreatedSuccessfully())
|
Analytics.send(OnboardingEvent.CreateWallet.WalletCreatedSuccessfully())
|
||||||
cardRepository.startCardActivation(scanResponse.card.cardId)
|
|
||||||
createWalletAndNavigateBackWithDone(scanResponse.copy(card = result.data.card))
|
createWalletAndNavigateBackWithDone(scanResponse.copy(card = result.data.card))
|
||||||
}
|
}
|
||||||
is CompletionResult.Failure -> _uiState.update {
|
is CompletionResult.Failure -> _uiState.update {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
||||||
import com.tangem.domain.qrscanning.usecases.ParseQrCodeUseCase
|
import com.tangem.domain.qrscanning.usecases.ParseQrCodeUseCase
|
||||||
import com.tangem.domain.tokens.GetCryptoCurrencyUseCase
|
import com.tangem.domain.tokens.GetCryptoCurrencyUseCase
|
||||||
import com.tangem.domain.tokens.GetNetworkAddressesUseCase
|
import com.tangem.domain.tokens.GetNetworkAddressesUseCase
|
||||||
import com.tangem.domain.transaction.usecase.IsUtxoConsolidationAvailableUseCase
|
import com.tangem.domain.transaction.usecase.IsSelfSendAvailableUseCase
|
||||||
import com.tangem.domain.transaction.usecase.ValidateWalletAddressUseCase
|
import com.tangem.domain.transaction.usecase.ValidateWalletAddressUseCase
|
||||||
import com.tangem.domain.transaction.usecase.ValidateWalletMemoUseCase
|
import com.tangem.domain.transaction.usecase.ValidateWalletMemoUseCase
|
||||||
import com.tangem.domain.txhistory.usecase.GetFixedTxHistoryItemsUseCase
|
import com.tangem.domain.txhistory.usecase.GetFixedTxHistoryItemsUseCase
|
||||||
|
|
@ -62,7 +62,7 @@ internal class SendDestinationModel @Inject constructor(
|
||||||
private val getCryptoCurrencyUseCase: GetCryptoCurrencyUseCase,
|
private val getCryptoCurrencyUseCase: GetCryptoCurrencyUseCase,
|
||||||
private val getNetworkAddressesUseCase: GetNetworkAddressesUseCase,
|
private val getNetworkAddressesUseCase: GetNetworkAddressesUseCase,
|
||||||
private val getFixedTxHistoryItemsUseCase: GetFixedTxHistoryItemsUseCase,
|
private val getFixedTxHistoryItemsUseCase: GetFixedTxHistoryItemsUseCase,
|
||||||
private val isUtxoConsolidationAvailableUseCase: IsUtxoConsolidationAvailableUseCase,
|
private val isSelfSendAvailableUseCase: IsSelfSendAvailableUseCase,
|
||||||
private val listenToQrScanningUseCase: ListenToQrScanningUseCase,
|
private val listenToQrScanningUseCase: ListenToQrScanningUseCase,
|
||||||
private val parseQrCodeUseCase: ParseQrCodeUseCase,
|
private val parseQrCodeUseCase: ParseQrCodeUseCase,
|
||||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||||
|
|
@ -197,7 +197,7 @@ internal class SendDestinationModel @Inject constructor(
|
||||||
waitForDelay(RECENT_LOAD_DELAY) { it }
|
waitForDelay(RECENT_LOAD_DELAY) { it }
|
||||||
}.conflate(),
|
}.conflate(),
|
||||||
) { destinationWalletList, txHistoryList ->
|
) { destinationWalletList, txHistoryList ->
|
||||||
val isUtxoConsolidationAvailable = isUtxoConsolidationAvailableUseCase.invokeSync(
|
val isSelfSendAvailable = isSelfSendAvailableUseCase.invokeSync(
|
||||||
userWalletId = userWalletId,
|
userWalletId = userWalletId,
|
||||||
network = cryptoCurrency.network,
|
network = cryptoCurrency.network,
|
||||||
)
|
)
|
||||||
|
|
@ -206,7 +206,7 @@ internal class SendDestinationModel @Inject constructor(
|
||||||
SendDestinationRecentListTransformer(
|
SendDestinationRecentListTransformer(
|
||||||
cryptoCurrency = cryptoCurrency,
|
cryptoCurrency = cryptoCurrency,
|
||||||
senderAddress = senderAddresses.value.firstOrNull()?.address,
|
senderAddress = senderAddresses.value.firstOrNull()?.address,
|
||||||
isUtxoConsolidationAvailable = isUtxoConsolidationAvailable,
|
isSelfSendAvailable = isSelfSendAvailable,
|
||||||
destinationWalletList = destinationWalletList,
|
destinationWalletList = destinationWalletList,
|
||||||
txHistoryList = txHistoryList,
|
txHistoryList = txHistoryList,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import kotlinx.collections.immutable.toPersistentList
|
||||||
|
|
||||||
internal class SendRecipientWalletListConverter(
|
internal class SendRecipientWalletListConverter(
|
||||||
private val senderAddress: String?,
|
private val senderAddress: String?,
|
||||||
private val isUtxoConsolidationAvailable: Boolean,
|
private val isSelfSendAvailable: Boolean,
|
||||||
) :
|
) :
|
||||||
Converter<List<DestinationWalletUM?>, PersistentList<DestinationRecipientListUM>> {
|
Converter<List<DestinationWalletUM?>, PersistentList<DestinationRecipientListUM>> {
|
||||||
override fun convert(value: List<DestinationWalletUM?>): PersistentList<DestinationRecipientListUM> {
|
override fun convert(value: List<DestinationWalletUM?>): PersistentList<DestinationRecipientListUM> {
|
||||||
|
|
@ -31,7 +31,7 @@ internal class SendRecipientWalletListConverter(
|
||||||
val isNotSameAddress = it.address != senderAddress
|
val isNotSameAddress = it.address != senderAddress
|
||||||
val isNotBlankAddress = it.address.isNotBlank()
|
val isNotBlankAddress = it.address.isNotBlank()
|
||||||
|
|
||||||
isNotBlankAddress && isCoin && (isNotSameAddress || isUtxoConsolidationAvailable)
|
isNotBlankAddress && isCoin && (isNotSameAddress || isSelfSendAvailable)
|
||||||
}
|
}
|
||||||
.groupBy { item -> item.name }
|
.groupBy { item -> item.name }
|
||||||
.values.map { wallets ->
|
.values.map { wallets ->
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import com.tangem.utils.transformer.Transformer
|
||||||
internal class SendDestinationRecentListTransformer(
|
internal class SendDestinationRecentListTransformer(
|
||||||
private val senderAddress: String?,
|
private val senderAddress: String?,
|
||||||
private val cryptoCurrency: CryptoCurrency,
|
private val cryptoCurrency: CryptoCurrency,
|
||||||
private val isUtxoConsolidationAvailable: Boolean,
|
private val isSelfSendAvailable: Boolean,
|
||||||
private val destinationWalletList: List<DestinationWalletUM>,
|
private val destinationWalletList: List<DestinationWalletUM>,
|
||||||
private val txHistoryList: List<TxInfo>,
|
private val txHistoryList: List<TxInfo>,
|
||||||
) : Transformer<DestinationUM> {
|
) : Transformer<DestinationUM> {
|
||||||
|
|
@ -21,7 +21,7 @@ internal class SendDestinationRecentListTransformer(
|
||||||
return state.copy(
|
return state.copy(
|
||||||
wallets = SendRecipientWalletListConverter(
|
wallets = SendRecipientWalletListConverter(
|
||||||
senderAddress = senderAddress,
|
senderAddress = senderAddress,
|
||||||
isUtxoConsolidationAvailable = isUtxoConsolidationAvailable,
|
isSelfSendAvailable = isSelfSendAvailable,
|
||||||
).convert(destinationWalletList),
|
).convert(destinationWalletList),
|
||||||
recent = SendRecipientHistoryListConverter(
|
recent = SendRecipientHistoryListConverter(
|
||||||
cryptoCurrency = cryptoCurrency,
|
cryptoCurrency = cryptoCurrency,
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,9 @@ internal class StakingModel @Inject constructor(
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
isInitialInfoStep && noBalanceState && !isAccountInitialized -> {
|
isInitialInfoStep && noBalanceState && !isAccountInitialized -> {
|
||||||
|
analyticsEventHandler.send(StakingAnalyticsEvent.UnitializedAddress(
|
||||||
|
token = cryptoCurrencyStatus.currency.symbol,
|
||||||
|
))
|
||||||
stakingEventFactory.createInitializeAccountAlert()
|
stakingEventFactory.createInitializeAccountAlert()
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,6 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
|
||||||
val isSepaAvailable = onrampSepaAvailableUseCase(
|
val isSepaAvailable = onrampSepaAvailableUseCase(
|
||||||
userWallet = userWallet,
|
userWallet = userWallet,
|
||||||
country = country,
|
country = country,
|
||||||
currency = country.defaultCurrency,
|
|
||||||
cryptoCurrency = bitcoinCurrency,
|
cryptoCurrency = bitcoinCurrency,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
# https://github.com/tangem/tangem-sdk-android/
|
# https://github.com/tangem/tangem-sdk-android/
|
||||||
# https://github.com/tangem/vico
|
# https://github.com/tangem/vico
|
||||||
|
|
||||||
tangemBlockchainSdk = "develop-1236"
|
tangemBlockchainSdk = "develop-1240"
|
||||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||||
tangemCardSdk = "develop-564"
|
tangemCardSdk = "develop-564"
|
||||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue