Compare commits
6 Commits
d30337eef2
...
6af5ef2529
Author | SHA1 | Date |
---|---|---|
dankito | 6af5ef2529 | |
dankito | 350a18c2a3 | |
dankito | 2c32c1970c | |
dankito | a5b4540443 | |
dankito | 166219d7e3 | |
dankito | 5af6cc82fc |
|
@ -13,6 +13,7 @@ import net.codinux.banking.persistence.entities.BankAccessEntity
|
|||
import net.codinux.banking.persistence.entities.UiSettingsEntity
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.settings.AppSettings
|
||||
import net.codinux.banking.ui.model.settings.ImageSettings
|
||||
|
||||
interface BankingRepository {
|
||||
|
||||
|
@ -25,6 +26,11 @@ interface BankingRepository {
|
|||
suspend fun saveUiSettings(settings: UiSettingsEntity)
|
||||
|
||||
|
||||
fun getImageSettings(id: String): ImageSettings?
|
||||
|
||||
suspend fun saveImageSettings(settings: ImageSettings)
|
||||
|
||||
|
||||
fun getAllBanks(): List<BankAccessEntity>
|
||||
|
||||
suspend fun persistBank(bank: BankAccess): BankAccessEntity
|
||||
|
|
|
@ -13,6 +13,7 @@ import net.codinux.banking.persistence.entities.BankAccessEntity
|
|||
import net.codinux.banking.persistence.entities.UiSettingsEntity
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.settings.AppSettings
|
||||
import net.codinux.banking.ui.model.settings.ImageSettings
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
|
||||
class InMemoryBankingRepository(
|
||||
|
@ -29,6 +30,8 @@ class InMemoryBankingRepository(
|
|||
|
||||
private var uiSettings: UiSettingsEntity = UiSettingsEntity(true, TransactionsGrouping.Month, true, true, true)
|
||||
|
||||
private var imageSettings = mutableMapOf<String, ImageSettings>()
|
||||
|
||||
|
||||
override fun getAppSettings(): AppSettings? = appSettings
|
||||
|
||||
|
@ -43,6 +46,13 @@ class InMemoryBankingRepository(
|
|||
}
|
||||
|
||||
|
||||
override fun getImageSettings(id: String) = imageSettings[id]
|
||||
|
||||
override suspend fun saveImageSettings(settings: ImageSettings) {
|
||||
imageSettings[settings.id] = settings
|
||||
}
|
||||
|
||||
|
||||
override fun getAllBanks(): List<BankAccessEntity> = banks.toList()
|
||||
|
||||
override suspend fun persistBank(bank: BankAccess): BankAccessEntity {
|
||||
|
|
|
@ -23,9 +23,9 @@ import net.codinux.banking.client.model.tan.TanMethod
|
|||
import net.codinux.banking.client.model.tan.TanMethodType
|
||||
import net.codinux.banking.persistence.entities.*
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.settings.AppAuthenticationMethod
|
||||
import net.codinux.banking.ui.model.settings.*
|
||||
import net.codinux.banking.ui.model.settings.AppSettings
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
import net.codinux.banking.ui.model.settings.ImageSettings
|
||||
import net.codinux.log.logger
|
||||
import kotlin.enums.EnumEntries
|
||||
import kotlin.js.JsName
|
||||
|
@ -39,7 +39,7 @@ open class SqliteBankingRepository : BankingRepository {
|
|||
|
||||
private val schema = BankmeisterDb.Schema
|
||||
|
||||
private val sqlDriver = createSqlDriverDriver("Bankmeister.db", schema, 1L)
|
||||
private val sqlDriver = createSqlDriverDriver("Bankmeister.db", schema, 2L)
|
||||
|
||||
private val database = BankmeisterDb(sqlDriver)
|
||||
|
||||
|
@ -89,6 +89,16 @@ open class SqliteBankingRepository : BankingRepository {
|
|||
}
|
||||
|
||||
|
||||
override fun getImageSettings(id: String): ImageSettings? =
|
||||
settingsQueries.getImageSettings(id) { height, frequency ->
|
||||
ImageSettings(id, mapToInt(height), mapToInt(frequency))
|
||||
}.executeAsOneOrNull()
|
||||
|
||||
override suspend fun saveImageSettings(settings: ImageSettings) {
|
||||
settingsQueries.upsertImageSettings(settings.id, mapInt(settings.height), mapInt(settings.frequency))
|
||||
}
|
||||
|
||||
|
||||
override fun getAllBanks(): List<BankAccessEntity> {
|
||||
val bankAccounts = getAllBankAccounts().groupBy { it.bankId }
|
||||
val tanMethods = getAllTanMethods().groupBy { it.bankId }.mapValues { it.value.toMutableList() }
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package net.codinux.banking.ui.model.settings
|
||||
|
||||
class ImageSettings(
|
||||
val id: String,
|
||||
|
||||
var height: Int,
|
||||
|
||||
var frequency: Int? = null // only needed for flicker code
|
||||
) {
|
||||
override fun toString() = "$id $height${if (frequency != null) " (frequency = $frequency)" else ""}"
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
CREATE TABLE IF NOT EXISTS ImageSettings (
|
||||
id TEXT PRIMARY KEY,
|
||||
|
||||
height INTEGER NOT NULL,
|
||||
width INTEGER, -- not used right now, add it just in case
|
||||
|
||||
frequency INTEGER
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE Holding DROP COLUMN quantity;
|
||||
|
||||
ALTER TABLE Holding ADD COLUMN quantity REAL;
|
|
@ -70,3 +70,22 @@ SELECT * FROM UiSettings WHERE id = 1;
|
|||
upsertUiSettings:
|
||||
INSERT OR REPLACE INTO UiSettings(id, transactionsGrouping, showBalance, showBankIcons, showColoredAmounts, showTransactionsInAlternatingColors)
|
||||
VALUES (1, ?, ?, ?, ?, ?);
|
||||
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ImageSettings (
|
||||
id TEXT PRIMARY KEY,
|
||||
|
||||
height INTEGER NOT NULL,
|
||||
width INTEGER, -- not used right now, add it just in case
|
||||
|
||||
frequency INTEGER
|
||||
);
|
||||
|
||||
|
||||
getImageSettings:
|
||||
SELECT height, frequency FROM ImageSettings WHERE id = ?;
|
||||
|
||||
upsertImageSettings:
|
||||
INSERT OR REPLACE INTO ImageSettings(id, height, frequency)
|
||||
VALUES (?, ?, ?);
|
||||
|
|
|
@ -29,6 +29,10 @@ actual fun createSqlDriverDriver(dbName: String, schema: SqlSchema<QueryResult.A
|
|||
}
|
||||
|
||||
|
||||
private fun setSchemaVersion(driver: SqlDriver, schemaVersion: Int) {
|
||||
driver.execute(null, "PRAGMA schema_version=$schemaVersion;", 0)
|
||||
}
|
||||
|
||||
private fun determineDataDirectory(): File {
|
||||
val currentDir = Path(System.getProperty("user.dir"))
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ android {
|
|||
applicationId = "net.codinux.banking.android" // the appId of the old Bankmeister app to be able to use the old PlayStore entry
|
||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
||||
targetSdk = libs.versions.android.targetSdk.get().toInt()
|
||||
versionCode = 17
|
||||
versionCode = 18
|
||||
versionName = "1.0.0-Alpha-15"
|
||||
}
|
||||
packaging {
|
||||
|
|
|
@ -14,6 +14,7 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.codinux.banking.client.model.tan.FlickerCode
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.model.Config.NewLine
|
||||
import net.codinux.banking.ui.service.tan.Bit
|
||||
import net.codinux.banking.ui.service.tan.FlickerCodeAnimator
|
||||
|
@ -22,23 +23,38 @@ import net.codinux.banking.ui.service.tan.Step
|
|||
|
||||
private const val FrequencyStepSize = 2
|
||||
|
||||
private val DefaultStripesHeight = 240.dp
|
||||
private val StripesHeightStepSize = 7.dp
|
||||
private val StripesWidthStepSize = 2.dp
|
||||
private val SpaceBetweenStripesStepSize = 1.dp
|
||||
|
||||
private val bankingService = DI.bankingService
|
||||
|
||||
|
||||
@Composable
|
||||
fun ChipTanFlickerCodeView(flickerCode: FlickerCode, textColor: Color = Color.Black) {
|
||||
|
||||
val animator = remember { FlickerCodeAnimator() }
|
||||
|
||||
var stripesHeight by remember { mutableStateOf(240.dp) }
|
||||
val flickerCodeSettings by remember { mutableStateOf(bankingService.getImageSettingsOrCreateDefault("FlickerCode", 240)) }
|
||||
|
||||
var stripesWidth by remember { mutableStateOf(45.dp) }
|
||||
val sizeFactor by remember { mutableStateOf(
|
||||
if (flickerCodeSettings.height == 240) {
|
||||
1
|
||||
} else {
|
||||
val diff = flickerCodeSettings.height.dp - DefaultStripesHeight
|
||||
|
||||
var spaceBetweenStripes by remember { mutableStateOf(15.dp) }
|
||||
(diff / StripesHeightStepSize).toInt()
|
||||
}
|
||||
) }
|
||||
|
||||
var frequency by remember { mutableStateOf(FlickerCodeAnimator.DefaultFrequency) }
|
||||
var stripesHeight by remember { mutableStateOf(DefaultStripesHeight + StripesHeightStepSize.times(sizeFactor)) }
|
||||
|
||||
var stripesWidth by remember { mutableStateOf(45.dp + StripesWidthStepSize.times(sizeFactor)) }
|
||||
|
||||
var spaceBetweenStripes by remember { mutableStateOf(15.dp + SpaceBetweenStripesStepSize.times(sizeFactor)) }
|
||||
|
||||
var frequency by remember { mutableStateOf(flickerCodeSettings.frequency ?: FlickerCodeAnimator.DefaultFrequency) }
|
||||
|
||||
var isPaused by remember { mutableStateOf(false) }
|
||||
|
||||
|
@ -51,6 +67,9 @@ fun ChipTanFlickerCodeView(flickerCode: FlickerCode, textColor: Color = Color.Bl
|
|||
stripesWidth = width
|
||||
stripesHeight = height
|
||||
spaceBetweenStripes = spaceBetween
|
||||
|
||||
flickerCodeSettings.height = height.value.toInt()
|
||||
bankingService.saveImageSettingsDebounced(flickerCodeSettings, coroutineScope)
|
||||
}
|
||||
|
||||
fun decreaseSize() {
|
||||
|
@ -76,6 +95,9 @@ fun ChipTanFlickerCodeView(flickerCode: FlickerCode, textColor: Color = Color.Bl
|
|||
frequency = newFrequency
|
||||
|
||||
animator.setFrequency(newFrequency)
|
||||
|
||||
flickerCodeSettings.frequency = newFrequency
|
||||
bankingService.saveImageSettingsDebounced(flickerCodeSettings, coroutineScope)
|
||||
}
|
||||
|
||||
fun decreaseFrequency() {
|
||||
|
|
|
@ -15,7 +15,7 @@ import androidx.compose.ui.unit.dp
|
|||
fun ImageSizeControls(decreaseEnabled: Boolean, increaseEnabled: Boolean, textColor: Color = Color.Black, onDecreaseImageSize: () -> Unit, onIncreaseImageSize: () -> Unit) {
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("Größe", color = textColor)
|
||||
Text("Größe", color = textColor, modifier = Modifier.padding(end = 6.dp))
|
||||
|
||||
TextButton({ onDecreaseImageSize() }, enabled = decreaseEnabled, modifier = Modifier.width(48.dp), colors = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent)) {
|
||||
Icon(Icons.Filled.ZoomOut, contentDescription = "Bild verkleinern", Modifier.size(28.dp), tint = textColor)
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package net.codinux.banking.ui.composables.tan
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.service.createImageBitmap
|
||||
|
||||
|
||||
private val bankingService = DI.bankingService
|
||||
|
||||
@Composable
|
||||
fun ImageView(
|
||||
imageBytes: ByteArray,
|
||||
imageSettingsId: String,
|
||||
contentDescription: String,
|
||||
initialImageHeight: Int = 300,
|
||||
minImageHeight: Int = 0,
|
||||
maxImageHeight: Int? = null,
|
||||
changeImageSizeStep: Int = 25,
|
||||
textColor: Color = Colors.MaterialThemeTextColor,
|
||||
) {
|
||||
|
||||
val imageSettings = bankingService.getImageSettingsOrCreateDefault(imageSettingsId, initialImageHeight)
|
||||
|
||||
var imageHeight by remember { mutableStateOf(imageSettings.height) }
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
|
||||
fun changeImageSize(by: Int) {
|
||||
imageHeight += by
|
||||
|
||||
imageSettings.height = imageHeight
|
||||
|
||||
bankingService.saveImageSettingsDebounced(imageSettings, coroutineScope)
|
||||
}
|
||||
|
||||
|
||||
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) {
|
||||
ImageSizeControls(imageHeight > minImageHeight, maxImageHeight == null || imageHeight < maxImageHeight, textColor, { changeImageSize(-changeImageSizeStep) }) { changeImageSize(changeImageSizeStep) }
|
||||
}
|
||||
|
||||
Row(Modifier.fillMaxWidth().padding(top = 6.dp), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) {
|
||||
Image(createImageBitmap(imageBytes), contentDescription, Modifier.height(imageHeight.dp), contentScale = ContentScale.FillHeight)
|
||||
}
|
||||
|
||||
}
|
|
@ -36,7 +36,7 @@ object DI {
|
|||
|
||||
var bankingRepository: BankingRepository = InMemoryBankingRepository(emptyList())
|
||||
|
||||
val bankingService by lazy { BankingService(uiState, uiSettings, bankingRepository, bankFinder) }
|
||||
val bankingService by lazy { BankingService(uiState, uiSettings, uiService, bankingRepository, bankFinder) }
|
||||
|
||||
|
||||
fun setRepository(repository: BankingRepository) {
|
||||
|
|
|
@ -1,33 +1,34 @@
|
|||
package net.codinux.banking.ui.dialogs
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import net.codinux.banking.client.model.tan.*
|
||||
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.ui.composables.BankIcon
|
||||
import net.codinux.banking.ui.composables.tan.ChipTanFlickerCodeView
|
||||
import net.codinux.banking.ui.composables.tan.ImageSizeControls
|
||||
import net.codinux.banking.ui.config.*
|
||||
import net.codinux.banking.ui.composables.tan.ImageView
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.config.Internationalization
|
||||
import net.codinux.banking.ui.forms.CaptionText
|
||||
import net.codinux.banking.ui.forms.OutlinedTextField
|
||||
import net.codinux.banking.ui.forms.Select
|
||||
import net.codinux.banking.ui.model.Config.NewLine
|
||||
import net.codinux.banking.ui.model.TanChallengeReceived
|
||||
import net.codinux.banking.ui.model.error.ErroneousAction
|
||||
import net.codinux.banking.ui.service.createImageBitmap
|
||||
import kotlin.io.encoding.Base64
|
||||
import kotlin.io.encoding.ExperimentalEncodingApi
|
||||
|
||||
|
@ -41,10 +42,6 @@ fun EnterTanDialog(tanChallengeReceived: TanChallengeReceived, onDismiss: () ->
|
|||
|
||||
val isNotADecoupledTanMethod = !!!isDecoupledMethod
|
||||
|
||||
var tanImageHeight by remember { mutableStateOf(250) }
|
||||
val minTanImageHeight = 100
|
||||
val maxTanImageHeight = 500
|
||||
|
||||
var showSelectingTanMediumNotImplementedWarning by remember { mutableStateOf(false) }
|
||||
|
||||
val textFieldFocus = remember { FocusRequester() }
|
||||
|
@ -150,13 +147,8 @@ fun EnterTanDialog(tanChallengeReceived: TanChallengeReceived, onDismiss: () ->
|
|||
tanImage.imageBytesBase64?.let { imageBytesBase64 ->
|
||||
val imageBytes = Base64.decode(imageBytesBase64)
|
||||
|
||||
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) {
|
||||
ImageSizeControls(tanImageHeight > minTanImageHeight, tanImageHeight < maxTanImageHeight, textColor, { tanImageHeight -= 25 }) { tanImageHeight += 25 }
|
||||
}
|
||||
|
||||
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) {
|
||||
Image(createImageBitmap(imageBytes), "Bild mit enkodierter TAN", Modifier.height(tanImageHeight.dp), contentScale = ContentScale.FillHeight)
|
||||
}
|
||||
// if it becomes necessary may also add the bank to ImageSettings.id to make ImageSettings bank specific
|
||||
ImageView(imageBytes, challenge.selectedTanMethod.type.toString(), "Bild mit enkodierter TAN", 250, 100, 500, textColor = textColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package net.codinux.banking.ui.screens
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.MaterialTheme
|
||||
|
@ -10,13 +9,11 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.codinux.banking.persistence.entities.BankAccountEntity
|
||||
import net.codinux.banking.ui.composables.BankIcon
|
||||
import net.codinux.banking.ui.composables.tan.ImageSizeControls
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.composables.tan.ImageView
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.extensions.ImeNext
|
||||
import net.codinux.banking.ui.extensions.rememberVerticalScroll
|
||||
|
@ -24,7 +21,6 @@ import net.codinux.banking.ui.forms.CaptionText
|
|||
import net.codinux.banking.ui.forms.OutlinedTextField
|
||||
import net.codinux.banking.ui.forms.Select
|
||||
import net.codinux.banking.ui.model.Config.NewLine
|
||||
import net.codinux.banking.ui.service.createImageBitmap
|
||||
import net.codinux.log.Log
|
||||
|
||||
private val epcQrCodeService = DI.epcQrCodeService
|
||||
|
@ -81,10 +77,6 @@ fun CreateEpcQrCodeScreen(onClosed: () -> Unit) {
|
|||
}
|
||||
}
|
||||
|
||||
var imageHeight by remember { mutableStateOf(350) }
|
||||
val minImageHeight = 100
|
||||
val maxImageHeight = 700
|
||||
|
||||
|
||||
FullscreenViewBase("EPC QR Code erstellen", "Schließen", onClosed = onClosed) {
|
||||
Column(Modifier.fillMaxWidth().rememberVerticalScroll()) {
|
||||
|
@ -94,15 +86,9 @@ fun CreateEpcQrCodeScreen(onClosed: () -> Unit) {
|
|||
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 }
|
||||
}
|
||||
ImageView(epcQrCodeBytes!!, "EpcQrCode", "Erzeugter EPC QR Code", 350, 100, 700)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
|
||||
Row(Modifier.fillMaxWidth().padding(top = 8.dp), horizontalArrangement = Arrangement.Center) {
|
||||
Text("Scannen Sie diesen Code auf einem anderen Gerät mit einer Banking App, z. B. Bankmeister", textAlign = TextAlign.Center, modifier = Modifier.padding(horizontal = 16.dp).padding(top = 8.dp))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import net.codinux.banking.client.model.request.GetAccountDataRequest
|
|||
import net.codinux.banking.client.model.request.TransferMoneyRequestForUser
|
||||
import net.codinux.banking.client.model.response.*
|
||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||
import net.codinux.banking.client.model.tan.TanMethodType
|
||||
import net.codinux.banking.client.service.BankingModelService
|
||||
import net.codinux.banking.persistence.BankingRepository
|
||||
import net.codinux.banking.persistence.entities.AccountTransactionEntity
|
||||
|
@ -28,6 +29,7 @@ import net.codinux.banking.ui.model.BankInfo
|
|||
import net.codinux.banking.ui.model.error.*
|
||||
import net.codinux.banking.ui.model.events.AccountTransactionsRetrievedEvent
|
||||
import net.codinux.banking.ui.model.events.TransferredMoneyEvent
|
||||
import net.codinux.banking.ui.model.settings.ImageSettings
|
||||
import net.codinux.banking.ui.model.settings.AppSettings
|
||||
import net.codinux.banking.ui.settings.UiSettings
|
||||
import net.codinux.banking.ui.state.UiState
|
||||
|
@ -39,10 +41,13 @@ import org.jetbrains.compose.resources.ExperimentalResourceApi
|
|||
class BankingService(
|
||||
private val uiState: UiState,
|
||||
private val uiSettings: UiSettings,
|
||||
private val uiService: UiService,
|
||||
private val bankingRepository: BankingRepository,
|
||||
private val bankFinder: BankFinder
|
||||
) {
|
||||
|
||||
private val preferredTanMethods = TanMethodType.NonVisualOrImageBasedOrFlickerCode
|
||||
|
||||
private val client = FinTs4kBankingClient(FinTsClientOptions(true, closeDialogs = false), SimpleBankingClientCallback { tanChallenge, callback ->
|
||||
uiState.receivedTanChallenge(tanChallenge, callback)
|
||||
})
|
||||
|
@ -93,6 +98,22 @@ class BankingService(
|
|||
))
|
||||
|
||||
|
||||
fun getImageSettingsOrCreateDefault(id: String, defaultHeight: Int): ImageSettings =
|
||||
bankingRepository.getImageSettings(id) ?: ImageSettings(id, defaultHeight)
|
||||
|
||||
fun saveImageSettingsDebounced(settings: ImageSettings, coroutineScope: CoroutineScope) {
|
||||
uiService.debounce(coroutineScope, 1_000) {
|
||||
saveImageSettings(settings)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveImageSettings(settings: ImageSettings) = try {
|
||||
bankingRepository.saveImageSettings(settings)
|
||||
} catch (e: Throwable) {
|
||||
log.error(e) { "Could not save ImageSettings ${settings.id}"}
|
||||
}
|
||||
|
||||
|
||||
fun getAllBanks() = bankingRepository.getAllBanks()
|
||||
|
||||
suspend fun updateBank(bank: BankAccessEntity, loginName: String, password: String, bankName: String?) {
|
||||
|
@ -167,7 +188,9 @@ class BankingService(
|
|||
suspend fun addAccount(bank: BankInfo, loginName: String, password: String, retrieveAllTransactions: Boolean = false): Boolean {
|
||||
try {
|
||||
val retrieveTransactions = if (retrieveAllTransactions) RetrieveTransactions.All else RetrieveTransactions.OfLast90Days
|
||||
val response = client.getAccountDataAsync(GetAccountDataRequest(bank.domesticBankCode, loginName, password, GetAccountDataOptions(retrieveTransactions), mapBankInfo(bank)))
|
||||
val options = GetAccountDataOptions(retrieveTransactions, preferredTanMethods = preferredTanMethods)
|
||||
|
||||
val response = client.getAccountDataAsync(GetAccountDataRequest(bank.domesticBankCode, loginName, password, options, mapBankInfo(bank)))
|
||||
|
||||
if (response.type == ResponseType.Success && response.data != null) {
|
||||
handleSuccessfulGetAccountDataResponse(response.data!!)
|
||||
|
@ -231,7 +254,7 @@ class BankingService(
|
|||
|
||||
private suspend fun updateAccountTransactions(bank: BankAccessEntity, bankAccount: BankAccountEntity? = null) {
|
||||
try {
|
||||
val response = client.updateAccountTransactionsAsync(bank, bankAccount?.let { listOf(it) })
|
||||
val response = client.updateAccountTransactionsAsync(bank, bankAccount?.let { listOf(it) }, preferredTanMethods)
|
||||
|
||||
handleCommonBankingClientResponseValues(response)
|
||||
|
||||
|
@ -401,7 +424,8 @@ class BankingService(
|
|||
bank, account,
|
||||
recipientName, recipientAccountIdentifier, recipientBankIdentifier,
|
||||
amount, "EUR",
|
||||
paymentReference, instantTransfer
|
||||
paymentReference, instantTransfer,
|
||||
preferredTanMethods
|
||||
))
|
||||
|
||||
handleCommonBankingClientResponseValues(response)
|
||||
|
|
|
@ -4,9 +4,9 @@ import kotlinx.coroutines.*
|
|||
|
||||
class UiService {
|
||||
|
||||
fun debounce(coroutineScope: CoroutineScope, action: () -> Unit): Job {
|
||||
fun debounce(coroutineScope: CoroutineScope, delayMillis: Long = 250, action: suspend () -> Unit): Job {
|
||||
return coroutineScope.launch {
|
||||
delay(250)
|
||||
delay(delayMillis)
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
kotlin = "2.0.10"
|
||||
kotlinx-coroutines = "1.8.1"
|
||||
|
||||
banking-client = "0.7.0"
|
||||
banking-client = "0.7.1"
|
||||
epcqrcode = "0.5.0"
|
||||
|
||||
kcsv = "2.2.0"
|
||||
|
|
Loading…
Reference in New Issue