Updated on 2026-08-14
This commit is contained in:
commit
9c32379865
379 changed files with 7260 additions and 3853 deletions
|
|
@ -31,7 +31,10 @@ dependencies {
|
|||
implementation(project(":domain:wallets:models"))
|
||||
implementation(projects.domain.settings)
|
||||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.txhistory)
|
||||
implementation(projects.domain.appCurrency)
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
|
||||
implementation(project(":common"))
|
||||
implementation(project(":core:analytics"))
|
||||
|
|
@ -51,6 +54,7 @@ dependencies {
|
|||
implementation(projects.data.settings)
|
||||
implementation(projects.data.tokens)
|
||||
implementation(projects.data.txhistory)
|
||||
implementation(projects.data.appCurrency)
|
||||
|
||||
/** Features */
|
||||
implementation(project(":features:onboarding"))
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit b791bd4cf6c5eca9778f89e87cd62b72d24f5ce9
|
||||
Subproject commit 8c1c53b73950698d4acfa4d925b8c14bf6f0da63
|
||||
|
|
@ -5,8 +5,8 @@ import androidx.lifecycle.LifecycleOwner
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.wallets.legacy.asLockable
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.domain.userWalletList.asLockable
|
||||
import kotlinx.coroutines.*
|
||||
import timber.log.Timber
|
||||
import kotlin.time.Duration
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.tangem.datasource.config.FeaturesLocalLoader
|
|||
import com.tangem.datasource.config.models.Config
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.domain.DomainLayer
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.common.LogConfig
|
||||
import com.tangem.domain.wallets.legacy.WalletManagersRepository
|
||||
|
|
@ -161,6 +162,9 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
@Inject
|
||||
lateinit var blockchainExceptionHandler: BlockchainExceptionHandler
|
||||
|
||||
@Inject
|
||||
lateinit var appCurrencyRepository: AppCurrencyRepository
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
|
|
@ -179,6 +183,7 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
walletConnectSessionsRepository = walletConnectSessionsRepository,
|
||||
tokenDetailsFeatureToggles = tokenDetailsFeatureToggles,
|
||||
scanCardProcessor = scanCardProcessor,
|
||||
appCurrencyRepository = appCurrencyRepository,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ fun Blockchain.getGreyedOutIconRes(): Int {
|
|||
Blockchain.Ethereum, Blockchain.EthereumTestnet -> R.drawable.ic_eth_no_color
|
||||
Blockchain.EthereumClassic, Blockchain.EthereumClassicTestnet -> R.drawable.ic_eth_no_color
|
||||
Blockchain.RSK -> R.drawable.ic_rsk_no_color
|
||||
Blockchain.Cardano, Blockchain.CardanoShelley -> R.drawable.ic_cardano_no_color
|
||||
Blockchain.Cardano -> R.drawable.ic_cardano_no_color
|
||||
Blockchain.Tezos -> R.drawable.ic_tezos_no_color
|
||||
Blockchain.XRP -> R.drawable.ic_xrp_no_color
|
||||
Blockchain.Stellar -> R.drawable.ic_stellar_no_color
|
||||
|
|
@ -46,6 +46,7 @@ fun Blockchain.getGreyedOutIconRes(): Int {
|
|||
Blockchain.Telos, Blockchain.TelosTestnet -> R.drawable.ic_telos_no_color
|
||||
Blockchain.AlephZero, Blockchain.AlephZeroTestnet -> R.drawable.ic_azero_no_color
|
||||
Blockchain.OctaSpace, Blockchain.OctaSpaceTestnet -> R.drawable.ic_octaspace_no_color
|
||||
Blockchain.Chia, Blockchain.ChiaTestnet -> R.drawable.ic_chia_no_color
|
||||
else -> R.drawable.ic_tangem_logo
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ import com.tangem.domain.common.LogConfig
|
|||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.*
|
||||
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
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||
|
|
@ -24,17 +26,13 @@ import com.tangem.tap.network.exchangeServices.ExchangeService
|
|||
import com.tangem.tap.network.exchangeServices.mercuryo.MercuryoEnvironment
|
||||
import com.tangem.tap.network.exchangeServices.mercuryo.MercuryoService
|
||||
import com.tangem.tap.network.exchangeServices.moonpay.MoonPayService
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.tap.userTokensRepository
|
||||
import com.tangem.tap.walletCurrenciesManager
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.DispatchFunction
|
||||
import org.rekotlin.Middleware
|
||||
import java.util.*
|
||||
import java.util.Locale
|
||||
|
||||
object GlobalMiddleware {
|
||||
val handler = globalMiddlewareHandler
|
||||
|
|
@ -68,13 +66,11 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
|
|||
}
|
||||
}
|
||||
is GlobalAction.RestoreAppCurrency -> {
|
||||
store.dispatch(
|
||||
GlobalAction.RestoreAppCurrency.Success(
|
||||
preferencesStorage.fiatCurrenciesPrefStorage.getAppCurrency()
|
||||
?.run { FiatCurrency(code, name, symbol) }
|
||||
?: FiatCurrency.Default,
|
||||
),
|
||||
)
|
||||
if (store.state.daggerGraphState.get(DaggerGraphState::walletFeatureToggles).isRedesignedScreenEnabled) {
|
||||
restoreAppCurrencyNew()
|
||||
} else {
|
||||
restoreAppCurrencyLegacy()
|
||||
}
|
||||
}
|
||||
is GlobalAction.HideWarningMessage -> {
|
||||
store.state.globalState.warningManager?.let {
|
||||
|
|
@ -193,6 +189,28 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
|
|||
}
|
||||
}
|
||||
|
||||
private fun restoreAppCurrencyLegacy() {
|
||||
store.dispatch(
|
||||
GlobalAction.RestoreAppCurrency.Success(
|
||||
preferencesStorage.fiatCurrenciesPrefStorage.getAppCurrency()
|
||||
?.run { FiatCurrency(code, name, symbol) }
|
||||
?: FiatCurrency.Default,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun restoreAppCurrencyNew() {
|
||||
scope.launch {
|
||||
val currency = store.state.daggerGraphState.get(DaggerGraphState::appCurrencyRepository)
|
||||
.getSelectedAppCurrency()
|
||||
.firstOrNull()
|
||||
?.run { FiatCurrency(code, name, symbol) }
|
||||
?: FiatCurrency.Default
|
||||
|
||||
store.dispatchWithMain(GlobalAction.RestoreAppCurrency.Success(currency))
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeSellExchangeService(config: Config): ExchangeService {
|
||||
return MoonPayService(
|
||||
apiKey = config.moonPayApiKey,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ internal class RuntimeUserWalletsStore(
|
|||
private val walletsStateHolder: WalletsStateHolder,
|
||||
) : UserWalletsStore {
|
||||
|
||||
override val selectedUserWalletOrNull: UserWallet?
|
||||
get() = walletsStateHolder.userWalletsListManager?.selectedUserWalletSync
|
||||
|
||||
override suspend fun getSyncOrNull(key: UserWalletId): UserWallet? {
|
||||
return walletsStateHolder.userWalletsListManager
|
||||
?.userWallets
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
internal object AppCurrencyDomainModule {
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetSelectedAppCurrencyUseCase(
|
||||
appCurrencyRepository: AppCurrencyRepository,
|
||||
): GetSelectedAppCurrencyUseCase {
|
||||
return GetSelectedAppCurrencyUseCase(appCurrencyRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.tokens.repository.TokensRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -18,23 +18,34 @@ internal object TokensDomainModule {
|
|||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetTokenListUseCase(
|
||||
tokensRepository: TokensRepository,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetTokenListUseCase {
|
||||
return GetTokenListUseCase(tokensRepository, quotesRepository, networksRepository, dispatchers)
|
||||
return GetTokenListUseCase(currenciesRepository, quotesRepository, networksRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetCurrencyUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetCurrencyUseCase {
|
||||
return GetCurrencyUseCase(currenciesRepository, quotesRepository, networksRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetPrimaryCurrencyUseCase(
|
||||
tokensRepository: TokensRepository,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetPrimaryCurrencyUseCase {
|
||||
return GetPrimaryCurrencyUseCase(tokensRepository, quotesRepository, networksRepository, dispatchers)
|
||||
return GetPrimaryCurrencyUseCase(currenciesRepository, quotesRepository, networksRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -55,9 +66,9 @@ internal object TokensDomainModule {
|
|||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideApplyTokenListSortingUseCase(
|
||||
tokensRepository: TokensRepository,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): ApplyTokenListSortingUseCase {
|
||||
return ApplyTokenListSortingUseCase(tokensRepository, dispatchers)
|
||||
return ApplyTokenListSortingUseCase(currenciesRepository, dispatchers)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,7 @@ package com.tangem.tap.di.domain
|
|||
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.legacy.WalletsStateHolder
|
||||
import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
|
||||
import com.tangem.domain.wallets.usecase.*
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -21,6 +19,12 @@ internal object WalletsDomainModule {
|
|||
return GetWalletsUseCase(walletsStateHolder = walletsStateHolder)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesGetSelectedWalletUseCase(walletsStateHolder: WalletsStateHolder): GetSelectedWalletUseCase {
|
||||
return GetSelectedWalletUseCase(walletsStateHolder = walletsStateHolder)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesSaveWalletUseCase(walletsStateHolder: WalletsStateHolder): SaveWalletUseCase {
|
||||
|
|
@ -32,4 +36,16 @@ internal object WalletsDomainModule {
|
|||
fun providesGetExploreUrlUseCase(walletsManagersFacade: WalletManagersFacade): GetExploreUrlUseCase {
|
||||
return GetExploreUrlUseCase(walletsManagersFacade = walletsManagersFacade)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesUnlockWalletUseCase(walletsStateHolder: WalletsStateHolder): UnlockWalletsUseCase {
|
||||
return UnlockWalletsUseCase(walletsStateHolder = walletsStateHolder)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesSelectWalletUseCase(walletsStateHolder: WalletsStateHolder): SelectWalletUseCase {
|
||||
return SelectWalletUseCase(walletsStateHolder = walletsStateHolder)
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ import com.tangem.crypto.bip39.DefaultMnemonic
|
|||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.ScanTask
|
||||
|
|
@ -80,7 +81,10 @@ class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigReposit
|
|||
|
||||
suspend fun createProductWallet(scanResponse: ScanResponse): CompletionResult<CreateProductWalletTaskResponse> {
|
||||
return runTaskAsync(
|
||||
CreateProductWalletTask(scanResponse.cardTypesResolver),
|
||||
CreateProductWalletTask(
|
||||
cardTypesResolver = scanResponse.cardTypesResolver,
|
||||
derivationStyleProvider = scanResponse.derivationStyleProvider,
|
||||
),
|
||||
scanResponse.card.cardId,
|
||||
Message(resources.getString(R.string.initial_message_create_wallet_body)),
|
||||
)
|
||||
|
|
@ -90,15 +94,20 @@ class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigReposit
|
|||
scanResponse: ScanResponse,
|
||||
mnemonic: String,
|
||||
): CompletionResult<CreateProductWalletTaskResponse> {
|
||||
return when (val seedResult = DefaultMnemonic(mnemonic, tangemSdk.wordlist).generateSeed()) {
|
||||
is CompletionResult.Success -> runTaskAsync(
|
||||
CreateProductWalletTask(scanResponse.cardTypesResolver, seedResult.data),
|
||||
scanResponse.card.cardId,
|
||||
Message(resources.getString(R.string.initial_message_create_wallet_body)),
|
||||
)
|
||||
|
||||
is CompletionResult.Failure -> CompletionResult.Failure(seedResult.error)
|
||||
val mnemonic = try {
|
||||
DefaultMnemonic(mnemonic, tangemSdk.wordlist)
|
||||
} catch (e: TangemSdkError.MnemonicException) {
|
||||
return CompletionResult.Failure(e)
|
||||
}
|
||||
return runTaskAsync(
|
||||
CreateProductWalletTask(
|
||||
scanResponse.cardTypesResolver,
|
||||
derivationStyleProvider = scanResponse.derivationStyleProvider,
|
||||
mnemonic,
|
||||
),
|
||||
scanResponse.card.cardId,
|
||||
Message(resources.getString(R.string.initial_message_create_wallet_body)),
|
||||
)
|
||||
}
|
||||
|
||||
private fun sendScanResultsToAnalytics(result: CompletionResult<ScanResponse>) {
|
||||
|
|
@ -246,12 +255,13 @@ class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigReposit
|
|||
}
|
||||
|
||||
companion object {
|
||||
@Deprecated("Use [DefaultCardSdkProvider] instead")
|
||||
val config = Config(
|
||||
linkedTerminal = true,
|
||||
allowUntrustedCards = true,
|
||||
filter = CardFilter(
|
||||
allowedCardTypes = FirmwareVersion.FirmwareType.values().toList(),
|
||||
maxFirmwareVersion = FirmwareVersion(major = 6, minor = 21),
|
||||
maxFirmwareVersion = FirmwareVersion(major = 6, minor = 33),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,8 @@ sealed class TapError(
|
|||
val stateError: String,
|
||||
) : TapError(R.string.common_custom_string, listOf("Unsupported state: $stateError"))
|
||||
|
||||
object ScanCardError : TapError(R.string.scan_card_error)
|
||||
object UnknownBlockchain : TapError(R.string.wallet_error_unsupported_blockchain_subtitle)
|
||||
object NoInternetConnection : TapError(R.string.wallet_notification_no_internet)
|
||||
object BlockchainInternalError : TapError(R.string.send_error_blockchain_internal)
|
||||
object AmountExceedsBalance : TapError(R.string.send_validation_amount_exceeds_balance)
|
||||
data class AmountLowerExistentialDeposit(
|
||||
override val args: List<Any>,
|
||||
|
|
@ -43,7 +41,7 @@ sealed class TapError(
|
|||
object DustChange : TapError(R.string.send_error_dust_change)
|
||||
|
||||
sealed class WalletManager {
|
||||
object CreationError : CustomError("Can't create wallet manager")
|
||||
object CreationError : CustomError(customMessage = "Can't create wallet manager")
|
||||
class NoAccountError(amountToCreateAccount: String) : CustomError(amountToCreateAccount)
|
||||
class InternalError(message: String) : CustomError(message)
|
||||
object BlockchainIsUnreachableTryLater : TapError(R.string.wallet_balance_blockchain_unreachable_try_later)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.tangem.common.doOnFailure
|
|||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -20,6 +21,8 @@ import com.tangem.tap.common.extensions.dispatchWithMain
|
|||
import com.tangem.tap.common.extensions.setContext
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.walletStores.WalletStoresError
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.Account
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
import com.tangem.tap.features.disclaimer.createDisclaimer
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
||||
|
|
@ -92,7 +95,8 @@ class TapWalletManager(
|
|||
null
|
||||
}
|
||||
scope.launch {
|
||||
store.state.daggerGraphState.walletConnectInteractor?.startListening(
|
||||
val wcInteractor = store.state.daggerGraphState.walletConnectInteractor ?: return@launch
|
||||
wcInteractor.startListening(
|
||||
userWalletId = userWallet.walletId.stringValue,
|
||||
cardId = cardId,
|
||||
)
|
||||
|
|
@ -106,6 +110,9 @@ class TapWalletManager(
|
|||
store.dispatchOnMain(WalletAction.LoadData.Success)
|
||||
store.state.globalState.topUpController?.loadDataSuccess()
|
||||
store.dispatchWithMain(WalletAction.Warnings.CheckHashesCount.VerifyOnlineIfNeeded)
|
||||
|
||||
val wcInteractor = store.state.daggerGraphState.walletConnectInteractor
|
||||
wcInteractor?.setUserChains(getAccountsForWc(wcInteractor))
|
||||
}
|
||||
.doOnFailure { error ->
|
||||
val errorAction = when (error) {
|
||||
|
|
@ -135,6 +142,23 @@ class TapWalletManager(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getAccountsForWc(wcInteractor: WalletConnectInteractor): List<Account> {
|
||||
return store.state.walletState.walletManagers
|
||||
.mapNotNull {
|
||||
val wallet = it.wallet
|
||||
val chainId = wcInteractor.blockchainHelper.networkIdToChainIdOrNull(
|
||||
wallet.blockchain.toNetworkId(),
|
||||
)
|
||||
chainId?.let {
|
||||
Account(
|
||||
chainId,
|
||||
wallet.address,
|
||||
wallet.publicKey.derivationPath?.rawPath,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateConfigManager(data: ScanResponse) {
|
||||
val configManager = store.state.globalState.configManager
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.domain.configurable.warningMessage
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.utils.extensions.removeByReplace
|
||||
import com.tangem.utils.extensions.removeBy
|
||||
import com.tangem.wallet.R
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
|
|
@ -44,12 +44,12 @@ class WarningMessagesManager {
|
|||
}
|
||||
|
||||
fun removeWarnings(origin: WarningMessage.Origin) {
|
||||
warningsList.removeByReplace { it.origin == origin }
|
||||
warningsList.removeBy { it.origin == origin }
|
||||
sortByPriority()
|
||||
}
|
||||
|
||||
fun removeWarnings(messageRes: Int) {
|
||||
warningsList.removeByReplace { it.messageResId == messageRes }
|
||||
warningsList.removeBy { it.messageResId == messageRes }
|
||||
}
|
||||
|
||||
fun containsWarning(warning: WarningMessage) = warning in warningsList
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
package com.tangem.tap.domain.model.builders
|
||||
|
||||
import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.domain.model.WalletStoreModel
|
||||
|
|
@ -47,7 +51,7 @@ private class BlockchainNetworkWalletStoreBuilderImpl(
|
|||
}
|
||||
|
||||
override fun build(): WalletStoreModel {
|
||||
val cardDerivationStyle = userWallet.scanResponse.card.derivationStyle
|
||||
val cardDerivationStyle = userWallet.scanResponse.derivationStyleProvider.getDerivationStyle()
|
||||
val blockchainWalletData = blockchainNetwork.getBlockchainWalletData(walletManager, cardDerivationStyle)
|
||||
val tokensWalletsData = blockchainNetwork.getTokensWalletsData(
|
||||
walletManager = walletManager,
|
||||
|
|
|
|||
|
|
@ -11,10 +11,12 @@ import com.tangem.common.extensions.ByteArrayKey
|
|||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.extensions.toMapKey
|
||||
import com.tangem.common.map
|
||||
import com.tangem.crypto.bip39.Mnemonic
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.TapWorkarounds.isTestCard
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.KeyWalletPublicKey
|
||||
import com.tangem.operations.CommandResponse
|
||||
|
|
@ -56,7 +58,8 @@ private data class CreateWalletResponse(
|
|||
|
||||
class CreateProductWalletTask(
|
||||
private val cardTypesResolver: CardTypesResolver,
|
||||
private val seed: ByteArray? = null,
|
||||
private val derivationStyleProvider: DerivationStyleProvider,
|
||||
private val mnemonic: Mnemonic? = null,
|
||||
) : CardSessionRunnable<CreateProductWalletTaskResponse> {
|
||||
|
||||
override val allowsRequestAccessCodeFromRepository: Boolean = false
|
||||
|
|
@ -76,7 +79,7 @@ class CreateProductWalletTask(
|
|||
cardTypesResolver.isTangemTwins() ->
|
||||
throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
|
||||
|
||||
else -> CreateWalletTangemWallet(seed)
|
||||
else -> CreateWalletTangemWallet(mnemonic, derivationStyleProvider)
|
||||
}
|
||||
commandProcessor.proceed(cardDto, session) {
|
||||
when (it) {
|
||||
|
|
@ -131,8 +134,12 @@ private class CreateWalletTangemNote(private val cardTypesResolver: CardTypesRes
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses for multiWallet 1st and 2nd
|
||||
*/
|
||||
private class CreateWalletTangemWallet(
|
||||
private val seed: ByteArray?,
|
||||
private val mnemonic: Mnemonic?,
|
||||
private val derivationStyleProvider: DerivationStyleProvider,
|
||||
) : ProductCommandProcessor<CreateProductWalletTaskResponse> {
|
||||
|
||||
private var primaryCard: PrimaryCard? = null
|
||||
|
|
@ -142,8 +149,9 @@ private class CreateWalletTangemWallet(
|
|||
session: CardSession,
|
||||
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
|
||||
) {
|
||||
val config = CardConfig.createConfig(card)
|
||||
val walletsOnCard = card.wallets.map { it.curve }.toSet()
|
||||
val curves = card.supportedCurves.intersect(CURVES_FOR_WALLETS).subtract(walletsOnCard).toList()
|
||||
val curves = card.supportedCurves.intersect(config.mandatoryCurves.toSet()).subtract(walletsOnCard).toList()
|
||||
|
||||
if (curves.isEmpty()) {
|
||||
val createWalletResponses = card.wallets.map { wallet ->
|
||||
|
|
@ -152,8 +160,7 @@ private class CreateWalletTangemWallet(
|
|||
proceedWithCreatedWallets(card, createWalletResponses, session, callback)
|
||||
return
|
||||
}
|
||||
|
||||
CreateWalletsTask(curves, seed).run(session) { result ->
|
||||
CreateWalletsTask(curves, mnemonic).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
proceedWithCreatedWallets(
|
||||
|
|
@ -242,9 +249,9 @@ private class CreateWalletTangemWallet(
|
|||
val blockchainsForCurve = getBlockchains(response.cardId, card).filter {
|
||||
it.getSupportedCurves().contains(response.wallet.curve)
|
||||
}
|
||||
val derivationPaths = blockchainsForCurve.mapNotNull {
|
||||
val derivationPaths = blockchainsForCurve.mapNotNull { blockchain ->
|
||||
isBlockchainsForCurvesExist = true
|
||||
it.derivationPath(card.derivationStyle)
|
||||
blockchain.derivationPath(derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
if (derivationPaths.isNotEmpty()) {
|
||||
map[response.wallet.publicKey.toMapKey()] = derivationPaths
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import com.tangem.common.card.EllipticCurve
|
|||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.crypto.bip39.Mnemonic
|
||||
import com.tangem.crypto.hdWallet.masterkey.AnyMasterKeyFactory
|
||||
import com.tangem.operations.CommandResponse
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.operations.wallet.CreateWalletTask
|
||||
|
|
@ -18,7 +20,7 @@ class CreateWalletsResponse(
|
|||
|
||||
class CreateWalletsTask(
|
||||
private val curves: List<EllipticCurve>,
|
||||
private val seed: ByteArray? = null,
|
||||
private val mnemonic: Mnemonic? = null,
|
||||
) : CardSessionRunnable<CreateWalletsResponse> {
|
||||
|
||||
private val createdWalletsResponses = mutableListOf<CreateWalletResponse>()
|
||||
|
|
@ -38,7 +40,10 @@ class CreateWalletsTask(
|
|||
session: CardSession,
|
||||
callback: (result: CompletionResult<CreateWalletsResponse>) -> Unit,
|
||||
) {
|
||||
CreateWalletTask(curve, seed).run(session) { result ->
|
||||
val extendedPrivateKey = mnemonic?.let {
|
||||
AnyMasterKeyFactory(mnemonic = it, passphrase = "").makeMasterKey(curve)
|
||||
}
|
||||
CreateWalletTask(curve, extendedPrivateKey).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
createdWalletsResponses.add(result.data)
|
||||
|
|
|
|||
|
|
@ -14,13 +14,15 @@ import com.tangem.common.tlv.TlvDecoder
|
|||
import com.tangem.crypto.CryptoUtils
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.TapWorkarounds.isExcluded
|
||||
import com.tangem.domain.common.TapWorkarounds.isNotSupportedInThatRelease
|
||||
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
||||
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
|
||||
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
|
||||
import com.tangem.domain.common.TwinsHelper
|
||||
import com.tangem.domain.common.extensions.getPrimaryCurve
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -51,7 +53,7 @@ class ScanProductTask(
|
|||
}
|
||||
val cardDto = CardDTO(card)
|
||||
|
||||
val error = getErrorIfExcludedCard(cardDto, card)
|
||||
val error = getErrorIfExcludedCard(cardDto)
|
||||
if (error != null) {
|
||||
callback(CompletionResult.Failure(error))
|
||||
return
|
||||
|
|
@ -81,11 +83,9 @@ class ScanProductTask(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getErrorIfExcludedCard(cardDto: CardDTO, card: Card): TangemError? {
|
||||
private fun getErrorIfExcludedCard(cardDto: CardDTO): TangemError? {
|
||||
if (cardDto.isExcluded) return TapSdkError.CardForDifferentApp
|
||||
if (cardDto.isNotSupportedInThatRelease) return TapSdkError.CardNotSupportedByRelease
|
||||
// todo check isImported to prevent using old app with imported wallet, remove before wallet 2.0 enabled ([REDACTED_TASK_KEY])
|
||||
if (card.wallets.any { it.isImported }) return TapSdkError.CardNotSupportedByRelease
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
|
@ -209,32 +209,24 @@ private class ScanWalletProcessor(
|
|||
callback: (result: CompletionResult<ScanResponse>) -> Unit,
|
||||
) {
|
||||
val productType = ProductType.Wallet
|
||||
val config = CardConfig.createConfig(card)
|
||||
scope.launch {
|
||||
val derivations = collectDerivations(card)
|
||||
val scanResponse = ScanResponse(
|
||||
card = card,
|
||||
productType = productType,
|
||||
walletData = session.environment.walletData,
|
||||
primaryCard = primaryCard,
|
||||
)
|
||||
val derivations = collectDerivations(card, config, scanResponse.derivationStyleProvider)
|
||||
if (derivations.isEmpty() || !card.settings.isHDWalletAllowed) {
|
||||
callback(
|
||||
CompletionResult.Success(
|
||||
ScanResponse(
|
||||
card = card,
|
||||
productType = productType,
|
||||
walletData = session.environment.walletData,
|
||||
primaryCard = primaryCard,
|
||||
),
|
||||
),
|
||||
)
|
||||
callback(CompletionResult.Success(scanResponse))
|
||||
return@launch
|
||||
}
|
||||
|
||||
DeriveMultipleWalletPublicKeysTask(derivations).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
val response = ScanResponse(
|
||||
card = card,
|
||||
productType = productType,
|
||||
walletData = session.environment.walletData,
|
||||
derivedKeys = result.data.entries,
|
||||
primaryCard = primaryCard,
|
||||
)
|
||||
val response = scanResponse.copy(derivedKeys = result.data.entries)
|
||||
callback(CompletionResult.Success(response))
|
||||
}
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
|
||||
|
|
@ -243,7 +235,10 @@ private class ScanWalletProcessor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun getBlockchainsToDerive(card: CardDTO): List<BlockchainNetwork> {
|
||||
private suspend fun getBlockchainsToDerive(
|
||||
card: CardDTO,
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
): List<BlockchainNetwork> {
|
||||
val userTokensRepository = userTokensRepository ?: return emptyList()
|
||||
val blockchainsToDerive = userTokensRepository.loadBlockchainsToDerive(card)
|
||||
.toMutableList()
|
||||
|
|
@ -251,11 +246,11 @@ private class ScanWalletProcessor(
|
|||
mutableListOf(
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Bitcoin,
|
||||
card = card,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
),
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Ethereum,
|
||||
card = card,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -265,11 +260,11 @@ private class ScanWalletProcessor(
|
|||
listOf(
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Ethereum,
|
||||
card = card,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
),
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.EthereumTestnet,
|
||||
card = card,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -279,7 +274,7 @@ private class ScanWalletProcessor(
|
|||
additionalBlockchainsToDerive.map {
|
||||
BlockchainNetwork(
|
||||
blockchain = it,
|
||||
card = card,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -295,7 +290,7 @@ private class ScanWalletProcessor(
|
|||
).map {
|
||||
BlockchainNetwork(
|
||||
blockchain = it,
|
||||
card = card,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -303,12 +298,16 @@ private class ScanWalletProcessor(
|
|||
return blockchainsToDerive.distinct()
|
||||
}
|
||||
|
||||
private suspend fun collectDerivations(card: CardDTO): Map<ByteArrayKey, List<DerivationPath>> {
|
||||
val blockchains = getBlockchainsToDerive(card)
|
||||
private suspend fun collectDerivations(
|
||||
card: CardDTO,
|
||||
config: CardConfig,
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
): Map<ByteArrayKey, List<DerivationPath>> {
|
||||
val blockchains = getBlockchainsToDerive(card, derivationStyleProvider)
|
||||
val derivations = mutableMapOf<ByteArrayKey, List<DerivationPath>>()
|
||||
|
||||
blockchains.forEach { blockchain ->
|
||||
val curve = blockchain.blockchain.getPrimaryCurve()
|
||||
val curve = config.primaryCurve(blockchain.blockchain)
|
||||
val wallet = card.wallets.firstOrNull { it.curve == curve } ?: return@forEach
|
||||
if (wallet.chainCode == null) return@forEach
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
package com.tangem.tap.domain.tokens
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.card.FirmwareVersion
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
|
||||
object CurrenciesRepository {
|
||||
fun getBlockchains(cardFirmware: CardDTO.FirmwareVersion, isTestNet: Boolean = false): List<Blockchain> {
|
||||
val blockchains = if (cardFirmware < FirmwareVersion.MultiWalletAvailable) {
|
||||
Blockchain.secp256k1Blockchains(isTestNet)
|
||||
} else {
|
||||
Blockchain.secp256k1Blockchains(isTestNet) + Blockchain.ed25519OnlyBlockchains(isTestNet)
|
||||
}
|
||||
return excludeUnsupportedBlockchains(blockchains)
|
||||
}
|
||||
|
||||
// Use this list to temporarily exclude a blockchain from the list of tokens.
|
||||
private fun excludeUnsupportedBlockchains(blockchains: List<Blockchain>): List<Blockchain> {
|
||||
return blockchains.toMutableList().apply {
|
||||
removeAll(
|
||||
listOf(
|
||||
// Any blockchain
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.domain.tokens
|
||||
|
||||
import android.content.Context
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechService
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@ class CreateSecondTwinWalletTask(
|
|||
return
|
||||
}
|
||||
|
||||
if (!TwinsHelper.isTwinsCompatible(firstCardId, card.cardId)) {
|
||||
callback(CompletionResult.Failure(IncompatibleTwinCard))
|
||||
return
|
||||
}
|
||||
|
||||
session.setMessage(preparingMessage)
|
||||
PurgeWalletCommand(publicKey).run(session) { response ->
|
||||
when (response) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.tap.domain.twins
|
||||
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.wallet.R
|
||||
|
||||
object IncompatibleTwinCard : TangemError(code = 50005) {
|
||||
override var customMessage: String = tangemSdkManager.getString(
|
||||
R.string.twin_error_wrong_twin,
|
||||
)
|
||||
override val messageResId: Int? = null
|
||||
}
|
||||
|
|
@ -2,10 +2,10 @@ package com.tangem.tap.domain.userWalletList.implementation
|
|||
|
||||
import com.tangem.common.*
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletsListError
|
||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||
import com.tangem.tap.domain.userWalletList.repository.SelectedUserWalletRepository
|
||||
import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ package com.tangem.tap.domain.userWalletList.implementation
|
|||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.catching
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletsListError
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import com.tangem.common.biometric.BiometricManager
|
|||
import com.tangem.common.biometric.BiometricStorage
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.services.secure.SecureStorage
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletsListError
|
||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||
import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import com.tangem.domain.wallets.models.UserWalletId
|
|||
import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
|
||||
import com.tangem.tap.domain.userWalletList.repository.UserWalletsPublicInformationRepository
|
||||
import com.tangem.tap.domain.userWalletList.utils.publicInformation
|
||||
import com.tangem.utils.extensions.plusOrReplace
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ internal class DefaultUserWalletsPublicInformationRepository(
|
|||
getAll()
|
||||
.flatMap { savedInformation ->
|
||||
val infoToSave = withContext(Dispatchers.Default) {
|
||||
savedInformation.plusOrReplace(userWallet.publicInformation) {
|
||||
savedInformation.addOrReplace(userWallet.publicInformation) {
|
||||
userWallet.walletId == it.walletId
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
package com.tangem.tap.domain.walletCurrencies.implementation
|
||||
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.common.*
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.wallets.legacy.WalletManagersRepository
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
|
|
@ -61,7 +62,9 @@ internal class DefaultWalletCurrenciesManager(
|
|||
}
|
||||
|
||||
val card = userWallet.scanResponse.card
|
||||
val currenciesToAddWithMissingBlockchains = currenciesToAdd.addMissingBlockchainsIfNeeded(card)
|
||||
val currenciesToAddWithMissingBlockchains = currenciesToAdd.addMissingBlockchainsIfNeeded(
|
||||
userWallet.scanResponse.derivationStyleProvider,
|
||||
)
|
||||
listeners.forEach { it.willCurrenciesAdd(userWallet, currenciesToAddWithMissingBlockchains) }
|
||||
|
||||
updateWalletStores(
|
||||
|
|
@ -167,13 +170,15 @@ internal class DefaultWalletCurrenciesManager(
|
|||
return networks
|
||||
}
|
||||
|
||||
private fun List<Currency>.addMissingBlockchainsIfNeeded(card: CardDTO): List<Currency> {
|
||||
private fun List<Currency>.addMissingBlockchainsIfNeeded(
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
): List<Currency> {
|
||||
if (this.isEmpty()) return this
|
||||
val currencies = this.asSequence()
|
||||
|
||||
return currencies
|
||||
.groupBy { currency ->
|
||||
findBlockchainCurrency(currency, currencies, card.derivationStyle)
|
||||
findBlockchainCurrency(currency, currencies, derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
.mapValues { (blockchainCurrency, blockchainCurrencies) ->
|
||||
findBlockchainTokens(blockchainCurrency, blockchainCurrencies)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import com.tangem.tap.features.wallet.models.getPendingTransactions
|
|||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.plusOrReplace
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import timber.log.Timber
|
||||
|
|
@ -429,7 +429,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
withContext(Dispatchers.Default) {
|
||||
WalletManagerStorage.update { prevManagers ->
|
||||
val newManagersForUserWallet = prevManagers[userWalletId].orEmpty()
|
||||
.plusOrReplace(walletManager) {
|
||||
.addOrReplace(walletManager) {
|
||||
it.wallet.blockchain == walletManager.wallet.blockchain
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.domain.walletStores.repository.implementation
|
||||
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.catching
|
||||
import com.tangem.common.doOnSuccess
|
||||
|
|
|
|||
|
|
@ -100,6 +100,28 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
Timber.d("sessionProposal: $sessionProposal")
|
||||
this@WalletConnectRepositoryImpl.sessionProposal = sessionProposal
|
||||
|
||||
val missingNetworks = findMissingNetworks(
|
||||
namespaces = sessionProposal.requiredNamespaces,
|
||||
userNamespaces = this@WalletConnectRepositoryImpl.userNamespaces ?: emptyMap(),
|
||||
)
|
||||
|
||||
if (missingNetworks.isNotEmpty()) {
|
||||
Timber.w("Not added blockchains: $missingNetworks")
|
||||
scope.launch {
|
||||
_events.emit(
|
||||
WalletConnectEvents.SessionApprovalError(
|
||||
WalletConnectError.ApprovalErrorMissingNetworks(missingNetworks.toList()),
|
||||
),
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val optionalWithoutMissingNetworks = removeMissingNetworks(
|
||||
namespaces = sessionProposal.optionalNamespaces,
|
||||
userNamespaces = this@WalletConnectRepositoryImpl.userNamespaces ?: emptyMap(),
|
||||
)
|
||||
|
||||
scope.launch {
|
||||
_events.emit(
|
||||
WalletConnectEvents.SessionProposal(
|
||||
|
|
@ -108,7 +130,7 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
sessionProposal.url,
|
||||
sessionProposal.icons,
|
||||
sessionProposal.requiredNamespaces.values.flatMap { it.chains ?: emptyList() },
|
||||
sessionProposal.optionalNamespaces.values.flatMap { it.chains ?: emptyList() },
|
||||
optionalWithoutMissingNetworks.toList(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -211,6 +233,10 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun setUserNamespaces(userNamespaces: Map<NetworkNamespace, List<Account>>) {
|
||||
this.userNamespaces = userNamespaces
|
||||
}
|
||||
|
||||
override fun pair(uri: String) {
|
||||
Web3Wallet.pair(Wallet.Params.Pair(uri))
|
||||
}
|
||||
|
|
@ -220,23 +246,6 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
|
||||
val sessionProposal: Wallet.Model.SessionProposal = requireNotNull(this.sessionProposal)
|
||||
|
||||
val missingNetworks = findMissingNetworks(
|
||||
namespaces = sessionProposal.requiredNamespaces,
|
||||
userNamespaces = userNamespaces,
|
||||
)
|
||||
|
||||
if (missingNetworks.isNotEmpty()) {
|
||||
Timber.e("Not added blockchains: $missingNetworks")
|
||||
scope.launch {
|
||||
_events.emit(
|
||||
WalletConnectEvents.SessionApprovalError(
|
||||
WalletConnectError.ApprovalErrorMissingNetworks(missingNetworks.toList()),
|
||||
),
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val userChains = userNamespaces.flatMap { namespace ->
|
||||
namespace.value.map { it.chainId to "${it.chainId}:${it.walletAddress}" }
|
||||
}.groupBy { pair -> pair.first }
|
||||
|
|
@ -433,4 +442,13 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
val userChains = userNamespaces.flatMap { it.value.map { account -> account.chainId } }
|
||||
return requiredChains.subtract(userChains.toSet())
|
||||
}
|
||||
|
||||
private fun removeMissingNetworks(
|
||||
namespaces: Map<String, Wallet.Model.Namespace.Proposal>,
|
||||
userNamespaces: Map<NetworkNamespace, List<Account>>,
|
||||
): Collection<String> {
|
||||
val wcProvidedChains = namespaces.values.flatMap { it.chains ?: emptyList() }
|
||||
val userChains = userNamespaces.flatMap { it.value.map { account -> account.chainId } }
|
||||
return wcProvidedChains.intersect(userChains.toSet())
|
||||
}
|
||||
}
|
||||
|
|
@ -44,6 +44,15 @@ class WalletConnectInteractor(
|
|||
}
|
||||
}
|
||||
|
||||
fun setUserChains(accounts: List<Account>) {
|
||||
val userNamespaces: Map<NetworkNamespace, List<Account>> = accounts
|
||||
.groupBy { account ->
|
||||
blockchainHelper.getNamespaceFromFullChainIdOrNull(account.chainId)
|
||||
?.let { NetworkNamespace(it) }
|
||||
}.filterNotNull()
|
||||
walletConnectRepository.setUserNamespaces(userNamespaces)
|
||||
}
|
||||
|
||||
private suspend fun subscribeToEvents() {
|
||||
events
|
||||
.onEach { wcEvent ->
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ interface WalletConnectRepository {
|
|||
|
||||
fun init(projectId: String)
|
||||
|
||||
fun setUserNamespaces(userNamespaces: Map<NetworkNamespace, List<Account>>)
|
||||
|
||||
fun updateSessions()
|
||||
|
||||
fun pair(uri: String)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.blockchain.common.Blockchain
|
|||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.domain.common.extensions.supportedBlockchains
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.tap.features.customtoken.impl.data.converters.FoundTokenConverter
|
||||
import com.tangem.tap.features.customtoken.impl.domain.CustomTokenRepository
|
||||
import com.tangem.tap.features.customtoken.impl.domain.models.FoundToken
|
||||
|
|
@ -27,8 +28,9 @@ class DefaultCustomTokenRepository(
|
|||
) : CustomTokenRepository {
|
||||
|
||||
override suspend fun findToken(address: String, networkId: String?): FoundToken {
|
||||
val supportedTokenNetworkIds = requireNotNull(reduxStateHolder.scanResponse?.card)
|
||||
.supportedBlockchains()
|
||||
val scanResponse = requireNotNull(reduxStateHolder.scanResponse)
|
||||
val supportedTokenNetworkIds = requireNotNull(scanResponse.card)
|
||||
.supportedBlockchains(scanResponse.cardTypesResolver)
|
||||
.filter(Blockchain::canHandleTokens)
|
||||
.map(Blockchain::toNetworkId)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ import com.tangem.common.extensions.guard
|
|||
import com.tangem.common.extensions.toMapKey
|
||||
import com.tangem.common.flatMap
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.util.hasDerivation
|
||||
import com.tangem.domain.features.addCustomToken.CustomCurrency
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -68,10 +69,11 @@ class DefaultCustomTokenInteractor(
|
|||
currencyList: List<Currency>,
|
||||
onSuccess: suspend (ScanResponse) -> Unit,
|
||||
) {
|
||||
val derivationDataList = listOfNotNull(
|
||||
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencyList),
|
||||
getDerivations(EllipticCurve.Ed25519, scanResponse, currencyList),
|
||||
)
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivationDataList = currencyList.mapNotNull {
|
||||
val curve = config.primaryCurve(it.blockchain)
|
||||
curve?.let { getDerivations(curve, scanResponse, currencyList) }
|
||||
}
|
||||
|
||||
val derivations = derivationDataList.associate(TokensMiddleware.DerivationData::derivations)
|
||||
if (derivations.isEmpty()) {
|
||||
|
|
@ -114,7 +116,7 @@ class DefaultCustomTokenInteractor(
|
|||
val manageTokensCandidates = currencyList.map { it.blockchain }.distinct().filter {
|
||||
it.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull {
|
||||
it.derivationPath(scanResponse.card.derivationStyle)
|
||||
it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
|
||||
val customTokensCandidates = currencyList.filter {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ internal fun AddCustomTokenFloatingButton(model: AddCustomTokenFloatingButton, m
|
|||
.imePadding()
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(id = R.string.common_add),
|
||||
text = stringResource(id = R.string.custom_token_add_token),
|
||||
iconResId = R.drawable.ic_plus_24,
|
||||
enabled = model.isEnabled,
|
||||
onClick = model.onClick,
|
||||
|
|
|
|||
|
|
@ -11,14 +11,15 @@ import androidx.lifecycle.LifecycleOwner
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.HDWalletError
|
||||
import com.tangem.domain.AddCustomTokenError
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.extensions.*
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.features.addCustomToken.CustomCurrency
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.features.customtoken.impl.domain.CustomTokenInteractor
|
||||
|
|
@ -206,10 +207,11 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
|
||||
private fun getNetworkSelectorItems(): List<SelectorItem.Title> {
|
||||
val defaultNetwork = createNetworkSelectorItem(blockchain = Blockchain.Unknown)
|
||||
val scanResponse = reduxStateHolder.scanResponse
|
||||
return listOf(defaultNetwork) + Blockchain.values()
|
||||
.filter { blockchain ->
|
||||
reduxStateHolder.scanResponse?.card?.supportedBlockchains()?.contains(blockchain) == true &&
|
||||
blockchain != Blockchain.Cardano
|
||||
scanResponse?.card?.supportedBlockchains(scanResponse.cardTypesResolver)
|
||||
?.contains(blockchain) == true
|
||||
}
|
||||
.sortedBy(Blockchain::fullName)
|
||||
.map(::createNetworkSelectorItem)
|
||||
|
|
@ -273,7 +275,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
),
|
||||
) + Blockchain.values()
|
||||
.filter { blockchain ->
|
||||
blockchain.isSupportedInApp() && !blockchain.isTestnet() && blockchain != Blockchain.Cardano
|
||||
blockchain.isSupportedInApp() && !blockchain.isTestnet()
|
||||
}
|
||||
.sortedBy(Blockchain::fullName)
|
||||
.map(::createDerivationPathSelectorAdditionalItem)
|
||||
|
|
@ -405,7 +407,11 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
val isSupportedToken = if (!isNetworkSelected()) {
|
||||
true
|
||||
} else {
|
||||
reduxStateHolder.scanResponse?.card?.canHandleToken(networkSelectorValue) ?: false
|
||||
val scanResponse = reduxStateHolder.scanResponse
|
||||
scanResponse?.card?.canHandleToken(
|
||||
blockchain = networkSelectorValue,
|
||||
cardTypesResolver = scanResponse.cardTypesResolver,
|
||||
) ?: false
|
||||
}
|
||||
|
||||
return buildSet {
|
||||
|
|
@ -439,8 +445,12 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
address = uiState.form.contractAddressInputField.value,
|
||||
blockchain = networkSelectorValue,
|
||||
)
|
||||
val isSupportedToken = reduxStateHolder.scanResponse?.card
|
||||
?.canHandleToken(networkSelectorValue)
|
||||
val scanResponse = reduxStateHolder.scanResponse
|
||||
val isSupportedToken = scanResponse?.card
|
||||
?.canHandleToken(
|
||||
blockchain = networkSelectorValue,
|
||||
cardTypesResolver = scanResponse.cardTypesResolver,
|
||||
)
|
||||
?: false
|
||||
|
||||
uiState.copySealed(
|
||||
|
|
@ -599,7 +609,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
if (blockchain == null) return null
|
||||
|
||||
val derivationStyle = if (!isDerivationPathSelected()) {
|
||||
reduxStateHolder.scanResponse?.card?.derivationStyle
|
||||
reduxStateHolder.scanResponse?.derivationStyleProvider?.getDerivationStyle()
|
||||
} else {
|
||||
DerivationStyle.LEGACY
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.tangem.domain.models.scan.ScanResponse
|
|||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.userwallets.UserWalletIdBuilder
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.legacy.isLockedSync
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
|
|
@ -27,7 +28,6 @@ import com.tangem.tap.common.redux.AppState
|
|||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
|
||||
import com.tangem.tap.domain.userWalletList.di.provideRuntimeImplementation
|
||||
import com.tangem.tap.domain.userWalletList.isLockedSync
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
package com.tangem.tap.features.details.redux.walletconnect
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
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.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
|
|
@ -357,9 +357,13 @@ class WalletConnectMiddleware {
|
|||
handleScanResponse(scanResponse = scanResponse, session = session, blockchain = blockchain)
|
||||
}
|
||||
|
||||
private fun getAvailableBlockchains(card: CardDTO, walletState: WalletState): List<Blockchain> {
|
||||
private fun getAvailableBlockchains(
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
walletState: WalletState,
|
||||
): List<Blockchain> {
|
||||
return walletState.currencies.filter {
|
||||
it.isBlockchain() && !it.isCustomCurrency(card.derivationStyle) && it.blockchain.isEvm()
|
||||
it.isBlockchain() &&
|
||||
!it.isCustomCurrency(derivationStyleProvider.getDerivationStyle()) && it.blockchain.isEvm()
|
||||
}.map { it.blockchain }
|
||||
}
|
||||
|
||||
|
|
@ -390,7 +394,7 @@ class WalletConnectMiddleware {
|
|||
walletPublicKey = wallet.publicKey.seedKey,
|
||||
derivedPublicKey = derivedKey,
|
||||
derivationPath = wallet.publicKey.derivationPath,
|
||||
derivationStyle = scanResponse.card.derivationStyle,
|
||||
derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle(),
|
||||
blockchain = wallet.blockchain,
|
||||
)
|
||||
|
||||
|
|
@ -403,7 +407,6 @@ class WalletConnectMiddleware {
|
|||
}
|
||||
|
||||
private fun handleScanResponse(scanResponse: ScanResponse, session: WalletConnectSession, blockchain: Blockchain) {
|
||||
val card = scanResponse.card
|
||||
if (!scanResponse.cardTypesResolver.isMultiwalletAllowed()) {
|
||||
store.dispatchOnMain(WalletConnectAction.UnsupportedCard)
|
||||
return
|
||||
|
|
@ -415,7 +418,11 @@ class WalletConnectMiddleware {
|
|||
NewWcSessionData(session = updatedSession, scanResponse = scanResponse, blockchain = blockchain),
|
||||
),
|
||||
)
|
||||
val blockchains = if (blockchain.isEvm()) getAvailableBlockchains(card, walletState) else emptyList()
|
||||
val blockchains = if (blockchain.isEvm()) {
|
||||
getAvailableBlockchains(scanResponse.derivationStyleProvider, walletState)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
store.dispatch(
|
||||
GlobalAction.ShowDialog(
|
||||
WalletConnectDialog.ApproveWcSession(session = updatedSession, networks = blockchains),
|
||||
|
|
@ -433,8 +440,9 @@ class WalletConnectMiddleware {
|
|||
} else {
|
||||
blockchain
|
||||
}
|
||||
val derivation = blockchainToMake.derivationPath(store.state.globalState.scanResponse?.card?.derivationStyle)
|
||||
?.rawPath
|
||||
val derivation = blockchainToMake.derivationPath(
|
||||
style = store.state.globalState.scanResponse?.derivationStyleProvider?.getDerivationStyle(),
|
||||
)?.rawPath
|
||||
val blockchainNetwork = BlockchainNetwork(
|
||||
blockchain = blockchainToMake,
|
||||
derivationPath = derivation,
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ package com.tangem.tap.features.details.redux.walletconnect
|
|||
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import com.tangem.wallet.R
|
|||
object ClipboardOrScanQrDialog {
|
||||
fun create(wcUri: String, context: Context): AlertDialog {
|
||||
return AlertDialog.Builder(context).apply {
|
||||
setTitle(context.getString(R.string.wallet_connect_title))
|
||||
setTitle(context.getString(R.string.common_select_action))
|
||||
setMessage(context.getText(R.string.wallet_connect_clipboard_alert))
|
||||
setPositiveButton(context.getText(R.string.wallet_connect_paste_from_clipboard)) { _, _ ->
|
||||
store.dispatch(WalletConnectAction.OpenSession(wcUri))
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ fun StoriesScreen(
|
|||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
text = stringResource(id = R.string.search_tokens_title),
|
||||
text = stringResource(id = R.string.common_search_tokens),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ private fun StoriesTitleText(text: String, isDarkBackground: Boolean) {
|
|||
.padding(start = 40.dp, end = 40.dp),
|
||||
text = text,
|
||||
fontSize = 32.sp,
|
||||
lineHeight = 38.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = if (isDarkBackground) Color.White else Color(0xFF090E13),
|
||||
textAlign = TextAlign.Center,
|
||||
|
|
@ -198,6 +199,7 @@ private fun StoriesSubtitleText(subtitleText: AnnotatedString) {
|
|||
fontWeight = FontWeight.Normal,
|
||||
text = subtitleText,
|
||||
fontSize = 20.sp,
|
||||
lineHeight = 26.sp,
|
||||
color = color,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,6 @@
|
|||
package com.tangem.tap.features.home.compose.views
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
|
|
@ -51,7 +46,7 @@ fun HomeButtons(
|
|||
},
|
||||
content = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.welcome_unlock_card),
|
||||
text = stringResource(id = R.string.home_button_scan),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import com.tangem.common.extensions.guard
|
|||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.TapWorkarounds.canSkipBackup
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
|
|
@ -38,10 +37,7 @@ object OnboardingHelper {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO for Shiba disabled check wallet 2, and only check canSkipBackup, enable when release wallet 2
|
||||
// ([REDACTED_TASK_KEY])
|
||||
// response.cardTypesResolver.isWallet2() -> {
|
||||
!response.card.canSkipBackup -> {
|
||||
response.cardTypesResolver.isWallet2() -> {
|
||||
val emptyWallets = response.card.wallets.isEmpty()
|
||||
val activationInProgress = cardInfoStorage.isActivationInProgress(cardId)
|
||||
val backupNotActive = response.card.backupStatus?.isActive != true
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ class OnboardingNoteFragment : BaseOnboardingFragment<OnboardingNoteState>() {
|
|||
btnAlternativeAction.isVisible = false
|
||||
}
|
||||
|
||||
tvHeader.setText(R.string.onboarding_top_up_header)
|
||||
tvHeader.setText(R.string.onboarding_topup_title)
|
||||
if (state.balanceNonCriticalError == null) {
|
||||
tvBody.setText(R.string.onboarding_top_up_body)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.core.analytics.Analytics
|
|||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
import com.tangem.tap.common.postUi
|
||||
|
|
@ -92,7 +93,7 @@ private fun handleOtherCardsAction(action: Action) {
|
|||
val blockchainNetwork =
|
||||
BlockchainNetwork(
|
||||
blockchain = primaryBlockchain,
|
||||
card = updatedCard,
|
||||
derivationStyleProvider = updatedResponse.derivationStyleProvider,
|
||||
)
|
||||
.updateTokens(
|
||||
listOfNotNull(primaryToken),
|
||||
|
|
@ -102,11 +103,11 @@ private fun handleOtherCardsAction(action: Action) {
|
|||
listOf(
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Bitcoin,
|
||||
card = updatedCard,
|
||||
derivationStyleProvider = updatedResponse.derivationStyleProvider,
|
||||
),
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Ethereum,
|
||||
card = updatedCard,
|
||||
derivationStyleProvider = updatedResponse.derivationStyleProvider,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.domain.common.extensions.withMainContext
|
|||
import com.tangem.domain.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.UserWalletIdBuilder
|
||||
import com.tangem.domain.wallets.legacy.isLockedSync
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
|
|
@ -21,7 +22,6 @@ import com.tangem.tap.common.redux.AppState
|
|||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.twins.TwinCardsManager
|
||||
import com.tangem.tap.domain.userWalletList.isLockedSync
|
||||
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
|
||||
import com.tangem.tap.features.onboarding.OnboardingDialog
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
|
|
@ -50,7 +50,7 @@ private val twinsWalletMiddleware: Middleware<AppState> = { dispatch, state ->
|
|||
|
||||
@Suppress("LongMethod", "ComplexMethod", "MagicNumber")
|
||||
private fun handle(action: Action, dispatch: DispatchFunction) {
|
||||
val action = action as? TwinCardsAction ?: return
|
||||
if (action !is TwinCardsAction) return
|
||||
|
||||
val globalState = store.state.globalState
|
||||
val onboardingManager = globalState.onboardingState.onboardingManager
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ class TwinsCardsFragment : BaseOnboardingFragment<TwinCardsState>() {
|
|||
btnAlternativeAction.isVisible = false
|
||||
}
|
||||
|
||||
tvHeader.setText(R.string.onboarding_top_up_header)
|
||||
tvHeader.setText(R.string.onboarding_topup_title)
|
||||
tvBody.setText(R.string.onboarding_top_up_body)
|
||||
|
||||
btnRefreshBalanceWidget.changeState(state.walletBalance.state)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.domain.common.BlockchainNetwork
|
|||
import com.tangem.domain.common.TapWorkarounds.canSkipBackup
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.Artwork
|
||||
|
|
@ -125,7 +126,10 @@ private fun handleWalletAction(action: Action) {
|
|||
} else {
|
||||
listOf(Blockchain.Bitcoin, Blockchain.Ethereum)
|
||||
}.map { blockchain ->
|
||||
BlockchainNetwork(blockchain, result.data.card)
|
||||
BlockchainNetwork(
|
||||
blockchain = blockchain,
|
||||
derivationStyleProvider = updatedResponse.derivationStyleProvider,
|
||||
)
|
||||
}
|
||||
|
||||
scope.launch {
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ package com.tangem.tap.features.onboarding.products.wallet.ui
|
|||
import androidx.compose.runtime.collectAsState
|
||||
import com.tangem.feature.onboarding.api.OnboardingSeedPhrase
|
||||
import com.tangem.feature.onboarding.api.OnboardingSeedPhraseApi
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseScreen
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseViewModel
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletStep
|
||||
import com.tangem.wallet.R
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -44,11 +46,27 @@ internal class OnboardingSeedPhraseStateHandler(
|
|||
walletFragment.binding.onboardingWalletContainer.hide()
|
||||
walletFragment.bindingSeedPhrase.onboardingSeedPhraseContainer.show()
|
||||
walletFragment.bindingSeedPhrase.onboardingSeedPhraseContainer.setContent {
|
||||
val subScreen = viewModel.currentScreen.collectAsState().value
|
||||
setMainScreenToolbarTitle(walletFragment, subScreen)
|
||||
|
||||
onboardingSeedPhraseApi.ScreenContent(
|
||||
uiState = viewModel.uiState,
|
||||
subScreen = viewModel.currentScreen.collectAsState().value,
|
||||
subScreen = subScreen,
|
||||
progress = viewModel.progress.collectAsState(0).value.toFloat() / onboardingWalletMaxProgress,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMainScreenToolbarTitle(walletFragment: OnboardingWalletFragment, subScreen: SeedPhraseScreen) {
|
||||
val titleResId = when (subScreen) {
|
||||
SeedPhraseScreen.Intro,
|
||||
SeedPhraseScreen.AboutSeedPhrase,
|
||||
SeedPhraseScreen.YourSeedPhrase,
|
||||
SeedPhraseScreen.CheckSeedPhrase,
|
||||
-> R.string.onboarding_create_wallet_header
|
||||
SeedPhraseScreen.ImportSeedPhrase -> R.string.onboarding_seed_intro_button_import
|
||||
}
|
||||
|
||||
walletFragment.binding.toolbar.title = walletFragment.getString(titleResId)
|
||||
}
|
||||
}
|
||||
|
|
@ -257,7 +257,7 @@ class OnboardingWalletFragment :
|
|||
prepareBackupView()
|
||||
tvHeader.text = getText(R.string.onboarding_title_scan_origin_card)
|
||||
tvBody.text = getString(
|
||||
R.string.onboarding_subtitle_scan_origin_card,
|
||||
R.string.onboarding_subtitle_scan_primary,
|
||||
)
|
||||
|
||||
with(layoutButtonsCommon) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.core.navigation.AppScreen
|
|||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.legacy.isLockable
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.MainScreen
|
||||
|
|
@ -20,7 +21,6 @@ import com.tangem.tap.common.extensions.dispatchWithMain
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
|
||||
import com.tangem.tap.domain.userWalletList.isLockable
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import com.tangem.core.navigation.NavigationAction
|
|||
import com.tangem.tap.common.GlobalLayoutStateHandler
|
||||
import com.tangem.tap.common.KeyboardObserver
|
||||
import com.tangem.tap.common.extensions.getQuantityString
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.features.BaseStoreFragment
|
||||
import com.tangem.tap.features.shop.domain.models.ProductState
|
||||
|
|
@ -153,11 +152,12 @@ internal class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSu
|
|||
animateProductSelection(state.selectedProduct)
|
||||
handlePriceState(state)
|
||||
handlePromoCodeState(state)
|
||||
if (shopifyFeatureToggleManager.isDynamicSalesProductsEnabled) {
|
||||
handleNotificationBlock(state)
|
||||
} else {
|
||||
handleOrderingDelayBlock(isVisible = state.isOrderingDelayBlockVisible)
|
||||
}
|
||||
// TODO: https://tangem.slack.com/archives/C01HARKDLQ0/p1691421861756069
|
||||
// if (shopifyFeatureToggleManager.isDynamicSalesProductsEnabled) {
|
||||
// handleNotificationBlock(state)
|
||||
// } else {
|
||||
// handleOrderingDelayBlock(isVisible = state.isOrderingDelayBlockVisible)
|
||||
// }
|
||||
handleButtonsState(state)
|
||||
}
|
||||
|
||||
|
|
@ -198,20 +198,20 @@ internal class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSu
|
|||
pbPromoCode.show(state.promoCodeLoading)
|
||||
}
|
||||
|
||||
private fun handleOrderingDelayBlock(isVisible: Boolean) {
|
||||
if (isVisible) binding.tvSoldOutDesc.show() else binding.tvSoldOutDesc.hide()
|
||||
}
|
||||
|
||||
private fun handleNotificationBlock(state: ShopState) {
|
||||
if (isVisible) {
|
||||
binding.tvSoldOutDesc.show()
|
||||
getSelectedSalesProduct(state)?.notification?.let { notification ->
|
||||
binding.tvSoldOutDesc.text = notification.description
|
||||
}
|
||||
} else {
|
||||
binding.tvSoldOutDesc.hide()
|
||||
}
|
||||
}
|
||||
// private fun handleOrderingDelayBlock(isVisible: Boolean) {
|
||||
// if (isVisible) binding.tvSoldOutDesc.show() else binding.tvSoldOutDesc.hide()
|
||||
// }
|
||||
//
|
||||
// private fun handleNotificationBlock(state: ShopState) {
|
||||
// if (isVisible) {
|
||||
// binding.tvSoldOutDesc.show()
|
||||
// getSelectedSalesProduct(state)?.notification?.let { notification ->
|
||||
// binding.tvSoldOutDesc.text = notification.description
|
||||
// }
|
||||
// } else {
|
||||
// binding.tvSoldOutDesc.hide()
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun handleButtonsState(state: ShopState) = with(binding) {
|
||||
btnPayGooglePay.root.show(state.isGooglePayAvailable)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.blockchain.common.Blockchain
|
|||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.domain.common.extensions.supportedBlockchains
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.tap.features.tokens.impl.data.converters.CoinsResponseConverter
|
||||
import com.tangem.tap.features.tokens.impl.domain.models.Token
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
|
|
@ -38,7 +39,8 @@ internal class TangemApiTokensPagingSource(
|
|||
val page = params.key ?: 0
|
||||
|
||||
return runCatching(dispatchers.io) {
|
||||
val supportedBlockchains = reduxStateHolder.scanResponse?.card?.supportedBlockchains()
|
||||
val scanResponse = reduxStateHolder.scanResponse
|
||||
val supportedBlockchains = scanResponse?.card?.supportedBlockchains(scanResponse.cardTypesResolver)
|
||||
?: Blockchain.values().toList()
|
||||
|
||||
api.getCoins(
|
||||
|
|
|
|||
|
|
@ -2,18 +2,19 @@ package com.tangem.tap.features.tokens.impl.domain
|
|||
|
||||
import androidx.paging.PagingData
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.extensions.toMapKey
|
||||
import com.tangem.common.flatMap
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.util.supportsHdWallet
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
|
|
@ -24,10 +25,6 @@ import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain
|
|||
import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.tap.userWalletsListManager
|
||||
import com.tangem.tap.walletCurrenciesManager
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import timber.log.Timber
|
||||
|
|
@ -51,11 +48,12 @@ internal class DefaultTokensListInteractor(
|
|||
override suspend fun saveChanges(tokens: List<TokenWithBlockchain>, blockchains: List<Blockchain>) {
|
||||
val scanResponse = requireNotNull(reduxStateHolder.scanResponse)
|
||||
|
||||
val derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle()
|
||||
val currentTokens = store.state.tokensState.addedWallets
|
||||
.toNonCustomTokensWithBlockchains(style = scanResponse.card.derivationStyle)
|
||||
.toNonCustomTokensWithBlockchains(derivationStyle = derivationStyle)
|
||||
|
||||
val currentBlockchains = store.state.tokensState.addedWallets
|
||||
.toNonCustomBlockchains(derivationStyle = scanResponse.card.derivationStyle)
|
||||
.toNonCustomBlockchains(derivationStyle = derivationStyle)
|
||||
|
||||
val blockchainsToAdd = blockchains.filterNot(currentBlockchains::contains)
|
||||
val blockchainsToRemove = currentBlockchains.filterNot(blockchains::contains)
|
||||
|
|
@ -73,18 +71,18 @@ internal class DefaultTokensListInteractor(
|
|||
remove(
|
||||
tokens = tokensToRemove,
|
||||
blockchains = blockchainsToRemove,
|
||||
derivationStyle = scanResponse.card.derivationStyle,
|
||||
derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle(),
|
||||
)
|
||||
|
||||
add(tokens = tokensToAdd, blockchains = blockchainsToAdd, scanResponse = scanResponse)
|
||||
}
|
||||
|
||||
private fun List<WalletDataModel>.toNonCustomTokensWithBlockchains(
|
||||
style: DerivationStyle?,
|
||||
derivationStyle: DerivationStyle?,
|
||||
): List<TokenWithBlockchain> {
|
||||
return this.map(WalletDataModel::currency)
|
||||
.mapNotNull { currency ->
|
||||
if (currency !is Currency.Token || currency.isCustomCurrency(style)) return@mapNotNull null
|
||||
if (currency !is Currency.Token || currency.isCustomCurrency(derivationStyle)) return@mapNotNull null
|
||||
TokenWithBlockchain(token = currency.token, blockchain = currency.blockchain)
|
||||
}
|
||||
.distinct()
|
||||
|
|
@ -123,7 +121,7 @@ internal class DefaultTokensListInteractor(
|
|||
val currenciesToAdd = convertToCurrencies(
|
||||
tokens = tokens,
|
||||
blockchains = blockchains,
|
||||
derivationStyle = scanResponse.card.derivationStyle,
|
||||
derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle(),
|
||||
)
|
||||
|
||||
// TODO("[REDACTED_TASK_KEY] use DerivationManager")
|
||||
|
|
@ -136,10 +134,11 @@ internal class DefaultTokensListInteractor(
|
|||
}
|
||||
|
||||
private suspend fun deriveMissingBlockchains(scanResponse: ScanResponse, currencies: List<Currency>) {
|
||||
val derivations = listOfNotNull(
|
||||
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencies),
|
||||
getDerivations(EllipticCurve.Ed25519, scanResponse, currencies),
|
||||
).associate(transform = TokensMiddleware.DerivationData::derivations)
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivations = currencies.mapNotNull {
|
||||
val curve = config.primaryCurve(it.blockchain)
|
||||
curve?.let { getDerivations(curve, scanResponse, currencies) }
|
||||
}.associate(transform = TokensMiddleware.DerivationData::derivations)
|
||||
|
||||
if (derivations.isEmpty()) {
|
||||
submitAdd(scanResponse, currencies)
|
||||
|
|
@ -184,7 +183,7 @@ internal class DefaultTokensListInteractor(
|
|||
.map(Currency::blockchain)
|
||||
.distinct()
|
||||
.filter { it.getSupportedCurves().contains(curve) }
|
||||
.mapNotNull { it.derivationPath(scanResponse.card.derivationStyle) }
|
||||
.mapNotNull { it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle()) }
|
||||
|
||||
val customTokensCandidates = currencyList
|
||||
.filter { it.blockchain.getSupportedCurves().contains(curve) }
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ private fun Preview_TokensListScreen_Read() {
|
|||
TokensListScreen(
|
||||
stateHolder = TokensListStateHolder.ReadContent(
|
||||
toolbarState = TokensListToolbarState.Title.Read(
|
||||
titleResId = R.string.search_tokens_title,
|
||||
titleResId = R.string.common_search_tokens,
|
||||
onBackButtonClick = {},
|
||||
onSearchButtonClick = {},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -11,12 +11,7 @@ import androidx.compose.material.Icon
|
|||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -186,7 +181,7 @@ private fun Preview_AddTokensToolbar_ReadAccess() {
|
|||
TangemTheme {
|
||||
TokensListToolbar(
|
||||
state = Title.Read(
|
||||
titleResId = R.string.search_tokens_title,
|
||||
titleResId = R.string.common_search_tokens,
|
||||
onBackButtonClick = {},
|
||||
onSearchButtonClick = {},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import com.tangem.core.ui.extensions.getActiveIconRes
|
|||
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
|
||||
import com.tangem.domain.common.extensions.canHandleToken
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.tap.common.extensions.fullNameWithoutTestnet
|
||||
import com.tangem.tap.common.extensions.getGreyedOutIconRes
|
||||
import com.tangem.tap.common.extensions.getNetworkName
|
||||
|
|
@ -102,14 +103,14 @@ internal class TokensListViewModel @Inject constructor(
|
|||
private fun getInitialToolbarState(): TokensListToolbarState {
|
||||
return if (args.isManageAccess) {
|
||||
TokensListToolbarState.Title.Manage(
|
||||
titleResId = R.string.main_manage_tokens,
|
||||
titleResId = R.string.add_tokens_title,
|
||||
onBackButtonClick = actionsHandler::onBackButtonClick,
|
||||
onSearchButtonClick = actionsHandler::onSearchButtonClick,
|
||||
onAddCustomTokenClick = actionsHandler::onAddCustomTokenClick,
|
||||
)
|
||||
} else {
|
||||
TokensListToolbarState.Title.Read(
|
||||
titleResId = R.string.search_tokens_title,
|
||||
titleResId = R.string.common_search_tokens,
|
||||
onBackButtonClick = actionsHandler::onBackButtonClick,
|
||||
onSearchButtonClick = actionsHandler::onSearchButtonClick,
|
||||
)
|
||||
|
|
@ -349,8 +350,14 @@ internal class TokensListViewModel @Inject constructor(
|
|||
toggledNetwork.changeToggleState()
|
||||
}
|
||||
} else {
|
||||
val scanResponse = reduxStateHolder.scanResponse
|
||||
val isUnsupportedToken =
|
||||
!(reduxStateHolder.scanResponse?.card?.canHandleToken(token.blockchain) ?: false)
|
||||
!(
|
||||
scanResponse?.card?.canHandleToken(
|
||||
blockchain = token.blockchain,
|
||||
cardTypesResolver = scanResponse.cardTypesResolver,
|
||||
) ?: false
|
||||
)
|
||||
|
||||
if (isUnsupportedToken) {
|
||||
router.openUnsupportedSoltanaNetworkAlert()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
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.derivation.DerivationStyle
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import org.rekotlin.Action
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
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.derivation.DerivationStyle
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
|
|
@ -13,7 +13,8 @@ import com.tangem.core.navigation.AppScreen
|
|||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.DomainWrapped
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.util.hasDerivation
|
||||
import com.tangem.domain.common.util.supportsHdWallet
|
||||
import com.tangem.domain.features.addCustomToken.CustomCurrency
|
||||
|
|
@ -21,7 +22,7 @@ import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenAction
|
|||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.redux.domainStore
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.ManageTokens
|
||||
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
|
|
@ -30,11 +31,6 @@ import com.tangem.tap.common.redux.global.GlobalAction
|
|||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
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 kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Middleware
|
||||
|
|
@ -72,7 +68,7 @@ object TokensMiddleware {
|
|||
currencies = convertToCurrencies(
|
||||
blockchains = blockchainsToRemove,
|
||||
tokens = tokensToRemove,
|
||||
derivationStyle = scanResponse.card.derivationStyle,
|
||||
derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle(),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -87,7 +83,7 @@ object TokensMiddleware {
|
|||
val currencyList = convertToCurrencies(
|
||||
blockchains = blockchainsToAdd,
|
||||
tokens = tokensToAdd,
|
||||
derivationStyle = scanResponse.card.derivationStyle,
|
||||
derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle(),
|
||||
)
|
||||
|
||||
if (scanResponse.supportsHdWallet()) {
|
||||
|
|
@ -123,10 +119,11 @@ object TokensMiddleware {
|
|||
currencyList: List<Currency>,
|
||||
onSuccess: (ScanResponse) -> Unit,
|
||||
) {
|
||||
val derivationDataList = listOfNotNull(
|
||||
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencyList),
|
||||
getDerivations(EllipticCurve.Ed25519, scanResponse, currencyList),
|
||||
)
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivationDataList = currencyList.mapNotNull {
|
||||
val curve = config.primaryCurve(it.blockchain)
|
||||
curve?.let { getDerivations(curve, scanResponse, currencyList) }
|
||||
}
|
||||
val derivations = derivationDataList.associate { it.derivations }
|
||||
if (derivations.isEmpty()) {
|
||||
onSuccess(scanResponse)
|
||||
|
|
@ -175,7 +172,7 @@ object TokensMiddleware {
|
|||
val manageTokensCandidates = currencyList.map { it.blockchain }.distinct().filter {
|
||||
it.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull {
|
||||
it.derivationPath(scanResponse.card.derivationStyle)
|
||||
it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
|
||||
val customTokensCandidates = currencyList.filter {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
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.derivation.DerivationStyle
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
package com.tangem.tap.features.wallet.converters
|
||||
|
||||
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.tokens.models.CryptoCurrency
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
class CryptoCurrencyConverter : Converter<Currency, CryptoCurrency> {
|
||||
|
||||
private val cryptoCurrencyFactory by lazy { CryptoCurrencyFactory() }
|
||||
|
||||
override fun convert(value: Currency): CryptoCurrency {
|
||||
return when (value) {
|
||||
is Currency.Blockchain -> requireNotNull(
|
||||
cryptoCurrencyFactory.createCoin(
|
||||
blockchain = value.blockchain,
|
||||
derivationStyleProvider = requireNotNull(
|
||||
store.state.globalState
|
||||
.userWalletsListManager
|
||||
?.selectedUserWalletSync
|
||||
?.scanResponse
|
||||
?.derivationStyleProvider,
|
||||
),
|
||||
),
|
||||
)
|
||||
is Currency.Token -> requireNotNull(
|
||||
cryptoCurrencyFactory.createToken(
|
||||
sdkToken = value.token,
|
||||
blockchain = value.blockchain,
|
||||
derivationStyleProvider = requireNotNull(
|
||||
store.state.globalState
|
||||
.userWalletsListManager
|
||||
?.selectedUserWalletSync
|
||||
?.scanResponse
|
||||
?.derivationStyleProvider,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.features.wallet.models
|
||||
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ package com.tangem.tap.features.wallet.redux.middlewares
|
|||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.core.analytics.Analytics
|
||||
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.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.MainScreen
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.TapWalletManager
|
||||
import com.tangem.tap.features.details.redux.DetailsAction
|
||||
|
|
@ -19,6 +21,8 @@ import com.tangem.tap.features.walletSelector.redux.WalletSelectorAction
|
|||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.userWalletsListManager
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
|
|
@ -26,8 +30,12 @@ class AppCurrencyMiddleware(
|
|||
private val walletRepository: WalletRepository,
|
||||
private val tapWalletManager: TapWalletManager,
|
||||
private val fiatCurrenciesPrefStorage: FiatCurrenciesPrefStorage,
|
||||
private val featureToggles: WalletFeatureToggles,
|
||||
private val appCurrencyRepository: AppCurrencyRepository,
|
||||
private val appCurrencyProvider: () -> FiatCurrency,
|
||||
) {
|
||||
private val showSelectorJobHolder = JobHolder()
|
||||
|
||||
fun handle(action: WalletAction.AppCurrencyAction) {
|
||||
when (action) {
|
||||
is WalletAction.AppCurrencyAction.ChooseAppCurrency -> showSelector()
|
||||
|
|
@ -36,6 +44,52 @@ class AppCurrencyMiddleware(
|
|||
}
|
||||
|
||||
private fun showSelector() {
|
||||
if (featureToggles.isRedesignedScreenEnabled) {
|
||||
showSelectorNew()
|
||||
} else {
|
||||
showSelectorLegacy()
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectCurrency(action: WalletAction.AppCurrencyAction.SelectAppCurrency) {
|
||||
Analytics.send(MainScreen.MainCurrencyChanged(AnalyticsParam.CurrencyType.FiatCurrency(action.fiatCurrency)))
|
||||
|
||||
scope.launch {
|
||||
appCurrencyRepository.changeAppCurrency(action.fiatCurrency.code)
|
||||
|
||||
store.dispatchWithMain(GlobalAction.ChangeAppCurrency(action.fiatCurrency))
|
||||
store.dispatchWithMain(DetailsAction.ChangeAppCurrency(action.fiatCurrency))
|
||||
store.dispatchWithMain(WalletSelectorAction.ChangeAppCurrency(action.fiatCurrency))
|
||||
|
||||
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard {
|
||||
Timber.e("Unable to select currency, no user wallet selected")
|
||||
return@launch
|
||||
}
|
||||
|
||||
tapWalletManager.loadData(selectedUserWallet, refresh = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSelectorNew() {
|
||||
scope.launch {
|
||||
val currencies = appCurrencyRepository.getAvailableAppCurrencies()
|
||||
|
||||
store.dispatchDialogShow(
|
||||
WalletDialog.CurrencySelectionDialog(
|
||||
currenciesList = currencies.map { appCurrency ->
|
||||
FiatCurrency(
|
||||
code = appCurrency.code,
|
||||
name = appCurrency.name,
|
||||
symbol = appCurrency.symbol,
|
||||
)
|
||||
},
|
||||
currentAppCurrency = appCurrencyProvider.invoke(),
|
||||
),
|
||||
)
|
||||
}.saveIn(showSelectorJobHolder)
|
||||
}
|
||||
|
||||
private fun showSelectorLegacy() {
|
||||
val storedFiatCurrencies = fiatCurrenciesPrefStorage.restore()
|
||||
if (storedFiatCurrencies.isNotEmpty()) {
|
||||
store.dispatchDialogShow(
|
||||
|
|
@ -65,23 +119,6 @@ class AppCurrencyMiddleware(
|
|||
}
|
||||
}
|
||||
|
||||
private fun selectCurrency(action: WalletAction.AppCurrencyAction.SelectAppCurrency) {
|
||||
Analytics.send(MainScreen.MainCurrencyChanged(AnalyticsParam.CurrencyType.FiatCurrency(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))
|
||||
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard {
|
||||
Timber.e("Unable to select currency, no user wallet selected")
|
||||
return
|
||||
}
|
||||
scope.launch {
|
||||
tapWalletManager.loadData(selectedUserWallet, refresh = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<DataSourceCurrency>.mapToUiModel(): List<FiatCurrency> {
|
||||
return this.map {
|
||||
FiatCurrency(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.features.wallet.redux.middlewares
|
||||
|
||||
import androidx.core.os.bundleOf
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.flatMap
|
||||
|
|
@ -7,6 +8,7 @@ import com.tangem.core.analytics.Analytics
|
|||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.tokendetails.navigation.TokenDetailsRouter
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken
|
||||
import com.tangem.tap.common.extensions.addContext
|
||||
|
|
@ -15,6 +17,7 @@ import com.tangem.tap.common.extensions.dispatchErrorNotification
|
|||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.features.wallet.converters.CryptoCurrencyConverter
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.features.wallet.redux.models.WalletDialog
|
||||
|
|
@ -28,12 +31,19 @@ import kotlinx.coroutines.launch
|
|||
import timber.log.Timber
|
||||
|
||||
class MultiWalletMiddleware {
|
||||
|
||||
private val cryptoCurrencyConverter by lazy { CryptoCurrencyConverter() }
|
||||
|
||||
@Suppress("LongMethod", "ComplexMethod")
|
||||
fun handle(action: WalletAction.MultiWallet, walletState: WalletState?) {
|
||||
when (action) {
|
||||
is WalletAction.MultiWallet.SelectWallet -> {
|
||||
if (action.currency != null) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.WalletDetails))
|
||||
val bundle = bundleOf(
|
||||
// TODO: [REDACTED_JIRA]
|
||||
TokenDetailsRouter.SELECTED_CURRENCY_KEY to cryptoCurrencyConverter.convert(action.currency),
|
||||
)
|
||||
store.dispatch(NavigationAction.NavigateTo(screen = AppScreen.WalletDetails, bundle = bundle))
|
||||
}
|
||||
}
|
||||
is WalletAction.MultiWallet.TryToRemoveWallet -> {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.tangem.core.navigation.AppScreen
|
|||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.domain.userwallets.GetCardImageUseCase
|
||||
import com.tangem.domain.wallets.legacy.lockIfLockable
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Basic
|
||||
|
|
@ -24,7 +25,6 @@ import com.tangem.tap.common.redux.global.GlobalAction
|
|||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.domain.model.WalletStoreModel
|
||||
import com.tangem.tap.domain.userWalletList.lockIfLockable
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.send.redux.PrepareSendScreen
|
||||
|
|
@ -55,6 +55,8 @@ class WalletMiddleware {
|
|||
walletRepository = store.state.featureRepositoryProvider.walletRepository,
|
||||
tapWalletManager = store.state.globalState.tapWalletManager,
|
||||
fiatCurrenciesPrefStorage = preferencesStorage.fiatCurrenciesPrefStorage,
|
||||
appCurrencyRepository = store.state.daggerGraphState.get(DaggerGraphState::appCurrencyRepository),
|
||||
featureToggles = store.state.daggerGraphState.get(DaggerGraphState::walletFeatureToggles),
|
||||
appCurrencyProvider = { store.state.globalState.appCurrency },
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ object MultipleAddressUiHelper {
|
|||
Blockchain.BitcoinTestnet,
|
||||
Blockchain.Litecoin,
|
||||
Blockchain.BitcoinCash,
|
||||
Blockchain.CardanoShelley,
|
||||
Blockchain.Cardano,
|
||||
)
|
||||
|
||||
fun typeToId(type: AddressType, blockchain: Blockchain): Int {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
package com.tangem.tap.features.wallet.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.*
|
||||
import android.widget.TextView
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.annotation.ColorRes
|
||||
|
|
@ -23,8 +19,8 @@ import com.tangem.common.doOnResult
|
|||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.feature.swap.api.SwapFeatureToggleManager
|
||||
import com.tangem.feature.swap.domain.SwapInteractor
|
||||
import com.tangem.sdk.extensions.dpToPx
|
||||
|
|
@ -32,14 +28,7 @@ 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.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.extensions.*
|
||||
import com.tangem.tap.common.recyclerView.SpaceItemDecoration
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.utils.SafeStoreSubscriber
|
||||
|
|
@ -57,15 +46,7 @@ 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.assembleWarnings
|
||||
import com.tangem.tap.features.wallet.ui.utils.getAvailableActions
|
||||
import com.tangem.tap.features.wallet.ui.utils.getFormattedCryptoAmount
|
||||
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.features.wallet.ui.utils.*
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.userWalletsListManagerSafe
|
||||
import com.tangem.tap.walletCurrenciesManager
|
||||
|
|
@ -336,10 +317,8 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), SafeSt
|
|||
private fun handleCurrencyIcon(currency: Currency) = with(binding.lWalletDetails.lBalance) {
|
||||
ivCurrency.load(
|
||||
currency = currency,
|
||||
derivationStyle = store.state.globalState
|
||||
.scanResponse
|
||||
?.card
|
||||
?.derivationStyle,
|
||||
derivationStyle = store.state.globalState.scanResponse
|
||||
?.derivationStyleProvider?.getDerivationStyle(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import androidx.recyclerview.widget.DiffUtil
|
|||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.tap.common.analytics.events.Portfolio
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
|
|
@ -77,10 +77,8 @@ class WalletAdapter : ListAdapter<WalletDataModel, WalletAdapter.WalletsViewHold
|
|||
|
||||
ivCurrency.load(
|
||||
currency = wallet.currency,
|
||||
derivationStyle = store.state.globalState
|
||||
.scanResponse
|
||||
?.card
|
||||
?.derivationStyle,
|
||||
derivationStyle = store.state.globalState.scanResponse
|
||||
?.derivationStyleProvider?.getDerivationStyle(),
|
||||
)
|
||||
|
||||
lContent.tvCurrency.text = wallet.currency.currencyName
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import android.widget.TextView
|
|||
import androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isVisible
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.sdk.extensions.dpToPx
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.wallet.databinding.ViewCurrencyIconBinding
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.badoo.mvicore.modelWatcher
|
|||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.tap.common.analytics.events.MainScreen
|
||||
import com.tangem.tap.common.analytics.events.Portfolio
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
|
|
@ -104,13 +104,13 @@ class MultiWalletView : WalletView() {
|
|||
watcher.invoke(state)
|
||||
|
||||
binding.btnAddToken.setOnClickListener {
|
||||
val card = store.state.globalState.scanResponse!!.card
|
||||
Analytics.send(Portfolio.ButtonManageTokens())
|
||||
|
||||
store.dispatch(
|
||||
TokensAction.SetArgs.ManageAccess(
|
||||
wallets = state.walletsDataFromStores,
|
||||
derivationStyle = card.derivationStyle,
|
||||
derivationStyle = store.state.globalState.scanResponse
|
||||
?.derivationStyleProvider?.getDerivationStyle(),
|
||||
),
|
||||
)
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.AddTokens))
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.tangem.core.navigation.NavigationAction
|
|||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.userwallets.UserWalletIdBuilder
|
||||
import com.tangem.domain.wallets.legacy.unlockIfLockable
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.*
|
||||
|
|
@ -20,7 +21,6 @@ import com.tangem.tap.common.extensions.onUserWalletSelected
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.domain.model.TotalFiatBalance
|
||||
import com.tangem.tap.domain.model.WalletStoreModel
|
||||
import com.tangem.tap.domain.userWalletList.unlockIfLockable
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.domain.wallets.legacy.isLocked
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.common.analytics.events.MyWallets
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletsListError
|
||||
import com.tangem.tap.domain.userWalletList.isLocked
|
||||
import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||
import com.tangem.tap.features.walletSelector.redux.WalletSelectorAction
|
||||
import com.tangem.tap.features.walletSelector.redux.WalletSelectorState
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ private fun LoadedTokensInfo(
|
|||
SpacerH2()
|
||||
Text(
|
||||
text = pluralStringResource(
|
||||
id = R.plurals.tokens_count,
|
||||
id = R.plurals.token_count,
|
||||
count = tokensCount,
|
||||
tokensCount,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.core.navigation.AppScreen
|
|||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.legacy.unlockIfLockable
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Basic
|
||||
|
|
@ -16,7 +17,6 @@ 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.domain.userWalletList.unlockIfLockable
|
||||
import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler
|
||||
import com.tangem.tap.features.signin.redux.SignInAction
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package com.tangem.tap.features.welcome.ui
|
|||
import androidx.lifecycle.ViewModel
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.tap.common.analytics.events.SignIn
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletsListError
|
||||
import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeAction
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeState
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.blockchain.common.Amount
|
|||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.tap.common.extensions.safeUpdate
|
||||
|
|
@ -96,7 +97,11 @@ suspend fun buyErc20TestnetTokens(card: CardDTO, walletManager: EthereumWalletMa
|
|||
amountToSend,
|
||||
destinationAddress,
|
||||
) as? Result.Success ?: return
|
||||
val fee = feeResult.data.minimum
|
||||
|
||||
val fee = when (val feeForTx = feeResult.data) {
|
||||
is TransactionFee.Choosable -> feeForTx.minimum
|
||||
is TransactionFee.Single -> feeForTx.normal
|
||||
}
|
||||
|
||||
val coinValue = walletManager.wallet.amounts[AmountType.Coin]?.value ?: BigDecimal.ZERO
|
||||
if (coinValue < fee.amount.value) return
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ internal class MercuryoService(private val environment: MercuryoEnvironment) : E
|
|||
return when (currencyName) {
|
||||
"BNB" -> Blockchain.BSC
|
||||
"ETH" -> Blockchain.Ethereum
|
||||
"ADA" -> Blockchain.CardanoShelley
|
||||
"ADA" -> Blockchain.Cardano
|
||||
else -> Blockchain.values().find { it.currency.lowercase() == currencyName.lowercase() }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ import com.tangem.common.extensions.ByteArrayKey
|
|||
import com.tangem.common.extensions.toMapKey
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.util.hasDerivation
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.lib.crypto.DerivationManager
|
||||
|
|
@ -46,13 +47,13 @@ class DerivationManagerImpl(
|
|||
} else {
|
||||
null
|
||||
}
|
||||
val blockchainNetwork = BlockchainNetwork(blockchain, card)
|
||||
val appCurrency = com.tangem.tap.features.wallet.models.Currency.fromBlockchainNetwork(
|
||||
blockchainNetwork,
|
||||
appToken,
|
||||
)
|
||||
val scanResponse = appStateHolder.scanResponse
|
||||
if (scanResponse != null) {
|
||||
val blockchainNetwork = BlockchainNetwork(blockchain, scanResponse.derivationStyleProvider)
|
||||
val appCurrency = com.tangem.tap.features.wallet.models.Currency.fromBlockchainNetwork(
|
||||
blockchainNetwork,
|
||||
appToken,
|
||||
)
|
||||
deriveMissingBlockchains(
|
||||
scanResponse = scanResponse,
|
||||
currencyList = listOf(appCurrency),
|
||||
|
|
@ -70,7 +71,7 @@ class DerivationManagerImpl(
|
|||
val scanResponse = appStateHolder.scanResponse
|
||||
val blockchain = Blockchain.fromNetworkId(networkId)
|
||||
if (scanResponse != null && blockchain != null) {
|
||||
return blockchain.derivationPath(appStateHolder.getActualCard()?.derivationStyle)?.rawPath
|
||||
return blockchain.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())?.rawPath
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
|
@ -93,10 +94,11 @@ class DerivationManagerImpl(
|
|||
onSuccess: (ScanResponse) -> Unit,
|
||||
onFailure: (Exception) -> Unit,
|
||||
) {
|
||||
val derivationDataList = listOfNotNull(
|
||||
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencyList),
|
||||
getDerivations(EllipticCurve.Ed25519, scanResponse, currencyList),
|
||||
)
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivationDataList = currencyList.mapNotNull {
|
||||
val curve = config.primaryCurve(it.blockchain)
|
||||
curve?.let { getDerivations(curve, scanResponse, currencyList) }
|
||||
}
|
||||
val derivations = derivationDataList.associate { it.derivations }
|
||||
if (derivations.isEmpty()) {
|
||||
onSuccess(scanResponse)
|
||||
|
|
@ -162,7 +164,7 @@ class DerivationManagerImpl(
|
|||
val manageTokensCandidates = currencyList.map { it.blockchain }.distinct().filter {
|
||||
it.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull {
|
||||
it.derivationPath(scanResponse.card.derivationStyle)
|
||||
it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
|
||||
val customTokensCandidates = currencyList.filter {
|
||||
|
|
|
|||
|
|
@ -1,86 +0,0 @@
|
|||
package com.tangem.tap.proxy
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.TransactionStatus
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.txhistory.TransactionHistoryItem
|
||||
import com.tangem.blockchain.common.txhistory.TransactionHistoryState
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.lib.crypto.TxHistoryManager
|
||||
import com.tangem.lib.crypto.models.ProxyAmount
|
||||
import com.tangem.lib.crypto.models.txhistory.ProxyTransactionHistoryItem
|
||||
import com.tangem.lib.crypto.models.txhistory.ProxyTransactionHistoryState
|
||||
import com.tangem.lib.crypto.models.txhistory.ProxyTransactionStatus
|
||||
|
||||
class TxHistoryManagerImpl(
|
||||
private val appStateHolder: AppStateHolder,
|
||||
) : TxHistoryManager {
|
||||
|
||||
override suspend fun checkTxHistoryState(networkId: String, derivationPath: String?): ProxyTransactionHistoryState {
|
||||
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
|
||||
val walletManager = getActualWalletManager(blockchain, derivationPath)
|
||||
val state = walletManager.getTransactionHistoryState(address = walletManager.wallet.address)
|
||||
return state.mapToProxy()
|
||||
}
|
||||
|
||||
override suspend fun getTxHistoryItems(
|
||||
networkId: String,
|
||||
derivationPath: String?,
|
||||
page: Int,
|
||||
pageSize: Int,
|
||||
): List<ProxyTransactionHistoryItem> {
|
||||
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
|
||||
val walletManager = getActualWalletManager(blockchain, derivationPath)
|
||||
val itemsResult = walletManager.getTransactionsHistory(
|
||||
address = walletManager.wallet.address,
|
||||
page = page,
|
||||
pageSize = pageSize,
|
||||
)
|
||||
|
||||
return when (itemsResult) {
|
||||
is Result.Success -> itemsResult.data.items.map { historyItem -> historyItem.mapToProxy() }
|
||||
is Result.Failure -> error(itemsResult.error.message ?: itemsResult.error.customMessage)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getActualWalletManager(blockchain: Blockchain, derivationPath: String?): WalletManager {
|
||||
val blockchainNetwork = BlockchainNetwork(blockchain, derivationPath, emptyList())
|
||||
val walletManager = appStateHolder.walletState?.getWalletManager(blockchainNetwork)
|
||||
return requireNotNull(walletManager) { "no wallet manager found" }
|
||||
}
|
||||
|
||||
private fun TransactionHistoryState.mapToProxy(): ProxyTransactionHistoryState {
|
||||
return when (this) {
|
||||
TransactionHistoryState.Success.Empty -> ProxyTransactionHistoryState.Success.Empty
|
||||
is TransactionHistoryState.Failed.FetchError -> ProxyTransactionHistoryState.Failed.FetchError(exception)
|
||||
TransactionHistoryState.NotImplemented -> ProxyTransactionHistoryState.NotImplemented
|
||||
is TransactionHistoryState.Success.HasTransactions ->
|
||||
ProxyTransactionHistoryState.Success.HasTransactions(txCount)
|
||||
}
|
||||
}
|
||||
|
||||
private fun TransactionHistoryItem.mapToProxy() = ProxyTransactionHistoryItem(
|
||||
txHash = txHash,
|
||||
timestamp = timestamp,
|
||||
direction = when (val direction = direction) {
|
||||
is TransactionHistoryItem.TransactionDirection.Incoming ->
|
||||
ProxyTransactionHistoryItem.TransactionDirection.Incoming(direction.from)
|
||||
is TransactionHistoryItem.TransactionDirection.Outgoing ->
|
||||
ProxyTransactionHistoryItem.TransactionDirection.Outgoing(direction.to)
|
||||
},
|
||||
status = when (status) {
|
||||
TransactionStatus.Confirmed -> ProxyTransactionStatus.Confirmed
|
||||
TransactionStatus.Unconfirmed -> ProxyTransactionStatus.Unconfirmed
|
||||
},
|
||||
type = when (type) {
|
||||
TransactionHistoryItem.TransactionType.Transfer -> ProxyTransactionHistoryItem.TransactionType.Transfer
|
||||
},
|
||||
amount = ProxyAmount(
|
||||
currencySymbol = amount.currencySymbol,
|
||||
value = requireNotNull(amount.value) { "Amount value must not be null" },
|
||||
decimals = amount.decimals,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.proxy.di
|
||||
|
||||
import androidx.compose.ui.text.intl.Locale
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
|
|
@ -8,7 +8,6 @@ import com.tangem.domain.common.util.cardTypesResolver
|
|||
import com.tangem.feature.learn2earn.domain.api.Learn2earnDependencyProvider
|
||||
import com.tangem.lib.crypto.DerivationManager
|
||||
import com.tangem.lib.crypto.TransactionManager
|
||||
import com.tangem.lib.crypto.TxHistoryManager
|
||||
import com.tangem.lib.crypto.UserWalletManager
|
||||
import com.tangem.tap.proxy.*
|
||||
import dagger.Module
|
||||
|
|
@ -59,12 +58,6 @@ class ProxyModule {
|
|||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideTxHistoryManager(appStateHolder: AppStateHolder): TxHistoryManager {
|
||||
return TxHistoryManagerImpl(appStateHolder = appStateHolder)
|
||||
}
|
||||
|
||||
// regions FeatureConsumers
|
||||
@Provides
|
||||
@Singleton
|
||||
|
|
@ -81,9 +74,7 @@ class ProxyModule {
|
|||
}
|
||||
}
|
||||
|
||||
override fun getLocaleProvider(): () -> String = { Locale.current.language }
|
||||
|
||||
override fun getWebViewAuthCredentialsProvider(): () -> String? = {
|
||||
override fun getWebViewAuthCredentialsProvider(): Provider<String?> = Provider {
|
||||
appStateHolder.mainStore?.state?.globalState?.configManager?.config?.tangemComAuthorization
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.proxy.redux
|
|||
|
||||
import com.tangem.datasource.asset.AssetReader
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
|
|
@ -31,6 +32,7 @@ data class DaggerGraphState(
|
|||
val tokenDetailsRouter: TokenDetailsRouter? = null,
|
||||
val scanCardProcessor: ScanCardProcessor? = null,
|
||||
val cardSdkConfigRepository: CardSdkConfigRepository? = null,
|
||||
val appCurrencyRepository: AppCurrencyRepository? = null,
|
||||
) : StateType {
|
||||
|
||||
inline fun <reified T> get(getDependency: DaggerGraphState.() -> T?): T {
|
||||
|
|
|
|||
13
app/src/main/res/drawable/ic_chia_no_color.xml
Normal file
13
app/src/main/res/drawable/ic_chia_no_color.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
<path
|
||||
android:pathData="M11,0L11,0A11,11 0,0 1,22 11L22,11A11,11 0,0 1,11 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z"
|
||||
android:fillColor="#EBEBEB"/>
|
||||
<path
|
||||
android:pathData="M11.415,6.503C11.372,6.507 11.212,6.521 11.061,6.534C10.799,6.555 10.406,6.603 10.342,6.624C10.325,6.629 10.255,6.642 10.185,6.654C9.672,6.737 9.036,6.949 8.678,7.157C8.613,7.195 8.543,7.233 8.521,7.241C8.44,7.273 7.903,7.658 7.704,7.825C6.237,9.061 5.459,10.99 5.785,12.584C5.825,12.778 5.83,12.78 5.964,12.678C6.179,12.514 6.368,12.389 6.631,12.235C6.785,12.144 7.451,11.811 7.478,11.811C7.482,11.811 7.533,11.789 7.591,11.763C8.174,11.487 9.873,10.889 10.726,10.658C10.758,10.649 10.905,10.608 11.05,10.568C11.86,10.341 11.995,10.311 11.995,10.35C11.995,10.358 11.949,10.383 11.892,10.403C11.613,10.502 10.855,10.816 10.824,10.843C10.814,10.852 10.795,10.86 10.781,10.86C10.768,10.86 10.699,10.888 10.629,10.921C10.559,10.953 10.496,10.981 10.488,10.981C10.482,10.981 10.409,11.012 10.329,11.052C10.248,11.091 10.178,11.123 10.173,11.123C10.168,11.123 10.089,11.159 9.996,11.204C9.903,11.248 9.822,11.285 9.817,11.285C9.734,11.285 7.837,12.304 7.238,12.67C7.102,12.754 6.987,12.822 6.983,12.822C6.977,12.822 6.791,12.942 6.197,13.328C5.534,13.759 4.427,14.564 3.745,15.113C3.664,15.179 3.567,15.256 3.53,15.287C2.939,15.759 2.863,15.845 3.199,15.664C3.954,15.259 4.795,14.854 5.4,14.607C5.77,14.455 6.161,14.342 6.425,14.309L6.535,14.296L6.809,14.578C7.526,15.314 8.297,15.688 9.432,15.849C9.702,15.887 10.568,15.882 10.774,15.841C10.835,15.83 10.967,15.805 11.069,15.788C11.173,15.769 11.283,15.747 11.316,15.738C11.349,15.729 11.432,15.705 11.502,15.687C12.809,15.338 13.928,14.506 14.918,13.144C14.94,13.113 15.028,12.995 15.115,12.88C15.202,12.765 15.291,12.643 15.313,12.61C15.336,12.577 15.391,12.494 15.437,12.427C15.953,11.68 16.683,10.45 17.154,9.536C17.205,9.436 17.288,9.276 17.338,9.182C17.387,9.087 17.547,8.759 17.695,8.454C17.842,8.148 17.971,7.882 17.981,7.862C18.023,7.782 18.007,7.764 17.813,7.684C17.791,7.675 17.645,7.625 17.488,7.572C17.331,7.52 17.154,7.461 17.095,7.44C16.837,7.351 16.408,7.223 15.885,7.081C15.432,6.957 15.308,6.924 15.137,6.886C15.05,6.867 14.957,6.843 14.93,6.834C14.903,6.825 14.828,6.806 14.763,6.795C14.58,6.759 14.5,6.742 14.33,6.704C13.697,6.564 13.148,6.513 12.213,6.503C11.818,6.498 11.459,6.5 11.415,6.503Z"
|
||||
android:fillColor="#909090"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="16dp"
|
||||
android:text="Select"
|
||||
android:text="@string/wallet_choice_wallet_option_title"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
|
|
|||
|
|
@ -264,16 +264,17 @@
|
|||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_sold_out_desc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="14dp"
|
||||
android:background="@drawable/shape_rectangle_rounded_4"
|
||||
android:padding="16dp"
|
||||
android:text="@string/shop_sold_out_description"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textSize="16sp" />
|
||||
<!--TODO: https://tangem.slack.com/archives/C01HARKDLQ0/p1691421861756069-->
|
||||
<!--<TextView-->
|
||||
<!-- android:id="@+id/tv_sold_out_desc"-->
|
||||
<!-- android:layout_width="match_parent"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_marginTop="14dp"-->
|
||||
<!-- android:background="@drawable/shape_rectangle_rounded_4"-->
|
||||
<!-- android:padding="16dp"-->
|
||||
<!-- android:text="@string/shop_sold_out_description"-->
|
||||
<!-- android:textColor="@color/text_tertiary"-->
|
||||
<!-- android:textSize="16sp" />-->
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ dependencies {
|
|||
/** Project */
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.libs.auth)
|
||||
implementation(projects.domain.core)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets.models)
|
||||
|
||||
/** Tangem libraries */
|
||||
|
|
|
|||
|
|
@ -60,4 +60,11 @@ interface TangemTechApi {
|
|||
@Query(value = "locale") locale: String,
|
||||
@Query(value = "shops") shops: String,
|
||||
): SalesResponse
|
||||
|
||||
@GET("quotes")
|
||||
suspend fun getQuotes(
|
||||
@Query("currencyId") currencyId: String,
|
||||
@Query("coinIds") coinIds: String,
|
||||
@Query("fields") fields: String = "price,priceChange24h,lastUpdatedAt",
|
||||
): QuotesResponse
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.datasource.api.tangemTech.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class QuotesResponse(
|
||||
@Json(name = "quotes")
|
||||
val quotes: Map<String, Quote>,
|
||||
) {
|
||||
|
||||
data class Quote(
|
||||
@Json(name = "price")
|
||||
val price: BigDecimal,
|
||||
@Json(name = "priceChange24h")
|
||||
val priceChange: BigDecimal,
|
||||
@Json(name = "lastUpdatedAt")
|
||||
val lastUpdated: String,
|
||||
)
|
||||
}
|
||||
|
|
@ -96,6 +96,7 @@ internal class ConfigManagerImpl @Inject constructor() : ConfigManager {
|
|||
mainnetApiKey = configValues.tonCenterKeys.mainnet,
|
||||
testnetApiKey = configValues.tonCenterKeys.testnet,
|
||||
),
|
||||
chiaFireAcademyApiKey = configValues.chiaFireAcademyApiKey,
|
||||
),
|
||||
appsFlyerDevKey = configValues.appsFlyer.appsFlyerDevKey,
|
||||
amplitudeApiKey = configValues.amplitudeApiKey,
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class ConfigValueModel(
|
|||
val kaspaSecondaryApiUrl: String,
|
||||
val walletConnectProjectId: String,
|
||||
val tangemComAuthorization: String?,
|
||||
val chiaFireAcademyApiKey: String?,
|
||||
)
|
||||
|
||||
data class AppsFlyer(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
package com.tangem.datasource.di
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse
|
||||
import com.tangem.datasource.local.appcurrency.AvailableAppCurrenciesStore
|
||||
import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore
|
||||
import com.tangem.datasource.local.appcurrency.implementation.DefaultAvailableAppCurrenciesStore
|
||||
import com.tangem.datasource.local.appcurrency.implementation.DefaultSelectedAppCurrencyStore
|
||||
import com.tangem.datasource.local.datastore.RuntimeDataStore
|
||||
import com.tangem.datasource.local.datastore.SharedPreferencesDataStore
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object AppCurrencyDataModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAvailableAppCurrenciesStore(): AvailableAppCurrenciesStore {
|
||||
return DefaultAvailableAppCurrenciesStore(
|
||||
dataStore = RuntimeDataStore(),
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSelectedAppCurrencyStore(
|
||||
@ApplicationContext context: Context,
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
): SelectedAppCurrencyStore {
|
||||
return DefaultSelectedAppCurrencyStore(
|
||||
dataStore = SharedPreferencesDataStore(
|
||||
preferencesName = "selected_app_currency",
|
||||
context = context,
|
||||
adapter = moshi.adapter(CurrenciesResponse.Currency::class.java),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.tangem.datasource.di
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.datasource.local.datastore.SharedPreferencesDataStore
|
||||
import com.tangem.datasource.local.quote.DefaultQuotesStore
|
||||
import com.tangem.datasource.local.quote.QuotesStore
|
||||
import com.tangem.datasource.local.quote.model.StoredQuote
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object QuotesStoreModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideQuotesStore(@ApplicationContext context: Context, @NetworkMoshi moshi: Moshi): QuotesStore {
|
||||
return DefaultQuotesStore(
|
||||
dataStore = SharedPreferencesDataStore(
|
||||
preferencesName = "quotes",
|
||||
context = context,
|
||||
adapter = moshi.adapter(StoredQuote::class.java),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.datasource.local.appcurrency
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse
|
||||
|
||||
interface AvailableAppCurrenciesStore {
|
||||
|
||||
suspend fun getAllSyncOrNull(): List<CurrenciesResponse.Currency>?
|
||||
|
||||
suspend fun getSyncOrNull(key: String): CurrenciesResponse.Currency?
|
||||
|
||||
suspend fun store(response: CurrenciesResponse)
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.datasource.local.appcurrency
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
// TODO: Will be implemented in [REDACTED_TASK_KEY] task
|
||||
internal class MockSelectedAppCurrencyStore : SelectedAppCurrencyStore {
|
||||
|
||||
override fun get(): Flow<CurrenciesResponse.Currency> {
|
||||
return flowOf(
|
||||
CurrenciesResponse.Currency(
|
||||
id = "usd",
|
||||
code = "USD",
|
||||
name = "US Dollar",
|
||||
unit = "$",
|
||||
type = "fiat",
|
||||
rateBTC = "",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun store(item: CurrenciesResponse.Currency) {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.datasource.local.appcurrency
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface SelectedAppCurrencyStore {
|
||||
|
||||
fun get(): Flow<CurrenciesResponse.Currency>
|
||||
|
||||
suspend fun store(item: CurrenciesResponse.Currency)
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.datasource.local.appcurrency.implementation
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse
|
||||
import com.tangem.datasource.local.appcurrency.AvailableAppCurrenciesStore
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStoreDecorator
|
||||
|
||||
internal class DefaultAvailableAppCurrenciesStore(
|
||||
private val dataStore: StringKeyDataStore<CurrenciesResponse.Currency>,
|
||||
) : AvailableAppCurrenciesStore,
|
||||
StringKeyDataStoreDecorator<String, CurrenciesResponse.Currency>(dataStore) {
|
||||
|
||||
override fun provideStringKey(key: String): String {
|
||||
return key
|
||||
}
|
||||
|
||||
override suspend fun store(response: CurrenciesResponse) {
|
||||
val currencies = response.currencies.associateBy(CurrenciesResponse.Currency::code)
|
||||
|
||||
dataStore.store(currencies)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.datasource.local.appcurrency.implementation
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse
|
||||
import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore
|
||||
import com.tangem.datasource.local.datastore.core.KeylessDataStoreDecorator
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||
|
||||
internal class DefaultSelectedAppCurrencyStore(
|
||||
dataStore: StringKeyDataStore<CurrenciesResponse.Currency>,
|
||||
) : SelectedAppCurrencyStore, KeylessDataStoreDecorator<CurrenciesResponse.Currency>(dataStore)
|
||||
|
|
@ -3,38 +3,49 @@ package com.tangem.datasource.local.datastore
|
|||
import com.squareup.moshi.JsonAdapter
|
||||
import com.tangem.datasource.files.FileReader
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||
import com.tangem.datasource.local.datastore.model.WriteTrigger
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import com.tangem.datasource.local.datastore.utils.Trigger
|
||||
import kotlinx.coroutines.flow.*
|
||||
import timber.log.Timber
|
||||
|
||||
@Deprecated("Use shared preferences data store instead")
|
||||
internal class FileDataStore<Value : Any>(
|
||||
private val fileReader: FileReader,
|
||||
private val adapter: JsonAdapter<Value>,
|
||||
) : StringKeyDataStore<Value> {
|
||||
|
||||
private val writeTrigger = MutableSharedFlow<WriteTrigger>(
|
||||
replay = 1,
|
||||
onBufferOverflow = BufferOverflow.DROP_OLDEST,
|
||||
)
|
||||
private val writeTrigger = Trigger()
|
||||
|
||||
override fun get(key: String): Flow<Value> {
|
||||
return writeTrigger
|
||||
.onEmpty { emit(WriteTrigger) }
|
||||
.map { getInternal(key) }
|
||||
.filterNotNull()
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
override fun getAll(): Flow<List<Value>> {
|
||||
val e = NotImplementedError("`getAll()` function not implemented for `FileDataStore`")
|
||||
Timber.e(e)
|
||||
|
||||
throw e
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(key: String): Value? {
|
||||
return getInternal(key)
|
||||
}
|
||||
|
||||
override suspend fun getAllSyncOrNull(): List<Value> {
|
||||
val e = NotImplementedError("`getAllSyncOrNull()` function not implemented for `FileDataStore`")
|
||||
Timber.e(e)
|
||||
|
||||
throw e
|
||||
}
|
||||
|
||||
override suspend fun store(key: String, item: Value) {
|
||||
try {
|
||||
val json = adapter.toJson(item)
|
||||
|
||||
fileReader.rewriteFile(json, key)
|
||||
writeTrigger.tryEmit(WriteTrigger)
|
||||
writeTrigger.trigger()
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "Unable to write file: $key")
|
||||
}
|
||||
|
|
@ -48,10 +59,14 @@ internal class FileDataStore<Value : Any>(
|
|||
|
||||
override suspend fun remove(key: String) {
|
||||
fileReader.removeFile(key)
|
||||
writeTrigger.trigger()
|
||||
}
|
||||
|
||||
override suspend fun clear() {
|
||||
// TODO: Implement if needed
|
||||
val e = NotImplementedError("`clear()` function not implemented for `FileDataStore`")
|
||||
Timber.e(e)
|
||||
|
||||
throw e
|
||||
}
|
||||
|
||||
private fun getInternal(fileName: String): Value? {
|
||||
|
|
|
|||
|
|
@ -13,10 +13,18 @@ internal class RuntimeDataStore<Data : Any> : StringKeyDataStore<Data> {
|
|||
.filterNotNull()
|
||||
}
|
||||
|
||||
override fun getAll(): Flow<List<Data>> {
|
||||
return store.map { value -> value.values.toList() }
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(key: String): Data? {
|
||||
return store.value[key]
|
||||
}
|
||||
|
||||
override suspend fun getAllSyncOrNull(): List<Data> {
|
||||
return store.value.values.toList()
|
||||
}
|
||||
|
||||
override suspend fun store(key: String, item: Data) {
|
||||
store.update { value ->
|
||||
value[key] = item
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
package com.tangem.datasource.local.datastore
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Context.MODE_PRIVATE
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||
import com.tangem.datasource.local.datastore.utils.Trigger
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import timber.log.Timber
|
||||
|
||||
internal class SharedPreferencesDataStore<Value : Any>(
|
||||
preferencesName: String,
|
||||
private val context: Context,
|
||||
private val adapter: JsonAdapter<Value>,
|
||||
) : StringKeyDataStore<Value> {
|
||||
|
||||
private val sharedPreferences: SharedPreferences by lazy {
|
||||
context.getSharedPreferences(preferencesName, MODE_PRIVATE)
|
||||
}
|
||||
|
||||
private val writeTrigger = Trigger()
|
||||
|
||||
override fun get(key: String): Flow<Value> {
|
||||
return writeTrigger
|
||||
.map { getInternal(key) }
|
||||
.filterNotNull()
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
override fun getAll(): Flow<List<Value>> {
|
||||
return writeTrigger
|
||||
.map { getAllInternal() }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(key: String): Value? {
|
||||
return getInternal(key)
|
||||
}
|
||||
|
||||
override suspend fun getAllSyncOrNull(): List<Value> {
|
||||
return getAllInternal()
|
||||
}
|
||||
|
||||
override suspend fun store(key: String, item: Value) {
|
||||
try {
|
||||
val json = adapter.toJson(item)
|
||||
|
||||
sharedPreferences.edit { putString(key, json) }
|
||||
writeTrigger.trigger()
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "Unable to edit preferences: $key")
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun store(items: Map<String, Value>) {
|
||||
items.forEach { (key, item) ->
|
||||
store(key, item)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun remove(key: String) {
|
||||
sharedPreferences.edit { remove(key) }
|
||||
writeTrigger.trigger()
|
||||
}
|
||||
|
||||
override suspend fun clear() {
|
||||
sharedPreferences.edit { clear() }
|
||||
writeTrigger.trigger()
|
||||
}
|
||||
|
||||
private fun getInternal(key: String): Value? {
|
||||
return try {
|
||||
val json = sharedPreferences.getString(key, null) ?: return null
|
||||
|
||||
adapter.fromJson(json)
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "Unable to get value from preferences: $key")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAllInternal(): List<Value> {
|
||||
return sharedPreferences.all.mapNotNull { (key, value) ->
|
||||
try {
|
||||
val json = value as? String ?: return@mapNotNull null
|
||||
|
||||
adapter.fromJson(json)
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "Unable to convert value from JSON: $key")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue