Updated on 2026-08-14
This commit is contained in:
commit
a797ab1dc3
38 changed files with 762 additions and 573 deletions
|
|
@ -2,7 +2,7 @@ package com.tangem.tap.common.redux
|
|||
|
||||
import com.tangem.tap.common.redux.global.globalReducer
|
||||
import com.tangem.tap.common.redux.navigation.NavigationReducer
|
||||
import com.tangem.tap.features.send.redux.reducers.SendReducer
|
||||
import com.tangem.tap.features.send.redux.reducers.SendScreenReducer
|
||||
import com.tangem.tap.features.details.redux.DetailsReducer
|
||||
import com.tangem.tap.features.wallet.redux.WalletReducer
|
||||
import org.rekotlin.Action
|
||||
|
|
@ -15,7 +15,7 @@ fun appReducer(action: Action, state: AppState?): AppState {
|
|||
navigationState = NavigationReducer.reduce(action, state),
|
||||
globalState = globalReducer(action, state),
|
||||
walletState = WalletReducer.reduce(action, state),
|
||||
sendState = SendReducer.reduce(action, state.sendState),
|
||||
sendState = SendScreenReducer.reduce(action, state.sendState),
|
||||
detailsState = DetailsReducer.reduce(action, state)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.tap.domain.TapError
|
||||
|
|
@ -32,6 +33,12 @@ class NotificationsHandler(coordinatorLayout: CoordinatorLayout) {
|
|||
showNotification(it.context.getString(message))
|
||||
}
|
||||
}
|
||||
|
||||
fun showToastNotification(message: Int) {
|
||||
baseLayout.get()?.let {
|
||||
Toast.makeText(it.context, it.context.getString(message), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val notificationsMiddleware: Middleware<AppState> = { dispatch, state ->
|
||||
|
|
@ -40,6 +47,9 @@ val notificationsMiddleware: Middleware<AppState> = { dispatch, state ->
|
|||
if (action is NotificationAction) {
|
||||
notificationsHandler?.showNotification(action.messageResource)
|
||||
}
|
||||
if (action is ToastNotificationAction) {
|
||||
notificationsHandler?.showToastNotification(action.messageResource)
|
||||
}
|
||||
if (action is ErrorAction) {
|
||||
notificationsHandler?.showNotification(action.error.localizedMessage)
|
||||
}
|
||||
|
|
@ -48,6 +58,10 @@ val notificationsMiddleware: Middleware<AppState> = { dispatch, state ->
|
|||
}
|
||||
}
|
||||
|
||||
interface ToastNotificationAction : Action {
|
||||
val messageResource: Int
|
||||
}
|
||||
|
||||
interface NotificationAction : Action {
|
||||
val messageResource: Int
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.tap.common.text
|
||||
|
||||
import android.text.InputFilter
|
||||
import android.text.Spanned
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class DecimalDigitsInputFilter(digitsBeforeDecimal: Int, digitsAfterDecimal: Int) : InputFilter {
|
||||
private val pattern: Pattern = Pattern.compile("(([1-9]{1}[0-9]{0," + (digitsBeforeDecimal - 1) + "})?||[0]{1})((\\.[0-9]{0," + digitsAfterDecimal + "})?)||(\\.)?")
|
||||
|
||||
override fun filter(source: CharSequence, sourceStart: Int, sourceEnd: Int, destination: Spanned, destinationStart: Int, destinationEnd: Int): CharSequence? {
|
||||
val destString = destination.toString()
|
||||
val prefix = destString.substring(0, destinationStart)
|
||||
val suffix = destString.substring(destinationEnd, destString.length)
|
||||
val newDestination = prefix + suffix
|
||||
|
||||
val resultPrefix = newDestination.substring(0, destinationStart)
|
||||
val resultSuffix = newDestination.substring(destinationStart, newDestination.length)
|
||||
val result = resultPrefix + source.toString() + resultSuffix
|
||||
|
||||
val hasMatches = pattern.matcher(result).matches()
|
||||
return if (hasMatches) null else ""
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package com.tangem.merchant.common.toggleWidget
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface ToggleState
|
||||
|
||||
interface StateModifier {
|
||||
fun stateChanged(container: ViewGroup, view: View, state: ToggleState)
|
||||
}
|
||||
|
||||
interface ToggleView {
|
||||
val mainViewModifiers: MutableList<StateModifier>
|
||||
val toggleViewModifiers: MutableList<StateModifier>
|
||||
|
||||
fun setState(state: ToggleState, andApply: Boolean = true)
|
||||
fun applyState()
|
||||
fun getView(): View
|
||||
fun getMainView(): View
|
||||
fun getToggleView(): View
|
||||
}
|
||||
|
||||
class ToggleWidget : ToggleView {
|
||||
private val container: ViewGroup
|
||||
private val mainView: View
|
||||
private val toggleView: View
|
||||
|
||||
private var state: ToggleState
|
||||
|
||||
constructor(
|
||||
container: ViewGroup,
|
||||
mainView: View,
|
||||
toggleView: View,
|
||||
initialState: ToggleState,
|
||||
mainViewModifier: List<StateModifier> = mutableListOf(),
|
||||
loadingViewModifier: List<StateModifier> = mutableListOf()
|
||||
) {
|
||||
this.container = container
|
||||
this.mainView = mainView
|
||||
this.toggleView = toggleView
|
||||
this.state = initialState
|
||||
this.mainViewModifiers.addAll(mainViewModifier)
|
||||
this.toggleViewModifiers.addAll(loadingViewModifier)
|
||||
}
|
||||
|
||||
constructor(
|
||||
container: ViewGroup,
|
||||
mainViewId: Int,
|
||||
toggleViewId: Int,
|
||||
initialState: ToggleState,
|
||||
mainViewModifier: List<StateModifier> = mutableListOf(),
|
||||
loadingViewModifier: List<StateModifier> = mutableListOf()
|
||||
) {
|
||||
this.container = container
|
||||
this.mainView = container.findViewById(mainViewId)
|
||||
this.toggleView = container.findViewById(toggleViewId)
|
||||
this.state = initialState
|
||||
this.mainViewModifiers.addAll(mainViewModifier)
|
||||
this.toggleViewModifiers.addAll(loadingViewModifier)
|
||||
}
|
||||
|
||||
override val mainViewModifiers: MutableList<StateModifier> = mutableListOf()
|
||||
|
||||
override val toggleViewModifiers: MutableList<StateModifier> = mutableListOf()
|
||||
|
||||
override fun setState(state: ToggleState, andApply: Boolean) {
|
||||
this.state = state
|
||||
if (andApply) applyState()
|
||||
}
|
||||
|
||||
override fun applyState() {
|
||||
mainViewModifiers.forEach { it.stateChanged(container, mainView, state) }
|
||||
toggleViewModifiers.forEach { it.stateChanged(container, toggleView, state) }
|
||||
}
|
||||
|
||||
override fun getView(): View = container
|
||||
|
||||
override fun getMainView(): View = mainView
|
||||
|
||||
override fun getToggleView(): View = toggleView
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
package com.tangem.tap.common.toggleWidget
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import androidx.core.widget.TextViewCompat
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.tangem.merchant.common.toggleWidget.StateModifier
|
||||
import com.tangem.merchant.common.toggleWidget.ToggleState
|
||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
|
||||
sealed class ProgressState : ToggleState {
|
||||
class Progress : ProgressState()
|
||||
class None : ProgressState()
|
||||
}
|
||||
|
||||
class ReplaceTextStateModifier(
|
||||
private val initialText: String,
|
||||
private val replaceText: String = ""
|
||||
) : StateModifier {
|
||||
|
||||
override fun stateChanged(container: ViewGroup, view: View, state: ToggleState) {
|
||||
val tv = view as? TextView ?: return
|
||||
|
||||
when (state) {
|
||||
is ProgressState.Progress -> {
|
||||
tv.text = replaceText
|
||||
}
|
||||
is ProgressState.None -> {
|
||||
tv.text = initialText
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TextViewDrawableStateModifier(
|
||||
private val initialDrawable: Drawable?,
|
||||
private val replaceDrawable: Drawable?,
|
||||
private val position: Int
|
||||
) : StateModifier {
|
||||
companion object {
|
||||
val LEFT = 1
|
||||
val RIGHT = 2
|
||||
}
|
||||
|
||||
override fun stateChanged(container: ViewGroup, view: View, state: ToggleState) {
|
||||
val drawable = when (state) {
|
||||
is ProgressState.Progress -> replaceDrawable
|
||||
is ProgressState.None -> initialDrawable
|
||||
else -> null
|
||||
}
|
||||
val drawableChanger = getChanger(view)
|
||||
drawableChanger?.change(drawable, position)
|
||||
}
|
||||
|
||||
private fun getChanger(view: View): DrawableChanger? = when (view) {
|
||||
is MaterialButton -> MaterialButtonChanger(view)
|
||||
is Button -> TextViewChanger(view)
|
||||
is TextView -> TextViewChanger(view)
|
||||
else -> null
|
||||
}
|
||||
|
||||
internal interface DrawableChanger {
|
||||
fun change(drawable: Drawable?, position: Int)
|
||||
}
|
||||
|
||||
internal class TextViewChanger(private val view: TextView) : DrawableChanger {
|
||||
override fun change(drawable: Drawable?, position: Int) {
|
||||
when (position) {
|
||||
LEFT -> setLeft(drawable)
|
||||
RIGHT -> setRight(drawable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setLeft(drawable: Drawable?) {
|
||||
if (drawable == null) {
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(view, 0, 0, 0, 0)
|
||||
} else {
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(view, drawable, null, null, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setRight(drawable: Drawable?) {
|
||||
if (drawable == null) {
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(view, 0, 0, 0, 0)
|
||||
} else {
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(view, null, null, drawable, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class MaterialButtonChanger(private val view: MaterialButton) : DrawableChanger {
|
||||
override fun change(drawable: Drawable?, position: Int) {
|
||||
when (position) {
|
||||
LEFT -> setLeft(drawable)
|
||||
RIGHT -> setRight(drawable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setLeft(drawable: Drawable?) {
|
||||
view.iconGravity = MaterialButton.ICON_GRAVITY_START
|
||||
view.icon = drawable
|
||||
}
|
||||
|
||||
private fun setRight(drawable: Drawable?) {
|
||||
view.iconGravity = MaterialButton.ICON_GRAVITY_END
|
||||
view.icon = drawable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ShowHideStateModifier(
|
||||
private val isShowOnLoading: Boolean = true,
|
||||
private val typeOfHiding: Int = View.INVISIBLE
|
||||
) : StateModifier {
|
||||
|
||||
override fun stateChanged(container: ViewGroup, view: View, state: ToggleState) {
|
||||
container.beginDelayedTransition()
|
||||
view.visibility = when (state) {
|
||||
is ProgressState.Progress -> if (isShowOnLoading) View.VISIBLE else typeOfHiding
|
||||
is ProgressState.None -> if (isShowOnLoading) typeOfHiding else View.VISIBLE
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ClickableStateModifier(
|
||||
private val isClickableOnLoading: Boolean = false
|
||||
) : StateModifier {
|
||||
|
||||
override fun stateChanged(container: ViewGroup, view: View, state: ToggleState) {
|
||||
view.isClickable = when (state) {
|
||||
is ProgressState.Progress -> isClickableOnLoading
|
||||
is ProgressState.None -> !isClickableOnLoading
|
||||
else -> return
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,6 @@ package com.tangem.tap.domain
|
|||
|
||||
import androidx.activity.ComponentActivity
|
||||
import com.tangem.*
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.commands.CommandResponse
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.CardType
|
||||
|
|
@ -11,7 +9,6 @@ import com.tangem.tangem_sdk_new.extensions.init
|
|||
import com.tangem.tap.domain.tasks.CreateWalletAndRescanTask
|
||||
import com.tangem.tap.domain.tasks.ScanNoteResponse
|
||||
import com.tangem.tap.domain.tasks.ScanNoteTask
|
||||
import com.tangem.tap.domain.tasks.SendTask
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
|
|
@ -31,21 +28,6 @@ class TangemSdkManager(val activity: ComponentActivity) {
|
|||
return runTaskAsyncReturnOnMain(CreateWalletAndRescanTask())
|
||||
}
|
||||
|
||||
suspend fun send(
|
||||
walletManager: WalletManager,
|
||||
recipientAddress: String,
|
||||
amountToSend: Amount,
|
||||
feeAmount: Amount
|
||||
): CompletionResult<CommandResponse> {
|
||||
return withContext(Dispatchers.IO) {
|
||||
suspendCoroutine { continuation ->
|
||||
tangemSdk.startSessionWithRunnable(SendTask(walletManager, recipientAddress, amountToSend, feeAmount)) {
|
||||
continuation.resume(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun <T : CommandResponse> runTaskAsync(
|
||||
runnable: CardSessionRunnable<T>, cardId: String? = null, initialMessage: Message? = null
|
||||
): CompletionResult<T> =
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ sealed class TapError(@StringRes val localizedMessage: Int): Throwable() {
|
|||
object UnknownBlockchain: TapError(R.string.wallet_unknown_blockchain)
|
||||
object NoInternetConnection: TapError(R.string.notification_no_internet)
|
||||
object InsufficientBalance: TapError(R.string.error_insufficient_balance)
|
||||
object BlockchainInternalError: TapError(R.string.error_insufficient_balance)
|
||||
object BlockchainInternalError: TapError(R.string.error_blockchain_internal)
|
||||
object UnknownError: TapError(R.string.error_unknown)
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
package com.tangem.tap.domain.tasks
|
||||
|
||||
import com.tangem.CardSession
|
||||
import com.tangem.CardSessionRunnable
|
||||
import com.tangem.TangemError
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.TransactionSender
|
||||
import com.tangem.blockchain.common.TransactionSigner
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.commands.CommandResponse
|
||||
import com.tangem.commands.SignCommand
|
||||
import com.tangem.commands.SignResponse
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.tap.scope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import timber.log.Timber
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
class SendTask(
|
||||
private val walletManager: WalletManager,
|
||||
private val recipientAddress: String,
|
||||
private val amountToSend: Amount,
|
||||
private val feeAmount: Amount,
|
||||
) : CardSessionRunnable<CommandResponse> {
|
||||
|
||||
override val requiresPin2: Boolean = false
|
||||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<CommandResponse>) -> Unit) {
|
||||
val txSender = walletManager as TransactionSender
|
||||
|
||||
val verifyResult = walletManager.validateTransaction(amountToSend, feeAmount)
|
||||
if (verifyResult.isNotEmpty()) {
|
||||
callback(CompletionResult.Failure(InsufficientBalance()))
|
||||
return
|
||||
}
|
||||
val txData = walletManager.createTransaction(amountToSend, feeAmount, recipientAddress)
|
||||
|
||||
scope.launch {
|
||||
when (val result = txSender.send(txData, SessionTransactionSigner(session))) {
|
||||
is SimpleResult.Success -> callback(CompletionResult.Success(SendResponse()))
|
||||
is SimpleResult.Failure -> {
|
||||
callback(CompletionResult.Failure(BlockchainInternalErrorConverter.convert(result.error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SendResponse : CommandResponse
|
||||
|
||||
class SessionTransactionSigner(
|
||||
private val session: CardSession
|
||||
) : TransactionSigner {
|
||||
override suspend fun sign(hashes: Array<ByteArray>, cardId: String): CompletionResult<SignResponse> =
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
Timber.d("sign transaction...")
|
||||
SignCommand(hashes).run(session) {
|
||||
if (continuation.isActive) {
|
||||
continuation.resume(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SendError : TangemError {
|
||||
}
|
||||
|
||||
class UnknownError : SendError() {
|
||||
override val code: Int = 1000
|
||||
override var customMessage: String = "Unknown error"
|
||||
}
|
||||
|
||||
open class ThrowableError(throwable: Throwable?) : SendError() {
|
||||
override val code: Int = 1001
|
||||
override var customMessage: String = throwable?.localizedMessage ?: "Unknown exception"
|
||||
}
|
||||
|
||||
class InsufficientBalance(
|
||||
override var customMessage: String = "Insufficient balance"
|
||||
) : SendError() {
|
||||
override val code: Int = 1021
|
||||
}
|
||||
|
||||
class BlockchainInternalError(
|
||||
override var customMessage: String
|
||||
) : SendError() {
|
||||
override val code: Int = 2000
|
||||
}
|
||||
|
||||
class BlockchainInternalErrorConverter {
|
||||
companion object {
|
||||
|
||||
private val stellarInternalErrors = mapOf(
|
||||
"tx_bad_seq" to "Sequence number does not match source account",
|
||||
"tx_too_late" to "The ledger closeTime was after the maxTime",
|
||||
"tx_failedop_no_destination" to "The destination account does not exist",
|
||||
"tx_no_source_account" to "Source account not found"
|
||||
)
|
||||
|
||||
fun convert(throwable: Throwable?): TangemError {
|
||||
val message = throwable?.message ?: return ThrowableError(throwable)
|
||||
|
||||
val customMessage = getInternalBlockchainErrorMessage(message)
|
||||
return if (customMessage == null) ThrowableError(throwable)
|
||||
else BlockchainInternalError(customMessage)
|
||||
}
|
||||
|
||||
private fun getInternalBlockchainErrorMessage(message: String): String? {
|
||||
return stellarInternalErrors[message]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ abstract class BaseStoreFragment(layoutId: Int) : Fragment(layoutId) {
|
|||
|
||||
abstract fun subscribeToStore()
|
||||
|
||||
private lateinit var mainView: View
|
||||
protected lateinit var mainView: View
|
||||
protected val storeSubscribersList = mutableListOf<StoreSubscriber<*>>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,12 @@ package com.tangem.tap.features.send.redux
|
|||
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.tap.common.redux.ErrorAction
|
||||
import com.tangem.tap.common.redux.ToastNotificationAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.features.send.redux.states.FeeType
|
||||
import com.tangem.tap.features.send.redux.states.MainCurrencyType
|
||||
import com.tangem.tap.features.send.redux.states.SendButtonState
|
||||
import com.tangem.wallet.R
|
||||
import org.rekotlin.Action
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -37,6 +40,9 @@ sealed class AddressPayIdVerifyAction : SendScreenAction {
|
|||
ADDRESS_SAME_AS_WALLET
|
||||
}
|
||||
|
||||
data class VerifyClipboard(val data: String?) : AddressPayIdVerifyAction()
|
||||
data class ChangePasteBtnEnableState(val isEnabled: Boolean) : AddressPayIdVerifyAction()
|
||||
|
||||
sealed class PayIdVerification : AddressPayIdVerifyAction() {
|
||||
data class SetError(val payId: String, val error: Error) : PayIdVerification()
|
||||
data class SetPayIdWalletAddress(val payId: String, val payIdWalletAddress: String) : PayIdVerification()
|
||||
|
|
@ -103,16 +109,11 @@ sealed class SendActionUi : SendScreenActionUi {
|
|||
}
|
||||
|
||||
sealed class SendAction : SendScreenAction {
|
||||
enum class Error {
|
||||
INSUFFICIENT_BALANCE, BLOCKCHAIN_INTERNAL
|
||||
|
||||
data class ChangeSendButtonState(val state: SendButtonState) : SendAction()
|
||||
object SendSuccess : SendAction(), ToastNotificationAction {
|
||||
override val messageResource: Int = R.string.send_transaction_complete
|
||||
}
|
||||
|
||||
object SendSuccess : SendAction()
|
||||
|
||||
data class SendError(val sendError: Error) : SendAction(), ErrorAction {
|
||||
override val error: TapError = when (sendError) {
|
||||
Error.INSUFFICIENT_BALANCE -> TapError.InsufficientBalance
|
||||
Error.BLOCKCHAIN_INTERNAL -> TapError.BlockchainInternalError
|
||||
}
|
||||
}
|
||||
data class SendError(override val error: TapError) : SendAction(), ErrorAction
|
||||
}
|
||||
|
|
@ -17,7 +17,12 @@ import org.rekotlin.DispatchFunction
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class AddressPayIdMiddleware {
|
||||
fun handle(data: String, appState: AppState?, dispatch: DispatchFunction) {
|
||||
fun handle(data: String?, appState: AppState?, dispatch: DispatchFunction) {
|
||||
if (data == null) {
|
||||
dispatch(AddressVerification.SetError("", Error.ADDRESS_INVALID_OR_UNSUPPORTED_BY_BLOCKCHAIN))
|
||||
return
|
||||
}
|
||||
|
||||
val sendState = appState?.sendState ?: return
|
||||
val walletManager = sendState.walletManager ?: return
|
||||
if (data == sendState.addressPayIdState.etFieldValue) return
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.tap.common.extensions.isGreaterThanOrEqual
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.send.redux.AmountAction
|
||||
import com.tangem.tap.features.send.redux.ReceiptAction
|
||||
import com.tangem.tap.features.send.redux.SendAction
|
||||
import com.tangem.tap.features.send.redux.states.MainCurrencyType
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.Action
|
||||
|
|
@ -43,6 +44,7 @@ class AmountMiddleware {
|
|||
dispatch(AmountAction.AmountVerification.SetError(checkResult.amount, checkResult.error))
|
||||
}
|
||||
dispatch(ReceiptAction.RefreshReceipt)
|
||||
dispatch(SendAction.ChangeSendButtonState(sendState.getButtonState()))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.common.extensions.isZero
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.send.redux.FeeAction
|
||||
import com.tangem.tap.features.send.redux.ReceiptAction
|
||||
import com.tangem.tap.features.send.redux.SendAction
|
||||
import com.tangem.tap.scope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -29,6 +30,7 @@ class RequestFeeMiddleware {
|
|||
dispatch(FeeAction.FeeCalculation.SetFeeError(FeeAction.Error.ADDRESS_OR_AMOUNT_IS_EMPTY))
|
||||
dispatch(FeeAction.ChangeLayoutVisibility(main = false, controls = true, chipGroup = true))
|
||||
dispatch(ReceiptAction.RefreshReceipt)
|
||||
dispatch(SendAction.ChangeSendButtonState(sendState.getButtonState()))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +69,7 @@ class RequestFeeMiddleware {
|
|||
}
|
||||
}
|
||||
dispatch(ReceiptAction.RefreshReceipt)
|
||||
dispatch(SendAction.ChangeSendButtonState(sendState.getButtonState()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,24 @@
|
|||
package com.tangem.tap.features.send.redux.middlewares
|
||||
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.blockchain.common.TransactionSender
|
||||
import com.tangem.blockchain.extensions.Signer
|
||||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdActionUi.ChangeAddressOrPayId
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction.*
|
||||
import com.tangem.tap.features.send.redux.AmountActionUi.CheckAmountToSend
|
||||
import com.tangem.tap.features.send.redux.FeeAction.RequestFee
|
||||
import com.tangem.tap.features.send.redux.SendAction
|
||||
import com.tangem.tap.features.send.redux.SendActionUi
|
||||
import com.tangem.tap.features.send.redux.states.SendButtonState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.tap.tangemSdk
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
|
|
@ -22,6 +30,18 @@ val sendMiddleware: Middleware<AppState> = { dispatch, appState ->
|
|||
{ action ->
|
||||
when (action) {
|
||||
is ChangeAddressOrPayId -> AddressPayIdMiddleware().handle(action.data, appState(), dispatch)
|
||||
is VerifyClipboard -> {
|
||||
AddressPayIdMiddleware().handle(action.data, appState()) {
|
||||
when (it) {
|
||||
is AddressVerification.SetWalletAddress, is PayIdVerification.SetPayIdWalletAddress -> {
|
||||
dispatch(ChangePasteBtnEnableState(true))
|
||||
}
|
||||
is AddressVerification.SetError, is PayIdVerification.SetError -> {
|
||||
dispatch(ChangePasteBtnEnableState(false))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is CheckAmountToSend -> AmountMiddleware().handle(action.data, appState(), dispatch)
|
||||
is RequestFee -> RequestFeeMiddleware().handle(appState(), dispatch)
|
||||
is SendActionUi.SendAmountToRecipient -> verifyAndSendTransaction(appState(), dispatch)
|
||||
|
|
@ -41,15 +61,44 @@ private fun verifyAndSendTransaction(appState: AppState?, dispatch: (Action) ->
|
|||
val feeAmount = Amount(sendState.feeState.getCurrentFee(), blockchain)
|
||||
val amountToSend = Amount(sendState.amountState.amountToSendCrypto, blockchain, recipientAddress)
|
||||
|
||||
val txSender = walletManager as TransactionSender
|
||||
|
||||
val verifyResult = walletManager.validateTransaction(amountToSend, feeAmount)
|
||||
if (verifyResult.isNotEmpty()) {
|
||||
dispatch(SendAction.SendError(TapError.InsufficientBalance))
|
||||
return
|
||||
}
|
||||
|
||||
dispatch(SendAction.ChangeSendButtonState(SendButtonState.PROGRESS))
|
||||
val txData = walletManager.createTransaction(amountToSend, feeAmount, recipientAddress)
|
||||
scope.launch {
|
||||
when (val sendResult = tangemSdkManager.send(walletManager, recipientAddress, amountToSend, feeAmount)) {
|
||||
is CompletionResult.Success -> dispatch(SendAction.SendSuccess)
|
||||
is CompletionResult.Failure -> {
|
||||
when (sendResult.error.code) {
|
||||
1021 -> dispatch(SendAction.SendError(SendAction.Error.INSUFFICIENT_BALANCE))
|
||||
1001, 2000 -> dispatch(SendAction.SendError(SendAction.Error.BLOCKCHAIN_INTERNAL))
|
||||
val result = txSender.send(txData, Signer(tangemSdk))
|
||||
withContext(Dispatchers.Main) {
|
||||
when (result) {
|
||||
is SimpleResult.Success -> {
|
||||
dispatch(SendAction.SendSuccess)
|
||||
dispatch(NavigationAction.PopBackTo())
|
||||
}
|
||||
is SimpleResult.Failure -> {
|
||||
when (result.error) {
|
||||
is Throwable -> {
|
||||
val message = (result.error as Throwable).message
|
||||
when {
|
||||
message == null -> {
|
||||
dispatch(SendAction.SendError(TapError.UnknownError))
|
||||
}
|
||||
message.contains("50002") -> {
|
||||
// user was cancelled the operation by closing the Sdk bottom sheet
|
||||
}
|
||||
else -> {
|
||||
dispatch(SendAction.SendError(TapError.BlockchainInternalError))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dispatch(SendAction.ChangeSendButtonState(SendButtonState.ENABLED))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ class AddressPayIdReducer : SendInternalReducer {
|
|||
is PayIdVerification.SetError -> state.copyPayIdError(action.payId, action.error)
|
||||
is AddressVerification.SetWalletAddress -> state.copyWalletAddress(action.address)
|
||||
is AddressVerification.SetError -> state.copyError(action.address, action.error)
|
||||
is AddressPayIdVerifyAction.ChangePasteBtnEnableState -> state.copy(pasteIsEnabled = action.isEnabled)
|
||||
is AddressPayIdVerifyAction.VerifyClipboard -> state
|
||||
}
|
||||
return updateLastState(sendState.copy(addressPayIdState = result), result)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ class AmountReducer : SendInternalReducer {
|
|||
viewAmountValue = fiatToSend.stripZeroPlainString(),
|
||||
viewBalanceValue = converter.toFiat(state.balanceCrypto).stripZeroPlainString(),
|
||||
mainCurrency = Value(MainCurrencyType.FIAT, TapCurrency.main),
|
||||
maxLengthOfAmount = sendState.getDecimals(action.mainCurrency),
|
||||
cursorAtTheSamePosition = false
|
||||
)
|
||||
}
|
||||
|
|
@ -52,6 +53,7 @@ class AmountReducer : SendInternalReducer {
|
|||
viewAmountValue = state.amountToSendCrypto.stripZeroPlainString(),
|
||||
viewBalanceValue = state.balanceCrypto.stripZeroPlainString(),
|
||||
mainCurrency = mainCurrency,
|
||||
maxLengthOfAmount = sendState.getDecimals(action.mainCurrency),
|
||||
cursorAtTheSamePosition = false
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.blockchain.common.AmountType
|
|||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.tap.common.CurrencyConverter
|
||||
import com.tangem.tap.common.entities.TapCurrency
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.features.send.redux.ReceiptAction.RefreshReceipt
|
||||
import com.tangem.tap.features.send.redux.SendScreenAction
|
||||
import com.tangem.tap.features.send.redux.states.*
|
||||
|
|
@ -29,14 +30,14 @@ class ReceiptReducer : SendInternalReducer {
|
|||
|
||||
val layoutType = determineLayoutType(amountState.mainCurrency.value, amountState.typeOfAmount)
|
||||
val symbols = determineSymbols(wallet)
|
||||
val showBlank = !sendState.isReadyToSend()
|
||||
val result = state.copy(
|
||||
visibleTypeOfReceipt = layoutType,
|
||||
mainCurrencyType = sendState.amountState.mainCurrency,
|
||||
mainLayoutIsVisible = sendState.isReadyToSend(),
|
||||
fiat = createFiatType(converter, amountState, feeState, symbols),
|
||||
crypto = createCryptoType(converter, amountState, feeState, symbols),
|
||||
tokenFiat = createTokenFiatType(converter, amountState, feeState, symbols),
|
||||
tokenCrypto = createTokenCryptoType(converter, amountState, feeState, symbols)
|
||||
fiat = createFiatType(converter, amountState, feeState, symbols, showBlank),
|
||||
crypto = createCryptoType(converter, amountState, feeState, symbols, showBlank),
|
||||
tokenFiat = createTokenFiatType(converter, amountState, feeState, symbols, showBlank),
|
||||
tokenCrypto = createTokenCryptoType(converter, amountState, feeState, symbols, showBlank)
|
||||
)
|
||||
return updateLastState(sendState.copy(receiptState = result), result)
|
||||
}
|
||||
|
|
@ -45,19 +46,24 @@ class ReceiptReducer : SendInternalReducer {
|
|||
converter: CurrencyConverter,
|
||||
amountState: AmountState,
|
||||
feeState: FeeState,
|
||||
symbols: ReceiptSymbols
|
||||
symbols: ReceiptSymbols,
|
||||
showBlank: Boolean
|
||||
): ReceiptFiat {
|
||||
val feeCrypto = feeState.getCurrentFee()
|
||||
val feeFiat = converter.toFiat(feeCrypto)
|
||||
|
||||
if (showBlank) {
|
||||
return ReceiptFiat("0", feeFiat.stripZeroPlainString(), feeFiat.stripZeroPlainString(), "0", symbols)
|
||||
}
|
||||
|
||||
return if (feeState.feeIsIncluded) {
|
||||
val amountFiat = converter.toFiat(amountState.amountToSendCrypto.minus(feeCrypto))
|
||||
val totalFiat = converter.toFiat(amountState.amountToSendCrypto)
|
||||
ReceiptFiat(
|
||||
amountFiat = amountFiat,
|
||||
feeFiat = feeFiat,
|
||||
totalFiat = totalFiat,
|
||||
willSentCrypto = amountState.amountToSendCrypto.stripTrailingZeros(),
|
||||
amountFiat = amountFiat.stripZeroPlainString(),
|
||||
feeFiat = feeFiat.stripZeroPlainString(),
|
||||
totalFiat = totalFiat.stripZeroPlainString(),
|
||||
willSentCrypto = amountState.amountToSendCrypto.stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
} else {
|
||||
|
|
@ -65,10 +71,10 @@ class ReceiptReducer : SendInternalReducer {
|
|||
val amountFiat = converter.toFiat(amountState.amountToSendCrypto)
|
||||
val totalFiat = converter.toFiat(totalAmountCrypto)
|
||||
ReceiptFiat(
|
||||
amountFiat = amountFiat,
|
||||
feeFiat = feeFiat,
|
||||
totalFiat = totalFiat,
|
||||
willSentCrypto = totalAmountCrypto.stripTrailingZeros(),
|
||||
amountFiat = amountFiat.stripZeroPlainString(),
|
||||
feeFiat = feeFiat.stripZeroPlainString(),
|
||||
totalFiat = totalFiat.stripZeroPlainString(),
|
||||
willSentCrypto = totalAmountCrypto.stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
}
|
||||
|
|
@ -78,25 +84,32 @@ class ReceiptReducer : SendInternalReducer {
|
|||
converter: CurrencyConverter,
|
||||
amountState: AmountState,
|
||||
feeState: FeeState,
|
||||
symbols: ReceiptSymbols
|
||||
symbols: ReceiptSymbols,
|
||||
showBlank: Boolean
|
||||
): ReceiptCrypto {
|
||||
val feeCrypto = feeState.getCurrentFee()
|
||||
|
||||
if (showBlank) {
|
||||
return ReceiptCrypto("0", feeCrypto.stripZeroPlainString(), "0", converter.toFiat(feeCrypto).stripZeroPlainString(), "0", symbols)
|
||||
}
|
||||
|
||||
if (feeState.feeIsIncluded) {
|
||||
return ReceiptCrypto(
|
||||
amountCrypto = amountState.amountToSendCrypto.minus(feeCrypto).stripTrailingZeros(),
|
||||
feeCrypto = feeCrypto.stripTrailingZeros(),
|
||||
totalCrypto = amountState.amountToSendCrypto.stripTrailingZeros(),
|
||||
willSentFiat = converter.toFiat(amountState.amountToSendCrypto),
|
||||
amountCrypto = amountState.amountToSendCrypto.minus(feeCrypto).stripZeroPlainString(),
|
||||
feeCrypto = feeCrypto.stripZeroPlainString(),
|
||||
totalCrypto = amountState.amountToSendCrypto.stripZeroPlainString(),
|
||||
feeFiat = converter.toFiat(feeCrypto).stripZeroPlainString(),
|
||||
willSentFiat = converter.toFiat(amountState.amountToSendCrypto).stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
} else {
|
||||
val totalCrypto = amountState.amountToSendCrypto.plus(feeCrypto)
|
||||
return ReceiptCrypto(
|
||||
amountCrypto = amountState.amountToSendCrypto.stripTrailingZeros(),
|
||||
feeCrypto = feeCrypto.stripTrailingZeros(),
|
||||
totalCrypto = totalCrypto.stripTrailingZeros(),
|
||||
willSentFiat = converter.toFiat(totalCrypto),
|
||||
amountCrypto = amountState.amountToSendCrypto.stripZeroPlainString(),
|
||||
feeCrypto = feeCrypto.stripZeroPlainString(),
|
||||
totalCrypto = totalCrypto.stripZeroPlainString(),
|
||||
feeFiat = converter.toFiat(feeCrypto).stripZeroPlainString(),
|
||||
willSentFiat = converter.toFiat(totalCrypto).stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
}
|
||||
|
|
@ -106,17 +119,23 @@ class ReceiptReducer : SendInternalReducer {
|
|||
converter: CurrencyConverter,
|
||||
amountState: AmountState,
|
||||
feeState: FeeState,
|
||||
symbols: ReceiptSymbols
|
||||
symbols: ReceiptSymbols,
|
||||
showBlank: Boolean
|
||||
): ReceiptTokenFiat {
|
||||
val feeCrypto = feeState.getCurrentFee()
|
||||
val amountFiat = converter.toFiat(amountState.amountToSendCrypto)
|
||||
val feeFiat = converter.toFiat(feeCrypto)
|
||||
|
||||
if (showBlank) {
|
||||
return ReceiptTokenFiat("0", feeFiat.stripZeroPlainString(), "0", "0", "0", symbols)
|
||||
}
|
||||
|
||||
return ReceiptTokenFiat(
|
||||
amountFiat = amountFiat,
|
||||
feeFiat = feeFiat,
|
||||
totalFiat = amountFiat.plus(feeFiat),
|
||||
willSentTokenCrypto = amountState.amountToSendCrypto.stripTrailingZeros(),
|
||||
willSentFeeCrypto = feeCrypto.stripTrailingZeros(),
|
||||
amountFiat = amountFiat.stripZeroPlainString(),
|
||||
feeFiat = feeFiat.stripZeroPlainString(),
|
||||
totalFiat = amountFiat.plus(feeFiat).stripZeroPlainString(),
|
||||
willSentTokenCrypto = amountState.amountToSendCrypto.stripZeroPlainString(),
|
||||
willSentFeeCrypto = feeCrypto.stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
}
|
||||
|
|
@ -125,14 +144,19 @@ class ReceiptReducer : SendInternalReducer {
|
|||
converter: CurrencyConverter,
|
||||
amountState: AmountState,
|
||||
feeState: FeeState,
|
||||
symbols: ReceiptSymbols
|
||||
symbols: ReceiptSymbols,
|
||||
showBlank: Boolean
|
||||
): ReceiptTokenCrypto {
|
||||
val feeCrypto = feeState.getCurrentFee()
|
||||
val totalFiat = converter.toFiat(amountState.amountToSendCrypto).plus(converter.toFiat(feeCrypto))
|
||||
if (showBlank) {
|
||||
return ReceiptTokenCrypto("0", feeCrypto.stripZeroPlainString(), "0", symbols)
|
||||
}
|
||||
|
||||
return ReceiptTokenCrypto(
|
||||
amountToken = amountState.amountToSendCrypto.stripTrailingZeros(),
|
||||
feeCrypto = feeCrypto.stripTrailingZeros(),
|
||||
totalFiat = totalFiat.stripTrailingZeros(),
|
||||
amountToken = amountState.amountToSendCrypto.stripZeroPlainString(),
|
||||
feeCrypto = feeCrypto.stripZeroPlainString(),
|
||||
totalFiat = totalFiat.stripZeroPlainString(),
|
||||
symbols = symbols
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@ package com.tangem.tap.features.send.redux.reducers
|
|||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.tap.common.CurrencyConverter
|
||||
import com.tangem.tap.features.send.redux.*
|
||||
import com.tangem.tap.features.send.redux.states.IdStateHolder
|
||||
import com.tangem.tap.features.send.redux.states.SendState
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.StateType
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
|
|
@ -17,7 +16,7 @@ interface SendInternalReducer {
|
|||
fun handle(action: SendScreenAction, sendState: SendState): SendState
|
||||
}
|
||||
|
||||
class SendReducer {
|
||||
class SendScreenReducer {
|
||||
companion object {
|
||||
fun reduce(incomingAction: Action, sendState: SendState): SendState {
|
||||
if (incomingAction is ReleaseSendState) return SendState()
|
||||
|
|
@ -29,18 +28,26 @@ class SendReducer {
|
|||
is AmountActionUi, is AmountAction -> AmountReducer()
|
||||
is FeeActionUi, is FeeAction -> FeeReducer()
|
||||
is ReceiptAction -> ReceiptReducer()
|
||||
is SendAction -> SendReducer()
|
||||
else -> EmptyReducer()
|
||||
}
|
||||
|
||||
|
||||
val newState = reducer.handle(action, sendState).copy(sendButtonIsEnabled = sendState.isReadyToSend())
|
||||
Timber.i("${newState.lastChangedStateType}.")
|
||||
|
||||
return newState
|
||||
return reducer.handle(action, sendState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SendReducer : SendInternalReducer {
|
||||
override fun handle(action: SendScreenAction, sendState: SendState): SendState {
|
||||
val result = when (action) {
|
||||
is SendAction.ChangeSendButtonState -> sendState.copy(sendButtonState = action.state)
|
||||
else -> return sendState
|
||||
}
|
||||
|
||||
return updateLastState(result, result)
|
||||
}
|
||||
}
|
||||
|
||||
private class EmptyReducer : SendInternalReducer {
|
||||
override fun handle(action: SendScreenAction, sendState: SendState): SendState = sendState
|
||||
}
|
||||
|
|
@ -63,5 +70,7 @@ private class PrepareSendScreenStatesReducer : SendInternalReducer {
|
|||
}
|
||||
}
|
||||
|
||||
internal fun updateLastState(sendState: SendState, lastChangedState: StateType): SendState =
|
||||
sendState.copy(lastChangedStateType = lastChangedState)
|
||||
internal fun updateLastState(sendState: SendState, lastChangedState: IdStateHolder): SendState {
|
||||
sendState.lastChangedStates.add(lastChangedState.stateId)
|
||||
return sendState
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.features.send.redux.states
|
||||
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class AddressPayIdState(
|
||||
val etFieldValue: String? = null,
|
||||
|
|
@ -9,8 +8,10 @@ data class AddressPayIdState(
|
|||
val truncatedFieldValue: String? = null,
|
||||
val recipientWalletAddress: String? = null,
|
||||
val error: AddressPayIdVerifyAction.Error? = null,
|
||||
val truncateHandler: ((String) -> String)? = null
|
||||
) : StateType {
|
||||
val truncateHandler: ((String) -> String)? = null,
|
||||
val pasteIsEnabled: Boolean = false,
|
||||
override val stateId: StateId = StateId.ADDRESS_PAY_ID
|
||||
) : SendScreenState {
|
||||
|
||||
fun isReady(): Boolean = error == null && recipientWalletAddress?.isNotEmpty() ?: false
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.tangem.tap.features.send.redux.states
|
|||
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.tap.features.send.redux.FeeAction
|
||||
import org.rekotlin.StateType
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
|
|
@ -20,8 +19,9 @@ data class FeeState(
|
|||
val mainLayoutIsVisible: Boolean = false,
|
||||
val controlsLayoutIsVisible: Boolean = true,
|
||||
val feeChipGroupIsVisible: Boolean = true,
|
||||
val error: FeeAction.Error? = null
|
||||
) : StateType {
|
||||
val error: FeeAction.Error? = null,
|
||||
override val stateId: StateId = StateId.FEE
|
||||
) : SendScreenState {
|
||||
fun isReady(): Boolean = error == null && currentFee != null
|
||||
|
||||
fun getCurrentFee(): BigDecimal = currentFee?.value?.value ?: BigDecimal.ZERO
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
package com.tangem.tap.features.send.redux.states
|
||||
|
||||
import org.rekotlin.StateType
|
||||
import java.math.BigDecimal
|
||||
|
||||
// Shows only one type of the layout
|
||||
enum class ReceiptLayoutType {
|
||||
UNKNOWN, FIAT, CRYPTO, TOKEN_FIAT, TOKEN_CRYPTO
|
||||
|
|
@ -15,8 +12,8 @@ data class ReceiptState(
|
|||
val tokenFiat: ReceiptTokenFiat? = null,
|
||||
val tokenCrypto: ReceiptTokenCrypto? = null,
|
||||
val mainCurrencyType: Value<MainCurrencyType>? = null,
|
||||
val mainLayoutIsVisible: Boolean = false,
|
||||
) : StateType
|
||||
override val stateId: StateId = StateId.RECEIPT
|
||||
) : SendScreenState
|
||||
|
||||
data class ReceiptSymbols(
|
||||
val fiat: String,
|
||||
|
|
@ -25,33 +22,34 @@ data class ReceiptSymbols(
|
|||
)
|
||||
|
||||
data class ReceiptFiat(
|
||||
val amountFiat: BigDecimal,
|
||||
val feeFiat: BigDecimal,
|
||||
val totalFiat: BigDecimal,
|
||||
val willSentCrypto: BigDecimal,
|
||||
val amountFiat: String,
|
||||
val feeFiat: String,
|
||||
val totalFiat: String,
|
||||
val willSentCrypto: String,
|
||||
val symbols: ReceiptSymbols
|
||||
)
|
||||
|
||||
data class ReceiptCrypto(
|
||||
val amountCrypto: BigDecimal,
|
||||
val feeCrypto: BigDecimal,
|
||||
val totalCrypto: BigDecimal,
|
||||
val willSentFiat: BigDecimal,
|
||||
val amountCrypto: String,
|
||||
val feeCrypto: String,
|
||||
val totalCrypto: String,
|
||||
val feeFiat: String,
|
||||
val willSentFiat: String,
|
||||
val symbols: ReceiptSymbols
|
||||
)
|
||||
|
||||
data class ReceiptTokenCrypto(
|
||||
val amountToken: BigDecimal,
|
||||
val feeCrypto: BigDecimal,
|
||||
val totalFiat: BigDecimal,
|
||||
val amountToken: String,
|
||||
val feeCrypto: String,
|
||||
val totalFiat: String,
|
||||
val symbols: ReceiptSymbols
|
||||
)
|
||||
|
||||
data class ReceiptTokenFiat(
|
||||
val amountFiat: BigDecimal,
|
||||
val feeFiat: BigDecimal,
|
||||
val totalFiat: BigDecimal,
|
||||
val willSentTokenCrypto: BigDecimal,
|
||||
val willSentFeeCrypto: BigDecimal,
|
||||
val amountFiat: String,
|
||||
val feeFiat: String,
|
||||
val totalFiat: String,
|
||||
val willSentTokenCrypto: String,
|
||||
val willSentFeeCrypto: String,
|
||||
val symbols: ReceiptSymbols
|
||||
)
|
||||
|
|
@ -14,17 +14,29 @@ import java.math.BigDecimal
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
|
||||
interface IdStateHolder {
|
||||
val stateId: StateId
|
||||
}
|
||||
|
||||
enum class StateId {
|
||||
SEND_SCREEN, ADDRESS_PAY_ID, AMOUNT, FEE, RECEIPT
|
||||
}
|
||||
|
||||
interface SendScreenState : StateType, IdStateHolder
|
||||
|
||||
data class SendState(
|
||||
val amount: Amount? = null,
|
||||
val walletManager: WalletManager? = null,
|
||||
val currencyConverter: CurrencyConverter = CurrencyConverter(BigDecimal.ONE),
|
||||
val lastChangedStateType: StateType = NoneState(),
|
||||
val lastChangedStates: LinkedHashSet<StateId> = linkedSetOf(),
|
||||
val addressPayIdState: AddressPayIdState = AddressPayIdState(),
|
||||
val amountState: AmountState = AmountState(),
|
||||
val feeState: FeeState = FeeState(),
|
||||
val receiptState: ReceiptState = ReceiptState(),
|
||||
val sendButtonIsEnabled: Boolean = false,
|
||||
) : StateType {
|
||||
val sendButtonState: SendButtonState = SendButtonState.DISABLED,
|
||||
override val stateId: StateId = StateId.SEND_SCREEN
|
||||
) : SendScreenState {
|
||||
|
||||
fun isReadyToSend(): Boolean {
|
||||
val sendState = store.state.sendState
|
||||
|
|
@ -32,9 +44,18 @@ data class SendState(
|
|||
}
|
||||
|
||||
fun addressPayIdIsReady(): Boolean = store.state.sendState.addressPayIdState.isReady()
|
||||
|
||||
fun getDecimals(type: MainCurrencyType): Int = when (type) {
|
||||
MainCurrencyType.FIAT -> 2
|
||||
MainCurrencyType.CRYPTO -> amount?.decimals ?: 0
|
||||
}
|
||||
|
||||
fun getButtonState(): SendButtonState = if (isReadyToSend()) SendButtonState.ENABLED else SendButtonState.DISABLED
|
||||
}
|
||||
|
||||
class NoneState : StateType
|
||||
enum class SendButtonState {
|
||||
ENABLED, DISABLED, PROGRESS
|
||||
}
|
||||
|
||||
data class AmountState(
|
||||
val viewAmountValue: String = BigDecimal.ZERO.toPlainString(),
|
||||
|
|
@ -44,8 +65,10 @@ data class AmountState(
|
|||
val amountToSendCrypto: BigDecimal = BigDecimal.ZERO,
|
||||
val balanceCrypto: BigDecimal = BigDecimal.ZERO,
|
||||
val cursorAtTheSamePosition: Boolean = true,
|
||||
val error: AmountAction.Error? = null
|
||||
) : StateType {
|
||||
val maxLengthOfAmount: Int = 2,
|
||||
val error: AmountAction.Error? = null,
|
||||
override val stateId: StateId = StateId.AMOUNT
|
||||
) : SendScreenState {
|
||||
fun isReady(): Boolean = error == null && !amountToSendCrypto.isZero()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,30 +8,28 @@ import android.view.inputmethod.EditorInfo
|
|||
import android.widget.EditText
|
||||
import androidx.core.view.postDelayed
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import com.tangem.merchant.common.toggleWidget.ToggleWidget
|
||||
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.extensions.getDrawableCompat
|
||||
import com.tangem.tap.common.extensions.getFromClipboard
|
||||
import com.tangem.tap.common.extensions.setOnImeActionListener
|
||||
import com.tangem.tap.common.qrCodeScan.ScanQrCodeActivity
|
||||
import com.tangem.tap.common.snackBar.MaxAmountSnackbar
|
||||
import com.tangem.tap.common.text.truncateMiddleWith
|
||||
import com.tangem.tap.common.toggleWidget.*
|
||||
import com.tangem.tap.features.send.BaseStoreFragment
|
||||
import com.tangem.tap.features.send.redux.*
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdActionUi.*
|
||||
import com.tangem.tap.features.send.redux.AmountActionUi.*
|
||||
import com.tangem.tap.features.send.redux.FeeAction
|
||||
import com.tangem.tap.features.send.redux.FeeActionUi.*
|
||||
import com.tangem.tap.features.send.redux.ReceiptAction
|
||||
import com.tangem.tap.features.send.redux.ReleaseSendState
|
||||
import com.tangem.tap.features.send.redux.SendActionUi
|
||||
import com.tangem.tap.features.send.redux.states.FeeType
|
||||
import com.tangem.tap.features.send.redux.states.MainCurrencyType
|
||||
import com.tangem.tap.features.send.ui.stateSubscribers.SendStateSubscriber
|
||||
import com.tangem.tap.mainScope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.btn_paste.*
|
||||
import kotlinx.android.synthetic.main.btn_qr_code.*
|
||||
import kotlinx.android.synthetic.main.fragment_send.*
|
||||
import kotlinx.android.synthetic.main.layout_send_address_payid.*
|
||||
import kotlinx.android.synthetic.main.layout_send_amount.*
|
||||
|
|
@ -45,12 +43,21 @@ import kotlinx.coroutines.flow.*
|
|||
*/
|
||||
class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
||||
|
||||
lateinit var sendBtn: ToggleWidget
|
||||
|
||||
private fun initSendButtonStates() {
|
||||
sendBtn = ToggleWidget(flSendButtonContainer, btnSend, progress, ProgressState.None())
|
||||
sendBtn.setupSendButtonStateModifiers(requireContext())
|
||||
sendBtn.setState(ProgressState.None())
|
||||
}
|
||||
|
||||
private val sendSubscriber = SendStateSubscriber(this)
|
||||
private lateinit var keyboardObserver: KeyboardObserver
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
initSendButtonStates()
|
||||
setupAddressOrPayIdLayout()
|
||||
setupAmountLayout()
|
||||
setupFeeLayout()
|
||||
|
|
@ -61,7 +68,8 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
}
|
||||
|
||||
private fun setupAddressOrPayIdLayout() {
|
||||
store.dispatch(SetTruncateHandler { etAddressOrPayId.truncateMiddleWith(it, " *** ") })
|
||||
store.dispatch(SetTruncateHandler { etAddressOrPayId.truncateMiddleWith(it, "...") })
|
||||
store.dispatch(AddressPayIdVerifyAction.VerifyClipboard(requireContext().getFromClipboard()?.toString()))
|
||||
|
||||
etAddressOrPayId.setOnFocusChangeListener { v, hasFocus ->
|
||||
store.dispatch(TruncateOrRestore(!hasFocus))
|
||||
|
|
@ -92,16 +100,22 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
if (requestCode != ScanQrCodeActivity.SCAN_QR_REQUEST_CODE) return
|
||||
|
||||
val scannedCode = data?.getStringExtra(ScanQrCodeActivity.SCAN_RESULT) ?: ""
|
||||
if (scannedCode.isEmpty()) return
|
||||
|
||||
store.dispatch(ChangeAddressOrPayId(scannedCode))
|
||||
store.dispatch(TruncateOrRestore(!etAddressOrPayId.isFocused))
|
||||
view?.postDelayed(200) { store.dispatch(FeeAction.RequestFee) }
|
||||
store.dispatch(FeeAction.RequestFee)
|
||||
}
|
||||
|
||||
private fun setupAmountLayout() {
|
||||
store.dispatch(SetMainCurrency(restoreMainCurrency()))
|
||||
store.dispatch(ReceiptAction.RefreshReceipt)
|
||||
store.dispatch(SendAction.ChangeSendButtonState(store.state.sendState.getButtonState()))
|
||||
|
||||
tvAmountCurrency.setOnClickListener {
|
||||
store.dispatch(ToggleMainCurrency)
|
||||
store.dispatch(ReceiptAction.RefreshReceipt)
|
||||
store.dispatch(SendAction.ChangeSendButtonState(store.state.sendState.getButtonState()))
|
||||
}
|
||||
|
||||
val maxAmountSnackbar = MaxAmountSnackbar.make(etAmountToSend) {
|
||||
|
|
@ -140,7 +154,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
val prevFocusChangeListener = etAmountToSend.onFocusChangeListener
|
||||
etAmountToSend.setOnFocusChangeListener { v, hasFocus ->
|
||||
prevFocusChangeListener.onFocusChange(v, hasFocus)
|
||||
if (hasFocus && etAmountToSend.text?.toString() == "0") etAmountToSend.setText("")
|
||||
// if (hasFocus && etAmountToSend.text?.toString() == "0") etAmountToSend.setText("")
|
||||
if (!hasFocus && etAmountToSend.text?.toString() == "") etAmountToSend.setText("0")
|
||||
}
|
||||
|
||||
|
|
@ -229,5 +243,15 @@ class FeeUiHelper {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private fun ToggleWidget.setupSendButtonStateModifiers(context: Context) {
|
||||
mainViewModifiers.clear()
|
||||
mainViewModifiers.add(ReplaceTextStateModifier(context.getString(R.string.send_btn_send), ""))
|
||||
mainViewModifiers.add(
|
||||
TextViewDrawableStateModifier(
|
||||
context.getDrawableCompat(R.drawable.ic_arrow_right), null, TextViewDrawableStateModifier.RIGHT
|
||||
))
|
||||
mainViewModifiers.add(ClickableStateModifier())
|
||||
toggleViewModifiers.clear()
|
||||
toggleViewModifiers.add(ShowHideStateModifier())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ package com.tangem.tap.features.send.ui.stateSubscribers
|
|||
|
||||
import android.content.Context
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.util.TypedValue
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.text.bold
|
||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
||||
import com.tangem.tap.common.extensions.enableError
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.extensions.update
|
||||
import com.tangem.tap.common.text.DecimalDigitsInputFilter
|
||||
import com.tangem.tap.common.toggleWidget.ProgressState
|
||||
import com.tangem.tap.features.send.BaseStoreFragment
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction.Error
|
||||
import com.tangem.tap.features.send.redux.AmountAction
|
||||
|
|
@ -34,14 +35,32 @@ import kotlinx.android.synthetic.main.layout_send_receipt.*
|
|||
class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber<SendState>(fragment) {
|
||||
|
||||
override fun updateWithNewState(fg: BaseStoreFragment, state: SendState) {
|
||||
when (state.lastChangedStateType) {
|
||||
is FeeState -> handleFeeState(fg, state.feeState)
|
||||
is AddressPayIdState -> handleAddressPayIdState(fg, state.addressPayIdState)
|
||||
is AmountState -> handleAmountState(fg, state.amountState)
|
||||
is ReceiptState -> handleReceiptState(fg, state.receiptState)
|
||||
val lastChangedStates = state.lastChangedStates.toList()
|
||||
state.lastChangedStates.clear()
|
||||
lastChangedStates.forEach {
|
||||
when (it) {
|
||||
StateId.ADDRESS_PAY_ID -> handleAddressPayIdState(fg, state.addressPayIdState)
|
||||
StateId.AMOUNT -> handleAmountState(fg, state.amountState)
|
||||
StateId.FEE -> handleFeeState(fg, state.feeState)
|
||||
StateId.RECEIPT -> handleReceiptState(fg, state.receiptState)
|
||||
}
|
||||
}
|
||||
|
||||
fg.btnSend.isEnabled = state.sendButtonIsEnabled
|
||||
val sendFragment = (fg as? SendFragment) ?: return
|
||||
when (state.sendButtonState) {
|
||||
SendButtonState.ENABLED -> {
|
||||
fg.btnSend.isEnabled = true
|
||||
sendFragment.sendBtn.setState(ProgressState.None(), true)
|
||||
}
|
||||
SendButtonState.DISABLED -> {
|
||||
fg.btnSend.isEnabled = false
|
||||
sendFragment.sendBtn.setState(ProgressState.None(), true)
|
||||
}
|
||||
SendButtonState.PROGRESS -> {
|
||||
fg.btnSend.isEnabled = true
|
||||
sendFragment.sendBtn.setState(ProgressState.Progress(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAddressPayIdState(fg: BaseStoreFragment, state: AddressPayIdState) {
|
||||
|
|
@ -58,6 +77,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
return if (resId == null) null
|
||||
else context.getString(resId)
|
||||
}
|
||||
fg.imvPaste.isEnabled = state.pasteIsEnabled
|
||||
|
||||
val et = fg.etAddressOrPayId
|
||||
val til = fg.tilAddressOrPayId
|
||||
|
|
@ -91,22 +111,25 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
}
|
||||
}
|
||||
|
||||
fg.etAmountToSend.filters = arrayOf(DecimalDigitsInputFilter(12, state.maxLengthOfAmount))
|
||||
val amountToSend = state.viewAmountValue
|
||||
fg.tvAmountToSendShadow.text = amountToSend
|
||||
if (amountToSend.length > 10) {
|
||||
// post is needed to wait for text size changes
|
||||
fg.tvAmountToSendShadow.post {
|
||||
fg.etAmountToSend.setTextSize(TypedValue.COMPLEX_UNIT_PX, fg.tvAmountToSendShadow.textSize - 2)
|
||||
fg.etAmountToSend.update(amountToSend)
|
||||
if (!state.cursorAtTheSamePosition) fg.etAmountToSend.setSelection(amountToSend.length)
|
||||
}
|
||||
} else {
|
||||
val textSize = fg.resources.getDimension(R.dimen.text_size_amount_to_send)
|
||||
fg.tvAmountToSendShadow.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
|
||||
fg.etAmountToSend.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
|
||||
fg.etAmountToSend.update(amountToSend)
|
||||
if (!state.cursorAtTheSamePosition) fg.etAmountToSend.setSelection(amountToSend.length)
|
||||
}
|
||||
fg.etAmountToSend.update(amountToSend)
|
||||
|
||||
// fg.tvAmountToSendShadow.text = amountToSend
|
||||
// if (amountToSend.length > 10) {
|
||||
// post is needed to wait for text size changes
|
||||
// fg.tvAmountToSendShadow.post {
|
||||
// fg.etAmountToSend.setTextSize(TypedValue.COMPLEX_UNIT_PX, fg.tvAmountToSendShadow.textSize - 2)
|
||||
// fg.etAmountToSend.update(amountToSend)
|
||||
// if (!state.cursorAtTheSamePosition) fg.etAmountToSend.setSelection(amountToSend.length)
|
||||
// }
|
||||
// } else {
|
||||
// val textSize = fg.resources.getDimension(R.dimen.text_size_amount_to_send)
|
||||
// fg.tvAmountToSendShadow.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
|
||||
// fg.etAmountToSend.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
|
||||
// fg.etAmountToSend.update(amountToSend)
|
||||
// if (!state.cursorAtTheSamePosition) fg.etAmountToSend.setSelection(amountToSend.length)
|
||||
// }
|
||||
|
||||
fg.tvAmountCurrency.update(state.mainCurrency.displayedValue)
|
||||
(fg as? SendFragment)?.saveMainCurrency(state.mainCurrency.value)
|
||||
|
|
@ -159,22 +182,21 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
val totalTokenLayout = fg.flTotalTokenCrypto as ViewGroup
|
||||
fun getString(id: Int): String = mainLayout.context.getString(id)
|
||||
|
||||
mainLayout.show(state.mainLayoutIsVisible)
|
||||
when (state.visibleTypeOfReceipt) {
|
||||
ReceiptLayoutType.FIAT -> {
|
||||
val receipt = state.fiat ?: return
|
||||
|
||||
totalLayout.show(true)
|
||||
totalTokenLayout.show(false)
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountFiat.toPlainString()} ${receipt.symbols.fiat}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeFiat.toPlainString()} ${receipt.symbols.fiat}")
|
||||
totalLayout.tvTotalValue.update("${receipt.totalFiat.toPlainString()} ${receipt.symbols.fiat}")
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}")
|
||||
totalLayout.tvTotalValue.update("${receipt.totalFiat} ${receipt.symbols.fiat}")
|
||||
|
||||
val willSent = SpannableStringBuilder()
|
||||
.bold { append(receipt.willSentCrypto.toPlainString()) }.append(" ")
|
||||
.bold { append(receipt.willSentCrypto) }.append(" ")
|
||||
.append(receipt.symbols.crypto).append(" ")
|
||||
.append(getString(R.string.send_total_will_be_sent))
|
||||
totalLayout.tvWillBeSentValue.update(willSent)
|
||||
totalLayout.tvWillBeSentValue.update(willSent.toString())
|
||||
|
||||
}
|
||||
ReceiptLayoutType.CRYPTO -> {
|
||||
|
|
@ -182,41 +204,41 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
|
||||
totalLayout.show(true)
|
||||
totalTokenLayout.show(false)
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountCrypto.toPlainString()} ${receipt.symbols.crypto}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeCrypto.toPlainString()} ${receipt.symbols.crypto}")
|
||||
totalLayout.tvTotalValue.update("${receipt.totalCrypto.toPlainString()} ${receipt.symbols.crypto}")
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountCrypto} ${receipt.symbols.crypto}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeCrypto} ${receipt.symbols.crypto}")
|
||||
totalLayout.tvTotalValue.update("${receipt.totalCrypto} ${receipt.symbols.crypto}")
|
||||
|
||||
val willSent = SpannableStringBuilder()
|
||||
.bold {
|
||||
append(getString(R.string.sign_rough))
|
||||
append(" ")
|
||||
append(receipt.willSentFiat.toPlainString())
|
||||
append(" ")
|
||||
append(getString(R.string.sign_rough)).append(" ")
|
||||
append(receipt.willSentFiat).append(" ")
|
||||
append(receipt.symbols.fiat)
|
||||
append(" (fee: ${receipt.feeFiat} ")
|
||||
append(receipt.symbols.fiat).append(")")
|
||||
}
|
||||
totalLayout.tvWillBeSentValue.update(willSent)
|
||||
totalLayout.tvWillBeSentValue.update(willSent.toString())
|
||||
}
|
||||
ReceiptLayoutType.TOKEN_FIAT -> {
|
||||
val receipt = state.tokenFiat ?: return
|
||||
|
||||
totalLayout.show(true)
|
||||
totalTokenLayout.show(false)
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountFiat.toPlainString()} ${receipt.symbols.fiat}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeFiat.toPlainString()} ${receipt.symbols.fiat}")
|
||||
totalLayout.tvTotalValue.update("${receipt.totalFiat.toPlainString()} ${receipt.symbols.fiat}")
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}")
|
||||
totalLayout.tvTotalValue.update("${receipt.totalFiat} ${receipt.symbols.fiat}")
|
||||
|
||||
val willSent = SpannableStringBuilder()
|
||||
.bold {
|
||||
append(receipt.symbols.token)
|
||||
append(" ")
|
||||
append(receipt.willSentFeeCrypto.toPlainString())
|
||||
append(receipt.willSentFeeCrypto)
|
||||
}.append(" ").append(getString(R.string.generic_and)).append(" ")
|
||||
.bold {
|
||||
append(receipt.symbols.crypto).append(" ")
|
||||
append(receipt.willSentFeeCrypto.toPlainString()).append(" ")
|
||||
append(receipt.willSentFeeCrypto).append(" ")
|
||||
}
|
||||
.append(mainLayout.context.getString(R.string.send_total_will_be_sent))
|
||||
totalLayout.tvWillBeSentValue.update(willSent)
|
||||
totalLayout.tvWillBeSentValue.update(willSent.toString())
|
||||
}
|
||||
ReceiptLayoutType.TOKEN_CRYPTO -> {
|
||||
val receipt = state.tokenCrypto ?: return
|
||||
|
|
@ -224,18 +246,16 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
totalLayout.show(false)
|
||||
totalTokenLayout.show(true)
|
||||
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountToken.toPlainString()} ${receipt.symbols.token}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeCrypto.toPlainString()} ${receipt.symbols.crypto}")
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountToken} ${receipt.symbols.token}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeCrypto} ${receipt.symbols.crypto}")
|
||||
|
||||
val willSent = SpannableStringBuilder()
|
||||
.bold {
|
||||
append(getString(R.string.sign_rough))
|
||||
append(" ")
|
||||
append(receipt.totalFiat.toPlainString())
|
||||
append(" ")
|
||||
append(getString(R.string.sign_rough)).append(" ")
|
||||
append(receipt.totalFiat).append(" ")
|
||||
append(receipt.symbols.fiat)
|
||||
}
|
||||
totalTokenLayout.tvTotalTokenCryptoValue.update(willSent)
|
||||
totalTokenLayout.tvTotalTokenCryptoValue.update(willSent.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue