Implemented generating EQP QR Code

This commit is contained in:
dankito 2024-10-01 21:48:19 +02:00
parent 737d35b9a6
commit 3d474f38ae
10 changed files with 146 additions and 1 deletions

View File

@ -78,6 +78,7 @@ kotlin {
implementation(libs.banking.client.model)
implementation(libs.fints4k.banking.client)
implementation(libs.epcqrcode)
implementation(libs.kcsv)
implementation(libs.klf)

View File

@ -56,6 +56,12 @@ fun FloatingActionMenu(
if (fabVisibilityAnimation.value > 0) {
Box(Modifier.fillMaxSize().padding(bottom = bottomPadding, end = 12.dp), contentAlignment = Alignment.BottomEnd) {
Column(Modifier, horizontalAlignment = Alignment.End) {
FloatingActionMenuItem("QR Code erstellen", "EPC QR Code erstellen") {
handleClick {
uiState.showCreateEpcQrCodeScreen.value = true
}
}
FloatingActionMenuItem("Überweisung", "Neue Überweisung", enabled = accountsThatSupportMoneyTransfer.isNotEmpty()) {
handleClick {
uiState.showTransferMoneyDialogData.value = ShowTransferMoneyDialogData()

View File

@ -15,6 +15,7 @@ private val formatUtil = DI.formatUtil
fun StateHandler(uiState: UiState, snackbarHostState: SnackbarHostState) {
val showAddAccountDialog by uiState.showAddAccountDialog.collectAsState()
val showTransferMoneyDialogData by uiState.showTransferMoneyDialogData.collectAsState()
val showCreateEpcQrCodeScreen by uiState.showCreateEpcQrCodeScreen.collectAsState()
val showAccountTransactionDetailsScreenForId by uiState.showAccountTransactionDetailsScreenForId.collectAsState()
val showBankSettingsScreenForBank by uiState.showBankSettingsScreenForBank.collectAsState()
@ -38,6 +39,10 @@ fun StateHandler(uiState: UiState, snackbarHostState: SnackbarHostState) {
TransferMoneyDialog(data) { uiState.showTransferMoneyDialogData.value = null }
}
if (showCreateEpcQrCodeScreen) {
CreateEpcQrCodeScreen { uiState.showCreateEpcQrCodeScreen.value = false }
}
showAccountTransactionDetailsScreenForId?.let { transactionId ->
DI.bankingService.getTransaction(transactionId)?.let { transaction ->

View File

@ -22,6 +22,9 @@ object Colors {
val BackgroundColorLight = Color("#FFFFFF")
val MaterialThemeTextColor = Color(0xFF4F4F4F) // to match dialog's text color of Material theme
val DrawerContentBackground = BackgroundColorDark
val DrawerPrimaryText = PrimaryTextColorDark

View File

@ -29,6 +29,8 @@ object DI {
val accountTransactionsFilterService = AccountTransactionsFilterService()
val epcQrCodeService = EpcQrCodeService()
val uiService = UiService()

View File

@ -136,7 +136,7 @@ fun EnterTanDialog(tanChallengeReceived: TanChallengeReceived, onDismiss: () ->
if (challenge.tanImage != null || challenge.flickerCode != null) {
Column(Modifier.fillMaxWidth().padding(top = 6.dp)) {
val textColor = Color(0xFF4F4F4F) // to match dialog's text color of Material theme
val textColor = Colors.MaterialThemeTextColor // to match dialog's text color of Material theme
challenge.flickerCode?.let { flickerCode ->
ChipTanFlickerCodeView(flickerCode, textColor)

View File

@ -0,0 +1,109 @@
package net.codinux.banking.ui.screens
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import net.codinux.banking.ui.composables.tan.ImageSizeControls
import net.codinux.banking.ui.config.Colors
import net.codinux.banking.ui.config.DI
import net.codinux.banking.ui.extensions.ImeNext
import net.codinux.banking.ui.forms.OutlinedTextField
import net.codinux.banking.ui.service.createImageBitmap
private val epcQrCodeService = DI.epcQrCodeService
@Composable
fun CreateEpcQrCodeScreen(onClosed: () -> Unit) {
var receiverName by remember { mutableStateOf("") }
var iban by remember { mutableStateOf("") }
var bic by remember { mutableStateOf("") }
var amount by remember { mutableStateOf("") }
var reference by remember { mutableStateOf("") }
val epcQrCodeBytes by remember(receiverName, iban, bic, amount, reference) {
derivedStateOf {
if (receiverName.isNotBlank() && iban.isNotBlank()) {
epcQrCodeService.generateEpcQrCode(receiverName, iban, bic.takeUnless { it.isBlank() }, amount.takeUnless { it.isBlank() }, reference.takeUnless { it.isBlank() })
} else {
null
}
}
}
var imageHeight by remember { mutableStateOf(350) }
val minImageHeight = 100
val maxImageHeight = 700
FullscreenViewBase("EPC QR Code erstellen", "Schließen", onClosed = onClosed) {
Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) {
if (epcQrCodeBytes == null) {
Text("Mit EPC QR Codes, welche als GiroCode, scan2code, ... vermarktet werden, können Überweisungsdaten ganz einfach von Banking Apps eingelesen werden.")
Text("Hier können Sie Ihren eigenen erstellen, so dass jemand Ihre Überweisungsdaten einlesen und Ihnen ganz schnell Geld überweisen kann.")
} else {
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) {
ImageSizeControls(imageHeight > minImageHeight, imageHeight < maxImageHeight, Colors.MaterialThemeTextColor, { imageHeight -= 25 }) { imageHeight += 25 }
}
Row(Modifier.fillMaxWidth().padding(bottom = 8.dp), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) {
Image(createImageBitmap(epcQrCodeBytes!!), "Erzeugter EPC QR Code", Modifier.height(imageHeight.dp), contentScale = ContentScale.FillHeight)
}
}
OutlinedTextField(
label = { Text("Empfänger*in") },
value = receiverName,
onValueChange = { receiverName = it },
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
keyboardOptions = KeyboardOptions.ImeNext
)
OutlinedTextField(
label = { Text("IBAN") },
value = iban,
onValueChange = { iban = it },
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
keyboardOptions = KeyboardOptions.ImeNext
)
OutlinedTextField(
label = { Text("BIC (optional)") },
value = bic,
onValueChange = { bic = it },
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
keyboardOptions = KeyboardOptions.ImeNext
)
OutlinedTextField(
label = { Text("Betrag (optional)") },
value = amount,
onValueChange = { amount = it },
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
keyboardOptions = KeyboardOptions.ImeNext
)
OutlinedTextField(
label = { Text("Verwendungszweck (optional)") },
value = reference,
onValueChange = { reference = it },
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
keyboardOptions = KeyboardOptions.ImeNext
)
}
}
}

View File

@ -0,0 +1,15 @@
package net.codinux.banking.ui.service
import net.codinux.banking.epcqrcode.EpcQrCode
import net.codinux.banking.epcqrcode.EpcQrCodeConfig
import net.codinux.banking.epcqrcode.EpcQrCodeGenerator
class EpcQrCodeService {
fun generateEpcQrCode(receiverName: String, iban: String, bic: String?, amount: String?, reference: String?, heightAndWidth: Int = EpcQrCode.DefaultHeightAndWidth): ByteArray {
val generator = EpcQrCodeGenerator()
return generator.generateEpcQrCode(EpcQrCodeConfig(receiverName, iban, bic, amount, reference, qrCodeHeightAndWidth = heightAndWidth)).bytes
}
}

View File

@ -67,6 +67,8 @@ class UiState : ViewModel() {
val showTransferMoneyDialogData = MutableStateFlow<ShowTransferMoneyDialogData?>(null)
val showCreateEpcQrCodeScreen = MutableStateFlow(false)
val showAccountTransactionDetailsScreenForId = MutableStateFlow<Long?>(null)
val showBankSettingsScreenForBank = MutableStateFlow<BankAccessEntity?>(null)

View File

@ -3,6 +3,7 @@ kotlin = "2.0.10"
kotlinx-coroutines = "1.8.1"
banking-client = "0.6.2-SNAPSHOT"
epcqrcode = "1.0.0-SNAPSHOT"
kcsv = "2.2.0"
kotlinx-serializable = "1.7.1"
@ -36,6 +37,7 @@ junit = "4.13.2"
[libraries]
banking-client-model = { group = "net.codinux.banking.client", name = "banking-client-model", version.ref = "banking-client" }
fints4k-banking-client = { group = "net.codinux.banking.client", name = "fints4k-banking-client", version.ref = "banking-client" }
epcqrcode = { group = "net.codinux.banking.epcqrcode", name = "epc-qr-code", version.ref = "epcqrcode" }
kcsv = { group = "net.codinux.csv", name = "kcsv", version.ref = "kcsv" }
coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }