Filtering transactions on click on account item in SideMenu

This commit is contained in:
dankito 2024-08-28 23:00:07 +02:00
parent 572bd8e9d8
commit ce5b99c290
7 changed files with 93 additions and 8 deletions

View File

@ -6,16 +6,18 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import bankmeister.composeapp.generated.resources.AppIcon import bankmeister.composeapp.generated.resources.AppIcon
import bankmeister.composeapp.generated.resources.Res import bankmeister.composeapp.generated.resources.Res
import kotlinx.coroutines.launch
import net.codinux.banking.ui.composables.BanksList import net.codinux.banking.ui.composables.BanksList
import net.codinux.banking.ui.config.Colors import net.codinux.banking.ui.config.Colors
import net.codinux.banking.ui.config.DI import net.codinux.banking.ui.config.DI
import net.codinux.banking.ui.model.BankAccountFilter
import org.jetbrains.compose.resources.imageResource import org.jetbrains.compose.resources.imageResource
private val uiState = DI.uiState private val uiState = DI.uiState
@ -34,6 +36,8 @@ private val HeaderBackground = Brush.linearGradient(
fun SideMenu(appContent: @Composable () -> Unit) { fun SideMenu(appContent: @Composable () -> Unit) {
val drawerState = uiState.drawerState.collectAsState().value val drawerState = uiState.drawerState.collectAsState().value
val coroutineScope = rememberCoroutineScope()
ModalDrawer( ModalDrawer(
modifier = Modifier.fillMaxHeight(), modifier = Modifier.fillMaxHeight(),
drawerState = drawerState, drawerState = drawerState,
@ -59,7 +63,17 @@ fun SideMenu(appContent: @Composable () -> Unit) {
Text("Konten", color = Colors.DrawerPrimaryText) Text("Konten", color = Colors.DrawerPrimaryText)
} }
BanksList(textColor = Colors.DrawerPrimaryText) BanksList(textColor = Colors.DrawerPrimaryText) { userAccount, bankAccount ->
uiState.accountFilter.value = if (userAccount == null) {
emptyList()
} else {
listOf(BankAccountFilter(userAccount, bankAccount))
}
coroutineScope.launch {
drawerState.close()
}
}
} }
} }
} }

View File

@ -1,5 +1,6 @@
package net.codinux.banking.ui.composables package net.codinux.banking.ui.composables
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -11,6 +12,8 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import bankmeister.composeapp.generated.resources.Res import bankmeister.composeapp.generated.resources.Res
import bankmeister.composeapp.generated.resources.account import bankmeister.composeapp.generated.resources.account
import net.codinux.banking.dataaccess.entities.BankAccountEntity
import net.codinux.banking.dataaccess.entities.UserAccountEntity
import net.codinux.banking.ui.config.DI import net.codinux.banking.ui.config.DI
private val uiState = DI.uiState private val uiState = DI.uiState
@ -18,11 +21,22 @@ private val uiState = DI.uiState
private val IconTextSpacing = 36.dp private val IconTextSpacing = 36.dp
@Composable @Composable
fun BanksList(modifier: Modifier = Modifier, itemModifier: Modifier = Modifier.height(48.dp).widthIn(min = 300.dp).padding(start = 8.dp), iconSize: Dp = 24.dp, textColor: Color = Color.White) { fun BanksList(
modifier: Modifier = Modifier,
iconSize: Dp = 24.dp,
textColor: Color = Color.White,
itemModifier: Modifier = Modifier.height(48.dp).widthIn(min = 300.dp).padding(start = 8.dp),
accountSelected: ((UserAccountEntity?, BankAccountEntity?) -> Unit)? = null
) {
val userAccounts = uiState.userAccounts.collectAsState() val userAccounts = uiState.userAccounts.collectAsState()
Column(modifier) { Column(modifier) {
Row(itemModifier, verticalAlignment = Alignment.CenterVertically) { Row(
itemModifier.clickable {
accountSelected?.invoke(null, null)
},
verticalAlignment = Alignment.CenterVertically
) {
BankIcon(null as? String?, Modifier.padding(end = IconTextSpacing), Modifier.size(iconSize), fallbackIcon = Res.drawable.account) BankIcon(null as? String?, Modifier.padding(end = IconTextSpacing), Modifier.size(iconSize), fallbackIcon = Res.drawable.account)
Text("Alle Konten", color = textColor) Text("Alle Konten", color = textColor)
@ -31,14 +45,24 @@ fun BanksList(modifier: Modifier = Modifier, itemModifier: Modifier = Modifier.h
userAccounts.value.forEach { userAccount -> userAccounts.value.forEach { userAccount ->
Spacer(Modifier.fillMaxWidth().height(12.dp)) Spacer(Modifier.fillMaxWidth().height(12.dp))
Row(itemModifier, verticalAlignment = Alignment.CenterVertically) { Row(
itemModifier.clickable {
accountSelected?.invoke(userAccount, null)
},
verticalAlignment = Alignment.CenterVertically
) {
BankIcon(userAccount, Modifier.padding(end = IconTextSpacing), Modifier.size(iconSize), fallbackIcon = Res.drawable.account) BankIcon(userAccount, Modifier.padding(end = IconTextSpacing), Modifier.size(iconSize), fallbackIcon = Res.drawable.account)
Text(userAccount.bankName, color = textColor) Text(userAccount.bankName, color = textColor)
} }
userAccount.accounts.sortedBy { it.displayIndex }.forEach { account -> userAccount.accounts.sortedBy { it.displayIndex }.forEach { account ->
Column(itemModifier.padding(start = iconSize + IconTextSpacing), verticalArrangement = Arrangement.Center) { Column(
itemModifier.clickable {
accountSelected?.invoke(userAccount, account)
}.padding(start = iconSize + IconTextSpacing),
verticalArrangement = Arrangement.Center
) {
Text(account.productName ?: account.identifier, color = textColor) Text(account.productName ?: account.identifier, color = textColor)
} }
} }

View File

@ -23,6 +23,8 @@ import net.codinux.banking.ui.config.DI
import net.codinux.banking.ui.state.UiState import net.codinux.banking.ui.state.UiState
import org.jetbrains.compose.ui.tooling.preview.Preview import org.jetbrains.compose.ui.tooling.preview.Preview
private val filterService = DI.bankAccountFilterService
private val formatUtil = DI.formatUtil private val formatUtil = DI.formatUtil
@Composable @Composable
@ -32,10 +34,16 @@ fun TransactionsList(uiState: UiState) {
derivedStateOf { userAccounts.associateBy { it.id } } derivedStateOf { userAccounts.associateBy { it.id } }
} }
val accountFilter by uiState.accountFilter.collectAsState()
val transactions by uiState.transactions.collectAsState() val transactions by uiState.transactions.collectAsState()
val groupedByMonth by remember(transactions) { val transactionsToDisplay by remember(accountFilter, transactions) {
derivedStateOf { transactions.groupBy { LocalDate(it.valueDate.year, it.valueDate.monthNumber, 1) } } derivedStateOf { filterService.filterAccounts(transactions, accountFilter) }
}
val groupedByMonth by remember(transactionsToDisplay) {
derivedStateOf { transactionsToDisplay.groupBy { LocalDate(it.valueDate.year, it.valueDate.monthNumber, 1) } }
} }
LazyColumn( LazyColumn(

View File

@ -24,6 +24,8 @@ object DI {
val bankIconService = BankIconService() val bankIconService = BankIconService()
val bankAccountFilterService = BankAccountFilterService()
var bankingRepository: BankingRepository = InMemoryBankingRepository(emptyList()) var bankingRepository: BankingRepository = InMemoryBankingRepository(emptyList())

View File

@ -0,0 +1,9 @@
package net.codinux.banking.ui.model
import net.codinux.banking.dataaccess.entities.BankAccountEntity
import net.codinux.banking.dataaccess.entities.UserAccountEntity
data class BankAccountFilter(
val userAccount: UserAccountEntity,
val bankAccount: BankAccountEntity? = null
)

View File

@ -0,0 +1,24 @@
package net.codinux.banking.ui.service
import net.codinux.banking.ui.model.AccountTransactionViewModel
import net.codinux.banking.ui.model.BankAccountFilter
class BankAccountFilterService {
fun filterAccounts(transactions: List<AccountTransactionViewModel>, accountsFilter: List<BankAccountFilter>): List<AccountTransactionViewModel> =
if (accountsFilter.isEmpty()) {
transactions
} else {
transactions.filter { matchesFilter(it, accountsFilter) }
}
private fun matchesFilter(transaction: AccountTransactionViewModel, accountsFilter: List<BankAccountFilter>): Boolean =
accountsFilter.any { (userAccount, bankAccount) ->
if (bankAccount != null) {
transaction.bankAccountId == bankAccount.id
} else {
transaction.userAccountId == userAccount.id
}
}
}

View File

@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import net.codinux.banking.dataaccess.entities.UserAccountEntity import net.codinux.banking.dataaccess.entities.UserAccountEntity
import net.codinux.banking.ui.model.AccountTransactionViewModel import net.codinux.banking.ui.model.AccountTransactionViewModel
import net.codinux.banking.ui.model.BankAccountFilter
import net.codinux.banking.ui.model.TanChallengeReceived import net.codinux.banking.ui.model.TanChallengeReceived
import net.codinux.banking.ui.model.error.ApplicationError import net.codinux.banking.ui.model.error.ApplicationError
import net.codinux.banking.ui.model.error.BankingClientError import net.codinux.banking.ui.model.error.BankingClientError
@ -21,6 +22,9 @@ class UiState : ViewModel() {
val drawerState = MutableStateFlow(DrawerState(DrawerValue.Open)) val drawerState = MutableStateFlow(DrawerState(DrawerValue.Open))
val accountFilter = MutableStateFlow<List<BankAccountFilter>>(emptyList())
val applicationErrorOccurred = MutableStateFlow<ApplicationError?>(null) val applicationErrorOccurred = MutableStateFlow<ApplicationError?>(null)
val bankingClientErrorOccurred = MutableStateFlow<BankingClientError?>(null) val bankingClientErrorOccurred = MutableStateFlow<BankingClientError?>(null)