Have downloadable shopping list

This commit is contained in:
Tim Holloway 2022-01-15 18:06:45 -05:00
parent 75a8487cfb
commit 18410682de
5 changed files with 166 additions and 30 deletions

View File

@ -25,7 +25,7 @@ public class ShopIngredient implements Comparable<Object> {
* @param ingkey
* @param shopCat
*/
public ShopIngredient( double amount, String unit,
public ShopIngredient( Double amount, String unit,
String item, String ingkey,
String shopCat) {
this.amount = amount;
@ -68,14 +68,14 @@ public class ShopIngredient implements Comparable<Object> {
/**
* @return the amount
*/
public double getAmount() {
public Double getAmount() {
return amount;
}
/**
* @param amount the amount to set
*/
public void setAmount(double amount) {
public void setAmount(Double amount) {
this.amount = amount;
}
@ -83,8 +83,12 @@ public class ShopIngredient implements Comparable<Object> {
* @return the displayAmount
*/
public String getDisplayAmount() {
Double amt = this.getAmount();
if ( amt == null) {
return "";
}
return IngredientDigester.displayAmount(
IngredientAmountFormat.IA_TEXT, this.getAmount(),
IngredientAmountFormat.IA_TEXT, amt,
null);
}
@ -112,7 +116,7 @@ public class ShopIngredient implements Comparable<Object> {
}
private String ingkey;
private double amount;
private Double amount;
private String displayAmount;
private String unit;

View File

@ -1,17 +1,22 @@
package com.mousetech.gourmetj;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
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.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.Recipe;
import com.mousetech.gourmetj.persistence.model.Shopcat;
import com.mousetech.gourmetj.utils.YamlShoppingList;
@Named
@ViewScoped
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
*/
@ -41,7 +92,7 @@ public class ShoppingListBean implements Serializable {
private List<ShopIngredient> siList;
// private List<ShopIngredient> ingredientList;
private List<RecipeReference> recipeList;
@PostConstruct
public void init() {
@ -50,8 +101,19 @@ public class ShoppingListBean implements Serializable {
buildMaps();
}
public List<Recipe> getRecipeList() {
return this.userSession.getShoppingList();
public List<RecipeReference> getRecipeList() {
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() {
@ -59,7 +121,8 @@ public class ShoppingListBean implements Serializable {
}
private void buildMaps() {
for (Recipe r : this.getRecipeList()) {
this.siList = new ArrayList<ShopIngredient>(30);
for (RecipeReference r : this.getRecipeList()) {
buildMapsFor(r);
}
// Now consolidate amounts and sort by
@ -77,8 +140,13 @@ public class ShoppingListBean implements Serializable {
*
* @see #buildMaps()
*/
private void buildMapsFor(Recipe r) {
for (Ingredient ing : r.getIngredientHash()) {
private void buildMapsFor(RecipeReference r) {
final int multiplier = r.getCount();
if (multiplier == 0) {
return;
}
for (Ingredient ing : r.getRecipe()
.getIngredientHash()) {
String ingkey = ing.getIngkey();
if (StringUtils.isBlank(ingkey)) {
continue;
@ -86,10 +154,21 @@ public class ShoppingListBean implements Serializable {
String shopCatName = ing.getShopCat() != null
? ing.getShopCat().getShopcategory()
: null;
ShopIngredient sing = new ShopIngredient(
ing.getAmount(), ing.getUnit(),
ing.getItem(), ing.getIngkey(), shopCatName);
ShopIngredient sing;
try {
Double amt = ing.getAmount();
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;
public List<String> getShopcatList() {
@ -211,6 +296,15 @@ public class ShoppingListBean implements Serializable {
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;
@ -295,8 +389,8 @@ public class ShoppingListBean implements Serializable {
this.shopcatRepository
.deleteShopcatFor(this.getSelectedIngkey());
} else {
this.shopcatRepository
.updateShopcatFor(newCat, this.getSelectedIngkey());
this.shopcatRepository.updateShopcatFor(newCat,
this.getSelectedIngkey());
}
}

View File

@ -23,7 +23,6 @@ textarea {
}
#footer {
position: absolute;
bottom: 90px;
width: 100%;
}

View File

@ -33,7 +33,9 @@
<f:selectItems
value="#{userSession.searchTypeList}"
/>
<p:ajax listener="#{adminMainBean.resetSuggestions}"/>
<p:ajax
listener="#{adminMainBean.resetSuggestions}"
/>
</p:selectOneMenu>
<p:commandButton id="ctlClear" value="Clear"
icon="ui-icon-close"
@ -46,6 +48,13 @@
<p:commandButton value="More..."
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>
</h:form>
<h:form id="form2">

View File

@ -23,6 +23,15 @@
border-width: 0;
border-style: none;
}
.noRecipe {
text-decoration: line-through;
color: gray;
}
.plusRecipe {
}
</style>
<h:messages />
<p:tabView id="tabGroupClient" orientation="left"
@ -38,11 +47,31 @@
<f:facet name="header">
<h:outputText value="Recipes" />
</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>
<h:outputText value="#{item.title}" />
<h:outputText id="rname"
styleClass="#{(item.count eq 0) ? 'noRecipe' :'plusRecipe' }"
value="#{item.recipe.title}"
/>
</p:column>
</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"
style="width: 25%; vertical-align: top;"
>
@ -64,11 +93,6 @@
/>
</p:column>
</p:headerRow>
<p:column label="ingKey">
<h:outputText
value="#{item.ingkey}"
/>
</p:column>
<p:column label="Amt"
style="width: 3em; text-align: right"
>
@ -95,11 +119,17 @@
</h:form>
</p:tab>
<!-- -->
<p:tab id="ingshopcatEditTab" title="Edit">
<p:tab id="ingshopcatEditTab"
title="Edit Shopping Categories"
>
<ui:include
src="/WEB-INF/layout/misctabs/ingshopkey.xhtml"
/>
</p:tab>
<!-- -->
<p:tab id="tabImportExport" title="Import/Export">
<h:outputText value="For future implementation" />
</p:tab>
</p:tabView>
<h:form id="frmHome">
<p:commandButton id="doHome" value="Home"