Add screen code, convert cost to a string, ignoring how to add rates on the screen for now.
This commit is contained in:
		| @@ -6,7 +6,7 @@ import androidx.room.PrimaryKey | ||||
| @Entity | ||||
| data class Expense ( | ||||
|     val name: String, | ||||
|     val cost: Double, | ||||
|     val cost: String, | ||||
|     val rate: Enum<Rate>, | ||||
|     @PrimaryKey(autoGenerate = true) | ||||
|     val ID: Int = 0, | ||||
|   | ||||
| @@ -0,0 +1,82 @@ | ||||
| package com.hyperling.expensetracker | ||||
|  | ||||
| import androidx.compose.foundation.layout.Arrangement | ||||
| import androidx.compose.foundation.layout.Box | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.foundation.layout.fillMaxWidth | ||||
| import androidx.compose.foundation.text.KeyboardOptions | ||||
| import androidx.compose.material3.AlertDialog | ||||
| import androidx.compose.material3.Button | ||||
| import androidx.compose.material3.Text | ||||
| import androidx.compose.material3.TextField | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.ui.Alignment | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.text.input.KeyboardCapitalization | ||||
| import androidx.compose.ui.text.input.KeyboardType | ||||
| import androidx.compose.ui.text.style.TextGeometricTransform | ||||
| import androidx.compose.ui.unit.dp | ||||
|  | ||||
| @Composable | ||||
| fun ExpenseDialogAdd( | ||||
|     state: ExpenseState, | ||||
|     onEvent: (ExpenseEvent) -> Unit, | ||||
|     modifier: Modifier = Modifier | ||||
| ) { | ||||
|     AlertDialog( | ||||
|         onDismissRequest = { | ||||
|             onEvent(ExpenseEvent.HideDialog) | ||||
|         }, | ||||
|         title = { Text(text = "Add Expense") }, | ||||
|         text = { | ||||
|             Column ( | ||||
|                 verticalArrangement = Arrangement.spacedBy(8.dp) | ||||
|             ){ | ||||
|                 TextField( | ||||
|                     value = state.name, | ||||
|                     onValueChange = { | ||||
|                         onEvent(ExpenseEvent.SetName(it)) | ||||
|                     }, | ||||
|                     placeholder = { | ||||
|                         Text(text = "Name") | ||||
|                     }, | ||||
|                     keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.Words) | ||||
|                 ) | ||||
|                 // TBD: Had to make this a String, can we turn it back to a Double somehow? | ||||
|                 TextField( | ||||
|                     value = state.cost, | ||||
|                     onValueChange = { | ||||
|                         onEvent(ExpenseEvent.SetCost(it)) | ||||
|                     }, | ||||
|                     placeholder = { | ||||
|                         Text(text = "Cost") | ||||
|                     }, | ||||
|                     keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal) | ||||
|                 ) | ||||
|                 /* Unsure what to do here yet, a simple Picker type does not seems to exist? | ||||
|                 TextField( | ||||
|                     value = state.rate, | ||||
|                     onValueChange = { | ||||
|                         onEvent(ExpenseEvent.SetRate(it)) | ||||
|                     }, | ||||
|                     placeholder = { | ||||
|                         Text(text = "Rate") | ||||
|                     }, | ||||
|                 ) | ||||
|                 */ | ||||
|             } | ||||
|         }, | ||||
|         confirmButton = { | ||||
|             Box( | ||||
|                 modifier = Modifier.fillMaxWidth(), | ||||
|                 contentAlignment = Alignment.Center | ||||
|             ) { | ||||
|                 Button(onClick = { | ||||
|                     onEvent(ExpenseEvent.SaveExpense) | ||||
|                 }) { | ||||
|                     Text(text = "Save") | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     ) | ||||
| } | ||||
| @@ -3,7 +3,7 @@ package com.hyperling.expensetracker | ||||
| sealed interface ExpenseEvent { | ||||
|     object SaveExpense: ExpenseEvent | ||||
|     data class SetName(val name: String): ExpenseEvent | ||||
|     data class SetCost(val cost: Double): ExpenseEvent | ||||
|     data class SetCost(val cost: String): ExpenseEvent | ||||
|     data class SetRate(val rate: Rate): ExpenseEvent | ||||
|     object ShowDialog: ExpenseEvent | ||||
|     object HideDialog: ExpenseEvent | ||||
|   | ||||
							
								
								
									
										126
									
								
								app/src/main/java/com/hyperling/expensetracker/ExpenseScreen.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								app/src/main/java/com/hyperling/expensetracker/ExpenseScreen.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| package com.hyperling.expensetracker | ||||
|  | ||||
| import androidx.compose.foundation.clickable | ||||
| import androidx.compose.foundation.horizontalScroll | ||||
| import androidx.compose.foundation.layout.Arrangement | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.foundation.layout.Row | ||||
| import androidx.compose.foundation.layout.fillMaxSize | ||||
| import androidx.compose.foundation.layout.fillMaxWidth | ||||
| import androidx.compose.foundation.lazy.LazyColumn | ||||
| import androidx.compose.foundation.lazy.items | ||||
| import androidx.compose.foundation.rememberScrollState | ||||
| import androidx.compose.material.icons.Icons | ||||
| import androidx.compose.material.icons.filled.Add | ||||
| import androidx.compose.material.icons.filled.Delete | ||||
| import androidx.compose.material3.FloatingActionButton | ||||
| import androidx.compose.material3.Icon | ||||
| import androidx.compose.material3.IconButton | ||||
| import androidx.compose.material3.RadioButton | ||||
| import androidx.compose.material3.Scaffold | ||||
| import androidx.compose.material3.Text | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.ui.Alignment | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import androidx.compose.ui.unit.dp | ||||
| import androidx.compose.ui.unit.sp | ||||
|  | ||||
| fun getEnumStringResourceID(enumName: String): Int { | ||||
|     return ( | ||||
|             when (enumName) { | ||||
|                 SortType.NAME.toString() -> R.string.NAME | ||||
|                 SortType.COST.toString() -> R.string.COST | ||||
|                 SortType.RATE.toString() -> R.string.RATE | ||||
|                 else -> 0 | ||||
|             } | ||||
|     ) | ||||
| } | ||||
|  | ||||
| @Composable | ||||
| fun ExpenseScreen( | ||||
|     state: ExpenseState, | ||||
|     onEvent: (ExpenseEvent) -> Unit | ||||
| ){ | ||||
|     Scaffold ( | ||||
|         floatingActionButton = { | ||||
|             FloatingActionButton(onClick = { | ||||
|                 onEvent(ExpenseEvent.ShowDialog) | ||||
|             }) { | ||||
|                 Icon( | ||||
|                     imageVector = Icons.Default.Add, | ||||
|                     contentDescription = "Add Expense", | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     ){ padding -> | ||||
|         if(state.isAddingExpense){ | ||||
|             ExpenseDialogAdd(state, onEvent) | ||||
|         } | ||||
|  | ||||
|         LazyColumn ( | ||||
|             contentPadding = padding, | ||||
|             modifier = Modifier.fillMaxSize(), | ||||
|             verticalArrangement = Arrangement.spacedBy(16.dp) | ||||
|         ){ | ||||
|             item { | ||||
|                 Row (){ | ||||
|                     Text(text = "Sort ascending by:") | ||||
|                 } | ||||
|                 Row ( | ||||
|                     modifier = Modifier | ||||
|                         .fillMaxWidth() | ||||
|                         .horizontalScroll(rememberScrollState()), | ||||
|                     verticalAlignment = Alignment.CenterVertically | ||||
|                 ){ | ||||
|                     SortType.values().forEach { sortType -> | ||||
|                         Row ( | ||||
|                             modifier = Modifier | ||||
|                                 .clickable { | ||||
|                                     onEvent(ExpenseEvent.SortExpenses(sortType)) | ||||
|                                 }, | ||||
|                             verticalAlignment = Alignment.CenterVertically | ||||
|                         ){ | ||||
|                             RadioButton( | ||||
|                                 selected = state.sortType == sortType, | ||||
|                                 onClick = { | ||||
|                                     onEvent(ExpenseEvent.SortExpenses(sortType)) | ||||
|                                 } | ||||
|                             ) | ||||
|                             Text(text = stringResource(getEnumStringResourceID(sortType.name))) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 Row (){ | ||||
|                     Text(text = "Expenses:") | ||||
|                 } | ||||
|             } | ||||
|             items(state.expenses) {expense -> | ||||
|                 Row ( | ||||
|                     modifier = Modifier.fillMaxWidth() | ||||
|                 ) { | ||||
|                     Column ( | ||||
|                         modifier = Modifier.weight(1f) | ||||
|                     ) { | ||||
|                         Text ( | ||||
|                             text = expense.name, | ||||
|                             fontSize = 20.sp | ||||
|                         ) | ||||
|                         Text( | ||||
|                             text = "${expense.cost} per ${expense.rate}", | ||||
|                             fontSize = 12.sp | ||||
|                         ) | ||||
|                     } | ||||
|                     IconButton(onClick = { | ||||
|                         onEvent(ExpenseEvent.DeleteExpense(expense)) | ||||
|                     }) { | ||||
|                         Icon( | ||||
|                             imageVector = Icons.Default.Delete, | ||||
|                             contentDescription = "Delete Expense" | ||||
|                         ) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -2,9 +2,9 @@ package com.hyperling.expensetracker | ||||
|  | ||||
| data class ExpenseState( | ||||
|     val expenses: List<Expense> = emptyList(), | ||||
|     val firstName: String = "", | ||||
|     val lastName: String = "", | ||||
|     val phoneNumber: String = "", | ||||
|     val name: String = "", | ||||
|     val cost: String = "", | ||||
|     val rate: Rate = Rate.MONTHLY, | ||||
|     val isAddingExpense: Boolean = false, | ||||
|     val sortType: SortType = SortType.NAME, | ||||
| ) | ||||
|   | ||||
| @@ -1,3 +1,6 @@ | ||||
| <resources> | ||||
|     <string name="app_name">Recurring Expenses</string> | ||||
|     <string name="NAME">Name</string> | ||||
|     <string name="COST">Cost</string> | ||||
|     <string name="RATE">Rate</string> | ||||
| </resources> | ||||
		Reference in New Issue
	
	Block a user