JaBudGetUI.java

package de.japrost.jabudget.vaadin.spring;

import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.provider.ListDataProvider;
import com.vaadin.flow.data.selection.SelectionEvent;
import com.vaadin.flow.router.Route;

import de.japrost.jabudget.domain.DomainException;
import de.japrost.jabudget.domain.account.Account;
import de.japrost.jabudget.service.AccountService;
import de.japrost.jabudget.service.SerializationService;

/**
 * Main UI for JaBudget.
 */
// this is a hack just to test main functionality
@Route("")
public class JaBudGetUI extends HorizontalLayout {

	private static final long serialVersionUID = 1L;

	// Account
	private final transient AccountService accountService;
	private ListDataProvider<Account> accountData;
	private Account selectedAccount;
	private Button newAccount;
	private Button clear;
	private Button delete;
	private TextField newId;
	private TextField newName;
	// Serialization
	private final transient SerializationService serializationService;
	private Button export;
	private Button impoort;

	/**
	 * Instantiate with all dependencies.
	 *
	 * @param accountService the {@link AccountService} to use.
	 * @param serializationService the {@link SerializationService} to use.
	 */
	public JaBudGetUI(final AccountService accountService, final SerializationService serializationService) {
		this.accountService = accountService;
		this.serializationService = serializationService;
		setSizeFull();
		add(initAccountOverview());
		add(initAccountForm());
		add(initSerialization());
	}

	private VerticalLayout initAccountOverview() {
		final VerticalLayout layout = new VerticalLayout();
		final Grid<Account> accounts = new Grid<>(Account.class);
		// accounts.setCaption("Accounts"); // I18N?
		accounts.setColumns("id", "name");
		accountData = new ListDataProvider<>(accountService.retrieveAll());
		accounts.setDataProvider(accountData);
		accounts.addSelectionListener(this::itemClicked);
		layout.add(accounts);
		return layout;
	}

	private void itemClicked(final SelectionEvent<Grid<Account>, Account> e) {
		selectedAccount = e.getFirstSelectedItem().get();
		newId.setValue(selectedAccount.getId());
		newName.setValue(selectedAccount.getName());
		newAccount.setText("Update");
		delete.setEnabled(true);
	}

	private FormLayout initAccountForm() {
		final FormLayout newAccountLayout = new FormLayout();
		newId = new TextField();
		newId.setLabel("id");
		newId.setRequiredIndicatorVisible(true);
		newId.addValueChangeListener(this::newIdValueChanged);
		newAccountLayout.add(newId);
		newName = new TextField();
		newName.setLabel("name");
		newAccountLayout.add(newName);
		newAccount = new Button();
		newAccount.setText("New");
		newAccount.setEnabled(false);
		newAccount.addClickListener(this::createNewAccount);
		newAccountLayout.add(newAccount);
		clear = new Button();
		clear.setText("Clear");
		clear.setEnabled(false);
		clear.addClickListener(this::clearAccount);
		newAccountLayout.add(clear);
		delete = new Button();
		delete.setText("Delete");
		delete.setEnabled(false);
		delete.addClickListener(this::deleteAccount);
		newAccountLayout.add(delete);
		return newAccountLayout;
	}

	private void clearAccount(final ClickEvent<Button> event) {
		newId.clear();
		newName.clear();
		newAccount.setText("New");
	}

	private void deleteAccount(final ClickEvent<Button> event) {
		final Boolean erased = accountService.erase(newId.getValue());
		if (erased) {
			accountData.getItems().remove(selectedAccount);
			accountData.refreshAll();
			// clear after remove since the newIdValueChanged is faster and sets selectedAccount to null
			newId.clear();
			newName.clear();
			newAccount.setText("New");
		}
	}

	private void createNewAccount(final ClickEvent<Button> event) {
		Account account;
		try {
			// this is a hack just to test main functionality
			if (newAccount.getText().equals("New")) {
				account = accountService.create(Account.Builder.builder(newId.getValue()).setName(newName.getValue()).build());
				accountData.getItems().add(account);
			} else {
				account = accountService.update(Account.Builder.builder(newId.getValue()).setName(newName.getValue()).build());
				accountData.getItems().remove(account);
				accountData.getItems().add(account);
			}
		} catch (final DomainException e) {
			// FIXME show error message
			return;
		}
		newId.clear();
		newName.clear();
		newAccount.setText("New");
		accountData.refreshAll();
	}

	private void newIdValueChanged(final HasValue.ValueChangeEvent<String> event) {
		if (event.getValue().length() == 0) {
			newAccount.setEnabled(false);
			clear.setEnabled(false);
			delete.setEnabled(false);
			selectedAccount = null;
		} else {
			newAccount.setEnabled(true);
			clear.setEnabled(true);
		}
	}

	private VerticalLayout initSerialization() {
		final VerticalLayout layout = new VerticalLayout();
		impoort = new Button();
		impoort.setText("Import");

		impoort.addClickListener(e -> {
			serializationService.deserialize();
			reloadAccounts();
		});
		layout.add(impoort);
		export = new Button();
		export.setText("Export");
		export.addClickListener(e -> serializationService.serialize());
		layout.add(export);
		return layout;
	}

	private void reloadAccounts() {
		accountData.getItems().clear();
		accountData.getItems().addAll(accountService.retrieveAll());
		accountData.refreshAll();
	}
}