Skip to content

Commit

Permalink
CoinGecko api to get token prices
Browse files Browse the repository at this point in the history
  • Loading branch information
sajalbnl committed Oct 5, 2024
1 parent 6e87382 commit a7a04cb
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.example.walletapp


import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.State
import com.example.walletapp.data.repository.CoinRepository

class CoinViewModel : ViewModel() {
private val repository = CoinRepository()

private val _prices = mutableStateOf<Map<String, Double>>(emptyMap()) // Token -> USD price
val prices: State<Map<String, Double>> = _prices

private val _errorMessage = mutableStateOf("")
val errorMessage: State<String> = _errorMessage

fun getTokenPrices(ids: String,
vsCurrencies: String) {
viewModelScope.launch {
try {
// Fetch prices for starknet and bitcoin in USD
val response = repository.getTokenPrices(ids,vsCurrencies)
if (response.isSuccessful) {
response.body()?.let { priceMap ->
val parsedPrices = mutableMapOf<String, Double>()
priceMap.forEach { (token, currencyMap) ->
parsedPrices[token] = currencyMap["usd"] ?: 0.0
}
_prices.value = parsedPrices
} ?: run {
_errorMessage.value = "No data available."
}
} else {
_errorMessage.value = "Error: ${response.code()} ${response.message()}"
}
} catch (e: Exception) {
_errorMessage.value = "Exception: ${e.localizedMessage}"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import StarknetClient
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.service.quickaccesswallet.WalletCard
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
Expand Down Expand Up @@ -51,11 +52,13 @@ import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.*
import androidx.compose.material.icons.filled.Close
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.draw.clip
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties
import androidx.lifecycle.viewmodel.compose.viewModel
import com.swmansion.starknet.data.types.Felt
import com.swmansion.starknet.provider.exceptions.RpcRequestFailedException
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -93,6 +96,19 @@ class WalletActivity : ComponentActivity() {
val starknetClient = StarknetClient(BuildConfig.RPC_URL)
var balance by remember { mutableStateOf("") }

val coinViewModel: CoinViewModel = viewModel()

val coinsPrices : HashMap<String,String> = rememberSaveable {
hashMapOf()
}

val prices by coinViewModel.prices
val errorMessage by coinViewModel.errorMessage

LaunchedEffect(Unit) {
coinViewModel.getTokenPrices(ids = "starknet,ethereum", vsCurrencies = "usd") // Fetch starknet and bitcoin prices in USD
}

LaunchedEffect (Unit){
try {
// Get the balance of the account
Expand All @@ -106,6 +122,20 @@ class WalletActivity : ComponentActivity() {
withContext(Dispatchers.Main) { Toast.makeText(context, e.message, Toast.LENGTH_LONG).show() }
}
}
if (errorMessage.isNotEmpty()) {
Text(
text = errorMessage,
color = MaterialTheme.colors.error,
modifier = Modifier.padding(16.dp)
)
} else {
Column(modifier = Modifier.padding(16.dp)) {
prices.forEach { (token, price) ->
coinsPrices[token] = price.toDoubleWithTwoDecimal()
Spacer(modifier = Modifier.height(8.dp))
}
}
}

Column(
modifier = Modifier
Expand Down Expand Up @@ -151,15 +181,15 @@ class WalletActivity : ComponentActivity() {

WalletCard(
icon = painterResource(id = R.drawable.ic_ethereum),
amount = "$11,625.7",
amount = coinsPrices["ethereum"]?.let { "$ $it" } ?: "",
exchange = balance,
type = "ETH"
)

// TOOD(#82): load actual balance
WalletCard(
icon = painterResource(id = R.drawable.token2),
amount = "$1.78",
amount = coinsPrices["starknet"]?.let { "$ $it" } ?: "",
exchange ="4.44",
type = "STRK"
)
Expand Down Expand Up @@ -225,6 +255,11 @@ fun BigDecimal.toDoubleWithTwoDecimal(): String {
val decimalFormat = DecimalFormat("#.00")
return decimalFormat.format(this.toDouble())
}
fun Double.toDoubleWithTwoDecimal(): String {
val decimalFormat = DecimalFormat("#.00")
val formattedValue = decimalFormat.format(this)
return if (this < 1) "0$formattedValue" else formattedValue
}

@Composable
fun WalletCard(icon: Painter, amount: String, exchange: String, type: String) {
Expand Down Expand Up @@ -252,6 +287,8 @@ fun BigDecimal.toDoubleWithTwoDecimal(): String {
color = Color.White,
fontSize = 18.sp
)


Row {
Text(
text = exchange,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.walletapp.data.datasource

import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Headers
import retrofit2.http.Query

interface CoinGeckoApi {
@Headers(
"accept: application/json",
"x-cg-demo-api-key: CG-mRdWfNFoZnKVan4GNdTrhZjL"
)
@GET("simple/price")
suspend fun getTokenPrices(
@Query("ids") ids: String, // Comma-separated token IDs
@Query("vs_currencies") vsCurrencies: String // Comma-separated currency codes
): Response<Map<String, Map<String, Double>>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.example.walletapp.data.repository

import com.example.walletapp.di.RetrofitClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import retrofit2.Response

class CoinRepository {
suspend fun getTokenPrices(
ids: String,
vsCurrencies: String
): Response<Map<String, Map<String, Double>>> {
return withContext(Dispatchers.IO) {
RetrofitClient.apiService.getTokenPrices(ids, vsCurrencies)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.walletapp.di

import com.example.walletapp.data.datasource.CoinGeckoApi

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitClient {
private const val BASE_URL = "https://api.coingecko.com/api/v3/"

val apiService: CoinGeckoApi by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(CoinGeckoApi::class.java)
}
}

0 comments on commit a7a04cb

Please sign in to comment.