refactor(client): client-side refactor to new modelling
This commit is contained in:
parent
88a85f2e04
commit
f04bbc037e
9 changed files with 147 additions and 49 deletions
|
|
@ -11,7 +11,7 @@ import client.scenes.recipe.RecipeDetailCtrl;
|
|||
|
||||
import client.utils.Config;
|
||||
import client.utils.ConfigService;
|
||||
import client.utils.DefaultRecipeFactory;
|
||||
import client.utils.DefaultValueFactory;
|
||||
import client.utils.LocaleAware;
|
||||
import client.utils.LocaleManager;
|
||||
import client.utils.ServerUtils;
|
||||
|
|
@ -217,7 +217,7 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
|||
*/
|
||||
@FXML
|
||||
private void addRecipe() {
|
||||
Recipe newRecipe = DefaultRecipeFactory.getDefaultRecipe(); // Create default recipe
|
||||
Recipe newRecipe = DefaultValueFactory.getDefaultRecipe(); // Create default recipe
|
||||
try {
|
||||
newRecipe = server.addRecipe(newRecipe); // get the new recipe id
|
||||
refresh(); // refresh view with server recipes
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package client.scenes.nutrition;
|
|||
|
||||
import client.scenes.FoodpalApplicationCtrl;
|
||||
import com.google.inject.Inject;
|
||||
import commons.Ingredient;
|
||||
import commons.Recipe;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
|
|
@ -14,12 +15,12 @@ import java.util.Set;
|
|||
|
||||
public class NutritionViewCtrl {
|
||||
private ObservableList<Recipe> recipes;
|
||||
private HashMap<String, Integer> ingredientStats;
|
||||
public ListView<String> nutritionIngredientsView;
|
||||
private HashMap<Ingredient, Integer> ingredientStats;
|
||||
public ListView<Ingredient> nutritionIngredientsView;
|
||||
private final NutritionDetailsCtrl nutritionDetailsCtrl;
|
||||
|
||||
// TODO into Ingredient class definition
|
||||
|
||||
// FIXME MOST LIKELY CURRENTLY BROKEN. TO BE FIXED.
|
||||
/**
|
||||
* Comedically verbose function to count unique appearances of an ingredient by name in each recipe.
|
||||
* For each recipe:
|
||||
|
|
@ -29,13 +30,15 @@ public class NutritionViewCtrl {
|
|||
* 2. For each recipe in list:
|
||||
* 1. If the name of the ingredient exists in the recipe list, increment the statistic by 1.
|
||||
* 2. Else maintain the same value for that statistic.
|
||||
* @param recipeList
|
||||
* @param recipeList The recipe list
|
||||
*/
|
||||
private void updateIngredientStats(
|
||||
List<Recipe> recipeList
|
||||
) {
|
||||
recipeList.forEach(recipe -> {
|
||||
Set<String> uniqueIngredients = new HashSet<>(recipe.getIngredients());
|
||||
Set<Ingredient> uniqueIngredients = new HashSet<>(
|
||||
recipe.getIngredients().stream().map(
|
||||
ingredient -> ingredient.ingredient).toList());
|
||||
nutritionIngredientsView.getItems().setAll(uniqueIngredients);
|
||||
uniqueIngredients.forEach(ingredient -> {
|
||||
ingredientStats.put(ingredient, 0);
|
||||
|
|
|
|||
|
|
@ -1,32 +1,71 @@
|
|||
package client.scenes.recipe;
|
||||
|
||||
import commons.FormalIngredient;
|
||||
import commons.Ingredient;
|
||||
import commons.RecipeIngredient;
|
||||
import commons.Unit;
|
||||
import commons.VagueIngredient;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.scene.control.ChoiceBox;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.layout.HBox;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
/**
|
||||
* A custom {@link OrderedEditableListCell<String>} for displaying and editing ingredients in an
|
||||
* IngredientList. Allows inline editing of ingredient names.
|
||||
* A custom {@link OrderedEditableListCell<String>} for
|
||||
* displaying and editing ingredients in an IngredientList.
|
||||
* Allows inline editing of ingredient names.
|
||||
*
|
||||
* @see IngredientListCtrl
|
||||
*/
|
||||
public class IngredientListCell extends OrderedEditableListCell<String> {
|
||||
public class IngredientListCell extends OrderedEditableListCell<RecipeIngredient> {
|
||||
@Override
|
||||
public void commitEdit(String newValue) {
|
||||
public void commitEdit(RecipeIngredient newValue) {
|
||||
super.commitEdit(newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an edit box on the ingredient.
|
||||
* It needs an {@link HBox HBox} container to fit 3 input boxes.
|
||||
* @see OrderedEditableListCell
|
||||
*/
|
||||
@Override
|
||||
public void startEdit() {
|
||||
super.startEdit();
|
||||
TextField amountInput = new TextField("0");
|
||||
RecipeIngredient ingredient = getItem();
|
||||
|
||||
Optional<Double> templateAmount = Optional.empty();
|
||||
Optional<Unit> unit = Optional.empty();
|
||||
|
||||
// Initialize the input fields with some initial data if we get a formal ingredient
|
||||
if (ingredient.getClass().equals(FormalIngredient.class)) {
|
||||
FormalIngredient formal = (FormalIngredient) ingredient;
|
||||
templateAmount = Optional.of(formal.getAmount());
|
||||
unit = Optional.of(Unit.fromString(formal.getUnitSuffix()).orElseThrow(
|
||||
() -> new RuntimeException("FormalIngredient whereas invalid unit")));
|
||||
}
|
||||
// TODO initialize some other data in the case of vague ingredient
|
||||
|
||||
// Initialize the input boxes
|
||||
TextField amountInput = new TextField(templateAmount.map(Object::toString).orElse(null));
|
||||
ChoiceBox<Unit> unitChoice = new ChoiceBox<>();
|
||||
unitChoice.setItems(FXCollections.observableArrayList(Unit.GRAM, Unit.KILOGRAM));
|
||||
TextField nameInput = new TextField("ingredient");
|
||||
|
||||
// initialize the current unit if it is present
|
||||
unit.ifPresent(unitChoice::setValue);
|
||||
unitChoice.setItems(FXCollections.observableArrayList(Unit.GRAMME, Unit.KILOGRAMME, Unit.TONNE, Unit.INFORMAL));
|
||||
|
||||
// calls makeInputLine to create the inline edit container
|
||||
HBox container = makeInputLine(ingredient, amountInput, unitChoice);
|
||||
|
||||
// set the graphic to the edit box
|
||||
this.setText(null);
|
||||
this.setGraphic(container);
|
||||
}
|
||||
private HBox makeInputLine(RecipeIngredient ingredient, TextField amountInput, ChoiceBox<Unit> unitChoice) {
|
||||
TextField nameInput = new TextField(ingredient.ingredient.name);
|
||||
HBox container = new HBox(amountInput, unitChoice, nameInput);
|
||||
container.setOnKeyReleased(event -> {
|
||||
if (event.getCode() != KeyCode.ENTER) {
|
||||
|
|
@ -34,15 +73,16 @@ public class IngredientListCell extends OrderedEditableListCell<String> {
|
|||
}
|
||||
Unit unit = unitChoice.getValue();
|
||||
String name = nameInput.getText();
|
||||
if (unit == null) {
|
||||
if (unit == null || !unit.isFormal()) {
|
||||
String desc = amountInput.getText();
|
||||
commitEdit(desc + " " + name);
|
||||
Ingredient newIngredient = new Ingredient(name, 0., 0., 0.);
|
||||
commitEdit(new VagueIngredient(newIngredient, desc));
|
||||
return;
|
||||
}
|
||||
int amount = Integer.parseInt(amountInput.getText());
|
||||
commitEdit(amount + " " + unit + " of " + name);
|
||||
double amount = Double.parseDouble(amountInput.getText());
|
||||
Ingredient newIngredient = new Ingredient(name, 0., 0., 0.);
|
||||
commitEdit(new FormalIngredient(newIngredient, amount, unit.suffix));
|
||||
});
|
||||
this.setText(null);
|
||||
this.setGraphic(container);
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package client.scenes.recipe;
|
||||
|
||||
import client.utils.DefaultValueFactory;
|
||||
import client.utils.LocaleAware;
|
||||
import client.utils.LocaleManager;
|
||||
import com.google.inject.Inject;
|
||||
|
|
@ -7,6 +8,8 @@ import commons.Recipe;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import commons.RecipeIngredient;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
|
|
@ -40,15 +43,15 @@ public class IngredientListCtrl implements LocaleAware {
|
|||
* changes and update the recipe accordingly.
|
||||
* </p>
|
||||
*/
|
||||
private ObservableList<String> ingredients;
|
||||
private ObservableList<RecipeIngredient> ingredients;
|
||||
|
||||
/**
|
||||
* A callback function that is called when the ingredient list is updated.
|
||||
*/
|
||||
private Consumer<List<String>> updateCallback;
|
||||
private Consumer<List<RecipeIngredient>> updateCallback;
|
||||
|
||||
@FXML
|
||||
public ListView<String> ingredientListView;
|
||||
public ListView<RecipeIngredient> ingredientListView;
|
||||
|
||||
@FXML
|
||||
public Label ingredientsLabel;
|
||||
|
|
@ -69,7 +72,7 @@ public class IngredientListCtrl implements LocaleAware {
|
|||
if (recipe == null) {
|
||||
this.ingredients = FXCollections.observableArrayList(new ArrayList<>());
|
||||
} else {
|
||||
List<String> ingredientList = recipe.getIngredients();
|
||||
List<RecipeIngredient> ingredientList = recipe.getIngredients();
|
||||
this.ingredients = FXCollections.observableArrayList(ingredientList);
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +85,7 @@ public class IngredientListCtrl implements LocaleAware {
|
|||
*
|
||||
* @param callback The function to call upon each update.
|
||||
*/
|
||||
public void setUpdateCallback(Consumer<List<String>> callback) {
|
||||
public void setUpdateCallback(Consumer<List<RecipeIngredient>> callback) {
|
||||
this.updateCallback = callback;
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +102,7 @@ public class IngredientListCtrl implements LocaleAware {
|
|||
* @param event The action event.
|
||||
*/
|
||||
private void handleIngredientAdd(ActionEvent event) {
|
||||
this.ingredients.add("Ingredient " + (this.ingredients.size() + 1));
|
||||
this.ingredients.add(DefaultValueFactory.getDefaultFormalIngredient());
|
||||
this.refresh();
|
||||
this.updateCallback.accept(this.ingredients);
|
||||
|
||||
|
|
@ -112,9 +115,9 @@ public class IngredientListCtrl implements LocaleAware {
|
|||
*
|
||||
* @param event The edit event.
|
||||
*/
|
||||
private void handleIngredientEdit(EditEvent<String> event) {
|
||||
private void handleIngredientEdit(EditEvent<RecipeIngredient> event) {
|
||||
int index = event.getIndex();
|
||||
String newValue = event.getNewValue();
|
||||
RecipeIngredient newValue = event.getNewValue();
|
||||
|
||||
this.ingredients.set(index, newValue);
|
||||
this.refresh();
|
||||
|
|
@ -154,9 +157,6 @@ public class IngredientListCtrl implements LocaleAware {
|
|||
|
||||
@Override
|
||||
public void initializeComponents() {
|
||||
// TODO: set up communication with the server
|
||||
// this would probably be best done with the callback (so this class doesn't
|
||||
// interact with the server at all)
|
||||
this.ingredientListView.setEditable(true);
|
||||
this.ingredientListView.setCellFactory(
|
||||
list -> {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@ package client.scenes.recipe;
|
|||
|
||||
import javafx.scene.control.ListCell;
|
||||
|
||||
/**
|
||||
* The abstract class that pre-defines common features between
|
||||
* {@link IngredientListCell IngredientListCell} and
|
||||
* {@link RecipeStepListCell RecipeStepListCell}.
|
||||
* @param <DataType> The type of data the list cell contains.
|
||||
*/
|
||||
public abstract class OrderedEditableListCell<DataType> extends ListCell<DataType> {
|
||||
/**
|
||||
* Get the display text for the given item, prefixed with its index.
|
||||
|
|
@ -23,6 +29,10 @@ public abstract class OrderedEditableListCell<DataType> extends ListCell<DataTyp
|
|||
this.setText(this.getDisplayText(item.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method stub that should be supplemented by child classes.
|
||||
*/
|
||||
public void startEdit() {
|
||||
super.startEdit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ import javafx.scene.input.KeyCode;
|
|||
/**
|
||||
* A custom ListCell for displaying and editing ingredients in an
|
||||
* RecipeStepList. Allows inline editing of ingredient names.
|
||||
*
|
||||
* The RecipeStepList only needs one {@link TextField TextField} element.
|
||||
* @see IngredientListCtrl
|
||||
* @see RecipeStepListCtrl
|
||||
*/
|
||||
public class RecipeStepListCell extends OrderedEditableListCell<String> {
|
||||
@Override
|
||||
public void startEdit() {
|
||||
super.startEdit();
|
||||
TextField textField = new TextField(this.getItem());
|
||||
|
||||
// Commit edit on Enter key press
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
package client.utils;
|
||||
|
||||
import commons.Recipe;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DefaultRecipeFactory {
|
||||
public static Recipe getDefaultRecipe() {
|
||||
return new Recipe(
|
||||
null,
|
||||
"Untitled recipe",
|
||||
List.of(),
|
||||
List.of());
|
||||
}
|
||||
}
|
||||
57
client/src/main/java/client/utils/DefaultValueFactory.java
Normal file
57
client/src/main/java/client/utils/DefaultValueFactory.java
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package client.utils;
|
||||
|
||||
import commons.FormalIngredient;
|
||||
import commons.Ingredient;
|
||||
import commons.Recipe;
|
||||
import commons.Unit;
|
||||
import commons.VagueIngredient;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A factory for default values used in the client UX flow.
|
||||
* @see DefaultValueFactory#getDefaultRecipe()
|
||||
* @see DefaultValueFactory#getDefaultFormalIngredient()
|
||||
* @see DefaultValueFactory#getDefaultVagueIngredient()
|
||||
*/
|
||||
public class DefaultValueFactory {
|
||||
/**
|
||||
* Instantiates a recipe with a default name and null-ID.
|
||||
* The ID is <code>null</code> such that it can be updated
|
||||
* as appropriate on the backend.
|
||||
* @return The default recipe.
|
||||
*/
|
||||
public static Recipe getDefaultRecipe() {
|
||||
return new Recipe(
|
||||
null,
|
||||
"Untitled recipe",
|
||||
List.of(),
|
||||
List.of());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a default formal ingredient with a default name and default ID.
|
||||
* Note in particular the ID being <code>0L</code>, see IngredientController
|
||||
* server-side implementation for more details on safeguards.
|
||||
* @return The default formal ingredient.
|
||||
*/
|
||||
public static FormalIngredient getDefaultFormalIngredient() {
|
||||
return new FormalIngredient(
|
||||
new Ingredient(0L, "default ingredient", 0., 0., 0.),
|
||||
0.0,
|
||||
Unit.GRAMME.suffix
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a vague ingredient. Not currently in use.
|
||||
* @see DefaultValueFactory#getDefaultFormalIngredient()
|
||||
* @return The vague ingredient.
|
||||
*/
|
||||
public static VagueIngredient getDefaultVagueIngredient() {
|
||||
return new VagueIngredient(
|
||||
new Ingredient(null,
|
||||
"default ingredient", 0., 0., 0.),
|
||||
"Some");
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package client.utils;
|
|||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import commons.Recipe;
|
||||
import commons.RecipeIngredient;
|
||||
import jakarta.ws.rs.ProcessingException;
|
||||
import jakarta.ws.rs.client.ClientBuilder;
|
||||
import org.glassfish.jersey.client.ClientConfig;
|
||||
|
|
@ -170,8 +171,8 @@ public class ServerUtils {
|
|||
|
||||
}
|
||||
|
||||
public void addRecipeIngredient(Recipe recipe, String ingredient) throws IOException, InterruptedException {
|
||||
List<String> ingredients = new ArrayList<>(recipe.getIngredients());
|
||||
public void addRecipeIngredient(Recipe recipe, RecipeIngredient ingredient) throws IOException, InterruptedException {
|
||||
List<RecipeIngredient> ingredients = new ArrayList<>(recipe.getIngredients());
|
||||
ingredients.add(ingredient);
|
||||
recipe.setIngredients(ingredients);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue