Have downloadable shopping list
This commit is contained in:
		
							parent
							
								
									75a8487cfb
								
							
						
					
					
						commit
						18410682de
					
				|  | @ -25,7 +25,7 @@ public class ShopIngredient implements Comparable<Object> { | ||||||
| 	 * @param ingkey | 	 * @param ingkey | ||||||
| 	 * @param shopCat | 	 * @param shopCat | ||||||
| 	 */ | 	 */ | ||||||
| 	public ShopIngredient(	double amount, String unit, | 	public ShopIngredient(	Double amount, String unit, | ||||||
| 							String item, String ingkey, | 							String item, String ingkey, | ||||||
| 							String shopCat) { | 							String shopCat) { | ||||||
| 		this.amount = amount; | 		this.amount = amount; | ||||||
|  | @ -68,14 +68,14 @@ public class ShopIngredient implements Comparable<Object> { | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the amount | 	 * @return the amount | ||||||
| 	 */ | 	 */ | ||||||
| 	public double getAmount() { | 	public Double getAmount() { | ||||||
| 		return amount; | 		return amount; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * @param amount the amount to set | 	 * @param amount the amount to set | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setAmount(double amount) { | 	public void setAmount(Double amount) { | ||||||
| 		this.amount = amount; | 		this.amount = amount; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -83,8 +83,12 @@ public class ShopIngredient implements Comparable<Object> { | ||||||
| 	 * @return the displayAmount | 	 * @return the displayAmount | ||||||
| 	 */ | 	 */ | ||||||
| 	public String getDisplayAmount() { | 	public String getDisplayAmount() { | ||||||
|  | 		Double amt = this.getAmount(); | ||||||
|  | 		if ( amt == null) { | ||||||
|  | 			return ""; | ||||||
|  | 		} | ||||||
| 		return IngredientDigester.displayAmount( | 		return IngredientDigester.displayAmount( | ||||||
| 			IngredientAmountFormat.IA_TEXT, this.getAmount(), | 			IngredientAmountFormat.IA_TEXT, amt, | ||||||
| 			null); | 			null); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -112,7 +116,7 @@ public class ShopIngredient implements Comparable<Object> { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private String ingkey; | 	private String ingkey; | ||||||
| 	private double amount; | 	private Double amount; | ||||||
| 	private String displayAmount; | 	private String displayAmount; | ||||||
| 	private String unit; | 	private String unit; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,17 +1,22 @@ | ||||||
| package com.mousetech.gourmetj; | package com.mousetech.gourmetj; | ||||||
| 
 | 
 | ||||||
|  | import java.io.ByteArrayOutputStream; | ||||||
|  | import java.io.PrintWriter; | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Comparator; | import java.util.Comparator; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
| import javax.annotation.PostConstruct; | import javax.annotation.PostConstruct; | ||||||
| import javax.faces.event.AjaxBehaviorEvent; |  | ||||||
| import javax.faces.view.ViewScoped; | import javax.faces.view.ViewScoped; | ||||||
| import javax.inject.Inject; | import javax.inject.Inject; | ||||||
| import javax.inject.Named; | import javax.inject.Named; | ||||||
| 
 | 
 | ||||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||||
|  | import org.primefaces.model.ByteArrayContent; | ||||||
|  | import org.primefaces.model.DefaultStreamedContent; | ||||||
|  | import org.primefaces.model.StreamedContent; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
| 
 | 
 | ||||||
|  | @ -19,11 +24,57 @@ import com.mousetech.gourmetj.persistence.dao.ShopcatRepository; | ||||||
| import com.mousetech.gourmetj.persistence.model.Ingredient; | import com.mousetech.gourmetj.persistence.model.Ingredient; | ||||||
| import com.mousetech.gourmetj.persistence.model.Recipe; | import com.mousetech.gourmetj.persistence.model.Recipe; | ||||||
| import com.mousetech.gourmetj.persistence.model.Shopcat; | import com.mousetech.gourmetj.persistence.model.Shopcat; | ||||||
|  | import com.mousetech.gourmetj.utils.YamlShoppingList; | ||||||
| 
 | 
 | ||||||
| @Named | @Named | ||||||
| @ViewScoped | @ViewScoped | ||||||
| public class ShoppingListBean implements Serializable { | public class ShoppingListBean implements Serializable { | ||||||
| 
 | 
 | ||||||
|  | 	public class RecipeReference { | ||||||
|  | 
 | ||||||
|  | 		private int count; | ||||||
|  | 		private Recipe recipe; | ||||||
|  | 
 | ||||||
|  | 		/** | ||||||
|  | 		 * Constructor Constructor. | ||||||
|  | 		 *  | ||||||
|  | 		 * @param r Recipe to reference (from Shopping List) | ||||||
|  | 		 */ | ||||||
|  | 		public RecipeReference(Recipe r) { | ||||||
|  | 			count = 1; | ||||||
|  | 			recipe = r; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/** | ||||||
|  | 		 * @return the count | ||||||
|  | 		 */ | ||||||
|  | 		public int getCount() { | ||||||
|  | 			return count; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/** | ||||||
|  | 		 * @param count the count to set | ||||||
|  | 		 */ | ||||||
|  | 		public void setCount(int count) { | ||||||
|  | 			this.count = count; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/** | ||||||
|  | 		 * @return the recipe | ||||||
|  | 		 */ | ||||||
|  | 		public Recipe getRecipe() { | ||||||
|  | 			return recipe; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/** | ||||||
|  | 		 * @param recipe the recipe to set | ||||||
|  | 		 */ | ||||||
|  | 		public void setRecipe(Recipe recipe) { | ||||||
|  | 			this.recipe = recipe; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Serial version for session save/restore | 	 * Serial version for session save/restore | ||||||
| 	 */ | 	 */ | ||||||
|  | @ -41,7 +92,7 @@ public class ShoppingListBean implements Serializable { | ||||||
| 
 | 
 | ||||||
| 	private List<ShopIngredient> siList; | 	private List<ShopIngredient> siList; | ||||||
| 
 | 
 | ||||||
| //	private List<ShopIngredient> ingredientList; | 	private List<RecipeReference> recipeList; | ||||||
| 
 | 
 | ||||||
| 	@PostConstruct | 	@PostConstruct | ||||||
| 	public void init() { | 	public void init() { | ||||||
|  | @ -50,8 +101,19 @@ public class ShoppingListBean implements Serializable { | ||||||
| 		buildMaps(); | 		buildMaps(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public List<Recipe> getRecipeList() { | 	public List<RecipeReference> getRecipeList() { | ||||||
| 		return this.userSession.getShoppingList(); | 		if (this.recipeList == null) { | ||||||
|  | 			this.recipeList = loadRecipeList(); | ||||||
|  | 		} | ||||||
|  | 		return this.recipeList; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private List<RecipeReference> loadRecipeList() { | ||||||
|  | 		List<RecipeReference> list = | ||||||
|  | 				userSession.getShoppingList().stream() | ||||||
|  | 					.map(r -> new RecipeReference(r)) | ||||||
|  | 					.collect(Collectors.toList()); | ||||||
|  | 		return list; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public List<ShopIngredient> getIngredientList() { | 	public List<ShopIngredient> getIngredientList() { | ||||||
|  | @ -59,7 +121,8 @@ public class ShoppingListBean implements Serializable { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private void buildMaps() { | 	private void buildMaps() { | ||||||
| 		for (Recipe r : this.getRecipeList()) { | 		this.siList = new ArrayList<ShopIngredient>(30); | ||||||
|  | 		for (RecipeReference r : this.getRecipeList()) { | ||||||
| 			buildMapsFor(r); | 			buildMapsFor(r); | ||||||
| 		} | 		} | ||||||
| 		// Now consolidate amounts and sort by | 		// Now consolidate amounts and sort by | ||||||
|  | @ -77,8 +140,13 @@ public class ShoppingListBean implements Serializable { | ||||||
| 	 *  | 	 *  | ||||||
| 	 * @see #buildMaps() | 	 * @see #buildMaps() | ||||||
| 	 */ | 	 */ | ||||||
| 	private void buildMapsFor(Recipe r) { | 	private void buildMapsFor(RecipeReference r) { | ||||||
| 		for (Ingredient ing : r.getIngredientHash()) { | 		final int multiplier = r.getCount(); | ||||||
|  | 		if (multiplier == 0) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		for (Ingredient ing : r.getRecipe() | ||||||
|  | 			.getIngredientHash()) { | ||||||
| 			String ingkey = ing.getIngkey(); | 			String ingkey = ing.getIngkey(); | ||||||
| 			if (StringUtils.isBlank(ingkey)) { | 			if (StringUtils.isBlank(ingkey)) { | ||||||
| 				continue; | 				continue; | ||||||
|  | @ -86,10 +154,21 @@ public class ShoppingListBean implements Serializable { | ||||||
| 			String shopCatName = ing.getShopCat() != null | 			String shopCatName = ing.getShopCat() != null | ||||||
| 					? ing.getShopCat().getShopcategory() | 					? ing.getShopCat().getShopcategory() | ||||||
| 					: null; | 					: null; | ||||||
| 			ShopIngredient sing = new ShopIngredient( | 			ShopIngredient sing; | ||||||
| 					ing.getAmount(), ing.getUnit(), | 			try { | ||||||
| 					ing.getItem(), ing.getIngkey(), shopCatName); | 				Double amt = ing.getAmount(); | ||||||
| 			siList.add(sing); | 				if (multiplier > 1 && (amt != null)) { | ||||||
|  | 					amt *= multiplier; | ||||||
|  | 				} | ||||||
|  | 				sing = new ShopIngredient(amt, ing.getUnit(), | ||||||
|  | 						ing.getItem(), ing.getIngkey(), | ||||||
|  | 						shopCatName); | ||||||
|  | 				siList.add(sing); | ||||||
|  | 			} catch (Exception e) { | ||||||
|  | 				log.error("Unable to create ShopIngredient for " | ||||||
|  | 						+ r.getRecipe() + " Ingredient " + ing); | ||||||
|  | 				e.printStackTrace(); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -150,6 +229,12 @@ public class ShoppingListBean implements Serializable { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	public StreamedContent getDlIngredientList() { | ||||||
|  | 		return YamlShoppingList | ||||||
|  | 			.createDownload(getIngredientList()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// ============================================= | ||||||
| 	private List<String> shopcatList; | 	private List<String> shopcatList; | ||||||
| 
 | 
 | ||||||
| 	public List<String> getShopcatList() { | 	public List<String> getShopcatList() { | ||||||
|  | @ -211,6 +296,15 @@ public class ShoppingListBean implements Serializable { | ||||||
| 		this.shopcatList = null; | 		this.shopcatList = null; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Primefaces AJAX listener for changes to amount values of | ||||||
|  | 	 * recipes the recipe list. Forces re-computation of | ||||||
|  | 	 * ingredient requirements. | ||||||
|  | 	 */ | ||||||
|  | 	public void pfAmountChange() { | ||||||
|  | 		buildMaps(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// === | 	// === | ||||||
| 	private String selectedShopcat; | 	private String selectedShopcat; | ||||||
| 
 | 
 | ||||||
|  | @ -291,12 +385,12 @@ public class ShoppingListBean implements Serializable { | ||||||
| 			return; // effective NO-OP | 			return; // effective NO-OP | ||||||
| 		} | 		} | ||||||
| 		newCat = newCat.trim(); | 		newCat = newCat.trim(); | ||||||
| 		if ( StringUtils.isBlank(newCat)) { | 		if (StringUtils.isBlank(newCat)) { | ||||||
| 			this.shopcatRepository | 			this.shopcatRepository | ||||||
| 			.deleteShopcatFor(this.getSelectedIngkey());			 | 				.deleteShopcatFor(this.getSelectedIngkey()); | ||||||
| 		} else { | 		} else { | ||||||
| 		this.shopcatRepository | 			this.shopcatRepository.updateShopcatFor(newCat, | ||||||
| 			.updateShopcatFor(newCat, this.getSelectedIngkey()); | 				this.getSelectedIngkey()); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -23,7 +23,6 @@ textarea { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #footer { | #footer { | ||||||
|     position: absolute; |  | ||||||
|     bottom: 90px; |     bottom: 90px; | ||||||
|     width: 100%; |     width: 100%; | ||||||
| } | } | ||||||
|  | @ -33,7 +33,9 @@ | ||||||
|                     <f:selectItems |                     <f:selectItems | ||||||
|                         value="#{userSession.searchTypeList}" |                         value="#{userSession.searchTypeList}" | ||||||
|                     /> |                     /> | ||||||
|                     <p:ajax listener="#{adminMainBean.resetSuggestions}"/> |                     <p:ajax | ||||||
|  |                         listener="#{adminMainBean.resetSuggestions}" | ||||||
|  |                     /> | ||||||
|                 </p:selectOneMenu> |                 </p:selectOneMenu> | ||||||
|                 <p:commandButton id="ctlClear" value="Clear" |                 <p:commandButton id="ctlClear" value="Clear" | ||||||
|                     icon="ui-icon-close" |                     icon="ui-icon-close" | ||||||
|  | @ -46,6 +48,13 @@ | ||||||
|                 <p:commandButton value="More..." |                 <p:commandButton value="More..." | ||||||
|                     action="#{adminMainBean.doMore}" |                     action="#{adminMainBean.doMore}" | ||||||
|                 /> |                 /> | ||||||
|  |                 <h:outputText id="slistSSize" | ||||||
|  |                     style="margin-left: 2em" | ||||||
|  |                     value="#{userSession.shoppingList.size()}" | ||||||
|  |                 /> | ||||||
|  |                 <h:outputLabel for="slistSize" | ||||||
|  |                     value=" Recipes in Shopping List" | ||||||
|  |                 /> | ||||||
|             </div> |             </div> | ||||||
|         </h:form> |         </h:form> | ||||||
|         <h:form id="form2"> |         <h:form id="form2"> | ||||||
|  |  | ||||||
|  | @ -23,6 +23,15 @@ | ||||||
| 	border-width: 0; | 	border-width: 0; | ||||||
| 	border-style: none; | 	border-style: none; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .noRecipe { | ||||||
|  | 	text-decoration: line-through; | ||||||
|  | 	color: gray; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .plusRecipe { | ||||||
|  | 	 | ||||||
|  | } | ||||||
| </style> | </style> | ||||||
|         <h:messages /> |         <h:messages /> | ||||||
|         <p:tabView id="tabGroupClient" orientation="left" |         <p:tabView id="tabGroupClient" orientation="left" | ||||||
|  | @ -38,11 +47,31 @@ | ||||||
|                         <f:facet name="header"> |                         <f:facet name="header"> | ||||||
|                             <h:outputText value="Recipes" /> |                             <h:outputText value="Recipes" /> | ||||||
|                         </f:facet> |                         </f:facet> | ||||||
|  |                         <p:column style="width: 4em"> | ||||||
|  |                             <p:spinner required="true" min="0" | ||||||
|  |                                 value="#{item.count}" size="1" | ||||||
|  |                             > | ||||||
|  |                                 <p:ajax | ||||||
|  |                                     listener="#{shoppingListBean.pfAmountChange}" | ||||||
|  |                                     update="@form:tblShopIngredients rname" | ||||||
|  |                                 /> | ||||||
|  |                             </p:spinner> | ||||||
|  |                         </p:column> | ||||||
|                         <p:column> |                         <p:column> | ||||||
|                             <h:outputText value="#{item.title}" /> |                             <h:outputText id="rname" | ||||||
|  |                                 styleClass="#{(item.count eq 0) ? 'noRecipe' :'plusRecipe' }" | ||||||
|  |                                 value="#{item.recipe.title}" | ||||||
|  |                             /> | ||||||
|                         </p:column> |                         </p:column> | ||||||
|                     </p:dataTable> |                     </p:dataTable> | ||||||
|                     <!-- ====== Ingredients ============================ --> |                     <!-- ====== Ingredients To Buy ======================= --> | ||||||
|  |                     <p:column id="dlIng"> | ||||||
|  |                         <p:commandButton value="Download List" ajax="false"> | ||||||
|  |                             <p:fileDownload | ||||||
|  |                                 value="#{shoppingListBean.dlIngredientList}"  | ||||||
|  |                             /> | ||||||
|  |                         </p:commandButton> | ||||||
|  |                     </p:column> | ||||||
|                     <p:column id="ingredientsc" |                     <p:column id="ingredientsc" | ||||||
|                         style="width: 25%; vertical-align: top;" |                         style="width: 25%; vertical-align: top;" | ||||||
|                     > |                     > | ||||||
|  | @ -64,11 +93,6 @@ | ||||||
|                                     /> |                                     /> | ||||||
|                                 </p:column> |                                 </p:column> | ||||||
|                             </p:headerRow> |                             </p:headerRow> | ||||||
|                             <p:column label="ingKey"> |  | ||||||
|                                 <h:outputText |  | ||||||
|                                     value="#{item.ingkey}" |  | ||||||
|                                 /> |  | ||||||
|                             </p:column> |  | ||||||
|                             <p:column label="Amt" |                             <p:column label="Amt" | ||||||
|                                 style="width: 3em; text-align: right" |                                 style="width: 3em; text-align: right" | ||||||
|                             > |                             > | ||||||
|  | @ -95,11 +119,17 @@ | ||||||
|                 </h:form> |                 </h:form> | ||||||
|             </p:tab> |             </p:tab> | ||||||
|             <!--  --> |             <!--  --> | ||||||
|             <p:tab id="ingshopcatEditTab" title="Edit"> |             <p:tab id="ingshopcatEditTab" | ||||||
|  |                 title="Edit Shopping Categories" | ||||||
|  |             > | ||||||
|                 <ui:include |                 <ui:include | ||||||
|                     src="/WEB-INF/layout/misctabs/ingshopkey.xhtml" |                     src="/WEB-INF/layout/misctabs/ingshopkey.xhtml" | ||||||
|                 /> |                 /> | ||||||
|             </p:tab> |             </p:tab> | ||||||
|  |             <!--  --> | ||||||
|  |             <p:tab id="tabImportExport" title="Import/Export"> | ||||||
|  |                 <h:outputText value="For future implementation" /> | ||||||
|  |             </p:tab> | ||||||
|         </p:tabView> |         </p:tabView> | ||||||
|         <h:form id="frmHome"> |         <h:form id="frmHome"> | ||||||
|             <p:commandButton id="doHome" value="Home" |             <p:commandButton id="doHome" value="Home" | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user