Add screen code, convert cost to a string, ignoring how to add rates on the screen for now.
This commit is contained in:
parent
a4513394d1
commit
e3a2625f68
@ -6,7 +6,7 @@ import androidx.room.PrimaryKey
|
|||||||
@Entity
|
@Entity
|
||||||
data class Expense (
|
data class Expense (
|
||||||
val name: String,
|
val name: String,
|
||||||
val cost: Double,
|
val cost: String,
|
||||||
val rate: Enum<Rate>,
|
val rate: Enum<Rate>,
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
val ID: Int = 0,
|
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 {
|
sealed interface ExpenseEvent {
|
||||||
object SaveExpense: ExpenseEvent
|
object SaveExpense: ExpenseEvent
|
||||||
data class SetName(val name: String): 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
|
data class SetRate(val rate: Rate): ExpenseEvent
|
||||||
object ShowDialog: ExpenseEvent
|
object ShowDialog: ExpenseEvent
|
||||||
object HideDialog: 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(
|
data class ExpenseState(
|
||||||
val expenses: List<Expense> = emptyList(),
|
val expenses: List<Expense> = emptyList(),
|
||||||
val firstName: String = "",
|
val name: String = "",
|
||||||
val lastName: String = "",
|
val cost: String = "",
|
||||||
val phoneNumber: String = "",
|
val rate: Rate = Rate.MONTHLY,
|
||||||
val isAddingExpense: Boolean = false,
|
val isAddingExpense: Boolean = false,
|
||||||
val sortType: SortType = SortType.NAME,
|
val sortType: SortType = SortType.NAME,
|
||||||
)
|
)
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Recurring Expenses</string>
|
<string name="app_name">Recurring Expenses</string>
|
||||||
|
<string name="NAME">Name</string>
|
||||||
|
<string name="COST">Cost</string>
|
||||||
|
<string name="RATE">Rate</string>
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user