Updated on 2026-08-14
This commit is contained in:
commit
d99ae5eeca
35 changed files with 534 additions and 280 deletions
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.tap.common.entities
|
||||
|
||||
data class FiatCurrency(
|
||||
val code: String,
|
||||
val name: String,
|
||||
val symbol: String,
|
||||
) {
|
||||
val displayName: String
|
||||
get() = "${this.name} (${this.code}) - ${this.symbol}"
|
||||
|
||||
companion object {
|
||||
val Default = FiatCurrency(
|
||||
symbol = "$",
|
||||
code = "USD",
|
||||
name = "US Dollar",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.tap.common.entities
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class TapCurrency {
|
||||
companion object{
|
||||
const val DEFAULT_FIAT_CURRENCY = "USD"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import android.text.Spanned
|
||||
import android.text.SpannedString
|
||||
import android.text.style.RelativeSizeSpan
|
||||
import androidx.core.text.buildSpannedString
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.network.api.tangemTech.CurrenciesResponse
|
||||
import com.tangem.tap.common.redux.global.FiatCurrencyName
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import java.text.DecimalFormat
|
||||
|
|
@ -37,7 +39,7 @@ fun BigDecimal.toFormattedCurrencyString(
|
|||
return "$formattedAmount $currency"
|
||||
}
|
||||
|
||||
fun BigDecimal.toFiatString(rateValue: BigDecimal, fiatCurrencyName: FiatCurrencyName): String {
|
||||
fun BigDecimal.toFiatString(rateValue: BigDecimal, fiatCurrencyName: String): String {
|
||||
var fiatValue = rateValue.multiply(this)
|
||||
fiatValue = fiatValue.setScale(2, RoundingMode.HALF_UP)
|
||||
return "≈ ${fiatCurrencyName} $fiatValue"
|
||||
|
|
@ -48,12 +50,10 @@ fun BigDecimal.toFiatValue(rateValue: BigDecimal): BigDecimal {
|
|||
return fiatValue.setScale(2, RoundingMode.HALF_UP)
|
||||
}
|
||||
|
||||
fun BigDecimal.toFormattedFiatValue(fiatCurrencyName: FiatCurrencyName): String {
|
||||
fun BigDecimal.toFormattedFiatValue(fiatCurrencyName: String): String {
|
||||
return "≈ ${fiatCurrencyName} $this"
|
||||
}
|
||||
|
||||
fun CurrenciesResponse.Currency.toFormattedString(): String = "${this.name} (${this.code}) - ${this.unit}"
|
||||
|
||||
fun BigDecimal.stripZeroPlainString(): String = this.stripTrailingZeros().toPlainString()
|
||||
|
||||
// 0.00 -> 0.00
|
||||
|
|
@ -87,4 +87,28 @@ fun BigDecimal.isGreaterThanOrEqual(value: BigDecimal): Boolean {
|
|||
fun BigDecimal.isLessThanOrEqual(value: BigDecimal): Boolean {
|
||||
val compareResult = this.compareTo(value)
|
||||
return compareResult == -1 || compareResult == 0
|
||||
}
|
||||
|
||||
fun BigDecimal.formatAmountAsSpannedString(
|
||||
currencySymbol: String,
|
||||
integerPartSizeProportion: Float = 1.4f
|
||||
): SpannedString {
|
||||
val amount = this.toFormattedString(
|
||||
decimals = 2,
|
||||
roundingMode = RoundingMode.HALF_UP
|
||||
)
|
||||
val integer = amount.substringAfter('.')
|
||||
val reminder = amount.substringBefore('.')
|
||||
|
||||
return buildSpannedString {
|
||||
append(
|
||||
integer,
|
||||
RelativeSizeSpan(integerPartSizeProportion),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
append('.')
|
||||
append(reminder)
|
||||
append(' ')
|
||||
append(currencySymbol)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.app.Activity
|
||||
import android.content.*
|
||||
import android.content.res.Resources
|
||||
|
|
@ -16,6 +18,7 @@ import androidx.annotation.ColorRes
|
|||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.tangem.common.extensions.VoidCallback
|
||||
|
|
@ -187,4 +190,47 @@ fun Context.safeStartActivity(
|
|||
|
||||
fun View.getString(resId: Int, vararg formatArgs: Any?): String {
|
||||
return context.getString(resId, formatArgs)
|
||||
}
|
||||
|
||||
fun View.showAnimated(durationMillis: Long = 300) {
|
||||
this.animateVisibility(
|
||||
show = true,
|
||||
durationMillis = durationMillis
|
||||
)
|
||||
}
|
||||
|
||||
fun View.hideAnimated(
|
||||
durationMillis: Long = 300,
|
||||
hiddenVisibility: Int = View.GONE
|
||||
) {
|
||||
this.animateVisibility(
|
||||
show = false,
|
||||
durationMillis = durationMillis,
|
||||
hiddenVisibility = hiddenVisibility
|
||||
)
|
||||
}
|
||||
|
||||
private fun View.animateVisibility(
|
||||
show: Boolean,
|
||||
durationMillis: Long = 300,
|
||||
hiddenVisibility: Int = View.GONE
|
||||
) {
|
||||
if (this.isVisible == show) return
|
||||
if (show) {
|
||||
this.alpha = 0f
|
||||
this.isVisible = true
|
||||
this.animate()
|
||||
.alpha(1f)
|
||||
.setDuration(durationMillis)
|
||||
.setListener(null)
|
||||
} else {
|
||||
this.animate()
|
||||
.alpha(0f)
|
||||
.setDuration(durationMillis)
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
this@animateVisibility.visibility = hiddenVisibility
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -57,7 +57,7 @@ fun WalletManager?.getToUpUrl(): String? {
|
|||
action = CurrencyExchangeManager.Action.Buy,
|
||||
blockchain = wallet.blockchain,
|
||||
cryptoCurrencyName = wallet.blockchain.currency,
|
||||
fiatCurrency = globalState.appCurrency,
|
||||
fiatCurrencyName = globalState.appCurrency.code,
|
||||
walletAddress = defaultAddress,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.common.CompletionResult
|
|||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.tap.common.analytics.GlobalAnalyticsHandler
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.redux.*
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.configurable.config.ConfigManager
|
||||
|
|
@ -54,9 +55,9 @@ sealed class GlobalAction : Action {
|
|||
|
||||
data class SetIfCardVerifiedOnline(val verified: Boolean) : GlobalAction()
|
||||
|
||||
data class ChangeAppCurrency(val appCurrency: FiatCurrencyName) : GlobalAction()
|
||||
data class ChangeAppCurrency(val appCurrency: FiatCurrency) : GlobalAction()
|
||||
object RestoreAppCurrency : GlobalAction() {
|
||||
data class Success(val appCurrency: FiatCurrencyName) : GlobalAction()
|
||||
data class Success(val appCurrency: FiatCurrency) : GlobalAction()
|
||||
}
|
||||
|
||||
data class UpdateWalletSignedHashes(
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class GlobalMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private val globalMiddlewareHandler: Middleware<AppState> = { dispatch, appState ->
|
||||
private val globalMiddlewareHandler: Middleware<AppState> = { _, appState ->
|
||||
{ nextDispatch ->
|
||||
{ action ->
|
||||
when (action) {
|
||||
|
|
@ -45,7 +45,7 @@ private val globalMiddlewareHandler: Middleware<AppState> = { dispatch, appState
|
|||
}
|
||||
is GlobalAction.RestoreAppCurrency -> {
|
||||
store.dispatch(GlobalAction.RestoreAppCurrency.Success(
|
||||
preferencesStorage.getAppCurrency()
|
||||
preferencesStorage.fiatCurrenciesPrefStorage.getAppCurrency()
|
||||
))
|
||||
}
|
||||
is GlobalAction.HideWarningMessage -> {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.tap.common.redux.global
|
|||
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.tap.common.analytics.AnalyticsHandler
|
||||
import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
import com.tangem.tap.domain.PayIdManager
|
||||
import com.tangem.tap.domain.TapWalletManager
|
||||
|
|
@ -22,7 +22,7 @@ data class GlobalState(
|
|||
val configManager: ConfigManager? = null,
|
||||
val warningManager: WarningMessagesManager? = null,
|
||||
val feedbackManager: FeedbackManager? = null,
|
||||
val appCurrency: FiatCurrencyName = DEFAULT_FIAT_CURRENCY,
|
||||
val appCurrency: FiatCurrency = FiatCurrency.Default,
|
||||
val scanCardFailsCounter: Int = 0,
|
||||
val dialog: StateDialog? = null,
|
||||
val currencyExchangeManager: CurrencyExchangeManager? = null,
|
||||
|
|
@ -40,7 +40,6 @@ data class AndroidResources(
|
|||
)
|
||||
}
|
||||
typealias CryptoCurrencyName = String
|
||||
typealias FiatCurrencyName = String
|
||||
|
||||
data class OnboardingState(
|
||||
val onboardingStarted: Boolean = false,
|
||||
|
|
|
|||
|
|
@ -4,11 +4,10 @@ import com.tangem.blockchain.common.Wallet
|
|||
import com.tangem.common.card.Card
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.TwinCardNumber
|
||||
import com.tangem.network.api.tangemTech.CurrenciesResponse
|
||||
import com.tangem.network.api.tangemTech.TangemTechService
|
||||
import com.tangem.operations.pins.CheckUserCodesResponse
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.redux.NotificationAction
|
||||
import com.tangem.tap.common.redux.global.FiatCurrencyName
|
||||
import com.tangem.tap.domain.termsOfUse.CardTou
|
||||
import com.tangem.wallet.R
|
||||
import org.rekotlin.Action
|
||||
|
|
@ -19,8 +18,8 @@ sealed class DetailsAction : Action {
|
|||
val scanResponse: ScanResponse,
|
||||
val wallets: List<Wallet>,
|
||||
val cardTou: CardTou,
|
||||
val fiatCurrencyName: FiatCurrencyName,
|
||||
val fiatCurrencies: List<FiatCurrencyName>? = null,
|
||||
val fiatCurrencyName: FiatCurrency,
|
||||
val fiatCurrencies: List<FiatCurrency>? = null,
|
||||
val tangemTechService: TangemTechService,
|
||||
) : DetailsAction()
|
||||
|
||||
|
|
@ -48,10 +47,10 @@ sealed class DetailsAction : Action {
|
|||
object CreateBackup : DetailsAction()
|
||||
|
||||
sealed class AppCurrencyAction : DetailsAction() {
|
||||
data class SetCurrencies(val currencies: List<CurrenciesResponse.Currency>) : AppCurrencyAction()
|
||||
data class SetCurrencies(val currencies: List<FiatCurrency>) : AppCurrencyAction()
|
||||
object ChooseAppCurrency : AppCurrencyAction()
|
||||
object Cancel : AppCurrencyAction()
|
||||
data class SelectAppCurrency(val fiatCurrencyName: FiatCurrencyName) : AppCurrencyAction()
|
||||
data class SelectAppCurrency(val fiatCurrency: FiatCurrency) : AppCurrencyAction()
|
||||
}
|
||||
|
||||
sealed class ManageSecurity : DetailsAction() {
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@ import com.tangem.common.CompletionResult
|
|||
import com.tangem.common.card.FirmwareVersion
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.network.api.tangemTech.CurrenciesResponse
|
||||
import com.tangem.operations.pins.CheckUserCodesResponse
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.extensions.dispatchNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
|
|
@ -28,7 +30,7 @@ class DetailsMiddleware {
|
|||
private val eraseWalletMiddleware = EraseWalletMiddleware()
|
||||
private val appCurrencyMiddleware = AppCurrencyMiddleware()
|
||||
private val manageSecurityMiddleware = ManageSecurityMiddleware()
|
||||
val detailsMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
val detailsMiddleware: Middleware<AppState> = { _, _ ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
when (action) {
|
||||
|
|
@ -71,7 +73,11 @@ class DetailsMiddleware {
|
|||
val fiatCurrenciesPrefStorage = preferencesStorage.fiatCurrenciesPrefStorage
|
||||
val storedFiatCurrencies = fiatCurrenciesPrefStorage.restore()
|
||||
if (storedFiatCurrencies.isNotEmpty()) {
|
||||
store.dispatch(DetailsAction.AppCurrencyAction.SetCurrencies(storedFiatCurrencies))
|
||||
store.dispatch(
|
||||
DetailsAction.AppCurrencyAction.SetCurrencies(
|
||||
currencies = storedFiatCurrencies.mapToUiModel()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
scope.launch {
|
||||
|
|
@ -79,9 +85,15 @@ class DetailsMiddleware {
|
|||
when (val result = tangemTechService.currencies()) {
|
||||
is Result.Success -> {
|
||||
val currenciesList = result.data.currencies
|
||||
if (currenciesList.isNotEmpty() && currenciesList.toSet() != storedFiatCurrencies.toSet()) {
|
||||
if (currenciesList.isNotEmpty() &&
|
||||
currenciesList.toSet() != storedFiatCurrencies.toSet()
|
||||
) {
|
||||
fiatCurrenciesPrefStorage.save(currenciesList)
|
||||
dispatchOnMain(DetailsAction.AppCurrencyAction.SetCurrencies(currenciesList))
|
||||
dispatchOnMain(
|
||||
DetailsAction.AppCurrencyAction.SetCurrencies(
|
||||
currencies = currenciesList.mapToUiModel()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
is Result.Failure -> {}
|
||||
|
|
@ -89,7 +101,17 @@ class DetailsMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
class EraseWalletMiddleware() {
|
||||
private fun List<CurrenciesResponse.Currency>.mapToUiModel(): List<FiatCurrency> {
|
||||
return this.map {
|
||||
FiatCurrency(
|
||||
code = it.code,
|
||||
name = it.name,
|
||||
symbol = it.unit
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class EraseWalletMiddleware {
|
||||
fun handle(action: DetailsAction.ResetToFactory) {
|
||||
when (action) {
|
||||
is DetailsAction.ResetToFactory.Proceed -> {
|
||||
|
|
@ -100,6 +122,8 @@ class DetailsMiddleware {
|
|||
store.dispatch(DetailsAction.ResetToFactory.Proceed.NotAllowedByCard)
|
||||
EraseWalletState.NotEmpty ->
|
||||
store.dispatch(DetailsAction.ResetToFactory.Proceed.NotEmpty)
|
||||
else -> { /* no-op */
|
||||
}
|
||||
}
|
||||
}
|
||||
is DetailsAction.ResetToFactory.Cancel -> {
|
||||
|
|
@ -128,6 +152,8 @@ class DetailsMiddleware {
|
|||
}
|
||||
}
|
||||
}
|
||||
else -> { /* no-op */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -137,10 +163,13 @@ class DetailsMiddleware {
|
|||
when (action) {
|
||||
is DetailsAction.AppCurrencyAction.SelectAppCurrency -> {
|
||||
store.state.globalState.tapWalletManager.rates.clear()
|
||||
preferencesStorage.saveAppCurrency(action.fiatCurrencyName)
|
||||
store.dispatch(GlobalAction.ChangeAppCurrency(action.fiatCurrencyName))
|
||||
preferencesStorage.fiatCurrenciesPrefStorage
|
||||
.saveAppCurrency(action.fiatCurrency)
|
||||
store.dispatch(GlobalAction.ChangeAppCurrency(action.fiatCurrency))
|
||||
store.dispatch(WalletAction.LoadFiatRate())
|
||||
}
|
||||
else -> { /* no-op */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -211,18 +240,22 @@ class DetailsMiddleware {
|
|||
actionToLog = Analytics.ActionToLog.ChangeSecOptions,
|
||||
parameters = mapOf(
|
||||
AnalyticsParam.NEW_SECURITY_OPTION to
|
||||
(selectedOption?.name ?: "")
|
||||
(selectedOption?.name ?: "")
|
||||
),
|
||||
card = store.state.detailsState.scanResponse?.card
|
||||
)
|
||||
}
|
||||
store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Failure)
|
||||
}
|
||||
else -> { /* no-op */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> { /* no-op */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ private fun handlePrepareScreen(
|
|||
wallets = action.wallets,
|
||||
cardInfo = action.scanResponse.card.toCardInfo(),
|
||||
appCurrencyState = state.appCurrencyState.copy(
|
||||
fiatCurrencyName = action.fiatCurrencyName,
|
||||
currentFiatCurrency = action.fiatCurrencyName,
|
||||
showAppCurrencyDialog = false,
|
||||
),
|
||||
cardTermsOfUseUrl = action.cardTou.getUrl(action.scanResponse.card),
|
||||
|
|
@ -109,7 +109,8 @@ private fun handleAppCurrencyAction(
|
|||
is DetailsAction.AppCurrencyAction.SelectAppCurrency -> {
|
||||
state.copy(
|
||||
appCurrencyState = state.appCurrencyState.copy(
|
||||
fiatCurrencyName = action.fiatCurrencyName, showAppCurrencyDialog = false
|
||||
currentFiatCurrency = action.fiatCurrency,
|
||||
showAppCurrencyDialog = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@ package com.tangem.tap.features.details.redux
|
|||
import android.net.Uri
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.network.api.tangemTech.CurrenciesResponse
|
||||
import com.tangem.tap.common.entities.Button
|
||||
import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY
|
||||
import com.tangem.tap.common.redux.global.FiatCurrencyName
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.StateType
|
||||
|
|
@ -53,7 +51,7 @@ data class SecurityScreenState(
|
|||
enum class SecurityOption { LongTap, PassCode, AccessCode }
|
||||
|
||||
data class AppCurrencyState(
|
||||
val fiatCurrencyName: FiatCurrencyName = DEFAULT_FIAT_CURRENCY,
|
||||
val currentFiatCurrency: FiatCurrency = FiatCurrency.Default,
|
||||
val showAppCurrencyDialog: Boolean = false,
|
||||
val fiatCurrencies: List<CurrenciesResponse.Currency>? = null,
|
||||
val fiatCurrencies: List<FiatCurrency>? = null,
|
||||
)
|
||||
|
|
@ -2,9 +2,7 @@ package com.tangem.tap.features.details.ui
|
|||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.network.api.tangemTech.CurrenciesResponse
|
||||
import com.tangem.tap.common.extensions.toFormattedString
|
||||
import com.tangem.tap.common.redux.global.FiatCurrencyName
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.features.details.redux.DetailsAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -13,20 +11,30 @@ class CurrencySelectionDialog {
|
|||
|
||||
var dialog: AlertDialog? = null
|
||||
|
||||
fun show(currenciesList: List<CurrenciesResponse.Currency>, currentAppCurrency: FiatCurrencyName, context: Context) {
|
||||
|
||||
fun show(
|
||||
currenciesList: List<FiatCurrency>,
|
||||
currentAppCurrency: FiatCurrency,
|
||||
context: Context
|
||||
) {
|
||||
if (dialog == null) {
|
||||
val currenciesToShow = currenciesList.map { it.toFormattedString() }.toTypedArray()
|
||||
var currentSelection = currenciesList.indexOfFirst { it.code == currentAppCurrency }
|
||||
val currenciesToShow = currenciesList
|
||||
.map { it.displayName }
|
||||
.toTypedArray()
|
||||
var currentSelection = currenciesList
|
||||
.indexOfFirst { it.code == currentAppCurrency.code }
|
||||
|
||||
dialog = AlertDialog.Builder(context)
|
||||
.setTitle(context.getString(R.string.details_row_title_currency))
|
||||
.setNegativeButton(context.getString(R.string.common_cancel)) { _, _ ->
|
||||
store.dispatch(DetailsAction.AppCurrencyAction.Cancel)
|
||||
}
|
||||
.setPositiveButton(context.getString(R.string.common_done)) { _, _ ->
|
||||
val selectedCurrency = currenciesList[currentSelection]
|
||||
store.dispatch(DetailsAction.AppCurrencyAction.SelectAppCurrency(selectedCurrency.code))
|
||||
.setTitle(context.getString(R.string.details_row_title_currency))
|
||||
.setNegativeButton(context.getString(R.string.common_cancel)) { _, _ ->
|
||||
store.dispatch(DetailsAction.AppCurrencyAction.Cancel)
|
||||
}
|
||||
.setPositiveButton(context.getString(R.string.common_done)) { _, _ ->
|
||||
val selectedCurrency = currenciesList[currentSelection]
|
||||
store.dispatch(
|
||||
DetailsAction.AppCurrencyAction.SelectAppCurrency(
|
||||
fiatCurrency = selectedCurrency
|
||||
)
|
||||
)
|
||||
}
|
||||
.setOnDismissListener {
|
||||
store.dispatch(DetailsAction.AppCurrencyAction.Cancel)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
|
|||
store.dispatch(DetailsAction.CreateBackup)
|
||||
}
|
||||
|
||||
tvAppCurrency.text = state.appCurrencyState.fiatCurrencyName
|
||||
tvAppCurrency.text = state.appCurrencyState.currentFiatCurrency.code
|
||||
|
||||
tvAppCurrencyTitle.setOnClickListener {
|
||||
store.dispatch(DetailsAction.AppCurrencyAction.ChooseAppCurrency)
|
||||
|
|
@ -144,9 +144,9 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
|
|||
if (state.appCurrencyState.showAppCurrencyDialog &&
|
||||
!state.appCurrencyState.fiatCurrencies.isNullOrEmpty()) {
|
||||
currencySelectionDialog.show(
|
||||
state.appCurrencyState.fiatCurrencies,
|
||||
state.appCurrencyState.fiatCurrencyName,
|
||||
requireContext()
|
||||
currenciesList = state.appCurrencyState.fiatCurrencies,
|
||||
currentAppCurrency = state.appCurrencyState.currentFiatCurrency,
|
||||
context = requireContext()
|
||||
)
|
||||
} else {
|
||||
currencySelectionDialog.clear()
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ class ReceiptReducer : SendInternalReducer {
|
|||
|
||||
private fun determineSymbols(wallet: Wallet, amountType: AmountType): ReceiptSymbols {
|
||||
return ReceiptSymbols(
|
||||
fiat = store.state.globalState.appCurrency,
|
||||
fiat = store.state.globalState.appCurrency.code,
|
||||
crypto = wallet.blockchain.currency,
|
||||
token = when (amountType) {
|
||||
is AmountType.Token -> amountType.token.symbol
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import com.tangem.blockchain.common.AmountType
|
|||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.tap.common.CurrencyConverter
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||
import com.tangem.tap.common.entities.TapCurrency
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
import com.tangem.tap.common.text.DecimalDigitsInputFilter
|
||||
import com.tangem.tap.domain.TapError
|
||||
|
|
@ -123,18 +123,18 @@ enum class ButtonState {
|
|||
}
|
||||
|
||||
data class AmountState(
|
||||
val amountToExtract: Amount? = null,
|
||||
val typeOfAmount: AmountType = AmountType.Coin,
|
||||
val viewAmountValue: InputViewValue = InputViewValue(BigDecimal.ZERO.toPlainString()),
|
||||
val viewBalanceValue: String = BigDecimal.ZERO.toPlainString(),
|
||||
val mainCurrency: MainCurrency = MainCurrency(MainCurrencyType.FIAT, TapCurrency.DEFAULT_FIAT_CURRENCY),
|
||||
val amountToSendCrypto: BigDecimal = BigDecimal.ZERO,
|
||||
val balanceCrypto: BigDecimal = BigDecimal.ZERO,
|
||||
val cursorAtTheSamePosition: Boolean = true,
|
||||
val maxLengthOfAmount: Int = 2,
|
||||
val decimalSeparator: String = ".",
|
||||
val error: TapError? = null,
|
||||
val inputIsEnabled: Boolean = true,
|
||||
val amountToExtract: Amount? = null,
|
||||
val typeOfAmount: AmountType = AmountType.Coin,
|
||||
val viewAmountValue: InputViewValue = InputViewValue(BigDecimal.ZERO.toPlainString()),
|
||||
val viewBalanceValue: String = BigDecimal.ZERO.toPlainString(),
|
||||
val mainCurrency: MainCurrency = MainCurrency(MainCurrencyType.FIAT, FiatCurrency.Default.code),
|
||||
val amountToSendCrypto: BigDecimal = BigDecimal.ZERO,
|
||||
val balanceCrypto: BigDecimal = BigDecimal.ZERO,
|
||||
val cursorAtTheSamePosition: Boolean = true,
|
||||
val maxLengthOfAmount: Int = 2,
|
||||
val decimalSeparator: String = ".",
|
||||
val error: TapError? = null,
|
||||
val inputIsEnabled: Boolean = true,
|
||||
) : SendScreenState {
|
||||
|
||||
override val stateId: StateId = StateId.AMOUNT
|
||||
|
|
@ -146,7 +146,7 @@ data class AmountState(
|
|||
fun createMainCurrency(type: MainCurrencyType, canSwitched: Boolean): MainCurrency {
|
||||
return if (!canSwitched) MainCurrency(type, amountToExtract?.currencySymbol ?: "NONE", false)
|
||||
else when (type) {
|
||||
MainCurrencyType.FIAT -> MainCurrency(type, store.state.globalState.appCurrency)
|
||||
MainCurrencyType.FIAT -> MainCurrency(type, store.state.globalState.appCurrency.code)
|
||||
MainCurrencyType.CRYPTO -> MainCurrency(type, amountToExtract?.currencySymbol ?: "NONE")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import com.tangem.Message
|
|||
import com.tangem.tangem_sdk_new.extensions.dpToPx
|
||||
import com.tangem.tangem_sdk_new.extensions.hideSoftKeyboard
|
||||
import com.tangem.tap.common.KeyboardObserver
|
||||
import com.tangem.tap.common.entities.TapCurrency
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.extensions.getFromClipboard
|
||||
import com.tangem.tap.common.extensions.setOnImeActionListener
|
||||
import com.tangem.tap.common.qrCodeScan.ScanQrCodeActivity
|
||||
|
|
@ -261,11 +261,10 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
|
||||
private fun restoreMainCurrency(): MainCurrencyType {
|
||||
val sp = requireContext().getSharedPreferences("SendScreen", Context.MODE_PRIVATE)
|
||||
val mainCurrency = sp.getString("mainCurrency", TapCurrency.DEFAULT_FIAT_CURRENCY)
|
||||
val foundType = MainCurrencyType.values()
|
||||
.firstOrNull { it.name.equals(mainCurrency!!, ignoreCase = true) }
|
||||
?: MainCurrencyType.CRYPTO
|
||||
return foundType
|
||||
val mainCurrency = sp.getString("mainCurrency", FiatCurrency.Default.code)
|
||||
return MainCurrencyType.values()
|
||||
.firstOrNull { it.name.equals(mainCurrency!!, ignoreCase = true) }
|
||||
?: MainCurrencyType.CRYPTO
|
||||
}
|
||||
|
||||
fun saveMainCurrency(type: MainCurrencyType) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.tap.features.wallet.models
|
||||
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class TotalBalance(
|
||||
val state: State,
|
||||
val fiatAmount: BigDecimal,
|
||||
val fiatCurrency: FiatCurrency,
|
||||
) {
|
||||
enum class State {
|
||||
Loading,
|
||||
SomeTokensFailed,
|
||||
Success,
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import com.tangem.tap.domain.tokens.BlockchainNetwork
|
|||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
|
||||
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
|
||||
import com.tangem.tap.features.wallet.models.PendingTransaction
|
||||
import com.tangem.tap.features.wallet.models.TotalBalance
|
||||
import com.tangem.tap.features.wallet.models.toPendingTransactions
|
||||
import com.tangem.tap.features.wallet.models.toPendingTransactionsForToken
|
||||
import com.tangem.tap.features.wallet.ui.BalanceStatus
|
||||
|
|
@ -44,6 +45,7 @@ data class WalletState(
|
|||
val primaryBlockchain: Blockchain? = null,
|
||||
val primaryToken: Token? = null,
|
||||
val isTestnet: Boolean = false,
|
||||
val totalBalance: TotalBalance? = null,
|
||||
) : StateType {
|
||||
|
||||
// if you do not delegate - the application crashes on startup,
|
||||
|
|
@ -196,18 +198,20 @@ data class WalletState(
|
|||
return copy(wallets = replaceWalletInWallets(walletStore))
|
||||
}
|
||||
|
||||
fun updateWalletStores(walletStores: List<WalletStore>): WalletState {
|
||||
val walletStores = walletStores.toMutableList()
|
||||
private fun updateWalletStores(walletStores: List<WalletStore>): WalletState {
|
||||
val walletStoresMutable = walletStores.toMutableList()
|
||||
val updatedWallets = wallets.map { oldWalletStore ->
|
||||
val walletStore = walletStores.find { it.blockchainNetwork == oldWalletStore.blockchainNetwork }
|
||||
val walletStore = walletStoresMutable.find {
|
||||
it.blockchainNetwork == oldWalletStore.blockchainNetwork
|
||||
}
|
||||
if (walletStore != null) {
|
||||
walletStores.remove(walletStore)
|
||||
walletStoresMutable.remove(walletStore)
|
||||
walletStore
|
||||
} else {
|
||||
oldWalletStore
|
||||
}
|
||||
}
|
||||
return copy(wallets = updatedWallets + walletStores)
|
||||
return copy(wallets = updatedWallets + walletStoresMutable)
|
||||
}
|
||||
|
||||
fun removeWallet(walletData: WalletData?): WalletState {
|
||||
|
|
@ -268,6 +272,14 @@ data class WalletState(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateTotalBalance(
|
||||
totalBalance: TotalBalance
|
||||
): WalletState {
|
||||
return this.copy(
|
||||
totalBalance = totalBalance
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class WalletDialog : StateDialog {
|
||||
|
|
|
|||
|
|
@ -61,8 +61,9 @@ class TradeCryptoMiddleware {
|
|||
action = exchangeAction,
|
||||
blockchain = currency.blockchain,
|
||||
cryptoCurrencyName = currencySymbol,
|
||||
fiatCurrency = appCurrency,
|
||||
walletAddress = defaultAddress)?.let { store.dispatchOnMain(NavigationAction.OpenUrl(it)) }
|
||||
fiatCurrencyName = appCurrency.code,
|
||||
walletAddress = defaultAddress
|
||||
)?.let { store.dispatchOnMain(NavigationAction.OpenUrl(it)) }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ class WalletMiddleware {
|
|||
warningsMiddleware.tryToShowAppRatingWarning(action.wallet)
|
||||
}
|
||||
is WalletAction.LoadFiatRate -> {
|
||||
val appCurrencyId = globalState.appCurrency
|
||||
val appCurrencyId = globalState.appCurrency.code
|
||||
scope.launch {
|
||||
val coinsList = when {
|
||||
action.wallet != null -> {
|
||||
|
|
@ -344,4 +344,4 @@ class WalletMiddleware {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -126,7 +126,7 @@ class MultiWalletReducer {
|
|||
),
|
||||
fiatAmountFormatted = tokenWalletData.fiatRate?.let {
|
||||
action.amount.value
|
||||
?.toFiatString(it, store.state.globalState.appCurrency)
|
||||
?.toFiatString(it, store.state.globalState.appCurrency.code)
|
||||
},
|
||||
blockchainAmount = wallet.amounts[AmountType.Coin]?.value ?: BigDecimal.ZERO
|
||||
),
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.tap.common.extensions.toFormattedCurrencyString
|
|||
import com.tangem.tap.common.extensions.toFormattedFiatValue
|
||||
import com.tangem.tap.domain.getFirstToken
|
||||
import com.tangem.tap.domain.tokens.BlockchainNetwork
|
||||
import com.tangem.tap.features.wallet.models.TotalBalance
|
||||
import com.tangem.tap.features.wallet.models.removeUnknownTransactions
|
||||
import com.tangem.tap.features.wallet.models.toPendingTransactions
|
||||
import com.tangem.tap.features.wallet.redux.*
|
||||
|
|
@ -16,6 +17,7 @@ import com.tangem.tap.features.wallet.ui.BalanceStatus
|
|||
import com.tangem.tap.features.wallet.ui.BalanceWidgetData
|
||||
import com.tangem.tap.features.wallet.ui.TokenData
|
||||
import com.tangem.tap.store
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
|
||||
class OnWalletLoadedReducer {
|
||||
|
|
@ -33,13 +35,12 @@ class OnWalletLoadedReducer {
|
|||
blockchainNetwork: BlockchainNetwork,
|
||||
walletState: WalletState
|
||||
): WalletState {
|
||||
val fiatCurrencySymbol = store.state.globalState.appCurrency
|
||||
val walletData = walletState.getWalletData(blockchainNetwork) ?: return walletState
|
||||
|
||||
val fiatCurrency = store.state.globalState.appCurrency
|
||||
val exchangeManager = store.state.globalState.currencyExchangeManager
|
||||
|
||||
val coinAmountValue = wallet.amounts[AmountType.Coin]?.value
|
||||
if (walletState.getWalletData(blockchainNetwork) == null) {
|
||||
return walletState
|
||||
}
|
||||
val formattedAmount = coinAmountValue?.toFormattedCurrencyString(
|
||||
wallet.blockchain.decimals(),
|
||||
wallet.blockchain.currency
|
||||
|
|
@ -54,10 +55,9 @@ class OnWalletLoadedReducer {
|
|||
} else {
|
||||
BalanceStatus.VerifiedOnline
|
||||
}
|
||||
val walletData = walletState.getWalletData(blockchainNetwork)
|
||||
|
||||
val fiatAmount = walletData?.fiatRate?.let { coinAmountValue?.toFiatValue(it) }
|
||||
val newWalletData = walletData?.copy(
|
||||
val fiatAmount = walletData.fiatRate?.let { coinAmountValue?.toFiatValue(it) }
|
||||
val newWalletData = walletData.copy(
|
||||
currencyData = walletData.currencyData.copy(
|
||||
status = balanceStatus, currency = wallet.blockchain.fullName,
|
||||
currencySymbol = wallet.blockchain.currency,
|
||||
|
|
@ -65,7 +65,7 @@ class OnWalletLoadedReducer {
|
|||
amount = coinAmountValue,
|
||||
amountFormatted = formattedAmount,
|
||||
fiatAmount = fiatAmount,
|
||||
fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(fiatCurrencySymbol)
|
||||
fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(fiatCurrency.code)
|
||||
),
|
||||
pendingTransactions = pendingTransactions.removeUnknownTransactions(),
|
||||
mainButton = WalletMainButton.SendButton(coinSendButton),
|
||||
|
|
@ -87,7 +87,7 @@ class OnWalletLoadedReducer {
|
|||
val tokenFiatAmount =
|
||||
tokenWalletData?.fiatRate?.let { rate -> tokenAmountValue?.toFiatValue(rate) }
|
||||
|
||||
val tokenSendButton = newWalletData?.shouldEnableTokenSendButton() == true
|
||||
val tokenSendButton = newWalletData.shouldEnableTokenSendButton()
|
||||
&& tokenPendingTransactions.isEmpty()
|
||||
tokenWalletData?.copy(
|
||||
currencyData = tokenWalletData.currencyData.copy(
|
||||
|
|
@ -99,31 +99,40 @@ class OnWalletLoadedReducer {
|
|||
token.symbol
|
||||
),
|
||||
fiatAmount = tokenFiatAmount,
|
||||
fiatAmountFormatted = tokenFiatAmount?.toFormattedFiatValue(fiatCurrencySymbol)
|
||||
fiatAmountFormatted = tokenFiatAmount?.toFormattedFiatValue(fiatCurrency.code)
|
||||
),
|
||||
pendingTransactions = tokenPendingTransactions.removeUnknownTransactions(),
|
||||
mainButton = WalletMainButton.SendButton(tokenSendButton),
|
||||
tradeCryptoState = TradeCryptoState.from(exchangeManager, tokenWalletData),
|
||||
)
|
||||
}
|
||||
val newWallets = (tokens + newWalletData).mapNotNull { it }
|
||||
val newWallets = tokens + newWalletData
|
||||
val wallets = walletState.replaceSomeWallets((newWallets))
|
||||
|
||||
val totalBalance = TotalBalance(
|
||||
state = wallets.findTotalBalanceState(),
|
||||
fiatAmount = wallets.calculateTotalFiatAmount(),
|
||||
fiatCurrency = fiatCurrency,
|
||||
)
|
||||
|
||||
val state = if (wallets.any { it.currencyData.status == BalanceStatus.Loading }) {
|
||||
ProgressState.Loading
|
||||
} else {
|
||||
ProgressState.Done
|
||||
}
|
||||
val newState = walletState.updateWalletsData(wallets)
|
||||
return newState.copy(
|
||||
state = state, error = null
|
||||
)
|
||||
return walletState
|
||||
.updateWalletsData(wallets)
|
||||
.updateTotalBalance(totalBalance)
|
||||
.copy(
|
||||
state = state,
|
||||
error = null
|
||||
)
|
||||
}
|
||||
|
||||
private fun onSingleWalletLoaded(wallet: Wallet, walletState: WalletState): WalletState {
|
||||
if (wallet.blockchain != walletState.primaryBlockchain) return walletState
|
||||
|
||||
val fiatCurrencySymbol = store.state.globalState.appCurrency
|
||||
val fiatCurrencyName = store.state.globalState.appCurrency.code
|
||||
val exchangeManager = store.state.globalState.currencyExchangeManager
|
||||
|
||||
val token = wallet.getFirstToken()
|
||||
|
|
@ -132,7 +141,7 @@ class OnWalletLoadedReducer {
|
|||
if (tokenAmount != null) {
|
||||
val tokenFiatRate = walletState.primaryWallet?.currencyData?.token?.fiatRate
|
||||
val tokenFiatAmount =
|
||||
tokenFiatRate?.let { tokenAmount.value?.toFiatString(it, fiatCurrencySymbol) }
|
||||
tokenFiatRate?.let { tokenAmount.value?.toFiatString(it, fiatCurrencyName) }
|
||||
TokenData(
|
||||
tokenAmount.value?.toFormattedCurrencyString(
|
||||
token.decimals, token.symbol
|
||||
|
|
@ -152,7 +161,7 @@ class OnWalletLoadedReducer {
|
|||
)
|
||||
val fiatRate = walletState.primaryWallet?.fiatRate
|
||||
val fiatAmountRaw = fiatRate?.multiply(amount)?.setScale(2, RoundingMode.DOWN)
|
||||
val fiatAmount = fiatRate?.let { amount?.toFiatString(it, fiatCurrencySymbol) }
|
||||
val fiatAmount = fiatRate?.let { amount?.toFiatString(it, fiatCurrencyName) }
|
||||
|
||||
val pendingTransactions = wallet.recentTransactions.toPendingTransactions(wallet.address)
|
||||
val sendButtonEnabled = amount?.isZero() == false && pendingTransactions.isEmpty()
|
||||
|
|
@ -183,4 +192,48 @@ class OnWalletLoadedReducer {
|
|||
state = ProgressState.Done, error = null
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<WalletData>.findTotalBalanceState(): TotalBalance.State {
|
||||
return this.mapToTotalBalanceState()
|
||||
.fold(initial = TotalBalance.State.Loading) { accState, newState ->
|
||||
accState or newState
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<WalletData>.calculateTotalFiatAmount(): BigDecimal {
|
||||
return this.map { it.currencyData.fiatAmount ?: BigDecimal.ZERO }
|
||||
.reduce(BigDecimal::plus)
|
||||
}
|
||||
|
||||
private fun List<WalletData>.mapToTotalBalanceState(): List<TotalBalance.State> {
|
||||
return this.map {
|
||||
when (it.currencyData.status) {
|
||||
BalanceStatus.VerifiedOnline,
|
||||
BalanceStatus.SameCurrencyTransactionInProgress,
|
||||
BalanceStatus.TransactionInProgress -> TotalBalance.State.Success
|
||||
BalanceStatus.Unreachable,
|
||||
BalanceStatus.NoAccount,
|
||||
BalanceStatus.EmptyCard,
|
||||
BalanceStatus.UnknownBlockchain -> TotalBalance.State.SomeTokensFailed
|
||||
BalanceStatus.Loading,
|
||||
null -> TotalBalance.State.Loading
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
infix fun TotalBalance.State.or(newState: TotalBalance.State): TotalBalance.State {
|
||||
return when (this) {
|
||||
TotalBalance.State.Loading -> when (newState) {
|
||||
TotalBalance.State.Loading -> this
|
||||
TotalBalance.State.SomeTokensFailed,
|
||||
TotalBalance.State.Success -> newState
|
||||
}
|
||||
TotalBalance.State.Success,
|
||||
TotalBalance.State.SomeTokensFailed -> when (newState) {
|
||||
TotalBalance.State.Loading,
|
||||
TotalBalance.State.SomeTokensFailed -> newState
|
||||
TotalBalance.State.Success -> this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,12 +4,12 @@ import com.tangem.blockchain.common.AmountType
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.domain.common.TwinCardNumber
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.extensions.toFiatString
|
||||
import com.tangem.tap.common.extensions.toFiatValue
|
||||
import com.tangem.tap.common.extensions.toFormattedCurrencyString
|
||||
import com.tangem.tap.common.extensions.toFormattedFiatValue
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.FiatCurrencyName
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.extensions.getArtworkUrl
|
||||
import com.tangem.tap.domain.getFirstToken
|
||||
|
|
@ -70,9 +70,9 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
when (action.error) {
|
||||
is TapError.NoInternetConnection -> {
|
||||
val wallets = newState.wallets
|
||||
.map {
|
||||
it.copy(
|
||||
walletsData = it.walletsData.map {
|
||||
.map { store ->
|
||||
store.copy(
|
||||
walletsData = store.walletsData.map {
|
||||
it.copy(
|
||||
currencyData = it.currencyData.copy(
|
||||
status = BalanceStatus.Unreachable
|
||||
|
|
@ -110,6 +110,8 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
)
|
||||
)
|
||||
}
|
||||
else -> { /* no-op */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -306,23 +308,23 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
}
|
||||
is WalletAction.SetWalletRent -> {
|
||||
var walletData = newState.getWalletData(action.blockchain)
|
||||
if (walletData == null) {
|
||||
newState
|
||||
} else {
|
||||
walletData =
|
||||
walletData.copy(warningRent = WalletRent(action.minRent, action.rentExempt))
|
||||
if (walletData != null) {
|
||||
walletData = walletData.copy(
|
||||
warningRent = WalletRent(action.minRent, action.rentExempt)
|
||||
)
|
||||
newState = newState.updateWalletsData(listOf(walletData))
|
||||
|
||||
}
|
||||
}
|
||||
is WalletAction.RemoveWalletRent -> {
|
||||
var walletData = newState.getWalletData(action.blockchain)
|
||||
if (walletData == null) {
|
||||
newState
|
||||
} else {
|
||||
if (walletData != null) {
|
||||
walletData = walletData.copy(warningRent = null)
|
||||
newState = newState.updateWalletsData(listOf(walletData))
|
||||
}
|
||||
}
|
||||
else -> { /* no-op */
|
||||
}
|
||||
}
|
||||
return newState
|
||||
}
|
||||
|
|
@ -377,22 +379,30 @@ private fun handleCheckSignedHashesActions(
|
|||
|
||||
private fun setNewFiatRate(
|
||||
fiatRate: Pair<Currency, BigDecimal?>,
|
||||
appCurrency: FiatCurrencyName, state: WalletState
|
||||
appCurrency: FiatCurrency,
|
||||
state: WalletState
|
||||
): WalletState {
|
||||
val rate = fiatRate.second ?: return state
|
||||
val rateFormatted = rate.toFormattedCurrencyString(2, appCurrency, RoundingMode.HALF_UP)
|
||||
val rateFormatted = rate.toFormattedCurrencyString(
|
||||
decimals = 2,
|
||||
currency = appCurrency.code,
|
||||
roundingMode = RoundingMode.HALF_UP
|
||||
)
|
||||
val currency = fiatRate.first
|
||||
|
||||
return if (!state.isMultiwalletAllowed) {
|
||||
setSingeWalletFiatRate(rate, rateFormatted, currency, appCurrency, state)
|
||||
setSingleWalletFiatRate(rate, rateFormatted, currency, appCurrency, state)
|
||||
} else {
|
||||
setMultiWalletFiatRate(rate, rateFormatted, currency, appCurrency, state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMultiWalletFiatRate(
|
||||
rate: BigDecimal, rateFormatted: String, currency: Currency,
|
||||
appCurrency: FiatCurrencyName, state: WalletState
|
||||
rate: BigDecimal,
|
||||
rateFormatted: String,
|
||||
currency: Currency,
|
||||
appCurrency: FiatCurrency,
|
||||
state: WalletState
|
||||
): WalletState {
|
||||
|
||||
val walletStore = state.getWalletStore(currency) ?: return state
|
||||
|
|
@ -405,7 +415,7 @@ private fun setMultiWalletFiatRate(
|
|||
is Currency.Token ->
|
||||
wallet?.getTokenAmount(currency.token)?.value?.toFiatValue(rate)
|
||||
}
|
||||
val fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(appCurrency)
|
||||
val fiatAmountFormatted = fiatAmount?.toFormattedFiatValue(appCurrency.code)
|
||||
val newWalletData = state.getWalletData(currency)?.copy(
|
||||
currencyData = walletData.currencyData.copy(
|
||||
fiatAmountFormatted = fiatAmountFormatted,
|
||||
|
|
@ -416,16 +426,19 @@ private fun setMultiWalletFiatRate(
|
|||
return state.updateWalletData(newWalletData)
|
||||
}
|
||||
|
||||
private fun setSingeWalletFiatRate(
|
||||
rate: BigDecimal, rateFormatted: String, currency: Currency,
|
||||
appCurrency: FiatCurrencyName, state: WalletState
|
||||
private fun setSingleWalletFiatRate(
|
||||
rate: BigDecimal,
|
||||
rateFormatted: String,
|
||||
currency: Currency,
|
||||
appCurrency: FiatCurrency,
|
||||
state: WalletState
|
||||
): WalletState {
|
||||
val wallet = state.primaryWalletManager?.wallet ?: return state
|
||||
val token = wallet.getFirstToken()
|
||||
|
||||
if (currency == state.primaryWallet?.currency) {
|
||||
val fiatAmount = wallet.amounts[AmountType.Coin]?.value
|
||||
?.toFiatString(rate, appCurrency)
|
||||
?.toFiatString(rate, appCurrency.code)
|
||||
val walletData = state.primaryWallet.copy(
|
||||
currencyData = state.primaryWallet.currencyData.copy(fiatAmountFormatted = fiatAmount),
|
||||
fiatRate = rate,
|
||||
|
|
@ -433,7 +446,9 @@ private fun setSingeWalletFiatRate(
|
|||
)
|
||||
return state.updateWalletData(walletData)
|
||||
} else if (currency is Currency.Token && currency.token == token) {
|
||||
val tokenFiatAmount = wallet.getTokenAmount(token)?.value?.toFiatString(rate, appCurrency)
|
||||
val tokenFiatAmount = wallet.getTokenAmount(token)
|
||||
?.value
|
||||
?.toFiatString(rate, appCurrency.code)
|
||||
val tokenData = state.primaryWallet?.currencyData?.token?.copy(
|
||||
fiatAmount = tokenFiatAmount,
|
||||
fiatRate = rate,
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
package com.tangem.tap.features.wallet.ui.wallet
|
||||
|
||||
import android.app.Dialog
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.TapWorkarounds.isTestCard
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.currenciesRepository
|
||||
import com.tangem.tap.features.tokens.redux.TokensAction
|
||||
import com.tangem.tap.features.wallet.models.TotalBalance
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletDialog
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
|
|
@ -51,6 +52,7 @@ class MultiWalletView : WalletView {
|
|||
btnScanMultiwallet.show()
|
||||
rvMultiwallet.show()
|
||||
btnAddToken.show()
|
||||
lCardTotalBalance.root.show()
|
||||
setupWalletCardNumber(binding)
|
||||
}
|
||||
|
||||
|
|
@ -97,6 +99,7 @@ class MultiWalletView : WalletView {
|
|||
val fragment = fragment ?: return
|
||||
val binding = binding ?: return
|
||||
|
||||
state.totalBalance?.let { handleTotalBalance(binding, it) }
|
||||
walletsAdapter.submitList(state.walletsData, state.primaryBlockchain, state.primaryToken)
|
||||
|
||||
binding.btnAddToken.setOnClickListener {
|
||||
|
|
@ -127,6 +130,38 @@ class MultiWalletView : WalletView {
|
|||
handleDialogs(state.walletDialog)
|
||||
}
|
||||
|
||||
private fun handleTotalBalance(
|
||||
binding: FragmentWalletBinding,
|
||||
totalBalance: TotalBalance,
|
||||
) = with(binding.lCardTotalBalance) {
|
||||
when (totalBalance.state) {
|
||||
TotalBalance.State.Loading -> {
|
||||
pbLoading.showAnimated()
|
||||
tvBalance.hideAnimated(hiddenVisibility = View.INVISIBLE)
|
||||
tvProcessing.hideAnimated()
|
||||
}
|
||||
TotalBalance.State.SomeTokensFailed -> {
|
||||
tvBalance.showAnimated()
|
||||
pbLoading.hideAnimated()
|
||||
tvProcessing.showAnimated()
|
||||
}
|
||||
TotalBalance.State.Success -> {
|
||||
tvBalance.showAnimated()
|
||||
pbLoading.hideAnimated()
|
||||
tvProcessing.hideAnimated()
|
||||
}
|
||||
}
|
||||
|
||||
tvBalance.text = totalBalance.fiatAmount.formatAmountAsSpannedString(
|
||||
currencySymbol = totalBalance.fiatCurrency.symbol
|
||||
)
|
||||
tvCurrencyName.text = totalBalance.fiatCurrency.code
|
||||
|
||||
tvCurrencyName.setOnClickListener {
|
||||
// TODO: Open app currency selector
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleErrorStates(
|
||||
state: WalletState,
|
||||
binding: FragmentWalletBinding,
|
||||
|
|
@ -148,6 +183,8 @@ class MultiWalletView : WalletView {
|
|||
fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle)
|
||||
)
|
||||
}
|
||||
else -> { /* no-op */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
package com.tangem.tap.network.coinmarketcap
|
||||
|
||||
import com.tangem.network.common.AddHeaderInterceptor
|
||||
import com.tangem.network.common.createRetrofitInstance
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface CoinMarketCapApi {
|
||||
|
||||
@GET("v1/tools/price-conversion")
|
||||
suspend fun getRateInfo(
|
||||
@Query("amount") amount: Int,
|
||||
@Query("symbol") cryptoCurrencyName: String,
|
||||
@Query("convert") fiatCurrencyName: String? = null
|
||||
): RateInfoResponse
|
||||
|
||||
@GET("v1/fiat/map")
|
||||
suspend fun getFiatMap(): FiatMapResponse
|
||||
|
||||
|
||||
companion object {
|
||||
private const val baseUrl = "https://pro-api.coinmarketcap.com/"
|
||||
|
||||
fun create(apiKey: String): CoinMarketCapApi {
|
||||
return createRetrofitInstance(
|
||||
baseUrl = baseUrl,
|
||||
interceptors = listOf(
|
||||
AddHeaderInterceptor(mapOf("X-CMC_PRO_API_KEY" to apiKey)),
|
||||
),
|
||||
).create(CoinMarketCapApi::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.tangem.tap.network.coinmarketcap
|
||||
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.common.services.performRequest
|
||||
import com.tangem.tap.common.redux.global.FiatCurrencyName
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.math.BigDecimal
|
||||
|
||||
//TODO: refactoring: move to the domain module and aggregate it as the alternative service for TangemTech
|
||||
class CoinMarketCapService() {
|
||||
private val api: CoinMarketCapApi by lazy { CoinMarketCapApi.create(getApiKey()) }
|
||||
|
||||
private fun getApiKey(): String {
|
||||
return store.state.globalState.configManager?.config?.coinMarketCapKey ?: ""
|
||||
}
|
||||
|
||||
suspend fun getRate(
|
||||
currency: String, fiatCurrency: FiatCurrencyName? = null
|
||||
): Result<BigDecimal> = withContext(Dispatchers.IO) {
|
||||
val response = performRequest { api.getRateInfo(1, currency, fiatCurrency) }
|
||||
return@withContext when (response) {
|
||||
is Result.Success -> Result.Success(response.data.data.getRate())
|
||||
is Result.Failure -> response
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getFiatCurrencies(): Result<List<FiatCurrency>> = withContext(Dispatchers.IO) {
|
||||
val response = performRequest { api.getFiatMap() }
|
||||
return@withContext when (response) {
|
||||
is Result.Success -> Result.Success(response.data.data.sortedBy { it.name })
|
||||
is Result.Failure -> response
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
package com.tangem.tap.network.coinmarketcap
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import java.math.BigDecimal
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class RateInfoResponse : CoinMarketResponse<RateData>()
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RateData(
|
||||
val quote: Map<String, CurrencyRate>
|
||||
) {
|
||||
fun getRate(): BigDecimal = quote.values.first().price
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CurrencyRate(
|
||||
val price: BigDecimal
|
||||
)
|
||||
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Status(
|
||||
val timestamp: String,
|
||||
@Json(name = "error_code")
|
||||
val errorCode: Int,
|
||||
@Json(name = "error_message")
|
||||
val errorMessage: String?,
|
||||
val elapsed: Int,
|
||||
@Json(name = "credit_count")
|
||||
val creditCount: Int,
|
||||
val notice: String?
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class FiatMapResponse : CoinMarketResponse<List<FiatCurrency>>()
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
open class CoinMarketResponse<T : Any> {
|
||||
lateinit var status: Status
|
||||
lateinit var data: T
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class FiatCurrency(
|
||||
val id: Int,
|
||||
val name: String,
|
||||
val sign: String,
|
||||
val symbol: String
|
||||
)
|
||||
|
|
@ -30,7 +30,7 @@ interface ExchangeUrlBuilder {
|
|||
action: CurrencyExchangeManager.Action,
|
||||
blockchain: Blockchain,
|
||||
cryptoCurrencyName: CryptoCurrencyName,
|
||||
fiatCurrency: String,
|
||||
fiatCurrencyName: String,
|
||||
walletAddress: String,
|
||||
): String?
|
||||
|
||||
|
|
@ -74,13 +74,19 @@ class CurrencyExchangeManager(
|
|||
action: Action,
|
||||
blockchain: Blockchain,
|
||||
cryptoCurrencyName: CryptoCurrencyName,
|
||||
fiatCurrency: String,
|
||||
fiatCurrencyName: String,
|
||||
walletAddress: String,
|
||||
): String? {
|
||||
if (blockchain.isTestnet()) return blockchain.getTestnetTopUpUrl()
|
||||
|
||||
val urlBuilder = getExchangeUrlBuilder(action)
|
||||
return urlBuilder.getUrl(action, blockchain, cryptoCurrencyName, fiatCurrency, walletAddress)
|
||||
return urlBuilder.getUrl(
|
||||
action,
|
||||
blockchain,
|
||||
cryptoCurrencyName,
|
||||
fiatCurrencyName,
|
||||
walletAddress
|
||||
)
|
||||
}
|
||||
|
||||
override fun getSellCryptoReceiptUrl(action: Action, transactionId: String): String? {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.SharedPreferences
|
|||
import androidx.core.content.edit
|
||||
import com.tangem.common.json.MoshiJsonConverter
|
||||
import com.tangem.network.api.tangemTech.CurrenciesResponse
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -12,15 +13,25 @@ class FiatCurrenciesPrefStorage(
|
|||
private val preferences: SharedPreferences,
|
||||
private val converter: MoshiJsonConverter,
|
||||
) {
|
||||
private val FIAT_CURRENCIES_KEY_OLD = "fiatCurrencies"
|
||||
private val FIAT_CURRENCIES_KEY = "fiatCurrencies_v2"
|
||||
|
||||
fun migrate() {
|
||||
preferences.edit(true) {
|
||||
remove(FIAT_CURRENCIES_KEY_OLD)
|
||||
remove(APP_CURRENCY_KEY_OLD)
|
||||
}
|
||||
}
|
||||
|
||||
fun getAppCurrency(): FiatCurrency {
|
||||
val json = preferences.getString(APP_CURRENCY_KEY, "")
|
||||
if (json.isNullOrBlank()) return FiatCurrency.Default
|
||||
|
||||
return converter.fromJson(json) ?: FiatCurrency.Default
|
||||
}
|
||||
|
||||
fun saveAppCurrency(fiatCurrency: FiatCurrency) {
|
||||
val json = converter.toJson(fiatCurrency)
|
||||
preferences.edit { putString(APP_CURRENCY_KEY, json) }
|
||||
}
|
||||
|
||||
fun save(currencies: List<CurrenciesResponse.Currency>) {
|
||||
val json: String = converter.toJson(currencies)
|
||||
return preferences.edit().putString(FIAT_CURRENCIES_KEY, json).apply()
|
||||
|
|
@ -33,4 +44,12 @@ class FiatCurrenciesPrefStorage(
|
|||
|
||||
return converter.fromJson(json, type) ?: emptyList()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val FIAT_CURRENCIES_KEY_OLD = "fiatCurrencies"
|
||||
private const val APP_CURRENCY_KEY_OLD = "appCurrency"
|
||||
|
||||
private const val FIAT_CURRENCIES_KEY = "fiatCurrencies_v2"
|
||||
private const val APP_CURRENCY_KEY = "appCurrency_v2"
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,6 @@ import android.content.Context
|
|||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import com.tangem.common.json.MoshiJsonConverter
|
||||
import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY
|
||||
import com.tangem.tap.common.redux.global.FiatCurrencyName
|
||||
import java.util.*
|
||||
|
||||
|
||||
|
|
@ -27,15 +25,6 @@ class PreferencesStorage(applicationContext: Application) {
|
|||
fiatCurrenciesPrefStorage.migrate()
|
||||
}
|
||||
|
||||
fun getAppCurrency(): FiatCurrencyName {
|
||||
return preferences.getString(APP_CURRENCY_KEY, DEFAULT_FIAT_CURRENCY)
|
||||
?: DEFAULT_FIAT_CURRENCY
|
||||
}
|
||||
|
||||
fun saveAppCurrency(fiatCurrencyName: FiatCurrencyName) {
|
||||
preferences.edit { putString(APP_CURRENCY_KEY, fiatCurrencyName) }
|
||||
}
|
||||
|
||||
fun getCountOfLaunches(): Int = preferences.getInt(APP_LAUNCH_COUNT_KEY, 1)
|
||||
|
||||
@Deprecated("Use UsedCardsPrefStorage instead")
|
||||
|
|
@ -74,7 +63,6 @@ class PreferencesStorage(applicationContext: Application) {
|
|||
|
||||
companion object {
|
||||
private const val PREFERENCES_NAME = "tapPrefs"
|
||||
private const val APP_CURRENCY_KEY = "appCurrency"
|
||||
private const val DISCLAIMER_ACCEPTED_KEY = "disclaimerAccepted"
|
||||
private const val TWINS_ONBOARDING_SHOWN_KEY = "twinsOnboardingShown"
|
||||
private const val APP_LAUNCH_COUNT_KEY = "launchCount"
|
||||
|
|
|
|||
97
app/src/main/res/layout/card_total_balance.xml
Normal file
97
app/src/main/res/layout/card_total_balance.xml
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/fl_balance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:minWidth="300dp">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card_balance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/white"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:elevation="3dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="18dp"
|
||||
android:paddingBottom="18dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:textColor="@color/iconGray"
|
||||
android:textSize="14sp"
|
||||
android:text="@string/main_page_balance"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/tv_currency_name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_balance"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="gone"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/darkGray6"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
tools:text="$ 22 325.40"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pb_loading"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:padding="2dp"
|
||||
android:visibility="gone"
|
||||
android:indeterminate="true"
|
||||
android:indeterminateTint="@color/accent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_title"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_processing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:visibility="gone"
|
||||
android:textColor="@color/warning"
|
||||
android:textSize="12sp"
|
||||
android:text="@string/main_processing_full_amount"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_balance"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_currency_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/darkGray1"
|
||||
android:textSize="16sp"
|
||||
app:drawableEndCompat="@drawable/ic_arrow_angle_down"
|
||||
app:drawableTint="@color/darkGray1"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
tools:text="USD" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</FrameLayout>
|
||||
|
|
@ -101,16 +101,26 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/barrier" />
|
||||
|
||||
<include
|
||||
android:id="@+id/l_card_total_balance"
|
||||
layout="@layout/card_total_balance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/rv_warning_messages"
|
||||
/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_pending_transaction"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
app:layout_goneMarginTop="12dp"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:overScrollMode="never"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/rv_warning_messages" />
|
||||
app:layout_constraintTop_toBottomOf="@id/l_card_total_balance" />
|
||||
|
||||
<include
|
||||
android:id="@+id/l_card_balance"
|
||||
|
|
@ -204,4 +214,4 @@
|
|||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
|||
|
|
@ -382,4 +382,6 @@
|
|||
<string name="feedback_preface_support">Привет, команда поддержки,</string>
|
||||
<string name="feedback_preface_tx_push_failed">Пожалуйста, расскажите нам больше о Вашей проблеме. Каждая деталь может быть полезной.</string>
|
||||
<string name="feedback_data_collection_message">Информация ниже не является обязательной. Вы можете стереть её, если хотите.</string>
|
||||
</resources>
|
||||
<string name="main_page_balance">Баланс</string>
|
||||
<string name="main_processing_full_amount">Обработка полной суммы…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -206,4 +206,6 @@
|
|||
<string name="xtz_withdrawal_message_warning">To avoid paying an increased commission the next time you top up your wallet, reduce the amount by %s XTZ</string>
|
||||
<string name="xtz_withdrawal_message_reduce">Reduce by %s XTZ</string>
|
||||
<string name="xtz_withdrawal_message_ignore">No, send all</string>
|
||||
</resources>
|
||||
<string name="main_page_balance">Total balance</string>
|
||||
<string name="main_processing_full_amount">Processing full amount…</string>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue