From 60a332149e18eb956cc19322e0db476e9c7babc4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 11 Dec 2020 16:59:23 +0300 Subject: [PATCH 01/16] Updated on 2026-08-14 --- .../tap/common/GlobalLayoutStateHandler.kt | 31 +++++++++++++++++++ .../tangem/tap/common/extensions/ViewGroup.kt | 19 ++++++++++++ .../tap/features/wallet/ui/WalletFragment.kt | 6 ++-- app/src/main/res/layout/layout_address.xml | 5 ++- 4 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt diff --git a/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt b/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt new file mode 100644 index 0000000000..acbac22f31 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt @@ -0,0 +1,31 @@ +package com.tangem.tap.common + +import android.view.View +import android.view.ViewTreeObserver + +/** +[REDACTED_AUTHOR] + */ +class GlobalLayoutStateHandler( + private val view: T, + attachImmediately: Boolean = true +) : ViewTreeObserver.OnGlobalLayoutListener { + + var onStateChanged: ((T) -> Unit)? = null + + init { + if (attachImmediately) attach() + } + + fun attach() { + view.viewTreeObserver.addOnGlobalLayoutListener(this) + } + + fun detach() { + view.viewTreeObserver.removeOnGlobalLayoutListener(this) + } + + override fun onGlobalLayout() { + onStateChanged?.invoke(view) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/ViewGroup.kt b/app/src/main/java/com/tangem/tap/common/extensions/ViewGroup.kt index 54d98f110d..fb9c20bfdb 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/ViewGroup.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/ViewGroup.kt @@ -3,9 +3,13 @@ package com.tangem.tap.common.extensions import android.view.LayoutInflater import android.view.ViewGroup import android.view.ViewParent +import androidx.core.view.forEach import androidx.transition.AutoTransition import androidx.transition.Transition import androidx.transition.TransitionManager +import com.google.android.material.chip.Chip +import com.google.android.material.chip.ChipGroup +import com.tangem.tap.common.GlobalLayoutStateHandler import timber.log.Timber /** @@ -25,4 +29,19 @@ fun ViewParent?.beginDelayedTransition(transition: Transition = AutoTransition() fun ViewGroup.beginDelayedTransition(transition: Transition = AutoTransition()) { TransitionManager.beginDelayedTransition(this, transition) +} + +fun ChipGroup.fitChipsByGroupWidth() { + val layoutStateHandler = GlobalLayoutStateHandler(this) + layoutStateHandler.onStateChanged = stateHandler@{ + if (it.childCount < 2) { + layoutStateHandler.detach() + return@stateHandler + } + + val spacingBetweenViews = it.chipSpacingHorizontal * (it.childCount - 1) + val width = (it.width - spacingBetweenViews) / it.childCount + it.forEach { chip -> (chip as? Chip)?.width = width } + layoutStateHandler.detach() + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index 6e921e5b9b..4addb8b567 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -13,9 +13,7 @@ import com.google.android.material.snackbar.Snackbar import com.squareup.picasso.Picasso import com.tangem.blockchain.blockchains.bitcoin.BitcoinAddressType import com.tangem.blockchain.common.address.AddressType -import com.tangem.tap.common.extensions.beginDelayedTransition -import com.tangem.tap.common.extensions.hide -import com.tangem.tap.common.extensions.show +import com.tangem.tap.common.extensions.* import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.TwinCardNumber @@ -230,6 +228,8 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber Date: Fri, 11 Dec 2020 16:59:43 +0300 Subject: [PATCH 02/16] Updated on 2026-08-14 --- .../tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt index 087c63af7a..c68dc9f200 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt @@ -169,6 +169,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber private fun handleFeeState(fg: BaseStoreFragment, state: FeeState) { var delayedTransitionScheduled = false + fg.chipGroup.fitChipsByGroupWidth() fg.view?.findViewById(R.id.clNetworkFee)?.let { it.show(state.mainLayoutIsVisible) { (it.parent as? ViewGroup)?.beginDelayedTransition() From 89f4a5c670daa505f11db214c65f103b3e16b709 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 11 Dec 2020 17:55:26 +0300 Subject: [PATCH 03/16] Updated on 2026-08-14 --- app/src/main/assets/features_dev.json | 19 ++---- app/src/main/assets/features_prod.json | 19 ++---- .../tangem/tap/domain/config/ConfigLoader.kt | 15 ++--- .../tangem/tap/domain/config/ConfigManager.kt | 61 ++++++++----------- .../tangem/tap/domain/config/JsonModels.kt | 23 +++---- 5 files changed, 52 insertions(+), 85 deletions(-) diff --git a/app/src/main/assets/features_dev.json b/app/src/main/assets/features_dev.json index 236d0285bd..fd84b700a9 100644 --- a/app/src/main/assets/features_dev.json +++ b/app/src/main/assets/features_dev.json @@ -1,14 +1,5 @@ -[ - { - "name": "isWalletPayIdEnabled", - "value": true - }, - { - "name": "isTopUpEnabled", - "value": true - }, - { - "name": "isCreatingTwinCardsAllowed", - "value": false - } -] \ No newline at end of file +{ + "isWalletPayIdEnabled": true, + "isTopUpEnabled": true, + "isCreatingTwinCardsAllowed": false +} \ No newline at end of file diff --git a/app/src/main/assets/features_prod.json b/app/src/main/assets/features_prod.json index 39b226d053..9e06a389d0 100644 --- a/app/src/main/assets/features_prod.json +++ b/app/src/main/assets/features_prod.json @@ -1,14 +1,5 @@ -[ - { - "name": "isWalletPayIdEnabled", - "value": false - }, - { - "name": "isTopUpEnabled", - "value": false - }, - { - "name": "isCreatingTwinCardsAllowed", - "value": true - } -] \ No newline at end of file +{ + "isWalletPayIdEnabled": false, + "isTopUpEnabled": false, + "isCreatingTwinCardsAllowed": true +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/config/ConfigLoader.kt b/app/src/main/java/com/tangem/tap/domain/config/ConfigLoader.kt index 60bb343e02..725208082f 100644 --- a/app/src/main/java/com/tangem/tap/domain/config/ConfigLoader.kt +++ b/app/src/main/java/com/tangem/tap/domain/config/ConfigLoader.kt @@ -6,7 +6,6 @@ import com.google.firebase.ktx.Firebase import com.google.firebase.remoteconfig.ktx.remoteConfig import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi -import com.squareup.moshi.Types import com.tangem.wallet.BuildConfig import timber.log.Timber @@ -30,16 +29,13 @@ class LocalLoader( override fun loadConfig(onComplete: (ConfigModel) -> Unit) { val config = try { - val featureType = Types.newParameterizedType(List::class.java, FeatureModel::class.java) - val featureAdapter: JsonAdapter> = moshi.adapter(featureType) - val valuesType = Types.newParameterizedType(List::class.java, ConfigValueModel::class.java) - val valuesAdapter: JsonAdapter> = moshi.adapter(valuesType) + val featureAdapter: JsonAdapter = moshi.adapter(FeatureModel::class.java) + val valuesAdapter: JsonAdapter = moshi.adapter(ConfigValueModel::class.java) val jsonFeatures = readAssetAsString(ConfigLoader.featuresName) val jsonConfigValues = readAssetAsString(ConfigLoader.configValuesName) - ConfigModel(featureAdapter.fromJson(jsonFeatures) ?: listOf(), - valuesAdapter.fromJson(jsonConfigValues) ?: listOf()) + ConfigModel(featureAdapter.fromJson(jsonFeatures), valuesAdapter.fromJson(jsonConfigValues)) } catch (ex: Exception) { Timber.e(ex) ConfigModel.empty() @@ -67,9 +63,8 @@ class RemoteLoader( onComplete(emptyConfig) return@addOnCompleteListener } - val featureType = Types.newParameterizedType(List::class.java, FeatureModel::class.java) - val featureAdapter: JsonAdapter> = moshi.adapter(featureType) - onComplete(ConfigModel(featureAdapter.fromJson(jsonConfig) ?: listOf(), listOf())) + val featureAdapter: JsonAdapter = moshi.adapter(FeatureModel::class.java) + onComplete(ConfigModel(featureAdapter.fromJson(jsonConfig), null)) } else { onComplete(emptyConfig) } diff --git a/app/src/main/java/com/tangem/tap/domain/config/ConfigManager.kt b/app/src/main/java/com/tangem/tap/domain/config/ConfigManager.kt index 49a2af61f1..75d02fd80b 100644 --- a/app/src/main/java/com/tangem/tap/domain/config/ConfigManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/config/ConfigManager.kt @@ -26,11 +26,11 @@ class ConfigManager( fun load(onComplete: VoidCallback? = null) { localLoader.loadConfig { config -> - config.features?.forEach { setupFeature(it.name, it.value) } - config.configValues?.forEach { setupKey(it.name, it.value) } + setupFeature(config.features) + setupKey(config.configValues) } remoteLoader.loadConfig { config -> - config.features?.forEach { setupFeature(it.name, it.value) } + setupFeature(config.features) onComplete?.invoke() } } @@ -52,40 +52,33 @@ class ConfigManager( } } - private fun setupFeature(name: String, value: Boolean) { - val newValue = value ?: return + private fun setupFeature(featureModel: FeatureModel?) { + val model = featureModel ?: return - when (name) { - isWalletPayIdEnabled -> { - config = config.copy(isWalletPayIdEnabled = newValue) - defaultConfig = defaultConfig.copy(isWalletPayIdEnabled = newValue) - } - isTopUpEnabled -> { - config = config.copy(isTopUpEnabled = newValue) - defaultConfig = defaultConfig.copy(isTopUpEnabled = newValue) - } - isCreatingTwinCardsAllowed -> { - config = config.copy(isCreatingTwinCardsAllowed = newValue) - defaultConfig = defaultConfig.copy(isCreatingTwinCardsAllowed = newValue) - } - } + config = config.copy( + isWalletPayIdEnabled = model.isWalletPayIdEnabled, + isTopUpEnabled = model.isTopUpEnabled, + isCreatingTwinCardsAllowed = model.isCreatingTwinCardsAllowed + ) + defaultConfig = defaultConfig.copy( + isWalletPayIdEnabled = model.isWalletPayIdEnabled, + isTopUpEnabled = model.isTopUpEnabled, + isCreatingTwinCardsAllowed = model.isCreatingTwinCardsAllowed + ) } - private fun setupKey(name: String, value: String) { - when (name) { - coinMarketCapKey -> { - config = config.copy(coinMarketCapKey = value) - defaultConfig = defaultConfig.copy(coinMarketCapKey = value) - } - moonPayApiKey -> { - config = config.copy(moonPayApiKey = value) - defaultConfig = defaultConfig.copy(moonPayApiKey = value) - } - moonPayApiSecretKey -> { - config = config.copy(moonPayApiSecretKey = value) - defaultConfig = defaultConfig.copy(moonPayApiSecretKey = value) - } - } + private fun setupKey(configValues: ConfigValueModel?) { + val values = configValues ?: return + config = config.copy( + coinMarketCapKey = values.coinMarketCapKey, + moonPayApiKey = values.moonPayApiKey, + moonPayApiSecretKey = values.moonPayApiSecretKey + ) + defaultConfig = defaultConfig.copy( + coinMarketCapKey = values.coinMarketCapKey, + moonPayApiKey = values.moonPayApiKey, + moonPayApiSecretKey = values.moonPayApiSecretKey + ) } companion object { diff --git a/app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt b/app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt index 1b7272765b..e5c5bc44fb 100644 --- a/app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt +++ b/app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt @@ -4,23 +4,20 @@ package com.tangem.tap.domain.config [REDACTED_AUTHOR] */ -interface BaseConfigModel { - val name: String - val value: V? -} - class FeatureModel( - override val name: String, - override val value: Boolean -) : BaseConfigModel + val isWalletPayIdEnabled: Boolean, + val isTopUpEnabled: Boolean, + val isCreatingTwinCardsAllowed: Boolean, +) class ConfigValueModel( - override val name: String, - override val value: String -) : BaseConfigModel + val coinMarketCapKey: String, + val moonPayApiKey: String, + val moonPayApiSecretKey: String, +) -class ConfigModel(val features: List?, val configValues: List?) { +class ConfigModel(val features: FeatureModel?, val configValues: ConfigValueModel?) { companion object { - fun empty(): ConfigModel = ConfigModel(listOf(), listOf()) + fun empty(): ConfigModel = ConfigModel(null, null) } } \ No newline at end of file From f2697b357ddbaafef63d5f9473f9b273def2ae6a Mon Sep 17 00:00:00 2001 From: Tangem Date: Sun, 13 Dec 2020 16:06:02 +0300 Subject: [PATCH 04/16] Updated on 2026-08-14 --- .../com/tangem/tap/common/GlobalLayoutStateHandler.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt b/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt index acbac22f31..af4645f141 100644 --- a/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt @@ -2,6 +2,7 @@ package com.tangem.tap.common import android.view.View import android.view.ViewTreeObserver +import timber.log.Timber /** [REDACTED_AUTHOR] @@ -13,16 +14,25 @@ class GlobalLayoutStateHandler( var onStateChanged: ((T) -> Unit)? = null + private var isAttached: Boolean = false + init { if (attachImmediately) attach() } fun attach() { + if (isAttached) { + Timber.d("Already attached") + return + } + + isAttached = true view.viewTreeObserver.addOnGlobalLayoutListener(this) } fun detach() { view.viewTreeObserver.removeOnGlobalLayoutListener(this) + isAttached = false } override fun onGlobalLayout() { From 9a4529cbdb423dbad716fb84a26bcdc01e4411f2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 14 Dec 2020 14:07:43 +0300 Subject: [PATCH 05/16] Updated on 2026-08-14 --- .../java/com/tangem/tap/features/wallet/redux/WalletState.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index 7593182093..36106df1a6 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -35,7 +35,8 @@ data class WalletState( val showSegwitAddress: Boolean get() { val listOfAddresses = walletAddresses?.list ?: return false - return wallet?.blockchain == Blockchain.Bitcoin && listOfAddresses.size > 1 + return (wallet?.blockchain == Blockchain.Bitcoin || wallet?.blockchain == Blockchain.BitcoinTestnet) + && listOfAddresses.size > 1 } } From edecedf446002e0fb3bd1359aaf57a6054c3ba4b Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 14 Dec 2020 17:34:52 +0300 Subject: [PATCH 06/16] Updated on 2026-08-14 --- .../send/redux/middlewares/RequestFeeMiddleware.kt | 8 +++----- .../features/send/redux/middlewares/SendMiddleware.kt | 10 +++++----- .../send/redux/reducers/AddressPayIdReducer.kt | 8 ++++---- .../features/send/redux/states/AddressPayIdState.kt | 6 +++--- .../send/ui/stateSubscribers/SendStateSubscriber.kt | 2 +- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt index 2b662e5852..49b02cfea8 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt @@ -33,15 +33,13 @@ class RequestFeeMiddleware { dispatch(SendAction.ChangeSendButtonState(sendState.getButtonState())) return } - val typedAmount = sendState.amountState.amountToExtract ?: return - val recipientAddress = sendState.addressPayIdState.recipientWalletAddress!! - val cryptoSendToRecipient = sendState.amountState.amountToSendCrypto - val recipientAmount = Amount(typedAmount, cryptoSendToRecipient) + val destinationAddress = sendState.addressPayIdState.destinationWalletAddress!! + val destinationAmount = Amount(typedAmount, sendState.amountState.amountToSendCrypto) val txSender = walletManager as TransactionSender scope.launch { - val feeResult = txSender.getFee(recipientAmount, recipientAddress) + val feeResult = txSender.getFee(destinationAmount, destinationAddress) withContext(Dispatchers.Main) { when (feeResult) { is Result.Success -> { diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt index 1c7db4b842..9c61d7dab9 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt @@ -51,7 +51,7 @@ private fun verifyAndSendTransaction( val sendState = appState?.sendState ?: return val walletManager = appState.globalState.scanNoteResponse?.walletManager ?: return val card = appState.globalState.scanNoteResponse.card - val recipientAddress = sendState.addressPayIdState.recipientWalletAddress ?: return + val destinationAddress = sendState.addressPayIdState.destinationWalletAddress ?: return val typedAmount = sendState.amountState.amountToExtract ?: return val feeAmount = sendState.feeState.currentFee ?: return @@ -66,14 +66,14 @@ private fun verifyAndSendTransaction( dispatch(AmountAction.SetAmount(typedAmount.value!!.minus(reduceAmount), false)) dispatch(AmountActionUi.CheckAmountToSend) }, sendAllCallback = { - sendTransaction(action, walletManager, amountToSend, feeAmount, recipientAddress, card, dispatch) + sendTransaction(action, walletManager, amountToSend, feeAmount, destinationAddress, card, dispatch) }, reduceAmount)) } transactionErrors.isNotEmpty() -> { dispatch(SendAction.SendError(createValidateTransactionError(transactionErrors, walletManager))) } else -> { - sendTransaction(action, walletManager, amountToSend, feeAmount, recipientAddress, card, dispatch) + sendTransaction(action, walletManager, amountToSend, feeAmount, destinationAddress, card, dispatch) } } } @@ -83,12 +83,12 @@ private fun sendTransaction( walletManager: WalletManager, amountToSend: Amount, feeAmount: Amount, - recipientAddress: String, + destinationAddress: String, card: Card, dispatch: (Action) -> Unit ) { dispatch(SendAction.ChangeSendButtonState(SendButtonState.PROGRESS)) - val txData = walletManager.createTransaction(amountToSend, feeAmount, recipientAddress) + val txData = walletManager.createTransaction(amountToSend, feeAmount, destinationAddress) scope.launch { walletManager.update() val isLinkedTerminal = tangemSdk.config.linkedTerminal diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AddressPayIdReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AddressPayIdReducer.kt index d7a1c97f10..3402e48d71 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AddressPayIdReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/AddressPayIdReducer.kt @@ -42,7 +42,7 @@ class AddressPayIdReducer : SendInternalReducer { viewFieldValue = InputViewValue(action.payId, action.isUserInput), normalFieldValue = action.payId, truncatedFieldValue = state.truncate(action.payId), - recipientWalletAddress = action.payIdWalletAddress, + destinationWalletAddress = action.payIdWalletAddress, error = null ) } @@ -51,13 +51,13 @@ class AddressPayIdReducer : SendInternalReducer { viewFieldValue = InputViewValue(action.address, action.isUserInput), normalFieldValue = action.address, truncatedFieldValue = state.truncate(action.address), - recipientWalletAddress = action.address, + destinationWalletAddress = action.address, error = null ) } is AddressPayIdVerifyAction.ChangePasteBtnEnableState -> state.copy(pasteIsEnabled = action.isEnabled) - is AddressVerification.SetAddressError -> state.copy(error = action.error, recipientWalletAddress = null) - is PayIdVerification.SetPayIdError -> state.copy(error = action.error, recipientWalletAddress = null) + is AddressVerification.SetAddressError -> state.copy(error = action.error, destinationWalletAddress = null) + is PayIdVerification.SetPayIdError -> state.copy(error = action.error, destinationWalletAddress = null) } return updateLastState(sendState.copy(addressPayIdState = result), result) } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt index b7a1622789..9307694212 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt @@ -6,7 +6,7 @@ data class AddressPayIdState( val viewFieldValue: InputViewValue = InputViewValue(""), val normalFieldValue: String? = null, val truncatedFieldValue: String? = null, - val recipientWalletAddress: String? = null, + val destinationWalletAddress: String? = null, val error: AddressPayIdVerifyAction.Error? = null, val truncateHandler: ((String) -> String)? = null, val walletPayIdEnabled: Boolean = false, @@ -17,7 +17,7 @@ data class AddressPayIdState( fun truncate(value: String): String = truncateHandler?.invoke(value) ?: value - fun isReady(): Boolean = error == null && recipientWalletAddress?.isNotEmpty() ?: false + fun isReady(): Boolean = error == null && destinationWalletAddress?.isNotEmpty() ?: false - fun isPayIdState(): Boolean = recipientWalletAddress != null && recipientWalletAddress != normalFieldValue + fun isPayIdState(): Boolean = destinationWalletAddress != null && destinationWalletAddress != normalFieldValue } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt index c68dc9f200..07ddffa598 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt @@ -113,7 +113,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber til.parent?.parent?.beginDelayedTransition() til.error = parsedError til.isErrorEnabled = parsedError != null - til.helperText = state.recipientWalletAddress + til.helperText = state.destinationWalletAddress til.isHelperTextEnabled = state.isPayIdState() && parsedError == null if (!state.viewFieldValue.isFromUserInput) et.update(state.viewFieldValue.value) From d07ea21d771363763530be807a56742fae3d9976 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 16 Dec 2020 22:54:00 +0300 Subject: [PATCH 07/16] Updated on 2026-08-14 --- .../features/send/redux/SendScreenAction.kt | 24 +- .../middlewares/AddressPayIdMiddleware.kt | 11 +- .../send/redux/middlewares/SendMiddleware.kt | 16 +- .../send/redux/reducers/SendScreenReducer.kt | 1 + .../reducers/TransactionExtrasReducer.kt | 105 ++++++++ .../send/redux/states/AddressPayIdState.kt | 33 ++- .../features/send/redux/states/SendState.kt | 3 +- .../tap/features/send/ui/SendFragment.kt | 53 ++++- .../stateSubscribers/SendStateSubscriber.kt | 50 ++-- .../tap/network/payid/PayIdVerifyApi.kt | 4 +- app/src/main/res/layout/fragment_send.xml | 1 + .../res/layout/layout_send_address_payid.xml | 225 ++++++++++++++---- .../main/res/values/strings_untranslated.xml | 3 + 13 files changed, 441 insertions(+), 88 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt index e54f0f07dc..6cbe7787d9 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.send.redux import com.tangem.Message import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.Blockchain import com.tangem.tap.common.redux.ErrorAction import com.tangem.tap.common.redux.ToastNotificationAction import com.tangem.tap.domain.TapError @@ -33,7 +34,27 @@ sealed class AddressPayIdActionUi : SendScreenActionUi { object CheckAddressPayId : AddressPayIdActionUi() data class SetTruncateHandler(val handler: (String) -> String) : AddressPayIdActionUi() data class TruncateOrRestore(val truncate: Boolean) : AddressPayIdActionUi() - data class ChangePayIdState(val walletPayIdEnabled: Boolean): AddressPayIdActionUi() + data class ChangePayIdState(val walletPayIdEnabled: Boolean) : AddressPayIdActionUi() +} + + +sealed class TransactionExtrasAction : SendScreenActionUi { + data class Prepare( + val blockchain: Blockchain, + val walletAddress: String, + val xrpTag: String?, + ) : TransactionExtrasAction() + + object Release : TransactionExtrasAction() + + sealed class XlmMemo : TransactionExtrasAction() { +// data class ChangeSelectedMemo(val memoType: XlmMemoType) : XlmMemo() + data class HandleUserInput(val data: String) : XlmMemo() + } + + sealed class XrpDestinationTag : TransactionExtrasAction() { + data class HandleUserInput(val data: String) : XrpDestinationTag() + } } sealed class AddressPayIdVerifyAction : SendScreenAction { @@ -122,6 +143,7 @@ sealed class SendAction : SendScreenAction { val sendAllCallback: () -> Unit, val reduceAmount: BigDecimal, ) : Dialog() + object Hide : Dialog() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AddressPayIdMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AddressPayIdMiddleware.kt index 74fdac0d5d..d82a747a4c 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AddressPayIdMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/AddressPayIdMiddleware.kt @@ -13,6 +13,7 @@ import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction.Error import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction.PayIdVerification.SetPayIdError import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction.PayIdVerification.SetPayIdWalletAddress import com.tangem.tap.features.send.redux.FeeAction +import com.tangem.tap.features.send.redux.TransactionExtrasAction import com.tangem.tap.scope import com.tangem.tap.store import kotlinx.coroutines.Dispatchers @@ -82,22 +83,26 @@ internal class AddressPayIdMiddleware { withContext(Dispatchers.Main) { when (result) { is Result.Success -> { - val address = result.data.getAddress() - if (address == null) { + val addressDetails = result.data.getAddressDetails() + if (addressDetails == null) { dispatch(SetPayIdError(Error.PAY_ID_NOT_REGISTERED)) return@withContext } + val address = addressDetails.address val failReason = isValidBlockchainAddressAndNotTheSameAsWallet(wallet, address) if (failReason == null) { dispatch(SetPayIdWalletAddress(payId, address, isUserInput)) + dispatch(TransactionExtrasAction.Prepare(wallet.blockchain, address, addressDetails.tag)) dispatch(FeeAction.RequestFee) } else { dispatch(SetAddressError(failReason)) + dispatch(TransactionExtrasAction.Release) } } is Result.Failure -> { dispatch(SetPayIdError(Error.PAY_ID_REQUEST_FAILED)) + dispatch(TransactionExtrasAction.Release) } } } @@ -110,8 +115,10 @@ internal class AddressPayIdMiddleware { val failReason = isValidBlockchainAddressAndNotTheSameAsWallet(wallet, supposedAddress) if (failReason == null) { dispatch(SetWalletAddress(supposedAddress, isUserInput)) + dispatch(TransactionExtrasAction.Prepare(wallet.blockchain, address, null)) } else { dispatch(SetAddressError(failReason)) + dispatch(TransactionExtrasAction.Release) } } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt index 9c61d7dab9..52735189af 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt @@ -1,6 +1,8 @@ package com.tangem.tap.features.send.redux.middlewares import com.google.firebase.crashlytics.FirebaseCrashlytics +import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras +import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder import com.tangem.blockchain.common.* import com.tangem.blockchain.extensions.Result import com.tangem.blockchain.extensions.Signer @@ -17,6 +19,7 @@ import com.tangem.tap.domain.extensions.minimalAmount import com.tangem.tap.features.send.redux.* import com.tangem.tap.features.send.redux.FeeAction.RequestFee import com.tangem.tap.features.send.redux.states.SendButtonState +import com.tangem.tap.features.send.redux.states.TransactionExtrasState import com.tangem.tap.scope import com.tangem.tap.tangemSdk import kotlinx.coroutines.Dispatchers @@ -66,14 +69,16 @@ private fun verifyAndSendTransaction( dispatch(AmountAction.SetAmount(typedAmount.value!!.minus(reduceAmount), false)) dispatch(AmountActionUi.CheckAmountToSend) }, sendAllCallback = { - sendTransaction(action, walletManager, amountToSend, feeAmount, destinationAddress, card, dispatch) + sendTransaction(action, walletManager, amountToSend, feeAmount, destinationAddress, + sendState.transactionExtrasState, card, dispatch) }, reduceAmount)) } transactionErrors.isNotEmpty() -> { dispatch(SendAction.SendError(createValidateTransactionError(transactionErrors, walletManager))) } else -> { - sendTransaction(action, walletManager, amountToSend, feeAmount, destinationAddress, card, dispatch) + sendTransaction(action, walletManager, amountToSend, feeAmount, destinationAddress, + sendState.transactionExtrasState, card, dispatch) } } } @@ -84,11 +89,16 @@ private fun sendTransaction( amountToSend: Amount, feeAmount: Amount, destinationAddress: String, + transactionExtras: TransactionExtrasState, card: Card, dispatch: (Action) -> Unit ) { dispatch(SendAction.ChangeSendButtonState(SendButtonState.PROGRESS)) - val txData = walletManager.createTransaction(amountToSend, feeAmount, destinationAddress) + var txData = walletManager.createTransaction(amountToSend, feeAmount, destinationAddress) + + transactionExtras.xlmMemo?.memo?.let { txData = txData.copy(extras = StellarTransactionExtras(it)) } + transactionExtras.xrpDestinationTag?.tag?.let { txData = txData.copy(extras = XrpTransactionBuilder.XrpTransactionExtras(it)) } + scope.launch { walletManager.update() val isLinkedTerminal = tangemSdk.config.linkedTerminal diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt index e7454abcc1..16da618931 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt @@ -25,6 +25,7 @@ class SendScreenReducer { val reducer: SendInternalReducer = when (action) { is PrepareSendScreen -> PrepareSendScreenStatesReducer() is AddressPayIdActionUi, is AddressPayIdVerifyAction -> AddressPayIdReducer() + is TransactionExtrasAction -> TransactionExtrasReducer() is AmountActionUi, is AmountAction -> AmountReducer() is FeeActionUi, is FeeAction -> FeeReducer() is ReceiptAction -> ReceiptReducer() diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt new file mode 100644 index 0000000000..7688e47496 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt @@ -0,0 +1,105 @@ +package com.tangem.tap.features.send.redux.reducers + +import com.tangem.blockchain.blockchains.stellar.StellarMemo +import com.tangem.blockchain.common.Blockchain +import com.tangem.tap.features.send.redux.SendScreenAction +import com.tangem.tap.features.send.redux.TransactionExtrasAction.* +import com.tangem.tap.features.send.redux.states.* + +/** +[REDACTED_AUTHOR] + */ +class TransactionExtrasReducer : SendInternalReducer { + override fun handle(action: SendScreenAction, sendState: SendState): SendState { + return when (action) { + is Prepare -> handleInitialization(action, sendState) + Release -> handleRelease(action, sendState) + is XlmMemo -> handleMemo(action, sendState, sendState.transactionExtrasState) + is XrpDestinationTag -> handleXrpTag(action, sendState, sendState.transactionExtrasState) + else -> sendState + } + } + + private fun handleInitialization(action: Prepare, sendState: SendState): SendState { + val emptyResult = TransactionExtrasState() + val result = when (action.blockchain) { + Blockchain.XRP -> { + // 'r' - without tag, 'x' - with tag + if (action.walletAddress.startsWith("r", true)) { + val tag = action.xrpTag?.toLongOrNull() + if (tag == null) { + TransactionExtrasState(xrpDestinationTag = XrpDestinationTagState()) + } else { + TransactionExtrasState(xrpDestinationTag = XrpDestinationTagState( + InputViewValue("$tag", false), tag) + ) + } + } else { + emptyResult + } + } + Blockchain.Stellar -> TransactionExtrasState(xlmMemo = XlmMemoState()) + else -> emptyResult + } + return updateLastState(sendState.copy(transactionExtrasState = result), result) + } + + private fun handleRelease(action: SendScreenAction, sendState: SendState): SendState { + val result = TransactionExtrasState() + return updateLastState(sendState.copy(transactionExtrasState = result), result) + } + + private fun handleMemo( + action: XlmMemo, + sendState: SendState, + infoState: TransactionExtrasState, + ): SendState { + fun clearMemo(memo: XlmMemoState): XlmMemoState = memo.copy(text = null, id = null) + + val result = when (action) { +// is XlmMemo.ChangeSelectedMemo -> { +// val inputViewValue = InputViewValue("", false) +// val memo = infoState.xlmMemo?.copy( +// viewFieldValue = inputViewValue, +// selectedMemoType = action.memoType, +// ) ?: XlmMemoState(inputViewValue, action.memoType) +// +// infoState.copy(xlmMemo = clearMemo(memo)) +// } + is XlmMemo.HandleUserInput -> { + val inputViewValue = InputViewValue(action.data, true) + var memo = infoState.xlmMemo?.copy(viewFieldValue = inputViewValue) ?: XlmMemoState(inputViewValue) + memo = clearMemo(memo) + memo = when (infoState.xlmMemo?.selectedMemoType) { + XlmMemoType.TEXT -> memo.copy(text = StellarMemo.Text(action.data)) + XlmMemoType.ID -> { + val id = action.data.toIntOrNull()?.toBigInteger() + if (id != null) memo.copy(id = StellarMemo.Id(id)) else memo + } + null -> memo + } + infoState.copy(xlmMemo = memo) + } + } + return updateLastState(sendState.copy(transactionExtrasState = result), result) + } + + private fun handleXrpTag( + action: XrpDestinationTag, + sendState: SendState, + infoState: TransactionExtrasState, + ): SendState { + val result = when (action) { + is XrpDestinationTag.HandleUserInput -> { + val tag = action.data.toLongOrNull() + if (tag != null) { + val tagState = XrpDestinationTagState(InputViewValue(action.data, true), tag) + infoState.copy(xrpDestinationTag = tagState) + } else { + infoState + } + } + } + return updateLastState(sendState.copy(transactionExtrasState = result), result) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt index 9307694212..8bc5d09bc3 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt @@ -1,5 +1,6 @@ package com.tangem.tap.features.send.redux.states +import com.tangem.blockchain.blockchains.stellar.StellarMemo import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction data class AddressPayIdState( @@ -20,4 +21,34 @@ data class AddressPayIdState( fun isReady(): Boolean = error == null && destinationWalletAddress?.isNotEmpty() ?: false fun isPayIdState(): Boolean = destinationWalletAddress != null && destinationWalletAddress != normalFieldValue -} \ No newline at end of file +} + +data class TransactionExtrasState( + val xlmMemo: XlmMemoState? = null, + val xrpDestinationTag: XrpDestinationTagState? = null +) : IdStateHolder { + override val stateId: StateId = StateId.ADDRESS_EXTRAS +} + +enum class XlmMemoType { + TEXT, ID +} + +data class XlmMemoState( + val viewFieldValue: InputViewValue = InputViewValue(""), + val selectedMemoType: XlmMemoType = XlmMemoType.ID, + val text: StellarMemo.Text? = null, + val id: StellarMemo.Id? = null, +) { + val memo: StellarMemo? + get() = when (selectedMemoType) { + XlmMemoType.TEXT -> text + XlmMemoType.ID -> id + } +} + +// tag must contains only digits +data class XrpDestinationTagState( + val viewFieldValue: InputViewValue = InputViewValue(""), + val tag: Long? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt index 2e3a6e4955..026f77c213 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt @@ -22,7 +22,7 @@ interface IdStateHolder { } enum class StateId { - SEND_SCREEN, ADDRESS_PAY_ID, AMOUNT, FEE, RECEIPT + SEND_SCREEN, ADDRESS_PAY_ID, ADDRESS_EXTRAS, AMOUNT, FEE, RECEIPT } interface SendScreenState : StateType, IdStateHolder @@ -33,6 +33,7 @@ data class SendState( val tokenConverter: CurrencyConverter? = null, val lastChangedStates: LinkedHashSet = linkedSetOf(), val addressPayIdState: AddressPayIdState = AddressPayIdState(), + val transactionExtrasState: TransactionExtrasState = TransactionExtrasState(), val amountState: AmountState = AmountState(), val feeState: FeeState = FeeState(), val receiptState: ReceiptState = ReceiptState(), diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt index 9714886b7b..874e744207 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt @@ -67,6 +67,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { initSendButtonStates() setupAddressOrPayIdLayout() + setupTransactionExtrasLayout() setupAmountLayout() setupFeeLayout() @@ -106,6 +107,32 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { } } + private fun setupTransactionExtrasLayout() { + etMemo.inputtedTextAsFlow() + .debounce(400) + .filter { + val info = store.state.sendState.transactionExtrasState + info.xlmMemo?.viewFieldValue?.value != it + } + .onEach { store.dispatch(TransactionExtrasAction.XlmMemo.HandleUserInput(it)) } + .launchIn(mainScope) + +// groupMemo.setOnCheckedChangeListener { group, checkedId -> +// if (checkedId == -1) return@setOnCheckedChangeListener +// +// store.dispatch(TransactionExtrasAction.XlmMemo.ChangeSelectedMemo(MemoUiHelper.toType(checkedId))) +// } + + etDestinationTag.inputtedTextAsFlow() + .debounce(400) + .filter { + val info = store.state.sendState.transactionExtrasState + info.xrpDestinationTag?.viewFieldValue?.value != it + } + .onEach { store.dispatch(TransactionExtrasAction.XrpDestinationTag.HandleUserInput(it)) } + .launchIn(mainScope) + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode != ScanQrCodeActivity.SCAN_QR_REQUEST_CODE) return @@ -191,7 +218,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { chipGroup.setOnCheckedChangeListener { group, checkedId -> if (checkedId == -1) return@setOnCheckedChangeListener - store.dispatch(ChangeSelectedFee(FeeUiHelper.idToFee(checkedId))) + store.dispatch(ChangeSelectedFee(FeeUiHelper.toType(checkedId))) store.dispatch(CheckAmountToSend) } swIncludeFee.setOnCheckedChangeListener { btn, isChecked -> @@ -238,7 +265,7 @@ fun EditText.inputtedTextAsFlow(): Flow = callbackFlow { class FeeUiHelper { companion object { - fun feeToId(fee: FeeType): Int { + fun toId(fee: FeeType): Int { return when (fee) { FeeType.SINGLE -> View.NO_ID FeeType.LOW -> R.id.chipLow @@ -247,7 +274,7 @@ class FeeUiHelper { } } - fun idToFee(id: Int): FeeType { + fun toType(id: Int): FeeType { return when (id) { R.id.chipLow -> FeeType.LOW R.id.chipNormal -> FeeType.NORMAL @@ -258,6 +285,26 @@ class FeeUiHelper { } } + +//class MemoUiHelper { +// companion object { +// fun toId(memo: MemoType): Int { +// return when (memo) { +// MemoType.TEXT -> R.id.chipMemoText +// MemoType.ID -> R.id.chipMemoId +// } +// } +// +// fun toType(id: Int): MemoType { +// return when (id) { +// R.id.chipMemoText -> MemoType.TEXT +// R.id.chipMemoId -> MemoType.ID +// else -> MemoType.TEXT +// } +// } +// } +//} + private fun ToggleWidget.setupSendButtonStateModifiers(context: Context) { mainViewModifiers.clear() mainViewModifiers.add(ReplaceTextStateModifier(context.getString(R.string.send_title), "")) diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt index 07ddffa598..da81ad52c5 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.send.ui.stateSubscribers import android.app.Dialog import android.content.Context +import android.text.InputType import android.text.SpannableStringBuilder import android.view.View import android.view.ViewGroup @@ -43,10 +44,12 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber override fun updateWithNewState(fg: BaseStoreFragment, state: SendState) { val lastChangedStates = state.lastChangedStates.toList() state.lastChangedStates.clear() + fg.main_send_container.beginDelayedTransition() lastChangedStates.forEach { when (it) { StateId.SEND_SCREEN -> handleSendScreen(fg, state) StateId.ADDRESS_PAY_ID -> handleAddressPayIdState(fg, state.addressPayIdState) + StateId.ADDRESS_EXTRAS -> handleTransactionExtrasState(fg, state.transactionExtrasState) StateId.AMOUNT -> handleAmountState(fg, state.amountState) StateId.FEE -> handleFeeState(fg, state.feeState) StateId.RECEIPT -> handleReceiptState(fg, state.receiptState) @@ -54,6 +57,25 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber } } + private fun handleTransactionExtrasState(fg: BaseStoreFragment, infoState: TransactionExtrasState) { + fun showView(view: View, info: Any?) { + view.show(info != null) + } + showView(fg.xlmMemoContainer, infoState.xlmMemo) + showView(fg.xrpDestinationTagContainer, infoState.xrpDestinationTag) + + infoState.xlmMemo?.let { + fg.etMemo.inputType = when (it.selectedMemoType) { + XlmMemoType.TEXT -> InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS + XlmMemoType.ID -> InputType.TYPE_CLASS_NUMBER + } + if (!it.viewFieldValue.isFromUserInput) fg.etMemo.setText(it.viewFieldValue.value) + } + infoState.xrpDestinationTag?.let { + if (!it.viewFieldValue.isFromUserInput) fg.etDestinationTag.setText(it.viewFieldValue.value) + } + } + private fun handleSendScreen(fg: BaseStoreFragment, state: SendState) { val sendFragment = (fg as? SendFragment) ?: return @@ -106,11 +128,10 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber val hintResId = if (state.walletPayIdEnabled) { R.string.send_destination_hint_address_payid - }else { + } else { R.string.send_destination_hint_address } til.hint = til.getString(hintResId) - til.parent?.parent?.beginDelayedTransition() til.error = parsedError til.isErrorEnabled = parsedError != null til.helperText = state.destinationWalletAddress @@ -130,10 +151,8 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber } else -> context.getString(state.error.localizedMessage) } - fg.amountContainer.parent?.beginDelayedTransition() fg.tilAmountToSend.enableError(true, message) } else { - if (fg.tilAmountToSend.isErrorEnabled) fg.amountContainer.parent?.beginDelayedTransition() fg.tilAmountToSend.enableError(false) } @@ -168,27 +187,12 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber } private fun handleFeeState(fg: BaseStoreFragment, state: FeeState) { - var delayedTransitionScheduled = false fg.chipGroup.fitChipsByGroupWidth() - fg.view?.findViewById(R.id.clNetworkFee)?.let { - it.show(state.mainLayoutIsVisible) { - (it.parent as? ViewGroup)?.beginDelayedTransition() - delayedTransitionScheduled = true - } - } + fg.view?.findViewById(R.id.clNetworkFee)?.show(state.mainLayoutIsVisible) fg.imvExpandCollapse.rotation = if (state.controlsLayoutIsVisible) 0f else 180f - fg.llFeeControlsContainer.show(state.controlsLayoutIsVisible) { - if (!delayedTransitionScheduled) { - fg.llFeeControlsContainer.parent?.parent?.beginDelayedTransition() - } - } - - fg.chipGroup.show(state.feeChipGroupIsVisible) { - if (!delayedTransitionScheduled) { - fg.llFeeControlsContainer.parent?.parent?.beginDelayedTransition() - } - } + fg.llFeeControlsContainer.show(state.controlsLayoutIsVisible) + fg.chipGroup.show(state.feeChipGroupIsVisible) fg.swIncludeFee.isEnabled = state.includeFeeSwitcherIsEnabled if (fg.swIncludeFee.isChecked != state.feeIsIncluded) { @@ -201,7 +205,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber } } - val chipId = FeeUiHelper.feeToId(state.selectedFeeType) + val chipId = FeeUiHelper.toId(state.selectedFeeType) if (fg.chipGroup.checkedChipId != chipId && chipId != View.NO_ID) fg.chipGroup.check(chipId) } diff --git a/app/src/main/java/com/tangem/tap/network/payid/PayIdVerifyApi.kt b/app/src/main/java/com/tangem/tap/network/payid/PayIdVerifyApi.kt index e026dd8b11..a40231aaf5 100644 --- a/app/src/main/java/com/tangem/tap/network/payid/PayIdVerifyApi.kt +++ b/app/src/main/java/com/tangem/tap/network/payid/PayIdVerifyApi.kt @@ -23,9 +23,9 @@ data class VerifyPayIdResponse( val addresses: List = mutableListOf(), val payId: String? = null, ) { - fun getAddress(): String? { + fun getAddressDetails(): PayIdAddressDetails? { return if (addresses.isEmpty()) null - else addresses[0].addressDetails.address + else addresses[0].addressDetails } } diff --git a/app/src/main/res/layout/fragment_send.xml b/app/src/main/res/layout/fragment_send.xml index fca84784bc..86ec08548b 100644 --- a/app/src/main/res/layout/fragment_send.xml +++ b/app/src/main/res/layout/fragment_send.xml @@ -33,6 +33,7 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior"> diff --git a/app/src/main/res/layout/layout_send_address_payid.xml b/app/src/main/res/layout/layout_send_address_payid.xml index 12a9d76915..00a5617a9d 100644 --- a/app/src/main/res/layout/layout_send_address_payid.xml +++ b/app/src/main/res/layout/layout_send_address_payid.xml @@ -1,76 +1,197 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + android:orientation="vertical" + android:visibility="gone" + tools:visibility="visible"> - + + + + + + + + + + + - + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + android:visibility="gone" + tools:visibility="visible"> - + - + - + - + - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings_untranslated.xml b/app/src/main/res/values/strings_untranslated.xml index dd823ac37c..46a07e670f 100644 --- a/app/src/main/res/values/strings_untranslated.xml +++ b/app/src/main/res/values/strings_untranslated.xml @@ -27,4 +27,7 @@ this wallet. Start Back + Memo + Destination tag + From 79cca95a0fbdb422ddb47b71315066ddb7aef7c0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 16 Dec 2020 22:56:05 +0300 Subject: [PATCH 08/16] Updated on 2026-08-14 --- app/src/main/java/com/tangem/tap/common/extensions/UI.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/UI.kt b/app/src/main/java/com/tangem/tap/common/extensions/UI.kt index 9491bc253a..c7bb0daf0f 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/UI.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/UI.kt @@ -5,6 +5,7 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.content.Intent +import android.content.res.Resources import android.graphics.drawable.Drawable import android.os.Build import android.text.Spannable @@ -39,6 +40,14 @@ fun View.getString(@StringRes id: Int): String { return context.getString(id) } +fun View.getResourceName(): String { + return try { + resources.getResourceEntryName(id) + } catch (ex: Resources.NotFoundException) { + "Not found" + } +} + fun View.show(show: Boolean, invokeBeforeStateChanged: (() -> Unit)? = null) { return if (show) this.show(invokeBeforeStateChanged) else this.hide(invokeBeforeStateChanged) From 87d6d1d6812320131d454e8a1450105a4dd778f7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 16 Dec 2020 22:59:23 +0300 Subject: [PATCH 09/16] Updated on 2026-08-14 --- .../tangem/tap/features/send/redux/states/AddressPayIdState.kt | 2 +- .../java/com/tangem/tap/features/send/redux/states/SendState.kt | 2 +- .../features/send/ui/stateSubscribers/SendStateSubscriber.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt index 8bc5d09bc3..52cf87c4fa 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressPayIdState.kt @@ -27,7 +27,7 @@ data class TransactionExtrasState( val xlmMemo: XlmMemoState? = null, val xrpDestinationTag: XrpDestinationTagState? = null ) : IdStateHolder { - override val stateId: StateId = StateId.ADDRESS_EXTRAS + override val stateId: StateId = StateId.TRANSACTION_EXTRAS } enum class XlmMemoType { diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt index 026f77c213..b85eb86bdc 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt @@ -22,7 +22,7 @@ interface IdStateHolder { } enum class StateId { - SEND_SCREEN, ADDRESS_PAY_ID, ADDRESS_EXTRAS, AMOUNT, FEE, RECEIPT + SEND_SCREEN, ADDRESS_PAY_ID, TRANSACTION_EXTRAS, AMOUNT, FEE, RECEIPT } interface SendScreenState : StateType, IdStateHolder diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt index da81ad52c5..439375e766 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt @@ -49,7 +49,7 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber when (it) { StateId.SEND_SCREEN -> handleSendScreen(fg, state) StateId.ADDRESS_PAY_ID -> handleAddressPayIdState(fg, state.addressPayIdState) - StateId.ADDRESS_EXTRAS -> handleTransactionExtrasState(fg, state.transactionExtrasState) + StateId.TRANSACTION_EXTRAS -> handleTransactionExtrasState(fg, state.transactionExtrasState) StateId.AMOUNT -> handleAmountState(fg, state.amountState) StateId.FEE -> handleFeeState(fg, state.feeState) StateId.RECEIPT -> handleReceiptState(fg, state.receiptState) From f1e3fe5bf35ac9da23234f690f9b1d1e7329f580 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 17 Dec 2020 12:08:05 +0300 Subject: [PATCH 10/16] Updated on 2026-08-14 --- .../tap/common/analytics/FirebaseAnalyticsHandler.kt | 10 +++++++++- .../java/com/tangem/tap/domain/config/ConfigLoader.kt | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/FirebaseAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/FirebaseAnalyticsHandler.kt index 5b468233ea..0d49728dd6 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/FirebaseAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/FirebaseAnalyticsHandler.kt @@ -6,12 +6,20 @@ import com.google.firebase.analytics.ktx.analytics import com.google.firebase.ktx.Firebase import com.tangem.commands.common.card.Card -object FirebaseAnalyticsHandler: AnalyticsHandler { +object FirebaseAnalyticsHandler : AnalyticsHandler { override fun triggerEvent(event: AnalyticsEvent, card: Card?) { Firebase.analytics .logEvent(event.event, setCardData(card)) } + fun logException(name: String, throwable: Throwable) { + Firebase.analytics.logEvent(name, bundleOf( + "message" to (throwable.message ?: "none"), + "cause_message" to (throwable.cause?.message ?: "none"), + "stack_trace" to throwable.stackTraceToString() + )) + } + private fun setCardData(card: Card?): Bundle { if (card == null) return bundleOf() return bundleOf( diff --git a/app/src/main/java/com/tangem/tap/domain/config/ConfigLoader.kt b/app/src/main/java/com/tangem/tap/domain/config/ConfigLoader.kt index 725208082f..738f7fd99f 100644 --- a/app/src/main/java/com/tangem/tap/domain/config/ConfigLoader.kt +++ b/app/src/main/java/com/tangem/tap/domain/config/ConfigLoader.kt @@ -1,11 +1,11 @@ package com.tangem.tap.domain.config import android.content.Context -import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.ktx.Firebase import com.google.firebase.remoteconfig.ktx.remoteConfig import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi +import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler import com.tangem.wallet.BuildConfig import timber.log.Timber @@ -69,7 +69,7 @@ class RemoteLoader( onComplete(emptyConfig) } }.addOnFailureListener { - FirebaseCrashlytics.getInstance().recordException(it) + FirebaseAnalyticsHandler.logException("remote_config_error", it) onComplete(emptyConfig) } } From 08f4e1c31e42b3a69d03692b20ccc974b8f38aa2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 21 Dec 2020 15:21:50 +0300 Subject: [PATCH 11/16] Updated on 2026-08-14 --- app/src/main/java/com/tangem/tap/network/Retrofit.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/network/Retrofit.kt b/app/src/main/java/com/tangem/tap/network/Retrofit.kt index 169baa076b..dd16923173 100644 --- a/app/src/main/java/com/tangem/tap/network/Retrofit.kt +++ b/app/src/main/java/com/tangem/tap/network/Retrofit.kt @@ -12,6 +12,7 @@ import retrofit2.Converter import retrofit2.Retrofit import retrofit2.converter.moshi.MoshiConverterFactory import java.math.BigDecimal +import java.util.concurrent.TimeUnit fun createRetrofitInstance( baseUrl: String, @@ -19,6 +20,7 @@ fun createRetrofitInstance( ): Retrofit { val okHttpBuilder = OkHttpClient.Builder() interceptors.forEach { okHttpBuilder.addInterceptor(it) } + addTimeOuts(okHttpBuilder) if (BuildConfig.DEBUG) okHttpBuilder.addInterceptor(createHttpLoggingInterceptor()) return Retrofit.Builder() @@ -28,6 +30,13 @@ fun createRetrofitInstance( .build() } +private fun addTimeOuts(okHttpBuilder: OkHttpClient.Builder) { + okHttpBuilder.callTimeout(1, TimeUnit.SECONDS) + okHttpBuilder.connectTimeout(20, TimeUnit.SECONDS) + okHttpBuilder.readTimeout(20, TimeUnit.SECONDS) + okHttpBuilder.writeTimeout(20, TimeUnit.SECONDS) +} + fun createMoshiConverterFactory(): Converter.Factory = MoshiConverterFactory.create(createMoshi()) fun createMoshi(): Moshi = Moshi.Builder() From c702e3367ba2023d49c53029596216f2f84d60dc Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 Jan 2021 14:32:35 +0300 Subject: [PATCH 12/16] Updated on 2026-08-14 --- app/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index aab2ec4bb8..2a198dd3cb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -71,9 +71,9 @@ dependencies { implementation 'com.google.android.material:material:1.2.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1' - implementation 'com.tangem:blockchain:1.119.0' - implementation 'com.tangem:core:1.86.0' - implementation 'com.tangem:sdk:1.86.0' + implementation 'com.tangem:blockchain:1.123.0' + implementation 'com.tangem:core:1.92.0' + implementation 'com.tangem:sdk:1.92.0' // WebView implementation "androidx.browser:browser:1.2.0" From f646e9a04825a5d844cf72930aa264c360756694 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 Jan 2021 16:18:19 +0300 Subject: [PATCH 13/16] Updated on 2026-08-14 --- app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt b/app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt index e5c5bc44fb..4724f8b2c3 100644 --- a/app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt +++ b/app/src/main/java/com/tangem/tap/domain/config/JsonModels.kt @@ -7,6 +7,7 @@ package com.tangem.tap.domain.config class FeatureModel( val isWalletPayIdEnabled: Boolean, val isTopUpEnabled: Boolean, + val isSendingToPayIdEnabled: Boolean, val isCreatingTwinCardsAllowed: Boolean, ) From f5935c7f7367bdb198a1af9119414e7036cf4600 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 Jan 2021 16:29:23 +0300 Subject: [PATCH 14/16] Updated on 2026-08-14 --- .../java/com/tangem/tap/domain/config/ConfigManager.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/config/ConfigManager.kt b/app/src/main/java/com/tangem/tap/domain/config/ConfigManager.kt index 0808870b86..c7acd653c7 100644 --- a/app/src/main/java/com/tangem/tap/domain/config/ConfigManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/config/ConfigManager.kt @@ -30,10 +30,10 @@ class ConfigManager( setupFeature(config.features) setupKey(config.configValues) } -// remoteLoader.loadConfig { config -> -// setupFeature(config.features) -// onComplete?.invoke() -// } + remoteLoader.loadConfig { config -> + setupFeature(config.features) + onComplete?.invoke() + } } fun turnOff(name: String) { From f4b9ca29b719185c1375d4ef215e18a698d7ea9b Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 12 Jan 2021 20:08:15 +0300 Subject: [PATCH 15/16] Updated on 2026-08-14 --- app/build.gradle | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 243194231d..e6b995b8dd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -71,10 +71,7 @@ dependencies { implementation 'com.google.android.material:material:1.2.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1' - implementation 'com.tangem:blockchain:1.123.0' - implementation 'com.tangem:core:1.90.0' - implementation 'com.tangem:sdk:1.90.0' - implementation 'com.tangem:blockchain:1.123.0' + implementation 'com.tangem:blockchain:1.127.0' implementation 'com.tangem:core:1.92.0' implementation 'com.tangem:sdk:1.92.0' From 1e39915bafb9a426dce4dc575ff144fd8ff7f374 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 13 Jan 2021 17:24:14 +0300 Subject: [PATCH 16/16] Updated on 2026-08-14 --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index e6b995b8dd..433a84d15c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -71,7 +71,7 @@ dependencies { implementation 'com.google.android.material:material:1.2.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1' - implementation 'com.tangem:blockchain:1.127.0' + implementation 'com.tangem:blockchain:1.128.0' implementation 'com.tangem:core:1.92.0' implementation 'com.tangem:sdk:1.92.0'