Selaa lähdekoodia

Merge branch 'refactor/model/nonPolymorphic'

* refactor/model/nonPolymorphic:
  Add a separate preparation panel
  Fixing exceptions
  Update ProductPanel, change PhasePanel to CardPanel with better syntax.
  Restore Product, since it seems like a useful concept (e.g. Sauce + Meat, etc.)
  Change the model to follow a significantly simpler system that doesn't depend on implicitly recursive polymorphism and type inspection.
Sam Jaffe 5 vuotta sitten
vanhempi
commit
e1704f39d7

+ 33 - 0
src/main/lombok/org/leumasjaffe/recipe/model/Card.java

@@ -0,0 +1,33 @@
+package org.leumasjaffe.recipe.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import lombok.Data;
+
+@Data
+public class Card {
+	int id = 0; // TODO Fix this
+	int[] dependsOn = {}; // decltype(id)[]
+	String vessel = "";
+	Optional<Preparation> preparation = Optional.empty();
+	List<Step> cooking = new ArrayList<>();
+	Optional<Rest> rest = Optional.empty();
+	
+	@JsonIgnore
+	Collection<Ingredient> getIngredients() {
+		return getIngredientsAsStream().collect(Collectors.toList());
+	}
+	
+	@JsonIgnore
+	Stream<Ingredient> getIngredientsAsStream() {
+		return preparation.map(p -> p.getIngredients().stream())
+				.orElse(cooking.stream().flatMap(s -> s.getIngredients().stream()));
+	}
+}

+ 0 - 28
src/main/lombok/org/leumasjaffe/recipe/model/CompoundRecipeComponent.java

@@ -1,28 +0,0 @@
-package org.leumasjaffe.recipe.model;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-
-@JsonIgnoreProperties({"duration", "ingredients", "components"})
-public interface CompoundRecipeComponent extends RecipeComponent {
-	Collection<RecipeComponent> getComponents();
-	
-	@Override
-	default Duration getDuration() {
-		return getComponents().stream().map(RecipeComponent::getDuration)
-				.reduce(Duration.ZERO, Duration::plus);
-	}
-	
-	@Override
-	default Collection<Ingredient> getIngredients() {
-		final Map<String, Ingredient> map = new HashMap<>();
-		getComponents().stream().flatMap(rc -> rc.getIngredients().stream()).forEach(i -> {
-			map.computeIfPresent(i.getName(), (k, v) -> v.plus(i));
-			map.computeIfAbsent(i.getName(), k -> i);
-		});
-		return map.values();
-	}
-}

+ 15 - 0
src/main/lombok/org/leumasjaffe/recipe/model/Preparation.java

@@ -0,0 +1,15 @@
+package org.leumasjaffe.recipe.model;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import lombok.Data;
+
+@Data
+public class Preparation {
+	Set<Ingredient> ingredients = new HashSet<>();
+	Map<String, String> instructions = new HashMap<>();
+	Duration duration;
+}

+ 13 - 39
src/main/lombok/org/leumasjaffe/recipe/model/Product.java

@@ -1,52 +1,26 @@
 package org.leumasjaffe.recipe.model;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
-import org.leumasjaffe.container.Pair;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 
 import lombok.Data;
 
 @Data
