diff --git a/client/pom.xml b/client/pom.xml
index ebbef30..b9eb186 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -21,13 +21,7 @@
commons
0.0.1-SNAPSHOT
-
-
- org.slf4j
- slf4j-api
- 2.0.17
- compile
-
+
com.fasterxml.jackson.core
jackson-databind
diff --git a/client/src/main/java/client/Ingredient/IngredientController.java b/client/src/main/java/client/Ingredient/IngredientController.java
index e674ab6..429fecd 100644
--- a/client/src/main/java/client/Ingredient/IngredientController.java
+++ b/client/src/main/java/client/Ingredient/IngredientController.java
@@ -23,7 +23,7 @@ public class IngredientController {
private final RestTemplate restTemplate = new RestTemplate(); // Simplified REST client
@FXML
- public void handleDeleteIngredient(ActionEvent event) {
+ private void handleDeleteIngredient(ActionEvent event) {
// Get selected ingredient
Ingredient selectedIngredient = ingredientListView.getSelectionModel().getSelectedItem();
if (selectedIngredient == null) {
diff --git a/client/src/main/java/client/MyModule.java b/client/src/main/java/client/MyModule.java
index 14eaa3e..4d027ca 100644
--- a/client/src/main/java/client/MyModule.java
+++ b/client/src/main/java/client/MyModule.java
@@ -21,11 +21,6 @@ import client.scenes.nutrition.NutritionDetailsCtrl;
import client.scenes.nutrition.NutritionViewCtrl;
import client.scenes.recipe.IngredientListCtrl;
import client.scenes.recipe.RecipeStepListCtrl;
-import client.scenes.shopping.ShoppingListCtrl;
-import client.scenes.shopping.ShoppingListNewItemPromptCtrl;
-import client.service.ShoppingListService;
-import client.service.ShoppingListServiceImpl;
-import client.service.ShoppingListViewModel;
import client.utils.ConfigService;
import client.utils.LocaleManager;
import client.utils.server.ServerUtils;
@@ -62,10 +57,6 @@ public class MyModule implements Module {
binder.bind(new TypeLiteral>() {}).toInstance(
new WebSocketDataService<>()
);
- binder.bind(ShoppingListNewItemPromptCtrl.class).in(Scopes.SINGLETON);
- binder.bind(ShoppingListCtrl.class).in(Scopes.SINGLETON);
- binder.bind(ShoppingListViewModel.class).toInstance(new ShoppingListViewModel());
- binder.bind(ShoppingListService.class).to(ShoppingListServiceImpl.class);
binder.bind(new TypeLiteral>() {}).toInstance(
new WebSocketDataService<>()
);
diff --git a/client/src/main/java/client/UI.java b/client/src/main/java/client/UI.java
index da3a2b3..752dbaf 100644
--- a/client/src/main/java/client/UI.java
+++ b/client/src/main/java/client/UI.java
@@ -2,7 +2,6 @@ package client;
import client.scenes.FoodpalApplicationCtrl;
import client.scenes.MainCtrl;
-import client.scenes.ServerConnectionDialogCtrl;
import client.utils.server.ServerUtils;
import com.google.inject.Injector;
import javafx.application.Application;
@@ -28,14 +27,9 @@ public class UI extends Application {
var serverUtils = INJECTOR.getInstance(ServerUtils.class);
if (!serverUtils.isServerAvailable()) {
- var connectionHandler = INJECTOR.getInstance(ServerConnectionDialogCtrl.class);
- boolean serverConnected = connectionHandler.promptForURL();
-
- if(!serverConnected){
- var msg = "User Cancelled Server connection. Shutting down";
- System.err.print(msg);
- return;
- }
+ var msg = "Server needs to be started before the client, but it does not seem to be available. Shutting down.";
+ System.err.println(msg);
+ return;
}
var foodpal = FXML.load(FoodpalApplicationCtrl.class, "client", "scenes", "FoodpalApplication.fxml");
diff --git a/client/src/main/java/client/exception/DuplicateIngredientException.java b/client/src/main/java/client/exception/DuplicateIngredientException.java
deleted file mode 100644
index af04346..0000000
--- a/client/src/main/java/client/exception/DuplicateIngredientException.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package client.exception;
-
-public class DuplicateIngredientException extends Exception{
- private final String ingredientName;
-
- public DuplicateIngredientException(String ingredientName){
- super("An ingredient with name " + ingredientName + " already exists, please provide a different name");
- this.ingredientName = ingredientName;
- }
-
- public DuplicateIngredientException(String ingredientName, String message){
- super(message);
- this.ingredientName = ingredientName;
- }
-
- public String getIngredientName() {
- return ingredientName;
- }
-
-}
diff --git a/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java b/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java
index 181279b..e7cb0df 100644
--- a/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java
+++ b/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java
@@ -2,17 +2,17 @@ package client.scenes;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.logging.Logger;
+import java.util.stream.Collectors;
-import client.UI;
import client.exception.InvalidModificationException;
import client.scenes.nutrition.NutritionViewCtrl;
import client.scenes.recipe.RecipeDetailCtrl;
-import client.scenes.shopping.ShoppingListCtrl;
import client.utils.Config;
import client.utils.ConfigService;
import client.utils.DefaultValueFactory;
@@ -21,6 +21,7 @@ import client.utils.LocaleManager;
import client.utils.server.ServerUtils;
import client.utils.WebSocketDataService;
import client.utils.WebSocketUtils;
+import commons.Ingredient;
import commons.Recipe;
import commons.ws.Topics;
@@ -31,20 +32,14 @@ import commons.ws.messages.Message;
import commons.ws.messages.UpdateRecipeMessage;
import jakarta.inject.Inject;
import javafx.application.Platform;
-import javafx.beans.property.ListProperty;
-import javafx.beans.property.SimpleListProperty;
-import javafx.collections.FXCollections;
-import javafx.collections.ListChangeListener;
import javafx.fxml.FXML;
-import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
+import javafx.scene.control.TextInputDialog;
import javafx.scene.control.ToggleButton;
-import javafx.scene.paint.Color;
-import javafx.stage.Stage;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
@@ -70,7 +65,8 @@ public class FoodpalApplicationCtrl implements LocaleAware {
@FXML
public ListView recipeList;
- private final ListProperty favouriteRecipeList = new SimpleListProperty<>();
+ @FXML
+ private ListView ingredientListView;
@FXML
private Button addRecipeButton;
@@ -88,8 +84,7 @@ public class FoodpalApplicationCtrl implements LocaleAware {
@FXML
private ToggleButton favouritesOnlyToggle;
- @FXML
- private Button manageIngredientsButton;
+ private List allRecipes = new ArrayList<>();
@FXML
private Label updatedBadge;
@@ -205,12 +200,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
} //gives star in front fav items
boolean fav = config.isFavourite(item.getId());
setText((fav ? "★ " : "") + item.getName());
-
- if(fav){
- setTextFill(Color.BLUE);
- }else{
- setTextFill(Color.BLACK);
- }
}
});
// When your selection changes, update details in the panel
@@ -288,13 +277,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
openSelectedRecipe();
}
});
- recipeList.getItems().addListener((ListChangeListener.Change extends Recipe> c) -> {
- favouriteRecipeList.set(
- FXCollections.observableList(
- recipeList.getItems().stream().filter(r -> config.isFavourite(r.getId())).toList()
- ));
- System.out.println(favouriteRecipeList);
- });
this.initializeSearchBar();
refresh();
@@ -308,9 +290,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
removeRecipeButton.setText(getLocaleString("menu.button.remove.recipe"));
cloneRecipeButton.setText(getLocaleString("menu.button.clone"));
recipesLabel.setText(getLocaleString("menu.label.recipes"));
-
- favouritesOnlyToggle.setText(getLocaleString("menu.button.favourites"));
- manageIngredientsButton.setText(getLocaleString("menu.button.ingredients"));
}
@Override
@@ -333,7 +312,8 @@ public class FoodpalApplicationCtrl implements LocaleAware {
logger.severe(msg);
printError(msg);
}
- recipeList.getItems().setAll(recipes);
+
+ allRecipes = new ArrayList<>(recipes);
applyRecipeFilterAndKeepSelection();
showUpdatedBadge();
@@ -429,21 +409,17 @@ public class FoodpalApplicationCtrl implements LocaleAware {
public void applyRecipeFilterAndKeepSelection() {
Recipe selected = recipeList.getSelectionModel().getSelectedItem();
Long selectedId = selected == null ? null : selected.getId();
- List view = recipeList.getItems().stream().toList();
+
+ List view = allRecipes;
if (favouritesOnlyToggle != null && favouritesOnlyToggle.isSelected()) {
- view = favouriteRecipeList.get();
- recipeList.getItems().setAll(view);
- }
- try {
- if (favouritesOnlyToggle != null && !favouritesOnlyToggle.isSelected()) {
- recipeList.getItems().setAll(server.getRecipes(config.getRecipeLanguages()));
- }
- }
- catch (IOException | InterruptedException e) {
- logger.severe(e.getMessage());
+ view = allRecipes.stream()
+ .filter(r -> config.isFavourite(r.getId()))
+ .collect(Collectors.toList());
}
+ recipeList.getItems().setAll(view);
+
// restore selection if possible
if (selectedId != null) {
Recipe match = view.stream()
@@ -463,6 +439,114 @@ public class FoodpalApplicationCtrl implements LocaleAware {
this.recipeDetailController.refreshFavouriteButton();
this.recipeDetailController.setVisible(!recipeList.getItems().isEmpty());
}
+
+ //Delete Ingredient button click
+ @FXML
+ private void handleDeleteIngredient() {
+ // Get selected ingredient
+ Ingredient selectedIngredient = ingredientListView.getSelectionModel().getSelectedItem();
+
+ if (selectedIngredient == null) {
+ // Show an error message if no ingredient is selected
+ showError("No ingredient selected", "Please select an ingredient to delete.");
+ return;
+ }
+
+ // Check if the ingredient is used in any recipe
+ checkIngredientUsage(selectedIngredient);
+ }
+
+ // Check if ingredient is used in any recipe before deleting
+ private void checkIngredientUsage(Ingredient ingredient) {
+ try {
+ long usageCount = server.getIngredientUsage(ingredient.getId()); // Check ingredient usage via ServerUtils
+
+ if (usageCount > 0) {
+ // If ingredient is used, show a warning dialog
+ showWarningDialog(ingredient, usageCount);
+ } else {
+ // If not used, delete
+ deleteIngredient(ingredient);
+ }
+ } catch (IOException | InterruptedException e) {
+ showError("Error", "Failed to check ingredient usage: " + e.getMessage());
+ }
+ }
+
+ private void deleteIngredient(Ingredient ingredient) {
+ try {
+ server.deleteIngredient(ingredient.getId()); // Call ServerUtils to delete the ingredient
+ showConfirmation("Success", "Ingredient '" + ingredient.getName() + "' has been deleted.");
+ refreshIngredientList(); // refresh the ingredient list
+ } catch (IOException | InterruptedException e) {
+ showError("Error", "Failed to delete ingredient: " + e.getMessage());
+ }
+ }
+
+ private void showWarningDialog(Ingredient ingredient, long usedInRecipes) {
+ Alert alert = new Alert(Alert.AlertType.WARNING);
+ }
+
+ private void showError(String title, String message) {
+ Alert alert = new Alert(Alert.AlertType.ERROR);
+ alert.setTitle(title);
+ alert.setHeaderText(null);
+ alert.setContentText(message);
+ alert.showAndWait();
+ }
+
+ private void showConfirmation(String title, String message) {
+ Alert alert = new Alert(Alert.AlertType.INFORMATION);
+ alert.setTitle(title);
+ alert.setHeaderText(null);
+ alert.setContentText(message);
+ alert.showAndWait();
+ }
+
+ private void refreshIngredientList() {
+ // Refresh
+ ingredientListView.getItems().clear();
+
+ }
+
+
+ @FXML
+ private void handleAddIngredient() {
+ //ask the user for the ingredient name
+ TextInputDialog dialog = new TextInputDialog();
+ dialog.setTitle("Add Ingredient");
+ dialog.setHeaderText("Enter the ingredient name:");
+ dialog.setContentText("Ingredient:");
+
+ // Wait for the user to enter a value
+ Optional result = dialog.showAndWait();
+
+ result.ifPresent(name -> {
+ // Create a new Ingredient object
+ Ingredient newIngredient = new Ingredient();
+ newIngredient.setName(name);
+
+ // Add the new ingredient to the ListView
+ ingredientListView.getItems().add(newIngredient);
+ });
+ }
+
+ // display ingredient name
+ @FXML
+ private void initializeIngredients() {
+ ingredientListView.setCellFactory(list -> new ListCell() {
+ @Override
+ protected void updateItem(Ingredient item, boolean empty) {
+ super.updateItem(item, empty);
+ if (empty || item == null) {
+ setText(null);
+ } else {
+ setText(item.getName()); // Display the ingredient name in the ListView
+ }
+ }
+ });
+ }
+
@FXML
private void openIngredientsPopup() {
try {
@@ -474,7 +558,7 @@ public class FoodpalApplicationCtrl implements LocaleAware {
var root = pair.getValue();
var stage = new javafx.stage.Stage();
- stage.setTitle(getLocaleString("menu.ingredients.title"));
+ stage.setTitle("Nutrition values view");
stage.initModality(javafx.stage.Modality.APPLICATION_MODAL);
stage.setScene(new javafx.scene.Scene(root));
stage.showAndWait();
@@ -514,14 +598,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
updatedBadgeTimer.playFromStart();
}
- public void openShoppingListWindow() throws IOException {
- var root = UI.getFXML().load(ShoppingListCtrl.class, "client", "scenes", "shopping", "ShoppingList.fxml");
- Stage stage = new Stage();
- stage.setTitle(this.getLocaleString("menu.shopping.title"));
- stage.setScene(new Scene(root.getValue()));
- stage.show();
- }
-
}
diff --git a/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java b/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java
index c06a04a..dfcd7be 100644
--- a/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java
+++ b/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java
@@ -1,17 +1,11 @@
package client.scenes.Ingredient;
-import client.exception.DuplicateIngredientException;
import client.scenes.nutrition.NutritionDetailsCtrl;
-import client.utils.LocaleAware;
-import client.utils.LocaleManager;
import client.utils.server.ServerUtils;
import commons.Ingredient;
import jakarta.inject.Inject;
import javafx.fxml.FXML;
-
import javafx.scene.control.Alert;
-import javafx.scene.control.Button;
-import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TextInputDialog;
@@ -25,18 +19,10 @@ import java.util.logging.Logger;
//TODO and check for capital letter milk and MILK are seen as different
-public class IngredientListCtrl implements LocaleAware {
+public class IngredientListCtrl {
+
private final ServerUtils server;
- private final LocaleManager localeManager;
private final Logger logger = Logger.getLogger(IngredientListCtrl.class.getName());
-
- @FXML
- public Label ingredientsLabel;
- public Button addButton;
- public Button refreshButton;
- public Button deleteButton;
- public Button closeButton;
-
@FXML
private ListView ingredientListView;
@FXML
@@ -45,30 +31,14 @@ public class IngredientListCtrl implements LocaleAware {
@Inject
public IngredientListCtrl(
ServerUtils server,
- LocaleManager localeManager,
NutritionDetailsCtrl nutritionDetailsCtrl
) {
this.server = server;
- this.localeManager = localeManager;
this.nutritionDetailsCtrl = nutritionDetailsCtrl;
}
- @Override
- public void updateText() {
- ingredientsLabel.setText(getLocaleString("menu.label.ingredients"));
- addButton.setText(getLocaleString("menu.button.add"));
- refreshButton.setText(getLocaleString("menu.button.refresh"));
- deleteButton.setText(getLocaleString("menu.button.delete"));
- closeButton.setText(getLocaleString("menu.button.close"));
- }
-
- @Override
- public LocaleManager getLocaleManager() {
- return this.localeManager;
- }
-
- @Override
- public void initializeComponents() {
+ @FXML
+ public void initialize() {
ingredientListView.setCellFactory(list -> new ListCell<>() {
@Override
protected void updateItem(Ingredient item, boolean empty) {
@@ -90,7 +60,6 @@ public class IngredientListCtrl implements LocaleAware {
refresh();
}
-
@FXML
private void addIngredient() {
TextInputDialog dialog = new TextInputDialog();
@@ -114,11 +83,10 @@ public class IngredientListCtrl implements LocaleAware {
refresh(); // reload list from server
} catch (IOException | InterruptedException e) {
showError("Failed to create ingredient: " + e.getMessage());
- } catch (DuplicateIngredientException e) {
- throw new RuntimeException(e);
}
}
+
@FXML
private void refresh() {
try {
diff --git a/client/src/main/java/client/scenes/LangSelectMenuCtrl.java b/client/src/main/java/client/scenes/LangSelectMenuCtrl.java
index 76fdef8..cc764f0 100644
--- a/client/src/main/java/client/scenes/LangSelectMenuCtrl.java
+++ b/client/src/main/java/client/scenes/LangSelectMenuCtrl.java
@@ -1,6 +1,5 @@
package client.scenes;
-import client.utils.Config;
import client.utils.LocaleAware;
import client.utils.LocaleManager;
import com.google.inject.Inject;
@@ -42,12 +41,11 @@ public class LangSelectMenuCtrl implements LocaleAware {
String lang = langSelectMenu.getSelectionModel().getSelectedItem();
logger.info("Switching locale to " + lang);
manager.setLocale(Locale.of(lang));
- initializeComponents();
}
@Override
public void initializeComponents() {
- langSelectMenu.getItems().setAll(Config.languages);
+ langSelectMenu.getItems().setAll("en", "pl", "nl", "zht", "zhc", "tok", "tr");
langSelectMenu.setValue(manager.getLocale().getLanguage());
langSelectMenu.setConverter(new StringConverter() {
@Override
diff --git a/client/src/main/java/client/scenes/LanguageFilterCtrl.java b/client/src/main/java/client/scenes/LanguageFilterCtrl.java
index fd1de08..80d01a0 100644
--- a/client/src/main/java/client/scenes/LanguageFilterCtrl.java
+++ b/client/src/main/java/client/scenes/LanguageFilterCtrl.java
@@ -1,6 +1,5 @@
package client.scenes;
-import client.utils.Config;
import client.utils.ConfigService;
import client.utils.LocaleAware;
import client.utils.LocaleManager;
@@ -55,7 +54,7 @@ public class LanguageFilterCtrl implements LocaleAware {
public void initializeComponents() {
var items = this.langFilterMenu.getItems();
- final List languages = List.of(Config.languages);
+ final List languages = List.of("en", "nl", "pl", "tok", "tr");
this.selectedLanguages = this.configService.getConfig().getRecipeLanguages();
this.updateMenuButtonDisplay();
diff --git a/client/src/main/java/client/scenes/SearchBarCtrl.java b/client/src/main/java/client/scenes/SearchBarCtrl.java
index c37f188..065455c 100644
--- a/client/src/main/java/client/scenes/SearchBarCtrl.java
+++ b/client/src/main/java/client/scenes/SearchBarCtrl.java
@@ -10,15 +10,11 @@ import javafx.animation.PauseTransition;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
-import javafx.scene.input.KeyCode;
import javafx.util.Duration;
import java.io.IOException;
-import java.util.Arrays;
import java.util.List;
-import java.util.Locale;
import java.util.function.Consumer;
-import java.util.stream.Collectors;
/**
* Controller for the search bar component.
@@ -103,11 +99,7 @@ public class SearchBarCtrl implements LocaleAware {
currentSearchTask = new Task<>() {
@Override
protected List call() throws IOException, InterruptedException {
- var recipes = serverUtils.getRecipesFiltered(
- "",
- configService.getConfig().getRecipeLanguages()
- );
- return applyMultiTermAndFilter(recipes, filter);
+ return serverUtils.getRecipesFiltered(filter, configService.getConfig().getRecipeLanguages());
}
};
@@ -154,61 +146,8 @@ public class SearchBarCtrl implements LocaleAware {
});
this.searchField.setOnKeyReleased(event -> {
- if (event.getCode() == KeyCode.ESCAPE) {
- searchField.clear();
- this.onSearch();
- return;
- }
// This cancels the current debounce timer and restarts it.
this.searchDebounce.playFromStart();
});
}
- private List applyMultiTermAndFilter(List recipes, String query) {
- if (recipes == null) {
- return List.of();
- }
- if (query == null || query.isBlank()) {
- return recipes;
- }
-
- var tokens = Arrays.stream(query.toLowerCase(Locale.ROOT).split("[\\s,]+"))
- .map(String::trim)
- .filter(s -> !s.isBlank())
- .filter(s -> !s.equals("and"))
- .toList();
-
- if (tokens.isEmpty()) {
- return recipes;
- }
-
- return recipes.stream()
- .filter(r -> {
- var sb = new StringBuilder();
-
- if (r.getName() != null) {
- sb.append(r.getName()).append(' ');
- }
-
- if (r.getIngredients() != null) {
- r.getIngredients().forEach(i -> {
- if (i != null) {
- sb.append(i).append(' ');
- }
- });
- }
-
- if (r.getPreparationSteps() != null) {
- r.getPreparationSteps().forEach(s -> {
- if (s != null) {
- sb.append(s).append(' ');
- }
- });
- }
-
- var haystack = sb.toString().toLowerCase(Locale.ROOT);
- return tokens.stream().allMatch(haystack::contains);
- })
- .collect(Collectors.toList());
- }
-
}
diff --git a/client/src/main/java/client/scenes/ServerConnectionDialogCtrl.java b/client/src/main/java/client/scenes/ServerConnectionDialogCtrl.java
deleted file mode 100644
index 4283d01..0000000
--- a/client/src/main/java/client/scenes/ServerConnectionDialogCtrl.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package client.scenes;
-
-
-import client.utils.ConfigService;
-import client.utils.server.ServerUtils;
-import com.google.inject.Inject;
-import javafx.scene.control.Alert;
-import javafx.scene.control.ButtonType;
-import javafx.scene.control.TextInputDialog;
-
-import java.util.Optional;
-
-
-public class ServerConnectionDialogCtrl {
-
- private final ConfigService configService;
- private final ServerUtils serverUtils;
-
-
-
- @Inject
- public ServerConnectionDialogCtrl(ConfigService configService, ServerUtils serverUtils) {
- this.configService = configService;
- this.serverUtils = serverUtils;
-
- }
-
- /**
- *
- * @return a boolean for if the user got connected to server or
- */
- public boolean promptForURL(){
- Alert error = new Alert(Alert.AlertType.ERROR); //creates an error alert
- error.setTitle("Server is Unavailable");
- error.setHeaderText("Unable to connect to Server");
- error.setContentText("The server at " + configService.getConfig().getServerUrl()
- + " is not available\n\n Would you like to try a different Server URL?");
-
- error.getButtonTypes().setAll(ButtonType.YES, ButtonType.NO);
- Optional userChoice = error.showAndWait(); //asks if user wants to input server URL
-
- if(userChoice.isEmpty() || userChoice.get() == ButtonType.NO){
- return false;
- }
-
- while(true){ // Keeps asking the user until either a valid url is provided or the user exits
- TextInputDialog dialog =
- new TextInputDialog(configService.getConfig().getServerUrl());
- dialog.setTitle("Enter new server URL");
- dialog.setContentText("Server URL:");
- Optional userRes = dialog.showAndWait();
- if(userRes.isEmpty()){
- return false; //user cancelled the operation
- }
- String newServer = userRes.get().trim();
-
- if(newServer.isEmpty()){
- Alert alert = new Alert(Alert.AlertType.WARNING);
- alert.setTitle("Invalid Input");
- alert.setHeaderText("Invalid server URL");
- alert.setContentText("Please enter a valid URL");
- alert.showAndWait();
- continue;
- }
- configService.getConfig().setServerUrl(newServer);
- if(serverUtils.isServerAvailable()){
- configService.save();
- Alert success = new Alert(Alert.AlertType.INFORMATION);
- success.setTitle("Success");
- success.setHeaderText("Connected to Server");
- success.setContentText("Successfully connected to the server!");
- success.showAndWait();
- return true;
- }
- else{
- Alert retry = new Alert(Alert.AlertType.ERROR);
- retry.setTitle("Failed");
- retry.setHeaderText("Failed to connect to Server");
- retry.setContentText("Would you like to try another URL?");
- retry.getButtonTypes().setAll(ButtonType.YES, ButtonType.NO);
- Optional result = retry.showAndWait();
- if(result.isEmpty() || result.get() == ButtonType.NO){
- return false;
- }
-
- }
-
- }
- }
-
-
-
-
-}
diff --git a/client/src/main/java/client/scenes/nutrition/NutritionDetailsCtrl.java b/client/src/main/java/client/scenes/nutrition/NutritionDetailsCtrl.java
index d8351f3..c7c968f 100644
--- a/client/src/main/java/client/scenes/nutrition/NutritionDetailsCtrl.java
+++ b/client/src/main/java/client/scenes/nutrition/NutritionDetailsCtrl.java
@@ -66,7 +66,7 @@ public class NutritionDetailsCtrl implements LocaleAware {
this.proteinInputElement.textProperty().bindBidirectional(vm.proteinProperty(), new NumberStringConverter());
this.carbInputElement.textProperty().bindBidirectional(vm.carbsProperty(), new NumberStringConverter());
this.estimatedKcalLabel.textProperty().bind(Bindings.createStringBinding(
- () -> String.format("Estimated energy value: %.1f kcal/100g", vm.getKcal()), vm.kcalProperty()
+ () -> String.format("Estimated energy value: %.1f", vm.getKcal()), vm.kcalProperty()
));
});
this.nutritionValueContainer.addEventHandler(KeyEvent.KEY_RELEASED, event -> {
diff --git a/client/src/main/java/client/scenes/recipe/IngredientListCtrl.java b/client/src/main/java/client/scenes/recipe/IngredientListCtrl.java
index 679e05d..7bb392f 100644
--- a/client/src/main/java/client/scenes/recipe/IngredientListCtrl.java
+++ b/client/src/main/java/client/scenes/recipe/IngredientListCtrl.java
@@ -8,7 +8,6 @@ import com.google.inject.Inject;
import commons.FormalIngredient;
import commons.Recipe;
import java.util.ArrayList;
-import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
@@ -79,13 +78,7 @@ public class IngredientListCtrl implements LocaleAware {
if (recipe == null) {
this.ingredients = FXCollections.observableArrayList(new ArrayList<>());
} else {
- List ingredientList = recipe
- .getIngredients()
- .stream()
- .sorted(Comparator.comparing(ingredient -> ingredient
- .getIngredient()
- .getName()))
- .toList();
+ List ingredientList = recipe.getIngredients();
this.ingredients = FXCollections.observableArrayList(ingredientList);
}
diff --git a/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java b/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java
index 091befd..de27245 100644
--- a/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java
+++ b/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java
@@ -1,7 +1,6 @@
package client.scenes.recipe;
import client.utils.server.ServerUtils;
-import client.exception.DuplicateIngredientException;
import commons.Ingredient;
import jakarta.inject.Inject;
import javafx.fxml.FXML;
@@ -68,15 +67,8 @@ public class IngredientsPopupCtrl {
server.createIngredient(name); // calls POST /api/ingredients
refresh(); // reload list from server
} catch (IOException | InterruptedException e) {
-
showError("Failed to create ingredient: " + e.getMessage());
- } catch (DuplicateIngredientException e) {
- showError("An ingredient with the name " + name + " already exists." +
- " Please provide a different name."); //checks if error received has the DUPLICATE string and creates a showError instance with an appropriate error message and description
-
}
-
-
}
diff --git a/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java b/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java
index d923ffd..d072669 100644
--- a/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java
+++ b/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java
@@ -2,7 +2,6 @@ package client.scenes.recipe;
import client.exception.UpdateException;
import client.scenes.FoodpalApplicationCtrl;
-import client.service.ShoppingListService;
import client.utils.Config;
import client.utils.ConfigService;
import client.utils.LocaleAware;
@@ -11,7 +10,6 @@ import client.utils.PrintExportService;
import client.utils.server.ServerUtils;
import client.utils.WebSocketDataService;
import com.google.inject.Inject;
-import commons.FormalIngredient;
import commons.Recipe;
import java.io.File;
@@ -20,9 +18,6 @@ import java.nio.file.Path;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
-
-import javafx.beans.binding.Bindings;
-import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
@@ -49,12 +44,8 @@ public class RecipeDetailCtrl implements LocaleAware {
private final FoodpalApplicationCtrl appCtrl;
private final ConfigService configService;
private final WebSocketDataService webSocketDataService;
- private final ShoppingListService shoppingListService;
public Spinner scaleSpinner;
- public Label inferredKcalLabel;
- public Spinner servingsSpinner;
- public Label inferredServeSizeLabel;
@FXML
private IngredientListCtrl ingredientListController;
@@ -71,14 +62,12 @@ public class RecipeDetailCtrl implements LocaleAware {
ServerUtils server,
FoodpalApplicationCtrl appCtrl,
ConfigService configService,
- ShoppingListService listService,
WebSocketDataService webSocketDataService) {
this.localeManager = localeManager;
this.server = server;
this.appCtrl = appCtrl;
this.configService = configService;
this.webSocketDataService = webSocketDataService;
- this.shoppingListService = listService;
}
@FXML
@@ -165,20 +154,12 @@ public class RecipeDetailCtrl implements LocaleAware {
// If there is a scale
// Prevents issues from first startup
- if (scaleSpinner.getValue() != null && servingsSpinner.getValue() != null) {
+ if (scaleSpinner.getValue() != null) {
Double scale = scaleSpinner.getValue();
+
// see impl. creates a scaled context for the recipe such that its non-scaled value is kept as a reference.
this.recipeView = new ScalableRecipeView(recipe, scale);
- // TODO i18n
- inferredKcalLabel.textProperty().bind(Bindings.createStringBinding(() ->
- String.format("Inferred %.1f kcal/100g for this recipe",
- Double.isNaN(this.recipeView.scaledKcalProperty().get()) ?
- 0.0 : this.recipeView.scaledKcalProperty().get())
- , this.recipeView.scaledKcalProperty()));
- recipeView.servingsProperty().set(servingsSpinner.getValue());
- inferredServeSizeLabel.textProperty().bind(Bindings.createStringBinding(
- () -> String.format("Inferred size per serving: %.1f g", recipeView.servingSizeProperty().get()),
- recipeView.servingSizeProperty()));
+
// expose the scaled view to list controllers
this.ingredientListController.refetchFromRecipe(this.recipeView.getScaled());
this.stepListController.refetchFromRecipe(this.recipeView.getScaled());
@@ -405,7 +386,7 @@ public class RecipeDetailCtrl implements LocaleAware {
public void initializeComponents() {
initStepsIngredientsList();
// creates a new scale spinner with an arbitrary max scale
- scaleSpinner.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(1, Double.MAX_VALUE, 1));
+ scaleSpinner.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0, Double.MAX_VALUE, 1));
scaleSpinner.setEditable(true);
scaleSpinner.valueProperty().addListener((observable, oldValue, newValue) -> {
if (newValue == null) {
@@ -414,23 +395,6 @@ public class RecipeDetailCtrl implements LocaleAware {
// triggers a UI update each time the spinner changes to a different value.
setCurrentlyViewedRecipe(recipe);
});
- servingsSpinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(1, Integer.MAX_VALUE, 1));
- servingsSpinner.setEditable(true);
- servingsSpinner.valueProperty().addListener((observable, oldValue, newValue) -> {
- if (newValue == null) {
- return;
- }
- setCurrentlyViewedRecipe(recipe);
- });
- langSelector.getItems().addAll(Config.languages);
- }
-
- public void handleAddAllToShoppingList(ActionEvent actionEvent) {
- System.out.println("handleAddAllToShoppingList");
- // TODO BACKLOG Add overview screen
- recipe.getIngredients().stream()
- .filter(x -> x.getClass().equals(FormalIngredient.class))
- .map(FormalIngredient.class::cast)
- .forEach(x -> shoppingListService.putIngredient(x, recipe));
+ langSelector.getItems().addAll("en", "nl", "pl", "tok");
}
}
diff --git a/client/src/main/java/client/scenes/recipe/ScalableRecipeView.java b/client/src/main/java/client/scenes/recipe/ScalableRecipeView.java
index e9192ab..db5de91 100644
--- a/client/src/main/java/client/scenes/recipe/ScalableRecipeView.java
+++ b/client/src/main/java/client/scenes/recipe/ScalableRecipeView.java
@@ -4,19 +4,14 @@ import commons.Recipe;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.DoubleProperty;
-import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleDoubleProperty;
-import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
public class ScalableRecipeView {
private final ObjectProperty recipe = new SimpleObjectProperty<>();
private final ObjectProperty scaled = new SimpleObjectProperty<>();
private final DoubleProperty scale = new SimpleDoubleProperty();
- private final DoubleProperty scaledKcal = new SimpleDoubleProperty();
- private final IntegerProperty servings = new SimpleIntegerProperty();
- private final DoubleProperty servingSize = new SimpleDoubleProperty();
public ScalableRecipeView(
Recipe recipe,
Double scale
@@ -27,11 +22,10 @@ public class ScalableRecipeView {
() -> Recipe.getScaled(this.recipe.get(), this.scale.get()),
this.recipe, this.scale);
this.scaled.bind(binding);
- this.scaledKcal.bind(Bindings.createDoubleBinding(() -> this.scaled.get().kcal(), this.scaled));
- this.servingSize.bind(Bindings.createDoubleBinding(
- () -> this.scaled.get().weight() * ( 1.0 / this.servings.get()),
- this.servings)
- );
+ }
+
+ public double getScale() {
+ return scale.get();
}
public Recipe getRecipe() {
@@ -42,14 +36,15 @@ public class ScalableRecipeView {
return scaled.get();
}
- public DoubleProperty scaledKcalProperty() {
- return scaledKcal;
+ public DoubleProperty scaleProperty() {
+ return scale;
}
- public IntegerProperty servingsProperty() {
- return servings;
+ public ObjectProperty scaledProperty() {
+ return scaled;
}
- public DoubleProperty servingSizeProperty() {
- return servingSize;
+
+ public ObjectProperty recipeProperty() {
+ return recipe;
}
}
diff --git a/client/src/main/java/client/scenes/shopping/ShoppingListCell.java b/client/src/main/java/client/scenes/shopping/ShoppingListCell.java
deleted file mode 100644
index d684435..0000000
--- a/client/src/main/java/client/scenes/shopping/ShoppingListCell.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package client.scenes.shopping;
-
-import client.scenes.recipe.OrderedEditableListCell;
-import commons.FormalIngredient;
-import javafx.scene.Node;
-import javafx.scene.control.Label;
-import javafx.scene.control.Spinner;
-import javafx.scene.control.SpinnerValueFactory;
-import javafx.scene.input.KeyCode;
-import javafx.scene.input.KeyEvent;
-import javafx.scene.layout.HBox;
-import javafx.util.Pair;
-
-import java.util.Optional;
-
-public class ShoppingListCell extends OrderedEditableListCell>> {
- private Node makeEditor() {
- HBox editor = new HBox();
- Spinner amountInput = new Spinner<>();
- FormalIngredient ingredient = getItem().getKey();
- amountInput.setEditable(true);
- amountInput.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0, Double.MAX_VALUE, ingredient.getAmount()));
- Label textLabel = new Label(getItem().getKey().getUnitSuffix() + " of " + getItem().getKey().getIngredient().getName());
- editor.getChildren().addAll(amountInput, textLabel);
- editor.addEventHandler(KeyEvent.KEY_RELEASED, e -> {
- if (e.getCode() != KeyCode.ENTER) {
- return;
- }
- Pair> pair = getItem();
- pair.getKey().setAmount(amountInput.getValue());
- commitEdit(pair);
- });
- return editor;
- }
- @Override
- public void startEdit() {
- super.startEdit();
- this.setText("");
- this.setGraphic(makeEditor());
- }
- @Override
- protected void updateItem(Pair> item, boolean empty) {
- super.updateItem(item, empty);
-
- if (empty) {
- this.setText("");
- return;
- }
-
- String display = item.getKey().toString() +
- item.getValue().map(recipe -> {
- return " (" + recipe + ")";
- }).orElse("");
-
- this.setText(display);
- }
- @Override
- public void cancelEdit() {
- super.cancelEdit();
- }
-
- @Override
- public void commitEdit(Pair> newValue) {
- super.commitEdit(newValue);
- }
-
-}
diff --git a/client/src/main/java/client/scenes/shopping/ShoppingListCtrl.java b/client/src/main/java/client/scenes/shopping/ShoppingListCtrl.java
deleted file mode 100644
index ec08c62..0000000
--- a/client/src/main/java/client/scenes/shopping/ShoppingListCtrl.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package client.scenes.shopping;
-
-import client.UI;
-import client.service.ShoppingListService;
-import client.utils.LocaleAware;
-import client.utils.LocaleManager;
-import com.google.inject.Inject;
-import commons.FormalIngredient;
-import javafx.event.ActionEvent;
-import javafx.fxml.FXML;
-import javafx.scene.Node;
-import javafx.scene.Parent;
-import javafx.scene.Scene;
-import javafx.scene.control.ListView;
-import javafx.stage.Modality;
-import javafx.stage.Stage;
-import javafx.util.Pair;
-
-import java.util.Optional;
-
-public class ShoppingListCtrl implements LocaleAware {
- ShoppingListService shopping;
-
- LocaleManager localeManager;
-
- @FXML
- private ListView>> shoppingListView;
- @Inject
- public ShoppingListCtrl(
- ShoppingListService shopping,
- LocaleManager localeManager
- ) {
- this.shopping = shopping;
- this.localeManager = localeManager;
- }
-
- @Override
- public void updateText() {
-
- }
-
- @Override
- public LocaleManager getLocaleManager() {
- return this.localeManager;
- }
-
- public void initializeComponents() {
- this.shoppingListView.setEditable(true);
- this.shoppingListView.setCellFactory(l -> new ShoppingListCell());
- this.shoppingListView.getItems().setAll(
- this.shopping.getItems()
- );
- }
- private void refreshList() {
- this.shoppingListView.getItems().setAll(
- this.shopping.getItems()
- );
- }
-
- public void handleAddItem(ActionEvent actionEvent) {
- Stage stage = new Stage();
- Pair root = UI.getFXML().load(ShoppingListNewItemPromptCtrl.class,
- "client", "scenes", "shopping", "ShoppingListItemAddModal.fxml");
- root.getKey().setNewValueConsumer(fi -> {
- this.shopping.putIngredient(fi);
- refreshList();
- });
- stage.setScene(new Scene(root.getValue()));
- stage.setTitle("My modal window");
- stage.initModality(Modality.WINDOW_MODAL);
- stage.initOwner(
- ((Node)actionEvent.getSource()).getScene().getWindow() );
- stage.show();
- }
-
- public void handleRemoveItem(ActionEvent actionEvent) {
- var x = this.shoppingListView.getSelectionModel().getSelectedItem();
- this.shopping.getItems().remove(x);
- refreshList();
- }
-}
diff --git a/client/src/main/java/client/scenes/shopping/ShoppingListNewItemPromptCtrl.java b/client/src/main/java/client/scenes/shopping/ShoppingListNewItemPromptCtrl.java
deleted file mode 100644
index 09bd44f..0000000
--- a/client/src/main/java/client/scenes/shopping/ShoppingListNewItemPromptCtrl.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package client.scenes.shopping;
-
-import client.utils.LocaleAware;
-import client.utils.LocaleManager;
-import client.utils.server.ServerUtils;
-import com.google.inject.Inject;
-import commons.FormalIngredient;
-import commons.Ingredient;
-import commons.Unit;
-import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.SimpleObjectProperty;
-import javafx.event.ActionEvent;
-import javafx.scene.control.MenuButton;
-import javafx.scene.control.MenuItem;
-import javafx.scene.control.Spinner;
-import javafx.scene.control.SpinnerValueFactory;
-import javafx.stage.Stage;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-public class ShoppingListNewItemPromptCtrl implements LocaleAware {
- public MenuButton ingredientSelection;
- private final ObjectProperty selected = new SimpleObjectProperty<>();
- private final ObjectProperty selectedUnit = new SimpleObjectProperty<>();
- private final ServerUtils server;
- private final LocaleManager localeManager;
- private Consumer newValueConsumer;
- public MenuButton unitSelect;
- public Spinner amountSelect;
-
- @Inject
- public ShoppingListNewItemPromptCtrl(ServerUtils server, LocaleManager localeManager) {
- this.server = server;
- this.localeManager = localeManager;
- }
-
- public void setNewValueConsumer(Consumer consumer) {
- this.newValueConsumer = consumer;
- }
-
- public void confirmAdd(ActionEvent actionEvent) {
- if (selected.get() == null || selectedUnit.get() == null) {
- System.err.println("You must select both an ingredient and an unit");
- return;
- }
- FormalIngredient fi = new FormalIngredient(selected.get(), amountSelect.getValue(), selectedUnit.get().suffix);
- newValueConsumer.accept(fi);
- Stage stage = (Stage) ingredientSelection.getScene().getWindow();
- stage.close();
- }
-
- public void cancelAdd(ActionEvent actionEvent) {
- }
- private void makeMenuItems(
- MenuButton menu,
- Iterable items,
- Function labelMapper,
- Consumer onSelect) {
- // Iterates over the list of items and applies the label and onSelect handlers.
- for (T item : items) {
- MenuItem mi = new MenuItem();
- mi.setText(labelMapper.apply(item));
- mi.setOnAction(_ -> {
- menu.setText(labelMapper.apply(item));
- onSelect.accept(item);
- });
- menu.getItems().add(mi);
- }
- }
- @Override
- public void updateText() {
-
- }
- @Override
- public void initializeComponents() {
- try {
- amountSelect.setValueFactory(
- new SpinnerValueFactory.DoubleSpinnerValueFactory(0, Double.MAX_VALUE, 0));
- amountSelect.setEditable(true);
- makeMenuItems(ingredientSelection, server.getIngredients(), Ingredient::getName, selected::set);
- makeMenuItems(unitSelect,
- Arrays.stream(Unit.values()).filter(u -> u.formal).toList(),
- Unit::toString, selectedUnit::set);
- } catch (IOException | InterruptedException e) {
- System.err.println(e.getMessage());
- }
- }
-
- @Override
- public LocaleManager getLocaleManager() {
- return localeManager;
- }
-}
diff --git a/client/src/main/java/client/service/NonFunctionalShoppingListService.java b/client/src/main/java/client/service/NonFunctionalShoppingListService.java
deleted file mode 100644
index d85b320..0000000
--- a/client/src/main/java/client/service/NonFunctionalShoppingListService.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package client.service;
-
-import com.google.inject.Inject;
-import commons.FormalIngredient;
-import commons.Recipe;
-import javafx.util.Pair;
-import org.apache.commons.lang3.NotImplementedException;
-
-import java.util.List;
-import java.util.Optional;
-
-public class NonFunctionalShoppingListService extends ShoppingListService {
- @Inject
- public NonFunctionalShoppingListService(ShoppingListViewModel viewModel) {
- super(viewModel);
- }
-
- @Override
- public void putIngredient(FormalIngredient ingredient) {
- throw new NotImplementedException();
- }
-
- @Override
- public void putIngredient(FormalIngredient ingredient, Recipe recipe) {
- throw new NotImplementedException();
- }
-
- @Override
- public void putIngredient(FormalIngredient ingredient, String recipeName) {
- throw new NotImplementedException();
- }
-
- @Override
- public void putArbitraryItem(String name) {
- throw new NotImplementedException();
- }
-
- @Override
- public FormalIngredient purgeIngredient(Long id) {
- throw new NotImplementedException();
- }
-
- @Override
- public FormalIngredient purgeIngredient(String ingredientName) {
- throw new NotImplementedException();
- }
-
- @Override
- public void reset() {
- throw new NotImplementedException();
- }
-
- @Override
- public List>> getItems() {
- throw new NotImplementedException();
- }
-
- @Override
- public String makePrintable() {
- throw new NotImplementedException();
- }
-}
diff --git a/client/src/main/java/client/service/ShoppingListItem.java b/client/src/main/java/client/service/ShoppingListItem.java
deleted file mode 100644
index 91dd98a..0000000
--- a/client/src/main/java/client/service/ShoppingListItem.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package client.service;
-
-import commons.FormalIngredient;
-public class ShoppingListItem {
- private FormalIngredient i;
-}
diff --git a/client/src/main/java/client/service/ShoppingListService.java b/client/src/main/java/client/service/ShoppingListService.java
deleted file mode 100644
index 04ef26b..0000000
--- a/client/src/main/java/client/service/ShoppingListService.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package client.service;
-
-import com.google.inject.Inject;
-import commons.FormalIngredient;
-import commons.Recipe;
-import javafx.util.Pair;
-
-import java.util.List;
-import java.util.Optional;
-
-public abstract class ShoppingListService {
- private ShoppingListViewModel viewModel;
- @Inject
- public ShoppingListService(ShoppingListViewModel viewModel) {
- this.viewModel = viewModel;
- }
-
- public ShoppingListViewModel getViewModel() {
- return viewModel;
- }
-
- public void setViewModel(ShoppingListViewModel viewModel) {
- this.viewModel = viewModel;
- }
-
- public abstract void putIngredient(FormalIngredient ingredient);
- public abstract void putIngredient(FormalIngredient ingredient, Recipe recipe);
- public abstract void putIngredient(FormalIngredient ingredient, String recipeName);
- public abstract void putArbitraryItem(String name);
-
- public abstract FormalIngredient purgeIngredient(Long id);
- public abstract FormalIngredient purgeIngredient(String ingredientName);
-
- public abstract void reset();
-
- public abstract List>> getItems();
- public abstract String makePrintable();
-}
diff --git a/client/src/main/java/client/service/ShoppingListServiceImpl.java b/client/src/main/java/client/service/ShoppingListServiceImpl.java
deleted file mode 100644
index 9941ee6..0000000
--- a/client/src/main/java/client/service/ShoppingListServiceImpl.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package client.service;
-
-import com.google.inject.Inject;
-import commons.FormalIngredient;
-import commons.Recipe;
-import javafx.util.Pair;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.logging.Logger;
-
-public class ShoppingListServiceImpl extends ShoppingListService {
- private final Logger logger = Logger.getLogger(ShoppingListServiceImpl.class.getName());
- @Inject
- public ShoppingListServiceImpl(
- ShoppingListViewModel model
- ) {
- super(model);
- }
-
- @Override
- public void putIngredient(FormalIngredient ingredient) {
- getViewModel().getListItems().add(new Pair<>(ingredient, Optional.empty()));
- }
-
- @Override
- public void putIngredient(FormalIngredient ingredient, Recipe recipe) {
- Pair> val = new Pair<>(ingredient, Optional.of(recipe.getName()));
- logger.info("putting ingredients into shopping list: " + val);
- getViewModel().getListItems().add(val);
- }
-
- @Override
- public void putIngredient(FormalIngredient ingredient, String recipeName) {
- getViewModel().getListItems().add(new Pair<>(ingredient, Optional.of(recipeName)));
- }
-
- @Override
- public void putArbitraryItem(String name) {
-
- }
-
- @Override
- public FormalIngredient purgeIngredient(Long id) {
- return null;
- }
-
- @Override
- public FormalIngredient purgeIngredient(String ingredientName) {
- FormalIngredient fi = getViewModel().getListItems().stream()
- .filter(i ->
- i.getKey().getIngredient().getName().equals(ingredientName))
- .findFirst().orElseThrow(NullPointerException::new).getKey();
- return null;
- }
-
- @Override
- public void reset() {
- getViewModel().getListItems().clear();
- }
-
- @Override
- public List>> getItems() {
- return getViewModel().getListItems();
- }
-
- @Override
- public String makePrintable() {
- return "TODO";
- }
-}
diff --git a/client/src/main/java/client/service/ShoppingListViewModel.java b/client/src/main/java/client/service/ShoppingListViewModel.java
deleted file mode 100644
index aaaa237..0000000
--- a/client/src/main/java/client/service/ShoppingListViewModel.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package client.service;
-
-import commons.FormalIngredient;
-import javafx.beans.property.ListProperty;
-import javafx.beans.property.SimpleListProperty;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.util.Pair;
-import org.apache.commons.lang3.NotImplementedException;
-
-import java.util.Optional;
-
-public class ShoppingListViewModel {
- /**
- * The formal ingredient provides the ingredient and its amount,
- * and the string (optional) describes the recipe where it came from.
- */
- private final ListProperty>> listItems = new SimpleListProperty<>(FXCollections.observableArrayList());
- public void addArbitrary() {
- throw new NotImplementedException();
- }
-
- public ObservableList>> getListItems() {
- return listItems.get();
- }
-}
diff --git a/client/src/main/java/client/utils/Config.java b/client/src/main/java/client/utils/Config.java
index d3c3823..a70d55c 100644
--- a/client/src/main/java/client/utils/Config.java
+++ b/client/src/main/java/client/utils/Config.java
@@ -5,7 +5,6 @@ import java.util.List;
public class Config {
private String language = "en";
- public static String[] languages = {"en", "nl", "pl", "tok", "zhc", "zht"};
private List recipeLanguages = new ArrayList<>();
private String serverUrl = "http://localhost:8080";
diff --git a/client/src/main/java/client/utils/server/Endpoints.java b/client/src/main/java/client/utils/server/Endpoints.java
index 6c23870..5b31304 100644
--- a/client/src/main/java/client/utils/server/Endpoints.java
+++ b/client/src/main/java/client/utils/server/Endpoints.java
@@ -4,9 +4,7 @@ import client.utils.ConfigService;
import com.google.inject.Inject;
import java.net.URI;
-import java.net.URLEncoder;
import java.net.http.HttpRequest;
-import java.nio.charset.StandardCharsets;
import java.util.List;
public class Endpoints {
@@ -83,23 +81,9 @@ public class Endpoints {
}
public HttpRequest.Builder getRecipesWith(String params) {
- if (params != null && params.contains("search=")) {
- int start = params.indexOf("search=") + "search=".length();
- int end = params.indexOf('&', start);
- if (end == -1) {
- end = params.length();
- }
-
- String rawValue = params.substring(start, end);
- String encodedValue = URLEncoder.encode(rawValue, StandardCharsets.UTF_8);
-
- params = params.substring(0, start) + encodedValue + params.substring(end);
- }
-
return this.http(this.createApiUrl("/recipes?" + params)).GET();
}
-
public HttpRequest.Builder createIngredient(HttpRequest.BodyPublisher body) {
String url = this.createApiUrl("/ingredients");
diff --git a/client/src/main/java/client/utils/server/ServerUtils.java b/client/src/main/java/client/utils/server/ServerUtils.java
index 8bd7f3b..5330fdd 100644
--- a/client/src/main/java/client/utils/server/ServerUtils.java
+++ b/client/src/main/java/client/utils/server/ServerUtils.java
@@ -1,18 +1,19 @@
package client.utils.server;
import client.utils.ConfigService;
-import client.exception.DuplicateIngredientException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.Inject;
import commons.Ingredient;
import commons.Recipe;
import commons.RecipeIngredient;
+import jakarta.ws.rs.ProcessingException;
import jakarta.ws.rs.client.ClientBuilder;
import org.glassfish.jersey.client.ClientConfig;
import java.io.IOException;
+import java.net.ConnectException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
@@ -170,9 +171,10 @@ public class ServerUtils {
.target(this.endpoints.baseUrl()) //
.request(APPLICATION_JSON) //
.get();
- }
- catch(Exception e){
- return false; //any exception caught will return false, not just processing exception.
+ } catch (ProcessingException e) {
+ if (e.getCause() instanceof ConnectException) {
+ return false;
+ }
}
return true;
}
@@ -268,7 +270,7 @@ public class ServerUtils {
//creates new ingredients in the ingredient list
- public Ingredient createIngredient(String name) throws IOException, InterruptedException, DuplicateIngredientException {
+ public Ingredient createIngredient(String name) throws IOException, InterruptedException {
Ingredient ingredient = new Ingredient(name, 0.0, 0.0, 0.0);
String json = objectMapper.writeValueAsString(ingredient);
@@ -276,11 +278,6 @@ public class ServerUtils {
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
- final int DUPLICATE_STATUS_CODE = 409;
- if (response.statusCode() == DUPLICATE_STATUS_CODE) {
- throw new DuplicateIngredientException(name);
- }
-
if (response.statusCode() != statusOK) {
throw new IOException("Failed to create ingredient. Server responds with: " + response.body());
}
diff --git a/client/src/main/resources/client/scenes/FoodpalApplication.fxml b/client/src/main/resources/client/scenes/FoodpalApplication.fxml
index adfffba..c777543 100644
--- a/client/src/main/resources/client/scenes/FoodpalApplication.fxml
+++ b/client/src/main/resources/client/scenes/FoodpalApplication.fxml
@@ -70,9 +70,6 @@
-
diff --git a/client/src/main/resources/client/scenes/nutrition/IngredientList.fxml b/client/src/main/resources/client/scenes/nutrition/IngredientList.fxml
index 751ed0b..653beaa 100644
--- a/client/src/main/resources/client/scenes/nutrition/IngredientList.fxml
+++ b/client/src/main/resources/client/scenes/nutrition/IngredientList.fxml
@@ -15,16 +15,16 @@
-
+
-
-
-
-
+
+
+
+
diff --git a/client/src/main/resources/client/scenes/recipe/RecipeDetailView.fxml b/client/src/main/resources/client/scenes/recipe/RecipeDetailView.fxml
index 602b827..127274c 100644
--- a/client/src/main/resources/client/scenes/recipe/RecipeDetailView.fxml
+++ b/client/src/main/resources/client/scenes/recipe/RecipeDetailView.fxml
@@ -25,23 +25,16 @@
-
-
-
-
-
-
-
+
+
-
-
diff --git a/client/src/main/resources/client/scenes/shopping/ShoppingList.fxml b/client/src/main/resources/client/scenes/shopping/ShoppingList.fxml
deleted file mode 100644
index 272e30d..0000000
--- a/client/src/main/resources/client/scenes/shopping/ShoppingList.fxml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/client/src/main/resources/client/scenes/shopping/ShoppingListItemAddModal.fxml b/client/src/main/resources/client/scenes/shopping/ShoppingListItemAddModal.fxml
deleted file mode 100644
index aee4c20..0000000
--- a/client/src/main/resources/client/scenes/shopping/ShoppingListItemAddModal.fxml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- Unit...
- Your ingredient...
-
-
-
-
-
-
-
diff --git a/client/src/main/resources/locale/lang.properties b/client/src/main/resources/locale/lang.properties
index 59f8bb1..7622bb6 100644
--- a/client/src/main/resources/locale/lang.properties
+++ b/client/src/main/resources/locale/lang.properties
@@ -16,8 +16,6 @@ menu.label.preparation=Preparation
menu.button.add.recipe=Add Recipe
menu.button.add.ingredient=Add Ingredient
menu.button.add.step=Add Step
-menu.button.favourites=Favourites
-menu.button.ingredients=Ingredients
menu.button.remove.recipe=Remove Recipe
menu.button.remove.ingredient=Remove Ingredient
@@ -27,15 +25,6 @@ menu.button.edit=Edit
menu.button.clone=Clone
menu.button.print=Print recipe
-menu.ingredients.title=Nutrition value
-
-menu.button.add=Add
-menu.button.refresh=Refresh
-menu.button.delete=Delete
-menu.button.close=Close
-
-menu.search=Search...
-
menu.label.selected-langs=Languages
lang.en.display=English
diff --git a/client/src/main/resources/locale/lang_en.properties b/client/src/main/resources/locale/lang_en.properties
index bf41079..02c0e2d 100644
--- a/client/src/main/resources/locale/lang_en.properties
+++ b/client/src/main/resources/locale/lang_en.properties
@@ -16,8 +16,6 @@ menu.label.preparation=Preparation
menu.button.add.recipe=Add Recipe
menu.button.add.ingredient=Add Ingredient
menu.button.add.step=Add Step
-menu.button.favourites=Favourites
-menu.button.ingredients=Ingredients
menu.button.remove.recipe=Remove Recipe
menu.button.remove.ingredient=Remove Ingredient
@@ -27,22 +25,13 @@ menu.button.edit=Edit
menu.button.clone=Clone
menu.button.print=Print recipe
-menu.ingredients.title=Nutrition value
-
-menu.button.add=Add
-menu.button.refresh=Refresh
-menu.button.delete=Delete
-menu.button.close=Close
-
menu.search=Search...
menu.label.selected-langs=Languages
-menu.shopping.title=Shopping list
-
lang.en.display=English
-lang.nl.display=Dutch
-lang.pl.display=Polish
+lang.nl.display=Nederlands
+lang.pl.display=Polski
lang.tok.display=toki pona
lang.tr.display=T\u00FCrk\u00E7e
lang.zht.display=中文(台灣)
diff --git a/client/src/main/resources/locale/lang_nl.properties b/client/src/main/resources/locale/lang_nl.properties
index f944251..1ebead8 100644
--- a/client/src/main/resources/locale/lang_nl.properties
+++ b/client/src/main/resources/locale/lang_nl.properties
@@ -16,8 +16,6 @@ menu.label.preparation=Bereiding
menu.button.add.recipe=Recept toevoegen
menu.button.add.ingredient=Ingrediënt toevoegen
menu.button.add.step=Stap toevoegen
-menu.button.favourites=Favorieten
-menu.button.ingredients=Ingrediënten
menu.button.remove.recipe=Recept verwijderen
menu.button.remove.ingredient=Ingrediënt verwijderen
@@ -27,21 +25,12 @@ menu.button.edit=Bewerken
menu.button.clone=Dupliceren
menu.button.print=Recept afdrukken
-menu.ingredients.title=Voedingswaarden
-
-menu.button.add=Toevoegen
-menu.button.refresh=Verversen
-menu.button.delete=Verwijderen
-menu.button.close=Sluiten
-
menu.label.selected-langs=Talen
-menu.shopping.title=Boodschappenlijst
-
menu.search=Zoeken...
-lang.en.display=Engels
+lang.en.display=English
lang.nl.display=Nederlands
-lang.pl.display=Pools
+lang.pl.display=Polski
lang.tok.display=toki pona
lang.tr.display=T\u00FCrk\u00E7e
lang.zht.display=中文(台灣)
diff --git a/client/src/main/resources/locale/lang_pl.properties b/client/src/main/resources/locale/lang_pl.properties
index 28695ad..e46b4d1 100644
--- a/client/src/main/resources/locale/lang_pl.properties
+++ b/client/src/main/resources/locale/lang_pl.properties
@@ -16,8 +16,6 @@ menu.label.preparation=Przygotowanie
menu.button.add.recipe=Dodaj przepis
menu.button.add.ingredient=Dodaj składnik
menu.button.add.step=Dodaj instrukcję
-menu.button.favourites=Ulubione
-menu.button.ingredients=Składniki
menu.button.remove.recipe=Usuń przepis
menu.button.remove.ingredient=Usuń składnik
@@ -27,21 +25,12 @@ menu.button.edit=Edytuj
menu.button.clone=Duplikuj
menu.button.print=Drukuj przepis
-menu.ingredients.title=wartości odżywcze
-
-menu.button.add=Dodaj
-menu.button.refresh=Odśwież
-menu.button.delete=Usuń
-menu.button.close=Zamknij
-
menu.search=Szukaj...
menu.label.selected-langs=Języki
-menu.shopping.title=Lista zakupw
-
-lang.en.display=Inglisz
-lang.nl.display=Holenderski
+lang.en.display=English
+lang.nl.display=Nederlands
lang.pl.display=Polski
lang.tok.display=toki pona
lang.tr.display=T\u00FCrk\u00E7e
diff --git a/client/src/main/resources/locale/lang_tok.properties b/client/src/main/resources/locale/lang_tok.properties
index 14cc3cd..56c3796 100644
--- a/client/src/main/resources/locale/lang_tok.properties
+++ b/client/src/main/resources/locale/lang_tok.properties
@@ -16,8 +16,6 @@ menu.label.preparation=nasin pi pali moku ni
menu.button.add.recipe=o pali e lipu moku sin
menu.button.add.ingredient=o pali e kipisi moku sin
menu.button.add.step=o pali e nasin pi pali moku ni
-menu.button.favourites=ijo pi pona mute tawa sina
-menu.button.ingredients=kipisi moku mute
menu.button.remove.recipe=o weka e lipu moku ni
menu.button.remove.ingredient=o weka e kipisi moku ni
@@ -27,19 +25,10 @@ menu.button.edit=o pali
menu.button.clone=o sama
menu.button.print=o tawa lon lipu
-menu.ingredients.title=nanpa moku
-
-menu.button.add=o pali
-menu.button.refresh=o pali sin
-menu.button.delete=o weka
-menu.button.close=o pini
-
menu.search=o alasa
menu.label.selected-langs=toki wile
-menu.shopping.title=ijo wile mani mute
-
lang.en.display=toki Inli
lang.nl.display=toki Netelan
lang.pl.display=toki Posuka
diff --git a/client/src/main/resources/locale/lang_tr.properties b/client/src/main/resources/locale/lang_tr.properties
index 4af12b8..917c3c9 100644
--- a/client/src/main/resources/locale/lang_tr.properties
+++ b/client/src/main/resources/locale/lang_tr.properties
@@ -16,8 +16,6 @@ menu.label.preparation=Haz\u0131rl\u0131k
menu.button.add.recipe=Tarif Ekle
menu.button.add.ingredient=Malzeme Ekle
menu.button.add.step=Ad\u0131m Ekle
-menu.button.favourites=Favoriler
-menu.button.ingredients=Malzemeler
menu.button.remove.recipe=Tarifi Sil
menu.button.remove.ingredient=Malzemeyi Sil
@@ -27,18 +25,9 @@ menu.button.edit=D\u00FCzenle
menu.button.clone=Kopyala
menu.button.print=Tarifi Yazd\u0131r
-menu.ingredients.title=besin değerleri
-
-menu.button.add=Ekle
-menu.button.refresh=yenilemek
-menu.button.delete=sil
-menu.button.close=kapat
-
-menu.search=Arama...
-
menu.label.selected-langs=Diller
-menu.shopping.title=Al??veri? listesi
+menu.search=Aramak
lang.en.display=English
lang.nl.display=Nederlands
diff --git a/client/src/test/java/client/Ingredient/IngredientControllerTest.java b/client/src/test/java/client/Ingredient/IngredientControllerTest.java
deleted file mode 100644
index 65dd6af..0000000
--- a/client/src/test/java/client/Ingredient/IngredientControllerTest.java
+++ /dev/null
@@ -1,176 +0,0 @@
-package client.Ingredient;
-
-import com.github.tomakehurst.wiremock.junit5.WireMockTest;
-import commons.Ingredient;
-import javafx.application.Platform;
-import javafx.collections.FXCollections;
-import javafx.event.ActionEvent;
-import javafx.scene.control.Button;
-import javafx.scene.control.ListView;
-import javafx.stage.Stage;
-import javafx.stage.Window;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import java.lang.reflect.Field;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.delete;
-import static com.github.tomakehurst.wiremock.client.WireMock.deleteRequestedFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.get;
-import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.ok;
-import static com.github.tomakehurst.wiremock.client.WireMock.okJson;
-import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
-import static com.github.tomakehurst.wiremock.client.WireMock.verify;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
-
-@EnabledIfEnvironmentVariable(named = "DISPLAY", matches = ".+")
-@WireMockTest(httpPort = 8080)
-class IngredientControllerMockTest {
-
- private IngredientController controller;
- private ListView ingredientListView;
-
- // starting javaFX and allow use of listview and alert usage
- @BeforeAll
- static void initJavaFx() throws Exception {
- CountDownLatch latch = new CountDownLatch(1);
- try {
- Platform.startup(latch::countDown);
- } catch (IllegalStateException alreadyStarted) {
- latch.countDown();
- }
- assertTrue(latch.await(3, TimeUnit.SECONDS), "JavaFX Platform failed to start");
- Platform.setImplicitExit(false);
- }
-//inject fxml fields and create controller + mock UI
- @BeforeEach
- void setup() throws Exception {
- controller = new IngredientController();
-
- ingredientListView = new ListView<>();
- ingredientListView.setItems(FXCollections.observableArrayList(
- new Ingredient("Bread", 1, 2, 3),
- new Ingredient("Cheese", 2, 2, 2),
- new Ingredient("Ham", 3, 3, 3)
- ));
-
- setPrivateField(controller, "ingredientListView", ingredientListView);
- setPrivateField(controller, "deleteButton", new Button("Delete"));
- }
-
- // pick ingredient -> backend says not in use -> fake delete ingredient
- @Test
- void deleteIngredientWhenNotUsedCallsUsageThenDeleteAndClearsList() throws Exception {
- Ingredient selected = ingredientListView.getItems().get(0);
- ingredientListView.getSelectionModel().select(selected);
-
- stubFor(get(urlEqualTo("/api/ingredients/" + selected.getId() + "/usage"))
- .willReturn(okJson("{\"ingredientId\":" + selected.getId() + ",\"usedInRecipes\":0}")));
-
- stubFor(delete(urlEqualTo("/api/ingredients/" + selected.getId()))
- .willReturn(ok()));
-
- // safe close for show and wait, run controller on JavaFX
- try (DialogCloser closer = startDialogCloser()) {
- runOnFxThreadAndWait(() -> controller.handleDeleteIngredient(new ActionEvent()));
- }
-
- verify(getRequestedFor(urlEqualTo("/api/ingredients/" + selected.getId() + "/usage")));
- verify(deleteRequestedFor(urlEqualTo("/api/ingredients/" + selected.getId())));
-
- assertEquals(0, ingredientListView.getItems().size());
- }
-
- //select ingredient -> if used backend says it and show warning -> safety delete but shouldn't happen
- @Test
- void deleteIngredientWhenUsedShowsWarningAndDoesNotDeleteIfDialogClosed() throws Exception {
- Ingredient selected = ingredientListView.getItems().get(1);
- ingredientListView.getSelectionModel().select(selected);
-
- stubFor(get(urlEqualTo("/api/ingredients/" + selected.getId() + "/usage"))
- .willReturn(okJson("{\"ingredientId\":" + selected.getId() + ",\"usedInRecipes\":2}")));
-
- stubFor(delete(urlEqualTo("/api/ingredients/" + selected.getId()))
- .willReturn(ok()));
-
- //safe close as if user selected cancel
- try (DialogCloser closer = startDialogCloser()) {
- runOnFxThreadAndWait(() -> controller.handleDeleteIngredient(new ActionEvent()));
- }
-
- // check usage but not delete
- verify(getRequestedFor(urlEqualTo("/api/ingredients/" + selected.getId() + "/usage")));
- verify(0, deleteRequestedFor(urlEqualTo("/api/ingredients/" + selected.getId())));
-
- assertEquals(3, ingredientListView.getItems().size());
- }
-
- // fxml helper
- private static void setPrivateField(Object target, String fieldName, Object value) throws Exception {
- Field f = target.getClass().getDeclaredField(fieldName);
- f.setAccessible(true);
- f.set(target, value);
- }
-
- //controller on JavaFX
- private static void runOnFxThreadAndWait(Runnable action) throws Exception {
- CountDownLatch latch = new CountDownLatch(1);
- Platform.runLater(() -> {
- try {
- action.run();
- } finally {
- latch.countDown();
- }
- });
- assertTrue(latch.await(8, TimeUnit.SECONDS), "FX action timed out");
- }
-
- // safe close so that show and wait doesn't wait forever
- private static DialogCloser startDialogCloser() {
- AtomicBoolean running = new AtomicBoolean(true);
-
- Thread t = new Thread(() -> {
- while (running.get()) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException ignored) {
- }
-
- Platform.runLater(() -> {
- for (Window w : Window.getWindows()) {
- if (w instanceof Stage stage && stage.isShowing()) {
- stage.close();
- }
- }
- });
- }
- }, "javafx-dialog-closer");
-
- t.setDaemon(true);
- t.start();
-
- return new DialogCloser(running);
- }
-
- // dialog closer
- private static final class DialogCloser implements AutoCloseable {
- private final AtomicBoolean running;
-
- private DialogCloser(AtomicBoolean running) {
- this.running = running;
- }
-
- @Override
- public void close() {
- running.set(false);
- }
- }
-}
diff --git a/commons/src/main/java/commons/FormalIngredient.java b/commons/src/main/java/commons/FormalIngredient.java
index 2c5c055..88d713a 100644
--- a/commons/src/main/java/commons/FormalIngredient.java
+++ b/commons/src/main/java/commons/FormalIngredient.java
@@ -76,15 +76,4 @@ public class FormalIngredient extends RecipeIngredient implements Scalable throw new IllegalStateException("Unexpected value: " + ri);
}).toList();
return new Recipe(recipe.getId(), recipe.getName(), recipe.getLocale(), i, recipe.getPreparationSteps());
- }
- public double kcal() {
- final double PER = 100; // Gram
- return
- this.ingredients.stream().mapToDouble(RecipeIngredient::getKcal).sum() /
- weight() * PER;
- }
- public double weight() {
- return this.ingredients.stream().mapToDouble(RecipeIngredient::getBaseAmount).sum();
+
}
-}
+}
\ No newline at end of file
diff --git a/commons/src/main/java/commons/RecipeIngredient.java b/commons/src/main/java/commons/RecipeIngredient.java
index f5dc86f..33d9b75 100644
--- a/commons/src/main/java/commons/RecipeIngredient.java
+++ b/commons/src/main/java/commons/RecipeIngredient.java
@@ -1,6 +1,5 @@
package commons;
-import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import jakarta.persistence.Entity;
@@ -93,8 +92,4 @@ public abstract class RecipeIngredient {
public int hashCode() {
return Objects.hash(id, ingredient);
}
- @JsonIgnore
- public abstract double getKcal();
- @JsonIgnore
- public abstract double getBaseAmount();
}
diff --git a/commons/src/main/java/commons/VagueIngredient.java b/commons/src/main/java/commons/VagueIngredient.java
index 1c4cbac..efa2fc3 100644
--- a/commons/src/main/java/commons/VagueIngredient.java
+++ b/commons/src/main/java/commons/VagueIngredient.java
@@ -50,13 +50,4 @@ public class VagueIngredient extends RecipeIngredient {
public int hashCode() {
return Objects.hashCode(description);
}
-
- @Override
- public double getKcal() {
- return 0;
- }
- @Override
- public double getBaseAmount() {
- return 0;
- }
}
diff --git a/locc.sh b/locc.sh
deleted file mode 100644
index 93a0fea..0000000
--- a/locc.sh
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/env bash
-set -u
-
-# 1. Check for git repo
-if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
- echo "Error: current directory is not a git repository." >&2
- exit 1
-fi
-
-# 2. Define path patterns
-PATH_CLIENT='client/src/**/*.java'
-PATH_SERVER='server/src/**/*.java'
-PATH_COMMONS='commons/src/**/*.java'
-PATH_PROD='*/src/main/*.java'
-PATH_TEST='*/src/test/*.java'
-PATH_ALL='*.java'
-
-# 3. Helper functions
-
-# Standard count: Includes imports, respects WS changes
-count_lines_standard() {
- git show --format="" --patch "$1" -- "$2" \
- | grep -E '^\+[^+/][^/]+$' \
- | grep -v '+ *[*@]' \
- | wc -l
-}
-
-# Strict count: Ignores imports, ignores pure WS changes
-count_lines_strict() {
- git show --format="" --patch -w "$1" -- "$2" \
- | grep -E '^\+[^+/][^/]+$' \
- | grep -v 'import' \
- | grep -v '+ *[*@]' \
- | wc -l
-}
-
-echo "Analyzing commits on 'main'..." >&2
-
-# 4. Main Loop
-# Use %ae for Author Email
-git log --no-merges --pretty=format:'%H %ae' main | {
-
- declare -A client_count
- declare -A server_count
- declare -A commons_count
- declare -A prod_count
- declare -A test_count
- declare -A total_count
- declare -A strict_count
- declare -A seen_users
-
- while read -r hash raw_email; do
- # Normalize email to lowercase
- email=$(echo "$raw_email" | tr '[:upper:]' '[:lower:]')
- seen_users["$email"]=1
-
- # Run counts (Standard)
- c_add=$(count_lines_standard "$hash" "$PATH_CLIENT")
- s_add=$(count_lines_standard "$hash" "$PATH_SERVER")
- k_add=$(count_lines_standard "$hash" "$PATH_COMMONS")
- p_add=$(count_lines_standard "$hash" "$PATH_PROD")
- t_add=$(count_lines_standard "$hash" "$PATH_TEST")
- all_add=$(count_lines_standard "$hash" "$PATH_ALL")
-
- # Run count (Strict)
- strict_add=$(count_lines_strict "$hash" "$PATH_ALL")
-
- # Accumulate
- client_count["$email"]=$(( ${client_count["$email"]:-0} + c_add ))
- server_count["$email"]=$(( ${server_count["$email"]:-0} + s_add ))
- commons_count["$email"]=$(( ${commons_count["$email"]:-0} + k_add ))
- prod_count["$email"]=$(( ${prod_count["$email"]:-0} + p_add ))
- test_count["$email"]=$(( ${test_count["$email"]:-0} + t_add ))
- total_count["$email"]=$(( ${total_count["$email"]:-0} + all_add ))
- strict_count["$email"]=$(( ${strict_count["$email"]:-0} + strict_add ))
-
- printf "." >&2
- done
-
- echo "" >&2
- echo "Done." >&2
-
- # 5. Print Table
- # Widths: Email=40, Others=10, Strict=13
- printf "%-40s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-13s\n" \
- "User Email" "Client" "Server" "Commons" "Prod" "Test" "Total" "Total (Strict)"
- printf "%s\n" "-----------------------------------------|------------|------------|------------|------------|------------|------------|----------------"
-
- for email in "${!seen_users[@]}"; do
- echo "$email"
- done | sort | while read -r e; do
- printf "%-40s | %-10d | %-10d | %-10d | %-10d | %-10d | %-10d | %-13d\n" \
- "$e" \
- "${client_count[$e]:-0}" \
- "${server_count[$e]:-0}" \
- "${commons_count[$e]:-0}" \
- "${prod_count[$e]:-0}" \
- "${test_count[$e]:-0}" \
- "${total_count[$e]:-0}" \
- "${strict_count[$e]:-0}"
- done
-}
diff --git a/server/src/test/java/server/PortCheckerTest.java b/server/src/test/java/server/PortCheckerTest.java
index a77e4d9..2843d99 100644
--- a/server/src/test/java/server/PortCheckerTest.java
+++ b/server/src/test/java/server/PortCheckerTest.java
@@ -31,37 +31,31 @@ class PortCheckerTest {
}
}
@Test
- void findNotDefaultFreePort() throws IOException {
+ void invalidPort(){
+ PortChecker checker = new PortChecker();
+
+ assertThrows(IllegalArgumentException.class, ()-> {
+ checker.isPortAvailable(-1);
+ }
+ );
+ assertThrows(IllegalArgumentException.class, ()-> {
+ checker.isPortAvailable(65536);
+ }
+ );
+ }
+ @Test
+ void findFreePort() throws IOException {
PortChecker checker = new PortChecker();
int port = checker.findFreePort();
- int lowestPossiblePort = 0;
- int highestPossiblePort = 65535;
+ int defaultPort = 8080;
+ int lastPort = 8090;
- assertTrue(port > lowestPossiblePort);
- assertTrue(port <= highestPossiblePort);
- assertTrue(checker.isPortAvailable(port));
- }
- @Test
- void findDefaultFreePort() throws IOException {
- PortChecker checker = new PortChecker();
+ boolean greaterOrEqual = port >= defaultPort;
+ boolean lessOrEqual = port <= lastPort;
+ boolean inRange = greaterOrEqual && lessOrEqual;
+ boolean isItFree = checker.isPortAvailable(port);
- boolean free = checker.isPortAvailable(8080);
-
- assertTrue(free);
- assertEquals(checker.findFreePort(),8080);
- }
-
- @Test
- void invalidFreePort(){
- PortChecker checker = new PortChecker();
-
- assertThrows(IllegalArgumentException.class, () ->
- checker.isPortAvailable(-1)
- );
-
- assertThrows(IllegalArgumentException.class, () ->
- checker.isPortAvailable(65536)
- );
+ assertTrue(inRange);
}
}
\ No newline at end of file
diff --git a/server/src/test/java/server/api/RecipeControllerTest.java b/server/src/test/java/server/api/RecipeControllerTest.java
index 9e397c7..f4d8c77 100644
--- a/server/src/test/java/server/api/RecipeControllerTest.java
+++ b/server/src/test/java/server/api/RecipeControllerTest.java
@@ -18,7 +18,6 @@ import server.service.RecipeService;
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.LongStream;
@@ -68,9 +67,7 @@ public class RecipeControllerTest {
.mapToObj(x -> new Recipe(
null,
"Recipe " + x,
- "en",
- List.of(),
- List.of()))
+ "en", List.of(), List.of()))
.toList();
controller = new RecipeController(
recipeService,
@@ -83,11 +80,8 @@ public class RecipeControllerTest {
if (tags.contains("test-from-init-data")) {
ids = LongStream
.range(0, NUM_RECIPES)
- .map(idx -> recipeRepository
- .save(recipes.get((int) idx))
- .getId())
- .boxed()
- .toList();
+ .map(idx -> recipeRepository.save(recipes.get((int) idx)).getId())
+ .boxed().toList();
}
// Some tests need to know the stored IDs of objects
@@ -123,65 +117,9 @@ public class RecipeControllerTest {
controller.getRecipes(
Optional.empty(),
Optional.empty(),
- Optional.of(List.of("en", "nl")))
- .getBody()
- .size());
+ Optional.of(List.of("en", "nl"))).getBody().size());;
}
- @Test
- @Tag("test-from-init-data")
- public void getRecipesWithNegativeLimit(){
- assertEquals(0,
- controller.getRecipes(Optional.empty(),
- Optional.of(-2),
- Optional.of(List.of("en")))
- .getBody().size());
-
- }
- @Test
- @Tag("test-from-init-data")
- public void getRecipesWithSearch() {
-
- recipeRepository.save(new Recipe(
- null,
- "banana pie",
- "en",
- List.of(),
- List.of()));
-
- assertEquals(1, controller.getRecipes(
- Optional.of("banana"),
- Optional.empty(),
- Optional.of(List.of("en"))).getBody().size());
-
- assertEquals("banana pie", Objects.requireNonNull(controller.getRecipes(
- Optional.of("banana"),
- Optional.empty(),
- Optional.of(List.of("en"))).getBody()).getFirst().getName());
- }
- @Test
- @Tag("test-from-init-data")
- public void getRecipesWithZeroLimit() {
- assertEquals(0, controller.getRecipes(
- Optional.empty(),
- Optional.of(0),
- Optional.of(List.of("en"))).getBody().size());
- }
- @Test
- @Tag("test-from-init-data")
- public void getRecipesWithEmptySearch() {
- var response = controller.getRecipes(
- Optional.of(" "),
- Optional.empty(),
- Optional.of(List.of("en"))
- );
- assertEquals(recipes.size(), response.getBody().size());
- }
-
-
-
-
-
@Test
@Tag("test-from-init-data")
public void getSomeRecipes() {
@@ -191,9 +129,7 @@ public class RecipeControllerTest {
controller.getRecipes(
Optional.empty(),
Optional.of(LIMIT),
- Optional.of(List.of("en")))
- .getBody()
- .size());
+ Optional.of(List.of("en"))).getBody().size());
}
@Test
@@ -204,9 +140,7 @@ public class RecipeControllerTest {
controller.getRecipes(
Optional.empty(),
Optional.empty(),
- Optional.of(List.of("en", "nl")))
- .getBody()
- .size());
+ Optional.of(List.of("en", "nl"))).getBody().size());
}
@Test
@@ -217,9 +151,7 @@ public class RecipeControllerTest {
controller.getRecipes(
Optional.empty(),
Optional.empty(),
- Optional.of(List.of("nl")))
- .getBody()
- .size());
+ Optional.of(List.of("nl"))).getBody().size());
}
@Test
@Tag("test-from-init-data")
@@ -229,9 +161,7 @@ public class RecipeControllerTest {
controller.getRecipes(
Optional.empty(),
Optional.of(LIMIT),
- Optional.of(List.of("en", "nl")))
- .getBody()
- .size());
+ Optional.of(List.of("en", "nl"))).getBody().size());
}
@Test
@@ -242,8 +172,7 @@ public class RecipeControllerTest {
// The third item in the input list is the same as the third item retrieved from the database
assertEquals(
recipes.get(CHECK_INDEX),
- controller.getRecipe(recipeIds.get(CHECK_INDEX))
- .getBody());
+ controller.getRecipe(recipeIds.get(CHECK_INDEX)).getBody());
}
@Test
@@ -252,8 +181,7 @@ public class RecipeControllerTest {
// There does not exist a recipe with ID=3 since there are no items in the repository.
assertEquals(
HttpStatus.NOT_FOUND,
- controller.getRecipe((long) CHECK_INDEX)
- .getStatusCode());
+ controller.getRecipe((long) CHECK_INDEX).getStatusCode());
}
@Test
@@ -264,8 +192,7 @@ public class RecipeControllerTest {
// The object has been successfully deleted
assertEquals(HttpStatus.OK,
- controller.deleteRecipe(recipeIds.get(DELETE_INDEX))
- .getStatusCode());
+ controller.deleteRecipe(recipeIds.get(DELETE_INDEX)).getStatusCode());
}
@Test
@@ -284,8 +211,7 @@ public class RecipeControllerTest {
public void deleteOneRecipeFail() {
final Long DELETE_INDEX = 5L;
assertEquals(HttpStatus.BAD_REQUEST,
- controller.deleteRecipe(DELETE_INDEX)
- .getStatusCode());
+ controller.deleteRecipe(DELETE_INDEX).getStatusCode());
}
@Test
@@ -293,16 +219,10 @@ public class RecipeControllerTest {
@Tag("need-ids")
public void updateOneRecipeHasNewData() {
final int UPDATE_INDEX = 5;
- Recipe newRecipe = controller.getRecipe(recipeIds
- .get(UPDATE_INDEX))
- .getBody();
-
+ Recipe newRecipe = controller.getRecipe(recipeIds.get(UPDATE_INDEX)).getBody();
newRecipe.setName("New recipe");
controller.updateRecipe(newRecipe.getId(), newRecipe);
-
assertEquals("New recipe",
- recipeRepository.getReferenceById(recipeIds
- .get(UPDATE_INDEX))
- .getName());
+ recipeRepository.getReferenceById(recipeIds.get(UPDATE_INDEX)).getName());
}
}