Merge branch 'highlight-list-view' into 'main'

added highlighting fav recipes + list

Closes #32

See merge request cse1105/2025-2026/teams/csep-team-76!35
This commit is contained in:
Natalia Cholewa 2025-12-20 18:51:46 +01:00
commit 16482a7017
2 changed files with 70 additions and 20 deletions

View file

@ -2,8 +2,10 @@ package client.scenes;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import client.exception.UpdateException;
import client.scenes.recipe.IngredientListCtrl;
@ -29,6 +31,7 @@ import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
@ -65,6 +68,7 @@ public class FoodpalApplicationCtrl implements LocaleAware {
@FXML
private Button favouriteButton;
// stores the users favourites and load and saves them
private Config config;
private final ConfigService configService;
@ -80,6 +84,12 @@ public class FoodpalApplicationCtrl implements LocaleAware {
@FXML
public Button printRecipeButton;
@FXML
private ToggleButton favouritesOnlyToggle;
private List<Recipe> allRecipes = new ArrayList<>();
@Inject
public FoodpalApplicationCtrl(
ServerUtils server,
@ -105,7 +115,12 @@ public class FoodpalApplicationCtrl implements LocaleAware {
@Override
protected void updateItem(Recipe item, boolean empty) {
super.updateItem(item, empty);
setText(empty || item == null ? "" : item.getName());
if (empty || item == null) {
setText("");
return;
} //gives star in front fav items
boolean fav = config.isFavourite(item.getId());
setText((fav ? "" : "") + item.getName());
}
});
// When your selection changes, update details in the panel
@ -172,13 +187,11 @@ public class FoodpalApplicationCtrl implements LocaleAware {
// Initialize callback for ingredient list updates
this.ingredientListCtrl.setUpdateCallback(newList -> {
Recipe selectedRecipe = recipeList.getSelectionModel().getSelectedItem();
if (selectedRecipe == null) {
// edge case error for NPE.
if (selectedRecipe == null) { // edge case error for NPE.
throw new NullPointerException("Null recipe whereas ingredients are edited");
}
selectedRecipe.setIngredients(newList);
try {
// propagate changes to server
try { // propagate changes to server
server.updateRecipe(selectedRecipe);
} catch (IOException | InterruptedException e) {
throw new UpdateException("Unable to update recipe to server for " + selectedRecipe);
@ -186,13 +199,11 @@ public class FoodpalApplicationCtrl implements LocaleAware {
});
this.stepListCtrl.setUpdateCallback(newList -> {
Recipe selectedRecipe = recipeList.getSelectionModel().getSelectedItem();
if (selectedRecipe == null) {
// edge case error for NPE.
if (selectedRecipe == null) { // edge case error for NPE.
throw new NullPointerException("Null recipe whereas ingredients are edited");
}
selectedRecipe.setPreparationSteps(newList);
try {
// propagate changes to server
try { // propagate changes to server
server.updateRecipe(selectedRecipe);
} catch (IOException | InterruptedException e) {
throw new UpdateException("Unable to update recipe to server for " + selectedRecipe);
@ -216,7 +227,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
refresh();
updateFavouriteButton(recipeList.getSelectionModel().getSelectedItem());
}
private void showName(String name) {
final int NAME_FONT_SIZE = 20;
editableTitleArea.getChildren().clear();
@ -224,17 +234,14 @@ public class FoodpalApplicationCtrl implements LocaleAware {
nameLabel.setFont(new Font("System Bold", NAME_FONT_SIZE));
editableTitleArea.getChildren().add(nameLabel);
}
@Override
public void updateText() {
addRecipeButton.setText(getLocaleString("menu.button.add.recipe"));
removeRecipeButton.setText(getLocaleString("menu.button.remove.recipe"));
cloneRecipeButton.setText(getLocaleString("menu.button.clone"));
editRecipeTitleButton.setText(getLocaleString("menu.button.edit"));
removeRecipeButton2.setText(getLocaleString("menu.button.remove.recipe"));
printRecipeButton.setText(getLocaleString("menu.button.print"));
recipesLabel.setText(getLocaleString("menu.label.recipes"));
}
@ -263,13 +270,8 @@ public class FoodpalApplicationCtrl implements LocaleAware {
System.err.println("Failed to load recipes: " + e.getMessage());
}
recipeList.getItems().setAll(recipes);
// Select first recipe in the list by default
if (!recipes.isEmpty()) {
recipeList.getSelectionModel().selectFirst();
}
detailsScreen.visibleProperty().set(!recipes.isEmpty());
allRecipes = new ArrayList<>(recipes);
applyRecipeFilterAndKeepSelection();
}
private void printError(String msg) {
@ -408,12 +410,58 @@ public class FoodpalApplicationCtrl implements LocaleAware {
}
configService.save();
//instant ui update
applyRecipeFilterAndKeepSelection();
recipeList.refresh();
updateFavouriteButton(selected);
}
@FXML
private void toggleFavouritesView() {
applyRecipeFilterAndKeepSelection();
}
private void applyRecipeFilterAndKeepSelection() {
Recipe selected = recipeList.getSelectionModel().getSelectedItem();
Long selectedId = selected == null ? null : selected.getId();
List<Recipe> view = allRecipes;
if (favouritesOnlyToggle != null && favouritesOnlyToggle.isSelected()) {
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()
.filter(r -> r.getId().equals(selectedId))
.findFirst()
.orElse(null);
if (match != null) {
recipeList.getSelectionModel().select(match);
} else if (!view.isEmpty()) {
recipeList.getSelectionModel().selectFirst();
}
} else if (!view.isEmpty()) {
recipeList.getSelectionModel().selectFirst();
}
updateFavouriteButton(recipeList.getSelectionModel().getSelectedItem());
detailsScreen.visibleProperty().set(!recipeList.getItems().isEmpty());
}
}

View file

@ -14,6 +14,7 @@
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.control.ToggleButton?>
<?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">
@ -53,6 +54,7 @@
<Button fx:id="addRecipeButton" onAction="#addRecipe" text="Add Recipe" />
<Button fx:id="removeRecipeButton" onAction="#removeSelectedRecipe" text="Remove Recipe" />
<Button fx:id= "cloneRecipeButton" mnemonicParsing="false" onAction="#cloneRecipe" text="Clone" />
<ToggleButton fx:id="favouritesOnlyToggle" text="Favourites" onAction="#toggleFavouritesView"/>
</HBox>
</VBox>
</left>