diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index aa64c0d699..3cf379b69f 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -20,6 +20,9 @@ configurations.all {
substitute(module("com.facebook.react:hermes-engine"))
.using(module("com.facebook.react:hermes-android:0.72.4"))
+
+ substitute(module("org.bouncycastle:bcprov-jdk15on"))
+ .using(module("org.bouncycastle:bcprov-jdk18on:1.73"))
}
force(
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 32e44932c0..99e803e45b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -120,7 +120,7 @@
diff --git a/app/src/main/assets/testnet_tokens.json b/app/src/main/assets/testnet_tokens.json
index 6be450bd32..b09a1ffa91 100644
--- a/app/src/main/assets/testnet_tokens.json
+++ b/app/src/main/assets/testnet_tokens.json
@@ -434,6 +434,16 @@
}
]
},
+ {
+ "id" : "algorand",
+ "symbol" : "ALGO",
+ "name" : "Algorand",
+ "networks" : [
+ {
+ "networkId" : "algorand/test"
+ }
+ ]
+ },
{
"id" : "arbitrum-one",
"symbol" : "ETH",
@@ -569,6 +579,16 @@
}
]
},
+ {
+ "id": "shibarium",
+ "name": "Shibarium",
+ "symbol": "BONE",
+ "networks": [
+ {
+ "networkId": "shibarium/test"
+ }
+ ]
+ },
{
"id": "aptos",
"name": "Aptos",
@@ -578,6 +598,16 @@
"networkId": "aptos/test"
}
]
+ },
+ {
+ "id": "hedera-hashgraph",
+ "name": "Hedera",
+ "symbol": "HBAR",
+ "networks": [
+ {
+ "networkId": "hedera-hashgraph/test"
+ }
+ ]
}
]
}
diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt
index 4ef519edbd..04b3f17541 100644
--- a/app/src/main/java/com/tangem/tap/MainActivity.kt
+++ b/app/src/main/java/com/tangem/tap/MainActivity.kt
@@ -37,7 +37,7 @@ import com.tangem.domain.card.ScanCardUseCase
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.feature.qrscanning.QrScanningRouter
-import com.tangem.features.managetokens.navigation.ManageTokensRouter
+import com.tangem.features.managetokens.navigation.ManageTokensUi
import com.tangem.features.send.api.navigation.SendRouter
import com.tangem.features.tester.api.TesterRouter
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
@@ -126,7 +126,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
lateinit var tokenDetailsRouter: TokenDetailsRouter
@Inject
- lateinit var manageTokensRouter: ManageTokensRouter
+ lateinit var manageTokensUi: ManageTokensUi
@Inject
lateinit var walletConnectInteractor: WalletConnectInteractor
@@ -213,7 +213,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
walletRouter = walletRouter,
walletConnectInteractor = walletConnectInteractor,
tokenDetailsRouter = tokenDetailsRouter,
- manageTokensRouter = manageTokensRouter,
+ manageTokensUi = manageTokensUi,
cardSdkConfigRepository = cardSdkConfigRepository,
sendRouter = sendRouter,
qrScanningRouter = qrScanningRouter,
diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt
index f892dddee4..e4337c01f6 100644
--- a/app/src/main/java/com/tangem/tap/TapApplication.kt
+++ b/app/src/main/java/com/tangem/tap/TapApplication.kt
@@ -10,6 +10,8 @@ import com.orhanobut.logger.AndroidLogAdapter
import com.orhanobut.logger.Logger
import com.tangem.Log
import com.tangem.LogFormat
+import com.tangem.blockchain.common.AccountCreator
+import com.tangem.blockchain.common.datastorage.BlockchainDataStorage
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.filter.OneTimeEventFilter
@@ -28,7 +30,6 @@ import com.tangem.domain.apptheme.GetAppThemeModeUseCase
import com.tangem.domain.apptheme.repository.AppThemeModeRepository
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
import com.tangem.domain.card.ScanCardProcessor
-import com.tangem.domain.card.repository.DerivationsRepository
import com.tangem.domain.common.LogConfig
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
@@ -37,10 +38,8 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
import com.tangem.features.send.api.featuretoggles.SendFeatureToggles
-import com.tangem.features.tester.api.TesterFeatureToggles
import com.tangem.tap.common.analytics.AnalyticsFactory
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
-import com.tangem.tap.common.analytics.handlers.BlockchainExceptionHandler
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler
import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
@@ -118,9 +117,6 @@ internal class TapApplication : Application(), ImageLoaderFactory {
@Inject
lateinit var scanCardProcessor: ScanCardProcessor
- @Inject
- lateinit var blockchainExceptionHandler: BlockchainExceptionHandler
-
@Inject
lateinit var appCurrencyRepository: AppCurrencyRepository
@@ -155,10 +151,10 @@ internal class TapApplication : Application(), ImageLoaderFactory {
lateinit var oneTimeEventFilter: OneTimeEventFilter
@Inject
- lateinit var derivationsRepository: DerivationsRepository
+ lateinit var blockchainDataStorage: BlockchainDataStorage
@Inject
- lateinit var testerFeatureToggles: TesterFeatureToggles
+ lateinit var accountCreator: AccountCreator
// endregion Injected
override fun onCreate() {
@@ -234,8 +230,8 @@ internal class TapApplication : Application(), ImageLoaderFactory {
balanceHidingRepository = balanceHidingRepository,
walletsRepository = walletsRepository,
sendFeatureToggles = sendFeatureToggles,
- derivationsRepository = derivationsRepository,
- testerFeatureToggles = testerFeatureToggles,
+ blockchainDataStorage = blockchainDataStorage,
+ accountCreator = accountCreator,
),
),
)
diff --git a/app/src/main/java/com/tangem/tap/common/CustomTabsManager.kt b/app/src/main/java/com/tangem/tap/common/CustomTabsManager.kt
index a913befc98..08f62eee72 100644
--- a/app/src/main/java/com/tangem/tap/common/CustomTabsManager.kt
+++ b/app/src/main/java/com/tangem/tap/common/CustomTabsManager.kt
@@ -1,6 +1,8 @@
package com.tangem.tap.common
import android.content.Context
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
+import android.content.Intent.FLAG_ACTIVITY_NO_HISTORY
import android.net.Uri
import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent
@@ -22,6 +24,10 @@ class CustomTabsManager {
if (MutableAppThemeModeHolder.isDarkThemeActive) COLOR_SCHEME_DARK else COLOR_SCHEME_LIGHT,
)
.build()
+
+ // Open CustomTabsActivity as new task without saving into the stack
+ customTabsIntent.intent.setFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_NO_HISTORY)
+
customTabsIntent.launchUrl(context, Uri.parse(url))
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt
index 13c04ec76f..ed47afa57c 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt
@@ -1,7 +1,6 @@
package com.tangem.tap.common.analytics.events
import com.tangem.core.analytics.models.AnalyticsEvent
-import com.tangem.tap.common.extensions.filterNotNull
/**
[REDACTED_AUTHOR]
@@ -42,17 +41,22 @@ sealed class WalletConnect(
val methodName: String,
val blockchain: String,
val errorCode: String? = null,
+ val errorDescription: String? = null,
) {
fun toParamsMap(): Map {
val validation = if (errorCode == null) Validation.SUCCESS.param else Validation.FAIL.param
- return mapOf(
- AnalyticsParam.DAPP_NAME to dAppName,
- AnalyticsParam.DAPP_URL to dAppUrl,
- AnalyticsParam.METHOD_NAME to methodName,
- AnalyticsParam.BLOCKCHAIN to blockchain,
- AnalyticsParam.VALIDATION to validation,
- if (errorCode != null) AnalyticsParam.ERROR_CODE to errorCode else null to null,
- ).filterNotNull()
+ val code = errorCode ?: SUCCESS_CODE
+ return buildMap {
+ put(AnalyticsParam.DAPP_NAME, dAppName)
+ put(AnalyticsParam.DAPP_URL, dAppUrl)
+ put(AnalyticsParam.METHOD_NAME, methodName)
+ put(AnalyticsParam.BLOCKCHAIN, blockchain)
+ put(AnalyticsParam.VALIDATION, validation)
+ put(AnalyticsParam.ERROR_CODE, code)
+ if (errorDescription != null) {
+ put(AnalyticsParam.ERROR_DESCRIPTION, errorDescription)
+ }
+ }
}
}
@@ -60,4 +64,8 @@ sealed class WalletConnect(
SUCCESS("Success"),
FAIL("Fail"),
}
+
+ companion object {
+ private const val SUCCESS_CODE = "0"
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt
index 6dc414e945..fa0d174bf9 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt
@@ -151,18 +151,7 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
AppScreen.ResetToFactory -> ResetCardFragment()
AppScreen.AccessCodeRecovery -> AccessCodeRecoveryFragment()
AppScreen.Disclaimer -> DisclaimerFragment()
- AppScreen.ManageTokens -> {
- val featureToggles = store.state.daggerGraphState.get(
- getDependency = DaggerGraphState::manageTokensFeatureToggles,
- )
- if (featureToggles.isRedesignedScreenEnabled) {
- store.state.daggerGraphState
- .get(getDependency = DaggerGraphState::manageTokensRouter)
- .getEntryFragment()
- } else {
- TokensListFragment()
- }
- }
+ AppScreen.ManageTokens -> TokensListFragment()
AppScreen.AddCustomToken -> AddCustomTokenFragment()
AppScreen.WalletDetails -> {
store.state.daggerGraphState
diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt
index e312758a52..892271058e 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt
@@ -33,7 +33,6 @@ import com.tangem.tap.features.shop.redux.ShopMiddleware
import com.tangem.tap.features.shop.redux.ShopState
import com.tangem.tap.features.signin.redux.SignInMiddleware
import com.tangem.tap.features.signin.redux.SignInState
-import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware
import com.tangem.tap.features.tokens.legacy.redux.TokensState
import com.tangem.tap.features.wallet.redux.middlewares.TradeCryptoMiddleware
import com.tangem.tap.features.welcome.redux.WelcomeMiddleware
@@ -91,7 +90,6 @@ data class AppState(
SendMiddleware().sendMiddleware,
DetailsMiddleware().detailsMiddleware,
DisclaimerMiddleware().disclaimerMiddleware,
- TokensMiddleware.tokensMiddleware,
WalletConnectMiddleware().walletConnectMiddleware,
BackupMiddleware().backupMiddleware,
ShopMiddleware().shopMiddleware,
diff --git a/app/src/main/java/com/tangem/tap/common/text/Truncate.kt b/app/src/main/java/com/tangem/tap/common/text/Truncate.kt
index 64aeea2d59..9131ec1023 100644
--- a/app/src/main/java/com/tangem/tap/common/text/Truncate.kt
+++ b/app/src/main/java/com/tangem/tap/common/text/Truncate.kt
@@ -77,7 +77,7 @@ class TruncateStart : BaseTruncate() {
class TruncateMiddle : BaseTruncate() {
override fun roughTruncate(text: String, residualLength: Int): String {
- if (text.length <= residualLength) return text
+ if (text.length <= residualLength || residualLength < 0) return text
hasBeenTruncated = true
val halfOfResidualLength = residualLength / 2
diff --git a/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt
index 0d32faca9a..76aa092682 100644
--- a/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt
+++ b/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt
@@ -8,8 +8,6 @@ import com.tangem.domain.demo.DemoConfig
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.wallets.legacy.WalletsStateHolder
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
-import com.tangem.tap.domain.TangemSdkManager
-import com.tangem.tap.domain.card.DefaultDerivePublicKeysUseCase
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@@ -62,14 +60,8 @@ internal object CardDomainModule {
@Provides
@ViewModelScoped
- fun provideDerivePublicKeysUseCase(
- tangemSdkManager: TangemSdkManager,
- derivationsRepository: DerivationsRepository,
- ): DerivePublicKeysUseCase {
- return DefaultDerivePublicKeysUseCase(
- tangemSdkManager = tangemSdkManager,
- derivationsRepository = derivationsRepository,
- )
+ fun provideDerivePublicKeysUseCase(derivationsRepository: DerivationsRepository): DerivePublicKeysUseCase {
+ return DerivePublicKeysUseCase(derivationsRepository = derivationsRepository)
}
@Provides
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 7149fc13da..c67960a860 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
@@ -99,6 +99,7 @@ internal object TokensDomainModule {
networksRepository: NetworksRepository,
marketCryptoCurrencyRepository: MarketCryptoCurrencyRepository,
swapRepository: SwapRepository,
+ currencyChecksRepository: CurrencyChecksRepository,
showSwapPromoTokenUseCase: ShouldShowSwapPromoTokenUseCase,
promoRepository: PromoRepository,
dispatchers: CoroutineDispatcherProvider,
@@ -109,6 +110,7 @@ internal object TokensDomainModule {
quotesRepository = quotesRepository,
networksRepository = networksRepository,
marketCryptoCurrencyRepository = marketCryptoCurrencyRepository,
+ currencyChecksRepository = currencyChecksRepository,
swapRepository = swapRepository,
showSwapPromoTokenUseCase = showSwapPromoTokenUseCase,
promoRepository = promoRepository,
diff --git a/app/src/main/java/com/tangem/tap/di/domain/VisaDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/VisaDomainModule.kt
index 61170463f0..479be1cc3c 100644
--- a/app/src/main/java/com/tangem/tap/di/domain/VisaDomainModule.kt
+++ b/app/src/main/java/com/tangem/tap/di/domain/VisaDomainModule.kt
@@ -1,18 +1,34 @@
package com.tangem.tap.di.domain
import com.tangem.domain.visa.GetVisaCurrencyUseCase
+import com.tangem.domain.visa.GetVisaTxDetailsUseCase
+import com.tangem.domain.visa.GetVisaTxHistoryUseCase
import com.tangem.domain.visa.repository.VisaRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ViewModelComponent
+import dagger.hilt.android.scopes.ViewModelScoped
@Module
@InstallIn(ViewModelComponent::class)
internal object VisaDomainModule {
@Provides
+ @ViewModelScoped
fun provideVisaCurrencyUseCase(visaRepository: VisaRepository): GetVisaCurrencyUseCase {
return GetVisaCurrencyUseCase(visaRepository)
}
+
+ @Provides
+ @ViewModelScoped
+ fun provideGetVisaTxHistoryUseCase(visaRepository: VisaRepository): GetVisaTxHistoryUseCase {
+ return GetVisaTxHistoryUseCase(visaRepository)
+ }
+
+ @Provides
+ @ViewModelScoped
+ fun provideGetVisaTxDetailsUseCase(visaRepository: VisaRepository): GetVisaTxDetailsUseCase {
+ return GetVisaTxDetailsUseCase(visaRepository)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/di/domain/WalletManagersFacadeModule.kt b/app/src/main/java/com/tangem/tap/di/domain/WalletManagersFacadeModule.kt
index 02a52ce342..3fedeef4ca 100644
--- a/app/src/main/java/com/tangem/tap/di/domain/WalletManagersFacadeModule.kt
+++ b/app/src/main/java/com/tangem/tap/di/domain/WalletManagersFacadeModule.kt
@@ -1,6 +1,8 @@
package com.tangem.tap.di.domain
import com.squareup.moshi.Moshi
+import com.tangem.blockchain.common.AccountCreator
+import com.tangem.blockchain.common.datastorage.BlockchainDataStorage
import com.tangem.datasource.asset.AssetReader
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.di.SdkMoshi
@@ -25,6 +27,8 @@ internal object WalletManagersFacadeModule {
walletManagersStore: WalletManagersStore,
userWalletsStore: UserWalletsStore,
configManager: ConfigManager,
+ blockchainDataStorage: BlockchainDataStorage,
+ accountCreator: AccountCreator,
mnemonicRepository: MnemonicRepository,
assetReader: AssetReader,
@SdkMoshi moshi: Moshi,
@@ -33,9 +37,11 @@ internal object WalletManagersFacadeModule {
walletManagersStore = walletManagersStore,
userWalletsStore = userWalletsStore,
configManager = configManager,
+ blockchainDataStorage = blockchainDataStorage,
assetReader = assetReader,
moshi = moshi,
mnemonic = mnemonicRepository.generateDefaultMnemonic(),
+ accountCreator = accountCreator,
)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt
index 8d9ba42e6a..24db8bcbc8 100644
--- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt
+++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt
@@ -5,19 +5,20 @@ import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.core.analytics.Analytics
+import com.tangem.core.analytics.models.Basic
import com.tangem.datasource.config.ConfigManager
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.operations.attestation.Attestation
-import com.tangem.core.analytics.models.Basic
import com.tangem.tap.common.extensions.setContext
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
import com.tangem.tap.features.disclaimer.createDisclaimer
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
+import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
@@ -40,8 +41,13 @@ class TapWalletManager(
field = value
}
- val walletManagerFactory: WalletManagerFactory
- by lazy { WalletManagerFactory(blockchainSdkConfig) }
+ val walletManagerFactory: WalletManagerFactory by lazy {
+ WalletManagerFactory(
+ config = blockchainSdkConfig,
+ accountCreator = store.state.daggerGraphState.get(DaggerGraphState::accountCreator),
+ blockchainDataStorage = store.state.daggerGraphState.get(DaggerGraphState::blockchainDataStorage),
+ )
+ }
suspend fun onWalletSelected(userWallet: UserWallet, sendAnalyticsEvent: Boolean) {
// If a previous job was running, it gets cancelled before the new one starts,
diff --git a/app/src/main/java/com/tangem/tap/domain/card/DefaultDerivePublicKeysUseCase.kt b/app/src/main/java/com/tangem/tap/domain/card/DefaultDerivePublicKeysUseCase.kt
deleted file mode 100644
index a09df2969a..0000000000
--- a/app/src/main/java/com/tangem/tap/domain/card/DefaultDerivePublicKeysUseCase.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.tangem.tap.domain.card
-
-import arrow.core.Either
-import arrow.core.left
-import arrow.core.right
-import com.tangem.common.doOnFailure
-import com.tangem.common.doOnSuccess
-import com.tangem.common.extensions.ByteArrayKey
-import com.tangem.crypto.hdWallet.DerivationPath
-import com.tangem.domain.card.DerivePublicKeysUseCase
-import com.tangem.domain.card.repository.DerivationsRepository
-import com.tangem.domain.tokens.model.CryptoCurrency
-import com.tangem.domain.wallets.models.UserWalletId
-import com.tangem.operations.derivation.DerivationTaskResponse
-import com.tangem.tap.domain.TangemSdkManager
-
-internal class DefaultDerivePublicKeysUseCase(
- private val tangemSdkManager: TangemSdkManager,
- private val derivationsRepository: DerivationsRepository,
-) : DerivePublicKeysUseCase {
-
- override suspend fun invoke(
- cardId: String?,
- derivations: Map>,
- ): Either {
- tangemSdkManager.derivePublicKeys(cardId = cardId, derivations = derivations)
- .doOnSuccess { return it.right() }
- .doOnFailure { return Unit.left() }
-
- return Unit.left()
- }
-
- override suspend fun invoke(
- userWalletId: UserWalletId,
- currencies: List,
- ): Either {
- return Either.catch {
- derivationsRepository.derivePublicKeys(userWalletId, currencies)
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/WalletConnectRepositoryImpl.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/WalletConnectRepositoryImpl.kt
index ab1355fae2..4f37c03839 100644
--- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/WalletConnectRepositoryImpl.kt
+++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/WalletConnectRepositoryImpl.kt
@@ -352,7 +352,8 @@ class WalletConnectRepositoryImpl @Inject constructor(
dAppUrl = session?.url ?: "",
methodName = requestData.method,
blockchain = requestData.blockchain,
- errorCode = WalletConnectError.ValidationError.toString(),
+ errorCode = WalletConnectError.ValidationError.error,
+ errorDescription = it.throwable.message,
)
},
)
diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectError.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectError.kt
index ca01b701a7..efb5215bd7 100644
--- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectError.kt
+++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectError.kt
@@ -1,12 +1,24 @@
package com.tangem.tap.domain.walletconnect2.domain.models
-sealed class WalletConnectError : Exception() {
- data class ApprovalErrorMissingNetworks(val missingChains: List) : WalletConnectError()
- data class ApprovalErrorAddNetwork(val networks: List) : WalletConnectError()
- data class ApprovalErrorUnsupportedNetwork(val unsupportedNetworks: List) : WalletConnectError()
- data class ExternalApprovalError(override val message: String?) : WalletConnectError()
- object WrongUserWallet : WalletConnectError()
- object UnsupportedMethod : WalletConnectError()
- object SigningError : WalletConnectError()
- object ValidationError : WalletConnectError()
+sealed class WalletConnectError(val error: String) : Exception() {
+ data class ApprovalErrorMissingNetworks(
+ val missingChains: List,
+ ) : WalletConnectError("ApprovalErrorMissingNetworks")
+
+ data class ApprovalErrorAddNetwork(
+ val networks: List,
+ ) : WalletConnectError("ApprovalErrorAddNetwork")
+
+ data class ApprovalErrorUnsupportedNetwork(
+ val unsupportedNetworks: List,
+ ) : WalletConnectError("ApprovalErrorUnsupportedNetwork")
+
+ data class ExternalApprovalError(
+ override val message: String?,
+ ) : WalletConnectError("ExternalApprovalError")
+
+ object WrongUserWallet : WalletConnectError("WrongUserWallet")
+ object UnsupportedMethod : WalletConnectError("UnsupportedMethod")
+ object SigningError : WalletConnectError("SigningError")
+ object ValidationError : WalletConnectError("ValidationError")
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/di/CustomTokenInteractorModule.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/di/CustomTokenInteractorModule.kt
index 44d4a98284..61dc90c2dc 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/di/CustomTokenInteractorModule.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/di/CustomTokenInteractorModule.kt
@@ -3,7 +3,6 @@ package com.tangem.tap.features.customtoken.impl.di
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.domain.card.DerivePublicKeysUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
-import com.tangem.features.tester.api.TesterFeatureToggles
import com.tangem.tap.features.customtoken.impl.data.DefaultCustomTokenRepository
import com.tangem.tap.features.customtoken.impl.domain.CustomTokenInteractor
import com.tangem.tap.features.customtoken.impl.domain.DefaultCustomTokenInteractor
@@ -30,7 +29,6 @@ internal object CustomTokenInteractorModule {
reduxStateHolder: AppStateHolder,
getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
derivePublicKeysUseCase: DerivePublicKeysUseCase,
- testerFeatureToggles: TesterFeatureToggles,
): CustomTokenInteractor {
return DefaultCustomTokenInteractor(
featureRepository = DefaultCustomTokenRepository(
@@ -40,7 +38,6 @@ internal object CustomTokenInteractorModule {
),
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
derivePublicKeysUseCase = derivePublicKeysUseCase,
- testerFeatureToggles = testerFeatureToggles,
)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/domain/DefaultCustomTokenInteractor.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/domain/DefaultCustomTokenInteractor.kt
index 2d6ad2aebf..f3f73a98d3 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/domain/DefaultCustomTokenInteractor.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/domain/DefaultCustomTokenInteractor.kt
@@ -1,40 +1,19 @@
package com.tangem.tap.features.customtoken.impl.domain
-import com.tangem.blockchain.blockchains.cardano.CardanoUtils
import com.tangem.blockchain.common.Blockchain
-import com.tangem.common.CompletionResult
-import com.tangem.common.card.EllipticCurve
-import com.tangem.common.core.TangemError
-import com.tangem.common.extensions.ByteArrayKey
-import com.tangem.common.extensions.toMapKey
-import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
import com.tangem.domain.card.DerivePublicKeysUseCase
-import com.tangem.domain.common.configs.CardConfig
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.domain.common.util.derivationStyleProvider
-import com.tangem.domain.common.util.hasDerivation
import com.tangem.domain.features.addCustomToken.CustomCurrency
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
import com.tangem.domain.tokens.model.CryptoCurrency
-import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
-import com.tangem.features.tester.api.TesterFeatureToggles
-import com.tangem.operations.derivation.ExtendedPublicKeysMap
-import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
-import com.tangem.tap.common.extensions.dispatchOnMain
-import com.tangem.tap.common.redux.global.GlobalAction
-import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.model.Currency
import com.tangem.tap.features.customtoken.impl.domain.models.FoundToken
-import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
-import com.tangem.tap.tangemSdkManager
-import com.tangem.tap.userWalletsListManager
-import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
-import kotlinx.coroutines.delay
import timber.log.Timber
/**
@@ -48,7 +27,6 @@ class DefaultCustomTokenInteractor(
private val featureRepository: CustomTokenRepository,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val derivePublicKeysUseCase: DerivePublicKeysUseCase,
- private val testerFeatureToggles: TesterFeatureToggles,
) : CustomTokenInteractor {
// TODO: Move to DI
@@ -70,136 +48,12 @@ class DefaultCustomTokenInteractor(
val userWallet = getSelectedWalletSyncUseCase().fold(ifLeft = { return }, ifRight = { it })
val currency = Currency.fromCustomCurrency(customCurrency)
- if (testerFeatureToggles.isDerivePublicKeysRefactoringEnabled) {
- val currencies = listOfNotNull(element = currency.toCryptoCurrency(userWallet.scanResponse))
- derivePublicKeysUseCase(userWalletId = userWallet.walletId, currencies = currencies)
- .onRight {
- addCryptoCurrenciesUseCase(userWalletId = userWallet.walletId, currencies = currencies)
- }
- .onLeft { Timber.e("Failed to derive public keys: $it") }
- } else {
- // TODO: delete [REDACTED_JIRA]
- val isNeedToDerive = isNeedToDerive(userWallet, currency)
- if (isNeedToDerive) {
- deriveMissingBlockchains(
- userWallet = userWallet,
- currencyList = listOf(currency),
- onSuccess = { submitAdd(userWallet = userWallet.copy(scanResponse = it), currency = currency) },
- ) {
- throw it
- }
- } else {
- submitAdd(userWallet, currency)
+ val currencies = listOfNotNull(element = currency.toCryptoCurrency(userWallet.scanResponse))
+ derivePublicKeysUseCase(userWalletId = userWallet.walletId, currencies = currencies)
+ .onRight {
+ addCryptoCurrenciesUseCase(userWalletId = userWallet.walletId, currencies = currencies)
}
- }
- }
-
- private fun isNeedToDerive(userWallet: UserWallet, currency: Currency): Boolean {
- val scanResponse = userWallet.scanResponse
- return currency.derivationPath?.let { !scanResponse.hasDerivation(currency.blockchain, it) } ?: false
- }
-
- private suspend fun deriveMissingBlockchains(
- userWallet: UserWallet,
- currencyList: List,
- onSuccess: suspend (ScanResponse) -> Unit,
- onFailure: suspend (TangemError) -> Unit,
- ) {
- val scanResponse = userWallet.scanResponse
- val config = CardConfig.createConfig(scanResponse.card)
- val derivationDataList = currencyList.mapNotNull { currency ->
- val curve = config.primaryCurve(currency.blockchain)
- curve?.let { getDerivations(curve, scanResponse, currency) }
- }
-
- val derivations = buildMap> {
- derivationDataList.forEach {
- val current = this[it.derivations.first]
- if (current != null) {
- current.addAll(it.derivations.second)
- current.distinct()
- } else {
- this[it.derivations.first] = it.derivations.second.toMutableList()
- }
- }
- }
- if (derivations.isEmpty()) {
- onSuccess(scanResponse)
- return
- }
-
- when (val result = tangemSdkManager.derivePublicKeys(cardId = null, derivations = derivations)) {
- is CompletionResult.Success -> {
- val newDerivedKeys = result.data.entries
- val oldDerivedKeys = scanResponse.derivedKeys
-
- val walletKeys = (newDerivedKeys.keys + oldDerivedKeys.keys).toSet()
-
- val updatedDerivedKeys = walletKeys.associateWith { walletKey ->
- val oldDerivations = ExtendedPublicKeysMap(oldDerivedKeys[walletKey] ?: emptyMap())
- val newDerivations = newDerivedKeys[walletKey] ?: ExtendedPublicKeysMap(emptyMap())
- ExtendedPublicKeysMap(oldDerivations + newDerivations)
- }
-
- val updatedScanResponse = scanResponse.copy(derivedKeys = updatedDerivedKeys)
- store.dispatchOnMain(GlobalAction.SaveScanResponse(updatedScanResponse))
- delay(DELAY_SDK_DIALOG_CLOSE)
-
- onSuccess(updatedScanResponse)
- }
- is CompletionResult.Failure -> {
- onFailure.invoke(result.error)
- store.dispatchDebugErrorNotification(TapError.CustomError("Error adding tokens"))
- }
- }
- }
-
- private fun getDerivations(
- curve: EllipticCurve,
- scanResponse: ScanResponse,
- currency: Currency,
- ): TokensMiddleware.DerivationData? {
- val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null
-
- val supportedCurves = currency.blockchain.getSupportedCurves()
- val path = currency.blockchain.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
- .takeIf { supportedCurves.contains(curve) }
-
- val customPath = currency.derivationPath?.let {
- DerivationPath(it)
- }.takeIf { supportedCurves.contains(curve) }
-
- val bothCandidates = listOfNotNull(path, customPath).distinct().toMutableList()
- if (bothCandidates.isEmpty()) return null
-
- if (currency is Currency.Blockchain && currency.blockchain == Blockchain.Cardano) {
- currency.derivationPath?.let {
- bothCandidates.add(CardanoUtils.extendedDerivationPath(DerivationPath(it)))
- }
- }
-
- val mapKeyOfWalletPublicKey = wallet.publicKey.toMapKey()
- val alreadyDerivedKeys: ExtendedPublicKeysMap =
- scanResponse.derivedKeys[mapKeyOfWalletPublicKey] ?: ExtendedPublicKeysMap(emptyMap())
- val alreadyDerivedPaths = alreadyDerivedKeys.keys.toList()
-
- val toDerive = bothCandidates.filterNot { alreadyDerivedPaths.contains(it) }
- if (toDerive.isEmpty()) return null
-
- return TokensMiddleware.DerivationData(derivations = mapKeyOfWalletPublicKey to toDerive)
- }
-
- private suspend fun submitAdd(userWallet: UserWallet, currency: Currency) {
- val scanResponse = userWallet.scanResponse
- val userWalletId = userWallet.walletId
-
- val currencyList = listOfNotNull(element = currency.toCryptoCurrency(scanResponse))
-
- userWalletsListManager.update(userWalletId) {
- it.copy(scanResponse = scanResponse)
- }
-
- addCryptoCurrenciesUseCase(userWalletId, currencyList)
+ .onLeft { Timber.e("Failed to derive public keys: $it") }
}
private fun Currency.toCryptoCurrency(scanResponse: ScanResponse): CryptoCurrency? {
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/validators/ContactAddressValidator.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/validators/ContractAddressValidator.kt
similarity index 87%
rename from app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/validators/ContactAddressValidator.kt
rename to app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/validators/ContractAddressValidator.kt
index b522a922b1..5db91d6354 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/validators/ContactAddressValidator.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/validators/ContractAddressValidator.kt
@@ -3,21 +3,21 @@ package com.tangem.tap.features.customtoken.impl.presentation.validators
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.address.AddressService
import com.tangem.common.card.EllipticCurve
-import com.tangem.domain.AddCustomTokenError
+import com.tangem.domain.tokens.error.AddCustomTokenError
/**
* Validator of contract address
*
[REDACTED_AUTHOR]
*/
-object ContactAddressValidator {
+object ContractAddressValidator {
/** Validate a [address] using [blockchain] */
fun validate(address: String, blockchain: Blockchain): ContractAddressValidatorResult {
return when {
- address.isEmpty() -> ContractAddressValidatorResult.Error(type = AddCustomTokenError.FieldIsEmpty)
+ address.isEmpty() -> ContractAddressValidatorResult.Error(type = AddCustomTokenError.FIELD_IS_EMPTY)
validateAddress(blockchain, address) -> ContractAddressValidatorResult.Success
- else -> ContractAddressValidatorResult.Error(type = AddCustomTokenError.InvalidContractAddress)
+ else -> ContractAddressValidatorResult.Error(type = AddCustomTokenError.INVALID_CONTRACT_ADDRESS)
}
}
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/validators/ContractAddressValidatorResult.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/validators/ContractAddressValidatorResult.kt
index 417b3821e0..daf1b4d159 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/validators/ContractAddressValidatorResult.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/validators/ContractAddressValidatorResult.kt
@@ -1,6 +1,6 @@
package com.tangem.tap.features.customtoken.impl.presentation.validators
-import com.tangem.domain.AddCustomTokenError
+import com.tangem.domain.tokens.error.AddCustomTokenError
/**
* Result of validation contract address
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt
index fae60b48c3..0825668edb 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt
@@ -16,13 +16,13 @@ import com.tangem.blockchain.common.derivation.DerivationStyle
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.crypto.hdWallet.HDWalletError
-import com.tangem.domain.AddCustomTokenError
import com.tangem.domain.common.DerivationStyleProvider
import com.tangem.domain.common.extensions.*
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.features.addCustomToken.CustomCurrency
import com.tangem.domain.tokens.GetCryptoCurrenciesUseCase
+import com.tangem.domain.tokens.error.AddCustomTokenError
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.tap.features.customtoken.impl.domain.CustomTokenInteractor
@@ -33,7 +33,7 @@ import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTok
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenSelectorField.SelectorItem
import com.tangem.tap.features.customtoken.impl.presentation.routers.CustomTokenRouter
import com.tangem.tap.features.customtoken.impl.presentation.states.AddCustomTokenStateHolder
-import com.tangem.tap.features.customtoken.impl.presentation.validators.ContactAddressValidator
+import com.tangem.tap.features.customtoken.impl.presentation.validators.ContractAddressValidator
import com.tangem.tap.features.customtoken.impl.presentation.validators.ContractAddressValidatorResult
import com.tangem.tap.features.details.ui.cardsettings.TextReference
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
@@ -461,11 +461,11 @@ internal class AddCustomTokenViewModel @Inject constructor(
private fun getTokenWarningSet(): Set {
val networkSelectorValue = uiState.form.networkSelectorField.selectedItem.blockchain
- val isContractAddressFieldEmpty = ContactAddressValidator.validate(
+ val isContractAddressFieldEmpty = ContractAddressValidator.validate(
address = uiState.form.contractAddressInputField.value,
blockchain = networkSelectorValue,
).let {
- it is ContractAddressValidatorResult.Error && it.type == AddCustomTokenError.FieldIsEmpty
+ it is ContractAddressValidatorResult.Error && it.type == AddCustomTokenError.FIELD_IS_EMPTY
}
val isSupportedToken = if (!isNetworkSelected()) {
@@ -513,7 +513,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
val state = when {
isAllTokenFieldsFilled() && isNetworkSelected() -> {
val networkSelectorValue = uiState.form.networkSelectorField.selectedItem.blockchain
- val error = ContactAddressValidator.validate(
+ val error = ContractAddressValidator.validate(
address = uiState.form.contractAddressInputField.value,
blockchain = networkSelectorValue,
)
@@ -621,7 +621,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
private fun handleContractAddressErrorValidation(type: AddCustomTokenError) {
when {
- isNetworkSelected() && type == AddCustomTokenError.InvalidContractAddress -> {
+ isNetworkSelected() && type == AddCustomTokenError.INVALID_CONTRACT_ADDRESS -> {
val isAnotherTokenFieldsFilled = isAnyTokenFieldsFilled()
uiState = uiState.copySealed(
form = uiState.form.copy(
@@ -644,7 +644,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
)
}
- !isNetworkSelected() || type == AddCustomTokenError.FieldIsEmpty -> {
+ !isNetworkSelected() || type == AddCustomTokenError.FIELD_IS_EMPTY -> {
uiState = uiState.copySealed(
form = uiState.form.copy(
contractAddressInputField = uiState.form.contractAddressInputField.copy(isError = false),
@@ -727,7 +727,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
)
val selectedNetwork = uiState.form.networkSelectorField.selectedItem.blockchain
- val validatorResult = ContactAddressValidator.validate(
+ val validatorResult = ContractAddressValidator.validate(
address = enteredValue,
blockchain = selectedNetwork,
)
diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt b/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt
index 79a40b22a9..73a454fe10 100644
--- a/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt
+++ b/app/src/main/java/com/tangem/tap/features/home/compose/StoriesScreen.kt
@@ -170,7 +170,7 @@ private fun StoriesScreenContent(config: StoriesScreenContentConfig, modifier: M
.padding(horizontal = TangemTheme.dimens.spacing16)
.align(Alignment.BottomCenter)
.fillMaxWidth(),
- verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
+ verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
) {
AnimatedVisibility(
visible = config.currentStory == Stories.Currencies,
diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt b/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt
index aebf48b161..0533961886 100644
--- a/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt
+++ b/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt
@@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
-import androidx.compose.material.ButtonColors
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -13,15 +12,11 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
-import com.tangem.core.ui.components.SpacerW8
-import com.tangem.core.ui.components.buttons.common.TangemButton
-import com.tangem.core.ui.components.buttons.common.TangemButtonColors
+import com.tangem.core.ui.components.SpacerW12
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
-import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.wallet.R
-@Suppress("MagicNumber")
@Composable
internal fun HomeButtons(
btnScanStateInProgress: Boolean,
@@ -38,7 +33,7 @@ internal fun HomeButtons(
showProgress = btnScanStateInProgress,
onClick = onScanButtonClick,
)
- SpacerW8()
+ SpacerW12()
OrderCardButton(
modifier = Modifier.weight(weight = 1f),
onClick = onShopButtonClick,
@@ -48,44 +43,26 @@ internal fun HomeButtons(
@Composable
private fun ScanCardButton(showProgress: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
- TangemButton(
+ StoriesButton(
modifier = modifier,
text = stringResource(id = R.string.home_button_scan),
+ useDarkerColors = false,
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_tangem_24),
- colors = LightBgScanCardButtonColors,
- showProgress = showProgress,
- enabled = true,
onClick = onClick,
+ showProgress = showProgress,
)
}
@Composable
private fun OrderCardButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
- TangemButton(
+ StoriesButton(
modifier = modifier,
text = stringResource(id = R.string.home_button_order),
- icon = TangemButtonIconPosition.None,
- colors = LightBgOrderCardButtonColors,
- showProgress = false,
- enabled = true,
+ useDarkerColors = true,
onClick = onClick,
)
}
-private val LightBgScanCardButtonColors: ButtonColors = TangemButtonColors(
- backgroundColor = TangemColorPalette.Light4,
- contentColor = TangemColorPalette.Dark6,
- disabledBackgroundColor = TangemColorPalette.Dark5,
- disabledContentColor = TangemColorPalette.Dark6,
-)
-
-private val LightBgOrderCardButtonColors: ButtonColors = TangemButtonColors(
- backgroundColor = TangemColorPalette.Dark6,
- contentColor = TangemColorPalette.White,
- disabledBackgroundColor = TangemColorPalette.Dark6,
- disabledContentColor = TangemColorPalette.White,
-)
-
// region Preview
@Preview(showBackground = true, widthDp = 360)
@Composable
@@ -95,10 +72,10 @@ private fun HomeButtonsPreview(@PreviewParameter(HomeButtonsParameterProvider::c
modifier = Modifier.background(Color.Black),
) {
HomeButtons(
- modifier = Modifier.padding(all = TangemTheme.dimens.spacing16),
btnScanStateInProgress = state.btnScanStateInProgress,
onScanButtonClick = {},
onShopButtonClick = {},
+ modifier = Modifier.padding(all = TangemTheme.dimens.spacing16),
)
}
}
diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/SearchCurrenciesButton.kt b/app/src/main/java/com/tangem/tap/features/home/compose/views/SearchCurrenciesButton.kt
index 722dd4f481..4e91ce98bc 100644
--- a/app/src/main/java/com/tangem/tap/features/home/compose/views/SearchCurrenciesButton.kt
+++ b/app/src/main/java/com/tangem/tap/features/home/compose/views/SearchCurrenciesButton.kt
@@ -1,31 +1,42 @@
package com.tangem.tap.features.home.compose.views
-import androidx.compose.material.ButtonColors
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
-import com.tangem.core.ui.components.buttons.common.TangemButton
-import com.tangem.core.ui.components.buttons.common.TangemButtonColors
+import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
-import com.tangem.core.ui.res.TangemColorPalette
+import com.tangem.core.ui.res.TangemTheme
import com.tangem.wallet.R
@Composable
internal fun SearchCurrenciesButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
- TangemButton(
+ StoriesButton(
modifier = modifier,
text = stringResource(id = R.string.common_search_tokens),
icon = TangemButtonIconPosition.Start(R.drawable.ic_search_24),
- onClick = onClick,
- colors = SearchCurrenciesButtonColors,
showProgress = false,
- enabled = true,
+ useDarkerColors = true,
+ onClick = onClick,
)
}
-private val SearchCurrenciesButtonColors: ButtonColors = TangemButtonColors(
- backgroundColor = TangemColorPalette.Dark5,
- contentColor = TangemColorPalette.White,
- disabledBackgroundColor = TangemColorPalette.Dark5,
- disabledContentColor = TangemColorPalette.White,
-)
\ No newline at end of file
+// region Preview
+@Preview(showBackground = true, widthDp = 360)
+@Composable
+private fun SearchCurrenciesButtonPreview() {
+ TangemTheme {
+ Box(
+ modifier = Modifier
+ .background(color = Color.Black)
+ .padding(all = TangemTheme.dimens.spacing16),
+ ) {
+ SearchCurrenciesButton(modifier = Modifier.fillMaxWidth(), onClick = {})
+ }
+ }
+}
+// endregion Preview
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesButton.kt b/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesButton.kt
new file mode 100644
index 0000000000..45b8745cca
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesButton.kt
@@ -0,0 +1,51 @@
+package com.tangem.tap.features.home.compose.views
+
+import androidx.compose.material.ButtonColors
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.tangem.core.ui.components.buttons.common.TangemButton
+import com.tangem.core.ui.components.buttons.common.TangemButtonColors
+import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
+import com.tangem.core.ui.res.TangemColorPalette
+import com.tangem.core.ui.res.TangemTheme
+
+@Composable
+internal fun StoriesButton(
+ text: String,
+ useDarkerColors: Boolean,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ icon: TangemButtonIconPosition = TangemButtonIconPosition.None,
+ showProgress: Boolean = false,
+) {
+ TangemButton(
+ modifier = modifier,
+ text = text,
+ icon = icon,
+ colors = if (useDarkerColors) DarkerButtonColors else LighterButtonColors,
+ showProgress = showProgress,
+ enabled = true,
+ shape = TangemTheme.shapes.roundedCornersXMedium,
+ iconPadding = when (icon) {
+ is TangemButtonIconPosition.Start -> TangemTheme.dimens.spacing4
+ is TangemButtonIconPosition.End,
+ is TangemButtonIconPosition.None,
+ -> TangemTheme.dimens.spacing8
+ },
+ onClick = onClick,
+ )
+}
+
+private val LighterButtonColors: ButtonColors = TangemButtonColors(
+ backgroundColor = TangemColorPalette.Light4,
+ contentColor = TangemColorPalette.Dark6,
+ disabledBackgroundColor = TangemColorPalette.Dark5,
+ disabledContentColor = TangemColorPalette.Dark6,
+)
+
+private val DarkerButtonColors: ButtonColors = TangemButtonColors(
+ backgroundColor = TangemColorPalette.Dark4,
+ contentColor = TangemColorPalette.White,
+ disabledBackgroundColor = TangemColorPalette.Dark4,
+ disabledContentColor = TangemColorPalette.White,
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt b/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt
index a8a1fd7bc1..ef3514bce4 100644
--- a/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt
+++ b/app/src/main/java/com/tangem/tap/features/home/compose/views/StoriesProgressBar.kt
@@ -13,10 +13,10 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
-import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.SpacerW4
+import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import kotlinx.coroutines.delay
@@ -30,7 +30,7 @@ fun StoriesProgressBar(
stepDuration: Int = 8_000,
onStepFinish: () -> Unit = {},
) {
- val progress = remember(currentStep) { Animatable(0f) }
+ val progress = remember(currentStep) { Animatable(initialValue = 0f) }
val context = LocalContext.current
val animatorSpeed = Settings.Global.getFloat(
@@ -75,20 +75,21 @@ fun StoriesProgressBar(
.height(TangemTheme.dimens.size2)
.weight(1f)
.clip(RoundedCornerShape(TangemTheme.dimens.radius2))
- .background(Color.White.copy(alpha = 0.4f)),
+ .background(TangemColorPalette.White.copy(alpha = .2f)),
) {
Box(
modifier = Modifier
.clip(RoundedCornerShape(TangemTheme.dimens.radius2))
- .background(Color.White)
- .fillMaxHeight().let {
+ .background(TangemColorPalette.White)
+ .fillMaxHeight()
+ .let {
when (index) {
currentStep -> it.fillMaxWidth(progress.value)
- in 0..currentStep -> it.fillMaxWidth(1f)
+ in 0..currentStep -> it.fillMaxWidth(fraction = 1f)
else -> it
}
},
- ) {}
+ )
}
if (index != steps) {
SpacerW4()
@@ -100,5 +101,12 @@ fun StoriesProgressBar(
@Preview
@Composable
private fun StoriesProgressBarPreview() {
- StoriesProgressBar(steps = 3, currentStep = 2, paused = false) { }
+ Box(
+ modifier = Modifier
+ .wrapContentSize()
+ .background(TangemColorPalette.Black)
+ .padding(vertical = TangemTheme.dimens.spacing16),
+ ) {
+ StoriesProgressBar(steps = 5, currentStep = 3, paused = false)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt
index 08f0c090d5..3c3409459e 100644
--- a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt
@@ -59,26 +59,41 @@ sealed class TransactionExtrasAction : SendScreenActionUi {
object Release : TransactionExtrasAction()
+ @Deprecated("Only in legacy send screen")
sealed class XlmMemo : TransactionExtrasAction() {
// data class ChangeSelectedMemo(val memoType: XlmMemoType) : XlmMemo()
data class HandleUserInput(val data: String) : XlmMemo()
}
+ @Deprecated("Only in legacy send screen")
sealed class BinanceMemo : TransactionExtrasAction() {
data class HandleUserInput(val data: String) : BinanceMemo()
}
+ @Deprecated("Only in legacy send screen")
sealed class XrpDestinationTag : TransactionExtrasAction() {
data class HandleUserInput(val data: String) : XrpDestinationTag()
}
+ @Deprecated("Only in legacy send screen")
sealed class TonMemo : TransactionExtrasAction() {
data class HandleUserInput(val data: String) : TonMemo()
}
+ @Deprecated("Only in legacy send screen")
sealed class CosmosMemo : TransactionExtrasAction() {
data class HandleUserInput(val data: String) : CosmosMemo()
}
+
+ @Deprecated("Only in legacy send screen")
+ sealed class HederaMemo : TransactionExtrasAction() {
+ data class HandleUserInput(val data: String) : HederaMemo()
+ }
+
+ @Deprecated("Only in legacy send screen")
+ sealed class AlgorandMemo : TransactionExtrasAction() {
+ data class HandleUserInput(val data: String) : AlgorandMemo()
+ }
}
sealed class AddressVerifyAction : SendScreenAction {
diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt
index 9fba907beb..2c21ea333c 100644
--- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt
@@ -1,8 +1,10 @@
package com.tangem.tap.features.send.redux.middlewares
import com.google.firebase.crashlytics.FirebaseCrashlytics
+import com.tangem.blockchain.blockchains.algorand.AlgorandTransactionExtras
import com.tangem.blockchain.blockchains.binance.BinanceTransactionExtras
import com.tangem.blockchain.blockchains.cosmos.CosmosTransactionExtras
+import com.tangem.blockchain.blockchains.hedera.HederaTransactionBuilder
import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider
import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras
import com.tangem.blockchain.blockchains.ton.TonTransactionExtras
@@ -171,6 +173,12 @@ private fun sendTransaction(
transactionExtras.xrpDestinationTag?.tag?.let { txData = txData.copy(extras = XrpTransactionExtras(it)) }
transactionExtras.cosmosMemoState?.memo?.let { txData = txData.copy(extras = CosmosTransactionExtras(it)) }
transactionExtras.tonMemoState?.memo?.let { txData = txData.copy(extras = TonTransactionExtras(it)) }
+ transactionExtras.hederaMemoState?.memo?.let {
+ txData = txData.copy(
+ extras = HederaTransactionBuilder.HederaTransactionExtras(it),
+ )
+ }
+ transactionExtras.algorandMemoState?.memo?.let { txData = txData.copy(extras = AlgorandTransactionExtras(it)) }
scope.launch {
// TODO: Risky commented this part, unknown logic, need to test if removed
diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt
index cb0fbaa3aa..c781547049 100644
--- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/TransactionExtrasReducer.kt
@@ -19,6 +19,8 @@ class TransactionExtrasReducer : SendInternalReducer {
is XrpDestinationTag -> handleXrpTag(action, sendState, sendState.transactionExtrasState)
is TonMemo -> handleTonMemo(action, sendState, sendState.transactionExtrasState)
is CosmosMemo -> handleCosmosMemo(action, sendState, sendState.transactionExtrasState)
+ is HederaMemo -> handleHederaMemo(action, sendState, sendState.transactionExtrasState)
+ is AlgorandMemo -> handleAlgorandMemo(action, sendState, sendState.transactionExtrasState)
else -> sendState
}
}
@@ -52,6 +54,10 @@ class TransactionExtrasReducer : SendInternalReducer {
Blockchain.TerraV1,
Blockchain.TerraV2,
-> TransactionExtrasState(cosmosMemoState = CosmosMemoState())
+ Blockchain.Hedera, Blockchain.HederaTestnet -> TransactionExtrasState(hederaMemoState = HederaMemoState())
+ Blockchain.Algorand, Blockchain.AlgorandTestnet -> TransactionExtrasState(
+ algorandMemoState = AlgorandMemoState(),
+ )
else -> emptyResult
}
return updateLastState(sendState.copy(transactionExtrasState = result), result)
@@ -162,4 +168,34 @@ class TransactionExtrasReducer : SendInternalReducer {
}
return updateLastState(sendState.copy(transactionExtrasState = result), result)
}
+
+ private fun handleHederaMemo(
+ action: HederaMemo,
+ sendState: SendState,
+ infoState: TransactionExtrasState,
+ ): SendState {
+ val result = when (action) {
+ is HederaMemo.HandleUserInput -> {
+ val memo = action.data
+ val input = InputViewValue(memo, true)
+ infoState.copy(hederaMemoState = HederaMemoState(input, memo))
+ }
+ }
+ return updateLastState(sendState.copy(transactionExtrasState = result), result)
+ }
+
+ private fun handleAlgorandMemo(
+ action: AlgorandMemo,
+ sendState: SendState,
+ infoState: TransactionExtrasState,
+ ): SendState {
+ val result = when (action) {
+ is AlgorandMemo.HandleUserInput -> {
+ val memo = action.data
+ val input = InputViewValue(memo, true)
+ infoState.copy(algorandMemoState = AlgorandMemoState(input, memo))
+ }
+ }
+ return updateLastState(sendState.copy(transactionExtrasState = result), result)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressState.kt
index b6b65a595f..3310a772ce 100644
--- a/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressState.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/AddressState.kt
@@ -23,18 +23,21 @@ data class AddressState(
fun isReady(): Boolean = error == null && destinationWalletAddress?.isNotEmpty() ?: false
}
+@Deprecated("Legacy")
data class TransactionExtrasState(
val xlmMemo: XlmMemoState? = null,
val binanceMemo: BinanceMemoState? = null,
val xrpDestinationTag: XrpDestinationTagState? = null,
val tonMemoState: TonMemoState? = null,
val cosmosMemoState: CosmosMemoState? = null,
+ val hederaMemoState: HederaMemoState? = null,
+ val algorandMemoState: AlgorandMemoState? = null,
) : IdStateHolder {
override val stateId: StateId = StateId.TRANSACTION_EXTRAS
fun isNull(): Boolean {
return xlmMemo == null && binanceMemo == null && xrpDestinationTag == null && tonMemoState == null &&
- cosmosMemoState == null
+ cosmosMemoState == null && hederaMemoState == null && algorandMemoState == null
}
fun isEmpty(): Boolean {
@@ -43,8 +46,16 @@ data class TransactionExtrasState(
val isXrpEmpty = xrpDestinationTag?.viewFieldValue?.value?.isEmpty() ?: false
val isTonEmpty = tonMemoState?.viewFieldValue?.value?.isEmpty() ?: false
val isCosmosEmpty = cosmosMemoState?.viewFieldValue?.value?.isEmpty() ?: false
+ val isHederaEmpty = hederaMemoState?.viewFieldValue?.value?.isEmpty() ?: false
+ val isAlgorandEmpty = algorandMemoState?.viewFieldValue?.value?.isEmpty() ?: false
- return isXlmEmpty || isBinanceEmpty || isXrpEmpty || isTonEmpty || isCosmosEmpty
+ return isXlmEmpty ||
+ isBinanceEmpty ||
+ isXrpEmpty ||
+ isTonEmpty ||
+ isCosmosEmpty ||
+ isHederaEmpty ||
+ isAlgorandEmpty
}
}
@@ -120,6 +131,18 @@ data class CosmosMemoState(
val error: TransactionExtraError? = null,
)
+data class HederaMemoState(
+ val viewFieldValue: InputViewValue = InputViewValue(""),
+ val memo: String? = null,
+ val error: TransactionExtraError? = null,
+)
+
+data class AlgorandMemoState(
+ val viewFieldValue: InputViewValue = InputViewValue(""),
+ val memo: String? = null,
+ val error: TransactionExtraError? = null,
+)
+
enum class TransactionExtraError {
INVALID_DESTINATION_TAG,
INVALID_XLM_MEMO,
diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt
index 3e8b23a5d3..775a5cc578 100644
--- a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt
@@ -234,6 +234,24 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
}
.onEach { store.dispatch(TransactionExtrasAction.CosmosMemo.HandleUserInput(it)) }
.launchIn(mainScope)
+
+ etHederaMemo.inputtedTextAsFlow()
+ .debounce(EDIT_TEXT_INPUT_DEBOUNCE)
+ .filter {
+ val info = store.state.sendState.transactionExtrasState
+ info.hederaMemoState?.viewFieldValue?.value != it
+ }
+ .onEach { store.dispatch(TransactionExtrasAction.HederaMemo.HandleUserInput(it)) }
+ .launchIn(mainScope)
+
+ etAlgorandMemo.inputtedTextAsFlow()
+ .debounce(EDIT_TEXT_INPUT_DEBOUNCE)
+ .filter {
+ val info = store.state.sendState.transactionExtrasState
+ info.algorandMemoState?.viewFieldValue?.value != it
+ }
+ .onEach { store.dispatch(TransactionExtrasAction.AlgorandMemo.HandleUserInput(it)) }
+ .launchIn(mainScope)
}
private fun onCodeScanned(scannedCode: String) {
diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt
index 927468b7ea..81899d8e65 100644
--- a/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/ui/stateSubscribers/SendStateSubscriber.kt
@@ -62,7 +62,8 @@ internal class SendStateSubscriber(
}
}
- @Suppress("ComplexMethod")
+ @Deprecated("Legacy")
+ @Suppress("ComplexMethod", "LongMethod")
private fun handleTransactionExtrasState(fg: SendFragment, infoState: TransactionExtrasState) =
with(fg.binding.lSendAddress) {
fun showView(view: View, info: Any?) {
@@ -73,6 +74,8 @@ internal class SendStateSubscriber(
showView(binanceMemoContainer, infoState.binanceMemo)
showView(tonMemoContainer, infoState.tonMemoState)
showView(cosmosMemoContainer, infoState.cosmosMemoState)
+ showView(hederaMemoContainer, infoState.hederaMemoState)
+ showView(algorandMemoContainer, infoState.algorandMemoState)
infoState.xlmMemo?.let {
if (!it.viewFieldValue.isFromUserInput) etXlmMemo.setText(it.viewFieldValue.value)
@@ -129,6 +132,26 @@ internal class SendStateSubscriber(
etCosmosMemo.setText(it.viewFieldValue.value)
}
}
+ infoState.hederaMemoState?.let {
+ if (infoState.hederaMemoState.error != null) {
+ tilHederaMemo.error = fg.getText(R.string.send_extras_error_invalid_memo)
+ } else {
+ tilHederaMemo.error = null
+ }
+ if (!it.viewFieldValue.isFromUserInput) {
+ etHederaMemo.setText(it.viewFieldValue.value)
+ }
+ }
+ infoState.algorandMemoState?.let {
+ if (infoState.algorandMemoState.error != null) {
+ tilAlgorandMemo.error = fg.getText(R.string.send_extras_error_invalid_memo)
+ } else {
+ tilAlgorandMemo.error = null
+ }
+ if (!it.viewFieldValue.isFromUserInput) {
+ etAlgorandMemo.setText(it.viewFieldValue.value)
+ }
+ }
}
@Suppress("ComplexMethod")
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/BriefNetworksList.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/BriefNetworksList.kt
index ea2c77ed2a..d5328878eb 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/BriefNetworksList.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/BriefNetworksList.kt
@@ -83,7 +83,9 @@ internal fun BriefNetworkItem(model: NetworkItemState, modifier: Modifier = Modi
Icon(
painter = painterResource(id = model.iconResId.value),
contentDescription = null,
- modifier = Modifier.size(size = TangemTheme.dimens.size20),
+ modifier = Modifier
+ .size(size = TangemTheme.dimens.size20)
+ .clip(CircleShape),
tint = if (isAdded) Color.Unspecified else TangemTheme.colors.text.tertiary,
)
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenListPreviewData.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenListPreviewData.kt
index f5481080e5..fafeb5d244 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenListPreviewData.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenListPreviewData.kt
@@ -80,6 +80,13 @@ object TokenListPreviewData {
iconResId = mutableStateOf(R.drawable.ic_bsc_16),
isMainNetwork = false,
),
+ // check icon clipping
+ NetworkItemState.ReadContent(
+ name = "SHIBARIUM",
+ protocolName = "BEP20",
+ iconResId = mutableStateOf(R.drawable.ic_shibarium_22),
+ isMainNetwork = false,
+ ),
)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListMigration.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListMigration.kt
index 7ccf604f5a..f4f5e5e72d 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListMigration.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListMigration.kt
@@ -3,14 +3,20 @@ package com.tangem.tap.features.tokens.impl.presentation.viewmodels
import arrow.core.Either
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
+import com.tangem.core.navigation.NavigationAction
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
+import com.tangem.domain.card.DerivePublicKeysUseCase
import com.tangem.domain.common.util.derivationStyleProvider
+import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
import com.tangem.domain.tokens.GetCryptoCurrenciesUseCase
import com.tangem.domain.tokens.TokenWithBlockchain
-import com.tangem.domain.tokens.TokensAction
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWallet
+import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
+import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
+import com.tangem.tap.common.extensions.dispatchOnMain
+import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
import timber.log.Timber
import kotlin.properties.Delegates
@@ -24,6 +30,8 @@ import kotlin.properties.Delegates
internal class TokensListMigration(
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val getCurrenciesUseCase: GetCryptoCurrenciesUseCase,
+ private val derivePublicKeysUseCase: DerivePublicKeysUseCase,
+ private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
) {
private var currentNewCoins: List by Delegates.notNull()
@@ -76,31 +84,72 @@ internal class TokensListMigration(
}
}
- fun onSaveButtonClick(
+ suspend fun onSaveButtonClick(
changedTokensList: MutableList,
changedBlockchainList: List,
) {
- store.dispatch(
- action = TokensAction.SaveChanges(
- currentTokens = currentNewTokens,
- currentCoins = currentNewCoins,
- changedTokens = changedTokensList.mapNotNull {
- cryptoCurrencyFactory.createToken(
- sdkToken = it.token,
- blockchain = it.blockchain,
- extraDerivationPath = null,
- derivationStyleProvider = currentUserWallet.scanResponse.derivationStyleProvider,
- )
- },
- changedCoins = changedBlockchainList.mapNotNull {
- cryptoCurrencyFactory.createCoin(
- blockchain = it,
- extraDerivationPath = null,
- derivationStyleProvider = currentUserWallet.scanResponse.derivationStyleProvider,
- )
- },
- userWallet = currentUserWallet,
- ),
+ val changedTokens = changedTokensList.mapNotNull {
+ cryptoCurrencyFactory.createToken(
+ sdkToken = it.token,
+ blockchain = it.blockchain,
+ extraDerivationPath = null,
+ derivationStyleProvider = currentUserWallet.scanResponse.derivationStyleProvider,
+ )
+ }
+
+ val changedCoins = changedBlockchainList.mapNotNull {
+ cryptoCurrencyFactory.createCoin(
+ blockchain = it,
+ extraDerivationPath = null,
+ derivationStyleProvider = currentUserWallet.scanResponse.derivationStyleProvider,
+ )
+ }
+
+ val blockchainsToAdd = changedCoins.filterNot(currentNewCoins::contains)
+ val blockchainsToRemove = currentNewCoins.filterNot(changedCoins::contains)
+
+ val tokensToAdd = changedTokens.filterNot(currentNewTokens::contains)
+ val tokensToRemove = currentNewTokens.filterNot { token -> changedTokens.any { it == token } }
+
+ removeCurrenciesIfNeeded(
+ userWalletId = currentUserWallet.walletId,
+ currencies = blockchainsToRemove + tokensToRemove,
+ )
+
+ val isNothingToDoWithTokens = tokensToAdd.isEmpty() && tokensToRemove.isEmpty()
+ val isNothingToDoWithBlockchain = blockchainsToAdd.isEmpty() && blockchainsToRemove.isEmpty()
+ if (isNothingToDoWithTokens && isNothingToDoWithBlockchain) {
+ store.dispatchDebugErrorNotification(message = "Nothing to save")
+ store.dispatchOnMain(NavigationAction.PopBackTo())
+ return
+ }
+
+ val currencyList = blockchainsToAdd + tokensToAdd
+
+ derivePublicKeysUseCase(userWalletId = currentUserWallet.walletId, currencies = currencyList)
+ .onRight {
+ addCryptoCurrenciesUseCase(userWalletId = currentUserWallet.walletId, currencies = currencyList)
+ store.dispatchOnMain(NavigationAction.PopBackTo())
+ }
+ .onLeft { Timber.e("Failed to derive public keys: $it") }
+ }
+
+ private suspend fun removeCurrenciesIfNeeded(userWalletId: UserWalletId, currencies: List) {
+ if (currencies.isEmpty()) return
+ val currenciesRepository = store.state.daggerGraphState.get(DaggerGraphState::currenciesRepository)
+ val walletManagersFacade = store.state.daggerGraphState.get(DaggerGraphState::walletManagersFacade)
+
+ currenciesRepository.removeCurrencies(userWalletId = userWalletId, currencies = currencies)
+
+ walletManagersFacade.remove(
+ userWalletId = userWalletId,
+ networks = currencies
+ .filterIsInstance()
+ .mapTo(hashSetOf(), CryptoCurrency::network),
+ )
+ walletManagersFacade.removeTokens(
+ userWalletId = userWalletId,
+ tokens = currencies.filterIsInstance().toSet(),
)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt
index 94c4974fc7..337e8f24ec 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListViewModel.kt
@@ -13,12 +13,14 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.ui.extensions.getActiveIconRes
import com.tangem.core.ui.extensions.getGreyedOutIconRes
+import com.tangem.domain.card.DerivePublicKeysUseCase
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
import com.tangem.domain.common.extensions.canHandleBlockchain
import com.tangem.domain.common.extensions.canHandleToken
import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.domain.common.extensions.supportedTokens
import com.tangem.domain.common.util.cardTypesResolver
+import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
import com.tangem.domain.tokens.GetCryptoCurrenciesUseCase
import com.tangem.domain.tokens.TokenWithBlockchain
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
@@ -67,6 +69,8 @@ internal class TokensListViewModel @Inject constructor(
private val router: TokensListRouter,
private val dispatchers: AppCoroutineDispatcherProvider,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
+ derivePublicKeysUseCase: DerivePublicKeysUseCase,
+ addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
analyticsEventHandler: AnalyticsEventHandler,
getCurrenciesUseCase: GetCryptoCurrenciesUseCase,
) : ViewModel(), DefaultLifecycleObserver {
@@ -88,6 +92,8 @@ internal class TokensListViewModel @Inject constructor(
private val tokensListMigration = TokensListMigration(
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
getCurrenciesUseCase = getCurrenciesUseCase,
+ derivePublicKeysUseCase = derivePublicKeysUseCase,
+ addCryptoCurrenciesUseCase = addCryptoCurrenciesUseCase,
)
init {
@@ -303,10 +309,13 @@ internal class TokensListViewModel @Inject constructor(
fun onSaveButtonClick() {
analyticsSender.sendWhenSaveButtonClicked()
- tokensListMigration.onSaveButtonClick(
- changedTokensList = changedTokensList,
- changedBlockchainList = changedBlockchainList,
- )
+
+ viewModelScope.launch(dispatchers.main) {
+ tokensListMigration.onSaveButtonClick(
+ changedTokensList = changedTokensList,
+ changedBlockchainList = changedBlockchainList,
+ )
+ }
}
private fun onSearchValueChange(newValue: String) {
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensMiddleware.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensMiddleware.kt
deleted file mode 100644
index eb39d0d64b..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensMiddleware.kt
+++ /dev/null
@@ -1,250 +0,0 @@
-package com.tangem.tap.features.tokens.legacy.redux
-
-import com.tangem.blockchain.blockchains.cardano.CardanoUtils
-import com.tangem.blockchain.common.Blockchain
-import com.tangem.common.CompletionResult
-import com.tangem.common.card.EllipticCurve
-import com.tangem.common.doOnSuccess
-import com.tangem.common.extensions.ByteArrayKey
-import com.tangem.common.extensions.toMapKey
-import com.tangem.core.navigation.NavigationAction
-import com.tangem.crypto.hdWallet.DerivationPath
-import com.tangem.domain.common.configs.CardConfig
-import com.tangem.domain.common.util.derivationStyleProvider
-import com.tangem.domain.common.util.supportsHdWallet
-import com.tangem.domain.models.scan.ScanResponse
-import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
-import com.tangem.domain.tokens.TokensAction
-import com.tangem.domain.tokens.model.CryptoCurrency
-import com.tangem.domain.wallets.models.UserWallet
-import com.tangem.domain.wallets.models.UserWalletId
-import com.tangem.operations.derivation.ExtendedPublicKeysMap
-import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
-import com.tangem.tap.common.extensions.dispatchOnMain
-import com.tangem.tap.common.redux.AppState
-import com.tangem.tap.common.redux.global.GlobalAction
-import com.tangem.tap.domain.TapError
-import com.tangem.tap.domain.card.DefaultDerivePublicKeysUseCase
-import com.tangem.tap.proxy.redux.DaggerGraphState
-import com.tangem.tap.scope
-import com.tangem.tap.store
-import com.tangem.tap.tangemSdkManager
-import com.tangem.tap.userWalletsListManager
-import kotlinx.coroutines.launch
-import org.rekotlin.Middleware
-import timber.log.Timber
-
-@Suppress("LargeClass")
-object TokensMiddleware {
-
- // TODO: Move to DI
- private val addCryptoCurrenciesUseCase by lazy(LazyThreadSafetyMode.NONE) {
- val currenciesRepository = store.state.daggerGraphState.get(DaggerGraphState::currenciesRepository)
- val networksRepository = store.state.daggerGraphState.get(DaggerGraphState::networksRepository)
-
- AddCryptoCurrenciesUseCase(currenciesRepository, networksRepository)
- }
-
- val tokensMiddleware: Middleware = { _, _ ->
- { next ->
- { action ->
- when (action) {
- is TokensAction.SaveChanges -> handleSaveChanges(action)
- }
- next(action)
- }
- }
- }
-
- private fun handleSaveChanges(action: TokensAction.SaveChanges) {
- scope.launch {
- val scanResponse = action.userWallet.scanResponse
-
- val currentTokens = action.currentTokens
- val currentBlockchains = action.currentCoins
-
- val blockchainsToAdd = action.changedCoins.filterNot(currentBlockchains::contains)
- val blockchainsToRemove = currentBlockchains.filterNot(action.changedCoins::contains)
-
- val tokensToAdd = action.changedTokens.filterNot(currentTokens::contains)
- val tokensToRemove = currentTokens.filterNot { token -> action.changedTokens.any { it == token } }
-
- removeCurrenciesIfNeeded(
- userWalletId = action.userWallet.walletId,
- currencies = blockchainsToRemove + tokensToRemove,
- )
-
- val isNothingToDoWithTokens = tokensToAdd.isEmpty() && tokensToRemove.isEmpty()
- val isNothingToDoWithBlockchain = blockchainsToAdd.isEmpty() && blockchainsToRemove.isEmpty()
- if (isNothingToDoWithTokens && isNothingToDoWithBlockchain) {
- store.dispatchDebugErrorNotification(message = "Nothing to save")
- store.dispatchOnMain(NavigationAction.PopBackTo())
- return@launch
- }
-
- val currencyList = blockchainsToAdd + tokensToAdd
-
- val featureToggles = store.state.daggerGraphState.get(DaggerGraphState::testerFeatureToggles)
- if (featureToggles.isDerivePublicKeysRefactoringEnabled) {
- val derivePublicKeys = DefaultDerivePublicKeysUseCase(
- tangemSdkManager = tangemSdkManager,
- derivationsRepository = store.state.daggerGraphState.get(DaggerGraphState::derivationsRepository),
- )
-
- derivePublicKeys(userWalletId = action.userWallet.walletId, currencies = currencyList)
- .onRight {
- addCryptoCurrenciesUseCase(
- userWalletId = action.userWallet.walletId,
- currencies = currencyList,
- )
- store.dispatchOnMain(NavigationAction.PopBackTo())
- }
- .onLeft { Timber.e("Failed to derive public keys: $it") }
- } else {
- // TODO: delete [REDACTED_JIRA]
- if (scanResponse.supportsHdWallet()) {
- deriveMissingCoins(scanResponse = scanResponse, currencyList = currencyList) {
- submitAdd(
- userWallet = action.userWallet,
- updatedScanResponse = it,
- currencyList = currencyList,
- )
- }
- } else {
- submitAdd(action.userWallet, scanResponse, currencyList)
- }
- }
- }
- }
-
- @Deprecated(message = "Use DerivePublicKeysUseCase instead")
- private fun deriveMissingCoins(
- scanResponse: ScanResponse,
- currencyList: List,
- onSuccess: (ScanResponse) -> Unit,
- ) {
- val config = CardConfig.createConfig(scanResponse.card)
- val derivationDataList = currencyList.mapNotNull { currency ->
- val curve = config.primaryCurve(blockchain = Blockchain.fromId(currency.network.id.value))
- curve?.let { getDerivations(curve, scanResponse, currency) }
- }
- val derivations = buildMap> {
- derivationDataList.forEach {
- val current = this[it.derivations.first]
- if (current != null) {
- current.addAll(it.derivations.second)
- current.distinct()
- } else {
- this[it.derivations.first] = it.derivations.second.toMutableList()
- }
- }
- }
-
- if (derivations.isEmpty()) {
- onSuccess(scanResponse)
- return
- }
-
- scope.launch {
- val result = tangemSdkManager.derivePublicKeys(
- cardId = null,
- derivations = derivations,
- )
- when (result) {
- is CompletionResult.Success -> {
- val newDerivedKeys = result.data.entries
- val oldDerivedKeys = scanResponse.derivedKeys
-
- val walletKeys = (newDerivedKeys.keys + oldDerivedKeys.keys).toSet()
-
- val updatedDerivedKeys = walletKeys.associateWith { walletKey ->
- val oldDerivations = ExtendedPublicKeysMap(oldDerivedKeys[walletKey] ?: emptyMap())
- val newDerivations = newDerivedKeys[walletKey] ?: ExtendedPublicKeysMap(emptyMap())
- ExtendedPublicKeysMap(oldDerivations + newDerivations)
- }
- val updatedScanResponse = scanResponse.copy(derivedKeys = updatedDerivedKeys)
-
- store.dispatchOnMain(GlobalAction.SaveScanResponse(updatedScanResponse))
-
- onSuccess(updatedScanResponse)
- }
- is CompletionResult.Failure -> {
- store.dispatchDebugErrorNotification(TapError.CustomError("Error adding tokens"))
- }
- }
- }
- }
-
- private fun getDerivations(
- curve: EllipticCurve,
- scanResponse: ScanResponse,
- currency: CryptoCurrency,
- ): DerivationData? {
- val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null
-
- val blockchain = Blockchain.fromId(currency.network.id.value)
- val supportedCurves = blockchain.getSupportedCurves()
- val path = blockchain.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
- .takeIf { supportedCurves.contains(curve) }
-
- val customPath = currency.network.derivationPath.value?.let {
- DerivationPath(it)
- }.takeIf { supportedCurves.contains(curve) }
-
- val bothCandidates = listOfNotNull(path, customPath).distinct().toMutableList()
- if (bothCandidates.isEmpty()) return null
-
- if (currency is CryptoCurrency.Coin && blockchain == Blockchain.Cardano) {
- currency.network.derivationPath.value?.let {
- bothCandidates.add(CardanoUtils.extendedDerivationPath(DerivationPath(it)))
- }
- }
-
- val mapKeyOfWalletPublicKey = wallet.publicKey.toMapKey()
- val alreadyDerivedKeys: ExtendedPublicKeysMap =
- scanResponse.derivedKeys[mapKeyOfWalletPublicKey] ?: ExtendedPublicKeysMap(emptyMap())
- val alreadyDerivedPaths = alreadyDerivedKeys.keys.toList()
-
- val toDerive = bothCandidates.filterNot { alreadyDerivedPaths.contains(it) }
- if (toDerive.isEmpty()) return null
-
- return DerivationData(derivations = mapKeyOfWalletPublicKey to toDerive)
- }
-
- class DerivationData(val derivations: Pair>)
-
- private fun submitAdd(
- userWallet: UserWallet,
- updatedScanResponse: ScanResponse,
- currencyList: List,
- ) {
- scope.launch {
- userWalletsListManager.update(
- userWalletId = userWallet.walletId,
- update = { it.copy(scanResponse = updatedScanResponse) },
- ).doOnSuccess {
- addCryptoCurrenciesUseCase(userWallet.walletId, currencyList)
- }
- }
- store.dispatchOnMain(NavigationAction.PopBackTo())
- }
-
- private suspend fun removeCurrenciesIfNeeded(userWalletId: UserWalletId, currencies: List) {
- if (currencies.isEmpty()) return
- val currenciesRepository = store.state.daggerGraphState.get(DaggerGraphState::currenciesRepository)
- val walletManagersFacade = store.state.daggerGraphState.get(DaggerGraphState::walletManagersFacade)
-
- currenciesRepository.removeCurrencies(userWalletId = userWalletId, currencies = currencies)
-
- walletManagersFacade.remove(
- userWalletId = userWalletId,
- networks = currencies
- .filterIsInstance()
- .mapTo(hashSetOf(), CryptoCurrency::network),
- )
- walletManagersFacade.removeTokens(
- userWalletId = userWalletId,
- tokens = currencies.filterIsInstance().toSet(),
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt
index 36123cf1a9..a3425aeb83 100644
--- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt
+++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt
@@ -46,6 +46,11 @@ object TradeCryptoMiddleware {
}
}
+ private val isSendRedesignedEnabled: Boolean
+ get() = store.state.daggerGraphState.get(
+ getDependency = DaggerGraphState::sendFeatureToggles,
+ ).isRedesignedSendEnabled
+
@Suppress("LongMethod", "CyclomaticComplexMethod")
private fun handle(state: () -> AppState?, action: TradeCryptoAction) {
if (DemoHelper.tryHandle(state, action)) return
@@ -54,11 +59,21 @@ object TradeCryptoMiddleware {
is TradeCryptoAction.FinishSelling -> openReceiptUrl(action.transactionId)
is TradeCryptoAction.Buy -> proceedBuyAction(state, action)
is TradeCryptoAction.Sell -> proceedSellAction(action)
- is TradeCryptoAction.Swap -> openSwap(
- currency = action.cryptoCurrency,
- )
- is TradeCryptoAction.SendToken -> handleSendToken(action = action)
- is TradeCryptoAction.SendCoin -> handleSendCoin(action = action)
+ is TradeCryptoAction.Swap -> openSwap(currency = action.cryptoCurrency)
+ is TradeCryptoAction.SendToken -> {
+ if (isSendRedesignedEnabled) {
+ handleNewSendToken(action = action)
+ } else {
+ handleSendToken(action = action)
+ }
+ }
+ is TradeCryptoAction.SendCoin -> {
+ if (isSendRedesignedEnabled) {
+ handleNewSendCoin(action = action)
+ } else {
+ handleSendCoin(action = action)
+ }
+ }
}
}
@@ -280,4 +295,35 @@ object TradeCryptoMiddleware {
store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Send, bundle = bundle))
}
}
+
+ private fun handleNewSendToken(action: TradeCryptoAction.SendToken) {
+ handleNewSend(
+ userWalletId = action.userWallet.walletId.stringValue,
+ txInfo = action.transactionInfo,
+ currency = action.tokenCurrency,
+ )
+ }
+
+ private fun handleNewSendCoin(action: TradeCryptoAction.SendCoin) {
+ handleNewSend(
+ userWalletId = action.userWallet.walletId.stringValue,
+ txInfo = action.transactionInfo,
+ currency = action.coinStatus.currency,
+ )
+ }
+
+ private fun handleNewSend(
+ userWalletId: String,
+ txInfo: TradeCryptoAction.TransactionInfo?,
+ currency: CryptoCurrency,
+ ) {
+ val bundle = bundleOf(
+ SendRouter.CRYPTO_CURRENCY_KEY to currency,
+ SendRouter.USER_WALLET_ID_KEY to userWalletId,
+ SendRouter.TRANSACTION_ID_KEY to txInfo?.transactionId,
+ SendRouter.DESTINATION_ADDRESS_KEY to txInfo?.destinationAddress,
+ SendRouter.AMOUNT_KEY to txInfo?.amount,
+ )
+ store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Send, bundle = bundle))
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/ExchangeService.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/ExchangeService.kt
index b139b14200..c3f3587c26 100644
--- a/app/src/main/java/com/tangem/tap/network/exchangeServices/ExchangeService.kt
+++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/ExchangeService.kt
@@ -67,6 +67,6 @@ interface ExchangeUrlBuilder {
companion object {
const val SCHEME = "https"
- const val SUCCESS_URL = "tangem://success.tangem.com"
+ const val SUCCESS_URL = "https://tangem.com/success"
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayApi.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayApi.kt
index ce7c4c2a7f..e5948ce873 100644
--- a/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayApi.kt
+++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayApi.kt
@@ -41,4 +41,11 @@ data class MoonPayCurrencies(
val isSupportedInUS: Boolean = false,
val isSellSupported: Boolean = false,
val notAllowedUSStates: List = emptyList(),
+ val metadata: MoonPayCurrenciesMetadata? = null,
+)
+
+@JsonClass(generateAdapter = true)
+data class MoonPayCurrenciesMetadata(
+ val contractAddress: String?,
+ val networkCode: String?,
)
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayService.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayService.kt
index 664f31e958..328904eb0a 100644
--- a/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayService.kt
+++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayService.kt
@@ -81,6 +81,7 @@ class MoonPayService(
override fun availableForSell(currency: Currency): Boolean {
val availableForSell = status?.availableForSell ?: return false
+ val metadata = status?.responseCurrencies?.map { it.metadata }
if (!isSellAllowed()) return false
return when (currency) {
@@ -92,7 +93,9 @@ class MoonPayService(
else -> availableForSell.contains(currency.currencySymbol)
}
}
- is Currency.Token -> false
+ is Currency.Token -> {
+ metadata?.any { it?.contractAddress.equals(currency.token.contractAddress, ignoreCase = true) } ?: false
+ }
}
}
diff --git a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt
deleted file mode 100644
index 63b07213d1..0000000000
--- a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt
+++ /dev/null
@@ -1,298 +0,0 @@
-package com.tangem.tap.proxy
-
-import com.tangem.blockchain.blockchains.cardano.CardanoUtils
-import com.tangem.blockchain.common.Blockchain
-import com.tangem.blockchain.common.Token
-import com.tangem.common.CompletionResult
-import com.tangem.common.card.EllipticCurve
-import com.tangem.common.core.TangemError
-import com.tangem.common.core.TangemSdkError
-import com.tangem.common.extensions.ByteArrayKey
-import com.tangem.common.extensions.toMapKey
-import com.tangem.crypto.hdWallet.DerivationPath
-import com.tangem.data.tokens.utils.CryptoCurrencyFactory
-import com.tangem.domain.common.BlockchainNetwork
-import com.tangem.domain.common.DerivationStyleProvider
-import com.tangem.domain.common.configs.CardConfig
-import com.tangem.domain.common.extensions.fromNetworkId
-import com.tangem.domain.common.util.derivationStyleProvider
-import com.tangem.domain.common.util.hasDerivation
-import com.tangem.domain.models.scan.ScanResponse
-import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
-import com.tangem.domain.tokens.model.CryptoCurrency
-import com.tangem.domain.tokens.repository.CurrenciesRepository
-import com.tangem.domain.tokens.repository.NetworksRepository
-import com.tangem.domain.wallets.models.UserWalletId
-import com.tangem.lib.crypto.DerivationManager
-import com.tangem.lib.crypto.models.Currency
-import com.tangem.lib.crypto.models.Currency.NonNativeToken
-import com.tangem.lib.crypto.models.errors.UserCancelledException
-import com.tangem.operations.derivation.ExtendedPublicKeysMap
-import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
-import com.tangem.tap.common.extensions.dispatchOnMain
-import com.tangem.tap.common.redux.global.GlobalAction
-import com.tangem.tap.domain.TapError
-import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware
-import com.tangem.tap.scope
-import com.tangem.tap.userWalletsListManager
-import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import kotlin.coroutines.suspendCoroutine
-import com.tangem.tap.domain.model.Currency as WalletModelCurrency
-
-class DerivationManagerImpl(
- private val appStateHolder: AppStateHolder,
- private val currenciesRepository: CurrenciesRepository,
- private val networksRepository: NetworksRepository,
-) : DerivationManager {
-
- // TODO: Move to DI
- private val addCryptoCurrenciesUseCase by lazy(LazyThreadSafetyMode.NONE) {
- AddCryptoCurrenciesUseCase(currenciesRepository, networksRepository)
- }
-
- override suspend fun deriveAndAddTokens(currency: Currency) = suspendCoroutine { continuation ->
- val selectedUserWallet = requireNotNull(
- userWalletsListManager.selectedUserWalletSync,
- ) { "selectedUserWallet shouldn't be null" }
- val scanResponse = selectedUserWallet.scanResponse
- val blockchain = requireNotNull(
- Blockchain.fromNetworkId(currency.networkId),
- ) { "unsupported blockchain" }
- val derivationStyleProvider = scanResponse.derivationStyleProvider
- val derivationPath = requireNotNull(
- blockchain.derivationPath(derivationStyleProvider.getDerivationStyle())?.rawPath,
- ) { "derivationPath shouldn't be null" }
- val hasDerivation = scanResponse.hasDerivation(
- blockchain,
- derivationPath,
- )
- if (hasDerivation) {
- scope.launch {
- addToken(
- userWalletId = selectedUserWallet.walletId,
- blockchain = blockchain,
- currency = currency,
- derivationPath = derivationPath,
- derivationStyleProvider = derivationStyleProvider,
- )
- continuation.resumeWith(Result.success(derivationPath))
- }
- } else {
- val blockchainNetwork = BlockchainNetwork(blockchain, scanResponse.derivationStyleProvider)
- val appCurrency = com.tangem.tap.domain.model.Currency.fromBlockchainNetwork(
- blockchainNetwork,
- getAppToken(currency),
- )
- deriveMissingBlockchains(
- scanResponse = scanResponse,
- currencyList = listOf(appCurrency),
- onSuccess = { updatedScanResponse ->
- scope.launch {
- userWalletsListManager.update(
- userWalletId = selectedUserWallet.walletId,
- update = { it.copy(scanResponse = updatedScanResponse) },
- )
- addToken(
- userWalletId = selectedUserWallet.walletId,
- blockchain = blockchain,
- currency = currency,
- derivationPath = derivationPath,
- derivationStyleProvider = derivationStyleProvider,
- )
- continuation.resumeWith(Result.success(derivationPath))
- }
- },
- onFailure = {
- continuation.resumeWith(Result.failure(it))
- },
- )
- }
- }
-
- private suspend fun addToken(
- userWalletId: UserWalletId,
- blockchain: Blockchain,
- currency: Currency,
- derivationPath: String,
- derivationStyleProvider: DerivationStyleProvider,
- ) {
- val cryptoCurrency = convertCurrency(
- blockchain = blockchain,
- currency = currency,
- derivationPath = derivationPath,
- derivationStyleProvider = derivationStyleProvider,
- )
-
- addCryptoCurrenciesUseCase(userWalletId, cryptoCurrency)
- }
-
- private fun convertCurrency(
- blockchain: Blockchain,
- currency: Currency,
- derivationPath: String,
- derivationStyleProvider: DerivationStyleProvider,
- ): CryptoCurrency {
- val cryptoCurrencyFactory = CryptoCurrencyFactory()
- return when (currency) {
- is Currency.NativeToken -> {
- cryptoCurrencyFactory.createCoin(
- blockchain = blockchain,
- extraDerivationPath = derivationPath,
- derivationStyleProvider = derivationStyleProvider,
- )
- }
- is NonNativeToken -> {
- val sdkToken = Token(
- name = currency.name,
- symbol = currency.symbol,
- contractAddress = currency.contractAddress,
- decimals = currency.decimalCount,
- id = currency.id,
- )
- cryptoCurrencyFactory.createToken(
- sdkToken = sdkToken,
- blockchain = blockchain,
- extraDerivationPath = derivationPath,
- derivationStyleProvider = derivationStyleProvider,
- )
- }
- } as CryptoCurrency
- }
-
- private fun deriveMissingBlockchains(
- scanResponse: ScanResponse,
- currencyList: List,
- onSuccess: (ScanResponse) -> Unit,
- onFailure: (Exception) -> Unit,
- ) {
- val config = CardConfig.createConfig(scanResponse.card)
- val derivationDataList = currencyList.mapNotNull { currency ->
- val curve = config.primaryCurve(currency.blockchain)
- curve?.let { getDerivations(curve, scanResponse, currency) }
- }
- val derivations = buildMap> {
- derivationDataList.forEach {
- val current = this[it.derivations.first]
- if (current != null) {
- current.addAll(it.derivations.second)
- current.distinct()
- } else {
- this[it.derivations.first] = it.derivations.second.toMutableList()
- }
- }
- }
- if (derivations.isEmpty()) {
- onSuccess(scanResponse)
- return
- }
-
- scope.launch {
- val selectedUserWallet = userWalletsListManager.selectedUserWalletSync
-
- val result = appStateHolder.tangemSdkManager?.derivePublicKeys(
- cardId = null, // always ignore cardId in derive task
- derivations = derivations,
- )
- when (result) {
- is CompletionResult.Success -> {
- val newDerivedKeys = result.data.entries
- val oldDerivedKeys = scanResponse.derivedKeys
-
- val walletKeys = (newDerivedKeys.keys + oldDerivedKeys.keys).toSet()
-
- val updatedDerivedKeys = walletKeys.associateWith { walletKey ->
- val oldDerivations = ExtendedPublicKeysMap(oldDerivedKeys[walletKey] ?: emptyMap())
- val newDerivations = newDerivedKeys[walletKey] ?: ExtendedPublicKeysMap(emptyMap())
- ExtendedPublicKeysMap(oldDerivations + newDerivations)
- }
- val updatedScanResponse = scanResponse.copy(
- derivedKeys = updatedDerivedKeys,
- )
- if (selectedUserWallet != null) {
- userWalletsListManager.update(
- userWalletId = selectedUserWallet.walletId,
- update = { it.copy(scanResponse = updatedScanResponse) },
- )
- }
- appStateHolder.mainStore?.dispatchOnMain(GlobalAction.SaveScanResponse(updatedScanResponse))
- delay(DELAY_SDK_DIALOG_CLOSE)
- onSuccess(updatedScanResponse)
- }
- is CompletionResult.Failure -> {
- appStateHolder.mainStore?.dispatchDebugErrorNotification(
- TapError.CustomError(
- "Error derivation",
- ),
- )
- onFailure.invoke(handleTangemError(result.error))
- }
- else -> {
- error("result result is null")
- }
- }
- }
- }
-
- private fun getDerivations(
- curve: EllipticCurve,
- scanResponse: ScanResponse,
- currency: com.tangem.tap.domain.model.Currency,
- ): TokensMiddleware.DerivationData? {
- val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null
-
- val supportedCurves = currency.blockchain.getSupportedCurves()
- val path = currency.blockchain.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
- .takeIf { supportedCurves.contains(curve) }
-
- val customPath = currency.derivationPath?.let {
- DerivationPath(it)
- }.takeIf { supportedCurves.contains(curve) }
-
- val bothCandidates = listOfNotNull(path, customPath).distinct().toMutableList()
- if (bothCandidates.isEmpty()) return null
-
- if (currency is WalletModelCurrency.Blockchain &&
- currency.blockchain == Blockchain.Cardano
- ) {
- currency.derivationPath?.let {
- bothCandidates.add(CardanoUtils.extendedDerivationPath(DerivationPath(it)))
- }
- }
-
- val mapKeyOfWalletPublicKey = wallet.publicKey.toMapKey()
- val alreadyDerivedKeys: ExtendedPublicKeysMap =
- scanResponse.derivedKeys[mapKeyOfWalletPublicKey] ?: ExtendedPublicKeysMap(emptyMap())
- val alreadyDerivedPaths = alreadyDerivedKeys.keys.toList()
-
- val toDerive = bothCandidates.filterNot { alreadyDerivedPaths.contains(it) }
- if (toDerive.isEmpty()) return null
-
- return TokensMiddleware.DerivationData(derivations = mapKeyOfWalletPublicKey to toDerive)
- }
-
- private fun getAppToken(currency: Currency): Token? {
- return if (currency is NonNativeToken) {
- Token(
- symbol = currency.symbol,
- contractAddress = currency.contractAddress,
- decimals = currency.decimalCount,
- )
- } else {
- null
- }
- }
- /**
- * Simple error handler
- * for now specifically handle only UserCancelled
- *
- * @param error [TangemError]
- */
- private fun handleTangemError(error: TangemError): Exception {
- if (error is TangemSdkError.UserCancelled) {
- return UserCancelledException()
- }
- return IllegalStateException(error.customMessage)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt b/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt
index 8c0c4eda47..d72bae0238 100644
--- a/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt
+++ b/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt
@@ -4,9 +4,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.tokens.repository.CurrenciesRepository
-import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
-import com.tangem.lib.crypto.DerivationManager
import com.tangem.lib.crypto.TransactionManager
import com.tangem.lib.crypto.UserWalletManager
import com.tangem.tap.proxy.*
@@ -56,18 +54,4 @@ internal object ProxyModule {
walletManagersFacade = walletManagersFacade,
)
}
-
- @Provides
- @Singleton
- fun provideDerivationManager(
- appStateHolder: AppStateHolder,
- currenciesRepository: CurrenciesRepository,
- networksRepository: NetworksRepository,
- ): DerivationManager {
- return DerivationManagerImpl(
- appStateHolder = appStateHolder,
- currenciesRepository = currenciesRepository,
- networksRepository = networksRepository,
- )
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt
index 9dab1b838d..995658a42c 100644
--- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt
+++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphAction.kt
@@ -3,7 +3,7 @@ package com.tangem.tap.proxy.redux
import com.tangem.feature.qrscanning.QrScanningRouter
import com.tangem.domain.card.ScanCardUseCase
import com.tangem.domain.card.repository.CardSdkConfigRepository
-import com.tangem.features.managetokens.navigation.ManageTokensRouter
+import com.tangem.features.managetokens.navigation.ManageTokensUi
import com.tangem.features.send.api.navigation.SendRouter
import com.tangem.features.tester.api.TesterRouter
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
@@ -19,7 +19,7 @@ sealed interface DaggerGraphAction : Action {
val walletRouter: WalletRouter,
val walletConnectInteractor: WalletConnectInteractor,
val tokenDetailsRouter: TokenDetailsRouter,
- val manageTokensRouter: ManageTokensRouter,
+ val manageTokensUi: ManageTokensUi,
val cardSdkConfigRepository: CardSdkConfigRepository,
val sendRouter: SendRouter,
val qrScanningRouter: QrScanningRouter,
diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt
index 5f2030f390..7074523df0 100644
--- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt
+++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphReducer.kt
@@ -18,7 +18,7 @@ object DaggerGraphReducer {
walletRouter = action.walletRouter,
walletConnectInteractor = action.walletConnectInteractor,
tokenDetailsRouter = action.tokenDetailsRouter,
- manageTokensRouter = action.manageTokensRouter,
+ manageTokensUi = action.manageTokensUi,
cardSdkConfigRepository = action.cardSdkConfigRepository,
sendRouter = action.sendRouter,
qrScanningRouter = action.qrScanningRouter,
diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt
index b1839fae93..4a543195d6 100644
--- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt
+++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt
@@ -1,5 +1,7 @@
package com.tangem.tap.proxy.redux
+import com.tangem.blockchain.common.AccountCreator
+import com.tangem.blockchain.common.datastorage.BlockchainDataStorage
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
import com.tangem.domain.apptheme.repository.AppThemeModeRepository
@@ -7,17 +9,15 @@ import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
import com.tangem.domain.card.ScanCardProcessor
import com.tangem.domain.card.ScanCardUseCase
import com.tangem.domain.card.repository.CardSdkConfigRepository
-import com.tangem.domain.card.repository.DerivationsRepository
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.feature.qrscanning.QrScanningRouter
import com.tangem.features.managetokens.featuretoggles.ManageTokensFeatureToggles
-import com.tangem.features.managetokens.navigation.ManageTokensRouter
+import com.tangem.features.managetokens.navigation.ManageTokensUi
import com.tangem.features.send.api.featuretoggles.SendFeatureToggles
import com.tangem.features.send.api.navigation.SendRouter
-import com.tangem.features.tester.api.TesterFeatureToggles
import com.tangem.features.tester.api.TesterRouter
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
import com.tangem.features.wallet.navigation.WalletRouter
@@ -39,7 +39,7 @@ data class DaggerGraphState(
val walletConnectInteractor: WalletConnectInteractor? = null,
val tokenDetailsRouter: TokenDetailsRouter? = null,
val manageTokensFeatureToggles: ManageTokensFeatureToggles? = null,
- val manageTokensRouter: ManageTokensRouter? = null,
+ val manageTokensUi: ManageTokensUi? = null,
val scanCardProcessor: ScanCardProcessor? = null,
val cardSdkConfigRepository: CardSdkConfigRepository? = null,
val appCurrencyRepository: AppCurrencyRepository? = null,
@@ -52,11 +52,9 @@ data class DaggerGraphState(
val sendFeatureToggles: SendFeatureToggles? = null,
val sendRouter: SendRouter? = null,
val qrScanningRouter: QrScanningRouter? = null,
-
- // FIXME: It is used only for TokensList screen. Remove after refactoring of TokensList
val currenciesRepository: CurrenciesRepository? = null,
- val derivationsRepository: DerivationsRepository? = null,
- val testerFeatureToggles: TesterFeatureToggles? = null,
+ val blockchainDataStorage: BlockchainDataStorage? = null,
+ val accountCreator: AccountCreator? = null,
) : StateType {
inline fun get(getDependency: DaggerGraphState.() -> T?): T {
diff --git a/app/src/main/res/layout/layout_send_address.xml b/app/src/main/res/layout/layout_send_address.xml
index 8367bf3524..1256f33037 100644
--- a/app/src/main/res/layout/layout_send_address.xml
+++ b/app/src/main/res/layout/layout_send_address.xml
@@ -260,6 +260,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt
index 830d2621c2..a684154112 100644
--- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt
+++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt
@@ -125,6 +125,7 @@ sealed class AnalyticsParam {
const val SOURCE = "Source"
const val BALANCE = "Balance"
const val BATCH = "Batch"
+ const val TYPE = "Type"
const val FEE_TYPE = "Fee Type"
const val PERMISSION_TYPE = "Permission Type"
const val PRODUCT_TYPE = "Product Type"
diff --git a/core/datasource/build.gradle.kts b/core/datasource/build.gradle.kts
index 137ccdb922..522cd3257e 100644
--- a/core/datasource/build.gradle.kts
+++ b/core/datasource/build.gradle.kts
@@ -33,7 +33,6 @@ dependencies {
implementation(deps.timber)
/** Network */
- implementation(deps.krateSharedPref)
implementation(deps.moshi)
implementation(deps.moshi.kotlin)
implementation(deps.okHttp)
diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/BigDecimalAdapter.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/BigDecimalAdapter.kt
index 568b042179..e81aa15e06 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/api/common/BigDecimalAdapter.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/BigDecimalAdapter.kt
@@ -7,7 +7,7 @@ import java.math.BigDecimal
/**
[REDACTED_AUTHOR]
*/
-class BigDecimalAdapter {
+internal class BigDecimalAdapter {
@FromJson
fun fromJson(value: String) = BigDecimal(value)
diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/DateTimeAdapter.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/DateTimeAdapter.kt
new file mode 100644
index 0000000000..38f4b81532
--- /dev/null
+++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/DateTimeAdapter.kt
@@ -0,0 +1,23 @@
+package com.tangem.datasource.api.common
+
+import com.squareup.moshi.*
+import org.joda.time.DateTime
+
+internal class DateTimeAdapter : JsonAdapter() {
+
+ @FromJson
+ override fun fromJson(reader: JsonReader): DateTime? {
+ val dateString = reader.nextString() ?: return null
+
+ return DateTime.parse(dateString)
+ }
+
+ @ToJson
+ override fun toJson(writer: JsonWriter, value: DateTime?) {
+ if (value != null) {
+ writer.value(value.toString())
+ } else {
+ writer.nullValue()
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/LocalDateAdapter.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/LocalDateAdapter.kt
index b11c76fccd..95978206f2 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/api/common/LocalDateAdapter.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/LocalDateAdapter.kt
@@ -1,14 +1,10 @@
package com.tangem.datasource.api.common
-import com.squareup.moshi.FromJson
-import com.squareup.moshi.JsonAdapter
-import com.squareup.moshi.JsonReader
-import com.squareup.moshi.JsonWriter
-import com.squareup.moshi.ToJson
+import com.squareup.moshi.*
import org.joda.time.LocalDate
import org.joda.time.format.DateTimeFormat
-class LocalDateAdapter : JsonAdapter() {
+internal class LocalDateAdapter : JsonAdapter() {
private val formatter = DateTimeFormat.forPattern("yyyy-MM-dd")
diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseCallAdapterFactory.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseCallAdapterFactory.kt
index 11eca2e0d6..8f8c65e92d 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseCallAdapterFactory.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseCallAdapterFactory.kt
@@ -6,7 +6,7 @@ import retrofit2.Retrofit
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
-internal class ApiResponseCallAdapterFactory private constructor() : CallAdapter.Factory() {
+class ApiResponseCallAdapterFactory private constructor() : CallAdapter.Factory() {
override fun get(returnType: Type, annotations: Array, retrofit: Retrofit): CallAdapter<*, *>? {
if (getRawType(returnType) != Call::class.java) {
diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt
index 43ff3af6e5..63e632438e 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt
@@ -75,4 +75,11 @@ interface TangemTechApi {
@GET("promotion")
suspend fun getPromotionInfo(@Query("programName") name: String): ApiResponse
+
+ @POST("user-network-account")
+ suspend fun createUserNetworkAccount(
+ @Header("card_public_key") cardPublicKey: String,
+ @Header("card_id") cardId: String,
+ @Body body: CreateUserNetworkAccountBody,
+ ): ApiResponse
}
\ No newline at end of file
diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/CreateUserNetworkAccountBody.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/CreateUserNetworkAccountBody.kt
new file mode 100644
index 0000000000..f359bbd961
--- /dev/null
+++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/CreateUserNetworkAccountBody.kt
@@ -0,0 +1,10 @@
+package com.tangem.datasource.api.tangemTech.models
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class CreateUserNetworkAccountBody(
+ @Json(name = "networkId") val networkId: String,
+ @Json(name = "walletPublicKey") val publicWalletKey: String,
+)
\ No newline at end of file
diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/CreateUserNetworkAccountResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/CreateUserNetworkAccountResponse.kt
new file mode 100644
index 0000000000..2dcb8bfb8f
--- /dev/null
+++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/CreateUserNetworkAccountResponse.kt
@@ -0,0 +1,17 @@
+package com.tangem.datasource.api.tangemTech.models
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class CreateUserNetworkAccountResponse(
+ @Json(name = "status") val status: Boolean,
+ @Json(name = "data") val data: AccountCreated,
+) {
+
+ @JsonClass(generateAdapter = true)
+ data class AccountCreated(
+ @Json(name = "accountId") val accountId: String,
+ @Json(name = "publicWalletKey") val publicWalletKey: String,
+ )
+}
\ No newline at end of file
diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt
index ed2d89b8d2..580334eb2b 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt
@@ -1,6 +1,7 @@
package com.tangem.datasource.config
import com.tangem.blockchain.common.*
+import com.tangem.datasource.BuildConfig
import com.tangem.datasource.config.ConfigManager.Companion.IS_CREATING_TWIN_CARDS_ALLOWED
import com.tangem.datasource.config.ConfigManager.Companion.IS_TOP_UP_ENABLED
import com.tangem.datasource.config.models.Config
@@ -105,7 +106,7 @@ internal class ConfigManagerImpl @Inject constructor() : ConfigManager {
sprinklr = configValues.sprinklr,
walletConnectProjectId = configValues.walletConnectProjectId,
tangemComAuthorization = configValues.tangemComAuthorization,
- express = configValues.express,
+ express = if (BuildConfig.ENVIRONMENT == "dev") configValues.devExpress else configValues.express,
)
}
@@ -145,6 +146,7 @@ internal class ConfigManagerImpl @Inject constructor() : ConfigManager {
jsonRpc = accessTokens.bitcoin?.jsonRPC,
blockBookRest = accessTokens.bitcoin?.blockBookRest,
),
+ algorand = GetBlockAccessToken(rest = accessTokens.algorand?.rest),
)
}
}
diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt b/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt
index ec2d4845ad..eaedb32084 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt
@@ -40,6 +40,7 @@ class ConfigValueModel(
val tangemComAuthorization: String?,
val chiaFireAcademyApiKey: String?,
val chiaTangemApiKey: String?,
+ val devExpress: ExpressModel?,
val express: ExpressModel?,
)
@@ -66,6 +67,7 @@ data class GetBlockAccessTokens(
@Json(name = "litecoin") val litecoin: GetBlockToken?,
@Json(name = "dash") val dash: GetBlockToken?,
@Json(name = "bitcoin") val bitcoin: GetBlockToken?,
+ @Json(name = "algorand") val algorand: GetBlockToken?,
)
@JsonClass(generateAdapter = true)
diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/AccountCreatorModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/AccountCreatorModule.kt
new file mode 100644
index 0000000000..7abd08cf54
--- /dev/null
+++ b/core/datasource/src/main/java/com/tangem/datasource/di/AccountCreatorModule.kt
@@ -0,0 +1,22 @@
+package com.tangem.datasource.di
+
+import com.tangem.blockchain.common.AccountCreator
+import com.tangem.datasource.api.tangemTech.TangemTechApi
+import com.tangem.datasource.local.blockchain.DefaultAccountCreator
+import com.tangem.lib.auth.AuthProvider
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+internal object AccountCreatorModule {
+
+ @Provides
+ @Singleton
+ fun provideAccountCreator(authProvider: AuthProvider, @DevTangemApi tangemTechApi: TangemTechApi): AccountCreator {
+ return DefaultAccountCreator(authProvider, tangemTechApi)
+ }
+}
\ No newline at end of file
diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/AppPreferenceStorageModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/AppPreferenceStorageModule.kt
deleted file mode 100644
index 2eefec13ed..0000000000
--- a/core/datasource/src/main/java/com/tangem/datasource/di/AppPreferenceStorageModule.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.tangem.datasource.di
-
-import com.tangem.datasource.local.AppPreferenceStorage
-import com.tangem.datasource.local.AppPreferenceStorageImpl
-import dagger.Binds
-import dagger.Module
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import javax.inject.Singleton
-
-@Module
-@InstallIn(SingletonComponent::class)
-internal interface AppPreferenceStorageModule {
-
- @Binds
- @Singleton
- fun bindAppPreferenceStorage(appPreferenceStorageImpl: AppPreferenceStorageImpl): AppPreferenceStorage
-}
\ No newline at end of file
diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/BlockchainDataStorageModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/BlockchainDataStorageModule.kt
new file mode 100644
index 0000000000..3d285b3fbe
--- /dev/null
+++ b/core/datasource/src/main/java/com/tangem/datasource/di/BlockchainDataStorageModule.kt
@@ -0,0 +1,21 @@
+package com.tangem.datasource.di
+
+import com.tangem.blockchain.common.datastorage.BlockchainDataStorage
+import com.tangem.datasource.local.blockchain.DefaultBlockchainDataStorage
+import com.tangem.datasource.local.preferences.AppPreferencesStore
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+internal object BlockchainDataStorageModule {
+
+ @Provides
+ @Singleton
+ fun provideBlockchainDataStorage(appPreferencesStore: AppPreferencesStore): BlockchainDataStorage {
+ return DefaultBlockchainDataStorage(appPreferencesStore)
+ }
+}
\ No newline at end of file
diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/MoshiModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/MoshiModule.kt
index bf3d94095f..c22d4433bf 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/di/MoshiModule.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/di/MoshiModule.kt
@@ -4,6 +4,7 @@ import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import com.tangem.common.json.MoshiJsonConverter
import com.tangem.datasource.api.common.BigDecimalAdapter
+import com.tangem.datasource.api.common.DateTimeAdapter
import com.tangem.datasource.api.common.LocalDateAdapter
import dagger.Module
import dagger.Provides
@@ -22,6 +23,7 @@ class MoshiModule {
return Moshi.Builder()
.add(BigDecimalAdapter())
.add(LocalDateAdapter())
+ .add(DateTimeAdapter())
.add(KotlinJsonAdapterFactory())
.build()
}
diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/AppPreferenceStorage.kt b/core/datasource/src/main/java/com/tangem/datasource/local/AppPreferenceStorage.kt
deleted file mode 100644
index d56ca29fa0..0000000000
--- a/core/datasource/src/main/java/com/tangem/datasource/local/AppPreferenceStorage.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.tangem.datasource.local
-
-/**
- * Application local storage
- *
-[REDACTED_AUTHOR]
- */
-@Deprecated(message = "Use AppPreferencesStore", level = DeprecationLevel.WARNING)
-interface AppPreferenceStorage {
-
- /** Json config with feature toggles 'ToggleName: String - Availability: Boolean' */
- var featureToggles: String
-}
\ No newline at end of file
diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/AppPreferenceStorageImpl.kt b/core/datasource/src/main/java/com/tangem/datasource/local/AppPreferenceStorageImpl.kt
deleted file mode 100644
index 3ce9a8aca9..0000000000
--- a/core/datasource/src/main/java/com/tangem/datasource/local/AppPreferenceStorageImpl.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.tangem.datasource.local
-
-import android.content.Context
-import dagger.hilt.android.qualifiers.ApplicationContext
-import hu.autsoft.krate.SimpleKrate
-import hu.autsoft.krate.default.withDefault
-import hu.autsoft.krate.stringPref
-import javax.inject.Inject
-import javax.inject.Singleton
-
-/**
- * Implementation of application local storage
- *
- * @param context application context
- *
-[REDACTED_AUTHOR]
- */
-@Singleton
-internal class AppPreferenceStorageImpl @Inject constructor(
- @ApplicationContext context: Context,
-) : SimpleKrate(context = context), AppPreferenceStorage {
-
- override var featureToggles: String by stringPref().withDefault("")
-}
\ No newline at end of file
diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/blockchain/DefaultAccountCreator.kt b/core/datasource/src/main/java/com/tangem/datasource/local/blockchain/DefaultAccountCreator.kt
new file mode 100644
index 0000000000..1501279d83
--- /dev/null
+++ b/core/datasource/src/main/java/com/tangem/datasource/local/blockchain/DefaultAccountCreator.kt
@@ -0,0 +1,31 @@
+package com.tangem.datasource.local.blockchain
+
+import com.tangem.blockchain.common.AccountCreator
+import com.tangem.blockchain.common.Blockchain
+import com.tangem.blockchain.common.BlockchainSdkError
+import com.tangem.blockchain.extensions.Result
+import com.tangem.common.extensions.toHexString
+import com.tangem.datasource.api.common.response.getOrThrow
+import com.tangem.datasource.api.tangemTech.TangemTechApi
+import com.tangem.datasource.api.tangemTech.models.CreateUserNetworkAccountBody
+import com.tangem.lib.auth.AuthProvider
+
+internal class DefaultAccountCreator(
+ private val authProvider: AuthProvider,
+ private val tangemTechApi: TangemTechApi,
+) : AccountCreator {
+
+ override suspend fun createAccount(blockchain: Blockchain, walletPublicKey: ByteArray): Result {
+ val request = CreateUserNetworkAccountBody(blockchain.id.removeSuffix("/test"), walletPublicKey.toHexString())
+ return try {
+ val response = tangemTechApi.createUserNetworkAccount(
+ cardPublicKey = authProvider.getCardPublicKey(),
+ cardId = authProvider.getCardId(),
+ body = request,
+ ).getOrThrow()
+ Result.Success(response.data.accountId)
+ } catch (e: Exception) {
+ Result.Failure(BlockchainSdkError.FailedToCreateAccount)
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/blockchain/DefaultBlockchainDataStorage.kt b/core/datasource/src/main/java/com/tangem/datasource/local/blockchain/DefaultBlockchainDataStorage.kt
new file mode 100644
index 0000000000..3f3d7192f5
--- /dev/null
+++ b/core/datasource/src/main/java/com/tangem/datasource/local/blockchain/DefaultBlockchainDataStorage.kt
@@ -0,0 +1,29 @@
+package com.tangem.datasource.local.blockchain
+
+import androidx.datastore.preferences.core.edit
+import androidx.datastore.preferences.core.stringPreferencesKey
+import com.tangem.blockchain.common.datastorage.BlockchainDataStorage
+import com.tangem.datasource.local.preferences.AppPreferencesStore
+import com.tangem.datasource.local.preferences.utils.getSyncOrNull
+
+/**
+ * [BlockchainDataStorage] implementation
+ *
+ * @property appPreferencesStore app preferences store
+ *
+[REDACTED_AUTHOR]
+ */
+internal class DefaultBlockchainDataStorage(
+ private val appPreferencesStore: AppPreferencesStore,
+) : BlockchainDataStorage {
+
+ override suspend fun getOrNull(key: String): String? {
+ return appPreferencesStore.getSyncOrNull(key = stringPreferencesKey(name = key))
+ }
+
+ override suspend fun store(key: String, value: String) {
+ appPreferencesStore.edit {
+ it[stringPreferencesKey(key)] = value
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt
index 652187147e..c5c54133ac 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt
@@ -52,6 +52,8 @@ object PreferencesKeys {
val IS_TOKEN_SWAP_PROMO_CHANGELLY_SHOW_KEY by lazy {
booleanPreferencesKey(name = "isTokenSwapPromoChangellyShown")
}
+
+ val FEATURE_TOGGLES_KEY by lazy { stringPreferencesKey(name = "featureToggles") }
}
/** Preferences keys set that should be migrated from "PreferencesDataSource" to a new DataStore */
diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/txhistory/DefaultTxHistoryItemsStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/txhistory/DefaultTxHistoryItemsStore.kt
index 7cbeb3f317..c992faf5bd 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/local/txhistory/DefaultTxHistoryItemsStore.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/local/txhistory/DefaultTxHistoryItemsStore.kt
@@ -2,6 +2,7 @@ package com.tangem.datasource.local.txhistory
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import com.tangem.datasource.local.datastore.core.StringKeyDataStoreDecorator
+import com.tangem.domain.txhistory.models.Page
import com.tangem.domain.txhistory.models.PaginationWrapper
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.utils.extensions.addOrReplace
@@ -13,28 +14,16 @@ internal class DefaultTxHistoryItemsStore(
override fun provideStringKey(key: TxHistoryItemsStore.Key): String = key.toString()
- override suspend fun getNextPageSyncOrNull(key: TxHistoryItemsStore.Key): Int? {
- val storedValue = getSyncOrNull(key) ?: return null
- val lastWrappedItems = storedValue.maxBy(PaginationWrapper<*>::page)
- val lastPage = lastWrappedItems.page
-
- return if (lastPage <= lastWrappedItems.totalPages) {
- lastPage
- } else {
- null
- }
- }
-
- override suspend fun getSyncOrNull(key: TxHistoryItemsStore.Key, page: Int): PaginationWrapper? {
+ override suspend fun getSyncOrNull(key: TxHistoryItemsStore.Key, page: Page): PaginationWrapper? {
val storedValue = getSyncOrNull(key)
- return storedValue?.firstOrNull { it.page == page }
+ return storedValue?.firstOrNull { it.currentPage == page }
}
override suspend fun store(key: TxHistoryItemsStore.Key, value: PaginationWrapper) {
val oldValue = getSyncOrNull(key).orEmpty()
val newValue = oldValue.addOrReplace(value) {
- it.page == value.page
+ it.currentPage == value.currentPage
}
store(key, newValue)
diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/txhistory/TxHistoryItemsStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/txhistory/TxHistoryItemsStore.kt
index e2f288e235..b49bc4fdd4 100644
--- a/core/datasource/src/main/java/com/tangem/datasource/local/txhistory/TxHistoryItemsStore.kt
+++ b/core/datasource/src/main/java/com/tangem/datasource/local/txhistory/TxHistoryItemsStore.kt
@@ -1,15 +1,14 @@
package com.tangem.datasource.local.txhistory
import com.tangem.domain.tokens.model.CryptoCurrency
+import com.tangem.domain.txhistory.models.Page
import com.tangem.domain.txhistory.models.PaginationWrapper
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.wallets.models.UserWalletId
interface TxHistoryItemsStore {
- suspend fun getNextPageSyncOrNull(key: Key): Int?
-
- suspend fun getSyncOrNull(key: Key, page: Int): PaginationWrapper?
+ suspend fun getSyncOrNull(key: Key, page: Page): PaginationWrapper?
suspend fun remove(key: Key)
diff --git a/core/deep-links/global/src/main/kotlin/com/tangem/core/deeplink/global/BuyCurrencyDeepLink.kt b/core/deep-links/global/src/main/kotlin/com/tangem/core/deeplink/global/BuyCurrencyDeepLink.kt
index 286f8f8c73..3c31ec55a7 100644
--- a/core/deep-links/global/src/main/kotlin/com/tangem/core/deeplink/global/BuyCurrencyDeepLink.kt
+++ b/core/deep-links/global/src/main/kotlin/com/tangem/core/deeplink/global/BuyCurrencyDeepLink.kt
@@ -4,7 +4,7 @@ import com.tangem.core.deeplink.DeepLink
class BuyCurrencyDeepLink(val onReceive: () -> Unit) : DeepLink {
- override val uri: String = "tangem://success.tangem.com"
+ override val uri: String = "tangem://redirect?action=dismissBrowser"
override fun onReceive(params: Map) {
onReceive()
diff --git a/core/featuretoggles/build.gradle.kts b/core/featuretoggles/build.gradle.kts
index c5f9b07545..5354b55813 100644
--- a/core/featuretoggles/build.gradle.kts
+++ b/core/featuretoggles/build.gradle.kts
@@ -7,14 +7,22 @@ plugins {
}
dependencies {
- implementation(project(":core:datasource"))
+ /** DI */
implementation(deps.hilt.android)
kapt(deps.hilt.kapt)
+
+ /** Local storages */
+ implementation(deps.androidx.datastore)
+
+ /** Other libraries */
implementation(deps.moshi)
implementation(deps.moshi.kotlin)
implementation(deps.timber)
+ /** Core modules */
+ implementation(projects.core.datasource)
+
testImplementation(deps.test.coroutine)
testImplementation(deps.test.junit)
testImplementation(deps.test.mockk)
diff --git a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json
index e91e7f03e8..e76218c369 100644
--- a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json
+++ b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json
@@ -14,13 +14,5 @@
{
"name": "REDESIGNED_SEND_SCREEN_ENABLED",
"version": "undefined"
- },
- {
- "name": "WALLETS_SCROLLING_PREVIEW_ENABLED",
- "version": "5.5.0"
- },
- {
- "name": "DERIVE_PUBLIC_KEYS_REFACTORING_ENABLED",
- "version": "5.5.0"
}
]
diff --git a/core/featuretoggles/src/main/kotlin/com/tangem/core/featuretoggle/di/FeatureTogglesManagerModule.kt b/core/featuretoggles/src/main/kotlin/com/tangem/core/featuretoggle/di/FeatureTogglesManagerModule.kt
index eadb4bf0fb..e67ca2a738 100644
--- a/core/featuretoggles/src/main/kotlin/com/tangem/core/featuretoggle/di/FeatureTogglesManagerModule.kt
+++ b/core/featuretoggles/src/main/kotlin/com/tangem/core/featuretoggle/di/FeatureTogglesManagerModule.kt
@@ -11,7 +11,7 @@ import com.tangem.core.featuretoggle.storage.LocalFeatureTogglesStorage
import com.tangem.core.featuretoggle.version.DefaultVersionProvider
import com.tangem.core.featuretoggles.BuildConfig
import com.tangem.datasource.asset.AssetReader
-import com.tangem.datasource.local.AppPreferenceStorage
+import com.tangem.datasource.local.preferences.AppPreferencesStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@@ -29,7 +29,7 @@ internal object FeatureTogglesManagerModule {
fun provideFeatureTogglesManager(
@ApplicationContext context: Context,
assetReader: AssetReader,
- appPreferenceStorage: AppPreferenceStorage,
+ appPreferencesStore: AppPreferencesStore,
): FeatureTogglesManager {
val moshi = Moshi.Builder().addLast(KotlinJsonAdapterFactory()).build()
val localFeatureTogglesStorage = LocalFeatureTogglesStorage(
@@ -41,8 +41,7 @@ internal object FeatureTogglesManagerModule {
return if (BuildConfig.TESTER_MENU_ENABLED) {
DevFeatureTogglesManager(
localFeatureTogglesStorage = localFeatureTogglesStorage,
- appPreferenceStorage = appPreferenceStorage,
- jsonAdapter = moshi.adapter(),
+ appPreferencesStore = appPreferencesStore,
versionProvider = versionProvider,
)
} else {
diff --git a/core/featuretoggles/src/main/kotlin/com/tangem/core/featuretoggle/manager/DevFeatureTogglesManager.kt b/core/featuretoggles/src/main/kotlin/com/tangem/core/featuretoggle/manager/DevFeatureTogglesManager.kt
index 12e0a496b6..9b29a65f66 100644
--- a/core/featuretoggles/src/main/kotlin/com/tangem/core/featuretoggle/manager/DevFeatureTogglesManager.kt
+++ b/core/featuretoggles/src/main/kotlin/com/tangem/core/featuretoggle/manager/DevFeatureTogglesManager.kt
@@ -1,25 +1,25 @@
package com.tangem.core.featuretoggle.manager
import androidx.annotation.VisibleForTesting
-import com.squareup.moshi.JsonAdapter
import com.tangem.core.featuretoggle.storage.FeatureTogglesStorage
import com.tangem.core.featuretoggle.utils.associateToggles
import com.tangem.core.featuretoggle.version.VersionProvider
-import com.tangem.datasource.local.AppPreferenceStorage
+import com.tangem.datasource.local.preferences.AppPreferencesStore
+import com.tangem.datasource.local.preferences.PreferencesKeys
+import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
+import com.tangem.datasource.local.preferences.utils.storeObject
import kotlin.properties.Delegates
/**
* Feature toggles manager implementation in DEV build
*
* @property localFeatureTogglesStorage local feature toggles storage
- * @property appPreferenceStorage application local storage
- * @property jsonAdapter adapter for parsing json
+ * @property appPreferencesStore application local store
* @property versionProvider application version provider
*/
internal class DevFeatureTogglesManager(
private val localFeatureTogglesStorage: FeatureTogglesStorage,
- private val appPreferenceStorage: AppPreferenceStorage,
- private val jsonAdapter: JsonAdapter