PantryView.java
package stud.ntnu.idatt1005.pantrypal.views;
import static stud.ntnu.idatt1005.pantrypal.utils.NodeUtils.addChildren;
import static stud.ntnu.idatt1005.pantrypal.utils.NodeUtils.addClasses;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Separator;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import stud.ntnu.idatt1005.pantrypal.controllers.Observer;
import stud.ntnu.idatt1005.pantrypal.controllers.PantryController;
import stud.ntnu.idatt1005.pantrypal.enums.Route;
import stud.ntnu.idatt1005.pantrypal.models.Grocery;
import stud.ntnu.idatt1005.pantrypal.models.Shelf;
import stud.ntnu.idatt1005.pantrypal.utils.NodeUtils;
import stud.ntnu.idatt1005.pantrypal.views.components.AddGroceryListElement;
import stud.ntnu.idatt1005.pantrypal.views.components.GroceryListElement;
import stud.ntnu.idatt1005.pantrypal.views.components.StyledButton;
/**
* A class that extends View and creates a view for the pantry.
* The goal is to provide a dedicated view for users to view their pantry.
* This class is associated with an PantryController to handle the logic
* and actions related to the pantry.
*/
public class PantryView extends View {
/**
* The controller responsible for managing the logic and
* actions associated with the pantry functionality.
*/
private final PantryController controller;
private static final String FX_FONT_SIZE = "-fx-font-size: ";
private double fontSize = 35;
/**
* Constructor for PantryView.
*
* @param controller The controller for the view.
*/
public PantryView(PantryController controller) {
super(controller, Route.PANTRY, "/styles/pantry.css");
this.controller = controller;
this.setScrollPane();
}
/**
* This method renders the pantry view.
* It creates a grid of shelves and groceries.
* It also creates a button to add a new shelf.
*
* @param shelves the shelves to be shown
*/
public void render(Shelf[] shelves) {
GridPane shelfGrid = new GridPane();
int row = 0;
int col = 0;
for (Shelf shelf : shelves) {
VBox shelfBox = this.shelf(shelf);
shelfGrid.add(shelfBox, col, row);
col++;
if (col == 3) {
col = 0;
row++;
}
}
var addShelfButton = this.addShelfButton();
addShelfButton.setOnAction(e -> controller.addShelf());
shelfGrid.add(addShelfButton, col, row);
shelfGrid.setAlignment(Pos.TOP_CENTER);
this.getBorderPane().setCenter(shelfGrid);
}
/**
* Creates a button for adding a shelf.
*
* @return a button for adding a shelf
*/
private Button addShelfButton() {
Button addShelfButton = new Button("Add new shelf");
NodeUtils.addClasses(addShelfButton, "add-shelf-button");
return addShelfButton;
}
/**
* Creates a VBox for representing a single shelf.
* It contains a header with the shelf name and
* buttons for editing and deleting the shelf.
* It also contains a list of groceries in the shelf.
*
* @param shelf the shelf object to be shown
* @return a VBox containing the visual representation of a shelf
*/
private VBox shelf(Shelf shelf) {
VBox container = new VBox();
container.setAlignment(Pos.TOP_CENTER);
NodeUtils.addClasses(container, "shelf");
HBox header = new HBox();
header.setAlignment(Pos.CENTER);
TextField title = new TextField(shelf.getName());
title.setMinWidth(200);
NodeUtils.addClasses(title, "shelf-title-textfield");
title.setEditable(false);
title.setStyle(FX_FONT_SIZE + fontSize + "px;");
title.textProperty().addListener((observable, oldValue, newValue) ->
updateShelfTextSize(title, newValue));
StyledButton edit = new StyledButton("Edit");
edit.setStyle("-fx-min-width: 80px;");
edit.setOnAction(e -> {
if (edit.getText().equals("Edit")) {
title.setEditable(true);
edit.setText("Save");
} else {
title.setEditable(false);
edit.setText("Edit");
this.controller.editShelfName(shelf, title.getText());
title.setStyle(FX_FONT_SIZE + fontSize + "px;");
}
});
StyledButton delete = new StyledButton(
"X", StyledButton.Variant.DELETE, StyledButton.Size.LARGE);
delete.setStyle("-fx-min-width: 80px;");
delete.setOnAction(e -> this.controller.deleteShelf(shelf));
addChildren(header, title, edit, delete);
updateShelfTextSize(title, shelf.getName());
Separator separator = new Separator();
addClasses(separator, "shelf-separator");
VBox groceryList = this.groceryList(shelf, controller.getGroceries(shelf));
addChildren(container, header, separator, groceryList);
return container;
}
private void updateShelfTextSize(TextField textField, String newValue) {
Text text = new Text(newValue);
text.setFont(textField.getFont());
double textWidth = text.getLayoutBounds().getWidth();
double textFieldWidth = (textField.getWidth() > 0 ? textField.getWidth() : 300);
while (textWidth * 1.2 > textFieldWidth) {
String currentFontName = textField.getFont().getName();
double currentFontSize = textField.getFont().getSize();
Font newFont = new Font(currentFontName, currentFontSize - 0.5);
textField.setStyle(FX_FONT_SIZE + (currentFontSize - 0.5) + "px;");
textField.setFont(newFont);
text.setFont(newFont);
textWidth = text.getLayoutBounds().getWidth();
this.fontSize = currentFontSize;
}
}
/**
* Creates a VBox for representing a list of groceries.
* Used to display the groceries in a shelf.
*
* @param shelf the shelf containing the groceries to be shown
* @param groceries the groceries to be shown
* @return a VBox containing the visual representation of a list of groceries
*/
private VBox groceryList(Shelf shelf, Grocery[] groceries) {
ScrollPane scrollContainer = new ScrollPane();
NodeUtils.addClasses(scrollContainer, "grocery-list-scroll-container");
VBox groceryList = new VBox();
NodeUtils.addClasses(groceryList, "grocery-list");
scrollContainer.setContent(groceryList);
scrollContainer.setFitToWidth(true);
for (Grocery grocery : groceries) {
GroceryListElement element = new GroceryListElement.GroceryListElementBuilder(grocery)
.text(grocery.getName())
.quantity()
.build();
for (Observer observer : observers) {
element.addObserver(observer);
}
addChildren(groceryList, element.getPane());
}
AddGroceryListElement addGroceryButton = new AddGroceryListElement(shelf.getName());
for (Observer observer : observers) {
addGroceryButton.addObserver(observer);
}
VBox container = new VBox();
addChildren(container, scrollContainer, addGroceryButton);
return container;
}
}