Compare commits
10 Commits
025b91d318
...
1890fd9151
Author | SHA1 | Date |
---|---|---|
dankito | 1890fd9151 | |
dankito | 05181e5f25 | |
dankito | 70aa32e1d6 | |
dankito | 772595b942 | |
dankito | 3a898b07b3 | |
dankito | 16dbd4b0e6 | |
dankito | b82ac2e905 | |
dankito | 9e1b1103c2 | |
dankito | ada01465b9 | |
dankito | 8d79bfc15d |
|
@ -0,0 +1,59 @@
|
|||
package net.codinux.banking.ui.dialogs
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import net.codinux.banking.client.model.BankAccountType
|
||||
import net.codinux.banking.client.model.BankAccountViewInfo
|
||||
import net.codinux.banking.client.model.BankingGroup
|
||||
import net.codinux.banking.client.model.BankViewInfo
|
||||
import net.codinux.banking.client.model.tan.*
|
||||
import net.codinux.banking.ui.model.TanChallengeReceived
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun EnterTanDialogPreview_EnterTan() {
|
||||
val tanMethods = listOf(TanMethod("Zeig mich an", TanMethodType.AppTan, "902"))
|
||||
val user = BankViewInfo("12345678", "SupiDupiNutzer", "Abzockbank", BankingGroup.Postbank)
|
||||
val tanChallenge = TanChallenge(TanChallengeType.EnterTan, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethods.first().identifier, tanMethods, user = user)
|
||||
|
||||
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun EnterTanDialogPreview_TanImage() {
|
||||
val tanImageBytes = "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"
|
||||
|
||||
val tanMethod = TanMethod("photoTAN-Verfahren", TanMethodType.photoTan, "902", 6, AllowedTanFormat.Numeric)
|
||||
val tanImage = TanImage("image/png", tanImageBytes)
|
||||
|
||||
val user = BankViewInfo("10010010", "Ihr krasser Login Name", "Phantasie Bank", BankingGroup.Comdirect)
|
||||
|
||||
val tanChallenge = TanChallenge(TanChallengeType.Image, ActionRequiringTan.GetAccountInfo, "Geben Sie die TAN ein", tanMethod.identifier, listOf(tanMethod), null, emptyList(), tanImage, null, user)
|
||||
|
||||
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun EnterTanDialogPreview_WithMultipleTanMedia() { // shows that dialog is really long if a TAN Image, select box for TAN Media, bank name, bank account, ... gets displayed
|
||||
val tanImageBytes = "iVBORw0KGgoAAAANSUhEUgAAAJYAAACWAQAAAAAUekxPAAABZUlEQVR4Xs2WsY7DMAxDtfmXvVmbflnDAT6SSXDBdQsz1O4QvQKVQkp2Y3+sn/hPvo5lxKiMlXP1YmCy2rsKYFcPBS7LURthT+Ri8AJTnp1DwQts5xzAvd5g+/wwxU2Xp0weXevu20PGJVFZ89lDDoPfMSFD5ULNPZnDYXxxiEk4Z0QskzFCsWzLDrS5ajaY2hEhhIW+UzU7LDl4GBn00YLt6TI43eOK2ZYm200hGSNdj5bOBqPXuWhR8NQp5TXYltmDv8/yj5oNVhxoNWNyT9VsMHiOkuX20Zwmw3HNBuJXU9NjMtQcg5nYk3TeZXqmELhSsF22ZXfAdd4CeZxhBsMT5KTxmBs4xRwO48RgQ9dmhnIZV3FwYDx90nsYLHUHoFj1eP39Z3jIeC1BAIw1yj5zWCzZkJo+nhaHpiZTL1LXuM4cl8EqHdx5y/GQbdrOoV5ooz7Pjefs8Ajs0EAz47CP9fXsFzPY58fQF5StAAAAAElFTkSuQmCC"
|
||||
val tanImage = TanImage("image/png", tanImageBytes)
|
||||
|
||||
val tanMethods = listOf(
|
||||
TanMethod("chipTAN optisch", TanMethodType.ChipTanFlickercode, "911", 6, AllowedTanFormat.Numeric),
|
||||
TanMethod("chipTAN-QR", TanMethodType.ChipTanQrCode, "913", 6, AllowedTanFormat.Numeric)
|
||||
)
|
||||
|
||||
val tanMedia = listOf(
|
||||
TanMedium(TanMediumType.TanGenerator, "SparkassenCard (Debitkarte)", TanMediumStatus.Available, TanGeneratorTanMedium("5678901234")),
|
||||
TanMedium(TanMediumType.TanGenerator, "SparkassenCard (Debitkarte)", TanMediumStatus.Used, TanGeneratorTanMedium("5432109876"))
|
||||
)
|
||||
|
||||
val user = BankViewInfo("10010010", "Ihr krasser Login Name", "Eine ganz gewöhnliche Sparkasse", BankingGroup.Sparkasse)
|
||||
val account = BankAccountViewInfo("12345678", null, BankAccountType.CheckingAccount, null, "Giro Konto")
|
||||
|
||||
val tanChallenge = TanChallenge(TanChallengeType.Image, ActionRequiringTan.GetTransactions, "Sie möchten eine \"Umsatzabfrage\" freigeben: Bitte bestätigen Sie den \"Startcode 80061030\" mit der Taste \"OK\".", "913", tanMethods, "SparkassenCard (Debitkarte)", tanMedia, tanImage, null, user, account)
|
||||
|
||||
EnterTanDialog(TanChallengeReceived(tanChallenge) { }) { }
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,24C18.6274,24 24,18.6274 24,12C24,5.3726 18.6274,0 12,0C5.3726,0 0,5.3726 0,12C0,18.6274 5.3726,24 12,24ZM6,7.5C6,6.9477 6.4477,6.5 7,6.5H17C17.5523,6.5 18,6.9477 18,7.5V16.5C18,17.0523 17.5523,17.5 17,17.5H7C6.4477,17.5 6,17.0523 6,16.5V7.5ZM7.5,12.9C7.5,12.6791 7.6791,12.5 7.9,12.5H16.1C16.3209,12.5 16.5,12.6791 16.5,12.9V13.1C16.5,13.3209 16.3209,13.5 16.1,13.5H7.9C7.6791,13.5 7.5,13.3209 7.5,13.1V12.9ZM13.9,8.5C13.6791,8.5 13.5,8.6791 13.5,8.9V9.3C13.5,9.5209 13.6791,9.7 13.9,9.7H16.1C16.3209,9.7 16.5,9.5209 16.5,9.3V8.9C16.5,8.6791 16.3209,8.5 16.1,8.5H13.9ZM7.5,14.9C7.5,14.6791 7.6791,14.5 7.9,14.5H16.1C16.3209,14.5 16.5,14.6791 16.5,14.9V15.1C16.5,15.3209 16.3209,15.5 16.1,15.5H7.9C7.6791,15.5 7.5,15.3209 7.5,15.1V14.9Z"
|
||||
android:fillColor="#989792"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
Binary file not shown.
Before Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
|
@ -6,10 +6,8 @@ import androidx.compose.foundation.layout.*
|
|||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material.icons.outlined.FilterAlt
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -20,13 +18,10 @@ import androidx.compose.ui.input.key.*
|
|||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import bankmeister.composeapp.generated.resources.Res
|
||||
import bankmeister.composeapp.generated.resources.filter_alt
|
||||
import kotlinx.coroutines.launch
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.extensions.toggle
|
||||
import org.jetbrains.compose.resources.imageResource
|
||||
|
||||
private val uiState = DI.uiState
|
||||
|
||||
|
@ -138,11 +133,11 @@ 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))
|
||||
Icon(Icons.Outlined.FilterAlt, "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")
|
||||
IconButton({ coroutineScope.launch { DI.bankingService.updateAccountTransactions() } }, Modifier.width(IconWidth)) {
|
||||
Icon(Icons.Filled.Cached, contentDescription = "Neue Kontoumsätze abholen") // other possible icons: Refresh, sync, autorenew
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ import androidx.compose.material.Divider
|
|||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.Send
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.SaveAs
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
|
@ -58,7 +58,7 @@ fun SideMenuContent() {
|
|||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
Column(Modifier.background(Colors.DrawerContentBackground).verticalScroll(ScrollState(0), enabled = true)) {
|
||||
Column(Modifier.fillMaxSize().background(Colors.DrawerContentBackground).verticalScroll(ScrollState(0), enabled = true)) {
|
||||
Column(Modifier.fillMaxWidth().height(HeaderHeight.dp).background(HeaderBackground).padding(16.dp)) {
|
||||
Spacer(Modifier.weight(1f))
|
||||
|
||||
|
@ -99,7 +99,7 @@ fun SideMenuContent() {
|
|||
Spacer(Modifier.height(VerticalSpacing))
|
||||
|
||||
NavigationMenuItem(itemModifier, "Neue Überweisung", textColor, horizontalPadding = ItemHorizontalPadding,
|
||||
icon = { Icon(Icons.Filled.Add, "Konto hinzufügen", Modifier.size(iconSize), tint = textColor) }) {
|
||||
icon = { Icon(Icons.Filled.Add, "Neue Überweisung", Modifier.size(iconSize), tint = textColor) }) {
|
||||
uiState.showTransferMoneyDialogData.value = ShowTransferMoneyDialogData()
|
||||
|
||||
coroutineScope.launch {
|
||||
|
@ -116,7 +116,7 @@ fun SideMenuContent() {
|
|||
UiSettings(Modifier.fillMaxWidth().padding(bottom = VerticalSpacing), textColor)
|
||||
|
||||
NavigationMenuItem(itemModifier, "Daten exportieren", textColor, horizontalPadding = ItemHorizontalPadding,
|
||||
icon = { Icon(Icons.AutoMirrored.Filled.Send, "Konto hinzufügen", Modifier.size(iconSize), tint = textColor) }) {
|
||||
icon = { Icon(Icons.Filled.SaveAs, "Daten als CSV oder JSON exportieren", Modifier.size(iconSize), tint = textColor) }) {
|
||||
uiState.showExportScreen.value = true
|
||||
|
||||
coroutineScope.launch {
|
||||
|
|
|
@ -1,56 +1,58 @@
|
|||
package net.codinux.banking.ui.composables
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.LocalContentAlpha
|
||||
import androidx.compose.material.LocalContentColor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.codinux.banking.client.model.User
|
||||
import net.codinux.banking.client.model.BankViewInfo
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.model.BankInfo
|
||||
import net.dankito.banking.banklistcreator.prettifier.BankingGroupMapper
|
||||
import org.jetbrains.compose.resources.DrawableResource
|
||||
import org.jetbrains.compose.resources.vectorResource
|
||||
|
||||
private val bankIconService = DI.bankIconService
|
||||
|
||||
private val DefaultIconModifier: Modifier = Modifier.size(16.dp)
|
||||
|
||||
@Composable
|
||||
fun BankIcon(user: User?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, iconResource: DrawableResource? = null) {
|
||||
fun BankIcon(user: User?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, fallbackIcon: ImageVector? = null, fallbackIconTintColor: Color? = null) {
|
||||
val iconUrl by remember(user?.bic) { mutableStateOf(user?.let { bankIconService.findIconForBank(it) }) }
|
||||
|
||||
BankIcon(iconUrl, modifier, iconModifier, iconResource = iconResource)
|
||||
BankIcon(iconUrl, modifier, iconModifier, fallbackIcon = fallbackIcon, fallbackIconTintColor = fallbackIconTintColor)
|
||||
}
|
||||
|
||||
private val bankingGroupMapper = BankingGroupMapper()
|
||||
|
||||
@Composable
|
||||
fun BankIcon(bank: BankInfo, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, iconResource: DrawableResource? = null) {
|
||||
fun BankIcon(bank: BankInfo, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, fallbackIcon: ImageVector? = null) {
|
||||
val iconUrl by remember(bank.bic) { mutableStateOf(bankIconService.findIconForBank(bank.name, bankingGroupMapper.getBankingGroup(bank.name, bank.bic))) }
|
||||
|
||||
BankIcon(iconUrl, modifier, iconModifier, iconResource = iconResource)
|
||||
BankIcon(iconUrl, modifier, iconModifier, fallbackIcon = fallbackIcon)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BankIcon(user: BankViewInfo?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, iconResource: DrawableResource? = null) {
|
||||
fun BankIcon(user: BankViewInfo?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, fallbackIcon: ImageVector? = null) {
|
||||
val iconUrl = user?.let { bankIconService.findIconForBank(it.bankName, it.bankingGroup) }
|
||||
|
||||
BankIcon(iconUrl, modifier, iconModifier, iconResource = iconResource)
|
||||
BankIcon(iconUrl, modifier, iconModifier, fallbackIcon = fallbackIcon)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BankIcon(iconUrl: String?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, contentDescription: String = "Favicon of this bank", iconResource: DrawableResource? = null) {
|
||||
fun BankIcon(iconUrl: String?, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, contentDescription: String = "Favicon of this bank", fallbackIcon: ImageVector? = null, fallbackIconTintColor: Color? = null) {
|
||||
Column(modifier) {
|
||||
if (iconUrl != null) {
|
||||
IconForUrl(iconUrl, contentDescription, modifier = iconModifier)
|
||||
} else if (iconResource != null) {
|
||||
Image(vectorResource(iconResource), contentDescription, iconModifier)
|
||||
} else if (fallbackIcon != null) {
|
||||
Icon(fallbackIcon, contentDescription, iconModifier, tint = fallbackIconTintColor ?: LocalContentColor.current.copy(alpha = LocalContentAlpha.current))
|
||||
} else {
|
||||
Column(iconModifier) { } // show a placeholder for consistent layout
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
package net.codinux.banking.ui.composables
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.AccountBalance
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import bankmeister.composeapp.generated.resources.Res
|
||||
import bankmeister.composeapp.generated.resources.account
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.config.DI
|
||||
|
@ -17,6 +18,8 @@ private val uiState = DI.uiState
|
|||
|
||||
private val IconTextSpacing = 24.dp
|
||||
|
||||
private val defaultBankIcon = Icons.Outlined.AccountBalance
|
||||
|
||||
@Composable
|
||||
fun BanksList(
|
||||
modifier: Modifier = Modifier,
|
||||
|
@ -30,14 +33,14 @@ fun BanksList(
|
|||
|
||||
|
||||
Column(modifier) {
|
||||
NavigationMenuItem(itemModifier, "Alle Konten", textColor, iconSize, IconTextSpacing, itemHorizontalPadding, iconResource = Res.drawable.account) {
|
||||
NavigationMenuItem(itemModifier, "Alle Konten", textColor, iconSize, IconTextSpacing, itemHorizontalPadding, icon = { Icon(defaultBankIcon, "Alle Konten", Modifier.size(iconSize), tint = textColor) }) {
|
||||
accountSelected?.invoke(null, null)
|
||||
}
|
||||
|
||||
users.value.sortedBy { it.displayIndex }.forEach { user ->
|
||||
Spacer(Modifier.fillMaxWidth().height(12.dp))
|
||||
|
||||
NavigationMenuItem(itemModifier, user.displayName, textColor, iconSize, IconTextSpacing, itemHorizontalPadding, user, iconResource = Res.drawable.account) {
|
||||
NavigationMenuItem(itemModifier, user.displayName, textColor, iconSize, IconTextSpacing, itemHorizontalPadding, user, fallbackIcon = defaultBankIcon) {
|
||||
accountSelected?.invoke(user, null)
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
@ -21,7 +22,6 @@ import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
|||
import net.codinux.banking.dataaccess.entities.UserEntity
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import org.jetbrains.compose.resources.DrawableResource
|
||||
|
||||
private val filterService = DI.accountTransactionsFilterService
|
||||
|
||||
|
@ -39,7 +39,7 @@ fun NavigationMenuItem(
|
|||
horizontalPadding: Dp = 8.dp,
|
||||
user: UserEntity? = null,
|
||||
bankAccount: BankAccountEntity? = null,
|
||||
iconResource: DrawableResource? = null,
|
||||
fallbackIcon: ImageVector? = null,
|
||||
icon: (@Composable () -> Unit)? = null,
|
||||
onClick: (() -> Unit)? = null
|
||||
) {
|
||||
|
@ -68,7 +68,7 @@ fun NavigationMenuItem(
|
|||
icon()
|
||||
}
|
||||
} else {
|
||||
BankIcon(user, Modifier.padding(end = iconTextSpacing), Modifier.size(iconSize), iconResource = iconResource)
|
||||
BankIcon(user, Modifier.padding(end = iconTextSpacing), Modifier.size(iconSize), fallbackIcon = fallbackIcon, fallbackIconTintColor = textColor)
|
||||
}
|
||||
|
||||
Text(text, color = textColor, modifier = Modifier.weight(1f), maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
|
|
|
@ -45,6 +45,8 @@ fun AddAccountDialog(
|
|||
|
||||
val disabledColor: Color = MaterialTheme.colors.onSurface.copy(ContentAlpha.disabled)
|
||||
|
||||
val bankAutocompleteFocus = remember { FocusRequester() }
|
||||
|
||||
val loginNameFocus = remember { FocusRequester() }
|
||||
|
||||
var isAddingAccount by remember { mutableStateOf(false) }
|
||||
|
@ -97,6 +99,7 @@ fun AddAccountDialog(
|
|||
AutocompleteTextField(
|
||||
label = "Bank (Suche mit Name, Ort, BIC oder Bankleitzahl)",
|
||||
value = enteredBankSearchQuery,
|
||||
textFieldFocus = bankAutocompleteFocus,
|
||||
onEnteredTextChanged = { enteredBankSearchQuery = it },
|
||||
onSelectedItemChanged = {
|
||||
selectedBank = it
|
||||
|
@ -166,4 +169,9 @@ fun AddAccountDialog(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LaunchedEffect(bankAutocompleteFocus) {
|
||||
bankAutocompleteFocus.requestFocus()
|
||||
}
|
||||
}
|
|
@ -4,6 +4,9 @@ import androidx.compose.foundation.Image
|
|||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ZoomIn
|
||||
import androidx.compose.material.icons.filled.ZoomOut
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -13,14 +16,9 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import bankmeister.composeapp.generated.resources.Res
|
||||
import bankmeister.composeapp.generated.resources.zoom_in
|
||||
import bankmeister.composeapp.generated.resources.zoom_out
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import net.codinux.banking.client.model.tan.ActionRequiringTan
|
||||
import net.codinux.banking.client.model.tan.AllowedTanFormat
|
||||
import net.codinux.banking.client.model.tan.EnterTanResult
|
||||
import net.codinux.banking.client.model.tan.*
|
||||
import net.codinux.banking.ui.composables.BankIcon
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.config.Internationalization
|
||||
|
@ -30,7 +28,6 @@ import net.codinux.banking.ui.model.TanChallengeReceived
|
|||
import net.codinux.banking.ui.model.error.ErroneousAction
|
||||
import net.codinux.banking.ui.service.createImageBitmap
|
||||
import net.codinux.log.Log
|
||||
import org.jetbrains.compose.resources.imageResource
|
||||
import kotlin.io.encoding.Base64
|
||||
import kotlin.io.encoding.ExperimentalEncodingApi
|
||||
|
||||
|
@ -113,9 +110,19 @@ fun EnterTanDialog(tanChallengeReceived: TanChallengeReceived, onDismiss: () ->
|
|||
"TAN Verfahren",
|
||||
challenge.availableTanMethods.sortedBy { it.identifier },
|
||||
challenge.selectedTanMethod,
|
||||
{ Log.info { "User selected TanMethod $it" } }, // TODO: change TanMethod
|
||||
{ tanMethod ->
|
||||
if (tanMethod.type != TanMethodType.ChipTanFlickercode) {
|
||||
tanChallengeReceived.callback(EnterTanResult(null, tanMethod))
|
||||
}
|
||||
},
|
||||
{ it.displayName }
|
||||
)
|
||||
) { tanMethod ->
|
||||
if (tanMethod.type == TanMethodType.ChipTanFlickercode) {
|
||||
Text(tanMethod.displayName + " (noch nicht implementiert)", color = MaterialTheme.colors.onSurface.copy(ContentAlpha.disabled))
|
||||
} else {
|
||||
Text(tanMethod.displayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (challenge.availableTanMedia.isNotEmpty()) {
|
||||
|
@ -135,7 +142,7 @@ fun EnterTanDialog(tanChallengeReceived: TanChallengeReceived, onDismiss: () ->
|
|||
Column(Modifier.fillMaxWidth().padding(top = 6.dp)) {
|
||||
if (challenge.flickerCode != null) {
|
||||
Text("Es tut uns Leid, für die TAN müsste ein Flickercode angezeigt werden, was wir noch nicht implementiert haben.")
|
||||
Text("Bitte wählen Sie ein anderes TAN Verfahren, z. B. manuelle TAN Eingabe wie chipTAN manuell.", Modifier.padding(top = 6.dp))
|
||||
Text("Bitte wählen Sie ein anderes TAN Verfahren, z. B. chipTAN-QrCode oder manuelle TAN Eingabe wie chipTAN manuell.", Modifier.padding(top = 6.dp))
|
||||
}
|
||||
|
||||
challenge.tanImage?.let { tanImage ->
|
||||
|
@ -146,11 +153,11 @@ fun EnterTanDialog(tanChallengeReceived: TanChallengeReceived, onDismiss: () ->
|
|||
Text("Größe")
|
||||
Spacer(Modifier.width(6.dp))
|
||||
TextButton({ tanImageHeight -= 25}, enabled = tanImageHeight > minTanImageHeight, modifier = Modifier.width(48.dp), colors = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent)) {
|
||||
Icon(imageResource(Res.drawable.zoom_out), contentDescription = "Bild mit enkodierter TAN verkleiner", Modifier.size(28.dp))
|
||||
Icon(Icons.Filled.ZoomOut, contentDescription = "Bild mit enkodierter TAN verkleiner", Modifier.size(28.dp))
|
||||
}
|
||||
Spacer(Modifier.width(6.dp))
|
||||
TextButton({ tanImageHeight += 25}, enabled = tanImageHeight < maxTanImageHeight, modifier = Modifier.width(48.dp), colors = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent)) {
|
||||
Icon(imageResource(Res.drawable.zoom_in), contentDescription = "Bild mit enkodierter TAN vergrößern", Modifier.size(28.dp))
|
||||
Icon(Icons.Filled.ZoomIn, contentDescription = "Bild mit enkodierter TAN vergrößern", Modifier.size(28.dp))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,7 +174,7 @@ fun EnterTanDialog(tanChallengeReceived: TanChallengeReceived, onDismiss: () ->
|
|||
Text(challenge.messageToShowToUser)
|
||||
}
|
||||
|
||||
challenge.tanExpirationTime?.let { expirationTime ->
|
||||
challenge.tanExpirationTime?.let { expirationTime -> // is almost never set
|
||||
Row(Modifier.padding(top = 16.dp)) {
|
||||
val time = expirationTime.toLocalDateTime(TimeZone.currentSystemDefault()).time
|
||||
Text("TAN ist gültig bis:", Modifier.padding(end = 6.dp))
|
||||
|
|
|
@ -6,16 +6,15 @@ import androidx.compose.foundation.layout.size
|
|||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Visibility
|
||||
import androidx.compose.material.icons.filled.VisibilityOff
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.unit.dp
|
||||
import bankmeister.composeapp.generated.resources.Res
|
||||
import bankmeister.composeapp.generated.resources.visibility
|
||||
import bankmeister.composeapp.generated.resources.visibility_off
|
||||
import org.jetbrains.compose.resources.imageResource
|
||||
|
||||
@Composable // try BasicSecureTextField
|
||||
fun PasswordTextField(password: String = "", label: String = "Passwort", forceHidePassword: Boolean? = null, onEnterPressed: (() -> Unit)? = null, onChange: (String) -> Unit) {
|
||||
|
@ -34,12 +33,12 @@ fun PasswordTextField(password: String = "", label: String = "Passwort", forceHi
|
|||
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
trailingIcon = {
|
||||
val visibilityIcon = if (passwordVisible) {
|
||||
Res.drawable.visibility_off
|
||||
Icons.Filled.VisibilityOff
|
||||
} else {
|
||||
Res.drawable.visibility
|
||||
Icons.Filled.Visibility
|
||||
}
|
||||
Icon(
|
||||
bitmap = imageResource(visibilityIcon),
|
||||
visibilityIcon,
|
||||
contentDescription = if (passwordVisible) "Hide password" else "Show password",
|
||||
modifier = Modifier.size(24.dp).clickable { passwordVisible = !passwordVisible }
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ banking-client = "0.5.2-SNAPSHOT"
|
|||
kcsv = "2.2.0"
|
||||
kotlinx-serializable = "1.7.1"
|
||||
|
||||
klf = "1.6.0"
|
||||
klf = "1.6.1"
|
||||
logback = "1.5.7"
|
||||
|
||||
sqlDelight = "2.0.2"
|
||||
|
|
Loading…
Reference in New Issue