diff --git a/src/me/teridax/jcash/Main.java b/src/me/teridax/jcash/Main.java index 7616d32..025f8d5 100644 --- a/src/me/teridax/jcash/Main.java +++ b/src/me/teridax/jcash/Main.java @@ -9,7 +9,6 @@ import javax.swing.*; public class Main { private static Main instance; - private final JFrame window; private Main() { diff --git a/src/me/teridax/jcash/banking/Account.java b/src/me/teridax/jcash/banking/Account.java index 961178c..ec0ded5 100644 --- a/src/me/teridax/jcash/banking/Account.java +++ b/src/me/teridax/jcash/banking/Account.java @@ -9,7 +9,7 @@ public abstract class Account { private final int iban; private final int pin; - private final double balance; + private double balance; public Account(int iban, int pin, double balance) { this.iban = iban; @@ -68,4 +68,17 @@ public abstract class Account { public String getDescription() { return String.format("%s (%s)", iban, getClass().getSimpleName()); } + + public void deposit(double amount) { + this.balance += amount; + } + + @Override + public String toString() { + return String.format("@Account [iban=%d, pin=%d, balance=%.2f]", iban, pin, balance); + } + + public void takeoff(double amount) { + this.balance = Math.max(0, this.balance - amount); + } } diff --git a/src/me/teridax/jcash/banking/Bank.java b/src/me/teridax/jcash/banking/Bank.java index 87a2af2..03b347b 100644 --- a/src/me/teridax/jcash/banking/Bank.java +++ b/src/me/teridax/jcash/banking/Bank.java @@ -1,6 +1,7 @@ package me.teridax.jcash.banking; import java.util.*; +import java.util.regex.Pattern; @SuppressWarnings("unused") public final class Bank { @@ -46,21 +47,20 @@ public final class Bank { } public static String validateBlz(String maybeBlz) { - var builder = new StringBuilder(); - maybeBlz.trim().chars().filter(ch -> Character.isDigit(ch) || Character.isLetter(ch)).forEach(builder::append); - var blz = builder.toString(); + var pattern = Pattern.compile("[\\w\\d-_]+"); + var matcher = pattern.matcher(maybeBlz); - if (blz.isEmpty()) { - throw new IllegalArgumentException("Bank Blz must only contain letters and digits"); - } + if (matcher.find()) + return matcher.group(); - return blz; + throw new IllegalArgumentException("not a valid BLZ: " + maybeBlz); } public Optional getAccount(int iban) { for (var owner : this.accounts.entrySet()) { for (var account : owner.getValue()) { - if (account.getIban() == iban) { + var tmp = account.getIban(); + if (tmp == iban) { return Optional.of(new Profile(owner.getKey(), this, account, getAccountsOfOwner(owner.getKey()))); } } diff --git a/src/me/teridax/jcash/banking/BankingManagementSystem.java b/src/me/teridax/jcash/banking/BankingManagementSystem.java index b09d361..c296c18 100644 --- a/src/me/teridax/jcash/banking/BankingManagementSystem.java +++ b/src/me/teridax/jcash/banking/BankingManagementSystem.java @@ -56,6 +56,6 @@ public final class BankingManagementSystem { } public Optional getBank(String blz) { - return this.banks.stream().filter(b -> !b.getBlz().equals(blz)).findFirst(); + return this.banks.stream().filter(b -> b.getBlz().equals(blz)).findFirst(); } } diff --git a/src/me/teridax/jcash/gui/account/AccountController.java b/src/me/teridax/jcash/gui/account/AccountController.java index 6a5227a..9f9aa07 100644 --- a/src/me/teridax/jcash/gui/account/AccountController.java +++ b/src/me/teridax/jcash/gui/account/AccountController.java @@ -2,6 +2,9 @@ package me.teridax.jcash.gui.account; import me.teridax.jcash.Main; import me.teridax.jcash.banking.Profile; +import me.teridax.jcash.gui.deposit.DepositDialog; +import me.teridax.jcash.gui.takeoff.TakeoffDialog; +import me.teridax.jcash.gui.transfer.TransferDialog; public class AccountController { @@ -25,6 +28,18 @@ public class AccountController { Main.getInstance().logout(); Main.getInstance().popLoginScreen(); }); + + this.view.getDeposit().addActionListener(e -> { + new DepositDialog(profile.getPrimaryAccount(), () -> this.view.setProfile(profile)); + }); + + this.view.getTakeoff().addActionListener(e -> { + new TakeoffDialog(profile.getPrimaryAccount(), () -> this.view.setProfile(profile)); + }); + + this.view.getTransfer().addActionListener(e -> { + new TransferDialog(profile.getPrimaryAccount(), () -> this.view.setProfile(profile)); + }); } public AccountView getView() { diff --git a/src/me/teridax/jcash/gui/deposit/DepositDialog.java b/src/me/teridax/jcash/gui/deposit/DepositDialog.java new file mode 100644 index 0000000..00e9e5b --- /dev/null +++ b/src/me/teridax/jcash/gui/deposit/DepositDialog.java @@ -0,0 +1,17 @@ +package me.teridax.jcash.gui.deposit; + +import me.teridax.jcash.banking.Account; + +public class DepositDialog { + + public DepositDialog(Account account, Runnable onDeposit) { + var view = new DepositView(account); + view.getDeposit().addActionListener(e -> { + account.deposit(view.getAmount()); + onDeposit.run(); + view.dispose(); + }); + view.getCancel().addActionListener(e -> view.dispose()); + view.showDialog(); + } +} diff --git a/src/me/teridax/jcash/gui/deposit/DepositView.java b/src/me/teridax/jcash/gui/deposit/DepositView.java new file mode 100644 index 0000000..7415a92 --- /dev/null +++ b/src/me/teridax/jcash/gui/deposit/DepositView.java @@ -0,0 +1,124 @@ +package me.teridax.jcash.gui.deposit; + +import me.teridax.jcash.banking.Account; + +import javax.swing.*; +import javax.swing.text.NumberFormatter; +import java.awt.*; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; + +public class DepositView { + + private JDialog dialog; + private JButton cancel; + private JButton deposit; + private JFormattedTextField value; + + public DepositView(Account account) { + createComponents(account); + layoutComponents(); + } + + public void showDialog() { + dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); + dialog.setTitle("Deposit money"); + dialog.pack(); + dialog.setResizable(false); + dialog.setLocationRelativeTo(null); + dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } + + private NumberFormatter getNumberFormat() { + var format = NumberFormat.getNumberInstance(Locale.GERMANY); + format.setParseIntegerOnly(false); + format.setMaximumFractionDigits(2); + + var formatter = new NumberFormatter(format); + formatter.setValueClass(Double.class); + formatter.setAllowsInvalid(false); + + return formatter; + } + + private void layoutComponents() { + dialog.getContentPane().setLayout(new GridBagLayout()); + + var c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.CENTER; + c.insets = new Insets(10, 10, 10, 10); + dialog.getContentPane().add(new JLabel("Deposit money"), c); + + c.gridx = 0; + c.gridy = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(new JLabel("Betrag", SwingConstants.RIGHT), c); + + c.gridx = 1; + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(value, c); + + c.gridx = 1; + c.gridy = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(cancel, c); + + c.gridx = 2; + c.gridy = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(deposit, c); + } + + private void createComponents(Account account) { + this.dialog = new JDialog(); + + this.cancel = new JButton("Abbrechen"); + this.deposit = new JButton("Einzahlen"); + this.value = new JFormattedTextField(getNumberFormat()); + + this.dialog.setContentPane(new JPanel(new GridBagLayout())); + } + + public double getAmount() { + if (value.getText().isBlank()) + return 0; + + try { + return NumberFormat.getNumberInstance().parse(value.getText()).doubleValue(); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + public JButton getCancel() { + return cancel; + } + + public JButton getDeposit() { + return deposit; + } + + public void dispose() { + this.dialog.dispose(); + } +} diff --git a/src/me/teridax/jcash/gui/login/LoginController.java b/src/me/teridax/jcash/gui/login/LoginController.java index 8d3ed26..06a614f 100644 --- a/src/me/teridax/jcash/gui/login/LoginController.java +++ b/src/me/teridax/jcash/gui/login/LoginController.java @@ -1,6 +1,5 @@ package me.teridax.jcash.gui.login; -import me.teridax.jcash.banking.Account; import me.teridax.jcash.banking.BankingManagementSystem; import javax.swing.*; @@ -9,8 +8,8 @@ import java.util.Optional; public class LoginController { - private LoginView view; - private LoginData data; + private final LoginView view; + private final LoginData data; private AccountSelectionListener listener; @@ -33,6 +32,7 @@ public class LoginController { return Optional.empty(); } } + private Optional getPin() { try { var iban = this.view.getPin().getPassword(); diff --git a/src/me/teridax/jcash/gui/login/LoginData.java b/src/me/teridax/jcash/gui/login/LoginData.java index e599931..3183c99 100644 --- a/src/me/teridax/jcash/gui/login/LoginData.java +++ b/src/me/teridax/jcash/gui/login/LoginData.java @@ -1,6 +1,5 @@ package me.teridax.jcash.gui.login; -import me.teridax.jcash.banking.Account; import me.teridax.jcash.banking.BankingManagementSystem; import me.teridax.jcash.banking.Profile; diff --git a/src/me/teridax/jcash/gui/login/LoginView.java b/src/me/teridax/jcash/gui/login/LoginView.java index 5b1114f..6d869c0 100644 --- a/src/me/teridax/jcash/gui/login/LoginView.java +++ b/src/me/teridax/jcash/gui/login/LoginView.java @@ -1,18 +1,21 @@ package me.teridax.jcash.gui.login; import javax.swing.*; +import javax.swing.text.NumberFormatter; import java.awt.*; +import java.text.NumberFormat; public class LoginView extends JPanel { - private final JTextField blz; - private final JTextField iban; + private final JFormattedTextField blz; + private final JFormattedTextField iban; private final JPasswordField pin; private final JButton login; public LoginView() { - this.blz = new JTextField("MA2424"); - this.iban = new JTextField("4711"); + this.blz = new JFormattedTextField("MA2424"); + this.iban = new JFormattedTextField(getNumberFormat()); + this.iban.setText("4711"); this.pin = new JPasswordField("1234"); this.login = new JButton("Login"); @@ -41,6 +44,19 @@ public class LoginView extends JPanel { content.add(login, constraints); } + private NumberFormatter getNumberFormat() { + var format = NumberFormat.getIntegerInstance(); + format.setGroupingUsed(false); + + var formatter = new NumberFormatter(format); + formatter.setValueClass(Integer.class); + formatter.setMinimum(0); + formatter.setMaximum(Integer.MAX_VALUE); + formatter.setAllowsInvalid(false); + + return formatter; + } + private void addInputRow(GridBagConstraints constraints, JComponent target, JComponent comp, int row, String name) { constraints.gridwidth = 1; constraints.gridx = 1; @@ -71,5 +87,4 @@ public class LoginView extends JPanel { public JButton getLogin() { return login; } - } diff --git a/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java b/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java new file mode 100644 index 0000000..e53bb25 --- /dev/null +++ b/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java @@ -0,0 +1,17 @@ +package me.teridax.jcash.gui.takeoff; + +import me.teridax.jcash.banking.Account; + +public class TakeoffDialog { + + public TakeoffDialog(Account account, Runnable onDeposit) { + var view = new TakeoffView(account); + view.getDeposit().addActionListener(e -> { + account.takeoff(view.getAmount()); + onDeposit.run(); + view.dispose(); + }); + view.getCancel().addActionListener(e -> view.dispose()); + view.showDialog(); + } +} diff --git a/src/me/teridax/jcash/gui/takeoff/TakeoffView.java b/src/me/teridax/jcash/gui/takeoff/TakeoffView.java new file mode 100644 index 0000000..483ce19 --- /dev/null +++ b/src/me/teridax/jcash/gui/takeoff/TakeoffView.java @@ -0,0 +1,130 @@ +package me.teridax.jcash.gui.takeoff; + +import me.teridax.jcash.banking.Account; + +import javax.swing.*; +import javax.swing.text.NumberFormatter; +import java.awt.*; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; + +import static javax.swing.JOptionPane.ERROR_MESSAGE; +import static javax.swing.JOptionPane.showMessageDialog; + +public class TakeoffView { + + private JDialog dialog; + private JButton cancel; + private JButton deposit; + private JFormattedTextField value; + + public TakeoffView(Account account) { + createComponents(account); + layoutComponents(); + } + + public void showDialog() { + dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); + dialog.setTitle("Deposit money"); + dialog.pack(); + dialog.setResizable(false); + dialog.setLocationRelativeTo(null); + dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } + + private NumberFormatter getNumberFormat(double balance) { + var format = NumberFormat.getNumberInstance(Locale.GERMANY); + format.setParseIntegerOnly(false); + format.setMaximumFractionDigits(2); + + var formatter = new NumberFormatter(format); + formatter.setValueClass(Double.class); + formatter.setAllowsInvalid(true); + formatter.setMaximum(balance); + + return formatter; + } + + private void layoutComponents() { + dialog.getContentPane().setLayout(new GridBagLayout()); + + var c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.CENTER; + c.insets = new Insets(10, 10, 10, 10); + dialog.getContentPane().add(new JLabel("Takeoff money"), c); + + c.gridx = 0; + c.gridy = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(new JLabel("Betrag", SwingConstants.RIGHT), c); + + c.gridx = 1; + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(value, c); + + c.gridx = 1; + c.gridy = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(cancel, c); + + c.gridx = 2; + c.gridy = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(deposit, c); + } + + private void createComponents(Account account) { + this.dialog = new JDialog(); + + this.cancel = new JButton("Abbrechen"); + this.deposit = new JButton("Auszahlen"); + this.value = new JFormattedTextField(getNumberFormat(account.getBalance())); + + this.dialog.setContentPane(new JPanel(new GridBagLayout())); + } + + public double getAmount() { + if (value.getText().isBlank()) { + showMessageDialog(null, "invalid amount", "currency must not be blank", ERROR_MESSAGE); + return 0; + } + + try { + return NumberFormat.getNumberInstance().parse(value.getText()).doubleValue(); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + public JButton getCancel() { + return cancel; + } + + public JButton getDeposit() { + return deposit; + } + + public void dispose() { + this.dialog.dispose(); + } +} diff --git a/src/me/teridax/jcash/gui/transfer/TransferDialog.java b/src/me/teridax/jcash/gui/transfer/TransferDialog.java new file mode 100644 index 0000000..0c56597 --- /dev/null +++ b/src/me/teridax/jcash/gui/transfer/TransferDialog.java @@ -0,0 +1,17 @@ +package me.teridax.jcash.gui.transfer; + +import me.teridax.jcash.banking.Account; + +public class TransferDialog { + + public TransferDialog(Account account, Runnable onDeposit) { + var view = new TransferView(account); + view.getDeposit().addActionListener(e -> { + account.takeoff(view.getAmount()); + onDeposit.run(); + view.dispose(); + }); + view.getCancel().addActionListener(e -> view.dispose()); + view.showDialog(); + } +} diff --git a/src/me/teridax/jcash/gui/transfer/TransferView.java b/src/me/teridax/jcash/gui/transfer/TransferView.java new file mode 100644 index 0000000..f69be5d --- /dev/null +++ b/src/me/teridax/jcash/gui/transfer/TransferView.java @@ -0,0 +1,168 @@ +package me.teridax.jcash.gui.transfer; + +import me.teridax.jcash.banking.Account; + +import javax.swing.*; +import javax.swing.text.NumberFormatter; +import java.awt.*; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; + +import static javax.swing.JOptionPane.ERROR_MESSAGE; +import static javax.swing.JOptionPane.showMessageDialog; + +public class TransferView { + + private JDialog dialog; + private JButton cancel; + private JButton deposit; + private JFormattedTextField iban; + private JFormattedTextField blz; + private JFormattedTextField value; + + public TransferView(Account account) { + createComponents(account); + layoutComponents(); + } + + public void showDialog() { + dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); + dialog.setTitle("Deposit money"); + dialog.pack(); + dialog.setResizable(false); + dialog.setLocationRelativeTo(null); + dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } + + private NumberFormatter getNumberFormat(double balance) { + var format = NumberFormat.getNumberInstance(Locale.GERMANY); + format.setParseIntegerOnly(false); + format.setMaximumFractionDigits(2); + + var formatter = new NumberFormatter(format); + formatter.setValueClass(Double.class); + formatter.setAllowsInvalid(true); + formatter.setMaximum(balance); + + return formatter; + } + + private void layoutComponents() { + dialog.getContentPane().setLayout(new GridBagLayout()); + + var c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.CENTER; + c.insets = new Insets(10, 10, 10, 10); + dialog.getContentPane().add(new JLabel("Takeoff money"), c); + + c.gridx = 0; + c.gridy = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(new JLabel("BLZ", SwingConstants.RIGHT), c); + + c.gridx = 1; + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(blz, c); + + c.gridx = 2; + c.gridy = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(new JLabel("IBAN", SwingConstants.RIGHT), c); + + c.gridx = 3; + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(iban, c); + + c.gridx = 0; + c.gridy = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(new JLabel("Betrag", SwingConstants.RIGHT), c); + + c.gridx = 1; + c.gridy = 2; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(value, c); + + c.gridx = 2; + c.gridy = 3; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(cancel, c); + + c.gridx = 3; + c.gridy = 3; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(deposit, c); + + dialog.getContentPane().add(value, c); + } + + private void createComponents(Account account) { + this.dialog = new JDialog(); + + this.cancel = new JButton("Abbrechen"); + this.deposit = new JButton("Auszahlen"); + this.value = new JFormattedTextField(getNumberFormat(account.getBalance())); + this.iban = new JFormattedTextField(); + this.blz = new JFormattedTextField(); + + this.dialog.setContentPane(new JPanel(new GridBagLayout())); + } + + public double getAmount() { + if (value.getText().isBlank()) { + showMessageDialog(null, "invalid amount", "currency must not be blank", ERROR_MESSAGE); + return 0; + } + + try { + return NumberFormat.getNumberInstance().parse(value.getText()).doubleValue(); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + public JButton getCancel() { + return cancel; + } + + public JButton getDeposit() { + return deposit; + } + + public void dispose() { + this.dialog.dispose(); + } +}