Updated on 2026-08-14
This commit is contained in:
parent
de890421cb
commit
40b616868d
25 changed files with 258 additions and 78 deletions
|
|
@ -33,6 +33,7 @@ dependencies {
|
|||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.txhistory)
|
||||
implementation(projects.domain.appCurrency)
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
|
||||
implementation(project(":common"))
|
||||
implementation(project(":core:analytics"))
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.datasource.di
|
||||
|
||||
import com.tangem.datasource.local.appcurrency.MockSelectedAppCurrencyStore
|
||||
import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object AppCurrencyDataModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSelectedAppCurrencyStore(): SelectedAppCurrencyStore {
|
||||
return MockSelectedAppCurrencyStore()
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels
|
||||
package com.tangem.utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.Job
|
||||
|
||||
|
|
@ -7,7 +7,7 @@ import kotlinx.coroutines.Job
|
|||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class JobHolder {
|
||||
class JobHolder {
|
||||
|
||||
private var job: Job? = null
|
||||
|
||||
|
|
@ -18,4 +18,4 @@ internal class JobHolder {
|
|||
}
|
||||
}
|
||||
|
||||
internal fun Job.saveIn(jobHolder: JobHolder) = jobHolder.update(job = this)
|
||||
fun Job.saveIn(jobHolder: JobHolder) = jobHolder.update(job = this)
|
||||
|
|
@ -17,7 +17,7 @@ internal class MockAppCurrencyRepository : AppCurrencyRepository {
|
|||
return mockAppCurrencies
|
||||
}
|
||||
|
||||
override suspend fun changeAppCurrency(appCurrency: AppCurrency) {
|
||||
override suspend fun changeAppCurrency(currencyCode: String) {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import com.tangem.data.tokens.repository.DefaultCurrenciesRepository
|
|||
import com.tangem.data.tokens.repository.DefaultNetworksRepository
|
||||
import com.tangem.data.tokens.repository.DefaultQuotesRepository
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore
|
||||
import com.tangem.datasource.local.quote.QuotesStore
|
||||
import com.tangem.datasource.local.token.UserTokensStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
|
|
@ -40,10 +41,17 @@ internal object TokensDataModule {
|
|||
fun provideQuotesRepository(
|
||||
tangemTechApi: TangemTechApi,
|
||||
quotesStore: QuotesStore,
|
||||
selectedAppCurrencyStore: SelectedAppCurrencyStore,
|
||||
cacheRegistry: CacheRegistry,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): QuotesRepository {
|
||||
return DefaultQuotesRepository(tangemTechApi, quotesStore, cacheRegistry, dispatchers)
|
||||
return DefaultQuotesRepository(
|
||||
tangemTechApi,
|
||||
quotesStore,
|
||||
selectedAppCurrencyStore,
|
||||
cacheRegistry,
|
||||
dispatchers,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.data.tokens.repository
|
|||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.tokens.utils.QuotesConverter
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore
|
||||
import com.tangem.datasource.local.quote.QuotesStore
|
||||
import com.tangem.domain.tokens.models.CryptoCurrency
|
||||
import com.tangem.domain.tokens.models.Quote
|
||||
|
|
@ -10,6 +11,7 @@ import com.tangem.domain.tokens.repository.QuotesRepository
|
|||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.channelFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -17,12 +19,15 @@ import timber.log.Timber
|
|||
internal class DefaultQuotesRepository(
|
||||
private val tangemTechApi: TangemTechApi,
|
||||
private val quotesStore: QuotesStore,
|
||||
private val selectedAppCurrencyStore: SelectedAppCurrencyStore,
|
||||
private val cacheRegistry: CacheRegistry,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : QuotesRepository {
|
||||
|
||||
private val quotesConverter = QuotesConverter()
|
||||
|
||||
private var quotesFetchedForAppCurrency: String? = null
|
||||
|
||||
override fun getQuotes(currenciesIds: Set<CryptoCurrency.ID>, refresh: Boolean): Flow<Set<Quote>> {
|
||||
return channelFlow {
|
||||
launch(dispatchers.io) {
|
||||
|
|
@ -32,22 +37,33 @@ internal class DefaultQuotesRepository(
|
|||
}
|
||||
|
||||
launch(dispatchers.io) {
|
||||
fetchExpiredQuotes(currenciesIds, refresh)
|
||||
selectedAppCurrencyStore.get().collectLatest { appCurrency ->
|
||||
fetchExpiredQuotes(currenciesIds, appCurrency.id, refresh)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchExpiredQuotes(currenciesIds: Set<CryptoCurrency.ID>, refresh: Boolean) {
|
||||
val expiredCurrenciesIds = filterExpiredCurrenciesIds(currenciesIds, refresh)
|
||||
private suspend fun fetchExpiredQuotes(
|
||||
currenciesIds: Set<CryptoCurrency.ID>,
|
||||
appCurrencyId: String,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
val expiredCurrenciesIds = filterExpiredCurrenciesIds(
|
||||
currenciesIds = currenciesIds,
|
||||
refresh = refresh || quotesFetchedForAppCurrency != appCurrencyId,
|
||||
)
|
||||
if (expiredCurrenciesIds.isEmpty()) return
|
||||
|
||||
fetchQuotes(expiredCurrenciesIds)
|
||||
quotesFetchedForAppCurrency = appCurrencyId
|
||||
|
||||
fetchQuotes(expiredCurrenciesIds, appCurrencyId)
|
||||
}
|
||||
|
||||
private suspend fun fetchQuotes(rawCurrenciesIds: Set<String>) {
|
||||
private suspend fun fetchQuotes(rawCurrenciesIds: Set<String>, appCurrencyId: String) {
|
||||
try {
|
||||
val response = tangemTechApi.getQuotes(
|
||||
currencyId = "usd", // TODO: [REDACTED_JIRA]
|
||||
currencyId = appCurrencyId,
|
||||
coinIds = rawCurrenciesIds.joinToString(separator = ","),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,5 +9,5 @@ interface AppCurrencyRepository {
|
|||
|
||||
suspend fun getAvailableAppCurrencies(): List<AppCurrency>
|
||||
|
||||
suspend fun changeAppCurrency(appCurrency: AppCurrency)
|
||||
suspend fun changeAppCurrency(currencyCode: String)
|
||||
}
|
||||
|
|
@ -4,11 +4,17 @@ plugins {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
/** Project - Domain */
|
||||
implementation(projects.domain.core)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
|
||||
/** Project - Other */
|
||||
implementation(projects.core.utils)
|
||||
|
||||
/** Tests */
|
||||
testImplementation(deps.test.junit)
|
||||
testImplementation(deps.test.coroutine)
|
||||
}
|
||||
|
|
@ -56,6 +56,8 @@ dependencies {
|
|||
implementation(projects.domain.txhistory.models)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.appCurrency)
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
|
||||
/** Feature Apis */
|
||||
implementation(projects.features.wallet.api)
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ internal class DefaultWalletRouter(private val navigationStateHolder: Navigation
|
|||
}
|
||||
|
||||
override fun openDetailsScreen() {
|
||||
// FIXME: Prepare details screen (e.g. dispatch action: `DetailsAction.PrepareScreen`)
|
||||
// [REDACTED_JIRA]
|
||||
navigationStateHolder.navigate(action = NavigationAction.NavigateTo(AppScreen.Details))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.factory
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
|
|
@ -25,6 +26,7 @@ import com.tangem.utils.converter.Converter
|
|||
*/
|
||||
internal class WalletLoadedTokensListConverter(
|
||||
private val currentStateProvider: Provider<WalletState>,
|
||||
appCurrencyProvider: Provider<AppCurrency>,
|
||||
cardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
isLockedWalletProvider: Provider<Boolean>,
|
||||
clickIntents: WalletClickIntents,
|
||||
|
|
@ -34,9 +36,8 @@ internal class WalletLoadedTokensListConverter(
|
|||
currentStateProvider = currentStateProvider,
|
||||
cardTypeResolverProvider = cardTypeResolverProvider,
|
||||
isLockedWalletProvider = isLockedWalletProvider,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
isWalletContentHidden = false, // TODO: [REDACTED_JIRA]
|
||||
fiatCurrencyCode = "USD", // TODO: [REDACTED_JIRA]
|
||||
fiatCurrencySymbol = "$", // TODO: [REDACTED_JIRA]
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.common.Provider
|
|||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeConfig
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.tokens.error.CurrencyError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
|
|
@ -20,8 +21,7 @@ import java.math.BigDecimal
|
|||
internal class WalletSingleCurrencyLoadedBalanceConverter(
|
||||
private val currentStateProvider: Provider<WalletState>,
|
||||
private val cardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
private val fiatCurrencyCode: String,
|
||||
private val fiatCurrencySymbol: String,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
) : Converter<Either<CurrencyError, CryptoCurrencyStatus>, WalletSingleCurrencyState.Content> {
|
||||
|
||||
override fun convert(value: Either<CurrencyError, CryptoCurrencyStatus>): WalletSingleCurrencyState.Content {
|
||||
|
|
@ -47,7 +47,7 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
|
|||
is CryptoCurrencyStatus.Loaded,
|
||||
-> MarketPriceBlockState.Content(
|
||||
currencyName = currencyName,
|
||||
price = formatPrice(status),
|
||||
price = formatPrice(status, appCurrencyProvider()),
|
||||
priceChangeConfig = PriceChangeConfig(
|
||||
valueInPercent = formatPriceChange(status),
|
||||
type = getPriceChangeType(status),
|
||||
|
|
@ -67,6 +67,7 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
|
|||
state: WalletSingleCurrencyState,
|
||||
): WalletsListConfig {
|
||||
val selectedWallet = state.walletsListConfig.wallets[state.walletsListConfig.selectedWalletIndex]
|
||||
|
||||
val updatedWallet = when (status) {
|
||||
is CryptoCurrencyStatus.NoQuote,
|
||||
is CryptoCurrencyStatus.Loaded,
|
||||
|
|
@ -81,7 +82,7 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
|
|||
),
|
||||
imageResId = selectedWallet.imageResId,
|
||||
onClick = selectedWallet.onClick,
|
||||
balance = formatFiatAmount(status),
|
||||
balance = formatFiatAmount(status, appCurrencyProvider()),
|
||||
)
|
||||
}
|
||||
is CryptoCurrencyStatus.Loading -> {
|
||||
|
|
@ -133,23 +134,23 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
|
|||
)
|
||||
}
|
||||
|
||||
private fun formatPrice(status: CryptoCurrencyStatus.Status): String {
|
||||
private fun formatPrice(status: CryptoCurrencyStatus.Status, appCurrency: AppCurrency): String {
|
||||
val fiatRate = status.fiatRate ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN
|
||||
|
||||
return BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = fiatRate,
|
||||
fiatCurrencyCode = fiatCurrencyCode,
|
||||
fiatCurrencySymbol = fiatCurrencySymbol,
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
}
|
||||
|
||||
private fun formatFiatAmount(status: CryptoCurrencyStatus.Status): String {
|
||||
private fun formatFiatAmount(status: CryptoCurrencyStatus.Status, appCurrency: AppCurrency): String {
|
||||
val fiatAmount = status.fiatAmount ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN
|
||||
|
||||
return BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = fiatAmount,
|
||||
fiatCurrencyCode = fiatCurrencyCode,
|
||||
fiatCurrencySymbol = fiatCurrencySymbol,
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.factory
|
|||
import androidx.paging.PagingData
|
||||
import arrow.core.Either
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.tokens.error.CurrencyError
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
|
|
@ -37,6 +38,7 @@ internal class WalletStateFactory(
|
|||
private val currentStateProvider: Provider<WalletState>,
|
||||
private val currentCardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
private val isLockedWalletProvider: Provider<Boolean>,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
) {
|
||||
|
||||
|
|
@ -47,6 +49,7 @@ internal class WalletStateFactory(
|
|||
currentStateProvider = currentStateProvider,
|
||||
cardTypeResolverProvider = currentCardTypeResolverProvider,
|
||||
isLockedWalletProvider = isLockedWalletProvider,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
}
|
||||
|
|
@ -70,8 +73,7 @@ internal class WalletStateFactory(
|
|||
WalletSingleCurrencyLoadedBalanceConverter(
|
||||
currentStateProvider = currentStateProvider,
|
||||
cardTypeResolverProvider = currentCardTypeResolverProvider,
|
||||
fiatCurrencyCode = "USD", // TODO: [REDACTED_JIRA]
|
||||
fiatCurrencySymbol = "$", // TODO: [REDACTED_JIRA]
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.utils
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeConfig
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.models.CryptoCurrency
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
|
|
@ -11,9 +13,8 @@ import com.tangem.utils.converter.Converter
|
|||
import java.math.BigDecimal
|
||||
|
||||
internal class CryptoCurrencyStatusToTokenItemConverter(
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val isWalletContentHidden: Boolean,
|
||||
private val fiatCurrencyCode: String,
|
||||
private val fiatCurrencySymbol: String,
|
||||
) : Converter<CryptoCurrencyStatus, TokenItemState> {
|
||||
|
||||
private val CryptoCurrencyStatus.networkIconResId: Int?
|
||||
|
|
@ -71,8 +72,9 @@ internal class CryptoCurrencyStatusToTokenItemConverter(
|
|||
|
||||
private fun CryptoCurrencyStatus.getFormattedFiatAmount(): String {
|
||||
val fiatAmount = value.fiatAmount ?: return UNKNOWN_AMOUNT_SIGN
|
||||
val appCurrency = appCurrencyProvider()
|
||||
|
||||
return BigDecimalFormatter.formatFiatAmount(fiatAmount, fiatCurrencyCode, fiatCurrencySymbol)
|
||||
return BigDecimalFormatter.formatFiatAmount(fiatAmount, appCurrency.code, appCurrency.symbol)
|
||||
}
|
||||
|
||||
private fun CryptoCurrencyStatus.mapToUnreachableTokenItemState() = TokenItemState.Unreachable(
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.utils
|
|||
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter.formatFiatAmount
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
|
||||
|
|
@ -11,10 +12,9 @@ import com.tangem.utils.converter.Converter
|
|||
internal class FiatBalanceToWalletCardConverter(
|
||||
private val currentState: WalletCardState,
|
||||
private val cardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val isLockedState: Boolean,
|
||||
private val isWalletContentHidden: Boolean,
|
||||
private val fiatCurrencyCode: String,
|
||||
private val fiatCurrencySymbol: String,
|
||||
) : Converter<TokenList.FiatBalance, WalletCardState> {
|
||||
|
||||
override fun convert(value: TokenList.FiatBalance): WalletCardState {
|
||||
|
|
@ -33,13 +33,15 @@ internal class FiatBalanceToWalletCardConverter(
|
|||
if (isWalletContentHidden) {
|
||||
WalletCardState.HiddenContent(id, title, additionalInfo, imageResId, onClick)
|
||||
} else {
|
||||
val appCurrency = appCurrencyProvider()
|
||||
|
||||
WalletCardState.Content(
|
||||
id = id,
|
||||
title = title,
|
||||
additionalInfo = additionalInfo,
|
||||
imageResId = imageResId,
|
||||
onClick = onClick,
|
||||
balance = formatFiatAmount(value.amount, fiatCurrencyCode, fiatCurrencySymbol),
|
||||
balance = formatFiatAmount(value.amount, appCurrency.code, appCurrency.symbol),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.utils
|
||||
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.NetworkGroup
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
|
|
@ -14,16 +16,14 @@ import kotlinx.collections.immutable.mutate
|
|||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
internal class TokenListToContentItemsConverter(
|
||||
appCurrencyProvider: Provider<AppCurrency>,
|
||||
isWalletContentHidden: Boolean,
|
||||
fiatCurrencyCode: String,
|
||||
fiatCurrencySymbol: String,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
) : Converter<TokenList, WalletTokensListState> {
|
||||
|
||||
private val tokenStatusConverter = CryptoCurrencyStatusToTokenItemConverter(
|
||||
isWalletContentHidden = isWalletContentHidden,
|
||||
fiatCurrencyCode = fiatCurrencyCode,
|
||||
fiatCurrencySymbol = fiatCurrencySymbol,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
)
|
||||
|
||||
override fun convert(value: TokenList): WalletTokensListState {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.utils
|
||||
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
|
|
@ -18,16 +19,14 @@ internal class TokenListToWalletStateConverter(
|
|||
private val currentStateProvider: Provider<WalletState>,
|
||||
private val cardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
private val isLockedWalletProvider: Provider<Boolean>,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val isWalletContentHidden: Boolean,
|
||||
private val fiatCurrencyCode: String,
|
||||
private val fiatCurrencySymbol: String,
|
||||
clickIntents: WalletClickIntents,
|
||||
) : Converter<TokensListModel, WalletMultiCurrencyState.Content> {
|
||||
|
||||
private val tokenListToContentConverter = TokenListToContentItemsConverter(
|
||||
isWalletContentHidden = isWalletContentHidden,
|
||||
fiatCurrencyCode = fiatCurrencyCode,
|
||||
fiatCurrencySymbol = fiatCurrencySymbol,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
|
||||
|
|
@ -51,9 +50,8 @@ internal class TokenListToWalletStateConverter(
|
|||
currentState = selectedWalletCard,
|
||||
isLockedState = isLockedWalletProvider(),
|
||||
cardTypeResolverProvider = cardTypeResolverProvider,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
isWalletContentHidden = isWalletContentHidden,
|
||||
fiatCurrencyCode = fiatCurrencyCode,
|
||||
fiatCurrencySymbol = fiatCurrencySymbol,
|
||||
)
|
||||
|
||||
return walletsListConfig.copy(
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.viewmodels
|
|||
|
||||
import androidx.lifecycle.*
|
||||
import androidx.paging.cachedIn
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.common.Provider
|
||||
|
|
@ -9,6 +10,8 @@ import com.tangem.common.doOnFailure
|
|||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.card.*
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.common.extensions.derivationPath
|
||||
|
|
@ -37,11 +40,10 @@ import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCard
|
|||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletStateFactory
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import kotlin.properties.Delegates
|
||||
|
|
@ -71,12 +73,15 @@ internal class WalletViewModel @Inject constructor(
|
|||
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
|
||||
private val getExploreUrlUseCase: GetExploreUrlUseCase,
|
||||
private val unlockWalletsUseCase: UnlockWalletsUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : ViewModel(), DefaultLifecycleObserver, WalletClickIntents {
|
||||
|
||||
/** Feature router */
|
||||
var router: InnerWalletRouter by Delegates.notNull()
|
||||
|
||||
private val selectedAppCurrencyFlow: StateFlow<AppCurrency> = createSelectedAppCurrencyFlow()
|
||||
|
||||
private val notificationsListFactory = WalletNotificationsListFactory(
|
||||
currentStateProvider = Provider { uiState },
|
||||
wasCardScannedCallback = getCardWasScannedUseCase::invoke,
|
||||
|
|
@ -95,6 +100,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
isLockedWalletProvider = Provider {
|
||||
wallets[requireNotNull(uiState as? WalletState.ContentState).walletsListConfig.selectedWalletIndex].isLocked
|
||||
},
|
||||
appCurrencyProvider = Provider(selectedAppCurrencyFlow::value),
|
||||
clickIntents = this,
|
||||
)
|
||||
|
||||
|
|
@ -432,4 +438,16 @@ internal class WalletViewModel @Inject constructor(
|
|||
override fun onBottomSheetDismiss() {
|
||||
uiState = stateFactory.getStateWithClosedBottomSheet()
|
||||
}
|
||||
|
||||
private fun createSelectedAppCurrencyFlow(): StateFlow<AppCurrency> {
|
||||
return getSelectedAppCurrencyUseCase()
|
||||
.map { maybeAppCurrency ->
|
||||
maybeAppCurrency.getOrElse { AppCurrency.Default }
|
||||
}
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = AppCurrency.Default,
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue