fix(#6): address PR review

- matchesQuery: use %.2f format to match the display (was Double.toString, which can use scientific notation and disagree with the row's %.2f)
- Remove unused Switch import in AddEditRecurringScreen (the active toggle uses ToggleItem)
- Extract CategoryDropdownField to ui/components/CategoryDropdownField.kt so both add/edit screens share one implementation; takes label as a parameter
- Remove unused recurring_list_active string
This commit is contained in:
Achmad Setyabudi Susilo
2026-06-28 19:49:02 +07:00
parent b0a62bedf0
commit e8c7a14c75
5 changed files with 66 additions and 106 deletions
@@ -0,0 +1,61 @@
package dev.achmad.ledgerr.ui.components
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuAnchorType
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import dev.achmad.ledgerr.domain.category.model.Category
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CategoryDropdownField(
categoryId: Long?,
categories: List<Category>,
onCategoryChange: (Long) -> Unit,
label: String,
modifier: Modifier = Modifier,
) {
var expanded by remember { mutableStateOf(false) }
val selectedName = categories.firstOrNull { it.id == categoryId }?.name.orEmpty()
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
modifier = modifier,
) {
OutlinedTextField(
value = selectedName,
onValueChange = {},
readOnly = true,
label = { Text(label) },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
modifier = Modifier
.fillMaxWidth()
.menuAnchor(ExposedDropdownMenuAnchorType.PrimaryNotEditable, enabled = true),
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
) {
categories.forEach { category ->
DropdownMenuItem(
text = { Text(category.name) },
onClick = {
onCategoryChange(category.id)
expanded = false
},
)
}
}
}
}
@@ -10,11 +10,7 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuAnchorType
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
@@ -22,9 +18,6 @@ import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@@ -35,11 +28,10 @@ import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import dev.achmad.ledgerr.R
import dev.achmad.ledgerr.domain.category.model.Category
import dev.achmad.ledgerr.ui.components.AppBar
import dev.achmad.ledgerr.ui.components.CategoryDropdownField
import dev.achmad.ledgerr.ui.components.DateField
import dev.achmad.ledgerr.ui.screens.category.CategoryScreen
import java.time.LocalDate
data class AddEditExpenseScreen(
val expenseId: Long? = null,
@@ -108,6 +100,7 @@ data class AddEditExpenseScreen(
categoryId = categoryId,
categories = categories,
onCategoryChange = screenModel::setCategory,
label = stringResource(R.string.add_edit_expense_field_category),
)
DateField(
@@ -135,46 +128,3 @@ data class AddEditExpenseScreen(
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun CategoryDropdownField(
categoryId: Long?,
categories: List<Category>,
onCategoryChange: (Long) -> Unit,
modifier: Modifier = Modifier,
) {
var expanded by remember { mutableStateOf(false) }
val selectedName = categories.firstOrNull { it.id == categoryId }?.name.orEmpty()
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
modifier = modifier,
) {
OutlinedTextField(
value = selectedName,
onValueChange = {},
readOnly = true,
label = { Text(stringResource(R.string.add_edit_expense_field_category)) },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
modifier = Modifier
.fillMaxWidth()
.menuAnchor(ExposedDropdownMenuAnchorType.PrimaryNotEditable, enabled = true),
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
) {
categories.forEach { category ->
DropdownMenuItem(
text = { Text(category.name) },
onClick = {
onCategoryChange(category.id)
expanded = false
},
)
}
}
}
}
@@ -10,24 +10,16 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuAnchorType
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@@ -38,9 +30,9 @@ import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import dev.achmad.ledgerr.R
import dev.achmad.ledgerr.domain.category.model.Category
import dev.achmad.ledgerr.domain.recurring.model.RecurringInterval
import dev.achmad.ledgerr.ui.components.AppBar
import dev.achmad.ledgerr.ui.components.CategoryDropdownField
import dev.achmad.ledgerr.ui.components.DateField
import dev.achmad.ledgerr.ui.components.LabeledRadioButton
import dev.achmad.ledgerr.ui.components.ToggleItem
@@ -114,6 +106,7 @@ data class AddEditRecurringScreen(
categoryId = categoryId,
categories = categories,
onCategoryChange = screenModel::setCategory,
label = stringResource(R.string.add_edit_recurring_field_category),
)
IntervalSection(
@@ -148,49 +141,6 @@ data class AddEditRecurringScreen(
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun CategoryDropdownField(
categoryId: Long?,
categories: List<Category>,
onCategoryChange: (Long) -> Unit,
modifier: Modifier = Modifier,
) {
var expanded by remember { mutableStateOf(false) }
val selectedName = categories.firstOrNull { it.id == categoryId }?.name.orEmpty()
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
modifier = modifier,
) {
OutlinedTextField(
value = selectedName,
onValueChange = {},
readOnly = true,
label = { Text(stringResource(R.string.add_edit_recurring_field_category)) },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
modifier = Modifier
.fillMaxWidth()
.menuAnchor(ExposedDropdownMenuAnchorType.PrimaryNotEditable, enabled = true),
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
) {
categories.forEach { category ->
DropdownMenuItem(
text = { Text(category.name) },
onClick = {
onCategoryChange(category.id)
expanded = false
},
)
}
}
}
}
@Composable
private fun IntervalSection(
selected: RecurringInterval,
@@ -106,7 +106,7 @@ class ExpenseListScreenModel(
private fun matchesQuery(item: ExpenseWithCategory, query: String): Boolean {
if (query.isBlank()) return true
val note = item.expense.note.orEmpty()
val amountStr = item.expense.amount.toString()
val amountStr = "%.2f".format(item.expense.amount)
val categoryName = item.category.name
return note.contains(query, ignoreCase = true) ||
amountStr.contains(query) ||
-1
View File
@@ -79,7 +79,6 @@
<string name="expense_list_delete_message">This will permanently delete the expense.</string>
<string name="expense_list_empty">No expenses yet</string>
<string name="recurring_list_empty">No recurring expenses</string>
<string name="recurring_list_active">Active</string>
<!-- Add / Edit expense (issue #6) -->
<string name="add_edit_expense_title_new">Add Expense</string>