use of xyz.zedler.patrick.grocy.model.StockItem in project grocy-android by patzly.
the class StockOverviewItemAdapter method onBindViewHolder.
@SuppressLint("ClickableViewAccessibility")
@Override
public void onBindViewHolder(@NonNull final ViewHolder viewHolder, int positionDoNotUse) {
GroupedListItem groupedListItem = groupedListItems.get(viewHolder.getAdapterPosition());
int type = getItemViewType(viewHolder.getAdapterPosition());
if (type == GroupedListItem.TYPE_HEADER) {
GroupViewHolder holder = (GroupViewHolder) viewHolder;
if (((GroupHeader) groupedListItem).getDisplayDivider() == 1) {
holder.binding.divider.setVisibility(View.VISIBLE);
} else {
holder.binding.divider.setVisibility(View.GONE);
}
holder.binding.name.setText(((GroupHeader) groupedListItem).getGroupName());
return;
}
StockItem stockItem = (StockItem) groupedListItem;
StockItemViewHolder holder = (StockItemViewHolder) viewHolder;
// NAME
holder.binding.textName.setText(stockItem.getProduct().getName());
if (shoppingListItemsProductIds.contains(String.valueOf(stockItem.getProduct().getId())) && shoppingListFeatureEnabled) {
holder.binding.viewOnShoppingList.setVisibility(View.VISIBLE);
} else {
holder.binding.viewOnShoppingList.setVisibility(View.GONE);
}
Context context = holder.binding.textAmount.getContext();
// AMOUNT
QuantityUnit quantityUnit = quantityUnitHashMap.get(stockItem.getProduct().getQuIdStockInt());
holder.binding.textAmount.setText(AmountUtil.getStockAmountInfo(context, pluralUtil, stockItem, quantityUnit));
if (missingItemsProductIds.contains(stockItem.getProductId())) {
holder.binding.textAmount.setTypeface(ResourcesCompat.getFont(context, R.font.jost_medium));
holder.binding.textAmount.setTextColor(ContextCompat.getColor(context, R.color.retro_blue_fg));
} else {
holder.binding.textAmount.setTypeface(ResourcesCompat.getFont(context, R.font.jost_book));
holder.binding.textAmount.setTextColor(ContextCompat.getColor(context, R.color.on_background_secondary));
}
// BEST BEFORE
String date = stockItem.getBestBeforeDate();
String days = null;
boolean colorDays = false;
if (date != null) {
days = String.valueOf(DateUtil.getDaysFromNow(date));
}
if (!showDateTracking) {
holder.binding.linearDays.setVisibility(View.GONE);
} else if (days != null && (sortMode.equals(FilterChipLiveDataStockSort.SORT_DUE_DATE) || Integer.parseInt(days) <= daysExpiringSoon && !date.equals(Constants.DATE.NEVER_OVERDUE))) {
holder.binding.linearDays.setVisibility(View.VISIBLE);
holder.binding.textDays.setText(new DateUtil(context).getHumanForDaysFromNow(date));
if (Integer.parseInt(days) <= daysExpiringSoon) {
colorDays = true;
}
} else {
holder.binding.linearDays.setVisibility(View.GONE);
holder.binding.textDays.setText(null);
}
if (colorDays) {
holder.binding.textDays.setTypeface(ResourcesCompat.getFont(context, R.font.jost_medium));
@ColorRes int color;
if (Integer.parseInt(days) >= 0) {
color = R.color.retro_yellow_fg;
} else if (stockItem.getDueTypeInt() == StockItem.DUE_TYPE_BEST_BEFORE) {
color = R.color.retro_dirt_fg;
} else {
color = R.color.retro_red_fg;
}
holder.binding.textDays.setTextColor(ContextCompat.getColor(context, color));
} else {
holder.binding.textDays.setTypeface(ResourcesCompat.getFont(context, R.font.jost_book));
holder.binding.textDays.setTextColor(ContextCompat.getColor(context, R.color.on_background_secondary));
}
// CONTAINER
holder.binding.linearContainer.setOnClickListener(view -> listener.onItemRowClicked(stockItem));
}
use of xyz.zedler.patrick.grocy.model.StockItem in project grocy-android by patzly.
the class ProductOverviewBottomSheet method onViewCreated.
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
activity = (MainActivity) requireActivity();
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(activity);
pluralUtil = new PluralUtil(activity);
ProductOverviewBottomSheetArgs args = ProductOverviewBottomSheetArgs.fromBundle(requireArguments());
boolean showActions = args.getShowActions();
if (args.getProductDetails() != null) {
productDetails = args.getProductDetails();
product = productDetails.getProduct();
stockItem = new StockItem(productDetails);
} else if (args.getStockItem() != null) {
stockItem = args.getStockItem();
quantityUnit = args.getQuantityUnit();
location = args.getLocation();
product = stockItem.getProduct();
}
// WEB REQUESTS
dlHelper = new DownloadHelper(activity, TAG);
// VIEWS
refreshItems();
binding.textName.setText(product.getName());
// TOOLBAR
boolean isInStock = stockItem.getAmountDouble() > 0;
MenuCompat.setGroupDividerEnabled(binding.toolbar.getMenu(), true);
// disable actions if necessary
binding.toolbar.getMenu().findItem(R.id.action_consume_all).setEnabled(isInStock);
binding.toolbar.getMenu().findItem(R.id.action_consume_spoiled).setEnabled(isInStock && product.getEnableTareWeightHandlingInt() == 0);
binding.toolbar.setOnMenuItemClickListener(item -> {
if (item.getItemId() == R.id.action_add_to_shopping_list) {
navigateDeepLink(R.string.deep_link_shoppingListItemEditFragment, new ShoppingListItemEditFragmentArgs.Builder(Constants.ACTION.CREATE).setProductId(String.valueOf(product.getId())).build().toBundle());
dismiss();
return true;
} else if (item.getItemId() == R.id.action_consume_all) {
activity.getCurrentFragment().performAction(Constants.ACTION.CONSUME_ALL, stockItem);
dismiss();
return true;
} else if (item.getItemId() == R.id.action_consume_spoiled) {
activity.getCurrentFragment().performAction(Constants.ACTION.CONSUME_SPOILED, stockItem);
dismiss();
return true;
} else if (item.getItemId() == R.id.action_edit_product) {
String productId = String.valueOf(product.getId());
navigateDeepLink(R.string.deep_link_masterProductFragment, new MasterProductFragmentArgs.Builder(Constants.ACTION.EDIT).setProductId(productId).build().toBundle());
dismiss();
return true;
}
return false;
});
Chip chipConsume = view.findViewById(R.id.chip_consume);
chipConsume.setVisibility(isInStock ? View.VISIBLE : View.GONE);
chipConsume.setOnClickListener(v -> {
NavHostFragment.findNavController(this).navigate(ProductOverviewBottomSheetDirections.actionProductOverviewBottomSheetDialogFragmentToConsumeFragment().setCloseWhenFinished(true).setProductId(String.valueOf(product.getId())));
dismiss();
});
Chip chipPurchase = view.findViewById(R.id.chip_purchase);
chipPurchase.setOnClickListener(v -> {
NavHostFragment.findNavController(this).navigate(ProductOverviewBottomSheetDirections.actionProductOverviewBottomSheetDialogFragmentToPurchaseFragment().setCloseWhenFinished(true).setProductId(String.valueOf(product.getId())));
dismiss();
});
Chip chipTransfer = view.findViewById(R.id.chip_transfer);
chipTransfer.setVisibility(isInStock && product.getEnableTareWeightHandlingInt() == 0 ? View.VISIBLE : View.GONE);
chipTransfer.setOnClickListener(v -> {
NavHostFragment.findNavController(this).navigate(ProductOverviewBottomSheetDirections.actionProductOverviewBottomSheetDialogFragmentToTransferFragment().setCloseWhenFinished(true).setProductId(String.valueOf(product.getId())));
dismiss();
});
Chip chipInventory = view.findViewById(R.id.chip_inventory);
chipInventory.setOnClickListener(v -> {
NavHostFragment.findNavController(this).navigate(ProductOverviewBottomSheetDirections.actionProductOverviewBottomSheetDialogFragmentToInventoryFragment().setCloseWhenFinished(true).setProductId(String.valueOf(product.getId())));
dismiss();
});
if (!showActions) {
view.findViewById(R.id.container_chips).setVisibility(View.GONE);
}
// DESCRIPTION
Spanned description = product.getDescription() != null ? Html.fromHtml(product.getDescription()) : null;
description = (Spanned) TextUtil.trimCharSequence(description);
if (description != null && !description.toString().isEmpty()) {
binding.cardDescription.setText(description.toString());
} else {
binding.cardDescription.setVisibility(View.GONE);
}
if (!showActions) {
// hide actions when set up with productDetails
binding.linearActionContainer.setVisibility(View.GONE);
// set info menu
binding.toolbar.getMenu().clear();
binding.toolbar.inflateMenu(R.menu.menu_actions_product_overview_info);
}
refreshButtonStates(false);
binding.buttonConsume.setOnClickListener(v -> {
disableActions();
activity.getCurrentFragment().performAction(Constants.ACTION.CONSUME, stockItem);
dismiss();
});
binding.buttonOpen.setOnClickListener(v -> {
disableActions();
activity.getCurrentFragment().performAction(Constants.ACTION.OPEN, stockItem);
dismiss();
});
// tooltips
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
binding.buttonConsume.setTooltipText(activity.getString(R.string.action_consume_one, quantityUnit.getName(), product.getName()));
binding.buttonOpen.setTooltipText(activity.getString(R.string.action_open_one, quantityUnit.getName(), product.getName()));
// TODO: tooltip colors
}
// no margin if description is != null
if (description != null) {
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(0, 0, 0, 0);
binding.linearAmount.setLayoutParams(layoutParams);
}
if (activity.isOnline() && !hasDetails()) {
dlHelper.getProductDetails(product.getId(), details -> {
productDetails = details;
stockItem = new StockItem(productDetails);
refreshButtonStates(true);
refreshItems();
loadPriceHistory();
}).perform(dlHelper.getUuid());
} else if (activity.isOnline() && hasDetails()) {
loadPriceHistory();
}
hideDisabledFeatures();
}
use of xyz.zedler.patrick.grocy.model.StockItem in project grocy-android by patzly.
the class StockOverviewViewModel method consumeProduct.
private void consumeProduct(StockItem stockItem, double amount, boolean spoiled) {
JSONObject body = new JSONObject();
try {
body.put("amount", amount);
body.put("allow_subproduct_substitution", true);
body.put("spoiled", spoiled);
} catch (JSONException e) {
if (debug) {
Log.e(TAG, "consumeProduct: " + e);
}
}
dlHelper.postWithArray(grocyApi.consumeProduct(stockItem.getProductId()), body, response -> {
String transactionId = null;
double amountConsumed = 0;
try {
transactionId = response.getJSONObject(0).getString("transaction_id");
for (int i = 0; i < response.length(); i++) {
amountConsumed -= response.getJSONObject(i).getDouble("amount");
}
} catch (JSONException e) {
if (debug) {
Log.e(TAG, "consumeProduct: " + e);
}
}
String msg = getApplication().getString(spoiled ? R.string.msg_consumed_spoiled : R.string.msg_consumed, NumUtil.trim(amountConsumed), pluralUtil.getQuantityUnitPlural(quantityUnitHashMap, stockItem.getProduct().getQuIdStockInt(), amountConsumed), stockItem.getProduct().getName());
SnackbarMessage snackbarMsg = new SnackbarMessage(msg, 15);
// set undo button on snackBar
if (transactionId != null) {
String finalTransactionId = transactionId;
snackbarMsg.setAction(getString(R.string.action_undo), v -> dlHelper.post(grocyApi.undoStockTransaction(finalTransactionId), response1 -> {
downloadData();
showSnackbar(new SnackbarMessage(getString(R.string.msg_undone_transaction), Snackbar.LENGTH_SHORT));
if (debug) {
Log.i(TAG, "consumeProduct: undone");
}
}, this::showErrorMessage));
}
downloadData();
showSnackbar(snackbarMsg);
if (debug) {
Log.i(TAG, "consumeProduct: consumed " + amountConsumed);
}
}, error -> {
showErrorMessage(error);
if (debug) {
Log.i(TAG, "consumeProduct: " + error);
}
});
}
use of xyz.zedler.patrick.grocy.model.StockItem in project grocy-android by patzly.
the class StockOverviewViewModel method loadFromDatabase.
public void loadFromDatabase(boolean downloadAfterLoading) {
repository.loadFromDatabase((quantityUnits, productGroups, stockItems, products, barcodes, shoppingListItems, locations, stockLocations) -> {
this.quantityUnits = quantityUnits;
quantityUnitHashMap = new HashMap<>();
for (QuantityUnit quantityUnit : quantityUnits) {
quantityUnitHashMap.put(quantityUnit.getId(), quantityUnit);
}
this.productGroups = productGroups;
productGroupHashMap = ArrayUtil.getProductGroupsHashMap(productGroups);
filterChipLiveDataProductGroup.setProductGroups(productGroups);
this.products = products;
productHashMap = new HashMap<>();
for (Product product : products) {
productHashMap.put(product.getId(), product);
}
this.productBarcodesTemp = barcodes;
productBarcodeHashMap = new HashMap<>();
for (ProductBarcode barcode : barcodes) {
productBarcodeHashMap.put(barcode.getBarcode().toLowerCase(), barcode);
}
int itemsDueCount = 0;
int itemsOverdueCount = 0;
int itemsExpiredCount = 0;
int itemsMissingCount = 0;
int itemsInStockCount = 0;
int itemsOpenedCount = 0;
productIdsMissingStockItems = new HashMap<>();
this.stockItems = stockItems;
for (StockItem stockItem : stockItems) {
stockItem.setProduct(productHashMap.get(stockItem.getProductId()));
if (stockItem.isItemDue()) {
itemsDueCount++;
}
if (stockItem.isItemOverdue()) {
itemsOverdueCount++;
}
if (stockItem.isItemExpired()) {
itemsExpiredCount++;
}
if (stockItem.isItemMissing()) {
itemsMissingCount++;
productIdsMissingStockItems.put(stockItem.getProductId(), stockItem);
}
if (!stockItem.isItemMissing() || stockItem.isItemMissingAndPartlyInStock()) {
itemsInStockCount++;
}
if (stockItem.getAmountOpenedDouble() > 0) {
itemsOpenedCount++;
}
}
this.shoppingListItems = shoppingListItems;
shoppingListItemsProductIds = new ArrayList<>();
for (ShoppingListItem item : shoppingListItems) {
if (item.getProductId() != null && !item.getProductId().isEmpty()) {
shoppingListItemsProductIds.add(item.getProductId());
}
}
this.locations = locations;
filterChipLiveDataLocation.setLocations(locations);
locationHashMap = new HashMap<>();
for (Location location : locations) {
locationHashMap.put(location.getId(), location);
}
this.stockCurrentLocationsTemp = stockLocations;
stockLocationsHashMap = new HashMap<>();
for (StockLocation stockLocation : stockLocations) {
HashMap<Integer, StockLocation> locationsForProductId = stockLocationsHashMap.get(stockLocation.getProductId());
if (locationsForProductId == null) {
locationsForProductId = new HashMap<>();
stockLocationsHashMap.put(stockLocation.getProductId(), locationsForProductId);
}
locationsForProductId.put(stockLocation.getLocationId(), stockLocation);
}
filterChipLiveDataStatus.setDueSoonCount(itemsDueCount).setOverdueCount(itemsOverdueCount).setExpiredCount(itemsExpiredCount).setBelowStockCount(itemsMissingCount).setInStockCount(itemsInStockCount).setOpenedCount(itemsOpenedCount).emitCounts();
updateFilteredStockItems();
if (downloadAfterLoading) {
downloadData();
}
});
}
use of xyz.zedler.patrick.grocy.model.StockItem in project grocy-android by patzly.
the class StockOverviewViewModel method updateFilteredStockItems.
public void updateFilteredStockItems() {
ArrayList<StockItem> filteredStockItems = new ArrayList<>();
ProductBarcode productBarcodeSearch = null;
if (searchInput != null && !searchInput.isEmpty()) {
productBarcodeSearch = productBarcodeHashMap.get(searchInput);
}
for (StockItem item : this.stockItems) {
if (item.getProduct() == null) {
// invalidate products and stock items offline cache because products may have changed
SharedPreferences.Editor editPrefs = sharedPrefs.edit();
editPrefs.putString(PREF.DB_LAST_TIME_PRODUCTS, null);
editPrefs.putString(PREF.DB_LAST_TIME_STOCK_ITEMS, null);
editPrefs.apply();
continue;
}
if (item.getProduct().getHideOnStockOverviewInt() == 1) {
continue;
}
boolean searchContainsItem = true;
if (searchInput != null && !searchInput.isEmpty()) {
searchContainsItem = item.getProduct().getName().toLowerCase().contains(searchInput);
}
if (!searchContainsItem && productBarcodeSearch == null || !searchContainsItem && productBarcodeSearch.getProductId() != item.getProductId()) {
continue;
}
int productGroupFilterId = filterChipLiveDataProductGroup.getSelectedId();
if (productGroupFilterId != FilterChipLiveDataProductGroup.NO_FILTER && NumUtil.isStringInt(item.getProduct().getProductGroupId()) && productGroupFilterId != Integer.parseInt(item.getProduct().getProductGroupId()) || productGroupFilterId != FilterChipLiveDataProductGroup.NO_FILTER && !NumUtil.isStringInt(item.getProduct().getProductGroupId())) {
continue;
}
int locationFilterId = filterChipLiveDataLocation.getSelectedId();
if (locationFilterId != FilterChipLiveDataLocation.NO_FILTER) {
HashMap<Integer, StockLocation> stockLocationsForProductId = stockLocationsHashMap.get(item.getProductId());
if (stockLocationsForProductId == null || !stockLocationsForProductId.containsKey(locationFilterId)) {
continue;
}
}
StockItem missingStockItem = productIdsMissingStockItems.get(item.getProductId());
if (filterChipLiveDataStatus.getStatus() == FilterChipLiveDataStockStatus.STATUS_ALL || filterChipLiveDataStatus.getStatus() == FilterChipLiveDataStockStatus.STATUS_DUE_SOON && item.isItemDue() || filterChipLiveDataStatus.getStatus() == FilterChipLiveDataStockStatus.STATUS_OVERDUE && item.isItemOverdue() || filterChipLiveDataStatus.getStatus() == FilterChipLiveDataStockStatus.STATUS_EXPIRED && item.isItemExpired() || filterChipLiveDataStatus.getStatus() == FilterChipLiveDataStockStatus.STATUS_BELOW_MIN && missingStockItem != null || filterChipLiveDataStatus.getStatus() == FilterChipLiveDataStockStatus.STATUS_IN_STOCK && (missingStockItem == null || missingStockItem.isItemMissingAndPartlyInStock()) || filterChipLiveDataStatus.getStatus() == FilterChipLiveDataStockStatus.STATUS_OPENED && item.getAmountOpenedDouble() > 0) {
filteredStockItems.add(item);
}
}
if (filteredStockItems.isEmpty()) {
InfoFullscreen info;
if (searchInput != null && !searchInput.isEmpty()) {
info = new InfoFullscreen(InfoFullscreen.INFO_NO_SEARCH_RESULTS);
} else if (filterChipLiveDataStatus.getStatus() != FilterChipLiveDataStockStatus.STATUS_ALL || filterChipLiveDataProductGroup.getSelectedId() != FilterChipLiveDataProductGroup.NO_FILTER || filterChipLiveDataLocation.getSelectedId() != FilterChipLiveDataProductGroup.NO_FILTER) {
info = new InfoFullscreen(InfoFullscreen.INFO_NO_FILTER_RESULTS);
} else {
info = new InfoFullscreen(InfoFullscreen.INFO_EMPTY_STOCK);
}
infoFullscreenLive.setValue(info);
} else {
infoFullscreenLive.setValue(null);
}
filteredStockItemsLive.setValue(filteredStockItems);
}
Aggregations