Added ddAccountDialog and started AccountsView

This commit is contained in:
dankl 2020-01-08 20:36:56 +01:00 committed by dankito
parent fb70a4176d
commit d7bdd1ae51
6 changed files with 337 additions and 6 deletions

View File

@ -2,13 +2,12 @@ package net.dankito.banking.javafx.dialogs.mainwindow
import net.dankito.banking.fints4javaBankingClientCreator
import net.dankito.banking.ui.javafx.RouterJavaFx
import net.dankito.banking.ui.javafx.controls.AccountsView
import net.dankito.banking.ui.javafx.dialogs.mainwindow.controls.MainMenuBar
import net.dankito.banking.ui.javafx.util.Base64ServiceJava8
import net.dankito.banking.ui.presenter.MainWindowPresenter
import tornadofx.*
import tornadofx.FX.Companion.messages
import tornadofx.View
import tornadofx.borderpane
import tornadofx.get
class MainWindow : View(messages["main.window.title"]) {
@ -16,12 +15,23 @@ class MainWindow : View(messages["main.window.title"]) {
private val presenter = MainWindowPresenter(fints4javaBankingClientCreator(), Base64ServiceJava8(), RouterJavaFx())
private var accountsView = AccountsView(presenter)
override val root = borderpane {
prefHeight = 620.0
prefWidth = 1150.0
top = MainMenuBar().root
center {
splitpane {
setDividerPosition(0, 0.2)
add(accountsView)
}
}
}
}

View File

@ -1,4 +1,26 @@
main.window.title=Banking
main.window.menu.file=File
main.window.menu.file.quit=Quit
main.window.menu.file.quit=Quit
ok=OK
cancel=Cancel
close=Close
accounts=Accounts
check=Check
accounts.view.context.menu.info=Info
add.account.dialog.title=Add account
add.account.dialog.bank.code.label=Bank code
add.account.dialog.customer.id.and.password.hint=Enter the same values here as in your online banking portal
add.account.dialog.customer.id=Customer Id (Account number)
add.account.dialog.customer.id.hint=The user name you use for logging in into online banking
add.account.dialog.password=Online banking password
add.account.dialog.password.hint=The password you use for logging in into online banking
add.account.dialog.could.not.add.account=Could not add account for bank code '%s' and customer id '%s': %s
add.account.dialog.add.account.success=Successfully added accounterror.message.could.not.retrieve.accounting.entries=Could not get entries for account '%s': %s

View File

@ -1,4 +1,26 @@
main.window.title=Banking
main.window.menu.file=Datei
main.window.menu.file.quit=Beenden
main.window.menu.file.quit=Beenden
ok=OK
cancel=Abbrechen
close=Schließen
accounts=Konten
check=Überprüfen
accounts.view.context.menu.info=Info
add.account.dialog.title=Konto hinzufügen
add.account.dialog.bank.code.label=Bankleitzahl
add.account.dialog.customer.id.and.password.hint=Geben Sie hier die selben Werte ein wie auf Ihrer Online Banking Webseite
add.account.dialog.customer.id=Kundennummer (Kontonummer)
add.account.dialog.customer.id.hint=Der Nutzernamen den Sie fürs Online Banking verwenden
add.account.dialog.password=Online Banking Passwort
add.account.dialog.password.hint=Das Passwort das Sie fürs Online Banking verwenden
add.account.dialog.could.not.add.account=Konnte Kontoinformation zu Bankleitzahl '%s' und Nutzername '%s' nicht finden: %s
add.account.dialog.add.account.success=Hinzufügen des Kontos war erfolgreich.

View File

@ -1,18 +1,21 @@
package net.dankito.banking.ui.javafx
import net.dankito.banking.ui.IRouter
import net.dankito.banking.ui.javafx.dialogs.AddAccountDialog
import net.dankito.banking.ui.model.Account
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
import net.dankito.banking.ui.model.tan.EnterTanResult
import net.dankito.banking.ui.model.tan.TanChallenge
import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
import net.dankito.banking.ui.presenter.MainWindowPresenter
import tornadofx.FX.Companion.messages
import tornadofx.get
open class RouterJavaFx : IRouter {
override fun showAddAccountDialog(presenter: MainWindowPresenter) {
AddAccountDialog(presenter).show(messages["add.account.dialog.title"])
}
override fun getTanFromUserFromNonUiThread(account: Account, tanChallenge: TanChallenge, presenter: MainWindowPresenter): EnterTanResult {

View File

@ -0,0 +1,43 @@
package net.dankito.banking.ui.javafx.controls
import javafx.geometry.Pos
import net.dankito.banking.ui.presenter.MainWindowPresenter
import net.dankito.utils.javafx.ui.extensions.fixedHeight
import net.dankito.utils.javafx.ui.extensions.fixedWidth
import tornadofx.*
open class AccountsView(protected val presenter: MainWindowPresenter) : View() {
override val root = vbox {
borderpane {
fixedHeight = 36.0
left = label(messages["accounts"]) {
borderpaneConstraints {
alignment = Pos.CENTER_LEFT
marginLeft = 4.0
}
}
right = button("+") {
fixedHeight = 32.0
fixedWidth = 32.0
action { showAddAccountDialog() }
borderpaneConstraints {
alignment = Pos.CENTER_RIGHT
marginTopBottom(2.0)
}
}
}
}
private fun showAddAccountDialog() {
presenter.showAddAccountDialog()
}
}

View File

@ -0,0 +1,231 @@
package net.dankito.banking.ui.javafx.dialogs
import javafx.beans.property.SimpleBooleanProperty
import javafx.beans.property.SimpleStringProperty
import javafx.geometry.Insets
import javafx.geometry.Pos
import javafx.scene.control.Tooltip
import javafx.scene.paint.Color
import javafx.scene.text.Font
import javafx.scene.text.FontWeight
import net.dankito.banking.ui.model.responses.AddAccountResponse
import net.dankito.banking.ui.presenter.MainWindowPresenter
import net.dankito.fints.model.BankInfo
import net.dankito.utils.javafx.ui.controls.UpdateButton
import net.dankito.utils.javafx.ui.dialogs.Window
import net.dankito.utils.javafx.ui.extensions.ensureOnlyUsesSpaceIfVisible
import net.dankito.utils.javafx.ui.extensions.setBackgroundToColor
import tornadofx.*
open class AddAccountDialog(protected val presenter: MainWindowPresenter) : Window() {
companion object {
private val LabelMargins = Insets(6.0, 4.0, 6.0, 4.0)
private val TextFieldHeight = 36.0
private val TextFieldMargins = Insets(0.0, 4.0, 12.0, 4.0)
private val ButtonHeight = 40.0
private val ButtonWidth = 150.0
}
private val bankCode = SimpleStringProperty("")
protected var selectedBank: BankInfo? = null
private val customerId = SimpleStringProperty("")
private val password = SimpleStringProperty("")
private val requiredDataHasBeenEntered = SimpleBooleanProperty(false)
private val checkEnteredCredentialsResult = SimpleStringProperty("")
private val isEnteredCredentialsResultVisible = SimpleBooleanProperty(false)
private val didEnteredCredentialsMatch = SimpleBooleanProperty(false)
private val checkCredentialsButton = UpdateButton(messages["check"])
init {
bankCode.addListener { _, _, newValue -> checkIsEnteredBankCodeValid(newValue) }
customerId.addListener { _, _, _ -> checkIfRequiredDataHasBeenEntered() }
password.addListener { _, _, _ -> checkIfRequiredDataHasBeenEntered() }
}
override val root = vbox {
prefWidth = 350.0
label(messages["add.account.dialog.bank.code.label"]) {
vboxConstraints {
margin = LabelMargins
}
}
textfield(bankCode) {
prefHeight = TextFieldHeight
vboxConstraints {
margin = TextFieldMargins
}
}
label(messages["add.account.dialog.customer.id.and.password.hint"]) {
font = Font.font(this.font.name, FontWeight.BOLD, this.font.size + 1)
isWrapText = true
vboxConstraints {
marginTop = 12.0
marginBottom = 6.0
}
}
label(messages["add.account.dialog.customer.id"]) {
vboxConstraints {
margin = LabelMargins
}
}
textfield(customerId) {
promptText = messages["add.account.dialog.customer.id.hint"]
prefHeight = TextFieldHeight
vboxConstraints {
margin = TextFieldMargins
}
}
label(messages["add.account.dialog.password"]) {
vboxConstraints {
margin = LabelMargins
}
}
passwordfield(password) {
promptText = messages["add.account.dialog.password.hint"]
prefHeight = TextFieldHeight
vboxConstraints {
margin = TextFieldMargins
}
}
label(checkEnteredCredentialsResult) {
visibleWhen(isEnteredCredentialsResultVisible)
ensureOnlyUsesSpaceIfVisible()
isWrapText = true
font = Font(font.size + 1)
paddingAll = 8.0
checkEnteredCredentialsResult.addListener { _, _, _ ->
if (didEnteredCredentialsMatch.value) {
setBackgroundToColor(Color.TRANSPARENT)
}
else {
setBackgroundToColor(Color.RED)
}
tooltip = Tooltip(checkEnteredCredentialsResult.value)
currentWindow?.sizeToScene()
}
vboxConstraints {
marginTop = 12.0
marginBottom = 6.0
}
}
hbox {
alignment = Pos.CENTER_RIGHT
button(messages["cancel"]) {
prefHeight = ButtonHeight
prefWidth = ButtonWidth
isCancelButton = true
action { close() }
hboxConstraints {
margin = Insets(6.0, 0.0, 4.0, 0.0)
}
}
add(checkCredentialsButton.apply {
prefHeight = ButtonHeight
prefWidth = ButtonWidth
isDefaultButton = true
enableWhen(requiredDataHasBeenEntered)
action { checkEnteredCredentials() }
hboxConstraints {
margin = Insets(6.0, 4.0, 4.0, 12.0)
}
})
}
}
protected open fun checkIsEnteredBankCodeValid(enteredBankCode: String?) {
enteredBankCode?.let {
val banksSearchResult = presenter.searchBanksByNameBankCodeOrCity(enteredBankCode)
// TODO: show banksSearchResult in AutoCompleteListView
val uniqueBankCodes = banksSearchResult.map { it.bankCode }.toSet()
selectedBank = if (uniqueBankCodes.size == 1) banksSearchResult.first() else null
checkIfRequiredDataHasBeenEntered()
}
}
protected open fun checkIfRequiredDataHasBeenEntered() {
requiredDataHasBeenEntered.value = selectedBank != null
&& selectedBank?.supportsFinTs3_0 == true
&& customerId.value.isNotEmpty() // TODO: check if it is of length 10?
&& password.value.isNotEmpty() // TODO: check if it is of length 5?
}
protected open fun checkEnteredCredentials() {
selectedBank?.let {
presenter.addAccountAsync(it, customerId.value, password.value) { response ->
runLater { handleAddAccountResultOnUiThread(response) }
}
}
}
protected open fun handleAddAccountResultOnUiThread(response: AddAccountResponse) {
isEnteredCredentialsResultVisible.value = true
didEnteredCredentialsMatch.value = response.isSuccessful
val account = response.account
// TODO: in case of success show alert to ask if account transactions should get retrieved?
val message = if (response.isSuccessful) messages["add.account.dialog.add.account.success"]
else String.format(messages["add.account.dialog.could.not.add.account"],
account.bank.bankCode, account.customerId, response.errorToShowToUser)
checkEnteredCredentialsResult.value = message
if (response.isSuccessful) {
close()
}
}
}