Added a filter bar to filter transactions by date

This commit is contained in:
dankito 2024-09-06 15:40:49 +02:00
parent 77c944d33b
commit 43bd89a047
8 changed files with 113 additions and 7 deletions

View File

@ -51,6 +51,8 @@ fun App() {
val snackbarHostState = remember { SnackbarHostState() }
val showFilterBar = uiState.showFilterBar.collectAsState()
var isInitialized by remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
@ -98,6 +100,10 @@ fun App() {
DesktopLayout(scaffoldPadding, uiState, uiSettings, snackbarHostState, desktopDrawerWidth)
}
}
if (showFilterBar.value) {
FilterBar()
}
}

View File

@ -127,6 +127,7 @@ fun BottomBar(showMenuDrawer: Boolean = true) {
}
}
if (userAccounts.isNotEmpty()) {
if (showSearchbar == false) {
Row(Modifier.fillMaxHeight().widthIn(IconWidth, IconWidth), verticalAlignment = Alignment.CenterVertically) {
@ -137,6 +138,10 @@ fun BottomBar(showMenuDrawer: Boolean = true) {
}
Row(Modifier.fillMaxHeight().widthIn(IconWidth.times(2), IconWidth.times(2)), verticalAlignment = Alignment.CenterVertically) {
IconButton({ uiState.showFilterBar.value = !!!uiState.showFilterBar.value }, Modifier.width(IconWidth)) {
Icon(imageResource(Res.drawable.filter_alt), "Kontoumsätze nach Konto, Zeitraum oder Betrag filtern", Modifier.size(24.dp))
}
IconButton({ coroutineScope.launch { DI.bankingService.updateAccountTransactions() } }, Modifier.width(IconWidth)) { // TODO: use sync, cached or autorenew as icon?
Icon(Icons.Filled.Refresh, contentDescription = "Neue Kontoumsätze abholen")
}

View File

@ -0,0 +1,73 @@
package net.codinux.banking.ui.appskeleton
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import net.codinux.banking.ui.config.DI
import net.codinux.banking.ui.forms.RoundedCornersCard
import net.codinux.banking.ui.forms.Select
private val uiState = DI.uiState
private val uiSettings = DI.uiSettings
val labelsWidth = 60.dp
val selectBoxesWidth = 154.dp
val horizontalPadding = 6.dp
@Composable
fun FilterBar() {
val transactions = uiState.transactions.collectAsState()
val transactionsFilter = uiState.transactionsFilter.collectAsState()
val filterService = DI.accountTransactionsFilterService
val years by remember(transactions) { derivedStateOf { filterService.getYearForWhichWeHaveTransactions(transactions.value).sorted() + listOf(null as? Int) } }
val months = listOf("Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember" /*, "1. Quartal", "2. Quartal", "3. Quartal", "4. Quartal" */, null)
Box(
contentAlignment = Alignment.BottomEnd,
modifier = Modifier.fillMaxSize().zIndex(1100f)
.padding(bottom = 64.dp, end = 74.dp)
) {
Column(Modifier.height(166.dp).width(390.dp)) {
RoundedCornersCard(cornerSize = 4.dp, shadowElevation = 24.dp) {
Column(Modifier.fillMaxWidth().background(Color.White).padding(16.dp)) {
Row(Modifier.fillMaxWidth().padding(top = 8.dp), verticalAlignment = Alignment.CenterVertically) {
Text("Zeitraum", Modifier.width(labelsWidth))
Select(
label = "Jahr",
items = years,
selectedItem = transactionsFilter.value.year,
onSelectedItemChanged = { year -> transactionsFilter.value.year = year },
getItemDisplayText = { year -> if (year == null) "" else year.toString() },
modifier = Modifier.width(selectBoxesWidth).padding(horizontal = horizontalPadding)
)
if (transactionsFilter.value.year != null) {
Select(
label ="Monat",
items = months,
selectedItem = transactionsFilter.value.month?.let { months[it - 1] },
onSelectedItemChanged = { month -> transactionsFilter.value.month = months.indexOf(month) + 1 },
getItemDisplayText = { month -> if (month == null) "" else month },
modifier = Modifier.width(selectBoxesWidth)
)
}
}
}
}
}
}
}

View File

@ -120,7 +120,7 @@ fun TransferMoneyDialog(
"Konto",
accountsSupportingTransferringMoney, senderAccount, { senderAccount = it },
{ account -> "${accountsToUserAccount[account]?.displayName} ${account.displayName}" },
{ BankIcon(accountsToUserAccount[senderAccount]) }
leadingIcon = { BankIcon(accountsToUserAccount[senderAccount]) }
) { account ->
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
BankIcon(accountsToUserAccount[account], Modifier.padding(end = 6.dp))

View File

@ -13,12 +13,13 @@ fun <T> Select(
selectedItem: T,
onSelectedItemChanged: (T) -> Unit,
getItemDisplayText: (T) -> String,
modifier: Modifier = Modifier,
leadingIcon: @Composable (() -> Unit)? = null,
dropDownItemContent: @Composable ((T) -> Unit)? = null
) {
var showDropDownMenu by remember { mutableStateOf(false) }
ExposedDropdownMenuBox(showDropDownMenu, { isExpanded -> showDropDownMenu = isExpanded }, Modifier.fillMaxWidth()) {
ExposedDropdownMenuBox(showDropDownMenu, { isExpanded -> showDropDownMenu = isExpanded }, modifier.fillMaxWidth()) {
OutlinedTextField(
value = getItemDisplayText(selectedItem),
onValueChange = { },

View File

@ -7,7 +7,7 @@ import net.codinux.banking.dataaccess.entities.UserAccountEntity
class AccountTransactionsFilter {
val noFiltersApplied: Boolean
get() = showAllAccounts && noSearchTermApplied
get() = showAllAccounts && noSearchTermApplied && noDateFilterApplied
var selectedAccounts = mutableStateOf<List<BankAccountFilter>>(emptyList())
@ -37,4 +37,13 @@ class AccountTransactionsFilter {
fun updateSearchTerm(searchTerm: String) {
this.searchTerm = searchTerm
}
var year by mutableStateOf<Int?>(null)
var month by mutableStateOf<Int?>(null)
val noDateFilterApplied: Boolean
get() = year == null && month == null
}

View File

@ -8,14 +8,20 @@ import net.codinux.banking.ui.model.BankAccountFilter
class AccountTransactionsFilterService {
fun filterAccounts(transactions: List<AccountTransactionViewModel>, transactionsFilter: AccountTransactionsFilter): List<AccountTransactionViewModel> {
val appliedAccountFilter = if (transactionsFilter.showAllAccounts) {
fun filterAccounts(transactions: List<AccountTransactionViewModel>, filter: AccountTransactionsFilter): List<AccountTransactionViewModel> {
var appliedAccountFilter = if (filter.showAllAccounts) {
transactions
} else {
transactions.filter { matchesFilter(it, transactionsFilter.selectedAccounts.value) }
transactions.filter { matchesFilter(it, filter.selectedAccounts.value) }
}
val searchTerm = transactionsFilter.searchTerm
filter.year?.let { year ->
val month = filter.month
appliedAccountFilter = appliedAccountFilter.filter { it.valueDate.year == year && (month == null || it.valueDate.monthNumber == month) }
}
val searchTerm = filter.searchTerm
return if (searchTerm.isBlank()) {
appliedAccountFilter
} else {
@ -57,4 +63,8 @@ class AccountTransactionsFilterService {
return filter?.bankAccount == bankAccount
}
fun getYearForWhichWeHaveTransactions(transactions: List<AccountTransactionViewModel>): List<Int> =
transactions.map { it.valueDate.year }.toSet().sortedDescending()
}

View File

@ -38,6 +38,8 @@ class UiState : ViewModel() {
val transactionsFilter = MutableStateFlow(AccountTransactionsFilter())
var showFilterBar = MutableStateFlow(false)
val showAddAccountDialog = MutableStateFlow(false)