Skip to content
Snippets Groups Projects
Commit 90911f75 authored by HSoreide's avatar HSoreide
Browse files

Improve UI based on customer feedback(21/4-23) and add help-button to the 'Add...

Improve UI based on customer feedback(21/4-23) and add help-button to the 'Add ingredients to Fridge' view
parent 6fa5ca8e
No related branches found
No related tags found
1 merge request!49Improve UI based on customer feedback(21/4-23) and add help-button to the 'Add...
...@@ -10,101 +10,34 @@ import javafx.fxml.Initializable; ...@@ -10,101 +10,34 @@ import javafx.fxml.Initializable;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.Parent; import javafx.scene.Parent;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView; import javafx.scene.control.ListView;
import javafx.scene.input.MouseEvent; import javafx.scene.input.MouseEvent;
import javafx.stage.Stage; import javafx.stage.Stage;
import no.ntnu.idatt1002.demo.data.recipes.*; import no.ntnu.idatt1002.demo.data.recipes.*;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.ResourceBundle; import java.util.ResourceBundle;
/**
* The AllRecipesController manages the view named AllRecipes.fxml that displays a scrollable list of all the
* recipes that are stored in the recipe register at 'src/main/resources/recipes/Recipes.register'. The controller
* holds an instance of the IngredientsAtHand class and the RecipeRegister class and combines the two to
* fill the list with recipes sorted by the number of ingredients that are not currently in the 'fridge' of the
* user. Each recipe is also lister with a percentage value that shows how many percent of the recipe's
* ingredients are actually in the fridge. This information is included so that recipes with a lower number of
* ingredients are not given an unfair advantage over others where the user may have a significant number of
* the ingredients available. Each listed recipe may be clicked on by the user to open it in a new view in full
* detail.
*
* @author hannesofie
*/
public class AllRecipesController implements Initializable { public class AllRecipesController implements Initializable {
IngredientsAtHand ingredientsAtHand; IngredientsAtHand ingredientsAtHand;
RecipeRegister recipeRegister; RecipeRegister recipeRegister;
@FXML @FXML
private ListView<String> allList; private Button goBackBtn;
private String selectedRecipeName;
/**
* 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 reads and creates
* an object of the IngredientsAtHand class and one of the RecipesRegister class.
* If the recipe register exists, the list is filled with Strings for each recipe at the format:
* <Recipe name> - X missing ingredients (XX%)
* Finally, a MouseClick event and handler is attached to the list that gets the recipe name of the clicked
* list item and runs the method showRecipe() with that name as input to show the recipe in detail in the
* view Recipe.fxml.
*
* @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) {
ingredientsAtHand = FileHandler.readIngredientsAtHand("Fridge"); @FXML
recipeRegister = FileHandler.readRecipeRegister("Recipes"); private ListView<String> allList;
ObservableList<String> recipes;
if(recipeRegister == null) {
recipes = FXCollections.observableArrayList(new ArrayList<>());
} else {
int numberOfRecipes = recipeRegister.getRecipes().size();
ArrayList<Recipe> sortedRecipes = recipeRegister.pickBestFits(numberOfRecipes, ingredientsAtHand);
recipes = FXCollections.observableArrayList(sortedRecipes.stream().map(recipe -> String.format("# %s - %d missing ingredients (%2.0f %%)", recipe.getName(), recipe.getMissingIngredients(), percent(recipe.getIngredientList().size() - recipe.getMissingIngredients(), recipe.getIngredientList().size()))).toList());
}
allList.setItems(recipes);
allList.setOnMouseClicked(new EventHandler<>() { private ObservableList<String> recipes;
/** private String selectedRecipeName;
* The handler method takes a MouseEvent(Mouse Click) and uses the list item that was subjected to the
* mouse click and extracts the recipe name. That name as a String is then passed to the method
* 'showRecipe' that loads the view Recipe.fxml to display this particular recipe in full detail.
*
* @param mouseEvent A mouse event, in this case a MouseClicked event.
*/
@Override
public void handle(MouseEvent mouseEvent) {
selectedRecipeName = allList.getSelectionModel()
.getSelectedItem().split("[-#]")[1].strip();
try {
showRecipe(selectedRecipeName);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
}
/**
* The goBack method is fired whenever the user presses the button 'Back To Suggestions'. It loads the location
* of the SuggestRecipes.fxml view and sets the new stage.
* @param event Action event that triggers this method, in this case a button click.
* @throws IOException If the method fails to load the location at the given file path.
*/
@FXML @FXML
private void goBack(ActionEvent event) throws IOException { private void goBack(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(); FXMLLoader loader = new FXMLLoader();
...@@ -117,12 +50,6 @@ public class AllRecipesController implements Initializable { ...@@ -117,12 +50,6 @@ public class AllRecipesController implements Initializable {
stage.show(); stage.show();
} }
/**
* The showRecipe method takes in a recipe name as a String and navigates to the view Recipe.fxml after having
* the RecipeController set the data of the view according to this particular recipe.
* @param recipeName A case-sensitive string representation of the recipe to open in detail.
* @throws IOException If the method fails to load the location of the Recipe.fxml view.
*/
private void showRecipe(String recipeName) throws IOException { private void showRecipe(String recipeName) throws IOException {
FXMLLoader loader = new FXMLLoader(); FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/view/Recipe.fxml")); loader.setLocation(getClass().getResource("/view/Recipe.fxml"));
...@@ -130,33 +57,59 @@ public class AllRecipesController implements Initializable { ...@@ -130,33 +57,59 @@ public class AllRecipesController implements Initializable {
Recipe recipeOfInterest = recipeRegister.getRecipe(recipeName); Recipe recipeOfInterest = recipeRegister.getRecipe(recipeName);
Parent root = loader.load(); Parent root = loader.load();
RecipeController recipeController = loader.getController(); RecipeController recipeController = loader.getController();
if(recipeOfInterest != null) { recipeController.setData(recipeOfInterest);
recipeController.setData(recipeOfInterest);
Stage stage = (Stage)allList.getParent().getScene().getWindow(); Stage stage = (Stage)allList.getParent().getScene().getWindow();
Scene scene = new Scene(root); Scene scene = new Scene(root);
stage.setScene(scene); stage.setScene(scene);
stage.show(); stage.show();
} else {
System.out.println("The selected recipe is null.");
}
} }
/** private float percent(int a, int b) {
* The percent method takes in two integers(a, b) and performs float-division(a/b) on then and multiplies the if(b != 0 && a != 0) {
* answer by 100 to get the percentage 'a' makes of the total 'b'. If either 'a' or 'b' is zero, zero is returned. return (float) a / b;
* In the current context; 'a' is an int representing a number of ingredients at hand and part of a recipe and 'b'
* is an int representing the total number of ingredients in the same recipe.
* @param a An int to divide by b and multiply by 100.
* @param b An int by which to divide 'a'.
* @return A float value presenting the percentage value of 'a' out of 'b'.
*/
private float percent(int a, int b) {
if (b != 0 && a != 0) {
return (a * 100f / b);
} else { } else {
return 0; return 0;
} }
}
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
ingredientsAtHand = FileHandler.readIngredientsAtHand("Fridge");
recipeRegister = FileHandler.readRecipeRegister("Recipes");
int numberOfRecipes = recipeRegister.getRecipes().size();
ArrayList<Recipe> sortedRecipes = recipeRegister.pickBestFits(numberOfRecipes, ingredientsAtHand);
recipes = FXCollections.observableArrayList(sortedRecipes.stream().map(recipe -> {
return String.format("# %s - %d missing ingredients (%.2f %% covered)", recipe.getName(), recipe.getMissingIngredients(), percent(recipe.getIngredientList().size() - recipe.getMissingIngredients(),recipe.getIngredientList().size()));
}).toList());
allList.setItems(recipes);
allList.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
selectedRecipeName = allList.getSelectionModel()
.getSelectedItem().split("-|#")[1].strip();
try {
showRecipe(selectedRecipeName);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
} }
} }
...@@ -31,5 +31,6 @@ public class IngredientTileController { ...@@ -31,5 +31,6 @@ public class IngredientTileController {
.append(ingredient.getAmount()).append(" ") .append(ingredient.getAmount()).append(" ")
.append(ingredient.getUnit().label); .append(ingredient.getUnit().label);
text.setText(String.valueOf(sb)); text.setText(String.valueOf(sb));
text.setStyle("-fx-font-size: 18");
} }
} }
...@@ -27,7 +27,7 @@ import java.util.ResourceBundle; ...@@ -27,7 +27,7 @@ import java.util.ResourceBundle;
public class RecipeTileController implements Initializable { public class RecipeTileController implements Initializable {
@FXML @FXML
private Button nameTag; private Label nameTag;
@FXML @FXML
private Label missingTag; private Label missingTag;
......
CARROT
MILK
AVOCADO
CANNED_TOMATO
CELERY
BROTH
BAY_LEAF
DRY_OREGANO
WHITE_BEANS
DRY_THYME
FRESH_YEAST
GARLIC_CLOVE
RED_ONION
PIE_DOUGH
BROCCOLI
LAM
CHILLI_POWDER
SAUSAGE
YELLOW_CHEESE YELLOW_CHEESE
MINCED_MEAT
ONION
HAM
WHEAT_FLOUR
ORANGE
OIL
POTATO
OLIVE_OIL
...@@ -10,15 +10,13 @@ ...@@ -10,15 +10,13 @@
} }
.button-style { .button-style {
//-fx-background-color: linear-gradient(#8ca45b, #1e5b5b);
-fx-background-color: white; -fx-background-color: white;
-fx-text-fill: black; -fx-text-fill: black;
-fx-background-radius: 30; -fx-background-radius: 30;
-fx-background-insets: 0; -fx-background-insets: 0;
-fx-font-family: "JetBrains Mono"; -fx-font-family: "JetBrains Mono";
-fx-font-size: 16; -fx-font-size: 16;
//-fx-text-fill: white;
} }
.welcome-button { .welcome-button {
...@@ -36,7 +34,7 @@ ...@@ -36,7 +34,7 @@
} }
#on-white { #on-white {
-fx-background-color: #79b2b2; -fx-background-color: #83b6b6;
-fx-text-fill: black; -fx-text-fill: black;
} }
...@@ -80,9 +78,10 @@ ...@@ -80,9 +78,10 @@
} }
.list-cell{ .list-cell{
-fx-font-size:18.0; -fx-font-size:20.0;
} }
.list-cell:even { .list-cell:even {
-fx-background-color: rgba(255, 255, 255, 0.7); -fx-background-color: rgba(255, 255, 255, 0.7);
} }
...@@ -101,12 +100,17 @@ ...@@ -101,12 +100,17 @@
-fx-alignment: center; -fx-alignment: center;
} }
.ingredient:hover { /*#ingredient-label {
-fx-scale-x: 1.05; -fx-font-family: "JetBrains Mono Medium";
-fx-scale-y: 1.05;
-fx-scale-z: 1.05;
} }
#ingredient:hover {
-fx-text-fill: red;
-fx-scale-x: 1.03;
-fx-scale-y: 1.03;
-fx-scale-z: 1.03;
}*/
.recipe-instructions { .recipe-instructions {
-fx-font-size: 16; -fx-font-size: 16;
-fx-font-style: italic; -fx-font-style: italic;
...@@ -122,9 +126,19 @@ ...@@ -122,9 +126,19 @@
.scroll-pane > .viewport { .scroll-pane > .viewport {
-fx-background-color: transparent; -fx-background-color: transparent;
} }
.scroll-pane { .scroll-pane {
-fx-background-color: rgba(255, 255, 255, 0.5); -fx-background-color: rgba(255, 255, 255, 0.35);
-fx-border-width: 5; -fx-border-width: 5;
-fx-border-radius: 5; -fx-border-radius: 5;
-fx-border-color: rgba(255, 255, 255, 0.75); -fx-border-color: rgba(255, 255, 255, 0.75);
} }
#help {
-fx-font-size: 30;
-fx-font-weight: bold;
-fx-background-color: #e09188;
-fx-border-width: 5;
-fx-border-radius: 30;
-fx-border-color: white;
}
\ No newline at end of file
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?> <?import javafx.scene.text.*?>
<DialogPane id="dialog-pane" expanded="true" prefHeight="524.0" prefWidth="614.0" stylesheets="@../style.css" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.AddIngredientController"> <DialogPane id="dialog-pane" expanded="true" prefHeight="555.0" prefWidth="614.0" stylesheets="@../style.css" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.AddIngredientController">
<content> <content>
<AnchorPane prefHeight="400.0" prefWidth="600.0"> <AnchorPane prefHeight="400.0" prefWidth="600.0">
<padding> <padding>
...@@ -56,9 +56,9 @@ ...@@ -56,9 +56,9 @@
</Pane> </Pane>
<Pane prefHeight="100.0" prefWidth="614.0"> <Pane prefHeight="100.0" prefWidth="614.0">
<children> <children>
<Label fx:id="status" layoutX="28.0" layoutY="6.0" prefHeight="44.0" prefWidth="558.0" textAlignment="CENTER" wrapText="true"> <Label fx:id="status" layoutX="28.0" layoutY="-4.0" prefHeight="44.0" prefWidth="558.0" textAlignment="CENTER" wrapText="true">
<font> <font>
<Font size="14.0" /> <Font size="20.0" />
</font></Label> </font></Label>
</children> </children>
</Pane> </Pane>
...@@ -66,17 +66,30 @@ ...@@ -66,17 +66,30 @@
</VBox> </VBox>
</children></AnchorPane> </children></AnchorPane>
</content> </content>
<header>
<Label fx:id="addIngredientPane" alignment="CENTER" contentDisplay="CENTER" styleClass="font" stylesheets="@../style.css" text="Add an ingredient to the fridge">
<font>
<Font size="24.0" />
</font>
<padding>
<Insets bottom="25.0" top="20.0" />
</padding>
</Label>
</header>
<buttonTypes> <buttonTypes>
<ButtonType fx:constant="CLOSE" /> <ButtonType fx:constant="CLOSE" />
</buttonTypes> </buttonTypes>
<header>
<HBox prefHeight="100.0" prefWidth="200.0">
<children>
<Pane prefHeight="100.0" prefWidth="543.0">
<children>
<Label layoutX="19.0" layoutY="30.0" prefWidth="516.0" styleClass="head-line" stylesheets="@../style.css" text="Add ingredients to Fridge">
<font>
<Font size="30.0" />
</font>
</Label>
</children>
</Pane>
<Pane prefHeight="100.0" prefWidth="102.0">
<children>
<Button id="help" fx:id="helpBtn" layoutX="9.0" layoutY="14.0" mnemonicParsing="false" onAction="#help" styleClass="button-style" stylesheets="@../style.css" text="?">
<font>
<Font name="System Bold" size="36.0" />
</font></Button>
</children>
</Pane>
</children>
</HBox>
</header>
</DialogPane> </DialogPane>
...@@ -5,11 +5,11 @@ ...@@ -5,11 +5,11 @@
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?> <?import javafx.scene.text.*?>
<Pane fx:id="ingredientPane" styleClass="ingredient" stylesheets="@../style.css" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.IngredientTileController"> <Pane id="ingredient" fx:id="ingredientPane" mouseTransparent="true" stylesheets="@../style.css" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.IngredientTileController">
<children> <children>
<Label fx:id="text" prefHeight="40.0" prefWidth="250.0" styleClass="font" stylesheets="@../style.css" text="Ingredient"> <Label id="ingredient-label" fx:id="text" prefHeight="40.0" prefWidth="250.0" styleClass="font" stylesheets="@../style.css" text="Ingredient">
<font> <font>
<Font name="Ani" size="14.0" /> <Font name="Ani" size="18.0" />
</font> </font>
<padding> <padding>
<Insets left="15.0" /> <Insets left="15.0" />
......
...@@ -7,34 +7,49 @@ ...@@ -7,34 +7,49 @@
<VBox fx:id="recipeTile" prefHeight="220.0" prefWidth="280.0" styleClass="recipe-tile" stylesheets="@../style.css" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.RecipeTileController"> <VBox fx:id="recipeTile" prefHeight="220.0" prefWidth="280.0" styleClass="recipe-tile" stylesheets="@../style.css" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.RecipeTileController">
<children> <children>
<Pane fx:id="namePane" prefHeight="178.0" prefWidth="268.0"> <Pane fx:id="namePane" prefHeight="218.0" prefWidth="268.0">
<children> <children>
<Button fx:id="nameTag" mnemonicParsing="false" onAction="#tileClick" prefHeight="149.0" prefWidth="268.0" styleClass="tile-button" stylesheets="@../style.css" text="nameOfRecipe"> <Button fx:id="tileBtn" alignment="TOP_LEFT" layoutX="-6.0" mnemonicParsing="false" onAction="#tileClick" prefHeight="213.0" prefWidth="280.0" styleClass="tile-button" stylesheets="@../style.css" textAlignment="CENTER">
<font> <font>
<Font size="24.0" /> <Font name="System Bold" size="24.0" />
</font> </font>
<graphic>
<VBox prefHeight="199.0" prefWidth="95.0">
<children>
<Pane prefHeight="132.0" prefWidth="248.0" styleClass="font" stylesheets="@../style.css">
<children>
<Label fx:id="nameTag" alignment="CENTER" contentDisplay="CENTER" prefHeight="135.0" prefWidth="250.0" text="nameOfRecipe" textAlignment="CENTER" wrapText="true">
<font>
<Font name="System Bold" size="24.0" />
</font>
</Label>
</children>
</Pane>
<HBox accessibleRole="BUTTON" prefHeight="66.0" prefWidth="268.0">
<children>
<Label alignment="CENTER" prefHeight="66.0" prefWidth="243.0" text="Missing ingredients:" textAlignment="CENTER" wrapText="true">
<font>
<Font size="24.0" />
</font>
<opaqueInsets>
<Insets left="20.0" right="20.0" />
</opaqueInsets>
</Label>
<Label id="noMissingIngredients" fx:id="missingTag" alignment="CENTER" contentDisplay="CENTER" prefHeight="69.0" prefWidth="127.0" text="# missing">
<font>
<Font size="24.0" />
</font>
</Label>
</children>
<opaqueInsets>
<Insets left="20.0" right="20.0" />
</opaqueInsets>
</HBox>
</children>
</VBox>
</graphic>
</Button> </Button>
</children> </children>
</Pane> </Pane>
<HBox prefHeight="88.0" prefWidth="500.0">
<children>
<Label alignment="CENTER" prefHeight="63.0" prefWidth="292.0" text="Ingredients missing:">
<font>
<Font size="18.0" />
</font>
<opaqueInsets>
<Insets left="20.0" right="20.0" />
</opaqueInsets>
</Label>
<Label id="noMissingIngredients" fx:id="missingTag" alignment="CENTER" contentDisplay="CENTER" prefHeight="69.0" prefWidth="127.0" text="# missing">
<font>
<Font size="24.0" />
</font>
</Label>
</children>
<opaqueInsets>
<Insets left="20.0" right="20.0" />
</opaqueInsets>
</HBox>
</children> </children>
</VBox> </VBox>
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
</Label> </Label>
</children> </children>
</Pane> </Pane>
<ListView id="list-cell" fx:id="fridgeList" prefHeight="470.0" prefWidth="378.0" stylesheets="@../style.css"> <ListView fx:id="fridgeList" prefHeight="470.0" prefWidth="378.0" styleClass="list-cell" stylesheets="@../style.css">
<VBox.margin> <VBox.margin>
<Insets right="20.0" /> <Insets right="20.0" />
</VBox.margin></ListView> </VBox.margin></ListView>
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
<children> <children>
<Label fx:id="missingList" stylesheets="@../style.css"> <Label fx:id="missingList" stylesheets="@../style.css">
<font> <font>
<Font name="System Bold" size="14.0" /> <Font name="System Bold" size="20.0" />
</font> </font>
<padding> <padding>
<Insets left="20.0" right="20.0" /> <Insets left="20.0" right="20.0" />
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
</BorderPane> </BorderPane>
</top> </top>
<center> <center>
<GridPane fx:id="recipeGrid" hgap="20.0" prefWidth="603.0" vgap="20.0" BorderPane.alignment="CENTER"> <GridPane fx:id="recipeGrid" hgap="20.0" prefHeight="443.0" prefWidth="609.0" vgap="20.0" BorderPane.alignment="CENTER">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment