diff options
| author | Daniël van den Berg <danielvandenberg95@gmail.com> | 2016-09-09 11:47:49 +0200 |
|---|---|---|
| committer | Mohamed Zenadi <zeapo@users.noreply.github.com> | 2016-09-09 11:47:49 +0200 |
| commit | a6da17417eed1412dfbd9c06d03d85f100d35608 (patch) | |
| tree | dfa093c2c2b0df651be55420bf6b0a903b605ece /app/src/main/java/com/zeapo/pwdstore/utils | |
| parent | 86083f03f5a60074cddb7496bff157b31ce8c2a3 (diff) | |
| download | HardenedPass-a6da17417eed1412dfbd9c06d03d85f100d35608.tar.gz HardenedPass-a6da17417eed1412dfbd9c06d03d85f100d35608.zip | |
Added the ability to move passwords around. (#210)
* Added the ability to move passwords around.
* Generified the PasswordRecyclerAdapter and the FolderRecyclerAdapter into EntryRecyclerAdapter
Diffstat (limited to 'app/src/main/java/com/zeapo/pwdstore/utils')
3 files changed, 228 insertions, 149 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/EntryRecyclerAdapter.java b/app/src/main/java/com/zeapo/pwdstore/utils/EntryRecyclerAdapter.java new file mode 100644 index 00000000..78b81928 --- /dev/null +++ b/app/src/main/java/com/zeapo/pwdstore/utils/EntryRecyclerAdapter.java @@ -0,0 +1,162 @@ +package com.zeapo.pwdstore.utils; + +import android.app.Activity; +import android.graphics.Color; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.zeapo.pwdstore.R; + +import java.util.ArrayList; +import java.util.Set; +import java.util.TreeSet; + +public abstract class EntryRecyclerAdapter extends RecyclerView.Adapter<EntryRecyclerAdapter.ViewHolder> { + private final Activity activity; + protected final ArrayList<PasswordItem> values; + protected final Set<Integer> selectedItems = new TreeSet<>(); + + public EntryRecyclerAdapter(Activity activity, ArrayList<PasswordItem> values) { + this.activity = activity; + this.values = values; + } + + // Return the size of your dataset (invoked by the layout manager) + @Override + public int getItemCount() { + return values.size(); + } + + public ArrayList<PasswordItem> getValues() { + return this.values; + } + + public void clear() { + this.values.clear(); + this.notifyDataSetChanged(); + } + + public void addAll(ArrayList<PasswordItem> list) { + this.values.addAll(list); + this.notifyDataSetChanged(); + } + + public void add(PasswordItem item) { + this.values.add(item); + this.notifyItemInserted(getItemCount()); + } + + public void toggleSelection(int position) { + if (!selectedItems.remove(position)) { + selectedItems.add(position); + } + } + + // use this after an item is removed to update the positions of items in set + // that followed the removed position + public void updateSelectedItems(int position, Set<Integer> selectedItems) { + Set<Integer> temp = new TreeSet<>(); + for (int selected : selectedItems) { + if (selected > position) { + temp.add(selected - 1); + } else { + temp.add(selected); + } + } + selectedItems.clear(); + selectedItems.addAll(temp); + } + + public void remove(int position) { + this.values.remove(position); + this.notifyItemRemoved(position); + + // keep selectedItems updated so we know what to notifyItemChanged + // (instead of just using notifyDataSetChanged) + updateSelectedItems(position, selectedItems); + } + + @NonNull + protected View.OnLongClickListener getOnLongClickListener(ViewHolder holder, PasswordItem pass) { + return new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + return false; + } + }; + } + + // Replace the contents of a view (invoked by the layout manager) + @Override + public void onBindViewHolder(final ViewHolder holder, int position) { + final PasswordItem pass = getValues().get(position); + holder.name.setText(pass.toString()); + if (pass.getType() == PasswordItem.TYPE_CATEGORY) { + holder.typeImage.setImageResource(R.drawable.ic_folder_grey600_24dp); + holder.name.setText(pass.toString() + "/"); + } else { + holder.typeImage.setImageResource(R.drawable.ic_action_secure); + holder.name.setText(pass.toString()); + } + + holder.type.setText(pass.getFullPathName()); + if (pass.getType() == PasswordItem.TYPE_CATEGORY) { +// holder.card.setCardBackgroundColor(activity.getResources().getColor(R.color.blue_grey_200)); + } else { +// holder.card.setCardBackgroundColor(activity.getResources().getColor(R.color.blue_grey_50)); + } + + holder.view.setOnClickListener(getOnClickListener(holder, pass)); + + holder.view.setOnLongClickListener(getOnLongClickListener(holder, pass)); + + // after removal, everything is rebound for some reason; views are shuffled? + boolean selected = selectedItems.contains(position); + holder.view.setSelected(selected); + if (selected) { + holder.itemView.setBackgroundResource(R.color.deep_orange_200); + holder.type.setTextColor(Color.BLACK); + } else { + holder.itemView.setBackgroundResource(Color.alpha(1)); + holder.type.setTextColor(ContextCompat.getColor(activity, R.color.grey_500)); + } + } + + @NonNull + protected abstract View.OnClickListener getOnClickListener(ViewHolder holder, PasswordItem pass); + + // Provide a reference to the views for each data item + // Complex data items may need more than one view per item, and + // you provide access to all the views for a data item in a view holder + public static class ViewHolder extends RecyclerView.ViewHolder { + // each data item is just a string in this case + public View view; + public TextView name; + public TextView type; + public ImageView typeImage; + + public ViewHolder(View v) { + super(v); + view = v; + name = (TextView) view.findViewById(R.id.label); + type = (TextView) view.findViewById(R.id.type); + typeImage = (ImageView) view.findViewById(R.id.type_image); + } + } + + // Create new views (invoked by the layout manager) + @Override + public PasswordRecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, + int viewType) { + // create a new view + View v = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.password_row_layout, parent, false); + return new ViewHolder(v); + } +} diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/FolderRecyclerAdapter.java b/app/src/main/java/com/zeapo/pwdstore/utils/FolderRecyclerAdapter.java new file mode 100644 index 00000000..04b243e1 --- /dev/null +++ b/app/src/main/java/com/zeapo/pwdstore/utils/FolderRecyclerAdapter.java @@ -0,0 +1,31 @@ +package com.zeapo.pwdstore.utils; + +import android.support.annotation.NonNull; +import android.view.View; + +import com.zeapo.pwdstore.SelectFolderFragment; +import com.zeapo.pwdstore.crypto.PgpHandler; + +import java.util.ArrayList; + +public class FolderRecyclerAdapter extends EntryRecyclerAdapter { + private final SelectFolderFragment.OnFragmentInteractionListener listener; + + // Provide a suitable constructor (depends on the kind of dataset) + public FolderRecyclerAdapter(PgpHandler activity, SelectFolderFragment.OnFragmentInteractionListener listener, ArrayList<PasswordItem> values) { + super(activity, values); + this.listener = listener; + } + + @NonNull + protected View.OnClickListener getOnClickListener(final ViewHolder holder, final PasswordItem pass) { + return new View.OnClickListener() { + @Override + public void onClick(View v) { + listener.onFragmentInteraction(pass); + notifyItemChanged(holder.getAdapterPosition()); + } + }; + } + +} diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRecyclerAdapter.java b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRecyclerAdapter.java index 0835425a..a4446198 100644 --- a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRecyclerAdapter.java +++ b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRecyclerAdapter.java @@ -1,17 +1,10 @@ package com.zeapo.pwdstore.utils; -import android.graphics.Color; -import android.os.Build; -import android.support.v4.content.ContextCompat; +import android.support.annotation.NonNull; import android.support.v7.view.ActionMode; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; import com.zeapo.pwdstore.PasswordFragment; import com.zeapo.pwdstore.PasswordStore; @@ -19,76 +12,46 @@ import com.zeapo.pwdstore.R; import java.util.ArrayList; import java.util.Iterator; -import java.util.Set; import java.util.TreeSet; -public class PasswordRecyclerAdapter extends RecyclerView.Adapter<PasswordRecyclerAdapter.ViewHolder> { +public class PasswordRecyclerAdapter extends EntryRecyclerAdapter { private final PasswordStore activity; - private final ArrayList<PasswordItem> values; private final PasswordFragment.OnFragmentInteractionListener listener; - private final Set<Integer> selectedItems; private ActionMode mActionMode; private Boolean canEdit; - // Provide a reference to the views for each data item - // Complex data items may need more than one view per item, and - // you provide access to all the views for a data item in a view holder - public static class ViewHolder extends RecyclerView.ViewHolder { - // each data item is just a string in this case - public View view; - public TextView name; - public TextView type; - public ImageView typeImage; - - public ViewHolder(View v) { - super(v); - view = v; - name = (TextView) view.findViewById(R.id.label); - type = (TextView) view.findViewById(R.id.type); - typeImage = (ImageView) view.findViewById(R.id.type_image); - } - } - // Provide a suitable constructor (depends on the kind of dataset) public PasswordRecyclerAdapter(PasswordStore activity, PasswordFragment.OnFragmentInteractionListener listener, ArrayList<PasswordItem> values) { - this.values = values; + super(activity, values); this.activity = activity; this.listener = listener; - selectedItems = new TreeSet<>(); } - // Create new views (invoked by the layout manager) @Override - public PasswordRecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, - int viewType) { - // create a new view - View v = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.password_row_layout, parent, false); - return new ViewHolder(v); + @NonNull + protected View.OnLongClickListener getOnLongClickListener(final ViewHolder holder, final PasswordItem pass) { + return new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + if (mActionMode != null) { + return false; + } + toggleSelection(holder.getAdapterPosition()); + canEdit = pass.getType() == PasswordItem.TYPE_PASSWORD; + // Start the CAB using the ActionMode.Callback + mActionMode = activity.startSupportActionMode(mActionModeCallback); + mActionMode.setTitle("" + selectedItems.size()); + mActionMode.invalidate(); + notifyItemChanged(holder.getAdapterPosition()); + return true; + } + }; } - // Replace the contents of a view (invoked by the layout manager) @Override - public void onBindViewHolder(final ViewHolder holder, int position) { - final PasswordItem pass = values.get(position); - holder.name.setText(pass.toString()); - if (pass.getType() == PasswordItem.TYPE_CATEGORY) { - holder.typeImage.setImageResource(R.drawable.ic_folder_grey600_24dp); - holder.name.setText(pass.toString() + "/"); - } else { - holder.typeImage.setImageResource(R.drawable.ic_action_secure); - holder.name.setText(pass.toString()); - } - int sdk = Build.VERSION.SDK_INT; - - holder.type.setText(pass.getFullPathName()); - if (pass.getType() == PasswordItem.TYPE_CATEGORY) { -// holder.card.setCardBackgroundColor(activity.getResources().getColor(R.color.blue_grey_200)); - } else { -// holder.card.setCardBackgroundColor(activity.getResources().getColor(R.color.blue_grey_50)); - } - - holder.view.setOnClickListener(new View.OnClickListener() { + @NonNull + protected View.OnClickListener getOnClickListener(final ViewHolder holder, final PasswordItem pass) { + return new View.OnClickListener() { @Override public void onClick(View v) { if (mActionMode != null) { @@ -97,7 +60,7 @@ public class PasswordRecyclerAdapter extends RecyclerView.Adapter<PasswordRecycl if (selectedItems.isEmpty()) { mActionMode.finish(); } else if (selectedItems.size() == 1 && !canEdit) { - if (values.get(selectedItems.iterator().next()).getType() == PasswordItem.TYPE_PASSWORD) { + if (getValues().get(selectedItems.iterator().next()).getType() == PasswordItem.TYPE_PASSWORD) { canEdit = true; mActionMode.invalidate(); } @@ -110,35 +73,7 @@ public class PasswordRecyclerAdapter extends RecyclerView.Adapter<PasswordRecycl } notifyItemChanged(holder.getAdapterPosition()); } - }); - - holder.view.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - if (mActionMode != null) { - return false; - } - toggleSelection(holder.getAdapterPosition()); - canEdit = pass.getType() == PasswordItem.TYPE_PASSWORD; - // Start the CAB using the ActionMode.Callback - mActionMode = activity.startSupportActionMode(mActionModeCallback); - mActionMode.setTitle("" + selectedItems.size()); - mActionMode.invalidate(); - notifyItemChanged(holder.getAdapterPosition()); - return true; - } - }); - - // after removal, everything is rebound for some reason; views are shuffled? - boolean selected = selectedItems.contains(position); - holder.view.setSelected(selected); - if (selected) { - holder.itemView.setBackgroundResource(R.color.deep_orange_200); - holder.type.setTextColor(Color.BLACK); - } else { - holder.itemView.setBackgroundResource(Color.alpha(1)); - holder.type.setTextColor(ContextCompat.getColor(activity, R.color.grey_500)); - } + }; } private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { @@ -172,9 +107,15 @@ public class PasswordRecyclerAdapter extends RecyclerView.Adapter<PasswordRecycl mode.finish(); // Action picked, so close the CAB return true; case R.id.menu_edit_password: - activity.editPassword(values.get(selectedItems.iterator().next())); + activity.editPassword(getValues().get(selectedItems.iterator().next())); mode.finish(); return true; + case R.id.menu_move_password: + ArrayList<PasswordItem> selectedPasswords = new ArrayList<>(); + for (Integer id : selectedItems) { + selectedPasswords.add(getValues().get(id)); + } + activity.movePasswords(selectedPasswords); default: return false; } @@ -183,67 +124,12 @@ public class PasswordRecyclerAdapter extends RecyclerView.Adapter<PasswordRecycl // Called when the user exits the action mode @Override public void onDestroyActionMode(ActionMode mode) { - for (Iterator it = selectedItems.iterator(); it.hasNext();) { + for (Iterator<Integer> it = selectedItems.iterator(); it.hasNext(); ) { // need the setSelected line in onBind - notifyItemChanged((Integer) it.next()); + notifyItemChanged(it.next()); it.remove(); } mActionMode = null; } }; - - // Return the size of your dataset (invoked by the layout manager) - @Override - public int getItemCount() { - return values.size(); - } - - public ArrayList<PasswordItem> getValues() { - return this.values; - } - - public void clear() { - this.values.clear(); - this.notifyDataSetChanged(); - } - - public void addAll(ArrayList<PasswordItem> list) { - this.values.addAll(list); - this.notifyDataSetChanged(); - } - - public void add(PasswordItem item) { - this.values.add(item); - this.notifyItemInserted(values.size()); - } - - public void remove(int position) { - this.values.remove(position); - this.notifyItemRemoved(position); - - // keep selectedItems updated so we know what to notifyItemChanged - // (instead of just using notifyDataSetChanged) - updateSelectedItems(position, selectedItems); - } - - public void toggleSelection(int position) { - if (!selectedItems.remove(position)) { - selectedItems.add(position); - } - } - - // use this after an item is removed to update the positions of items in set - // that followed the removed position - public void updateSelectedItems(int position, Set<Integer> selectedItems) { - Set<Integer> temp = new TreeSet<>(); - for (int selected : selectedItems) { - if (selected > position) { - temp.add(selected - 1); - } else { - temp.add(selected); - } - } - selectedItems.clear(); - selectedItems.addAll(temp); - } } |
