Updated on 2026-08-14
This commit is contained in:
parent
883a652715
commit
bb9d49e2e6
10 changed files with 175 additions and 1 deletions
|
|
@ -3,9 +3,11 @@ package com.tangem.tap.common.redux.global
|
|||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.commands.Card
|
||||
import org.rekotlin.Action
|
||||
import java.math.BigDecimal
|
||||
|
||||
sealed class GlobalAction : Action {
|
||||
|
||||
data class LoadCard(val card: Card) : GlobalAction()
|
||||
data class LoadWalletManager(val walletManager: WalletManager) : GlobalAction()
|
||||
data class SetFiatRate(val fiatRates: Pair<String, BigDecimal>) : GlobalAction()
|
||||
}
|
||||
|
|
@ -11,6 +11,11 @@ fun globalReducer(action: Action, state: AppState): GlobalState {
|
|||
|
||||
when (action) {
|
||||
is GlobalAction.LoadCard -> newState = newState.copy(card = action.card)
|
||||
is GlobalAction.SetFiatRate -> {
|
||||
val rates = newState.fiatRates.rates.toMutableMap()
|
||||
rates[action.fiatRates.first] = action.fiatRates.second
|
||||
newState = newState.copy(fiatRates = FiatRates(rates))
|
||||
}
|
||||
is GlobalAction.LoadWalletManager ->
|
||||
newState = newState.copy(walletManager = action.walletManager)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,20 @@ package com.tangem.tap.common.redux.global
|
|||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.commands.Card
|
||||
import org.rekotlin.StateType
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class GlobalState(
|
||||
val card: Card? = null,
|
||||
val walletManager: WalletManager? = null,
|
||||
val fiatRates: FiatRates = FiatRates(emptyMap()),
|
||||
) : StateType
|
||||
|
||||
data class FiatRates(
|
||||
val rates: Map<String, BigDecimal>
|
||||
) {
|
||||
fun getRateForCryptoCurrency(currency: String): BigDecimal? {
|
||||
return rates[currency]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ val homeMiddleware: Middleware<AppState> = { dispatch, state ->
|
|||
store.dispatch(GlobalAction.LoadCard(result.data.card))
|
||||
store.dispatch(GlobalAction.LoadWalletManager(result.data.walletManager))
|
||||
store.dispatch(WalletAction.LoadWallet)
|
||||
store.dispatch(WalletAction.LoadFiatRate)
|
||||
store.dispatch(WalletAction.LoadPayId)
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,17 @@ import com.tangem.tap.common.redux.NotificationAction
|
|||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.wallet.R
|
||||
import org.rekotlin.Action
|
||||
import java.math.BigDecimal
|
||||
|
||||
sealed class WalletAction : Action {
|
||||
object LoadWallet : WalletAction() {
|
||||
data class Success(val wallet: Wallet): WalletAction()
|
||||
object Failure: WalletAction()
|
||||
}
|
||||
object LoadFiatRate : WalletAction() {
|
||||
data class Success(val fiatRates: Pair<String, BigDecimal>) : WalletAction()
|
||||
object Failure: WalletAction()
|
||||
}
|
||||
object LoadPayId : WalletAction() {
|
||||
data class Success(val payId: String): WalletAction()
|
||||
object NotCreated: WalletAction()
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.tangem.tap.common.redux.global.GlobalAction
|
|||
import com.tangem.tap.domain.PayIdManager
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.isPayIdSupported
|
||||
import com.tangem.tap.network.coinmarketcap.CoinMarketCapService
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
|
|
@ -47,6 +48,36 @@ val walletMiddleware: Middleware<AppState> = { dispatch, state ->
|
|||
}
|
||||
}
|
||||
}
|
||||
is WalletAction.LoadFiatRate -> {
|
||||
scope.launch {
|
||||
val blockchainCurrency = store.state.globalState.walletManager?.wallet?.blockchain?.currency
|
||||
val tokenCurrency = store.state.globalState.walletManager?.wallet?.token?.symbol
|
||||
|
||||
val blockchainRate = blockchainCurrency?.let { CoinMarketCapService().getRate(it) }
|
||||
val tokenRate = tokenCurrency?.let { CoinMarketCapService().getRate(it) }
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
when (blockchainRate) {
|
||||
is Result.Success -> {
|
||||
store.dispatch(GlobalAction.SetFiatRate(blockchainCurrency to blockchainRate.data)
|
||||
)
|
||||
store.dispatch(WalletAction.LoadFiatRate.Success(blockchainCurrency to blockchainRate.data)
|
||||
)
|
||||
}
|
||||
is Result.Failure, null -> store.dispatch(WalletAction.LoadFiatRate.Failure)
|
||||
}
|
||||
when (tokenRate) {
|
||||
is Result.Success -> {
|
||||
store.dispatch(GlobalAction.SetFiatRate(tokenCurrency to tokenRate.data)
|
||||
)
|
||||
store.dispatch(WalletAction.LoadFiatRate.Success(tokenCurrency to tokenRate.data)
|
||||
)
|
||||
}
|
||||
is Result.Failure, null -> store.dispatch(WalletAction.LoadFiatRate.Failure)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is WalletAction.LoadPayId -> {
|
||||
if (!TapConfig.usePayId ||
|
||||
store.state.walletState.payIdData.payIdState == PayIdState.Disabled ||
|
||||
|
|
@ -107,6 +138,7 @@ val walletMiddleware: Middleware<AppState> = { dispatch, state ->
|
|||
store.dispatch(GlobalAction.LoadCard(result.data.card))
|
||||
store.dispatch(GlobalAction.LoadWalletManager(result.data.walletManager))
|
||||
store.dispatch(WalletAction.LoadWallet)
|
||||
store.dispatch(WalletAction.LoadFiatRate)
|
||||
store.dispatch(WalletAction.LoadPayId)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.features.wallet.redux
|
||||
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.tap.common.extensions.toFiatString
|
||||
import com.tangem.tap.common.extensions.toFormattedString
|
||||
import com.tangem.tap.common.extensions.toQrCode
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
|
|
@ -26,22 +27,45 @@ fun walletReducer(action: Action, state: AppState): WalletState {
|
|||
is WalletAction.LoadWallet.Success -> {
|
||||
val token = action.wallet.amounts[AmountType.Token]
|
||||
val tokenData = if (token != null) {
|
||||
val tokenFiatRate = state.globalState.fiatRates.getRateForCryptoCurrency(token.currencySymbol)
|
||||
val tokenFiatAmount = tokenFiatRate?.let { token.value?.toFiatString(it) }
|
||||
TokenData(
|
||||
token.value?.toFormattedString(action.wallet.blockchain) ?: "",
|
||||
token.currencySymbol)
|
||||
token.currencySymbol, tokenFiatAmount)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val amount = action.wallet.amounts[AmountType.Coin]?.value
|
||||
val fiatRate = state.globalState.fiatRates.getRateForCryptoCurrency(action.wallet.blockchain.currency)
|
||||
val fiatAmount = fiatRate?.let { amount?.toFiatString(it) }
|
||||
newState = newState.copy(
|
||||
state = ProgressState.Done, wallet = action.wallet,
|
||||
currencyData = BalanceWidgetData(
|
||||
BalanceStatus.VerifiedOnline, action.wallet.blockchain.fullName,
|
||||
amount?.toFormattedString(action.wallet.blockchain),
|
||||
token = tokenData,
|
||||
fiatAmount = fiatAmount
|
||||
)
|
||||
)
|
||||
}
|
||||
is WalletAction.LoadFiatRate.Success -> {
|
||||
val rate = action.fiatRates.second
|
||||
val currency = action.fiatRates.first
|
||||
val fiatAmount = if (currency == newState.wallet?.blockchain?.currency) {
|
||||
newState.wallet?.amounts?.get(AmountType.Coin)?.value?.toFiatString(rate)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val tokenFiatAmount = if (currency == newState.wallet?.token?.symbol) {
|
||||
newState.wallet?.amounts?.get(AmountType.Token)?.value?.toFiatString(rate)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
newState = newState.copy(currencyData = newState.currencyData.copy(
|
||||
fiatAmount = fiatAmount,
|
||||
token = newState.currencyData.token?.copy(fiatAmount = tokenFiatAmount)
|
||||
))
|
||||
}
|
||||
is WalletAction.LoadWallet.Failure -> newState = newState.copy(
|
||||
state = ProgressState.Done,
|
||||
currencyData = newState.currencyData.copy(status = BalanceStatus.Unreachable)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.tap.network.coinmarketcap
|
||||
|
||||
import com.tangem.tap.TapConfig
|
||||
import com.tangem.tap.network.createRetrofitInstance
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface CoinMarketCapApi {
|
||||
|
||||
@GET("v1/tools/price-conversion")
|
||||
suspend fun getRateInfo(
|
||||
@Query("amount") amount: Int,
|
||||
@Query("symbol") cryptoId: String
|
||||
): RateInfoResponse
|
||||
|
||||
companion object {
|
||||
private const val baseUrl = "https://pro-api.coinmarketcap.com/"
|
||||
|
||||
fun create(): CoinMarketCapApi {
|
||||
return createRetrofitInstance(
|
||||
baseUrl,
|
||||
listOf(createCoinMarketRequestInterceptor()),
|
||||
).create(CoinMarketCapApi::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCoinMarketRequestInterceptor(): Interceptor {
|
||||
return object : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val requestBuilder = chain.request().newBuilder()
|
||||
requestBuilder.addHeader("X-CMC_PRO_API_KEY", TapConfig.coinMarketCapKey)
|
||||
return chain.proceed(requestBuilder.build())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.tap.network.coinmarketcap
|
||||
|
||||
import com.tangem.commands.common.network.Result
|
||||
import com.tangem.commands.common.network.performRequest
|
||||
import java.math.BigDecimal
|
||||
|
||||
class CoinMarketCapService {
|
||||
private val api: CoinMarketCapApi by lazy { CoinMarketCapApi.create() }
|
||||
|
||||
suspend fun getRate(currency: String): Result<BigDecimal> {
|
||||
val response = performRequest { api.getRateInfo(1, currency) }
|
||||
return when (response) {
|
||||
is Result.Success -> Result.Success(response.data.data.quote.usd.price)
|
||||
is Result.Failure -> response
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.tangem.tap.network.coinmarketcap
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import java.math.BigDecimal
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RateInfoResponse(
|
||||
val status: Status,
|
||||
val data: RateData
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RateData(
|
||||
val quote: Quote
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Quote(
|
||||
@Json(name = "USD")
|
||||
val usd: CurrencyRate
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CurrencyRate(
|
||||
val price: BigDecimal
|
||||
)
|
||||
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Status(
|
||||
val timestamp: String,
|
||||
@Json(name = "error_code")
|
||||
val errorCode: Int,
|
||||
@Json(name = "error_message")
|
||||
val errorMessage: String?,
|
||||
val elapsed: Int,
|
||||
@Json(name = "credit_count")
|
||||
val creditCount: Int,
|
||||
val notice: String?
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue