From 1e82d2c1dbd42c57c75991a2ff7205402a55c8ed Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Sun, 17 May 2020 08:08:05 +0200 Subject: [PATCH 1/4] Add Categories Signed-off-by: tobiasKaminsky --- app/build.gradle | 1 + .../woefe/shoppinglist/activity/EditBar.java | 37 +++-- .../activity/RecyclerListAdapter.java | 139 ++++++++++++------ .../activity/ShoppingListFragment.java | 13 +- .../shoppinglist/shoppinglist/ListItem.java | 14 +- .../shoppinglist/ShoppingList.java | 62 ++++++-- .../shoppinglist/ShoppingListMarshaller.java | 51 +++++-- .../ShoppingListUnmarshaller.java | 42 +++++- .../shoppinglist/ShoppingListsManager.java | 4 +- .../main/res/layout/fragment_shoppinglist.xml | 19 ++- app/src/main/res/layout/list_category.xml | 38 +++++ app/src/main/res/layout/list_item.xml | 2 +- app/src/main/res/values/strings.xml | 1 + 13 files changed, 324 insertions(+), 99 deletions(-) create mode 100644 app/src/main/res/layout/list_category.xml diff --git a/app/build.gradle b/app/build.gradle index 454efa1..3dbc789 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,4 +44,5 @@ dependencies { implementation 'com.android.support:design:28.0.0' implementation 'com.android.support:preference-v7:28.0.0' implementation 'com.android.support:recyclerview-v7:28.0.0' + implementation 'com.afollestad:sectioned-recyclerview:0.5.0' } diff --git a/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java b/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java index 2d1e219..7c0cbd0 100644 --- a/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java +++ b/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java @@ -31,9 +31,11 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.inputmethod.InputMethodManager; +import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ImageButton; import android.widget.RelativeLayout; +import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; @@ -46,12 +48,14 @@ public class EditBar implements ShoppingList.ShoppingListListener { private static final String KEY_SAVED_DESCRIPTION = "SAVED_DESCRIPTION"; private static final String KEY_SAVED_QUANTITY = "SAVED_QUANTITY"; + private static final String KEY_SAVED_CATEGORY = "SAVED_CATEGORY"; private static final String KEY_SAVED_MODE = "SAVED_MODE"; private static final String KEY_SAVE_IS_VISIBLE = "SAVE_IS_VISIBLE"; private final Context ctx; private final RelativeLayout layout; private final EditText descriptionText; private final EditText quantityText; + private final Spinner categorySpinner; private final TextView duplicateWarnText; private Mode mode; private EditBarListener listener; @@ -59,6 +63,7 @@ public class EditBar implements ShoppingList.ShoppingListListener { private int position; private final Set descriptionIndex = new HashSet<>(); private ShoppingList shoppingList; + private ArrayAdapter categoryAdapter; public EditBar(View boundView, final Context ctx) { this.ctx = ctx; @@ -66,6 +71,10 @@ public EditBar(View boundView, final Context ctx) { final ImageButton button = boundView.findViewById(R.id.button_add_new_item); this.descriptionText = boundView.findViewById(R.id.new_item_description); this.quantityText = boundView.findViewById(R.id.new_item_quantity); + this.categorySpinner = boundView.findViewById(R.id.category_description); + categoryAdapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item); + categoryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + categorySpinner.setAdapter(categoryAdapter); this.duplicateWarnText = boundView.findViewById(R.id.text_warn); this.mode = Mode.ADD; @@ -141,6 +150,7 @@ private void setButtonEnabled(ImageButton button, boolean enabled) { private void onConfirm() { String desc = descriptionText.getText().toString(); String qty = quantityText.getText().toString(); + String category = categorySpinner.getSelectedItem().toString(); if (desc.equals("")) { Toast.makeText(ctx, R.string.error_description_empty, Toast.LENGTH_SHORT).show(); @@ -148,32 +158,35 @@ private void onConfirm() { } if (mode == Mode.ADD) { - listener.onNewItem(desc, qty); + listener.onNewItem(desc, qty, category); descriptionText.requestFocus(); } else if (mode == Mode.EDIT) { - listener.onEditSave(position, desc, qty); + listener.onEditSave(position, desc, qty, category); } descriptionText.setText(""); quantityText.setText(""); + //categorySpinner.setText(""); } - public void showEdit(int position, String description, String quantity) { - this.position = position; - prepare(Mode.EDIT, description, quantity); + public void showEdit(String description, String quantity, String category) { + // this.position = position; + prepare(Mode.EDIT, description, quantity, category); show(); } public void showAdd() { - prepare(Mode.ADD, "", ""); + prepare(Mode.ADD, "", "", ""); show(); } - private void prepare(Mode mode, String description, String quantity) { + private void prepare(Mode mode, String description, String quantity, String category) { this.mode = mode; quantityText.setText(quantity); descriptionText.setText(""); descriptionText.append(description); + int position = shoppingList.getCategories().indexOf(category); + categorySpinner.setSelection(position); } public void enableAutoHideFAB(RecyclerView view) { @@ -269,6 +282,7 @@ public void removeEditBarListener(EditBarListener l) { public void saveState(Bundle state) { state.putString(KEY_SAVED_DESCRIPTION, descriptionText.getText().toString()); state.putString(KEY_SAVED_QUANTITY, quantityText.getText().toString()); + state.putInt(KEY_SAVED_CATEGORY, categorySpinner.getSelectedItemPosition()); state.putBoolean(KEY_SAVE_IS_VISIBLE, isVisible()); state.putSerializable(KEY_SAVED_MODE, mode); } @@ -276,9 +290,10 @@ public void saveState(Bundle state) { public void restoreState(Bundle state) { String description = state.getString(KEY_SAVED_DESCRIPTION); String quantity = state.getString(KEY_SAVED_QUANTITY); + categorySpinner.setSelection(state.getInt(KEY_SAVED_CATEGORY)); Mode mode = (Mode) state.getSerializable(KEY_SAVED_MODE); if (state.getBoolean(KEY_SAVE_IS_VISIBLE)) { - prepare(mode, description, quantity); + prepare(mode, description, quantity, categorySpinner.getSelectedItem().toString()); layout.setVisibility(View.VISIBLE); fab.hide(); } @@ -305,13 +320,15 @@ public void onShoppingListUpdate(ShoppingList list, ShoppingList.Event e) { } descriptionIndex.clear(); descriptionIndex.addAll(list.createDescriptionIndex()); + categoryAdapter.clear(); + categoryAdapter.addAll(shoppingList.getCategories()); checkDuplicate(descriptionText.getText().toString()); } public interface EditBarListener { - void onEditSave(int position, String description, String quantity); + void onEditSave(int position, String description, String quantity, String category); - void onNewItem(String description, String quantity); + void onNewItem(String description, String quantity, String category); } private enum Mode { diff --git a/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java b/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java index 5f9c18c..6bba47b 100644 --- a/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java +++ b/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java @@ -15,6 +15,8 @@ import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter; +import com.afollestad.sectionedrecyclerview.SectionedViewHolder; import com.woefe.shoppinglist.R; import com.woefe.shoppinglist.shoppinglist.ListItem; import com.woefe.shoppinglist.shoppinglist.ShoppingList; @@ -22,7 +24,7 @@ /** * @author Wolfgang Popp */ -public class RecyclerListAdapter extends RecyclerView.Adapter { +public class RecyclerListAdapter extends SectionedRecyclerViewAdapter { private final int colorChecked; private final int colorDefault; private final int colorBackground; @@ -40,9 +42,6 @@ public void onShoppingListUpdate(ShoppingList list, ShoppingList.Event e) { case ShoppingList.Event.ITEM_INSERTED: notifyItemInserted(e.getIndex()); break; - case ShoppingList.Event.ITEM_MOVED: - notifyItemMoved(e.getOldIndex(), e.getNewIndex()); - break; case ShoppingList.Event.ITEM_REMOVED: notifyItemRemoved(e.getIndex()); break; @@ -72,8 +71,8 @@ public void disconnectShoppingList() { } } - public void move(int fromPos, int toPos) { - shoppingList.move(fromPos, toPos); + public void move(ListItem from, ListItem to) { + shoppingList.move(from, to); } public void remove(int pos) { @@ -90,76 +89,119 @@ public void setOnItemLongClickListener(ItemLongClickListener listener) { @NonNull @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.list_item, parent, false); - return new ViewHolder(v); + public SectionedViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + if (viewType == VIEW_TYPE_HEADER) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_category, parent, false); + return new CategoryViewHolder(v); + } else { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false); + return new ItemViewHolder(v); + } + } + + @Override + public int getSectionCount() { + return shoppingList.getCategories().size(); + } + + @Override + public int getItemCount(int section) { + String category = shoppingList.getCategories().get(section); + int count = 0; + + for (int i = 0; i < shoppingList.size(); i++) { + if (shoppingList.get(i).getCategory().equals(category)) { + count++; + } + } + + return count; + } + + @Override + public void onBindHeaderViewHolder(SectionedViewHolder sectionedViewHolder, int section, boolean expanded) { + CategoryViewHolder categoryViewHolder = (CategoryViewHolder) sectionedViewHolder; + categoryViewHolder.category.setText(shoppingList.getCategories().get(section)); + } + + @Override + public void onBindFooterViewHolder(SectionedViewHolder sectionedViewHolder, int i) { + // not needed } @Override - public void onBindViewHolder(@NonNull final ViewHolder holder, int position) { - ListItem listItem = shoppingList.get(position); - holder.description.setText(listItem.getDescription()); - holder.quantity.setText(listItem.getQuantity()); + public void onBindViewHolder(SectionedViewHolder sectionedViewHolder, + int section, + int relativePosition, + final int absolutePosition) { + + final ItemViewHolder itemViewHolder = (ItemViewHolder) sectionedViewHolder; + String category = shoppingList.getCategories().get(section); + final ListItem listItem = shoppingList.getListItemByCategory(category).get(relativePosition); + + itemViewHolder.description.setText(listItem.getDescription()); + itemViewHolder.quantity.setText(listItem.getQuantity()); + itemViewHolder.listItem = listItem; if (listItem.isChecked()) { - holder.description.setTextColor(colorChecked); - holder.quantity.setTextColor(colorChecked); + itemViewHolder.description.setTextColor(colorChecked); + itemViewHolder.quantity.setTextColor(colorChecked); } else { - holder.description.setTextColor(colorDefault); - holder.quantity.setTextColor(colorDefault); + itemViewHolder.description.setTextColor(colorDefault); + itemViewHolder.quantity.setTextColor(colorDefault); } - holder.itemView.setBackgroundColor(colorBackground); + itemViewHolder.itemView.setBackgroundColor(colorBackground); - holder.view.setOnClickListener(new View.OnClickListener() { + itemViewHolder.view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - shoppingList.toggleChecked(holder.getAdapterPosition()); + shoppingList.toggleChecked(listItem, absolutePosition); } }); - - holder.view.setOnLongClickListener(new View.OnLongClickListener() { + itemViewHolder.view.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { return longClickListener != null - && longClickListener.onLongClick(holder.getAdapterPosition()); + && longClickListener.onLongClick(listItem); } }); - holder.dragHandler.setOnTouchListener(new View.OnTouchListener() { + itemViewHolder.dragHandler.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { - touchHelper.startDrag(holder); + touchHelper.startDrag(itemViewHolder); return true; } return false; } }); - } - @Override - public int getItemCount() { - if (shoppingList != null) { - return shoppingList.size(); - } - return 0; + public interface ItemLongClickListener { + boolean onLongClick(ListItem item); } - public interface ItemLongClickListener { - boolean onLongClick(int position); + static class CategoryViewHolder extends SectionedViewHolder { + TextView category; + + CategoryViewHolder(View itemView) { + super(itemView); + + category = itemView.findViewById(R.id.category); + } } - public static class ViewHolder extends RecyclerView.ViewHolder { + static class ItemViewHolder extends SectionedViewHolder { TextView description; TextView quantity; ImageView dragHandler; View view; + ListItem listItem; - public ViewHolder(View itemView) { + public ItemViewHolder(View itemView) { super(itemView); view = itemView; description = itemView.findViewById(R.id.text_description); @@ -190,19 +232,28 @@ public boolean isLongPressDragEnabled() { } @Override - public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; final int swipeFlags = ItemTouchHelper.START; return makeMovementFlags(dragFlags, swipeFlags); } @Override - public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { + public boolean onMove(@NonNull RecyclerView recyclerView, + RecyclerView.ViewHolder viewHolder, + RecyclerView.ViewHolder target) { if (viewHolder.getItemViewType() != target.getItemViewType()) { return false; } - RecyclerListAdapter.this.move(viewHolder.getAdapterPosition(), target.getAdapterPosition()); + if (!(viewHolder instanceof ItemViewHolder) || !(target instanceof ItemViewHolder)) { + return false; + } + + ItemViewHolder sourceViewHolder = (ItemViewHolder) viewHolder; + ItemViewHolder targetViewHolder = (ItemViewHolder) target; + + RecyclerListAdapter.this.move(sourceViewHolder.listItem, targetViewHolder.listItem); return true; } @@ -212,7 +263,13 @@ public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { } @Override - public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + public void onChildDraw(@NonNull Canvas c, + @NonNull RecyclerView recyclerView, + @NonNull RecyclerView.ViewHolder viewHolder, + float dX, + float dY, + int actionState, + boolean isCurrentlyActive) { if (actionState != ItemTouchHelper.ACTION_STATE_SWIPE) { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); diff --git a/app/src/main/java/com/woefe/shoppinglist/activity/ShoppingListFragment.java b/app/src/main/java/com/woefe/shoppinglist/activity/ShoppingListFragment.java index a24e4dc..2fe65f2 100644 --- a/app/src/main/java/com/woefe/shoppinglist/activity/ShoppingListFragment.java +++ b/app/src/main/java/com/woefe/shoppinglist/activity/ShoppingListFragment.java @@ -110,9 +110,8 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) { adapter.registerRecyclerView(recyclerView); adapter.setOnItemLongClickListener(new RecyclerListAdapter.ItemLongClickListener() { @Override - public boolean onLongClick(int position) { - ListItem listItem = shoppingList.get(position); - editBar.showEdit(position, listItem.getDescription(), listItem.getQuantity()); + public boolean onLongClick(ListItem listItem) { + editBar.showEdit(listItem.getDescription(), listItem.getQuantity(), listItem.getCategory()); return true; } }); @@ -134,15 +133,15 @@ public void onSaveInstanceState(Bundle outState) { } @Override - public void onEditSave(int position, String description, String quantity) { - shoppingList.editItem(position, description, quantity); + public void onEditSave(int position, String description, String quantity, String category) { + shoppingList.editItem(position, description, quantity, category); editBar.hide(); recyclerView.smoothScrollToPosition(position); } @Override - public void onNewItem(String description, String quantity) { - shoppingList.add(description, quantity); + public void onNewItem(String description, String quantity, String category) { + shoppingList.add(description, quantity, category); recyclerView.smoothScrollToPosition(recyclerView.getAdapter().getItemCount() - 1); } diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ListItem.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ListItem.java index 7c173f6..c480d17 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ListItem.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ListItem.java @@ -26,11 +26,13 @@ public class ListItem { private boolean isChecked; private String description; private String quantity; + private String category; - public ListItem(boolean isChecked, String description, String quantity) { + public ListItem(boolean isChecked, String description, String quantity, String category) { this.isChecked = isChecked; this.description = description; this.quantity = quantity; + this.category = category; } public boolean isChecked() { @@ -57,11 +59,19 @@ public void setQuantity(String quantity) { this.quantity = quantity; } + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + static class ListItemWithID extends ListItem { private final int id; public ListItemWithID(int id, ListItem item) { - super(item.isChecked, item.description, item.quantity); + super(item.isChecked, item.description, item.quantity, item.category); this.id = id; } diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java index 36a49bb..6ddad0f 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java @@ -40,6 +40,8 @@ public class ShoppingList extends ArrayList { private String name; private static int currentID; private final List listeners = new LinkedList<>(); + private List categories = new ArrayList<>(); + public static final String DEFAULT_CATEGORY = "Allgemein"; public ShoppingList(String name) { super(); @@ -51,6 +53,12 @@ public ShoppingList(String name, Collection collection) { this.name = name; } + public void addDefaultCategory() { + if (categories.isEmpty()) { + categories.add(DEFAULT_CATEGORY); // todo translate + } + } + public String getName() { return name; } @@ -71,8 +79,8 @@ public boolean add(ListItem item) { return res; } - public boolean add(String description, String quantity) { - return add(new ListItem(false, description, quantity)); + public boolean add(String description, String quantity, String category) { + return add(new ListItem(false, description, quantity, category)); } @Override @@ -82,14 +90,14 @@ public void add(int index, ListItem element) { } @Override - public boolean addAll(Collection c) { + public boolean addAll(@NonNull Collection c) { boolean b = super.addAll(c); notifyListChanged(Event.newOther()); return b; } @Override - public boolean addAll(int index, Collection c) { + public boolean addAll(int index, @NonNull Collection c) { boolean b = super.addAll(index, c); notifyListChanged(Event.newOther()); return b; @@ -125,7 +133,7 @@ protected void removeRange(int fromIndex, int toIndex) { } @Override - public boolean removeAll(Collection c) { + public boolean removeAll(@NonNull Collection c) { boolean b = super.removeAll(c); if (b) { notifyListChanged(Event.newOther()); @@ -134,7 +142,7 @@ public boolean removeAll(Collection c) { } @Override - public boolean removeIf(Predicate filter) { + public boolean removeIf(@NonNull Predicate filter) { boolean b = false; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { b = super.removeIf(filter); @@ -146,7 +154,7 @@ public boolean removeIf(Predicate filter) { } @Override - public void replaceAll(UnaryOperator operator) { + public void replaceAll(@NonNull UnaryOperator operator) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { super.replaceAll(operator); notifyListChanged(Event.newOther()); @@ -154,7 +162,7 @@ public void replaceAll(UnaryOperator operator) { } @Override - public boolean retainAll(Collection c) { + public boolean retainAll(@NonNull Collection c) { boolean b = super.retainAll(c); if (b) { notifyListChanged(Event.newOther()); @@ -195,24 +203,28 @@ public void sort(Comparator c) { notifyListChanged(Event.newOther()); } - public void setChecked(int index, boolean isChecked) { - get(index).setChecked(isChecked); - notifyListChanged(Event.newItemChanged(index)); + public void setChecked(ListItem item, boolean isChecked, int absolutePosition) { + get(indexOf(item)).setChecked(isChecked); + notifyListChanged(Event.newItemChanged(absolutePosition)); } - public void toggleChecked(int index) { - setChecked(index, !get(index).isChecked()); + public void toggleChecked(ListItem item, int absolutePosition) { + setChecked(item, !item.isChecked(), absolutePosition); } - public void move(int oldIndex, int newIndex) { + public void move(ListItem from, ListItem to) { + int oldIndex = indexOf(from); + int newIndex = indexOf(to); + super.add(newIndex, super.remove(oldIndex)); notifyListChanged(Event.newItemMoved(oldIndex, newIndex)); } - public void editItem(int index, String newDescription, String newQuantity) { + public void editItem(int index, String newDescription, String newQuantity, String newCategory) { ListItem listItem = get(index); listItem.setDescription(newDescription); listItem.setQuantity(newQuantity); + listItem.setCategory(newCategory); notifyListChanged(Event.newItemChanged(index)); } @@ -249,6 +261,26 @@ private synchronized int generateID() { return ++currentID; } + public void parseCategories(String line) { + categories.addAll(Arrays.asList(line.split(":")[1].split(","))); + } + + public List getCategories() { + return categories; + } + + public List getListItemByCategory(String desiredCategory) { + List list = new ArrayList<>(); + + for (int i = 0; i < size(); i++) { + if (desiredCategory.equals(get(i).getCategory())) { + list.add(get(i)); + } + } + + return list; + } + private void notifyListChanged(ShoppingList.Event event) { for (ShoppingListListener listener : listeners) { listener.onShoppingListUpdate(this, event); diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListMarshaller.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListMarshaller.java index c1b42f7..74a49a8 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListMarshaller.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListMarshaller.java @@ -20,6 +20,7 @@ package com.woefe.shoppinglist.shoppinglist; import android.support.annotation.NonNull; +import android.text.TextUtils; import java.io.BufferedWriter; import java.io.IOException; @@ -34,25 +35,47 @@ public static void marshall(@NonNull OutputStream stream, @NonNull ShoppingList writer.write(list.getName()); writer.write(" ]\n\n"); - for (ListItem item : list) { - String quantity = item.getQuantity(); - String description = item.getDescription(); - - if (item.isChecked()) { - writer.write("// "); + writer.write("Categories:"); + int categorySize = list.getCategories().size(); + for (int i = 0; i < categorySize; i++) { + writer.write(list.getCategories().get(i)); + if (i < categorySize - 1) { + writer.write(","); } + } + writer.write("\n"); - if (description != null) { - writer.write(description); + for (String category : list.getCategories()) { + for (ListItem item : list.getListItemByCategory(category)) { + writeItem(item, writer); } + } + } + } - if (quantity != null && !quantity.equals("")) { - writer.write(" #"); - writer.write(quantity); - } + private static void writeItem(ListItem item, BufferedWriter writer) throws IOException { + String quantity = item.getQuantity(); + String description = item.getDescription(); + String category = item.getCategory(); - writer.write("\n"); - } + if (item.isChecked()) { + writer.write("// "); } + + if (description != null) { + writer.write(description); + } + + if (quantity != null && !quantity.equals("")) { + writer.write(" #"); + writer.write(quantity); + } + + if (!TextUtils.isEmpty(category)) { + writer.write(" $"); + writer.write(category); + } + + writer.write("\n"); } } diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListUnmarshaller.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListUnmarshaller.java index 9039aae..a770aec 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListUnmarshaller.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListUnmarshaller.java @@ -27,9 +27,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import static com.woefe.shoppinglist.shoppinglist.ShoppingList.DEFAULT_CATEGORY; + public class ShoppingListUnmarshaller { private static final Pattern EMPTY_LINE = Pattern.compile("^\\s*$"); private static final Pattern HEADER = Pattern.compile("\\[(.*)]"); + private static final Pattern CATEGORY = Pattern.compile("^Categories:.*$"); public static ShoppingList unmarshal(String filename) throws IOException, UnmarshallException { return unmarshal(new FileInputStream(filename)); @@ -56,34 +59,61 @@ public static ShoppingList unmarshal(InputStream inputStream) throws IOException String line; while ((line = reader.readLine()) != null) { - if (!EMPTY_LINE.matcher(line).matches()) { - shoppingList.add(createListItem(line)); + if (CATEGORY.matcher(line).matches()) { + shoppingList.parseCategories(line); + } else if (!EMPTY_LINE.matcher(line).matches()) { + shoppingList.add(createListItem(line, shoppingList)); } } + if (shoppingList.getCategories().isEmpty()) { + shoppingList.addDefaultCategory(); + } + return shoppingList; } - private static ListItem createListItem(String item) { + private static ListItem createListItem(String item, ShoppingList shoppingList) { boolean isChecked = item.startsWith("//"); int index; String quantity; String name; + String category; if (isChecked) { item = item.substring(2); } index = item.lastIndexOf("#"); + int indexCategory = item.lastIndexOf("$"); if (index != -1) { - quantity = item.substring(index + 1).trim(); + if (indexCategory != -1) { + quantity = item.substring(index + 1, indexCategory).trim(); + } else { + quantity = item.substring(index + 1).trim(); + } name = item.substring(0, index).trim(); } else { quantity = ""; - name = item.trim(); + + if (indexCategory != -1) { + name = item.substring(0, indexCategory); + } else { + name = item.trim(); + } + } + + if (indexCategory != -1) { + category = item.substring(indexCategory + 1).trim(); + } else { + category = DEFAULT_CATEGORY; + } + + if (!shoppingList.getCategories().contains(category)) { + shoppingList.getCategories().add(category); } - return new ListItem(isChecked, name.trim(), quantity); + return new ListItem(isChecked, name.trim(), quantity, category); } } diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListsManager.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListsManager.java index aeadc69..e74c7f8 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListsManager.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListsManager.java @@ -205,7 +205,9 @@ void addList(String name) throws ShoppingListException { } String filename = new File(this.directory, URLEncoder.encode(name) + FILE_ENDING).getPath(); - ShoppingListMetadata metadata = addShoppingList(new ShoppingList(name), filename); + ShoppingList shoppingList = new ShoppingList(name); + shoppingList.addDefaultCategory(); + ShoppingListMetadata metadata = addShoppingList(shoppingList, filename); metadata.isDirty = true; } diff --git a/app/src/main/res/layout/fragment_shoppinglist.xml b/app/src/main/res/layout/fragment_shoppinglist.xml index 906cea7..48d3f26 100644 --- a/app/src/main/res/layout/fragment_shoppinglist.xml +++ b/app/src/main/res/layout/fragment_shoppinglist.xml @@ -78,12 +78,27 @@ android:singleLine="true" /> + + + + diff --git a/app/src/main/res/layout/list_category.xml b/app/src/main/res/layout/list_category.xml new file mode 100644 index 0000000..c6fff3d --- /dev/null +++ b/app/src/main/res/layout/list_category.xml @@ -0,0 +1,38 @@ + + + + + + diff --git a/app/src/main/res/layout/list_item.xml b/app/src/main/res/layout/list_item.xml index 12bddd6..62a65e2 100644 --- a/app/src/main/res/layout/list_item.xml +++ b/app/src/main/res/layout/list_item.xml @@ -55,4 +55,4 @@ android:layout_height="wrap_content" android:contentDescription="@string/swap" /> - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a49a9e2..1b696ee 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -67,4 +67,5 @@ <h3>License</h3> ShoppingList is licensed under <a href="https://raw.githubusercontent.com/woefe/ShoppingList/master/COPYING">GPLv3+</a> <h3>Author</h3> Wolfgang Popp <h3>Contributors</h3> • <b>Pierre Rudloff</b> (French translation)<br/> • <b>unbranched</b> (Italian translation)<br/> + Category From 60c384f6a834d44d0fa19f812b3d7e6cc8edeff1 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Sat, 23 May 2020 08:07:31 +0200 Subject: [PATCH 2/4] wip Signed-off-by: tobiasKaminsky --- .../woefe/shoppinglist/activity/EditBar.java | 4 +- .../activity/RecyclerListAdapter.java | 93 ++++++++++++------- .../shoppinglist/ShoppingList.java | 53 +++++++---- .../shoppinglist/ShoppingListMarshaller.java | 9 +- .../ShoppingListUnmarshaller.java | 12 +-- 5 files changed, 108 insertions(+), 63 deletions(-) diff --git a/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java b/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java index 7c0cbd0..1843bdb 100644 --- a/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java +++ b/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java @@ -185,7 +185,7 @@ private void prepare(Mode mode, String description, String quantity, String cate quantityText.setText(quantity); descriptionText.setText(""); descriptionText.append(description); - int position = shoppingList.getCategories().indexOf(category); + int position = shoppingList.getCategories().indexOfKey(category); categorySpinner.setSelection(position); } @@ -321,7 +321,7 @@ public void onShoppingListUpdate(ShoppingList list, ShoppingList.Event e) { descriptionIndex.clear(); descriptionIndex.addAll(list.createDescriptionIndex()); categoryAdapter.clear(); - categoryAdapter.addAll(shoppingList.getCategories()); + categoryAdapter.addAll(shoppingList.getCategories().keySet()); checkDuplicate(descriptionText.getText().toString()); } diff --git a/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java b/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java index 6bba47b..def0c1a 100644 --- a/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java +++ b/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java @@ -8,6 +8,7 @@ import android.support.v4.content.ContextCompat; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; +import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -21,6 +22,8 @@ import com.woefe.shoppinglist.shoppinglist.ListItem; import com.woefe.shoppinglist.shoppinglist.ShoppingList; +import java.util.ArrayList; + /** * @author Wolfgang Popp */ @@ -42,6 +45,16 @@ public void onShoppingListUpdate(ShoppingList list, ShoppingList.Event e) { case ShoppingList.Event.ITEM_INSERTED: notifyItemInserted(e.getIndex()); break; + case ShoppingList.Event.ITEM_MOVED: + notifyItemMoved(e.getOldIndex(), e.getNewIndex()); + Log.d("LIST", ""); + Log.d("LIST", "------------"); + for (ListItem item : shoppingList.getCategories().get("Allgemein")) { + Log.d("LIST", item.getDescription()); + } + Log.d("LIST", "------------"); + Log.d("LIST", ""); + break; case ShoppingList.Event.ITEM_REMOVED: notifyItemRemoved(e.getIndex()); break; @@ -71,8 +84,17 @@ public void disconnectShoppingList() { } } - public void move(ListItem from, ListItem to) { - shoppingList.move(from, to); + public void move(String category, + int fromPositionInCategory, + int toPositionInCategory, + int fromAbsolutePosition, + int toAbsolutePosition) { + shoppingList.moveInCategory(category, + fromPositionInCategory, + toPositionInCategory, + fromAbsolutePosition, + toAbsolutePosition + ); } public void remove(int pos) { @@ -106,22 +128,13 @@ public int getSectionCount() { @Override public int getItemCount(int section) { - String category = shoppingList.getCategories().get(section); - int count = 0; - - for (int i = 0; i < shoppingList.size(); i++) { - if (shoppingList.get(i).getCategory().equals(category)) { - count++; - } - } - - return count; + return shoppingList.getCategories().valueAt(section).size(); } @Override public void onBindHeaderViewHolder(SectionedViewHolder sectionedViewHolder, int section, boolean expanded) { CategoryViewHolder categoryViewHolder = (CategoryViewHolder) sectionedViewHolder; - categoryViewHolder.category.setText(shoppingList.getCategories().get(section)); + categoryViewHolder.category.setText(shoppingList.getCategories().keyAt(section)); } @Override @@ -134,10 +147,9 @@ public void onBindViewHolder(SectionedViewHolder sectionedViewHolder, int section, int relativePosition, final int absolutePosition) { - final ItemViewHolder itemViewHolder = (ItemViewHolder) sectionedViewHolder; - String category = shoppingList.getCategories().get(section); - final ListItem listItem = shoppingList.getListItemByCategory(category).get(relativePosition); + ArrayList list = shoppingList.getCategories().valueAt(section); + final ListItem listItem = list.get(relativePosition); itemViewHolder.description.setText(listItem.getDescription()); itemViewHolder.quantity.setText(listItem.getQuantity()); @@ -208,6 +220,10 @@ public ItemViewHolder(View itemView) { quantity = itemView.findViewById(R.id.text_quantity); dragHandler = itemView.findViewById(R.id.drag_n_drop_handler); } + + public int getPositionInCategory() { + return getRelativePosition().relativePos(); + } } public class RecyclerListCallback extends ItemTouchHelper.Callback { @@ -232,44 +248,59 @@ public boolean isLongPressDragEnabled() { } @Override - public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { + public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; final int swipeFlags = ItemTouchHelper.START; return makeMovementFlags(dragFlags, swipeFlags); } @Override - public boolean onMove(@NonNull RecyclerView recyclerView, - RecyclerView.ViewHolder viewHolder, - RecyclerView.ViewHolder target) { + public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { if (viewHolder.getItemViewType() != target.getItemViewType()) { return false; } - if (!(viewHolder instanceof ItemViewHolder) || !(target instanceof ItemViewHolder)) { - return false; - } +// if (!(viewHolder instanceof ItemViewHolder) || !(target instanceof ItemViewHolder)) { +// return false; +// } ItemViewHolder sourceViewHolder = (ItemViewHolder) viewHolder; ItemViewHolder targetViewHolder = (ItemViewHolder) target; - RecyclerListAdapter.this.move(sourceViewHolder.listItem, targetViewHolder.listItem); + RecyclerListAdapter.this.move(sourceViewHolder.listItem.getCategory(), + sourceViewHolder.getPositionInCategory(), + targetViewHolder.getPositionInCategory(), + sourceViewHolder.getAdapterPosition(), + targetViewHolder.getAdapterPosition()); + + +// RecyclerListAdapter.this.move(shoppingList.indexOf(sourceViewHolder.listItem), +// shoppingList.indexOf(targetViewHolder.listItem)); + + // RecyclerListAdapter.this.move(sourceViewHolder.getAdapterPosition(), targetViewHolder.getAdapterPosition()); + + return true; } +// @Override +// public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { +// super.clearView(recyclerView, viewHolder); +// +// if(dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) { +// reallyMoved(dragFrom, dragTo); +// } +// +// dragFrom = dragTo = -1; +// } + @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { RecyclerListAdapter.this.remove(viewHolder.getAdapterPosition()); } @Override - public void onChildDraw(@NonNull Canvas c, - @NonNull RecyclerView recyclerView, - @NonNull RecyclerView.ViewHolder viewHolder, - float dX, - float dY, - int actionState, - boolean isCurrentlyActive) { + public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (actionState != ItemTouchHelper.ACTION_STATE_SWIPE) { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java index 6ddad0f..4bd141f 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java @@ -21,6 +21,8 @@ import android.os.Build; import android.support.annotation.NonNull; +import android.util.ArrayMap; +import android.util.Log; import java.util.ArrayList; import java.util.Arrays; @@ -40,7 +42,7 @@ public class ShoppingList extends ArrayList { private String name; private static int currentID; private final List listeners = new LinkedList<>(); - private List categories = new ArrayList<>(); + private ArrayMap> categories = new ArrayMap<>(); public static final String DEFAULT_CATEGORY = "Allgemein"; public ShoppingList(String name) { @@ -55,7 +57,7 @@ public ShoppingList(String name, Collection collection) { public void addDefaultCategory() { if (categories.isEmpty()) { - categories.add(DEFAULT_CATEGORY); // todo translate + categories.put(DEFAULT_CATEGORY, new ArrayList()); // todo translate } } @@ -176,6 +178,16 @@ public void clear() { notifyListChanged(Event.newOther()); } + @Override + public int size() { + int size = 0; + + for (ArrayList categoryList : getCategories().values()) { + size += categoryList.size(); + } + return size; + } + @NonNull @Override public Iterator iterator() { @@ -215,11 +227,28 @@ public void toggleChecked(ListItem item, int absolutePosition) { public void move(ListItem from, ListItem to) { int oldIndex = indexOf(from); int newIndex = indexOf(to); - + + Log.d("MOVE", "From " + oldIndex + " to " + newIndex); + + super.add(newIndex, super.remove(oldIndex)); + notifyListChanged(Event.newItemMoved(oldIndex, newIndex)); + } + + public void move(int oldIndex, int newIndex) { super.add(newIndex, super.remove(oldIndex)); notifyListChanged(Event.newItemMoved(oldIndex, newIndex)); } + public void moveInCategory(String category, + int oldIndex, + int newIndex, + int fromAbsolutePosition, + int toAbsolutePosition) { + List list = getCategories().get(category); + list.add(newIndex, list.remove(oldIndex)); + notifyListChanged(Event.newItemMoved(fromAbsolutePosition, toAbsolutePosition)); + } + public void editItem(int index, String newDescription, String newQuantity, String newCategory) { ListItem listItem = get(index); listItem.setDescription(newDescription); @@ -261,26 +290,10 @@ private synchronized int generateID() { return ++currentID; } - public void parseCategories(String line) { - categories.addAll(Arrays.asList(line.split(":")[1].split(","))); - } - - public List getCategories() { + public ArrayMap> getCategories() { return categories; } - public List getListItemByCategory(String desiredCategory) { - List list = new ArrayList<>(); - - for (int i = 0; i < size(); i++) { - if (desiredCategory.equals(get(i).getCategory())) { - list.add(get(i)); - } - } - - return list; - } - private void notifyListChanged(ShoppingList.Event event) { for (ShoppingListListener listener : listeners) { listener.onShoppingListUpdate(this, event); diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListMarshaller.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListMarshaller.java index 74a49a8..687a914 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListMarshaller.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListMarshaller.java @@ -38,17 +38,18 @@ public static void marshall(@NonNull OutputStream stream, @NonNull ShoppingList writer.write("Categories:"); int categorySize = list.getCategories().size(); for (int i = 0; i < categorySize; i++) { - writer.write(list.getCategories().get(i)); + writer.write(list.getCategories().keyAt(i)); if (i < categorySize - 1) { writer.write(","); } } - writer.write("\n"); + writer.write("\n\n"); - for (String category : list.getCategories()) { - for (ListItem item : list.getListItemByCategory(category)) { + for (String category : list.getCategories().keySet()) { + for (ListItem item : list.getCategories().get(category)) { writeItem(item, writer); } + writer.write("\n"); } } } diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListUnmarshaller.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListUnmarshaller.java index a770aec..7032e38 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListUnmarshaller.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListUnmarshaller.java @@ -24,6 +24,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -59,10 +60,9 @@ public static ShoppingList unmarshal(InputStream inputStream) throws IOException String line; while ((line = reader.readLine()) != null) { - if (CATEGORY.matcher(line).matches()) { - shoppingList.parseCategories(line); - } else if (!EMPTY_LINE.matcher(line).matches()) { - shoppingList.add(createListItem(line, shoppingList)); + if (!EMPTY_LINE.matcher(line).matches() && !CATEGORY.matcher(line).matches()) { + ListItem item = createListItem(line, shoppingList); + shoppingList.getCategories().get(item.getCategory()).add(item); } } @@ -110,8 +110,8 @@ private static ListItem createListItem(String item, ShoppingList shoppingList) { category = DEFAULT_CATEGORY; } - if (!shoppingList.getCategories().contains(category)) { - shoppingList.getCategories().add(category); + if (!shoppingList.getCategories().containsKey(category)) { + shoppingList.getCategories().put(category, new ArrayList()); } return new ListItem(isChecked, name.trim(), quantity, category); From 9476352c0a90f556ac316580b4dba300c551d83d Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Sat, 23 May 2020 09:23:02 +0200 Subject: [PATCH 3/4] wip Signed-off-by: tobiasKaminsky --- .../woefe/shoppinglist/activity/EditBar.java | 38 ++- .../activity/RecyclerListAdapter.java | 13 +- .../activity/ShoppingListFragment.java | 13 +- .../shoppinglist/shoppinglist/ListItem.java | 45 ++- .../shoppinglist/ShoppingList.java | 258 +++--------------- .../shoppinglist/ShoppingListsManager.java | 4 +- 6 files changed, 111 insertions(+), 260 deletions(-) diff --git a/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java b/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java index 1843bdb..c616d21 100644 --- a/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java +++ b/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java @@ -40,17 +40,16 @@ import android.widget.Toast; import com.woefe.shoppinglist.R; +import com.woefe.shoppinglist.shoppinglist.ListItem; import com.woefe.shoppinglist.shoppinglist.ShoppingList; -import java.util.HashSet; -import java.util.Set; - public class EditBar implements ShoppingList.ShoppingListListener { private static final String KEY_SAVED_DESCRIPTION = "SAVED_DESCRIPTION"; private static final String KEY_SAVED_QUANTITY = "SAVED_QUANTITY"; private static final String KEY_SAVED_CATEGORY = "SAVED_CATEGORY"; private static final String KEY_SAVED_MODE = "SAVED_MODE"; private static final String KEY_SAVE_IS_VISIBLE = "SAVE_IS_VISIBLE"; + private static final String KEY_SAVE_ITEM = "ITEM"; private final Context ctx; private final RelativeLayout layout; private final EditText descriptionText; @@ -60,10 +59,9 @@ public class EditBar implements ShoppingList.ShoppingListListener { private Mode mode; private EditBarListener listener; private final FloatingActionButton fab; - private int position; - private final Set descriptionIndex = new HashSet<>(); private ShoppingList shoppingList; private ArrayAdapter categoryAdapter; + private ListItem item; public EditBar(View boundView, final Context ctx) { this.ctx = ctx; @@ -133,7 +131,7 @@ private void checkDuplicate(String str) { if (mode != Mode.ADD || !isVisible()) { return; } - if (descriptionIndex.contains(str.toLowerCase())) { + if (shoppingList.contains(str.toLowerCase())) { duplicateWarnText.setText(ctx.getString(R.string.duplicate_warning, str)); duplicateWarnText.setVisibility(View.VISIBLE); } else { @@ -161,7 +159,7 @@ private void onConfirm() { listener.onNewItem(desc, qty, category); descriptionText.requestFocus(); } else if (mode == Mode.EDIT) { - listener.onEditSave(position, desc, qty, category); + listener.onEditSave(item, desc, qty, category); } descriptionText.setText(""); @@ -169,23 +167,22 @@ private void onConfirm() { //categorySpinner.setText(""); } - public void showEdit(String description, String quantity, String category) { - // this.position = position; - prepare(Mode.EDIT, description, quantity, category); + public void showEdit(ListItem item) { + prepare(Mode.EDIT, item, item.getDescription(), item.getQuantity(), item.getCategory()); show(); } public void showAdd() { - prepare(Mode.ADD, "", "", ""); + prepare(Mode.ADD, new ListItem(), "", "", ""); show(); } - private void prepare(Mode mode, String description, String quantity, String category) { + private void prepare(Mode mode, ListItem item, String description, String quantity, String category) { this.mode = mode; - quantityText.setText(quantity); - descriptionText.setText(""); - descriptionText.append(description); - int position = shoppingList.getCategories().indexOfKey(category); + this.item = item; + quantityText.setText(item.getQuantity()); + descriptionText.append(item.getDescription()); + int position = shoppingList.getCategories().indexOfKey(item.getCategory()); categorySpinner.setSelection(position); } @@ -285,6 +282,7 @@ public void saveState(Bundle state) { state.putInt(KEY_SAVED_CATEGORY, categorySpinner.getSelectedItemPosition()); state.putBoolean(KEY_SAVE_IS_VISIBLE, isVisible()); state.putSerializable(KEY_SAVED_MODE, mode); + state.putParcelable(KEY_SAVE_ITEM, item); } public void restoreState(Bundle state) { @@ -292,8 +290,10 @@ public void restoreState(Bundle state) { String quantity = state.getString(KEY_SAVED_QUANTITY); categorySpinner.setSelection(state.getInt(KEY_SAVED_CATEGORY)); Mode mode = (Mode) state.getSerializable(KEY_SAVED_MODE); + ListItem item = state.getParcelable(KEY_SAVE_ITEM); + if (state.getBoolean(KEY_SAVE_IS_VISIBLE)) { - prepare(mode, description, quantity, categorySpinner.getSelectedItem().toString()); + prepare(mode, item, description, quantity, categorySpinner.getSelectedItem().toString()); layout.setVisibility(View.VISIBLE); fab.hide(); } @@ -318,15 +318,13 @@ public void onShoppingListUpdate(ShoppingList list, ShoppingList.Event e) { hide(); return; } - descriptionIndex.clear(); - descriptionIndex.addAll(list.createDescriptionIndex()); categoryAdapter.clear(); categoryAdapter.addAll(shoppingList.getCategories().keySet()); checkDuplicate(descriptionText.getText().toString()); } public interface EditBarListener { - void onEditSave(int position, String description, String quantity, String category); + void onEditSave(ListItem item, String description, String quantity, String category); void onNewItem(String description, String quantity, String category); } diff --git a/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java b/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java index def0c1a..5998edc 100644 --- a/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java +++ b/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java @@ -40,10 +40,12 @@ public class RecyclerListAdapter extends SectionedRecyclerViewAdapter CREATOR = new Creator() { + @Override + public ListItem createFromParcel(Parcel in) { + return new ListItem(in); } - } + @Override + public ListItem[] newArray(int size) { + return new ListItem[size]; + } + }; } diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java index 4bd141f..2605faa 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java @@ -19,39 +19,22 @@ package com.woefe.shoppinglist.shoppinglist; -import android.os.Build; -import android.support.annotation.NonNull; import android.util.ArrayMap; -import android.util.Log; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.Comparator; -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import java.util.ListIterator; -import java.util.Set; -import java.util.function.Predicate; -import java.util.function.UnaryOperator; -public class ShoppingList extends ArrayList { +public class ShoppingList { private String name; - private static int currentID; private final List listeners = new LinkedList<>(); private ArrayMap> categories = new ArrayMap<>(); - public static final String DEFAULT_CATEGORY = "Allgemein"; + public static final String DEFAULT_CATEGORY = "Allgemein"; // todo translate public ShoppingList(String name) { - super(); - this.name = name; - } - - public ShoppingList(String name, Collection collection) { - super(collection); this.name = name; } @@ -70,115 +53,29 @@ public void setName(String name) { notifyListChanged(Event.newOther()); } - public int getId(int index) { - return ((ListItem.ListItemWithID) get(index)).getId(); - } - - @Override - public boolean add(ListItem item) { - boolean res = super.add(new ListItem.ListItemWithID(generateID(), item)); - notifyListChanged(Event.newItemInserted(size() - 1)); - return res; - } - public boolean add(String description, String quantity, String category) { - return add(new ListItem(false, description, quantity, category)); - } - - @Override - public void add(int index, ListItem element) { - super.add(index, element); - notifyListChanged(Event.newItemInserted(index)); - } - - @Override - public boolean addAll(@NonNull Collection c) { - boolean b = super.addAll(c); - notifyListChanged(Event.newOther()); - return b; - } - - @Override - public boolean addAll(int index, @NonNull Collection c) { - boolean b = super.addAll(index, c); - notifyListChanged(Event.newOther()); - return b; - } - - @Override - public ListItem set(int index, ListItem element) { - ListItem old = super.set(index, element); - notifyListChanged(Event.newItemChanged(index)); - return old; - } - - @Override - public ListItem remove(int index) { - ListItem res = super.remove(index); - notifyListChanged(Event.newItemRemoved(index)); - return res; - } - - @Override - public boolean remove(Object o) { - boolean b = super.remove(o); - if (b) { - notifyListChanged(Event.newOther()); - } - return b; - } + ListItem item = new ListItem(false, description, quantity, category); + boolean res = getListForItem(item).add(item); - @Override - protected void removeRange(int fromIndex, int toIndex) { - super.removeRange(fromIndex, toIndex); - notifyListChanged(Event.newOther()); - } - - @Override - public boolean removeAll(@NonNull Collection c) { - boolean b = super.removeAll(c); - if (b) { - notifyListChanged(Event.newOther()); - } - return b; - } - - @Override - public boolean removeIf(@NonNull Predicate filter) { - boolean b = false; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { - b = super.removeIf(filter); - } - if (b) { - notifyListChanged(Event.newOther()); - } - return b; - } - - @Override - public void replaceAll(@NonNull UnaryOperator operator) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - super.replaceAll(operator); - notifyListChanged(Event.newOther()); + if (res) { + notifyListChanged(Event.newItemInserted(0)); } + + return res; } - @Override - public boolean retainAll(@NonNull Collection c) { - boolean b = super.retainAll(c); + public void remove(ListItem item) { + boolean b = getListForItem(item).remove(item); if (b) { notifyListChanged(Event.newOther()); } - return b; } - @Override - public void clear() { - super.clear(); + void clear() { + categories.clear(); notifyListChanged(Event.newOther()); } - @Override public int size() { int size = 0; @@ -188,35 +85,16 @@ public int size() { return size; } - @NonNull - @Override - public Iterator iterator() { - return new Itr(super.iterator()); - } - - @NonNull - @Override - public ListIterator listIterator(int index) { - return new ListItr(super.listIterator(index)); - } - - @NonNull - @Override - public ListIterator listIterator() { - return new ListItr(super.listIterator()); - } - - @Override public void sort(Comparator c) { - ListItem[] items = toArray(new ListItem[size()]); - Arrays.sort(items, c); - super.clear(); - super.addAll(Arrays.asList(items)); + for (ArrayList list : categories.values()) { + list.sort(c); + } notifyListChanged(Event.newOther()); } - public void setChecked(ListItem item, boolean isChecked, int absolutePosition) { - get(indexOf(item)).setChecked(isChecked); + private void setChecked(ListItem item, boolean isChecked, int absolutePosition) { + List list = getListForItem(item); + list.get(list.indexOf(item)).setChecked(isChecked); notifyListChanged(Event.newItemChanged(absolutePosition)); } @@ -224,21 +102,6 @@ public void toggleChecked(ListItem item, int absolutePosition) { setChecked(item, !item.isChecked(), absolutePosition); } - public void move(ListItem from, ListItem to) { - int oldIndex = indexOf(from); - int newIndex = indexOf(to); - - Log.d("MOVE", "From " + oldIndex + " to " + newIndex); - - super.add(newIndex, super.remove(oldIndex)); - notifyListChanged(Event.newItemMoved(oldIndex, newIndex)); - } - - public void move(int oldIndex, int newIndex) { - super.add(newIndex, super.remove(oldIndex)); - notifyListChanged(Event.newItemMoved(oldIndex, newIndex)); - } - public void moveInCategory(String category, int oldIndex, int newIndex, @@ -249,35 +112,25 @@ public void moveInCategory(String category, notifyListChanged(Event.newItemMoved(fromAbsolutePosition, toAbsolutePosition)); } - public void editItem(int index, String newDescription, String newQuantity, String newCategory) { - ListItem listItem = get(index); - listItem.setDescription(newDescription); - listItem.setQuantity(newQuantity); - listItem.setCategory(newCategory); - notifyListChanged(Event.newItemChanged(index)); + public void editItem(ListItem item, String newDescription, String newQuantity, String newCategory) { + item.setDescription(newDescription); + item.setQuantity(newQuantity); + item.setCategory(newCategory); + notifyListChanged(Event.newItemChanged(-1)); } public void removeAllCheckedItems() { - Iterator it = iterator(); - - while (it.hasNext()) { - ListItem item = it.next(); - if (item.isChecked()) { - it.remove(); + for (ArrayList list : categories.values()) { + for (ListItem item : list) { + if (item.isChecked()) { + list.remove(item); + } } } notifyListChanged(Event.newOther()); } - public Set createDescriptionIndex() { - Set descriptionIndex = new HashSet<>(); - for (ListItem listItem : this) { - descriptionIndex.add(listItem.getDescription().toLowerCase()); - } - return descriptionIndex; - } - public void addListener(ShoppingListListener listener) { listeners.add(listener); } @@ -286,10 +139,6 @@ public void removeListener(ShoppingListListener listener) { listeners.remove(listener); } - private synchronized int generateID() { - return ++currentID; - } - public ArrayMap> getCategories() { return categories; } @@ -395,47 +244,22 @@ public void remove() { } } - private class ListItr extends Itr implements ListIterator { - - private ListIterator iterator; - - private ListItr(ListIterator iterator) { - super(iterator); - this.iterator = iterator; - } - - @Override - public boolean hasPrevious() { - return iterator.hasPrevious(); - } - - @Override - public ListItem previous() { - return iterator.previous(); - } - - @Override - public int nextIndex() { - return iterator.nextIndex(); + private List getListForItem(ListItem item) { + if (!categories.containsKey(item.getCategory())) { + categories.put(item.getCategory(), new ArrayList()); } - @Override - public int previousIndex() { - return iterator.previousIndex(); - } - - @Override - public void set(ListItem listItem) { - iterator.set(listItem); - //TODO get index and use Event.newItemChanged - notifyListChanged(Event.newOther()); - } + return categories.get(item.getCategory()); + } - @Override - public void add(ListItem listItem) { - iterator.add(listItem); - //TODO get index and use Event.newItemInserted - notifyListChanged(Event.newOther()); + public boolean contains(String item) { + for (ArrayList list : categories.values()) { + for (ListItem listItem : list) { + if (item.equalsIgnoreCase(listItem.getDescription())) { + return true; + } + } } + return false; } } diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListsManager.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListsManager.java index e74c7f8..e8dd2b5 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListsManager.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListsManager.java @@ -167,7 +167,7 @@ public void onEvent(int event, String path) { try { ShoppingList list = ShoppingListUnmarshaller.unmarshal(metadata.filename); metadata.shoppingList.clear(); - metadata.shoppingList.addAll(list); + metadata.shoppingList = list; metadata.isDirty = false; String oldName = metadata.shoppingList.getName(); @@ -250,7 +250,7 @@ void rename(String oldName, String newName) { } private class ShoppingListMetadata { - private final ShoppingList shoppingList; + private ShoppingList shoppingList; private final String filename; private boolean isDirty; private FileObserver observer; From 8ca91016d6388af775a8c750498fa83a11c6719e Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Sat, 23 May 2020 15:31:49 +0200 Subject: [PATCH 4/4] correct category order Signed-off-by: tobiasKaminsky --- .../woefe/shoppinglist/activity/EditBar.java | 6 +++--- .../activity/RecyclerListAdapter.java | 11 +++++++---- .../shoppinglist/shoppinglist/ShoppingList.java | 5 +++++ .../shoppinglist/ShoppingListMarshaller.java | 17 +++++++++++------ .../shoppinglist/ShoppingListUnmarshaller.java | 6 +++++- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java b/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java index c616d21..eb3d36d 100644 --- a/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java +++ b/app/src/main/java/com/woefe/shoppinglist/activity/EditBar.java @@ -180,8 +180,8 @@ public void showAdd() { private void prepare(Mode mode, ListItem item, String description, String quantity, String category) { this.mode = mode; this.item = item; - quantityText.setText(item.getQuantity()); - descriptionText.append(item.getDescription()); + quantityText.setText(quantity); + descriptionText.append(description); int position = shoppingList.getCategories().indexOfKey(item.getCategory()); categorySpinner.setSelection(position); } @@ -319,7 +319,7 @@ public void onShoppingListUpdate(ShoppingList list, ShoppingList.Event e) { return; } categoryAdapter.clear(); - categoryAdapter.addAll(shoppingList.getCategories().keySet()); + categoryAdapter.addAll(shoppingList.getAllCategories()); checkDuplicate(descriptionText.getText().toString()); } diff --git a/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java b/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java index 5998edc..33b364a 100644 --- a/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java +++ b/app/src/main/java/com/woefe/shoppinglist/activity/RecyclerListAdapter.java @@ -125,18 +125,20 @@ public SectionedViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int vie @Override public int getSectionCount() { - return shoppingList.getCategories().size(); + return shoppingList.getAllCategories().size(); } @Override public int getItemCount(int section) { - return shoppingList.getCategories().valueAt(section).size(); + String category = shoppingList.getAllCategories().get(section); + ArrayList list = shoppingList.getCategories().get(category); + return (list == null) ? 0 : list.size(); } @Override public void onBindHeaderViewHolder(SectionedViewHolder sectionedViewHolder, int section, boolean expanded) { CategoryViewHolder categoryViewHolder = (CategoryViewHolder) sectionedViewHolder; - categoryViewHolder.category.setText(shoppingList.getCategories().keyAt(section)); + categoryViewHolder.category.setText(shoppingList.getAllCategories().get(section)); } @Override @@ -150,7 +152,8 @@ public void onBindViewHolder(SectionedViewHolder sectionedViewHolder, int relativePosition, final int absolutePosition) { final ItemViewHolder itemViewHolder = (ItemViewHolder) sectionedViewHolder; - ArrayList list = shoppingList.getCategories().valueAt(section); + String category = shoppingList.getAllCategories().get(section); + ArrayList list = shoppingList.getCategories().get(category); final ListItem listItem = list.get(relativePosition); itemViewHolder.description.setText(listItem.getDescription()); diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java index 2605faa..1f301cd 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingList.java @@ -30,6 +30,7 @@ public class ShoppingList { private String name; + private List allCategories = new ArrayList<>(); private final List listeners = new LinkedList<>(); private ArrayMap> categories = new ArrayMap<>(); public static final String DEFAULT_CATEGORY = "Allgemein"; // todo translate @@ -143,6 +144,10 @@ public ArrayMap> getCategories() { return categories; } + public List getAllCategories() { + return allCategories; + } + private void notifyListChanged(ShoppingList.Event event) { for (ShoppingListListener listener : listeners) { listener.onShoppingListUpdate(this, event); diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListMarshaller.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListMarshaller.java index 687a914..0d5bf80 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListMarshaller.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListMarshaller.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.util.List; public class ShoppingListMarshaller { public static void marshall(@NonNull OutputStream stream, @NonNull ShoppingList list) throws IOException { @@ -36,20 +37,24 @@ public static void marshall(@NonNull OutputStream stream, @NonNull ShoppingList writer.write(" ]\n\n"); writer.write("Categories:"); - int categorySize = list.getCategories().size(); + int categorySize = list.getAllCategories().size(); for (int i = 0; i < categorySize; i++) { - writer.write(list.getCategories().keyAt(i)); + writer.write(list.getAllCategories().get(i)); if (i < categorySize - 1) { writer.write(","); } } writer.write("\n\n"); - for (String category : list.getCategories().keySet()) { - for (ListItem item : list.getCategories().get(category)) { - writeItem(item, writer); + for (String category : list.getAllCategories()) { + List itemList = list.getCategories().get(category); + + if (itemList != null) { + for (ListItem item : itemList) { + writeItem(item, writer); + } + writer.write("\n"); } - writer.write("\n"); } } } diff --git a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListUnmarshaller.java b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListUnmarshaller.java index 7032e38..19ede34 100644 --- a/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListUnmarshaller.java +++ b/app/src/main/java/com/woefe/shoppinglist/shoppinglist/ShoppingListUnmarshaller.java @@ -60,7 +60,11 @@ public static ShoppingList unmarshal(InputStream inputStream) throws IOException String line; while ((line = reader.readLine()) != null) { - if (!EMPTY_LINE.matcher(line).matches() && !CATEGORY.matcher(line).matches()) { + if (CATEGORY.matcher(line).matches()) { + for (String category : line.split(":")[1].split(",")) { + shoppingList.getAllCategories().add(category); + } + } else if (!EMPTY_LINE.matcher(line).matches()) { ListItem item = createListItem(line, shoppingList); shoppingList.getCategories().get(item.getCategory()).add(item); }