Implemented saving Image (and FlickerCode) settings
This commit is contained in:
parent
166219d7e3
commit
a5b4540443
|
@ -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,9 @@
|
|||
|
||||
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
|
||||
);
|
|
@ -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 (?, ?, ?);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -9,11 +9,16 @@ 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,
|
||||
|
@ -22,11 +27,19 @@ fun ImageView(
|
|||
textColor: Color = Colors.MaterialThemeTextColor,
|
||||
) {
|
||||
|
||||
var imageHeight by remember { mutableStateOf(initialImageHeight) }
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -147,7 +147,8 @@ fun EnterTanDialog(tanChallengeReceived: TanChallengeReceived, onDismiss: () ->
|
|||
tanImage.imageBytesBase64?.let { imageBytesBase64 ->
|
||||
val imageBytes = Base64.decode(imageBytesBase64)
|
||||
|
||||
ImageView(imageBytes, "Bild mit enkodierter TAN", 250, 100, 500, textColor = textColor)
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ 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 {
|
||||
ImageView(epcQrCodeBytes!!, "Erzeugter EPC QR Code", 350, 100, 700)
|
||||
ImageView(epcQrCodeBytes!!, "EpcQrCode", "Erzeugter EPC QR Code", 350, 100, 700)
|
||||
|
||||
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))
|
||||
|
|
|
@ -28,6 +28,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,6 +40,7 @@ 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
|
||||
) {
|
||||
|
@ -93,6 +95,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?) {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue