merge main into feature/client-side-search
This commit is contained in:
commit
96eb19d74c
18 changed files with 528 additions and 138 deletions
|
|
@ -4,7 +4,6 @@ package client.scenes;
|
|||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import client.exception.UpdateException;
|
||||
import client.scenes.recipe.IngredientListCtrl;
|
||||
|
|
@ -23,7 +22,6 @@ import commons.ws.Topics;
|
|||
import commons.ws.messages.Message;
|
||||
import jakarta.inject.Inject;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
|
|
@ -48,18 +46,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
|||
public VBox detailsScreen;
|
||||
public HBox editableTitleArea;
|
||||
|
||||
|
||||
// all of these aren't used with only my part of the code
|
||||
// everything in the top bar ===
|
||||
@FXML
|
||||
private Button flagEnButton; //already here for advanced stuff
|
||||
|
||||
@FXML
|
||||
private Button flagNlButton; //already here for advanced stuff
|
||||
|
||||
@FXML
|
||||
private Button flagPlButton; //already here for advanced stuff
|
||||
|
||||
// everything in the left lane
|
||||
@FXML
|
||||
public Label recipesLabel;
|
||||
|
|
@ -113,6 +99,23 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
|||
|
||||
initializeWebSocket();
|
||||
}
|
||||
private void initRecipeList() {
|
||||
// Show recipe name in the list
|
||||
recipeList.setCellFactory(list -> new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(Recipe item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setText(empty || item == null ? "" : item.getName());
|
||||
}
|
||||
});
|
||||
// When your selection changes, update details in the panel
|
||||
recipeList.getSelectionModel().selectedItemProperty().addListener(
|
||||
(obs, oldRecipe, newRecipe) -> {
|
||||
showRecipeDetails(newRecipe);
|
||||
updateFavouriteButton(newRecipe);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Inject
|
||||
void setSearchBarCtrl(SearchBarCtrl searchBarCtrl) {
|
||||
|
|
@ -165,11 +168,7 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeComponents() {
|
||||
config = configService.getConfig();
|
||||
// TODO Reduce code duplication??
|
||||
private void initStepsIngredientsList() {
|
||||
// Initialize callback for ingredient list updates
|
||||
this.ingredientListCtrl.setUpdateCallback(newList -> {
|
||||
Recipe selectedRecipe = recipeList.getSelectionModel().getSelectedItem();
|
||||
|
|
@ -199,21 +198,12 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
|||
throw new UpdateException("Unable to update recipe to server for " + selectedRecipe);
|
||||
}
|
||||
});
|
||||
// Show recipe name in the list
|
||||
recipeList.setCellFactory(list -> new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(Recipe item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
setText(empty || item == null ? "" : item.getName());
|
||||
}
|
||||
});
|
||||
// When your selection changes, update details in the panel
|
||||
recipeList.getSelectionModel().selectedItemProperty().addListener(
|
||||
(obs, oldRecipe, newRecipe) -> {
|
||||
showRecipeDetails(newRecipe);
|
||||
updateFavouriteButton(newRecipe);
|
||||
}
|
||||
);
|
||||
}
|
||||
@Override
|
||||
public void initializeComponents() {
|
||||
config = configService.getConfig();
|
||||
initStepsIngredientsList();
|
||||
initRecipeList();
|
||||
|
||||
// Double-click to go to detail screen
|
||||
recipeList.setOnMouseClicked(event -> {
|
||||
|
|
@ -222,7 +212,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
|||
openSelectedRecipe();
|
||||
}
|
||||
});
|
||||
|
||||
this.initializeSearchBar();
|
||||
refresh();
|
||||
updateFavouriteButton(recipeList.getSelectionModel().getSelectedItem());
|
||||
|
|
@ -247,13 +236,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
|||
printRecipeButton.setText(getLocaleString("menu.button.print"));
|
||||
|
||||
recipesLabel.setText(getLocaleString("menu.label.recipes"));
|
||||
|
||||
// TODO propagate ResourceBundle lang changes to nested controller
|
||||
// ingredientsLabel.setText(getLocaleString("menu.label.ingredients"));
|
||||
// preparationLabel.setText(getLocaleString("menu.label.preparation"));
|
||||
|
||||
// addIngredientButton.setText(getLocaleString("menu.button.add.ingredient"));
|
||||
// addPreparationStepButton.setText(getLocaleString("menu.button.add.step"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -378,15 +360,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
|||
editableTitleArea.getChildren().add(edit);
|
||||
edit.requestFocus();
|
||||
}
|
||||
|
||||
// Language buttons
|
||||
@FXML
|
||||
private void switchLocale(ActionEvent event) {
|
||||
Button button = (Button)event.getSource();
|
||||
String lang = (String)button.getUserData();
|
||||
localeManager.setLocale(Locale.of(lang));
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void makePrintable() {
|
||||
System.out.println("Recipe printed");
|
||||
|
|
|
|||
100
client/src/main/java/client/scenes/LangSelectMenuCtrl.java
Normal file
100
client/src/main/java/client/scenes/LangSelectMenuCtrl.java
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
package client.scenes;
|
||||
|
||||
import client.utils.LocaleAware;
|
||||
import client.utils.LocaleManager;
|
||||
import com.google.inject.Inject;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* The language selection menu controller.
|
||||
* This needs to implement {@link LocaleAware LocaleAware} so that the
|
||||
* <code>getLocaleString(String)</code> function is available.
|
||||
*/
|
||||
public class LangSelectMenuCtrl implements LocaleAware {
|
||||
public ComboBox<String> langSelectMenu;
|
||||
private final LocaleManager manager;
|
||||
|
||||
@Inject
|
||||
public LangSelectMenuCtrl(LocaleManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the locale of the application depending on which button the user selects in the list.
|
||||
* @param event The action event triggered by the user.
|
||||
*/
|
||||
@FXML
|
||||
private void switchLocale(ActionEvent event) {
|
||||
String lang = langSelectMenu.getSelectionModel().getSelectedItem();
|
||||
manager.setLocale(Locale.of(lang));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeComponents() {
|
||||
langSelectMenu.getItems().setAll("en", "pl", "nl");
|
||||
langSelectMenu.setConverter(new StringConverter<String>() {
|
||||
@Override
|
||||
public String toString(String s) {
|
||||
if (s == null) {
|
||||
return "";
|
||||
}
|
||||
return getLocaleString("lang." + s + ".display");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fromString(String s) {
|
||||
return s;
|
||||
}
|
||||
});
|
||||
langSelectMenu.setCellFactory(list -> new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(String item, boolean empty) {
|
||||
final int IMAGE_HEIGHT = 32;
|
||||
final int HBOX_SPACING = 10;
|
||||
super.updateItem(item, empty);
|
||||
if (item == null || empty) {
|
||||
setText(null);
|
||||
setGraphic(null);
|
||||
return;
|
||||
}
|
||||
InputStream imageStream = getClass().getResourceAsStream("/flag_" + item + ".png");
|
||||
if (imageStream == null) {
|
||||
setGraphic(new HBox(new Label(getLocaleString("lang." + item + ".display"))));
|
||||
return;
|
||||
}
|
||||
Image img = new Image(imageStream);
|
||||
ImageView imageView = new ImageView(img);
|
||||
imageView.setFitHeight(IMAGE_HEIGHT);
|
||||
imageView.setFitWidth(IMAGE_HEIGHT);
|
||||
setGraphic(
|
||||
new HBox(
|
||||
HBOX_SPACING,
|
||||
imageView,
|
||||
new Label(getLocaleString("lang." + item + ".display"))
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateText() {
|
||||
// doesn't do anything; the text doesn't need to be updated.
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocaleManager getLocaleManager() {
|
||||
return manager;
|
||||
}
|
||||
}
|
||||
67
client/src/main/java/client/utils/PrintExportService.java
Normal file
67
client/src/main/java/client/utils/PrintExportService.java
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package client.utils;
|
||||
|
||||
import commons.Recipe;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class PrintExportService {
|
||||
|
||||
/**
|
||||
* Builds the String with all the recipe data in a human-readable format and returns said string.
|
||||
* @param recipe - Recipe Object that needs to be converted
|
||||
* @return - String Result that is the converted recipe object
|
||||
*/
|
||||
public static String buildRecipeText(Recipe recipe){
|
||||
String result = "Title: " + recipe.getName() + "\nRecipe ID: " + recipe.getId() + "\n" +
|
||||
"Ingredients: "; //Starts the string with name and recipe ID
|
||||
for(int i =0; i<recipe.getIngredients().size();i++){ // For loop adding ingredients one by one
|
||||
result += recipe.getIngredients().get(i) + ", ";
|
||||
}
|
||||
result += "\nSteps:\n";
|
||||
for(int i =0; i<recipe.getPreparationSteps().size();i++){ // Preparation Steps separated by new lines
|
||||
result += (i+1) + ": " + recipe.getPreparationSteps().get(i) + "\n";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that checks if the directory path of the selected directory is valid and throws and error.
|
||||
* if not valid
|
||||
* @param path - Path to directory
|
||||
*/
|
||||
public static void validateFolder(Path path){
|
||||
if (path == null) { //Null path value
|
||||
throw new IllegalArgumentException("Path is empty");
|
||||
}
|
||||
if(!Files.exists(path)){ //If Folder doesn't exist
|
||||
throw new IllegalArgumentException("Folder does not exist");
|
||||
}
|
||||
if(!Files.isDirectory(path)){ // If folder is not directory
|
||||
throw new IllegalArgumentException("Given path is not a folder");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that exports a plain-text String of recipe data, into a newly created file from
|
||||
* a selected directory provided as a path to the method and names said file based on the
|
||||
* nameOfFile param.
|
||||
* @param recipeData - String containing recipe data that will be written to file
|
||||
* @param dirFilePath - Path to Folder
|
||||
* @param nameOfFile - Name of file to be created
|
||||
*/
|
||||
public static void exportToFile(String recipeData, Path dirFilePath, String nameOfFile){
|
||||
validateFolder(dirFilePath); //runs validate Folder method to check if Directory path is valid
|
||||
Path filePath = dirFilePath.resolve(nameOfFile); //Creates a file with name provided in directory and stores path in PATH object
|
||||
try {
|
||||
Files.writeString(filePath, recipeData); // Writes the recipe data into the File.
|
||||
}
|
||||
catch (IOException e){
|
||||
System.err.println("An error occurred while writing to the file");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<?import javafx.scene.control.ComboBox?>
|
||||
<BorderPane prefHeight="800.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/25" xmlns:fx="http://javafx.com/fxml/1" fx:controller="client.scenes.FoodpalApplicationCtrl">
|
||||
|
||||
<!-- TOP BAR -->
|
||||
|
|
@ -23,58 +24,12 @@
|
|||
<padding>
|
||||
<Insets bottom="10" left="10" right="10" top="10" />
|
||||
</padding>
|
||||
<GridPane>
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="198.0" minWidth="10.0" prefWidth="130.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="95.0" minWidth="2.0" prefWidth="70.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints maxHeight="54.0" minHeight="10.0" prefHeight="54.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="25.0" minHeight="6.0" prefHeight="6.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
|
||||
<Label prefHeight="56.0" prefWidth="158.0" text="FoodPal">
|
||||
<font>
|
||||
<Font name="System Bold" size="29.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<ButtonBar prefHeight="40.0" prefWidth="200.0" GridPane.rowIndex="2">
|
||||
<buttons>
|
||||
<ToolBar prefHeight="35.0" prefWidth="123.0">
|
||||
<items>
|
||||
<Button fx:id="flagEnButton" minWidth="33.0" onAction="#switchLocale" userData="en" prefHeight="25.0" prefWidth="33.0" text="EN" />
|
||||
<Button fx:id="flagNlButton" onAction="#switchLocale" userData="nl" text="NL" />
|
||||
<Button fx:id="flagPlButton" onAction="#switchLocale" userData="pl" text="PL" />
|
||||
</items>
|
||||
</ToolBar>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</children>
|
||||
</GridPane>
|
||||
|
||||
<Pane HBox.hgrow="ALWAYS" />
|
||||
|
||||
<HBox spacing="5" />
|
||||
<GridPane prefHeight="90.0" prefWidth="114.0">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="315.0" minWidth="10.0" prefWidth="32.1666259765625" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="315.0" minWidth="10.0" prefWidth="24.8333740234375" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="173.0" minWidth="10.0" prefWidth="28.6666259765625" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="95.0" minWidth="10.0" prefWidth="34.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
|
||||
<Button fx:id="refreshButton" onAction="#refresh" prefHeight="25.0" prefWidth="34.0" text="⟳" GridPane.columnIndex="3" GridPane.rowIndex="2" />
|
||||
</children>
|
||||
</GridPane>
|
||||
</HBox>
|
||||
<Label prefHeight="56.0" prefWidth="158.0" text="FoodPal">
|
||||
<font>
|
||||
<Font name="System Bold" size="29.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</HBox>
|
||||
</top>
|
||||
|
||||
<!-- LEFT: RECIPE LIST -->
|
||||
|
|
@ -83,7 +38,8 @@
|
|||
<padding>
|
||||
<Insets bottom="10" left="10" right="10" top="10" />
|
||||
</padding>
|
||||
|
||||
<fx:include source="LangSelect.fxml" />
|
||||
<Button fx:id="refreshButton" onAction="#refresh" prefHeight="25.0" prefWidth="34.0" text="⟳" GridPane.columnIndex="3" GridPane.rowIndex="2" />
|
||||
<Label fx:id="recipesLabel" text="Recipes">
|
||||
<font>
|
||||
<Font name="System Bold" size="15.0" />
|
||||
|
|
|
|||
16
client/src/main/resources/client/scenes/LangSelect.fxml
Normal file
16
client/src/main/resources/client/scenes/LangSelect.fxml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import java.lang.*?>
|
||||
<?import java.util.*?>
|
||||
<?import javafx.scene.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<ComboBox
|
||||
fx:id="langSelectMenu"
|
||||
xmlns="http://javafx.com/javafx/25"
|
||||
xmlns:fx="http://javafx.com/fxml/1"
|
||||
onAction="#switchLocale"
|
||||
fx:controller="client.scenes.LangSelectMenuCtrl"
|
||||
>
|
||||
</ComboBox>
|
||||
BIN
client/src/main/resources/flag_en.png
Normal file
BIN
client/src/main/resources/flag_en.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 995 B |
BIN
client/src/main/resources/flag_nl.png
Normal file
BIN
client/src/main/resources/flag_nl.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 266 B |
BIN
client/src/main/resources/flag_pl.png
Normal file
BIN
client/src/main/resources/flag_pl.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 241 B |
|
|
@ -24,3 +24,7 @@ menu.button.remove.step=Remove Step
|
|||
menu.button.edit=Edit
|
||||
menu.button.clone=Clone
|
||||
menu.button.print=Print recipe
|
||||
|
||||
lang.en.display=English
|
||||
lang.nl.display=Dutch
|
||||
lang.pl.display=Polish
|
||||
|
|
@ -26,3 +26,6 @@ menu.button.clone=Clone
|
|||
menu.button.print=Print recipe
|
||||
|
||||
menu.search=Search...
|
||||
lang.en.display=English
|
||||
lang.nl.display=Nederlands
|
||||
lang.pl.display=Polski
|
||||
|
|
|
|||
|
|
@ -26,3 +26,6 @@ menu.button.clone=Dupliceren
|
|||
menu.button.print=Recept afdrukken
|
||||
|
||||
menu.search=Zoeken...
|
||||
lang.en.display=English
|
||||
lang.nl.display=Nederlands
|
||||
lang.pl.display=Polski
|
||||
|
|
|
|||
|
|
@ -26,3 +26,6 @@ menu.button.clone=Duplikuj
|
|||
menu.button.print=Drukuj przepis
|
||||
|
||||
menu.search=Szukaj...
|
||||
lang.en.display=English
|
||||
lang.nl.display=Nederlands
|
||||
lang.pl.display=Polski
|
||||
|
|
|
|||
70
client/src/test/java/client/scenes/PrintExportTest.java
Normal file
70
client/src/test/java/client/scenes/PrintExportTest.java
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
package client.scenes;
|
||||
|
||||
import client.utils.PrintExportService;
|
||||
import client.utils.ServerUtils;
|
||||
import commons.Recipe;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class PrintExportTest {
|
||||
static ServerUtils dv = new ServerUtils();
|
||||
@BeforeEach
|
||||
public void setup(){
|
||||
Assumptions.assumeTrue(dv.isServerAvailable(), "Server not available");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildRecipeTextTest(){
|
||||
List<String> ingredients = new ArrayList<>();
|
||||
ingredients.add("Banana");
|
||||
ingredients.add("Bread");
|
||||
final long testRecipeId = 1234L;
|
||||
List<String> preparationSteps = new ArrayList<>();
|
||||
preparationSteps.add("Mix Ingredients");
|
||||
preparationSteps.add("Heat in Oven");
|
||||
Recipe recipe1 = new Recipe(testRecipeId, "Banana Bread", ingredients, preparationSteps);
|
||||
|
||||
assertEquals("""
|
||||
Title: Banana Bread
|
||||
Recipe ID: 1234
|
||||
Ingredients: Banana, Bread,\s
|
||||
Steps:
|
||||
1: Mix Ingredients
|
||||
2: Heat in Oven
|
||||
""", PrintExportService.buildRecipeText(recipe1));
|
||||
|
||||
}
|
||||
|
||||
@TempDir
|
||||
Path tempDir;
|
||||
@Test
|
||||
public void validateFolderWithValidFolderTest(){
|
||||
assertDoesNotThrow(() -> PrintExportService.validateFolder(tempDir));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateFolderWithNullPathTest(){
|
||||
IllegalArgumentException i = assertThrows(IllegalArgumentException.class,
|
||||
()->PrintExportService.validateFolder(null));
|
||||
assertEquals("Path is empty", i.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateFolderWithFilePathTest() throws IOException {
|
||||
Path filePath = Files.createFile(tempDir.resolve("TestFile"));
|
||||
IllegalArgumentException i = assertThrows(IllegalArgumentException.class,
|
||||
()->PrintExportService.validateFolder(filePath));
|
||||
assertEquals("Given path is not a folder", i.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -50,6 +50,10 @@ public class Ingredient {
|
|||
+ carbsPer100g * KCAL_PER_GRAM_CARBS
|
||||
+ fatPer100g * KCAL_PER_GRAM_FAT;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public class RecipeIngredient {
|
|||
|
||||
public double amountInBaseUnit() {
|
||||
Unit unit = getUnit();
|
||||
if (unit == null || unit.isFormal() || unit.conversionFactor <= 0) {
|
||||
if (unit == null || !unit.isFormal() || unit.conversionFactor <= 0) {
|
||||
return 0.0;
|
||||
}
|
||||
return amount * unit.conversionFactor;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,95 @@
|
|||
package commons;
|
||||
//should i do it or wait for lines for next week
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public class RecipeIngredientTest {
|
||||
|
||||
private RecipeIngredient gram;
|
||||
private RecipeIngredient kilogram;
|
||||
private RecipeIngredient milliliter;
|
||||
private RecipeIngredient liter;
|
||||
private RecipeIngredient teaspoon;
|
||||
private RecipeIngredient tablespoon;
|
||||
private RecipeIngredient cup;
|
||||
private RecipeIngredient piece;
|
||||
private RecipeIngredient pinch;
|
||||
private RecipeIngredient handful;
|
||||
private RecipeIngredient toTaste;
|
||||
private RecipeIngredient invalid;
|
||||
|
||||
@BeforeEach
|
||||
void setup(){
|
||||
Recipe recipe = new Recipe();
|
||||
Ingredient ingredient = new Ingredient();
|
||||
gram = new RecipeIngredient(recipe,ingredient,1,"GRAM");
|
||||
kilogram = new RecipeIngredient(recipe,ingredient,1,"KILOGRAM");
|
||||
|
||||
milliliter = new RecipeIngredient(recipe,ingredient,1,"MILLILITER");
|
||||
liter = new RecipeIngredient(recipe,ingredient,1,"LITER");
|
||||
teaspoon = new RecipeIngredient(recipe,ingredient,1,"TEASPOON");
|
||||
tablespoon = new RecipeIngredient(recipe,ingredient,1,"TABLESPOON");
|
||||
cup = new RecipeIngredient(recipe,ingredient,1,"CUP");
|
||||
piece = new RecipeIngredient(recipe,ingredient,1,"PIECE");
|
||||
pinch = new RecipeIngredient(recipe,ingredient,1,"PINCH");
|
||||
handful = new RecipeIngredient(recipe,ingredient,1,"HANDFUL");
|
||||
toTaste = new RecipeIngredient(recipe,ingredient,1,"TO_TASTE");
|
||||
|
||||
invalid = new RecipeIngredient(recipe,ingredient,1,"INVALID");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void getFormalUnitTest(){
|
||||
assertEquals(Unit.GRAM, gram.getUnit());
|
||||
assertEquals(Unit.KILOGRAM, kilogram.getUnit());
|
||||
assertEquals(Unit.MILLILITER, milliliter.getUnit());
|
||||
assertEquals(Unit.LITER, liter.getUnit());
|
||||
assertEquals(Unit.TEASPOON, teaspoon.getUnit());
|
||||
assertEquals(Unit.TABLESPOON, tablespoon.getUnit());
|
||||
assertEquals(Unit.CUP, cup.getUnit());
|
||||
|
||||
assertEquals(Unit.PIECE, piece.getUnit());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getInformalUnitTest(){
|
||||
assertEquals(Unit.PINCH, pinch.getUnit());
|
||||
assertEquals(Unit.HANDFUL, handful.getUnit());
|
||||
assertEquals(Unit.TO_TASTE, toTaste.getUnit());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUnknownUnitTest(){
|
||||
assertNull(invalid.getUnit());
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertFormalToBaseUnit(){
|
||||
assertEquals(1000, kilogram.amountInBaseUnit());
|
||||
|
||||
assertEquals(1,milliliter.amountInBaseUnit());
|
||||
assertEquals(1000.0,liter.amountInBaseUnit());
|
||||
assertEquals(15.0,tablespoon.amountInBaseUnit());
|
||||
assertEquals(5,teaspoon.amountInBaseUnit());
|
||||
assertEquals(240.0,cup.amountInBaseUnit());
|
||||
|
||||
assertEquals(1.0,piece.amountInBaseUnit());
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertInformalToBaseUnit(){
|
||||
assertEquals(0,pinch.amountInBaseUnit());
|
||||
assertEquals(0,handful.amountInBaseUnit());
|
||||
assertEquals(0, toTaste.amountInBaseUnit());
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertUnknownToBaseUnit(){
|
||||
assertEquals(0,invalid.amountInBaseUnit());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,134 @@
|
|||
# Week 6 meeting agenda
|
||||
|
||||
| Key | Value |
|
||||
| ------------ |-----------------------------------------------------------------------------------------|
|
||||
| Date | Dec 18th |
|
||||
| Time | 14:45 |
|
||||
| Location | Hall D |
|
||||
| Chair | Rithvik Sriram |
|
||||
| Minute Taker | Mei Chang van der Werff |
|
||||
| Attendees | Mei Chang van der Werff, Natalia Cholewa, Rithvik Sriram, Aysegul Aydinlik, Steven Liu |
|
||||
| Key | Value |
|
||||
| ------------ |--------------------------------------------------------------------------------------------------|
|
||||
| Date | Dec 18th |
|
||||
| Time | 14:45 |
|
||||
| Location | Hall D |
|
||||
| Chair | Rithvik Sriram |
|
||||
| Minute Taker | Mei Chang van der Werff |
|
||||
| Attendees | Mei Chang van der Werff, Natalia Cholewa, Rithvik Sriram, Aysegul Aydinlik, Steven Liu (online) |
|
||||
## Table of contents
|
||||
1. (1 min) Introduction by chair
|
||||
2. (1 min) Any additions to the agenda?
|
||||
3. (1-2 min) TA announcements?
|
||||
4. (1 min) Go over TA feedback given
|
||||
5. (33 min) **Meeting content**
|
||||
1. (5 min) Week 6 progress in terms of completion
|
||||
- How far are we in terms of completion?
|
||||
2. (5 min) Progress check in terms of feature/issue completion
|
||||
- What have we completed/going to complete this week?
|
||||
3. (3 min) Small Showcase of the product
|
||||
* (Steven joins the meeting online)
|
||||
|
||||
4. (20 min) **Sprint planning week 7-8**
|
||||
- What needs to be done?
|
||||
- Handle Backend-Server code delegation
|
||||
- How do we do it?
|
||||
- Who does it?
|
||||
5. (2 min) Designate teams.
|
||||
6. (1 min) Who is the next chair and minute taker?
|
||||
1. (1 min) Introduction by chair
|
||||
> Meeting starts at **14:46**
|
||||
---
|
||||
|
||||
2. (1 min) Any additions to the agenda?
|
||||
> Tomorrow is the deadline for technology, it's best to go over the requirements real quick. \
|
||||
> To prevent failing this assignment like the previous 2
|
||||
---
|
||||
3. (1-2 min) TA announcements?
|
||||
> If there are any questions about my feedback ask them now
|
||||
4. (1 min) Go over TA feedback given
|
||||
>*We've made a little summary of our feedback, and had a few questions*
|
||||
> ### _Time Tracking_:
|
||||
>- **What exactly is expected from us for the time tracking?** \
|
||||
>We need to do an estimate of how long a task/issue might take. And after implementing it, you have to upload the actual taken time
|
||||
>- **Are the Mr and issues time tracking connected?** \
|
||||
>Yes, but not 100% sure. It's better to double-check it yourself
|
||||
>
|
||||
>### _Milestones_:
|
||||
>- **What was the exact issue, they are too big?** \
|
||||
>Our understanding of milestones is wrong, the milestones should be kinda our weekly tasks deadline. \
|
||||
>And when we don't finish a task it should be moved to the next milestone, of the next week.
|
||||
>
|
||||
> ### _UserStory (backlog)_:
|
||||
>- **How should we do this?** \
|
||||
> You can just put it in the issue description.Don't make it your mr title! \
|
||||
>A different groups makes the user story a parent issue and make children issues with the actual code, but we can choose what we want
|
||||
>>For now, we will just put the user Story in the issue description, we will discuss it later if we want to change the method or not
|
||||
>
|
||||
>
|
||||
>### _Commit and MR issues_:
|
||||
>- Not all commits are related to the Mr
|
||||
>- Our commits are too big, editing ±20 files are way too many. Try too keep it to 3-5 files max.
|
||||
>- Also do only client or only server in a commit, don't combine them.
|
||||
> - `mvn clean verify` before pushing to check whether the pipeline fails or not
|
||||
|
||||
---
|
||||
5. (33 min) Meeting content
|
||||
* (5 min) Week 6 progress in terms of completion
|
||||
- How far are we in terms of completion?
|
||||
>* 4.1 We still need to merge to connection of the print function, the Mr needed some changes but we can do that later. But do Rebase the MR as the branch is behind with A LOT of commits
|
||||
>* 4.2 We've done the websockets, we only need to merge it
|
||||
>* 4.3 We've done some backend parts but they are not yet connected to the client side
|
||||
>* 4.4 The favourite button and message were made this week
|
||||
>* 4.4 The search bar is currently in prgress on both the client and server side
|
||||
>* 4.5 We keep this for week 8 or next week if there are not enough tasks
|
||||
> >Let's focus on just connecting everything next week and after that we can start implementing 4.5
|
||||
|
||||
* (5 min) Progress check in terms of feature/issue completion
|
||||
- What have we completed/going to complete this week?
|
||||
> **Rithvik**: the backend of the searchbar and favourites is in progress. \
|
||||
> **Aysegul**: Made the favourite button and some UI elements, sadly enough no penguin icon yet :< \
|
||||
> **Oskar**: Finished the websocket implementation, however there is a small TODO left. Steven is going to do that. Also connected the config \
|
||||
> **Mei Chang**: Deleted all the left over example code, made the favourite recipe message(backend), created a test class, made unit use enums and did a small TODO about setters.\
|
||||
> **Natalia**: Almost finished the search bar (frontend) and improved testing on the client side. Will do some refactoring tomorrow. \
|
||||
> **Steven**: Forgot to ask. But did make the language buttons a dropdown box, and did some other things
|
||||
* (3 min) Small Showcase of the product
|
||||
>We didn't have a lot of time to review and merge our code, so there is not big difference compared to last week. \
|
||||
> We've shown the language dropdown box
|
||||
* (20 min) Sprint planning week 7-8
|
||||
- What needs to be done?
|
||||
- Handle Backend-Server code delegation
|
||||
- How do we do it?
|
||||
- Who does it?
|
||||
>We didn't really divide the tasks, just the roles. We will distribute tasks on the monday meeting. \
|
||||
> We did discuss some things general tasks that need to be done
|
||||
>
|
||||
> ### Server
|
||||
> - Testing
|
||||
> - Refactoring (Oskar)
|
||||
> - Some backend websocket things
|
||||
> - Add more endpoints
|
||||
>
|
||||
> ### Client
|
||||
> - Connecting everything to the UI
|
||||
> - Some frontend websocket things
|
||||
|
||||
|
||||
* (2 min) Designate teams.
|
||||
>There is not a lot of server code that needs to be done so we're keeping the 2/4 server/client distribution this week.\
|
||||
> Since there are still 3 people who need their LOC in server they have prioriy
|
||||
> - Ayse and Oskar will do Server
|
||||
> - The others will do Client
|
||||
|
||||
* (1 min) Who is the next chair and minute taker?
|
||||
> Mei Chang will be the Chair \
|
||||
> Aysegul will be the minute taker
|
||||
---
|
||||
>### Some Questions
|
||||
> **What's the criteria of production code in server?**\
|
||||
> Answer: recommendation to do 50/50 or 60/40 production/test code.
|
||||
>
|
||||
> **Can we copy code from the internet?**\
|
||||
> Answer: Yes, but do put the link of where you got the code from in comments
|
||||
>
|
||||
> **For a test I want to change the gitlab UI, is that allowed?**
|
||||
> **And I need to write a docx file for this, is the team fine with that?**\
|
||||
> Answer TA: Yes, but make sure it doesn't affect the other teammates \
|
||||
> Team: Yeah we're fine with that
|
||||
|
||||
---
|
||||
6. (2 min) Questions
|
||||
> #### We haven't yet talked about the technology requirements.
|
||||
> We might didn't split the ui correctly, there is too much logic in it.\
|
||||
> Server utils isn't server decorated
|
||||
>
|
||||
> **What is business logic?** \
|
||||
> Something about the fact that not everything should be in the same file, but split across files
|
||||
---
|
||||
7. (1 min) Summarize everything
|
||||
8. (1 min) TA remarks
|
||||
**Max time:** ~40 minutes
|
||||
>- 3 people still need to do server LOC; Aysegul, Oskar, Mei Chang.
|
||||
>- Next week our priority is connecting everything
|
||||
>- We need to improve our code contribution and planning based on the feedback
|
||||
---
|
||||
8. (1 min) TA remarks \
|
||||
Max time: ~40 minutes
|
||||
|
||||
> Ta will look at technology on Tuesday
|
||||
>
|
||||
>Meeting ends: **15:18**\
|
||||
>Actual meeting time: 32 minutes
|
||||
|
|
|
|||
|
|
@ -134,8 +134,7 @@ public class IngredientController {
|
|||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
// TODO: Refactor to use setters
|
||||
updated.id = id;
|
||||
updated.setId(id);
|
||||
Ingredient savedIngredient = ingredientRepository.save(updated);
|
||||
messagingTemplate.convertAndSend(Topics.INGREDIENTS, new CreateIngredientMessage(savedIngredient));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue