---
# System prepended metadata

title: 'PGL: proyecto base examen Calculadora'
tags: [kotlin]

---

# PGL: Proyecto Calculadora

Vamos a crear una aplicación donde utilizaremos todo lo aprendido.

Como vimos en el proyecto anterior lo primero vamos a plantear la estrctura de nuestro proyecto para ello pulsamos en el botón derecho sobre la carpeta principal del proyecto dentro de Java->New->Package y creamos varias carpetas:
- components : donde crearemos todos los componentes reutilizables en el proyecto. Dentro varios files:
    - BodyComponent.kt
    - CardComponent.kt 
- views: colocaremos las distintas vistas del proyecto en este caso será sólo una:
    - HomeView.kt

Así quedará la estructura del proyecto:

![](https://hackmd.io/_uploads/H1S04wuM6.png)


Si en el MainActivity cambiamos el contenido para que muestre el HomeView dará un error.
Arréglalo!


Seguidamente vamos a ir al ui.theme para añadir nuevos colores y cambiar algo el tema principal. en color.kt añadimos:

```
val Primary = Color(0xFF6AC451)
```
Y en Theme.kt en el LightColorScheme vamos a modificar para que el color primario sea el indicado: 
```
private val LightColorScheme = lightColorScheme(
    primary = Primary,
    secondary = PurpleGrey40,
    tertiary = Pink40
    )
```

Empezamos con el HomeView y el HomeviewContent, creando un scaffold:

```
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeView(){
    Scaffold (topBar ={
        CenterAlignedTopAppBar(title = { Text(text ="App Descuentos")},
            colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
                containerColor = MaterialTheme.colorScheme.primary
            )
        )
    } ){
        ContentHomeView(it)
    }
}

@Composable
fun ContentHomeView(paddingValues: PaddingValues) {
    Column (modifier= Modifier
        .padding(paddingValues)
        .padding(10.dp)
        .fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    )
    {
        Text(text = "Hola")
    }
}
```
## BodyComponents: Spacer Genérico

Vamos a crear por lo pronto dos componentes que nos permitan poner espacio tanto vertical como horizontal pasando dicho espacio como parámetro

```
@Composable
fun SpaceH(size: Dp =5.dp){
    Spacer(modifier = Modifier.height(size))
}
@Composable
fun SpaceW(size: Dp=5.dp){
    Spacer(modifier = Modifier.width(size))
}
```

## BodyComponents: OutlinedTextField Genérico
Creamos un input de texto "outlined", va a cambiar en tiempo de ejecución por lo que incluimos el onValueChange y además fíjate en que añadimos el keyboardOptions para que por defecto salga en el móvil el teclado numérico:
```
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainTextField(value:String, onValueChange:(String)->Unit, label:String){
    OutlinedTextField(
        value = value,
        onValueChange = onValueChange,
        label={ Text(text = label)},
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 30.dp )
    )
}
```
Para ver cómo nos va quedando incluye el siguiente código en el ContentHomeView:
```
@Composable
fun ContentHomeView(paddingValues: PaddingValues) {
    Column (modifier= Modifier
        .padding(paddingValues)
        .padding(10.dp)
        .fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    )
    {
        var precio by remember { mutableStateOf("") }
        var descuento by remember { mutableStateOf("") }

        MainTextField(value = precio, onValueChange ={precio=it} , label ="Precio" )
        MainTextField(value = descuento, onValueChange ={descuento=it} , label ="Descuento" )
    }
}
```

## BodyComponents: OutlinedButton Genérico

Vamos a añadir un botón a nuestros componentes:
```
@Composable
fun MainButton(text:String, color: Color = MaterialTheme.colorScheme.primary, onClick:()->Unit){
    OutlinedButton(onClick =onClick, colors=ButtonDefaults.outlinedButtonColors(
        contentColor = color,
        containerColor = Color.Transparent
    ),
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 30.dp)
    ) {
        Text(text = text)
    }
}
```

Añadimos al ContentHomeView las llamadas a dos botones, por ahora sin hacer nada, a ver qué tal va quedando:
```
 MainButton(text = "Generar Descuento" ){

        }
        MainButton(text = "Limpiar", color=Color.Red) {
            
        }
```

Debería ser algo así
![](https://hackmd.io/_uploads/SydVHFuG6.png)


## CardComponents: MainCard
Las cards son componentes normales en cualquier aplicación móvil:
https://developer.android.com/jetpack/compose/components/card

Vamos a crear dos cards a partir de una MainCard que van a contener al resto de elementos:


```
@Composable
fun TwoCards(title1:String,number1:Double, title2:String, number2:Double){
    Row(modifier=Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.SpaceEvenly
    ){
     MainCard(title = title1, number =number1 ,
        modifier = Modifier
            .padding(start=30.dp)
            .weight(1f)
    )
    SpaceW()
        MainCard(title = title2, number =number2 ,
            modifier = Modifier
                .padding(end=30.dp)
                .weight(1f)
        )

    }
}
@Composable
fun MainCard(title: String, number:Double, modifier: Modifier){

    Card(modifier=modifier,
        colors=CardDefaults.cardColors(
            containerColor = Color.LightGray
        )
    ) {
        Column(
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally,
            modifier = Modifier.padding(16.dp)
        ) {
            Text(text = title, color= Color.Black, fontSize = 20.sp)
            Text(text ="$number€", color= Color.Black, fontSize = 20.sp)
        }
    }
}
```
Nos faltaría proveer de los parámetros necesarios y llamar a estas cards desde ContentHomeView


```
@Composable
fun ContentHomeView(paddingValues: PaddingValues) {
    Column (modifier= Modifier
        .padding(paddingValues)
        .padding(10.dp)
        .fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    )
    {
        var precio by remember { mutableStateOf("") }
        var descuento by remember { mutableStateOf("") }
        var precioDescuento by remember { mutableStateOf(0.0) }
        var totalDescuento by remember { mutableStateOf(0.0) }

        TwoCards(title1 = "Total", number1 =totalDescuento , title2 ="Descuento" , number2 =precioDescuento )
        MainTextField(value = precio, onValueChange ={precio=it} , label ="Precio" )
        SpaceH()
        MainTextField(value = descuento, onValueChange ={descuento=it} , label ="Descuento" )
        SpaceH()
        MainButton(text = "Generar Descuento" ){

        }
        MainButton(text = "Limpiar", color=Color.Red) {
            
        }

    }
}
```

Al ejecutarse ahora mismo debería verse así:
![](https://hackmd.io/_uploads/HyHOJc_fT.png)


# Calcular el descuento
Ahora sólo faltaría hacer funcionar los botones y que calcule el descuento

Añadimos estas dos funciones en HomeView.kt
```
fun calcularPrecio(precio:Double, descuento:Double):Double{
    var res=precio - calcularDescuento(precio, descuento)
    return kotlin.math.round (res*100)/100
}

fun calcularDescuento(precio:Double, descuento:Double): Double{
    var res=precio *(1- descuento/100)
    return kotlin.math.round (res*100)/100
}
```

Y ya sólo quedaría hacer estas operaciones o limpiar al pulsar los botones:
```
@Composable
fun ContentHomeView(paddingValues: PaddingValues) {
    Column (modifier= Modifier
        .padding(paddingValues)
        .padding(10.dp)
        .fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    )
    {
        var precio by remember { mutableStateOf("") }
        var descuento by remember { mutableStateOf("") }
        var precioDescuento by remember { mutableStateOf(0.0) }
        var totalDescuento by remember { mutableStateOf(0.0) }

        TwoCards(title1 = "Total", number1 =totalDescuento , title2 ="Descuento" , number2 =precioDescuento )
        MainTextField(value = precio, onValueChange ={precio=it} , label ="Precio" )
        SpaceH()
        MainTextField(value = descuento, onValueChange ={descuento=it} , label ="Descuento" )
        SpaceH()
        MainButton(text = "Generar Descuento" ){
            precioDescuento= calcularPrecio(precio.toDouble(), descuento.toDouble())
            totalDescuento= calcularDescuento(precio.toDouble(), descuento.toDouble())
        }
        MainButton(text = "Limpiar", color=Color.Red) {
            precio=""
            descuento=""
            precioDescuento=0.0
            totalDescuento=0.0

        }

    }
}
```
## Alertas

Qué pasa si pulsamos el botón de calcular descuento sin haber introducido ningún valor??

La aplicación falla porque el botón esperaba tener los datos necesarios. Vamos a crear una alerta para estos casos.
