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
|
||||
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>
|
Loading…
x
Reference in New Issue
Block a user