Implemented saving TAN settings like TAN image size and flicker code frequency
This commit is contained in:
parent
3072517eef
commit
e86b17d08b
|
@ -79,8 +79,8 @@ class BankingModule(private val applicationContext: Context) {
|
|||
fun provideBankingPresenter(bankingClientCreator: IBankingClientCreator, bankFinder: IBankFinder,
|
||||
@Named(DatabaseFolderKey) databaseFolder: File, @Named(DataFolderKey) dataFolder: File,
|
||||
persister: IBankingPersistence, bankIconFinder: IBankIconFinder,
|
||||
router: IRouter, threadPool: IThreadPool) : BankingPresenter {
|
||||
return BankingPresenter(bankingClientCreator, bankFinder, databaseFolder, dataFolder, persister, bankIconFinder, router, threadPool)
|
||||
router: IRouter, serializer: ISerializer, threadPool: IThreadPool) : BankingPresenter {
|
||||
return BankingPresenter(bankingClientCreator, bankFinder, databaseFolder, dataFolder, persister, bankIconFinder, router, serializer, threadPool)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package net.dankito.banking.ui.android.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.text.InputType
|
||||
|
@ -13,8 +12,9 @@ import android.widget.Spinner
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import kotlinx.android.synthetic.main.dialog_enter_tan.*
|
||||
import kotlinx.android.synthetic.main.dialog_enter_tan.view.*
|
||||
import kotlinx.android.synthetic.main.view_tan_image.view.*
|
||||
import kotlinx.android.synthetic.main.dialog_enter_tan.view.flickerCodeView
|
||||
import net.dankito.banking.ui.android.R
|
||||
import net.dankito.banking.ui.android.di.BankingComponent
|
||||
import net.dankito.banking.ui.android.adapter.TanMediumAdapter
|
||||
|
@ -30,6 +30,8 @@ import javax.inject.Inject
|
|||
open class EnterTanDialog : DialogFragment() {
|
||||
|
||||
companion object {
|
||||
val QrCodeTanProcedures = listOf(TanProcedureType.ChipTanQrCode, TanProcedureType.QrCode)
|
||||
|
||||
val OpticalTanProcedures = listOf(TanProcedureType.ChipTanFlickercode, TanProcedureType.ChipTanQrCode,
|
||||
TanProcedureType.ChipTanPhotoTanMatrixCode, TanProcedureType.photoTan, TanProcedureType.QrCode)
|
||||
|
||||
|
@ -146,7 +148,7 @@ open class EnterTanDialog : DialogFragment() {
|
|||
|
||||
val flickerCode = (tanChallenge as FlickerCodeTanChallenge).flickerCode
|
||||
if (flickerCode.decodingSuccessful) {
|
||||
flickerCodeView.setCode(flickerCode)
|
||||
flickerCodeView.setCode(flickerCode, presenter.appSettings.flickerCodeSettings)
|
||||
}
|
||||
else {
|
||||
showDecodingTanChallengeFailedErrorDelayed(flickerCode.decodingError)
|
||||
|
@ -157,15 +159,14 @@ open class EnterTanDialog : DialogFragment() {
|
|||
|
||||
val decodedImage = (tanChallenge as ImageTanChallenge).image
|
||||
if (decodedImage.decodingSuccessful) {
|
||||
val bitmap = BitmapFactory.decodeByteArray(decodedImage.imageBytes, 0, decodedImage.imageBytes.size)
|
||||
rootView.imgTanImageView.setImageBitmap(bitmap)
|
||||
rootView.tanImageView.setImage(tanChallenge as ImageTanChallenge, if (isQrTan(tanChallenge)) presenter.appSettings.qrCodeSettings else presenter.appSettings.photoTanSettings)
|
||||
}
|
||||
else {
|
||||
showDecodingTanChallengeFailedErrorDelayed(decodedImage.decodingError)
|
||||
}
|
||||
}
|
||||
|
||||
rootView.edtxtEnteredTan.inputType = InputType.TYPE_CLASS_NUMBER
|
||||
rootView.edtxtEnteredTan.inputType = InputType.TYPE_CLASS_NUMBER // TODO: is this always true that TAN is a number?
|
||||
|
||||
rootView.edtxtEnteredTan.setOnKeyListener { _, keyCode, _ ->
|
||||
if (keyCode == KeyEvent.KEYCODE_ENTER) {
|
||||
|
@ -230,7 +231,33 @@ open class EnterTanDialog : DialogFragment() {
|
|||
|
||||
tanEnteredCallback(result)
|
||||
|
||||
checkIfAppSettingsChanged()
|
||||
|
||||
dismiss()
|
||||
}
|
||||
|
||||
|
||||
protected open fun checkIfAppSettingsChanged() {
|
||||
if (flickerCodeView.didTanProcedureSettingsChange) {
|
||||
presenter.appSettings.flickerCodeSettings = flickerCodeView.tanProcedureSettings
|
||||
|
||||
presenter.appSettingsChanged()
|
||||
}
|
||||
|
||||
if (tanImageView.didTanProcedureSettingsChange) {
|
||||
if (isQrTan(tanChallenge)) {
|
||||
presenter.appSettings.qrCodeSettings = tanImageView.tanProcedureSettings
|
||||
}
|
||||
else {
|
||||
presenter.appSettings.photoTanSettings = tanImageView.tanProcedureSettings
|
||||
}
|
||||
|
||||
presenter.appSettingsChanged()
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun isQrTan(tanChallenge: TanChallenge): Boolean {
|
||||
return QrCodeTanProcedures.contains(tanChallenge.tanProcedure.type)
|
||||
}
|
||||
|
||||
}
|
|
@ -12,21 +12,24 @@ import net.dankito.banking.ui.android.R
|
|||
import net.dankito.banking.ui.model.tan.FlickerCode
|
||||
import net.dankito.banking.ui.util.FlickerCodeAnimator
|
||||
import net.dankito.banking.fints.tan.Bit
|
||||
import net.dankito.banking.ui.model.settings.ITanView
|
||||
import net.dankito.banking.ui.model.settings.TanProcedureSettings
|
||||
import net.dankito.utils.android.extensions.asActivity
|
||||
|
||||
|
||||
open class ChipTanFlickerCodeView @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
) : LinearLayout(context, attrs, defStyleAttr), ITanView {
|
||||
|
||||
companion object {
|
||||
const val FrequencyStepSize = 2
|
||||
const val MinFrequency = 2
|
||||
const val MaxFrequency = 40
|
||||
const val DefaultFrequency = 30
|
||||
|
||||
const val StripesHeightStepSize = 7
|
||||
const val StripesWidthStepSize = 2
|
||||
const val StripesRightMarginStepSize = 1
|
||||
const val SpaceBetweenStripesStepSize = 1
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,13 +51,20 @@ open class ChipTanFlickerCodeView @JvmOverloads constructor(
|
|||
|
||||
protected var stripesHeight = 360
|
||||
protected var stripesWidth = 120
|
||||
protected var stripesMarginRight = 30.0 // set back to 30
|
||||
protected var spaceBetweenStripes = 30
|
||||
|
||||
protected var currentFrequency = 30
|
||||
protected var currentFrequency = DefaultFrequency
|
||||
|
||||
protected var isFlickerCodePaused = false
|
||||
|
||||
|
||||
override var didTanProcedureSettingsChange: Boolean = false
|
||||
protected set
|
||||
|
||||
override var tanProcedureSettings: TanProcedureSettings? = null
|
||||
protected set
|
||||
|
||||
|
||||
init {
|
||||
setupUi(context)
|
||||
}
|
||||
|
@ -82,12 +92,17 @@ open class ChipTanFlickerCodeView @JvmOverloads constructor(
|
|||
|
||||
stripesHeight = stripe1.layoutParams.height
|
||||
stripesWidth = stripe1.layoutParams.width
|
||||
(stripe1.layoutParams as? MarginLayoutParams)?.let { stripesMarginRight = it.rightMargin.toDouble() }
|
||||
(stripe1.layoutParams as? MarginLayoutParams)?.let { spaceBetweenStripes = it.rightMargin }
|
||||
|
||||
tanGeneratorLeftMarker = rootView.findViewById(R.id.tanGeneratorLeftMarker)
|
||||
tanGeneratorRightMarker = rootView.findViewById(R.id.tanGeneratorRightMarker)
|
||||
|
||||
setMarkerPositionAfterStripesLayoutSet()
|
||||
|
||||
tanProcedureSettings?.let {
|
||||
setSize(it.width, it.height, it.space)
|
||||
setFrequency(it.frequency)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,22 +115,30 @@ open class ChipTanFlickerCodeView @JvmOverloads constructor(
|
|||
|
||||
|
||||
open fun decreaseSize() {
|
||||
stripesHeight -= StripesHeightStepSize
|
||||
stripesWidth -= StripesWidthStepSize
|
||||
stripesMarginRight -= StripesRightMarginStepSize
|
||||
|
||||
setWidth(context)
|
||||
setSize(
|
||||
stripesWidth - StripesWidthStepSize,
|
||||
stripesHeight - StripesHeightStepSize,
|
||||
spaceBetweenStripes - SpaceBetweenStripesStepSize
|
||||
)
|
||||
}
|
||||
|
||||
open fun increaseSize() {
|
||||
stripesHeight += StripesHeightStepSize
|
||||
stripesWidth += StripesWidthStepSize
|
||||
stripesMarginRight += StripesRightMarginStepSize
|
||||
|
||||
setWidth(context)
|
||||
setSize(
|
||||
stripesWidth + StripesWidthStepSize,
|
||||
stripesHeight + StripesHeightStepSize,
|
||||
spaceBetweenStripes + SpaceBetweenStripesStepSize
|
||||
)
|
||||
}
|
||||
|
||||
protected open fun setWidth(context: Context) {
|
||||
open fun setSize(width: Int, height: Int, spaceBetweenStripes: Int) {
|
||||
this.stripesWidth = width
|
||||
this.stripesHeight = height
|
||||
this.spaceBetweenStripes = spaceBetweenStripes
|
||||
|
||||
applySize()
|
||||
}
|
||||
|
||||
protected open fun applySize() {
|
||||
allStripes.forEach { stripe ->
|
||||
val params = stripe.layoutParams
|
||||
params.height = stripesHeight
|
||||
|
@ -123,7 +146,7 @@ open class ChipTanFlickerCodeView @JvmOverloads constructor(
|
|||
|
||||
(params as? MarginLayoutParams)?.let { marginParams ->
|
||||
if (marginParams.rightMargin > 0) { // don't set a margin right on fifth stripe
|
||||
marginParams.rightMargin = stripesMarginRight.toInt()
|
||||
marginParams.rightMargin = spaceBetweenStripes
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,6 +156,8 @@ open class ChipTanFlickerCodeView @JvmOverloads constructor(
|
|||
requestLayout()
|
||||
|
||||
setMarkerPositionAfterStripesLayoutSet()
|
||||
|
||||
tanProcedureSettingsChanged()
|
||||
}
|
||||
|
||||
protected open fun setMarkerPositionAfterStripesLayoutSet() {
|
||||
|
@ -148,22 +173,28 @@ open class ChipTanFlickerCodeView @JvmOverloads constructor(
|
|||
|
||||
open fun decreaseFrequency() {
|
||||
if (currentFrequency - FrequencyStepSize >= MinFrequency) {
|
||||
currentFrequency -= FrequencyStepSize
|
||||
|
||||
setFrequency(currentFrequency)
|
||||
setFrequency(currentFrequency - FrequencyStepSize)
|
||||
}
|
||||
}
|
||||
|
||||
open fun increaseFrequency() {
|
||||
if (currentFrequency + FrequencyStepSize <= MaxFrequency) {
|
||||
currentFrequency += FrequencyStepSize
|
||||
|
||||
setFrequency(currentFrequency)
|
||||
setFrequency(currentFrequency + FrequencyStepSize)
|
||||
}
|
||||
}
|
||||
|
||||
open fun setFrequency(frequency: Int) {
|
||||
currentFrequency = frequency
|
||||
|
||||
animator.setFrequency(frequency)
|
||||
|
||||
tanProcedureSettingsChanged()
|
||||
}
|
||||
|
||||
protected open fun tanProcedureSettingsChanged() {
|
||||
tanProcedureSettings = TanProcedureSettings(stripesWidth, stripesHeight, spaceBetweenStripes, currentFrequency)
|
||||
|
||||
didTanProcedureSettingsChange = true // we don't check if settings really changed, it's not that important
|
||||
}
|
||||
|
||||
|
||||
|
@ -181,10 +212,19 @@ open class ChipTanFlickerCodeView @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
|
||||
open fun setCode(flickerCode: FlickerCode) {
|
||||
open fun setCode(flickerCode: FlickerCode, tanProcedureSettings: TanProcedureSettings?) {
|
||||
animator.stop()
|
||||
|
||||
setFrequency(currentFrequency)
|
||||
tanProcedureSettings?.let {
|
||||
setSize(it.width, it.height, it.space)
|
||||
setFrequency(it.frequency)
|
||||
}
|
||||
?: run {
|
||||
setFrequency(DefaultFrequency)
|
||||
}
|
||||
|
||||
this.tanProcedureSettings = tanProcedureSettings
|
||||
this.didTanProcedureSettingsChange = false
|
||||
|
||||
animator.animateFlickerCode(flickerCode) { step ->
|
||||
context.asActivity()?.runOnUiThread {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package net.dankito.banking.ui.android.views
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.BitmapFactory
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.ImageView
|
||||
|
@ -8,11 +9,14 @@ import android.widget.LinearLayout
|
|||
import kotlinx.android.synthetic.main.view_tan_image.view.*
|
||||
import kotlinx.android.synthetic.main.view_tan_image_size_controls.view.*
|
||||
import net.dankito.banking.ui.android.R
|
||||
import net.dankito.banking.ui.model.settings.ITanView
|
||||
import net.dankito.banking.ui.model.settings.TanProcedureSettings
|
||||
import net.dankito.banking.ui.model.tan.ImageTanChallenge
|
||||
|
||||
|
||||
open class TanImageView @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
) : LinearLayout(context, attrs, defStyleAttr), ITanView {
|
||||
|
||||
companion object {
|
||||
const val ChangeSizeStepSizeDp = 10f
|
||||
|
@ -26,6 +30,13 @@ open class TanImageView @JvmOverloads constructor(
|
|||
protected lateinit var imgTanImageView: ImageView
|
||||
|
||||
|
||||
override var didTanProcedureSettingsChange: Boolean = false
|
||||
protected set
|
||||
|
||||
override var tanProcedureSettings: TanProcedureSettings? = null
|
||||
protected set
|
||||
|
||||
|
||||
init {
|
||||
MinHeight = convertDpToPx(context, 150f).toInt()
|
||||
MaxHeight = convertDpToPx(context, 500f).toInt()
|
||||
|
@ -44,6 +55,17 @@ open class TanImageView @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
|
||||
open fun setImage(challenge: ImageTanChallenge, tanProcedureSettings: TanProcedureSettings?) {
|
||||
val decodedImage = challenge.image
|
||||
|
||||
val bitmap = BitmapFactory.decodeByteArray(decodedImage.imageBytes, 0, decodedImage.imageBytes.size)
|
||||
rootView.imgTanImageView.setImageBitmap(bitmap)
|
||||
|
||||
tanProcedureSettings?.let {
|
||||
setWidthAndHeight(it.width)
|
||||
}
|
||||
}
|
||||
|
||||
open fun decreaseSize() {
|
||||
changeSizeBy(ChangeSizeStepSizeDp * -1)
|
||||
}
|
||||
|
@ -56,16 +78,30 @@ open class TanImageView @JvmOverloads constructor(
|
|||
val params = imgTanImageView.layoutParams
|
||||
val newWidthAndHeight = params.height + convertDpToPx(context, changeSizeBy).toInt()
|
||||
|
||||
setWidthAndHeight(newWidthAndHeight)
|
||||
}
|
||||
|
||||
protected open fun setWidthAndHeight(newWidthAndHeight: Int) {
|
||||
if (newWidthAndHeight in MinHeight..MaxHeight) {
|
||||
val params = imgTanImageView.layoutParams
|
||||
|
||||
params.height = newWidthAndHeight
|
||||
params.width = newWidthAndHeight
|
||||
|
||||
imgTanImageView.layoutParams = params // TODO: needed?
|
||||
|
||||
requestLayout()
|
||||
|
||||
tanProcedureSettingsChanged(newWidthAndHeight)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun tanProcedureSettingsChanged(newWidthAndHeight: Int) {
|
||||
tanProcedureSettings = TanProcedureSettings(newWidthAndHeight, newWidthAndHeight)
|
||||
|
||||
didTanProcedureSettingsChange = true // we don't check if settings really changed, it's not that important
|
||||
}
|
||||
|
||||
/**
|
||||
* This method converts dp unit to equivalent pixels, depending on device density.
|
||||
*
|
||||
|
|
|
@ -11,6 +11,7 @@ import net.dankito.banking.ui.model.Account
|
|||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||
import net.dankito.banking.ui.model.tan.*
|
||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||
import net.dankito.utils.extensions.htmlToPlainText
|
||||
import net.dankito.utils.javafx.ui.dialogs.Window
|
||||
import tornadofx.*
|
||||
|
||||
|
@ -23,6 +24,8 @@ open class EnterTanDialog(
|
|||
) : Window() {
|
||||
|
||||
companion object {
|
||||
val QrCodeTanProcedures = listOf(TanProcedureType.ChipTanQrCode, TanProcedureType.QrCode)
|
||||
|
||||
private val ButtonHeight = 40.0
|
||||
private val ButtonWidth = 150.0
|
||||
}
|
||||
|
@ -30,6 +33,10 @@ open class EnterTanDialog(
|
|||
|
||||
protected val dialogService = JavaFxDialogService()
|
||||
|
||||
protected var flickerCodeView: ChipTanFlickerCodeView? = null
|
||||
|
||||
protected var tanImageView: TanImageView? = null
|
||||
|
||||
|
||||
protected val tanProceduresWithoutUnsupported = account.supportedTanProcedures.filterNot { it.type == TanProcedureType.ChipTanUsb } // USB tan generators are not supported
|
||||
|
||||
|
@ -93,7 +100,9 @@ open class EnterTanDialog(
|
|||
marginBottom = 12.0
|
||||
}
|
||||
|
||||
add(ChipTanFlickerCodeView(flickerCode))
|
||||
add(ChipTanFlickerCodeView(flickerCode, presenter.appSettings.flickerCodeSettings).apply {
|
||||
flickerCodeView = this
|
||||
})
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -104,7 +113,8 @@ open class EnterTanDialog(
|
|||
(challenge as? ImageTanChallenge)?.let { imageTanChallenge ->
|
||||
val decodedImage = imageTanChallenge.image
|
||||
if (decodedImage.decodingSuccessful) {
|
||||
add(TanImageView(decodedImage).apply {
|
||||
add(TanImageView(decodedImage, if (isQrTan(challenge)) presenter.appSettings.qrCodeSettings else presenter.appSettings.photoTanSettings).apply {
|
||||
tanImageView = this
|
||||
|
||||
vboxConstraints {
|
||||
marginLeftRight(30.0)
|
||||
|
@ -216,6 +226,8 @@ open class EnterTanDialog(
|
|||
else {
|
||||
tanEnteredCallback(EnterTanResult.userEnteredTan(enteredTan.value))
|
||||
|
||||
checkIfAppSettingsChanged()
|
||||
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
@ -226,4 +238,28 @@ open class EnterTanDialog(
|
|||
close()
|
||||
}
|
||||
|
||||
|
||||
protected open fun checkIfAppSettingsChanged() {
|
||||
if (flickerCodeView?.didTanProcedureSettingsChange == true) {
|
||||
presenter.appSettings.flickerCodeSettings = flickerCodeView?.tanProcedureSettings
|
||||
|
||||
presenter.appSettingsChanged()
|
||||
}
|
||||
|
||||
if (tanImageView?.didTanProcedureSettingsChange == true) {
|
||||
if (isQrTan(challenge)) {
|
||||
presenter.appSettings.qrCodeSettings = tanImageView?.tanProcedureSettings
|
||||
}
|
||||
else {
|
||||
presenter.appSettings.photoTanSettings = tanImageView?.tanProcedureSettings
|
||||
}
|
||||
|
||||
presenter.appSettingsChanged()
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun isQrTan(tanChallenge: TanChallenge): Boolean {
|
||||
return QrCodeTanProcedures.contains(tanChallenge.tanProcedure.type)
|
||||
}
|
||||
|
||||
}
|
|
@ -9,13 +9,18 @@ import net.dankito.banking.ui.util.FlickerCodeAnimator
|
|||
import net.dankito.banking.fints.tan.Bit
|
||||
import net.dankito.banking.javafx.dialogs.tan.controls.ChipTanFlickerCodeStripeView
|
||||
import net.dankito.banking.javafx.dialogs.tan.controls.TanGeneratorMarkerView
|
||||
import net.dankito.banking.ui.model.settings.ITanView
|
||||
import net.dankito.banking.ui.model.settings.TanProcedureSettings
|
||||
import net.dankito.utils.javafx.ui.extensions.fixedHeight
|
||||
import net.dankito.utils.javafx.ui.extensions.fixedWidth
|
||||
import net.dankito.utils.javafx.ui.extensions.setBackgroundToColor
|
||||
import tornadofx.*
|
||||
|
||||
|
||||
open class ChipTanFlickerCodeView(protected val flickerCode: FlickerCode): View() {
|
||||
open class ChipTanFlickerCodeView(
|
||||
protected val flickerCode: FlickerCode,
|
||||
tanProcedureSettings: TanProcedureSettings?
|
||||
): View(), ITanView {
|
||||
|
||||
companion object {
|
||||
const val ChangeSizeStripeHeightStep = 7.0
|
||||
|
@ -26,6 +31,7 @@ open class ChipTanFlickerCodeView(protected val flickerCode: FlickerCode): View(
|
|||
const val MaxFlickerCodeViewWidth = 1000.0 // what is a senseful value?
|
||||
|
||||
const val ChangeFrequencyStep = 5
|
||||
const val DefaultFrequency = 30
|
||||
|
||||
const val IconWidth = 26.0
|
||||
const val IconHeight = 26.0
|
||||
|
@ -34,9 +40,9 @@ open class ChipTanFlickerCodeView(protected val flickerCode: FlickerCode): View(
|
|||
|
||||
protected val flickerCodeLeftRightMargin = SimpleDoubleProperty(31.0)
|
||||
|
||||
protected val stripeHeight = SimpleDoubleProperty(127.0)
|
||||
protected val stripeWidth = SimpleDoubleProperty(42.0)
|
||||
protected val spaceBetweenStripes = SimpleDoubleProperty(10.0)
|
||||
protected val stripesHeight = SimpleDoubleProperty(tanProcedureSettings?.height?.toDouble() ?: 127.0)
|
||||
protected val stripesWidth = SimpleDoubleProperty(tanProcedureSettings?.width?.toDouble() ?: 42.0)
|
||||
protected val spaceBetweenStripes = SimpleDoubleProperty(tanProcedureSettings?.space?.toDouble() ?: 10.0)
|
||||
|
||||
protected val flickerCodeViewWidth = SimpleDoubleProperty()
|
||||
|
||||
|
@ -52,15 +58,22 @@ open class ChipTanFlickerCodeView(protected val flickerCode: FlickerCode): View(
|
|||
protected val isMinFrequencyReached = SimpleBooleanProperty(false)
|
||||
protected val isMaxFrequencyReached = SimpleBooleanProperty(false)
|
||||
|
||||
protected var currentFrequency = 20
|
||||
protected var currentFrequency = tanProcedureSettings?.frequency ?: DefaultFrequency
|
||||
|
||||
protected val animator = FlickerCodeAnimator()
|
||||
|
||||
|
||||
override var didTanProcedureSettingsChange: Boolean = false
|
||||
protected set
|
||||
|
||||
override var tanProcedureSettings: TanProcedureSettings? = tanProcedureSettings
|
||||
protected set
|
||||
|
||||
|
||||
init {
|
||||
flickerCodeViewWidth.bind(stripeWidth.add(spaceBetweenStripes).multiply(4).add(stripeWidth).add(flickerCodeLeftRightMargin).add(flickerCodeLeftRightMargin))
|
||||
flickerCodeViewWidth.bind(stripesWidth.add(spaceBetweenStripes).multiply(4).add(stripesWidth).add(flickerCodeLeftRightMargin).add(flickerCodeLeftRightMargin))
|
||||
|
||||
animator.setFrequency(currentFrequency)
|
||||
setFrequency(currentFrequency)
|
||||
}
|
||||
|
||||
|
||||
|
@ -122,13 +135,13 @@ open class ChipTanFlickerCodeView(protected val flickerCode: FlickerCode): View(
|
|||
add(TanGeneratorMarkerView().apply {
|
||||
setLeftMarkerPosition(this)
|
||||
|
||||
stripeWidth.addListener { _, _, _ -> setLeftMarkerPosition(this) }
|
||||
stripesWidth.addListener { _, _, _ -> setLeftMarkerPosition(this) }
|
||||
})
|
||||
|
||||
add(TanGeneratorMarkerView().apply {
|
||||
setRightMarkerPosition(this)
|
||||
|
||||
stripeWidth.addListener { _, _, _ -> setRightMarkerPosition(this) }
|
||||
stripesWidth.addListener { _, _, _ -> setRightMarkerPosition(this) }
|
||||
})
|
||||
|
||||
vboxConstraints {
|
||||
|
@ -139,11 +152,11 @@ open class ChipTanFlickerCodeView(protected val flickerCode: FlickerCode): View(
|
|||
hbox {
|
||||
minHeight = 150.0
|
||||
|
||||
add(ChipTanFlickerCodeStripeView(stripe1, stripeWidth, stripeHeight, spaceBetweenStripes))
|
||||
add(ChipTanFlickerCodeStripeView(stripe2, stripeWidth, stripeHeight, spaceBetweenStripes))
|
||||
add(ChipTanFlickerCodeStripeView(stripe3, stripeWidth, stripeHeight, spaceBetweenStripes))
|
||||
add(ChipTanFlickerCodeStripeView(stripe4, stripeWidth, stripeHeight, spaceBetweenStripes))
|
||||
add(ChipTanFlickerCodeStripeView(stripe5, stripeWidth, stripeHeight, SimpleDoubleProperty(0.0)))
|
||||
add(ChipTanFlickerCodeStripeView(stripe1, stripesWidth, stripesHeight, spaceBetweenStripes))
|
||||
add(ChipTanFlickerCodeStripeView(stripe2, stripesWidth, stripesHeight, spaceBetweenStripes))
|
||||
add(ChipTanFlickerCodeStripeView(stripe3, stripesWidth, stripesHeight, spaceBetweenStripes))
|
||||
add(ChipTanFlickerCodeStripeView(stripe4, stripesWidth, stripesHeight, spaceBetweenStripes))
|
||||
add(ChipTanFlickerCodeStripeView(stripe5, stripesWidth, stripesHeight, SimpleDoubleProperty(0.0)))
|
||||
}
|
||||
|
||||
vboxConstraints {
|
||||
|
@ -153,6 +166,10 @@ open class ChipTanFlickerCodeView(protected val flickerCode: FlickerCode): View(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
updateMinAndMaxSizeReached()
|
||||
updateMinAndMaxFrequencyReached()
|
||||
|
||||
animator.animateFlickerCode(flickerCode) { step ->
|
||||
runLater {
|
||||
paintFlickerCode(step)
|
||||
|
@ -171,22 +188,23 @@ open class ChipTanFlickerCodeView(protected val flickerCode: FlickerCode): View(
|
|||
|
||||
protected open fun setLeftMarkerPosition(component: UIComponent) {
|
||||
component.root.anchorpaneConstraints {
|
||||
leftAnchor = (stripeWidth.value / 2)
|
||||
leftAnchor = (stripesWidth.value / 2)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun setRightMarkerPosition(component: UIComponent) {
|
||||
component.root.anchorpaneConstraints {
|
||||
rightAnchor = (stripeWidth.value / 2)
|
||||
rightAnchor = (stripesWidth.value / 2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected open fun increaseSize() {
|
||||
if (isMaxSizeReached.value == false) {
|
||||
stripeHeight.value = stripeHeight.value + ChangeSizeStripeHeightStep
|
||||
stripeWidth.value = stripeWidth.value + ChangeSizeStripeWidthStep
|
||||
spaceBetweenStripes.value = spaceBetweenStripes.value + ChangeSizeSpaceBetweenStripesStep
|
||||
setSize(stripesWidth.value + ChangeSizeStripeWidthStep, stripesHeight.value + ChangeSizeStripeHeightStep,
|
||||
spaceBetweenStripes.value + ChangeSizeSpaceBetweenStripesStep)
|
||||
|
||||
tanProcedureSettingsChanged()
|
||||
}
|
||||
|
||||
updateMinAndMaxSizeReached()
|
||||
|
@ -194,16 +212,27 @@ open class ChipTanFlickerCodeView(protected val flickerCode: FlickerCode): View(
|
|||
|
||||
protected open fun decreaseSize() {
|
||||
if (isMinSizeReached.value == false) {
|
||||
stripeHeight.value = stripeHeight.value - ChangeSizeStripeHeightStep
|
||||
stripeWidth.value = stripeWidth.value - ChangeSizeStripeWidthStep
|
||||
spaceBetweenStripes.value = spaceBetweenStripes.value - ChangeSizeSpaceBetweenStripesStep
|
||||
setSize(stripesWidth.value - ChangeSizeStripeWidthStep, stripesHeight.value - ChangeSizeStripeHeightStep,
|
||||
spaceBetweenStripes.value - ChangeSizeSpaceBetweenStripesStep)
|
||||
|
||||
tanProcedureSettingsChanged()
|
||||
}
|
||||
|
||||
updateMinAndMaxSizeReached()
|
||||
}
|
||||
|
||||
open fun setSize(width: Double, height: Double, spaceBetweenStripes: Double) {
|
||||
this.stripesWidth.value = width
|
||||
this.stripesHeight.value = height
|
||||
this.spaceBetweenStripes.value = spaceBetweenStripes
|
||||
|
||||
tanProcedureSettingsChanged()
|
||||
|
||||
updateMinAndMaxSizeReached()
|
||||
}
|
||||
|
||||
protected open fun updateMinAndMaxSizeReached() {
|
||||
val flickerCodeWidth = stripeWidth.value * 5 + spaceBetweenStripes.value * 4
|
||||
val flickerCodeWidth = stripesWidth.value * 5 + spaceBetweenStripes.value * 4
|
||||
|
||||
isMinSizeReached.value = flickerCodeWidth < MinFlickerCodeViewWidth
|
||||
isMaxSizeReached.value = flickerCodeWidth > MaxFlickerCodeViewWidth
|
||||
|
@ -213,8 +242,7 @@ open class ChipTanFlickerCodeView(protected val flickerCode: FlickerCode): View(
|
|||
if (isMaxFrequencyReached.value == false
|
||||
&& (currentFrequency + ChangeFrequencyStep) <= FlickerCodeAnimator.MaxFrequency) {
|
||||
|
||||
currentFrequency += ChangeFrequencyStep
|
||||
animator.setFrequency(currentFrequency)
|
||||
setFrequency(currentFrequency + ChangeFrequencyStep)
|
||||
}
|
||||
|
||||
updateMinAndMaxFrequencyReached()
|
||||
|
@ -224,16 +252,33 @@ open class ChipTanFlickerCodeView(protected val flickerCode: FlickerCode): View(
|
|||
if (isMinFrequencyReached.value == false
|
||||
&& (currentFrequency - ChangeFrequencyStep) >= FlickerCodeAnimator.MinFrequency) {
|
||||
|
||||
currentFrequency -= ChangeFrequencyStep
|
||||
animator.setFrequency(currentFrequency)
|
||||
setFrequency(currentFrequency - ChangeFrequencyStep)
|
||||
}
|
||||
|
||||
updateMinAndMaxFrequencyReached()
|
||||
}
|
||||
|
||||
protected open fun setFrequency(frequency: Int) {
|
||||
currentFrequency = frequency
|
||||
|
||||
animator.setFrequency(currentFrequency)
|
||||
|
||||
updateMinAndMaxFrequencyReached()
|
||||
|
||||
tanProcedureSettingsChanged()
|
||||
}
|
||||
|
||||
protected open fun updateMinAndMaxFrequencyReached() {
|
||||
isMaxFrequencyReached.value = (currentFrequency + ChangeFrequencyStep) > FlickerCodeAnimator.MaxFrequency
|
||||
isMinFrequencyReached.value = (currentFrequency - ChangeFrequencyStep) < FlickerCodeAnimator.MinFrequency
|
||||
}
|
||||
|
||||
|
||||
protected open fun tanProcedureSettingsChanged() {
|
||||
tanProcedureSettings = TanProcedureSettings(stripesWidth.value.toInt(), stripesHeight.value.toInt(),
|
||||
spaceBetweenStripes.value.toInt(), currentFrequency)
|
||||
|
||||
didTanProcedureSettingsChange = true // we don't check if settings really changed, it's not that important
|
||||
}
|
||||
|
||||
}
|
|
@ -4,13 +4,18 @@ import javafx.beans.property.SimpleBooleanProperty
|
|||
import javafx.geometry.Pos
|
||||
import javafx.scene.image.Image
|
||||
import javafx.scene.image.ImageView
|
||||
import net.dankito.banking.ui.model.settings.ITanView
|
||||
import net.dankito.banking.ui.model.settings.TanProcedureSettings
|
||||
import net.dankito.banking.ui.model.tan.TanImage
|
||||
import net.dankito.utils.javafx.ui.extensions.updateWindowSize
|
||||
import tornadofx.*
|
||||
import java.io.ByteArrayInputStream
|
||||
|
||||
|
||||
open class TanImageView(protected val tanImage: TanImage) : View() {
|
||||
open class TanImageView(
|
||||
protected val tanImage: TanImage,
|
||||
tanProcedureSettings: TanProcedureSettings?
|
||||
) : View(), ITanView {
|
||||
|
||||
companion object {
|
||||
private const val ChangeSizeStepSize = 10.0
|
||||
|
@ -29,6 +34,13 @@ open class TanImageView(protected val tanImage: TanImage) : View() {
|
|||
protected var tanImageView: ImageView by singleAssign()
|
||||
|
||||
|
||||
override var didTanProcedureSettingsChange: Boolean = false
|
||||
protected set
|
||||
|
||||
override var tanProcedureSettings: TanProcedureSettings? = tanProcedureSettings
|
||||
protected set
|
||||
|
||||
|
||||
override val root = vbox {
|
||||
add(TanImageSizeView(IconHeight, IconWidth, isMinSizeReached, isMaxSizeReached, { decreaseSize() }, { increaseSize() } ))
|
||||
|
||||
|
@ -45,6 +57,12 @@ open class TanImageView(protected val tanImage: TanImage) : View() {
|
|||
marginBottom = 4.0
|
||||
}
|
||||
}
|
||||
|
||||
tanProcedureSettings?.let {
|
||||
runLater {
|
||||
setWidthAndHeight(it.width.toDouble())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -59,14 +77,26 @@ open class TanImageView(protected val tanImage: TanImage) : View() {
|
|||
protected open fun changeSizeBy(changeSizeBy: Double) {
|
||||
val newWidthAndHeight = tanImageView.fitHeight + changeSizeBy
|
||||
|
||||
setWidthAndHeight(newWidthAndHeight)
|
||||
}
|
||||
|
||||
protected open fun setWidthAndHeight(newWidthAndHeight: Double) {
|
||||
if (newWidthAndHeight in MinHeight..MaxHeight) {
|
||||
tanImageView.fitHeight = newWidthAndHeight
|
||||
|
||||
updateWindowSize()
|
||||
|
||||
tanProcedureSettingsChanged(newWidthAndHeight.toInt())
|
||||
}
|
||||
|
||||
isMinSizeReached.value = tanImageView.fitHeight <= MinHeight
|
||||
isMaxSizeReached.value = tanImageView.fitHeight >= MaxHeight
|
||||
}
|
||||
|
||||
protected open fun tanProcedureSettingsChanged(newWidthAndHeight: Int) {
|
||||
tanProcedureSettings = TanProcedureSettings(newWidthAndHeight, newWidthAndHeight)
|
||||
|
||||
didTanProcedureSettingsChange = true // we don't check if settings really changed, it's not that important
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package net.dankito.banking.ui.model.settings
|
||||
|
||||
|
||||
open class AppSettings(
|
||||
var flickerCodeSettings: TanProcedureSettings? = null,
|
||||
var qrCodeSettings: TanProcedureSettings? = null,
|
||||
var photoTanSettings: TanProcedureSettings? = null
|
||||
) {
|
||||
|
||||
internal constructor() : this(null, null, null) // for object deserializers
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package net.dankito.banking.ui.model.settings
|
||||
|
||||
|
||||
interface ITanView {
|
||||
|
||||
val didTanProcedureSettingsChange: Boolean
|
||||
|
||||
val tanProcedureSettings: TanProcedureSettings?
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package net.dankito.banking.ui.model.settings
|
||||
|
||||
|
||||
open class TanProcedureSettings(
|
||||
var width: Int,
|
||||
var height: Int,
|
||||
var space: Int = -1, // only needed for flicker code view
|
||||
var frequency: Int = -1 // only needed for flicker code view
|
||||
) {
|
||||
|
||||
internal constructor() : this(0, 0) // for object deserializers
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return "Size $width x $height, frequency $frequency"
|
||||
}
|
||||
|
||||
}
|
|
@ -17,10 +17,13 @@ import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
|
|||
import net.dankito.banking.util.IBankIconFinder
|
||||
import net.dankito.banking.fints.banks.IBankFinder
|
||||
import net.dankito.banking.fints.model.BankInfo
|
||||
import net.dankito.banking.ui.model.settings.AppSettings
|
||||
import net.dankito.utils.IThreadPool
|
||||
import net.dankito.utils.ThreadPool
|
||||
import net.dankito.utils.extensions.containsExactly
|
||||
import net.dankito.utils.extensions.ofMaxLength
|
||||
import net.dankito.utils.serialization.ISerializer
|
||||
import net.dankito.utils.serialization.JacksonJsonSerializer
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
@ -39,6 +42,7 @@ open class BankingPresenter(
|
|||
protected val persister: IBankingPersistence,
|
||||
protected val bankIconFinder: IBankIconFinder,
|
||||
protected val router: IRouter,
|
||||
protected val serializer: ISerializer = JacksonJsonSerializer(),
|
||||
protected val threadPool: IThreadPool = ThreadPool()
|
||||
) {
|
||||
|
||||
|
@ -93,6 +97,7 @@ open class BankingPresenter(
|
|||
|
||||
init {
|
||||
threadPool.runAsync {
|
||||
readAppSettings()
|
||||
readPersistedAccounts()
|
||||
}
|
||||
|
||||
|
@ -543,6 +548,36 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
|
||||
var appSettings: AppSettings = AppSettings()
|
||||
protected set
|
||||
|
||||
open fun appSettingsChanged() {
|
||||
persistAppSettings()
|
||||
}
|
||||
|
||||
protected open fun persistAppSettings() {
|
||||
try {
|
||||
serializer.serializeObject(appSettings, getAppSettingsFile())
|
||||
} catch (e: Exception) {
|
||||
log.error("Could not persist AppSettings to file ${getAppSettingsFile()}", e)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun readAppSettings() {
|
||||
try {
|
||||
serializer.deserializeObject(getAppSettingsFile(), AppSettings::class.java)?.let {
|
||||
appSettings = it
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
log.error("Could not read AppSettings from file ${getAppSettingsFile()}", e)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun getAppSettingsFile(): File {
|
||||
return File(dataFolder, "app_settings.json")
|
||||
}
|
||||
|
||||
|
||||
open fun addAccountsChangedListener(listener: (List<Account>) -> Unit): Boolean {
|
||||
return accountsChangedListeners.add(listener)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue