From 95855960f0bc84a29794125c11ffb14631d632d9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 22 Feb 2024 15:14:21 +0300 Subject: [PATCH 01/10] Updated on 2026-08-14 --- .../repository/DelegatedKeystoreManager.kt | 12 +++-- .../BiometricUserWalletsKeysRepository.kt | 45 +++++++++---------- gradle/dependencies.toml | 4 +- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DelegatedKeystoreManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DelegatedKeystoreManager.kt index 6073f2de68..3c548bd255 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DelegatedKeystoreManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DelegatedKeystoreManager.kt @@ -8,11 +8,15 @@ internal class DelegatedKeystoreManager( private val keystoreManagerProvider: Provider, ) : KeystoreManager { - override suspend fun authenticateAndGetKey(keyAlias: String): SecretKey? { - return keystoreManagerProvider().authenticateAndGetKey(keyAlias) + override suspend fun get(keyAlias: String): SecretKey? { + return keystoreManagerProvider().get(keyAlias) } - override suspend fun storeKey(keyAlias: String, key: SecretKey) { - keystoreManagerProvider().storeKey(keyAlias, key) + override suspend fun get(keyAliases: Collection): Map { + return keystoreManagerProvider().get(keyAliases) + } + + override suspend fun store(keyAlias: String, key: SecretKey) { + return keystoreManagerProvider().store(keyAlias, key) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt index 17c733dd35..0b06c9565f 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt @@ -81,41 +81,38 @@ internal class BiometricUserWalletsKeysRepository( } private suspend fun getAllInternal(): CompletionResult> { - return getUserWalletsIds() - .map { userWalletId -> - getEncryptionKey(userWalletId) - .doOnFailure { error -> - when (error) { - is TangemSdkError.UserCanceledAuthentication -> { - // If the user cancels biometric authentication, then cancel operation with error - return CompletionResult.Failure(error) - } - is TangemSdkError.KeystoreInvalidated -> { - // If the biometric cryptography key was invalidated, - // then delete all user wallets encryption keys and cancel operation with error - getUserWalletsIds().forEach { userWalletId -> - deleteEncryptionKey(userWalletId) - } + return catching { + val userWalletIds = getUserWalletsIds() - return CompletionResult.Failure(error) - } + getEncryptionKeys(userWalletIds) + } + .doOnFailure { error -> + when (error) { + is TangemSdkError.KeystoreInvalidated -> { + // If the biometric cryptography key was invalidated, then delete all encryption keys + getUserWalletsIds().forEach { userWalletId -> + deleteEncryptionKey(userWalletId) } } - } - .fold(listOf()) { acc, data -> - if (data != null) acc + data else acc + else -> Unit + } } } - private suspend fun getEncryptionKey(userWalletId: UserWalletId): CompletionResult { - return catching { authenticatedStorage.get(StorageKey.UserWalletEncryptionKey(userWalletId).name) } - .map { it.decodeToKey() } + private suspend fun getEncryptionKeys(userWalletsIds: List): List { + val keys = userWalletsIds.map { userWalletId -> + StorageKey.UserWalletEncryptionKey(userWalletId).name + } + + return authenticatedStorage.get(keys).mapNotNull { (_, encodedData) -> + encodedData.decodeToKey() + } } private suspend fun storeEncryptionKey(encryptionKey: UserWalletEncryptionKey): CompletionResult { return catching { authenticatedStorage.store( - key = StorageKey.UserWalletEncryptionKey(encryptionKey.walletId).name, + keyAlias = StorageKey.UserWalletEncryptionKey(encryptionKey.walletId).name, data = encryptionKey.encode(), ) } diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index e8e2ee6152..9404d9c15c 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -85,9 +85,9 @@ web3j = "4.10.1" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "release-app_5.7-504" +tangemBlockchainSdk = "release-app_5.7-506" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "release-app_5.7-329" +tangemCardSdk = "release-app_5.7-330" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ # endregion Tangem From 8fbcf01a4c4a284eb7694013fba7394a3992a301 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 1 Mar 2024 12:43:24 +0000 Subject: [PATCH 02/10] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt index ec450b5f39..2335c5caeb 100644 --- a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt @@ -3,10 +3,12 @@ package com.tangem.tap.proxy import androidx.core.text.isDigitsOnly import com.google.firebase.crashlytics.FirebaseCrashlytics import com.tangem.Message +import com.tangem.blockchain.blockchains.algorand.AlgorandTransactionExtras import com.tangem.blockchain.blockchains.binance.BinanceTransactionExtras import com.tangem.blockchain.blockchains.cosmos.CosmosTransactionExtras import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager +import com.tangem.blockchain.blockchains.hedera.HederaTransactionBuilder import com.tangem.blockchain.blockchains.optimism.OptimismWalletManager import com.tangem.blockchain.blockchains.stellar.StellarMemo import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras @@ -136,6 +138,8 @@ class TransactionManagerImpl( Blockchain.XRP -> memo.toLongOrNull()?.let { XrpTransactionBuilder.XrpTransactionExtras(it) } Blockchain.Cosmos -> CosmosTransactionExtras(memo) Blockchain.TON -> TonTransactionExtras(memo) + Blockchain.Hedera -> HederaTransactionBuilder.HederaTransactionExtras(memo) + Blockchain.Algorand -> AlgorandTransactionExtras(memo) else -> null } } From 91863768854a8ea43f957ce003da12674cb2821a Mon Sep 17 00:00:00 2001 From: Tangem Date: Sat, 2 Mar 2024 13:09:13 +0000 Subject: [PATCH 03/10] Updated on 2026-08-14 --- .../com/tangem/feature/swap/ui/StateBuilder.kt | 4 ++-- .../feature/swap/viewmodels/SwapViewModel.kt | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index 53e3148278..5e8c386764 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -888,10 +888,10 @@ internal class StateBuilder( ) } - fun addAlert(uiState: SwapStateHolder, onClick: () -> Unit): SwapStateHolder { + fun addAlert(uiState: SwapStateHolder, message: TextReference? = null, onClick: () -> Unit): SwapStateHolder { return uiState.copy( alert = SwapWarning.GenericWarning( - message = null, + message = message, onClick = onClick, ), ) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index d194494046..39ca0d7991 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -8,6 +8,7 @@ import arrow.core.getOrElse import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.Basic +import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.utils.InputNumberFormatter import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency @@ -113,7 +114,7 @@ internal class SwapViewModel @Inject constructor( val cryptoCurrencyStatus = getCryptoCurrencyStatusUseCase(it.walletId, initialCryptoCurrency.id).getOrNull() if (cryptoCurrencyStatus == null) { - uiState = stateBuilder.addAlert(uiState, swapRouter::back) + uiState = stateBuilder.addAlert(uiState = uiState, onClick = swapRouter::back) } else { initialCryptoCurrencyStatus = cryptoCurrencyStatus initTokens() @@ -459,7 +460,12 @@ internal class SwapViewModel @Inject constructor( return } val fromCurrency = requireNotNull(dataState.fromCryptoCurrency) - val fee = requireNotNull(dataState.selectedFee) + val fee = dataState.selectedFee + // TODO: unexpected crash for some users, this workaround to prevent app crash and follow to support + if (fee == null) { + makeDefaultAlert(TextReference.Str("Fee estimation error. Please send feedback to support.")) + return + } viewModelScope.launch(dispatchers.main) { runCatching(dispatchers.io) { swapInteractor.onSwap( @@ -749,6 +755,12 @@ internal class SwapViewModel @Inject constructor( } } + private fun makeDefaultAlert(message: TextReference) { + uiState = stateBuilder.addAlert(uiState, message) { + uiState = stateBuilder.clearAlert(uiState) + } + } + @Suppress("LongMethod", "CyclomaticComplexMethod") private fun createUiActions(): UiActions { return UiActions( From ec2f42a9dce0d27569b9d35d8ab39dc7bb9a7d0f Mon Sep 17 00:00:00 2001 From: Tangem Date: Sat, 2 Mar 2024 13:11:22 +0000 Subject: [PATCH 04/10] Updated on 2026-08-14 --- .../main/java/com/tangem/domain/common/extensions/Blockchain.kt | 1 + gradle/dependencies.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt index aca3f01cc2..db20fc08a4 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt @@ -261,4 +261,5 @@ private const val NODL_AMOUNT_TO_CREATE_ACCOUNT = 1.5 private val excludedBlockchains = listOf( Blockchain.Unknown, Blockchain.Playa3ull, + Blockchain.Hedera, ) \ No newline at end of file diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 9404d9c15c..08469f5c44 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -85,7 +85,7 @@ web3j = "4.10.1" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "release-app_5.7-506" +tangemBlockchainSdk = "release-app_5.7-509" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "release-app_5.7-330" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From baa1edbf0c617516c81686b12c3d505e5cf5ff97 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 4 Mar 2024 08:25:18 +0000 Subject: [PATCH 05/10] Updated on 2026-08-14 --- .../main/java/com/tangem/domain/common/extensions/Blockchain.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt index db20fc08a4..aca3f01cc2 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt @@ -261,5 +261,4 @@ private const val NODL_AMOUNT_TO_CREATE_ACCOUNT = 1.5 private val excludedBlockchains = listOf( Blockchain.Unknown, Blockchain.Playa3ull, - Blockchain.Hedera, ) \ No newline at end of file From ebe9f2ec91588102a88aeeb60869644c29210d61 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 4 Mar 2024 09:19:12 +0000 Subject: [PATCH 06/10] Updated on 2026-08-14 --- .../main/java/com/tangem/datasource/di/AccountCreatorModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/AccountCreatorModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/AccountCreatorModule.kt index 7abd08cf54..3b97ba24d9 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/AccountCreatorModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/AccountCreatorModule.kt @@ -16,7 +16,7 @@ internal object AccountCreatorModule { @Provides @Singleton - fun provideAccountCreator(authProvider: AuthProvider, @DevTangemApi tangemTechApi: TangemTechApi): AccountCreator { + fun provideAccountCreator(authProvider: AuthProvider, tangemTechApi: TangemTechApi): AccountCreator { return DefaultAccountCreator(authProvider, tangemTechApi) } } \ No newline at end of file From 8475ec3afca7455896301ebad9709496ded54e38 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 5 Mar 2024 13:25:06 +0800 Subject: [PATCH 07/10] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 5 ++++ .../DefaultFeedbackManagerFeatureToggles.kt | 12 ++++++++++ .../di/FeedbackManagerFeatureTogglesModule.kt | 23 +++++++++++++++++++ .../tangem/tap/di/data/CardSDKLoggerModule.kt | 1 + .../tap/proxy/redux/DaggerGraphState.kt | 2 ++ .../configs/feature_toggles_config.json | 4 ++++ .../feedback/FeedbackManagerFeatureToggles.kt | 6 +++++ gradle/dependencies.toml | 2 +- 8 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/tangem/tap/common/feedback/DefaultFeedbackManagerFeatureToggles.kt create mode 100644 app/src/main/java/com/tangem/tap/di/FeedbackManagerFeatureTogglesModule.kt create mode 100644 domain/legacy/src/main/java/com/tangem/domain/feedback/FeedbackManagerFeatureToggles.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 794eed1b33..051cb803b8 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -32,6 +32,7 @@ import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.card.repository.CardRepository import com.tangem.domain.common.LogConfig +import com.tangem.domain.feedback.FeedbackManagerFeatureToggles import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase import com.tangem.domain.tokens.repository.CurrenciesRepository @@ -174,6 +175,9 @@ internal class TapApplication : Application(), ImageLoaderFactory { @Inject lateinit var cardRepository: CardRepository + + @Inject + lateinit var feedbackManagerFeatureToggles: FeedbackManagerFeatureToggles // endregion Injected override fun onCreate() { @@ -261,6 +265,7 @@ internal class TapApplication : Application(), ImageLoaderFactory { wasTwinsOnboardingShownUseCase = wasTwinsOnboardingShownUseCase, saveTwinsOnboardingShownUseCase = saveTwinsOnboardingShownUseCase, cardRepository = cardRepository, + feedbackManagerFeatureToggles = feedbackManagerFeatureToggles, ), ), ) diff --git a/app/src/main/java/com/tangem/tap/common/feedback/DefaultFeedbackManagerFeatureToggles.kt b/app/src/main/java/com/tangem/tap/common/feedback/DefaultFeedbackManagerFeatureToggles.kt new file mode 100644 index 0000000000..85acfd9af6 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/feedback/DefaultFeedbackManagerFeatureToggles.kt @@ -0,0 +1,12 @@ +package com.tangem.tap.common.feedback + +import com.tangem.core.featuretoggle.manager.FeatureTogglesManager +import com.tangem.domain.feedback.FeedbackManagerFeatureToggles + +internal class DefaultFeedbackManagerFeatureToggles( + private val featureTogglesManager: FeatureTogglesManager, +) : FeedbackManagerFeatureToggles { + + override val isLocalLogsEnabled: Boolean + get() = featureTogglesManager.isFeatureEnabled(name = "LOCAL_USER_LOGS_ENABLED") +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/di/FeedbackManagerFeatureTogglesModule.kt b/app/src/main/java/com/tangem/tap/di/FeedbackManagerFeatureTogglesModule.kt new file mode 100644 index 0000000000..4202ba1af8 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/di/FeedbackManagerFeatureTogglesModule.kt @@ -0,0 +1,23 @@ +package com.tangem.tap.di + +import com.tangem.core.featuretoggle.manager.FeatureTogglesManager +import com.tangem.domain.feedback.FeedbackManagerFeatureToggles +import com.tangem.tap.common.feedback.DefaultFeedbackManagerFeatureToggles +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object FeedbackManagerFeatureTogglesModule { + + @Provides + @Singleton + fun provideFeedbackManagerFeatureToggles( + featureTogglesManager: FeatureTogglesManager, + ): FeedbackManagerFeatureToggles { + return DefaultFeedbackManagerFeatureToggles(featureTogglesManager) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/di/data/CardSDKLoggerModule.kt b/app/src/main/java/com/tangem/tap/di/data/CardSDKLoggerModule.kt index 89e6a89d62..6da93efeb4 100644 --- a/app/src/main/java/com/tangem/tap/di/data/CardSDKLoggerModule.kt +++ b/app/src/main/java/com/tangem/tap/di/data/CardSDKLoggerModule.kt @@ -32,6 +32,7 @@ internal object CardSDKLoggerModule { Log.Level.View, Log.Level.Network, Log.Level.Error, + Log.Level.Biometric, ) return TangemCardSDKLogger( diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt index c2b7b52edd..0afb10ab8d 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt @@ -10,6 +10,7 @@ import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.card.ScanCardUseCase import com.tangem.domain.card.repository.CardRepository import com.tangem.domain.card.repository.CardSdkConfigRepository +import com.tangem.domain.feedback.FeedbackManagerFeatureToggles import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase import com.tangem.domain.tokens.repository.CurrenciesRepository @@ -65,4 +66,5 @@ data class DaggerGraphState( val wasTwinsOnboardingShownUseCase: WasTwinsOnboardingShownUseCase? = null, val saveTwinsOnboardingShownUseCase: SaveTwinsOnboardingShownUseCase? = null, val cardRepository: CardRepository? = null, + val feedbackManagerFeatureToggles: FeedbackManagerFeatureToggles? = null, ) : StateType \ No newline at end of file diff --git a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json index 0180204de2..1b7b643cea 100644 --- a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json @@ -18,5 +18,9 @@ { "name": "GENERAL_USER_WALLETS_LIST_MANAGER_ENABLED", "version": "5.7.0" + }, + { + "name": "LOCAL_USER_LOGS_ENABLED", + "version": "5.8.0" } ] diff --git a/domain/legacy/src/main/java/com/tangem/domain/feedback/FeedbackManagerFeatureToggles.kt b/domain/legacy/src/main/java/com/tangem/domain/feedback/FeedbackManagerFeatureToggles.kt new file mode 100644 index 0000000000..2b259e17b6 --- /dev/null +++ b/domain/legacy/src/main/java/com/tangem/domain/feedback/FeedbackManagerFeatureToggles.kt @@ -0,0 +1,6 @@ +package com.tangem.domain.feedback + +interface FeedbackManagerFeatureToggles { + + val isLocalLogsEnabled: Boolean +} \ No newline at end of file diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 4086422ee6..0659211db3 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -87,7 +87,7 @@ web3j = "4.10.1" # region Tangem tangemBlockchainSdk = "develop-510" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "develop-324" +tangemCardSdk = "develop-331" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ # endregion Tangem From 95f1c123ba1b38048c77988e928351bd8df2b140 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 5 Mar 2024 13:45:30 +0500 Subject: [PATCH 08/10] Updated on 2026-08-14 --- .../GetFeePaidCryptoCurrencyStatusSyncUseCase.kt | 15 +++++---------- .../operations/CurrenciesStatusesOperations.kt | 12 ++++++++++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetFeePaidCryptoCurrencyStatusSyncUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetFeePaidCryptoCurrencyStatusSyncUseCase.kt index 7b43c6221f..cd41c82702 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetFeePaidCryptoCurrencyStatusSyncUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetFeePaidCryptoCurrencyStatusSyncUseCase.kt @@ -3,7 +3,6 @@ package com.tangem.domain.tokens import arrow.core.Either import arrow.core.raise.either import com.tangem.domain.tokens.error.TokenListError -import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.FeePaidCurrency import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations @@ -35,17 +34,13 @@ class GetFeePaidCryptoCurrencyStatusSyncUseCase( return either { when (feePaidCurrency) { - FeePaidCurrency.Coin -> getCryptoCurrencyStatus(operations, cryptoCurrency.id) + FeePaidCurrency.Coin -> + operations + .getNetworkCoinSync(cryptoCurrency.network.id, cryptoCurrency.network.derivationPath) + .getOrNull() FeePaidCurrency.SameCurrency -> cryptoCurrencyStatus - is FeePaidCurrency.Token -> getCryptoCurrencyStatus(operations, feePaidCurrency.tokenId) + is FeePaidCurrency.Token -> operations.getCurrencyStatusSync(feePaidCurrency.tokenId).getOrNull() } } } - - private suspend fun getCryptoCurrencyStatus( - operations: CurrenciesStatusesOperations, - cryptoCurrencyId: CryptoCurrency.ID, - ): CryptoCurrencyStatus? { - return operations.getCurrencyStatusSync(cryptoCurrencyId).getOrNull() - } } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt index 92d6969de0..fac9f7fc95 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt @@ -109,6 +109,18 @@ internal class CurrenciesStatusesOperations( } } + suspend fun getNetworkCoinSync( + networkId: Network.ID, + derivationPath: Network.DerivationPath, + ): Either { + val currency = recover( + block = { getNetworkCoin(networkId, derivationPath) }, + recover = { return it.left() }, + ) + + return getCurrencyStatusSync(currency.id) + } + suspend fun getPrimaryCurrencyStatusSync(): Either = either { val currency = catch( block = { currenciesRepository.getSingleCurrencyWalletPrimaryCurrency(userWalletId) }, From a2d8d157bcbe94fb14f4e030803ff4c2256deca4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 4 Mar 2024 19:40:21 +0000 Subject: [PATCH 09/10] Updated on 2026-08-14 --- .../tokens/impl/data/DefaultTokensListRepository.kt | 3 ++- .../tokens/impl/data/TangemApiTokensPagingSource.kt | 6 ++++-- .../impl/data/converters/CoinsResponseConverter.kt | 13 ++++++++++--- .../data/converters/TestnetTokensConfigConverter.kt | 5 +++-- .../impl/domain/DefaultTokensListInteractor.kt | 7 +++++-- .../tokens/impl/domain/TokensListInteractor.kt | 2 +- .../tokens/impl/domain/TokensListRepository.kt | 3 ++- .../presentation/viewmodels/TokensListViewModel.kt | 2 +- 8 files changed, 28 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/data/DefaultTokensListRepository.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/DefaultTokensListRepository.kt index 114990f05b..ca1cf6190f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/data/DefaultTokensListRepository.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/DefaultTokensListRepository.kt @@ -29,7 +29,7 @@ internal class DefaultTokensListRepository( private val testnetTokensStorage: TestnetTokensStorage, ) : TokensListRepository { - override fun getAvailableTokens(searchText: String?): Flow> { + override fun getAvailableTokens(searchText: String?, needFilterExcluded: Boolean): Flow> { return Pager( config = PagingConfig( pageSize = 100, @@ -42,6 +42,7 @@ internal class DefaultTokensListRepository( dispatchers = dispatchers, getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase, searchText = searchText, + needFilterExcluded = needFilterExcluded, ) getSelectedWalletSyncUseCase().fold( diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/data/TangemApiTokensPagingSource.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/TangemApiTokensPagingSource.kt index 4fc0e646b3..acf336dac3 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/data/TangemApiTokensPagingSource.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/TangemApiTokensPagingSource.kt @@ -27,8 +27,10 @@ internal class TangemApiTokensPagingSource( private val dispatchers: CoroutineDispatcherProvider, private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, private val searchText: String?, + needFilterExcluded: Boolean = false, ) : PagingSource() { + private val coinsResponseConverter = CoinsResponseConverter(needFilterExcluded) override fun getRefreshKey(state: PagingState): Int? { return state.anchorPosition?.let { anchorPosition -> state.closestPageToPosition(anchorPosition)?.prevKey?.plus(other = 1) @@ -41,7 +43,7 @@ internal class TangemApiTokensPagingSource( return runCatching(dispatchers.io) { val supportedBlockchains = getSelectedWalletSyncUseCase().fold( - ifLeft = { Blockchain.values().toList() }, + ifLeft = { Blockchain.entries }, ifRight = { it.scanResponse.card.supportedBlockchains(it.scanResponse.cardTypesResolver) }, ) @@ -55,7 +57,7 @@ internal class TangemApiTokensPagingSource( }.fold( onSuccess = { response -> LoadResult.Page( - data = CoinsResponseConverter.convert(response), + data = coinsResponseConverter.convert(response), prevKey = if (page == 0) null else page.minus(other = 1), nextKey = if (response.coins.isEmpty()) null else page.plus(other = 1), ) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/CoinsResponseConverter.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/CoinsResponseConverter.kt index d8c3de965b..2bffd45d01 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/CoinsResponseConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/CoinsResponseConverter.kt @@ -3,6 +3,7 @@ package com.tangem.tap.features.tokens.impl.data.converters import com.tangem.blockchain.common.Blockchain import com.tangem.datasource.api.tangemTech.models.CoinsResponse import com.tangem.domain.common.extensions.fromNetworkId +import com.tangem.domain.common.extensions.isSupportedInApp import com.tangem.tap.features.tokens.impl.domain.models.Token import com.tangem.utils.converter.Converter @@ -11,9 +12,7 @@ import com.tangem.utils.converter.Converter * [REDACTED_AUTHOR] */ -internal object CoinsResponseConverter : Converter> { - - private const val DEFAULT_IMAGE_HOST = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/" +internal class CoinsResponseConverter(val needFilterExcluded: Boolean) : Converter> { override fun convert(value: CoinsResponse): List { return value.coins.map { token -> @@ -25,6 +24,10 @@ internal object CoinsResponseConverter : Converter> { networks = token.networks.mapNotNull { network -> val blockchain = Blockchain.fromNetworkId(network.networkId) ?: return@mapNotNull null + if (needFilterExcluded && !blockchain.isSupportedInApp()) { + return@mapNotNull null + } + // filter tokens, if contractAddress != null, assume that it is a token if (network.contractAddress != null && !blockchain.canHandleTokens() @@ -47,4 +50,8 @@ internal object CoinsResponseConverter : Converter> { fun getIconUrl(id: String, imageHost: String? = null): String { return "${imageHost ?: DEFAULT_IMAGE_HOST}large/$id.png" } + + private companion object { + const val DEFAULT_IMAGE_HOST = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/" + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/TestnetTokensConfigConverter.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/TestnetTokensConfigConverter.kt index 5a532d7012..d1babd19b7 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/TestnetTokensConfigConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/TestnetTokensConfigConverter.kt @@ -13,13 +13,14 @@ import com.tangem.utils.converter.Converter */ internal object TestnetTokensConfigConverter : Converter> { + private val coinsResponseConverter = CoinsResponseConverter(needFilterExcluded = false) override fun convert(value: TestnetTokensConfig): List { return value.tokens.map { token -> Token( id = token.id, name = token.name, symbol = token.symbol, - iconUrl = CoinsResponseConverter.getIconUrl(token.id), + iconUrl = coinsResponseConverter.getIconUrl(token.id), networks = token.networks?.mapNotNull { network -> val blockchain = Blockchain.fromNetworkId(network.id) ?: return@mapNotNull null @@ -27,7 +28,7 @@ internal object TestnetTokensConfigConverter : Converter> { - return repository.getAvailableTokens(searchText = searchText.ifBlank(defaultValue = { null })) + override fun getTokensList(searchText: String, needFilterExcluded: Boolean): Flow> { + return repository.getAvailableTokens( + searchText = searchText.ifBlank(defaultValue = { null }), + needFilterExcluded = needFilterExcluded, + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListInteractor.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListInteractor.kt index c363dfc3c2..4b8edb914d 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListInteractor.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListInteractor.kt @@ -12,5 +12,5 @@ import kotlinx.coroutines.flow.Flow internal interface TokensListInteractor { /** Get tokens list using filter by text [searchText] */ - fun getTokensList(searchText: String): Flow> + fun getTokensList(searchText: String, needFilterExcluded: Boolean): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListRepository.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListRepository.kt index 8b2f16a644..67a9626b6b 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListRepository.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/domain/TokensListRepository.kt @@ -15,8 +15,9 @@ internal interface TokensListRepository { * Get available tokens list * * @param searchText search text + * @param needFilterExcluded flag that determines if excluded tokens should be filtered * * @throws com.tangem.datasource.api.common.response.ApiResponseError */ - fun getAvailableTokens(searchText: String?): Flow> + fun getAvailableTokens(searchText: String?, needFilterExcluded: Boolean): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt index 337e8f24ec..0853b72b8f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt @@ -250,7 +250,7 @@ internal class TokensListViewModel @Inject constructor( } private fun getTokensListBySearchText(text: String): Flow> { - return interactor.getTokensList(searchText = text) + return interactor.getTokensList(searchText = text, needFilterExcluded = !isManageAccess) .mapToTokenItemState() .cachedIn(viewModelScope) } From f5758d6a20dbdebf0dd2ae058087a7b88e20b4d2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 28 Feb 2024 16:41:28 +0000 Subject: [PATCH 10/10] Updated on 2026-08-14 --- .../java/com/tangem/tap/common/analytics/events/Onboarding.kt | 2 -- .../tangem/tap/features/onboarding/OnboardingMenuProvider.kt | 4 ++-- .../onboarding/products/wallet/ui/OnboardingWalletFragment.kt | 2 ++ .../products/wallet/ui/dialogs/WalletActivationErrorDialog.kt | 3 +++ .../tap/features/send/ui/dialogs/RequestFeeErrorDialog.kt | 3 +++ .../features/send/ui/dialogs/SendTransactionFailsDialog.kt | 3 +++ .../src/main/java/com/tangem/core/analytics/models/Basic.kt | 2 ++ 7 files changed, 15 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt index 9088608413..f35a636601 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt @@ -87,8 +87,6 @@ sealed class Onboarding( class SetupFinished : Twins("Twin Setup Finished") } - class ButtonChat : Onboarding("Onboarding", "Button - Chat") - class EnableBiometrics(state: AnalyticsParam.OnOffState) : Onboarding( category = "Onboarding / Biometric", event = "Enable Biometric", diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt index b979fd2d8c..936a202358 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt @@ -5,7 +5,7 @@ import android.view.MenuInflater import android.view.MenuItem import androidx.core.view.MenuProvider import com.tangem.core.analytics.Analytics -import com.tangem.tap.common.analytics.events.Onboarding +import com.tangem.core.analytics.models.Basic import com.tangem.tap.common.feedback.SupportInfo import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.store @@ -21,7 +21,7 @@ class OnboardingMenuProvider : MenuProvider { override fun onMenuItemSelected(menuItem: MenuItem): Boolean = when (menuItem.itemId) { R.id.menu_item_chat_support -> { - Analytics.send(Onboarding.ButtonChat()) + Analytics.send(Basic.ButtonSupport()) // changed on email support [REDACTED_TASK_KEY] store.dispatch(GlobalAction.SendEmail(SupportInfo())) true diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt index dd07c89355..0655d01aa9 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt @@ -22,6 +22,7 @@ import com.tangem.common.CardIdFormatter import com.tangem.common.CompletionResult import com.tangem.common.core.CardIdDisplayFormat import com.tangem.core.analytics.Analytics +import com.tangem.core.analytics.models.Basic import com.tangem.core.ui.extensions.setStatusBarColor import com.tangem.domain.common.util.cardTypesResolver import com.tangem.feature.onboarding.data.model.CreateWalletResponse @@ -501,6 +502,7 @@ class OnboardingWalletFragment : private fun makeSeedPhraseRouter(): SeedPhraseRouter = SeedPhraseRouter( onBack = ::legacyOnBackHandler, onOpenChat = { + Analytics.send(Basic.ButtonSupport()) // changed on email support [REDACTED_TASK_KEY] store.dispatch(GlobalAction.SendEmail(SupportInfo())) }, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/WalletActivationErrorDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/WalletActivationErrorDialog.kt index cfabd25957..ddec9cdfb3 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/WalletActivationErrorDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/WalletActivationErrorDialog.kt @@ -3,6 +3,8 @@ package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs import android.app.Dialog import android.content.Context import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.tangem.core.analytics.Analytics +import com.tangem.core.analytics.models.Basic import com.tangem.tap.common.extensions.dispatchDialogHide import com.tangem.tap.common.feedback.SupportInfo import com.tangem.tap.common.redux.global.GlobalAction @@ -19,6 +21,7 @@ object WalletActivationErrorDialog { setPositiveButton(R.string.common_ok) { _, _ -> dialog.onConfirm() } setNegativeButton(R.string.common_support) { _, _ -> // changed on email support [REDACTED_TASK_KEY] + Analytics.send(Basic.ButtonSupport()) store.dispatch(GlobalAction.SendEmail(SupportInfo())) } setOnDismissListener { store.dispatchDialogHide() } diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/RequestFeeErrorDialog.kt b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/RequestFeeErrorDialog.kt index cc67c24921..9cf4359f72 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/RequestFeeErrorDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/RequestFeeErrorDialog.kt @@ -2,6 +2,8 @@ package com.tangem.tap.features.send.ui.dialogs import android.content.Context import androidx.appcompat.app.AlertDialog +import com.tangem.core.analytics.Analytics +import com.tangem.core.analytics.models.Basic import com.tangem.tap.common.feedback.SendTransactionFailedEmail import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.features.send.redux.SendAction @@ -19,6 +21,7 @@ object RequestFeeErrorDialog { setTitle(R.string.common_fee_error) setMessage(context.getString(R.string.alert_failed_to_send_transaction_message, errorMessage)) setNegativeButton(R.string.details_row_title_contact_to_support) { _, _ -> + Analytics.send(Basic.ButtonSupport()) store.dispatch(GlobalAction.SendEmail(SendTransactionFailedEmail(errorMessage))) } setPositiveButton(R.string.common_retry) { _, _ -> dialog.onRetry() } diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt index 4c300f7aeb..f862ff5e94 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt @@ -5,6 +5,8 @@ import androidx.appcompat.app.AlertDialog import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.BlockchainSdkError import com.tangem.common.module.ModuleMessageConverter +import com.tangem.core.analytics.Analytics +import com.tangem.core.analytics.models.Basic import com.tangem.sdk.extensions.localizedDescription import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.common.feedback.SendTransactionFailedEmail @@ -31,6 +33,7 @@ object SendTransactionFailsDialog { setTitle(R.string.alert_failed_to_send_transaction_title) setMessage(context.getString(R.string.alert_failed_to_send_transaction_message, errorMessage)) setNeutralButton(R.string.details_row_title_contact_to_support) { _, _ -> + Analytics.send(Basic.ButtonSupport()) store.dispatch(GlobalAction.SendEmail(SendTransactionFailedEmail(errorMessage))) } setPositiveButton(R.string.common_cancel) { _, _ -> } diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/Basic.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/Basic.kt index 9e1da068ec..8820f8ff12 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/Basic.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/Basic.kt @@ -75,4 +75,6 @@ sealed class Basic( ) class WalletOpened : Basic(event = "Wallet Opened") + + class ButtonSupport : Basic("Request Support") } \ No newline at end of file