# Almacenamiento de datos con DataStore
El dataStore es el método más simple para guardar datos de manera permanente en nuestro móvil, no es una base de datos, se suele usar para variables de estado o settings.
En nuestro caso vamos guardar el email y si preferimos modo oscuro o claro en una aplicación, lo guardará nuestra preferencia, hasta que la cambiemos o hasta que borremos nuestra aplicación.
Lo primero que debemos hacer es incluir la dependencia, abrimos una nueva aplicación y vamos al build.gradle (modules)y en dependencies añadimos esta linea:
` implementation("androidx.datastore:datastore-preferences:1.0.0")`
Tal y como indica en:
https://developer.android.com/topic/libraries/architecture/datastore?hl=es-419
Por lo pronto modificamos el Greeting por defecto para mostrar algo así:
```
@Composable
fun Greeting() {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxSize()
) {
var email by remember { mutableStateOf("")}
TextField(
value = email,
onValueChange ={email=it},
keyboardOptions = KeyboardOptions(keyboardType= KeyboardType.Email)
)
Spacer(modifier=Modifier.height(16.dp))
Button(onClick = { /*TODO*/ }) {
Text("Guardar Email")
}
Spacer(modifier=Modifier.height(16.dp))
Text("Email")
}
}
```

Vamos a hacer que el email introducido se guarde en nuestro móvil, cada vez que entremos podremos recuperar ese dato.
Pero primero algunas consideraciones sobre el remember, como has visto sirve para guardar valores en tiempo de ejecución, pero se borra si por ejemplo giras la pantalla, o sea, no se guarda el valor en caso de cambios de estado, por eso vamos a cambiar esta linea por rememberSaveable que sí se guarda más allá de los cambio de estados.
` var email by rememberSaveable { mutableStateOf("")}`
En su momento vimos algunas opciones de la elevación de estados pero les dije que era muy amplio, como ven...vamos dando el resto de opciones poco a poco:
https://developer.android.com/jetpack/compose/state?hl=es-419
Tenemos nuestro ejemplo montado vamos con el DataStore. Creamos un nuevo archivo llamado StoreUserEmail.
```
class StoreUserEmail (private val context: Context){
}
```
Esta será la definición de la clase y verás que pasamos una variable del tipo Context, puedes ver la documentación pero digamos que nos va a permitir acceder a información del sistema operativo Android, nos permite acceder a información del sistema donde se está ejecutando nuestra aplicación.
Vamos a añadir también un companion objet
https://developer.android.com/kotlin/common-patterns?hl=es-419
Es una clase auxiliar que podemos usar dentro de otra clase pero que no es necesario instanciar.
Aquí es donde vamos a tener la definición del dato a guardar y hay que tener cuidado al elegir la importación de la preferences del data store:

Asegúrate de elegir el andoidx.datastore.preferences.core porque el resto están obosoletos.
Vamos a gestionar todo con un flow así que declaramos getEmail como parte del flow, y de nuevo cuidado

