diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 5294908fc5..6edc1d9d21 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -17,6 +17,7 @@
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index ea77304740..89ca7c3734 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -22,6 +22,7 @@ dependencies {
implementation(project(":core:utils"))
implementation(project(":libs:crypto"))
implementation(project(":libs:auth"))
+ implementation(project(":data:source:preferences"))
/** Features */
implementation(project(":features:onboarding"))
diff --git a/app/src/main/assets/testnet_tokens.json b/app/src/main/assets/testnet_tokens.json
index d36455384c..b7f5b4f8e4 100644
--- a/app/src/main/assets/testnet_tokens.json
+++ b/app/src/main/assets/testnet_tokens.json
@@ -484,6 +484,17 @@
"networkId": "ravencoin/test"
}
]
+ },
+ {
+ "id": "cosmos",
+ "symbol": "ATOM",
+ "name": "Cosmos Hub",
+ "networks":
+ [
+ {
+ "networkId": "cosmos/test"
+ }
+ ]
}
]
}
diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt
index f8efc046b2..b224a7f81a 100644
--- a/app/src/main/java/com/tangem/tap/TapApplication.kt
+++ b/app/src/main/java/com/tangem/tap/TapApplication.kt
@@ -12,6 +12,7 @@ import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
import com.tangem.core.analytics.Analytics
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
+import com.tangem.data.source.preferences.PreferencesDataSource
import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.datasource.asset.AssetReader
import com.tangem.datasource.config.ConfigManager
@@ -50,10 +51,8 @@ import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository
import com.tangem.tap.domain.walletStores.repository.di.provideDefaultImplementation
import com.tangem.tap.domain.walletconnect.WalletConnectRepository
import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
-import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles
-import com.tangem.tap.persistence.PreferencesStorage
import com.tangem.tap.proxy.AppStateHolder
-import com.tangem.tap.proxy.redux.DaggerGraphAction
+import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.wallet.BuildConfig
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.launch
@@ -66,7 +65,7 @@ lateinit var store: Store
lateinit var foregroundActivityObserver: ForegroundActivityObserver
lateinit var activityResultCaller: ActivityResultCaller
-lateinit var preferencesStorage: PreferencesStorage
+lateinit var preferencesStorage: PreferencesDataSource
lateinit var walletConnectRepository: WalletConnectRepository
lateinit var shopService: TangemShopService
lateinit var userTokensRepository: UserTokensRepository
@@ -129,10 +128,10 @@ class TapApplication : Application(), ImageLoaderFactory {
lateinit var networkConnectionManager: NetworkConnectionManager
@Inject
- lateinit var tokensListFeatureToggles: TokensListFeatureToggles
+ lateinit var customTokenFeatureToggles: CustomTokenFeatureToggles
@Inject
- lateinit var customTokenFeatureToggles: CustomTokenFeatureToggles
+ lateinit var preferencesDataSource: PreferencesDataSource
override fun onCreate() {
super.onCreate()
@@ -142,7 +141,13 @@ class TapApplication : Application(), ImageLoaderFactory {
appReducer(action, state, appStateHolder)
},
middleware = AppState.getMiddleware(),
- state = AppState(),
+ state = AppState(
+ daggerGraphState = DaggerGraphState(
+ assetReader = assetReader,
+ networkConnectionManager = networkConnectionManager,
+ customTokenFeatureToggles = customTokenFeatureToggles,
+ ),
+ ),
)
if (BuildConfig.DEBUG) {
@@ -154,7 +159,7 @@ class TapApplication : Application(), ImageLoaderFactory {
registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks)
DomainLayer.init()
- preferencesStorage = PreferencesStorage(this)
+ preferencesStorage = preferencesDataSource
walletConnectRepository = WalletConnectRepository(this)
val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.sdkMoshi, BuildConfig.ENVIRONMENT)
@@ -178,15 +183,6 @@ class TapApplication : Application(), ImageLoaderFactory {
appStateHolder.userTokensRepository = userTokensRepository
appStateHolder.walletStoresManager = walletStoresManager
- store.dispatch(
- action = DaggerGraphAction.SetApplicationDependencies(
- assetReader = assetReader,
- networkConnectionManager = networkConnectionManager,
- tokensListFeatureToggles = tokensListFeatureToggles,
- customTokenFeatureToggles = customTokenFeatureToggles,
- ),
- )
-
scope.launch {
featureTogglesManager.init()
}
@@ -248,7 +244,7 @@ class TapApplication : Application(), ImageLoaderFactory {
private fun initFeedbackManager(
context: Context,
- preferencesStorage: PreferencesStorage,
+ preferencesStorage: PreferencesDataSource,
foregroundActivityObserver: ForegroundActivityObserver,
store: Store,
) {
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt
index 30caf9f355..97edaae4c1 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/topup/TopUpController.kt
@@ -3,9 +3,11 @@ package com.tangem.tap.common.analytics.topup
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.isZero
import com.tangem.core.analytics.Analytics
+import com.tangem.data.source.preferences.model.DataSourceTopupInfo
+import com.tangem.data.source.preferences.storage.ToppedUpWalletStorage
import com.tangem.domain.common.CardTypesResolver
-import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.UserWalletId
+import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.analytics.converters.TopUpEventConverter
import com.tangem.tap.common.analytics.events.AnalyticsParam
@@ -19,7 +21,6 @@ import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager
import com.tangem.tap.domain.walletStores.WalletStoresManager
import com.tangem.tap.features.wallet.models.Currency
-import com.tangem.tap.persistence.ToppedUpWalletStorage
import com.tangem.tap.scope
import kotlinx.coroutines.launch
import java.math.BigDecimal
@@ -90,9 +91,9 @@ class TopUpController(
val isToppedUpInPast = findToppedUpCurrenciesInPast(walletDataModels).isNotEmpty()
if (isToppedUpInPast) {
- val newWalletInfo = ToppedUpWalletStorage.TopupInfo(
+ val newWalletInfo = DataSourceTopupInfo(
walletId = userWalletId.stringValue,
- cardBalanceState = AnalyticsParam.CardBalanceState.Full,
+ cardBalanceState = DataSourceTopupInfo.CardBalanceState.Full,
)
topupWalletStorage.save(newWalletInfo)
return@launch
@@ -109,9 +110,9 @@ class TopUpController(
fun registerEmptyWallet(scanResponse: ScanResponse) {
UserWalletIdBuilder.scanResponse(scanResponse).build()?.let {
topupWalletStorage.save(
- ToppedUpWalletStorage.TopupInfo(
+ DataSourceTopupInfo(
walletId = it.stringValue,
- cardBalanceState = AnalyticsParam.CardBalanceState.Empty,
+ cardBalanceState = DataSourceTopupInfo.CardBalanceState.Empty,
),
)
}
@@ -129,17 +130,28 @@ class TopUpController(
cardTypesResolver: CardTypesResolver,
) {
val topupInfo = topupWalletStorage.restore(userWalletId.stringValue).guard {
- val topupInfo = ToppedUpWalletStorage.TopupInfo(
+ val topupInfo = DataSourceTopupInfo(
walletId = userWalletId.stringValue,
- cardBalanceState = cardBalanceState,
+ cardBalanceState = when (cardBalanceState) {
+ AnalyticsParam.CardBalanceState.BlockchainError ->
+ DataSourceTopupInfo.CardBalanceState.BlockchainError
+ AnalyticsParam.CardBalanceState.CustomToken ->
+ DataSourceTopupInfo.CardBalanceState.CustomToken
+ AnalyticsParam.CardBalanceState.Empty ->
+ DataSourceTopupInfo.CardBalanceState.Empty
+ AnalyticsParam.CardBalanceState.Full ->
+ DataSourceTopupInfo.CardBalanceState.Full
+ },
)
topupWalletStorage.save(topupInfo)
return
}
- if (topupInfo.isToppedUp) return
- if (!topupInfo.isToppedUp && cardBalanceState.isToppedUp()) {
- topupWalletStorage.save(topupInfo.copy(cardBalanceState = AnalyticsParam.CardBalanceState.Full))
+ val isToppedUp = topupInfo.cardBalanceState == DataSourceTopupInfo.CardBalanceState.Full
+ if (isToppedUp) return
+
+ if (cardBalanceState.isToppedUp()) {
+ topupWalletStorage.save(topupInfo.copy(cardBalanceState = DataSourceTopupInfo.CardBalanceState.Full))
TopUpEventConverter().convert(cardTypesResolver)?.let {
Analytics.send(it)
}
diff --git a/app/src/main/java/com/tangem/tap/common/chat/ChatManager.kt b/app/src/main/java/com/tangem/tap/common/chat/ChatManager.kt
index bc69217fa1..182aa7350b 100644
--- a/app/src/main/java/com/tangem/tap/common/chat/ChatManager.kt
+++ b/app/src/main/java/com/tangem/tap/common/chat/ChatManager.kt
@@ -2,19 +2,19 @@ package com.tangem.tap.common.chat
import android.content.Context
import android.os.Build
-import com.tangem.tap.ForegroundActivityObserver
import com.tangem.datasource.config.models.ChatConfig
-import com.tangem.tap.common.chat.opener.ChatOpener
import com.tangem.datasource.config.models.SprinklrConfig
import com.tangem.datasource.config.models.ZendeskConfig
+import com.tangem.data.source.preferences.PreferencesDataSource
+import com.tangem.tap.ForegroundActivityObserver
+import com.tangem.tap.common.chat.opener.ChatOpener
import com.tangem.tap.common.chat.opener.implementation.SprinklrChatOpener
import com.tangem.tap.common.chat.opener.implementation.ZendeskChatOpener
import com.tangem.tap.common.redux.AppState
-import com.tangem.tap.persistence.PreferencesStorage
import org.rekotlin.Store
class ChatManager(
- private val preferencesStorage: PreferencesStorage,
+ private val preferencesStorage: PreferencesDataSource,
private val foregroundActivityObserver: ForegroundActivityObserver,
private val store: Store,
) {
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt b/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt
index 5aae0ce706..58a7fa8076 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt
@@ -40,6 +40,7 @@ fun Blockchain.getGreyedOutIconRes(): Int {
Blockchain.TON, Blockchain.TONTestnet -> R.drawable.ic_ton_no_color
Blockchain.Kava, Blockchain.KavaTestnet -> R.drawable.ic_kava_no_color
Blockchain.Ravencoin, Blockchain.RavencoinTestnet -> R.drawable.ic_ravencoin_no_color
+ Blockchain.Cosmos, Blockchain.CosmosTestnet -> R.drawable.ic_cosmos_no_color
else -> R.drawable.ic_tangem_logo
}
}
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Collections.kt b/app/src/main/java/com/tangem/tap/common/extensions/Collections.kt
index 517d8ca5ed..ee2867d25c 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/Collections.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/Collections.kt
@@ -1,15 +1,5 @@
package com.tangem.tap.common.extensions
-/**
-[REDACTED_AUTHOR]
- */
-fun List.containsAny(list: List): Boolean {
- this.forEach { mainItem ->
- list.forEach { if (it == mainItem) return true }
- }
- return false
-}
-
fun MutableList.removeBy(predicate: (T) -> Boolean): Boolean {
val toRemove = this.filter(predicate)
this.removeAll(toRemove)
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 efd80355aa..806a46dd1d 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
@@ -5,6 +5,7 @@ import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
+import androidx.fragment.app.FragmentTransaction
import com.tangem.feature.referral.ReferralFragment
import com.tangem.feature.swap.presentation.SwapFragment
import com.tangem.tap.common.redux.navigation.AppScreen
@@ -28,7 +29,6 @@ import com.tangem.tap.features.saveWallet.ui.SaveWalletBottomSheetFragment
import com.tangem.tap.features.send.ui.SendFragment
import com.tangem.tap.features.shop.ui.ShopFragment
import com.tangem.tap.features.tokens.impl.presentation.TokensListFragment
-import com.tangem.tap.features.tokens.legacy.AddTokensFragment
import com.tangem.tap.features.wallet.ui.WalletDetailsFragment
import com.tangem.tap.features.wallet.ui.WalletFragment
import com.tangem.tap.features.walletSelector.ui.WalletSelectorBottomSheetFragment
@@ -45,24 +45,35 @@ fun FragmentActivity.openFragment(
bundle: Bundle? = null,
fgShareTransition: FragmentShareTransition? = null,
) {
- val transaction = this.supportFragmentManager.beginTransaction()
- val fragment = fragmentFactory(screen)
- fragment.arguments = bundle
- fgShareTransition?.apply {
- fragment.sharedElementEnterTransition = enterTransitionSet
- fragment.sharedElementReturnTransition = exitTransitionSet
- transaction.setReorderingAllowed(true)
- shareElements.forEach { shareElement ->
- shareElement.wView.get()?.let { view ->
- transaction.addSharedElement(view, shareElement.elementName)
+ val transaction = supportFragmentManager.beginTransaction().apply {
+ setReorderingAllowed(true)
+ }
+
+ val fragment = fragmentFactory(screen).apply {
+ arguments = bundle
+
+ if (fgShareTransition != null) {
+ sharedElementEnterTransition = fgShareTransition.enterTransitionSet
+ sharedElementReturnTransition = fgShareTransition.exitTransitionSet
+ fgShareTransition.shareElements.forEach { shareElement ->
+ shareElement.wView.get()?.let { view ->
+ transaction.addSharedElement(view, shareElement.elementName)
+ }
}
}
}
+
if (screen.isDialogFragment) {
- (fragment as DialogFragment).show(transaction, screen.name)
- if (addToBackstack) {
- transaction.addToBackStack(screen.name)
+ val dialogFragment = requireNotNull(fragment as? DialogFragment) {
+ "If screen.isDialogFragment == true then fragment must be a DialogFragment"
}
+
+ dialogFragment.showAllowingStateLoss(
+ fragmentManager = supportFragmentManager,
+ baseTransaction = transaction,
+ tag = screen.name,
+ addToBackstack = addToBackstack,
+ )
} else {
transaction.replace(R.id.fragment_container, fragment, screen.name)
if (addToBackstack) {
@@ -72,6 +83,29 @@ fun FragmentActivity.openFragment(
}
}
+private fun DialogFragment.showAllowingStateLoss(
+ fragmentManager: FragmentManager,
+ baseTransaction: FragmentTransaction,
+ tag: String,
+ addToBackstack: Boolean,
+) {
+ runCatching {
+ if (addToBackstack) baseTransaction.addToBackStack(tag)
+ show(baseTransaction, tag)
+ }
+ .onFailure { throwable ->
+ if (throwable is IllegalStateException) {
+ val transaction = fragmentManager.beginTransaction()
+ transaction.add(this, tag)
+ if (addToBackstack) transaction.addToBackStack(tag)
+
+ transaction.commitAllowingStateLoss()
+ } else {
+ Timber.e(throwable)
+ }
+ }
+}
+
fun FragmentActivity.popBackTo(screen: AppScreen?, inclusive: Boolean = false) {
val inclusiveFlag = if (inclusive) FragmentManager.POP_BACK_STACK_INCLUSIVE else 0
try {
@@ -113,12 +147,8 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
AppScreen.ResetToFactory -> ResetCardFragment()
AppScreen.AccessCodeRecovery -> AccessCodeRecoveryFragment()
AppScreen.Disclaimer -> DisclaimerFragment()
- AppScreen.AddTokens -> {
- val featureToggles = store.state.daggerGraphState.get(
- getDependency = DaggerGraphState::tokensListFeatureToggles,
- )
- if (featureToggles.isRedesignedScreenEnabled) TokensListFragment() else AddTokensFragment()
- }
+ AppScreen.AddTokens -> TokensListFragment()
+
AppScreen.AddCustomToken -> {
val featureToggles = store.state.daggerGraphState.get(
getDependency = DaggerGraphState::customTokenFeatureToggles,
@@ -129,6 +159,7 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
AddCustomTokenFragment()
}
}
+
AppScreen.WalletDetails -> WalletDetailsFragment()
AppScreen.WalletConnectSessions -> WalletConnectFragment()
AppScreen.QrScan -> QrScanFragment()
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 2efd12e515..de6bae2411 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
@@ -101,7 +101,7 @@ data class AppState(
SendMiddleware().sendMiddleware,
DetailsMiddleware().detailsMiddleware,
DisclaimerMiddleware().disclaimerMiddleware,
- TokensMiddleware().tokensMiddleware,
+ TokensMiddleware.tokensMiddleware,
WalletConnectMiddleware().walletConnectMiddleware,
BackupMiddleware().backupMiddleware,
ShopMiddleware().shopMiddleware,
diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt
index 39d29a451f..01d00c9a82 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt
@@ -5,11 +5,12 @@ import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.datasource.config.models.Config
import com.tangem.domain.common.LogConfig
-import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.extensions.withMainContext
+import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.models.scan.ScanResponse
+import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchOnMain
@@ -75,7 +76,9 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
is GlobalAction.RestoreAppCurrency -> {
store.dispatch(
GlobalAction.RestoreAppCurrency.Success(
- preferencesStorage.fiatCurrenciesPrefStorage.getAppCurrency(),
+ preferencesStorage.fiatCurrenciesPrefStorage.getAppCurrency()
+ ?.run { FiatCurrency(code, name, symbol) }
+ ?: FiatCurrency.Default,
),
)
}
diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt
index 9d908f0724..b5122147ca 100644
--- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt
+++ b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt
@@ -1,16 +1,16 @@
package com.tangem.tap.domain.configurable.warningMessage
import com.tangem.blockchain.common.Blockchain
-import com.tangem.tap.common.extensions.containsAny
import com.tangem.tap.common.extensions.removeBy
import com.tangem.wallet.R
+import java.util.concurrent.CopyOnWriteArrayList
/**
[REDACTED_AUTHOR]
*/
class WarningMessagesManager {
- private val warningsList: MutableList = mutableListOf()
+ private val warningsList = CopyOnWriteArrayList()
fun addWarning(warning: WarningMessage) {
if (findWarning(warning) == null) {
@@ -19,36 +19,27 @@ class WarningMessagesManager {
}
}
- fun getWarnings(
- location: WarningMessage.Location,
- forBlockchains: List = emptyList(),
- ): List {
- return warningsList
- .filter { !it.isHidden && it.location.contains(location) }
- .filter {
- val list = it.blockchainList
- when {
- list == null -> true
- list.containsAny(forBlockchains) -> true
- else -> false
- }
- }
+ fun getWarnings(location: WarningMessage.Location, blockchains: List): List {
+ return warningsList.filter { message ->
+ val messageBlockchains = message.blockchainList
+ val isCorrespondingMessageBlockchains = messageBlockchains == null ||
+ messageBlockchains.any(blockchains::contains)
+ val isCorrespondingMessageLocation = message.location.contains(location)
+
+ !message.isHidden && isCorrespondingMessageLocation && isCorrespondingMessageBlockchains
+ }
}
fun hideWarning(warning: WarningMessage): Boolean {
- val foundWarning = findWarning(warning)
- return when {
- foundWarning == null -> false
- foundWarning.type == WarningMessage.Type.Temporary ||
- foundWarning.type == WarningMessage.Type.AppRating -> {
- if (foundWarning.isHidden) {
- false
- } else {
- foundWarning.isHidden = true
- true
- }
- }
- else -> false
+ val foundWarning = findWarning(warning) ?: return false
+ val isCorrectType = foundWarning.type == WarningMessage.Type.Temporary ||
+ foundWarning.type == WarningMessage.Type.AppRating
+
+ return if (!foundWarning.isHidden && isCorrectType) {
+ foundWarning.isHidden = true
+ true
+ } else {
+ false
}
}
@@ -72,31 +63,31 @@ class WarningMessagesManager {
companion object {
const val REMAINING_SIGNATURES_WARNING = 10
- fun devCardWarning(): WarningMessage = WarningMessage(
- "",
- "",
+ val devCardWarning = WarningMessage(
+ title = "",
+ message = "",
type = WarningMessage.Type.Permanent,
priority = WarningMessage.Priority.Critical,
- listOf(WarningMessage.Location.MainScreen),
- null,
- R.string.common_warning,
- R.string.alert_developer_card,
- WarningMessage.Origin.Local,
+ location = listOf(WarningMessage.Location.MainScreen),
+ blockchains = null,
+ titleResId = R.string.common_warning,
+ messageResId = R.string.alert_developer_card,
+ origin = WarningMessage.Origin.Local,
)
- fun alreadySignedHashesWarning(): WarningMessage = WarningMessage(
- "",
- "",
+ val alreadySignedHashesWarning = WarningMessage(
+ title = "",
+ message = "",
type = WarningMessage.Type.Temporary,
priority = WarningMessage.Priority.Info,
- listOf(WarningMessage.Location.MainScreen),
- null,
- R.string.common_warning,
- R.string.alert_card_signed_transactions,
- WarningMessage.Origin.Local,
+ location = listOf(WarningMessage.Location.MainScreen),
+ blockchains = null,
+ titleResId = R.string.common_warning,
+ messageResId = R.string.alert_card_signed_transactions,
+ origin = WarningMessage.Origin.Local,
)
- fun signedHashesMultiWalletWarning(): WarningMessage = WarningMessage(
+ val signedHashesMultiWalletWarning = WarningMessage(
title = "",
message = "",
type = WarningMessage.Type.Temporary,
@@ -110,69 +101,71 @@ class WarningMessagesManager {
titleFormatArg = "\u26A0",
)
- fun appRatingWarning(): WarningMessage = WarningMessage(
- "",
- "",
- WarningMessage.Type.AppRating,
- WarningMessage.Priority.Info,
- listOf(WarningMessage.Location.MainScreen),
- null,
- R.string.warning_rate_app_title,
- R.string.warning_rate_app_message,
- WarningMessage.Origin.Local,
+ val appRatingWarning = WarningMessage(
+ title = "",
+ message = "",
+ type = WarningMessage.Type.AppRating,
+ priority = WarningMessage.Priority.Info,
+ location = listOf(WarningMessage.Location.MainScreen),
+ blockchains = null,
+ titleResId = R.string.warning_rate_app_title,
+ messageResId = R.string.warning_rate_app_message,
+ origin = WarningMessage.Origin.Local,
)
- fun isAlreadySignedHashesWarning(warning: WarningMessage): Boolean {
- return warning.messageResId == R.string.alert_card_signed_transactions
- }
-
- fun onlineVerificationFailed(): WarningMessage = WarningMessage(
- "",
- "",
- type = WarningMessage.Type.Permanent,
- priority = WarningMessage.Priority.Critical,
- listOf(WarningMessage.Location.MainScreen),
- null,
- R.string.warning_failed_to_verify_card_title,
- R.string.warning_failed_to_verify_card_message,
- WarningMessage.Origin.Local,
- )
-
- fun remainingSignaturesNotEnough(remainingSignatures: Int): WarningMessage = WarningMessage(
+ val onlineVerificationFailed = WarningMessage(
title = "",
message = "",
type = WarningMessage.Type.Permanent,
priority = WarningMessage.Priority.Critical,
- listOf(WarningMessage.Location.MainScreen),
+ location = listOf(WarningMessage.Location.MainScreen),
blockchains = null,
- titleResId = R.string.common_warning,
- messageResId = R.string.warning_low_signatures_format,
+ titleResId = R.string.warning_failed_to_verify_card_title,
+ messageResId = R.string.warning_failed_to_verify_card_message,
origin = WarningMessage.Origin.Local,
- messageFormatArg = remainingSignatures.toString(),
)
- fun testCardWarning(): WarningMessage = WarningMessage(
- "",
- "",
+ val testCardWarning = WarningMessage(
+ title = "",
+ message = "",
type = WarningMessage.Type.TestCard,
priority = WarningMessage.Priority.Critical,
- listOf(WarningMessage.Location.MainScreen, WarningMessage.Location.SendScreen),
- null,
- R.string.common_warning,
- R.string.warning_testnet_card_message,
- WarningMessage.Origin.Local,
+ location = listOf(WarningMessage.Location.MainScreen, WarningMessage.Location.SendScreen),
+ blockchains = null,
+ titleResId = R.string.common_warning,
+ messageResId = R.string.warning_testnet_card_message,
+ origin = WarningMessage.Origin.Local,
)
- fun demoCardWarning(): WarningMessage = WarningMessage(
- "",
- "",
+ val demoCardWarning = WarningMessage(
+ title = "",
+ message = "",
type = WarningMessage.Type.Permanent,
priority = WarningMessage.Priority.Critical,
- listOf(WarningMessage.Location.MainScreen),
- null,
- R.string.common_warning,
- R.string.alert_demo_message,
- WarningMessage.Origin.Local,
+ location = listOf(WarningMessage.Location.MainScreen),
+ blockchains = null,
+ titleResId = R.string.common_warning,
+ messageResId = R.string.alert_demo_message,
+ origin = WarningMessage.Origin.Local,
)
+
+ fun remainingSignaturesNotEnough(remainingSignatures: Int): WarningMessage {
+ return WarningMessage(
+ title = "",
+ message = "",
+ type = WarningMessage.Type.Permanent,
+ priority = WarningMessage.Priority.Critical,
+ location = listOf(WarningMessage.Location.MainScreen),
+ blockchains = null,
+ titleResId = R.string.common_warning,
+ messageResId = R.string.warning_low_signatures_format,
+ origin = WarningMessage.Origin.Local,
+ messageFormatArg = remainingSignatures.toString(),
+ )
+ }
+
+ fun isAlreadySignedHashesWarning(warning: WarningMessage): Boolean {
+ return warning.messageResId == R.string.alert_card_signed_transactions
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt
index 75ea69067b..4a7518e9f9 100644
--- a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt
@@ -10,12 +10,12 @@ import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.toMapKey
-import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.common.map
-import com.tangem.domain.models.scan.CardDTO
+import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.domain.common.TapWorkarounds.isTestCard
+import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.KeyWalletPublicKey
import com.tangem.operations.CommandResponse
import com.tangem.operations.backup.PrimaryCard
@@ -233,17 +233,38 @@ private class CreateWalletTangemWallet : ProductCommandProcessor) -> Unit,
) {
val map = mutableMapOf>()
+ var isBlockchainsForCurvesExist = false
createWalletResponse.forEach { response ->
val blockchainsForCurve = getBlockchains(response.cardId, card).filter {
it.getSupportedCurves().contains(response.wallet.curve)
}
- val derivationPaths = blockchainsForCurve.mapNotNull { it.derivationPath(card.derivationStyle) }
+ val derivationPaths = blockchainsForCurve.mapNotNull {
+ isBlockchainsForCurvesExist = true
+ it.derivationPath(card.derivationStyle)
+ }
if (derivationPaths.isNotEmpty()) {
map[response.wallet.publicKey.toMapKey()] = derivationPaths
}
}
+ val cardEnv = session.environment.card
+ if (cardEnv == null) {
+ callback(CompletionResult.Failure(TangemSdkError.CardError()))
+ return
+ }
if (map.isEmpty()) {
- callback(CompletionResult.Failure(TangemSdkError.UnknownError()))
+ if (isBlockchainsForCurvesExist) {
+ callback(CompletionResult.Failure(TangemSdkError.UnknownError()))
+ } else {
+ // if there is no blockchains to derive, just return success response with empty derivedKeys
+ callback(
+ CompletionResult.Success(
+ CreateProductWalletTaskResponse(
+ card = cardEnv,
+ primaryCard = primaryCard,
+ ),
+ ),
+ )
+ }
return
}
@@ -254,7 +275,7 @@ private class CreateWalletTangemWallet : ProductCommandProcessor.updateWithAmounts(wallet: Wallet): List {
val amount = wallet.fundsAvailable(AmountType.Coin)
if (pendingTransactions.isEmpty()) {
- WalletDataModel.VerifiedOnline(
- amount = amount,
- )
+ WalletDataModel.VerifiedOnline(amount)
} else {
- WalletDataModel.TransactionInProgress(
- amount = amount,
- pendingTransactions = pendingTransactions,
- )
+ WalletDataModel.TransactionInProgress(amount, pendingTransactions)
}
}
+
is Currency.Token -> {
val token = currency.token
val amount = wallet.fundsAvailable(AmountType.Token(token))
- val hasTokenPendingTransactions = pendingTransactions
- .any { it.transactionData.amount.currencySymbol == token.symbol }
+ val hasTokenPendingTransactions = pendingTransactions.any {
+ it.transactionData.amount.currencySymbol == token.symbol
+ }
+
when {
hasTokenPendingTransactions -> {
- WalletDataModel.TransactionInProgress(
- amount = amount,
- pendingTransactions = pendingTransactions,
- )
+ WalletDataModel.TransactionInProgress(amount, pendingTransactions)
}
+
pendingTransactions.isNotEmpty() -> {
- WalletDataModel.SameCurrencyTransactionInProgress(
- amount = amount,
- pendingTransactions = pendingTransactions,
- )
+ // FIXME: Necessary to avoid passing pending transactions
+ // because SameCurrencyTransactionInProgress didn't use it. It used only to define main button
+ // availability. UI layer turned off pending transaction visibility for this state.
+ WalletDataModel.SameCurrencyTransactionInProgress(amount, pendingTransactions)
}
else -> {
- WalletDataModel.VerifiedOnline(
- amount = amount,
- )
+ WalletDataModel.VerifiedOnline(amount)
}
}
}
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/data/converters/FoundTokenConverter.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/data/converters/FoundTokenConverter.kt
index ebd6da9985..977869feb2 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/data/converters/FoundTokenConverter.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/data/converters/FoundTokenConverter.kt
@@ -16,6 +16,7 @@ object FoundTokenConverter : Converter {
id = value.id,
name = value.name,
symbol = value.symbol,
+ isActive = value.active,
network = value.networks.firstOrNull()?.let { network ->
FoundToken.Network(
id = network.networkId,
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/domain/models/FoundToken.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/domain/models/FoundToken.kt
index 25c3cb5836..6ca52f5eb5 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/domain/models/FoundToken.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/domain/models/FoundToken.kt
@@ -3,14 +3,21 @@ package com.tangem.tap.features.customtoken.impl.domain.models
/**
* Found token model
*
- * @property id id
- * @property name name
- * @property symbol symbol
- * @property network network
+ * @property id id
+ * @property name name
+ * @property symbol symbol
+ * @property isActive flag that determines status of token
+ * @property network network
*
[REDACTED_AUTHOR]
*/
-data class FoundToken(val id: String, val name: String, val symbol: String, val network: Network) {
+data class FoundToken(
+ val id: String,
+ val name: String,
+ val symbol: String,
+ val isActive: Boolean,
+ val network: Network,
+) {
/**
* Found token network
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/AddCustomTokenFragment.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/AddCustomTokenFragment.kt
index ee63fc97e0..f4478fc4fc 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/AddCustomTokenFragment.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/AddCustomTokenFragment.kt
@@ -6,6 +6,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.core.view.WindowCompat
import androidx.fragment.app.Fragment
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.transition.TransitionInflater
@@ -24,6 +25,8 @@ import dagger.hilt.android.AndroidEntryPoint
internal class AddCustomTokenFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+ activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) }
+
with(TransitionInflater.from(requireContext())) {
enterTransition = inflateTransition(R.transition.fade)
exitTransition = inflateTransition(R.transition.fade)
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/models/AddCustomTokenViewsModels.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/models/AddCustomTokenViewsModels.kt
index 90dcb8a583..a43c5a84c4 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/models/AddCustomTokenViewsModels.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/models/AddCustomTokenViewsModels.kt
@@ -1,8 +1,6 @@
package com.tangem.tap.features.customtoken.impl.presentation.models
import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.ui.text.input.ImeAction
-import androidx.compose.ui.text.input.KeyboardType
import com.tangem.blockchain.common.Blockchain
import com.tangem.tap.features.details.ui.cardsettings.TextReference
import com.tangem.wallet.R
@@ -94,106 +92,94 @@ internal sealed interface AddCustomTokenInputField {
/** Label */
val label: TextReference
- /** Input availability */
- val isEnabled: Boolean
-
- /** Flag that determine if current value has error */
- val isError: Boolean
-
/** Placeholder (hint) */
val placeholder: TextReference
- /** Flag that determine the processing of current value */
- val isLoading: Boolean
-
/**
* Input field model to enter the contract address
*
- * @property value current value
- * @property onValueChange lambda be invoked when value is been changed
- * @property isError flag that determine if current value has error
- * @property isLoading flag that determine the processing of current value
+ * @property value current value
+ * @property onValueChange lambda be invoked when value is been changed
+ * @property keyboardOptions keyboard options
+ * @property label label
+ * @property placeholder placeholder (hint)
+ * @property isLoading flag that determine the processing of current value
+ * @property isError flag that determine if current value has error
+ * @property error error description
*/
data class ContactAddress(
override val value: String,
override val onValueChange: (String) -> Unit,
- override val isError: Boolean,
- override val isLoading: Boolean,
- ) : AddCustomTokenInputField {
- override val isEnabled = true
- override val keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next)
- override val label = TextReference.Res(R.string.custom_token_contract_address_input_title)
- override val placeholder = TextReference.Str(value = "0x0000000000000000000000000000000000000000")
- }
+ override val keyboardOptions: KeyboardOptions,
+ override val label: TextReference,
+ override val placeholder: TextReference,
+ val isLoading: Boolean,
+ val isError: Boolean,
+ val error: TextReference? = null,
+ ) : AddCustomTokenInputField
/**
* Input field model to enter the token name
*
- * @property value current value
- * @property onValueChange lambda be invoked when value is been changed
- * @property isEnabled input availability
- * @property isError flag that determine if current value has error
+ * @property value current value
+ * @property onValueChange lambda be invoked when value is been changed
+ * @property keyboardOptions keyboard options
+ * @property label label
+ * @property placeholder placeholder (hint)
+ * @property isEnabled input availability
*/
data class TokenName(
override val value: String,
override val onValueChange: (String) -> Unit,
- override val isEnabled: Boolean,
- override val isError: Boolean,
- ) : AddCustomTokenInputField {
- override val keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next)
- override val label = TextReference.Res(R.string.custom_token_name_input_title)
- override val placeholder = TextReference.Res(id = R.string.custom_token_name_input_placeholder)
- override val isLoading = false
- }
+ override val keyboardOptions: KeyboardOptions,
+ override val label: TextReference,
+ override val placeholder: TextReference,
+ val isEnabled: Boolean,
+ ) : AddCustomTokenInputField
/**
* Input field model to enter the token symbol
*
- * @property value current value
- * @property onValueChange lambda be invoked when value is been changed
- * @property isEnabled input availability
- * @property isError flag that determine if current value has error
+ * @property value current value
+ * @property onValueChange lambda be invoked when value is been changed
+ * @property keyboardOptions keyboard options
+ * @property label label
+ * @property placeholder placeholder (hint)
+ * @property isEnabled input availability
*/
data class TokenSymbol(
override val value: String,
override val onValueChange: (String) -> Unit,
- override val isEnabled: Boolean,
- override val isError: Boolean,
- ) : AddCustomTokenInputField {
- override val keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next)
- override val label = TextReference.Res(R.string.custom_token_token_symbol_input_title)
- override val placeholder = TextReference.Res(id = R.string.custom_token_token_symbol_input_placeholder)
- override val isLoading = false
- }
+ override val keyboardOptions: KeyboardOptions,
+ override val label: TextReference,
+ override val placeholder: TextReference,
+ val isEnabled: Boolean,
+ ) : AddCustomTokenInputField
/**
* Input field model to enter the token decimals
*
- * @property value current value
- * @property onValueChange lambda be invoked when value is been changed
- * @property isEnabled input availability
- * @property isError flag that determine if current value has error
+ * @property value current value
+ * @property onValueChange lambda be invoked when value is been changed
+ * @property keyboardOptions keyboard options
+ * @property label label
+ * @property placeholder placeholder (hint)
+ * @property isEnabled input availability
*/
data class Decimals(
override val value: String,
override val onValueChange: (String) -> Unit,
- override val isEnabled: Boolean,
- override val isError: Boolean,
- ) : AddCustomTokenInputField {
- override val keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Next)
- override val label = TextReference.Res(R.string.custom_token_decimals_input_title)
- override val placeholder = TextReference.Str(value = "8")
- override val isLoading = false
- }
+ override val keyboardOptions: KeyboardOptions,
+ override val label: TextReference,
+ override val placeholder: TextReference,
+ val isEnabled: Boolean,
+ ) : AddCustomTokenInputField
}
/** Base selector field model of add custom token screen */
internal sealed interface AddCustomTokenSelectorField {
- /** Selection availability */
- val isEnabled: Boolean
-
- /** Label string resource id */
+ /** Label */
val label: TextReference
/** Selected menu item */
@@ -208,35 +194,34 @@ internal sealed interface AddCustomTokenSelectorField {
/**
* Network selector model
*
+ * @property label label
* @property selectedItem selected menu item
* @property items menu items
* @property onMenuItemClick lambda be invoked when menu item is been selected
*/
data class Network(
+ override val label: TextReference,
override val selectedItem: SelectorItem.Title,
override val items: List,
override val onMenuItemClick: (Int) -> Unit,
- ) : AddCustomTokenSelectorField {
- override val isEnabled = true
- override val label = TextReference.Res(R.string.custom_token_network_input_title)
- }
+ ) : AddCustomTokenSelectorField
/**
* Derivation path selector model
*
- * @property isEnabled selection availability
+ * @property label label
* @property selectedItem selected menu item
* @property items menu items
* @property onMenuItemClick lambda be invoked when menu item is been selected
+ * @property isEnabled selection availability
*/
data class DerivationPath(
- override val isEnabled: Boolean,
+ override val label: TextReference,
override val selectedItem: SelectorItem.TitleWithSubtitle,
override val items: List,
override val onMenuItemClick: (Int) -> Unit,
- ) : AddCustomTokenSelectorField {
- override val label = TextReference.Res(R.string.custom_token_derivation_path_input_title)
- }
+ val isEnabled: Boolean,
+ ) : AddCustomTokenSelectorField
/** Base menu item model */
sealed interface SelectorItem {
@@ -259,17 +244,40 @@ internal sealed interface AddCustomTokenSelectorField {
* Menu item with title ans subtitle
*
* @property title title text
- * @property subtitle subtitle text
* @property blockchain blockchain
+ * @property subtitle subtitle text
*/
data class TitleWithSubtitle(
override val title: TextReference,
- val subtitle: TextReference,
override val blockchain: Blockchain,
+ val subtitle: TextReference,
) : SelectorItem
}
}
+/**
+ * Warning model of add custom token screen
+ *
+ * @property description warning description
+ */
+internal sealed class AddCustomTokenWarning(val description: TextReference) {
+
+ /** Potential scam warning */
+ object PotentialScamToken : AddCustomTokenWarning(
+ description = TextReference.Res(R.string.custom_token_validation_error_not_found),
+ )
+
+ /** Token already added warning */
+ object TokenAlreadyAdded : AddCustomTokenWarning(
+ description = TextReference.Res(R.string.custom_token_validation_error_already_added),
+ )
+
+ /** Unsupported Solana token warning */
+ object UnsupportedSolanaToken : AddCustomTokenWarning(
+ description = TextReference.Res(R.string.alert_manage_tokens_unsupported_message),
+ )
+}
+
/**
* Floating button of add custom token screen
*
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/models/CustomTokenType.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/models/CustomTokenType.kt
new file mode 100644
index 0000000000..b36fe58ce3
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/models/CustomTokenType.kt
@@ -0,0 +1,4 @@
+package com.tangem.tap.features.customtoken.impl.presentation.models
+
+/** Custom token type */
+enum class CustomTokenType { TOKEN, BLOCKCHAIN }
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/routers/CustomTokenRouter.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/routers/CustomTokenRouter.kt
index 933bda4bc7..bcd32893fe 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/routers/CustomTokenRouter.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/routers/CustomTokenRouter.kt
@@ -9,4 +9,7 @@ internal interface CustomTokenRouter {
/** Return to last screen */
fun popBackStack()
+
+ /** Open wallet (main) screen */
+ fun openWalletScreen()
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/routers/DefaultCustomTokenRouter.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/routers/DefaultCustomTokenRouter.kt
index 9460879f92..25eb163e9b 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/routers/DefaultCustomTokenRouter.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/routers/DefaultCustomTokenRouter.kt
@@ -1,5 +1,6 @@
package com.tangem.tap.features.customtoken.impl.presentation.routers
+import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.store
@@ -9,4 +10,8 @@ internal class DefaultCustomTokenRouter : CustomTokenRouter {
override fun popBackStack() {
store.dispatch(NavigationAction.PopBackTo())
}
+
+ override fun openWalletScreen() {
+ store.dispatch(NavigationAction.PopBackTo(screen = AppScreen.Wallet))
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/states/AddCustomTokenStateHolder.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/states/AddCustomTokenStateHolder.kt
index 17b0f92c9c..32eba291ef 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/states/AddCustomTokenStateHolder.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/states/AddCustomTokenStateHolder.kt
@@ -4,8 +4,8 @@ import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTok
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenFloatingButton
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenForm
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenTestBlock
+import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenWarning
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokensToolbar
-import com.tangem.tap.features.details.ui.cardsettings.TextReference
/**
* State holder of add custom token screen
@@ -24,7 +24,7 @@ internal sealed interface AddCustomTokenStateHolder {
val form: AddCustomTokenForm
/** Warnings */
- val warnings: List
+ val warnings: Set
/** Floating button model */
val floatingButton: AddCustomTokenFloatingButton
@@ -42,7 +42,7 @@ internal sealed interface AddCustomTokenStateHolder {
onBackButtonClick: () -> Unit = this.onBackButtonClick,
toolbar: AddCustomTokensToolbar = this.toolbar,
form: AddCustomTokenForm = this.form,
- warnings: List = this.warnings,
+ warnings: Set = this.warnings,
floatingButton: AddCustomTokenFloatingButton = this.floatingButton,
): AddCustomTokenStateHolder {
return when (this) {
@@ -64,7 +64,7 @@ internal sealed interface AddCustomTokenStateHolder {
override val onBackButtonClick: () -> Unit,
override val toolbar: AddCustomTokensToolbar,
override val form: AddCustomTokenForm,
- override val warnings: List,
+ override val warnings: Set,
override val floatingButton: AddCustomTokenFloatingButton,
) : AddCustomTokenStateHolder
@@ -83,7 +83,7 @@ internal sealed interface AddCustomTokenStateHolder {
override val onBackButtonClick: () -> Unit,
override val toolbar: AddCustomTokensToolbar,
override val form: AddCustomTokenForm,
- override val warnings: List,
+ override val warnings: Set,
override val floatingButton: AddCustomTokenFloatingButton,
val testBlock: AddCustomTokenTestBlock,
val bottomSheet: AddCustomTokenChooseTokenBottomSheet,
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenContent.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenContent.kt
index 7b746c3ec4..e57d82cc15 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenContent.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenContent.kt
@@ -9,22 +9,21 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.FabPosition
import androidx.compose.material.Scaffold
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.key
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.tooling.preview.Preview
-import com.tangem.blockchain.common.Blockchain
+import androidx.compose.ui.unit.dp
import com.tangem.core.ui.res.TangemTheme
-import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenFloatingButton
-import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenInputField
-import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenSelectorField
-import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokensToolbar
import com.tangem.tap.features.customtoken.impl.presentation.states.AddCustomTokenStateHolder
import com.tangem.tap.features.customtoken.impl.presentation.ui.components.AddCustomTokenFloatingButton
import com.tangem.tap.features.customtoken.impl.presentation.ui.components.AddCustomTokenForm
import com.tangem.tap.features.customtoken.impl.presentation.ui.components.AddCustomTokenToolbar
-import com.tangem.tap.features.customtoken.impl.presentation.ui.components.AddCustomTokenWarning
-import com.tangem.tap.features.details.ui.cardsettings.TextReference
-import com.tangem.wallet.R
+import com.tangem.tap.features.customtoken.impl.presentation.ui.components.AddCustomTokenWarnings
/**
* Add custom token content
@@ -37,6 +36,7 @@ import com.tangem.wallet.R
internal fun AddCustomTokenContent(state: AddCustomTokenStateHolder.Content) {
BackHandler(onBack = state.onBackButtonClick)
+ var floatingButtonHeight by remember { mutableStateOf(0.dp) }
Scaffold(
topBar = {
AddCustomTokenToolbar(
@@ -44,78 +44,36 @@ internal fun AddCustomTokenContent(state: AddCustomTokenStateHolder.Content) {
onBackButtonClick = state.toolbar.onBackButtonClick,
)
},
- floatingActionButton = { AddCustomTokenFloatingButton(model = state.floatingButton) },
+ floatingActionButton = {
+ val density = LocalDensity.current
+ val verticalPadding = TangemTheme.dimens.spacing32
+ AddCustomTokenFloatingButton(
+ model = state.floatingButton,
+ modifier = Modifier.onSizeChanged {
+ floatingButtonHeight = with(density) { it.height.toDp() + verticalPadding }
+ },
+ )
+ },
floatingActionButtonPosition = FabPosition.Center,
) {
Column(
modifier = Modifier
+ .verticalScroll(rememberScrollState())
.padding(paddingValues = it)
- .fillMaxSize()
- .verticalScroll(rememberScrollState()),
+ .padding(bottom = floatingButtonHeight)
+ .fillMaxSize(),
) {
AddCustomTokenForm(model = state.form)
- state.warnings.forEach { description ->
- key(description) {
- AddCustomTokenWarning(description)
- }
- }
+ AddCustomTokenWarnings(warnings = state.warnings)
}
}
}
-@Preview(showSystemUi = true)
+@Preview
@Composable
private fun Preview_AddCustomTokenContent() {
TangemTheme {
- AddCustomTokenContent(
- state = AddCustomTokenStateHolder.Content(
- onBackButtonClick = {},
- toolbar = AddCustomTokensToolbar(
- title = TextReference.Res(R.string.add_custom_token_title),
- onBackButtonClick = {},
- ),
- form = com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenForm(
- contractAddressInputField = AddCustomTokenInputField.ContactAddress(
- value = "",
- onValueChange = {},
- isError = false,
- isLoading = false,
- ),
- networkSelectorField = AddCustomTokenSelectorField.Network(
- selectedItem = AddCustomTokenSelectorField.SelectorItem.Title(
- title = TextReference.Str("Avalanche"),
- blockchain = Blockchain.Avalanche,
- ),
- items = listOf(),
- onMenuItemClick = {},
- ),
- tokenNameInputField = AddCustomTokenInputField.TokenName(
- value = "",
- onValueChange = {},
- isEnabled = false,
- isError = false,
- ),
- tokenSymbolInputField = AddCustomTokenInputField.TokenSymbol(
- value = "",
- onValueChange = {},
- isEnabled = false,
- isError = false,
- ),
- decimalsInputField = AddCustomTokenInputField.Decimals(
- value = "",
- onValueChange = {},
- isEnabled = false,
- isError = false,
- ),
- derivationPathSelectorField = null,
- ),
- warnings = listOf(),
- floatingButton = AddCustomTokenFloatingButton(
- isEnabled = false,
- onClick = {},
- ),
- ),
- )
+ AddCustomTokenContent(state = AddCustomTokenPreviewData.createContent())
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenPreviewData.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenPreviewData.kt
new file mode 100644
index 0000000000..e463c90ae9
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenPreviewData.kt
@@ -0,0 +1,124 @@
+package com.tangem.tap.features.customtoken.impl.presentation.ui
+
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
+import com.tangem.blockchain.common.Blockchain
+import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenChooseTokenBottomSheet
+import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenFloatingButton
+import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenForm
+import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenInputField
+import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenSelectorField
+import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenTestBlock
+import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenWarning
+import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokensToolbar
+import com.tangem.tap.features.customtoken.impl.presentation.states.AddCustomTokenStateHolder
+import com.tangem.tap.features.details.ui.cardsettings.TextReference
+import com.tangem.wallet.R
+
+/**
+[REDACTED_AUTHOR]
+ */
+internal object AddCustomTokenPreviewData {
+
+ fun createWarnings(): Set {
+ return setOf(
+ AddCustomTokenWarning.PotentialScamToken,
+ AddCustomTokenWarning.TokenAlreadyAdded,
+ AddCustomTokenWarning.UnsupportedSolanaToken,
+ )
+ }
+
+ fun createDefaultForm(): AddCustomTokenForm {
+ return AddCustomTokenForm(
+ contractAddressInputField = AddCustomTokenInputField.ContactAddress(
+ value = "",
+ onValueChange = {},
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
+ label = TextReference.Res(R.string.custom_token_contract_address_input_title),
+ placeholder = TextReference.Str(value = "0x0000000000000000000000000000000000000000"),
+ isLoading = false,
+ isError = false,
+ error = null,
+ ),
+ networkSelectorField = AddCustomTokenSelectorField.Network(
+ label = TextReference.Res(R.string.custom_token_network_input_title),
+ selectedItem = AddCustomTokenSelectorField.SelectorItem.Title(
+ title = TextReference.Res(R.string.custom_token_network_input_not_selected),
+ blockchain = Blockchain.Unknown,
+ ),
+ items = emptyList(),
+ onMenuItemClick = {},
+ ),
+ tokenNameInputField = AddCustomTokenInputField.TokenName(
+ value = "",
+ onValueChange = {},
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
+ label = TextReference.Res(R.string.custom_token_name_input_title),
+ placeholder = TextReference.Res(id = R.string.custom_token_name_input_placeholder),
+ isEnabled = false,
+ ),
+ tokenSymbolInputField = AddCustomTokenInputField.TokenSymbol(
+ value = "",
+ onValueChange = {},
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
+ label = TextReference.Res(R.string.custom_token_token_symbol_input_title),
+ placeholder = TextReference.Res(id = R.string.custom_token_token_symbol_input_placeholder),
+ isEnabled = false,
+ ),
+ decimalsInputField = AddCustomTokenInputField.Decimals(
+ value = "",
+ onValueChange = {},
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Next),
+ label = TextReference.Res(R.string.custom_token_decimals_input_title),
+ placeholder = TextReference.Str(value = "8"),
+ isEnabled = false,
+ ),
+ derivationPathSelectorField = AddCustomTokenSelectorField.DerivationPath(
+ label = TextReference.Res(R.string.custom_token_derivation_path_input_title),
+ selectedItem = AddCustomTokenSelectorField.SelectorItem.TitleWithSubtitle(
+ title = TextReference.Res(R.string.custom_token_derivation_path_default),
+ subtitle = TextReference.Res(R.string.custom_token_derivation_path_default),
+ blockchain = Blockchain.Unknown,
+ ),
+ items = emptyList(),
+ onMenuItemClick = {},
+ isEnabled = true,
+ ),
+ )
+ }
+
+ fun createTestContent(): AddCustomTokenStateHolder.TestContent {
+ return AddCustomTokenStateHolder.TestContent(
+ onBackButtonClick = {},
+ toolbar = AddCustomTokensToolbar(
+ title = TextReference.Res(R.string.add_custom_token_title),
+ onBackButtonClick = {},
+ ),
+ form = createDefaultForm(),
+ warnings = createWarnings(),
+ floatingButton = AddCustomTokenFloatingButton(isEnabled = false, onClick = {}),
+ testBlock = AddCustomTokenTestBlock(
+ chooseTokenButtonText = "Choose token",
+ clearButtonText = "Clear address",
+ resetButtonText = "Reset",
+ onClearAddressButtonClick = {},
+ onResetButtonClick = {},
+ ),
+ bottomSheet = AddCustomTokenChooseTokenBottomSheet(categoriesBlocks = emptyList(), onTestTokenClick = {}),
+ )
+ }
+
+ fun createContent(): AddCustomTokenStateHolder.Content {
+ return AddCustomTokenStateHolder.Content(
+ onBackButtonClick = {},
+ toolbar = AddCustomTokensToolbar(
+ title = TextReference.Res(R.string.add_custom_token_title),
+ onBackButtonClick = {},
+ ),
+ form = createDefaultForm(),
+ warnings = createWarnings(),
+ floatingButton = AddCustomTokenFloatingButton(isEnabled = false, onClick = {}),
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenScreen.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenScreen.kt
index 82f284fb98..71d079e899 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenScreen.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenScreen.kt
@@ -1,6 +1,10 @@
package com.tangem.tap.features.customtoken.impl.presentation.ui
import androidx.compose.runtime.Composable
+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.res.TangemTheme
import com.tangem.tap.features.customtoken.impl.presentation.states.AddCustomTokenStateHolder
/**
@@ -10,11 +14,27 @@ import com.tangem.tap.features.customtoken.impl.presentation.states.AddCustomTok
*
[REDACTED_AUTHOR]
*/
-@Suppress("UnusedPrivateMember")
@Composable
internal fun AddCustomTokenScreen(stateHolder: AddCustomTokenStateHolder) {
when (stateHolder) {
is AddCustomTokenStateHolder.Content -> AddCustomTokenContent(state = stateHolder)
is AddCustomTokenStateHolder.TestContent -> AddCustomTokenTestContent(state = stateHolder)
}
-}
\ No newline at end of file
+}
+
+@Preview(showSystemUi = true)
+@Composable
+private fun Preview_AddCustomTokenScreen(
+ @PreviewParameter(AddCustomTokenScreenProvider::class) stateHolder: AddCustomTokenStateHolder,
+) {
+ TangemTheme {
+ AddCustomTokenScreen(stateHolder)
+ }
+}
+
+private class AddCustomTokenScreenProvider : CollectionPreviewParameterProvider(
+ collection = listOf(
+ AddCustomTokenPreviewData.createContent(),
+ AddCustomTokenPreviewData.createTestContent(),
+ ),
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenTestContent.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenTestContent.kt
index dce924a655..c23fa86835 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenTestContent.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/AddCustomTokenTestContent.kt
@@ -4,6 +4,7 @@ import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@@ -19,33 +20,33 @@ import androidx.compose.material.FabPosition
import androidx.compose.material.Text
import androidx.compose.material.rememberBottomSheetScaffoldState
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.tangem.blockchain.common.Blockchain
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.SpacerH8
import com.tangem.core.ui.components.atoms.Hand
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenChooseTokenBottomSheet
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenChooseTokenBottomSheet.TestTokenItem
-import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenFloatingButton
-import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenInputField
-import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenSelectorField
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenTestBlock
-import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokensToolbar
import com.tangem.tap.features.customtoken.impl.presentation.states.AddCustomTokenStateHolder
import com.tangem.tap.features.customtoken.impl.presentation.ui.components.AddCustomTokenFloatingButton
import com.tangem.tap.features.customtoken.impl.presentation.ui.components.AddCustomTokenForm
import com.tangem.tap.features.customtoken.impl.presentation.ui.components.AddCustomTokenToolbar
-import com.tangem.tap.features.details.ui.cardsettings.TextReference
-import com.tangem.wallet.R
+import com.tangem.tap.features.customtoken.impl.presentation.ui.components.AddCustomTokenWarnings
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -74,6 +75,7 @@ internal fun AddCustomTokenTestContent(state: AddCustomTokenStateHolder.TestCont
},
)
+ var floatingButtonHeight by remember { mutableStateOf(0.dp) }
BottomSheetScaffold(
sheetContent = {
SheetContent(
@@ -95,7 +97,16 @@ internal fun AddCustomTokenTestContent(state: AddCustomTokenStateHolder.TestCont
},
)
},
- floatingActionButton = { AddCustomTokenFloatingButton(model = state.floatingButton) },
+ floatingActionButton = {
+ val density = LocalDensity.current
+ val verticalPadding = TangemTheme.dimens.spacing32
+ AddCustomTokenFloatingButton(
+ model = state.floatingButton,
+ modifier = Modifier.onSizeChanged {
+ floatingButtonHeight = with(density) { it.height.toDp() + verticalPadding }
+ },
+ )
+ },
floatingActionButtonPosition = FabPosition.Center,
sheetBackgroundColor = TangemTheme.colors.background.secondary,
sheetPeekHeight = TangemTheme.dimens.size0,
@@ -104,15 +115,19 @@ internal fun AddCustomTokenTestContent(state: AddCustomTokenStateHolder.TestCont
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
- .padding(it),
+ .padding(paddingValues = it)
+ .padding(bottom = floatingButtonHeight)
+ .fillMaxSize(),
) {
TestBlock(
- model = state.testBlock,
+ state.testBlock,
coroutineScope,
bottomSheetScaffoldState,
)
AddCustomTokenForm(model = state.form)
+
+ AddCustomTokenWarnings(warnings = state.warnings)
}
}
}
@@ -243,69 +258,10 @@ private fun TestBlock(
}
}
-@Preview(showSystemUi = true)
+@Preview
@Composable
private fun Preview_AddCustomTokenTestContent() {
TangemTheme {
- AddCustomTokenTestContent(
- state = AddCustomTokenStateHolder.TestContent(
- onBackButtonClick = {},
- toolbar = AddCustomTokensToolbar(
- title = TextReference.Res(R.string.add_custom_token_title),
- onBackButtonClick = {},
- ),
- form = com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenForm(
- contractAddressInputField = AddCustomTokenInputField.ContactAddress(
- value = "",
- onValueChange = {},
- isError = false,
- isLoading = false,
- ),
- networkSelectorField = AddCustomTokenSelectorField.Network(
- selectedItem = AddCustomTokenSelectorField.SelectorItem.Title(
- title = TextReference.Str(value = "Avalanche"),
- blockchain = Blockchain.Avalanche,
- ),
- items = listOf(),
- onMenuItemClick = {},
- ),
- tokenNameInputField = AddCustomTokenInputField.TokenName(
- value = "",
- onValueChange = {},
- isEnabled = false,
- isError = false,
- ),
- tokenSymbolInputField = AddCustomTokenInputField.TokenSymbol(
- value = "",
- onValueChange = {},
- isEnabled = false,
- isError = false,
- ),
- decimalsInputField = AddCustomTokenInputField.Decimals(
- value = "",
- onValueChange = {},
- isEnabled = false,
- isError = false,
- ),
- derivationPathSelectorField = null,
- ),
- warnings = listOf(),
- floatingButton = AddCustomTokenFloatingButton(
- isEnabled = false,
- onClick = {},
- ),
- testBlock = AddCustomTokenTestBlock(
- chooseTokenButtonText = "Choose token",
- clearButtonText = "Clear address",
- resetButtonText = "Reset",
- onClearAddressButtonClick = {},
- onResetButtonClick = {},
- ),
- bottomSheet = AddCustomTokenChooseTokenBottomSheet(
- categoriesBlocks = listOf(),
- onTestTokenClick = {},
- ),
- ),
- )
+ AddCustomTokenTestContent(state = AddCustomTokenPreviewData.createTestContent())
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenFloatingButton.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenFloatingButton.kt
index 082bfe4939..618a46fd70 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenFloatingButton.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenFloatingButton.kt
@@ -8,6 +8,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
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.PrimaryButtonIconLeft
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenFloatingButton
@@ -16,14 +18,15 @@ import com.tangem.wallet.R
/**
* Add custom token floating button. Attached above the keyboard.
*
- * @param model button model
+ * @param model button model
+ * @param modifier modifier
*
[REDACTED_AUTHOR]
*/
@Composable
-internal fun AddCustomTokenFloatingButton(model: AddCustomTokenFloatingButton) {
+internal fun AddCustomTokenFloatingButton(model: AddCustomTokenFloatingButton, modifier: Modifier = Modifier) {
PrimaryButtonIconLeft(
- modifier = Modifier
+ modifier = modifier
.imePadding()
.padding(horizontal = TangemTheme.dimens.spacing16)
.fillMaxWidth(),
@@ -36,16 +39,17 @@ internal fun AddCustomTokenFloatingButton(model: AddCustomTokenFloatingButton) {
@Preview
@Composable
-private fun Preview_AddCustomTokenFloatingButton_Enabled() {
+private fun Preview_AddCustomTokenFloatingButton(
+ @PreviewParameter(AddCustomTokenFloatingButtonProvider::class) model: AddCustomTokenFloatingButton,
+) {
TangemTheme {
- AddCustomTokenFloatingButton(model = AddCustomTokenFloatingButton(isEnabled = true, onClick = {}))
+ AddCustomTokenFloatingButton(model)
}
}
-@Preview
-@Composable
-private fun Preview_AddCustomTokenFloatingButton_Disabled() {
- TangemTheme {
- AddCustomTokenFloatingButton(model = AddCustomTokenFloatingButton(isEnabled = false, onClick = {}))
- }
-}
\ No newline at end of file
+private class AddCustomTokenFloatingButtonProvider : CollectionPreviewParameterProvider(
+ listOf(
+ AddCustomTokenFloatingButton(isEnabled = true, onClick = {}),
+ AddCustomTokenFloatingButton(isEnabled = false, onClick = {}),
+ ),
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenForm.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenForm.kt
index 44904ac319..6b2e38d732 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenForm.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenForm.kt
@@ -1,6 +1,10 @@
package com.tangem.tap.features.customtoken.impl.presentation.ui.components
import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.slideInVertically
+import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -14,6 +18,7 @@ import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.ExposedDropdownMenuBox
import androidx.compose.material.ExposedDropdownMenuDefaults
import androidx.compose.material.LinearProgressIndicator
+import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@@ -26,13 +31,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
-import com.tangem.blockchain.common.Blockchain
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.common.compose.TangemTextFieldsDefault
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenForm
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenInputField
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenSelectorField
-import com.tangem.tap.features.details.ui.cardsettings.TextReference
+import com.tangem.tap.features.customtoken.impl.presentation.ui.AddCustomTokenPreviewData
import com.tangem.tap.features.details.ui.cardsettings.resolveReference
/**
@@ -68,7 +74,37 @@ internal fun AddCustomTokenForm(model: AddCustomTokenForm) {
@Composable
private fun InputField(model: AddCustomTokenInputField) {
+ Column {
+ val isError = (model as? AddCustomTokenInputField.ContactAddress)?.isError ?: false
+
+ TextField(model, isError)
+
+ (model as? AddCustomTokenInputField.ContactAddress)?.error?.resolveReference()?.let {
+ AnimatedVisibility(
+ visible = isError,
+ enter = fadeIn() + slideInVertically(),
+ exit = slideOutVertically() + fadeOut(),
+ ) {
+ Text(
+ text = it,
+ color = MaterialTheme.colors.error,
+ style = TangemTheme.typography.body2,
+ )
+ }
+ }
+ }
+}
+
+@Composable
+private fun TextField(model: AddCustomTokenInputField, isError: Boolean) {
Box {
+ val isEnabled = when (model) {
+ is AddCustomTokenInputField.ContactAddress -> true
+ is AddCustomTokenInputField.Decimals -> model.isEnabled
+ is AddCustomTokenInputField.TokenName -> model.isEnabled
+ is AddCustomTokenInputField.TokenSymbol -> model.isEnabled
+ }
+
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = model.value,
@@ -79,8 +115,8 @@ private fun InputField(model: AddCustomTokenInputField) {
text = model.label.resolveReference(),
style = TangemTheme.typography.caption,
color = TangemTextFieldsDefault.defaultTextFieldColors.labelColor(
- enabled = model.isEnabled,
- error = model.isError,
+ enabled = isEnabled,
+ error = isError,
interactionSource = remember { MutableInteractionSource() },
).value,
)
@@ -90,20 +126,20 @@ private fun InputField(model: AddCustomTokenInputField) {
text = model.placeholder.resolveReference(),
style = TangemTheme.typography.body1,
color = TangemTextFieldsDefault.defaultTextFieldColors
- .placeholderColor(enabled = model.isEnabled)
+ .placeholderColor(enabled = isEnabled)
.value,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
},
singleLine = true,
- enabled = model.isEnabled,
- isError = model.isError,
+ enabled = isEnabled,
+ isError = isError,
colors = TangemTextFieldsDefault.defaultTextFieldColors,
)
AnimatedVisibility(
- visible = model.isLoading,
+ visible = (model as? AddCustomTokenInputField.ContactAddress)?.isLoading ?: false,
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
@@ -124,6 +160,7 @@ private fun SelectorField(model: AddCustomTokenSelectorField) {
expanded = isExpanded,
onExpandedChange = { isExpanded = !isExpanded },
) {
+ val isEnabled = (model as? AddCustomTokenSelectorField.DerivationPath)?.isEnabled ?: true
OutlinedTextField(
value = when (val item = model.selectedItem) {
is AddCustomTokenSelectorField.SelectorItem.Title -> item.title
@@ -132,14 +169,14 @@ private fun SelectorField(model: AddCustomTokenSelectorField) {
modifier = Modifier.fillMaxWidth(),
onValueChange = {},
readOnly = true,
- enabled = model.isEnabled,
+ enabled = isEnabled,
label = { Text(text = model.label.resolveReference()) },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = isExpanded) },
colors = TangemTextFieldsDefault.defaultTextFieldColors,
)
ExposedDropdownMenu(
- expanded = isExpanded && model.isEnabled,
+ expanded = isExpanded && isEnabled,
onDismissRequest = { isExpanded = false },
) {
FocusRequester
@@ -173,44 +210,18 @@ private fun SelectorField(model: AddCustomTokenSelectorField) {
@Preview
@Composable
-private fun Preview_AddCustomTokenForm() {
+private fun Preview_AddCustomTokenForm(@PreviewParameter(AddCustomTokenFormProvider::class) model: AddCustomTokenForm) {
TangemTheme {
- AddCustomTokenForm(
- AddCustomTokenForm(
- contractAddressInputField = AddCustomTokenInputField.ContactAddress(
- value = "",
- onValueChange = {},
- isError = false,
- isLoading = false,
- ),
- networkSelectorField = AddCustomTokenSelectorField.Network(
- selectedItem = AddCustomTokenSelectorField.SelectorItem.Title(
- title = TextReference.Str(value = "Avalanche"),
- blockchain = Blockchain.Avalanche,
- ),
- items = listOf(),
- onMenuItemClick = {},
- ),
- tokenNameInputField = AddCustomTokenInputField.TokenName(
- value = "",
- onValueChange = {},
- isEnabled = false,
- isError = false,
- ),
- tokenSymbolInputField = AddCustomTokenInputField.TokenSymbol(
- value = "",
- onValueChange = {},
- isEnabled = false,
- isError = false,
- ),
- decimalsInputField = AddCustomTokenInputField.Decimals(
- value = "",
- onValueChange = {},
- isEnabled = false,
- isError = false,
- ),
- derivationPathSelectorField = null,
- ),
- )
+ AddCustomTokenForm(model)
}
-}
\ No newline at end of file
+}
+
+private class AddCustomTokenFormProvider : CollectionPreviewParameterProvider(
+ collection = listOf(
+ AddCustomTokenPreviewData.createDefaultForm(),
+ AddCustomTokenPreviewData.createDefaultForm().copy(derivationPathSelectorField = null),
+ AddCustomTokenPreviewData.createDefaultForm().let { form ->
+ form.copy(contractAddressInputField = form.contractAddressInputField.copy(isLoading = true))
+ },
+ ),
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenWarning.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenWarnings.kt
similarity index 51%
rename from app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenWarning.kt
rename to app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenWarnings.kt
index 5eb76c6e66..7627e3c6af 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenWarning.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/ui/components/AddCustomTokenWarnings.kt
@@ -2,39 +2,56 @@ package com.tangem.tap.features.customtoken.impl.presentation.ui.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.key
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
-import com.tangem.tap.features.details.ui.cardsettings.TextReference
+import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenWarning
+import com.tangem.tap.features.customtoken.impl.presentation.ui.AddCustomTokenPreviewData
import com.tangem.tap.features.details.ui.cardsettings.resolveReference
import com.tangem.wallet.R
/**
- * Add custom token warning component
- * FIXME("Incorrect typography. Replace with typography from design system")
+ * Add custom token warnings
*
- * @param description warning description
- * @param modifier modifier
+ * @param warnings warnings descriptions set
*
[REDACTED_AUTHOR]
*/
@Composable
-internal fun AddCustomTokenWarning(description: TextReference, modifier: Modifier = Modifier) {
+internal fun AddCustomTokenWarnings(warnings: Set) {
+ Column(
+ modifier = Modifier
+ .padding(horizontal = TangemTheme.dimens.spacing16)
+ .fillMaxWidth(),
+ verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
+ ) {
+ warnings.forEach { warning ->
+ key(warning) { AddCustomTokenWarning(warning) }
+ }
+ }
+}
+
+@Composable
+private fun AddCustomTokenWarning(warning: AddCustomTokenWarning) {
Card(
- modifier = modifier,
- shape = RoundedCornerShape(TangemTheme.dimens.radius4),
+ modifier = Modifier.fillMaxSize(),
+ shape = TangemTheme.shapes.roundedCornersSmall2,
backgroundColor = TangemColorPalette.Tangerine,
contentColor = TangemColorPalette.White,
elevation = TangemTheme.dimens.elevation4,
) {
+ // FIXME("Incorrect typography. Replace with typography from design system")
Column(
modifier = Modifier.padding(all = TangemTheme.dimens.spacing16),
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
@@ -45,10 +62,18 @@ internal fun AddCustomTokenWarning(description: TextReference, modifier: Modifie
style = TangemTheme.typography.body2.copy(fontWeight = FontWeight.Bold),
)
Text(
- text = description.resolveReference(),
+ text = warning.description.resolveReference(),
fontSize = 13.sp,
lineHeight = 18.sp,
)
}
}
+}
+
+@Preview
+@Composable
+private fun Preview_AddCustomTokenWarnings() {
+ TangemTheme {
+ AddCustomTokenWarnings(warnings = AddCustomTokenPreviewData.createWarnings())
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenAnalyticsSender.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenAnalyticsSender.kt
new file mode 100644
index 0000000000..e9641c119f
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenAnalyticsSender.kt
@@ -0,0 +1,35 @@
+package com.tangem.tap.features.customtoken.impl.presentation.viewmodels
+
+import com.tangem.core.analytics.api.AnalyticsEventHandler
+import com.tangem.tap.common.analytics.events.ManageTokens
+import com.tangem.tap.features.wallet.models.Currency
+
+/** Analytics sender for tokens list screen */
+class AddCustomTokenAnalyticsSender(private val analyticsEventHandler: AnalyticsEventHandler) {
+
+ fun sendWhenScreenOpened() {
+ analyticsEventHandler.send(ManageTokens.CustomToken.ScreenOpened)
+ }
+
+ fun sendWhenAddTokenButtonClicked(currency: Currency, address: String) {
+ analyticsEventHandler.send(
+ when (currency) {
+ is Currency.Blockchain -> {
+ ManageTokens.CustomToken.TokenWasAdded.Blockchain(
+ derivationPath = currency.derivationPath,
+ blockchain = currency.blockchain,
+ )
+ }
+
+ is Currency.Token -> {
+ ManageTokens.CustomToken.TokenWasAdded.Token(
+ symbol = currency.currencySymbol,
+ derivationPath = currency.derivationPath,
+ blockchain = currency.blockchain,
+ contractAddress = address,
+ )
+ }
+ },
+ )
+ }
+}
\ No newline at end of file
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 22b13b1216..5e2020d8ef 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
@@ -1,8 +1,11 @@
package com.tangem.tap.features.customtoken.impl.presentation.viewmodels
+import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
@@ -14,12 +17,14 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.AddCustomTokenError
import com.tangem.domain.common.TapWorkarounds.derivationStyle
-import com.tangem.domain.common.TapWorkarounds.isTestCard
+import com.tangem.domain.common.extensions.canHandleToken
import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.domain.common.extensions.isSupportedInApp
import com.tangem.domain.common.extensions.supportedBlockchains
-import com.tangem.tap.common.analytics.events.ManageTokens
+import com.tangem.domain.common.extensions.toNetworkId
+import com.tangem.tap.domain.model.WalletDataModel
import com.tangem.tap.features.customtoken.impl.domain.CustomTokenInteractor
+import com.tangem.tap.features.customtoken.impl.domain.models.FoundToken
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenChooseTokenBottomSheet
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenChooseTokenBottomSheet.TestTokenItem
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenChooseTokenBottomSheet.TokensCategoryBlock
@@ -27,8 +32,11 @@ import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTok
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenForm
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenInputField
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenSelectorField
+import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenSelectorField.SelectorItem
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenTestBlock
+import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenWarning
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokensToolbar
+import com.tangem.tap.features.customtoken.impl.presentation.models.CustomTokenType
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
@@ -36,6 +44,7 @@ import com.tangem.tap.features.customtoken.impl.presentation.validators.Contract
import com.tangem.tap.features.details.ui.cardsettings.TextReference
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.proxy.AppStateHolder
+import com.tangem.tap.store
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
import com.tangem.utils.coroutines.runCatching
import com.tangem.wallet.BuildConfig
@@ -49,34 +58,37 @@ import javax.inject.Inject
/**
* ViewModel for add custom token screen
*
- * @param featureRouter feature router
- * @property featureInteractor feature interactor
- * @property dispatchers coroutine dispatchers provider
- * @property reduxStateHolder redux state holder
- * @property analyticsEventHandler analytics event handler
+ * @param analyticsEventHandler analytics event handler
+ * @param featureRouter feature router
+ * @property featureInteractor feature interactor
+ * @property dispatchers coroutine dispatchers provider
+ * @property reduxStateHolder redux state holder
*
[REDACTED_AUTHOR]
*/
+@Suppress("LargeClass")
@HiltViewModel
internal class AddCustomTokenViewModel @Inject constructor(
+ analyticsEventHandler: AnalyticsEventHandler,
featureRouter: CustomTokenRouter,
private val featureInteractor: CustomTokenInteractor,
private val dispatchers: AppCoroutineDispatcherProvider,
private val reduxStateHolder: AppStateHolder,
- private val analyticsEventHandler: AnalyticsEventHandler,
) : ViewModel(), DefaultLifecycleObserver {
+ private val analyticsSender = AddCustomTokenAnalyticsSender(analyticsEventHandler)
private val actionsHandler = ActionsHandler(featureRouter)
private val testActionsHandler = TestActionsHandler()
+ private val formStateBuilder = FormStateBuilder()
/** Screen state */
var uiState by mutableStateOf(getInitialUiState())
private set
- private var foundTokenId: String? = null
+ private var foundToken: FoundToken? = null
override fun onCreate(owner: LifecycleOwner) {
- analyticsEventHandler.send(ManageTokens.CustomToken.ScreenOpened)
+ analyticsSender.sendWhenScreenOpened()
}
private fun getInitialUiState(): AddCustomTokenStateHolder {
@@ -84,8 +96,8 @@ internal class AddCustomTokenViewModel @Inject constructor(
AddCustomTokenStateHolder.TestContent(
onBackButtonClick = actionsHandler::onBackButtonClick,
toolbar = createToolbar(),
- form = createForm(),
- warnings = listOf(),
+ form = formStateBuilder.createForm(),
+ warnings = emptySet(),
floatingButton = createFloatingButton(),
testBlock = AddCustomTokenTestBlock(
chooseTokenButtonText = "Choose token",
@@ -106,8 +118,8 @@ internal class AddCustomTokenViewModel @Inject constructor(
AddCustomTokenStateHolder.Content(
onBackButtonClick = actionsHandler::onBackButtonClick,
toolbar = createToolbar(),
- form = createForm(),
- warnings = listOf(),
+ form = formStateBuilder.createForm(),
+ warnings = emptySet(),
floatingButton = createFloatingButton(),
)
}
@@ -120,155 +132,32 @@ internal class AddCustomTokenViewModel @Inject constructor(
)
}
- private fun createForm(): AddCustomTokenForm {
- return AddCustomTokenForm(
- contractAddressInputField = createContractAddressInputField(),
- networkSelectorField = createNetworkSelectorField(),
- tokenNameInputField = createTokenNameInputField(),
- tokenSymbolInputField = createTokenSymbolInputField(),
- decimalsInputField = createDecimalsInputField(),
- derivationPathSelectorField = createDerivationPathsSelectorField(),
- )
+ private fun createFloatingButton(): AddCustomTokenFloatingButton {
+ return AddCustomTokenFloatingButton(isEnabled = false, onClick = actionsHandler::onAddCustomTokenClick)
}
- private fun createContractAddressInputField(): AddCustomTokenInputField.ContactAddress {
- return AddCustomTokenInputField.ContactAddress(
- value = "",
- onValueChange = actionsHandler::onContactAddressValueChange,
- isError = false,
- isLoading = false,
- )
- }
+ private inner class FormStateBuilder {
- private fun createNetworkSelectorField(): AddCustomTokenSelectorField.Network {
- val selectorItems = getNetworkSelectorItems()
- return AddCustomTokenSelectorField.Network(
- selectedItem = requireNotNull(selectorItems.firstOrNull()),
- items = selectorItems,
- onMenuItemClick = {
- actionsHandler.onNetworkSelectorItemClick(
- selectedItem = requireNotNull(selectorItems.getOrNull(it)),
- )
- },
- )
- }
-
- private fun getNetworkSelectorItems(): List {
- val card = reduxStateHolder.scanResponse?.card
- val evmBlockchains = Blockchain.values().filter { card?.isTestCard == it.isTestnet() && it.isEvm() }
-
- val additionalBlockchains = listOf(
- Blockchain.Binance,
- Blockchain.BinanceTestnet,
- Blockchain.Solana,
- Blockchain.SolanaTestnet,
- Blockchain.Tron,
- Blockchain.TronTestnet,
- )
-
- return (evmBlockchains + additionalBlockchains)
- .filter { card?.supportedBlockchains()?.contains(it) == true }
- .map(::createNetworkSelectorItem)
- .toMutableList()
- .apply {
- add(index = 0, element = createNetworkSelectorItem(blockchain = Blockchain.Unknown))
- }
- }
-
- private fun createNetworkSelectorItem(blockchain: Blockchain): AddCustomTokenSelectorField.SelectorItem.Title {
- return when (blockchain) {
- Blockchain.Unknown -> {
- AddCustomTokenSelectorField.SelectorItem.Title(
- title = TextReference.Res(R.string.custom_token_network_input_not_selected),
- blockchain = Blockchain.Unknown,
- )
- }
-
- else -> {
- AddCustomTokenSelectorField.SelectorItem.Title(
- title = TextReference.Str(blockchain.fullName),
- blockchain = blockchain,
- )
- }
- }
- }
-
- private fun createTokenNameInputField(): AddCustomTokenInputField.TokenName {
- return AddCustomTokenInputField.TokenName(
- value = "",
- onValueChange = actionsHandler::onTokenNameValueChange,
- isEnabled = false,
- isError = false,
- )
- }
-
- private fun createTokenSymbolInputField(): AddCustomTokenInputField.TokenSymbol {
- return AddCustomTokenInputField.TokenSymbol(
- value = "",
- onValueChange = actionsHandler::onTokenSymbolValueChange,
- isEnabled = false,
- isError = false,
- )
- }
-
- private fun createDecimalsInputField(): AddCustomTokenInputField.Decimals {
- return AddCustomTokenInputField.Decimals(
- value = "",
- onValueChange = actionsHandler::onDecimalsValueChange,
- isEnabled = false,
- isError = false,
- )
- }
-
- private fun createDerivationPathsSelectorField(): AddCustomTokenSelectorField.DerivationPath? {
- if (reduxStateHolder.scanResponse?.card?.settings?.isHDWalletAllowed == false) return null
-
- val selectorItems = getDerivationPathsSelectorItems()
- return AddCustomTokenSelectorField.DerivationPath(
- isEnabled = true,
- selectedItem = requireNotNull(selectorItems.firstOrNull()),
- items = selectorItems,
- onMenuItemClick = {
- val field = requireNotNull(uiState.form.derivationPathSelectorField)
- uiState = uiState.copySealed(
- form = uiState.form.copy(
- derivationPathSelectorField = field.copy(
- selectedItem = requireNotNull(selectorItems.getOrNull(it)),
- ),
- ),
- )
- },
- )
- }
-
- private fun getDerivationPathsSelectorItems(): List {
- val evmBlockchains = Blockchain.values().filter {
- reduxStateHolder.scanResponse?.card?.isTestCard == it.isTestnet() && it.isEvm() && it.isSupportedInApp()
+ fun createForm(): AddCustomTokenForm {
+ return AddCustomTokenForm(
+ contractAddressInputField = createContractAddressInputField(),
+ networkSelectorField = createNetworkSelectorField(),
+ tokenNameInputField = createTokenNameInputField(),
+ tokenSymbolInputField = createTokenSymbolInputField(),
+ decimalsInputField = createDecimalsInputField(),
+ derivationPathSelectorField = createDerivationPathsSelectorField(),
+ )
}
- return evmBlockchains
- .sortedBy(Blockchain::fullName)
- .map(::createDerivationPathSelectorItem)
- .toMutableList()
- .apply {
- add(index = 0, element = createDerivationPathSelectorItem(Blockchain.Unknown))
- }
- }
-
- private fun createDerivationPathSelectorItem(
- blockchain: Blockchain,
- ): AddCustomTokenSelectorField.SelectorItem.TitleWithSubtitle {
- return when (blockchain) {
- Blockchain.Unknown -> {
- AddCustomTokenSelectorField.SelectorItem.TitleWithSubtitle(
+ fun createDerivationPathSelectorItem(blockchain: Blockchain): SelectorItem.TitleWithSubtitle {
+ return if (blockchain == Blockchain.Unknown) {
+ SelectorItem.TitleWithSubtitle(
title = TextReference.Res(R.string.custom_token_derivation_path_default),
subtitle = TextReference.Res(R.string.custom_token_derivation_path_default),
blockchain = Blockchain.Unknown,
)
- }
-
- else -> {
- AddCustomTokenSelectorField.SelectorItem.TitleWithSubtitle(
+ } else {
+ SelectorItem.TitleWithSubtitle(
title = blockchain.derivationPath(DerivationStyle.LEGACY)?.rawPath?.let(TextReference::Str)
?: TextReference.Res(R.string.custom_token_derivation_path_default),
subtitle = TextReference.Str(blockchain.fullName),
@@ -276,10 +165,396 @@ internal class AddCustomTokenViewModel @Inject constructor(
)
}
}
+
+ fun createNetworkSelectorItem(blockchain: Blockchain): SelectorItem.Title {
+ return if (blockchain == Blockchain.Unknown) {
+ SelectorItem.Title(
+ title = TextReference.Res(R.string.custom_token_network_input_not_selected),
+ blockchain = Blockchain.Unknown,
+ )
+ } else {
+ SelectorItem.Title(
+ title = TextReference.Str(blockchain.fullName),
+ blockchain = blockchain,
+ )
+ }
+ }
+
+ private fun createContractAddressInputField(): AddCustomTokenInputField.ContactAddress {
+ return AddCustomTokenInputField.ContactAddress(
+ value = "",
+ onValueChange = actionsHandler::onContactAddressValueChange,
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
+ label = TextReference.Res(R.string.custom_token_contract_address_input_title),
+ placeholder = TextReference.Str(value = "0x0000000000000000000000000000000000000000"),
+ isLoading = false,
+ isError = false,
+ error = null,
+ )
+ }
+
+ private fun createNetworkSelectorField(): AddCustomTokenSelectorField.Network {
+ val selectorItems = getNetworkSelectorItems()
+ return AddCustomTokenSelectorField.Network(
+ label = TextReference.Res(R.string.custom_token_network_input_title),
+ selectedItem = requireNotNull(selectorItems.firstOrNull()),
+ items = selectorItems,
+ onMenuItemClick = actionsHandler::onNetworkSelectorItemClick,
+ )
+ }
+
+ private fun getNetworkSelectorItems(): List {
+ val defaultNetwork = createNetworkSelectorItem(blockchain = Blockchain.Unknown)
+ return listOf(defaultNetwork) + Blockchain.values()
+ .filter { blockchain ->
+ (blockchain.isEvm() || blockchain.canHandleTokens()) &&
+ reduxStateHolder.scanResponse?.card?.supportedBlockchains()?.contains(blockchain) == true
+ }
+ .map(::createNetworkSelectorItem)
+ }
+
+ private fun createTokenNameInputField(): AddCustomTokenInputField.TokenName {
+ return AddCustomTokenInputField.TokenName(
+ value = "",
+ onValueChange = actionsHandler::onTokenNameValueChange,
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
+ label = TextReference.Res(R.string.custom_token_name_input_title),
+ placeholder = TextReference.Res(id = R.string.custom_token_name_input_placeholder),
+ isEnabled = false,
+ )
+ }
+
+ private fun createTokenSymbolInputField(): AddCustomTokenInputField.TokenSymbol {
+ return AddCustomTokenInputField.TokenSymbol(
+ value = "",
+ onValueChange = actionsHandler::onTokenSymbolValueChange,
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
+ label = TextReference.Res(R.string.custom_token_token_symbol_input_title),
+ placeholder = TextReference.Res(id = R.string.custom_token_token_symbol_input_placeholder),
+ isEnabled = false,
+ )
+ }
+
+ private fun createDecimalsInputField(): AddCustomTokenInputField.Decimals {
+ return AddCustomTokenInputField.Decimals(
+ value = "",
+ onValueChange = actionsHandler::onDecimalsValueChange,
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Next),
+ label = TextReference.Res(R.string.custom_token_decimals_input_title),
+ placeholder = TextReference.Str(value = "8"),
+ isEnabled = false,
+ )
+ }
+
+ private fun createDerivationPathsSelectorField(): AddCustomTokenSelectorField.DerivationPath? {
+ if (reduxStateHolder.scanResponse?.card?.settings?.isHDWalletAllowed == false) return null
+
+ val selectorItems = getDerivationPathsSelectorItems()
+ return AddCustomTokenSelectorField.DerivationPath(
+ label = TextReference.Res(R.string.custom_token_derivation_path_input_title),
+ selectedItem = requireNotNull(selectorItems.firstOrNull()),
+ items = selectorItems,
+ onMenuItemClick = actionsHandler::onDerivationPathSelectorItemClick,
+ isEnabled = true,
+ )
+ }
+
+ private fun getDerivationPathsSelectorItems(): List {
+ val defaultDerivationPath = createDerivationPathSelectorItem(Blockchain.Unknown)
+ return listOf(defaultDerivationPath) + Blockchain.values()
+ .filter { blockchain -> blockchain.isEvm() && blockchain.isSupportedInApp() }
+ .sortedBy(Blockchain::fullName)
+ .map(::createDerivationPathSelectorItem)
+ }
}
- private fun createFloatingButton(): AddCustomTokenFloatingButton {
- return AddCustomTokenFloatingButton(isEnabled = false, onClick = actionsHandler::onAddCustomTokenClick)
+ private fun updateForm(address: String, selectedNetwork: Blockchain) {
+ viewModelScope.launch(dispatchers.main) {
+ runCatching(dispatchers.io) {
+ featureInteractor.findToken(address = address, blockchain = selectedNetwork)
+ }
+ .onSuccess { token ->
+ foundToken = token
+ uiState = uiState.copySealed(
+ form = uiState.form.copy(
+ contractAddressInputField = uiState.form.contractAddressInputField.copy(
+ isLoading = false,
+ ),
+ networkSelectorField = uiState.form.networkSelectorField.copy(
+ selectedItem = formStateBuilder.createNetworkSelectorItem(
+ blockchain = Blockchain.fromNetworkId(token.network.id)
+ ?: Blockchain.Unknown,
+ ),
+ ),
+ tokenNameInputField = uiState.form.tokenNameInputField.copy(
+ value = token.name,
+ isEnabled = false,
+ ),
+ tokenSymbolInputField = uiState.form.tokenSymbolInputField.copy(
+ value = token.symbol,
+ isEnabled = false,
+ ),
+ decimalsInputField = uiState.form.decimalsInputField.copy(
+ value = token.network.decimalCount,
+ isEnabled = false,
+ ),
+ ),
+ )
+ }
+ .onFailure {
+ foundToken = null
+ uiState = uiState.copySealed(
+ form = uiState.form.copy(
+ contractAddressInputField = uiState.form.contractAddressInputField.copy(
+ isLoading = false,
+ ),
+ tokenNameInputField = uiState.form.tokenNameInputField.copy(isEnabled = true),
+ tokenSymbolInputField = uiState.form.tokenSymbolInputField.copy(isEnabled = true),
+ decimalsInputField = uiState.form.decimalsInputField.copy(isEnabled = true),
+ ),
+ )
+ Timber.e(it)
+ }
+
+ updateDerivationPathSelector()
+ updateWarnings()
+ updateFloatingButton()
+ }
+ }
+
+ private fun updateDerivationPathSelector() {
+ val derivationPathSelectorField = uiState.form.derivationPathSelectorField ?: return
+ val selectedValue = derivationPathSelectorField.selectedItem.blockchain
+ val isSupported = selectedValue.isEvm() || !isDerivationPathSelected()
+
+ uiState = uiState.copySealed(
+ form = uiState.form.copy(
+ derivationPathSelectorField = uiState.form.derivationPathSelectorField?.copy(
+ isEnabled = if (derivationPathSelectorField.isEnabled != isSupported) {
+ isSupported
+ } else {
+ derivationPathSelectorField.isEnabled
+ },
+ selectedItem = if (isDerivationPathSelected() && !isSupported) {
+ formStateBuilder.createDerivationPathSelectorItem(Blockchain.Unknown)
+ } else {
+ derivationPathSelectorField.selectedItem
+ },
+ ),
+ ),
+ )
+ }
+
+ private fun isDerivationPathSelected(): Boolean {
+ return uiState.form.derivationPathSelectorField?.selectedItem?.blockchain != Blockchain.Unknown
+ }
+
+ private fun updateWarnings() {
+ uiState = uiState.copySealed(
+ warnings = buildSet {
+ when (getCustomTokenType()) {
+ CustomTokenType.TOKEN -> {
+ addAll(getTokenWarningSet())
+ }
+
+ CustomTokenType.BLOCKCHAIN -> {
+ if (isCustomTokenAlreadyAdded()) add(AddCustomTokenWarning.TokenAlreadyAdded)
+ if (isDerivationPathSelected()) add(AddCustomTokenWarning.PotentialScamToken)
+ }
+ }
+ },
+ )
+ }
+
+ private fun getCustomTokenType(): CustomTokenType {
+ return if (isAnyTokenFieldsFilled() || isAllTokenFieldsFilled()) {
+ CustomTokenType.TOKEN
+ } else {
+ CustomTokenType.BLOCKCHAIN
+ }
+ }
+
+ private fun isAnyTokenFieldsFilled(): Boolean {
+ return with(uiState.form) {
+ contractAddressInputField.value.isNotEmpty() || tokenNameInputField.value.isNotEmpty() ||
+ tokenSymbolInputField.value.isNotEmpty() || decimalsInputField.value.isNotEmpty()
+ }
+ }
+
+ private fun isAllTokenFieldsFilled(): Boolean {
+ return with(uiState.form) {
+ contractAddressInputField.value.isNotEmpty() && tokenNameInputField.value.isNotEmpty() &&
+ tokenSymbolInputField.value.isNotEmpty() && decimalsInputField.value.isNotEmpty()
+ }
+ }
+
+ private fun getTokenWarningSet(): Set {
+ val networkSelectorValue = uiState.form.networkSelectorField.selectedItem.blockchain
+
+ val isContractAddressFieldEmpty = ContactAddressValidator.validate(
+ address = uiState.form.contractAddressInputField.value,
+ blockchain = networkSelectorValue,
+ ).let {
+ it is ContractAddressValidatorResult.Error && it.type == AddCustomTokenError.FieldIsEmpty
+ }
+
+ val isSupportedToken = if (!isNetworkSelected()) {
+ true
+ } else {
+ reduxStateHolder.scanResponse?.card?.canHandleToken(networkSelectorValue) ?: false
+ }
+
+ return buildSet {
+ if (!isSupportedToken && !isContractAddressFieldEmpty) add(AddCustomTokenWarning.UnsupportedSolanaToken)
+ if (isCustomTokenAlreadyAdded()) add(AddCustomTokenWarning.TokenAlreadyAdded)
+ if (foundToken == null && isAnyTokenFieldsFilled() || foundToken?.isActive == false) {
+ add(AddCustomTokenWarning.PotentialScamToken)
+ }
+ }
+ }
+
+ private fun isNetworkSelected(): Boolean {
+ return uiState.form.networkSelectorField.selectedItem.blockchain != Blockchain.Unknown
+ }
+
+ private fun updateFloatingButton() {
+ if (isCustomTokenAlreadyAdded()) {
+ uiState = uiState.copySealed(
+ warnings = uiState.warnings + AddCustomTokenWarning.TokenAlreadyAdded,
+ floatingButton = uiState.floatingButton.copy(isEnabled = false),
+ )
+ return
+ }
+
+ val state = when {
+ isAllTokenFieldsFilled() && isNetworkSelected() -> {
+ val networkSelectorValue = uiState.form.networkSelectorField.selectedItem.blockchain
+ val error = ContactAddressValidator.validate(
+ address = uiState.form.contractAddressInputField.value,
+ blockchain = networkSelectorValue,
+ )
+ val isSupportedToken = reduxStateHolder.scanResponse?.card
+ ?.canHandleToken(networkSelectorValue)
+ ?: false
+
+ uiState.copySealed(
+ floatingButton = uiState.floatingButton.copy(
+ isEnabled = error is ContractAddressValidatorResult.Success && isSupportedToken,
+ ),
+ )
+ }
+
+ isAnyTokenFieldsFilled() -> {
+ uiState.copySealed(floatingButton = uiState.floatingButton.copy(isEnabled = false))
+ }
+
+ else -> {
+ uiState.copySealed(
+ floatingButton = uiState.floatingButton.copy(
+ isEnabled = if (isNetworkSelected()) !isBlockchainAlreadyAdded() else false,
+ ),
+ )
+ }
+ }
+
+ uiState = state.copySealed(
+ warnings = uiState.warnings - AddCustomTokenWarning.TokenAlreadyAdded,
+ )
+ }
+
+ private fun isCustomTokenAlreadyAdded(): Boolean {
+ return when (getCustomTokenType()) {
+ CustomTokenType.TOKEN -> isTokenAlreadyAdded()
+ CustomTokenType.BLOCKCHAIN -> isBlockchainAlreadyAdded()
+ }
+ }
+
+ private fun isTokenAlreadyAdded(): Boolean {
+ return store.state.walletState.walletsStores
+ .map { walletStore -> walletStore.walletsData.map(WalletDataModel::currency) }
+ .flatten()
+ .filterIsInstance()
+ .any { wrappedCurrency ->
+ val contractAddress = uiState.form.contractAddressInputField.value
+ val networkSelectorValue = uiState.form.networkSelectorField.selectedItem.blockchain
+ val sameId = foundToken?.id == wrappedCurrency.token.id
+ val sameAddress = contractAddress == wrappedCurrency.token.contractAddress
+ val sameBlockchain =
+ Blockchain.fromNetworkId(networkSelectorValue.toNetworkId()) == wrappedCurrency.blockchain
+ val isSameDerivationPath = getDerivationPath()?.rawPath == wrappedCurrency.derivationPath
+ sameId && sameAddress && sameBlockchain && isSameDerivationPath
+ }
+ }
+
+ private fun isBlockchainAlreadyAdded(): Boolean {
+ return store.state.walletState.walletsStores
+ .map { walletStore -> walletStore.walletsData.map(WalletDataModel::currency) }
+ .flatten()
+ .filterIsInstance()
+ .any {
+ val networkSelectorValue = uiState.form.networkSelectorField.selectedItem.blockchain
+ networkSelectorValue == it.blockchain && getDerivationPath()?.rawPath == it.derivationPath
+ }
+ }
+
+ private fun handleContractAddressErrorValidation(type: AddCustomTokenError) {
+ when {
+ isNetworkSelected() && type == AddCustomTokenError.InvalidContractAddress -> {
+ val isAnotherTokenFieldsFilled = isAnyTokenFieldsFilled()
+ uiState = uiState.copySealed(
+ form = uiState.form.copy(
+ contractAddressInputField = uiState.form.contractAddressInputField.copy(
+ isError = true,
+ error = TextReference.Res(
+ id = R.string.custom_token_creation_error_invalid_contract_address,
+ ),
+ ),
+ tokenNameInputField = uiState.form.tokenNameInputField.copy(
+ isEnabled = isAnotherTokenFieldsFilled,
+ ),
+ tokenSymbolInputField = uiState.form.tokenSymbolInputField.copy(
+ isEnabled = isAnotherTokenFieldsFilled,
+ ),
+ decimalsInputField = uiState.form.decimalsInputField.copy(
+ isEnabled = isAnotherTokenFieldsFilled,
+ ),
+ ),
+ )
+ }
+
+ !isNetworkSelected() || type == AddCustomTokenError.FieldIsEmpty -> {
+ uiState = uiState.copySealed(
+ form = uiState.form.copy(
+ contractAddressInputField = uiState.form.contractAddressInputField.copy(isError = false),
+ tokenNameInputField = uiState.form.tokenNameInputField.copy(value = "", isEnabled = false),
+ tokenSymbolInputField = uiState.form.tokenSymbolInputField.copy(
+ value = "",
+ isEnabled = false,
+ ),
+ decimalsInputField = uiState.form.decimalsInputField.copy(value = "", isEnabled = false),
+ ),
+ )
+ }
+
+ else -> Unit
+ }
+ }
+
+ private fun getDerivationPath(): DerivationPath? {
+ val isNotDerivationPathSelected = !isDerivationPathSelected()
+ val network = if (isNotDerivationPathSelected) {
+ uiState.form.networkSelectorField.selectedItem.blockchain
+ } else {
+ uiState.form.derivationPathSelectorField?.selectedItem?.blockchain
+ }
+
+ return network?.derivationPath(
+ style = if (isNotDerivationPathSelected) {
+ reduxStateHolder.scanResponse?.card?.derivationStyle
+ } else {
+ DerivationStyle.LEGACY
+ },
+ )
}
private inner class ActionsHandler(private val featureRouter: CustomTokenRouter) {
@@ -288,85 +563,47 @@ internal class AddCustomTokenViewModel @Inject constructor(
featureRouter.popBackStack()
}
- fun onAddCustomTokenClick() {
- if (uiState.form.networkSelectorField.selectedItem.blockchain != Blockchain.Unknown) {
- val selectedNetwork = uiState.form.networkSelectorField.selectedItem.blockchain
-
- val currency = if (isAnyTokenFieldsFilled() || isAllTokenFieldsFilled()) {
- Currency.Token(
- token = Token(
- name = uiState.form.tokenNameInputField.value,
- symbol = uiState.form.tokenSymbolInputField.value,
- contractAddress = uiState.form.contractAddressInputField.value,
- decimals = uiState.form.decimalsInputField.value.toInt(),
- id = foundTokenId,
- ),
- blockchain = selectedNetwork,
- derivationPath = getDerivationPath(
- mainNetwork = selectedNetwork,
- derivationNetwork = uiState.form.derivationPathSelectorField?.selectedItem?.blockchain,
- derivationStyle = reduxStateHolder.scanResponse?.card?.derivationStyle,
- )?.rawPath,
- )
- } else {
- Currency.Blockchain(
- blockchain = selectedNetwork,
- derivationPath = getDerivationPath(
- mainNetwork = selectedNetwork,
- derivationNetwork = uiState.form.derivationPathSelectorField?.selectedItem?.blockchain,
- derivationStyle = reduxStateHolder.scanResponse?.card?.derivationStyle,
- )?.rawPath,
- )
- }
-
- sendOnAddTokenButtonClick(currency = currency, address = uiState.form.contractAddressInputField.value)
-
- viewModelScope.launch(dispatchers.io) {
- featureInteractor.saveToken(
- currency = currency,
- address = uiState.form.contractAddressInputField.value,
- )
- }
- }
- }
-
fun onContactAddressValueChange(enteredValue: String) {
- with(uiState.form) {
- val selectedNetwork = networkSelectorField.selectedItem.blockchain
- val isValid = ContactAddressValidator.validate(
- address = enteredValue,
- blockchain = selectedNetwork,
- )
-
- when (isValid) {
- is ContractAddressValidatorResult.Success -> {
- uiState = uiState.copySealed(
- form = uiState.form.copy(
- contractAddressInputField = contractAddressInputField.copy(
- isError = false,
- isLoading = true,
- ),
- ),
- )
- updateForm(address = enteredValue, selectedNetwork = selectedNetwork)
- }
-
- is ContractAddressValidatorResult.Error -> {
- handleContractAddressErrorValidation(type = isValid.type)
- }
- }
-
- updateDerivationPathSelector()
-
- // TODO("[REDACTED_TASK_KEY] Update warnings")
- // TODO("[REDACTED_TASK_KEY] Update floating button")
- }
- }
-
- fun onNetworkSelectorItemClick(selectedItem: AddCustomTokenSelectorField.SelectorItem.Title) {
uiState = uiState.copySealed(
form = uiState.form.copy(
- networkSelectorField = uiState.form.networkSelectorField.copy(selectedItem = selectedItem),
+ contractAddressInputField = uiState.form.contractAddressInputField.copy(value = enteredValue),
+ ),
+ )
+
+ val selectedNetwork = uiState.form.networkSelectorField.selectedItem.blockchain
+ val validatorResult = ContactAddressValidator.validate(
+ address = enteredValue,
+ blockchain = selectedNetwork,
+ )
+
+ when (validatorResult) {
+ is ContractAddressValidatorResult.Success -> {
+ uiState = uiState.copySealed(
+ form = uiState.form.copy(
+ contractAddressInputField = uiState.form.contractAddressInputField.copy(
+ isError = false,
+ isLoading = true,
+ ),
+ ),
+ )
+ updateForm(address = enteredValue, selectedNetwork = selectedNetwork)
+ }
+
+ is ContractAddressValidatorResult.Error -> {
+ handleContractAddressErrorValidation(type = validatorResult.type)
+ updateDerivationPathSelector()
+ updateWarnings()
+ updateFloatingButton()
+ }
+ }
+ }
+
+ fun onNetworkSelectorItemClick(index: Int) {
+ uiState = uiState.copySealed(
+ form = uiState.form.copy(
+ networkSelectorField = uiState.form.networkSelectorField.copy(
+ selectedItem = requireNotNull(uiState.form.networkSelectorField.items.getOrNull(index)),
+ ),
),
)
onContactAddressValueChange(uiState.form.contractAddressInputField.value)
@@ -378,7 +615,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
tokenNameInputField = uiState.form.tokenNameInputField.copy(value = enteredValue),
),
)
- // TODO("[REDACTED_TASK_KEY] Update floating button")
+ updateFloatingButton()
}
fun onTokenSymbolValueChange(enteredValue: String) {
@@ -387,7 +624,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
tokenSymbolInputField = uiState.form.tokenSymbolInputField.copy(value = enteredValue),
),
)
- // TODO("[REDACTED_TASK_KEY] Update floating button")
+ updateFloatingButton()
}
fun onDecimalsValueChange(enteredValue: String) {
@@ -396,156 +633,53 @@ internal class AddCustomTokenViewModel @Inject constructor(
decimalsInputField = uiState.form.decimalsInputField.copy(value = enteredValue),
),
)
- // TODO("[REDACTED_TASK_KEY] Update floating button")
+ updateFloatingButton()
}
- private fun getDerivationPath(
- mainNetwork: Blockchain,
- derivationNetwork: Blockchain?,
- derivationStyle: DerivationStyle?,
- ): DerivationPath? {
- val network = if (derivationNetwork == Blockchain.Unknown) mainNetwork else derivationNetwork
-
- return network?.derivationPath(
- style = if (derivationNetwork == Blockchain.Unknown) derivationStyle else DerivationStyle.LEGACY,
+ fun onDerivationPathSelectorItemClick(index: Int) {
+ val field = requireNotNull(uiState.form.derivationPathSelectorField)
+ uiState = uiState.copySealed(
+ form = uiState.form.copy(
+ derivationPathSelectorField = field.copy(
+ selectedItem = requireNotNull(field.items.getOrNull(index)),
+ ),
+ ),
)
}
- private fun sendOnAddTokenButtonClick(currency: Currency, address: String) {
- when (currency) {
- is Currency.Blockchain -> {
- analyticsEventHandler.send(
- ManageTokens.CustomToken.TokenWasAdded.Blockchain(
- derivationPath = currency.derivationPath,
- blockchain = currency.blockchain,
- ),
- )
- }
+ fun onAddCustomTokenClick() {
+ if (!isNetworkSelected()) return
- is Currency.Token -> {
- analyticsEventHandler.send(
- ManageTokens.CustomToken.TokenWasAdded.Token(
- symbol = currency.currencySymbol,
- derivationPath = currency.derivationPath,
- blockchain = currency.blockchain,
- contractAddress = address,
- ),
- )
- }
- }
- }
-
- private fun isAnyTokenFieldsFilled(): Boolean {
- return with(uiState.form) {
- contractAddressInputField.value.isNotEmpty() || tokenNameInputField.value.isNotEmpty() ||
- tokenSymbolInputField.value.isNotEmpty() || decimalsInputField.value.isNotEmpty()
- }
- }
-
- private fun isAllTokenFieldsFilled(): Boolean {
- return with(uiState.form) {
- contractAddressInputField.value.isNotEmpty() && tokenNameInputField.value.isNotEmpty() &&
- tokenSymbolInputField.value.isNotEmpty() && decimalsInputField.value.isNotEmpty()
- }
- }
-
- private fun updateForm(address: String, selectedNetwork: Blockchain) {
viewModelScope.launch(dispatchers.main) {
- runCatching(dispatchers.io) {
- featureInteractor.findToken(address = address, blockchain = selectedNetwork)
- }
- .onSuccess { token ->
- with(uiState.form) {
- uiState = uiState.copySealed(
- form = copy(
- contractAddressInputField = contractAddressInputField.copy(isLoading = false),
- networkSelectorField = networkSelectorField.copy(
- selectedItem = createNetworkSelectorItem(
- blockchain = Blockchain.fromNetworkId(token.network.id)
- ?: Blockchain.Unknown,
- ),
- ),
- tokenNameInputField = tokenNameInputField.copy(
- value = token.name,
- isEnabled = false,
- ),
- tokenSymbolInputField = tokenSymbolInputField.copy(
- value = token.symbol,
- isEnabled = false,
- ),
- decimalsInputField = decimalsInputField.copy(
- value = token.network.decimalCount,
- isEnabled = false,
- ),
- ),
- )
- }
- }
- .onFailure {
- foundTokenId = null
- Timber.e(it)
- }
- }
- }
-
- private fun handleContractAddressErrorValidation(type: AddCustomTokenError) {
- with(uiState.form) {
- val isNetworkSelectorFilled = networkSelectorField.selectedItem.blockchain != Blockchain.Unknown
- val isAnotherTokenFieldsFilled = isAnyTokenFieldsFilled()
-
- when {
- isNetworkSelectorFilled && type == AddCustomTokenError.InvalidContractAddress -> {
- // TODO("[REDACTED_TASK_KEY] Add error")
-
- uiState = uiState.copySealed(
- form = uiState.form.copy(
- tokenNameInputField = tokenNameInputField.copy(isEnabled = isAnotherTokenFieldsFilled),
- tokenSymbolInputField = tokenSymbolInputField.copy(
- isEnabled = isAnotherTokenFieldsFilled,
- ),
- decimalsInputField = decimalsInputField.copy(isEnabled = isAnotherTokenFieldsFilled),
+ val address = uiState.form.contractAddressInputField.value
+ val currency = when (getCustomTokenType()) {
+ CustomTokenType.TOKEN -> {
+ Currency.Token(
+ token = Token(
+ name = uiState.form.tokenNameInputField.value,
+ symbol = uiState.form.tokenSymbolInputField.value,
+ contractAddress = address,
+ decimals = requireNotNull(uiState.form.decimalsInputField.value.toIntOrNull()),
+ id = foundToken?.id,
),
+ blockchain = uiState.form.networkSelectorField.selectedItem.blockchain,
+ derivationPath = getDerivationPath()?.rawPath,
)
}
- !isNetworkSelectorFilled || type == AddCustomTokenError.FieldIsEmpty -> {
- uiState = uiState.copySealed(
- form = uiState.form.copy(
- contractAddressInputField = contractAddressInputField.copy(isError = false),
- tokenNameInputField = tokenNameInputField.copy(value = "", isEnabled = false),
- tokenSymbolInputField = tokenSymbolInputField.copy(value = "", isEnabled = false),
- decimalsInputField = decimalsInputField.copy(value = "", isEnabled = false),
- ),
+ CustomTokenType.BLOCKCHAIN -> {
+ Currency.Blockchain(
+ blockchain = uiState.form.networkSelectorField.selectedItem.blockchain,
+ derivationPath = getDerivationPath()?.rawPath,
)
}
-
- else -> Unit
}
- }
- }
- private fun updateDerivationPathSelector() {
- val selectedValue = uiState.form.derivationPathSelectorField?.selectedItem?.blockchain ?: return
- val isSupported = selectedValue.isEvm() || selectedValue == Blockchain.Unknown
+ analyticsSender.sendWhenAddTokenButtonClicked(currency, address)
- if (selectedValue != Blockchain.Unknown && !isSupported) {
- uiState = uiState.copySealed(
- form = uiState.form.copy(
- derivationPathSelectorField = uiState.form.derivationPathSelectorField?.copy(
- selectedItem = createDerivationPathSelectorItem(Blockchain.Unknown),
- ),
- ),
- )
- }
-
- if (uiState.form.derivationPathSelectorField?.isEnabled != isSupported) {
- uiState = uiState.copySealed(
- form = uiState.form.copy(
- derivationPathSelectorField = uiState.form.derivationPathSelectorField?.copy(
- isEnabled = isSupported,
- ),
- ),
- )
+ runCatching(dispatchers.io) { featureInteractor.saveToken(currency, address) }
+ .onSuccess { featureRouter.openWalletScreen() }
+ .onFailure(Timber::e)
}
}
}
@@ -553,31 +687,37 @@ internal class AddCustomTokenViewModel @Inject constructor(
private inner class TestActionsHandler {
fun onClearAddressButtonClick() {
- with(uiState.form) {
- uiState = uiState.copySealed(
- form = copy(
- contractAddressInputField = contractAddressInputField.copy(value = ""),
- tokenNameInputField = tokenNameInputField.copy(value = "", isEnabled = false),
- tokenSymbolInputField = tokenSymbolInputField.copy(value = "", isEnabled = false),
- decimalsInputField = decimalsInputField.copy(value = "", isEnabled = false),
+ uiState = uiState.copySealed(
+ form = uiState.form.copy(
+ contractAddressInputField = uiState.form.contractAddressInputField.copy(
+ value = "",
+ isLoading = false,
+ isError = false,
+ error = null,
),
- )
- }
+ ),
+ )
}
fun onResetButtonClick() {
with(uiState.form) {
uiState = uiState.copySealed(
- form = copy(
- contractAddressInputField = contractAddressInputField.copy(value = ""),
+ form = uiState.form.copy(
+ contractAddressInputField = contractAddressInputField.copy(
+ value = "",
+ isLoading = false,
+ isError = false,
+ error = null,
+ ),
networkSelectorField = networkSelectorField.copy(
- selectedItem = requireNotNull(networkSelectorField.items.firstOrNull()),
+ selectedItem = formStateBuilder.createNetworkSelectorItem(blockchain = Blockchain.Unknown),
),
tokenNameInputField = tokenNameInputField.copy(value = "", isEnabled = false),
tokenSymbolInputField = tokenSymbolInputField.copy(value = "", isEnabled = false),
decimalsInputField = decimalsInputField.copy(value = "", isEnabled = false),
derivationPathSelectorField = derivationPathSelectorField?.copy(
- selectedItem = requireNotNull(derivationPathSelectorField.items.firstOrNull()),
+ isEnabled = true,
+ selectedItem = formStateBuilder.createDerivationPathSelectorItem(Blockchain.Unknown),
),
),
)
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/legacy/AddCustomTokenFragment.kt b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/AddCustomTokenFragment.kt
index 280a46e758..204f95ec25 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/legacy/AddCustomTokenFragment.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/AddCustomTokenFragment.kt
@@ -15,11 +15,11 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenState
import com.tangem.domain.redux.domainStore
import com.tangem.tap.common.analytics.events.ManageTokens
-import com.tangem.tap.common.compose.ClosePopupTrigger
import com.tangem.tap.features.BaseStoreFragment
import com.tangem.tap.features.FragmentOnBackPressedHandler
import com.tangem.tap.features.addBackPressHandler
import com.tangem.tap.features.customtoken.legacy.compose.AddCustomTokenScreen
+import com.tangem.tap.features.customtoken.legacy.compose.ClosePopupTrigger
import com.tangem.wallet.R
import org.rekotlin.StoreSubscriber
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/AddCustomTokenScreen.kt b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/AddCustomTokenScreen.kt
index 88ba8be37d..0a4ad3b4a6 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/AddCustomTokenScreen.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/AddCustomTokenScreen.kt
@@ -49,8 +49,6 @@ import com.tangem.domain.features.addCustomToken.redux.ScreenState
import com.tangem.domain.features.addCustomToken.redux.ViewStates
import com.tangem.domain.redux.domainStore
import com.tangem.tap.common.compose.AddCustomTokenWarning
-import com.tangem.tap.common.compose.ClosePopupTrigger
-import com.tangem.tap.common.compose.ComposeDialogManager
import com.tangem.tap.domain.moduleMessage.ModuleMessageConverter
import com.tangem.tap.features.customtoken.legacy.compose.test.TestCase
import com.tangem.tap.features.customtoken.legacy.compose.test.TestCasesList
@@ -174,12 +172,14 @@ fun Warnings(warnings: List) {
Column {
warnings.forEachIndexed { index, item ->
val modifier = when (index) {
- 0 -> Modifier.padding(16.dp, 0.dp, 16.dp, 0.dp)
- warnings.lastIndex -> Modifier.padding(16.dp, 8.dp, 16.dp, 16.dp)
- else -> Modifier.padding(16.dp, 8.dp, 16.dp, 0.dp)
+ 0 -> Modifier.padding(vertical = 0.dp)
+ warnings.lastIndex -> Modifier.padding(top = 8.dp, bottom = 16.dp)
+ else -> Modifier.padding(top = 8.dp, bottom = 0.dp)
}
AddCustomTokenWarning(
- modifier = modifier.fillMaxWidth(),
+ modifier = modifier
+ .padding(horizontal = TangemTheme.dimens.spacing16)
+ .fillMaxWidth(),
warning = item,
converter = warningConverter,
)
diff --git a/app/src/main/java/com/tangem/tap/common/compose/BlockchainSpinner.kt b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/BlockchainSpinner.kt
similarity index 94%
rename from app/src/main/java/com/tangem/tap/common/compose/BlockchainSpinner.kt
rename to app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/BlockchainSpinner.kt
index 215fb7b312..d6c60c2b26 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/BlockchainSpinner.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/BlockchainSpinner.kt
@@ -1,4 +1,4 @@
-package com.tangem.tap.common.compose
+package com.tangem.tap.features.customtoken.legacy.compose
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.fillMaxWidth
diff --git a/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/ComposeDialogManager.kt
similarity index 86%
rename from app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt
rename to app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/ComposeDialogManager.kt
index 617f2f2c46..453ace8c9e 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/ComposeDialogManager.kt
@@ -1,4 +1,4 @@
-package com.tangem.tap.common.compose
+package com.tangem.tap.features.customtoken.legacy.compose
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
@@ -31,17 +31,18 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.tangem.core.ui.components.SpacerH16
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.datasource.api.tangemTech.models.CoinsResponse
import com.tangem.domain.DomainDialog
import com.tangem.domain.redux.domainStore
import com.tangem.domain.redux.global.DomainGlobalAction
import com.tangem.domain.redux.global.DomainGlobalState
import com.tangem.tap.domain.moduleMessage.ModuleMessageConverter
-import com.tangem.tap.features.customtoken.legacy.compose.SelectTokenNetworkDialog
import com.tangem.wallet.R
import org.rekotlin.StoreSubscriber
@Composable
-fun ComposeDialogManager() {
+internal fun ComposeDialogManager() {
val dialogSate = remember { mutableStateOf(null) }
val subscriber = remember {
object : StoreSubscriber {
@@ -94,27 +95,22 @@ private fun ShowTheDialog(dialogState: MutableState) {
* Dialog with single item selection
*/
@Composable
-fun SimpleDialog(
+fun SimpleDialog(
title: String,
- items: List,
- onSelect: (T) -> Unit,
+ items: List,
+ onSelect: (CoinsResponse.Coin.Network) -> Unit,
onDismissRequest: () -> Unit,
- itemContent: @Composable (T) -> Unit,
+ itemContent: @Composable (CoinsResponse.Coin.Network) -> Unit,
) {
Dialog(
- properties = DialogProperties(false, false),
+ properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false),
onDismissRequest = { },
) {
- Surface(
- modifier = Modifier.fillMaxWidth(),
- shape = MaterialTheme.shapes.medium,
- ) {
- Column(
- modifier = Modifier.padding(22.dp),
- ) {
+ Surface(modifier = Modifier.fillMaxWidth(), shape = MaterialTheme.shapes.medium) {
+ Column(modifier = Modifier.padding(TangemTheme.dimens.spacing22)) {
DialogTitle(title = title)
LazyColumn {
- items(items) { item ->
+ items(items = items, key = CoinsResponse.Coin.Network::networkId) { item ->
Row(
modifier = Modifier
.fillMaxWidth()
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/FormFieldViews.kt b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/FormFieldViews.kt
index 9b5c87e6b7..a640e91575 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/FormFieldViews.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/FormFieldViews.kt
@@ -17,8 +17,6 @@ import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenAction.OnTo
import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenAction.OnTokenSymbolChanged
import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenState
import com.tangem.domain.redux.domainStore
-import com.tangem.tap.common.compose.BlockchainSpinner
-import com.tangem.tap.common.compose.ClosePopupTrigger
import com.tangem.tap.common.compose.OutlinedTextFieldWidget
import com.tangem.tap.common.compose.TitleSubtitle
import com.tangem.wallet.R
diff --git a/app/src/main/java/com/tangem/tap/common/compose/OutlinedSpinner.kt b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/OutlinedSpinner.kt
similarity index 83%
rename from app/src/main/java/com/tangem/tap/common/compose/OutlinedSpinner.kt
rename to app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/OutlinedSpinner.kt
index 981e5e00e6..a3ddaedf7e 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/OutlinedSpinner.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/OutlinedSpinner.kt
@@ -1,9 +1,10 @@
-package com.tangem.tap.common.compose
+package com.tangem.tap.features.customtoken.legacy.compose
import android.os.Handler
import android.os.Looper
import androidx.compose.material.*
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
@@ -12,6 +13,7 @@ import androidx.core.os.postDelayed
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.extensions.VoidCallback
import com.tangem.domain.common.form.Field
+import com.tangem.tap.common.compose.TangemTextFieldsDefault
import com.tangem.tap.common.extensions.ValueCallback
/**
@@ -20,7 +22,7 @@ import com.tangem.tap.common.extensions.ValueCallback
@Suppress("MagicNumber")
@OptIn(ExperimentalMaterialApi::class)
@Composable
-fun OutlinedSpinner(
+internal fun OutlinedSpinner(
label: String,
itemList: List,
selectedItem: Field.Data,
@@ -71,15 +73,11 @@ fun OutlinedSpinner(
)
if (isEnabled) {
- ExposedDropdownMenu(
- expanded = rIsExpanded.value,
- onDismissRequest = onDismissRequest,
- ) {
+ ExposedDropdownMenu(expanded = rIsExpanded.value, onDismissRequest = onDismissRequest) {
itemList.forEach { item ->
- DropdownMenuItem(onClick = { onDropDownItemSelectedInternal(item) }) {
- when (dropdownItemView) {
- null -> Text(textFieldConverter(item))
- else -> dropdownItemView(item)
+ key(item) {
+ DropdownMenuItem(onClick = { onDropDownItemSelectedInternal(item) }) {
+ if (dropdownItemView == null) Text(textFieldConverter(item)) else dropdownItemView(item)
}
}
}
@@ -91,7 +89,6 @@ fun OutlinedSpinner(
class ClosePopupTrigger {
var close: () -> Unit = {}
var onCloseComplete: () -> Unit = {}
- var isTriggered = false
}
@Preview
diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/SelectTokenNetworkDialog.kt b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/SelectTokenNetworkDialog.kt
index fd824e960f..441969ad5e 100644
--- a/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/SelectTokenNetworkDialog.kt
+++ b/app/src/main/java/com/tangem/tap/features/customtoken/legacy/compose/SelectTokenNetworkDialog.kt
@@ -3,7 +3,6 @@ package com.tangem.tap.features.customtoken.legacy.compose
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.tangem.domain.DomainDialog
-import com.tangem.tap.common.compose.SimpleDialog
import com.tangem.tap.common.compose.TitleSubtitle
import com.tangem.wallet.R
diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerDataProvider.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerDataProvider.kt
index 0097f34142..9d3b4aeda6 100644
--- a/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerDataProvider.kt
+++ b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerDataProvider.kt
@@ -1,6 +1,6 @@
package com.tangem.tap.features.disclaimer
-import com.tangem.tap.persistence.DisclaimerPrefStorage
+import com.tangem.data.source.preferences.storage.DisclaimerPrefStorage
/**
[REDACTED_AUTHOR]
diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt
index 30b3f43d1c..56519de4ff 100644
--- a/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt
+++ b/app/src/main/java/com/tangem/tap/features/disclaimer/DisclaimerType.kt
@@ -1,11 +1,11 @@
package com.tangem.tap.features.disclaimer
-import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.common.TapWorkarounds.isSaltPay
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
-import com.tangem.tap.persistence.DisclaimerPrefStorage
+import com.tangem.domain.models.scan.CardDTO
+import com.tangem.data.source.preferences.storage.DisclaimerPrefStorage
import com.tangem.tap.preferencesStorage
-import java.util.*
+import java.util.Locale
/**
[REDACTED_AUTHOR]
diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt
index 64ea0798e0..acf3408acf 100644
--- a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt
+++ b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt
@@ -91,8 +91,7 @@ class HomeFragment : Fragment(), StoreSubscriber {
onSearchTokensClick = {
Analytics.send(IntroductionProcess.ButtonTokensList())
store.dispatch(NavigationAction.NavigateTo(AppScreen.AddTokens))
- store.dispatch(TokensAction.AllowToAddTokens(false))
- store.dispatch(TokensAction.LoadCurrencies())
+ store.dispatch(TokensAction.SetArgs.ReadAccess)
},
)
}
diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt
index e35aa85d7a..bf80a5b458 100644
--- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt
+++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt
@@ -15,7 +15,7 @@ import com.tangem.tap.domain.extensions.getOrLoadCardArtworkUrl
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.models.hasPendingTransactions
import com.tangem.tap.features.wallet.redux.ProgressState
-import com.tangem.tap.persistence.UsedCardsPrefStorage
+import com.tangem.data.source.preferences.storage.UsedCardsPrefStorage
import timber.log.Timber
import java.math.BigDecimal
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/api/featuretoggles/TokensListFeatureToggles.kt b/app/src/main/java/com/tangem/tap/features/tokens/api/featuretoggles/TokensListFeatureToggles.kt
deleted file mode 100644
index 286eb6d0e0..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/api/featuretoggles/TokensListFeatureToggles.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.tangem.tap.features.tokens.api.featuretoggles
-
-/**
- * TokensList feature toggles
- *
-[REDACTED_AUTHOR]
- */
-interface TokensListFeatureToggles {
-
- /** Availability of redesigned screen (internal feature) */
- val isRedesignedScreenEnabled: Boolean
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListFeatureTogglesModule.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListFeatureTogglesModule.kt
deleted file mode 100644
index d2b8ae0470..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListFeatureTogglesModule.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.tangem.tap.features.tokens.impl.di
-
-import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
-import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles
-import com.tangem.tap.features.tokens.impl.featuretoggles.DefaultTokensListFeatureToggles
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import javax.inject.Singleton
-
-/**
-[REDACTED_AUTHOR]
- */
-@Module
-@InstallIn(SingletonComponent::class)
-internal object TokensListFeatureTogglesModule {
-
- @Provides
- @Singleton
- fun providesTokensListFeatureToggles(featureTogglesManager: FeatureTogglesManager): TokensListFeatureToggles {
- return DefaultTokensListFeatureToggles(featureTogglesManager)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListRouterModule.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListRouterModule.kt
index 2a7da5cca4..07a7a3412d 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListRouterModule.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/di/TokensListRouterModule.kt
@@ -1,5 +1,6 @@
package com.tangem.tap.features.tokens.impl.di
+import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
import com.tangem.tap.features.tokens.impl.presentation.router.DefaultTokensListRouter
import com.tangem.tap.features.tokens.impl.presentation.router.TokensListRouter
import dagger.Module
@@ -17,5 +18,7 @@ internal object TokensListRouterModule {
@Provides
@ViewModelScoped
- fun provideTokensListRouter(): TokensListRouter = DefaultTokensListRouter()
+ fun provideTokensListRouter(customTokenFeatureToggles: CustomTokenFeatureToggles): TokensListRouter {
+ return DefaultTokensListRouter(customTokenFeatureToggles)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/featuretoggles/DefaultTokensListFeatureToggles.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/featuretoggles/DefaultTokensListFeatureToggles.kt
deleted file mode 100644
index b9aa44c70f..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/featuretoggles/DefaultTokensListFeatureToggles.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.tangem.tap.features.tokens.impl.featuretoggles
-
-import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
-import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles
-
-/**
- * Default implementation of TokensList feature toggles
- *
- * @property featureTogglesManager manager for getting information about the availability of feature toggles
- *
-[REDACTED_AUTHOR]
- */
-internal class DefaultTokensListFeatureToggles(
- private val featureTogglesManager: FeatureTogglesManager,
-) : TokensListFeatureToggles {
-
- override val isRedesignedScreenEnabled: Boolean
- get() = featureTogglesManager.isFeatureEnabled(name = "REDESIGNED_TOKEN_LIST_SCREEN_ENABLED")
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/TokensListFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/TokensListFragment.kt
index 0a455118c1..e5ac57cfc8 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/TokensListFragment.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/TokensListFragment.kt
@@ -5,6 +5,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.core.view.WindowCompat
import androidx.fragment.app.Fragment
import androidx.hilt.navigation.compose.hiltViewModel
@@ -35,7 +36,9 @@ internal class TokensListFragment : Fragment() {
setContent {
isTransitionGroup = true
- val viewModel = hiltViewModel()
+ val viewModel = hiltViewModel().apply {
+ LocalLifecycleOwner.current.lifecycle.addObserver(this)
+ }
TangemTheme {
TokensListScreen(stateHolder = viewModel.uiState)
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/models/TokensListArgs.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/models/TokensListArgs.kt
index 88fdf58dd7..207976d628 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/models/TokensListArgs.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/models/TokensListArgs.kt
@@ -12,7 +12,7 @@ import com.tangem.tap.store
*/
class TokensListArgs {
/** Tokens list screen mode */
- val isManageAccess: Boolean get() = store.state.tokensState.allowToAdd
+ val isManageAccess: Boolean get() = store.state.tokensState.isManageAccess
/** Tokens list that accessible from the main screen */
val mainScreenTokenList: List get() = store.state.tokensState.addedTokens
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/DefaultTokensListRouter.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/DefaultTokensListRouter.kt
index 73e09a433e..cbfe64e505 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/DefaultTokensListRouter.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/router/DefaultTokensListRouter.kt
@@ -3,7 +3,9 @@ package com.tangem.tap.features.tokens.impl.presentation.router
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchNotification
import com.tangem.tap.common.redux.AppDialog
+import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
+import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
import com.tangem.tap.features.tokens.legacy.redux.TokensAction
import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.store
@@ -15,15 +17,20 @@ import com.tangem.wallet.R
*
[REDACTED_AUTHOR]
*/
-internal class DefaultTokensListRouter : TokensListRouter {
+internal class DefaultTokensListRouter(
+ private val customTokenFeatureToggles: CustomTokenFeatureToggles,
+) : TokensListRouter {
override fun popBackStack() {
store.dispatch(NavigationAction.PopBackTo())
- store.dispatch(TokensAction.ResetState)
}
override fun openAddCustomTokenScreen() {
- store.dispatch(TokensAction.PrepareAndNavigateToAddCustomToken)
+ if (customTokenFeatureToggles.isRedesignedScreenEnabled) {
+ store.dispatch(NavigationAction.NavigateTo(AppScreen.AddCustomToken))
+ } else {
+ store.dispatch(TokensAction.PrepareAndNavigateToAddCustomToken)
+ }
}
override fun showAddressCopiedNotification() {
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/NetworkItemState.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/NetworkItemState.kt
index 081a399e06..bfcffbdf69 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/NetworkItemState.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/NetworkItemState.kt
@@ -4,7 +4,6 @@ import androidx.compose.runtime.MutableState
import com.tangem.blockchain.common.Blockchain
import com.tangem.core.ui.extensions.getActiveIconRes
import com.tangem.tap.common.extensions.getGreyedOutIconRes
-import com.tangem.tap.features.tokens.legacy.redux.ContractAddress
/**
* Network item state
@@ -62,7 +61,7 @@ sealed interface NetworkItemState {
override val isMainNetwork: Boolean,
val isAdded: MutableState,
val id: String,
- val address: ContractAddress?,
+ val address: String?,
val decimalCount: Int?,
val blockchain: Blockchain,
val onToggleClick: (TokenItemState.ManageContent, ManageContent) -> Unit,
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenItem.kt
index 9f3c695bb2..b3ee9856f3 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenItem.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokenItem.kt
@@ -139,6 +139,7 @@ private fun Icon(name: String, iconUrl: String, modifier: Modifier = Modifier) {
)
}
+// TODO(use CurrencyPlaceholderIcon here?)
@Composable
private fun PlaceholderIcon(name: String, modifier: Modifier = Modifier) {
Box(
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListAnalyticsSender.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListAnalyticsSender.kt
index 8e839d1ddd..95d0e9371e 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListAnalyticsSender.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/viewmodels/TokensListAnalyticsSender.kt
@@ -9,6 +9,10 @@ import com.tangem.tap.common.analytics.events.ManageTokens
/** Analytics sender for tokens list screen */
class TokensListAnalyticsSender(private val analyticsEventHandler: AnalyticsEventHandler) {
+ fun sendWhenScreenOpened() {
+ analyticsEventHandler.send(event = ManageTokens.ScreenOpened())
+ }
+
fun sendWhenTokenAdded(token: Token) {
analyticsEventHandler.send(
event = ManageTokens.TokenSwitcherChanged(
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 eff8dd3e7d..a386333139 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
@@ -3,6 +3,8 @@ package com.tangem.tap.features.tokens.impl.presentation.viewmodels
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.LoadState
@@ -59,7 +61,7 @@ internal class TokensListViewModel @Inject constructor(
private val dispatchers: AppCoroutineDispatcherProvider,
private val reduxStateHolder: AppStateHolder,
analyticsEventHandler: AnalyticsEventHandler,
-) : ViewModel() {
+) : ViewModel(), DefaultLifecycleObserver {
private val args = TokensListArgs()
private val analyticsSender = TokensListAnalyticsSender(analyticsEventHandler)
@@ -72,6 +74,10 @@ internal class TokensListViewModel @Inject constructor(
private val changedTokensList: MutableList = args.mainScreenTokenList.toMutableList()
private val changedBlockchainList: MutableList = args.mainScreenBlockchainList.toMutableList()
+ override fun onCreate(owner: LifecycleOwner) {
+ if (args.isManageAccess) analyticsSender.sendWhenScreenOpened()
+ }
+
private fun getInitialUiState(): TokensListStateHolder {
return if (args.isManageAccess) {
TokensListStateHolder.ManageContent(
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/AddTokensFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/AddTokensFragment.kt
deleted file mode 100644
index 3d6216bf22..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/AddTokensFragment.kt
+++ /dev/null
@@ -1,174 +0,0 @@
-package com.tangem.tap.features.tokens.legacy
-
-import android.os.Bundle
-import android.view.Menu
-import android.view.MenuInflater
-import android.view.MenuItem
-import android.view.View
-import androidx.appcompat.app.AppCompatActivity
-import androidx.appcompat.widget.SearchView
-import androidx.compose.runtime.MutableState
-import androidx.compose.runtime.mutableStateOf
-import androidx.transition.TransitionInflater
-import by.kirich1409.viewbindingdelegate.viewBinding
-import com.tangem.blockchain.common.Blockchain
-import com.tangem.core.analytics.Analytics
-import com.tangem.core.ui.res.TangemTheme
-import com.tangem.tap.common.analytics.events.ManageTokens
-import com.tangem.tap.common.extensions.copyToClipboard
-import com.tangem.tap.common.extensions.dispatchNotification
-import com.tangem.tap.common.extensions.dispatchOnMain
-import com.tangem.tap.common.extensions.getString
-import com.tangem.tap.common.redux.navigation.NavigationAction
-import com.tangem.tap.features.BaseFragment
-import com.tangem.tap.features.addBackPressHandler
-import com.tangem.tap.features.tokens.legacy.redux.ContractAddress
-import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain
-import com.tangem.tap.features.tokens.legacy.redux.TokensAction
-import com.tangem.tap.features.tokens.legacy.redux.TokensState
-import com.tangem.tap.features.tokens.legacy.ui.compose.CurrenciesScreen
-import com.tangem.tap.mainScope
-import com.tangem.tap.store
-import com.tangem.wallet.R
-import com.tangem.wallet.databinding.FragmentAddTokensBinding
-import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.debounce
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import org.rekotlin.StoreSubscriber
-
-@AndroidEntryPoint
-internal class AddTokensFragment : BaseFragment(R.layout.fragment_add_tokens), StoreSubscriber {
-
- private val binding: FragmentAddTokensBinding by viewBinding(FragmentAddTokensBinding::bind)
- private var tokensState: MutableState = mutableStateOf(store.state.tokensState)
- private var searchInput = mutableStateOf("")
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setHasOptionsMenu(true)
- addBackPressHandler(this)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) = with(binding) {
- super.onViewCreated(view, savedInstanceState)
-
- (activity as? AppCompatActivity)?.setSupportActionBar(toolbar)
- toolbar.setNavigationOnClickListener { handleOnBackPressed() }
-
- val onSaveChanges = { tokens: List, blockchains: List ->
- Analytics.send(ManageTokens.ButtonSaveChanges())
- store.dispatch(TokensAction.SaveChanges(tokens, blockchains))
- }
- val onNetworkItemClicked = { contractAddress: ContractAddress ->
- context?.copyToClipboard(contractAddress)
- store.dispatchNotification(R.string.contract_address_copied_message)
- }
-
- val onLoadMore = {
- store.dispatch(TokensAction.LoadMore(scanResponse = store.state.globalState.scanResponse))
- }
-
- cvCurrencies.setContent {
- TangemTheme {
- CurrenciesScreen(
- tokensState = tokensState,
- onSaveChanges = onSaveChanges,
- onNetworkItemClick = onNetworkItemClicked,
- onLoadMore = onLoadMore,
- )
- }
- }
- }
-
- override fun onStart() {
- super.onStart()
- store.subscribe(this) { state ->
- state
- .skipRepeats { oldState, newState -> oldState.tokensState == newState.tokensState }
- .select { it.tokensState }
- }
- }
-
- override fun onStop() {
- super.onStop()
- store.unsubscribe(this)
- }
-
- override fun onDestroy() {
- store.dispatch(TokensAction.ResetState)
- super.onDestroy()
- }
-
- @Suppress("MagicNumber")
- override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
- inflater.inflate(R.menu.menu_popular_tokens, menu)
-
- val addCustomTokenAllowed = store.state.tokensState.allowToAdd
- menu.findItem(R.id.menu_navigate_add_custom_token).isVisible = addCustomTokenAllowed
-
- val menuItem = menu.findItem(R.id.menu_search)
- val searchView: SearchView = menuItem.actionView as SearchView
- searchView.queryHint = searchView.getString(R.string.common_search)
- searchView.maxWidth = android.R.attr.width
- searchView.inputtedTextAsFlow()
- .debounce(800)
- .distinctUntilChanged()
- .onEach {
- searchInput.value = it.lowercase()
- dispatchOnMain(TokensAction.SetSearchInput(searchInput.value))
- }
- .launchIn(mainScope)
- return super.onCreateOptionsMenu(menu, inflater)
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- return when (item.itemId) {
- R.id.menu_search -> true
- R.id.menu_navigate_add_custom_token -> {
- Analytics.send(ManageTokens.ButtonCustomToken())
- store.dispatch(TokensAction.PrepareAndNavigateToAddCustomToken)
- true
- }
- else -> super.onOptionsItemSelected(item)
- }
- }
-
- override fun configureTransitions() {
- super.configureTransitions()
- val inflater = TransitionInflater.from(requireContext())
- enterTransition = inflater.inflateTransition(R.transition.slide_right)
- exitTransition = inflater.inflateTransition(R.transition.fade)
- }
-
- override fun handleOnBackPressed() {
- store.dispatch(NavigationAction.PopBackTo())
- store.dispatch(TokensAction.ResetState)
- }
-
- override fun newState(state: TokensState) {
- if (activity == null || view == null) return
- val toolbarTitle =
- if (state.allowToAdd) R.string.main_manage_tokens else R.string.search_tokens_title
- tokensState.value = state
- binding.toolbar.title = getString(toolbarTitle)
- }
-
- private fun SearchView.inputtedTextAsFlow(): Flow = callbackFlow {
- val watcher = setOnQueryTextListener(
- object : SearchView.OnQueryTextListener {
- override fun onQueryTextSubmit(query: String?): Boolean = false
-
- override fun onQueryTextChange(newText: String?): Boolean {
- trySend(newText ?: "")
- return false
- }
- },
- )
- awaitClose { watcher }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensAction.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensAction.kt
index bea0320bbe..21f763e48a 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensAction.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensAction.kt
@@ -2,37 +2,22 @@ package com.tangem.tap.features.tokens.legacy.redux
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationStyle
-import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.domain.model.WalletDataModel
-import com.tangem.tap.domain.tokens.Currency
import org.rekotlin.Action
-sealed class TokensAction : Action {
+sealed interface TokensAction : Action {
- object ResetState : TokensAction()
+ /** Single way to pass data to the screen */
+ sealed interface SetArgs : TokensAction {
- data class AllowToAddTokens(val allow: Boolean) : TokensAction()
+ data class ManageAccess(val wallets: List, val derivationStyle: DerivationStyle?) : SetArgs
- data class LoadCurrencies(val scanResponse: ScanResponse? = null) : TokensAction() {
- data class Success(val currencies: List, val loadMore: Boolean) : TokensAction()
- object Failure : TokensAction()
+ object ReadAccess : SetArgs
}
- data class LoadMore(
- val scanResponse: ScanResponse? = null,
- ) : TokensAction()
+ // TODO: [REDACTED_TASK_KEY] Remove this action
+ data class SaveChanges(val tokens: List, val blockchains: List) : TokensAction
- data class SetAddedCurrencies(
- val wallets: List,
- val derivationStyle: DerivationStyle?,
- ) : TokensAction()
-
- data class SaveChanges(
- val addedTokens: List,
- val addedBlockchains: List,
- ) : TokensAction()
-
- object PrepareAndNavigateToAddCustomToken : TokensAction()
-
- data class SetSearchInput(val searchInput: String) : TokensAction()
+ // TODO: Remove this action in 4.7 release
+ object PrepareAndNavigateToAddCustomToken : TokensAction
}
\ No newline at end of file
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
index be311deb0a..70a7e1b2cd 100644
--- 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
@@ -8,13 +8,10 @@ import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.toMapKey
import com.tangem.common.flatMap
-import com.tangem.common.services.Result
import com.tangem.core.analytics.Analytics
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.DomainWrapped
import com.tangem.domain.common.TapWorkarounds.derivationStyle
-import com.tangem.domain.common.TapWorkarounds.isTestCard
-import com.tangem.domain.common.extensions.supportedBlockchains
import com.tangem.domain.common.util.hasDerivation
import com.tangem.domain.common.util.supportsHdWallet
import com.tangem.domain.features.addCustomToken.CustomCurrency
@@ -31,132 +28,77 @@ import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.TapError
-import com.tangem.tap.domain.tokens.LoadAvailableCoinsService
+import com.tangem.tap.domain.model.WalletDataModel
import com.tangem.tap.features.wallet.models.Currency
-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 com.tangem.tap.walletCurrenciesManager
-import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Middleware
import timber.log.Timber
-@Suppress("LargeClass")
-class TokensMiddleware {
+object TokensMiddleware {
val tokensMiddleware: Middleware = { _, _ ->
{ next ->
{ action ->
when (action) {
- is TokensAction.LoadCurrencies -> handleLoadCurrencies(action.scanResponse)
is TokensAction.SaveChanges -> handleSaveChanges(action)
is TokensAction.PrepareAndNavigateToAddCustomToken -> handleAddingCustomToken()
- is TokensAction.SetSearchInput -> {
- Analytics.send(ManageTokens.TokenSearched())
- handleLoadCurrencies(
- scanResponse = store.state.globalState.scanResponse,
- newSearchInput = action.searchInput,
- )
- }
- is TokensAction.LoadMore -> {
- if (store.state.tokensState.needToLoadMore &&
- store.state.tokensState.currencies.isNotEmpty()
- ) {
- handleLoadCurrencies(action.scanResponse)
- }
- }
}
next(action)
}
}
}
- private fun handleLoadCurrencies(scanResponse: ScanResponse?, newSearchInput: String? = null) {
- val tokensState = store.state.tokensState
-
- val supportedBlockchains: List = scanResponse?.card?.supportedBlockchains()
- ?: Blockchain.values().toList().filterNot(Blockchain::isTestnet)
-
- val loadCoinsService = LoadAvailableCoinsService(
- tangemTechApi = store.state.domainNetworks.tangemTechService.api,
- dispatchers = AppCoroutineDispatcherProvider(),
- assetReader = store.state.daggerGraphState.get(DaggerGraphState::assetReader),
- )
-
+ private fun handleSaveChanges(action: TokensAction.SaveChanges) {
scope.launch {
- val result = loadCoinsService.getSupportedTokens(
- isTestNet = scanResponse?.card?.isTestCard ?: false,
- supportedBlockchains = supportedBlockchains,
- page = if (newSearchInput == null) tokensState.pageToLoad else 0,
- searchInput = if (newSearchInput == null) tokensState.searchInput else newSearchInput.ifBlank { null },
+ val scanResponse = store.state.globalState.scanResponse ?: return@launch
+
+ val currentTokens = store.state.tokensState.addedTokens
+ val currentBlockchains = store.state.tokensState.addedBlockchains
+
+ val blockchainsToAdd = action.blockchains.filterNot(currentBlockchains::contains)
+ val blockchainsToRemove =
+ store.state.tokensState.addedBlockchains.filterNot(action.blockchains::contains)
+
+ val tokensToAdd = action.tokens.filterNot(currentTokens::contains)
+ val tokensToRemove = currentTokens.filterNot { token -> action.tokens.any { it.token == token.token } }
+
+ removeCurrenciesIfNeeded(
+ currencies = convertToCurrencies(
+ blockchains = blockchainsToRemove,
+ tokens = tokensToRemove,
+ derivationStyle = scanResponse.card.derivationStyle,
+ ),
)
- store.dispatchOnMain(
- action = when (result) {
- is Result.Success -> {
- TokensAction.LoadCurrencies.Success(
- currencies = result.data.currencies.filter(supportedBlockchains.toSet()),
- loadMore = result.data.moreAvailable,
- )
- }
- is Result.Failure -> {
- TokensAction.LoadCurrencies.Failure
- }
- },
- )
- }
- }
+ 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
+ }
- private fun handleSaveChanges(action: TokensAction.SaveChanges) = scope.launch {
- val scanResponse = store.state.globalState.scanResponse ?: return@launch
-
- val currentTokens = store.state.tokensState.addedWallets.toNonCustomTokensWithBlockchains(
- derivationStyle = scanResponse.card.derivationStyle,
- )
- val currentBlockchains = store.state.tokensState.addedWallets.toNonCustomBlockchains(
- derivationStyle = scanResponse.card.derivationStyle,
- )
-
- val blockchainsToAdd = action.addedBlockchains.filterNot(currentBlockchains::contains)
- val blockchainsToRemove = currentBlockchains.filterNot(action.addedBlockchains::contains)
-
- val tokensToAdd = action.addedTokens.filterNot(currentTokens::contains)
- val tokensToRemove = currentTokens.filterNot { token -> action.addedTokens.any { it.token == token.token } }
-
- removeCurrenciesIfNeeded(
- currencies = convertToCurrencies(
- blockchains = blockchainsToRemove,
- tokens = tokensToRemove,
+ val currencyList = convertToCurrencies(
+ blockchains = blockchainsToAdd,
+ tokens = tokensToAdd,
derivationStyle = scanResponse.card.derivationStyle,
- ),
- )
+ )
- 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 = convertToCurrencies(
- blockchains = blockchainsToAdd,
- tokens = tokensToAdd,
- derivationStyle = scanResponse.card.derivationStyle,
- )
-
- if (scanResponse.supportsHdWallet()) {
- deriveMissingBlockchains(scanResponse, currencyList) {
- submitAdd(it, currencyList)
+ if (scanResponse.supportsHdWallet()) {
+ deriveMissingBlockchains(scanResponse, currencyList) {
+ submitAdd(it, currencyList)
+ store.dispatchOnMain(NavigationAction.PopBackTo())
+ }
+ } else {
+ submitAdd(scanResponse, currencyList)
store.dispatchOnMain(NavigationAction.PopBackTo())
}
- } else {
- submitAdd(scanResponse, currencyList)
- store.dispatchOnMain(NavigationAction.PopBackTo())
}
}
@@ -316,21 +258,23 @@ class TokensMiddleware {
}
}
- val addedCurrencies = store.state.walletState.walletsStores.map { walletStore ->
- walletStore.walletsData.map { walletData -> walletData.currency }
- }.flatten().map {
- when (it) {
- is Currency.Blockchain -> DomainWrapped.Currency.Blockchain(
- it.blockchain,
- it.derivationPath,
- )
- is Currency.Token -> DomainWrapped.Currency.Token(
- it.token,
- it.blockchain,
- it.derivationPath,
- )
+ val addedCurrencies = store.state.walletState.walletsStores
+ .map { walletStore -> walletStore.walletsData.map(WalletDataModel::currency) }
+ .flatten()
+ .map { currency ->
+ when (currency) {
+ is Currency.Blockchain -> DomainWrapped.Currency.Blockchain(
+ currency.blockchain,
+ currency.derivationPath,
+ )
+
+ is Currency.Token -> DomainWrapped.Currency.Token(
+ currency.token,
+ currency.blockchain,
+ currency.derivationPath,
+ )
+ }
}
- }
domainStore.dispatch(AddCustomTokenAction.Init.SetAddedCurrencies(addedCurrencies))
domainStore.dispatch(AddCustomTokenAction.Init.SetOnAddTokenCallback(onAddCustomToken))
store.dispatch(NavigationAction.NavigateTo(AppScreen.AddCustomToken))
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensReducer.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensReducer.kt
index 7b5d5eaef5..e2589be5b7 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensReducer.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensReducer.kt
@@ -1,6 +1,11 @@
package com.tangem.tap.features.tokens.legacy.redux
+import com.tangem.blockchain.common.Blockchain
+import com.tangem.blockchain.common.DerivationStyle
import com.tangem.tap.common.redux.AppState
+import com.tangem.tap.domain.model.WalletDataModel
+import com.tangem.tap.features.wallet.models.Currency
+import com.tangem.tap.features.wallet.models.Currency.Token
import org.rekotlin.Action
object TokensReducer {
@@ -10,47 +15,41 @@ object TokensReducer {
private fun internalReduce(action: Action, state: AppState): TokensState {
if (action !is TokensAction) return state.tokensState
- val tokensState = state.tokensState
return when (action) {
- is TokensAction.ResetState -> TokensState()
- is TokensAction.LoadCurrencies -> {
- val loadingState = if (tokensState.currencies.isEmpty()) {
- LoadCoinsState.LOADING
- } else {
- LoadCoinsState.LOADED
- }
- tokensState.copy(
- scanResponse = action.scanResponse,
- loadCoinsState = loadingState,
- )
- }
- is TokensAction.LoadCurrencies.Success -> {
- tokensState.copy(
- currencies = tokensState.currencies + action.currencies,
- needToLoadMore = action.loadMore,
- pageToLoad = tokensState.pageToLoad + 1,
- loadCoinsState = LoadCoinsState.LOADED,
- )
- }
- is TokensAction.SetAddedCurrencies -> {
- tokensState.copy(
+ is TokensAction.SetArgs.ManageAccess -> {
+ state.tokensState.copy(
+ isManageAccess = true,
+ addedWallets = action.wallets,
addedBlockchains = action.wallets.toNonCustomBlockchains(action.derivationStyle),
addedTokens = action.wallets.toNonCustomTokensWithBlockchains(action.derivationStyle),
- addedWallets = action.wallets,
)
}
- is TokensAction.AllowToAddTokens -> {
- tokensState.copy(allowToAdd = action.allow)
+
+ is TokensAction.SetArgs.ReadAccess -> {
+ state.tokensState.copy(isManageAccess = false)
}
- is TokensAction.SetSearchInput -> {
- tokensState.copy(
- searchInput = action.searchInput.ifBlank { null },
- needToLoadMore = true,
- currencies = emptyList(),
- pageToLoad = 0,
- loadCoinsState = LoadCoinsState.LOADING,
- )
- }
- else -> tokensState
+
+ else -> state.tokensState
}
+}
+
+private fun List.toNonCustomBlockchains(derivationStyle: DerivationStyle?): List {
+ return mapNotNull { walletDataModel ->
+ if (walletDataModel.currency.isCustomCurrency(derivationStyle)) {
+ null
+ } else {
+ (walletDataModel.currency as? Currency.Blockchain)?.blockchain
+ }
+ }.distinct()
+}
+
+private fun List.toNonCustomTokensWithBlockchains(
+ derivationStyle: DerivationStyle?,
+): List {
+ return mapNotNull { walletDataModel ->
+ if (walletDataModel.currency !is Token) return@mapNotNull null
+ if (walletDataModel.currency.isCustomCurrency(derivationStyle)) return@mapNotNull null
+
+ TokenWithBlockchain(walletDataModel.currency.token, walletDataModel.currency.blockchain)
+ }.distinct()
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensState.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensState.kt
index 4f77d60fac..156fd0c922 100644
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensState.kt
+++ b/app/src/main/java/com/tangem/tap/features/tokens/legacy/redux/TokensState.kt
@@ -1,76 +1,16 @@
package com.tangem.tap.features.tokens.legacy.redux
import com.tangem.blockchain.common.Blockchain
-import com.tangem.blockchain.common.DerivationStyle
import com.tangem.blockchain.common.Token
-import com.tangem.domain.models.scan.ScanResponse
-import com.tangem.domain.common.extensions.canHandleToken
-import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.tap.domain.model.WalletDataModel
-import com.tangem.tap.domain.tokens.Currency
import org.rekotlin.StateType
-import com.tangem.tap.features.wallet.models.Currency.Token as CurrencyToken
data class TokensState(
+ val isManageAccess: Boolean = false,
val addedWallets: List = emptyList(),
val addedTokens: List = emptyList(),
val addedBlockchains: List = emptyList(),
- val currencies: List = emptyList(),
- val searchInput: String? = null,
- val allowToAdd: Boolean = true,
- val scanResponse: ScanResponse? = null,
- val needToLoadMore: Boolean = true,
- val pageToLoad: Int = 0,
- val loadCoinsState: LoadCoinsState = LoadCoinsState.LOADING,
-) : StateType {
+) : StateType
- fun canHandleToken(token: TokenWithBlockchain): Boolean {
- return scanResponse?.card?.canHandleToken(token.blockchain) ?: false
- }
-}
-
-typealias ContractAddress = String
-
-fun List.toNonCustomTokensWithBlockchains(
- derivationStyle: DerivationStyle?,
-): List {
- return mapNotNull {
- if (it.currency !is CurrencyToken) return@mapNotNull null
- if (it.currency.isCustomCurrency(derivationStyle)) return@mapNotNull null
- TokenWithBlockchain(it.currency.token, it.currency.blockchain)
- }.distinct()
-}
-
-fun List.toNonCustomBlockchains(derivationStyle: DerivationStyle?): List {
- return mapNotNull {
- if (it.currency.isCustomCurrency(derivationStyle)) {
- null
- } else {
- (it.currency as? com.tangem.tap.features.wallet.models.Currency.Blockchain)?.blockchain
- }
- }.distinct()
-}
-
-data class TokenWithBlockchain(
- val token: Token,
- val blockchain: Blockchain,
-)
-
-fun List.filter(supportedBlockchains: Set?): List {
- if (supportedBlockchains == null) return this
-
- return map { currency ->
- currency.copy(
- contracts = currency.contracts.filter { contract ->
- supportedBlockchains.contains(contract.blockchain) &&
- (contract.blockchain.canHandleTokens() || contract.address == null)
- },
- )
- }.filterNot { currency ->
- currency.contracts.isEmpty() && !supportedBlockchains.contains(Blockchain.fromNetworkId(currency.id))
- }
-}
-
-enum class LoadCoinsState {
- LOADING, LOADED,
-}
\ No newline at end of file
+// TODO: [REDACTED_TASK_KEY] Remove this class
+data class TokenWithBlockchain(val token: Token, val blockchain: Blockchain)
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrenciesScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrenciesScreen.kt
deleted file mode 100644
index 6088fde47a..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrenciesScreen.kt
+++ /dev/null
@@ -1,232 +0,0 @@
-@file:Suppress("MagicNumber")
-
-package com.tangem.tap.features.tokens.legacy.ui.compose
-
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.core.tween
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material.CircularProgressIndicator
-import androidx.compose.material.FabPosition
-import androidx.compose.material.Scaffold
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.colorResource
-import androidx.compose.ui.res.stringResource
-import com.tangem.blockchain.common.Blockchain
-import com.tangem.core.analytics.Analytics
-import com.tangem.core.ui.components.Keyboard
-import com.tangem.core.ui.components.PrimaryButton
-import com.tangem.core.ui.components.SystemBarsEffect
-import com.tangem.core.ui.components.keyboardAsState
-import com.tangem.core.ui.res.TangemTheme
-import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
-import com.tangem.domain.common.extensions.fromNetworkId
-import com.tangem.tap.common.analytics.events.AnalyticsParam
-import com.tangem.tap.common.analytics.events.ManageTokens
-import com.tangem.tap.common.compose.extensions.addAndNotify
-import com.tangem.tap.common.compose.extensions.removeAndNotify
-import com.tangem.tap.common.extensions.dispatchDialogShow
-import com.tangem.tap.common.redux.AppDialog
-import com.tangem.tap.domain.tokens.Currency
-import com.tangem.tap.features.tokens.legacy.redux.ContractAddress
-import com.tangem.tap.features.tokens.legacy.redux.LoadCoinsState
-import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain
-import com.tangem.tap.features.tokens.legacy.redux.TokensState
-import com.tangem.tap.features.wallet.redux.models.WalletDialog
-import com.tangem.tap.store
-import com.tangem.wallet.R
-
-@Suppress("LongMethod")
-@Composable
-fun CurrenciesScreen(
- tokensState: MutableState,
- onSaveChanges: (List, List) -> Unit,
- onNetworkItemClick: (ContractAddress) -> Unit,
- onLoadMore: () -> Unit,
-) {
- val tokensAddedOnMainScreen = remember { tokensState.value.addedTokens }
- val blockchainsAddedOnMainScreen = remember { tokensState.value.addedBlockchains }
-
- val addedTokensState = remember { mutableStateOf(tokensState.value.addedTokens) }
- val addedBlockchainsState = remember { mutableStateOf(tokensState.value.addedBlockchains) }
-
- val keyboardState by keyboardAsState()
-
- val onAddCurrencyToggleClick = { currency: Currency, token: TokenWithBlockchain? ->
- val blockchain = Blockchain.fromNetworkId(currency.id)
- if (blockchain != null && token == null) {
- toggleBlockchain(
- blockchain,
- blockchainsAddedOnMainScreen,
- addedBlockchainsState,
- addedTokensState.value,
- )
- } else if (token != null) {
- toggleToken(
- token,
- tokensAddedOnMainScreen,
- addedTokensState,
- tokensState.value,
- )
- }
- }
-
- val statusBarColor = colorResource(id = R.color.backgroundLightGray)
- SystemBarsEffect {
- setSystemBarsColor(color = statusBarColor)
- }
-
- Scaffold(
- floatingActionButton = {
- if (tokensState.value.allowToAdd) {
- SaveChangesButton(keyboardState) {
- onSaveChanges(addedTokensState.value, addedBlockchainsState.value)
- }
- }
- },
- floatingActionButtonPosition = FabPosition.Center,
- ) {
- AnimatedVisibility(
- visible = tokensState.value.loadCoinsState == LoadCoinsState.LOADING,
- enter = fadeIn(),
- exit = fadeOut(),
- ) {
- Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
- CircularProgressIndicator(color = Color(0xFF1ACE80))
- }
- }
- AnimatedVisibility(
- visible = tokensState.value.loadCoinsState == LoadCoinsState.LOADED,
- enter = fadeIn(animationSpec = tween(1000)),
- exit = fadeOut(animationSpec = tween(1000)),
- ) {
- Column {
- val showHeader = tokensState.value.scanResponse?.card?.useOldStyleDerivation == true
- ListOfCurrencies(
- header = { if (showHeader) CurrenciesWarning() },
- currencies = tokensState.value.currencies,
- addedTokens = addedTokensState.value,
- addedBlockchains = addedBlockchainsState.value,
- allowToAdd = tokensState.value.allowToAdd,
- onAddCurrencyToggle = { currency, token ->
- onAddCurrencyToggleClick(currency, token)
- },
- onNetworkItemClick = onNetworkItemClick,
- onLoadMore = onLoadMore,
- )
- }
- }
- }
-}
-
-private fun toggleBlockchain(
- blockchain: Blockchain,
- blockchainsAddedOnMainScreen: List,
- addedBlockchainsState: MutableState>,
- addedTokens: List,
-) {
- val isTryingToRemove = addedBlockchainsState.value.contains(blockchain)
- val isAddedOnMainScreen = blockchainsAddedOnMainScreen.contains(blockchain)
- val isTokenWithSameBlockchainFound = addedTokens.any { it.blockchain == blockchain }
- val analyticsCurrencyTypeParam = AnalyticsParam.CurrencyType.Blockchain(blockchain)
-
- if (isTryingToRemove) {
- if (isTokenWithSameBlockchainFound) {
- store.dispatchDialogShow(
- WalletDialog.TokensAreLinkedDialog(
- currencyTitle = blockchain.name,
- currencySymbol = blockchain.currency,
- ),
- )
- } else if (isAddedOnMainScreen) {
- store.dispatchDialogShow(
- WalletDialog.RemoveWalletDialog(
- currencyTitle = blockchain.name,
- onOk = {
- analyticsCurrencyTypeParam.sendOn()
- addedBlockchainsState.removeAndNotify(blockchain)
- },
- ),
- )
- } else {
- analyticsCurrencyTypeParam.sendOff()
- addedBlockchainsState.removeAndNotify(blockchain)
- }
- } else {
- analyticsCurrencyTypeParam.sendOn()
- addedBlockchainsState.addAndNotify(blockchain)
- }
-}
-
-private fun toggleToken(
- token: TokenWithBlockchain,
- tokensAddedOnMainScreen: List,
- addedTokensState: MutableState>,
- tokensState: TokensState,
-) {
- val isTryingToRemove = addedTokensState.value.contains(token)
- val isAddedOnMainScreen = tokensAddedOnMainScreen.contains(token)
- val isUnsupportedToken = !tokensState.canHandleToken(token)
- val analyticsCurrencyTypeParam = AnalyticsParam.CurrencyType.Token(token.token)
-
- if (isTryingToRemove) {
- if (isAddedOnMainScreen) {
- store.dispatchDialogShow(
- WalletDialog.RemoveWalletDialog(
- currencyTitle = token.token.name,
- onOk = {
- analyticsCurrencyTypeParam.sendOff()
- addedTokensState.removeAndNotify(token)
- },
- ),
- )
- } else {
- analyticsCurrencyTypeParam.sendOff()
- addedTokensState.removeAndNotify(token)
- }
- } else {
- if (isUnsupportedToken) {
- store.dispatchDialogShow(
- AppDialog.SimpleOkDialogRes(
- headerId = R.string.common_warning,
- messageId = R.string.alert_manage_tokens_unsupported_message,
- ),
- )
- } else {
- analyticsCurrencyTypeParam.sendOn()
- addedTokensState.addAndNotify(token)
- }
- }
-}
-
-private fun AnalyticsParam.CurrencyType.sendOn() {
- Analytics.send(ManageTokens.TokenSwitcherChanged(this, AnalyticsParam.OnOffState.On))
-}
-
-private fun AnalyticsParam.CurrencyType.sendOff() {
- Analytics.send(ManageTokens.TokenSwitcherChanged(this, AnalyticsParam.OnOffState.Off))
-}
-
-@Composable
-fun SaveChangesButton(keyboardState: Keyboard, onSaveChanges: () -> Unit) {
- PrimaryButton(
- modifier = Modifier
- .padding(bottom = keyboardState.height)
- .padding(horizontal = TangemTheme.dimens.spacing16)
- .fillMaxWidth(),
- text = stringResource(id = R.string.common_save_changes),
- onClick = onSaveChanges,
- )
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrenciesWarning.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrenciesWarning.kt
deleted file mode 100644
index b4b94b8edb..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrenciesWarning.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.tangem.tap.features.tokens.legacy.ui.compose
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.AnnotatedString
-import androidx.compose.ui.text.SpanStyle
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import com.tangem.wallet.R
-
-@Suppress("MagicNumber")
-@Composable
-fun CurrenciesWarning() {
- Box(
- contentAlignment = Alignment.Center,
- modifier = Modifier
- .padding(16.dp)
- .background(
- color = Color(0xFFF2F2F2),
- shape = RoundedCornerShape(10.dp),
- ),
- ) {
- val warning = stringResource(id = R.string.alert_manage_tokens_addresses_message)
- val end = warning.indexOf(" ")
- val spanStyles = listOf(
- AnnotatedString.Range(
- SpanStyle(fontWeight = FontWeight.Bold),
- start = 0,
- end = end,
- ),
- )
- Text(
- text = AnnotatedString(text = warning, spanStyles = spanStyles),
- textAlign = TextAlign.Start,
- color = Color(0xFF848488),
- modifier = Modifier.padding(
- top = 8.dp,
- bottom = 8.dp,
- start = 16.dp,
- end = 16.dp,
- ),
- fontSize = 13.sp,
- fontWeight = FontWeight.Normal,
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrencyPlaceholderIcon.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrencyPlaceholderIcon.kt
deleted file mode 100644
index 43a2885497..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/CurrencyPlaceholderIcon.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.tangem.tap.features.tokens.legacy.ui.compose
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-
-@Composable
-fun CurrencyPlaceholderIcon(id: String) {
- val letterColor: Color = Color.White
- val circleColor: Color = Color.Black
-
- Box(
- contentAlignment = Alignment.Center,
- modifier = Modifier
- .background(circleColor, shape = CircleShape),
- ) {
- Text(
- text = id.firstOrNull()?.titlecase() ?: "",
- textAlign = TextAlign.Center,
- color = letterColor,
- modifier = Modifier.padding(4.dp),
- fontSize = 20.sp,
- fontWeight = FontWeight.Bold,
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/ListOfCurrencies.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/ListOfCurrencies.kt
deleted file mode 100644
index 4f067daa9d..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/ListOfCurrencies.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.tangem.tap.features.tokens.legacy.ui.compose
-
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.itemsIndexed
-import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import com.tangem.blockchain.common.Blockchain
-import com.tangem.tap.common.compose.extensions.HideKeyboardOnScroll
-import com.tangem.tap.common.compose.extensions.OnBottomReached
-import com.tangem.tap.domain.tokens.Currency
-import com.tangem.tap.features.tokens.legacy.redux.ContractAddress
-import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain
-import com.tangem.tap.features.tokens.legacy.ui.compose.currencyItem.CurrencyItem
-
-@Suppress("LongParameterList")
-@Composable
-fun ListOfCurrencies(
- header: @Composable () -> Unit,
- currencies: List,
- addedTokens: List,
- addedBlockchains: List,
- allowToAdd: Boolean,
- onAddCurrencyToggle: (Currency, TokenWithBlockchain?) -> Unit,
- onNetworkItemClick: (ContractAddress) -> Unit,
- onLoadMore: () -> Unit,
-) {
- val expandedCurrencies = remember { mutableStateOf(listOf("")) }
-
- val onCurrencyClick = { currencyId: String ->
- val mutableList = expandedCurrencies.value.toMutableList()
- if (mutableList.contains(currencyId)) {
- mutableList.remove(currencyId)
- } else {
- mutableList.add(currencyId)
- }
- expandedCurrencies.value = mutableList
- }
-
- val listState = rememberLazyListState()
- listState.HideKeyboardOnScroll()
- listState.OnBottomReached(loadMoreThreshold = 40) { onLoadMore() }
-
- LazyColumn(
- state = listState,
- modifier = Modifier
- .fillMaxSize(),
- contentPadding = PaddingValues(bottom = 90.dp),
- verticalArrangement = Arrangement.spacedBy(12.dp),
- ) {
- item { header() }
- itemsIndexed(currencies) { _, currency ->
- CurrencyItem(
- currency = currency,
- addedTokens = addedTokens,
- addedBlockchains = addedBlockchains,
- allowToAdd = allowToAdd,
- isExpanded = expandedCurrencies.value.contains(currency.id),
- onCurrencyClick = { onCurrencyClick(currency.id) },
- onAddCurrencyToggle = onAddCurrencyToggle,
- onNetworkItemClick = onNetworkItemClick,
- )
- }
- }
-}
-
-val Currency.fullName: String
- get() = "${this.name} (${this.symbol})"
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyExpandedContent.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyExpandedContent.kt
deleted file mode 100644
index 9ea93f61d6..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyExpandedContent.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.tangem.tap.features.tokens.legacy.ui.compose.currencyItem
-
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.expandVertically
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.shrinkVertically
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import com.tangem.blockchain.common.Blockchain
-import com.tangem.tap.domain.tokens.Contract
-import com.tangem.tap.domain.tokens.Currency
-import com.tangem.tap.features.tokens.legacy.redux.ContractAddress
-import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain
-
-@Suppress("LongParameterList")
-@Composable
-fun CurrencyExpandedContent(
- currency: Currency,
- addedTokens: List,
- addedBlockchains: List,
- allowToAdd: Boolean,
- isExpanded: Boolean,
- onAddCurrencyToggle: (Currency, TokenWithBlockchain?) -> Unit,
- onNetworkItemClick: (ContractAddress) -> Unit,
-) {
- AnimatedVisibility(
- visible = isExpanded,
- enter = fadeIn() + expandVertically(),
- exit = fadeOut() + shrinkVertically(),
- ) {
- val blockchains = currency.contracts.map { it.blockchain }
- Column(modifier = Modifier.fillMaxWidth()) {
- blockchains.mapIndexed { index, blockchain ->
- val currencyContract = currency.contracts
- .firstOrNull { it.blockchain == blockchain }
- ?: return@mapIndexed
-
- val added = if (currencyContract.address != null) {
- addedTokens.any(currencyContract::isInclude)
- } else {
- addedBlockchains.contains(blockchain)
- }
- NetworkItem(
- currency = currency,
- contract = currencyContract,
- blockchain = blockchain,
- allowToAdd = allowToAdd,
- added = added,
- index = index,
- size = blockchains.size,
- onAddCurrencyToggle = onAddCurrencyToggle,
- onNetworkItemClick = onNetworkItemClick,
- )
- }
- }
- }
-}
-
-private fun Contract.isInclude(addedToken: TokenWithBlockchain): Boolean =
- address == addedToken.token.contractAddress && blockchain == addedToken.blockchain
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyItem.kt
deleted file mode 100644
index a15c17000f..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyItem.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.tangem.tap.features.tokens.legacy.ui.compose.currencyItem
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.runtime.Composable
-import com.tangem.blockchain.common.Blockchain
-import com.tangem.tap.domain.tokens.Currency
-import com.tangem.tap.features.tokens.legacy.redux.ContractAddress
-import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain
-
-@Suppress("LongParameterList")
-@Composable
-fun CurrencyItem(
- currency: Currency,
- addedTokens: List,
- addedBlockchains: List,
- allowToAdd: Boolean,
- isExpanded: Boolean,
- onCurrencyClick: () -> Unit,
- onAddCurrencyToggle: (Currency, TokenWithBlockchain?) -> Unit,
- onNetworkItemClick: (ContractAddress) -> Unit,
-) {
- Column {
- CurrencyItemHeader(
- currency = currency,
- addedTokens = addedTokens,
- addedBlockchains = addedBlockchains,
- isExpanded = isExpanded,
- onCurrencyClick = onCurrencyClick,
- )
- CurrencyExpandedContent(
- currency = currency,
- addedTokens = addedTokens,
- addedBlockchains = addedBlockchains,
- allowToAdd = allowToAdd,
- isExpanded = isExpanded,
- onAddCurrencyToggle = onAddCurrencyToggle,
- onNetworkItemClick = onNetworkItemClick,
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyItemHeader.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyItemHeader.kt
deleted file mode 100644
index bf5fc63457..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/CurrencyItemHeader.kt
+++ /dev/null
@@ -1,213 +0,0 @@
-package com.tangem.tap.features.tokens.legacy.ui.compose.currencyItem
-
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.interaction.MutableInteractionSource
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.heightIn
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
-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.res.painterResource
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import coil.compose.SubcomposeAsyncImage
-import coil.request.ImageRequest
-import com.tangem.blockchain.common.Blockchain
-import com.tangem.core.ui.extensions.getActiveIconRes
-import com.tangem.domain.common.extensions.fromNetworkId
-import com.tangem.tap.common.extensions.getGreyedOutIconRes
-import com.tangem.tap.domain.tokens.Contract
-import com.tangem.tap.domain.tokens.Currency
-import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain
-import com.tangem.tap.features.tokens.legacy.ui.compose.CurrencyPlaceholderIcon
-import com.tangem.tap.features.tokens.legacy.ui.compose.fullName
-import com.tangem.wallet.R
-
-@Suppress("LongMethod", "MagicNumber")
-@Composable
-fun CurrencyItemHeader(
- currency: Currency,
- addedTokens: List,
- addedBlockchains: List,
- isExpanded: Boolean,
- onCurrencyClick: () -> Unit,
-) {
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .heightIn(min = 62.dp)
- .clickable(
- interactionSource = remember { MutableInteractionSource() },
- indication = null,
- onClick = onCurrencyClick,
- ),
- ) {
- Box(
- modifier = Modifier
- .padding(horizontal = 16.dp)
- .align(Alignment.CenterVertically)
- .clip(RoundedCornerShape(6.dp)),
- ) {
- SubcomposeAsyncImage(
- modifier = Modifier
- .size(46.dp),
- model = ImageRequest.Builder(LocalContext.current)
- .data(currency.iconUrl)
- .crossfade(true)
- .build(),
- contentDescription = currency.id,
- loading = { CurrencyPlaceholderIcon(currency.id) },
- error = { CurrencyPlaceholderIcon(currency.id) },
- )
- }
-
- Column(
- modifier = Modifier
- .weight(1f)
- .align(Alignment.CenterVertically),
- ) {
- Text(
- text = currency.fullName,
- fontSize = 17.sp,
- fontWeight = FontWeight.Normal,
- color = Color(0xFF1C1C1E),
- )
- Spacer(modifier = Modifier.size(6.dp))
-
- Box(
- modifier = Modifier
- .fillMaxWidth()
- .height(20.dp),
- ) {
- if (isExpanded) {
- Text(
- modifier = Modifier.align(Alignment.TopStart),
- text = stringResource(id = R.string.currency_subtitle_expanded),
- fontSize = 13.sp,
- fontWeight = FontWeight.Normal,
- color = Color(0xFF8E8E93),
- )
- } else {
- NetworksRow(
- currency = currency,
- addedTokens = addedTokens,
- addedBlockchains = addedBlockchains,
- )
- }
- }
- }
-
- val expandCollapseArrow = if (isExpanded) R.drawable.ic_arrow_extended else R.drawable.ic_arrow_collapsed
- Image(
- painter = painterResource(id = expandCollapseArrow),
- contentDescription = null,
- Modifier
- .padding(20.dp)
- .align(Alignment.CenterVertically),
- )
- }
-}
-
-@Composable
-private fun NetworksRow(
- currency: Currency,
- addedTokens: List,
- addedBlockchains: List,
-) {
- Row {
- if (currency.contracts.isNotEmpty()) {
- currency.contracts.map { contract ->
- if (contract.address == null) {
- BlockchainNetworkItem(
- blockchain = contract.blockchain,
- isMainNetwork = true,
- addedBlockchains = addedBlockchains,
- )
- } else {
- val isAdded = addedTokens.any(contract::isInclude)
- val iconResId = if (isAdded) {
- getActiveIconRes(contract.blockchain.id)
- } else {
- contract.blockchain.getGreyedOutIconRes()
- }
- Image(
- modifier = Modifier
- .size(20.dp),
- painter = painterResource(id = iconResId),
- contentDescription = null,
- )
- Spacer(Modifier.size(5.dp))
- }
- }
- } else {
- BlockchainNetworkItem(
- blockchain = Blockchain.fromNetworkId(currency.id),
- isMainNetwork = false,
- addedBlockchains = addedBlockchains,
- )
- }
- }
-}
-
-@Suppress("MagicNumber")
-@Composable
-private fun BlockchainNetworkItem(
- blockchain: Blockchain?,
- isMainNetwork: Boolean,
- addedBlockchains: List,
-) {
- val added = addedBlockchains.contains(blockchain)
- val icon = if (added) blockchain?.let { getActiveIconRes(it.id) } else blockchain?.getGreyedOutIconRes()
- if (icon != null) {
- Box(
- Modifier
- .size(20.dp),
- ) {
- Image(
- painter = painterResource(id = icon),
- contentDescription = null,
- Modifier
- .size(20.dp),
- )
- if (isMainNetwork) {
- Box(
- modifier = Modifier
- .align(Alignment.TopEnd)
- .size(7.dp)
- .clip(CircleShape)
- .background(Color.White),
- ) {
- Box(
- modifier = Modifier
- .align(Alignment.Center)
- .size(5.dp)
- .clip(CircleShape)
- .background(Color(0xFF1ACE80)),
- )
- }
- }
- }
- Spacer(modifier = Modifier.size(5.dp))
- }
-}
-
-private fun Contract.isInclude(addedToken: TokenWithBlockchain): Boolean =
- address == addedToken.token.contractAddress && blockchain == addedToken.blockchain
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/NetworkItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/NetworkItem.kt
deleted file mode 100644
index 4d7eab3fb6..0000000000
--- a/app/src/main/java/com/tangem/tap/features/tokens/legacy/ui/compose/currencyItem/NetworkItem.kt
+++ /dev/null
@@ -1,186 +0,0 @@
-package com.tangem.tap.features.tokens.legacy.ui.compose.currencyItem
-
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.background
-import androidx.compose.foundation.combinedClickable
-import androidx.compose.foundation.interaction.MutableInteractionSource
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.heightIn
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material.Switch
-import androidx.compose.material.SwitchDefaults
-import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
-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.text.AnnotatedString
-import androidx.compose.ui.text.SpanStyle
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import coil.compose.SubcomposeAsyncImage
-import com.tangem.blockchain.common.Blockchain
-import com.tangem.blockchain.common.Token
-import com.tangem.core.ui.extensions.getActiveIconRes
-import com.tangem.tap.common.extensions.fullNameWithoutTestnet
-import com.tangem.tap.common.extensions.getGreyedOutIconRes
-import com.tangem.tap.common.extensions.getNetworkName
-import com.tangem.tap.domain.tokens.Contract
-import com.tangem.tap.domain.tokens.Currency
-import com.tangem.tap.features.tokens.impl.presentation.ui.NetworkItemArrow
-import com.tangem.tap.features.tokens.legacy.redux.ContractAddress
-import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain
-import com.tangem.tap.features.tokens.legacy.ui.compose.CurrencyPlaceholderIcon
-
-@Suppress("LongParameterList", "LongMethod", "MagicNumber")
-@OptIn(ExperimentalFoundationApi::class)
-@Composable
-fun NetworkItem(
- currency: Currency,
- contract: Contract,
- blockchain: Blockchain,
- allowToAdd: Boolean,
- added: Boolean,
- index: Int,
- size: Int,
- onAddCurrencyToggle: (Currency, TokenWithBlockchain?) -> Unit,
- onNetworkItemClick: (ContractAddress) -> Unit,
-) {
- val rowHeight = 53.dp
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .heightIn(rowHeight)
- .combinedClickable(
- enabled = allowToAdd,
- onLongClick = {
- contract.address?.let { onNetworkItemClick(it) }
- },
- onClick = {},
- indication = null,
- interactionSource = remember { MutableInteractionSource() },
- ),
- ) {
- Box(
- Modifier
- .width(78.dp)
- .padding(start = 38.dp),
- ) {
- NetworkItemArrow(
- itemHeight = rowHeight,
- isLastItem = index == size - 1,
- )
- }
- Box(
- modifier = Modifier
- .align(Alignment.CenterVertically),
- ) {
- SubcomposeAsyncImage(
- model = if (added) getActiveIconRes(blockchain.id) else blockchain.getGreyedOutIconRes(),
- contentDescription = blockchain.fullName,
- loading = { CurrencyPlaceholderIcon(blockchain.id) },
- error = { CurrencyPlaceholderIcon(blockchain.id) },
- modifier = Modifier
- .size(20.dp),
- )
- if (contract.address == null) {
- Box(
- modifier = Modifier
- .align(Alignment.TopEnd)
- .size(7.dp)
- .clip(CircleShape)
- .background(Color.White),
- ) {
- Box(
- modifier = Modifier
- .align(Alignment.Center)
- .size(5.dp)
- .clip(CircleShape)
- .background(Color(0xFF1ACE80)),
- )
- }
- }
- }
- Spacer(Modifier.width(6.dp))
- Text(
- modifier = Modifier
- .weight(1f)
- .align(Alignment.CenterVertically),
- text = prepareNetworkNameSpannableText(
- blockchain = blockchain,
- contractAddress = contract.address,
- ),
- fontWeight = FontWeight.SemiBold,
- fontSize = 13.sp,
- color = if (added) Color.Black else Color(0xFF848488),
- )
-
- if (allowToAdd) {
- val token = if (contract.address != null) {
- Token(
- id = currency.id,
- name = currency.name,
- symbol = currency.symbol,
- contractAddress = contract.address,
- decimals = contract.decimalCount!!,
- )
- } else {
- null
- }
- val tokenWithBlockchain = token?.let { TokenWithBlockchain(it, contract.blockchain) }
-
- val currencyToSave = if (contract.address == null) {
- currency.copy(id = contract.networkId)
- } else {
- currency
- }
-
- Switch(
- modifier = Modifier
- .fillMaxHeight()
- .padding(start = 16.dp, end = 16.dp),
- checked = added,
- onCheckedChange = { onAddCurrencyToggle(currencyToSave, tokenWithBlockchain) },
- colors = SwitchDefaults.colors(
- checkedThumbColor = Color(0xFF1ACE80),
- ),
- )
- }
- }
-}
-
-@Suppress("MagicNumber")
-@Composable
-private fun prepareNetworkNameSpannableText(blockchain: Blockchain, contractAddress: String?): AnnotatedString {
- val blockchainName = blockchain.fullNameWithoutTestnet.uppercase()
- val additionalText =
- if (contractAddress == null) "MAIN" else blockchain.getNetworkName().uppercase()
-
- val text = "$blockchainName $additionalText"
-
- val startOfAdditionalText =
- if (additionalText.isNotBlank()) text.indexOf(additionalText) else text.length
-
- val spanStyles = listOf(
- AnnotatedString.Range(
- SpanStyle(
- fontWeight = FontWeight.Normal,
- color = if (contractAddress != null) Color(0xFF8E8E93) else Color(0xFF1ACE80),
- ),
- start = startOfAdditionalText,
- end = text.length,
- ),
- )
- return AnnotatedString(text = text, spanStyles = spanStyles)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt
index cabb464853..bc5e960649 100644
--- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt
+++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt
@@ -2,7 +2,9 @@ package com.tangem.tap.features.wallet.redux.middlewares
import com.tangem.common.extensions.guard
import com.tangem.core.analytics.Analytics
-import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse
+import com.tangem.data.source.preferences.model.DataSourceCurrency
+import com.tangem.data.source.preferences.model.DataSourceFiatCurrency
+import com.tangem.data.source.preferences.storage.FiatCurrenciesPrefStorage
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.MainScreen
import com.tangem.tap.common.entities.FiatCurrency
@@ -14,7 +16,6 @@ import com.tangem.tap.features.wallet.domain.WalletRepository
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.features.walletSelector.redux.WalletSelectorAction
-import com.tangem.tap.persistence.FiatCurrenciesPrefStorage
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.userWalletsListManager
@@ -47,8 +48,10 @@ class AppCurrencyMiddleware(
scope.launch {
runCatching { walletRepository.getCurrencyList() }
- .onSuccess {
- val currenciesList = it.currencies
+ .onSuccess { response ->
+ val currenciesList = response.currencies
+ .map { with(it) { DataSourceCurrency(id, code, name, rateBTC, unit, type) } }
+
if (currenciesList.isNotEmpty() && currenciesList.toSet() != storedFiatCurrencies.toSet()) {
fiatCurrenciesPrefStorage.save(currenciesList)
store.dispatchDialogShow(
@@ -64,7 +67,9 @@ class AppCurrencyMiddleware(
private fun selectCurrency(action: WalletAction.AppCurrencyAction.SelectAppCurrency) {
Analytics.send(MainScreen.MainCurrencyChanged(AnalyticsParam.CurrencyType.FiatCurrency(action.fiatCurrency)))
- fiatCurrenciesPrefStorage.saveAppCurrency(action.fiatCurrency)
+ fiatCurrenciesPrefStorage.saveAppCurrency(
+ with(action.fiatCurrency) { DataSourceFiatCurrency(code, name, symbol) },
+ )
store.dispatch(GlobalAction.ChangeAppCurrency(action.fiatCurrency))
store.dispatch(DetailsAction.ChangeAppCurrency(action.fiatCurrency))
store.dispatch(WalletSelectorAction.ChangeAppCurrency(action.fiatCurrency))
@@ -77,7 +82,7 @@ class AppCurrencyMiddleware(
}
}
- private fun List.mapToUiModel(): List {
+ private fun List.mapToUiModel(): List {
return this.map {
FiatCurrency(
code = it.code,
diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt
index 3ade28d8db..fa6759eb26 100644
--- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt
+++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt
@@ -31,7 +31,7 @@ class WarningsMiddleware {
is WalletAction.Warnings.CheckIfNeeded -> {
showCardWarningsIfNeeded(globalState)
val readyToShow = preferencesStorage.appRatingLaunchObserver.isReadyToShow()
- if (readyToShow) addWarningMessage(WarningMessagesManager.appRatingWarning(), true)
+ if (readyToShow) addWarningMessage(warning = WarningMessagesManager.appRatingWarning, autoUpdate = true)
}
is WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline -> checkHashesCountOnline()
is WalletAction.Warnings.CheckHashesCount.SaveCardId -> {
@@ -69,7 +69,7 @@ class WarningsMiddleware {
preferencesStorage.appRatingLaunchObserver.foundWalletWithFunds()
}
if (preferencesStorage.appRatingLaunchObserver.isReadyToShow()) {
- addWarningMessage(WarningMessagesManager.appRatingWarning(), true)
+ addWarningMessage(WarningMessagesManager.appRatingWarning, true)
}
}
@@ -78,21 +78,21 @@ class WarningsMiddleware {
val card = scanResponse.card
globalState.warningManager?.removeWarnings(WarningMessage.Origin.Local)
if (card.isTestCard) {
- addWarningMessage(WarningMessagesManager.testCardWarning(), autoUpdate = true)
+ addWarningMessage(WarningMessagesManager.testCardWarning, autoUpdate = true)
return@let
}
showWarningLowRemainingSignaturesIfNeeded(card)
if (card.firmwareVersion.type != FirmwareVersion.FirmwareType.Release) {
- addWarningMessage(WarningMessagesManager.devCardWarning())
+ addWarningMessage(WarningMessagesManager.devCardWarning)
} else if (!preferencesStorage.usedCardsPrefStorage.wasScanned(card.cardId)) {
checkIfWarningNeeded(scanResponse)?.let { warning -> addWarningMessage(warning) }
}
if (card.firmwareVersion.type == FirmwareVersion.FirmwareType.Release && !globalState.cardVerifiedOnline) {
- addWarningMessage(WarningMessagesManager.onlineVerificationFailed())
+ addWarningMessage(WarningMessagesManager.onlineVerificationFailed)
}
if (scanResponse.isDemoCard()) {
- addWarningMessage(WarningMessagesManager.demoCardWarning())
+ addWarningMessage(WarningMessagesManager.demoCardWarning)
}
setWarningMessages()
}
@@ -113,7 +113,7 @@ class WarningsMiddleware {
if (scanResponse.cardTypesResolver.isMultiwalletAllowed()) {
val isBackupForbidden = with(scanResponse.card.settings) { !(isBackupAllowed || isHDWalletAllowed) }
return if (scanResponse.card.hasSignedHashes() && isBackupForbidden) {
- WarningMessagesManager.signedHashesMultiWalletWarning()
+ WarningMessagesManager.signedHashesMultiWalletWarning
} else {
store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId)
null
@@ -123,7 +123,7 @@ class WarningsMiddleware {
val validator = store.state.walletState.walletManagers.firstOrNull() as? SignatureCountValidator
return if (validator == null) {
if (scanResponse.card.hasSignedHashes()) {
- WarningMessagesManager.alreadySignedHashesWarning()
+ WarningMessagesManager.alreadySignedHashesWarning
} else {
store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId)
null
@@ -161,9 +161,9 @@ class WarningsMiddleware {
}
is SimpleResult.Failure ->
if (result.error is BlockchainSdkError.SignatureCountNotMatched) {
- addWarningMessage(WarningMessagesManager.alreadySignedHashesWarning(), true)
+ addWarningMessage(WarningMessagesManager.alreadySignedHashesWarning, true)
} else if (signedHashes > 0) {
- addWarningMessage(WarningMessagesManager.alreadySignedHashesWarning(), true)
+ addWarningMessage(WarningMessagesManager.alreadySignedHashesWarning, true)
}
null -> Unit
}
diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt
index 4ea69fa30f..afee65593c 100644
--- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt
+++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt
@@ -1,7 +1,11 @@
package com.tangem.tap.features.wallet.ui
import android.os.Bundle
-import android.view.*
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.annotation.ColorRes
@@ -27,8 +31,16 @@ import com.tangem.tap.common.SnackbarHandler
import com.tangem.tap.common.TestActions
import com.tangem.tap.common.analytics.events.DetailsScreen
import com.tangem.tap.common.analytics.events.Token
-import com.tangem.tap.common.extensions.*
+import com.tangem.tap.common.extensions.appendIfNotNull
+import com.tangem.tap.common.extensions.beginDelayedTransition
+import com.tangem.tap.common.extensions.fitChipsByGroupWidth
+import com.tangem.tap.common.extensions.getColor
+import com.tangem.tap.common.extensions.getString
+import com.tangem.tap.common.extensions.hide
+import com.tangem.tap.common.extensions.show
+import com.tangem.tap.common.extensions.toQrCode
import com.tangem.tap.common.recyclerView.SpaceItemDecoration
+import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.common.utils.SafeStoreSubscriber
import com.tangem.tap.domain.model.WalletDataModel
@@ -45,7 +57,15 @@ import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter
import com.tangem.tap.features.wallet.ui.adapters.WalletDetailWarningMessagesAdapter
import com.tangem.tap.features.wallet.ui.images.load
import com.tangem.tap.features.wallet.ui.test.TestWallet
-import com.tangem.tap.features.wallet.ui.utils.*
+import com.tangem.tap.features.wallet.ui.utils.assembleWarnings
+import com.tangem.tap.features.wallet.ui.utils.getAvailableActions
+import com.tangem.tap.features.wallet.ui.utils.getFormattedAmount
+import com.tangem.tap.features.wallet.ui.utils.getFormattedFiatAmount
+import com.tangem.tap.features.wallet.ui.utils.isAvailableToBuy
+import com.tangem.tap.features.wallet.ui.utils.isAvailableToSell
+import com.tangem.tap.features.wallet.ui.utils.isAvailableToSwap
+import com.tangem.tap.features.wallet.ui.utils.mainButton
+import com.tangem.tap.features.wallet.ui.utils.shouldShowMultipleAddress
import com.tangem.tap.store
import com.tangem.tap.userWalletsListManagerSafe
import com.tangem.tap.walletCurrenciesManager
@@ -63,9 +83,7 @@ import javax.inject.Inject
*/
@Suppress("LargeClass", "MagicNumber")
@AndroidEntryPoint
-class WalletDetailsFragment :
- Fragment(R.layout.fragment_wallet_details),
- SafeStoreSubscriber {
+class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), SafeStoreSubscriber {
@Inject
lateinit var swapInteractor: SwapInteractor
@@ -157,18 +175,6 @@ class WalletDetailsFragment :
exitTransition = inflater.inflateTransition(R.transition.fade)
}
- override fun onStart() {
- super.onStart()
- store.subscribe(this) { state ->
- state.select { it.walletState }
- }
- }
-
- override fun onStop() {
- super.onStop()
- store.unsubscribe(this)
- }
-
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as? AppCompatActivity)?.setSupportActionBar(binding.toolbar)
@@ -180,6 +186,16 @@ class WalletDetailsFragment :
setupTestActionButton()
}
+ override fun onStart() {
+ super.onStart()
+ store.subscribe(this) { state -> state.select(AppState::walletState) }
+ }
+
+ override fun onStop() {
+ super.onStop()
+ store.unsubscribe(this)
+ }
+
override fun onDestroyView() {
super.onDestroyView()
clearWatchers()
@@ -198,18 +214,13 @@ class WalletDetailsFragment :
rvWarningMessages.addItemDecoration(SpaceItemDecoration.vertical(8f))
}
- private fun setupButtons() = with(binding) {
- rowButtons.onSendClick = {
- store.dispatch(WalletAction.Send())
- }
+ private fun setupButtons() {
+ binding.rowButtons.onSendClick = { store.dispatch(WalletAction.Send()) }
}
private fun setupTestActionButton() {
view?.findViewById(R.id.l_balance)?.let { view ->
- TestActions.initFor(
- view = view,
- actions = TestWallet.solanaRentExemptWarning(),
- )
+ TestActions.initFor(view = view, actions = TestWallet.solanaRentExemptWarning())
}
}
@@ -223,10 +234,8 @@ class WalletDetailsFragment :
private fun updateViewMeasurements() {
val tvFiatAmount = binding.lWalletDetails.lBalance.tvFiatAmount
- val paddingStart = when (tvFiatAmount.text) {
- UNKNOWN_AMOUNT_SIGN -> 16f
- else -> 12f
- }
+ val paddingStart = if (tvFiatAmount.text == UNKNOWN_AMOUNT_SIGN) 16f else 12f
+
tvFiatAmount.setPadding(
tvFiatAmount.dpToPx(paddingStart).toInt(),
tvFiatAmount.paddingTop,
@@ -259,12 +268,11 @@ class WalletDetailsFragment :
}
binding.srlWalletDetails.isRefreshing = true
lifecycleScope.launch(Dispatchers.Default) {
- walletCurrenciesManager.update(selectedUserWallet, walletData.currency)
- .doOnResult {
- withMainContext {
- binding.srlWalletDetails.isRefreshing = false
- }
+ walletCurrenciesManager.update(selectedUserWallet, walletData.currency).doOnResult {
+ withMainContext {
+ binding.srlWalletDetails.isRefreshing = false
}
+ }
}
}
}
@@ -272,14 +280,11 @@ class WalletDetailsFragment :
private fun setupCopyAndShareButtons(walletAddress: String?) {
binding.lWalletDetails.btnCopy.setOnClickListener {
- if (walletAddress != null) {
- store.dispatch(WalletAction.CopyAddress(walletAddress, requireContext()))
- }
+ if (walletAddress != null) store.dispatch(WalletAction.CopyAddress(walletAddress, requireContext()))
}
+
binding.lWalletDetails.btnShare.setOnClickListener {
- if (walletAddress != null) {
- store.dispatch(WalletAction.ShareAddress(walletAddress, requireContext()))
- }
+ if (walletAddress != null) store.dispatch(WalletAction.ShareAddress(walletAddress, requireContext()))
}
}
@@ -339,9 +344,7 @@ class WalletDetailsFragment :
}
private fun showPendingTransactionsIfPresent(pendingTransactions: List) {
- val knownTransactions = pendingTransactions.filterNot {
- it.type == PendingTransactionType.Unknown
- }
+ val knownTransactions = pendingTransactions.filterNot { it.type == PendingTransactionType.Unknown }
pendingTransactionAdapter.submitList(knownTransactions)
binding.rvPendingTransaction.show(knownTransactions.isNotEmpty())
}
@@ -387,8 +390,7 @@ class WalletDetailsFragment :
chipGroupAddressType.show()
chipGroupAddressType.fitChipsByGroupWidth()
- val checkedId =
- MultipleAddressUiHelper.typeToId(selectedAddress.type)
+ val checkedId = MultipleAddressUiHelper.typeToId(selectedAddress.type)
if (checkedId != View.NO_ID) chipGroupAddressType.check(checkedId)
chipGroupAddressType.setOnCheckedChangeListener { _, checkedId ->
@@ -443,11 +445,14 @@ class WalletDetailsFragment :
-> {
lBalance.tvStatus.setVerifiedBalanceStatus(R.string.wallet_balance_verified)
}
- else -> {
+
+ is WalletDataModel.TransactionInProgress -> {
lBalance.tvStatus.setWarningStatus(R.string.wallet_balance_tx_in_progress)
+ showPendingTransactionsIfPresent(status.pendingTransactions)
}
+
+ else -> Unit
}
- showPendingTransactionsIfPresent(status.pendingTransactions)
}
is WalletDataModel.Unreachable -> {
lBalanceError.root.hide()
@@ -470,10 +475,12 @@ class WalletDetailsFragment :
walletData.currency.currencySymbol,
)
}
- else -> {}
+
+ else -> Unit
}
}
+ @Deprecated("Deprecated in Java")
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_remove -> {
@@ -483,10 +490,15 @@ class WalletDetailsFragment :
}
false
}
+
else -> super.onOptionsItemSelected(item)
}
}
+ @Deprecated(
+ message = "Deprecated in Java",
+ replaceWith = ReplaceWith("inflater.inflate(R.menu.menu_wallet_details, menu)", "com.tangem.wallet.R"),
+ )
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_wallet_details, menu)
}
diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt
index ce2e4ea085..ded1be23f3 100644
--- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt
+++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt
@@ -105,14 +105,12 @@ internal class WalletViewModel @Inject constructor(
private fun bootstrapSelectedWalletStoresChanges(manager: UserWalletsListManager) {
observeWalletStoresUpdatesJob = manager.selectedUserWallet
.map { it.walletId }
- .flatMapLatest { selectedUserWalletId ->
- walletStoresManager.get(selectedUserWalletId)
- }
+ .flatMapLatest(walletStoresManager::get)
.debounce { walletStores ->
if (walletStores.isNotEmpty()) WALLET_STORES_DEBOUNCE_TIMEOUT else 0
}
.onEach { walletStores ->
- store.dispatch(WalletAction.WalletStoresChanged(walletStores))
+ store.dispatchOnMain(WalletAction.WalletStoresChanged(walletStores))
}
.launchIn(viewModelScope)
}
diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SignedHashesWarningDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SignedHashesWarningDialog.kt
index b9996b1c18..c44801d9c8 100644
--- a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SignedHashesWarningDialog.kt
+++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/SignedHashesWarningDialog.kt
@@ -16,9 +16,7 @@ object SignedHashesWarningDialog {
setPositiveButton(R.string.common_understand) { _, _ ->
store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId)
store.dispatch(
- GlobalAction.HideWarningMessage(
- WarningMessagesManager.signedHashesMultiWalletWarning(),
- ),
+ GlobalAction.HideWarningMessage(WarningMessagesManager.signedHashesMultiWalletWarning),
)
}
setNegativeButton(R.string.common_cancel) { _, _ -> }
diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt
index fbe46121d7..269f0ec071 100644
--- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt
+++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt
@@ -6,7 +6,6 @@ import com.badoo.mvicore.modelWatcher
import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.tap.common.analytics.events.MainScreen
-import com.tangem.tap.common.analytics.events.ManageTokens
import com.tangem.tap.common.analytics.events.Portfolio
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.extensions.getQuantityString
@@ -108,16 +107,13 @@ class MultiWalletView : WalletView() {
binding.btnAddToken.setOnClickListener {
val card = store.state.globalState.scanResponse!!.card
Analytics.send(Portfolio.ButtonManageTokens())
- store.dispatch(TokensAction.LoadCurrencies(scanResponse = store.state.globalState.scanResponse))
- store.dispatch(TokensAction.AllowToAddTokens(true))
+
store.dispatch(
- TokensAction.SetAddedCurrencies(
+ TokensAction.SetArgs.ManageAccess(
wallets = state.walletsDataFromStores,
derivationStyle = card.derivationStyle,
),
)
-
- Analytics.send(ManageTokens.ScreenOpened())
store.dispatch(NavigationAction.NavigateTo(AppScreen.AddTokens))
}
handleErrorStates(state = state, binding = binding, fragment = fragment)
@@ -175,7 +171,8 @@ class MultiWalletView : WalletView() {
fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle),
)
}
- else -> { /* no-op */ }
+
+ else -> Unit
}
}
diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt
index b41635abb0..e997860d4e 100644
--- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt
+++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt
@@ -57,4 +57,6 @@ internal sealed interface WalletSelectorAction : Action {
) : WalletSelectorAction
object CloseError : WalletSelectorAction
+
+ object ClearUserWallets : WalletSelectorAction
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt
index 675ca89cdf..53cd284846 100644
--- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt
+++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt
@@ -7,8 +7,8 @@ import com.tangem.common.doOnSuccess
import com.tangem.common.flatMap
import com.tangem.common.map
import com.tangem.core.analytics.Analytics
-import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.common.util.UserWalletId
+import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Basic
import com.tangem.tap.common.analytics.events.MyWallets
@@ -81,6 +81,12 @@ internal class WalletSelectorMiddleware {
is WalletSelectorAction.ChangeAppCurrency -> {
refreshUserWalletsAmounts()
}
+ is WalletSelectorAction.ClearUserWallets -> scope.launch {
+ clearUserWallets()
+ .doOnFailure { e ->
+ Timber.e(e, "Unable to clear user wallets")
+ }
+ }
is WalletSelectorAction.AddWallet.Success,
is WalletSelectorAction.AddWallet.Error,
is WalletSelectorAction.SelectedWalletChanged,
diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt
index 2d06b37937..2a8ace7ad3 100644
--- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt
+++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt
@@ -59,6 +59,7 @@ internal object WalletSelectorReducer {
is WalletSelectorAction.SelectWallet,
is WalletSelectorAction.RemoveWallets,
is WalletSelectorAction.RenameWallet,
+ is WalletSelectorAction.ClearUserWallets,
-> state
}
}
diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt
index 4f24d56193..ecb5291d26 100644
--- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt
+++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt
@@ -15,7 +15,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
@@ -46,11 +45,8 @@ internal class WalletSelectorBottomSheetFragment : ComposeBottomSheetFragment {
- return viewModel.state.collectAsState()
- }
+ override fun provideState(): State = viewModel.state.collectAsState()
- @OptIn(ExperimentalComposeUiApi::class)
@Composable
override fun ScreenContent(state: WalletSelectorScreenState, modifier: Modifier) {
val snackbarHostState = remember { SnackbarHostState() }
diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt
index 99024dad35..5a947b1cbd 100644
--- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt
+++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorViewModel.kt
@@ -200,13 +200,17 @@ internal class WalletSelectorViewModel : ViewModel(), StoreSubscriber WarningModel.BiometricsDisabledWarning(
- onConfirm = { /* [REDACTED_TODO_COMMENT] */ },
+ onConfirm = this::clearUserWallets,
onDismiss = this::dismissWarningDialog,
)
else -> currentDialog
}
}
+ private fun clearUserWallets() {
+ store.dispatch(WalletSelectorAction.ClearUserWallets)
+ }
+
private fun dismissWarningDialog() {
stateInternal.update { prevState ->
prevState.copy(
diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt
index ecf9cc83e9..71d7f6a253 100644
--- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt
+++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WallectSelectorScreenContent.kt
@@ -23,7 +23,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
@@ -174,8 +173,8 @@ private fun Footer(
Column(
modifier = Modifier
.padding(
- top = dimensionResource(id = R.dimen.spacing24),
- bottom = dimensionResource(id = R.dimen.spacing16),
+ top = TangemTheme.dimens.spacing24,
+ bottom = TangemTheme.dimens.spacing16,
)
.padding(horizontal = TangemTheme.dimens.spacing16)
.fillMaxWidth(),
diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeAction.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeAction.kt
index 0d248ec7af..a0484fc798 100644
--- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeAction.kt
+++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeAction.kt
@@ -18,4 +18,6 @@ internal sealed interface WelcomeAction : Action {
data class HandleIntentIfNeeded(val intent: Intent?) : WelcomeAction
object CloseError : WelcomeAction
+
+ object ClearUserWallets : WelcomeAction
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt
index 6e7da12221..5e242d9cec 100644
--- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt
+++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt
@@ -3,11 +3,14 @@ package com.tangem.tap.features.welcome.redux
import android.content.Intent
import com.tangem.common.core.TangemSdkError
import com.tangem.common.doOnFailure
+import com.tangem.common.doOnResult
import com.tangem.common.doOnSuccess
+import com.tangem.common.flatMap
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Basic
import com.tangem.tap.common.extensions.dispatchOnMain
+import com.tangem.tap.common.extensions.dispatchWithMain
import com.tangem.tap.common.extensions.onUserWalletSelected
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.navigation.AppScreen
@@ -51,6 +54,9 @@ internal class WelcomeMiddleware {
is WelcomeAction.HandleIntentIfNeeded -> {
handleInitialIntent(action.intent)
}
+ is WelcomeAction.ClearUserWallets -> {
+ clearUserWallets()
+ }
is WelcomeAction.ProceedWithBiometrics.Error,
is WelcomeAction.ProceedWithCard.Error,
is WelcomeAction.ProceedWithBiometrics.Success,
@@ -60,22 +66,31 @@ internal class WelcomeMiddleware {
}
}
- private fun proceedWithBiometrics(state: WelcomeState) {
- scope.launch {
- userWalletsListManager.unlockIfLockable()
- .doOnFailure { error ->
- Timber.e(error, "Unable to unlock user wallets with biometrics")
- store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics.Error(error))
- }
- .doOnSuccess { selectedUserWallet ->
- store.dispatchOnMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Biometric))
- store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet))
- store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics.Success)
- store.onUserWalletSelected(userWallet = selectedUserWallet)
+ private fun clearUserWallets() = scope.launch {
+ userWalletsListManager.clear()
+ .flatMap { tangemSdkManager.clearSavedUserCodes() }
+ .doOnFailure { e ->
+ Timber.e(e, "Unable to clear user wallets")
+ }
+ .doOnResult {
+ store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Home))
+ }
+ }
- intentHandler.handleWalletConnectLink(state.intent)
- }
- }
+ private fun proceedWithBiometrics(state: WelcomeState) = scope.launch {
+ userWalletsListManager.unlockIfLockable()
+ .doOnFailure { error ->
+ Timber.e(error, "Unable to unlock user wallets with biometrics")
+ store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics.Error(error))
+ }
+ .doOnSuccess { selectedUserWallet ->
+ store.dispatchOnMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Biometric))
+ store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet))
+ store.dispatchOnMain(WelcomeAction.ProceedWithBiometrics.Success)
+ store.onUserWalletSelected(userWallet = selectedUserWallet)
+
+ intentHandler.handleWalletConnectLink(state.intent)
+ }
}
private fun proceedWithCard(state: WelcomeState) = scope.launch {
diff --git a/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeViewModel.kt b/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeViewModel.kt
index e19891caa2..ad39cbe5ae 100644
--- a/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeViewModel.kt
+++ b/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeViewModel.kt
@@ -72,7 +72,7 @@ internal class WelcomeViewModel : ViewModel(), StoreSubscriber {
onDismiss = this::dismissWarning,
)
is UserWalletsListError.BiometricsAuthenticationDisabled -> WarningModel.BiometricsDisabledWarning(
- onConfirm = { /* [REDACTED_TODO_COMMENT] */ },
+ onConfirm = this::clearUserWallets,
onDismiss = this::dismissWarning,
)
else -> null
@@ -88,6 +88,10 @@ internal class WelcomeViewModel : ViewModel(), StoreSubscriber {
closeError()
}
+ private fun clearUserWallets() {
+ store.dispatch(WelcomeAction.ClearUserWallets)
+ }
+
private fun subscribeToStoreChanges() {
store.subscribe(this) { appState ->
appState.skip { old, new -> old.welcomeState == new.welcomeState }
diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/BuyExchangeService.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/BuyExchangeService.kt
index fec559a528..180f96317b 100644
--- a/app/src/main/java/com/tangem/tap/network/exchangeServices/BuyExchangeService.kt
+++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/BuyExchangeService.kt
@@ -13,7 +13,7 @@ import kotlinx.coroutines.launch
* Temporary wrapper for the buy services. Service switches based on selected product type.
* Just now - UtorgService used only for the SaltPay cards
*/
-class BuyExchangeService(
+internal class BuyExchangeService(
private val productTypeProvider: () -> ProductType?,
private val mercuryoService: MercuryoService,
private val utorgService: UtorgExchangeService,
diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoService.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoService.kt
index 8f76434576..f7725ec89a 100644
--- a/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoService.kt
+++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/mercuryo/MercuryoService.kt
@@ -11,57 +11,21 @@ import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
import com.tangem.tap.network.exchangeServices.ExchangeService
import com.tangem.tap.network.exchangeServices.ExchangeUrlBuilder
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.CopyOnWriteArrayList
/**
[REDACTED_AUTHOR]
*/
-class MercuryoService(
- private val environment: MercuryoEnvironment,
-) : ExchangeService {
+internal class MercuryoService(private val environment: MercuryoEnvironment) : ExchangeService {
private val api: MercuryoApi = environment.mercuryoApi
- private val blockchainsAvailableToBuy = mutableListOf()
- private val tokensAvailableToBy = mutableMapOf>()
+ private val blockchainsAvailableToBuy = CopyOnWriteArrayList()
+ private val tokensAvailableToBuy = ConcurrentHashMap>()
override fun featureIsSwitchedOn(): Boolean = true
- @Suppress("NestedBlockDepth")
- override suspend fun update() {
- when (val result = performRequest { api.currencies(environment.apiVersion) }) {
- is Result.Success -> {
- val response = result.data
- if (response.status == RESPONSE_SUCCESS_STATUS_CODE) {
- // all currencies which can be bought
- val currenciesAvailableToBy = response.data.crypto
- // tokens which can be bought only from specific blockchain network
- val supportedTokensWithNetwork = response.data.config.base
-
- currenciesAvailableToBy.forEach { currencyName ->
- val blockchain = blockchainFromCurrencyName(currencyName)
- if (blockchain == null) {
- // suppose its a token
- supportedTokensWithNetwork[currencyName]?.let {
- blockchainFromCurrencyName(it)
- }?.let { blockchainNetwork ->
- val supportedInBlockchainsNetwork = tokensAvailableToBy[currencyName]
- ?: mutableListOf()
- supportedInBlockchainsNetwork.add(blockchainNetwork)
- tokensAvailableToBy[currencyName] = supportedInBlockchainsNetwork
- }
- } else {
- blockchainsAvailableToBuy.add(blockchain)
- }
- }
- }
- }
- is Result.Failure -> {
- blockchainsAvailableToBuy.clear()
- tokensAvailableToBy.clear()
- }
- }
- }
-
override fun isBuyAllowed(): Boolean = true
override fun isSellAllowed(): Boolean = false
@@ -83,20 +47,32 @@ class MercuryoService(
when {
blockchain.isTestnet() -> blockchain.getTestnetTopUpUrl() != null
unsupportedBlockchains.contains(blockchain) -> false
- else -> {
- blockchainsAvailableToBuy.contains(currency.blockchain)
- }
+ else -> blockchainsAvailableToBuy.contains(blockchain)
}
}
+
is Currency.Token -> {
- val supportedInBlockchains = tokensAvailableToBy[currency.currencySymbol] ?: return false
- supportedInBlockchains.contains(currency.blockchain)
+ val supportedInBlockchains = tokensAvailableToBuy[currency.currencySymbol] ?: return false
+ supportedInBlockchains.contains(blockchain)
}
}
}
override fun availableForSell(currency: Currency): Boolean = false
+ override suspend fun update() {
+ val result = performRequest { api.currencies(environment.apiVersion) }
+ when {
+ result is Result.Success && result.data.status == RESPONSE_SUCCESS_STATUS_CODE -> {
+ handleSuccessfullyUpdatedData(data = result.data.data)
+ }
+ result is Result.Failure -> {
+ blockchainsAvailableToBuy.clear()
+ tokensAvailableToBuy.clear()
+ }
+ }
+ }
+
override fun getUrl(
action: CurrencyExchangeManager.Action,
blockchain: Blockchain,
@@ -117,24 +93,40 @@ class MercuryoService(
.appendQueryParameter("fix_currency", "true")
.appendQueryParameter("return_url", ExchangeUrlBuilder.SUCCESS_URL)
- val url = builder.build().toString()
- return url
- }
-
- private fun signature(address: String): String {
- return (address + environment.secret).calculateSha512().toHexString().lowercase()
+ return builder.build().toString()
}
override fun getSellCryptoReceiptUrl(action: CurrencyExchangeManager.Action, transactionId: String): String? = null
- private fun blockchainFromCurrencyName(currencyName: String): Blockchain? = when (currencyName) {
- "BNB" -> Blockchain.BSC
- "ETH" -> Blockchain.Ethereum
- "ADA" -> Blockchain.CardanoShelley
- else -> Blockchain.values().find { it.currency.lowercase() == currencyName.lowercase() }
+ private fun handleSuccessfullyUpdatedData(data: MercuryoCurrenciesResponse.Data) {
+ data.crypto.forEach { currencyName ->
+ val blockchain = blockchainFromCurrencyName(currencyName)
+ if (blockchain == null) {
+ val specificBlockchain = data.config.base[currencyName]?.let(::blockchainFromCurrencyName)
+ if (specificBlockchain != null) {
+ tokensAvailableToBuy.set(
+ key = currencyName,
+ value = tokensAvailableToBuy[currencyName].orEmpty() + specificBlockchain,
+ )
+ }
+ } else {
+ blockchainsAvailableToBuy.add(blockchain)
+ }
+ }
}
- companion object {
- private const val RESPONSE_SUCCESS_STATUS_CODE = 200
+ private fun blockchainFromCurrencyName(currencyName: String): Blockchain? {
+ return when (currencyName) {
+ "BNB" -> Blockchain.BSC
+ "ETH" -> Blockchain.Ethereum
+ "ADA" -> Blockchain.CardanoShelley
+ else -> Blockchain.values().find { it.currency.lowercase() == currencyName.lowercase() }
+ }
+ }
+
+ private fun signature(address: String) = (address + environment.secret).calculateSha512().toHexString().lowercase()
+
+ private companion object {
+ const val RESPONSE_SUCCESS_STATUS_CODE = 200
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/persistence/CardBalanceStateAdapter.kt b/app/src/main/java/com/tangem/tap/persistence/CardBalanceStateAdapter.kt
deleted file mode 100644
index 0385071ff3..0000000000
--- a/app/src/main/java/com/tangem/tap/persistence/CardBalanceStateAdapter.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.tangem.tap.persistence
-
-import com.squareup.moshi.FromJson
-import com.squareup.moshi.ToJson
-import com.tangem.tap.common.analytics.events.AnalyticsParam
-
-class CardBalanceStateAdapter {
-
- @ToJson
- fun toJson(src: AnalyticsParam.CardBalanceState): String = src.value
-
- @FromJson
- fun fromJson(json: String): AnalyticsParam.CardBalanceState {
- return when (json) {
- AnalyticsParam.CardBalanceState.Empty.value -> AnalyticsParam.CardBalanceState.Empty
- AnalyticsParam.CardBalanceState.Full.value -> AnalyticsParam.CardBalanceState.Full
- else -> error("CardBalanceState not found")
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt
index 72645564d0..c673ac8577 100644
--- a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt
+++ b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt
@@ -107,8 +107,8 @@ class DerivationManagerImpl(
val selectedUserWallet = appStateHolder.userWalletsListManager?.selectedUserWalletSync
val result = appStateHolder.tangemSdkManager?.derivePublicKeys(
- scanResponse.card.cardId,
- derivations,
+ cardId = null, // always ignore cardId in derive task
+ derivations = derivations,
)
when (result) {
is CompletionResult.Success -> {
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 65a4cdb3e9..2952ed0257 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
@@ -1,20 +1,9 @@
package com.tangem.tap.proxy.redux
-import com.tangem.datasource.asset.AssetReader
-import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.features.tester.api.TesterRouter
-import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
-import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles
import org.rekotlin.Action
sealed interface DaggerGraphAction : Action {
- data class SetApplicationDependencies(
- val assetReader: AssetReader,
- val networkConnectionManager: NetworkConnectionManager,
- val tokensListFeatureToggles: TokensListFeatureToggles,
- val customTokenFeatureToggles: CustomTokenFeatureToggles,
- ) : DaggerGraphAction
-
data class SetActivityDependencies(val testerRouter: TesterRouter) : DaggerGraphAction
}
\ No newline at end of file
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 3bb0e65284..43cb94af5c 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
@@ -12,12 +12,6 @@ object DaggerGraphReducer {
private fun internalReduce(action: DaggerGraphAction, state: AppState): DaggerGraphState {
return when (action) {
- is DaggerGraphAction.SetApplicationDependencies -> state.daggerGraphState.copy(
- assetReader = action.assetReader,
- networkConnectionManager = action.networkConnectionManager,
- tokensListFeatureToggles = action.tokensListFeatureToggles,
- customTokenFeatureToggles = action.customTokenFeatureToggles,
- )
is DaggerGraphAction.SetActivityDependencies -> state.daggerGraphState.copy(
testerRouter = action.testerRouter,
)
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 dd0a501489..73fc659cf8 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
@@ -4,14 +4,12 @@ import com.tangem.datasource.asset.AssetReader
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.features.tester.api.TesterRouter
import com.tangem.tap.features.customtoken.api.featuretoggles.CustomTokenFeatureToggles
-import com.tangem.tap.features.tokens.api.featuretoggles.TokensListFeatureToggles
import org.rekotlin.StateType
data class DaggerGraphState(
val assetReader: AssetReader? = null,
val testerRouter: TesterRouter? = null,
val networkConnectionManager: NetworkConnectionManager? = null,
- val tokensListFeatureToggles: TokensListFeatureToggles? = null,
val customTokenFeatureToggles: CustomTokenFeatureToggles? = null,
) : StateType {
diff --git a/app/src/main/res/anim/slide_in_right.xml b/app/src/main/res/anim/slide_in_right.xml
deleted file mode 100644
index 465c50c0cd..0000000000
--- a/app/src/main/res/anim/slide_in_right.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/anim/slide_in_up.xml b/app/src/main/res/anim/slide_in_up.xml
deleted file mode 100644
index a821c2d9c6..0000000000
--- a/app/src/main/res/anim/slide_in_up.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
diff --git a/app/src/main/res/anim/slide_out_down.xml b/app/src/main/res/anim/slide_out_down.xml
deleted file mode 100644
index f6095c0a17..0000000000
--- a/app/src/main/res/anim/slide_out_down.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
diff --git a/app/src/main/res/anim/slide_out_right.xml b/app/src/main/res/anim/slide_out_right.xml
deleted file mode 100644
index a4b3ff52cc..0000000000
--- a/app/src/main/res/anim/slide_out_right.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/color/selector_btn_black.xml b/app/src/main/res/color/selector_btn_black.xml
deleted file mode 100644
index 5fae92a59d..0000000000
--- a/app/src/main/res/color/selector_btn_black.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/color/selector_btn_gray_text_color.xml b/app/src/main/res/color/selector_btn_gray_text_color.xml
deleted file mode 100644
index 8e5c0ab355..0000000000
--- a/app/src/main/res/color/selector_btn_gray_text_color.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/color/selector_btn_green.xml b/app/src/main/res/color/selector_btn_green.xml
deleted file mode 100644
index 0af5088cd4..0000000000
--- a/app/src/main/res/color/selector_btn_green.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable-hdpi/floating_cards.png b/app/src/main/res/drawable-hdpi/floating_cards.png
deleted file mode 100644
index 6f8eba908f..0000000000
Binary files a/app/src/main/res/drawable-hdpi/floating_cards.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_binance.png b/app/src/main/res/drawable-hdpi/ic_binance.png
deleted file mode 100644
index edce12fa14..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_binance.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_btc.png b/app/src/main/res/drawable-hdpi/ic_btc.png
deleted file mode 100644
index be16f5a51b..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_btc.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_btc_cash.png b/app/src/main/res/drawable-hdpi/ic_btc_cash.png
deleted file mode 100644
index ec0864fdb8..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_btc_cash.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_cardano.png b/app/src/main/res/drawable-hdpi/ic_cardano.png
deleted file mode 100644
index 8a4ac01ad4..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_cardano.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_ltc.png b/app/src/main/res/drawable-hdpi/ic_ltc.png
deleted file mode 100644
index 6c0fb4ad3c..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_ltc.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_rsk.png b/app/src/main/res/drawable-hdpi/ic_rsk.png
deleted file mode 100644
index be49cda24f..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_rsk.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_stellar.png b/app/src/main/res/drawable-hdpi/ic_stellar.png
deleted file mode 100644
index 7bb500ef1d..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_stellar.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_tezos.png b/app/src/main/res/drawable-hdpi/ic_tezos.png
deleted file mode 100644
index 938fc9d3d4..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_tezos.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_xlm.png b/app/src/main/res/drawable-hdpi/ic_xlm.png
deleted file mode 100644
index 6155f291ea..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_xlm.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_xrp.png b/app/src/main/res/drawable-hdpi/ic_xrp.png
deleted file mode 100644
index 058650f44b..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_xrp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/thousands_of_currencies.png b/app/src/main/res/drawable-hdpi/thousands_of_currencies.png
deleted file mode 100644
index af3bf1ca51..0000000000
Binary files a/app/src/main/res/drawable-hdpi/thousands_of_currencies.png and /dev/null differ
diff --git a/app/src/main/res/drawable-ldpi/ic_binance.png b/app/src/main/res/drawable-ldpi/ic_binance.png
deleted file mode 100644
index 18aa82ea4b..0000000000
Binary files a/app/src/main/res/drawable-ldpi/ic_binance.png and /dev/null differ
diff --git a/app/src/main/res/drawable-ldpi/ic_btc.png b/app/src/main/res/drawable-ldpi/ic_btc.png
deleted file mode 100644
index 982bb50ad1..0000000000
Binary files a/app/src/main/res/drawable-ldpi/ic_btc.png and /dev/null differ
diff --git a/app/src/main/res/drawable-ldpi/ic_btc_cash.png b/app/src/main/res/drawable-ldpi/ic_btc_cash.png
deleted file mode 100644
index 3789ae5071..0000000000
Binary files a/app/src/main/res/drawable-ldpi/ic_btc_cash.png and /dev/null differ
diff --git a/app/src/main/res/drawable-ldpi/ic_cardano.png b/app/src/main/res/drawable-ldpi/ic_cardano.png
deleted file mode 100644
index dd8332ef62..0000000000
Binary files a/app/src/main/res/drawable-ldpi/ic_cardano.png and /dev/null differ
diff --git a/app/src/main/res/drawable-ldpi/ic_ltc.png b/app/src/main/res/drawable-ldpi/ic_ltc.png
deleted file mode 100644
index a9dc421e25..0000000000
Binary files a/app/src/main/res/drawable-ldpi/ic_ltc.png and /dev/null differ
diff --git a/app/src/main/res/drawable-ldpi/ic_rsk.png b/app/src/main/res/drawable-ldpi/ic_rsk.png
deleted file mode 100644
index 416da64bb7..0000000000
Binary files a/app/src/main/res/drawable-ldpi/ic_rsk.png and /dev/null differ
diff --git a/app/src/main/res/drawable-ldpi/ic_stellar.png b/app/src/main/res/drawable-ldpi/ic_stellar.png
deleted file mode 100644
index 0de7200a90..0000000000
Binary files a/app/src/main/res/drawable-ldpi/ic_stellar.png and /dev/null differ
diff --git a/app/src/main/res/drawable-ldpi/ic_tezos.png b/app/src/main/res/drawable-ldpi/ic_tezos.png
deleted file mode 100644
index 502e81b732..0000000000
Binary files a/app/src/main/res/drawable-ldpi/ic_tezos.png and /dev/null differ
diff --git a/app/src/main/res/drawable-ldpi/ic_xlm.png b/app/src/main/res/drawable-ldpi/ic_xlm.png
deleted file mode 100644
index 3262fe8e13..0000000000
Binary files a/app/src/main/res/drawable-ldpi/ic_xlm.png and /dev/null differ
diff --git a/app/src/main/res/drawable-ldpi/ic_xrp.png b/app/src/main/res/drawable-ldpi/ic_xrp.png
deleted file mode 100644
index 70d484bc18..0000000000
Binary files a/app/src/main/res/drawable-ldpi/ic_xrp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/floating_cards.png b/app/src/main/res/drawable-mdpi/floating_cards.png
deleted file mode 100644
index 9ff5cb944a..0000000000
Binary files a/app/src/main/res/drawable-mdpi/floating_cards.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_binance.png b/app/src/main/res/drawable-mdpi/ic_binance.png
deleted file mode 100644
index 9254cb4a01..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_binance.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_btc.png b/app/src/main/res/drawable-mdpi/ic_btc.png
deleted file mode 100644
index f02a7a13a1..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_btc.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_btc_cash.png b/app/src/main/res/drawable-mdpi/ic_btc_cash.png
deleted file mode 100644
index e0dea3ea53..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_btc_cash.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_cardano.png b/app/src/main/res/drawable-mdpi/ic_cardano.png
deleted file mode 100644
index 7ff6fc7ec0..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_cardano.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_ltc.png b/app/src/main/res/drawable-mdpi/ic_ltc.png
deleted file mode 100644
index 13f1de9253..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_ltc.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_rsk.png b/app/src/main/res/drawable-mdpi/ic_rsk.png
deleted file mode 100644
index af269e0bda..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_rsk.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_stellar.png b/app/src/main/res/drawable-mdpi/ic_stellar.png
deleted file mode 100644
index 207f7c21a8..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_stellar.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_tezos.png b/app/src/main/res/drawable-mdpi/ic_tezos.png
deleted file mode 100644
index 71d699414b..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_tezos.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_xlm.png b/app/src/main/res/drawable-mdpi/ic_xlm.png
deleted file mode 100644
index 1a35164ed1..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_xlm.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_xrp.png b/app/src/main/res/drawable-mdpi/ic_xrp.png
deleted file mode 100644
index ec5e3bb680..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_xrp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/thousands_of_currencies.png b/app/src/main/res/drawable-mdpi/thousands_of_currencies.png
deleted file mode 100644
index 4f448c7df8..0000000000
Binary files a/app/src/main/res/drawable-mdpi/thousands_of_currencies.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/web_3.png b/app/src/main/res/drawable-mdpi/web_3.png
deleted file mode 100644
index df3245ff41..0000000000
Binary files a/app/src/main/res/drawable-mdpi/web_3.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/floating_cards.png b/app/src/main/res/drawable-xhdpi/floating_cards.png
deleted file mode 100644
index 3445299a6f..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/floating_cards.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/googlepay_button_background_image.9.png b/app/src/main/res/drawable-xhdpi/googlepay_button_background_image.9.png
deleted file mode 100755
index 40f767d533..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/googlepay_button_background_image.9.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_binance.png b/app/src/main/res/drawable-xhdpi/ic_binance.png
deleted file mode 100644
index 4a1619f750..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_binance.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_btc.png b/app/src/main/res/drawable-xhdpi/ic_btc.png
deleted file mode 100644
index e58ee8b721..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_btc.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_btc_cash.png b/app/src/main/res/drawable-xhdpi/ic_btc_cash.png
deleted file mode 100644
index 4709218591..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_btc_cash.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_cardano.png b/app/src/main/res/drawable-xhdpi/ic_cardano.png
deleted file mode 100644
index 5e9c1be96a..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_cardano.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_ltc.png b/app/src/main/res/drawable-xhdpi/ic_ltc.png
deleted file mode 100644
index 1135186fa5..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_ltc.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_rsk.png b/app/src/main/res/drawable-xhdpi/ic_rsk.png
deleted file mode 100644
index 2016162c6d..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_rsk.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_stellar.png b/app/src/main/res/drawable-xhdpi/ic_stellar.png
deleted file mode 100644
index d6073f7fc7..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_stellar.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_tezos.png b/app/src/main/res/drawable-xhdpi/ic_tezos.png
deleted file mode 100644
index 811d221bdb..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_tezos.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_xlm.png b/app/src/main/res/drawable-xhdpi/ic_xlm.png
deleted file mode 100644
index 7ebe6a2fe8..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_xlm.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_xrp.png b/app/src/main/res/drawable-xhdpi/ic_xrp.png
deleted file mode 100644
index aa8adabc2c..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_xrp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/thousands_of_currencies.png b/app/src/main/res/drawable-xhdpi/thousands_of_currencies.png
deleted file mode 100644
index cd226e8bf3..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/thousands_of_currencies.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/web_3.png b/app/src/main/res/drawable-xhdpi/web_3.png
deleted file mode 100644
index 8af4c9c432..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/web_3.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/floating_cards.png b/app/src/main/res/drawable-xxhdpi/floating_cards.png
deleted file mode 100644
index 000db85171..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/floating_cards.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/googlepay_button_background_image.9.png b/app/src/main/res/drawable-xxhdpi/googlepay_button_background_image.9.png
deleted file mode 100755
index 91035e2a41..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/googlepay_button_background_image.9.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_binance.png b/app/src/main/res/drawable-xxhdpi/ic_binance.png
deleted file mode 100644
index dbe9c0805f..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_binance.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_btc.png b/app/src/main/res/drawable-xxhdpi/ic_btc.png
deleted file mode 100644
index 87f552a566..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_btc.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_btc_cash.png b/app/src/main/res/drawable-xxhdpi/ic_btc_cash.png
deleted file mode 100644
index 11d710501e..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_btc_cash.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_cardano.png b/app/src/main/res/drawable-xxhdpi/ic_cardano.png
deleted file mode 100644
index 74faea419a..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_cardano.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_ltc.png b/app/src/main/res/drawable-xxhdpi/ic_ltc.png
deleted file mode 100644
index 0cf80c3570..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_ltc.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_rsk.png b/app/src/main/res/drawable-xxhdpi/ic_rsk.png
deleted file mode 100644
index 3a660c50bc..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_rsk.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_stellar.png b/app/src/main/res/drawable-xxhdpi/ic_stellar.png
deleted file mode 100644
index 8824973627..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_stellar.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_tezos.png b/app/src/main/res/drawable-xxhdpi/ic_tezos.png
deleted file mode 100644
index 16dccf95c8..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_tezos.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_xlm.png b/app/src/main/res/drawable-xxhdpi/ic_xlm.png
deleted file mode 100644
index 0dc1b2ba5f..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_xlm.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_xrp.png b/app/src/main/res/drawable-xxhdpi/ic_xrp.png
deleted file mode 100644
index 881d6b7b4b..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_xrp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/thousands_of_currencies.png b/app/src/main/res/drawable-xxhdpi/thousands_of_currencies.png
deleted file mode 100644
index 572bb12ae8..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/thousands_of_currencies.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/web_3.png b/app/src/main/res/drawable-xxhdpi/web_3.png
deleted file mode 100644
index 8aa6f0b237..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/web_3.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/floating_cards.png b/app/src/main/res/drawable-xxxhdpi/floating_cards.png
deleted file mode 100644
index 81dd5e3119..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/floating_cards.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/googlepay_button_background_image.9.png b/app/src/main/res/drawable-xxxhdpi/googlepay_button_background_image.9.png
deleted file mode 100755
index ab905289bc..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/googlepay_button_background_image.9.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_binance.png b/app/src/main/res/drawable-xxxhdpi/ic_binance.png
deleted file mode 100644
index f18f7ff9d7..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_binance.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_btc.png b/app/src/main/res/drawable-xxxhdpi/ic_btc.png
deleted file mode 100644
index 165164f069..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_btc.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_btc_cash.png b/app/src/main/res/drawable-xxxhdpi/ic_btc_cash.png
deleted file mode 100644
index babd59d8b1..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_btc_cash.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_cardano.png b/app/src/main/res/drawable-xxxhdpi/ic_cardano.png
deleted file mode 100644
index 1f8b6888a5..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_cardano.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_ltc.png b/app/src/main/res/drawable-xxxhdpi/ic_ltc.png
deleted file mode 100644
index d159e6728f..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_ltc.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_rsk.png b/app/src/main/res/drawable-xxxhdpi/ic_rsk.png
deleted file mode 100644
index b442ac65a4..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_rsk.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_stellar.png b/app/src/main/res/drawable-xxxhdpi/ic_stellar.png
deleted file mode 100644
index a19f0db146..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_stellar.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_tezos.png b/app/src/main/res/drawable-xxxhdpi/ic_tezos.png
deleted file mode 100644
index d91ceab8fc..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_tezos.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_xlm.png b/app/src/main/res/drawable-xxxhdpi/ic_xlm.png
deleted file mode 100644
index 6500485826..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_xlm.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_xrp.png b/app/src/main/res/drawable-xxxhdpi/ic_xrp.png
deleted file mode 100644
index 22400ff291..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_xrp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/thousands_of_currencies.png b/app/src/main/res/drawable-xxxhdpi/thousands_of_currencies.png
deleted file mode 100644
index 5e2406e2c7..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/thousands_of_currencies.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/web_3.png b/app/src/main/res/drawable-xxxhdpi/web_3.png
deleted file mode 100644
index 988c52d448..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/web_3.png and /dev/null differ
diff --git a/app/src/main/res/drawable/anim_progress_balance.xml b/app/src/main/res/drawable/anim_progress_balance.xml
deleted file mode 100644
index ada4670265..0000000000
--- a/app/src/main/res/drawable/anim_progress_balance.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/card_default.png b/app/src/main/res/drawable/card_default.png
deleted file mode 100644
index 597996135d..0000000000
Binary files a/app/src/main/res/drawable/card_default.png and /dev/null differ
diff --git a/app/src/main/res/drawable/googlepay_button_background.xml b/app/src/main/res/drawable/googlepay_button_background.xml
deleted file mode 100755
index b81005b06f..0000000000
--- a/app/src/main/res/drawable/googlepay_button_background.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/drawable/googlepay_button_content.xml b/app/src/main/res/drawable/googlepay_button_content.xml
deleted file mode 100755
index b2cdb1d52b..0000000000
--- a/app/src/main/res/drawable/googlepay_button_content.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_alert.xml b/app/src/main/res/drawable/ic_alert.xml
deleted file mode 100644
index befebf5833..0000000000
--- a/app/src/main/res/drawable/ic_alert.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_arrow_down_short_button.xml b/app/src/main/res/drawable/ic_arrow_down_short_button.xml
deleted file mode 100644
index 18b58e3f6c..0000000000
--- a/app/src/main/res/drawable/ic_arrow_down_short_button.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_arrow_up_short_btn.xml b/app/src/main/res/drawable/ic_arrow_up_short_btn.xml
deleted file mode 100644
index b739da9ccb..0000000000
--- a/app/src/main/res/drawable/ic_arrow_up_short_btn.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_arrows_up_down_short_btn.xml b/app/src/main/res/drawable/ic_arrows_up_down_short_btn.xml
deleted file mode 100644
index 51b285c947..0000000000
--- a/app/src/main/res/drawable/ic_arrows_up_down_short_btn.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_backup.xml b/app/src/main/res/drawable/ic_backup.xml
deleted file mode 100644
index b377ea3f2a..0000000000
--- a/app/src/main/res/drawable/ic_backup.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_binance_no_color.xml b/app/src/main/res/drawable/ic_binance_no_color.xml
deleted file mode 100644
index 2e20021097..0000000000
--- a/app/src/main/res/drawable/ic_binance_no_color.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_btn_round_background.xml b/app/src/main/res/drawable/ic_btn_round_background.xml
deleted file mode 100644
index 8571c0603a..0000000000
--- a/app/src/main/res/drawable/ic_btn_round_background.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_card_home.xml b/app/src/main/res/drawable/ic_card_home.xml
deleted file mode 100644
index e355d53e24..0000000000
--- a/app/src/main/res/drawable/ic_card_home.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_cards.xml b/app/src/main/res/drawable/ic_cards.xml
deleted file mode 100644
index 9b226dff8e..0000000000
--- a/app/src/main/res/drawable/ic_cards.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_chevron.xml b/app/src/main/res/drawable/ic_chevron.xml
deleted file mode 100644
index 31e861dd95..0000000000
--- a/app/src/main/res/drawable/ic_chevron.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_clear.xml b/app/src/main/res/drawable/ic_clear.xml
deleted file mode 100644
index 2f59f4cb34..0000000000
--- a/app/src/main/res/drawable/ic_clear.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_cosmos_no_color.xml b/app/src/main/res/drawable/ic_cosmos_no_color.xml
new file mode 100644
index 0000000000..2b45162689
--- /dev/null
+++ b/app/src/main/res/drawable/ic_cosmos_no_color.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_dash.xml b/app/src/main/res/drawable/ic_dash.xml
deleted file mode 100644
index 67df63c241..0000000000
--- a/app/src/main/res/drawable/ic_dash.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_dot_not_selected.xml b/app/src/main/res/drawable/ic_dot_not_selected.xml
deleted file mode 100644
index a6d0f14af2..0000000000
--- a/app/src/main/res/drawable/ic_dot_not_selected.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_dots.xml b/app/src/main/res/drawable/ic_dots.xml
deleted file mode 100644
index e85d610944..0000000000
--- a/app/src/main/res/drawable/ic_dots.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_ducatus.png b/app/src/main/res/drawable/ic_ducatus.png
deleted file mode 100644
index cfae76f29f..0000000000
Binary files a/app/src/main/res/drawable/ic_ducatus.png and /dev/null differ
diff --git a/app/src/main/res/drawable/ic_ellipse_4.xml b/app/src/main/res/drawable/ic_ellipse_4.xml
deleted file mode 100644
index 4aec420912..0000000000
--- a/app/src/main/res/drawable/ic_ellipse_4.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_ethc_no_color.xml b/app/src/main/res/drawable/ic_ethc_no_color.xml
deleted file mode 100644
index 8053e14918..0000000000
--- a/app/src/main/res/drawable/ic_ethc_no_color.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_filter.xml b/app/src/main/res/drawable/ic_filter.xml
deleted file mode 100644
index e2c70a78fa..0000000000
--- a/app/src/main/res/drawable/ic_filter.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_group_1243.xml b/app/src/main/res/drawable/ic_group_1243.xml
deleted file mode 100644
index c1e2907eb0..0000000000
--- a/app/src/main/res/drawable/ic_group_1243.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_group_1258.xml b/app/src/main/res/drawable/ic_group_1258.xml
deleted file mode 100644
index b15674c9de..0000000000
--- a/app/src/main/res/drawable/ic_group_1258.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_link_long.xml b/app/src/main/res/drawable/ic_link_long.xml
deleted file mode 100644
index 927b54b5d4..0000000000
--- a/app/src/main/res/drawable/ic_link_long.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_no_tokens.xml b/app/src/main/res/drawable/ic_no_tokens.xml
deleted file mode 100644
index f1149e0fad..0000000000
--- a/app/src/main/res/drawable/ic_no_tokens.xml
+++ /dev/null
@@ -1,468 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_onboarding_chat_24.xml b/app/src/main/res/drawable/ic_onboarding_chat_24.xml
deleted file mode 100644
index a54ee4625a..0000000000
--- a/app/src/main/res/drawable/ic_onboarding_chat_24.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_onboarding_qr_code_scan_24.xml b/app/src/main/res/drawable/ic_onboarding_qr_code_scan_24.xml
deleted file mode 100644
index 93e77daea8..0000000000
--- a/app/src/main/res/drawable/ic_onboarding_qr_code_scan_24.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_progress_balance.xml b/app/src/main/res/drawable/ic_progress_balance.xml
deleted file mode 100644
index d31defe1e7..0000000000
--- a/app/src/main/res/drawable/ic_progress_balance.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_reset.xml b/app/src/main/res/drawable/ic_reset.xml
deleted file mode 100644
index 8c0845dbb0..0000000000
--- a/app/src/main/res/drawable/ic_reset.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_save.xml b/app/src/main/res/drawable/ic_save.xml
deleted file mode 100644
index 756c7557dc..0000000000
--- a/app/src/main/res/drawable/ic_save.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_scan_for_short_btn.xml b/app/src/main/res/drawable/ic_scan_for_short_btn.xml
deleted file mode 100644
index 1c281ecd9c..0000000000
--- a/app/src/main/res/drawable/ic_scan_for_short_btn.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_security.xml b/app/src/main/res/drawable/ic_security.xml
deleted file mode 100644
index ba3c214505..0000000000
--- a/app/src/main/res/drawable/ic_security.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_send_short_btn.xml b/app/src/main/res/drawable/ic_send_short_btn.xml
deleted file mode 100644
index 273ed56f76..0000000000
--- a/app/src/main/res/drawable/ic_send_short_btn.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_share_green.xml b/app/src/main/res/drawable/ic_share_green.xml
deleted file mode 100644
index 57ee232b90..0000000000
--- a/app/src/main/res/drawable/ic_share_green.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_shop.xml b/app/src/main/res/drawable/ic_shop.xml
deleted file mode 100644
index eecb2d68af..0000000000
--- a/app/src/main/res/drawable/ic_shop.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_tangem_pale.xml b/app/src/main/res/drawable/ic_tangem_pale.xml
deleted file mode 100644
index dacddc1972..0000000000
--- a/app/src/main/res/drawable/ic_tangem_pale.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_twin_cards_background_warning.xml b/app/src/main/res/drawable/ic_twin_cards_background_warning.xml
deleted file mode 100644
index 54cccb6fa8..0000000000
--- a/app/src/main/res/drawable/ic_twin_cards_background_warning.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/onboarding_circle.xml b/app/src/main/res/drawable/onboarding_circle.xml
deleted file mode 100644
index 7f7459b556..0000000000
--- a/app/src/main/res/drawable/onboarding_circle.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/rectangle_twin_background.xml b/app/src/main/res/drawable/rectangle_twin_background.xml
deleted file mode 100644
index 73ca08b417..0000000000
--- a/app/src/main/res/drawable/rectangle_twin_background.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ripple.xml b/app/src/main/res/drawable/ripple.xml
deleted file mode 100644
index c6e07a265f..0000000000
--- a/app/src/main/res/drawable/ripple.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_circle_home_screen.xml b/app/src/main/res/drawable/shape_circle_home_screen.xml
deleted file mode 100644
index 6cc2f8cc4e..0000000000
--- a/app/src/main/res/drawable/shape_circle_home_screen.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/dialog_create_payid.xml b/app/src/main/res/layout/dialog_create_payid.xml
deleted file mode 100644
index 3c4d10891d..0000000000
--- a/app/src/main/res/layout/dialog_create_payid.xml
+++ /dev/null
@@ -1,106 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/dialog_qrcode.xml b/app/src/main/res/layout/dialog_qrcode.xml
deleted file mode 100644
index 79b7c187e4..0000000000
--- a/app/src/main/res/layout/dialog_qrcode.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_add_tokens.xml b/app/src/main/res/layout/fragment_add_tokens.xml
deleted file mode 100644
index 0b5881f415..0000000000
--- a/app/src/main/res/layout/fragment_add_tokens.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_details_confirm.xml b/app/src/main/res/layout/fragment_details_confirm.xml
deleted file mode 100644
index c4daafda8d..0000000000
--- a/app/src/main/res/layout/fragment_details_confirm.xml
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_topup.xml b/app/src/main/res/layout/fragment_topup.xml
deleted file mode 100644
index 366c9faa7c..0000000000
--- a/app/src/main/res/layout/fragment_topup.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_wallet_connect_sessions.xml b/app/src/main/res/layout/fragment_wallet_connect_sessions.xml
deleted file mode 100644
index a2990696a4..0000000000
--- a/app/src/main/res/layout/fragment_wallet_connect_sessions.xml
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_currency_subtitle.xml b/app/src/main/res/layout/item_currency_subtitle.xml
deleted file mode 100644
index 677c928c32..0000000000
--- a/app/src/main/res/layout/item_currency_subtitle.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_currency_wallet_content.xml b/app/src/main/res/layout/item_currency_wallet_content.xml
index 5eb26a5bbb..4bb15bb54b 100644
--- a/app/src/main/res/layout/item_currency_wallet_content.xml
+++ b/app/src/main/res/layout/item_currency_wallet_content.xml
@@ -19,8 +19,8 @@
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:ellipsize="end"
- android:gravity="start"
android:maxLines="1"
+ android:textAlignment="viewStart"
android:textColor="@color/text_primary_1"
android:textSize="16sp"
android:textStyle="bold"
@@ -67,8 +67,8 @@
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:ellipsize="end"
- android:gravity="start"
android:maxLines="1"
+ android:textAlignment="viewStart"
android:textColor="@color/text_tertiary"
android:textSize="12sp"
android:visibility="gone"
diff --git a/app/src/main/res/layout/item_popular_token.xml b/app/src/main/res/layout/item_popular_token.xml
deleted file mode 100644
index 86b44d34bf..0000000000
--- a/app/src/main/res/layout/item_popular_token.xml
+++ /dev/null
@@ -1,101 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/item_wallet_connect_session.xml b/app/src/main/res/layout/item_wallet_connect_session.xml
deleted file mode 100644
index b7ef47ef46..0000000000
--- a/app/src/main/res/layout/item_wallet_connect_session.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_address.xml b/app/src/main/res/layout/layout_address.xml
index ae0481aa8c..22853700ed 100644
--- a/app/src/main/res/layout/layout_address.xml
+++ b/app/src/main/res/layout/layout_address.xml
@@ -109,7 +109,8 @@
android:layout_gravity="center"
android:background="?selectableItemBackgroundBorderless"
android:padding="5dp"
- app:srcCompat="@drawable/ic_copy" />
+ app:srcCompat="@drawable/ic_copy"
+ android:importantForAccessibility="no" />
@@ -133,7 +134,8 @@
android:layout_gravity="center"
android:background="?selectableItemBackgroundBorderless"
android:padding="2dp"
- app:srcCompat="@drawable/ic_qr_code_show" />
+ app:srcCompat="@drawable/ic_qr_code_show"
+ android:importantForAccessibility="no" />
@@ -142,7 +144,7 @@
style="@style/TextViewOnboarding.Body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="@dimen/spacing16"
+ android:layout_margin="@dimen/layout_address_info_margin"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_explore"
@@ -166,7 +168,8 @@
android:src="@drawable/ic_payid"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/v_payid_divider" />
+ app:layout_constraintTop_toBottomOf="@id/v_payid_divider"
+ android:importantForAccessibility="no" />
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_search_view.xml b/app/src/main/res/layout/layout_search_view.xml
deleted file mode 100644
index 65bbfa77d1..0000000000
--- a/app/src/main/res/layout/layout_search_view.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_token.xml b/app/src/main/res/layout/layout_token.xml
deleted file mode 100644
index 07baf720d5..0000000000
--- a/app/src/main/res/layout/layout_token.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_wallet_long_buttons.xml b/app/src/main/res/layout/layout_wallet_long_buttons.xml
deleted file mode 100644
index 60ac6691fb..0000000000
--- a/app/src/main/res/layout/layout_wallet_long_buttons.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/layout_wallet_short_buttons.xml b/app/src/main/res/layout/layout_wallet_short_buttons.xml
deleted file mode 100644
index e8c85a41d5..0000000000
--- a/app/src/main/res/layout/layout_wallet_short_buttons.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/test_shopify_fragment.xml b/app/src/main/res/layout/test_shopify_fragment.xml
deleted file mode 100644
index b844d1b1d3..0000000000
--- a/app/src/main/res/layout/test_shopify_fragment.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/view_bg_home.xml b/app/src/main/res/layout/view_bg_home.xml
deleted file mode 100644
index 4cba83727d..0000000000
--- a/app/src/main/res/layout/view_bg_home.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_compose.xml b/app/src/main/res/layout/view_compose.xml
deleted file mode 100644
index 0d5a7a4452..0000000000
--- a/app/src/main/res/layout/view_compose.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_popular_tokens.xml b/app/src/main/res/menu/menu_popular_tokens.xml
deleted file mode 100644
index 5cc1ac82f8..0000000000
--- a/app/src/main/res/menu/menu_popular_tokens.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/raw/scan_card_sound.mp3 b/app/src/main/res/raw/scan_card_sound.mp3
deleted file mode 100644
index aa667e4463..0000000000
Binary files a/app/src/main/res/raw/scan_card_sound.mp3 and /dev/null differ
diff --git a/app/src/main/res/values-h680dp/dimens.xml b/app/src/main/res/values-h680dp/dimens.xml
index 7a03c1b4cf..fa745a10ec 100644
--- a/app/src/main/res/values-h680dp/dimens.xml
+++ b/app/src/main/res/values-h680dp/dimens.xml
@@ -4,12 +4,8 @@
- 1.1
- -10dp
- 1
1
- 0dp
- - 1
- - 1
- 1
@@ -30,7 +26,6 @@
80dp
- 24dp
20dp
32dp
80dp
diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml
deleted file mode 100644
index 62df1875a4..0000000000
--- a/app/src/main/res/values-w820dp/dimens.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
- 64dp
-
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index a5c157e311..9544c3520b 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -8,10 +8,7 @@
@color/accent
@color/darkGray6
- #6A6A6A
- @color/accent
- #C4291C
#FFB71B
@color/backgroundLightGray
@@ -19,17 +16,11 @@
#FFFFFF
#F3F3F3
#F8F8FB
- #DADADF
- #D0D0D5
- #C7C7CC
#D1D1D6
- #CACACC
- #B6B6B8
#8E8E90
#666668
#48484A
#3A3A3C
- #2C2C2E
#1C1C1E
#FFFFFF
@@ -42,101 +33,47 @@
#F2F2F2
#090E13
- #14181D
-
- #1F000000
#14212121
@color/colorSecondary
- #0029FF
- #1F50FF
- #CBE4FF
#E0E6FA
- #55000000
-
#1C1C1E
#FFB71B
#CA0F03
- #EFEFF0
-
- #DE1010
#007AFF
- #000000
- #0029FF
- #919191
- #656565
- #494949
- #3B3B3B
- #303030
- #1E1E1E
- #06311F
- #ED7979
- #F5F5F5
- #EBEBEB
- #D3D3D3
- #C9C9C9
- #B0B0B0
- #A3EBCC
- #1ACE80
- #FFB71B
- #FFFFFF
- #000000
- #FFFFFF
#FFFFFF
#F5F5F5
#EBEBEB
- #1ACE80
- #A3EBCC
#1E1E1E
#EBEBEB
#1ACE80
- #FFFFFF
- #EBEBEB
-
-
-
- #EBEBEB
- #F5F5F5
-
#1ACE80
#FFB71B
#C9C9C9
#B0B0B0
- #000000
#FFFFFF
#656565
#DE1010
-
- #EBEBEB
- #663B3B3B
- #FFFFFF
-
-
-
- #1ACE80
#FFB71B
- #FFFFFF
#C9C9C9
#1E1E1E
#FFFFFF
#656565
#919191
- #DE1010
-
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index fdeae808a2..8f75b4d5f4 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -1,34 +1,5 @@
- 0.8dp
- 4dp
- 8dp
- 4dp
- 4dp
- 8dp
- 8dp
- 80dp
- 8dp
- 168dp
- 132dp
-
- 144dp
-
- 140dp
- 16dp
-
- 11dp
- 13dp
- 15dp
- 19dp
- 23dp
- 26dp
- 34dp
-
- 180dp
- 30dp
- 135dp
-
4dp
8dp
12dp
@@ -41,12 +12,8 @@
- 0.9
- -60dp
- 0.9
- 0.9
- -40dp
- - 0.9
- - 0.9
- 1
@@ -67,11 +34,12 @@
40dp
- 12dp
8dp
16dp
38dp
78dp
78dp
+ 16dp
+
diff --git a/app/src/main/res/values/googlepay_strings.xml b/app/src/main/res/values/googlepay_strings.xml
index 81d01c2b74..6b6087807c 100755
--- a/app/src/main/res/values/googlepay_strings.xml
+++ b/app/src/main/res/values/googlepay_strings.xml
@@ -1,12 +1,4 @@
- Google Pay
- Buy with Google Pay
- Donate With Google Pay
- Pay With Google Pay
- Subscribe With Google Pay
- Book With Google Pay
- Checkout With Google Pay
- Order With Google Pay
- View In Google Pay
+ Buy with Google Pay
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index f45be251fc..9356f81daf 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -13,11 +13,6 @@
-
-
-
-
-
-
-
-