Updated on 2026-08-14
This commit is contained in:
commit
531eb86ac5
1243 changed files with 49302 additions and 12422 deletions
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.features.yield.supply.api
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
interface YieldSupplyEntryComponent : ComposableContentComponent {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
val apy: String,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, YieldSupplyEntryComponent>
|
||||
}
|
||||
|
|
@ -3,4 +3,5 @@ package com.tangem.features.yield.supply.api
|
|||
interface YieldSupplyFeatureToggles {
|
||||
|
||||
val isYieldSupplyFeatureEnabled: Boolean
|
||||
val isYieldSupplyPendingTransactionsEnabled: Boolean
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.features.yield.supply.api.entry
|
||||
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
|
||||
/**
|
||||
* Route for switching yield supply promo and active flows.
|
||||
*/
|
||||
sealed class YieldSupplyEntryRoute : Route {
|
||||
|
||||
/** Initial empty route with no UI */
|
||||
data object Empty : YieldSupplyEntryRoute()
|
||||
|
||||
/** Route to yield supply promo screen */
|
||||
data class Promo(
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
val apy: String,
|
||||
) : YieldSupplyEntryRoute()
|
||||
|
||||
/** Route to yield supply active screen */
|
||||
data class Active(
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
) : YieldSupplyEntryRoute()
|
||||
}
|
||||
|
|
@ -8,4 +8,7 @@ internal class DefaultYieldSupplyFeatureToggles(
|
|||
) : YieldSupplyFeatureToggles {
|
||||
override val isYieldSupplyFeatureEnabled: Boolean
|
||||
get() = featureToggles.isFeatureEnabled("YIELD_SUPPLY_FEATURE_ENABLED")
|
||||
|
||||
override val isYieldSupplyPendingTransactionsEnabled: Boolean
|
||||
get() = featureToggles.isFeatureEnabled("YIELD_SUPPLY_PENDING_TRANSACTIONS_ENABLED")
|
||||
}
|
||||
|
|
@ -31,4 +31,5 @@ internal data class YieldSupplyActionUM(
|
|||
val yieldSupplyFeeUM: YieldSupplyFeeUM,
|
||||
val isPrimaryButtonEnabled: Boolean,
|
||||
val isTransactionSending: Boolean,
|
||||
val isHoldToConfirmEnabled: Boolean,
|
||||
)
|
||||
|
|
@ -156,6 +156,7 @@ private class YieldSupplyActionContentPreviewProvider : PreviewParameterProvider
|
|||
),
|
||||
isPrimaryButtonEnabled = false,
|
||||
isTransactionSending = false,
|
||||
isHoldToConfirmEnabled = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
package com.tangem.features.yield.supply.impl.entry
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.extensions.compose.stack.Children
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.fade
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.childStack
|
||||
import com.arkivanov.decompose.router.stack.pop
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyActiveComponent
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyEntryComponent
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyPromoComponent
|
||||
import com.tangem.features.yield.supply.api.entry.YieldSupplyEntryRoute
|
||||
import com.tangem.features.yield.supply.impl.entry.model.YieldSupplyEntryModel
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultYieldSupplyEntryComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: YieldSupplyEntryComponent.Params,
|
||||
private val yieldSupplyPromoComponentFactory: YieldSupplyPromoComponent.Factory,
|
||||
private val yieldSupplyActiveComponentFactory: YieldSupplyActiveComponent.Factory,
|
||||
) : YieldSupplyEntryComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val stackNavigation = StackNavigation<YieldSupplyEntryRoute>()
|
||||
|
||||
private val innerRouter = InnerRouter<YieldSupplyEntryRoute>(
|
||||
stackNavigation = stackNavigation,
|
||||
popCallback = { onChildBack() },
|
||||
)
|
||||
|
||||
private val model: YieldSupplyEntryModel = getOrCreateModel(
|
||||
params = params,
|
||||
router = innerRouter,
|
||||
)
|
||||
|
||||
private val childStack = childStack(
|
||||
key = "yieldSupplyEntryStack",
|
||||
source = stackNavigation,
|
||||
serializer = null,
|
||||
initialConfiguration = model.initialRoute,
|
||||
handleBackButton = true,
|
||||
childFactory = { configuration, factoryContext ->
|
||||
getChildComponent(
|
||||
configuration = configuration,
|
||||
factoryContext = childByContext(
|
||||
componentContext = factoryContext,
|
||||
router = innerRouter,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val childStackValue by childStack.subscribeAsState()
|
||||
|
||||
Children(
|
||||
stack = childStackValue,
|
||||
modifier = modifier,
|
||||
animation = stackAnimation { fade() },
|
||||
) { child ->
|
||||
child.instance.Content(Modifier.fillMaxSize())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getChildComponent(
|
||||
configuration: YieldSupplyEntryRoute,
|
||||
factoryContext: AppComponentContext,
|
||||
): ComposableContentComponent = when (configuration) {
|
||||
is YieldSupplyEntryRoute.Empty -> EmptyComponent
|
||||
is YieldSupplyEntryRoute.Promo -> yieldSupplyPromoComponentFactory.create(
|
||||
context = factoryContext,
|
||||
params = YieldSupplyPromoComponent.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
currency = configuration.cryptoCurrency,
|
||||
apy = configuration.apy,
|
||||
),
|
||||
)
|
||||
is YieldSupplyEntryRoute.Active -> yieldSupplyActiveComponentFactory.create(
|
||||
context = factoryContext,
|
||||
params = YieldSupplyActiveComponent.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrency = configuration.cryptoCurrency,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private object EmptyComponent : ComposableContentComponent {
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
Box(modifier = modifier)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onChildBack() {
|
||||
if (childStack.value.backStack.isEmpty() ||
|
||||
childStack.value.backStack.last().configuration is YieldSupplyEntryRoute.Empty
|
||||
) {
|
||||
router.pop()
|
||||
} else {
|
||||
stackNavigation.pop()
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : YieldSupplyEntryComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: YieldSupplyEntryComponent.Params,
|
||||
): DefaultYieldSupplyEntryComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.tangem.features.yield.supply.impl.entry.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyEntryComponent
|
||||
import com.tangem.features.yield.supply.impl.entry.DefaultYieldSupplyEntryComponent
|
||||
import com.tangem.features.yield.supply.impl.entry.model.YieldSupplyEntryModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface YieldSupplyEntryBindsModule {
|
||||
@Binds
|
||||
@Singleton
|
||||
fun provideYieldSupplyEntryComponentFactory(
|
||||
impl: DefaultYieldSupplyEntryComponent.Factory,
|
||||
): YieldSupplyEntryComponent.Factory
|
||||
}
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface YieldSupplyEntryModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(YieldSupplyEntryModel::class)
|
||||
fun provideYieldSupplyEntryModel(impl: YieldSupplyEntryModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package com.tangem.features.yield.supply.impl.entry.model
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.model.details.NavigationAction
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyEnterStatusUseCase
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyEntryComponent
|
||||
import com.tangem.features.yield.supply.api.entry.YieldSupplyEntryRoute
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class YieldSupplyEntryModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val router: Router,
|
||||
private val yieldSupplyEnterStatusUseCase: YieldSupplyEnterStatusUseCase,
|
||||
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<YieldSupplyEntryComponent.Params>()
|
||||
|
||||
val initialRoute: YieldSupplyEntryRoute = YieldSupplyEntryRoute.Empty
|
||||
|
||||
init {
|
||||
navigateToInitialRoute()
|
||||
}
|
||||
|
||||
private fun navigateToInitialRoute() {
|
||||
val userWalletId = params.userWalletId
|
||||
val cryptoCurrency = params.cryptoCurrency
|
||||
modelScope.launch(dispatchers.default) {
|
||||
getSingleCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencyId = cryptoCurrency.id,
|
||||
).onLeft { error ->
|
||||
Timber.e("Failed to get CryptoCurrencyStatus: $error")
|
||||
withContext(dispatchers.mainImmediate) {
|
||||
router.pop()
|
||||
}
|
||||
}.onRight { cryptoCurrencyStatus ->
|
||||
withContext(dispatchers.mainImmediate) {
|
||||
val route = getInitialRoute(cryptoCurrencyStatus)
|
||||
if (route != null) {
|
||||
router.replaceCurrent(route)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getInitialRoute(cryptoCurrencyStatus: CryptoCurrencyStatus): YieldSupplyEntryRoute? {
|
||||
val userWalletId = params.userWalletId
|
||||
val cryptoCurrency = params.cryptoCurrency
|
||||
val token = cryptoCurrency as? CryptoCurrency.Token
|
||||
if (token == null) {
|
||||
router.pop()
|
||||
return null
|
||||
}
|
||||
|
||||
val tokenEnterStatus = yieldSupplyEnterStatusUseCase(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
).getOrNull()
|
||||
val isActiveYield = cryptoCurrencyStatus.value.yieldSupplyStatus?.isActive == true
|
||||
|
||||
if (tokenEnterStatus != null) {
|
||||
router.replaceCurrent(
|
||||
AppRoute.CurrencyDetails(
|
||||
userWalletId = userWalletId,
|
||||
currency = token,
|
||||
navigationAction = NavigationAction.YieldSupply(
|
||||
isActive = isActiveYield,
|
||||
),
|
||||
),
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
return if (isActiveYield) {
|
||||
YieldSupplyEntryRoute.Active(cryptoCurrency = token)
|
||||
} else {
|
||||
YieldSupplyEntryRoute.Promo(cryptoCurrency = token, apy = params.apy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,6 @@ package com.tangem.features.yield.supply.impl.main.model
|
|||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import android.os.SystemClock
|
||||
import com.tangem.common.routing.AppRoute.YieldSupplyPromo
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
|
|
@ -25,8 +23,7 @@ import com.tangem.domain.models.yield.supply.YieldSupplyStatus
|
|||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.domain.yield.supply.YieldSupplyRepository
|
||||
import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus
|
||||
import com.tangem.domain.yield.supply.models.YieldSupplyPendingStatus
|
||||
import com.tangem.domain.yield.supply.usecase.*
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyComponent
|
||||
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
|
||||
|
|
@ -34,12 +31,7 @@ import com.tangem.features.yield.supply.impl.R
|
|||
import com.tangem.features.yield.supply.impl.main.entity.YieldSupplyUM
|
||||
import com.tangem.features.yield.supply.impl.main.model.transformers.YieldSupplyTokenStatusSuccessTransformer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.DelayedWork
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import com.tangem.utils.transformer.update
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -58,12 +50,12 @@ internal class YieldSupplyModel @Inject constructor(
|
|||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
|
||||
private val singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
|
||||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
private val yieldSupplyGetTokenStatusUseCase: YieldSupplyGetTokenStatusUseCase,
|
||||
private val yieldSupplyIsAvailableUseCase: YieldSupplyIsAvailableUseCase,
|
||||
private val yieldSupplyActivateUseCase: YieldSupplyActivateUseCase,
|
||||
private val yieldSupplyDeactivateUseCase: YieldSupplyDeactivateUseCase,
|
||||
private val yieldSupplyRepository: YieldSupplyRepository,
|
||||
private val yieldSupplyEnterStatusUseCase: YieldSupplyEnterStatusUseCase,
|
||||
private val yieldSupplyEnterStatusFlowUseCase: YieldSupplyEnterStatusFlowUseCase,
|
||||
private val yieldSupplyMinAmountUseCase: YieldSupplyMinAmountUseCase,
|
||||
private val yieldSupplyGetDustMinAmountUseCase: YieldSupplyGetDustMinAmountUseCase,
|
||||
) : Model(), YieldSupplyClickIntents {
|
||||
|
|
@ -76,11 +68,8 @@ internal class YieldSupplyModel @Inject constructor(
|
|||
private val cryptoCurrency = params.cryptoCurrency
|
||||
private var appCurrency: AppCurrency = AppCurrency.Default
|
||||
var userWallet: UserWallet by Delegates.notNull()
|
||||
private var latestCryptoCurrencyStatus: CryptoCurrencyStatus? = null
|
||||
|
||||
private val fetchCurrencyJobHolder = JobHolder()
|
||||
private val loadStatusJobHolder = JobHolder()
|
||||
|
||||
private var lastStatusCheckTimestamp = 0L
|
||||
private val isFirstCryptoCurrencyStatusEmission = AtomicBoolean(true)
|
||||
|
||||
init {
|
||||
|
|
@ -92,7 +81,7 @@ internal class YieldSupplyModel @Inject constructor(
|
|||
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
|
||||
val isAvailable = yieldSupplyIsAvailableUseCase(params.userWalletId, params.cryptoCurrency)
|
||||
if (isAvailable) {
|
||||
subscribeOnCurrencyStatusUpdates()
|
||||
loadUserWalletData()
|
||||
singleNetworkStatusFetcher(
|
||||
params = SingleNetworkStatusFetcher.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
|
|
@ -103,29 +92,12 @@ internal class YieldSupplyModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnCurrencyStatusUpdates() {
|
||||
private fun loadUserWalletData() {
|
||||
modelScope.launch {
|
||||
getUserWalletUseCase(params.userWalletId).fold(
|
||||
ifRight = { wallet ->
|
||||
userWallet = wallet
|
||||
|
||||
getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet(
|
||||
userWalletId = params.userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
isSingleWalletWithTokens = false,
|
||||
).onEach { maybeCryptoCurrency ->
|
||||
maybeCryptoCurrency.fold(
|
||||
ifRight = { cryptoCurrencyStatus ->
|
||||
if (isFirstCryptoCurrencyStatusEmission.compareAndSet(true, false)) {
|
||||
sendInfoAboutProtocolStatus(cryptoCurrencyStatus)
|
||||
}
|
||||
onCryptoCurrencyStatusUpdated(cryptoCurrencyStatus)
|
||||
},
|
||||
ifLeft = {
|
||||
Timber.w(it.toString())
|
||||
},
|
||||
)
|
||||
}.launchIn(modelScope)
|
||||
subscribeOnCurrencyStatusUpdates()
|
||||
},
|
||||
ifLeft = {
|
||||
Timber.w(it.toString())
|
||||
|
|
@ -135,6 +107,36 @@ internal class YieldSupplyModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnCurrencyStatusUpdates() {
|
||||
combine(
|
||||
getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet(
|
||||
userWalletId = params.userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
isSingleWalletWithTokens = false,
|
||||
),
|
||||
yieldSupplyEnterStatusFlowUseCase(
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
),
|
||||
) { maybeCryptoCurrency, _ ->
|
||||
maybeCryptoCurrency
|
||||
}.flowOn(dispatchers.io)
|
||||
.onEach { maybeCryptoCurrency ->
|
||||
maybeCryptoCurrency.fold(
|
||||
ifRight = { cryptoCurrencyStatus ->
|
||||
latestCryptoCurrencyStatus = cryptoCurrencyStatus
|
||||
if (isFirstCryptoCurrencyStatusEmission.compareAndSet(true, false)) {
|
||||
sendInfoAboutProtocolStatus(cryptoCurrencyStatus)
|
||||
}
|
||||
onCryptoCurrencyStatusUpdated(cryptoCurrencyStatus)
|
||||
},
|
||||
ifLeft = {
|
||||
Timber.w(it.toString())
|
||||
},
|
||||
)
|
||||
}.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private suspend fun loadTokenStatus() {
|
||||
val cryptoCurrencyToken = cryptoCurrency as? CryptoCurrency.Token ?: return
|
||||
yieldSupplyGetTokenStatusUseCase(cryptoCurrencyToken)
|
||||
|
|
@ -152,108 +154,59 @@ internal class YieldSupplyModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onStartEarningClick() {
|
||||
val apy = when (val yieldSupplyUM = uiState.value) {
|
||||
is YieldSupplyUM.Available -> yieldSupplyUM.apy
|
||||
is YieldSupplyUM.Content -> yieldSupplyUM.apy
|
||||
else -> ""
|
||||
}
|
||||
appRouter.push(
|
||||
YieldSupplyPromo(
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrency = params.cryptoCurrency,
|
||||
apy = apy,
|
||||
),
|
||||
)
|
||||
navigateToYieldSupplyEntry()
|
||||
}
|
||||
|
||||
override fun onActiveClick() {
|
||||
navigateToYieldSupplyEntry()
|
||||
}
|
||||
|
||||
private fun navigateToYieldSupplyEntry() {
|
||||
val cryptoCurrencyStatus = latestCryptoCurrencyStatus ?: return
|
||||
val apy = when (val yieldSupplyUM = uiState.value) {
|
||||
is YieldSupplyUM.Available -> yieldSupplyUM.apy
|
||||
is YieldSupplyUM.Content -> yieldSupplyUM.apy
|
||||
else -> ""
|
||||
}
|
||||
appRouter.push(
|
||||
AppRoute.YieldSupplyActive(
|
||||
AppRoute.YieldSupplyEntry(
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrency = params.cryptoCurrency,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
apy = apy,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaximumLineLength")
|
||||
private fun onCryptoCurrencyStatusUpdated(cryptoCurrencyStatus: CryptoCurrencyStatus) = modelScope.launch(
|
||||
dispatchers.default,
|
||||
) {
|
||||
val yieldSupplyStatus = cryptoCurrencyStatus.value.yieldSupplyStatus
|
||||
val tokenProtocolStatus = yieldSupplyRepository.getTokenProtocolStatus(
|
||||
userWallet.walletId,
|
||||
cryptoCurrency,
|
||||
)
|
||||
val tokenPendingStatus = yieldSupplyRepository.getTokenPendingStatus(
|
||||
userWallet.walletId,
|
||||
cryptoCurrencyStatus,
|
||||
)
|
||||
|
||||
val isActive = yieldSupplyStatus?.isActive == true
|
||||
private suspend fun onCryptoCurrencyStatusUpdated(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
val isCryptoCurrencyStatusFromCache = cryptoCurrencyStatus.value.sources.networkSource != StatusSource.ACTUAL
|
||||
val processing = uiState.value is YieldSupplyUM.Processing
|
||||
Timber.d(
|
||||
"YIELD " +
|
||||
"yieldSupplyStatus $yieldSupplyStatus " +
|
||||
"tokenProtocolStatus $tokenProtocolStatus " +
|
||||
"tokenPendingStatus $tokenPendingStatus " +
|
||||
"isActive $isActive " +
|
||||
"processing $processing " +
|
||||
"isCryptoCurrencyStatusFromCache $isCryptoCurrencyStatusFromCache",
|
||||
)
|
||||
if (isCryptoCurrencyStatusFromCache && processing) {
|
||||
return@launch
|
||||
return
|
||||
}
|
||||
|
||||
when {
|
||||
tokenProtocolStatus != null && tokenPendingStatus != null -> {
|
||||
showProcessing(tokenPendingStatus)
|
||||
lastStatusCheckTimestamp = 0L
|
||||
}
|
||||
tokenProtocolStatus == YieldSupplyEnterStatus.Exit && isActive ||
|
||||
tokenProtocolStatus == YieldSupplyEnterStatus.Enter && !isActive -> {
|
||||
if (lastStatusCheckTimestamp != 0L) {
|
||||
if (SystemClock.elapsedRealtime() - lastStatusCheckTimestamp > MAX_STATUS_CHECK_LIMIT) {
|
||||
loadStatus(cryptoCurrencyStatus)
|
||||
lastStatusCheckTimestamp = 0L
|
||||
} else {
|
||||
showProcessing(tokenProtocolStatus)
|
||||
}
|
||||
} else {
|
||||
showProcessing(tokenProtocolStatus)
|
||||
lastStatusCheckTimestamp = SystemClock.elapsedRealtime()
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
loadStatus(cryptoCurrencyStatus)
|
||||
lastStatusCheckTimestamp = 0L
|
||||
}
|
||||
}
|
||||
}.saveIn(loadStatusJobHolder)
|
||||
val pendingStatus = yieldSupplyEnterStatusUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
).getOrNull()
|
||||
|
||||
private fun showProcessing(status: YieldSupplyEnterStatus) {
|
||||
if (pendingStatus != null) {
|
||||
showProcessing(pendingStatus)
|
||||
} else {
|
||||
loadStatus(cryptoCurrencyStatus)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showProcessing(status: YieldSupplyPendingStatus) {
|
||||
uiState.update {
|
||||
when (status) {
|
||||
YieldSupplyEnterStatus.Enter -> YieldSupplyUM.Processing.Enter
|
||||
YieldSupplyEnterStatus.Exit -> YieldSupplyUM.Processing.Exit
|
||||
is YieldSupplyPendingStatus.Enter -> YieldSupplyUM.Processing.Enter
|
||||
is YieldSupplyPendingStatus.Exit -> YieldSupplyUM.Processing.Exit
|
||||
}
|
||||
}
|
||||
fetchCurrencyWithDelay()
|
||||
}
|
||||
|
||||
private suspend fun loadStatus(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
val yieldSupplyStatus = cryptoCurrencyStatus.value.yieldSupplyStatus
|
||||
yieldSupplyRepository.saveTokenProtocolStatus(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
yieldSupplyEnterStatus = null,
|
||||
)
|
||||
if (yieldSupplyStatus?.isActive == true) {
|
||||
loadActiveState(
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
|
|
@ -264,20 +217,6 @@ internal class YieldSupplyModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun fetchCurrencyWithDelay() {
|
||||
coroutineScope.launch(dispatchers.io) {
|
||||
delay(PROCESSING_UPDATE_DELAY)
|
||||
singleNetworkStatusFetcher(
|
||||
params = SingleNetworkStatusFetcher.Params(
|
||||
userWalletId = userWallet.walletId,
|
||||
network = cryptoCurrency.network,
|
||||
),
|
||||
).onLeft {
|
||||
fetchCurrencyWithDelay()
|
||||
}
|
||||
}.saveIn(fetchCurrencyJobHolder)
|
||||
}
|
||||
|
||||
private suspend fun loadActiveState(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
yieldSupplyStatus: YieldSupplyStatus,
|
||||
|
|
@ -382,9 +321,4 @@ internal class YieldSupplyModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PROCESSING_UPDATE_DELAY = 10_000L
|
||||
const val MAX_STATUS_CHECK_LIMIT = 10_000L
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,9 @@ import com.tangem.common.ui.userwallet.ext.walletInterationIcon
|
|||
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.components.HoldToConfirmButton
|
||||
import com.tangem.core.ui.components.PrimaryButtonIconEnd
|
||||
import com.tangem.core.ui.R as CoreR
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||
|
|
@ -74,15 +76,30 @@ internal class YieldSupplyApproveComponent(
|
|||
)
|
||||
},
|
||||
footer = {
|
||||
PrimaryButtonIconEnd(
|
||||
text = stringResourceSafe(R.string.common_confirm),
|
||||
onClick = model::onClick,
|
||||
iconResId = walletInterationIcon(params.userWallet),
|
||||
enabled = state.isPrimaryButtonEnabled,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
)
|
||||
val modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
|
||||
if (state.isHoldToConfirmEnabled) {
|
||||
HoldToConfirmButton(
|
||||
text = stringResourceSafe(
|
||||
CoreR.string.common_hold_to,
|
||||
stringResourceSafe(R.string.common_confirm),
|
||||
),
|
||||
onConfirm = model::onClick,
|
||||
enabled = state.isPrimaryButtonEnabled,
|
||||
isLoading = state.isTransactionSending,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
PrimaryButtonIconEnd(
|
||||
text = stringResourceSafe(R.string.common_confirm),
|
||||
onClick = model::onClick,
|
||||
iconResId = walletInterationIcon(params.userWallet),
|
||||
enabled = state.isPrimaryButtonEnabled,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
},
|
||||
content = {
|
||||
YieldSupplyActionContent(
|
||||
|
|
|
|||
|
|
@ -18,11 +18,13 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.isHotWallet
|
||||
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.transaction.usecase.CreateApprovalTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetContractAddressUseCase
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyPendingTracker
|
||||
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
|
||||
import com.tangem.features.yield.supply.impl.R
|
||||
import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory
|
||||
|
|
@ -58,6 +60,7 @@ internal class YieldSupplyApproveModel @Inject constructor(
|
|||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase,
|
||||
private val yieldSupplyGetContractAddressUseCase: YieldSupplyGetContractAddressUseCase,
|
||||
private val yieldSupplyPendingTracker: YieldSupplyPendingTracker,
|
||||
private val yieldSupplyAlertFactory: YieldSupplyAlertFactory,
|
||||
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
|
||||
|
||||
|
|
@ -95,6 +98,7 @@ internal class YieldSupplyApproveModel @Inject constructor(
|
|||
yieldSupplyFeeUM = YieldSupplyFeeUM.Loading,
|
||||
isPrimaryButtonEnabled = false,
|
||||
isTransactionSending = false,
|
||||
isHoldToConfirmEnabled = params.userWallet.isHotWallet,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -157,11 +161,17 @@ internal class YieldSupplyApproveModel @Inject constructor(
|
|||
)
|
||||
params.callback.onTransactionProgress(false)
|
||||
},
|
||||
ifRight = {
|
||||
ifRight = { txHash ->
|
||||
yieldSupplyPendingTracker.addPending(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
txIds = listOf(txHash),
|
||||
)
|
||||
val event = AnalyticsParam.TxSentFrom.Earning(
|
||||
blockchain = cryptoCurrency.network.name,
|
||||
token = cryptoCurrency.symbol,
|
||||
feeType = AnalyticsParam.FeeType.Normal,
|
||||
feeToken = feeCryptoCurrencyStatus.currency.symbol,
|
||||
)
|
||||
analyticsEventHandler.send(
|
||||
Basic.TransactionSent(
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ internal class YieldSupplyNotificationsModel @Inject constructor(
|
|||
fee = data.feeValue.orZero(),
|
||||
userWalletId = params.userWalletId,
|
||||
tokenStatus = cryptoCurrencyStatus,
|
||||
coinStatus = feeCryptoCurrencyStatus,
|
||||
feeStatus = feeCryptoCurrencyStatus,
|
||||
).getOrNull()
|
||||
|
||||
addExceedsBalanceNotification(
|
||||
|
|
@ -64,7 +64,8 @@ internal class YieldSupplyNotificationsModel @Inject constructor(
|
|||
blockchainId = cryptoCurrencyStatus.currency.network.backendId,
|
||||
),
|
||||
onClick = ::openTokenDetails,
|
||||
onAnalyticsEvent = { },
|
||||
onAnalyticsEvent = { /*no-op*/ },
|
||||
onResetAnalyticsEvent = { /*no-op*/ },
|
||||
)
|
||||
|
||||
addFeeUnreachableNotification(
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import com.tangem.common.ui.userwallet.ext.walletInterationIcon
|
|||
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.components.HoldToConfirmButton
|
||||
import com.tangem.core.ui.components.PrimaryButtonIconEnd
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
|
|
@ -25,6 +26,7 @@ import com.tangem.core.ui.extensions.stringResourceSafe
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.core.ui.R as CoreR
|
||||
import com.tangem.features.yield.supply.impl.R
|
||||
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM
|
||||
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM
|
||||
|
|
@ -106,22 +108,36 @@ internal class YieldSupplyStartEarningComponent(
|
|||
override fun Footer() {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
val icon = if (state.isPrimaryButtonEnabled) {
|
||||
walletInterationIcon(model.userWallet)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
|
||||
PrimaryButtonIconEnd(
|
||||
text = stringResourceSafe(R.string.yield_module_start_earning),
|
||||
onClick = model::onClick,
|
||||
enabled = state.isPrimaryButtonEnabled,
|
||||
iconResId = icon,
|
||||
showProgress = state.isTransactionSending,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
)
|
||||
if (state.isHoldToConfirmEnabled) {
|
||||
HoldToConfirmButton(
|
||||
text = stringResourceSafe(
|
||||
CoreR.string.common_hold_to,
|
||||
stringResourceSafe(R.string.yield_module_start_earning),
|
||||
),
|
||||
onConfirm = model::onClick,
|
||||
enabled = state.isPrimaryButtonEnabled,
|
||||
isLoading = state.isTransactionSending,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
val icon = if (state.isPrimaryButtonEnabled) {
|
||||
walletInterationIcon(model.userWallet)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
PrimaryButtonIconEnd(
|
||||
text = stringResourceSafe(R.string.yield_module_start_earning),
|
||||
onClick = model::onClick,
|
||||
enabled = state.isPrimaryButtonEnabled,
|
||||
iconResId = icon,
|
||||
showProgress = state.isTransactionSending,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class Params(
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ internal class YieldSupplyStartEarningEntryModel @Inject constructor(
|
|||
yieldSupplyFeeUM = YieldSupplyFeeUM.Loading,
|
||||
isPrimaryButtonEnabled = false,
|
||||
isTransactionSending = false,
|
||||
isHoldToConfirmEnabled = false,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,13 +16,14 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.isHotWallet
|
||||
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.domain.yield.supply.YieldSupplyRepository
|
||||
import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus
|
||||
import com.tangem.domain.yield.supply.models.YieldSupplyPendingStatus
|
||||
import com.tangem.domain.yield.supply.usecase.*
|
||||
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
|
||||
import com.tangem.features.yield.supply.impl.R
|
||||
|
|
@ -66,6 +67,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
|
|||
private val yieldSupplyGetMaxFeeUseCase: YieldSupplyGetMaxFeeUseCase,
|
||||
private val yieldSupplyGetCurrentFeeUseCase: YieldSupplyGetCurrentFeeUseCase,
|
||||
private val yieldSupplyRepository: YieldSupplyRepository,
|
||||
private val yieldSupplyPendingTracker: YieldSupplyPendingTracker,
|
||||
private val appsFlyerStore: AppsFlyerStore,
|
||||
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
|
||||
|
||||
|
|
@ -108,6 +110,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
|
|||
yieldSupplyFeeUM = YieldSupplyFeeUM.Loading,
|
||||
isPrimaryButtonEnabled = false,
|
||||
isTransactionSending = false,
|
||||
isHoldToConfirmEnabled = false,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -247,23 +250,27 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
|
|||
},
|
||||
)
|
||||
},
|
||||
ifRight = {
|
||||
onStartEarningTransactionSuccess(yieldSupplyFeeUM)
|
||||
ifRight = { txsData ->
|
||||
onStartEarningTransactionSuccess(yieldSupplyFeeUM, txsData)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun onStartEarningTransactionSuccess(yieldSupplyFeeUM: YieldSupplyFeeUM.Content) {
|
||||
yieldSupplyRepository.saveTokenProtocolStatus(
|
||||
userWalletId,
|
||||
cryptoCurrency,
|
||||
YieldSupplyEnterStatus.Enter,
|
||||
private suspend fun onStartEarningTransactionSuccess(
|
||||
yieldSupplyFeeUM: YieldSupplyFeeUM.Content,
|
||||
txsData: List<String>,
|
||||
) {
|
||||
yieldSupplyRepository.saveTokenProtocolPendingStatus(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
yieldSupplyPendingStatus = YieldSupplyPendingStatus.Enter(txsData),
|
||||
)
|
||||
val event = AnalyticsParam.TxSentFrom.Earning(
|
||||
blockchain = cryptoCurrency.network.name,
|
||||
token = cryptoCurrency.symbol,
|
||||
feeType = AnalyticsParam.FeeType.Normal,
|
||||
feeToken = feeCryptoCurrencyStatusFlow.value.currency.symbol,
|
||||
)
|
||||
analytics.send(
|
||||
YieldSupplyAnalytics.FundsEarned(
|
||||
|
|
@ -291,6 +298,11 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
|
|||
}
|
||||
|
||||
modelScope.launch {
|
||||
yieldSupplyPendingTracker.addPending(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
txIds = txsData,
|
||||
)
|
||||
params.callback.onTransactionSent()
|
||||
}
|
||||
}
|
||||
|
|
@ -300,6 +312,9 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
|
|||
getUserWalletUseCase(userWalletId).fold(
|
||||
ifRight = { wallet ->
|
||||
userWallet = wallet
|
||||
uiState.update {
|
||||
it.copy(isHoldToConfirmEnabled = wallet.isHotWallet)
|
||||
}
|
||||
getCurrenciesStatusUpdates()
|
||||
},
|
||||
ifLeft = {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ import com.tangem.common.ui.userwallet.ext.walletInterationIcon
|
|||
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.components.HoldToConfirmButton
|
||||
import com.tangem.core.ui.components.PrimaryButtonIconEnd
|
||||
import com.tangem.core.ui.R as CoreR
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||
|
|
@ -78,16 +80,31 @@ internal class YieldSupplyStopEarningComponent(
|
|||
)
|
||||
},
|
||||
footer = {
|
||||
PrimaryButtonIconEnd(
|
||||
text = stringResourceSafe(R.string.common_confirm),
|
||||
onClick = model::onClick,
|
||||
iconResId = walletInterationIcon(params.userWallet),
|
||||
enabled = state.isPrimaryButtonEnabled,
|
||||
showProgress = state.isTransactionSending,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
)
|
||||
val modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
|
||||
if (state.isHoldToConfirmEnabled) {
|
||||
HoldToConfirmButton(
|
||||
text = stringResourceSafe(
|
||||
CoreR.string.common_hold_to,
|
||||
stringResourceSafe(R.string.common_confirm),
|
||||
),
|
||||
onConfirm = model::onClick,
|
||||
enabled = state.isPrimaryButtonEnabled,
|
||||
isLoading = state.isTransactionSending,
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
PrimaryButtonIconEnd(
|
||||
text = stringResourceSafe(R.string.common_confirm),
|
||||
onClick = model::onClick,
|
||||
iconResId = walletInterationIcon(params.userWallet),
|
||||
enabled = state.isPrimaryButtonEnabled,
|
||||
showProgress = state.isTransactionSending,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
},
|
||||
content = {
|
||||
YieldSupplyActionContent(
|
||||
|
|
|
|||
|
|
@ -16,14 +16,16 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.isHotWallet
|
||||
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.yield.supply.INCREASE_GAS_LIMIT_FOR_SUPPLY
|
||||
import com.tangem.domain.yield.supply.YieldSupplyRepository
|
||||
import com.tangem.domain.yield.supply.increaseGasLimitBy
|
||||
import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus
|
||||
import com.tangem.domain.yield.supply.models.YieldSupplyPendingStatus
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyDeactivateUseCase
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyPendingTracker
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyStopEarningUseCase
|
||||
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
|
||||
import com.tangem.features.yield.supply.impl.R
|
||||
|
|
@ -62,6 +64,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
|
|||
private val yieldSupplyAlertFactory: YieldSupplyAlertFactory,
|
||||
private val yieldSupplyDeactivateUseCase: YieldSupplyDeactivateUseCase,
|
||||
private val yieldSupplyRepository: YieldSupplyRepository,
|
||||
private val yieldSupplyPendingTracker: YieldSupplyPendingTracker,
|
||||
private val appsFlyerStore: AppsFlyerStore,
|
||||
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
|
||||
|
||||
|
|
@ -99,6 +102,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
|
|||
yieldSupplyFeeUM = YieldSupplyFeeUM.Loading,
|
||||
isPrimaryButtonEnabled = false,
|
||||
isTransactionSending = false,
|
||||
isHoldToConfirmEnabled = params.userWallet.isHotWallet,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -169,18 +173,18 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
|
|||
)
|
||||
params.callback.onTransactionProgress(false)
|
||||
},
|
||||
ifRight = {
|
||||
onStopEarningTransactionSuccess()
|
||||
ifRight = { txData ->
|
||||
onStopEarningTransactionSuccess(txData)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun onStopEarningTransactionSuccess() {
|
||||
yieldSupplyRepository.saveTokenProtocolStatus(
|
||||
userWallet.walletId,
|
||||
cryptoCurrency,
|
||||
YieldSupplyEnterStatus.Exit,
|
||||
private suspend fun onStopEarningTransactionSuccess(txId: String) {
|
||||
yieldSupplyRepository.saveTokenProtocolPendingStatus(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
yieldSupplyPendingStatus = YieldSupplyPendingStatus.Exit(listOf(txId)),
|
||||
)
|
||||
analytics.send(
|
||||
YieldSupplyAnalytics.FundsWithdrawn(
|
||||
|
|
@ -193,6 +197,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
|
|||
blockchain = cryptoCurrency.network.name,
|
||||
token = cryptoCurrency.symbol,
|
||||
feeType = AnalyticsParam.FeeType.Normal,
|
||||
feeToken = feeCryptoCurrencyStatus.currency.symbol,
|
||||
)
|
||||
analytics.send(
|
||||
Basic.TransactionSent(
|
||||
|
|
@ -206,6 +211,11 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
|
|||
}
|
||||
|
||||
modelScope.launch {
|
||||
yieldSupplyPendingTracker.addPending(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
txIds = listOf(txId),
|
||||
)
|
||||
params.callback.onStopEarningTransactionSent()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue