diff --git a/app/src/main/java/com/tangem/tap/LockUserWalletsTimer.kt b/app/src/main/java/com/tangem/tap/LockUserWalletsTimer.kt
index 18f3cff503..33d7f81b88 100644
--- a/app/src/main/java/com/tangem/tap/LockUserWalletsTimer.kt
+++ b/app/src/main/java/com/tangem/tap/LockUserWalletsTimer.kt
@@ -30,7 +30,7 @@ internal class LockUserWalletsTimer(
lifecycle.addObserver(this)
}
- override fun onResume(owner: LifecycleOwner) {
+ override fun onStart(owner: LifecycleOwner) {
owner.lifecycleScope.launch {
val wasApplicationStopped = settingsRepository.wasApplicationStopped()
val shouldOpenWelcomeScreenOnResume = settingsRepository.shouldOpenWelcomeScreenOnResume()
@@ -45,8 +45,6 @@ internal class LockUserWalletsTimer(
settingsRepository.setWasApplicationStopped(value = false)
- start()
-
if (shouldOpenWelcomeScreenOnResume) {
store.dispatchNavigationAction { replaceAll(AppRoute.Welcome()) }
settingsRepository.setShouldOpenWelcomeScreenOnResume(value = false)
@@ -54,6 +52,10 @@ internal class LockUserWalletsTimer(
}
}
+ override fun onResume(owner: LifecycleOwner) {
+ start()
+ }
+
override fun onStop(owner: LifecycleOwner) {
Timber.i("Owner stopped")
diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 92629c43f6..f6655e8627 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -5,7 +5,7 @@
Продать
Это может занять несколько секунд. Пожалуйста, попробуйте позже.
Данные ещё не загрузились
- Это действие в данный момент недоступно, пожалуйста попробуйте позже или обновите данные, сделав свайп экрана вниз.
+ Это действие в данный момент недоступно, пожалуйста, попробуйте позже или обновите данные, сделав свайп экрана вниз.
Кнопка недоступна
Выберите токен
Не нашли свой токен? Перейдите в раздел «Рынок» на главной странице и добавьте его в свой портфель для обмена.
diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml
index 7a2ba44136..e93c5799e5 100644
--- a/core/res/src/main/res/values-uk-rUA/strings.xml
+++ b/core/res/src/main/res/values-uk-rUA/strings.xml
@@ -12,6 +12,7 @@
Немає доступних токенів для обміну з обраним токеном. Будь ласка, оберіть інший.
Немає вільної пари
Щоб скористатися функцією обміну, у вашому портфелі має бути щонайменше 2 токени.
+ Додайте токени
У вас додано лише 1 токен. Щоб скористатися функцією обміну, потрібно додати мінімум 2 токени.
Додайте токени
Оберіть токен для отримання
@@ -324,6 +325,7 @@
Розкажіть, будь ласка, яку картку або кільце ви маєте?
Привіт, команда підтримки,
Будь ласка, розкажіть нам більше про вашу проблему. Кожна дрібниця може допомогти.
+ Раніше активований гаманець
Мої пропозиції
Не вдається відсканувати картку/кільце
Звернення в підтримку
@@ -598,6 +600,7 @@
Пошук за країною
Недоступно
Пошук по валюті
+ Використовуючи сервіс покупки, ви погоджуєтесь з %1$s та %2$s
Сума покупки не може бути більше ніж %s
Сума покупки повинна бути не менше %s
Для данної валюти немає доступних провайдерів
diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt
index 85dbdb56f6..25a92979ef 100644
--- a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt
+++ b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt
@@ -468,6 +468,7 @@ internal class DefaultOnrampRepository(
OnrampQuote.Error(
paymentMethod = paymentMethod,
provider = provider,
+ fromAmount = fromOnrampAmount,
error = onrampError,
)
}
diff --git a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampQuote.kt b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampQuote.kt
index c511e04b8a..c36638db32 100644
--- a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampQuote.kt
+++ b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampQuote.kt
@@ -6,11 +6,12 @@ sealed class OnrampQuote {
abstract val paymentMethod: OnrampPaymentMethod
abstract val provider: OnrampProvider
+ abstract val fromAmount: OnrampAmount
data class Data(
override val paymentMethod: OnrampPaymentMethod,
override val provider: OnrampProvider,
- val fromAmount: OnrampAmount,
+ override val fromAmount: OnrampAmount,
val toAmount: OnrampAmount,
val minFromAmount: OnrampAmount,
val maxFromAmount: OnrampAmount,
@@ -19,13 +20,14 @@ sealed class OnrampQuote {
data class AmountError(
override val paymentMethod: OnrampPaymentMethod,
override val provider: OnrampProvider,
- val fromAmount: OnrampAmount,
+ override val fromAmount: OnrampAmount,
val error: OnrampError.AmountError,
) : OnrampQuote()
data class Error(
override val paymentMethod: OnrampPaymentMethod,
override val provider: OnrampProvider,
+ override val fromAmount: OnrampAmount,
val error: OnrampError,
) : OnrampQuote()
}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/ConfirmResidencyComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/ConfirmResidencyComponent.kt
index feb6cd9c68..7dda243f37 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/ConfirmResidencyComponent.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/ConfirmResidencyComponent.kt
@@ -10,7 +10,7 @@ internal interface ConfirmResidencyComponent : ComposableBottomSheetComponent {
data class Params(
val cryptoCurrency: CryptoCurrency,
val country: OnrampCountry,
- val onDismiss: (OnrampCountry) -> Unit,
+ val onDismiss: () -> Unit,
)
interface Factory : ComponentFactory
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt
index 62dd39d0dd..0a88231cc3 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt
@@ -66,11 +66,17 @@ internal class DefaultConfirmResidencyComponent @AssistedInject constructor(
config: ConfirmResidencyBottomSheetConfig,
componentContext: ComponentContext,
): ComposableBottomSheetComponent = when (config) {
- ConfirmResidencyBottomSheetConfig.SelectCountry -> selectCountryComponentFactory.create(
+ is ConfirmResidencyBottomSheetConfig.SelectCountry -> selectCountryComponentFactory.create(
context = childByContext(componentContext),
params = SelectCountryComponent.Params(
cryptoCurrency = params.cryptoCurrency,
- onDismiss = model.bottomSheetNavigation::dismiss,
+ onDismiss = {
+ // Dismiss country select sheet
+ model.bottomSheetNavigation.dismiss()
+
+ // Dismiss confirm residency sheet
+ config.onDismiss()
+ },
),
)
}
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/entity/ConfirmResidencyBottomSheetConfig.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/entity/ConfirmResidencyBottomSheetConfig.kt
index baacb6b92a..0900dfebc2 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/entity/ConfirmResidencyBottomSheetConfig.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/entity/ConfirmResidencyBottomSheetConfig.kt
@@ -6,5 +6,5 @@ import kotlinx.serialization.Serializable
internal sealed class ConfirmResidencyBottomSheetConfig {
@Serializable
- data object SelectCountry : ConfirmResidencyBottomSheetConfig()
+ data class SelectCountry(val onDismiss: () -> Unit) : ConfirmResidencyBottomSheetConfig()
}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt
index 5237af3c2b..f622253ea1 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt
@@ -10,6 +10,7 @@ import com.tangem.core.decompose.navigation.Router
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.onramp.OnrampSaveDefaultCountryUseCase
import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent
+import com.tangem.domain.onramp.model.OnrampCountry
import com.tangem.features.onramp.confirmresidency.ConfirmResidencyComponent
import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyBottomSheetConfig
import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyUM
@@ -35,7 +36,7 @@ internal class ConfirmResidencyModel @Inject constructor(
country = params.country.name,
countryFlagUrl = params.country.image,
isCountrySupported = params.country.onrampAvailable,
- primaryButtonConfig = getPrimaryButtonConfig(),
+ primaryButtonConfig = getPrimaryButtonConfig(params.country),
secondaryButtonConfig = ConfirmResidencyUM.ActionButtonConfig(
onClick = ::onChangeClick,
text = resourceReference(R.string.common_change),
@@ -47,11 +48,12 @@ internal class ConfirmResidencyModel @Inject constructor(
analyticsEventHandler.send(OnrampAnalyticsEvent.ResidenceConfirmScreenOpened(params.country.name))
}
- private fun getPrimaryButtonConfig() = if (params.country.onrampAvailable) {
+ private fun getPrimaryButtonConfig(country: OnrampCountry) = if (country.onrampAvailable) {
ConfirmResidencyUM.ActionButtonConfig(
onClick = {
- analyticsEventHandler.send(OnrampAnalyticsEvent.OnResidenceConfirm(params.country.name))
- modelScope.launch { saveDefaultCountryUseCase.invoke(params.country) }
+ analyticsEventHandler.send(OnrampAnalyticsEvent.OnResidenceConfirm(country.name))
+ modelScope.launch { saveDefaultCountryUseCase.invoke(country) }
+ params.onDismiss()
},
text = resourceReference(R.string.common_confirm),
)
@@ -67,6 +69,6 @@ internal class ConfirmResidencyModel @Inject constructor(
private fun onChangeClick() {
analyticsEventHandler.send(OnrampAnalyticsEvent.OnResidenceChange)
- bottomSheetNavigation.activate(ConfirmResidencyBottomSheetConfig.SelectCountry)
+ bottomSheetNavigation.activate(ConfirmResidencyBottomSheetConfig.SelectCountry(params.onDismiss))
}
}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt
index 739d1a4d6e..5164c91d5b 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt
@@ -58,7 +58,7 @@ internal class DefaultOnrampMainComponent @AssistedInject constructor(
country = config.country,
onDismiss = {
model.bottomSheetNavigation.dismiss()
- model.handleOnrampAvailable(it.defaultCurrency)
+ model.handleOnrampAvailable()
},
),
)
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt
index ddcbb59d1c..865ec89ec6 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt
@@ -19,7 +19,6 @@ import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.onramp.*
import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent
import com.tangem.domain.onramp.model.OnrampAvailability
-import com.tangem.domain.onramp.model.OnrampCurrency
import com.tangem.domain.onramp.model.OnrampProviderWithQuote
import com.tangem.domain.onramp.model.OnrampQuote
import com.tangem.domain.onramp.model.error.OnrampError
@@ -105,8 +104,7 @@ internal class OnrampMainComponentModel @Inject constructor(
)
}
- fun handleOnrampAvailable(currency: OnrampCurrency) {
- _state.update { stateFactory.getReadyState(currency) }
+ fun handleOnrampAvailable() {
subscribeToCountryAndCurrencyUpdates()
subscribeToQuotesUpdate()
}
@@ -125,7 +123,7 @@ internal class OnrampMainComponentModel @Inject constructor(
private fun handleOnrampAvailability(availability: OnrampAvailability) {
when (availability) {
- is OnrampAvailability.Available -> handleOnrampAvailable(availability.currency)
+ is OnrampAvailability.Available -> handleOnrampAvailable()
is OnrampAvailability.ConfirmResidency,
is OnrampAvailability.NotSupported,
-> bottomSheetNavigation.activate(OnrampMainBottomSheetConfig.ConfirmResidency(availability.country))
@@ -139,7 +137,13 @@ internal class OnrampMainComponentModel @Inject constructor(
ifLeft = ::handleOnrampError,
ifRight = { country ->
if (country == null) return@onEach
- _state.update { amountStateFactory.getUpdatedCurrencyState(country.defaultCurrency) }
+ _state.update {
+ if (it is OnrampMainComponentUM.InitialLoading) {
+ stateFactory.getReadyState(country.defaultCurrency)
+ } else {
+ amountStateFactory.getUpdatedCurrencyState(country.defaultCurrency)
+ }
+ }
updatePairsAndQuotes()
},
)
@@ -278,10 +282,11 @@ internal class OnrampMainComponentModel @Inject constructor(
private fun handleQuoteResult(quotes: List) {
sendOnrampQuotesErrorAnalytic(quotes)
- val quote = quotes.firstOrNull()
+ val quote = quotes.firstOrNull { it !is OnrampQuote.Error }
if (quote == null) {
_state.update { stateFactory.getErrorState() }
+ lastAmount.value = BigDecimal.ZERO
return
}
@@ -295,15 +300,17 @@ internal class OnrampMainComponentModel @Inject constructor(
val isBestProvider = quote == bestProvider && hasBestProvider
- if (quote is OnrampQuote.Data && lastAmount.value != quote.fromAmount.value) {
+ if (lastAmount.value != quote.fromAmount.value) {
lastAmount.value = quote.fromAmount.value
- analyticsEventHandler.send(
- OnrampAnalyticsEvent.ProviderCalculated(
- providerName = quote.provider.info.name,
- tokenSymbol = params.cryptoCurrency.symbol,
- paymentMethod = quote.paymentMethod.name,
- ),
- )
+ if (quote is OnrampQuote.Data) {
+ analyticsEventHandler.send(
+ OnrampAnalyticsEvent.ProviderCalculated(
+ providerName = quote.provider.info.name,
+ tokenSymbol = params.cryptoCurrency.symbol,
+ paymentMethod = quote.paymentMethod.name,
+ ),
+ )
+ }
_state.update {
amountStateFactory.getAmountSecondaryUpdatedState(
quote = quote,
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/entity/ProviderListItemUM.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/entity/ProviderListItemUM.kt
index 0e6727be5b..f3c9d5341b 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/entity/ProviderListItemUM.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/entity/ProviderListItemUM.kt
@@ -6,30 +6,42 @@ internal sealed interface ProviderListItemUM {
val providerId: String
val name: String
+ val imageUrl: String
- data class Available(
- override val providerId: String,
- override val name: String,
- val imageUrl: String,
- val rate: String,
- val isBestRate: Boolean,
- val diffRate: TextReference?,
- val isSelected: Boolean,
- val onClick: () -> Unit,
- ) : ProviderListItemUM
+ sealed interface Available : ProviderListItemUM {
+ val onClick: () -> Unit
+ val providerResult: SelectProviderResult
+ val isBestRate: Boolean
+ val isSelected: Boolean
- data class AvailableWithError(
- override val providerId: String,
- override val name: String,
- val imageUrl: String,
- val subtitle: TextReference,
- val onClick: () -> Unit,
- ) : ProviderListItemUM
+ data class Content(
+ override val providerId: String,
+ override val name: String,
+ override val onClick: () -> Unit,
+ override val imageUrl: String,
+ override val providerResult: SelectProviderResult,
+ override val isBestRate: Boolean,
+ override val isSelected: Boolean,
+ val rate: String,
+ val diffRate: TextReference?,
+ ) : Available
+
+ data class WithError(
+ override val providerId: String,
+ override val name: String,
+ override val onClick: () -> Unit,
+ override val imageUrl: String,
+ override val providerResult: SelectProviderResult,
+ override val isBestRate: Boolean,
+ override val isSelected: Boolean,
+ val subtitle: TextReference,
+ ) : Available
+ }
data class Unavailable(
override val providerId: String,
override val name: String,
- val imageUrl: String,
+ override val imageUrl: String,
val subtitle: TextReference,
) : ProviderListItemUM
}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/entity/ProviderListUM.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/entity/ProviderListUM.kt
index 28350458da..b4f1435144 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/entity/ProviderListUM.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/entity/ProviderListUM.kt
@@ -4,13 +4,14 @@ import com.tangem.domain.onramp.model.OnrampPaymentMethod
import kotlinx.collections.immutable.ImmutableList
internal data class SelectPaymentAndProviderUM(
- val paymentMethods: ImmutableList,
- val selectedPaymentMethod: SelectProviderUM,
+ val paymentMethods: ImmutableList,
+ val selectedPaymentMethod: PaymentProviderUM,
+ val selectedProviderId: String,
val isPaymentMethodClickEnabled: Boolean,
val onPaymentMethodClick: () -> Unit,
)
-internal data class SelectProviderUM(
+internal data class PaymentProviderUM(
val paymentMethod: OnrampPaymentMethod,
val providers: ImmutableList,
)
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt
index 1c94f39113..e85759d361 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt
@@ -72,9 +72,21 @@ internal class SelectProviderModel @Inject constructor(
},
ifRight = { it },
)
+
+ val filteredEmptyMethods = methods.mapNotNull { method ->
+ val providers = getOnrampProviderWithQuoteUseCase(method).getOrNull()
+ if (!providers.isNullOrEmpty()) {
+ PaymentProviderUM(
+ paymentMethod = method,
+ providers = providers.toProvidersListItems(),
+ )
+ } else {
+ null
+ }
+ }
_state.value = state.value.copy(
- paymentMethods = methods.toPersistentList(),
- isPaymentMethodClickEnabled = methods.isNotEmpty(),
+ paymentMethods = filteredEmptyMethods.toPersistentList(),
+ isPaymentMethodClickEnabled = filteredEmptyMethods.isNotEmpty(),
)
}
}
@@ -111,13 +123,19 @@ internal class SelectProviderModel @Inject constructor(
private fun getInitialState(): SelectPaymentAndProviderUM {
return SelectPaymentAndProviderUM(
- paymentMethods = persistentListOf(params.selectedPaymentMethod),
+ paymentMethods = persistentListOf(
+ PaymentProviderUM(
+ paymentMethod = params.selectedPaymentMethod,
+ providers = emptyList().toImmutableList(),
+ ),
+ ),
isPaymentMethodClickEnabled = false,
onPaymentMethodClick = ::openPaymentMethods,
- selectedPaymentMethod = SelectProviderUM(
+ selectedPaymentMethod = PaymentProviderUM(
paymentMethod = params.selectedPaymentMethod,
providers = emptyList().toImmutableList(),
),
+ selectedProviderId = params.selectedProviderId,
)
}
@@ -131,16 +149,18 @@ internal class SelectProviderModel @Inject constructor(
)
}
- private fun ImmutableList.toPaymentUMList(): ImmutableList = map { method ->
+ private fun ImmutableList.toPaymentUMList(): ImmutableList = map { method ->
PaymentMethodUM(
- id = method.id,
- imageUrl = method.imageUrl,
- name = method.name,
+ id = method.paymentMethod.id,
+ imageUrl = method.paymentMethod.imageUrl,
+ name = method.paymentMethod.name,
onSelect = { onPaymentMethodSelected(method) },
)
}.toPersistentList()
- private fun onPaymentMethodSelected(paymentMethod: OnrampPaymentMethod) {
+ private fun onPaymentMethodSelected(methodContainer: PaymentProviderUM) {
+ val paymentMethod = methodContainer.paymentMethod
+ val firstProvider = methodContainer.providers.firstOrNull()
analyticsEventHandler.send(OnrampAnalyticsEvent.OnPaymentMethodChosen(paymentMethod = paymentMethod.name))
modelScope.launch {
saveSelectedPaymentMethod.invoke(paymentMethod)
@@ -151,6 +171,10 @@ internal class SelectProviderModel @Inject constructor(
),
)
}
+ if (firstProvider is ProviderListItemUM.Available) {
+ onProviderSelected(firstProvider.providerResult, firstProvider.isBestRate)
+ }
+
bottomSheetNavigation.dismiss()
}
}
@@ -165,6 +189,8 @@ internal class SelectProviderModel @Inject constructor(
val hasBestProvider = isMultipleQuotes && isOtherQuotesHasData
return sorted.map { quote ->
+ val isSelectedProvider = state.value.selectedProviderId == quote.provider.id
+
when (quote) {
is OnrampProviderWithQuote.Data -> {
val rate = quote.toAmount.value.format {
@@ -173,28 +199,29 @@ internal class SelectProviderModel @Inject constructor(
val rateDiff = bestProvider?.toAmount?.value?.let { bestRate ->
BigDecimal.ONE - quote.toAmount.value / bestRate
}
- val isSelectedProvider = quote.provider.id == params.selectedProviderId
- val isSelectedPayment = quote.paymentMethod.id == params.selectedPaymentMethod.id
val isBestProvider = quote == bestProvider && hasBestProvider
- ProviderListItemUM.Available(
+ val providerResult = SelectProviderResult.ProviderWithQuote(
+ paymentMethod = quote.paymentMethod,
+ provider = quote.provider,
+ fromAmount = quote.fromAmount,
+ toAmount = quote.toAmount,
+ )
+ ProviderListItemUM.Available.Content(
providerId = quote.provider.id,
imageUrl = quote.provider.info.imageLarge,
name = quote.provider.info.name,
rate = rate,
- isSelected = isSelectedProvider && isSelectedPayment,
isBestRate = isBestProvider,
diffRate = stringReference("$MINUS${rateDiff.format { percent() }}")
.takeIf { hasBestProvider },
+ providerResult = providerResult,
+ isSelected = isSelectedProvider,
onClick = {
onProviderSelected(
- result = SelectProviderResult.ProviderWithQuote(
- paymentMethod = quote.paymentMethod,
- provider = quote.provider,
- fromAmount = quote.fromAmount,
- toAmount = quote.toAmount,
- ),
+ result = providerResult,
isBestRate = isBestProvider,
)
+ params.onDismiss()
},
)
}
@@ -207,21 +234,25 @@ internal class SelectProviderModel @Inject constructor(
is OnrampError.AmountError.TooBigError -> R.string.express_provider_max_amount
is OnrampError.AmountError.TooSmallError -> R.string.express_provider_min_amount
}
-
- ProviderListItemUM.AvailableWithError(
+ val providerResult = SelectProviderResult.ProviderWithError(
+ paymentMethod = quoteError.paymentMethod,
+ provider = quote.provider,
+ quoteError = quote.quoteError,
+ )
+ ProviderListItemUM.Available.WithError(
providerId = quote.provider.id,
imageUrl = quote.provider.info.imageLarge,
name = quote.provider.info.name,
subtitle = resourceReference(errorSubtitleRes, wrappedList(amount)),
+ providerResult = providerResult,
+ isBestRate = false,
+ isSelected = isSelectedProvider,
onClick = {
onProviderSelected(
- result = SelectProviderResult.ProviderWithError(
- paymentMethod = quoteError.paymentMethod,
- provider = quote.provider,
- quoteError = quote.quoteError,
- ),
+ result = providerResult,
isBestRate = bestProvider == quote,
)
+ params.onDismiss()
},
)
}
@@ -247,8 +278,10 @@ internal class SelectProviderModel @Inject constructor(
tokenSymbol = params.cryptoCurrency.symbol,
),
)
+ _state.update {
+ it.copy(selectedProviderId = result.provider.id)
+ }
params.onProviderClick(result, isBestRate)
- params.onDismiss()
}
private fun sendOnrampErrorEvent(error: OnrampError) {
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/previewData/SelectProviderPreviewData.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/previewData/SelectProviderPreviewData.kt
index 4110250555..f4a23e8734 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/previewData/SelectProviderPreviewData.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/previewData/SelectProviderPreviewData.kt
@@ -2,59 +2,83 @@ package com.tangem.features.onramp.providers.model.previewData
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.stringReference
-import com.tangem.domain.onramp.model.OnrampPaymentMethod
-import com.tangem.domain.onramp.model.PaymentMethodType
+import com.tangem.domain.onramp.model.*
+import com.tangem.features.onramp.providers.entity.PaymentProviderUM
import com.tangem.features.onramp.providers.entity.ProviderListItemUM
import com.tangem.features.onramp.providers.entity.SelectPaymentAndProviderUM
-import com.tangem.features.onramp.providers.entity.SelectProviderUM
+import com.tangem.features.onramp.providers.entity.SelectProviderResult
import kotlinx.collections.immutable.persistentListOf
+import java.math.BigDecimal
internal object SelectProviderPreviewData {
- private val paymentMethods = persistentListOf(
- OnrampPaymentMethod(
- id = "card",
- name = "Card",
- imageUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/PaymentMethods/visa-mc.png",
- type = PaymentMethodType.CARD,
- ),
+ private val paymentMethod = OnrampPaymentMethod(
+ id = "card",
+ name = "Card",
+ imageUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/PaymentMethods/visa-mc.png",
+ type = PaymentMethodType.CARD,
)
- private val providerListUM = SelectProviderUM(
- paymentMethod = paymentMethods.first(),
+ private val provider = OnrampProvider(
+ id = "mercuryo",
+ info = OnrampProviderInfo(
+ name = "Mercuryo",
+ imageLarge = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/mercuryo1024.png",
+ termsOfUseLink = null,
+ privacyPolicyLink = null,
+ ),
+ paymentMethods = listOf(),
+ )
+
+ private val providerListUM = PaymentProviderUM(
+ paymentMethod = paymentMethod,
providers = persistentListOf(
- ProviderListItemUM.Available(
- providerId = "mercuryo",
- imageUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/mercuryo1024.png",
- name = "Mercuryo",
+ ProviderListItemUM.Available.Content(
+ providerId = provider.id,
+ imageUrl = provider.info.imageLarge,
+ name = provider.info.name,
rate = "1 BTC",
isSelected = true,
isBestRate = true,
diffRate = TextReference.EMPTY,
+ providerResult = SelectProviderResult.ProviderWithQuote(
+ paymentMethod = paymentMethod,
+ provider = provider,
+ fromAmount = OnrampAmount(symbol = "$", value = BigDecimal.ONE, decimals = 2),
+ toAmount = OnrampAmount(symbol = "BTC", value = BigDecimal.ONE, decimals = 18),
+
+ ),
onClick = {},
),
- ProviderListItemUM.Available(
- providerId = "mercuryo",
- imageUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/mercuryo1024.png",
- name = "Mercuryo",
+ ProviderListItemUM.Available.Content(
+ providerId = provider.id,
+ imageUrl = provider.info.imageLarge,
+ name = provider.info.name,
rate = "1 BTC",
isSelected = false,
isBestRate = false,
diffRate = stringReference("-0.03%"),
+ providerResult = SelectProviderResult.ProviderWithQuote(
+ paymentMethod = paymentMethod,
+ provider = provider,
+ fromAmount = OnrampAmount(symbol = "$", value = BigDecimal.ONE, decimals = 2),
+ toAmount = OnrampAmount(symbol = "BTC", value = BigDecimal.ONE, decimals = 18),
+ ),
onClick = {},
),
ProviderListItemUM.Unavailable(
- providerId = "mercuryo",
- imageUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/mercuryo1024.png",
- name = "Mercuryo",
+ providerId = provider.id,
+ imageUrl = provider.info.imageLarge,
+ name = provider.info.name,
subtitle = stringReference("Avaiable from 0,00413 BTC"),
),
),
)
val state = SelectPaymentAndProviderUM(
- paymentMethods = paymentMethods,
+ paymentMethods = persistentListOf(providerListUM),
selectedPaymentMethod = providerListUM,
+ selectedProviderId = provider.id,
isPaymentMethodClickEnabled = false,
onPaymentMethodClick = {},
)
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/ui/SelectProviderBottomSheet.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/ui/SelectProviderBottomSheet.kt
index 9918d1f05e..071e09b4b6 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/ui/SelectProviderBottomSheet.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/ui/SelectProviderBottomSheet.kt
@@ -124,16 +124,17 @@ private fun PaymentMethodBlock(
@Composable
private fun ProviderItem(state: ProviderListItemUM, modifier: Modifier = Modifier) {
when (state) {
- is ProviderListItemUM.Available -> AvailableProviderItem(
+ is ProviderListItemUM.Available.Content -> AvailableProviderItem(
modifier = modifier,
state = state,
)
- is ProviderListItemUM.AvailableWithError -> {
+ is ProviderListItemUM.Available.WithError -> {
UnavailableProviderItem(
modifier = modifier.clickable(onClick = state.onClick),
imageUrl = state.imageUrl,
providerName = state.name,
subtitle = state.subtitle,
+ isSelected = state.isSelected,
)
}
is ProviderListItemUM.Unavailable -> UnavailableProviderItem(
@@ -141,12 +142,13 @@ private fun ProviderItem(state: ProviderListItemUM, modifier: Modifier = Modifie
imageUrl = state.imageUrl,
providerName = state.name,
subtitle = state.subtitle,
+ isSelected = false,
)
}
}
@Composable
-private fun AvailableProviderItem(state: ProviderListItemUM.Available, modifier: Modifier = Modifier) {
+private fun AvailableProviderItem(state: ProviderListItemUM.Available.Content, modifier: Modifier = Modifier) {
Row(
modifier = modifier
.then(
@@ -220,10 +222,19 @@ private fun UnavailableProviderItem(
imageUrl: String,
providerName: String,
subtitle: TextReference,
+ isSelected: Boolean,
modifier: Modifier = Modifier,
) {
Row(
- modifier = modifier.padding(all = TangemTheme.dimens.spacing12),
+ modifier = modifier
+ .then(
+ if (isSelected) {
+ Modifier.selectedBorder()
+ } else {
+ Modifier.clip(RoundedCornerShape(16.dp))
+ },
+ )
+ .padding(all = TangemTheme.dimens.spacing12),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
) {
diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt
index 431017f917..13de36639d 100644
--- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt
+++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt
@@ -185,6 +185,14 @@ internal class SwapViewModel @Inject constructor(
}.launchIn(viewModelScope)
}
+ override fun onStart(owner: LifecycleOwner) {
+ startLoadingQuotesFromLastState(true)
+ }
+
+ override fun onStop(owner: LifecycleOwner) {
+ singleTaskScheduler.cancelTask()
+ }
+
override fun onCleared() {
singleTaskScheduler.cancelTask()
super.onCleared()
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt
index 358d295129..672da4f66c 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt
@@ -152,6 +152,7 @@ internal object TokenDetailsPreviewData {
formatArgs = wrappedList("Solana"),
),
iconState = iconState,
+ isEnabled = true,
onStakeClicked = {},
)
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/StakingBlockUM.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/StakingBlockUM.kt
index 0072e90707..789ddc5ec5 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/StakingBlockUM.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/StakingBlockUM.kt
@@ -24,6 +24,7 @@ internal sealed interface StakingBlockUM {
val iconState: IconState,
val titleText: TextReference,
val subtitleText: TextReference,
+ val isEnabled: Boolean,
val onStakeClicked: () -> Unit,
) : StakingBlockUM
}
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt
index a8bf99a969..2a9be57347 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt
@@ -158,7 +158,7 @@ internal class TokenDetailsLoadedBalanceConverter(
return when {
stakingCryptoAmount.isNullOrZero() && stakingEntryInfo != null -> {
if (pendingBalances.isEmpty()) {
- getStakeAvailableState(stakingEntryInfo, iconState)
+ getStakeAvailableState(stakingEntryInfo, iconState, isStakingButtonEnabled(status))
} else {
getStakedBlockWithFiatAmount(status, pendingBalances.sumOf { it.amount }, null)
}
@@ -170,6 +170,12 @@ internal class TokenDetailsLoadedBalanceConverter(
}
}
+ private fun isStakingButtonEnabled(status: CryptoCurrencyStatus): Boolean {
+ return status.value is CryptoCurrencyStatus.Loaded ||
+ status.value is CryptoCurrencyStatus.NoQuote ||
+ status.value is CryptoCurrencyStatus.Custom
+ }
+
private fun getStakedBlockWithFiatAmount(
status: CryptoCurrencyStatus,
stakingAmount: BigDecimal?,
@@ -210,6 +216,7 @@ internal class TokenDetailsLoadedBalanceConverter(
private fun getStakeAvailableState(
stakingEntryInfo: StakingEntryInfo,
iconState: IconState,
+ isEnabled: Boolean,
): StakingBlockUM.StakeAvailable {
val apr = stakingEntryInfo.apr.format { percent() }
return StakingBlockUM.StakeAvailable(
@@ -222,6 +229,7 @@ internal class TokenDetailsLoadedBalanceConverter(
formatArgs = wrappedList(stakingEntryInfo.tokenSymbol),
),
iconState = iconState,
+ isEnabled = isEnabled,
onStakeClicked = clickIntents::onStakeBannerClick,
)
}
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/TokenStakingBlock.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/TokenStakingBlock.kt
index a8ba9f84c2..484de66cba 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/TokenStakingBlock.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/staking/TokenStakingBlock.kt
@@ -112,6 +112,7 @@ private fun StakingAvailableContent(state: StakingBlockUM.StakeAvailable, modifi
SecondaryButton(
modifier = Modifier.fillMaxWidth(),
text = stringResource(id = R.string.common_stake),
+ enabled = state.isEnabled,
onClick = state.onStakeClicked,
)
}
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/Wallet2CobrandImage.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/Wallet2CobrandImage.kt
index 033f180725..80663dd7de 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/Wallet2CobrandImage.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/Wallet2CobrandImage.kt
@@ -161,7 +161,7 @@ internal enum class Wallet2CobrandImage(
Pastel(
cards2ResId = R.drawable.ill_pastel_cards3_120_106,
cards3ResId = R.drawable.ill_pastel_cards3_120_106,
- batchIds = setOf("AF43", "AF44", "AF45"),
+ batchIds = setOf("AF43", "AF44", "AF45", "AF78", "AF79", "AF80"),
),
RedPanda(
@@ -204,7 +204,7 @@ internal enum class Wallet2CobrandImage(
Vivid(
cards2ResId = R.drawable.ill_vivid_cards3_120_106,
cards3ResId = R.drawable.ill_vivid_cards3_120_106,
- batchIds = setOf("AF40", "AF41", "AF42"),
+ batchIds = setOf("AF40", "AF41", "AF42", "AF75", "AF76", "AF77"),
),
VoltInu(