Updated on 2026-08-14
This commit is contained in:
parent
fbfd7476fa
commit
c1ca73561d
9 changed files with 101 additions and 129 deletions
|
|
@ -22,4 +22,6 @@ object TangemBlogUrlBuilder {
|
|||
const val RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP = "https://tangem.com/en/blog/post/give-revoke-permission/"
|
||||
|
||||
const val YIELD_SUPPLY_HOW_IT_WORKS_URL = "https://tangem.com/en/blog/post/savings-account"
|
||||
const val YIELD_SUPPLY_TOS_URL = "https://aave.com/terms-of-service"
|
||||
const val YIELD_SUPPLY_PRIVACY_URL = "https://aave.com/privacy-policy"
|
||||
}
|
||||
|
|
@ -5,15 +5,18 @@ import com.tangem.domain.tokens.repository.YieldSupplyWarningsViewedRepository
|
|||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Suppress("UnusedPrivateProperty")
|
||||
class NeedShowYieldSupplyDepositedWarningUseCase(
|
||||
private val yieldSupplyWarningsViewedRepository: YieldSupplyWarningsViewedRepository,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(cryptoCurrencyStatus: CryptoCurrencyStatus?): Boolean = withContext(dispatchers.io) {
|
||||
val hasActiveLending = cryptoCurrencyStatus?.value?.yieldSupplyStatus?.isActive == true
|
||||
if (!hasActiveLending) return@withContext false
|
||||
val showedWarnings = yieldSupplyWarningsViewedRepository.getViewedWarnings()
|
||||
return@withContext !showedWarnings.contains(cryptoCurrencyStatus?.currency?.name)
|
||||
// TEMPORARY REQUIREMENTS
|
||||
return@withContext false
|
||||
// val hasActiveLending = cryptoCurrencyStatus?.value?.yieldSupplyStatus?.isActive == true
|
||||
// if (!hasActiveLending) return@withContext false
|
||||
// val showedWarnings = yieldSupplyWarningsViewedRepository.getViewedWarnings()
|
||||
// return@withContext !showedWarnings.contains(cryptoCurrencyStatus?.currency?.name)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.network.NetworkAddress
|
||||
import com.tangem.domain.models.serialization.SerializedBigDecimal
|
||||
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
|
||||
import com.tangem.domain.tokens.repository.YieldSupplyWarningsViewedRepository
|
||||
import com.tangem.domain.tokens.mock.MockTokens
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.impl.annotations.RelaxedMockK
|
||||
import io.mockk.junit5.MockKExtension
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@ExtendWith(MockKExtension::class)
|
||||
class NeedShowYieldSupplyDepositedWarningUseCaseTest {
|
||||
|
||||
@RelaxedMockK
|
||||
private lateinit var repository: YieldSupplyWarningsViewedRepository
|
||||
|
||||
private lateinit var dispatchers: TestingCoroutineDispatcherProvider
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
dispatchers = TestingCoroutineDispatcherProvider()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN null status WHEN invoke THEN returns false`() = runTest {
|
||||
val useCase = NeedShowYieldSupplyDepositedWarningUseCase(repository, dispatchers)
|
||||
|
||||
val result = useCase.invoke(null)
|
||||
|
||||
assertThat(result).isFalse()
|
||||
coVerify(exactly = 0) { repository.getViewedWarnings() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN inactive lending WHEN invoke THEN returns false`() = runTest {
|
||||
val useCase = NeedShowYieldSupplyDepositedWarningUseCase(repository, dispatchers)
|
||||
val status = createStatus(isActive = false)
|
||||
|
||||
val result = useCase.invoke(status)
|
||||
|
||||
assertThat(result).isFalse()
|
||||
coVerify(exactly = 0) { repository.getViewedWarnings() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN active lending and not viewed WHEN invoke THEN returns true`() = runTest {
|
||||
val useCase = NeedShowYieldSupplyDepositedWarningUseCase(repository, dispatchers)
|
||||
val status = createStatus(isActive = true)
|
||||
coEvery { repository.getViewedWarnings() } returns emptySet()
|
||||
|
||||
val result = useCase.invoke(status)
|
||||
|
||||
assertThat(result).isTrue()
|
||||
coVerify(exactly = 1) { repository.getViewedWarnings() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN active lending and already viewed WHEN invoke THEN returns false`() = runTest {
|
||||
val useCase = NeedShowYieldSupplyDepositedWarningUseCase(repository, dispatchers)
|
||||
val status = createStatus(isActive = true)
|
||||
coEvery { repository.getViewedWarnings() } returns setOf(status.currency.name)
|
||||
|
||||
val result = useCase.invoke(status)
|
||||
|
||||
assertThat(result).isFalse()
|
||||
coVerify(exactly = 1) { repository.getViewedWarnings() }
|
||||
}
|
||||
|
||||
private fun createStatus(isActive: Boolean): CryptoCurrencyStatus {
|
||||
val currency = MockTokens.token1
|
||||
val yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = isActive,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
)
|
||||
val value = CryptoCurrencyStatus.NoQuote(
|
||||
amount = SerializedBigDecimal.ZERO,
|
||||
yieldBalance = null,
|
||||
yieldSupplyStatus = yieldSupplyStatus,
|
||||
hasCurrentNetworkTransactions = false,
|
||||
pendingTransactions = emptySet(),
|
||||
networkAddress = NetworkAddress.Single(
|
||||
defaultAddress = NetworkAddress.Address(
|
||||
value = "address",
|
||||
type = NetworkAddress.Address.Type.Primary,
|
||||
),
|
||||
),
|
||||
sources = CryptoCurrencyStatus.Sources(),
|
||||
)
|
||||
|
||||
return CryptoCurrencyStatus(
|
||||
currency = currency,
|
||||
value = value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.features.yield.supply.impl.common
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Trigger for entering/exiting protocol from other components
|
||||
*/
|
||||
interface YieldSupplyProtocolTrigger {
|
||||
suspend fun onEnterProtocol()
|
||||
suspend fun onExitProtocol()
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener to observe entering/exiting protocol events
|
||||
*/
|
||||
interface YieldSupplyProtocolListener {
|
||||
val enterProtocolTriggerFlow: Flow<Unit>
|
||||
val exitProtocolTriggerFlow: Flow<Unit>
|
||||
}
|
||||
|
||||
@Singleton
|
||||
internal class DefaultYieldSupplyProtocolTrigger @Inject constructor() :
|
||||
YieldSupplyProtocolTrigger,
|
||||
YieldSupplyProtocolListener {
|
||||
|
||||
override val enterProtocolTriggerFlow = MutableSharedFlow<Unit>()
|
||||
override val exitProtocolTriggerFlow = MutableSharedFlow<Unit>()
|
||||
|
||||
override suspend fun onEnterProtocol() {
|
||||
enterProtocolTriggerFlow.emit(Unit)
|
||||
}
|
||||
|
||||
override suspend fun onExitProtocol() {
|
||||
exitProtocolTriggerFlow.emit(Unit)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,10 @@ package com.tangem.features.yield.supply.impl.di
|
|||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.features.yield.supply.impl.DefaultYieldSupplyFeatureToggles
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles
|
||||
import com.tangem.features.yield.supply.impl.common.DefaultYieldSupplyProtocolTrigger
|
||||
import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolListener
|
||||
import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolTrigger
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -19,3 +23,16 @@ internal object YieldSupplyFeatureModule {
|
|||
return DefaultYieldSupplyFeatureToggles(featureTogglesManager)
|
||||
}
|
||||
}
|
||||
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@Module
|
||||
internal interface YieldSupplyProtocolModuleBinds {
|
||||
|
||||
@Singleton
|
||||
@Binds
|
||||
fun bindYieldSupplyProtocolTrigger(impl: DefaultYieldSupplyProtocolTrigger): YieldSupplyProtocolTrigger
|
||||
|
||||
@Singleton
|
||||
@Binds
|
||||
fun bindYieldSupplyProtocolListener(impl: DefaultYieldSupplyProtocolTrigger): YieldSupplyProtocolListener
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyIsAvailableUseCase
|
|||
import com.tangem.features.yield.supply.impl.R
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyComponent
|
||||
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
|
||||
import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolListener
|
||||
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
|
||||
|
|
@ -56,6 +57,7 @@ internal class YieldSupplyModel @Inject constructor(
|
|||
private val yieldSupplyIsAvailableUseCase: YieldSupplyIsAvailableUseCase,
|
||||
private val yieldSupplyActivateUseCase: YieldSupplyActivateUseCase,
|
||||
private val yieldSupplyDeactivateUseCase: YieldSupplyDeactivateUseCase,
|
||||
private val yieldSupplyProtocolListener: YieldSupplyProtocolListener,
|
||||
) : Model(), YieldSupplyClickIntents {
|
||||
|
||||
private val params = paramsContainer.require<YieldSupplyComponent.Params>()
|
||||
|
|
@ -83,6 +85,28 @@ internal class YieldSupplyModel @Inject constructor(
|
|||
|
||||
init {
|
||||
checkIfYieldSupplyIsAvailable()
|
||||
observeProtocolEvents()
|
||||
}
|
||||
|
||||
private fun observeProtocolEvents() {
|
||||
yieldSupplyProtocolListener.exitProtocolTriggerFlow.onEach {
|
||||
uiState.update {
|
||||
YieldSupplyUM.Processing.Exit
|
||||
}
|
||||
coroutineScope.launch(dispatchers.io) {
|
||||
delay(PROCESSING_UPDATE_DELAY)
|
||||
fetchCurrencyStatusUseCase(userWalletId = userWallet.walletId, cryptoCurrency.id)
|
||||
}
|
||||
}.launchIn(modelScope)
|
||||
yieldSupplyProtocolListener.enterProtocolTriggerFlow.onEach {
|
||||
uiState.update {
|
||||
YieldSupplyUM.Processing.Enter
|
||||
}
|
||||
coroutineScope.launch(dispatchers.io) {
|
||||
delay(PROCESSING_UPDATE_DELAY)
|
||||
fetchCurrencyStatusUseCase(userWalletId = userWallet.walletId, cryptoCurrency.id)
|
||||
}
|
||||
}.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun checkIfYieldSupplyIsAvailable() {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.tangem.features.yield.supply.impl.R
|
|||
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
|
||||
import com.tangem.features.yield.supply.impl.promo.YieldSupplyPromoConfig
|
||||
import com.tangem.features.yield.supply.impl.promo.entity.YieldSupplyPromoUM
|
||||
import com.tangem.utils.TangemBlogUrlBuilder
|
||||
import com.tangem.utils.TangemBlogUrlBuilder.YIELD_SUPPLY_HOW_IT_WORKS_URL
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import javax.inject.Inject
|
||||
|
|
@ -31,8 +32,8 @@ internal class YieldSupplyPromoModel @Inject constructor(
|
|||
val params: YieldSupplyPromoComponent.Params = paramsContainer.require()
|
||||
|
||||
val uiState: YieldSupplyPromoUM = YieldSupplyPromoUM(
|
||||
tosLink = "https://tangem.com/terms-of-service/", // TODO replace with real link
|
||||
policyLink = "https://tangem.com/privacy-policy/", // TODO replace with real link
|
||||
tosLink = TangemBlogUrlBuilder.YIELD_SUPPLY_TOS_URL,
|
||||
policyLink = TangemBlogUrlBuilder.YIELD_SUPPLY_PRIVACY_URL,
|
||||
title = resourceReference(R.string.yield_module_promo_screen_title),
|
||||
subtitle = resourceReference(
|
||||
R.string.yield_module_promo_screen_variable_rate_info,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ 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.UserWallet
|
||||
import com.tangem.domain.tokens.FetchCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
|
|
@ -29,6 +28,7 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyStartEarningUseCase
|
|||
import com.tangem.features.yield.supply.impl.R
|
||||
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
|
||||
import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory
|
||||
import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolTrigger
|
||||
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM
|
||||
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM
|
||||
import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionInProgressTransformer
|
||||
|
|
@ -41,7 +41,6 @@ import com.tangem.features.yield.supply.impl.subcomponents.startearning.model.tr
|
|||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import com.tangem.utils.transformer.update
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -63,11 +62,11 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
|
|||
private val yieldSupplyEstimateEnterFeeUseCase: YieldSupplyEstimateEnterFeeUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val yieldSupplyNotificationsUpdateTrigger: YieldSupplyNotificationsUpdateTrigger,
|
||||
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
|
||||
private val yieldSupplyAlertFactory: YieldSupplyAlertFactory,
|
||||
private val yieldSupplyActivateUseCase: YieldSupplyActivateUseCase,
|
||||
private val yieldSupplyGetTokenStatusUseCase: YieldSupplyGetTokenStatusUseCase,
|
||||
private val yieldSupplyMinAmountUseCase: YieldSupplyMinAmountUseCase,
|
||||
private val yieldSupplyProtocolTrigger: YieldSupplyProtocolTrigger,
|
||||
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
|
||||
|
||||
private val params: YieldSupplyStartEarningComponent.Params = paramsContainer.require()
|
||||
|
|
@ -253,14 +252,9 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
|
|||
)
|
||||
},
|
||||
ifRight = {
|
||||
yieldSupplyActivateUseCase(cryptoCurrency)
|
||||
modelScope.launch(NonCancellable) {
|
||||
fetchCurrencyStatusUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrency.id,
|
||||
)
|
||||
}
|
||||
yieldSupplyProtocolTrigger.onEnterProtocol()
|
||||
analytics.send(YieldSupplyAnalytics.FundsEarned)
|
||||
yieldSupplyActivateUseCase(cryptoCurrency)
|
||||
modelScope.launch {
|
||||
params.callback.onTransactionSent()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ 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.tokens.FetchCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
|
|
@ -22,6 +21,7 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyStopEarningUseCase
|
|||
import com.tangem.features.yield.supply.impl.R
|
||||
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
|
||||
import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory
|
||||
import com.tangem.features.yield.supply.impl.common.YieldSupplyProtocolTrigger
|
||||
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM
|
||||
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM
|
||||
import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionInProgressTransformer
|
||||
|
|
@ -35,7 +35,6 @@ import com.tangem.utils.TangemBlogUrlBuilder
|
|||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import com.tangem.utils.transformer.update
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -56,7 +55,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
|
|||
private val yieldSupplyNotificationsUpdateTrigger: YieldSupplyNotificationsUpdateTrigger,
|
||||
private val yieldSupplyAlertFactory: YieldSupplyAlertFactory,
|
||||
private val yieldSupplyDeactivateUseCase: YieldSupplyDeactivateUseCase,
|
||||
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
|
||||
private val yieldSupplyProtocolTrigger: YieldSupplyProtocolTrigger,
|
||||
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
|
||||
|
||||
private val params: YieldSupplyStopEarningComponent.Params = paramsContainer.require()
|
||||
|
|
@ -159,6 +158,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
|
|||
)
|
||||
},
|
||||
ifRight = {
|
||||
yieldSupplyProtocolTrigger.onExitProtocol()
|
||||
analytics.send(
|
||||
YieldSupplyAnalytics.FundsWithdrawn(
|
||||
token = cryptoCurrency.symbol,
|
||||
|
|
@ -166,10 +166,9 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
|
|||
),
|
||||
)
|
||||
yieldSupplyDeactivateUseCase(cryptoCurrency)
|
||||
modelScope.launch(NonCancellable) {
|
||||
fetchCurrencyStatusUseCase(userWalletId = userWallet.walletId, cryptoCurrency.id)
|
||||
}
|
||||
modelScope.launch {
|
||||
params.callback.onTransactionSent()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue