diff --git a/BankingJavaFxApp/src/main/resources/Messages.properties b/BankingJavaFxApp/src/main/resources/Messages.properties index cfb8e637..3ec4997c 100755 --- a/BankingJavaFxApp/src/main/resources/Messages.properties +++ b/BankingJavaFxApp/src/main/resources/Messages.properties @@ -28,6 +28,11 @@ add.account.dialog.successfully.added.account.bank.supports.retrieving.transacti 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.frequency.label=Speed: -enter.tan.dialog.enter.tan.label=TAN: \ No newline at end of file +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. \ No newline at end of file diff --git a/BankingJavaFxApp/src/main/resources/Messages_de.properties b/BankingJavaFxApp/src/main/resources/Messages_de.properties index 65096090..7f212ff5 100755 --- a/BankingJavaFxApp/src/main/resources/Messages_de.properties +++ b/BankingJavaFxApp/src/main/resources/Messages_de.properties @@ -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.select.tan.procedure=TAN Verfahren: +enter.tan.dialog.select.tan.medium=TAN Medium: enter.tan.dialog.size.label=Größe: enter.tan.dialog.frequency.label=Geschwindigkeit: -enter.tan.dialog.enter.tan.label=TAN: \ No newline at end of file +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. \ No newline at end of file diff --git a/BankingJavaFxControls/src/main/kotlin/net/dankito/banking/ui/javafx/dialogs/JavaFxDialogService.kt b/BankingJavaFxControls/src/main/kotlin/net/dankito/banking/ui/javafx/dialogs/JavaFxDialogService.kt index f6c3e107..b3024794 100755 --- a/BankingJavaFxControls/src/main/kotlin/net/dankito/banking/ui/javafx/dialogs/JavaFxDialogService.kt +++ b/BankingJavaFxControls/src/main/kotlin/net/dankito/banking/ui/javafx/dialogs/JavaFxDialogService.kt @@ -21,40 +21,32 @@ import java.io.StringWriter open class JavaFxDialogService { - open fun showInfoMessage(infoMessage: CharSequence, alertTitle: CharSequence?) { - showInfoMessage(infoMessage, alertTitle, FX.primaryStage) - } - - open fun showInfoMessage(infoMessage: CharSequence, alertTitle: CharSequence?, owner: Stage?) { + open fun showInfoMessage(infoMessage: CharSequence, alertTitle: CharSequence? = null, owner: Stage? = FX.primaryStage) { Platform.runLater { showInfoMessageOnUiThread(infoMessage, alertTitle, owner) } } - open fun showInfoMessageOnUiThread(infoMessage: CharSequence, alertTitle: CharSequence?, owner: Stage?) { - val alert = createDialog(Alert.AlertType.INFORMATION, infoMessage, alertTitle, owner, ButtonType.OK) + open fun showInfoMessageOnUiThread(infoMessage: CharSequence, alertTitle: CharSequence? = null, owner: Stage? = FX.primaryStage): ButtonType? { + 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?) { - showErrorMessage(errorMessage, alertTitle, exception, null) - } - - open fun showErrorMessage(errorMessage: CharSequence, alertTitle: CharSequence?, exception: Exception?, owner: Stage?) { + open fun showErrorMessage(errorMessage: CharSequence, alertTitle: CharSequence? = null, exception: Exception? = null, owner: Stage? = FX.primaryStage) { Platform.runLater { showErrorMessageOnUiThread(errorMessage, alertTitle, exception, owner) } } - open fun showErrorMessageOnUiThread(errorMessage: CharSequence, alertTitle: CharSequence?, exception: Exception?, owner: Stage?) { - val alert = createDialog(Alert.AlertType.ERROR, errorMessage, alertTitle, owner, ButtonType.OK) + open fun showErrorMessageOnUiThread(errorMessage: CharSequence, alertTitle: CharSequence? = null, exception: Exception? = null, owner: Stage? = FX.primaryStage): ButtonType? { + val dialog = createDialog(Alert.AlertType.ERROR, errorMessage, alertTitle, owner, ButtonType.OK) 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 pw = PrintWriter(sw) exception.printStackTrace(pw) @@ -77,13 +69,17 @@ open class JavaFxDialogService { expContent.add(textArea, 0, 1) // 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? { val dialog = createDialog(alertType, message, alertTitle, owner, *buttons) + return showAndWaitForResult(dialog) + } + + protected open fun showAndWaitForResult(dialog: Alert): ButtonType? { val result = dialog.showAndWait() return result.map { it }.orElse(null) diff --git a/BankingJavaFxControls/src/main/kotlin/net/dankito/banking/ui/javafx/dialogs/tan/EnterTanDialog.kt b/BankingJavaFxControls/src/main/kotlin/net/dankito/banking/ui/javafx/dialogs/tan/EnterTanDialog.kt index 4afa5325..7909901f 100644 --- a/BankingJavaFxControls/src/main/kotlin/net/dankito/banking/ui/javafx/dialogs/tan/EnterTanDialog.kt +++ b/BankingJavaFxControls/src/main/kotlin/net/dankito/banking/ui/javafx/dialogs/tan/EnterTanDialog.kt @@ -1,13 +1,14 @@ package net.dankito.banking.ui.javafx.dialogs.tan +import javafx.beans.property.SimpleObjectProperty import javafx.beans.property.SimpleStringProperty import javafx.geometry.Insets import javafx.geometry.Pos 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.tan.EnterTanResult -import net.dankito.banking.ui.model.tan.FlickerCodeTanChallenge -import net.dankito.banking.ui.model.tan.TanChallenge +import net.dankito.banking.ui.model.responses.BankingClientResponse +import net.dankito.banking.ui.model.tan.* import net.dankito.banking.ui.presenter.MainWindowPresenter import net.dankito.utils.javafx.ui.dialogs.Window import tornadofx.* @@ -26,22 +27,74 @@ open class EnterTanDialog( } + protected val dialogService = JavaFxDialogService() + + + protected val selectedTanProcedure = SimpleObjectProperty(account.selectedTanProcedure ?: account.supportedTanProcedures.firstOrNull()) + + protected val selectedTanMedium = SimpleObjectProperty(account.tanMediaSorted.firstOrNull()) + 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 { paddingAll = 4.0 - (challenge as? FlickerCodeTanChallenge)?.let { flickerCodeTanChallenge -> - hbox { - alignment = Pos.CENTER - - vboxConstraints { - marginLeftRight(30.0) - marginBottom = 12.0 + form { + fieldset { + field(messages["enter.tan.dialog.select.tan.procedure"]) { + combobox(selectedTanProcedure, account.supportedTanProcedures) { + cellFormat { + text = it.displayName + } + } } - 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()) { cancelledEnteringTan() } @@ -121,7 +193,7 @@ open class EnterTanDialog( } } - private fun cancelledEnteringTan() { + protected open fun cancelledEnteringTan() { tanEnteredCallback(EnterTanResult.userDidNotEnterTan()) close() diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/Account.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/Account.kt index 47cf3d4a..035dc04b 100644 --- a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/Account.kt +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/Account.kt @@ -1,6 +1,7 @@ package net.dankito.banking.ui.model 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 java.math.BigDecimal @@ -23,6 +24,9 @@ open class Account( var tanMedia: List = listOf() + val tanMediaSorted: List + get() = tanMedia.sortedByDescending { it.status == TanMediumStatus.Used } + val displayName: String get() = bank.name diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt index 9fd3b1e3..9a20b4ba 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt @@ -15,13 +15,13 @@ import android.widget.Spinner import kotlinx.android.synthetic.main.dialog_enter_tan.view.* import kotlinx.android.synthetic.main.view_tan_image.view.* 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.TanProceduresAdapter import net.dankito.banking.fints4java.android.ui.listener.ListItemSelectedListener 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.MainWindowPresenter open class EnterTanDialog : DialogFragment() { @@ -104,7 +104,7 @@ open class EnterTanDialog : DialogFragment() { protected open fun setupSelectTanMediumView(rootView: View) { rootView.lytTanMedium.visibility = View.VISIBLE - tanMediumAdapter.setItems(account.tanMedia.sortedByDescending { it.status == TanMediumStatus.Used }) + tanMediumAdapter.setItems(account.tanMediaSorted) rootView.spnTanMedium.adapter = tanMediumAdapter rootView.spnTanMedium.onItemSelectedListener = ListItemSelectedListener(tanMediumAdapter) { selectedTanMedium -> @@ -131,12 +131,12 @@ open class EnterTanDialog : DialogFragment() { val flickerCodeView = rootView.flickerCodeView flickerCodeView.visibility = View.VISIBLE - val flickercode = (tanChallenge as FlickerCodeTanChallenge).flickerCode - if (flickercode.decodingSuccessful) { - flickerCodeView.setCode(flickercode) + val flickerCode = (tanChallenge as FlickerCodeTanChallenge).flickerCode + if (flickerCode.decodingSuccessful) { + flickerCodeView.setCode(flickerCode) } else { - showDecodingTanChallengeFailedErrorDelayed(flickercode.decodingError) + showDecodingTanChallengeFailedErrorDelayed(flickerCode.decodingError) } } else if (tanChallenge is ImageTanChallenge) { diff --git a/fints4javaAndroidApp/src/main/res/values/strings.xml b/fints4javaAndroidApp/src/main/res/values/strings.xml index ca7ada80..9d67ca18 100644 --- a/fints4javaAndroidApp/src/main/res/values/strings.xml +++ b/fints4javaAndroidApp/src/main/res/values/strings.xml @@ -65,7 +65,7 @@ TAN procedure TAN medium Enter TAN: - Could not decode QR code / PhotoTan. Most likely an internal error:\n%s. + Could not decode flicker code or QR code / PhotoTan. Most likely an internal error:\n%s. TAN medium successfully changed to \'%s\'. Could not change TAN medium to \'%s\':\n%s.