Переглянути джерело

Extract out ingredient amounts.

Sam Jaffe 5 роки тому
батько
коміт
745eee4962

+ 110 - 0
src/main/lombok/org/leumasjaffe/recipe/model/Amount.java

@@ -0,0 +1,110 @@
+package org.leumasjaffe.recipe.model;
+
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data @AllArgsConstructor
+public class Amount {
+	@AllArgsConstructor
+	public static enum Volume {
+		ml("ml", 1),
+		tsp("tsp", 5),
+		Tbsp("Tbsp", 15),
+		cup("cup", 240),
+		pinch("pinch", 0.3125),
+		dash("dash", 0.625);
+
+		final String displayName;
+		final double atomicUnits;
+	}
+	
+	@AllArgsConstructor
+	public static enum Weight {
+		g("g", 1),
+		oz("oz", 28.3495),
+		lb("lb", 453.592),
+		kg("kg", 1000);
+		
+		final String displayName;
+		final double atomicUnits;
+	}
+	
+	public static enum Unit {
+		COUNT, WEIGHT, VOLUME;
+	}
+	
+	Unit type;
+	double value;
+	Volume vol;
+	Weight wgt;
+	String unit;
+	
+	@JsonCreator
+	public Amount(final String serial) {
+		final String[] tokens = serial.split(" ", 2);
+		value = Double.parseDouble(tokens[0]);
+		final Optional<Volume> rv = Stream.of(Volume.values())
+				.filter(v -> v.displayName.equals(tokens[1])).findFirst();
+		if (rv.isPresent()) {
+			vol = rv.get();
+			return;
+		}
+		final Optional<Weight> rw = Stream.of(Weight.values())
+				.filter(w -> w.displayName.equals(tokens[1])).findFirst();
+		if (rw.isPresent()) {
+			wgt = rw.get();
+			return;
+		}
+		unit = tokens[1];
+	}
+	
+	@JsonValue @Override
+	public String toString() {
+		StringBuilder build = new StringBuilder();
+		build.append(value);
+		build.append(' ');
+		build.append(unitName());
+		return build.toString();
+	}
+	
+	private String unitName() {
+		switch (type) {
+		case COUNT:
+			return unit;
+		case WEIGHT:
+			return wgt.displayName;
+		case VOLUME:
+			return vol.displayName;
+		default:
+			throw new IllegalStateException("Unknown enum value: " + type);
+		}
+	}
+
+	public Amount plus(final Amount amount) {
+		if (type != amount.type) {
+			throw new IllegalArgumentException("Cannot merge mass and volume together");
+		} else if (!unit.equals(amount.unit)) {
+			throw new IllegalArgumentException("Cannot merge objects with different units");
+		}
+		return new Amount(type, value + amount.value * scale(amount), vol, wgt, unit);
+	}
+
+	private double scale(final Amount amount) {
+		switch (type) {
+		case COUNT:
+			return 1.0;
+		case WEIGHT:
+			return amount.wgt.atomicUnits / wgt.atomicUnits;
+		case VOLUME:
+			return amount.vol.atomicUnits / vol.atomicUnits;
+		default:
+			throw new IllegalStateException("Unknown enum value: " + type);
+		}
+	}
+}

+ 3 - 57
src/main/lombok/org/leumasjaffe/recipe/model/Ingredient.java

@@ -1,73 +1,19 @@
 package org.leumasjaffe.recipe.model;
 
-import org.leumasjaffe.container.Either;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
 import lombok.AllArgsConstructor;
 import lombok.Data;
-import lombok.Getter;
 
 @Data @AllArgsConstructor
 public class Ingredient {
-	@AllArgsConstructor @Getter
-	public static enum Volume {
-		ml("ml", 1),
-		tsp("tsp", 5),
-		Tbsp("Tbsp", 15),
-		cup("cup", 240);
-
-		final String displayName;
-		final double atomicUnits;
-	}
-	
-	@AllArgsConstructor @Getter
-	public static enum Weight {
-		g("g", 1),
-		oz("oz", 28.3495),
-		lb("lb", 453.592),
-		kg("kg", 1000),
-		pinch("pinch", 0.36),
-		dash("dash", 0.72);
-		
-		final String displayName;
-		final double atomicUnits;
-	}
-	
 	String name;
-	double value = 0;
-	@JsonIgnore Either<Volume, Weight> measure;
+	Amount amount;
 	
 	Ingredient plus(final Ingredient rhs) {
 		if (!name.equals(rhs.name)) {
 			throw new IllegalArgumentException("Combining ingredients of differing types");
-		} else if (measure.getState() != rhs.measure.getState()) {
+		} else if (amount.type != rhs.amount.type) {
 			throw new IllegalArgumentException("Cannot merge mass and volume together");
 		}
-		return new Ingredient(name, value + (rhs.value * conversionRatio(rhs.measure)), measure);
-	}
-
-	private double conversionRatio(Either<Volume, Weight> rhs) {
-		return units(rhs) / units(measure);
-	}
-
-	private static double units(Either<Volume, Weight> measure) {
-		return measure.unify(Volume::getAtomicUnits, Weight::getAtomicUnits);
-	}
-	
-	@JsonProperty("unit")
-	private String[] measureToString() {
-		String[] rval = {null, null};
-		return rval;
-	}
-	
-	@JsonProperty("unit")
-	private void measureFromString(String[] s) {
-		if (s[0] != null) {
-			measure = Either.ofLeft(Volume.valueOf(s[0]));
-		} else if (s[1] != null) {
-			measure = Either.ofRight(Weight.valueOf(s[1]));
-		}
+		return new Ingredient(name, amount.plus(rhs.amount));
 	}
 }

