feat(client/shopping): create add ingredient modal

This commit is contained in:
Zhongheng Liu 2026-01-22 19:52:53 +01:00
commit f03c12cc0f
Signed by: steven
GPG key ID: F69B980899C1C09D
3 changed files with 112 additions and 0 deletions

View file

@ -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<WebSocketDataService<Long, Recipe>>() {}).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);

View file

@ -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<Ingredient> selected = new SimpleObjectProperty<>();
private final ObjectProperty<Unit> selectedUnit = new SimpleObjectProperty<>();
private final ServerUtils server;
private final LocaleManager localeManager;
private Consumer<FormalIngredient> newValueConsumer;
public MenuButton unitSelect;
public Spinner<Double> amountSelect;
@Inject
public ShoppingListNewItemPromptCtrl(ServerUtils server, LocaleManager localeManager) {
this.server = server;
this.localeManager = localeManager;
}
public void setNewValueConsumer(Consumer<FormalIngredient> 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 <T> void makeMenuItems(
MenuButton menu,
Iterable<T> items,
Function<T, String> labelMapper,
Consumer<T> 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;
}
}

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="$CONTROLLER_NAME$"
prefHeight="400.0" prefWidth="600.0" >
</AnchorPane>