From 40cfc0b98ef3d1754f480d2d565126edacb51f1b Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 22 Jan 2026 18:44:25 +0100 Subject: [PATCH 1/8] fix(client/logging): added slf4j-api to client pom.xml --- client/pom.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/client/pom.xml b/client/pom.xml index b9eb186..ebbef30 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -21,7 +21,13 @@ commons 0.0.1-SNAPSHOT - + + + org.slf4j + slf4j-api + 2.0.17 + compile + com.fasterxml.jackson.core jackson-databind From c0107d752af7ad7febb73c332d9524c6bdc78bd9 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 22 Jan 2026 18:45:45 +0100 Subject: [PATCH 2/8] feat(client/shoplist): UI control logic for add all to list --- .../client/scenes/FoodpalApplicationCtrl.java | 9 ++++----- .../client/scenes/recipe/RecipeDetailCtrl.java | 15 +++++++++++++++ .../client/scenes/shopping/ShoppingListCtrl.java | 8 +++++++- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java b/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java index 327941c..416d830 100644 --- a/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java +++ b/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java @@ -9,10 +9,12 @@ 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; @@ -33,8 +35,6 @@ import commons.ws.messages.UpdateRecipeMessage; import jakarta.inject.Inject; import javafx.application.Platform; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.Alert; import javafx.scene.control.Button; @@ -616,11 +616,10 @@ public class FoodpalApplicationCtrl implements LocaleAware { } public void openShoppingListWindow() throws IOException { - FXMLLoader loader = new FXMLLoader(getClass().getResource("shopping/ShoppingList.fxml")); - Parent root = (Parent)loader.load(); + 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)); + stage.setScene(new Scene(root.getValue())); stage.show(); } diff --git a/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java b/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java index f1eeb5d..04140d1 100644 --- a/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java +++ b/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java @@ -2,6 +2,7 @@ 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; @@ -10,6 +11,7 @@ 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,6 +22,7 @@ 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; @@ -46,6 +49,7 @@ 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; @@ -67,12 +71,14 @@ 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 @@ -418,4 +424,13 @@ public class RecipeDetailCtrl implements LocaleAware { }); langSelector.getItems().addAll("en", "nl", "pl", "tok"); } + + 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)); + } } diff --git a/client/src/main/java/client/scenes/shopping/ShoppingListCtrl.java b/client/src/main/java/client/scenes/shopping/ShoppingListCtrl.java index b73ec9d..0e76b79 100644 --- a/client/src/main/java/client/scenes/shopping/ShoppingListCtrl.java +++ b/client/src/main/java/client/scenes/shopping/ShoppingListCtrl.java @@ -5,6 +5,7 @@ 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.control.ListCell; import javafx.scene.control.ListView; @@ -19,7 +20,6 @@ public class ShoppingListCtrl implements LocaleAware { @FXML private ListView>> shoppingListView; - @Inject public ShoppingListCtrl( ShoppingListService shopping, @@ -63,4 +63,10 @@ public class ShoppingListCtrl implements LocaleAware { this.shopping.getItems() ); } + + public void handleAddItem(ActionEvent actionEvent) { + } + + public void handleRemoveItem(ActionEvent actionEvent) { + } } From 21b2465b9130b46ec26883080a585a709bd99e8d Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 22 Jan 2026 18:46:33 +0100 Subject: [PATCH 3/8] feat(client/service/shop): functional service backend --- client/src/main/java/client/MyModule.java | 6 +- .../java/client/service/ShoppingListItem.java | 6 ++ .../client/service/ShoppingListService.java | 9 +++ .../service/ShoppingListServiceImpl.java | 71 +++++++++++++++++++ .../client/service/ShoppingListViewModel.java | 4 ++ 5 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 client/src/main/java/client/service/ShoppingListItem.java create mode 100644 client/src/main/java/client/service/ShoppingListServiceImpl.java diff --git a/client/src/main/java/client/MyModule.java b/client/src/main/java/client/MyModule.java index e40e613..cf55986 100644 --- a/client/src/main/java/client/MyModule.java +++ b/client/src/main/java/client/MyModule.java @@ -21,8 +21,9 @@ import client.scenes.nutrition.NutritionDetailsCtrl; import client.scenes.nutrition.NutritionViewCtrl; import client.scenes.recipe.IngredientListCtrl; import client.scenes.recipe.RecipeStepListCtrl; -import client.service.NonFunctionalShoppingListService; +import client.scenes.shopping.ShoppingListCtrl; import client.service.ShoppingListService; +import client.service.ShoppingListServiceImpl; import client.service.ShoppingListViewModel; import client.utils.ConfigService; import client.utils.LocaleManager; @@ -60,8 +61,9 @@ public class MyModule implements Module { binder.bind(new TypeLiteral>() {}).toInstance( new WebSocketDataService<>() ); + binder.bind(ShoppingListCtrl.class).in(Scopes.SINGLETON); binder.bind(ShoppingListViewModel.class).toInstance(new ShoppingListViewModel()); - binder.bind(ShoppingListService.class).to(NonFunctionalShoppingListService.class); + binder.bind(ShoppingListService.class).to(ShoppingListServiceImpl.class); binder.bind(new TypeLiteral>() {}).toInstance( new WebSocketDataService<>() ); diff --git a/client/src/main/java/client/service/ShoppingListItem.java b/client/src/main/java/client/service/ShoppingListItem.java new file mode 100644 index 0000000..91dd98a --- /dev/null +++ b/client/src/main/java/client/service/ShoppingListItem.java @@ -0,0 +1,6 @@ +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 index f757165..04ef26b 100644 --- a/client/src/main/java/client/service/ShoppingListService.java +++ b/client/src/main/java/client/service/ShoppingListService.java @@ -14,6 +14,15 @@ public abstract class ShoppingListService { 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); diff --git a/client/src/main/java/client/service/ShoppingListServiceImpl.java b/client/src/main/java/client/service/ShoppingListServiceImpl.java new file mode 100644 index 0000000..9941ee6 --- /dev/null +++ b/client/src/main/java/client/service/ShoppingListServiceImpl.java @@ -0,0 +1,71 @@ +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 index 30e03df..aaaa237 100644 --- a/client/src/main/java/client/service/ShoppingListViewModel.java +++ b/client/src/main/java/client/service/ShoppingListViewModel.java @@ -4,6 +4,7 @@ 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; @@ -19,4 +20,7 @@ public class ShoppingListViewModel { throw new NotImplementedException(); } + public ObservableList>> getListItems() { + return listItems.get(); + } } From 483617c5bf46022c293e4575c4d044f7b5a07cd3 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 22 Jan 2026 18:46:52 +0100 Subject: [PATCH 4/8] feat(client/fxml): add relevant components --- .../scenes/recipe/RecipeDetailView.fxml | 1 + .../client/scenes/shopping/ShoppingList.fxml | 24 ++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/client/src/main/resources/client/scenes/recipe/RecipeDetailView.fxml b/client/src/main/resources/client/scenes/recipe/RecipeDetailView.fxml index 28ba793..602b827 100644 --- a/client/src/main/resources/client/scenes/recipe/RecipeDetailView.fxml +++ b/client/src/main/resources/client/scenes/recipe/RecipeDetailView.fxml @@ -25,6 +25,7 @@ diff --git a/client/src/main/resources/client/scenes/shopping/ShoppingList.fxml b/client/src/main/resources/client/scenes/shopping/ShoppingList.fxml index 314caf3..272e30d 100644 --- a/client/src/main/resources/client/scenes/shopping/ShoppingList.fxml +++ b/client/src/main/resources/client/scenes/shopping/ShoppingList.fxml @@ -4,12 +4,20 @@ - - - - - - - - + + + + + + + + + + + From f03c12cc0f22bf4a5eec33cb17470e2901c4be37 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 22 Jan 2026 19:52:53 +0100 Subject: [PATCH 5/8] feat(client/shopping): create add ingredient modal --- client/src/main/java/client/MyModule.java | 2 + .../ShoppingListNewItemPromptCtrl.java | 96 +++++++++++++++++++ .../shopping/ShoppingListItemAddModal.fxml | 14 +++ 3 files changed, 112 insertions(+) create mode 100644 client/src/main/java/client/scenes/shopping/ShoppingListNewItemPromptCtrl.java create mode 100644 client/src/main/resources/client/scenes/shopping/ShoppingListItemAddModal.fxml diff --git a/client/src/main/java/client/MyModule.java b/client/src/main/java/client/MyModule.java index cf55986..14eaa3e 100644 --- a/client/src/main/java/client/MyModule.java +++ b/client/src/main/java/client/MyModule.java @@ -22,6 +22,7 @@ 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; @@ -61,6 +62,7 @@ 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); diff --git a/client/src/main/java/client/scenes/shopping/ShoppingListNewItemPromptCtrl.java b/client/src/main/java/client/scenes/shopping/ShoppingListNewItemPromptCtrl.java new file mode 100644 index 0000000..09bd44f --- /dev/null +++ b/client/src/main/java/client/scenes/shopping/ShoppingListNewItemPromptCtrl.java @@ -0,0 +1,96 @@ +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/resources/client/scenes/shopping/ShoppingListItemAddModal.fxml b/client/src/main/resources/client/scenes/shopping/ShoppingListItemAddModal.fxml new file mode 100644 index 0000000..31fbc18 --- /dev/null +++ b/client/src/main/resources/client/scenes/shopping/ShoppingListItemAddModal.fxml @@ -0,0 +1,14 @@ + + + + + + + + + + + From 795926298eb5fabcebcf1f1d84b6cf221a968bff Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 22 Jan 2026 19:53:27 +0100 Subject: [PATCH 6/8] feat(client/shopping): create custom editable shopping list cell element --- .../scenes/shopping/ShoppingListCell.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 client/src/main/java/client/scenes/shopping/ShoppingListCell.java diff --git a/client/src/main/java/client/scenes/shopping/ShoppingListCell.java b/client/src/main/java/client/scenes/shopping/ShoppingListCell.java new file mode 100644 index 0000000..d684435 --- /dev/null +++ b/client/src/main/java/client/scenes/shopping/ShoppingListCell.java @@ -0,0 +1,67 @@ +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); + } + +} From 670de432c5d177e4f39ec3c0538bd908e2a614ca Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 22 Jan 2026 19:54:33 +0100 Subject: [PATCH 7/8] feat(client/shopping): delegate list view cell rendering and make add element handler --- .../scenes/shopping/ShoppingListCtrl.java | 49 +++++++++++-------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/client/src/main/java/client/scenes/shopping/ShoppingListCtrl.java b/client/src/main/java/client/scenes/shopping/ShoppingListCtrl.java index 0e76b79..ec08c62 100644 --- a/client/src/main/java/client/scenes/shopping/ShoppingListCtrl.java +++ b/client/src/main/java/client/scenes/shopping/ShoppingListCtrl.java @@ -1,5 +1,6 @@ package client.scenes.shopping; +import client.UI; import client.service.ShoppingListService; import client.utils.LocaleAware; import client.utils.LocaleManager; @@ -7,8 +8,12 @@ import com.google.inject.Inject; import commons.FormalIngredient; import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.scene.control.ListCell; +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; @@ -40,33 +45,37 @@ public class ShoppingListCtrl implements LocaleAware { } public void initializeComponents() { - this.shoppingListView.setCellFactory(l -> new ListCell<>() { - @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); - } - }); - + 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(); } } From 234c8c3d64b1ff32ea9cedbaccb61e41597c03ed Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 22 Jan 2026 19:54:49 +0100 Subject: [PATCH 8/8] feat(client/shopping): fxml definition for various UI elements --- .../shopping/ShoppingListItemAddModal.fxml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/client/src/main/resources/client/scenes/shopping/ShoppingListItemAddModal.fxml b/client/src/main/resources/client/scenes/shopping/ShoppingListItemAddModal.fxml index 31fbc18..aee4c20 100644 --- a/client/src/main/resources/client/scenes/shopping/ShoppingListItemAddModal.fxml +++ b/client/src/main/resources/client/scenes/shopping/ShoppingListItemAddModal.fxml @@ -8,7 +8,17 @@ - + fx:controller="client.scenes.shopping.ShoppingListNewItemPromptCtrl" + prefHeight="400.0" prefWidth="600.0"> + + + + Unit... + Your ingredient... + + + + + +