+ 12 - 40
src/main/lombok/org/leumasjaffe/recipe/view/IngredientPanel.java

@@ -5,18 +5,12 @@ import java.awt.GridBagLayout;
 import javax.swing.JTextField;
 import java.awt.GridBagConstraints;
 import java.awt.Insets;
-import java.awt.event.ItemEvent;
 import java.text.NumberFormat;
 import java.util.Locale;
 
-import javax.swing.JToggleButton;
 import javax.swing.event.DocumentListener;
 import javax.swing.text.NumberFormatter;
 
-import org.leumasjaffe.recipe.model.Ingredient;
-
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.JComboBox;
 import javax.swing.JFormattedTextField;
 import java.awt.Font;
 import javax.swing.JLabel;
@@ -24,12 +18,13 @@ import javax.swing.JLabel;
 @SuppressWarnings("serial")
 public class IngredientPanel extends JPanel implements AutoGrowPanel.DocumentListenable {
 	private JTextField txtName;
+	private JTextField txtUnit;
 	
 	public IngredientPanel() {
 		GridBagLayout gridBagLayout = new GridBagLayout();
-		gridBagLayout.columnWidths = new int[]{0, 100, 40, 0, 0, 0};
+		gridBagLayout.columnWidths = new int[]{0, 100, 40, 40, 0};
 		gridBagLayout.rowHeights = new int[]{0, 0};
-		gridBagLayout.columnWeights = new double[]{0.0, 1.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
+		gridBagLayout.columnWeights = new double[]{0.0, 1.0, 0.0, 0.0, Double.MIN_VALUE};
 		gridBagLayout.rowWeights = new double[]{0.0, Double.MIN_VALUE};
 		setLayout(gridBagLayout);
 		
@@ -64,38 +59,15 @@ public class IngredientPanel extends JPanel implements AutoGrowPanel.DocumentLis
 		add(txtAmount, gbc_txtAmount);
 		txtAmount.setColumns(4);
 		
-		JToggleButton tglbtnUnits = new JToggleButton("vol");
-		tglbtnUnits.setFont(new Font("Source Code Pro", Font.PLAIN, 10));
-		tglbtnUnits.setMargin(new Insets(2, 5, 2, 5));
-		GridBagConstraints gbc_tglbtnUnits = new GridBagConstraints();
-		gbc_tglbtnUnits.insets = new Insets(0, 0, 0, 5);
-		gbc_tglbtnUnits.gridx = 3;
-		gbc_tglbtnUnits.gridy = 0;
-		add(tglbtnUnits, gbc_tglbtnUnits);
-		
-		JComboBox<Ingredient.Weight> weights = new JComboBox<>(new DefaultComboBoxModel<>(Ingredient.Weight.values()));
-		weights.setFont(new Font("Source Code Pro", Font.PLAIN, 10));
-		JComboBox<Ingredient.Volume> volumes = new JComboBox<>(new DefaultComboBoxModel<>(Ingredient.Volume.values()));
-		volumes.setFont(new Font("Source Code Pro", Font.PLAIN, 10));
-		GridBagConstraints gbc_comboBox = new GridBagConstraints();
-		gbc_comboBox.fill = GridBagConstraints.HORIZONTAL;
-		gbc_comboBox.gridx = 4;
-		gbc_comboBox.gridy = 0;
-		add(volumes, gbc_comboBox);
-//		add(weights, gbc_comboBox);
-
-		tglbtnUnits.addItemListener(e -> {
-			if (e.getStateChange() == ItemEvent.SELECTED) {
-				tglbtnUnits.setText("wgt");
-				remove(volumes);
-				add(weights, gbc_comboBox);
-			} else {
-				tglbtnUnits.setText("vol");
-				remove(weights);
-				add(volumes, gbc_comboBox);
-			}
-			repaint();
-		});
+		txtUnit = new JTextField();
+		txtUnit.setFont(new Font("Source Code Pro", Font.PLAIN, 10));
+		GridBagConstraints gbc_txtUnit = new GridBagConstraints();
+		gbc_txtUnit.anchor = GridBagConstraints.ABOVE_BASELINE;
+		gbc_txtUnit.fill = GridBagConstraints.HORIZONTAL;
+		gbc_txtUnit.gridx = 3;
+		gbc_txtUnit.gridy = 0;
+		add(txtUnit, gbc_txtUnit);
+		txtUnit.setColumns(10);
 	}
 
 	@Override

+ 1 - 5
src/test/resources/example.json

@@ -13,11 +13,7 @@
             "ingredients": [
               {
                 "name": "onion",
-                "value": 100,
-                "unit": [
-                  null,
-                  "g"
-                ]
+                "amount": "100 g"
               }
             ],
             "duration": {