Added navigation menu item to add an account

This commit is contained in:
dankito 2024-08-29 00:44:53 +02:00
parent f221bd2095
commit 2c0a3d4ec5
7 changed files with 53 additions and 25 deletions

View File

@ -35,8 +35,6 @@ fun App() {
val colors = MaterialTheme.colors.copy(primary = Colors.Primary, primaryVariant = Colors.PrimaryDark, secondary = Colors.Accent, onSecondary = Color.White)
var showAddAccountDialog by remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope()
coroutineScope.launch {
@ -61,15 +59,11 @@ fun App() {
FloatingActionButton(
shape = CircleShape,
modifier = Modifier.offset((-12).dp, (-26).dp),
onClick = { showAddAccountDialog = true }
onClick = { DI.uiState.showAddAccountDialog.value = true }
) {
Icon(Icons.Filled.Add, contentDescription = "Add a bank account")
}
}
if (showAddAccountDialog) {
AddAccountDialog { showAddAccountDialog = false }
}
}
StateHandler(DI.uiState)

View File

@ -6,6 +6,8 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
@ -35,9 +37,15 @@ private val HeaderBackground = Brush.linearGradient(
)
)
private val textColor = Colors.DrawerPrimaryText
private val ItemHeight = 48.dp
private val itemModifier = Modifier.height(ItemHeight).widthIn(min = 300.dp).padding(start = 8.dp)
private val ItemHorizontalPadding = 8.dp
private val itemModifier = Modifier.height(ItemHeight).widthIn(min = 300.dp)
private val iconSize = 24.dp
@Composable
@ -51,7 +59,7 @@ fun SideMenu(appContent: @Composable () -> Unit) {
drawerState = drawerState,
content = appContent,
drawerBackgroundColor = Colors.DrawerContentBackground,
drawerContentColor = Colors.DrawerPrimaryText, // seems to have no effect
drawerContentColor = textColor, // seems to have no effect
drawerContent = {
Column(Modifier) {
Column(Modifier.fillMaxWidth().height(HeaderHeight.dp).background(HeaderBackground).padding(16.dp)) {
@ -68,10 +76,10 @@ fun SideMenu(appContent: @Composable () -> Unit) {
Column(Modifier.verticalScroll(ScrollState(0), enabled = true).padding(horizontal = 16.dp, vertical = 24.dp)) {
Column(Modifier.height(ItemHeight), verticalArrangement = Arrangement.Center) {
Text("Konten", color = Colors.DrawerPrimaryText)
Text("Konten", color = textColor)
}
BanksList(textColor = Colors.DrawerPrimaryText, itemModifier = itemModifier) { userAccount, bankAccount ->
BanksList(iconSize = iconSize, textColor = textColor, itemModifier = itemModifier, itemHorizontalPadding = ItemHorizontalPadding) { userAccount, bankAccount ->
uiState.accountFilter.value = if (userAccount == null) {
emptyList()
} else {
@ -82,6 +90,16 @@ fun SideMenu(appContent: @Composable () -> Unit) {
drawerState.close()
}
}
Spacer(Modifier.height(12.dp))
NavigationMenuItem(itemModifier, "Konto hinzufügen", textColor, horizontalPadding = ItemHorizontalPadding, icon = { Icon(Icons.Filled.Add, "Konto hinzufügen", Modifier.size(iconSize)) }) {
uiState.showAddAccountDialog.value = true
coroutineScope.launch {
drawerState.close()
}
}
}
}
}

View File

@ -22,35 +22,35 @@ private val bankIconService = DI.bankIconService
private val DefaultIconModifier: Modifier = Modifier.size(16.dp)
@Composable
fun BankIcon(userAccount: UserAccount?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, fallbackIcon: DrawableResource? = null) {
fun BankIcon(userAccount: UserAccount?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, iconResource: DrawableResource? = null) {
val iconUrl by remember(userAccount?.bic) { mutableStateOf(userAccount?.let { bankIconService.findIconForBank(it) }) }
BankIcon(iconUrl, modifier, iconModifier, fallbackIcon = fallbackIcon)
BankIcon(iconUrl, modifier, iconModifier, iconResource = iconResource)
}
private val bankingGroupMapper = BankingGroupMapper()
@Composable
fun BankIcon(bank: BankInfo, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, fallbackIcon: DrawableResource? = null) {
fun BankIcon(bank: BankInfo, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, iconResource: DrawableResource? = null) {
val iconUrl by remember(bank.bic) { mutableStateOf(bankIconService.findIconForBank(bank.name, bankingGroupMapper.getBankingGroup(bank.name, bank.bic))) }
BankIcon(iconUrl, modifier, iconModifier, fallbackIcon = fallbackIcon)
BankIcon(iconUrl, modifier, iconModifier, iconResource = iconResource)
}
@Composable
fun BankIcon(userAccount: UserAccountViewInfo?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, fallbackIcon: DrawableResource? = null) {
fun BankIcon(userAccount: UserAccountViewInfo?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, iconResource: DrawableResource? = null) {
val iconUrl = userAccount?.let { bankIconService.findIconForBank(it.bankName, it.bankingGroup) }
BankIcon(iconUrl, modifier, iconModifier, fallbackIcon = fallbackIcon)
BankIcon(iconUrl, modifier, iconModifier, iconResource = iconResource)
}
@Composable
fun BankIcon(iconUrl: String?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, contentDescription: String = "Favicon of this bank", fallbackIcon: DrawableResource? = null) {
fun BankIcon(iconUrl: String?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, contentDescription: String = "Favicon of this bank", iconResource: DrawableResource? = null) {
Column(modifier) {
if (iconUrl != null) {
IconForUrl(iconUrl, contentDescription, modifier = iconModifier)
} else if (fallbackIcon != null) {
Image(vectorResource(fallbackIcon), contentDescription, iconModifier)
} else if (iconResource != null) {
Image(vectorResource(iconResource), contentDescription, iconModifier)
} else {
Column(iconModifier) { } // show a placeholder for consistent layout
}

View File

@ -22,26 +22,27 @@ 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),
itemModifier: Modifier = Modifier.height(48.dp).widthIn(min = 300.dp),
itemHorizontalPadding: Dp = 8.dp,
accountSelected: ((UserAccountEntity?, BankAccountEntity?) -> Unit)? = null
) {
val userAccounts = uiState.userAccounts.collectAsState()
Column(modifier) {
NavigationMenuItem(itemModifier, "Alle Konten", textColor, iconSize, IconTextSpacing, fallbackIcon = Res.drawable.account) {
NavigationMenuItem(itemModifier, "Alle Konten", textColor, iconSize, IconTextSpacing, itemHorizontalPadding, iconResource = Res.drawable.account) {
accountSelected?.invoke(null, null)
}
userAccounts.value.sortedBy { it.displayIndex }.forEach { userAccount ->
Spacer(Modifier.fillMaxWidth().height(12.dp))
NavigationMenuItem(itemModifier, userAccount.bankName, textColor, iconSize, IconTextSpacing, userAccount, fallbackIcon = Res.drawable.account) {
NavigationMenuItem(itemModifier, userAccount.bankName, textColor, iconSize, IconTextSpacing, itemHorizontalPadding, userAccount, iconResource = Res.drawable.account) {
accountSelected?.invoke(userAccount, null)
}
userAccount.accounts.sortedBy { it.displayIndex }.forEach { account ->
NavigationMenuItem(itemModifier, account.productName ?: account.identifier, textColor, iconSize, IconTextSpacing) {
NavigationMenuItem(itemModifier, account.productName ?: account.identifier, textColor, iconSize, IconTextSpacing, itemHorizontalPadding, bankAccount = account) {
accountSelected?.invoke(userAccount, account)
}
}

View File

@ -53,7 +53,13 @@ fun NavigationMenuItem(
}
.padding(horizontal = horizontalPadding)
) {
BankIcon(userAccount, Modifier.padding(end = iconTextSpacing), Modifier.size(iconSize), fallbackIcon = fallbackIcon)
if (icon != null) {
Column(Modifier.padding(end = iconTextSpacing)) {
icon()
}
} else {
BankIcon(userAccount, Modifier.padding(end = iconTextSpacing), Modifier.size(iconSize), iconResource = iconResource)
}
Text(text, color = textColor)
}

View File

@ -1,6 +1,7 @@
package net.codinux.banking.ui.composables
import androidx.compose.runtime.*
import net.codinux.banking.ui.dialogs.AddAccountDialog
import net.codinux.banking.ui.dialogs.ApplicationErrorDialog
import net.codinux.banking.ui.dialogs.BankingClientErrorDialog
import net.codinux.banking.ui.dialogs.EnterTanDialog
@ -8,10 +9,16 @@ import net.codinux.banking.ui.state.UiState
@Composable
fun StateHandler(uiState: UiState) {
val showAddAccountDialog by uiState.showAddAccountDialog.collectAsState()
val tanChallengeReceived by uiState.tanChallengeReceived.collectAsState()
val bankingClientError by uiState.bankingClientErrorOccurred.collectAsState()
val applicationError by uiState.applicationErrorOccurred.collectAsState()
if (showAddAccountDialog) {
AddAccountDialog { uiState.showAddAccountDialog.value = false }
}
tanChallengeReceived?.let { tanChallengeReceived ->
EnterTanDialog(tanChallengeReceived) {
uiState.tanChallengeReceived.value = null

View File

@ -25,6 +25,8 @@ class UiState : ViewModel() {
val accountFilter = MutableStateFlow<List<BankAccountFilter>>(emptyList())
val showAddAccountDialog = MutableStateFlow(false)
val tanChallengeReceived = MutableStateFlow<TanChallengeReceived?>(null)
val bankingClientErrorOccurred = MutableStateFlow<BankingClientError?>(null)