-public class Product implements CompoundRecipeComponent {
-	@Data
-	public static class Phase implements CompoundRecipeComponent {
-		List<Step> steps = new ArrayList<>();
-
-		@SuppressWarnings("unchecked")
-		@Override
-		public Collection<RecipeComponent> getComponents() {
-			return (Collection<RecipeComponent>)(List<?>) steps;
-		}
-	}
+public class Product {
+	String name;
+	List<Card> cards;
 	
-	@Data
-	public static class RecipePhase {
-		List<Pair<Phase, Rest>> additionalPhases = new ArrayList<>();
-		Phase phase;
-		Optional<Rest> rest = Optional.empty();
-		
-		void addComponents(Collection<RecipeComponent> comps) {
-			additionalPhases.forEach(pair -> {
-				comps.add(pair.getLeft());
-				comps.add(pair.getRight());
-			});
-			comps.add(phase);
-			rest.ifPresent(comps::add);
-		}
+	@JsonIgnore
+	Collection<Ingredient> getIngredients() {
+		return getIngredientsAsStream().collect(Collectors.toList());
 	}
 	
-	String name;
-	RecipePhase prep;
-	RecipePhase cooking;
-	
-	@Override
-	public Collection<RecipeComponent> getComponents() {
-		Collection<RecipeComponent> comps = new ArrayList<>();
-		prep.addComponents(comps);
-		cooking.addComponents(comps);
-		return comps;
+	@JsonIgnore
+	Stream<Ingredient> getIngredientsAsStream() {
+		return cards.stream().flatMap(Card::getIngredientsAsStream);
 	}
-}
+}

+ 11 - 13
src/main/lombok/org/leumasjaffe/recipe/model/Recipe.java

@@ -1,30 +1,28 @@
 package org.leumasjaffe.recipe.model;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 import javax.swing.ImageIcon;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
 import lombok.Data;
 
-/**
- * Recipe handling logic::
- * 	if (num components == 1) {
- * 	  let c := components(0)
- * 	  create ingredient listing c.ingredients
- *    add product panel for c
- *  } else {
- *    for (each component c) {
- *    	create ingredient listing c.title => c.ingredients
- *      add product panel for c with heading c.title
- *    }
- *  }
- */
 @Data
 public class Recipe {
 	String title;
 	String description;
+	Object nutrition;
+	int servings;
 	Optional<ImageIcon> photo; // TODO JSONIZATION	
 	List<Product> products = new ArrayList<>();
+	
+	@JsonIgnore
+	Collection<Ingredient> getIngredients() {
+		return products.stream().flatMap(Product::getIngredientsAsStream).collect(Collectors.toList());
+	}
 }

+ 0 - 8
src/main/lombok/org/leumasjaffe/recipe/model/RecipeComponent.java

@@ -1,8 +0,0 @@
-package org.leumasjaffe.recipe.model;
-
-import java.util.Collection;
-
-public interface RecipeComponent {
-	Collection<Ingredient> getIngredients();
-	Duration getDuration();
-}

+ 1 - 10
src/main/lombok/org/leumasjaffe/recipe/model/Rest.java

@@ -1,22 +1,13 @@
 package org.leumasjaffe.recipe.model;
 
-import java.util.Collection;
-import java.util.Collections;
-
 import lombok.Data;
 
 @Data
-public class Rest implements RecipeComponent {
+public class Rest {
 	public enum Where {
 		FREEZER, REFRIGERATOR, ROOM_TEMPERATURE, WARM_PLACE
 	}
 	
 	Where where;
 	Duration duration;
-	
-	@Override
-	public Collection<Ingredient> getIngredients() {
-		return Collections.emptyList();
-	}
-
 }

+ 1 - 1
src/main/lombok/org/leumasjaffe/recipe/model/Step.java

@@ -6,7 +6,7 @@ import java.util.Set;
 import lombok.Data;
 
 @Data
-public class Step implements RecipeComponent {
+public class Step {
 	Set<Ingredient> ingredients = new HashSet<>();
 	Duration duration;
 	String instruction;

+ 35 - 0
src/main/lombok/org/leumasjaffe/recipe/view/CardPanel.java

@@ -0,0 +1,35 @@
+package org.leumasjaffe.recipe.view;
+
+import javax.swing.JPanel;
+
+import org.leumasjaffe.recipe.model.Card;
+import org.leumasjaffe.recipe.model.Preparation;
+import org.leumasjaffe.recipe.model.Rest;
+import org.leumasjaffe.recipe.model.Step;
+import org.jdesktop.swingx.VerticalLayout;
+
+@SuppressWarnings("serial")
+public class CardPanel extends JPanel {
+	private int steps = 0;
+	
+	public CardPanel(final Card card) {		
+		setLayout(new VerticalLayout(5));
+		
+		card.getPreparation().ifPresent(this::addPrep);
+		card.getCooking().forEach(this::addStep);
+		card.getRest().ifPresent(this::addRest);
+	}
+	
+	void addPrep(final Preparation step) {
+		add(new PreparationPanel(step));
+	}
+	
+	void addStep(final Step step) {
+		add(new StepPanel(steps++, step));
+	}
+	
+	void addRest(final Rest rest) {
+		add(new RestPanel(rest));
+	}
+
+}

+ 0 - 22
src/main/lombok/org/leumasjaffe/recipe/view/PhasePanel.java

@@ -1,22 +0,0 @@
-package org.leumasjaffe.recipe.view;
-
-import javax.swing.JPanel;
-import javax.swing.JSeparator;
-
-import org.leumasjaffe.recipe.model.Product;
-import org.leumasjaffe.recipe.model.Step;
-import org.jdesktop.swingx.VerticalLayout;
-
-@SuppressWarnings("serial")
-public class PhasePanel extends JPanel {
-
-	public PhasePanel(Product.Phase phase) {
-		setLayout(new VerticalLayout(5));
-		int i = 0;
-		for (Step comp : phase.getSteps()) {
-			add(new StepPanel(i++, comp));
-			add(new JSeparator());
-		}
-	}
-
-}

+ 97 - 0
src/main/lombok/org/leumasjaffe/recipe/view/PreparationPanel.java

@@ -0,0 +1,97 @@
+package org.leumasjaffe.recipe.view;
+
+import javax.swing.JPanel;
+import javax.swing.event.DocumentListener;
+
+import org.leumasjaffe.recipe.model.Preparation;
+
+import java.awt.GridBagLayout;
+
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+
+import javax.swing.JLabel;
+import javax.swing.JTextPane;
+import java.awt.Component;
+import javax.swing.Box;
+import java.awt.Dimension;
+
+@SuppressWarnings("serial")
+public class PreparationPanel extends JPanel implements AutoGrowPanel.DocumentListenable {
+	private JLabel lblIndex;
+	private JTextPane txtpnInstructions;
+		
+	public PreparationPanel(Preparation step) {
+		GridBagLayout gridBagLayout = new GridBagLayout();
+		gridBagLayout.columnWidths = new int[]{0, 0, 0};
+		gridBagLayout.rowHeights = new int[]{0, 0};
+		gridBagLayout.columnWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
+		gridBagLayout.rowWeights = new double[]{1.0, Double.MIN_VALUE};
+		setLayout(gridBagLayout);
+		
+		JPanel panelLeft = new JPanel();
+		panelLeft.setPreferredSize(new Dimension(200, 50));
+		GridBagConstraints gbc_panelLeft = new GridBagConstraints();
+		gbc_panelLeft.insets = new Insets(0, 0, 0, 5);
+		gbc_panelLeft.fill = GridBagConstraints.BOTH;
+		gbc_panelLeft.gridx = 0;
+		gbc_panelLeft.gridy = 0;
+		add(panelLeft, gbc_panelLeft);
+		GridBagLayout gbl_panelLeft = new GridBagLayout();
+		gbl_panelLeft.columnWidths = new int[]{0, 0, 0, 0};
+		gbl_panelLeft.rowHeights = new int[]{0, 0, 0};
+		gbl_panelLeft.columnWeights = new double[]{0.0, 1.0, 0.0, Double.MIN_VALUE};
+		gbl_panelLeft.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
+		panelLeft.setLayout(gbl_panelLeft);
+		
+		lblIndex = new JLabel("");
+		GridBagConstraints gbc_lblIndex = new GridBagConstraints();
+		gbc_lblIndex.fill = GridBagConstraints.HORIZONTAL;
+		gbc_lblIndex.insets = new Insets(0, 0, 5, 5);
+		gbc_lblIndex.gridx = 0;
+		gbc_lblIndex.gridy = 0;
+		panelLeft.add(lblIndex, gbc_lblIndex);
+		
+		Component horizontalGlue = Box.createHorizontalGlue();
+		GridBagConstraints gbc_horizontalGlue = new GridBagConstraints();
+		gbc_horizontalGlue.insets = new Insets(0, 0, 5, 5);
+		gbc_horizontalGlue.gridx = 1;
+		gbc_horizontalGlue.gridy = 0;
+		panelLeft.add(horizontalGlue, gbc_horizontalGlue);
+		
+		JLabel lblDuration = new JLabel("Duration");
+		GridBagConstraints gbc_lblDuration = new GridBagConstraints();
+		gbc_lblDuration.insets = new Insets(0, 0, 5, 0);
+		gbc_lblDuration.gridx = 2;
+		gbc_lblDuration.gridy = 0;
+		panelLeft.add(lblDuration, gbc_lblDuration);
+		
+		AutoGrowPanel panelIngredients = new AutoGrowPanel(IngredientPanel::new);
+		GridBagConstraints gbc_panelIngredients = new GridBagConstraints();
+		gbc_panelIngredients.gridwidth = 3;
+		gbc_panelIngredients.insets = new Insets(0, 0, 0, 5);
+		gbc_panelIngredients.fill = GridBagConstraints.BOTH;
+		gbc_panelIngredients.gridx = 0;
+		gbc_panelIngredients.gridy = 1;
+		panelLeft.add(panelIngredients, gbc_panelIngredients);
+		
+		txtpnInstructions = new JTextPane();
+		txtpnInstructions.setPreferredSize(new Dimension(200, 30));
+		txtpnInstructions.setText("Instructions");
+		GridBagConstraints gbc_txtpnInstructions = new GridBagConstraints();
+		gbc_txtpnInstructions.fill = GridBagConstraints.BOTH;
+		gbc_txtpnInstructions.gridx = 1;
+		gbc_txtpnInstructions.gridy = 0;
+		add(txtpnInstructions, gbc_txtpnInstructions);
+	}
+
+	@Override
+	public void addDocumentListener(DocumentListener dl) {
+		this.txtpnInstructions.getDocument().addDocumentListener(dl);
+	}
+
+	@Override
+	public void removeDocumentListener(DocumentListener dl) {
+		this.txtpnInstructions.getDocument().removeDocumentListener(dl);		
+	}
+}

+ 5 - 20
src/main/lombok/org/leumasjaffe/recipe/view/ProductPanel.java

@@ -3,9 +3,8 @@ package org.leumasjaffe.recipe.view;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 
+import org.leumasjaffe.recipe.model.Card;
 import org.leumasjaffe.recipe.model.Product;
-import org.leumasjaffe.recipe.model.RecipeComponent;
-import org.leumasjaffe.recipe.model.Rest;
 import org.jdesktop.swingx.VerticalLayout;
 
 import javax.swing.JButton;
@@ -18,30 +17,16 @@ public class ProductPanel extends JScrollPane {
 		JPanel panelColumnHeader = new JPanel();
 		setColumnHeaderView(panelColumnHeader);
 		
-		JButton btnAddStep = new JButton("Add Step");
+		JButton btnAddStep = new JButton("Add Card");
 		panelColumnHeader.add(btnAddStep);
 		
 		panelViewPort = new JPanel();
 		setViewportView(panelViewPort);
 		panelViewPort.setLayout(new VerticalLayout(5));
 		
-		for (RecipeComponent comp : product.getComponents()) {
-			if (comp instanceof Rest) {
-				addRest((Rest) comp);
-			} else if (comp instanceof Product.Phase) {
-				addPhase((Product.Phase) comp);
-			}
+		for (final Card card : product.getCards()) {
+			panelViewPort.add(new CardPanel(card));
+			panelViewPort.add(new JSeparator());
 		}
 	}
-	
-	void addPhase(final Product.Phase phase) {
-		panelViewPort.add(new PhasePanel(phase));
-		panelViewPort.add(new JSeparator());
-	}
-	
-	void addRest(final Rest rest) {
-		panelViewPort.add(new RestPanel(rest));
-		panelViewPort.add(new JSeparator());
-	}
-
 }

+ 26 - 26
src/test/resources/example.json

@@ -4,34 +4,34 @@
   "products": [
     {
       "name": "Curry",
-      "prep": {
-        "phase": {
-          "steps": [
-            {
-              "ingredients": [
-                {
-                  "name": "onion",
-                  "value": 100,
-                  "unit": [ null, "g" ]
-                }
-              ],
-              "duration": {
-                "displayAs": "MINUTES",
-                "isApproximate": true,
-                "minSeconds": 300,
-                "maxSeconds": 600
-              },
-              "instruction": "Expode"
+      "cards": [
+        {
+          "id": 0,
+          "dependsOn": [],
+          "vessel": "",
+          "preparation": {
+            "ingredients": [
+              {
+                "name": "onion",
+                "value": 100,
+                "unit": [
+                  null,
+                  "g"
+                ]
+              }
+            ],
+            "duration": {
+              "displayAs": "MINUTES",
+              "isApproximate": true,
+              "minSeconds": 300,
+              "maxSeconds": 600
+            },
+            "instructions": {
+              
             }
-          ]
+          }
         }
-      },
-      "cooking": {
-        "phase": {
-          "steps": [
-          ]
-        }
-      }
+      ]
     }
   ]
 }