Implemented changing TAN procedure and TAN medium
This commit is contained in:
parent
ce58ef60ca
commit
b0ee9bb0d5
|
@ -28,6 +28,11 @@ add.account.dialog.successfully.added.account.bank.supports.retrieving.transacti
|
||||||
|
|
||||||
|
|
||||||
enter.tan.dialog.title=TAN required
|
enter.tan.dialog.title=TAN required
|
||||||
|
enter.tan.dialog.select.tan.procedure=TAN procedure:
|
||||||
|
enter.tan.dialog.select.tan.medium=TAN medium:
|
||||||
enter.tan.dialog.size.label=Size:
|
enter.tan.dialog.size.label=Size:
|
||||||
enter.tan.dialog.frequency.label=Speed:
|
enter.tan.dialog.frequency.label=Speed:
|
||||||
enter.tan.dialog.enter.tan.label=TAN:
|
enter.tan.dialog.enter.tan.label=TAN:
|
||||||
|
enter.tan.dialog.error.could.not.decode.tan.image=Could not decode flicker code or QR code / PhotoTan. Most likely an internal error:\n%s.
|
||||||
|
enter.tan.dialog.tan.medium.successfully.changed=TAN medium successfully changed to \'%s\'.
|
||||||
|
enter.tan.dialog.tan.error.changing.tan.medium=Could not change TAN medium to \'%s\':\n%s.
|
|
@ -28,6 +28,11 @@ add.account.dialog.successfully.added.account.bank.supports.retrieving.transacti
|
||||||
|
|
||||||
|
|
||||||
enter.tan.dialog.title=TAN wird benötigt
|
enter.tan.dialog.title=TAN wird benötigt
|
||||||
|
enter.tan.dialog.select.tan.procedure=TAN Verfahren:
|
||||||
|
enter.tan.dialog.select.tan.medium=TAN Medium:
|
||||||
enter.tan.dialog.size.label=Größe:
|
enter.tan.dialog.size.label=Größe:
|
||||||
enter.tan.dialog.frequency.label=Geschwindigkeit:
|
enter.tan.dialog.frequency.label=Geschwindigkeit:
|
||||||
enter.tan.dialog.enter.tan.label=TAN:
|
enter.tan.dialog.enter.tan.label=TAN:
|
||||||
|
enter.tan.dialog.error.could.not.decode.tan.image=Flickercode bzw. QR-Code / PhotoTan konnte nicht dekodiert werden. Höchst wahrscheinlich ein interner Fehler:\n%s.
|
||||||
|
enter.tan.dialog.tan.medium.successfully.changed=TAN Medium erfolgreich geändert zu \'%s\'.
|
||||||
|
enter.tan.dialog.tan.error.changing.tan.medium=TAN Medium konnte nicht geändert werden zu \'%s\':\n%s.
|
|
@ -21,40 +21,32 @@ import java.io.StringWriter
|
||||||
|
|
||||||
open class JavaFxDialogService {
|
open class JavaFxDialogService {
|
||||||
|
|
||||||
open fun showInfoMessage(infoMessage: CharSequence, alertTitle: CharSequence?) {
|
open fun showInfoMessage(infoMessage: CharSequence, alertTitle: CharSequence? = null, owner: Stage? = FX.primaryStage) {
|
||||||
showInfoMessage(infoMessage, alertTitle, FX.primaryStage)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun showInfoMessage(infoMessage: CharSequence, alertTitle: CharSequence?, owner: Stage?) {
|
|
||||||
Platform.runLater { showInfoMessageOnUiThread(infoMessage, alertTitle, owner) }
|
Platform.runLater { showInfoMessageOnUiThread(infoMessage, alertTitle, owner) }
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun showInfoMessageOnUiThread(infoMessage: CharSequence, alertTitle: CharSequence?, owner: Stage?) {
|
open fun showInfoMessageOnUiThread(infoMessage: CharSequence, alertTitle: CharSequence? = null, owner: Stage? = FX.primaryStage): ButtonType? {
|
||||||
val alert = createDialog(Alert.AlertType.INFORMATION, infoMessage, alertTitle, owner, ButtonType.OK)
|
val dialog = createDialog(Alert.AlertType.INFORMATION, infoMessage, alertTitle, owner, ButtonType.OK)
|
||||||
|
|
||||||
alert.showAndWait()
|
return showAndWaitForResult(dialog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun showErrorMessage(errorMessage: CharSequence, alertTitle: CharSequence?, exception: Exception?) {
|
open fun showErrorMessage(errorMessage: CharSequence, alertTitle: CharSequence? = null, exception: Exception? = null, owner: Stage? = FX.primaryStage) {
|
||||||
showErrorMessage(errorMessage, alertTitle, exception, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun showErrorMessage(errorMessage: CharSequence, alertTitle: CharSequence?, exception: Exception?, owner: Stage?) {
|
|
||||||
Platform.runLater { showErrorMessageOnUiThread(errorMessage, alertTitle, exception, owner) }
|
Platform.runLater { showErrorMessageOnUiThread(errorMessage, alertTitle, exception, owner) }
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun showErrorMessageOnUiThread(errorMessage: CharSequence, alertTitle: CharSequence?, exception: Exception?, owner: Stage?) {
|
open fun showErrorMessageOnUiThread(errorMessage: CharSequence, alertTitle: CharSequence? = null, exception: Exception? = null, owner: Stage? = FX.primaryStage): ButtonType? {
|
||||||
val alert = createDialog(Alert.AlertType.ERROR, errorMessage, alertTitle, owner, ButtonType.OK)
|
val dialog = createDialog(Alert.AlertType.ERROR, errorMessage, alertTitle, owner, ButtonType.OK)
|
||||||
|
|
||||||
if (exception != null) {
|
if (exception != null) {
|
||||||
createExpandableException(alert, exception)
|
createExpandableException(dialog, exception)
|
||||||
}
|
}
|
||||||
|
|
||||||
alert.showAndWait()
|
return showAndWaitForResult(dialog)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun createExpandableException(alert: Alert, exception: Exception) {
|
protected open fun createExpandableException(dialog: Alert, exception: Exception) {
|
||||||
val sw = StringWriter()
|
val sw = StringWriter()
|
||||||
val pw = PrintWriter(sw)
|
val pw = PrintWriter(sw)
|
||||||
exception.printStackTrace(pw)
|
exception.printStackTrace(pw)
|
||||||
|
@ -77,13 +69,17 @@ open class JavaFxDialogService {
|
||||||
expContent.add(textArea, 0, 1)
|
expContent.add(textArea, 0, 1)
|
||||||
|
|
||||||
// Set expandable Exception into the dialog pane.
|
// Set expandable Exception into the dialog pane.
|
||||||
alert.dialogPane.expandableContent = expContent
|
dialog.dialogPane.expandableContent = expContent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun showDialog(alertType: Alert.AlertType, message: CharSequence, alertTitle: CharSequence? = null, owner: Stage? = FX.primaryStage, vararg buttons: ButtonType): ButtonType? {
|
open fun showDialog(alertType: Alert.AlertType, message: CharSequence, alertTitle: CharSequence? = null, owner: Stage? = FX.primaryStage, vararg buttons: ButtonType): ButtonType? {
|
||||||
val dialog = createDialog(alertType, message, alertTitle, owner, *buttons)
|
val dialog = createDialog(alertType, message, alertTitle, owner, *buttons)
|
||||||
|
|
||||||
|
return showAndWaitForResult(dialog)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun showAndWaitForResult(dialog: Alert): ButtonType? {
|
||||||
val result = dialog.showAndWait()
|
val result = dialog.showAndWait()
|
||||||
|
|
||||||
return result.map { it }.orElse(null)
|
return result.map { it }.orElse(null)
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
package net.dankito.banking.ui.javafx.dialogs.tan
|
package net.dankito.banking.ui.javafx.dialogs.tan
|
||||||
|
|
||||||
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.beans.property.SimpleStringProperty
|
import javafx.beans.property.SimpleStringProperty
|
||||||
import javafx.geometry.Insets
|
import javafx.geometry.Insets
|
||||||
import javafx.geometry.Pos
|
import javafx.geometry.Pos
|
||||||
import net.dankito.banking.javafx.dialogs.tan.controls.ChipTanFlickerCodeView
|
import net.dankito.banking.javafx.dialogs.tan.controls.ChipTanFlickerCodeView
|
||||||
|
import net.dankito.banking.ui.javafx.dialogs.JavaFxDialogService
|
||||||
import net.dankito.banking.ui.model.Account
|
import net.dankito.banking.ui.model.Account
|
||||||
import net.dankito.banking.ui.model.tan.EnterTanResult
|
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||||
import net.dankito.banking.ui.model.tan.FlickerCodeTanChallenge
|
import net.dankito.banking.ui.model.tan.*
|
||||||
import net.dankito.banking.ui.model.tan.TanChallenge
|
|
||||||
import net.dankito.banking.ui.presenter.MainWindowPresenter
|
import net.dankito.banking.ui.presenter.MainWindowPresenter
|
||||||
import net.dankito.utils.javafx.ui.dialogs.Window
|
import net.dankito.utils.javafx.ui.dialogs.Window
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
@ -26,22 +27,74 @@ open class EnterTanDialog(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected val dialogService = JavaFxDialogService()
|
||||||
|
|
||||||
|
|
||||||
|
protected val selectedTanProcedure = SimpleObjectProperty<TanProcedure>(account.selectedTanProcedure ?: account.supportedTanProcedures.firstOrNull())
|
||||||
|
|
||||||
|
protected val selectedTanMedium = SimpleObjectProperty<TanMedium>(account.tanMediaSorted.firstOrNull())
|
||||||
|
|
||||||
protected val enteredTan = SimpleStringProperty("")
|
protected val enteredTan = SimpleStringProperty("")
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
selectedTanProcedure.addListener { _, _, newValue ->
|
||||||
|
tanEnteredCallback(EnterTanResult.userAsksToChangeTanProcedure(newValue))
|
||||||
|
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedTanMedium.addListener { _, _, newValue ->
|
||||||
|
if (newValue.status != TanMediumStatus.Used) {
|
||||||
|
tanEnteredCallback(EnterTanResult.userAsksToChangeTanMedium(newValue) { response ->
|
||||||
|
runLater { handleChangeTanMediumResponseOnUiThread(newValue, response) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override val root = vbox {
|
override val root = vbox {
|
||||||
paddingAll = 4.0
|
paddingAll = 4.0
|
||||||
|
|
||||||
(challenge as? FlickerCodeTanChallenge)?.let { flickerCodeTanChallenge ->
|
form {
|
||||||
hbox {
|
fieldset {
|
||||||
alignment = Pos.CENTER
|
field(messages["enter.tan.dialog.select.tan.procedure"]) {
|
||||||
|
combobox(selectedTanProcedure, account.supportedTanProcedures) {
|
||||||
vboxConstraints {
|
cellFormat {
|
||||||
marginLeftRight(30.0)
|
text = it.displayName
|
||||||
marginBottom = 12.0
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add(ChipTanFlickerCodeView(flickerCodeTanChallenge.flickerCode))
|
if (account.tanMediaSorted.isNotEmpty()) {
|
||||||
|
field(messages["enter.tan.dialog.select.tan.medium"]) {
|
||||||
|
combobox(selectedTanMedium, account.tanMediaSorted) {
|
||||||
|
cellFormat {
|
||||||
|
text = it.displayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(challenge as? FlickerCodeTanChallenge)?.let { flickerCodeTanChallenge ->
|
||||||
|
val flickerCode = flickerCodeTanChallenge.flickerCode
|
||||||
|
if (flickerCode.decodingSuccessful) {
|
||||||
|
hbox {
|
||||||
|
alignment = Pos.CENTER
|
||||||
|
|
||||||
|
vboxConstraints {
|
||||||
|
marginLeftRight(30.0)
|
||||||
|
marginBottom = 12.0
|
||||||
|
}
|
||||||
|
|
||||||
|
add(ChipTanFlickerCodeView(flickerCode))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
showDecodingTanChallengeFailedError(flickerCode.decodingError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +163,26 @@ open class EnterTanDialog(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun finishedEnteringTan() {
|
protected open fun showDecodingTanChallengeFailedError(error: Exception?) {
|
||||||
|
dialogService.showErrorMessage(String.format(messages["enter.tan.dialog.error.could.not.decode.tan.image"], error?.localizedMessage),
|
||||||
|
null, error, currentStage)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun handleChangeTanMediumResponseOnUiThread(newUsedTanMedium: TanMedium, response: BankingClientResponse) {
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
dialogService.showInfoMessageOnUiThread(String.format(messages["enter.tan.dialog.tan.medium.successfully.changed"],
|
||||||
|
newUsedTanMedium.displayName), null, currentStage)
|
||||||
|
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dialogService.showErrorMessageOnUiThread(String.format(messages["enter.tan.dialog.tan.error.changing.tan.medium"],
|
||||||
|
newUsedTanMedium.displayName, response.errorToShowToUser), null, response.error, currentStage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected open fun finishedEnteringTan() {
|
||||||
if (enteredTan.value.isNullOrEmpty()) {
|
if (enteredTan.value.isNullOrEmpty()) {
|
||||||
cancelledEnteringTan()
|
cancelledEnteringTan()
|
||||||
}
|
}
|
||||||
|
@ -121,7 +193,7 @@ open class EnterTanDialog(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cancelledEnteringTan() {
|
protected open fun cancelledEnteringTan() {
|
||||||
tanEnteredCallback(EnterTanResult.userDidNotEnterTan())
|
tanEnteredCallback(EnterTanResult.userDidNotEnterTan())
|
||||||
|
|
||||||
close()
|
close()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.dankito.banking.ui.model
|
package net.dankito.banking.ui.model
|
||||||
|
|
||||||
import net.dankito.banking.ui.model.tan.TanMedium
|
import net.dankito.banking.ui.model.tan.TanMedium
|
||||||
|
import net.dankito.banking.ui.model.tan.TanMediumStatus
|
||||||
import net.dankito.banking.ui.model.tan.TanProcedure
|
import net.dankito.banking.ui.model.tan.TanProcedure
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
@ -23,6 +24,9 @@ open class Account(
|
||||||
|
|
||||||
var tanMedia: List<TanMedium> = listOf()
|
var tanMedia: List<TanMedium> = listOf()
|
||||||
|
|
||||||
|
val tanMediaSorted: List<TanMedium>
|
||||||
|
get() = tanMedia.sortedByDescending { it.status == TanMediumStatus.Used }
|
||||||
|
|
||||||
|
|
||||||
val displayName: String
|
val displayName: String
|
||||||
get() = bank.name
|
get() = bank.name
|
||||||
|
|
|
@ -15,13 +15,13 @@ import android.widget.Spinner
|
||||||
import kotlinx.android.synthetic.main.dialog_enter_tan.view.*
|
import kotlinx.android.synthetic.main.dialog_enter_tan.view.*
|
||||||
import kotlinx.android.synthetic.main.view_tan_image.view.*
|
import kotlinx.android.synthetic.main.view_tan_image.view.*
|
||||||
import net.dankito.banking.fints4java.android.R
|
import net.dankito.banking.fints4java.android.R
|
||||||
import net.dankito.banking.ui.presenter.MainWindowPresenter
|
|
||||||
import net.dankito.banking.fints4java.android.ui.adapter.TanMediumAdapter
|
import net.dankito.banking.fints4java.android.ui.adapter.TanMediumAdapter
|
||||||
import net.dankito.banking.fints4java.android.ui.adapter.TanProceduresAdapter
|
import net.dankito.banking.fints4java.android.ui.adapter.TanProceduresAdapter
|
||||||
import net.dankito.banking.fints4java.android.ui.listener.ListItemSelectedListener
|
import net.dankito.banking.fints4java.android.ui.listener.ListItemSelectedListener
|
||||||
import net.dankito.banking.ui.model.Account
|
import net.dankito.banking.ui.model.Account
|
||||||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||||
import net.dankito.banking.ui.model.tan.*
|
import net.dankito.banking.ui.model.tan.*
|
||||||
|
import net.dankito.banking.ui.presenter.MainWindowPresenter
|
||||||
|
|
||||||
|
|
||||||
open class EnterTanDialog : DialogFragment() {
|
open class EnterTanDialog : DialogFragment() {
|
||||||
|
@ -104,7 +104,7 @@ open class EnterTanDialog : DialogFragment() {
|
||||||
protected open fun setupSelectTanMediumView(rootView: View) {
|
protected open fun setupSelectTanMediumView(rootView: View) {
|
||||||
rootView.lytTanMedium.visibility = View.VISIBLE
|
rootView.lytTanMedium.visibility = View.VISIBLE
|
||||||
|
|
||||||
tanMediumAdapter.setItems(account.tanMedia.sortedByDescending { it.status == TanMediumStatus.Used })
|
tanMediumAdapter.setItems(account.tanMediaSorted)
|
||||||
|
|
||||||
rootView.spnTanMedium.adapter = tanMediumAdapter
|
rootView.spnTanMedium.adapter = tanMediumAdapter
|
||||||
rootView.spnTanMedium.onItemSelectedListener = ListItemSelectedListener(tanMediumAdapter) { selectedTanMedium ->
|
rootView.spnTanMedium.onItemSelectedListener = ListItemSelectedListener(tanMediumAdapter) { selectedTanMedium ->
|
||||||
|
@ -131,12 +131,12 @@ open class EnterTanDialog : DialogFragment() {
|
||||||
val flickerCodeView = rootView.flickerCodeView
|
val flickerCodeView = rootView.flickerCodeView
|
||||||
flickerCodeView.visibility = View.VISIBLE
|
flickerCodeView.visibility = View.VISIBLE
|
||||||
|
|
||||||
val flickercode = (tanChallenge as FlickerCodeTanChallenge).flickerCode
|
val flickerCode = (tanChallenge as FlickerCodeTanChallenge).flickerCode
|
||||||
if (flickercode.decodingSuccessful) {
|
if (flickerCode.decodingSuccessful) {
|
||||||
flickerCodeView.setCode(flickercode)
|
flickerCodeView.setCode(flickerCode)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
showDecodingTanChallengeFailedErrorDelayed(flickercode.decodingError)
|
showDecodingTanChallengeFailedErrorDelayed(flickerCode.decodingError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (tanChallenge is ImageTanChallenge) {
|
else if (tanChallenge is ImageTanChallenge) {
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
<string name="dialog_enter_tan_select_tan_procedure">TAN procedure</string>
|
<string name="dialog_enter_tan_select_tan_procedure">TAN procedure</string>
|
||||||
<string name="dialog_enter_tan_select_tan_medium">TAN medium</string>
|
<string name="dialog_enter_tan_select_tan_medium">TAN medium</string>
|
||||||
<string name="dialog_enter_tan_enter_tan">Enter TAN:</string>
|
<string name="dialog_enter_tan_enter_tan">Enter TAN:</string>
|
||||||
<string name="dialog_enter_tan_error_could_not_decode_tan_image">Could not decode QR code / PhotoTan. Most likely an internal error:\n%s.</string>
|
<string name="dialog_enter_tan_error_could_not_decode_tan_image">Could not decode flicker code or QR code / PhotoTan. Most likely an internal error:\n%s.</string>
|
||||||
<string name="dialog_enter_tan_tan_medium_successfully_changed">TAN medium successfully changed to \'%s\'.</string>
|
<string name="dialog_enter_tan_tan_medium_successfully_changed">TAN medium successfully changed to \'%s\'.</string>
|
||||||
<string name="dialog_enter_tan_error_changing_tan_medium">Could not change TAN medium to \'%s\':\n%s.</string>
|
<string name="dialog_enter_tan_error_changing_tan_medium">Could not change TAN medium to \'%s\':\n%s.</string>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue