From 2c0a3d4ec59f986bef3a1a4d3a699cabc843b5c6 Mon Sep 17 00:00:00 2001 From: dankito Date: Thu, 29 Aug 2024 00:44:53 +0200 Subject: [PATCH] Added navigation menu item to add an account --- .../kotlin/net/codinux/banking/ui/App.kt | 8 +----- .../banking/ui/appskeleton/SideMenu.kt | 26 ++++++++++++++++--- .../banking/ui/composables/BankIcon.kt | 18 ++++++------- .../banking/ui/composables/BanksList.kt | 9 ++++--- .../ui/composables/NavigationMenuItem.kt | 8 +++++- .../banking/ui/composables/StateHandler.kt | 7 +++++ .../net/codinux/banking/ui/state/UiState.kt | 2 ++ 7 files changed, 53 insertions(+), 25 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/App.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/App.kt index 446ab8f..3d3485e 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/App.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/App.kt @@ -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) diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/SideMenu.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/SideMenu.kt index 316b335..d169880 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/SideMenu.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/SideMenu.kt @@ -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() + } + } } } } diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt index 08f93b1..ee546f9 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt @@ -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 } diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BanksList.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BanksList.kt index ceec201..516992a 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BanksList.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BanksList.kt @@ -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) } } diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/NavigationMenuItem.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/NavigationMenuItem.kt index 055b6e5..264ea25 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/NavigationMenuItem.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/NavigationMenuItem.kt @@ -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) } diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/StateHandler.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/StateHandler.kt index da02286..a735f71 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/StateHandler.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/StateHandler.kt @@ -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 diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/state/UiState.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/state/UiState.kt index a6b469e..f914866 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/state/UiState.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/state/UiState.kt @@ -25,6 +25,8 @@ class UiState : ViewModel() { val accountFilter = MutableStateFlow>(emptyList()) + val showAddAccountDialog = MutableStateFlow(false) + val tanChallengeReceived = MutableStateFlow(null) val bankingClientErrorOccurred = MutableStateFlow(null)