diff --git a/wallet_app/app/build.gradle.kts b/wallet_app/app/build.gradle.kts index 28eef37..b1c09b6 100644 --- a/wallet_app/app/build.gradle.kts +++ b/wallet_app/app/build.gradle.kts @@ -74,6 +74,10 @@ dependencies { implementation("com.swmansion.starknet:starknet:0.13.0@aar"){ isTransitive = true } + + // DataStore + implementation("androidx.datastore:datastore-preferences:1.1.1") + // Navigation stuff implementation(libs.androidx.navigation.compose.v283) implementation(libs.androidx.navigation.compose.v283) diff --git a/wallet_app/app/src/main/java/com/example/walletapp/datastore/WalletStoreModule.kt b/wallet_app/app/src/main/java/com/example/walletapp/datastore/WalletStoreModule.kt new file mode 100644 index 0000000..5f4ae6a --- /dev/null +++ b/wallet_app/app/src/main/java/com/example/walletapp/datastore/WalletStoreModule.kt @@ -0,0 +1,48 @@ +package com.example.walletapp.datastore + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import androidx.datastore.preferences.preferencesDataStore +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class WalletStoreModule(private val context: Context) { + companion object { + private val Context.dataStore: DataStore by preferencesDataStore("wallet_prefs") + private val HAS_ACCOUNT = booleanPreferencesKey("has_account") + private val ACCOUNT_NAME = stringPreferencesKey("acc_name") + private val PRIVATE_KEY = stringPreferencesKey("private_key") + } + + val hasAccount: Flow = context.dataStore.data.map { preferences -> + preferences[HAS_ACCOUNT] ?: false + } + + suspend fun setHasAccount(hasAccount: Boolean) { + context.dataStore.edit { preferences -> + preferences[HAS_ACCOUNT] = hasAccount + } + } + val accName: Flow = context.dataStore.data.map { preferences -> + preferences[ACCOUNT_NAME] ?: "" + } + + suspend fun setAccountName(accName: String) { + context.dataStore.edit { preferences -> + preferences[ACCOUNT_NAME] = accName + } + } + val privateKey: Flow = context.dataStore.data.map { preferences -> + preferences[PRIVATE_KEY] ?: "" + } + + suspend fun setPrivateKey(privateKey: String) { + context.dataStore.edit { preferences -> + preferences[PRIVATE_KEY] = privateKey + } + } +} \ No newline at end of file diff --git a/wallet_app/app/src/main/java/com/example/walletapp/ui/WalletApp.kt b/wallet_app/app/src/main/java/com/example/walletapp/ui/WalletApp.kt index 51b4ed2..3326f7b 100644 --- a/wallet_app/app/src/main/java/com/example/walletapp/ui/WalletApp.kt +++ b/wallet_app/app/src/main/java/com/example/walletapp/ui/WalletApp.kt @@ -1,12 +1,14 @@ package com.example.walletapp.ui import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import com.example.walletapp.BuildConfig +import com.example.walletapp.datastore.WalletStoreModule import com.example.walletapp.ui.account.AddTokenScreen import com.example.walletapp.ui.account.TokenViewModel import com.example.walletapp.ui.account.WalletScreen @@ -19,6 +21,9 @@ import com.example.walletapp.ui.onboarding.OnboardingScreen import com.example.walletapp.ui.theme.WalletappTheme import com.example.walletapp.ui.transfer.ReceiveScreen import com.example.walletapp.ui.transfer.SendScreen +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import kotlinx.serialization.Serializable // main user account view @@ -48,21 +53,17 @@ object Receive @Composable fun WalletApp(tokenViewModel: TokenViewModel) { val walletViewModel: WalletViewModel = viewModel() + val context = LocalContext.current + val dataStore = WalletStoreModule(context) + val hasAccountState = dataStore.hasAccount.collectAsState(initial = null) + hasAccountState.value?.let { hasAccount -> WalletappTheme { - // TODO(#109): get this information from a data store - val hasAccount = false - fun getStart(): Any { - return if (hasAccount) { - Wallet - } else { - Onboarding - } - } + val startDestination = if (hasAccount) Wallet else Onboarding val navController = rememberNavController() - NavHost(navController, startDestination = getStart()) { + NavHost(navController, startDestination = startDestination) { composable { OnboardingScreen( @@ -78,7 +79,7 @@ fun WalletApp(tokenViewModel: TokenViewModel) { } composable { FinalizeAccountCreationScreen( - onContinue = { navController.navigate( route = CreatePin )}, + onContinue = { navController.navigate( route = CreatePin ) }, onBackButtonPressed = { navController.navigateUp() } ) } @@ -90,7 +91,11 @@ fun WalletApp(tokenViewModel: TokenViewModel) { } composable { CreatePinScreen( - onContinue = { navController.navigate( route = Wallet )} + onContinue = { navController.navigate( route = Wallet ) + CoroutineScope(Dispatchers.IO).launch { + dataStore.setHasAccount(true) + } + } ) } @@ -119,4 +124,5 @@ fun WalletApp(tokenViewModel: TokenViewModel) { } } } + } } \ No newline at end of file diff --git a/wallet_app/app/src/main/java/com/example/walletapp/ui/onboarding/FinalizeAccountCreationScreen.kt b/wallet_app/app/src/main/java/com/example/walletapp/ui/onboarding/FinalizeAccountCreationScreen.kt index 91d43ba..cfb86b6 100644 --- a/wallet_app/app/src/main/java/com/example/walletapp/ui/onboarding/FinalizeAccountCreationScreen.kt +++ b/wallet_app/app/src/main/java/com/example/walletapp/ui/onboarding/FinalizeAccountCreationScreen.kt @@ -29,9 +29,12 @@ import androidx.compose.ui.unit.sp import android.content.ClipboardManager import android.content.ClipData import android.widget.Toast -import androidx.compose.ui.graphics.painter.Painter import androidx.core.graphics.toColorInt import com.example.walletapp.R +import com.example.walletapp.datastore.WalletStoreModule +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -90,7 +93,7 @@ fun FinalizeAccountCreationScreen( fun AccountInfoView(onContinue: () -> Unit) { val context = LocalContext.current as Activity val clipboardManager = LocalContext.current.getSystemService(ClipboardManager::class.java) - + val dataStore = WalletStoreModule(context) var checked by remember { mutableStateOf(true) } val accountName = "Starknet" val privateKey = "q78ggh277ibckewjtnM" @@ -276,7 +279,11 @@ fun AccountInfoView(onContinue: () -> Unit) { Spacer(modifier = Modifier.weight(1f)) Button( - onClick = onContinue, + onClick = {onContinue() + CoroutineScope(Dispatchers.IO).launch { + dataStore.setAccountName(accountName) + dataStore.setPrivateKey(privateKey) + }}, contentPadding = ButtonDefaults.ContentPadding, shape = RoundedCornerShape(8.dp), colors = ButtonDefaults.buttonColors( diff --git a/wallet_app/app/src/main/java/com/example/walletapp/ui/onboarding/ImportAccountScreen.kt b/wallet_app/app/src/main/java/com/example/walletapp/ui/onboarding/ImportAccountScreen.kt index a996ad7..175f437 100644 --- a/wallet_app/app/src/main/java/com/example/walletapp/ui/onboarding/ImportAccountScreen.kt +++ b/wallet_app/app/src/main/java/com/example/walletapp/ui/onboarding/ImportAccountScreen.kt @@ -1,10 +1,7 @@ package com.example.walletapp.ui.onboarding import android.app.Activity -import android.content.Intent -import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -13,7 +10,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button @@ -24,16 +20,12 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextFieldDefaults -import androidx.compose.material3.TopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.IconButton -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.SheetState import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.ArrowForward -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -44,15 +36,16 @@ 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.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign 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.datastore.WalletStoreModule import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -145,6 +138,8 @@ fun PrivateKeyView(modifier: Modifier = Modifier, onNext: () -> Unit) { val scope = rememberCoroutineScope() var openBottomSheet by remember { mutableStateOf(false) } val sheetState = rememberModalBottomSheetState() + val context = (LocalContext.current as Activity) + val dataStore = WalletStoreModule(context) Column( modifier = modifier @@ -197,7 +192,10 @@ fun PrivateKeyView(modifier: Modifier = Modifier, onNext: () -> Unit) { Spacer(modifier = Modifier.weight(1f)) Button( - onClick = onNext, + onClick = {onNext() + CoroutineScope(Dispatchers.IO).launch { + dataStore.setPrivateKey(accountName) + }}, contentPadding = ButtonDefaults.ContentPadding, shape = RoundedCornerShape(8.dp), colors = ButtonDefaults.buttonColors( @@ -231,6 +229,7 @@ fun CreateNameView(modifier: Modifier = Modifier, onFinishAccountImport: () -> U val borderColor = Color("#1B1B76".toColorInt()) var accountName by remember { mutableStateOf("") } val context = (LocalContext.current as Activity) + val dataStore = WalletStoreModule(context) Column( modifier = modifier @@ -283,7 +282,10 @@ fun CreateNameView(modifier: Modifier = Modifier, onFinishAccountImport: () -> U Spacer(modifier = Modifier.weight(1f)) Button( - onClick = onFinishAccountImport, + onClick = {onFinishAccountImport() + CoroutineScope(Dispatchers.IO).launch { + dataStore.setAccountName(accountName) + }}, contentPadding = ButtonDefaults.ContentPadding, shape = RoundedCornerShape(8.dp), colors = ButtonDefaults.buttonColors( diff --git a/wallet_app/app/src/main/java/com/example/walletapp/utils/StarknetClient.kt b/wallet_app/app/src/main/java/com/example/walletapp/utils/StarknetClient.kt index 342fabf..aaf45c5 100644 --- a/wallet_app/app/src/main/java/com/example/walletapp/utils/StarknetClient.kt +++ b/wallet_app/app/src/main/java/com/example/walletapp/utils/StarknetClient.kt @@ -32,9 +32,6 @@ const val ACCOUNT_CLASS_HASH = "0x04c6d6cf894f8bc96bb9c525e6853e5483177841f7388f class StarknetClient(private val rpcUrl: String) { private val provider = JsonRpcProvider(rpcUrl) - private val privateKey = BuildConfig.PRIVATE_KEY - private val accountAddress = BuildConfig.ACCOUNT_ADDRESS - private val tag = "StarknetClient" private val keystore = Keystore() suspend fun deployAccount() {