Skip to content
Snippets Groups Projects
AddIngredientController.java 5.8 KiB
Newer Older
package no.ntnu.idatt1002.demo.controller;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import java.util.stream.Collectors;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import no.ntnu.idatt1002.demo.data.recipes.FileHandler;
import no.ntnu.idatt1002.demo.data.recipes.FoodItem;
import no.ntnu.idatt1002.demo.data.recipes.IngredientsAtHand;

/**
 * The AddIngredientController manages a dialog pane used to display a search-field along with a list of all the
 * possible food types in the application according to the FoodItem enum class. The food types in the list may be
 * selected and added to an up-to-date IngredientsAtHand object that is then written to file. The user may add
 * several food types before pressing 'close' and exit the dialog. The food types that are not already contained
 * in the IngredientsAtHand are listed underneath the list so that the user can keep track of the newly added
 * food types. Upon opening the dialog, the search field is already selected and the user can start typing a search.
 * When pressing 'Enter' on the keyboard, the search is performed and matches are displayed in the list. If the search
 * field is left blank upon search, all food types are listed again.
 */
public class AddIngredientController implements Initializable {

    private ObservableList<String> ingredients;
    private String[] ingredientsList;

    @FXML
    private Button addBtn;

    @FXML
    private ListView<String> listView;

    @FXML
    private TextField searchBar;

    @FXML
    private Button searchBtn;

    @FXML
    private Label status;

    private String statusText = "Added: ";
    /**
     * The initialize method of the controller takes in a URL (location) and ResourceBundle(resources) to
     * initialize the controller once its root element has been processed.
     * The method then sets the list items of the list, sets the focus on the search-field and makes sure that the
     * label underneath the list that states the added food types to the user can wrap if it fills the full width
     * of the window.
     * @param url The location to resolve the relative paths to the root object.
     * @param resourceBundle Resources used to localize the root object.
     */
    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        listView.setItems(FXCollections.observableArrayList(Arrays.stream(FoodItem.values()).map(value -> value.label).toList()));
        Platform.runLater(() -> searchBar.requestFocus());
        status.setWrapText(true);
    }

    /**
     * The addToFridge method reads an up-to-date instance of the IngredientsAtHand object from file and
     * gets hold of the FoodItem constant that is currently selected in the list. If the selected FoodItem is not
     * already at hand, it is added and the IngredientAtHand object is written to file. The label beneath the
     * list is also updated with the name of the food type to keep track of what has been added. If the
     * selected food type was already at hand, it is not added again and the label is not updated.
     *
     * @throws IOException If the method fails to write or read the Ingredients at hand object to/from file.
     */
    void addToFridge() throws IOException {
        IngredientsAtHand ingredientsAtHand = FileHandler.readIngredientsAtHand("Fridge");
        FoodItem item = FoodItem.valueOf(listView.getSelectionModel().getSelectedItem().replace(" ", "_").toUpperCase());

        if(item != null && ingredientsAtHand!= null ) {
            if(!ingredientsAtHand.atHand(item)) {
                ingredientsAtHand.addIngredient(item);
                FileHandler.writeIngredientsAtHand(ingredientsAtHand, "Fridge");

                if(status.isVisible() && status.getText().isBlank()) {
                    statusText += String.format("%s", item.label);
                } else if (status.isVisible()){
                    statusText += String.format(", %s", item.label);
                }
                status.setText(statusText);
    /**
     * The search method is fired whenever the 'Search' button is pressed by the user. It clears the list and then
     * refills it by adding all the resulting values from the call to the method 'searchList'.
     */
       listView.getItems().addAll(searchList(searchBar.getText(),
               Arrays.stream(FoodItem.values()).toList().stream().map(value -> value.label).toArray(String[]::new)));
     * The searchList method takes in a string of what the user wrote in the search field and an array of
     * Strings that represents every label of the FoodItem enum class. The search word from the user is
     * trimmed and split by space and matched against all the constants of the FoodItem enums. Any matches are then
     * to a List of strings and returned.
     * @param searchWords A String of what the user wrote in the search field.
     * @param listOfStrings A list of strings, in this case, each representing a constant of the FoodItem enum class.
     * @return A list of strings food types of FoodItem that match the se search word(s).
     */
    private List<String> searchList(String searchWords, String[] listOfStrings) {
        String[] searchWordsArray = searchWords.trim().split(" ");
        return Arrays.stream(listOfStrings).filter((in) -> Arrays.stream(searchWordsArray).allMatch((word) ->
                in.toLowerCase().contains(word.toLowerCase()))).collect(Collectors.toList());