diff --git a/app/src/main/java/com/hyperling/expensetracker/Expense.kt b/app/src/main/java/com/hyperling/expensetracker/Expense.kt index 2445868..e9fc8a8 100644 --- a/app/src/main/java/com/hyperling/expensetracker/Expense.kt +++ b/app/src/main/java/com/hyperling/expensetracker/Expense.kt @@ -6,7 +6,7 @@ import androidx.room.PrimaryKey @Entity data class Expense ( val name: String, - val cost: Double, + val cost: String, val rate: Enum, @PrimaryKey(autoGenerate = true) val ID: Int = 0, diff --git a/app/src/main/java/com/hyperling/expensetracker/ExpenseDialogAdd.kt b/app/src/main/java/com/hyperling/expensetracker/ExpenseDialogAdd.kt new file mode 100644 index 0000000..e93d682 --- /dev/null +++ b/app/src/main/java/com/hyperling/expensetracker/ExpenseDialogAdd.kt @@ -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") + } + } + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/hyperling/expensetracker/ExpenseEvent.kt b/app/src/main/java/com/hyperling/expensetracker/ExpenseEvent.kt index 5e474dd..d01a0fb 100644 --- a/app/src/main/java/com/hyperling/expensetracker/ExpenseEvent.kt +++ b/app/src/main/java/com/hyperling/expensetracker/ExpenseEvent.kt @@ -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 diff --git a/app/src/main/java/com/hyperling/expensetracker/ExpenseScreen.kt b/app/src/main/java/com/hyperling/expensetracker/ExpenseScreen.kt new file mode 100644 index 0000000..973c760 --- /dev/null +++ b/app/src/main/java/com/hyperling/expensetracker/ExpenseScreen.kt @@ -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" + ) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/hyperling/expensetracker/ExpenseState.kt b/app/src/main/java/com/hyperling/expensetracker/ExpenseState.kt index 620c14e..a901376 100644 --- a/app/src/main/java/com/hyperling/expensetracker/ExpenseState.kt +++ b/app/src/main/java/com/hyperling/expensetracker/ExpenseState.kt @@ -2,9 +2,9 @@ package com.hyperling.expensetracker data class ExpenseState( val expenses: List = 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, ) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 22f39bd..9339f6c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,6 @@ Recurring Expenses + Name + Cost + Rate \ No newline at end of file