Updated on 2026-08-14
This commit is contained in:
commit
a25b99f933
10 changed files with 74 additions and 8 deletions
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.appcurrency.FetchAppCurrenciesUseCase
|
||||
import com.tangem.domain.appcurrency.GetAvailableCurrenciesUseCase
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.SelectAppCurrencyUseCase
|
||||
|
|
@ -8,6 +9,7 @@ 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)
|
||||
|
|
@ -31,4 +33,10 @@ internal object AppCurrencyDomainModule {
|
|||
): GetAvailableCurrenciesUseCase {
|
||||
return GetAvailableCurrenciesUseCase(appCurrencyRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideFetchAppCurrenciesUseCase(appCurrencyRepository: AppCurrencyRepository): FetchAppCurrenciesUseCase {
|
||||
return FetchAppCurrenciesUseCase(appCurrencyRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,11 +5,13 @@ import androidx.lifecycle.viewModelScope
|
|||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.core.navigation.ReduxNavController
|
||||
import com.tangem.domain.appcurrency.FetchAppCurrenciesUseCase
|
||||
import com.tangem.domain.balancehiding.BalanceHidingSettings
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.balancehiding.ListenToFlipsUseCase
|
||||
import com.tangem.domain.balancehiding.UpdateBalanceHidingSettingsUseCase
|
||||
import com.tangem.tap.features.main.model.MainScreenState
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -20,6 +22,8 @@ internal class MainViewModel @Inject constructor(
|
|||
private val updateBalanceHidingSettingsUseCase: UpdateBalanceHidingSettingsUseCase,
|
||||
private val listenToFlipsUseCase: ListenToFlipsUseCase,
|
||||
private val reduxNavController: ReduxNavController,
|
||||
private val fetchAppCurrenciesUseCase: FetchAppCurrenciesUseCase,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
) : ViewModel(), MainIntents {
|
||||
|
||||
|
|
@ -33,11 +37,18 @@ internal class MainViewModel @Inject constructor(
|
|||
val state: StateFlow<MainScreenState> = stateHolder.stateFlow
|
||||
|
||||
init {
|
||||
updateAppCurrencies()
|
||||
observeFlips()
|
||||
displayBalancesHidingStatusToast()
|
||||
displayHiddenBalancesModalNotification()
|
||||
}
|
||||
|
||||
private fun updateAppCurrencies() {
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
fetchAppCurrenciesUseCase.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeFlips() {
|
||||
listenToFlipsUseCase().launchIn(viewModelScope)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
package com.tangem.datasource.api.tangemTech.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CurrenciesResponse(
|
||||
@Json(name = "currencies") val currencies: List<Currency>,
|
||||
@Json(name = "imageHost") val imageHost: String? = null,
|
||||
) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Currency(
|
||||
@Json(name = "id") val id: String,
|
||||
@Json(name = "code") val code: String, // this is an uppercase id
|
||||
|
|
@ -13,5 +17,7 @@ data class CurrenciesResponse(
|
|||
@Json(name = "rateBTC") val rateBTC: String,
|
||||
@Json(name = "unit") val unit: String, // $, €, ₽
|
||||
@Json(name = "type") val type: String,
|
||||
val iconSmallUrl: String? = null,
|
||||
val iconMediumUrl: String? = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -15,8 +15,20 @@ internal class DefaultAvailableAppCurrenciesStore(
|
|||
}
|
||||
|
||||
override suspend fun store(response: CurrenciesResponse) {
|
||||
val currencies = response.currencies.associateBy(CurrenciesResponse.Currency::code)
|
||||
val currencies = response.currencies
|
||||
.map {
|
||||
it.copy(
|
||||
iconSmallUrl = response.imageHost?.plus(IMAGE_SMALL)?.format(it.id),
|
||||
iconMediumUrl = response.imageHost?.plus(IMAGE_MEDIUM)?.format(it.id),
|
||||
)
|
||||
}
|
||||
.associateBy(CurrenciesResponse.Currency::code)
|
||||
|
||||
dataStore.store(currencies)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val IMAGE_MEDIUM = "medium/%s.png"
|
||||
const val IMAGE_SMALL = "small/%s.png"
|
||||
}
|
||||
}
|
||||
|
|
@ -77,16 +77,18 @@ internal class DefaultAppCurrencyRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchDefaultAppCurrency() {
|
||||
fetchAvailableCurrenciesIfExpired()
|
||||
|
||||
changeAppCurrency(DEFAULT_CURRENCY_CODE)
|
||||
override suspend fun fetchDefaultAppCurrency(isRefresh: Boolean) {
|
||||
withContext(dispatchers.io) {
|
||||
fetchAvailableCurrenciesIfExpired(isRefresh)
|
||||
val appCurrency = appPreferencesStore.getSyncOrNull(PreferencesKeys.SELECTED_APP_CURRENCY_KEY)
|
||||
changeAppCurrency(appCurrency ?: DEFAULT_CURRENCY_CODE)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchAvailableCurrenciesIfExpired() {
|
||||
private suspend fun fetchAvailableCurrenciesIfExpired(isRefresh: Boolean = false) {
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = AVAILABLE_CURRENCIES_CACHE_KEY,
|
||||
skipCache = false,
|
||||
skipCache = isRefresh,
|
||||
expireIn = Duration.standardMinutes(AVAILABLE_CURRENCIES_CACHE_KEY_EXPIRE_MINUTES),
|
||||
block = { fetchAvailableCurrencies() },
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ internal class AppCurrencyConverter : Converter<CurrenciesResponse.Currency, App
|
|||
code = value.code,
|
||||
name = value.name,
|
||||
symbol = value.unit,
|
||||
iconSmallUrl = value.iconSmallUrl,
|
||||
iconMediumUrl = value.iconMediumUrl,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,8 @@ data class AppCurrency(
|
|||
val code: String,
|
||||
val name: String,
|
||||
val symbol: String,
|
||||
val iconSmallUrl: String? = null,
|
||||
val iconMediumUrl: String? = null,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.domain.appcurrency
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.domain.appcurrency.error.SelectedAppCurrencyError
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
|
||||
class FetchAppCurrenciesUseCase(
|
||||
private val appCurrencyRepository: AppCurrencyRepository,
|
||||
) {
|
||||
suspend operator fun invoke(): Either<Throwable, Unit> = either {
|
||||
catch(
|
||||
block = { appCurrencyRepository.fetchDefaultAppCurrency(isRefresh = true) },
|
||||
catch = { SelectedAppCurrencyError.DataError(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,9 +5,14 @@ import kotlinx.coroutines.flow.Flow
|
|||
|
||||
interface AppCurrencyRepository {
|
||||
|
||||
/**
|
||||
* Get Selected App Currency from cache or load from network.
|
||||
*/
|
||||
fun getSelectedAppCurrency(): Flow<AppCurrency>
|
||||
|
||||
suspend fun getAvailableAppCurrencies(): List<AppCurrency>
|
||||
|
||||
suspend fun changeAppCurrency(currencyCode: String)
|
||||
|
||||
suspend fun fetchDefaultAppCurrency(isRefresh: Boolean = false)
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ internal class SendAmountStateConverter(
|
|||
),
|
||||
SendAmountSegmentedButtonsConfig(
|
||||
title = stringReference(appCurrency.code),
|
||||
iconState = iconStateConverter.convert(status),
|
||||
iconUrl = appCurrency.iconSmallUrl,
|
||||
isFiat = true,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue