Added navigation menu item to add an account
This commit is contained in:
parent
f221bd2095
commit
2c0a3d4ec5
|
@ -35,8 +35,6 @@ fun App() {
|
||||||
|
|
||||||
val colors = MaterialTheme.colors.copy(primary = Colors.Primary, primaryVariant = Colors.PrimaryDark, secondary = Colors.Accent, onSecondary = Color.White)
|
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()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
|
@ -61,15 +59,11 @@ fun App() {
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
modifier = Modifier.offset((-12).dp, (-26).dp),
|
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")
|
Icon(Icons.Filled.Add, contentDescription = "Add a bank account")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showAddAccountDialog) {
|
|
||||||
AddAccountDialog { showAddAccountDialog = false }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StateHandler(DI.uiState)
|
StateHandler(DI.uiState)
|
||||||
|
|
|
@ -6,6 +6,8 @@ import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.*
|
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.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
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 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
|
@Composable
|
||||||
|
@ -51,7 +59,7 @@ fun SideMenu(appContent: @Composable () -> Unit) {
|
||||||
drawerState = drawerState,
|
drawerState = drawerState,
|
||||||
content = appContent,
|
content = appContent,
|
||||||
drawerBackgroundColor = Colors.DrawerContentBackground,
|
drawerBackgroundColor = Colors.DrawerContentBackground,
|
||||||
drawerContentColor = Colors.DrawerPrimaryText, // seems to have no effect
|
drawerContentColor = textColor, // seems to have no effect
|
||||||
drawerContent = {
|
drawerContent = {
|
||||||
Column(Modifier) {
|
Column(Modifier) {
|
||||||
Column(Modifier.fillMaxWidth().height(HeaderHeight.dp).background(HeaderBackground).padding(16.dp)) {
|
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.verticalScroll(ScrollState(0), enabled = true).padding(horizontal = 16.dp, vertical = 24.dp)) {
|
||||||
Column(Modifier.height(ItemHeight), verticalArrangement = Arrangement.Center) {
|
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) {
|
uiState.accountFilter.value = if (userAccount == null) {
|
||||||
emptyList()
|
emptyList()
|
||||||
} else {
|
} else {
|
||||||
|
@ -82,6 +90,16 @@ fun SideMenu(appContent: @Composable () -> Unit) {
|
||||||
drawerState.close()
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,35 +22,35 @@ private val bankIconService = DI.bankIconService
|
||||||
private val DefaultIconModifier: Modifier = Modifier.size(16.dp)
|
private val DefaultIconModifier: Modifier = Modifier.size(16.dp)
|
||||||
|
|
||||||
@Composable
|
@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) }) }
|
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()
|
private val bankingGroupMapper = BankingGroupMapper()
|
||||||
|
|
||||||
@Composable
|
@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))) }
|
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
|
@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) }
|
val iconUrl = userAccount?.let { bankIconService.findIconForBank(it.bankName, it.bankingGroup) }
|
||||||
|
|
||||||
BankIcon(iconUrl, modifier, iconModifier, fallbackIcon = fallbackIcon)
|
BankIcon(iconUrl, modifier, iconModifier, iconResource = iconResource)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@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) {
|
Column(modifier) {
|
||||||
if (iconUrl != null) {
|
if (iconUrl != null) {
|
||||||
IconForUrl(iconUrl, contentDescription, modifier = iconModifier)
|
IconForUrl(iconUrl, contentDescription, modifier = iconModifier)
|
||||||
} else if (fallbackIcon != null) {
|
} else if (iconResource != null) {
|
||||||
Image(vectorResource(fallbackIcon), contentDescription, iconModifier)
|
Image(vectorResource(iconResource), contentDescription, iconModifier)
|
||||||
} else {
|
} else {
|
||||||
Column(iconModifier) { } // show a placeholder for consistent layout
|
Column(iconModifier) { } // show a placeholder for consistent layout
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,26 +22,27 @@ fun BanksList(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
iconSize: Dp = 24.dp,
|
iconSize: Dp = 24.dp,
|
||||||
textColor: Color = Color.White,
|
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
|
accountSelected: ((UserAccountEntity?, BankAccountEntity?) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
val userAccounts = uiState.userAccounts.collectAsState()
|
val userAccounts = uiState.userAccounts.collectAsState()
|
||||||
|
|
||||||
|
|
||||||
Column(modifier) {
|
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)
|
accountSelected?.invoke(null, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
userAccounts.value.sortedBy { it.displayIndex }.forEach { userAccount ->
|
userAccounts.value.sortedBy { it.displayIndex }.forEach { userAccount ->
|
||||||
Spacer(Modifier.fillMaxWidth().height(12.dp))
|
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)
|
accountSelected?.invoke(userAccount, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
userAccount.accounts.sortedBy { it.displayIndex }.forEach { account ->
|
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)
|
accountSelected?.invoke(userAccount, account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,13 @@ fun NavigationMenuItem(
|
||||||
}
|
}
|
||||||
.padding(horizontal = horizontalPadding)
|
.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)
|
Text(text, color = textColor)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.codinux.banking.ui.composables
|
package net.codinux.banking.ui.composables
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
|
import net.codinux.banking.ui.dialogs.AddAccountDialog
|
||||||
import net.codinux.banking.ui.dialogs.ApplicationErrorDialog
|
import net.codinux.banking.ui.dialogs.ApplicationErrorDialog
|
||||||
import net.codinux.banking.ui.dialogs.BankingClientErrorDialog
|
import net.codinux.banking.ui.dialogs.BankingClientErrorDialog
|
||||||
import net.codinux.banking.ui.dialogs.EnterTanDialog
|
import net.codinux.banking.ui.dialogs.EnterTanDialog
|
||||||
|
@ -8,10 +9,16 @@ import net.codinux.banking.ui.state.UiState
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun StateHandler(uiState: UiState) {
|
fun StateHandler(uiState: UiState) {
|
||||||
|
val showAddAccountDialog by uiState.showAddAccountDialog.collectAsState()
|
||||||
val tanChallengeReceived by uiState.tanChallengeReceived.collectAsState()
|
val tanChallengeReceived by uiState.tanChallengeReceived.collectAsState()
|
||||||
val bankingClientError by uiState.bankingClientErrorOccurred.collectAsState()
|
val bankingClientError by uiState.bankingClientErrorOccurred.collectAsState()
|
||||||
val applicationError by uiState.applicationErrorOccurred.collectAsState()
|
val applicationError by uiState.applicationErrorOccurred.collectAsState()
|
||||||
|
|
||||||
|
|
||||||
|
if (showAddAccountDialog) {
|
||||||
|
AddAccountDialog { uiState.showAddAccountDialog.value = false }
|
||||||
|
}
|
||||||
|
|
||||||
tanChallengeReceived?.let { tanChallengeReceived ->
|
tanChallengeReceived?.let { tanChallengeReceived ->
|
||||||
EnterTanDialog(tanChallengeReceived) {
|
EnterTanDialog(tanChallengeReceived) {
|
||||||
uiState.tanChallengeReceived.value = null
|
uiState.tanChallengeReceived.value = null
|
||||||
|
|
|
@ -25,6 +25,8 @@ class UiState : ViewModel() {
|
||||||
val accountFilter = MutableStateFlow<List<BankAccountFilter>>(emptyList())
|
val accountFilter = MutableStateFlow<List<BankAccountFilter>>(emptyList())
|
||||||
|
|
||||||
|
|
||||||
|
val showAddAccountDialog = MutableStateFlow(false)
|
||||||
|
|
||||||
val tanChallengeReceived = MutableStateFlow<TanChallengeReceived?>(null)
|
val tanChallengeReceived = MutableStateFlow<TanChallengeReceived?>(null)
|
||||||
|
|
||||||
val bankingClientErrorOccurred = MutableStateFlow<BankingClientError?>(null)
|
val bankingClientErrorOccurred = MutableStateFlow<BankingClientError?>(null)
|
||||||
|
|
Loading…
Reference in New Issue