Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Token added functionality,balance and price of all tokens #117

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions wallet_app/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ dependencies {
implementation(libs.androidx.hilt.navigation.fragment)
implementation (libs.androidx.hilt.navigation.compose.v100alpha03)

implementation("androidx.room:room-runtime:2.6.1")
kapt("androidx.room:room-compiler:2.6.1")
implementation("androidx.room:room-ktx:2.6.1")

implementation(libs.androidx.ui.tooling.preview)
debugImplementation(libs.androidx.ui.tooling)
Expand Down
1 change: 1 addition & 0 deletions wallet_app/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".WalletAppApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example.walletapp

import android.app.Application
import com.example.walletapp.db.TokenDatabase


class WalletAppApplication : Application() {

// Lazy initialization of the database
val database: TokenDatabase by lazy { TokenDatabase.getDatabase(this) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.walletapp.db


import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import com.example.walletapp.model.Token
import kotlinx.coroutines.flow.Flow
import androidx.room.Query

@Dao
interface TokenDao {

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(token: Token)

@Query("SELECT * FROM token_table")
fun getAllTokens(): Flow<List<Token>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.example.walletapp.db

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.walletapp.model.Token
import com.example.walletapp.utils.Converters
import com.swmansion.starknet.data.types.Felt
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

@Database(entities = [Token::class], version = 1, exportSchema = false)
@TypeConverters(Converters::class)
abstract class TokenDatabase : RoomDatabase() {

abstract fun tokenDao(): TokenDao

companion object {
@Volatile
private var INSTANCE: TokenDatabase? = null

fun getDatabase(context: Context): TokenDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
TokenDatabase::class.java,
"token_database"
)
.addCallback(DatabaseCallback()) // Add callback here
.build()
INSTANCE = instance
instance
}
}
}

private class DatabaseCallback : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
INSTANCE?.let { database ->
CoroutineScope(Dispatchers.IO).launch {
populateDatabase(database.tokenDao())
}
}
}

suspend fun populateDatabase(tokenDao: TokenDao) {
// Add default tokens
val token1 = Token(contactAddress = Felt.fromHex("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"), name = "ethereum", symbol = "ETH", decimals = 18)
val token2 = Token(contactAddress = Felt.fromHex("0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d"), name = "starknet", symbol = "STRK", decimals = 18)
tokenDao.insert(token1)
tokenDao.insert(token2)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package com.example.walletapp.model

class Token (
val address: String,
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.swmansion.starknet.data.types.Felt

@Entity(tableName = "token_table")
data class Token(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val contactAddress: Felt,
val name: String,
val symbol: String,
val name: String
val decimals: Int
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.core.view.WindowCompat
import androidx.lifecycle.ViewModelProvider
import com.example.walletapp.BuildConfig
import com.example.walletapp.WalletAppApplication
import com.example.walletapp.ui.account.TokenRepository
import com.example.walletapp.ui.account.TokenViewModel
import com.example.walletapp.utils.StarknetClient

class MainActivity : ComponentActivity() {
Expand All @@ -23,10 +27,16 @@ class MainActivity : ComponentActivity() {
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Access the database instance
val database = (application as WalletAppApplication).database
val repository = TokenRepository(database.tokenDao())
val tokenViewModel: TokenViewModel = ViewModelProvider(
this, TokenViewModel.Factory(application,repository)
).get(TokenViewModel::class.java)
enableEdgeToEdge()
WindowCompat.setDecorFitsSystemWindows(window, true)
setContent {
WalletApp()
WalletApp(tokenViewModel)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.example.walletapp.ui.account.AddTokenScreen
import com.example.walletapp.ui.account.TokenViewModel
import com.example.walletapp.ui.account.WalletScreen
import com.example.walletapp.ui.activity.FinalizeAccountCreationScreen
import com.example.walletapp.ui.onboarding.CreateAccountScreen
Expand Down Expand Up @@ -42,7 +43,7 @@ object Send
object Receive

@Composable
fun WalletApp() {
fun WalletApp(tokenViewModel: TokenViewModel) {
WalletappTheme {

// TODO(#109): get this information from a data store
Expand Down Expand Up @@ -90,11 +91,13 @@ fun WalletApp() {
WalletScreen(
onNewTokenPress = { navController.navigate( route = AddToken ) },
onReceivePress = { navController.navigate( route = Receive ) },
onSendPress = { navController.navigate( route = Send ) }
onSendPress = { navController.navigate( route = Send ) },
tokenViewModel = tokenViewModel
)
}
composable<AddToken> {
AddTokenScreen(
tokenViewModel=tokenViewModel,
onConfirm = { navController.navigateUp() }
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.example.walletapp.ui.account

import android.app.Activity
import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
Expand All @@ -22,20 +24,24 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.graphics.toColorInt
import com.example.walletapp.R
import com.example.walletapp.model.Token
import com.swmansion.starknet.data.types.Felt

@Composable
fun AddTokenScreen(onConfirm: () -> Unit) {
fun AddTokenScreen(tokenViewModel:TokenViewModel,onConfirm: () -> Unit) {
Surface(modifier = Modifier.fillMaxSize()) {
val contactAddress = rememberSaveable { mutableStateOf("") }
val name = rememberSaveable { mutableStateOf("") }
val symbol = rememberSaveable { mutableStateOf("") }
val decimals = rememberSaveable { mutableStateOf("") }
val context = (LocalContext.current as Activity)

Column(
modifier = Modifier
Expand Down Expand Up @@ -92,7 +98,36 @@ fun AddTokenScreen(onConfirm: () -> Unit) {

// TODO: handle saving the token data
Button(
onClick = onConfirm,
onClick = {
val decimalValue = decimals.value.toIntOrNull()
val addressPattern = Regex("^0x[a-fA-F0-9]{64}$")
if (!addressPattern.matches(contactAddress.value)) {
Toast.makeText(context, "Please enter a valid address", Toast.LENGTH_LONG).show()
}
else if (name.value.isEmpty()) {
Toast.makeText(context, "Please enter name", Toast.LENGTH_LONG)
.show()
}
else if (symbol.value.isEmpty()) {
Toast.makeText(context, "Please enter symbol", Toast.LENGTH_LONG)
.show()
} else if (decimalValue == null || decimalValue !in 0..18) {
Toast.makeText(context, "Please enter valid decimal", Toast.LENGTH_LONG)
.show()
}else{
onConfirm()
// Save data to local storage here
val address=Felt.fromHex(contactAddress.value)
val newToken = Token(
contactAddress = address,
name = name.value,
symbol = symbol.value,
decimals = decimalValue
)
tokenViewModel.insertToken(newToken) // Insert the new token
Toast.makeText(context, "Token added!", Toast.LENGTH_LONG).show()
}
},
colors = ButtonDefaults.buttonColors(backgroundColor = Color("#1B1B76".toColorInt())),
modifier = Modifier
.fillMaxWidth()
Expand Down Expand Up @@ -135,10 +170,11 @@ fun SimpleTextField(
shape = RoundedCornerShape(15.dp),
modifier = Modifier.fillMaxWidth(),
textStyle = TextStyle(
color = Color.Black,
color = Color.White,
fontSize = 16.sp
)
)
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example.walletapp.ui.account

import com.example.walletapp.db.TokenDao
import com.example.walletapp.model.Token
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext

class TokenRepository(private val tokenDao: TokenDao) {

// Get all tokens from the database
val allTokens: Flow<List<Token>> = tokenDao.getAllTokens()

// Insert a token into the database
suspend fun insertToken(token: Token) {
withContext(Dispatchers.IO) {
tokenDao.insert(token)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.example.walletapp.ui.account

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import com.example.walletapp.model.Token
import kotlinx.coroutines.launch

class TokenViewModel(application: Application, private val repository: TokenRepository) : AndroidViewModel(application) {


// Expose all tokens as LiveData
val tokens: LiveData<List<Token>> = repository.allTokens.asLiveData()

// Function to insert a new token
fun insertToken(token: Token) {
viewModelScope.launch {
repository.insertToken(token)
}
}

// Define a factory to pass the repository
class Factory(private val application: Application, private val repository: TokenRepository) :
ViewModelProvider.AndroidViewModelFactory(application) {

override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(TokenViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return TokenViewModel(application, repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
}

Loading
Loading