added some javadoc
This commit is contained in:
parent
88deb75ed7
commit
2fd1fc2b22
|
@ -22,12 +22,20 @@ public final class Main {
|
||||||
*/
|
*/
|
||||||
private static Main instance;
|
private static Main instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Primary class for controlling GUI of this application
|
||||||
|
*/
|
||||||
private final MainFrame window;
|
private final MainFrame window;
|
||||||
|
|
||||||
private Main() {
|
private Main() {
|
||||||
this.window = new MainFrame();
|
this.window = new MainFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user a dialog to select a file to load the database from.
|
||||||
|
* If a valid database has been read a login screen will be shown.
|
||||||
|
* If no file was selected or the database was invalid the application will close.
|
||||||
|
*/
|
||||||
public void loadDatabase() {
|
public void loadDatabase() {
|
||||||
try {
|
try {
|
||||||
var bms = Loader.load();
|
var bms = Loader.load();
|
||||||
|
@ -131,6 +139,11 @@ public final class Main {
|
||||||
return this.window.getWindow();
|
return this.window.getWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs the user out of the currently open account.
|
||||||
|
* This will show the login mask and clear the password field or the previous
|
||||||
|
* login attempt.
|
||||||
|
*/
|
||||||
public void logout() {
|
public void logout() {
|
||||||
this.window.logout();
|
this.window.logout();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ public class StringDecoder {
|
||||||
return NumberFormat.getInstance(Locales.getDefaultLocale());
|
return NumberFormat.getInstance(Locales.getDefaultLocale());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a NumberFormatter for parsing double values in the appropriate locale.
|
||||||
|
* @return the number formatter
|
||||||
|
*/
|
||||||
public static NumberFormatter getNumberFormatter(double maxValue) {
|
public static NumberFormatter getNumberFormatter(double maxValue) {
|
||||||
var formatter = new NumberFormatter();
|
var formatter = new NumberFormatter();
|
||||||
formatter.setValueClass(Double.class);
|
formatter.setValueClass(Double.class);
|
||||||
|
@ -29,7 +33,11 @@ public class StringDecoder {
|
||||||
return formatter;
|
return formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object getIntegerNumberFormatter() {
|
/**
|
||||||
|
* Returns a NumberFormatter for parsing integer values in the appropriate locale.
|
||||||
|
* @return the number formatter
|
||||||
|
*/
|
||||||
|
public static NumberFormatter getIntegerNumberFormatter() {
|
||||||
var formatter = new NumberFormatter();
|
var formatter = new NumberFormatter();
|
||||||
formatter.setValueClass(Integer.class);
|
formatter.setValueClass(Integer.class);
|
||||||
formatter.setMinimum(0d);
|
formatter.setMinimum(0d);
|
||||||
|
|
|
@ -7,14 +7,28 @@ import java.util.Objects;
|
||||||
|
|
||||||
import static me.teridax.jcash.Logging.LOGGER;
|
import static me.teridax.jcash.Logging.LOGGER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static class for providing the capabilities to load images from file.
|
||||||
|
*/
|
||||||
public class IconProvider {
|
public class IconProvider {
|
||||||
|
|
||||||
private static final Image DEFAULT_IMAGE = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB);
|
private static final Image DEFAULT_IMAGE = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the windows icon.
|
||||||
|
* @return the windows icon
|
||||||
|
*/
|
||||||
public static Image getWindowIcon() {
|
public static Image getWindowIcon() {
|
||||||
return loadIcon("res/register.png");
|
return loadIcon("res/register.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the specified image from disk.
|
||||||
|
* If the file cannot be made into an image because its corrupted or the file cannot be read,
|
||||||
|
* the default image is returned {@link #DEFAULT_IMAGE}
|
||||||
|
* @param path the path to the image
|
||||||
|
* @return the specified image or {@link #DEFAULT_IMAGE}
|
||||||
|
*/
|
||||||
private static Image loadIcon(String path) {
|
private static Image loadIcon(String path) {
|
||||||
try {
|
try {
|
||||||
var is = Objects.requireNonNull(IconProvider.class.getResourceAsStream(path));
|
var is = Objects.requireNonNull(IconProvider.class.getResourceAsStream(path));
|
||||||
|
@ -26,6 +40,10 @@ public class IconProvider {
|
||||||
return DEFAULT_IMAGE;
|
return DEFAULT_IMAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the background image used for the login screen
|
||||||
|
* @return login screen background image
|
||||||
|
*/
|
||||||
public static Image getBackground() {
|
public static Image getBackground() {
|
||||||
return loadIcon("res/background.png");
|
return loadIcon("res/background.png");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package me.teridax.jcash.gui;
|
package me.teridax.jcash.gui;
|
||||||
|
|
||||||
import java.text.ParseException;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when some user input is invalid
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class InvalidInputException extends IllegalStateException {
|
public class InvalidInputException extends IllegalStateException {
|
||||||
|
|
||||||
public InvalidInputException(String message, Exception cause) {
|
public InvalidInputException(String message, Exception cause) {
|
||||||
|
|
|
@ -14,16 +14,31 @@ import static me.teridax.jcash.lang.Translator.translate;
|
||||||
|
|
||||||
public class MainFrame {
|
public class MainFrame {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant used to identify the login screen on the cardlayout
|
||||||
|
*/
|
||||||
private static final String LOGIN_SCREEN_STRING_IDENT = "LoginScreen";
|
private static final String LOGIN_SCREEN_STRING_IDENT = "LoginScreen";
|
||||||
|
/**
|
||||||
|
* Constant used to identify the profile screen on the cardlayout
|
||||||
|
*/
|
||||||
private static final String PROFILE_SCREEN_STRING_IDENT = "ProfileScreen";
|
private static final String PROFILE_SCREEN_STRING_IDENT = "ProfileScreen";
|
||||||
private static final String VERSION = "v2.0.0";
|
/**
|
||||||
|
* Version of this application
|
||||||
|
*/
|
||||||
|
private static final String VERSION = "v2.1.0";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Primary window of this program
|
* Primary window of this program
|
||||||
*/
|
*/
|
||||||
private final JFrame window;
|
private final JFrame window;
|
||||||
|
/**
|
||||||
|
* Primary layout of this application
|
||||||
|
*/
|
||||||
private final CardLayout layout;
|
private final CardLayout layout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database containing every bank, account and owner available
|
||||||
|
*/
|
||||||
private BankingManagementSystem bms;
|
private BankingManagementSystem bms;
|
||||||
|
|
||||||
private LoginController loginMask;
|
private LoginController loginMask;
|
||||||
|
@ -44,10 +59,17 @@ public class MainFrame {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a general information string about this application
|
||||||
|
* @return the locale and the current version as string
|
||||||
|
*/
|
||||||
private String getInfoString() {
|
private String getInfoString() {
|
||||||
return " locale: [" + Locales.getDefaultLocale().toString() + "] " + VERSION;
|
return " locale: [" + Locales.getDefaultLocale().toString() + "] " + VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the GUI components of login screen and profile view
|
||||||
|
*/
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
// create the login mask
|
// create the login mask
|
||||||
|
|
||||||
|
@ -68,6 +90,11 @@ public class MainFrame {
|
||||||
this.window.getContentPane().add(accountController.getView(), PROFILE_SCREEN_STRING_IDENT);
|
this.window.getContentPane().add(accountController.getView(), PROFILE_SCREEN_STRING_IDENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the BMS of this application to use for the GUI.
|
||||||
|
* This method will show the login screen to the user
|
||||||
|
* @param bms the BMS to use for the GUI
|
||||||
|
*/
|
||||||
public void setBms(BankingManagementSystem bms) {
|
public void setBms(BankingManagementSystem bms) {
|
||||||
this.bms = bms;
|
this.bms = bms;
|
||||||
this.loginMask.setBankingManagementSystem(bms);
|
this.loginMask.setBankingManagementSystem(bms);
|
||||||
|
|
|
@ -10,6 +10,14 @@ import java.text.NumberFormat;
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the string so that it will be displayed as a Heading 1 element by JLabels.
|
||||||
|
* This embeds the given string into two html tags.
|
||||||
|
* Note that eny html entities in the string will be formatted as valid HTML entities.
|
||||||
|
* Meaning they won't show up in as plain text.
|
||||||
|
* @param title the title to format.
|
||||||
|
* @return the given string embedded into <pre><html><h1>$string</h1></html></pre>
|
||||||
|
*/
|
||||||
public static String addHeading(String title) {
|
public static String addHeading(String title) {
|
||||||
return String.format("<html><h1>%s</h1></html>", title);
|
return String.format("<html><h1>%s</h1></html>", title);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,9 @@ public class TakeoffController {
|
||||||
this.view.showDialog();
|
this.view.showDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to take off some money from an account.
|
||||||
|
*/
|
||||||
private void takeOff() {
|
private void takeOff() {
|
||||||
try {
|
try {
|
||||||
account.takeoff(view.getAmount());
|
account.takeoff(view.getAmount());
|
||||||
|
|
|
@ -11,6 +11,9 @@ import java.text.ParseException;
|
||||||
|
|
||||||
import static me.teridax.jcash.lang.Translator.translate;
|
import static me.teridax.jcash.lang.Translator.translate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dialog for taking off money of an account.
|
||||||
|
*/
|
||||||
public class TakeoffView {
|
public class TakeoffView {
|
||||||
|
|
||||||
private JDialog dialog;
|
private JDialog dialog;
|
||||||
|
@ -25,6 +28,9 @@ public class TakeoffView {
|
||||||
layoutComponents();
|
layoutComponents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes this dialog visible.
|
||||||
|
*/
|
||||||
public void showDialog() {
|
public void showDialog() {
|
||||||
dialog.setIconImage(IconProvider.getWindowIcon());
|
dialog.setIconImage(IconProvider.getWindowIcon());
|
||||||
dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
|
dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
|
||||||
|
@ -104,6 +110,10 @@ public class TakeoffView {
|
||||||
dialog.getContentPane().add(buttonPanel, c);
|
dialog.getContentPane().add(buttonPanel, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The createComponents function creates the components of the dialog.
|
||||||
|
* @param maxValue Set the maximum value of the jformattedtextfield
|
||||||
|
*/
|
||||||
private void createComponents(double maxValue) {
|
private void createComponents(double maxValue) {
|
||||||
this.dialog = new JDialog();
|
this.dialog = new JDialog();
|
||||||
|
|
||||||
|
@ -116,6 +126,10 @@ public class TakeoffView {
|
||||||
this.dialog.setContentPane(new JPanel(new GridBagLayout()));
|
this.dialog.setContentPane(new JPanel(new GridBagLayout()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The getAmount function is used to get the amount of currency that has been entered into the text field.
|
||||||
|
* @return A double value, which is the parsed amount from the text field
|
||||||
|
*/
|
||||||
public double getAmount() throws InvalidInputException {
|
public double getAmount() throws InvalidInputException {
|
||||||
if (value.getText().isBlank())
|
if (value.getText().isBlank())
|
||||||
throw new InvalidInputException("currency value is blank or has been invalid whilst entered");
|
throw new InvalidInputException("currency value is blank or has been invalid whilst entered");
|
||||||
|
@ -128,6 +142,13 @@ public class TakeoffView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setCommittedValue function sets the text of the enteredValue and balanceAfterDeposit TextFields to
|
||||||
|
* a String representation of amount and after, respectively.
|
||||||
|
* @param amount Set the text of enteredvalue
|
||||||
|
* @param after Set the balance after deposit
|
||||||
|
*/
|
||||||
public void setCommittedValue(double amount, double after) {
|
public void setCommittedValue(double amount, double after) {
|
||||||
enteredValue.setText(StringDecoder.getNumberFormat().format(amount));
|
enteredValue.setText(StringDecoder.getNumberFormat().format(amount));
|
||||||
balanceAfterDeposit.setText(StringDecoder.getNumberFormat().format(after));
|
balanceAfterDeposit.setText(StringDecoder.getNumberFormat().format(after));
|
||||||
|
|
|
@ -34,6 +34,7 @@ public class TransferController {
|
||||||
this.view.getTransfer().addActionListener(e -> transfer());
|
this.view.getTransfer().addActionListener(e -> transfer());
|
||||||
this.view.getCancel().addActionListener(e -> view.dispose());
|
this.view.getCancel().addActionListener(e -> view.dispose());
|
||||||
|
|
||||||
|
// validates the users input
|
||||||
var validator = new DocumentListener() {
|
var validator = new DocumentListener() {
|
||||||
@Override
|
@Override
|
||||||
public void insertUpdate(DocumentEvent documentEvent) {
|
public void insertUpdate(DocumentEvent documentEvent) {
|
||||||
|
@ -58,6 +59,10 @@ public class TransferController {
|
||||||
this.view.showDialog();
|
this.view.showDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the target bank account is valid.
|
||||||
|
* @return true if the target bank account is valid false otherwise
|
||||||
|
*/
|
||||||
private boolean validateTargetAccount() {
|
private boolean validateTargetAccount() {
|
||||||
if (transferData.validateBLZ(this.view.getBlz())) {
|
if (transferData.validateBLZ(this.view.getBlz())) {
|
||||||
return transferData.validateIBAN(this.view.getBlz(), view.getIban());
|
return transferData.validateIBAN(this.view.getBlz(), view.getIban());
|
||||||
|
@ -65,6 +70,11 @@ public class TransferController {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the entered value to transfer is valid.
|
||||||
|
* This method will also commit the valid value back to the text field.
|
||||||
|
* @return true if the value to transfer is valid, false otherwise
|
||||||
|
*/
|
||||||
private boolean validateTransferValue() {
|
private boolean validateTransferValue() {
|
||||||
var balance = account.getBalance();
|
var balance = account.getBalance();
|
||||||
try {
|
try {
|
||||||
|
@ -83,6 +93,10 @@ public class TransferController {
|
||||||
view.getTransfer().setEnabled(valid);
|
view.getTransfer().setEnabled(valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to transfer the balance from one account to another
|
||||||
|
* This method will close the dialog.
|
||||||
|
*/
|
||||||
private void transfer() {
|
private void transfer() {
|
||||||
try {
|
try {
|
||||||
var amount = view.getAmount();
|
var amount = view.getAmount();
|
||||||
|
|
|
@ -47,10 +47,24 @@ public class TransferData {
|
||||||
account.get().getPrimaryAccount().deposit(amount);
|
account.get().getPrimaryAccount().deposit(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the given BLZ. If no bank with the given BLZ can be found
|
||||||
|
* this method returns false. Otherwise, true is returned.
|
||||||
|
* @param blz the BLZ to validate
|
||||||
|
* @return true if the BLZ is valid and false otherwise
|
||||||
|
*/
|
||||||
public boolean validateBLZ(String blz) {
|
public boolean validateBLZ(String blz) {
|
||||||
return bms.getBank(blz).isPresent();
|
return bms.getBank(blz).isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the given IBAN for the given BLZ. This method assumes the BLZ to be valid.
|
||||||
|
* If this is not the case, this function will throw an exception.
|
||||||
|
* Returns true if an account with the given IBAN was found for bank of the given BLZ.
|
||||||
|
* @param blz bank to search in
|
||||||
|
* @param ibanString account to search for
|
||||||
|
* @return true if the account was found false otherwise
|
||||||
|
*/
|
||||||
public boolean validateIBAN(String blz, String ibanString) {
|
public boolean validateIBAN(String blz, String ibanString) {
|
||||||
var bank = bms.getBank(blz);
|
var bank = bms.getBank(blz);
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -11,6 +11,24 @@ import java.text.ParseException;
|
||||||
|
|
||||||
import static me.teridax.jcash.lang.Translator.translate;
|
import static me.teridax.jcash.lang.Translator.translate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JDialog for displaying the GUI for a transfer dialog
|
||||||
|
* with the following crude layout:
|
||||||
|
* <pre>
|
||||||
|
┌───────────────────────────────────────────────┐
|
||||||
|
│ ┌─────────────┐ ┌────────────────┐ │
|
||||||
|
│ BLZ │ │ IBAN │ │ │
|
||||||
|
│ └─────────────┘ └────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────┐ │
|
||||||
|
│ VALUE │ │ │
|
||||||
|
│ └─────────────┘ │
|
||||||
|
│ ┌───────┐ ┌────────┐ │
|
||||||
|
│ │Cancel │ │Transfer│ │
|
||||||
|
│ └───────┘ └────────┘ │
|
||||||
|
└───────────────────────────────────────────────┘
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
public class TransferView {
|
public class TransferView {
|
||||||
|
|
||||||
private JDialog dialog;
|
private JDialog dialog;
|
||||||
|
@ -19,7 +37,6 @@ public class TransferView {
|
||||||
private JFormattedTextField iban;
|
private JFormattedTextField iban;
|
||||||
private JFormattedTextField blz;
|
private JFormattedTextField blz;
|
||||||
private JFormattedTextField value;
|
private JFormattedTextField value;
|
||||||
|
|
||||||
private JLabel balanceAfterTransfer;
|
private JLabel balanceAfterTransfer;
|
||||||
private JLabel enteredValue;
|
private JLabel enteredValue;
|
||||||
|
|
||||||
|
@ -28,6 +45,9 @@ public class TransferView {
|
||||||
layoutComponents();
|
layoutComponents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes this dialog visible to the user
|
||||||
|
*/
|
||||||
public void showDialog() {
|
public void showDialog() {
|
||||||
dialog.setIconImage(IconProvider.getWindowIcon());
|
dialog.setIconImage(IconProvider.getWindowIcon());
|
||||||
dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
|
dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
|
||||||
|
@ -40,6 +60,9 @@ public class TransferView {
|
||||||
dialog.setVisible(true);
|
dialog.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layout all components of this dialog.
|
||||||
|
*/
|
||||||
private void layoutComponents() {
|
private void layoutComponents() {
|
||||||
var c = new GridBagConstraints();
|
var c = new GridBagConstraints();
|
||||||
|
|
||||||
|
@ -142,6 +165,11 @@ public class TransferView {
|
||||||
this.dialog.setContentPane(new JPanel(new GridBagLayout()));
|
this.dialog.setContentPane(new JPanel(new GridBagLayout()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the entered amount parsed into a double value.
|
||||||
|
* @return the amount parsed into a double
|
||||||
|
* @throws InvalidInputException if the text in {@link #value} is not a valid double value.
|
||||||
|
*/
|
||||||
public double getAmount() throws InvalidInputException {
|
public double getAmount() throws InvalidInputException {
|
||||||
if (value.getText().isBlank())
|
if (value.getText().isBlank())
|
||||||
throw new InvalidInputException("currency value is blank or has been invalid whilst entered");
|
throw new InvalidInputException("currency value is blank or has been invalid whilst entered");
|
||||||
|
@ -154,6 +182,11 @@ public class TransferView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the values to display in the dialog labels as overview information.
|
||||||
|
* @param amount the amount to transfer
|
||||||
|
* @param after balance after the transfer
|
||||||
|
*/
|
||||||
public void setCommittedValue(double amount, double after) {
|
public void setCommittedValue(double amount, double after) {
|
||||||
enteredValue.setText(StringDecoder.getNumberFormat().format(amount));
|
enteredValue.setText(StringDecoder.getNumberFormat().format(amount));
|
||||||
balanceAfterTransfer.setText(StringDecoder.getNumberFormat().format(after));
|
balanceAfterTransfer.setText(StringDecoder.getNumberFormat().format(after));
|
||||||
|
|
|
@ -10,6 +10,9 @@ import java.util.Locale;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class Locales {
|
public class Locales {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default locale initialized to the fallback locale used by this application.
|
||||||
|
*/
|
||||||
private static Locale defaultLocale = new Locale("en", "EN");
|
private static Locale defaultLocale = new Locale("en", "EN");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,6 +6,11 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static translator class.
|
||||||
|
* This is a very simple translator able to translate base tokens from english into a variety of
|
||||||
|
* configured languages.
|
||||||
|
*/
|
||||||
public final class Translator {
|
public final class Translator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue