From d6404db31177d73054db442d9d59d98c9830c9a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Romano?= <91881450+aromano-bc@users.noreply.github.com> Date: Fri, 25 Nov 2022 13:34:21 +0000 Subject: [PATCH] feat(on_hold): PAY-466 [Android] V1 - New On Hold page - Frontend (#4137) --- .../android/ui/locks/LockItemDelegate.kt | 37 -- .../android/ui/locks/LocksDetailsActivity.kt | 67 +-- .../ui/locks/LocksDetailsDelegateAdapter.kt | 14 - .../android/ui/locks/LocksDetailsScreen.kt | 410 ++++++++++++++++++ .../res/layout/activity_on_hold_details.xml | 148 ------- app/src/main/res/layout/lock_item.xml | 29 -- .../payments/data/WithdrawalLocksResponse.kt | 3 +- .../api/services/PaymentsService.kt | 9 +- .../paymentmethods/model/FundsLocksModel.kt | 3 +- .../blockchain/extensions/KotlinExtensions.kt | 30 ++ .../componentlib/tablerow/TableRow.kt | 7 +- .../core/payments/PaymentsRepository.kt | 8 +- .../core/payments/PaymentsRepositoryTest.kt | 12 +- .../src/main/res/values-es/strings.xml | 2 +- .../src/main/res/values-fr/strings.xml | 2 +- .../src/main/res/values-pt/strings.xml | 2 +- .../src/main/res/values-ru/strings.xml | 2 +- .../src/main/res/values/strings.xml | 8 +- 18 files changed, 490 insertions(+), 303 deletions(-) delete mode 100644 app/src/main/java/piuk/blockchain/android/ui/locks/LockItemDelegate.kt delete mode 100644 app/src/main/java/piuk/blockchain/android/ui/locks/LocksDetailsDelegateAdapter.kt create mode 100644 app/src/main/java/piuk/blockchain/android/ui/locks/LocksDetailsScreen.kt delete mode 100644 app/src/main/res/layout/activity_on_hold_details.xml delete mode 100644 app/src/main/res/layout/lock_item.xml create mode 100644 common/interface/src/main/kotlin/com/blockchain/extensions/KotlinExtensions.kt diff --git a/app/src/main/java/piuk/blockchain/android/ui/locks/LockItemDelegate.kt b/app/src/main/java/piuk/blockchain/android/ui/locks/LockItemDelegate.kt deleted file mode 100644 index 2b360ffff4..0000000000 --- a/app/src/main/java/piuk/blockchain/android/ui/locks/LockItemDelegate.kt +++ /dev/null @@ -1,37 +0,0 @@ -package piuk.blockchain.android.ui.locks - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView -import com.blockchain.domain.paymentmethods.model.FundsLock -import com.blockchain.utils.capitalizeFirstChar -import piuk.blockchain.android.databinding.LockItemBinding -import piuk.blockchain.android.ui.adapters.AdapterDelegate - -class LockItemDelegate : AdapterDelegate { - - override fun isForViewType(items: List, position: Int): Boolean = true - - override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder = - LockItemViewHolder( - LockItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) - ) - - override fun onBindViewHolder( - items: List, - position: Int, - holder: RecyclerView.ViewHolder - ) = (holder as LockItemViewHolder).bind(items[position]) -} - -private class LockItemViewHolder( - private val binding: LockItemBinding -) : RecyclerView.ViewHolder(binding.root) { - - fun bind(lock: FundsLock) { - with(binding) { - dateLock.text = "${lock.date.month.name.capitalizeFirstChar()} ${lock.date.dayOfMonth}, ${lock.date.year}" - amountLock.text = lock.amount.toStringWithSymbol() - } - } -} diff --git a/app/src/main/java/piuk/blockchain/android/ui/locks/LocksDetailsActivity.kt b/app/src/main/java/piuk/blockchain/android/ui/locks/LocksDetailsActivity.kt index 1d65b0ffd0..1a4dd0a0e9 100644 --- a/app/src/main/java/piuk/blockchain/android/ui/locks/LocksDetailsActivity.kt +++ b/app/src/main/java/piuk/blockchain/android/ui/locks/LocksDetailsActivity.kt @@ -4,24 +4,15 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle -import android.text.method.LinkMovementMethod +import androidx.activity.compose.setContent import com.blockchain.commonarch.presentation.base.BlockchainActivity -import com.blockchain.componentlib.databinding.ToolbarGeneralBinding import com.blockchain.domain.paymentmethods.model.FundsLocks import com.blockchain.utils.unsafeLazy -import piuk.blockchain.android.R -import piuk.blockchain.android.databinding.ActivityOnHoldDetailsBinding import piuk.blockchain.android.support.SupportCentreActivity -import piuk.blockchain.android.ui.customviews.BlockchainListDividerDecor import piuk.blockchain.android.urllinks.TRADING_ACCOUNT_LOCKS -import piuk.blockchain.android.util.StringUtils class LocksDetailsActivity : BlockchainActivity() { - private val binding: ActivityOnHoldDetailsBinding by lazy { - ActivityOnHoldDetailsBinding.inflate(layoutInflater) - } - private val fundsLocks: FundsLocks by unsafeLazy { intent?.getSerializableExtra(KEY_LOCKS) as FundsLocks } @@ -29,55 +20,23 @@ class LocksDetailsActivity : BlockchainActivity() { override val alwaysDisableScreenshots: Boolean get() = false - override val toolbarBinding: ToolbarGeneralBinding - get() = binding.toolbar - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(binding.root) - updateToolbar( - toolbarTitle = getString(R.string.funds_locked_details_toolbar), - backAction = { onBackPressedDispatcher.onBackPressed() } - ) - setUpRecyclerView() - setUpTextInfo() - } - - private fun setUpRecyclerView() { - val locksDetailsDelegateAdapter = LocksDetailsDelegateAdapter() - locksDetailsDelegateAdapter.items = fundsLocks.locks - binding.recyclerViewLocks.apply { - adapter = locksDetailsDelegateAdapter - addItemDecoration(BlockchainListDividerDecor(context)) + setContent { + LocksDetailsScreen( + locks = fundsLocks, + backClicked = { onBackPressedDispatcher.onBackPressed() }, + learnMoreClicked = { + startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(TRADING_ACCOUNT_LOCKS))) + }, + contactSupportClicked = { + startActivity(SupportCentreActivity.newIntent(this, FUND_LOCKS_SUPPORT)) + }, + okClicked = { finish() } + ) } } - private fun setUpTextInfo() { - val amountOnHold = fundsLocks.onHoldTotalAmount.toStringWithSymbol() - with(binding) { - totalAmount.text = amountOnHold - titleAmount.text = getString(R.string.funds_locked_details_title, amountOnHold) - learnMore.setOnClickListener { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(TRADING_ACCOUNT_LOCKS))) } - - contactSupport.apply { - movementMethod = LinkMovementMethod.getInstance() - text = setContactSupportLink(R.string.funds_locked_details_contact_support) - } - } - } - - private fun setContactSupportLink(stringId: Int): CharSequence { - return StringUtils.getStringWithMappedAnnotations( - this, - stringId, - emptyMap() - ) { onSupportClicked() } - } - - private fun onSupportClicked() { - startActivity(SupportCentreActivity.newIntent(this, FUND_LOCKS_SUPPORT)) - } - companion object { private const val KEY_LOCKS = "LOCKS" private const val FUND_LOCKS_SUPPORT = "Funds Locks" diff --git a/app/src/main/java/piuk/blockchain/android/ui/locks/LocksDetailsDelegateAdapter.kt b/app/src/main/java/piuk/blockchain/android/ui/locks/LocksDetailsDelegateAdapter.kt deleted file mode 100644 index 949cac8908..0000000000 --- a/app/src/main/java/piuk/blockchain/android/ui/locks/LocksDetailsDelegateAdapter.kt +++ /dev/null @@ -1,14 +0,0 @@ -package piuk.blockchain.android.ui.locks - -import com.blockchain.domain.paymentmethods.model.FundsLock -import piuk.blockchain.android.ui.adapters.AdapterDelegatesManager -import piuk.blockchain.android.ui.adapters.DelegationAdapter - -class LocksDetailsDelegateAdapter : DelegationAdapter(AdapterDelegatesManager(), emptyList()) { - - init { - with(delegatesManager) { - addAdapterDelegate(LockItemDelegate()) - } - } -} diff --git a/app/src/main/java/piuk/blockchain/android/ui/locks/LocksDetailsScreen.kt b/app/src/main/java/piuk/blockchain/android/ui/locks/LocksDetailsScreen.kt new file mode 100644 index 0000000000..05ea350bb3 --- /dev/null +++ b/app/src/main/java/piuk/blockchain/android/ui/locks/LocksDetailsScreen.kt @@ -0,0 +1,410 @@ +package piuk.blockchain.android.ui.locks + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.blockchain.componentlib.basic.ComposeColors +import com.blockchain.componentlib.basic.ComposeGravities +import com.blockchain.componentlib.basic.ComposeTypographies +import com.blockchain.componentlib.basic.Image +import com.blockchain.componentlib.basic.ImageResource +import com.blockchain.componentlib.basic.SimpleText +import com.blockchain.componentlib.button.MinimalButton +import com.blockchain.componentlib.button.PrimaryButton +import com.blockchain.componentlib.button.SmallMinimalButton +import com.blockchain.componentlib.divider.HorizontalDivider +import com.blockchain.componentlib.navigation.NavigationBar +import com.blockchain.componentlib.tablerow.TableRow +import com.blockchain.componentlib.theme.AppTheme +import com.blockchain.componentlib.theme.White +import com.blockchain.domain.paymentmethods.model.FundsLock +import com.blockchain.domain.paymentmethods.model.FundsLocks +import info.blockchain.balance.CryptoCurrency +import info.blockchain.balance.CurrencyType +import info.blockchain.balance.FiatCurrency +import info.blockchain.balance.Money +import java.math.BigInteger +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import piuk.blockchain.android.R + +@Composable +fun LocksDetailsScreen( + locks: FundsLocks, + backClicked: () -> Unit, + learnMoreClicked: () -> Unit, + contactSupportClicked: () -> Unit, + okClicked: () -> Unit, +) { + Column( + Modifier.fillMaxSize() + .background(White) + ) { + Column( + Modifier.fillMaxWidth() + .weight(1f) + ) { + NavigationBar( + title = stringResource(R.string.funds_locked_details_toolbar), + onBackButtonClick = backClicked, + ) + + SimpleText( + modifier = Modifier.padding( + top = AppTheme.dimensions.standardSpacing, + start = AppTheme.dimensions.smallSpacing, + ), + text = stringResource(R.string.funds_locked_details_title), + style = ComposeTypographies.Caption2, + color = ComposeColors.Title, + gravity = ComposeGravities.Start, + ) + SimpleText( + modifier = Modifier.padding( + top = AppTheme.dimensions.composeSmallestSpacing, + start = AppTheme.dimensions.smallSpacing, + ), + text = locks.onHoldTotalAmount.toStringWithSymbol(), + style = ComposeTypographies.Title3, + color = ComposeColors.Title, + gravity = ComposeGravities.Start, + ) + + HorizontalDivider( + Modifier + .fillMaxWidth() + .padding(top = AppTheme.dimensions.standardSpacing) + ) + + LazyColumn( + Modifier.weight(1f, fill = false) + ) { + items(locks.locks) { item -> + Item(item) + HorizontalDivider(Modifier.fillMaxWidth()) + } + } + + SimpleText( + modifier = Modifier + .fillMaxWidth() + .padding( + top = AppTheme.dimensions.smallSpacing, + start = AppTheme.dimensions.smallSpacing, + end = AppTheme.dimensions.smallSpacing, + ), + text = stringResource(R.string.funds_locked_summary_text), + style = ComposeTypographies.Caption1, + color = ComposeColors.Body, + gravity = ComposeGravities.Start, + ) + + SmallMinimalButton( + modifier = Modifier.padding(AppTheme.dimensions.smallSpacing), + text = stringResource(R.string.common_learn_more), + onClick = learnMoreClicked, + ) + } + + Column(Modifier.fillMaxWidth()) { + MinimalButton( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = AppTheme.dimensions.standardSpacing), + text = stringResource(R.string.contact_support), + onClick = contactSupportClicked, + ) + + PrimaryButton( + modifier = Modifier + .fillMaxWidth() + .padding( + horizontal = AppTheme.dimensions.standardSpacing, + vertical = AppTheme.dimensions.smallSpacing, + ), + text = stringResource(R.string.common_ok), + onClick = okClicked, + ) + } + } +} + +@Composable +private fun Item( + item: FundsLock +) { + TableRow( + contentStart = { + val asset = item.buyAmount?.currency ?: item.amount.currency + Image( + modifier = Modifier + .align(Alignment.CenterVertically) + .size(AppTheme.dimensions.standardSpacing), + imageResource = ImageResource.Remote( + url = asset.logo, + shape = if (asset.type == CurrencyType.CRYPTO) CircleShape else RectangleShape, + ), + ) + }, + content = { + Column( + modifier = Modifier + .weight(1f) + .padding(start = AppTheme.dimensions.smallSpacing) + ) { + val actionText = item.buyAmount?.currency?.name?.let { + stringResource(R.string.funds_locked_details_item_action_buy_title, it) + } ?: stringResource(R.string.funds_locked_details_item_action_deposit_title, item.amount.currency.name) + SimpleText( + text = actionText, + style = ComposeTypographies.Paragraph2, + color = ComposeColors.Title, + gravity = ComposeGravities.Start, + ) + + val dateFormatter = DateTimeFormatter.ofPattern("MMM dd") + val dateString = dateFormatter.format(item.date) + SimpleText( + modifier = Modifier.padding(top = AppTheme.dimensions.smallestSpacing), + text = stringResource(R.string.funds_locked_details_item_action_available, dateString), + style = ComposeTypographies.Paragraph1, + color = ComposeColors.Body, + gravity = ComposeGravities.Start, + ) + } + }, + contentEnd = { + Column( + modifier = Modifier.weight(1f), + horizontalAlignment = Alignment.End, + ) { + SimpleText( + text = item.amount.toStringWithSymbol(), + style = ComposeTypographies.Paragraph2, + color = ComposeColors.Title, + gravity = ComposeGravities.End, + ) + + val buyAmount = item.buyAmount + if (buyAmount != null) { + SimpleText( + modifier = Modifier.padding(top = AppTheme.dimensions.smallestSpacing), + text = buyAmount.toStringWithSymbol(), + style = ComposeTypographies.Paragraph1, + color = ComposeColors.Body, + gravity = ComposeGravities.End, + ) + } + } + } + ) +// ConstraintLayout( +// Modifier +// .fillMaxWidth() +// .background(White) +// .padding(all = AppTheme.dimensions.smallSpacing) +// ) { +// val ( +// iconRef, +// actionRef, +// fiatAmountRef, +// dateRef, +// cryptoAmountRef, +// ) = createRefs() +// +// val asset = item.buyAmount?.currency ?: item.amount.currency +// Image( +// modifier = Modifier +// .constrainAs(iconRef) { +// top.linkTo(parent.top) +// bottom.linkTo(parent.bottom) +// start.linkTo(parent.start) +// } +// .size(AppTheme.dimensions.standardSpacing), +// imageResource = ImageResource.Remote( +// url = asset.logo, +// shape = if (asset.type == CurrencyType.CRYPTO) CircleShape else null, +// ), +// ) +// +// val actionText = item.buyAmount?.currency?.name?.let { +// stringResource(R.string.funds_locked_details_item_action_buy_title, it) +// } ?: stringResource(R.string.funds_locked_details_item_action_deposit_title, item.amount.currency.name) +// SimpleText( +// modifier = Modifier +// .constrainAs(actionRef) { +// top.linkTo(parent.top) +// start.linkTo(iconRef.end) +// bottom.linkTo(dateRef.top) +// } +// .padding(start = AppTheme.dimensions.smallSpacing), +// text = actionText, +// style = ComposeTypographies.Paragraph2, +// color = ComposeColors.Title, +// gravity = ComposeGravities.Start, +// ) +// +// SimpleText( +// modifier = Modifier +// .constrainAs(fiatAmountRef) { +// top.linkTo(parent.top) +// end.linkTo(parent.end) +// bottom.linkTo(cryptoAmountRef.top) +// }, +// text = item.amount.toStringWithSymbol(), +// style = ComposeTypographies.Paragraph2, +// color = ComposeColors.Title, +// gravity = ComposeGravities.End, +// ) +// +// val dateFormatter = DateTimeFormatter.ofPattern("MMM dd") +// val dateString = dateFormatter.format(item.date) +// SimpleText( +// modifier = Modifier +// .constrainAs(dateRef) { +// top.linkTo(actionRef.bottom) +// start.linkTo(iconRef.end) +// bottom.linkTo(parent.bottom) +// } +// .padding( +// top = AppTheme.dimensions.smallestSpacing, +// start = AppTheme.dimensions.smallSpacing, +// ), +// text = stringResource(R.string.funds_locked_details_item_action_available, dateString), +// style = ComposeTypographies.Paragraph1, +// color = ComposeColors.Body, +// gravity = ComposeGravities.Start, +// ) +// +// SimpleText( +// modifier = Modifier +// .constrainAs(cryptoAmountRef) { +// top.linkTo(fiatAmountRef.bottom) +// end.linkTo(parent.end) +// bottom.linkTo(parent.bottom) +// visibility = if (item.buyAmount != null) Visibility.Visible else Visibility.Gone +// } +// .padding(top = AppTheme.dimensions.smallestSpacing), +// text = item.buyAmount?.toStringWithSymbol().orEmpty(), +// style = ComposeTypographies.Paragraph1, +// color = ComposeColors.Body, +// gravity = ComposeGravities.End, +// ) +// +// } +} + +@Composable +@Preview(heightDp = 800) +private fun PreviewScreen1() { + val locks = FundsLocks( + onHoldTotalAmount = Money.fromMinor(FiatCurrency.fromCurrencyCode("USD"), BigInteger.valueOf(1000)), + locks = listOf( + FundsLock( + amount = Money.fromMinor(FiatCurrency.fromCurrencyCode("USD"), BigInteger.valueOf(1000)), + date = ZonedDateTime.now(), + buyAmount = null, + ), + FundsLock( + amount = Money.fromMinor(FiatCurrency.fromCurrencyCode("EUR"), BigInteger.valueOf(500)), + date = ZonedDateTime.now(), + buyAmount = null, + ), + ) + ) + LocksDetailsScreen( + locks = locks, + backClicked = {}, + learnMoreClicked = {}, + contactSupportClicked = {}, + okClicked = {}, + ) +} + +@Composable +@Preview(heightDp = 800) +private fun PreviewScreen2() { + val locks = FundsLocks( + onHoldTotalAmount = Money.fromMinor(FiatCurrency.fromCurrencyCode("USD"), BigInteger.valueOf(1000)), + locks = listOf( + FundsLock( + amount = Money.fromMinor(FiatCurrency.fromCurrencyCode("USD"), BigInteger.valueOf(1000)), + date = ZonedDateTime.now(), + buyAmount = null, + ), + FundsLock( + amount = Money.fromMinor(FiatCurrency.fromCurrencyCode("EUR"), BigInteger.valueOf(500)), + date = ZonedDateTime.now(), + buyAmount = null, + ), + FundsLock( + amount = Money.fromMinor(FiatCurrency.fromCurrencyCode("EUR"), BigInteger.valueOf(500)), + date = ZonedDateTime.now(), + buyAmount = null, + ), + FundsLock( + amount = Money.fromMinor(FiatCurrency.fromCurrencyCode("EUR"), BigInteger.valueOf(500)), + date = ZonedDateTime.now(), + buyAmount = null, + ), + FundsLock( + amount = Money.fromMinor(FiatCurrency.fromCurrencyCode("GBP"), BigInteger.valueOf(5500)), + date = ZonedDateTime.now(), + buyAmount = Money.fromMinor(CryptoCurrency.BTC, BigInteger.valueOf(1000)), + ), + FundsLock( + amount = Money.fromMinor(FiatCurrency.fromCurrencyCode("EUR"), BigInteger.valueOf(1500)), + date = ZonedDateTime.now(), + buyAmount = Money.fromMinor(CryptoCurrency.ETHER, BigInteger.valueOf(2000)), + ), + FundsLock( + amount = Money.fromMinor(FiatCurrency.fromCurrencyCode("USD"), BigInteger.valueOf(3500)), + date = ZonedDateTime.now(), + buyAmount = Money.fromMinor(CryptoCurrency.XLM, BigInteger.valueOf(2000)), + ), + ) + ) + LocksDetailsScreen( + locks = locks, + backClicked = {}, + learnMoreClicked = {}, + contactSupportClicked = {}, + okClicked = {}, + ) +} + +@Composable +@Preview +private fun PreviewItemDeposit() { + Item( + FundsLock( + amount = Money.fromMinor(FiatCurrency.fromCurrencyCode("USD"), BigInteger.valueOf(3500)), + date = ZonedDateTime.now(), + buyAmount = null, + ) + ) +} + +@Composable +@Preview +private fun PreviewItemBuy() { + Item( + FundsLock( + amount = Money.fromMinor(FiatCurrency.fromCurrencyCode("USD"), BigInteger.valueOf(3500)), + date = ZonedDateTime.now(), + buyAmount = Money.fromMinor(CryptoCurrency.XLM, BigInteger.valueOf(2000)), + ) + ) +} diff --git a/app/src/main/res/layout/activity_on_hold_details.xml b/app/src/main/res/layout/activity_on_hold_details.xml deleted file mode 100644 index 1993461e8e..0000000000 --- a/app/src/main/res/layout/activity_on_hold_details.xml +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/lock_item.xml b/app/src/main/res/layout/lock_item.xml deleted file mode 100644 index e5b1c0172a..0000000000 --- a/app/src/main/res/layout/lock_item.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/blockchainApi/src/main/java/com/blockchain/api/payments/data/WithdrawalLocksResponse.kt b/blockchainApi/src/main/java/com/blockchain/api/payments/data/WithdrawalLocksResponse.kt index 6365c0773f..12044a6b39 100644 --- a/blockchainApi/src/main/java/com/blockchain/api/payments/data/WithdrawalLocksResponse.kt +++ b/blockchainApi/src/main/java/com/blockchain/api/payments/data/WithdrawalLocksResponse.kt @@ -19,7 +19,8 @@ data class LockPeriod( @SerialName("amount") val localCurrencyAmount: LocalCurrencyAmount, @SerialName("expiresAt") - val expiresAt: String + val expiresAt: String, + val bought: LocalCurrencyAmount?, ) @Serializable diff --git a/blockchainApi/src/main/java/com/blockchain/api/services/PaymentsService.kt b/blockchainApi/src/main/java/com/blockchain/api/services/PaymentsService.kt index 35f2fa1352..920cce8167 100644 --- a/blockchainApi/src/main/java/com/blockchain/api/services/PaymentsService.kt +++ b/blockchainApi/src/main/java/com/blockchain/api/services/PaymentsService.kt @@ -32,7 +32,9 @@ private fun WithdrawalLocksResponse.toWithdrawalLocks() = CollateralLock( currency = lockPeriod.localCurrencyAmount.currency, value = lockPeriod.localCurrencyAmount.amount, - date = lockPeriod.expiresAt + date = lockPeriod.expiresAt, + buyCurrency = lockPeriod.bought?.currency, + buyValue = lockPeriod.bought?.amount, ) } ) @@ -46,7 +48,10 @@ data class CollateralLocks( data class CollateralLock( val currency: String, val value: String, - val date: String + val date: String, + // Used for locks on purchases + val buyCurrency: String?, + val buyValue: String?, ) fun String.toMobilePaymentType(): MobilePaymentType = diff --git a/common/domain/src/main/java/com/blockchain/domain/paymentmethods/model/FundsLocksModel.kt b/common/domain/src/main/java/com/blockchain/domain/paymentmethods/model/FundsLocksModel.kt index 3ee2b216da..826c5e18dd 100644 --- a/common/domain/src/main/java/com/blockchain/domain/paymentmethods/model/FundsLocksModel.kt +++ b/common/domain/src/main/java/com/blockchain/domain/paymentmethods/model/FundsLocksModel.kt @@ -11,5 +11,6 @@ data class FundsLocks( data class FundsLock( val amount: Money, - val date: ZonedDateTime + val date: ZonedDateTime, + val buyAmount: Money?, ) : Serializable diff --git a/common/interface/src/main/kotlin/com/blockchain/extensions/KotlinExtensions.kt b/common/interface/src/main/kotlin/com/blockchain/extensions/KotlinExtensions.kt new file mode 100644 index 0000000000..812efa1ee5 --- /dev/null +++ b/common/interface/src/main/kotlin/com/blockchain/extensions/KotlinExtensions.kt @@ -0,0 +1,30 @@ +package com.blockchain.extensions + +inline fun safeLet(p1: T1?, p2: T2?, block: (T1, T2) -> R?): R? { + return if (p1 != null && p2 != null) block(p1, p2) else null +} + +inline fun safeLet(p1: T1?, p2: T2?, p3: T3?, block: (T1, T2, T3) -> R?): R? { + return if (p1 != null && p2 != null && p3 != null) block(p1, p2, p3) else null +} + +inline fun safeLet( + p1: T1?, + p2: T2?, + p3: T3?, + p4: T4?, + block: (T1, T2, T3, T4) -> R? +): R? { + return if (p1 != null && p2 != null && p3 != null && p4 != null) block(p1, p2, p3, p4) else null +} + +inline fun safeLet( + p1: T1?, + p2: T2?, + p3: T3?, + p4: T4?, + p5: T5?, + block: (T1, T2, T3, T4, T5) -> R? +): R? { + return if (p1 != null && p2 != null && p3 != null && p4 != null && p5 != null) block(p1, p2, p3, p4, p5) else null +} diff --git a/componentlib/src/main/java/com/blockchain/componentlib/tablerow/TableRow.kt b/componentlib/src/main/java/com/blockchain/componentlib/tablerow/TableRow.kt index 89d499668b..0f9bcab14e 100644 --- a/componentlib/src/main/java/com/blockchain/componentlib/tablerow/TableRow.kt +++ b/componentlib/src/main/java/com/blockchain/componentlib/tablerow/TableRow.kt @@ -14,8 +14,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.dimensionResource -import com.blockchain.componentlib.R import com.blockchain.componentlib.theme.AppTheme @Composable @@ -67,10 +65,7 @@ fun TableRow( backgroundColor: Color = AppTheme.colors.background ) { TableRow( - paddingValues = PaddingValues( - horizontal = dimensionResource(R.dimen.standard_spacing), - vertical = dimensionResource(R.dimen.medium_spacing) - ), + paddingValues = PaddingValues(AppTheme.dimensions.smallSpacing), content = content, contentStart = contentStart, contentEnd = contentEnd, diff --git a/core/src/main/java/com/blockchain/core/payments/PaymentsRepository.kt b/core/src/main/java/com/blockchain/core/payments/PaymentsRepository.kt index bc803a85ed..c1c44e72f0 100644 --- a/core/src/main/java/com/blockchain/core/payments/PaymentsRepository.kt +++ b/core/src/main/java/com/blockchain/core/payments/PaymentsRepository.kt @@ -92,6 +92,7 @@ import com.blockchain.domain.paymentmethods.model.YapilyAttributes import com.blockchain.domain.paymentmethods.model.YapilyInstitution import com.blockchain.domain.paymentmethods.model.YodleeAttributes import com.blockchain.enviroment.EnvironmentConfig +import com.blockchain.extensions.safeLet import com.blockchain.featureflag.FeatureFlag import com.blockchain.nabu.common.extensions.wrapErrorMessage import com.blockchain.nabu.datamanagers.toSupportedPartner @@ -167,7 +168,12 @@ class PaymentsRepository( locks = locks.locks.map { lock -> FundsLock( amount = Money.fromMinor(localCurrency, lock.value.toBigInteger()), - date = lock.date.toZonedDateTime() + date = lock.date.toZonedDateTime(), + buyAmount = safeLet(lock.buyCurrency, lock.buyValue) { currency, value -> + assetCatalogue.fromNetworkTicker(currency)?.let { + Money.fromMinor(it, value.toBigInteger()) + } + }, ) } ) diff --git a/core/src/test/java/com/blockchain/core/payments/PaymentsRepositoryTest.kt b/core/src/test/java/com/blockchain/core/payments/PaymentsRepositoryTest.kt index 98983add42..02376382f2 100644 --- a/core/src/test/java/com/blockchain/core/payments/PaymentsRepositoryTest.kt +++ b/core/src/test/java/com/blockchain/core/payments/PaymentsRepositoryTest.kt @@ -99,6 +99,7 @@ import com.blockchain.testutils.rxInit import com.blockchain.testutils.usd import com.blockchain.utils.toZonedDateTime import info.blockchain.balance.AssetCatalogue +import info.blockchain.balance.CryptoCurrency import info.blockchain.balance.FiatCurrency import info.blockchain.balance.Money import io.mockk.coEvery @@ -139,6 +140,7 @@ class PaymentsRepositoryTest { private const val AUTH = "auth" private const val ID = "id" private const val NETWORK_TICKER = "GBP" + private const val BUY_NETWORK_TICKER = "BTC" private const val APPLICATION_ID = "applicationId" } @@ -245,12 +247,15 @@ class PaymentsRepositoryTest { NETWORK_TICKER, "1000", listOf( - CollateralLock(NETWORK_TICKER, "10", date) + CollateralLock(NETWORK_TICKER, "10", date, BUY_NETWORK_TICKER, "1000") ) ) val localCurrency = - mockk(relaxed = true).apply { every { networkTicker } returns (NETWORK_TICKER) } + mockk(relaxed = true) { every { networkTicker } returns (NETWORK_TICKER) } + val buyCurrency = + mockk(relaxed = true) { every { networkTicker } returns (BUY_NETWORK_TICKER) } every { withdrawLocksCache.withdrawLocks() } returns Single.just(locks) + every { assetCatalogue.fromNetworkTicker(BUY_NETWORK_TICKER) } returns buyCurrency // ASSERT subject.getWithdrawalLocks(localCurrency).test() @@ -260,7 +265,8 @@ class PaymentsRepositoryTest { listOf( FundsLock( Money.fromMinor(localCurrency, BigInteger("10")), - date.toZonedDateTime() + date.toZonedDateTime(), + Money.fromMinor(buyCurrency, BigInteger("1000")), ) ) ) diff --git a/string-resources/src/main/res/values-es/strings.xml b/string-resources/src/main/res/values-es/strings.xml index 7e56d483f9..00309490b6 100644 --- a/string-resources/src/main/res/values-es/strings.xml +++ b/string-resources/src/main/res/values-es/strings.xml @@ -1955,7 +1955,7 @@ Disponible para enviar %s En espera Ver detalles - Los fondos recién agregados están sujetos a un período de retención. Mientras tanto, puedes realizar transferencias entre tus cuentas de Trading, Rewards y Exchange. Más información → + Los fondos recién agregados están sujetos a un período de retención. Mientras tanto, puedes realizar transferencias entre tus cuentas de Trading, Rewards y Exchange. Los fondos recién agregados están sujetos a un período de retención. Mientras tanto, puede realizar transferencias entre sus cuentas de Trading, Rewards y Exchange. ¿Hay algo que no se ve bien? Ponte en contacto con el equipo de asistencia MANTENIDO HASTA diff --git a/string-resources/src/main/res/values-fr/strings.xml b/string-resources/src/main/res/values-fr/strings.xml index b454832d89..0aac602393 100644 --- a/string-resources/src/main/res/values-fr/strings.xml +++ b/string-resources/src/main/res/values-fr/strings.xml @@ -1956,7 +1956,7 @@ Disponible pour envoyer %s en attente Afficher les détails - Les fonds nouvellement ajoutés sont soumis à une période de détention. Dans l\'intervalle, vous pouvez effectuer des transferts entre vos comptes Trading, Rewards et Exchange. En savoir plus → + Les fonds nouvellement ajoutés sont soumis à une période de détention. Dans l\'intervalle, vous pouvez effectuer des transferts entre vos comptes Trading, Rewards et Exchange. Les fonds nouvellement ajoutés sont sujets à une période de détention. Dans l\'intervalle, vous pouvez effectuer des transferts entre vos comptes Trading, Récompenses et Exchange. Vous voyez quelque chose qui ne va pas ? Contacter le service d\'assistance DÉTENUS JUSQU\'AU diff --git a/string-resources/src/main/res/values-pt/strings.xml b/string-resources/src/main/res/values-pt/strings.xml index ba787b8899..78616108f4 100644 --- a/string-resources/src/main/res/values-pt/strings.xml +++ b/string-resources/src/main/res/values-pt/strings.xml @@ -1955,7 +1955,7 @@ Disponível para envio %s Em espera Veja Detalhes - Os fundos recém-adicionados estão sujeitos a um período de retenção. Pode transferir, entretanto, entre as suas contas Trading, Rewards e Exchange. Saiba mais → + Os fundos recém-adicionados estão sujeitos a um período de retenção. Pode transferir, entretanto, entre as suas contas Trading, Rewards e Exchange. Os fundos recém-adicionados estão sujeitos a um período de retenção. Pode transferir entre as suas contas Trading, Rewards e Exchange entretanto. Vê algo que não parece certo? Contacte o apoio ao cliente RETIDO ATÉ diff --git a/string-resources/src/main/res/values-ru/strings.xml b/string-resources/src/main/res/values-ru/strings.xml index 37c308d4e0..3890fbf453 100644 --- a/string-resources/src/main/res/values-ru/strings.xml +++ b/string-resources/src/main/res/values-ru/strings.xml @@ -1957,7 +1957,7 @@ Доступно для отправки %s на удержании Просмотреть подробности - Для вновь добавленных средств действует период удержания. Во время удержания вы можете переводить средства между своими торговыми счетами, счетами вознаграждений и Exchange. Подробнее → + Для вновь добавленных средств действует период удержания. Во время удержания вы можете переводить средства между своими торговыми счетами, счетами вознаграждений и Exchange. Для вновь добавленных средств действует период удержания. Во время удержания вы можете переводить средства между своими торговыми счетами, счетами вознаграждений и Exchange. Что-то не так? Свяжитесь со службой поддержки УДЕРЖИВАЕТСЯ ДО diff --git a/string-resources/src/main/res/values/strings.xml b/string-resources/src/main/res/values/strings.xml index 6f9318959d..b38e2f11a3 100644 --- a/string-resources/src/main/res/values/strings.xml +++ b/string-resources/src/main/res/values/strings.xml @@ -2508,7 +2508,7 @@ If you want to know more about our verification process visit our Available to Withdraw %s On Hold See Details - Newly added funds are subject to a holding period. You can transfer between your Trading, Rewards, and Exchange accounts in the meantime. Learn more → + Newly added funds are subject to a holding period. You can transfer between your Trading, Rewards, and Exchange accounts in the meantime. Newly added funds are subject to a holding period. You can transfer between your Trading, Rewards, and Exchange accounts in the meantime. @@ -2517,8 +2517,10 @@ If you want to know more about our verification process visit our AMOUNT Total On Hold - %s On Hold - Learn More + Total On Hold + Bought %1$s + Deposited %1$s + Available %1$s For security purposes, a %s holding period will be applied to your funds. We will notify you once the funds are available.