# 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:

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í

## 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í:

# 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.