Tienen que escoger la `Flow<T> kotlinx.coroutines.flow`
```
val getEmail: Flow<String> = context.dataStore.data
.map { preferences->
preferences[USER_EMAIL]?:""
}
```
Se usa un map para seleccionar de todas las preferencias del contexto la de USER_EMAIL, para entender esto mejor, sigamos profundizando en el FLOW!
https://developer.android.com/kotlin/flow?hl=es-419
La clase StoreUserEmail quedaría como queda:
```
class StoreUserEmail (private val context: Context){
companion object {
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore("UserEmail")
val USER_EMAIL= stringPreferencesKey("user_email")
}
val getEmail: Flow<String> = context.dataStore.data
.map { preferences->
preferences[USER_EMAIL]?:""
}
suspend fun saveEmail(email:String){
context.dataStore.edit { preferences ->
preferences[USER_EMAIL]=email }
}
}
```
En resumen estás declarando los atributos que necesitas (dentro de un comanion object), un getter y un setter.
Para utilizar esto en el composable Greetings necesitamos primero recuperar el contexto, declarar un scope para la corrutina que vamos a lanzar y además crear una objeto de la clase StoreUserEmail pasándole el contexto como parámetro:
```
fun Greeting() {
val context=LocalContext.current;
val scope = rememberCoroutineScope()
val dataStore=StoreUserEmail(context)
```
Para saber más de localContext:
https://developer.android.com/jetpack/compose/compositionlocal?hl=es-419
Para saber más del rememberCoroutineScope
https://developer.android.com/jetpack/compose/side-effects?hl=es-419
Hacemos que el botón guardar email llame a una corrutina que del dataStore que guarda el valor en la textField y el código de greentings quedaría:
```
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Greeting() {
val context=LocalContext.current;
val scope = rememberCoroutineScope()
val dataStore=StoreUserEmail(context)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxSize()
) {
var email by rememberSaveable { mutableStateOf("")}
val userEmail=dataStore.getEmail.collectAsState(initial ="")
TextField(
value = email,
onValueChange ={email=it},
keyboardOptions = KeyboardOptions(keyboardType= KeyboardType.Email)
)
Spacer(modifier=Modifier.height(16.dp))
Button(onClick = {
scope.launch{
//como lo vamos a enviar al thread principal no hace falta usar el dispatcher
dataStore.saveEmail(email)
}
}) {
Text("Guardar Email")
}
Spacer(modifier=Modifier.height(16.dp))
Text(userEmail.value)
}
}
```
Ejecutamos y guardamos un email:

Parece que no pasa nada, pero cierra la aplicación y vuélvela a abrir.

## Guardar el modo de visualización
Vamos a crear un botón de "dark mode" que se guarde para que cada vez que iniciemos la aplicación guarde nuestra preferencia.
Crearemos una nueva clase StoreDarkMode y copiamos el código de StoreUserEmail, lo modificamos ligeramente:
```
class StoreDarkMode (private val context: Context){
companion object {
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore("DarkMode")
val DARK_MODE= booleanPreferencesKey("dark_mode")
}
val getDarkMode: Flow<Boolean> = context.dataStore.data
.map { preferences->
preferences[DARK_MODE]?:false
}
suspend fun saveDarkMode(dark_mode:Boolean){
context.dataStore.edit { preferences ->
preferences[DARK_MODE]=dark_mode }
}
}
```
para cambiar al darkmode es necesario que sea desde el mainActivity así que lo modificamos como sigue:
```
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val darkModeStore=StoreDarkMode(this)
val darkMode= darkModeStore.getDarkMode.collectAsState(initial = false)
DataStoreAppTheme (
darkTheme=darkMode.value
){
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting(darkModeStore,darkMode.value)
}
}
}
}
}
```
Y greetings:
```
@Composable
fun Greeting(darkModeStore: StoreDarkMode, darkMode:Boolean) {
val context=LocalContext.current;
val scope = rememberCoroutineScope()
val dataStore=StoreUserEmail(context)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxSize()
) {
var email by rememberSaveable { mutableStateOf("")}
val userEmail=dataStore.getEmail.collectAsState(initial ="")
TextField(
value = email,
onValueChange ={email=it},
keyboardOptions = KeyboardOptions(keyboardType= KeyboardType.Email)
)
Spacer(modifier=Modifier.height(16.dp))
Button(onClick = {
scope.launch{
//como lo vamos a enviar al thread principal no hace falta usar el dispatcher
dataStore.saveEmail(email)
}
}) {
Text("Guardar Email")
}
Spacer(modifier=Modifier.height(16.dp))
Text(userEmail.value)
Spacer(modifier=Modifier.height(16.dp))
Button(onClick = {
scope.launch {
if (darkMode){
darkModeStore.saveDarkMode(false)
}else {
darkModeStore.saveDarkMode(true)
}
}
}) {
Text("Cambiar a Dark")
}
Switch(checked = darkMode, onCheckedChange = {isChecked->
scope.launch {
darkModeStore.saveDarkMode(isChecked)
}
})
}
}
```
Si pulsas el botón deberá verse el modo oscuro y si apagas el dispositivo y vuelves a abrir el aplicativo debe recordar tanto el modo como el email introducido.
Lo normal es que el botón del DarkMode sea un switch, por eso lo hemos incluido, último cambio antes de hacer ya nuestro primera app utilizando todo lo dado.