Skip to content

Commit

Permalink
Merge pull request #217 from sora-xor/sca-133
Browse files Browse the repository at this point in the history
Sca-133
  • Loading branch information
arvifox authored Oct 8, 2023
2 parents e31a434 + 643fa3e commit 481403c
Show file tree
Hide file tree
Showing 18 changed files with 369 additions and 200 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ buildscript {
composeCompiler : '1.5.3',
composeConstraintLayout: '1.1.0-alpha05',
uiCore : '0.2.7',
soraCard : '0.1.51',
soraCard : '0.1.54',
lazySodium : '5.0.2',
jna : '5.8.0',
accompanist : '0.30.1',
Expand Down
3 changes: 2 additions & 1 deletion common/src/main/java/jp/co/soramitsu/common/domain/Fiat.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package jp.co.soramitsu.common.domain

import java.math.BigDecimal
import jp.co.soramitsu.common.domain.OptionsProvider.nbspace
import jp.co.soramitsu.common.util.NumbersFormatter

fun formatFiatAmount(
Expand All @@ -43,7 +44,7 @@ fun formatFiatAmount(
) = "$currencySymbol%s".format(nf.format(value, 2, checkFraction))

fun formatFiatChange(value: Double, nf: NumbersFormatter) =
String.format("%s%s %%", if (value >= 0.0001) "+" else "", nf.format(value * 100, 2)).trim()
String.format("%s%s$nbspace%%", if (value >= 0.0001) "+" else "", nf.format(value * 100, 2)).trim()

fun List<Asset>.fiatSum(): Double =
if (isNotEmpty()) map { it.fiat ?: 0.0 }.reduce { acc, d -> acc + d } else 0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,24 +56,24 @@ class FiatTest {
@Test
fun test001() {
val f = formatFiatChange(12.2394, nf)
assertEquals("+1${nbspace}223.94 %", f)
assertEquals("+1${nbspace}223.94${nbspace}%", f)
}

@Test
fun test002() {
val f = formatFiatChange(0.0004, nf)
assertEquals("+0.04 %", f)
assertEquals("+0.04${nbspace}%", f)
}

@Test
fun test003() {
val f = formatFiatChange(0.0001, nf)
assertEquals("+0.01 %", f)
assertEquals("+0.01${nbspace}%", f)
}

@Test
fun test004() {
val f = formatFiatChange(0.0000999999, nf)
assertEquals("0 %", f)
assertEquals("0${nbspace}%", f)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,15 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import jp.co.soramitsu.common.R
Expand Down Expand Up @@ -128,26 +131,28 @@ fun BasicPoolListItem(
style = MaterialTheme.customTypography.textXSBold,
color = MaterialTheme.customColors.fgSecondary,
)
ConstraintLayout(
modifier = Modifier.wrapContentSize()
) {
val (token1, token2) = createRefs()
TokenIcon(
modifier = Modifier.constrainAs(token1) {
top.linkTo(parent.top)
start.linkTo(parent.start)
},
uri = state.token1Icon,
size = Size.Small,
)
TokenIcon(
modifier = Modifier.constrainAs(token2) {
top.linkTo(parent.top)
start.linkTo(token1.start, margin = 24.dp)
},
uri = state.token2Icon,
size = Size.Small,
)
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
ConstraintLayout(
modifier = Modifier.wrapContentSize()
) {
val (token1, token2) = createRefs()
TokenIcon(
modifier = Modifier.constrainAs(token1) {
top.linkTo(parent.top)
start.linkTo(parent.start)
},
uri = state.token1Icon,
size = Size.Small,
)
TokenIcon(
modifier = Modifier.constrainAs(token2) {
top.linkTo(parent.top)
start.linkTo(token1.start, margin = 24.dp)
},
uri = state.token2Icon,
size = Size.Small,
)
}
}
Column(
modifier = Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ data class CardsState(
val cards: List<CardState> = emptyList(),
)

sealed interface CardState
sealed class CardState(
open val loading: Boolean,
)

sealed interface AssetCardState

Expand All @@ -62,7 +64,8 @@ data class TitledAmountCardState(
val collapsedState: Boolean = false,
val onCollapseClick: () -> Unit,
val onExpandClick: (() -> Unit)? = null,
) : CardState
override val loading: Boolean,
) : CardState(loading)

class FavoriteAssetsCardState(
val assets: List<AssetItemCardState>
Expand Down Expand Up @@ -118,18 +121,22 @@ fun mapAssetsToCardState(
}

data class SoraCardState(
val balance: String?,
val success: Boolean,
val ibanBalance: String?,
val kycStatus: String?,
val visible: Boolean = false,
) : CardState
override val loading: Boolean,
) : CardState(loading)

data class BuyXorState(
val visible: Boolean = false,
) : CardState
override val loading: Boolean,
) : CardState(loading)

data class ReferralState(
val visible: Boolean = false,
) : CardState
override val loading: Boolean,
) : CardState(loading)

class FavoritePoolsCardState(
val state: PoolsListState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,7 @@ interface SoraCardInteractor {

suspend fun fetchIbanBalance(): Result<String>

suspend fun fetchApplicationFee(): String

suspend fun logOutFromSoraCard()
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ internal class SoraCardClientProxy @Inject constructor(

suspend fun getKycStatus() = clientsFacade.getKycStatus()

suspend fun getApplicationFee() = clientsFacade.getApplicationFee()

suspend fun getIBAN() = clientsFacade.getIBAN()

suspend fun logout() = clientsFacade.logout()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ internal class SoraCardInteractorImpl @Inject constructor(
"%s%.2f".format(euroSign, euroValue)
}

override suspend fun fetchApplicationFee(): String = soraCardClientProxy.getApplicationFee()

override suspend fun logOutFromSoraCard() {
soraCardClientProxy.logout()
setLogout()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import android.view.View
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.ScrollState
import androidx.fragment.app.viewModels
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.compose.composable
Expand Down Expand Up @@ -84,9 +85,10 @@ class GetSoraCardFragment : SoraBaseFragment<GetSoraCardViewModel>() {
composable(
route = theOnlyRoute,
) {
val state = viewModel.state.collectAsStateWithLifecycle().value
GetSoraCardScreen(
scrollState = scrollState,
state = viewModel.state.value,
state = state,
viewModel::onSeeBlacklist,
viewModel::onEnableCard,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ fun GetSoraCardScreen(

AnnualFee()

FreeCardIssuance()
FreeCardIssuance(state.applicationFee)

Text(
modifier = Modifier
Expand All @@ -130,7 +130,6 @@ fun GetSoraCardScreen(
),
color = MaterialTheme.customColors.statusError,
)

FilledButton(
modifier = Modifier
.fillMaxWidth()
Expand Down Expand Up @@ -169,7 +168,9 @@ private fun AnnualFee() {
}

@Composable
private fun FreeCardIssuance() {
private fun FreeCardIssuance(
applicationFee: String,
) {
ContentCard(
modifier = Modifier
.fillMaxWidth()
Expand Down Expand Up @@ -203,7 +204,7 @@ private fun FreeCardIssuance() {
.fillMaxWidth()
.wrapContentHeight()
.padding(vertical = Dimens.x2),
text = stringResource(R.string.sora_card_free_card_issuance_conditions_euro),
text = stringResource(jp.co.soramitsu.oauth.R.string.details_free_card_issuance_conditions_euro, applicationFee),
style = MaterialTheme.customTypography.paragraphM,
color = MaterialTheme.customColors.fgSecondary,
)
Expand All @@ -216,7 +217,7 @@ private fun FreeCardIssuance() {
private fun PreviewGetSoraCardScreen() {
GetSoraCardScreen(
scrollState = rememberScrollState(),
state = GetSoraCardState(),
state = GetSoraCardState(applicationFee = "29"),
{}, {},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ package jp.co.soramitsu.feature_sora_card_impl.presentation
data class GetSoraCardState(
val xorRatioAvailable: Boolean = false,
val connection: Boolean = false,
val applicationFee: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package jp.co.soramitsu.feature_sora_card_impl.presentation

import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import dagger.assisted.Assisted
Expand All @@ -55,7 +54,10 @@ import jp.co.soramitsu.oauth.base.sdk.contract.SoraCardContractData
import jp.co.soramitsu.oauth.base.sdk.contract.SoraCardResult
import jp.co.soramitsu.sora.substrate.runtime.SubstrateOptionsProvider
import jp.co.soramitsu.sora.substrate.substrate.ConnectionManager
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach

Expand Down Expand Up @@ -84,33 +86,40 @@ class GetSoraCardViewModel @AssistedInject constructor(
private val _launchSoraCardRegistration = SingleLiveEvent<SoraCardContractData>()
val launchSoraCardRegistration: LiveData<SoraCardContractData> = _launchSoraCardRegistration

var state = mutableStateOf(GetSoraCardState())
private set
private val _state = MutableStateFlow(GetSoraCardState(applicationFee = "."))
val state = _state.asStateFlow()

private var applicationFeeCache: String? = null

init {
_toolbarState.value = initSmallTitle2(
title = R.string.get_sora_card_title,
)

soraCardInteractor.subscribeToSoraCardAvailabilityFlow()
.onEach {
.combine(connectionManager.connectionState) { f1, f2 ->
f1 to f2
}
.catch { onError(it) }
.onEach { (info, connection) ->
currentSoraCardContractData = createSoraCardContract(
userAvailableXorAmount = it.xorBalance.toDouble(),
isEnoughXorAvailable = it.enoughXor,
userAvailableXorAmount = info.xorBalance.toDouble(),
isEnoughXorAvailable = info.enoughXor,
)
state.value = state.value.copy(
xorRatioAvailable = it.xorRatioAvailable,
_state.value = _state.value.copy(
connection = connection,
applicationFee = fetchApplicationFee(),
xorRatioAvailable = info.xorRatioAvailable,
)
}.launchIn(viewModelScope)

connectionManager.connectionState
.catch { onError(it) }
.onEach {
state.value = state.value.copy(connection = it)
}
.launchIn(viewModelScope)
}

private suspend fun fetchApplicationFee(): String =
applicationFeeCache ?: soraCardInteractor.fetchApplicationFee().also {
applicationFeeCache = it
}

fun handleSoraCardResult(soraCardResult: SoraCardResult) {
when (soraCardResult) {
is SoraCardResult.NavigateTo -> {
Expand All @@ -120,12 +129,15 @@ class GetSoraCardViewModel @AssistedInject constructor(
OutwardsScreen.BUY -> assetsRouter.showBuyCrypto()
}
}

is SoraCardResult.Success -> {
soraCardInteractor.setStatus(soraCardResult.status)
}

is SoraCardResult.Failure -> {
soraCardInteractor.setStatus(soraCardResult.status)
}

is SoraCardResult.Canceled -> {}
is SoraCardResult.Logout -> {
soraCardInteractor.setLogout()
Expand Down
Loading

0 comments on commit 481403c

Please sign in to comment.