Merge branch 'feature/shopping-list-crud' into 'main'
CRUD functionality for shopping list Closes #80 See merge request cse1105/2025-2026/teams/csep-team-76!85
This commit is contained in:
commit
1fd3b26faa
14 changed files with 362 additions and 37 deletions
|
|
@ -21,7 +21,13 @@
|
||||||
<artifactId>commons</artifactId>
|
<artifactId>commons</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Source: https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>2.0.17</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,10 @@ import client.scenes.nutrition.NutritionDetailsCtrl;
|
||||||
import client.scenes.nutrition.NutritionViewCtrl;
|
import client.scenes.nutrition.NutritionViewCtrl;
|
||||||
import client.scenes.recipe.IngredientListCtrl;
|
import client.scenes.recipe.IngredientListCtrl;
|
||||||
import client.scenes.recipe.RecipeStepListCtrl;
|
import client.scenes.recipe.RecipeStepListCtrl;
|
||||||
import client.service.NonFunctionalShoppingListService;
|
import client.scenes.shopping.ShoppingListCtrl;
|
||||||
|
import client.scenes.shopping.ShoppingListNewItemPromptCtrl;
|
||||||
import client.service.ShoppingListService;
|
import client.service.ShoppingListService;
|
||||||
|
import client.service.ShoppingListServiceImpl;
|
||||||
import client.service.ShoppingListViewModel;
|
import client.service.ShoppingListViewModel;
|
||||||
import client.utils.ConfigService;
|
import client.utils.ConfigService;
|
||||||
import client.utils.LocaleManager;
|
import client.utils.LocaleManager;
|
||||||
|
|
@ -60,8 +62,10 @@ public class MyModule implements Module {
|
||||||
binder.bind(new TypeLiteral<WebSocketDataService<Long, Recipe>>() {}).toInstance(
|
binder.bind(new TypeLiteral<WebSocketDataService<Long, Recipe>>() {}).toInstance(
|
||||||
new WebSocketDataService<>()
|
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(ShoppingListViewModel.class).toInstance(new ShoppingListViewModel());
|
||||||
binder.bind(ShoppingListService.class).to(NonFunctionalShoppingListService.class);
|
binder.bind(ShoppingListService.class).to(ShoppingListServiceImpl.class);
|
||||||
binder.bind(new TypeLiteral<WebSocketDataService<Long, Ingredient>>() {}).toInstance(
|
binder.bind(new TypeLiteral<WebSocketDataService<Long, Ingredient>>() {}).toInstance(
|
||||||
new WebSocketDataService<>()
|
new WebSocketDataService<>()
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,12 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import client.UI;
|
||||||
import client.exception.InvalidModificationException;
|
import client.exception.InvalidModificationException;
|
||||||
import client.scenes.nutrition.NutritionViewCtrl;
|
import client.scenes.nutrition.NutritionViewCtrl;
|
||||||
import client.scenes.recipe.RecipeDetailCtrl;
|
import client.scenes.recipe.RecipeDetailCtrl;
|
||||||
|
|
||||||
|
import client.scenes.shopping.ShoppingListCtrl;
|
||||||
import client.utils.Config;
|
import client.utils.Config;
|
||||||
import client.utils.ConfigService;
|
import client.utils.ConfigService;
|
||||||
import client.utils.DefaultValueFactory;
|
import client.utils.DefaultValueFactory;
|
||||||
|
|
@ -34,8 +36,6 @@ import javafx.beans.property.SimpleListProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
|
||||||
import javafx.scene.Parent;
|
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
|
@ -515,11 +515,10 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openShoppingListWindow() throws IOException {
|
public void openShoppingListWindow() throws IOException {
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("shopping/ShoppingList.fxml"));
|
var root = UI.getFXML().load(ShoppingListCtrl.class, "client", "scenes", "shopping", "ShoppingList.fxml");
|
||||||
Parent root = (Parent)loader.load();
|
|
||||||
Stage stage = new Stage();
|
Stage stage = new Stage();
|
||||||
stage.setTitle(this.getLocaleString("menu.shopping.title"));
|
stage.setTitle(this.getLocaleString("menu.shopping.title"));
|
||||||
stage.setScene(new Scene(root));
|
stage.setScene(new Scene(root.getValue()));
|
||||||
stage.show();
|
stage.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package client.scenes.recipe;
|
||||||
|
|
||||||
import client.exception.UpdateException;
|
import client.exception.UpdateException;
|
||||||
import client.scenes.FoodpalApplicationCtrl;
|
import client.scenes.FoodpalApplicationCtrl;
|
||||||
|
import client.service.ShoppingListService;
|
||||||
import client.utils.Config;
|
import client.utils.Config;
|
||||||
import client.utils.ConfigService;
|
import client.utils.ConfigService;
|
||||||
import client.utils.LocaleAware;
|
import client.utils.LocaleAware;
|
||||||
|
|
@ -10,6 +11,7 @@ import client.utils.PrintExportService;
|
||||||
import client.utils.server.ServerUtils;
|
import client.utils.server.ServerUtils;
|
||||||
import client.utils.WebSocketDataService;
|
import client.utils.WebSocketDataService;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import commons.FormalIngredient;
|
||||||
import commons.Recipe;
|
import commons.Recipe;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
@ -20,6 +22,7 @@ import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.ComboBox;
|
import javafx.scene.control.ComboBox;
|
||||||
|
|
@ -46,6 +49,7 @@ public class RecipeDetailCtrl implements LocaleAware {
|
||||||
private final FoodpalApplicationCtrl appCtrl;
|
private final FoodpalApplicationCtrl appCtrl;
|
||||||
private final ConfigService configService;
|
private final ConfigService configService;
|
||||||
private final WebSocketDataService<Long, Recipe> webSocketDataService;
|
private final WebSocketDataService<Long, Recipe> webSocketDataService;
|
||||||
|
private final ShoppingListService shoppingListService;
|
||||||
|
|
||||||
public Spinner<Double> scaleSpinner;
|
public Spinner<Double> scaleSpinner;
|
||||||
public Label inferredKcalLabel;
|
public Label inferredKcalLabel;
|
||||||
|
|
@ -67,12 +71,14 @@ public class RecipeDetailCtrl implements LocaleAware {
|
||||||
ServerUtils server,
|
ServerUtils server,
|
||||||
FoodpalApplicationCtrl appCtrl,
|
FoodpalApplicationCtrl appCtrl,
|
||||||
ConfigService configService,
|
ConfigService configService,
|
||||||
|
ShoppingListService listService,
|
||||||
WebSocketDataService<Long, Recipe> webSocketDataService) {
|
WebSocketDataService<Long, Recipe> webSocketDataService) {
|
||||||
this.localeManager = localeManager;
|
this.localeManager = localeManager;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.appCtrl = appCtrl;
|
this.appCtrl = appCtrl;
|
||||||
this.configService = configService;
|
this.configService = configService;
|
||||||
this.webSocketDataService = webSocketDataService;
|
this.webSocketDataService = webSocketDataService;
|
||||||
|
this.shoppingListService = listService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
|
|
@ -418,4 +424,13 @@ public class RecipeDetailCtrl implements LocaleAware {
|
||||||
});
|
});
|
||||||
langSelector.getItems().addAll("en", "nl", "pl", "tok");
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<Pair<FormalIngredient, Optional<String>>> {
|
||||||
|
private Node makeEditor() {
|
||||||
|
HBox editor = new HBox();
|
||||||
|
Spinner<Double> 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<FormalIngredient, Optional<String>> 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<FormalIngredient, Optional<String>> 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<FormalIngredient, Optional<String>> newValue) {
|
||||||
|
super.commitEdit(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,19 @@
|
||||||
package client.scenes.shopping;
|
package client.scenes.shopping;
|
||||||
|
|
||||||
|
import client.UI;
|
||||||
import client.service.ShoppingListService;
|
import client.service.ShoppingListService;
|
||||||
import client.utils.LocaleAware;
|
import client.utils.LocaleAware;
|
||||||
import client.utils.LocaleManager;
|
import client.utils.LocaleManager;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import commons.FormalIngredient;
|
import commons.FormalIngredient;
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
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.scene.control.ListView;
|
||||||
|
import javafx.stage.Modality;
|
||||||
|
import javafx.stage.Stage;
|
||||||
import javafx.util.Pair;
|
import javafx.util.Pair;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -19,7 +25,6 @@ public class ShoppingListCtrl implements LocaleAware {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ListView<Pair<FormalIngredient, Optional<String>>> shoppingListView;
|
private ListView<Pair<FormalIngredient, Optional<String>>> shoppingListView;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ShoppingListCtrl(
|
public ShoppingListCtrl(
|
||||||
ShoppingListService shopping,
|
ShoppingListService shopping,
|
||||||
|
|
@ -40,27 +45,37 @@ public class ShoppingListCtrl implements LocaleAware {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeComponents() {
|
public void initializeComponents() {
|
||||||
this.shoppingListView.setCellFactory(l -> new ListCell<>() {
|
this.shoppingListView.setEditable(true);
|
||||||
@Override
|
this.shoppingListView.setCellFactory(l -> new ShoppingListCell());
|
||||||
protected void updateItem(Pair<FormalIngredient, Optional<String>> 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.getItems().setAll(
|
this.shoppingListView.getItems().setAll(
|
||||||
this.shopping.getItems()
|
this.shopping.getItems()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
private void refreshList() {
|
||||||
|
this.shoppingListView.getItems().setAll(
|
||||||
|
this.shopping.getItems()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleAddItem(ActionEvent actionEvent) {
|
||||||
|
Stage stage = new Stage();
|
||||||
|
Pair<ShoppingListNewItemPromptCtrl, Parent> 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package client.service;
|
||||||
|
|
||||||
|
import commons.FormalIngredient;
|
||||||
|
public class ShoppingListItem {
|
||||||
|
private FormalIngredient i;
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,15 @@ public abstract class ShoppingListService {
|
||||||
public ShoppingListService(ShoppingListViewModel viewModel) {
|
public ShoppingListService(ShoppingListViewModel viewModel) {
|
||||||
this.viewModel = 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);
|
||||||
public abstract void putIngredient(FormalIngredient ingredient, Recipe recipe);
|
public abstract void putIngredient(FormalIngredient ingredient, Recipe recipe);
|
||||||
public abstract void putIngredient(FormalIngredient ingredient, String recipeName);
|
public abstract void putIngredient(FormalIngredient ingredient, String recipeName);
|
||||||
|
|
|
||||||
|
|
@ -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<FormalIngredient, Optional<String>> 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<Pair<FormalIngredient, Optional<String>>> getItems() {
|
||||||
|
return getViewModel().getListItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String makePrintable() {
|
||||||
|
return "TODO";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import commons.FormalIngredient;
|
||||||
import javafx.beans.property.ListProperty;
|
import javafx.beans.property.ListProperty;
|
||||||
import javafx.beans.property.SimpleListProperty;
|
import javafx.beans.property.SimpleListProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
import javafx.util.Pair;
|
import javafx.util.Pair;
|
||||||
import org.apache.commons.lang3.NotImplementedException;
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
|
|
||||||
|
|
@ -19,4 +20,7 @@ public class ShoppingListViewModel {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ObservableList<Pair<FormalIngredient, Optional<String>>> getListItems() {
|
||||||
|
return listItems.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
<Button fx:id="removeRecipeButton" mnemonicParsing="false" onAction="#removeSelectedRecipe" text="Remove Recipe" />
|
<Button fx:id="removeRecipeButton" mnemonicParsing="false" onAction="#removeSelectedRecipe" text="Remove Recipe" />
|
||||||
<Button fx:id="printRecipeButton" mnemonicParsing="false" onAction="#printRecipe" text="Print Recipe" />
|
<Button fx:id="printRecipeButton" mnemonicParsing="false" onAction="#printRecipe" text="Print Recipe" />
|
||||||
<Button fx:id="favouriteButton" onAction="#toggleFavourite" text="☆" />
|
<Button fx:id="favouriteButton" onAction="#toggleFavourite" text="☆" />
|
||||||
|
<Button onAction="#handleAddAllToShoppingList">Shop</Button>
|
||||||
</HBox>
|
</HBox>
|
||||||
|
|
||||||
<HBox>
|
<HBox>
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,20 @@
|
||||||
<?import javafx.scene.control.TitledPane?>
|
<?import javafx.scene.control.TitledPane?>
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
|
||||||
<TitledPane animated="false" collapsible="false" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" text="Shopping List" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/25">
|
<?import javafx.scene.layout.HBox?>
|
||||||
<content>
|
<?import javafx.scene.control.Button?>
|
||||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
|
<?import javafx.scene.layout.VBox?>
|
||||||
<children>
|
<TitledPane animated="false" collapsible="false" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
|
||||||
<ListView fx:id="shoppingListView" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" text="Shopping List"
|
||||||
</children>
|
fx:controller="client.scenes.shopping.ShoppingListCtrl"
|
||||||
</AnchorPane>
|
xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/25">
|
||||||
</content>
|
<VBox>
|
||||||
|
<ListView fx:id="shoppingListView" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
|
||||||
|
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
|
||||||
|
AnchorPane.topAnchor="0.0"/>
|
||||||
|
<HBox>
|
||||||
|
<Button onAction="#handleAddItem">Add</Button>
|
||||||
|
<Button onAction="#handleRemoveItem">Delete</Button>
|
||||||
|
</HBox>
|
||||||
|
</VBox>
|
||||||
</TitledPane>
|
</TitledPane>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?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="client.scenes.shopping.ShoppingListNewItemPromptCtrl"
|
||||||
|
prefHeight="400.0" prefWidth="600.0">
|
||||||
|
<VBox>
|
||||||
|
<HBox>
|
||||||
|
<Spinner fx:id="amountSelect" />
|
||||||
|
<MenuButton fx:id="unitSelect">Unit...</MenuButton>
|
||||||
|
<MenuButton fx:id="ingredientSelection">Your ingredient...</MenuButton>
|
||||||
|
</HBox>
|
||||||
|
<HBox>
|
||||||
|
<Button onAction="#confirmAdd">Confirm</Button>
|
||||||
|
<Button onAction="#cancelAdd">Cancel</Button>
|
||||||
|
</HBox>
|
||||||
|
</VBox>
|
||||||
|
</AnchorPane>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue