Updated on 2026-08-14
This commit is contained in:
commit
4de32b1119
34 changed files with 660 additions and 368 deletions
|
|
@ -92,9 +92,9 @@ dependencies {
|
|||
implementation 'com.google.android.play:core-ktx:1.8.1'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
implementation "com.tangem:blockchain:${versions.tamgem_blockchain_sdk}"
|
||||
implementation "com.tangem.tangem-sdk-kotlin:core:${versions.tamgem_card_sdk}"
|
||||
implementation "com.tangem.tangem-sdk-kotlin:android:${versions.tamgem_card_sdk}"
|
||||
implementation "com.tangem:blockchain:${versions.tangem_blockchain_sdk}"
|
||||
implementation "com.tangem.tangem-sdk-kotlin:core:${versions.tangem_card_sdk}"
|
||||
implementation "com.tangem.tangem-sdk-kotlin:android:${versions.tangem_card_sdk}"
|
||||
|
||||
// WebView
|
||||
implementation "androidx.browser:browser:1.3.0"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.tangem.blockchain.common.BlockchainError
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.AnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||
import com.tangem.tap.features.demo.DemoTransactionSender
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
fun AnalyticsHandler.logSendTransactionError(
|
||||
error: BlockchainError,
|
||||
action: Analytics.ActionToLog,
|
||||
parameters: Map<AnalyticsParam, String>? = mapOf(),
|
||||
card: Card? = null,
|
||||
) {
|
||||
when (val blockchainSdkError = (error as BlockchainSdkError)) {
|
||||
is BlockchainSdkError.WrappedTangemError -> {
|
||||
val tangemSdkError = (blockchainSdkError.tangemError as? TangemSdkError) ?: return
|
||||
|
||||
logCardSdkError(
|
||||
error = tangemSdkError,
|
||||
actionToLog = action,
|
||||
parameters = parameters,
|
||||
card = card,
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
when {
|
||||
blockchainSdkError.customMessage.contains(DemoTransactionSender.ID) -> return
|
||||
else -> {
|
||||
val params = parameters?.toMutableMap() ?: mutableMapOf()
|
||||
params[AnalyticsParam.ACTION] = action.key
|
||||
params[AnalyticsParam.ERROR_CODE] = error.code.toString()
|
||||
params[AnalyticsParam.ERROR_DESCRIPTION] = "${error.javaClass.simpleName}: ${error.customMessage}"
|
||||
params[AnalyticsParam.ERROR_KEY] = "BlockchainSdkError"
|
||||
|
||||
FirebaseCrashlytics.getInstance().apply {
|
||||
params.forEach { setCustomKey(it.key.param, it.value) }
|
||||
recordException(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,10 +44,6 @@ sealed class TapError(
|
|||
val customMessage: String = "Unsupported state:"
|
||||
) : TapError(R.string.common_custom_string, listOf("$customMessage $stateError"))
|
||||
|
||||
sealed class XmlError {
|
||||
object AssetAccountNotCreated : TapError(R.string.send_error_no_account_xlm)
|
||||
}
|
||||
|
||||
sealed class WalletManager {
|
||||
object CreationError : CustomError("Can't create wallet manager")
|
||||
class NoAccountError(amountToCreateAccount: String) : CustomError(amountToCreateAccount)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.blockchain.blockchains.ethereum.EthereumUtils
|
|||
import com.tangem.blockchain.blockchains.ethereum.EthereumUtils.Companion.toKeccak
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
import com.tangem.blockchain.common.CommonSigner
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.TransactionSender
|
||||
|
|
@ -24,6 +25,7 @@ import com.tangem.common.extensions.toHexString
|
|||
import com.tangem.crypto.CryptoUtils
|
||||
import com.tangem.operations.sign.SignHashCommand
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.extensions.logSendTransactionError
|
||||
import com.tangem.tap.common.extensions.safeUpdate
|
||||
import com.tangem.tap.common.extensions.toFormattedString
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession
|
||||
|
|
@ -38,8 +40,8 @@ import com.tangem.tap.tangemSdk
|
|||
import com.tangem.tap.tangemSdkManager
|
||||
import com.trustwallet.walletconnect.models.ethereum.WCEthereumSignMessage
|
||||
import com.trustwallet.walletconnect.models.ethereum.WCEthereumTransaction
|
||||
import java.math.BigDecimal
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
|
||||
class WalletConnectSdkHelper {
|
||||
|
||||
|
|
@ -69,7 +71,7 @@ class WalletConnectSdkHelper {
|
|||
(walletManager as? EthereumGasLoader)?.getGasPrice()) {
|
||||
is Result.Success -> result.data.toBigDecimal()
|
||||
is Result.Failure -> {
|
||||
Timber.e(result.error)
|
||||
(result.error as? Throwable)?.let { Timber.e(it) }
|
||||
return null
|
||||
}
|
||||
null -> return null
|
||||
|
|
@ -143,13 +145,11 @@ class WalletConnectSdkHelper {
|
|||
HEX_PREFIX + data.walletManager.wallet.recentTransactions.last().hash
|
||||
}
|
||||
is SimpleResult.Failure -> {
|
||||
(result.error as? TangemSdkError)?.let { error ->
|
||||
store.state.globalState.analyticsHandlers?.logCardSdkError(
|
||||
error,
|
||||
Analytics.ActionToLog.WalletConnectTransaction,
|
||||
)
|
||||
}
|
||||
Timber.e(result.error)
|
||||
store.state.globalState.analyticsHandlers?.logSendTransactionError(
|
||||
result.error,
|
||||
Analytics.ActionToLog.WalletConnectTransaction,
|
||||
)
|
||||
Timber.e(result.error as BlockchainSdkError)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
package com.tangem.tap.features.demo
|
||||
|
||||
import com.tangem.blockchain.blockchains.bitcoin.BitcoinWalletManager
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.TransactionSender
|
||||
import com.tangem.blockchain.common.TransactionSigner
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.toBlockchainCustomError
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.common.CompletionResult
|
||||
|
|
@ -476,7 +482,7 @@ class DemoTransactionSender(
|
|||
publicKey = walletManager.wallet.publicKey
|
||||
)
|
||||
return when (signerResponse) {
|
||||
is CompletionResult.Success -> SimpleResult.Failure(Exception(ID))
|
||||
is CompletionResult.Success -> SimpleResult.Failure(Exception(ID).toBlockchainCustomError())
|
||||
is CompletionResult.Failure -> SimpleResult.fromTangemSdkError(signerResponse.error)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.features.details.redux
|
||||
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.domain.common.TapWorkarounds.isSaltPay
|
||||
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
||||
import com.tangem.domain.common.TapWorkarounds.isTangemNote
|
||||
import com.tangem.domain.common.isTangemTwin
|
||||
|
|
@ -19,7 +20,6 @@ class DetailsReducer {
|
|||
|
||||
private fun internalReduce(action: Action, state: AppState): DetailsState {
|
||||
if (action !is DetailsAction) return state.detailsState
|
||||
|
||||
val detailsState = state.detailsState
|
||||
return when (action) {
|
||||
is DetailsAction.PrepareScreen -> {
|
||||
|
|
@ -40,7 +40,6 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
|
|||
}
|
||||
is DetailsAction.ChangeAppCurrency ->
|
||||
detailsState.copy(appCurrency = action.fiatCurrency)
|
||||
|
||||
else -> detailsState
|
||||
}
|
||||
}
|
||||
|
|
@ -48,7 +47,6 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
|
|||
private fun handlePrepareScreen(
|
||||
action: DetailsAction.PrepareScreen,
|
||||
): DetailsState {
|
||||
|
||||
return DetailsState(
|
||||
scanResponse = action.scanResponse,
|
||||
wallets = action.wallets,
|
||||
|
|
@ -99,7 +97,8 @@ private fun prepareSecurityOptions(card: Card): ManageSecurityState {
|
|||
private fun isResetToFactoryAllowedByCard(card: Card): Boolean {
|
||||
val notAllowedByAnyWallet = card.wallets.any { it.settings.isPermanent }
|
||||
val notAllowedByCard = notAllowedByAnyWallet ||
|
||||
(card.isWalletDataSupported && (!card.isTangemNote() && !card.settings.isBackupAllowed))
|
||||
(card.isWalletDataSupported && (!card.isTangemNote() && !card.settings.isBackupAllowed)) ||
|
||||
card.isSaltPay
|
||||
return !notAllowedByCard
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +139,6 @@ private fun handleSecurityAction(
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
else -> state
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ fun AppSettingsScreen(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun AppSettings(
|
||||
private fun AppSettings(
|
||||
state: AppSettingsScreenState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
|
@ -69,13 +69,15 @@ fun AppSettings(
|
|||
.fillMaxSize(),
|
||||
) {
|
||||
AppSettingsElement(
|
||||
state = state, setting = PrivacySetting.SaveWallets,
|
||||
state = state,
|
||||
setting = PrivacySetting.SaveWallets,
|
||||
onDialogStateChange = onDialogStateChange,
|
||||
modifier = modifier,
|
||||
)
|
||||
Spacer(modifier = Modifier.size(32.dp))
|
||||
AppSettingsElement(
|
||||
state = state, setting = PrivacySetting.SaveAccessCode,
|
||||
state = state,
|
||||
setting = PrivacySetting.SaveAccessCode,
|
||||
onDialogStateChange = onDialogStateChange,
|
||||
modifier = modifier,
|
||||
)
|
||||
|
|
@ -83,7 +85,7 @@ fun AppSettings(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun AppSettingsElement(
|
||||
private fun AppSettingsElement(
|
||||
state: AppSettingsScreenState,
|
||||
setting: PrivacySetting,
|
||||
onDialogStateChange: (PrivacySetting?) -> Unit,
|
||||
|
|
@ -103,7 +105,6 @@ fun AppSettingsElement(
|
|||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 20.dp),
|
||||
// .clickable { state.onSettingToggled(element, !checked) },
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(
|
||||
|
|
@ -140,7 +141,7 @@ fun AppSettingsElement(
|
|||
}
|
||||
}
|
||||
|
||||
fun onCheckedChange(
|
||||
private fun onCheckedChange(
|
||||
element: PrivacySetting, enabled: Boolean,
|
||||
onSettingToggled: (PrivacySetting, Boolean) -> Unit,
|
||||
onDialogStateChange: (PrivacySetting?) -> Unit,
|
||||
|
|
@ -154,7 +155,7 @@ fun onCheckedChange(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsAlertDialog(
|
||||
private fun SettingsAlertDialog(
|
||||
element: PrivacySetting,
|
||||
onDialogStateChange: (PrivacySetting?) -> Unit,
|
||||
onSettingToggled: (PrivacySetting, Boolean) -> Unit,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import androidx.compose.animation.core.LinearOutSlowInEasing
|
|||
import androidx.compose.animation.core.animateDp
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.core.updateTransition
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.indication
|
||||
|
|
@ -19,7 +18,6 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
|
|
@ -44,35 +42,26 @@ fun TangemSwitch(
|
|||
val transition = updateTransition(checked, label = "SwitchState")
|
||||
val color by transition.animateColor(
|
||||
transitionSpec = {
|
||||
tween(200, easing = FastOutLinearInEasing)
|
||||
tween(durationMillis = 200, easing = FastOutLinearInEasing)
|
||||
},
|
||||
label = "",
|
||||
) {
|
||||
when (it) {
|
||||
true -> enabledColor
|
||||
false -> disabledColor
|
||||
}
|
||||
) { enabled ->
|
||||
if (enabled) enabledColor else disabledColor
|
||||
}
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val clickable = Modifier.clickable(
|
||||
interactionSource = interactionSource,
|
||||
indication = null,
|
||||
) {
|
||||
if (!checked) {
|
||||
onCheckedChange(true)
|
||||
} else {
|
||||
onCheckedChange(false)
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.then(clickable)
|
||||
modifier = modifier
|
||||
.clickable(
|
||||
interactionSource = interactionSource,
|
||||
indication = null,
|
||||
) {
|
||||
onCheckedChange(!checked)
|
||||
}
|
||||
.indication(
|
||||
interactionSource = MutableInteractionSource(),
|
||||
interactionSource = interactionSource,
|
||||
indication = rememberRipple(
|
||||
bounded = true,
|
||||
radius = 100.dp,
|
||||
bounded = false,
|
||||
color = Color.Transparent,
|
||||
),
|
||||
),
|
||||
|
|
@ -81,36 +70,27 @@ fun TangemSwitch(
|
|||
modifier = modifier
|
||||
.width(size)
|
||||
.height(size / 2)
|
||||
.indication(MutableInteractionSource(), null)
|
||||
.indication(interactionSource, null)
|
||||
.background(color = color, shape = RoundedCornerShape(100)),
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
) {
|
||||
val roundCardSize = this.maxWidth / 2
|
||||
val xOffset by transition.animateDp(
|
||||
transitionSpec = {
|
||||
tween(150, easing = LinearOutSlowInEasing)
|
||||
tween(durationMillis = 150, easing = LinearOutSlowInEasing)
|
||||
},
|
||||
label = "xOffset",
|
||||
) { state ->
|
||||
when (state) {
|
||||
false -> 0.dp
|
||||
true -> this.maxWidth - roundCardSize
|
||||
}
|
||||
) { enabled ->
|
||||
if (enabled) this.maxWidth - roundCardSize else 0.dp
|
||||
}
|
||||
|
||||
Card(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(this.maxWidth / 2)
|
||||
.offset(x = xOffset, y = 0.dp)
|
||||
.padding(3.dp),
|
||||
shape = RoundedCornerShape(100),
|
||||
backgroundColor = Color.White,
|
||||
border = BorderStroke(
|
||||
if (!checked) 0.5.dp else 0.dp,
|
||||
color = Color.LightGray,
|
||||
),
|
||||
) {
|
||||
}
|
||||
.padding(3.dp)
|
||||
.background(color = Color.White, shape = RoundedCornerShape(100)),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import com.tangem.Message
|
|||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.tap.common.redux.ErrorAction
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
import com.tangem.tap.common.redux.ToastNotificationAction
|
||||
|
|
@ -155,7 +156,10 @@ sealed class SendAction : SendScreenAction {
|
|||
val reduceAmount: BigDecimal,
|
||||
) : Dialog()
|
||||
|
||||
data class SendTransactionFails(val errorMessage: String) : Dialog()
|
||||
sealed class SendTransactionFails : Dialog() {
|
||||
data class CardSdkError(val error: TangemSdkError): Dialog()
|
||||
data class BlockchainSdkError(val error: com.tangem.blockchain.common.BlockchainSdkError): Dialog()
|
||||
}
|
||||
object Hide : Dialog()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import com.tangem.tap.common.analytics.AnalyticsParam
|
|||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.logSendTransactionError
|
||||
import com.tangem.tap.common.extensions.safeUpdate
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
|
|
@ -52,14 +53,13 @@ import com.tangem.tap.scope
|
|||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdk
|
||||
import com.tangem.wallet.R
|
||||
import java.util.EnumSet
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -79,13 +79,19 @@ class SendMiddleware {
|
|||
is SendActionUi.CheckIfTransactionDataWasProvided -> {
|
||||
val transactionData = appState()?.sendState?.externalTransactionData
|
||||
if (transactionData != null) {
|
||||
store.dispatchOnMain(AddressPayIdVerifyAction.AddressVerification.SetWalletAddress(
|
||||
transactionData.destinationAddress, false
|
||||
))
|
||||
store.dispatchOnMain(
|
||||
AddressPayIdVerifyAction.AddressVerification.SetWalletAddress(
|
||||
transactionData.destinationAddress, false,
|
||||
),
|
||||
)
|
||||
store.dispatchOnMain(AmountActionUi.SetMainCurrency(MainCurrencyType.CRYPTO))
|
||||
store.dispatchOnMain(AmountActionUi.HandleUserInput(transactionData.amount))
|
||||
store.dispatchOnMain(AmountAction.SetAmount(transactionData.amount.toBigDecimal(),
|
||||
false))
|
||||
store.dispatchOnMain(
|
||||
AmountAction.SetAmount(
|
||||
transactionData.amount.toBigDecimal(),
|
||||
false,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -93,7 +99,6 @@ class SendMiddleware {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun verifyAndSendTransaction(
|
||||
|
|
@ -113,23 +118,31 @@ private fun verifyAndSendTransaction(
|
|||
when {
|
||||
hadTezosError -> {
|
||||
val reduceAmount = walletManager.wallet.blockchain.minimalAmount()
|
||||
dispatch(SendAction.Dialog.TezosWarningDialog(reduceCallback = {
|
||||
dispatch(AmountAction.SetAmount(typedAmount.value!!.minus(reduceAmount), false))
|
||||
dispatch(AmountActionUi.CheckAmountToSend)
|
||||
}, sendAllCallback = {
|
||||
sendTransaction(
|
||||
action, walletManager, amountToSend, feeAmount, destinationAddress,
|
||||
sendState.transactionExtrasState, card, sendState.externalTransactionData,
|
||||
dispatch
|
||||
)
|
||||
}, reduceAmount))
|
||||
dispatch(
|
||||
SendAction.Dialog.TezosWarningDialog(
|
||||
reduceCallback = {
|
||||
dispatch(AmountAction.SetAmount(typedAmount.value!!.minus(reduceAmount), false))
|
||||
dispatch(AmountActionUi.CheckAmountToSend)
|
||||
},
|
||||
sendAllCallback = {
|
||||
sendTransaction(
|
||||
action, walletManager, amountToSend, feeAmount, destinationAddress,
|
||||
sendState.transactionExtrasState, card, sendState.externalTransactionData,
|
||||
dispatch,
|
||||
)
|
||||
},
|
||||
reduceAmount,
|
||||
),
|
||||
)
|
||||
}
|
||||
transactionErrors.isNotEmpty() -> {
|
||||
dispatch(SendAction.SendError(createValidateTransactionError(transactionErrors, walletManager)))
|
||||
}
|
||||
else -> {
|
||||
sendTransaction(action, walletManager, amountToSend, feeAmount, destinationAddress,
|
||||
sendState.transactionExtrasState, card, sendState.externalTransactionData, dispatch)
|
||||
sendTransaction(
|
||||
action, walletManager, amountToSend, feeAmount, destinationAddress,
|
||||
sendState.transactionExtrasState, card, sendState.externalTransactionData, dispatch,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -150,7 +163,9 @@ private fun sendTransaction(
|
|||
|
||||
transactionExtras.xlmMemo?.memo?.let { txData = txData.copy(extras = StellarTransactionExtras(it)) }
|
||||
transactionExtras.binanceMemo?.memo?.let { txData = txData.copy(extras = BinanceTransactionExtras(it.toString())) }
|
||||
transactionExtras.xrpDestinationTag?.tag?.let { txData = txData.copy(extras = XrpTransactionBuilder.XrpTransactionExtras(it)) }
|
||||
transactionExtras.xrpDestinationTag?.tag?.let {
|
||||
txData = txData.copy(extras = XrpTransactionBuilder.XrpTransactionExtras(it))
|
||||
}
|
||||
|
||||
scope.launch {
|
||||
val updateWalletResult = walletManager.safeUpdate()
|
||||
|
|
@ -178,14 +193,14 @@ private fun sendTransaction(
|
|||
val signer = TangemSigner(
|
||||
card = card,
|
||||
tangemSdk = tangemSdk,
|
||||
initialMessage = action.messageForSigner
|
||||
initialMessage = action.messageForSigner,
|
||||
) { signResponse ->
|
||||
store.dispatch(
|
||||
GlobalAction.UpdateWalletSignedHashes(
|
||||
walletSignedHashes = signResponse.totalSignedHashes,
|
||||
walletPublicKey = walletManager.wallet.publicKey.seedKey,
|
||||
remainingSignatures = signResponse.remainingSignatures
|
||||
)
|
||||
remainingSignatures = signResponse.remainingSignatures,
|
||||
),
|
||||
)
|
||||
}
|
||||
val sendResult = try {
|
||||
|
|
@ -211,7 +226,7 @@ private fun sendTransaction(
|
|||
store.state.globalState.analyticsHandlers?.triggerEvent(
|
||||
event = AnalyticsEvent.TRANSACTION_IS_SENT,
|
||||
card = card,
|
||||
blockchain = walletManager.wallet.blockchain.currency
|
||||
blockchain = walletManager.wallet.blockchain.currency,
|
||||
)
|
||||
dispatch(SendAction.SendSuccess)
|
||||
|
||||
|
|
@ -231,69 +246,48 @@ private fun sendTransaction(
|
|||
}
|
||||
}
|
||||
is SimpleResult.Failure -> {
|
||||
when (sendResult.error) {
|
||||
store.state.globalState.feedbackManager?.infoHolder?.updateOnSendError(
|
||||
wallet = walletManager.wallet,
|
||||
host = walletManager.currentHost,
|
||||
amountToSend = amountToSend,
|
||||
feeAmount = feeAmount,
|
||||
destinationAddress = destinationAddress,
|
||||
)
|
||||
store.state.globalState.analyticsHandlers?.logSendTransactionError(
|
||||
error = sendResult.error,
|
||||
action = Analytics.ActionToLog.SendTransaction,
|
||||
parameters = mapOf(AnalyticsParam.BLOCKCHAIN to walletManager.wallet.blockchain.currency),
|
||||
card = card,
|
||||
)
|
||||
|
||||
val error = (sendResult.error as? BlockchainSdkError) ?: return@withContext
|
||||
|
||||
when (error) {
|
||||
is BlockchainSdkError.WrappedTangemError -> {
|
||||
val tangemSdkError = (error.tangemError as? TangemSdkError) ?: return@withContext
|
||||
if (tangemSdkError is TangemSdkError.UserCancelled) return@withContext
|
||||
|
||||
dispatch(SendAction.Dialog.SendTransactionFails.CardSdkError(tangemSdkError))
|
||||
}
|
||||
is BlockchainSdkError.CreateAccountUnderfunded -> {
|
||||
val error = sendResult.error as BlockchainSdkError.CreateAccountUnderfunded
|
||||
// from XLM, XRP
|
||||
val reserve = error.minReserve.value?.stripZeroPlainString() ?: "0"
|
||||
val symbol = error.minReserve.currencySymbol
|
||||
dispatch(SendAction.SendError(TapError.CreateAccountUnderfunded(listOf(reserve, symbol))))
|
||||
}
|
||||
is BlockchainSdkError.SendException -> {
|
||||
sendResult.error?.let { FirebaseCrashlytics.getInstance().recordException(it) }
|
||||
}
|
||||
is Throwable -> {
|
||||
val throwable = sendResult.error as Throwable
|
||||
val message = throwable.message
|
||||
val infoHolder = store.state.globalState.feedbackManager?.infoHolder
|
||||
else -> {
|
||||
when {
|
||||
message == null -> {
|
||||
dispatch(SendAction.SendError(TapError.UnknownError))
|
||||
infoHolder?.updateOnSendError(
|
||||
wallet = walletManager.wallet,
|
||||
host = walletManager.currentHost,
|
||||
amountToSend = amountToSend,
|
||||
feeAmount = feeAmount,
|
||||
destinationAddress = destinationAddress
|
||||
error.customMessage.contains(DemoTransactionSender.ID) -> {
|
||||
store.dispatchDialogShow(
|
||||
AppDialog.SimpleOkDialogRes(
|
||||
headerId = R.string.common_done,
|
||||
messageId = R.string.alert_demo_feature_disabled,
|
||||
onOk = { dispatch(NavigationAction.PopBackTo()) },
|
||||
),
|
||||
)
|
||||
dispatch(SendAction.Dialog.SendTransactionFails("unknown error"))
|
||||
}
|
||||
message.contains("50002") -> {
|
||||
// user was cancelled the operation by closing the Sdk bottom sheet
|
||||
}
|
||||
// make it easier latter by handling an appropriate enumError or, like on iOS,
|
||||
// accept a string identifier of the error message
|
||||
message.contains("Target account is not created. To create account send 1+ XLM.") -> {
|
||||
dispatch(SendAction.SendError(TapError.XmlError.AssetAccountNotCreated))
|
||||
}
|
||||
message.contains(DemoTransactionSender.ID) -> {
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
store.dispatchDialogShow(AppDialog.SimpleOkDialogRes(
|
||||
R.string.common_done,
|
||||
R.string.alert_demo_feature_disabled
|
||||
) { dispatch(NavigationAction.PopBackTo()) })
|
||||
}
|
||||
else -> {
|
||||
(sendResult.error as? TangemSdkError)?.let { error ->
|
||||
store.state.globalState.analyticsHandlers?.logCardSdkError(
|
||||
error,
|
||||
Analytics.ActionToLog.SendTransaction,
|
||||
mapOf(
|
||||
AnalyticsParam.BLOCKCHAIN
|
||||
to walletManager.wallet.blockchain.currency),
|
||||
card = card,
|
||||
)
|
||||
}
|
||||
Timber.e(throwable)
|
||||
FirebaseCrashlytics.getInstance().recordException(throwable)
|
||||
dispatch(SendAction.SendError(TapError.CustomError(message)))
|
||||
infoHolder?.updateOnSendError(
|
||||
wallet = walletManager.wallet,
|
||||
host = walletManager.currentHost,
|
||||
amountToSend = amountToSend,
|
||||
feeAmount = feeAmount,
|
||||
destinationAddress = destinationAddress
|
||||
)
|
||||
dispatch(SendAction.Dialog.SendTransactionFails(message))
|
||||
dispatch(SendAction.Dialog.SendTransactionFails.BlockchainSdkError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -328,7 +322,10 @@ fun extractErrorsForAmountField(errors: EnumSet<TransactionError>): EnumSet<Tran
|
|||
return showIntoAmountField
|
||||
}
|
||||
|
||||
fun createValidateTransactionError(errorList: EnumSet<TransactionError>, walletManager: WalletManager): TapError.ValidateTransactionErrors {
|
||||
fun createValidateTransactionError(
|
||||
errorList: EnumSet<TransactionError>,
|
||||
walletManager: WalletManager,
|
||||
): TapError.ValidateTransactionErrors {
|
||||
val tapErrors = errorList.map {
|
||||
when (it) {
|
||||
TransactionError.AmountExceedsBalance -> TapError.AmountExceedsBalance
|
||||
|
|
|
|||
|
|
@ -106,8 +106,12 @@ class FeeReducer : SendInternalReducer {
|
|||
|
||||
private fun getFeePrecision(sendState: SendState): FeePrecision {
|
||||
val blockchain = sendState.walletManager?.wallet?.blockchain
|
||||
return if ((blockchain?.fullNameWithoutTestnet == Blockchain.Arbitrum.fullName || blockchain?.fullNameWithoutTestnet == Blockchain.Tron.fullName) &&
|
||||
sendState.amountState.typeOfAmount is AmountType.Token) {
|
||||
return if (
|
||||
(blockchain?.fullNameWithoutTestnet == Blockchain.Arbitrum.fullName ||
|
||||
blockchain?.fullNameWithoutTestnet == Blockchain.Tron.fullName ||
|
||||
blockchain?.fullNameWithoutTestnet == Blockchain.Gnosis.fullName) &&
|
||||
sendState.amountState.typeOfAmount is AmountType.Token
|
||||
) {
|
||||
FeePrecision.CAN_BE_LOWER
|
||||
} else {
|
||||
FeePrecision.PRECISE
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.features.send.ui.dialogs
|
|||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.tangem_sdk_new.extensions.localizedDescription
|
||||
import com.tangem.tap.common.feedback.SendTransactionFailedEmail
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.features.send.redux.SendAction
|
||||
|
|
@ -14,14 +15,22 @@ import com.tangem.wallet.R
|
|||
class SendTransactionFailsDialog {
|
||||
|
||||
companion object {
|
||||
fun create(context: Context, dialog: SendAction.Dialog.SendTransactionFails): AlertDialog {
|
||||
fun create(context: Context, dialog: SendAction.Dialog.SendTransactionFails.CardSdkError): AlertDialog {
|
||||
return create(context, dialog.error.localizedDescription(context))
|
||||
}
|
||||
|
||||
fun create(context: Context, dialog: SendAction.Dialog.SendTransactionFails.BlockchainSdkError): AlertDialog {
|
||||
return create(context, dialog.error.customMessage)
|
||||
}
|
||||
|
||||
private fun create(context: Context, errorMessage: String): AlertDialog {
|
||||
return AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.alert_failed_to_send_transaction_title)
|
||||
setMessage(context.getString(R.string.alert_failed_to_send_transaction_message, dialog.errorMessage))
|
||||
setMessage(context.getString(R.string.alert_failed_to_send_transaction_message, errorMessage))
|
||||
setNeutralButton(R.string.alert_button_send_feedback) { _, _ ->
|
||||
store.dispatch(GlobalAction.SendEmail(SendTransactionFailedEmail(dialog.errorMessage)))
|
||||
store.dispatch(GlobalAction.SendEmail(SendTransactionFailedEmail(errorMessage)))
|
||||
}
|
||||
setPositiveButton(R.string.common_no) { _, _ -> }
|
||||
setPositiveButton(R.string.common_cancel) { _, _ -> }
|
||||
setOnDismissListener { store.dispatch(SendAction.Dialog.Hide) }
|
||||
}.create()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,12 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.core.text.bold
|
||||
import com.tangem.common.extensions.remove
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
||||
import com.tangem.tap.common.extensions.enableError
|
||||
import com.tangem.tap.common.extensions.getColor
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.extensions.update
|
||||
import com.tangem.tap.common.redux.getMessageString
|
||||
import com.tangem.tap.common.text.DecimalDigitsInputFilter
|
||||
import com.tangem.tap.domain.MultiMessageError
|
||||
|
|
@ -17,7 +22,17 @@ import com.tangem.tap.features.BaseStoreFragment
|
|||
import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction.Error
|
||||
import com.tangem.tap.features.send.redux.FeeAction
|
||||
import com.tangem.tap.features.send.redux.SendAction
|
||||
import com.tangem.tap.features.send.redux.states.*
|
||||
import com.tangem.tap.features.send.redux.states.AddressPayIdState
|
||||
import com.tangem.tap.features.send.redux.states.AmountState
|
||||
import com.tangem.tap.features.send.redux.states.FeeState
|
||||
import com.tangem.tap.features.send.redux.states.MainCurrencyType
|
||||
import com.tangem.tap.features.send.redux.states.ReceiptLayoutType
|
||||
import com.tangem.tap.features.send.redux.states.ReceiptState
|
||||
import com.tangem.tap.features.send.redux.states.SendState
|
||||
import com.tangem.tap.features.send.redux.states.StateId
|
||||
import com.tangem.tap.features.send.redux.states.TransactionExtraError
|
||||
import com.tangem.tap.features.send.redux.states.TransactionExtrasState
|
||||
import com.tangem.tap.features.send.redux.states.XlmMemoType
|
||||
import com.tangem.tap.features.send.ui.FeeUiHelper
|
||||
import com.tangem.tap.features.send.ui.SendFragment
|
||||
import com.tangem.tap.features.send.ui.dialogs.SendTransactionFailsDialog
|
||||
|
|
@ -117,7 +132,13 @@ class SendStateSubscriber(fragment: BaseStoreFragment) :
|
|||
dialog?.show()
|
||||
}
|
||||
}
|
||||
is SendAction.Dialog.SendTransactionFails -> {
|
||||
is SendAction.Dialog.SendTransactionFails.CardSdkError -> {
|
||||
if (dialog == null) {
|
||||
dialog = SendTransactionFailsDialog.create(fg.requireContext(), state.dialog)
|
||||
dialog?.show()
|
||||
}
|
||||
}
|
||||
is SendAction.Dialog.SendTransactionFails.BlockchainSdkError -> {
|
||||
if (dialog == null) {
|
||||
dialog = SendTransactionFailsDialog.create(fg.requireContext(), state.dialog)
|
||||
dialog?.show()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
package com.tangem.tap.features.wallet.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.annotation.ColorRes
|
||||
|
|
@ -11,21 +15,32 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.transition.TransitionInflater
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.tangem_sdk_new.extensions.dpToPx
|
||||
import com.tangem.tap.common.SnackbarHandler
|
||||
import com.tangem.tap.common.TestActions
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.extensions.appendIfNotNull
|
||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
||||
import com.tangem.tap.common.extensions.fitChipsByGroupWidth
|
||||
import com.tangem.tap.common.extensions.getColor
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.extensions.toQrCode
|
||||
import com.tangem.tap.common.recyclerView.SpaceItemDecoration
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
|
||||
import com.tangem.tap.features.onboarding.getQRReceiveMessage
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.features.wallet.models.PendingTransaction
|
||||
import com.tangem.tap.features.wallet.redux.*
|
||||
import com.tangem.tap.features.wallet.redux.ErrorType
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletData
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT_SIGN
|
||||
import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter
|
||||
import com.tangem.tap.features.wallet.ui.adapters.WalletDetailWarningMessagesAdapter
|
||||
import com.tangem.tap.features.wallet.ui.images.loadCurrencyIcon
|
||||
import com.tangem.tap.features.wallet.ui.test.TestWalletDetails
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -199,11 +214,12 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details),
|
|||
}
|
||||
|
||||
private fun handleCurrencyIcon(wallet: WalletData) = with(binding.lWalletDetails.lBalance) {
|
||||
loadCurrencyIcon(
|
||||
currencyImageView = ivCurrency,
|
||||
currencyTextView = tvTokenLetter,
|
||||
blockchain = wallet.currency.blockchain,
|
||||
token = (wallet.currency as? Currency.Token)?.token
|
||||
ivCurrency.load(
|
||||
currency = wallet.currency,
|
||||
derivationStyle = store.state.globalState
|
||||
.scanResponse
|
||||
?.card
|
||||
?.derivationStyle,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import androidx.transition.TransitionInflater
|
|||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import coil.load
|
||||
import coil.size.Scale
|
||||
import com.tangem.domain.common.TapWorkarounds.isSaltPay
|
||||
import com.tangem.tap.MainActivity
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.recyclerView.SpaceItemDecoration
|
||||
|
|
@ -32,6 +33,7 @@ import com.tangem.tap.features.wallet.redux.WalletAction
|
|||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.features.wallet.ui.adapters.WarningMessagesAdapter
|
||||
import com.tangem.tap.features.wallet.ui.wallet.MultiWalletView
|
||||
import com.tangem.tap.features.wallet.ui.wallet.SaltPaySingleWalletView
|
||||
import com.tangem.tap.features.wallet.ui.wallet.SingleWalletView
|
||||
import com.tangem.tap.features.wallet.ui.wallet.WalletView
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -112,17 +114,22 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
|
||||
override fun newState(state: WalletState) {
|
||||
if (activity == null || view == null) return
|
||||
|
||||
if (state.isMultiwalletAllowed &&
|
||||
state.primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard &&
|
||||
walletView is SingleWalletView
|
||||
) {
|
||||
walletView = MultiWalletView()
|
||||
walletView.changeWalletView(this, binding)
|
||||
} else if (!state.isMultiwalletAllowed && walletView is MultiWalletView) {
|
||||
walletView = SingleWalletView()
|
||||
walletView.changeWalletView(this, binding)
|
||||
val isSaltPay = store.state.globalState.scanResponse?.card?.isSaltPay == true
|
||||
when {
|
||||
isSaltPay -> {
|
||||
walletView = SaltPaySingleWalletView()
|
||||
}
|
||||
state.isMultiwalletAllowed &&
|
||||
state.primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard &&
|
||||
walletView is SingleWalletView -> {
|
||||
walletView = MultiWalletView()
|
||||
}
|
||||
!state.isMultiwalletAllowed && walletView is MultiWalletView -> {
|
||||
walletView = SingleWalletView()
|
||||
}
|
||||
}
|
||||
|
||||
walletView.changeWalletView(this, binding)
|
||||
walletView.onNewState(state)
|
||||
|
||||
if (!state.shouldShowDetails) {
|
||||
|
|
@ -134,7 +141,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
setupNoInternetHandling(state)
|
||||
setupCardImage(state.cardImage)
|
||||
|
||||
showWarningsIfPresent(state.mainWarningsList)
|
||||
if (!isSaltPay) showWarningsIfPresent(state.mainWarningsList)
|
||||
|
||||
binding.srlWallet.isRefreshing = state.state == ProgressState.Refreshing
|
||||
binding.srlWallet.setOnRefreshListener {
|
||||
|
|
|
|||
|
|
@ -9,15 +9,12 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.tap.common.extensions.getRoundIconRes
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletData
|
||||
import com.tangem.tap.features.wallet.ui.BalanceStatus
|
||||
import com.tangem.tap.features.wallet.ui.images.loadCurrencyIcon
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import com.tangem.wallet.databinding.ItemCurrencyWalletBinding
|
||||
|
|
@ -67,12 +64,6 @@ class WalletAdapter
|
|||
// Skip changes when on refreshing status
|
||||
if (status == BalanceStatus.Refreshing) return@with
|
||||
|
||||
val isCustomCurrency = wallet.currency.isCustomCurrency(
|
||||
derivationStyle = store.state.globalState
|
||||
.scanResponse
|
||||
?.card
|
||||
?.derivationStyle
|
||||
)
|
||||
val statusMessage = when (status) {
|
||||
BalanceStatus.TransactionInProgress -> {
|
||||
root.getString(R.string.wallet_balance_tx_in_progress)
|
||||
|
|
@ -87,7 +78,8 @@ class WalletAdapter
|
|||
BalanceStatus.UnknownBlockchain,
|
||||
BalanceStatus.Loading,
|
||||
BalanceStatus.Refreshing,
|
||||
null -> null
|
||||
null,
|
||||
-> null
|
||||
}
|
||||
|
||||
if (status == null || status == BalanceStatus.Loading) {
|
||||
|
|
@ -98,11 +90,12 @@ class WalletAdapter
|
|||
lContent.root.show()
|
||||
}
|
||||
|
||||
loadCurrencyIcon(
|
||||
currencyImageView = ivCurrency,
|
||||
currencyTextView = tvTokenLetter,
|
||||
token = (wallet.currency as? Currency.Token)?.token,
|
||||
blockchain = wallet.currency.blockchain,
|
||||
ivCurrency.load(
|
||||
currency = wallet.currency,
|
||||
derivationStyle = store.state.globalState
|
||||
.scanResponse
|
||||
?.card
|
||||
?.derivationStyle,
|
||||
)
|
||||
|
||||
lContent.tvCurrency.text = wallet.currencyData.currency
|
||||
|
|
@ -116,10 +109,6 @@ class WalletAdapter
|
|||
lContent.tvExchangeRate.text = wallet.fiatRateString
|
||||
?: root.getString(id = R.string.token_item_no_rate)
|
||||
|
||||
badgeCustomBalance.isVisible = isCustomCurrency
|
||||
ivBlockchain.isVisible = wallet.currency.isToken()
|
||||
ivBlockchain.setImageResource(wallet.currency.blockchain.getRoundIconRes())
|
||||
|
||||
cardWallet.setOnClickListener {
|
||||
store.dispatch(WalletAction.MultiWallet.SelectWallet(wallet))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,22 +19,7 @@ import com.tangem.wallet.R
|
|||
private const val QCX = "QCX"
|
||||
private const val VOYR = "VOYRME"
|
||||
|
||||
fun loadCurrencyIcon(
|
||||
currencyImageView: CurrencyIconView,
|
||||
currencyTextView: TextView,
|
||||
token: Token?,
|
||||
blockchain: Blockchain,
|
||||
) {
|
||||
CurrencyIconLoader(
|
||||
currencyImageView = currencyImageView.imageView,
|
||||
currencyTextView = currencyTextView,
|
||||
token = token,
|
||||
blockchain = blockchain
|
||||
)
|
||||
.load()
|
||||
}
|
||||
|
||||
private class CurrencyIconLoader(
|
||||
class CurrencyIconRequest(
|
||||
private val currencyImageView: ImageFilterView,
|
||||
private val currencyTextView: TextView,
|
||||
private val token: Token?,
|
||||
|
|
|
|||
|
|
@ -3,27 +3,69 @@ package com.tangem.tap.features.wallet.ui.images
|
|||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isVisible
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.tangem_sdk_new.extensions.dpToPx
|
||||
import com.tangem.tap.common.extensions.getRoundIconRes
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.wallet.databinding.ViewCurrencyIconBinding
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class CurrencyIconView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0,
|
||||
) : MaterialCardView(context, attrs, defStyleAttr) {
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
private val binding = ViewCurrencyIconBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
this
|
||||
this,
|
||||
)
|
||||
|
||||
val imageView: ImageFilterView
|
||||
get() = binding.iv
|
||||
private val currencyImageView: ImageFilterView
|
||||
get() = binding.ivCurrency
|
||||
|
||||
private val currencyTextView: TextView
|
||||
get() = binding.tvTokenLetter
|
||||
|
||||
private var isBlockchainIconVisible: Boolean
|
||||
get() = binding.ivBlockchain.isVisible
|
||||
set(value) = binding.ivBlockchain::isVisible.set(value)
|
||||
|
||||
private var isBadgeVisible: Boolean
|
||||
get() = binding.badge.isVisible
|
||||
set(value) = binding.badge::isVisible.set(value)
|
||||
|
||||
@DrawableRes
|
||||
private var blockchainIconRes: Int? = null
|
||||
set(value) {
|
||||
if (value != null && value != field && isBlockchainIconVisible) {
|
||||
binding.ivBlockchain.setImageResource(value)
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
elevation = 0f
|
||||
cardElevation = 0f
|
||||
radius = dpToPx(6f)
|
||||
minWidth = dpToPx(48f).roundToInt()
|
||||
minHeight = dpToPx(48f).roundToInt()
|
||||
}
|
||||
|
||||
fun load(
|
||||
currency: Currency,
|
||||
derivationStyle: DerivationStyle?,
|
||||
) {
|
||||
isBlockchainIconVisible = currency.isToken()
|
||||
isBadgeVisible = currency.isCustomCurrency(derivationStyle)
|
||||
blockchainIconRes = currency.blockchain.getRoundIconRes()
|
||||
|
||||
CurrencyIconRequest(
|
||||
currencyImageView = currencyImageView,
|
||||
currencyTextView = currencyTextView,
|
||||
token = (currency as? Currency.Token)?.token,
|
||||
blockchain = currency.blockchain,
|
||||
).load()
|
||||
}
|
||||
}
|
||||
|
|
@ -25,14 +25,8 @@ import com.tangem.wallet.R
|
|||
import com.tangem.wallet.databinding.FragmentWalletBinding
|
||||
|
||||
|
||||
class MultiWalletView : WalletView {
|
||||
|
||||
private var fragment: WalletFragment? = null
|
||||
private var binding: FragmentWalletBinding? = null
|
||||
|
||||
class MultiWalletView : WalletView() {
|
||||
private lateinit var walletsAdapter: WalletAdapter
|
||||
|
||||
|
||||
override fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
setFragment(fragment, binding)
|
||||
onViewCreated()
|
||||
|
|
@ -47,6 +41,7 @@ class MultiWalletView : WalletView {
|
|||
lAddress.root.hide()
|
||||
lButtonsShort.root.hide()
|
||||
lButtonsLong.root.hide()
|
||||
lSingleWalletBalance.root.hide()
|
||||
rvMultiwallet.show()
|
||||
btnAddToken.show()
|
||||
setupWalletCardNumber(binding)
|
||||
|
|
@ -64,15 +59,6 @@ class MultiWalletView : WalletView {
|
|||
}
|
||||
}
|
||||
|
||||
override fun setFragment(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
this.fragment = fragment
|
||||
this.binding = binding
|
||||
}
|
||||
|
||||
override fun removeFragment() {
|
||||
this.fragment = null
|
||||
this.binding = null
|
||||
}
|
||||
|
||||
override fun onViewCreated() {
|
||||
setupWalletsRecyclerView()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package com.tangem.tap.features.wallet.ui.wallet
|
||||
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.extensions.animateVisibility
|
||||
import com.tangem.tap.common.extensions.formatAmountAsSpannedString
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.databinding.LayoutSingleWalletBalanceBinding
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class SaltPayBalanceWidgetData(
|
||||
val state: ProgressState? = null,
|
||||
val currencySymbol: String? = null,
|
||||
val currency: String? = null,
|
||||
val fiatAmount: BigDecimal? = null,
|
||||
val fiatCurrency: FiatCurrency? = null,
|
||||
)
|
||||
|
||||
class SaltPayBalanceWidget(
|
||||
private val binding: LayoutSingleWalletBalanceBinding,
|
||||
private val data: SaltPayBalanceWidgetData,
|
||||
) {
|
||||
fun setup(): Unit = with(binding) {
|
||||
if (data.state == ProgressState.Loading) {
|
||||
veilBalance.veil()
|
||||
veilBalanceCrypto.veil()
|
||||
} else {
|
||||
veilBalance.unVeil()
|
||||
veilBalanceCrypto.unVeil()
|
||||
}
|
||||
tvProcessing.animateVisibility(
|
||||
show = data.state == ProgressState.Error,
|
||||
)
|
||||
veilBalanceCrypto.animateVisibility(
|
||||
show = data.state != ProgressState.Error,
|
||||
)
|
||||
tvBalance.text = data.fiatAmount?.formatAmountAsSpannedString(
|
||||
currencySymbol = data.fiatCurrency?.symbol ?: "",
|
||||
)
|
||||
tvBalanceCrypto.text = data.currency
|
||||
|
||||
tvCurrencyName.text = data.fiatCurrency?.code
|
||||
|
||||
tvCurrencyName.setOnClickListener {
|
||||
store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.tangem.tap.features.wallet.ui.wallet
|
||||
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.features.wallet.redux.WalletData
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.features.wallet.ui.WalletFragment
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.databinding.FragmentWalletBinding
|
||||
|
||||
class SaltPaySingleWalletView : WalletView() {
|
||||
override fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
setFragment(fragment, binding)
|
||||
onViewCreated()
|
||||
showSingleWalletView(binding)
|
||||
}
|
||||
|
||||
private fun showSingleWalletView(binding: FragmentWalletBinding) = with(binding) {
|
||||
rvMultiwallet.hide()
|
||||
btnAddToken.hide()
|
||||
rvPendingTransaction.hide()
|
||||
tvTwinCardNumber.hide()
|
||||
lCardBalance.root.hide()
|
||||
lAddress.root.hide()
|
||||
lSingleWalletBalance.root.show()
|
||||
}
|
||||
|
||||
override fun onViewCreated() {
|
||||
}
|
||||
|
||||
override fun onNewState(state: WalletState) {
|
||||
val binding = binding ?: return
|
||||
state.primaryWallet ?: return
|
||||
|
||||
setupBalance(state, state.primaryWallet, binding)
|
||||
}
|
||||
|
||||
private fun setupBalance(state: WalletState, primaryWallet: WalletData, binding: FragmentWalletBinding) {
|
||||
binding.lSingleWalletBalance.root.show()
|
||||
SaltPayBalanceWidget(
|
||||
binding = binding.lSingleWalletBalance,
|
||||
data = SaltPayBalanceWidgetData(
|
||||
state = state.state,
|
||||
currencySymbol = primaryWallet.currencyData.currencySymbol,
|
||||
currency = primaryWallet.currencyData.amountFormatted,
|
||||
fiatAmount = primaryWallet.currencyData.fiatAmount,
|
||||
fiatCurrency = store.state.globalState.appCurrency,
|
||||
),
|
||||
).setup()
|
||||
}
|
||||
}
|
||||
|
|
@ -21,22 +21,8 @@ import com.tangem.tap.store
|
|||
import com.tangem.wallet.R
|
||||
import com.tangem.wallet.databinding.FragmentWalletBinding
|
||||
|
||||
class SingleWalletView : WalletView {
|
||||
|
||||
class SingleWalletView : WalletView() {
|
||||
private lateinit var pendingTransactionAdapter: PendingTransactionsAdapter
|
||||
private var fragment: WalletFragment? = null
|
||||
private var binding: FragmentWalletBinding? = null
|
||||
|
||||
override fun setFragment(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
this.fragment = fragment
|
||||
this.binding = binding
|
||||
}
|
||||
|
||||
override fun removeFragment() {
|
||||
fragment = null
|
||||
binding = null
|
||||
}
|
||||
|
||||
override fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
setFragment(fragment, binding)
|
||||
onViewCreated()
|
||||
|
|
@ -49,13 +35,13 @@ class SingleWalletView : WalletView {
|
|||
rvPendingTransaction.hide()
|
||||
lCardBalance.root.show()
|
||||
lAddress.root.show()
|
||||
lSingleWalletBalance.root.hide()
|
||||
}
|
||||
|
||||
override fun onViewCreated() {
|
||||
setupTransactionsRecyclerView()
|
||||
}
|
||||
|
||||
|
||||
private fun setupTransactionsRecyclerView() {
|
||||
val fragment = fragment ?: return
|
||||
pendingTransactionAdapter = PendingTransactionsAdapter()
|
||||
|
|
@ -65,7 +51,6 @@ class SingleWalletView : WalletView {
|
|||
}
|
||||
|
||||
override fun onNewState(state: WalletState) {
|
||||
val fragment = fragment ?: return
|
||||
val binding = binding ?: return
|
||||
state.primaryWallet ?: return
|
||||
|
||||
|
|
@ -81,7 +66,6 @@ class SingleWalletView : WalletView {
|
|||
binding?.rvPendingTransaction?.show(pendingTransactions.isNotEmpty())
|
||||
}
|
||||
|
||||
|
||||
private fun setupBalance(state: WalletState, primaryWallet: WalletData) {
|
||||
val fragment = fragment ?: return
|
||||
binding?.apply {
|
||||
|
|
@ -90,13 +74,13 @@ class SingleWalletView : WalletView {
|
|||
binding = this.lCardBalance,
|
||||
fragment = fragment,
|
||||
data = primaryWallet.currencyData,
|
||||
isTwinCard = state.isTangemTwins
|
||||
isTwinCard = state.isTangemTwins,
|
||||
).setup()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupTwinCards(
|
||||
twinCardsState: TwinCardsState?, binding: FragmentWalletBinding
|
||||
twinCardsState: TwinCardsState?, binding: FragmentWalletBinding,
|
||||
) = with(binding) {
|
||||
twinCardsState?.cardNumber?.let { cardNumber ->
|
||||
tvTwinCardNumber.show()
|
||||
|
|
@ -113,11 +97,9 @@ class SingleWalletView : WalletView {
|
|||
}
|
||||
|
||||
private fun setupButtons(
|
||||
state: WalletData, isTwinsWallet: Boolean, binding: FragmentWalletBinding
|
||||
state: WalletData, isTwinsWallet: Boolean, binding: FragmentWalletBinding,
|
||||
) = with(binding) {
|
||||
|
||||
setupButtonsType(state, binding)
|
||||
|
||||
val tradeState = state.tradeCryptoState
|
||||
val btnConfirm = if (tradeState.isAvailableToSell() || tradeState.isAvailableToBuy()) {
|
||||
lButtonsShort.btnConfirm
|
||||
|
|
@ -137,8 +119,8 @@ class SingleWalletView : WalletView {
|
|||
store.dispatch(
|
||||
WalletAction.DialogAction.QrCode(
|
||||
currency = state.currency,
|
||||
selectedAddress = selectedAddress
|
||||
)
|
||||
selectedAddress = selectedAddress,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -207,7 +189,6 @@ class SingleWalletView : WalletView {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private fun setupAddressCard(state: WalletData, binding: FragmentWalletBinding) = with(binding.lAddress) {
|
||||
if (state.walletAddresses != null && state.currency is Currency.Blockchain) {
|
||||
binding.lAddress.root.show()
|
||||
|
|
@ -215,7 +196,6 @@ class SingleWalletView : WalletView {
|
|||
(binding.lAddress.root as? ViewGroup)?.beginDelayedTransition()
|
||||
chipGroupAddressType.show()
|
||||
chipGroupAddressType.fitChipsByGroupWidth()
|
||||
|
||||
val checkedId =
|
||||
MultipleAddressUiHelper.typeToId(state.walletAddresses.selectedAddress.type)
|
||||
if (checkedId != View.NO_ID) chipGroupAddressType.check(checkedId)
|
||||
|
|
@ -234,8 +214,8 @@ class SingleWalletView : WalletView {
|
|||
store.dispatch(
|
||||
WalletAction.ExploreAddress(
|
||||
state.walletAddresses.selectedAddress.exploreUrl,
|
||||
fragment!!.requireContext()
|
||||
)
|
||||
fragment!!.requireContext(),
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,16 +4,20 @@ import com.tangem.tap.features.wallet.redux.WalletState
|
|||
import com.tangem.tap.features.wallet.ui.WalletFragment
|
||||
import com.tangem.wallet.databinding.FragmentWalletBinding
|
||||
|
||||
interface WalletView {
|
||||
abstract class WalletView {
|
||||
protected var fragment: WalletFragment? = null
|
||||
protected var binding: FragmentWalletBinding? = null
|
||||
fun setFragment(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
this.fragment = fragment
|
||||
this.binding = binding
|
||||
}
|
||||
|
||||
fun setFragment(fragment: WalletFragment, binding: FragmentWalletBinding)
|
||||
|
||||
fun removeFragment()
|
||||
|
||||
fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding)
|
||||
|
||||
fun onViewCreated()
|
||||
|
||||
fun onNewState(state: WalletState)
|
||||
fun removeFragment() {
|
||||
fragment = null
|
||||
binding = null
|
||||
}
|
||||
|
||||
abstract fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding)
|
||||
abstract fun onViewCreated()
|
||||
abstract fun onNewState(state: WalletState)
|
||||
}
|
||||
|
|
@ -148,6 +148,16 @@
|
|||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/rv_pending_transaction" />
|
||||
|
||||
<include
|
||||
android:id="@+id/l_single_wallet_balance"
|
||||
layout="@layout/layout_single_wallet_balance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/rv_pending_transaction" />
|
||||
|
||||
<include
|
||||
android:id="@+id/l_address"
|
||||
layout="@layout/layout_address"
|
||||
|
|
|
|||
|
|
@ -27,52 +27,12 @@
|
|||
|
||||
<com.tangem.tap.features.wallet.ui.images.CurrencyIconView
|
||||
android:id="@+id/iv_currency"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_token_letter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_currency"
|
||||
app:layout_constraintEnd_toEndOf="@id/iv_currency"
|
||||
app:layout_constraintStart_toStartOf="@id/iv_currency"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_currency"
|
||||
tools:text="J" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_blockchain"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:padding="2dp"
|
||||
android:translationX="4dp"
|
||||
android:translationY="-4dp"
|
||||
android:background="@drawable/shape_circle"
|
||||
android:backgroundTint="@color/backgroundWhite"
|
||||
android:contentDescription="@null"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_currency"
|
||||
app:layout_constraintEnd_toEndOf="@id/iv_currency"
|
||||
tools:src="@drawable/ic_eth"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<View
|
||||
android:id="@+id/badge_custom_balance"
|
||||
android:layout_width="10dp"
|
||||
android:layout_height="10dp"
|
||||
android:background="@drawable/shape_badge_custom_currency"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_currency"
|
||||
app:layout_constraintEnd_toEndOf="@id/iv_currency"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<include
|
||||
layout="@layout/item_currency_wallet_content"
|
||||
android:id="@+id/l_content"
|
||||
|
|
|
|||
|
|
@ -41,26 +41,12 @@
|
|||
|
||||
<com.tangem.tap.features.wallet.ui.images.CurrencyIconView
|
||||
android:id="@+id/iv_currency"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_token_letter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_currency"
|
||||
app:layout_constraintEnd_toEndOf="@id/iv_currency"
|
||||
app:layout_constraintStart_toStartOf="@id/iv_currency"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_currency"
|
||||
tools:text="J" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_status"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
|||
116
app/src/main/res/layout/layout_single_wallet_balance.xml
Normal file
116
app/src/main/res/layout/layout_single_wallet_balance.xml
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView 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/card_balance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="18dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="18dp"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@string/main_page_balance"
|
||||
android:textColor="@color/iconGray"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toStartOf="@id/tv_currency_name"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.skydoves.androidveil.VeilLayout
|
||||
android:id="@+id/veil_balance"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/tv_processing"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_title"
|
||||
app:veilLayout_baseColor="@color/lightGray0"
|
||||
app:veilLayout_highlightColor="@color/lightGray1"
|
||||
app:veilLayout_layout="@layout/card_total_balance_shimmer"
|
||||
app:veilLayout_radius="4dp"
|
||||
app:veilLayout_shimmerEnable="true"
|
||||
app:veilLayout_veiled="true"
|
||||
tools:veilLayout_veiled="false">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_balance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:minWidth="152dp"
|
||||
android:textColor="@color/darkGray6"
|
||||
android:textSize="26sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="22 325.40 $" />
|
||||
|
||||
</com.skydoves.androidveil.VeilLayout>
|
||||
|
||||
<com.skydoves.androidveil.VeilLayout
|
||||
android:id="@+id/veil_balance_crypto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginTop="4dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/veil_balance"
|
||||
app:veilLayout_baseColor="@color/lightGray0"
|
||||
app:veilLayout_highlightColor="@color/lightGray1"
|
||||
app:veilLayout_layout="@layout/card_total_balance_shimmer"
|
||||
app:veilLayout_radius="4dp"
|
||||
app:veilLayout_shimmerEnable="true"
|
||||
app:veilLayout_veiled="true"
|
||||
tools:veilLayout_veiled="false"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_balance_crypto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:maxLines="1"
|
||||
android:minWidth="152dp"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="12sp"
|
||||
tools:text="5.13123123123 ETH"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</com.skydoves.androidveil.VeilLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_processing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:text="@string/wallet_balance_blockchain_unreachable"
|
||||
android:textColor="@color/warning"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/veil_balance"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<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_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="USD" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
|
@ -2,20 +2,65 @@
|
|||
<merge 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:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:background="@null"
|
||||
android:elevation="0dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="0dp"
|
||||
tools:parentTag="androidx.cardview.widget.CardView">
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
tools:layout_gravity="center"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/iv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="fitCenter"
|
||||
tools:src="@drawable/ic_eth" />
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/container_iv_currency"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="@null"
|
||||
android:elevation="0dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/iv_currency"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="fitCenter"
|
||||
tools:src="@drawable/ic_eth" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_token_letter"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="J" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_blockchain"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:background="@drawable/shape_circle"
|
||||
android:backgroundTint="@color/backgroundWhite"
|
||||
android:contentDescription="@null"
|
||||
android:padding="2dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/ic_eth"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<View
|
||||
android:id="@+id/badge"
|
||||
android:layout_width="10dp"
|
||||
android:layout_height="10dp"
|
||||
android:background="@drawable/shape_badge_custom_currency"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/container_iv_currency"
|
||||
app:layout_constraintEnd_toEndOf="@id/container_iv_currency"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</merge>
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@
|
|||
<string name="alert_failed_to_send_email_title">Не удалось отправить электронное письмо</string>
|
||||
<string name="alert_failed_to_send_email_message">Причина: %s</string>
|
||||
<string name="alert_failed_to_send_transaction_title">Не могу отправить транзакцию</string>
|
||||
<string name="alert_failed_to_send_transaction_message">Причина: %s. Хотите отправить отзыв?</string>
|
||||
<string name="alert_failed_to_send_transaction_message">Причина: %s</string>
|
||||
<string name="alert_troubleshooting_scan_card_title">У Вас возникли трудности со сканированием вашей карты?</string>
|
||||
<string name="alert_troubleshooting_scan_card_message">Пожалуйста, попробуйте приложить карту точно так, как показано на анимации, или обратитесь в поддержку</string>
|
||||
<string name="alert_troubleshooting_scan_card_ok">Отмена</string>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
<string name="alert_failed_to_send_email_title" translatable="false">Failed to send email</string>
|
||||
<string name="alert_failed_to_send_email_message" translatable="false">Reason: %s</string>
|
||||
<string name="alert_failed_to_send_transaction_title" translatable="false">Can\'t send a transaction</string>
|
||||
<string name="alert_failed_to_send_transaction_message" translatable="false">Reason: %s. Do you want to send feedback?</string>
|
||||
<string name="alert_failed_to_send_transaction_message" translatable="false">Reason: %s</string>
|
||||
<string name="alert_troubleshooting_scan_card_title" translatable="false">Are you having difficulty scanning your card?</string>
|
||||
<string name="alert_troubleshooting_scan_card_message" translatable="false">Please try to tap the card exactly as shown in the animation or request support.</string>
|
||||
<string name="alert_troubleshooting_scan_card_ok" translatable="false">I\'m okay</string>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
ext.versions = [
|
||||
kotlin : '1.6.10',
|
||||
build_gradle : '7.1.3',
|
||||
tamgem_card_sdk : 'develop-157',
|
||||
tamgem_blockchain_sdk: 'develop-99',
|
||||
tangem_card_sdk : 'develop-159',
|
||||
tangem_blockchain_sdk: 'develop-100',
|
||||
// tangem_blockchain_sdk: '0.0.1',
|
||||
]
|
||||
|
||||
ext.environmentConfig = [
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@ dependencies {
|
|||
implementation implementation(project(path: ':network'))
|
||||
implementation implementation(project(path: ':common'))
|
||||
|
||||
implementation "com.tangem:blockchain:${versions.tamgem_blockchain_sdk}"
|
||||
implementation "com.tangem.tangem-sdk-kotlin:core:${versions.tamgem_card_sdk}"
|
||||
implementation "com.tangem.tangem-sdk-kotlin:android:${versions.tamgem_card_sdk}"
|
||||
implementation "com.tangem:blockchain:${versions.tangem_blockchain_sdk}"
|
||||
implementation "com.tangem.tangem-sdk-kotlin:core:${versions.tangem_card_sdk}"
|
||||
implementation "com.tangem.tangem-sdk-kotlin:android:${versions.tangem_card_sdk}"
|
||||
|
||||
// Kotlin coroutines
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'
|
||||
|
|
|
|||
|
|
@ -9,20 +9,18 @@ import java.util.*
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
object TapWorkarounds {
|
||||
|
||||
fun isStart2CoinIssuer(cardIssuer: String?): Boolean {
|
||||
return cardIssuer?.lowercase(Locale.US) == START_2_COIN_ISSUER
|
||||
}
|
||||
|
||||
val Card.isStart2Coin: Boolean
|
||||
get() = isStart2CoinIssuer(issuer.name)
|
||||
|
||||
val Card.isSaltPay: Boolean
|
||||
get() = false //TODO fix when we know which cards are SaltPay cards
|
||||
val Card.isTestCard: Boolean
|
||||
get() = batchId == TEST_CARD_BATCH && cardId.startsWith(TEST_CARD_ID_STARTS_WITH)
|
||||
|
||||
val Card.useOldStyleDerivation: Boolean
|
||||
get() = batchId == "AC01" || batchId == "AC02" || batchId == "CB95"
|
||||
|
||||
val Card.derivationStyle: DerivationStyle?
|
||||
get() = if (!settings.isHDWalletAllowed) {
|
||||
null
|
||||
|
|
@ -42,21 +40,19 @@ object TapWorkarounds {
|
|||
return false
|
||||
}
|
||||
|
||||
fun Card.isTangemNote(): Boolean = tangemNoteBatches.contains(batchId)
|
||||
|
||||
fun Card.isTangemNote(): Boolean = tangemNoteBatches.contains(batchId) || isSaltPay
|
||||
fun isTangemWalletBatch(card: Card): Boolean = tangemWalletBatches.contains(card.batchId)
|
||||
|
||||
fun Card.getTangemNoteBlockchain(): Blockchain? = tangemNoteBatches[batchId]
|
||||
fun Card.getTangemNoteBlockchain(): Blockchain? =
|
||||
tangemNoteBatches[batchId] ?: if (isSaltPay) Blockchain.Gnosis else null
|
||||
|
||||
private const val START_2_COIN_ISSUER = "start2coin"
|
||||
private const val TEST_CARD_BATCH = "99FF"
|
||||
private const val TEST_CARD_ID_STARTS_WITH = "FF99"
|
||||
|
||||
private val excludedBatches = listOf(
|
||||
"0027",
|
||||
"0030",
|
||||
"0031",
|
||||
"0035"
|
||||
"0035",
|
||||
)
|
||||
|
||||
private val excludedIssuers = listOf(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ dependencies {
|
|||
implementation implementation(project(path: ':common'))
|
||||
|
||||
// Tangem sdk's
|
||||
implementation "com.tangem.tangem-sdk-kotlin:core:${versions.tamgem_card_sdk}"
|
||||
implementation "com.tangem.tangem-sdk-kotlin:core:${versions.tangem_card_sdk}"
|
||||
|
||||
// Kotlin coroutines
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue