Skip to content

Commit

Permalink
sc-42
Browse files Browse the repository at this point in the history
  • Loading branch information
arvifox committed Jul 31, 2024
1 parent 88d86ad commit 4088d33
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import jp.co.soramitsu.ui_core.component.button.BleachedButton
import jp.co.soramitsu.ui_core.component.button.properties.Order
import jp.co.soramitsu.ui_core.component.button.properties.Size
import jp.co.soramitsu.ui_core.component.card.ContentCard
import jp.co.soramitsu.ui_core.extensions.withOpacity
import jp.co.soramitsu.ui_core.resources.Dimens
import jp.co.soramitsu.ui_core.theme.customColors
import jp.co.soramitsu.ui_core.theme.customTypography
Expand Down Expand Up @@ -186,24 +187,28 @@ internal fun AssetDetailsBalanceCard(
AmountCardIcon(
res = R.drawable.ic_new_arrow_up_24,
text = stringResource(id = R.string.common_send),
enabled = true,
onClick = onSendClick,
)
}
AmountCardIcon(
res = R.drawable.ic_new_arrow_down_24,
text = stringResource(id = R.string.common_receive),
enabled = true,
onClick = onReceiveClick,
)
AmountCardIcon(
res = R.drawable.ic_refresh_24,
text = stringResource(id = R.string.polkaswap_swap_title),
enabled = true,
onClick = onSwapClick,
)

if (buyCryptoAvailable && onBuyCryptoClick != null) {
AmountCardIcon(
res = R.drawable.ic_buy_crypto,
text = stringResource(id = R.string.common_buy),
enabled = false,
onClick = onBuyCryptoClick
)
}
Expand All @@ -216,6 +221,7 @@ internal fun AssetDetailsBalanceCard(
private fun AmountCardIcon(
@DrawableRes res: Int,
text: String,
enabled: Boolean,
onClick: () -> Unit,
) {
Column(
Expand All @@ -228,6 +234,7 @@ private fun AmountCardIcon(
shape = CircleShape,
size = Size.Large,
order = Order.TERTIARY,
enabled = enabled,
leftIcon = painterResource(res),
onClick = onClick,
)
Expand All @@ -238,7 +245,7 @@ private fun AmountCardIcon(
.padding(top = Dimens.x1),
text = text,
style = MaterialTheme.customTypography.textXSBold,
color = MaterialTheme.customColors.fgSecondary,
color = MaterialTheme.customColors.fgSecondary.withOpacity(opacity = if (enabled) 1.0f else 0.3f),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ internal fun ProfileItems(
icon = R.drawable.ic_buy_crypto,
onClick = onSoraCardClick,
)
CategoryItem(
modifier = Modifier
.testTagAsId("BuyXor")
.padding(top = Dimens.x2),
title = stringResource(id = R.string.buy_crypto_buy_xor_with_fiat_title),
subtitle = stringResource(id = R.string.buy_crypto_buy_xor_with_fiat_subtitle),
icon = R.drawable.ic_settings_buy_crypto,
onClick = onBuyCrypto,
)
// CategoryItem(
// modifier = Modifier
// .testTagAsId("BuyXor")
// .padding(top = Dimens.x2),
// title = stringResource(id = R.string.buy_crypto_buy_xor_with_fiat_title),
// subtitle = stringResource(id = R.string.buy_crypto_buy_xor_with_fiat_subtitle),
// icon = R.drawable.ic_settings_buy_crypto,
// onClick = onBuyCrypto,
// )
}
CategoryItem(
modifier = Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,20 @@ import jp.co.soramitsu.oauth.base.sdk.contract.IbanInfo
import jp.co.soramitsu.oauth.base.sdk.contract.SoraCardCommonVerification
import jp.co.soramitsu.sora.substrate.runtime.SubstrateOptionsProvider
import kotlin.math.min
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch

internal class SoraCardInteractorImpl @Inject constructor(
private val assetsInteractor: AssetsInteractor,
Expand All @@ -82,51 +86,60 @@ internal class SoraCardInteractorImpl @Inject constructor(

private val _ibanFlow = MutableStateFlow<IbanInfo?>(null)
private val _phoneFlow = MutableStateFlow("")
private val _verStatus = MutableStateFlow(SoraCardCommonVerification.NotFound)

@OptIn(FlowPreview::class)
@Suppress("UNCHECKED_CAST")
override suspend fun initialize() {
combine(
flow { emit(soraCardClientProxy.init()) },
needInstallUpdate(),
fetchApplicationFee(),
_ibanFlow.asStateFlow(),
subscribeToSoraCardAvailabilityFlow(),
checkSoraCardPending(),
_phoneFlow.asStateFlow(),
) { flows ->
val init = flows[0] as Pair<Boolean, String>
val needUpdate = flows[1] as Boolean
val fee = flows[2] as String
val ibanInfo = flows[3] as IbanInfo?
val availability = flows[4] as SoraCardAvailabilityInfo
val verification = flows[5] as SoraCardCommonVerification
val phone = flows[6] as String
SoraCardBasicStatus(
initialized = init.first,
initError = init.second,
availabilityInfo = availability,
verification = verification,
needInstallUpdate = needUpdate,
applicationFee = fee,
ibanInfo = ibanInfo,
phone = phone,
)
}
.debounce(1000)
.collect {
_soraCardBasicStatus.value = it
coroutineScope {
launch {
resetInfo()
}
resetInfo()
launch {
checkSoraCardPending()
}
combine(
flow { emit(soraCardClientProxy.init()) },
needInstallUpdate(),
fetchApplicationFee(),
_ibanFlow.asStateFlow(),
subscribeToSoraCardAvailabilityFlow(),
_verStatus.asStateFlow(),
_phoneFlow.asStateFlow(),
) { flows ->
val init = flows[0] as Pair<Boolean, String>
val needUpdate = flows[1] as Boolean
val fee = flows[2] as String
val ibanInfo = flows[3] as IbanInfo?
val availability = flows[4] as SoraCardAvailabilityInfo
val verification = flows[5] as SoraCardCommonVerification
val phone = flows[6] as String
SoraCardBasicStatus(
initialized = init.first,
initError = init.second,
availabilityInfo = availability,
verification = verification,
needInstallUpdate = needUpdate,
applicationFee = fee,
ibanInfo = ibanInfo,
phone = phone,
)
}
.debounce(1000)
.collectLatest {
_soraCardBasicStatus.value = it
}
}
}

override val basicStatus: StateFlow<SoraCardBasicStatus> = _soraCardBasicStatus.asStateFlow()

private suspend fun checkSoraCardPending() = flow {
private suspend fun checkSoraCardPending() {
var isLoopInProgress = true
while (isLoopInProgress) {
val status =
soraCardClientProxy.getKycStatus().getOrDefault(SoraCardCommonVerification.NotFound)
emit(status)
_verStatus.value = status
if (status != SoraCardCommonVerification.Pending) {
isLoopInProgress = false
} else {
Expand Down Expand Up @@ -156,19 +169,15 @@ internal class SoraCardInteractorImpl @Inject constructor(
}

override suspend fun setStatus(status: SoraCardCommonVerification) {
_soraCardBasicStatus.value = _soraCardBasicStatus.value.copy(
verification = status,
)
_verStatus.value = status
resetInfo()
}

override suspend fun setLogout() {
soraCardClientProxy.logout()
_soraCardBasicStatus.value = _soraCardBasicStatus.value.copy(
verification = SoraCardCommonVerification.NotFound,
ibanInfo = null,
phone = null,
)
_verStatus.value = SoraCardCommonVerification.NotFound
_ibanFlow.value = null
_phoneFlow.value = ""
}

private fun subscribeToSoraCardAvailabilityFlow() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,10 @@ class SoraCardDetailsViewModel @Inject constructor(
ibanCache = basicStatus.ibanInfo
val phoneFormatted = basicStatus.phone?.let { "+$it" }
_soraCardDetailsScreenState.value = local.copy(
soraCardIBANCardState = basicStatus.ibanInfo?.let { iban ->
SoraCardIBANCardState(
iban.iban,
iban.ibanStatus == IbanStatus.CLOSED,
)
},
soraCardIBANCardState = SoraCardIBANCardState(
iban = basicStatus.ibanInfo?.iban.orEmpty(),
closed = basicStatus.ibanInfo?.ibanStatus == IbanStatus.CLOSED,
),
soraCardMainSoraContentCardState = local.soraCardMainSoraContentCardState.copy(
balance = basicStatus.ibanInfo?.balance,
phone = phoneFormatted,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ fun SoraCardMainSoraContentCard(
.padding(horizontal = Dimens.x1)
.weight(1f),
size = Size.Large,
enabled = true,
enabled = false,
order = Order.PRIMARY,
onClick = onExchangeXor,
text = stringResource(id = jp.co.soramitsu.oauth.R.string.exchange_xor),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package jp.co.soramitsu.feature_sora_card_impl.presentation.get.card

import java.math.BigDecimal
import jp.co.soramitsu.androidfoundation.coroutine.CoroutineManager
import jp.co.soramitsu.androidfoundation.testing.MainCoroutineRule
import jp.co.soramitsu.demeter.domain.DemeterFarmingInteractor
import jp.co.soramitsu.feature_assets_api.domain.AssetsInteractor
import jp.co.soramitsu.feature_polkaswap_api.domain.interfaces.PoolsInteractor
import jp.co.soramitsu.feature_sora_card_api.domain.SoraCardInteractor
import jp.co.soramitsu.feature_sora_card_impl.domain.SoraCardClientProxy
import jp.co.soramitsu.feature_sora_card_impl.domain.SoraCardInteractorImpl
import jp.co.soramitsu.oauth.base.sdk.contract.IbanInfo
import jp.co.soramitsu.oauth.base.sdk.contract.IbanStatus
import jp.co.soramitsu.oauth.base.sdk.contract.SoraCardCommonVerification
import jp.co.soramitsu.test_data.PolkaswapTestData.POOL_DATA
import jp.co.soramitsu.test_data.TestAssets
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.wheneverBlocking

@RunWith(MockitoJUnitRunner::class)
@OptIn(ExperimentalCoroutinesApi::class)
class SoraCardInteractorTest {

@get:Rule
var mainCoroutineRule = MainCoroutineRule()

@Mock
private lateinit var ai: AssetsInteractor

@Mock
private lateinit var pi: PoolsInteractor

@Mock
private lateinit var sccp: SoraCardClientProxy

@Mock
private lateinit var dfi: DemeterFarmingInteractor

@Mock
private lateinit var cm: CoroutineManager

private lateinit var soraCardInteractor: SoraCardInteractor

@OptIn(ExperimentalStdlibApi::class)
@Before
fun setUp() = runTest {
`when`(cm.io).thenReturn(this.coroutineContext[CoroutineDispatcher]!!)
wheneverBlocking { sccp.init() } doReturn (true to "")
wheneverBlocking { sccp.getVersion() } doReturn Result.success("2.3.4")
wheneverBlocking { sccp.getApplicationFee() } doReturn "$8.98"
wheneverBlocking {
sccp.getKycStatus()
} doReturn Result.success(SoraCardCommonVerification.Successful)
wheneverBlocking { ai.subscribeAssetOfCurAccount(any()) } doReturn flowOf(TestAssets.xorAsset())
wheneverBlocking { pi.getPoolsCacheOfCurAccount() } doReturn listOf(POOL_DATA)
wheneverBlocking { dfi.getStakedFarmedBalanceOfAsset(any()) } doReturn BigDecimal.ONE
soraCardInteractor = SoraCardInteractorImpl(
assetsInteractor = ai,
poolsInteractor = pi,
soraCardClientProxy = sccp,
demeterFarmingInteractor = dfi,
coroutineManager = cm,
)
}

@Test
fun `test init with full data`() = runTest {
wheneverBlocking { sccp.getIBAN() } doReturn Result.success(
IbanInfo(
"iban",
IbanStatus.ACTIVE,
"$12.34",
"ok",
)
)
wheneverBlocking { sccp.getPhone() } doReturn "+123"
advanceUntilIdle()
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
soraCardInteractor.initialize()
}
advanceTimeBy(1100.milliseconds)
val bs = soraCardInteractor.basicStatus.value
assertTrue(bs.initialized)
}

@Test
fun `test call status set`() = runTest {
wheneverBlocking { sccp.getIBAN() } doReturn Result.success(null)
wheneverBlocking { sccp.getPhone() } doReturn "+123"
advanceUntilIdle()
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
soraCardInteractor.initialize()
}
advanceTimeBy(1100.milliseconds)
var bs = soraCardInteractor.basicStatus.value
assertTrue(bs.initialized)
soraCardInteractor.setStatus(SoraCardCommonVerification.Pending)
advanceUntilIdle()
bs = soraCardInteractor.basicStatus.value
assertTrue(bs.initialized)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ class WalletRepositoryImpl @Inject constructor(
val card = CardsHubMapper.map(cardLocal)
when (card?.cardType) {
CardHubType.GET_SORA_CARD -> if (soraCard) card else null
CardHubType.BUY_XOR_TOKEN -> if (soraCard) card else null
// CardHubType.BUY_XOR_TOKEN -> if (soraCard) card else null
CardHubType.BUY_XOR_TOKEN -> null
else -> card
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ class CardsHubViewModel @Inject constructor(
_state.value = _state.value.copy(
accountAddress = data.first.substrateAddress,
curAccount = data.first.accountTitle(),
loading = false,
)
val flows = data.second.filter { it.visibility }.map { cardHub ->
when (cardHub.cardType) {
Expand Down
Loading

0 comments on commit 4088d33

Please sign in to comment.