From da93332bc0568a0ee4c912026f84c69c0e993d6d Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 19 Sep 2023 16:22:34 +0300 Subject: [PATCH 001/159] Updated on 2026-08-14 --- .../paramsInterceptor/CardContextInterceptor.kt | 1 + .../tangem/tap/domain/tasks/product/ScanProductTask.kt | 10 +++++++++- .../com/tangem/domain/common/extensions/Blockchain.kt | 5 ++--- .../com/tangem/domain/models/scan/ScanResponse.kt | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt index 0db51098a3..6db15ac882 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt @@ -45,6 +45,7 @@ class CardContextInterceptor( ProductType.Note -> "Note" ProductType.Twins -> "Twin" ProductType.Wallet -> "Wallet" + ProductType.Wallet2 -> "Wallet 2.0" ProductType.Start2Coin -> "Start2Coin" else -> if (DemoHelper.isDemoCard(scanResponse)) { if (DemoHelper.isTestDemoCard(scanResponse)) { diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index 31a7a1ade4..b587dee326 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -216,7 +216,7 @@ private class ScanWalletProcessor( session: CardSession, callback: (result: CompletionResult) -> Unit, ) { - val productType = ProductType.Wallet + val productType = getWalletProductType(card) val config = CardConfig.createConfig(card) scope.launch { val scanResponse = ScanResponse( @@ -280,6 +280,14 @@ private class ScanWalletProcessor( return blockchainsToDerive.distinct() } + private fun getWalletProductType(card: CardDTO): ProductType { + return if (card.firmwareVersion >= FirmwareVersion.Ed25519Slip0010Available) { + ProductType.Wallet2 + } else { + ProductType.Wallet + } + } + private fun getDefaultBlockchains( derivationStyleProvider: DerivationStyleProvider, ): MutableList { 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 0970e85d77..3d315d3d8e 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 @@ -175,7 +175,6 @@ fun Blockchain.toCoinId(): String { Blockchain.Dash -> "dash" Blockchain.Kaspa -> "kaspa" Blockchain.TON, Blockchain.TONTestnet -> "the-open-network" - Blockchain.Unknown -> "unknown" Blockchain.Kava, Blockchain.KavaTestnet -> "kava" Blockchain.Ravencoin, Blockchain.RavencoinTestnet -> "ravencoin" Blockchain.Cosmos, Blockchain.CosmosTestnet -> "cosmos" @@ -185,8 +184,8 @@ fun Blockchain.toCoinId(): String { Blockchain.Telos, Blockchain.TelosTestnet -> "telos" Blockchain.AlephZero, Blockchain.AlephZeroTestnet -> "aleph-zero" Blockchain.OctaSpace, Blockchain.OctaSpaceTestnet -> "octaspace" - Blockchain.Chia -> "chia" - Blockchain.ChiaTestnet -> "chia/test" + Blockchain.Chia, Blockchain.ChiaTestnet -> "chia" + Blockchain.Unknown -> "unknown" } } diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/scan/ScanResponse.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/scan/ScanResponse.kt index c6f1d9f75c..74a552e520 100644 --- a/domain/models/src/main/kotlin/com/tangem/domain/models/scan/ScanResponse.kt +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/scan/ScanResponse.kt @@ -21,5 +21,5 @@ data class ScanResponse( typealias KeyWalletPublicKey = ByteArrayKey enum class ProductType { - Note, Twins, Wallet, Start2Coin + Note, Twins, Wallet, Start2Coin, Wallet2 } \ No newline at end of file From 8c792a2ce85c5be1de704ff53dd7885c95b0d51d Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 4 Oct 2023 14:33:33 +0500 Subject: [PATCH 002/159] Updated on 2026-08-14 --- .../wallet/redux/middlewares/WalletMiddleware.kt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 889dab19e8..b4f81bd001 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -180,7 +180,7 @@ class WalletMiddleware { } if (walletState.isMultiwalletAllowed) { - val amountToSend = sendableAmounts.find { it.currencySymbol == currency.currencySymbol } + val amountToSend = findAmountToSend(currency = currency, amounts = sendableAmounts) if (amountToSend == null) { val error = TapError.UnsupportedState("WalletAction.Send: Amount to send is null") FirebaseCrashlytics.getInstance().recordException(IllegalStateException(error.stateError)) @@ -277,6 +277,18 @@ class WalletMiddleware { } } + private fun findAmountToSend(currency: Currency, amounts: List): Amount? { + return amounts.find { amount -> + val amountType = amount.type + if (amountType is AmountType.Token && currency is Currency.Token) { + val token = amountType.token + token.symbol == currency.currencySymbol && token.contractAddress == currency.token.contractAddress + } else { + amount.currencySymbol == currency.currencySymbol + } + } + } + private fun makeInitSendStateActionByAmount( amount: Amount, walletStore: WalletStoreModel, From 40869beea94a837c81093ad3f8597bb9805a1807 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 12 Oct 2023 15:53:38 +0800 Subject: [PATCH 003/159] Updated on 2026-08-14 --- .../presentation/tokendetails/ui/TokenDetailsScreen.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt index 288f8e1464..e2ecb00e2e 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt @@ -1,5 +1,6 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui +import androidx.activity.compose.BackHandler import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.* @@ -42,6 +43,8 @@ import kotlinx.collections.immutable.PersistentList @OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class) @Composable internal fun TokenDetailsScreen(state: TokenDetailsState) { + BackHandler(onBack = state.topAppBarConfig.onBackClick) + Scaffold( topBar = { TokenDetailsTopAppBar(config = state.topAppBarConfig) }, containerColor = TangemTheme.colors.background.secondary, From e156c413694ddd5b8736afd5b375ae34a8a791dc Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 12 Oct 2023 12:23:07 +0300 Subject: [PATCH 004/159] Updated on 2026-08-14 --- gradle/dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index b63f0cc158..4c1ae2ae45 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -82,9 +82,9 @@ okHttp-prettyLogging = "3.1.0" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "develop-358" +tangemBlockchainSdk = "release-app_5.0-359" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "develop-302" +tangemCardSdk = "release-app_5.0-303" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds # endregion Tangem From 2176c243e0cb52b4fbcc6838c6d832b0715a50a8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 12 Oct 2023 18:09:04 +0800 Subject: [PATCH 005/159] Updated on 2026-08-14 --- .../tap/common/analytics/events/AnalyticsParam.kt | 9 +++++---- .../tangem/tap/common/analytics/events/Onboarding.kt | 7 ++++++- .../paramsInterceptor/CardContextInterceptor.kt | 1 + .../tangem/tap/domain/tasks/product/ScanProductTask.kt | 4 +++- .../tangem/tap/features/onboarding/OnboardingHelper.kt | 2 +- .../wallet/redux/OnboardingWalletMiddleware.kt | 7 ++++++- .../tangem/data/card/DefaultCardSdkConfigRepository.kt | 1 + .../com/tangem/domain/common/extensions/Blockchain.kt | 5 ++--- .../com/tangem/domain/userwallets/UserWalletBuilder.kt | 1 + .../tangem/domain/userwallets/UserWalletIdBuilder.kt | 1 + .../com/tangem/domain/models/scan/ScanResponse.kt | 2 +- .../wallet2/viewmodel/SeedPhraseViewModel.kt | 10 +++++----- 12 files changed, 33 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt index d1dd0f06bb..e7e51bdd4c 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt @@ -133,9 +133,9 @@ sealed class AnalyticsParam { } sealed class WalletCreationType(val value: String) { - object PrivateKey : WalletCreationType("Private key") - object NewSeed : WalletCreationType("New seed") - object SeedImport : WalletCreationType("Seed import") + object PrivateKey : WalletCreationType(value = "Private Key") + object NewSeed : WalletCreationType(value = "New Seed") + object SeedImport : WalletCreationType(value = "Seed Import") } companion object Key { @@ -152,7 +152,8 @@ sealed class AnalyticsParam { const val ERROR_DESCRIPTION = "Error Description" const val ERROR_CODE = "Error Code" const val ERROR_KEY = "Error Key" - const val CREATION_TYPE = "Creation type" + const val CREATION_TYPE = "Creation Type" + const val SEED_PHRASE_LENGTH = "Seed Phrase Length" const val DAPP_NAME = "DApp Name" const val DAPP_URL = "DApp Url" const val METHOD_NAME = "Method Name" 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 a9432ad404..9088608413 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 @@ -23,9 +23,14 @@ sealed class Onboarding( class ButtonCreateWallet : CreateWallet("Button - Create Wallet") class WalletCreatedSuccessfully( creationType: AnalyticsParam.WalletCreationType = AnalyticsParam.WalletCreationType.PrivateKey, + seedPhraseLength: Int? = null, ) : CreateWallet( event = "Wallet Created Successfully", - params = mapOf(AnalyticsParam.CREATION_TYPE to creationType.value), + params = buildMap { + put(AnalyticsParam.CREATION_TYPE, creationType.value) + + if (seedPhraseLength != null) put(AnalyticsParam.SEED_PHRASE_LENGTH, seedPhraseLength.toString()) + }, ) } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt index 0db51098a3..6db15ac882 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/CardContextInterceptor.kt @@ -45,6 +45,7 @@ class CardContextInterceptor( ProductType.Note -> "Note" ProductType.Twins -> "Twin" ProductType.Wallet -> "Wallet" + ProductType.Wallet2 -> "Wallet 2.0" ProductType.Start2Coin -> "Start2Coin" else -> if (DemoHelper.isDemoCard(scanResponse)) { if (DemoHelper.isTestDemoCard(scanResponse)) { diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index 30b5814a11..e6be2ff4c2 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -209,7 +209,9 @@ private class ScanWalletProcessor( session: CardSession, callback: (result: CompletionResult) -> Unit, ) { - val productType = ProductType.Wallet + val isWallet2 = card.settings.isKeysImportAllowed || card.firmwareVersion >= FirmwareVersion.KeysImportAvailable + + val productType = if (isWallet2) ProductType.Wallet2 else ProductType.Wallet val config = CardConfig.createConfig(card) scope.launch { val scanResponse = ScanResponse( diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt index 29c6d0fe98..6369010887 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt @@ -53,7 +53,7 @@ object OnboardingHelper { fun whereToNavigate(scanResponse: ScanResponse): AppScreen { return when (scanResponse.productType) { ProductType.Note -> AppScreen.OnboardingNote - ProductType.Wallet -> if (scanResponse.card.settings.isBackupAllowed) { + ProductType.Wallet, ProductType.Wallet2 -> if (scanResponse.card.settings.isBackupAllowed) { AppScreen.OnboardingWallet } else { AppScreen.OnboardingOther diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index b46578b48b..b825a98b28 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -237,7 +237,12 @@ private fun handleWallet2Action(action: OnboardingWallet2Action) { SeedPhraseSource.IMPORTED -> AnalyticsParam.WalletCreationType.SeedImport SeedPhraseSource.GENERATED -> AnalyticsParam.WalletCreationType.NewSeed } - Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully(creationType)) + Analytics.send( + event = Onboarding.CreateWallet.WalletCreatedSuccessfully( + creationType = creationType, + seedPhraseLength = action.mnemonicComponents.size, + ), + ) val response = CreateWalletResponse( card = result.data.card, derivedKeys = result.data.derivedKeys, diff --git a/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt b/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt index 321a48b0bf..11dc95e2b1 100644 --- a/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt +++ b/data/card/src/main/java/com/tangem/data/card/DefaultCardSdkConfigRepository.kt @@ -50,6 +50,7 @@ internal class DefaultCardSdkConfigRepository( ProductType.Note, ProductType.Wallet, ProductType.Start2Coin, + ProductType.Wallet2, -> CardIdDisplayFormat.Full } } 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 925137aab5..8c4877ad37 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 @@ -179,7 +179,6 @@ fun Blockchain.toCoinId(): String { Blockchain.Dash -> "dash" Blockchain.Kaspa -> "kaspa" Blockchain.TON, Blockchain.TONTestnet -> "the-open-network" - Blockchain.Unknown -> "unknown" Blockchain.Kava, Blockchain.KavaTestnet -> "kava" Blockchain.Ravencoin, Blockchain.RavencoinTestnet -> "ravencoin" Blockchain.Cosmos, Blockchain.CosmosTestnet -> "cosmos" @@ -189,10 +188,10 @@ fun Blockchain.toCoinId(): String { Blockchain.Telos, Blockchain.TelosTestnet -> "telos" Blockchain.AlephZero, Blockchain.AlephZeroTestnet -> "aleph-zero" Blockchain.OctaSpace, Blockchain.OctaSpaceTestnet -> "octaspace" - Blockchain.Chia -> "chia" - Blockchain.ChiaTestnet -> "chia/test" + Blockchain.Chia, Blockchain.ChiaTestnet -> "chia" Blockchain.Near -> "near" Blockchain.NearTestnet -> "near/test" + Blockchain.Unknown -> "unknown" } } diff --git a/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletBuilder.kt b/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletBuilder.kt index 4916db578c..29890a9abd 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletBuilder.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletBuilder.kt @@ -25,6 +25,7 @@ class UserWalletBuilder( cardTypesResolver.isStart2Coin() -> "Start2Coin" else -> "Wallet" } + ProductType.Wallet2 -> "Wallet" } /** diff --git a/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletIdBuilder.kt b/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletIdBuilder.kt index cad0957152..40ac39de3c 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletIdBuilder.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/userwallets/UserWalletIdBuilder.kt @@ -60,6 +60,7 @@ class UserWalletIdBuilder private constructor( ProductType.Twins -> scanResponse.secondTwinPublicKey?.hexToBytes() ProductType.Note, ProductType.Wallet, + ProductType.Wallet2, ProductType.Start2Coin, -> null }, diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/scan/ScanResponse.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/scan/ScanResponse.kt index c6f1d9f75c..74a552e520 100644 --- a/domain/models/src/main/kotlin/com/tangem/domain/models/scan/ScanResponse.kt +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/scan/ScanResponse.kt @@ -21,5 +21,5 @@ data class ScanResponse( typealias KeyWalletPublicKey = ByteArrayKey enum class ProductType { - Note, Twins, Wallet, Start2Coin + Note, Twins, Wallet, Start2Coin, Wallet2 } \ No newline at end of file diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseViewModel.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseViewModel.kt index 7cdaf16171..719abb7761 100644 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseViewModel.kt +++ b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/viewmodel/SeedPhraseViewModel.kt @@ -156,6 +156,7 @@ class SeedPhraseViewModel @Inject constructor( ), suggestedPhraseClick = ::buttonSuggestedPhraseClick, buttonCreateWalletClick = { + analyticsEventHandler.send(SeedPhraseEvents.ButtonImport) buttonImportWalletClick(importedMnemonicComponents, SeedPhraseSource.IMPORTED) }, ), @@ -165,7 +166,7 @@ class SeedPhraseViewModel @Inject constructor( // region CheckSeedPhrase private fun onTextFieldChanged(field: SeedPhraseField, textFieldValue: TextFieldValue) { - viewModelScope.launchSingle { + launchSingle { updateUi { uiBuilder.checkSeedPhrase.updateTextField(uiState, field, textFieldValue) } val fieldState = field.getState(uiState) @@ -278,7 +279,6 @@ class SeedPhraseViewModel @Inject constructor( } private fun buttonImportWalletClick(mnemonicComponents: List?, seedPhraseSource: SeedPhraseSource) { - analyticsEventHandler.send(SeedPhraseEvents.ButtonImport) mnemonicComponents ?: return viewModelScope.launch(dispatchers.io) { @@ -325,7 +325,7 @@ class SeedPhraseViewModel @Inject constructor( private fun buttonGenerateSeedPhraseClick() { analyticsEventHandler.send(SeedPhraseEvents.ButtonGenerateSeedPhrase) - viewModelScope.launchSingle { + launchSingle { updateUi { uiBuilder.generateMnemonicComponents(uiState) } delay(DELAY_GENERATE_SEED_PHRASE) interactor.generateMnemonic() @@ -380,7 +380,7 @@ class SeedPhraseViewModel @Inject constructor( } private fun buttonSuggestedPhraseClick(suggestionIndex: Int) { - viewModelScope.launchSingle { + launchSingle { val textFieldValue = uiState.importSeedPhraseState.tvSeedPhrase.textFieldValue val word = uiState.importSeedPhraseState.suggestionsList[suggestionIndex] val cursorPosition = textFieldValue.selection.end @@ -420,7 +420,7 @@ class SeedPhraseViewModel @Inject constructor( SeedPhraseField.Eleventh -> uiState.checkSeedPhraseState.tvEleventhPhrase } - private fun CoroutineScope.launchSingle(block: suspend CoroutineScope.() -> Unit): Job { + private fun launchSingle(block: suspend CoroutineScope.() -> Unit): Job { return viewModelScope.launch(dispatchers.single, block = block) } From 2ad2edd6c823885067dcec10fe9bf80d8a0f1e90 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 12 Oct 2023 21:49:34 +0800 Subject: [PATCH 006/159] Updated on 2026-08-14 --- .../tap/di/domain/TokensDomainModule.kt | 10 +++ .../tokens/FetchCardTokenListUseCase.kt | 72 ++++++++++++++++ .../wallet/viewmodels/WalletViewModel.kt | 82 +++++++++---------- 3 files changed, 123 insertions(+), 41 deletions(-) create mode 100644 domain/tokens/src/main/kotlin/com/tangem/domain/tokens/FetchCardTokenListUseCase.kt diff --git a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt index ba41f1dda4..026bf203bb 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt @@ -122,6 +122,16 @@ internal object TokensDomainModule { return FetchCurrencyStatusUseCase(currenciesRepository, networksRepository, quotesRepository) } + @Provides + @ViewModelScoped + fun provideFetchCardTokenListUseCase( + currenciesRepository: CurrenciesRepository, + quotesRepository: QuotesRepository, + networksRepository: NetworksRepository, + ): FetchCardTokenListUseCase { + return FetchCardTokenListUseCase(currenciesRepository, networksRepository, quotesRepository) + } + @Provides @ViewModelScoped fun provideGetCryptoCurrencyUseCase(currenciesRepository: CurrenciesRepository): GetCryptoCurrencyUseCase { diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/FetchCardTokenListUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/FetchCardTokenListUseCase.kt new file mode 100644 index 0000000000..7448714472 --- /dev/null +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/FetchCardTokenListUseCase.kt @@ -0,0 +1,72 @@ +package com.tangem.domain.tokens + +import arrow.core.Either +import arrow.core.raise.Raise +import arrow.core.raise.catch +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.Network +import com.tangem.domain.tokens.repository.CurrenciesRepository +import com.tangem.domain.tokens.repository.NetworksRepository +import com.tangem.domain.tokens.repository.QuotesRepository +import com.tangem.domain.wallets.models.UserWalletId +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.coroutineScope + +class FetchCardTokenListUseCase( + private val currenciesRepository: CurrenciesRepository, + private val networksRepository: NetworksRepository, + private val quotesRepository: QuotesRepository, +) { + + suspend operator fun invoke(userWalletId: UserWalletId, refresh: Boolean = false): Either { + return either { + val currencies = fetchCurrencies(userWalletId = userWalletId) + + coroutineScope { + val fetchStatuses = async { + fetchNetworksStatuses( + userWalletId = userWalletId, + networks = currencies.mapTo(destination = hashSetOf(), transform = CryptoCurrency::network), + refresh = refresh, + ) + } + val fetchQuotes = async { + fetchQuotes( + currenciesIds = currencies.mapTo(destination = hashSetOf(), transform = CryptoCurrency::id), + refresh = refresh, + ) + } + + awaitAll(fetchStatuses, fetchQuotes) + } + } + } + + private suspend fun Raise.fetchCurrencies(userWalletId: UserWalletId): List { + return catch( + block = { currenciesRepository.getSingleCurrencyWalletWithCardCurrencies(userWalletId = userWalletId) }, + catch = { raise(TokenListError.DataError(it)) }, + ) + } + + private suspend fun Raise.fetchNetworksStatuses( + userWalletId: UserWalletId, + networks: Set, + refresh: Boolean, + ) { + catch( + block = { networksRepository.getNetworkStatusesSync(userWalletId, networks, refresh) }, + catch = { raise(TokenListError.DataError(it)) }, + ) + } + + private suspend fun fetchQuotes(currenciesIds: Set, refresh: Boolean) { + catch( + block = { quotesRepository.getQuotesSync(currenciesIds, refresh) }, + catch = { /* Ignore error */ }, + ) + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index f0b0798819..23054b94df 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -97,6 +97,7 @@ internal class WalletViewModel @Inject constructor( private val getTokenListUseCase: GetTokenListUseCase, private val getCardTokensListUseCase: GetCardTokensListUseCase, private val fetchTokenListUseCase: FetchTokenListUseCase, + private val fetchCardTokenListUseCase: FetchCardTokenListUseCase, private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase, private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase, private val getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase, @@ -544,6 +545,24 @@ internal class WalletViewModel @Inject constructor( } } + private fun refreshMultiCurrencyContent(walletIndex: Int) { + uiState = stateFactory.getRefreshingState() + + viewModelScope.launch(dispatchers.main) { + val wallet = getWallet(walletIndex) + + val maybeFetchResult = if (isSingleWalletWithTokens(wallet)) { + fetchCardTokenListUseCase(userWalletId = wallet.walletId, refresh = true) + } else { + fetchTokenListUseCase(userWalletId = wallet.walletId, refresh = true) + } + + maybeFetchResult.onLeft { uiState = stateFactory.getStateByTokenListError(it) } + + uiState = stateFactory.getRefreshedState() + }.saveIn(refreshContentJobHolder) + } + override fun onOrganizeTokensClick() { analyticsEventsHandler.send(PortfolioEvent.OrganizeTokens) @@ -702,6 +721,27 @@ internal class WalletViewModel @Inject constructor( refreshSingleCurrencyContent(selectedWalletIndex) } + private fun refreshSingleCurrencyContent(walletIndex: Int) { + uiState = stateFactory.getRefreshingState() + val wallet = getWallet(walletIndex) + + viewModelScope.launch(dispatchers.main) { + val result = fetchCurrencyStatusUseCase(wallet.walletId, refresh = true) + + uiState = stateFactory.getRefreshedState() + uiState = result.fold(stateFactory::getStateByCurrencyStatusError) { uiState } + + singleWalletCryptoCurrencyStatus?.let { + val singleCurrencyState = uiState as WalletSingleCurrencyState + if (singleCurrencyState.txHistoryState !is TxHistoryState.Content) { + // show loading indicator while refreshing in non content state + uiState = stateFactory.getLoadingTxHistoryState(1.right()) + } + updateTxHistory(wallet.walletId, it.currency, refresh = true) + } + }.saveIn(refreshContentJobHolder) + } + override fun onExploreClick() { viewModelScope.launch(dispatchers.io) { val wallet = getWallet( @@ -924,9 +964,7 @@ internal class WalletViewModel @Inject constructor( uiState = stateFactory.getLockedState() } wallet.isMultiCurrency -> getMultiCurrencyContent(wallet, index) - isSingleWalletWithTokens(wallet) -> { - getSingleCurrencyWithTokenContent(index) - } + isSingleWalletWithTokens(wallet) -> getSingleCurrencyWithTokenContent(index) !wallet.isMultiCurrency -> getSingleCurrencyContent(index) } } @@ -1137,44 +1175,6 @@ internal class WalletViewModel @Inject constructor( .saveIn(notificationsJobHolder) } - private fun refreshMultiCurrencyContent(walletIndex: Int) { - uiState = stateFactory.getRefreshingState() - val wallet = getWallet(walletIndex) - - viewModelScope.launch(dispatchers.io) { - if (isSingleWalletWithTokens(wallet)) { - // TODO add refresh for nodl cards ([REDACTED_JIRA]) - delay(timeMillis = 1000) - } else { - val result = fetchTokenListUseCase(wallet.walletId, refresh = true) - uiState = result.fold(stateFactory::getStateByTokenListError) { uiState } - } - - uiState = stateFactory.getRefreshedState() - }.saveIn(refreshContentJobHolder) - } - - private fun refreshSingleCurrencyContent(walletIndex: Int) { - uiState = stateFactory.getRefreshingState() - val wallet = getWallet(walletIndex) - - viewModelScope.launch(dispatchers.io) { - val result = fetchCurrencyStatusUseCase(wallet.walletId, refresh = true) - - uiState = stateFactory.getRefreshedState() - uiState = result.fold(stateFactory::getStateByCurrencyStatusError) { uiState } - - singleWalletCryptoCurrencyStatus?.let { - val singleCurrencyState = uiState as WalletSingleCurrencyState - if (singleCurrencyState.txHistoryState !is TxHistoryState.Content) { - // show loading indicator while refreshing in non content state - uiState = stateFactory.getLoadingTxHistoryState(1.right()) - } - updateTxHistory(wallet.walletId, it.currency, refresh = true) - } - }.saveIn(refreshContentJobHolder) - } - private fun createSelectedAppCurrencyFlow(): StateFlow { return getSelectedAppCurrencyUseCase() .map { maybeAppCurrency -> From dd11f56a38db1cc9dd2a793fe7003a499f1001ca Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 13 Oct 2023 14:26:43 +0500 Subject: [PATCH 007/159] Updated on 2026-08-14 --- core/res/src/main/res/values-ru/strings.xml | 21 ++++--- core/res/src/main/res/values/strings.xml | 18 +++--- .../components/TokenDetailsNotification.kt | 56 ++++++++++--------- .../tokendetails/ui/TokenDetailsScreen.kt | 12 +++- .../state/components/WalletNotification.kt | 10 ++-- 5 files changed, 71 insertions(+), 46 deletions(-) diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 2250396755..4917da1390 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -568,21 +568,26 @@ Узнать больше Понятно! Очень круто! - Сеть %1$s использует концепцию экзистенциального депозита. Если баланс вашего счета опустится ниже %2$s, он будет деактивирован, а все оставшиеся средства будут уничтожены. - Для работы с сетью необходим депозит. + Cеть %1$s использует концепцию экзистенциального депозита. Если баланс вашего счета будет ниже %2$s, то он будет деактивирован, а средства на счете уничтожены. + Для работы с сетью необходим депозит Эта карта может быть производственным образцом или подделкой Проверка подлинности не удалась Важная информация о безопасности %s На этой карте осталось только %s подписей. Вы должны вывести все свои средства. В данный момент сеть недоступна. Пожалуйста, попробуйте позже. - Сеть недоступна. - Как вам Tangem? - Один вопрос + Сеть недоступна + Пополните ваш кошелек + Ваш отзыв мотивирует нас сделать кошелек Tangem еще лучше + Нравится Tangem? + Необходима плата за аренду сети + %1$s - это токен в сети %2$s. Для совершения транзакции %3$s, вам необходимо внести депозит в размере %4$s (%5$s), чтобы покрыть комиссию сети. + Недостаточно %1$s для оплаты комиссии сети + Отправка средств станет доступной после завершения транзакции %s Эта карта подписывала транзакции в прошлом - В настоящее время сеть недоступна. Пожалуйста, повторите попытку позже. - Некоторые сети в настоящее время недоступны. Пожалуйста, повторите попытку позже. + Сеть Solana взимает арендную плату в размере %1$s каждые 2 дня. Аккаунты, которые не могут позволить себе арендную плату, удаляются из сети. Пополните свой счет более чем на %2$s, чтобы не платить арендную плату. + Некоторые сети в настоящее время недоступны. Пожалуйста, повторите попытку позже. + Некоторые сети недоступны Это тестовая карта. Не принимайте её в качестве оплаты. Эта карта должна использоваться только в целях тестирования и разработки. - Некоторые сети недоступны Отказаться Вы не закончили резервное копирование. Хотите продолжить? Да, возобновить diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 8b245bc9b9..b04bede936 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -588,7 +588,7 @@ Love it! Ok, Got it! Really cool! - %1$s network has a concept of Existential Deposit. If your account drops below %2$s it will be deactivated and any remaining funds will be destroyed. + %1$s network requires an Existential Deposit. If your account drops below %2$s, it will be deactivated, and any remaining funds will be destroyed. Network requires Existential Deposit This card might be a production sample or counterfeit Authenticity check failed @@ -596,15 +596,19 @@ There are only %s signatures available on this card. You must withdraw all of your funds. The network is currently unreachable. Please try again later. Network is unreachable - How do you like Tangem? - One question - Rate the app + Top up your wallet + Your review keeps us motivated to make Tangem Wallet even better + Enjoying Tangem? + Network rent fee required + %1$s is a token in the %2$s network. To make a %3$s transaction, you must deposit some %4$s (%5$s) to cover the network fee. + Insufficient %1$s to cover network fee + Sending funds will be available once the %s transaction is complete This card has signed transactions in the past - Network currently is unreachable. Please try again later. - Some networks currently are unreachable. Please try again later. + Solana network charges a rent of %1$s every 2 days. Accounts that can\'t afford the rent are purged from the network. Deposit your account with more than %2$s to use it for free. + Some networks currently are unreachable. Please try again later. + Some networks are unreachable This is a Testnet card. Don\'t accept it as a payment. This card must only be used for testing and development purposes. Note top up - Some networks are unreachable Discard You have an interrupted backup. Do you want to resume? Yes, resume diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt index 99d77114ba..fd43bdcd6e 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt @@ -11,49 +11,52 @@ import com.tangem.features.tokendetails.impl.R // TODO: Finalize notification strings [REDACTED_JIRA] @Immutable -sealed class TokenDetailsNotification( - open val config: NotificationConfig, -) { +sealed class TokenDetailsNotification { + + abstract val config: NotificationConfig + + sealed class Informational : TokenDetailsNotification() + sealed class Warning : TokenDetailsNotification() data class RentInfo( private val rentInfo: CryptoCurrencyWarning.Rent, private val onCloseClick: () -> Unit, - ) : TokenDetailsNotification( - config = NotificationConfig( - title = TextReference.Res(R.string.send_network_fee_title), + ) : Warning() { + override val config = NotificationConfig( + title = TextReference.Res(R.string.warning_rent_fee_title), subtitle = TextReference.Res( - id = R.string.solana_rent_warning, + id = R.string.warning_solana_rent_fee_message, formatArgs = wrappedList(rentInfo.rent, rentInfo.exemptionAmount), ), iconResId = R.drawable.img_attention_20, onCloseClick = onCloseClick, - ), - ) + ) + } data class ExistentialDeposit( private val existentialInfo: CryptoCurrencyWarning.ExistentialDeposit, - ) : TokenDetailsNotification( - config = NotificationConfig( + ) : Informational() { + override val config = NotificationConfig( title = resourceReference(R.string.warning_existential_deposit_title), subtitle = TextReference.Res( id = R.string.warning_existential_deposit_message, formatArgs = wrappedList(existentialInfo.currencyName, existentialInfo.edStringValueWithSymbol), ), - iconResId = R.drawable.img_attention_20, - ), - ) + iconResId = R.drawable.ic_alert_circle_24, + ) + } data class NetworkFee( private val feeInfo: CryptoCurrencyWarning.BalanceNotEnoughForFee, private val onBuyClick: () -> Unit, - ) : TokenDetailsNotification( - config = NotificationConfig( + ) : Warning() { + override val config = NotificationConfig( title = TextReference.Res( - id = R.string.notification_title_not_enough_funds, + id = R.string.warning_send_blocked_funds_for_fee_title, formatArgs = wrappedList(feeInfo.blockchainFullName), ), subtitle = TextReference.Res( - id = R.string.token_details_send_blocked_fee_format, + id = R.string.warning_send_blocked_funds_for_fee_message, formatArgs = wrappedList( feeInfo.currency.name, feeInfo.blockchainFullName, @@ -64,17 +67,20 @@ sealed class TokenDetailsNotification( ), iconResId = feeInfo.currency.networkIconResId, buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( - text = TextReference.Res(R.string.common_buy), + text = resourceReference( + id = R.string.common_buy_currency, + formatArgs = wrappedList(feeInfo.blockchainSymbol), + ), onClick = onBuyClick, ), - ), - ) + ) + } - object NetworksUnreachable : TokenDetailsNotification( - config = NotificationConfig( + object NetworksUnreachable : Warning() { + override val config = NotificationConfig( title = resourceReference(R.string.warning_network_unreachable_title), subtitle = resourceReference(R.string.warning_network_unreachable_message), iconResId = R.drawable.img_attention_20, - ), - ) + ) + } } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt index e2ecb00e2e..67f09871a1 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt @@ -32,6 +32,7 @@ import com.tangem.core.ui.components.transactions.txHistoryItems import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState +import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsBalanceBlock import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsDialogs import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsTopAppBar @@ -93,7 +94,16 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) { items = state.notifications, key = { it.config::class.java }, contentType = { it.config::class.java }, - itemContent = { Notification(config = it.config, modifier = itemModifier.animateItemPlacement()) }, + itemContent = { + Notification( + modifier = itemModifier.animateItemPlacement(), + config = it.config, + iconTint = when (it) { + is TokenDetailsNotification.Warning -> null + is TokenDetailsNotification.Informational -> TangemTheme.colors.icon.accent + }, + ) + }, ) if (!state.isCustomToken) { item( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt index 5a2120d0e3..6c3fd2d2d8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt @@ -79,13 +79,13 @@ sealed class WalletNotification(val config: NotificationConfig) { ) object NetworksUnreachable : Warning( - title = resourceReference(id = R.string.wallet_balance_blockchain_unreachable), - subtitle = resourceReference(id = R.string.warning_subtitle_network_unreachable), + title = resourceReference(id = R.string.warning_network_unreachable_title), + subtitle = resourceReference(id = R.string.warning_network_unreachable_message), ) object SomeNetworksUnreachable : Warning( - title = resourceReference(id = R.string.warning_title_some_networks_unreachable), - subtitle = resourceReference(id = R.string.warning_subtitle_some_networks_unreachable), + title = resourceReference(id = R.string.warning_some_networks_unreachable_title), + subtitle = resourceReference(id = R.string.warning_some_networks_unreachable_message), ) data class TopUpNote(val errorMessage: String) : Warning( @@ -137,7 +137,7 @@ sealed class WalletNotification(val config: NotificationConfig) { val onCloseClick: () -> Unit, ) : WalletNotification( config = NotificationConfig( - title = resourceReference(id = R.string.warning_rate_app_title_new), + title = resourceReference(id = R.string.warning_rate_app_title), subtitle = resourceReference(id = R.string.warning_rate_app_message), iconResId = R.drawable.ic_star_24, buttonsState = NotificationConfig.ButtonsState.PairButtonsConfig( From 62b7fbda75aee5b22ac4f27bb6fbaa29e7b4b6f2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 13 Oct 2023 16:36:15 +0800 Subject: [PATCH 008/159] Updated on 2026-08-14 --- .../wallet/ui/OnboardingWalletFragment.kt | 8 +- .../wallet/viewmodels/WalletViewModel.kt | 80 +++++++++---------- 2 files changed, 43 insertions(+), 45 deletions(-) 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 2eb4abdc18..aa714f2c28 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 @@ -191,7 +191,7 @@ class OnboardingWalletFragment : } } - internal fun loadImageIntoImageView(uri: Uri?, view: ImageView) { + private fun loadImageIntoImageView(uri: Uri?, view: ImageView) { view.load(uri) { placeholder(R.drawable.card_placeholder_black) error(R.drawable.card_placeholder_black) @@ -412,7 +412,7 @@ class OnboardingWalletFragment : animator.showWriteBackupCard(state, cardNumber) } - internal fun showSuccess() = with(binding) { + private fun showSuccess() = with(binding) { toolbar.title = getString(R.string.onboarding_done_header) tvHeader.text = getText(R.string.onboarding_done_header) @@ -427,9 +427,7 @@ class OnboardingWalletFragment : layoutButtonsCommon.btnWalletAlternativeAction.hide() layoutButtonsCommon.btnWalletMainAction.setOnClickListener { showConfetti(false) - lifecycleScope.launch { - store.dispatch(OnboardingWalletAction.FinishOnboarding(lifecycleCoroutineScope = lifecycleScope)) - } + store.dispatch(OnboardingWalletAction.FinishOnboarding(lifecycleCoroutineScope = lifecycleScope)) } animator.showSuccess { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index 23054b94df..a182b01ae7 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -1012,21 +1012,31 @@ internal class WalletViewModel @Inject constructor( } } - private fun initAndSetupWc(tokenListFlow: SharedFlow>, wallet: UserWallet) { - initWalletConnectForWallet(wallet) - tokenListFlow - .filter(::filterLoadedTokenList) - .take(1) - .onEach { - it.onRight { - setupWalletConnectOnWallet(wallet) - } + private fun initAndSetupWc(tokenListFlow: MaybeTokenListFlow, wallet: UserWallet) { + viewModelScope + .launch(dispatchers.main) { + initWalletConnectForWallet(wallet) + + tokenListFlow + .filterLoadedTokenList() + .take(count = 1) + .collect { setupWalletConnectOnWallet(wallet) } } - .flowOn(dispatchers.io) - .launchIn(viewModelScope) .saveIn(updateWcJobHolder) } + private fun initWalletConnectForWallet(userWallet: UserWallet) { + reduxStateHolder.dispatch( + action = WalletConnectActions.New.Initialize(userWallet = userWallet), + ) + } + + private fun setupWalletConnectOnWallet(userWallet: UserWallet) { + reduxStateHolder.dispatch( + action = WalletConnectActions.New.SetupUserChains(userWallet = userWallet), + ) + } + private fun isSingleWalletWithTokens(userWallet: UserWallet): Boolean { return userWallet.scanResponse.walletData?.token != null && !userWallet.isMultiCurrency } @@ -1035,23 +1045,23 @@ internal class WalletViewModel @Inject constructor( return !this.any { it.value is CryptoCurrencyStatus.Loading } } - private fun filterLoadedTokenList(either: Either): Boolean { - return either.fold( - ifRight = { list -> - when (list) { - is TokenList.Ungrouped -> { - list.currencies.isAllCurrenciesLoaded() + private fun MaybeTokenListFlow.filterLoadedTokenList(): MaybeTokenListFlow { + return filter { either -> + either.fold( + ifRight = { list -> + when (list) { + is TokenList.Ungrouped -> { + list.currencies.isAllCurrenciesLoaded() + } + is TokenList.GroupedByNetwork -> { + list.groups.flatMap(NetworkGroup::currencies).isAllCurrenciesLoaded() + } + else -> false } - is TokenList.GroupedByNetwork -> { - list.groups.flatMap { group -> group.currencies }.isAllCurrenciesLoaded() - } - else -> { - false - } - } - }, - ifLeft = { false }, - ) + }, + ifLeft = { false }, + ) + } } private fun List.hasNonZeroWallets(): Boolean { @@ -1187,18 +1197,6 @@ internal class WalletViewModel @Inject constructor( ) } - private fun initWalletConnectForWallet(userWallet: UserWallet) { - reduxStateHolder.dispatch( - WalletConnectActions.New.Initialize(userWallet = userWallet), - ) - } - - private fun setupWalletConnectOnWallet(userWallet: UserWallet) { - reduxStateHolder.dispatch( - WalletConnectActions.New.SetupUserChains(userWallet = userWallet), - ) - } - private fun getWallet(index: Int): UserWallet { return requireNotNull( value = wallets.getOrNull(index), @@ -1214,4 +1212,6 @@ internal class WalletViewModel @Inject constructor( } private fun getCardTypeResolver(index: Int): CardTypesResolver = getWallet(index).scanResponse.cardTypesResolver -} \ No newline at end of file +} + +typealias MaybeTokenListFlow = Flow> \ No newline at end of file From c795074253a26e48b572b6f96a83ee2be3f74cec Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 12 Oct 2023 16:34:59 +0300 Subject: [PATCH 009/159] Updated on 2026-08-14 --- .../chooseaddress/ChooseAddressBottomSheet.kt | 38 +++++-------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/chooseaddress/ChooseAddressBottomSheet.kt b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/chooseaddress/ChooseAddressBottomSheet.kt index adcdb176c1..5b41ed7fe6 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/chooseaddress/ChooseAddressBottomSheet.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/chooseaddress/ChooseAddressBottomSheet.kt @@ -1,17 +1,11 @@ package com.tangem.core.ui.components.bottomsheets.chooseaddress -import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Text -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import com.tangem.core.ui.R +import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import com.tangem.core.ui.components.SecondaryButton +import com.tangem.core.ui.R +import com.tangem.core.ui.components.SimpleSettingsRow import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.res.TangemTheme @@ -30,27 +24,13 @@ fun ChooseAddressBottomSheet(config: TangemBottomSheetConfig) { @Composable private fun ChooseAddressBottomSheetContent(content: ChooseAddressBottomSheetConfig) { Column( - modifier = Modifier - .fillMaxWidth() - .padding( - start = TangemTheme.dimens.spacing24, - top = TangemTheme.dimens.spacing24, - end = TangemTheme.dimens.spacing24, - bottom = TangemTheme.dimens.spacing16, - ), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing24), + modifier = Modifier.background(TangemTheme.colors.background.primary), ) { - Text( - text = stringResource(id = R.string.token_details_choose_address), - color = TangemTheme.colors.text.secondary, - textAlign = TextAlign.Center, - style = TangemTheme.typography.body2, - ) content.addressModels.forEach { addressModel -> - SecondaryButton( - text = addressModel.type.name, - onClick = { content.onClick(addressModel) }, + SimpleSettingsRow( + title = addressModel.type.name, + icon = R.drawable.ic_arrow_top_right_24, + onItemsClick = { content.onClick(addressModel) }, ) } } From e7da35375ba30145e9e925c1c1c4d13405cb57df Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 12 Oct 2023 16:01:51 +0300 Subject: [PATCH 010/159] Updated on 2026-08-14 --- .../repository/DefaultNetworksRepository.kt | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt index 673b9fdf4c..bd536ed456 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultNetworksRepository.kt @@ -53,7 +53,7 @@ internal class DefaultNetworksRepository( override suspend fun fetchNetworkPendingTransactions(userWalletId: UserWalletId, networks: Set) { withContext(dispatchers.io) { - fetchNetworksPendingTransactionsIfCacheExpired(userWalletId, networks, false) + fetchNetworksPendingTransactions(userWalletId, networks) } } @@ -82,16 +82,12 @@ internal class DefaultNetworksRepository( } } - private suspend fun fetchNetworksPendingTransactionsIfCacheExpired( - userWalletId: UserWalletId, - networks: Set, - refresh: Boolean, - ) { + private suspend fun fetchNetworksPendingTransactions(userWalletId: UserWalletId, networks: Set) { coroutineScope { networks .map { network -> async { - fetchNetworkPendingTransactionsIfCacheExpired(userWalletId, network, refresh) + fetchNetworkPendingTransactions(userWalletId, network) } } .awaitAll() @@ -110,20 +106,6 @@ internal class DefaultNetworksRepository( ) } - private suspend fun fetchNetworkPendingTransactionsIfCacheExpired( - userWalletId: UserWalletId, - network: Network, - refresh: Boolean, - ) { - val key = getNetworksStatusesCacheKey(userWalletId, network) - cacheRegistry.invalidate(key) - cacheRegistry.invokeOnExpire( - key = key, - skipCache = refresh, - block = { fetchNetworkPendingTransactions(userWalletId, network) }, - ) - } - private suspend fun fetchNetworkStatus(userWalletId: UserWalletId, network: Network) { val currencies = getCurrencies(userWalletId, network) From 3f3a114dadd8403b7fb147e937311d7ccff3e03c Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 13 Oct 2023 17:33:05 +0800 Subject: [PATCH 011/159] Updated on 2026-08-14 --- .../wallet/ui/components/common/WalletCard.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletCard.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletCard.kt index 4f7ed253be..ec7c87f061 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletCard.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletCard.kt @@ -79,7 +79,7 @@ internal fun WalletCard(state: WalletCardState, isBalanceHidden: Boolean, modifi }, ) - var balanceWidth by remember { mutableStateOf(value = Int.MIN_VALUE) } + var balanceWidth by remember { mutableIntStateOf(value = Int.MIN_VALUE) } Balance( state = state, isBalanceHidden = isBalanceHidden, @@ -153,12 +153,12 @@ private fun CardContainer( Surface( modifier = modifier .defaultMinSize(minHeight = TangemTheme.dimens.size108) + .onSizeChanged { itemSize = it } .then( if (isLockedState) { Modifier } else { Modifier - .onSizeChanged { itemSize = it } .clip(shape = TangemTheme.shapes.roundedCornersXMedium) .indication(interactionSource = interactionSource, indication = LocalIndication.current) .pointerInput(true) { @@ -277,7 +277,6 @@ private fun TitleText(text: String, modifier: Modifier = Modifier) { ) } -@OptIn(ExperimentalAnimationApi::class) @Composable private fun Balance(state: WalletCardState, isBalanceHidden: Boolean, modifier: Modifier = Modifier) { AnimatedContent( @@ -285,7 +284,7 @@ private fun Balance(state: WalletCardState, isBalanceHidden: Boolean, modifier: label = "Update the balance", modifier = modifier, transitionSpec = { - fadeIn(animationSpec = tween(durationMillis = 220, delayMillis = 90)) with + fadeIn(animationSpec = tween(durationMillis = 220, delayMillis = 90)) togetherWith fadeOut(animationSpec = tween(durationMillis = 90)) }, ) { walletCardState -> @@ -329,7 +328,6 @@ private fun Modifier.nonContentBalanceSize(dimens: TangemDimens): Modifier { .size(width = dimens.size102, height = dimens.size24) } -@OptIn(ExperimentalAnimationApi::class) @Composable private fun AdditionalInfo(text: TextReference?, modifier: Modifier = Modifier) { AnimatedContent( @@ -337,7 +335,7 @@ private fun AdditionalInfo(text: TextReference?, modifier: Modifier = Modifier) label = "Update the additional text", modifier = modifier, transitionSpec = { - fadeIn(animationSpec = tween(durationMillis = 220, delayMillis = 90)) with + fadeIn(animationSpec = tween(durationMillis = 220, delayMillis = 90)) togetherWith fadeOut(animationSpec = tween(durationMillis = 90)) }, ) { animatedText -> From 355acaea56ea7468d55edaa6ee51c917a868f08f Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 13 Oct 2023 13:51:55 +0300 Subject: [PATCH 012/159] Updated on 2026-08-14 --- .../main/res/values-ru/strings-blockchain.xml | 2 +- .../main/res/values/strings-blockchain.xml | 2 +- core/res/src/main/res/values/strings.xml | 1 - .../tokens/model/CryptoCurrencyStatus.kt | 4 ++-- .../model/warnings/CryptoCurrencyWarning.kt | 5 ++++ .../tokens/GetCurrencyWarningsUseCase.kt | 13 +++++++++- .../operations/CurrencyStatusOperations.kt | 13 +++++----- .../domain/tokens/mock/MockTokenLists.kt | 2 +- .../domain/tokens/mock/MockTokensStates.kt | 8 +++---- .../components/TokenDetailsNotification.kt | 14 +++++++++-- .../TokenDetailsNotificationConverter.kt | 5 ++++ .../state/components/WalletNotification.kt | 21 +++++++++++----- .../components/common/WalletNotifications.kt | 1 + .../WalletNotificationsListFactory.kt | 24 +++++++++++-------- 14 files changed, 80 insertions(+), 35 deletions(-) diff --git a/core/res/src/main/res/values-ru/strings-blockchain.xml b/core/res/src/main/res/values-ru/strings-blockchain.xml index fcec1f9e0c..0744b44f6b 100644 --- a/core/res/src/main/res/values-ru/strings-blockchain.xml +++ b/core/res/src/main/res/values-ru/strings-blockchain.xml @@ -7,7 +7,7 @@ Недостаточно средств для совершения транзакции. Пожалуйста, пополните свой аккаунт. Произошла ошибка. Код: %s. Из-за ограничений Kaspa в одну транзакцию может поместиться только %1$d UTXO. Это означает, что вы можете отправить только %2$s или меньше. Вам нужно уменьшить сумму. - Пополните счет на %1$s+ %2$s, чтобы создать аккаунт + Чтобы использовать сеть %1$s, вы должны оплатить резерв аккаунта (%2$s %3$s), который блокируется и не используется в вашем балансе. Аккаунт получателя не активирован. Отправьте %s или более для активации аккаунта. Минимальная сумма: %s Сдача слишком мала diff --git a/core/res/src/main/res/values/strings-blockchain.xml b/core/res/src/main/res/values/strings-blockchain.xml index 7e938d5420..bb28ad284c 100644 --- a/core/res/src/main/res/values/strings-blockchain.xml +++ b/core/res/src/main/res/values/strings-blockchain.xml @@ -7,7 +7,7 @@ Not enough funds for the transaction. Please top up your account. An error occurred. Code: %s. Due to Kaspa limitations only %1$d UTXOs can fit in a single transaction. This means you can only send %2$s or less. You need to reduce the amount. - Load %1$s+ %2$s to create account + To use the %1$s network, you must pay the account reserve (%2$s %3$s), which locks up and hides that amount indefinitely. Destination account is not active. Send %s or more to activate the account. Minimum amount is %s Change is too small diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index b04bede936..9e2b6673a4 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -608,7 +608,6 @@ Some networks currently are unreachable. Please try again later. Some networks are unreachable This is a Testnet card. Don\'t accept it as a payment. This card must only be used for testing and development purposes. - Note top up Discard You have an interrupted backup. Do you want to resume? Yes, resume diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrencyStatus.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrencyStatus.kt index b4187361d6..8f49493cc5 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrencyStatus.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrencyStatus.kt @@ -71,10 +71,10 @@ data class CryptoCurrencyStatus( /** * Represents a state where there is no account associated with the cryptocurrency * - * @property errorMessage error message + * @property amountToCreateAccount base reserve amount for account creation */ data class NoAccount( - val errorMessage: String, + val amountToCreateAccount: BigDecimal, override val priceChange: BigDecimal?, override val fiatRate: BigDecimal?, ) : Status(isError = false) { diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt index 89663cf0fa..6c8ec13eb1 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt @@ -18,6 +18,11 @@ sealed class CryptoCurrencyWarning { object SomeNetworksUnreachable : CryptoCurrencyWarning() + data class SomeNetworksNoAccount( + val amountToCreateAccount: BigDecimal, + val amountCurrency: CryptoCurrency, + ) : CryptoCurrencyWarning() + /** * Represents wallet blockchain rent * @param rent Amount that will be charged in overtime if the blockchain does not have an amount greater than diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt index 227161d34f..b35a730d3a 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt @@ -40,7 +40,8 @@ class GetCurrencyWarningsUseCase( flowOf(walletManagersFacade.getRentInfo(userWalletId, currency.network)), flowOf(walletManagersFacade.getExistentialDeposit(userWalletId, currency.network)), flowOf(getNetworkUnavailableWarning(currencyStatus)), - ) { maybeFeeWarning, maybeRentWarning, maybeEdWarning, maybeNetworkUnavailable -> + flowOf(getNetworkNoAccountWarning(currencyStatus)), + ) { maybeFeeWarning, maybeRentWarning, maybeEdWarning, maybeNetworkUnavailable, maybeNetworkNoAccount -> setOfNotNull( maybeRentWarning, maybeEdWarning?.let { @@ -51,6 +52,7 @@ class GetCurrencyWarningsUseCase( }, maybeFeeWarning, maybeNetworkUnavailable, + maybeNetworkNoAccount, ) }.flowOn(dispatchers.io) } @@ -106,6 +108,15 @@ class GetCurrencyWarningsUseCase( } } + private fun getNetworkNoAccountWarning(currencyStatus: CryptoCurrencyStatus): CryptoCurrencyWarning? { + return (currencyStatus.value as? CryptoCurrencyStatus.NoAccount)?.let { + CryptoCurrencyWarning.SomeNetworksNoAccount( + amountToCreateAccount = it.amountToCreateAccount, + amountCurrency = currencyStatus.currency, + ) + } + } + private fun BigDecimal?.isZero(): Boolean { return this?.signum() == 0 } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt index 804c8a58bc..89f506ab39 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt @@ -20,7 +20,7 @@ internal class CurrencyStatusOperations( null -> CryptoCurrencyStatus.Loading is NetworkStatus.MissedDerivation -> createMissedDerivationStatus() is NetworkStatus.Unreachable -> createUnreachableStatus() - is NetworkStatus.NoAccount -> createNoAccountStatus(status.errorMessage) + is NetworkStatus.NoAccount -> createNoAccountStatus(status.amountToCreateAccount) is NetworkStatus.Verified -> createStatus(status) } } @@ -31,11 +31,12 @@ internal class CurrencyStatusOperations( private fun createUnreachableStatus(): CryptoCurrencyStatus.Unreachable = CryptoCurrencyStatus.Unreachable(priceChange = quote?.priceChange, fiatRate = quote?.fiatRate) - private fun createNoAccountStatus(message: String): CryptoCurrencyStatus.NoAccount = CryptoCurrencyStatus.NoAccount( - errorMessage = message, - priceChange = quote?.priceChange, - fiatRate = quote?.fiatRate, - ) + private fun createNoAccountStatus(amount: BigDecimal): CryptoCurrencyStatus.NoAccount = + CryptoCurrencyStatus.NoAccount( + amountToCreateAccount = amount, + priceChange = quote?.priceChange, + fiatRate = quote?.fiatRate, + ) private fun createStatus(status: NetworkStatus.Verified): CryptoCurrencyStatus.Status { val amount = status.amounts[currency.id] diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokenLists.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokenLists.kt index fb41b5aa56..0cbc4a5d5c 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokenLists.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokenLists.kt @@ -48,7 +48,7 @@ internal object MockTokenLists { val loadingUngroupedTokenList = with(failedUngroupedTokenList) { copy( - currencies = currencies.map { it.copy(value = CryptoCurrencyStatus.Loading) }, + currencies = currencies.map { it.copy(value = CryptoCurrencyStatus.Loading) }.toNonEmptyListOrNull() ?: emptyList(), totalFiatBalance = TokenList.FiatBalance.Loading, ) } diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokensStates.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokensStates.kt index 69e1b66b5c..d1410765aa 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokensStates.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokensStates.kt @@ -60,7 +60,7 @@ internal object MockTokensStates { value = CryptoCurrencyStatus.NoAccount( priceChange = MockQuotes.quote7.priceChange, fiatRate = MockQuotes.quote7.fiatRate, - errorMessage = "", + amountToCreateAccount = MockNetworks.amountToCreateAccount, ), ) @@ -69,7 +69,7 @@ internal object MockTokensStates { value = CryptoCurrencyStatus.NoAccount( priceChange = MockQuotes.quote8.priceChange, fiatRate = MockQuotes.quote8.fiatRate, - errorMessage = "", + amountToCreateAccount = MockNetworks.amountToCreateAccount, ), ) @@ -78,7 +78,7 @@ internal object MockTokensStates { value = CryptoCurrencyStatus.NoAccount( priceChange = MockQuotes.quote9.priceChange, fiatRate = MockQuotes.quote9.fiatRate, - errorMessage = "", + amountToCreateAccount = MockNetworks.amountToCreateAccount, ), ) @@ -87,7 +87,7 @@ internal object MockTokensStates { value = CryptoCurrencyStatus.NoAccount( priceChange = MockQuotes.quote10.priceChange, fiatRate = MockQuotes.quote10.fiatRate, - errorMessage = "", + amountToCreateAccount = MockNetworks.amountToCreateAccount, ), ) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt index fd43bdcd6e..6a6488777c 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt @@ -9,9 +9,8 @@ import com.tangem.core.ui.extensions.wrappedList import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning import com.tangem.features.tokendetails.impl.R -// TODO: Finalize notification strings [REDACTED_JIRA] @Immutable -sealed class TokenDetailsNotification { +internal sealed class TokenDetailsNotification { abstract val config: NotificationConfig @@ -83,4 +82,15 @@ sealed class TokenDetailsNotification { iconResId = R.drawable.img_attention_20, ) } + + class NetworksNoAccount(val network: String, val symbol: String, val amount: String) : Informational() { + override val config = NotificationConfig( + title = resourceReference(R.string.warning_no_account_title), + subtitle = resourceReference( + R.string.no_account_generic, + wrappedList(network, amount, symbol), + ), + iconResId = R.drawable.ic_alert_circle_24, + ) + } } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt index 945fd6107e..6a20547a9f 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt @@ -37,6 +37,11 @@ internal class TokenDetailsNotificationConverter( onCloseClick = clickIntents::onCloseRentInfoNotification, ) CryptoCurrencyWarning.SomeNetworksUnreachable -> TokenDetailsNotification.NetworksUnreachable + is CryptoCurrencyWarning.SomeNetworksNoAccount -> TokenDetailsNotification.NetworksNoAccount( + network = warning.amountCurrency.name, + amount = warning.amountToCreateAccount.toString(), + symbol = warning.amountCurrency.symbol, + ) } } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt index 6c3fd2d2d8..4f62061929 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletNotification.kt @@ -2,7 +2,10 @@ package com.tangem.feature.wallet.presentation.wallet.state.components import androidx.compose.runtime.Immutable import com.tangem.core.ui.components.notifications.NotificationConfig -import com.tangem.core.ui.extensions.* +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.pluralReference +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.wrappedList import com.tangem.feature.wallet.impl.R /** @@ -88,11 +91,6 @@ sealed class WalletNotification(val config: NotificationConfig) { subtitle = resourceReference(id = R.string.warning_some_networks_unreachable_message), ) - data class TopUpNote(val errorMessage: String) : Warning( - title = resourceReference(id = R.string.warning_title_note_top_up), - subtitle = stringReference(value = errorMessage), - ) - data class NumberOfSignedHashesIncorrect(val onCloseClick: () -> Unit) : Warning( title = resourceReference(id = R.string.common_warning), subtitle = resourceReference(id = R.string.alert_card_signed_transactions), @@ -117,6 +115,17 @@ sealed class WalletNotification(val config: NotificationConfig) { ), ) + data class NoAccount(val network: String, val symbol: String, val amount: String) : WalletNotification( + config = NotificationConfig( + title = resourceReference(id = R.string.warning_no_account_title), + subtitle = resourceReference( + id = R.string.no_account_generic, + wrappedList(network, amount, symbol), + ), + iconResId = R.drawable.ic_alert_circle_24, + ), + ) + data class UnlockWallets(val onClick: () -> Unit) : WalletNotification( config = NotificationConfig( title = resourceReference(id = R.string.common_unlock_needed), diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt index 22c20dcfc7..1ef6f61148 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletNotifications.kt @@ -32,6 +32,7 @@ internal fun LazyListScope.notifications(configs: ImmutableList TangemTheme.colors.icon.accent is WalletNotification.RateApp -> TangemTheme.colors.icon.attention is WalletNotification.UnlockWallets -> TangemTheme.colors.icon.primary1 + is WalletNotification.NoAccount -> TangemTheme.colors.icon.accent is WalletNotification.Warning -> null }, ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt index 859b8ccf58..4b160e908b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt @@ -143,10 +143,7 @@ internal class WalletNotificationsListFactory( condition = cryptoCurrencyList.hasUnreachableNetworks(), ) - val errorMessage = cryptoCurrencyList.geNoAccountStatusMessage() - if (errorMessage != null) { - add(element = WalletNotification.Warning.TopUpNote(errorMessage = errorMessage)) - } + addNoAccountWarning(cryptoCurrencyList) addIf( element = WalletNotification.Warning.NumberOfSignedHashesIncorrect( @@ -169,12 +166,19 @@ internal class WalletNotificationsListFactory( return any { it.value is CryptoCurrencyStatus.Unreachable } } - private fun List.geNoAccountStatusMessage(): String? { - return this - .map(CryptoCurrencyStatus::value) - .filterIsInstance() - .firstOrNull() - ?.errorMessage + private fun MutableList.addNoAccountWarning(cryptoCurrencyList: List) { + val noAccountNetwork = cryptoCurrencyList.firstOrNull { it.value is CryptoCurrencyStatus.NoAccount } + if (noAccountNetwork != null) { + val amountToCreateAccount = (noAccountNetwork.value as? CryptoCurrencyStatus.NoAccount) + ?.amountToCreateAccount.toString() + add( + element = WalletNotification.NoAccount( + network = noAccountNetwork.currency.name, + amount = amountToCreateAccount, + symbol = noAccountNetwork.currency.symbol, + ), + ) + } } /** From 5f95ba532e65333579a5e7f9ddc3c9421be99fa3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 13 Oct 2023 22:51:18 +0800 Subject: [PATCH 013/159] Updated on 2026-08-14 --- .../BiometricUserWalletsListManager.kt | 46 +++++++++++-------- .../wallets/legacy/UserWalletsListManager.kt | 7 +++ .../wallets/usecase/UnlockWalletsUseCase.kt | 5 +- .../wallet/viewmodels/WalletViewModel.kt | 8 +++- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt index 59819e3d7d..f4c32feb54 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt @@ -57,21 +57,11 @@ internal class BiometricUserWalletsListManager( get() = state.value.userWallets.size override suspend fun unlock(): CompletionResult { - return unlockWithBiometryInternal() - .mapFailure { error -> - if (error is UserWalletsListError) { - error - } else { - UserWalletsListError.UnableToUnlockUserWallets(cause = error) - } - } - .map { - selectedUserWalletSync.guard { - throw UserWalletsListError.UnableToUnlockUserWallets( - cause = IllegalStateException("No user wallet selected"), - ) - } - } + return unlockWithBiometryInternal().mapUnlockResult() + } + + override suspend fun unlockAndSelect(selectedWalletId: UserWalletId): CompletionResult { + return unlockWithBiometryInternal(selectedWalletId = selectedWalletId).mapUnlockResult() } override fun lock() { @@ -198,7 +188,7 @@ internal class BiometricUserWalletsListManager( } } - private suspend fun unlockWithBiometryInternal(): CompletionResult { + private suspend fun unlockWithBiometryInternal(selectedWalletId: UserWalletId? = null): CompletionResult { return keysRepository.getAll() .map { keys -> state.update { prevState -> @@ -207,7 +197,7 @@ internal class BiometricUserWalletsListManager( ) } } - .flatMap { loadModels() } + .flatMap { loadModels(selectedWalletId = selectedWalletId) } .map { state.update { prevState -> val hasLockedUserWallets = prevState.userWallets.any { it.isLocked } @@ -216,6 +206,24 @@ internal class BiometricUserWalletsListManager( } } + private fun CompletionResult.mapUnlockResult(): CompletionResult { + return this + .mapFailure { error -> + if (error is UserWalletsListError) { + error + } else { + UserWalletsListError.UnableToUnlockUserWallets(cause = error) + } + } + .map { + selectedUserWalletSync.guard { + throw UserWalletsListError.UnableToUnlockUserWallets( + cause = IllegalStateException("No user wallet selected"), + ) + } + } + } + private suspend fun saveEncryptionKeyIfNotNull(userWallet: UserWallet): CompletionResult { val encryptionKey = userWallet.scanResponse.card.encryptionKey ?.let { UserWalletEncryptionKey(userWallet.walletId, it) } @@ -237,7 +245,7 @@ internal class BiometricUserWalletsListManager( } } - private suspend fun loadModels(): CompletionResult { + private suspend fun loadModels(selectedWalletId: UserWalletId? = null): CompletionResult { return getSavedUserWallets() .map { userWallets -> if (userWallets.isNotEmpty()) { @@ -247,7 +255,7 @@ internal class BiometricUserWalletsListManager( prevState.copy( userWallets = wallets, selectedUserWalletId = findOrSetSelectedUserWalletId( - prevSelectedWalletId = prevState.selectedUserWalletId, + prevSelectedWalletId = selectedWalletId ?: prevState.selectedUserWalletId, userWallets = wallets, ), ) diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/legacy/UserWalletsListManager.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/legacy/UserWalletsListManager.kt index ff4e805ad1..db6a353f7b 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/legacy/UserWalletsListManager.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/legacy/UserWalletsListManager.kt @@ -110,6 +110,13 @@ interface UserWalletsListManager { */ suspend fun unlock(): CompletionResult + /** + * Unlock all [UserWallet]s and select passed [UserWalletId] + * + * @param selectedWalletId [UserWalletId] of [UserWallet] which must be selected + */ + suspend fun unlockAndSelect(selectedWalletId: UserWalletId): CompletionResult + /** Remove [UserWallet]s from [userWallets] and set [isLocked] as true */ fun lock() } diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/UnlockWalletsUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/UnlockWalletsUseCase.kt index 3459902720..2a713a0ac8 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/UnlockWalletsUseCase.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/UnlockWalletsUseCase.kt @@ -8,6 +8,7 @@ import com.tangem.common.doOnSuccess import com.tangem.domain.wallets.legacy.WalletsStateHolder import com.tangem.domain.wallets.legacy.asLockable import com.tangem.domain.wallets.models.UnlockWalletError +import com.tangem.domain.wallets.models.UserWalletId /** * Unlock wallets use case @@ -18,11 +19,11 @@ import com.tangem.domain.wallets.models.UnlockWalletError */ class UnlockWalletsUseCase(private val walletsStateHolder: WalletsStateHolder) { - suspend operator fun invoke(): Either { + suspend operator fun invoke(selectedWalletId: UserWalletId): Either { val userWalletsListManager = walletsStateHolder.userWalletsListManager?.asLockable() ?: return UnlockWalletError.CommonError.left() - userWalletsListManager.unlock() + userWalletsListManager.unlockAndSelect(selectedWalletId = selectedWalletId) .doOnSuccess { return Unit.right() } .doOnFailure { return UnlockWalletError.CommonError.left() } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index a182b01ae7..34ffd5f578 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -763,10 +763,14 @@ internal class WalletViewModel @Inject constructor( } override fun onUnlockWalletClick() { + val state = uiState as? WalletState.ContentState ?: return + analyticsEventsHandler.send(WalletScreenAnalyticsEvent.NoticeWalletLocked) - viewModelScope.launch(dispatchers.io) { - unlockWalletsUseCase() + viewModelScope.launch(dispatchers.main) { + unlockWalletsUseCase( + selectedWalletId = state.walletsListConfig.wallets[state.walletsListConfig.selectedWalletIndex].id, + ) } } From 4942718cc938a7008d9a3d5c9ccf59083a0094ee Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 13 Oct 2023 19:08:56 +0800 Subject: [PATCH 014/159] Updated on 2026-08-14 --- .../common/redux/global/GlobalMiddleware.kt | 9 +- .../warningMessage/WarningMessagesManager.kt | 20 +-- .../impl/presentation/ui/TokensListScreen.kt | 2 +- .../redux/middlewares/WarningsMiddleware.kt | 5 +- .../tap/features/wallet/ui/BalanceWidget.kt | 17 ++- .../wallet/ui/WalletDetailsFragment.kt | 11 +- .../wallet/ui/WalletWarningConverter.kt | 68 ++++----- .../wallet/ui/adapters/WalletAdapter.kt | 7 +- .../ui/adapters/WarningMessagesAdapter.kt | 31 ++-- .../ui/dialogs/SignedHashesWarningDialog.kt | 6 +- app/src/main/res/layout/layout_balance.xml | 69 +++++---- .../layout/layout_single_wallet_balance.xml | 139 +++++++++--------- .../layout/layout_wallet_backup_warning.xml | 88 +++++------ .../res/layout/layout_warning_card_action.xml | 23 +-- core/res/src/main/res/values-de/strings.xml | 2 - core/res/src/main/res/values-fr/strings.xml | 2 - core/res/src/main/res/values-it/strings.xml | 2 - core/res/src/main/res/values-ru/strings.xml | 57 ++++--- .../src/main/res/values-zh-rTW/strings.xml | 22 +-- core/res/src/main/res/values/strings.xml | 50 +++---- .../components/WalletBottomSheetConfig.kt | 2 +- .../state/components/WalletNotification.kt | 34 ++--- 22 files changed, 322 insertions(+), 344 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt index 9f6d1d71c0..e3c134ee2d 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt @@ -14,7 +14,6 @@ import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.dispatchWithMain import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.common.redux.AppState -import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager import com.tangem.tap.features.send.redux.SendAction import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.network.exchangeServices.BuyExchangeService @@ -84,10 +83,10 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di is GlobalAction.HideWarningMessage -> { store.state.globalState.warningManager?.let { if (it.hideWarning(action.warning)) { - if (WarningMessagesManager.isAlreadySignedHashesWarning(action.warning)) { - // TODO: No appropriate warningMessage identification. Make it better later - store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId) - } + // if (WarningMessagesManager.isAlreadySignedHashesWarning()) { + // // TODO: No appropriate warningMessage identification. Make it better later + // store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId) + // } store.dispatch(WalletAction.Warnings.Update) store.dispatch(SendAction.Warnings.Update) diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt index 183ba76207..f1345d6989 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt @@ -8,6 +8,8 @@ import java.util.concurrent.CopyOnWriteArrayList /** [REDACTED_AUTHOR] */ +// TODO: Delete with WalletFeatureToggles +@Deprecated(message = "Used only in old wallet screen") class WarningMessagesManager { private val warningsList = CopyOnWriteArrayList() @@ -73,7 +75,7 @@ class WarningMessagesManager { location = listOf(WarningMessage.Location.MainScreen), blockchains = null, titleResId = R.string.common_warning, - messageResId = R.string.alert_developer_card, + // messageResId = R.string.alert_developer_card, origin = WarningMessage.Origin.Local, ) @@ -85,7 +87,7 @@ class WarningMessagesManager { location = listOf(WarningMessage.Location.MainScreen), blockchains = null, titleResId = R.string.common_warning, - messageResId = R.string.alert_card_signed_transactions, + // messageResId = R.string.alert_card_signed_transactions, origin = WarningMessage.Origin.Local, ) @@ -96,8 +98,8 @@ class WarningMessagesManager { priority = WarningMessage.Priority.Info, location = listOf(WarningMessage.Location.MainScreen), blockchains = null, - titleResId = R.string.warning_important_security_info, - messageResId = R.string.warning_signed_tx_previously, + // titleResId = R.string.warning_important_security_info, + // messageResId = R.string.warning_signed_tx_previously, origin = WarningMessage.Origin.Local, buttonTextId = R.string.warning_button_learn_more, titleFormatArg = "\u26A0", @@ -147,7 +149,7 @@ class WarningMessagesManager { location = listOf(WarningMessage.Location.MainScreen), blockchains = null, titleResId = R.string.common_warning, - messageResId = R.string.alert_demo_message, + // messageResId = R.string.alert_demo_message, origin = WarningMessage.Origin.Local, ) @@ -160,14 +162,14 @@ class WarningMessagesManager { location = listOf(WarningMessage.Location.MainScreen), blockchains = null, titleResId = R.string.common_warning, - messageResId = R.string.warning_low_signatures_format, + // messageResId = R.string.warning_low_signatures_format, origin = WarningMessage.Origin.Local, messageFormatArg = remainingSignatures.toString(), ) } - fun isAlreadySignedHashesWarning(warning: WarningMessage): Boolean { - return warning.messageResId == R.string.alert_card_signed_transactions - } + // fun isAlreadySignedHashesWarning(warning: WarningMessage): Boolean { + // return warning.messageResId == R.string.alert_card_signed_transactions + // } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt index 67d8066531..cf7f9c448b 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt @@ -151,7 +151,7 @@ private fun DifferentAddressesWarning() { ), contentAlignment = Alignment.Center, ) { - val text = stringResource(id = R.string.alert_manage_tokens_addresses_message) + val text = stringResource(id = R.string.warning_manage_tokens_legacy_derivation_message) Text( text = text, modifier = Modifier.padding( diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt index e908e27b26..39e905255e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt @@ -19,11 +19,12 @@ import com.tangem.tap.preferencesStorage import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store -import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +// TODO: Delete with WalletFeatureToggles +@Deprecated(message = "Used only in old wallet screen") class WarningsMiddleware { fun handle(action: WalletAction.Warnings, globalState: GlobalState?) { when (action) { @@ -49,7 +50,7 @@ class WarningsMiddleware { if (action.remainingSignatures != null && action.remainingSignatures <= WarningMessagesManager.REMAINING_SIGNATURES_WARNING ) { - store.state.globalState.warningManager?.removeWarnings(R.string.warning_low_signatures_format) + // store.state.globalState.warningManager?.removeWarnings(R.string.warning_low_signatures_format) addWarningMessage( warning = WarningMessagesManager.remainingSignaturesNotEnough(action.remainingSignatures), autoUpdate = true, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt index 3cab6df274..eb7dfd7126 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/BalanceWidget.kt @@ -10,6 +10,8 @@ import com.tangem.tap.store import com.tangem.wallet.R import com.tangem.wallet.databinding.CardBalanceBinding +// TODO: Delete with WalletFeatureToggles +@Deprecated(message = "Used only in old wallet screen") class BalanceWidget( private val binding: CardBalanceBinding, private val fragment: WalletFragment, @@ -46,12 +48,11 @@ class BalanceWidget( val statusView = if (blockchainWalletData.status is WalletDataModel.VerifiedOnline) { R.id.tv_status_verified } else { - tvStatusError.text = - fragment.getText(R.string.wallet_balance_tx_in_progress) + // tvStatusError.text = fragment.getText(R.string.wallet_balance_tx_in_progress) R.id.group_error } showStatus(statusView) - tvStatusErrorMessage.hide() + // tvStatusErrorMessage.hide() if (tokenWalletData != null) { showBalanceWithToken(blockchainWalletData, true) @@ -70,12 +71,12 @@ class BalanceWidget( tvCurrency.text = currency tvAmount.text = "" - tvStatusErrorMessage.text = blockchainWalletData.status.errorMessage - tvStatusError.text = - fragment.getString(R.string.wallet_balance_blockchain_unreachable) + // tvStatusErrorMessage.text = blockchainWalletData.status.errorMessage + // TODO: Delete with WalletFeatureToggles + // tvStatusError.text = fragment.getString(R.string.wallet_balance_blockchain_unreachable) showStatus(R.id.group_error) - tvStatusErrorMessage.show(!blockchainWalletData.status.errorMessage.isNullOrBlank()) + // tvStatusErrorMessage.show(!blockchainWalletData.status.errorMessage.isNullOrBlank()) } is WalletDataModel.NoAccount -> with(binding.lBalanceError) { binding.lBalance.root.hide() @@ -93,7 +94,7 @@ class BalanceWidget( } private fun showStatus(@IdRes viewRes: Int) = with(binding.lBalance) { - groupError.show(viewRes == R.id.group_error) + // groupError.show(viewRes == R.id.group_error) tvStatusLoading.show(viewRes == R.id.tv_status_loading) tvStatusVerified.show(viewRes == R.id.tv_status_verified) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 9099193e8b..de08710457 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -62,7 +62,9 @@ import javax.inject.Inject /** * Wallet details fragment - use only for MultiWallet */ +// TODO: Delete with WalletFeatureToggles @Suppress("LargeClass", "MagicNumber") +@Deprecated(message = "Used only in old wallet screen") @AndroidEntryPoint class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), SafeStoreSubscriber { @@ -436,10 +438,11 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), SafeSt lBalance.root.show() lBalance.groupBalance.hide() lBalance.tvError.show() - lBalance.tvError.setWarningStatus( - R.string.wallet_balance_blockchain_unreachable, - status.errorMessage, - ) + // TODO: Delete with WalletFeatureToggles + // lBalance.tvError.setWarningStatus( + // R.string.wallet_balance_blockchain_unreachable, + // status.errorMessage, + // ) } is WalletDataModel.NoAccount -> { lBalance.root.hide() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt index afbf3bff5a..5f98692fca 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletWarningConverter.kt @@ -9,43 +9,45 @@ import com.tangem.wallet.R /** [REDACTED_AUTHOR] */ +// TODO: Delete with WalletFeatureToggles +@Deprecated(message = "Used only in old wallet screen") class WalletWarningConverter( private val context: Context, ) : ModuleMessageConverter { override fun convert(message: WalletWarning): WalletWarningDescription { - val warningMessage = when (message) { - is WalletWarning.ExistentialDeposit -> { - context.getString( - R.string.warning_existential_deposit_message, - message.currencyName, - message.edStringValueWithSymbol, - ) - } - is WalletWarning.BalanceNotEnoughForFee -> { - context.getString( - R.string.token_details_send_blocked_fee_format, - message.currencyName, - message.blockchainFullName, - message.currencyName, - message.blockchainFullName, - message.blockchainSymbol, - ) - } - is WalletWarning.TransactionInProgress -> { - context.getString( - R.string.token_details_send_blocked_tx_format, - message.currencyName, - ) - } - is WalletWarning.Rent -> { - context.getString( - R.string.solana_rent_warning, - message.walletRent.rent, - message.walletRent.exemptionAmount, - ) - } - } - return WalletWarningDescription(context.getString(R.string.common_warning), warningMessage) + // val warningMessage = when (message) { + // is WalletWarning.ExistentialDeposit -> { + // context.getString( + // R.string.warning_existential_deposit_message, + // message.currencyName, + // message.edStringValueWithSymbol, + // ) + // } + // is WalletWarning.BalanceNotEnoughForFee -> { + // context.getString( + // R.string.token_details_send_blocked_fee_format, + // message.currencyName, + // message.blockchainFullName, + // message.currencyName, + // message.blockchainFullName, + // message.blockchainSymbol, + // ) + // } + // is WalletWarning.TransactionInProgress -> { + // context.getString( + // R.string.token_details_send_blocked_tx_format, + // message.currencyName, + // ) + // } + // is WalletWarning.Rent -> { + // context.getString( + // R.string.solana_rent_warning, + // message.walletRent.rent, + // message.walletRent.exemptionAmount, + // ) + // } + // } + return WalletWarningDescription(context.getString(R.string.common_warning), "") } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt index 3f511f7b65..0b1e671dab 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WalletAdapter.kt @@ -22,6 +22,8 @@ import com.tangem.tap.store import com.tangem.wallet.R import com.tangem.wallet.databinding.ItemCurrencyWalletBinding +// TODO: Delete with WalletFeatureToggles +@Deprecated(message = "Used only in old wallet screen") class WalletAdapter : ListAdapter(DiffUtilCallback) { override fun getItemId(position: Int): Long { @@ -59,7 +61,8 @@ class WalletAdapter : ListAdapter { - root.getString(R.string.wallet_balance_blockchain_unreachable) + // TODO: Delete with WalletFeatureToggles + // root.getString(R.string.wallet_balance_blockchain_unreachable) } is WalletDataModel.MissedDerivation -> { root.getString(R.string.wallet_balance_missing_derivation) @@ -86,7 +89,7 @@ class WalletAdapter : ListAdapter(DiffUtilCallback) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WarningMessageVH { @@ -94,11 +91,11 @@ class WarningMessageVH(val binding: LayoutWarningCardActionBinding) : RecyclerVi val buttonAction = when (warning.titleResId) { - R.string.warning_important_security_info -> { - View.OnClickListener { - store.dispatch(WalletAction.DialogAction.SignedHashesMultiWalletDialog) - } - } + // R.string.warning_important_security_info -> { + // View.OnClickListener { + // store.dispatch(WalletAction.DialogAction.SignedHashesMultiWalletDialog) + // } + // } else -> { View.OnClickListener { store.dispatch(GlobalAction.HideWarningMessage(warning)) @@ -120,12 +117,12 @@ class WarningMessageVH(val binding: LayoutWarningCardActionBinding) : RecyclerVi store.dispatch(GlobalAction.HideWarningMessage(warning)) store.dispatch(WalletAction.Warnings.AppRating.RemindLater) } - binding.btnCanBeBetter.setOnClickListener { - Analytics.send(MainScreen.NoticeRateAppButton(AnalyticsParam.RateApp.Disliked)) - store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow) - store.dispatch(GlobalAction.HideWarningMessage(warning)) - store.dispatch(GlobalAction.SendEmail(RateCanBeBetterEmail())) - } + // binding.btnCanBeBetter.setOnClickListener { + // Analytics.send(MainScreen.NoticeRateAppButton(AnalyticsParam.RateApp.Disliked)) + // store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow) + // store.dispatch(GlobalAction.HideWarningMessage(warning)) + // store.dispatch(GlobalAction.SendEmail(RateCanBeBetterEmail())) + // } binding.btnReallyCool.setOnClickListener { val activity = binding.root.context.getActivity() ?: return@setOnClickListener diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SignedHashesWarningDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SignedHashesWarningDialog.kt index f4de1c7672..8ebbffeb54 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SignedHashesWarningDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SignedHashesWarningDialog.kt @@ -9,11 +9,13 @@ import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.store import com.tangem.wallet.R +// TODO: Delete with WalletFeatureToggles +@Deprecated(message = "Used only in old wallet screen") object SignedHashesWarningDialog { fun create(context: Context): AlertDialog { return MaterialAlertDialogBuilder(context, R.style.CustomMaterialDialog).apply { - setTitle(context.getString(R.string.warning_important_security_info, "\u26A0")) - setMessage(R.string.alert_signed_hashes_message) + // setTitle(context.getString(R.string.warning_important_security_info, "\u26A0")) + // setMessage(R.string.alert_signed_hashes_message) setPositiveButton(R.string.common_understand) { _, _ -> store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId) store.dispatch( diff --git a/app/src/main/res/layout/layout_balance.xml b/app/src/main/res/layout/layout_balance.xml index 6addd2be86..4141bd7302 100644 --- a/app/src/main/res/layout/layout_balance.xml +++ b/app/src/main/res/layout/layout_balance.xml @@ -38,41 +38,40 @@ app:layout_constraintTop_toBottomOf="@id/tv_currency" tools:visibility="visible" /> - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + android:paddingBottom="4dp" + android:src="@drawable/img_warning_triangle_24" + android:scaleType="center" + android:background="@drawable/shape_ellipse" + android:backgroundTint="@color/buttonGray" + android:contentDescription="@null" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" /> - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_warning_card_action.xml b/app/src/main/res/layout/layout_warning_card_action.xml index e85e77d3e5..bbb58fab01 100644 --- a/app/src/main/res/layout/layout_warning_card_action.xml +++ b/app/src/main/res/layout/layout_warning_card_action.xml @@ -45,17 +45,18 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/warning_content_container" /> -