Use stable IDs for the adapter

Fixes #346
This commit is contained in:
Jakob Nixdorf 2021-03-07 20:15:31 +01:00
parent ba5bb7705b
commit 283fb5630d
No known key found for this signature in database
GPG key ID: BE99BF86574A7DBC
3 changed files with 319 additions and 239 deletions

View file

@ -79,6 +79,7 @@ public class Entry {
public static final int COLOR_RED = 1;
private static final int EXPIRY_TIME = 8;
private int color = COLOR_DEFAULT;
private long listId = 0;
public Entry(){}
@ -368,10 +369,6 @@ public class Entry {
return period;
}
public void setPeriod(int period) {
this.period = period;
}
public long getCounter() {
return counter;
}
@ -384,10 +381,6 @@ public class Entry {
return digits;
}
public void setDigits(int digits) {
this.digits = digits;
}
public List<String> getTags() { return tags; }
public void setTags(List<String> tags) { this.tags = tags; }
@ -400,10 +393,6 @@ public class Entry {
return this.algorithm;
}
public void setAlgorithm(TokenCalculator.HashAlgorithm algorithm) {
this.algorithm = algorithm;
}
public boolean hasNonDefaultPeriod() {
return this.period != TokenCalculator.TOTP_DEFAULT_PERIOD;
}
@ -444,6 +433,14 @@ public class Entry {
return currentOTP;
}
public long getListId() {
return listId;
}
public void setListId(long newId) {
listId = newId;
}
public boolean updateOTP() {
if (type == OTPType.TOTP || type == OTPType.STEAM) {
long time = System.currentTimeMillis() / 1000;
@ -503,9 +500,14 @@ public class Entry {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Entry entry = (Entry) o;
return type == entry.type &&
period == entry.period &&
counter == entry.counter &&
@ -541,9 +543,9 @@ public class Entry {
/**
* Returns the label with issuer prefix removed (if present)
* @param issuer
* @param label
* @return
* @param issuer - Name of the issuer to remove from the label
* @param label - Full label from which the issuer should be removed
* @return - label with the issuer removed
*/
private String getStrippedLabel(String issuer, String label) {
if (issuer == null || issuer.isEmpty() || !label.startsWith(issuer + ":")) {

View file

@ -0,0 +1,205 @@
package org.shadowice.flocke.andotp.Database;
import org.shadowice.flocke.andotp.Utilities.Constants;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
public class EntryList {
private final ArrayList<Entry> entries;
private final AtomicLong currentId = new AtomicLong();
public EntryList() {
entries = new ArrayList<>();
}
public boolean addEntry(Entry newEntry) {
return addEntry(newEntry, false);
}
public boolean addEntry(Entry newEntry, boolean update) {
if (! entries.contains(newEntry)) {
long newId = currentId.incrementAndGet();
newEntry.setListId(newId);
entries.add(newEntry);
return true;
} else {
if (update) {
int oldIdx = entries.indexOf(newEntry);
Entry oldEntry = entries.get(oldIdx);
newEntry.setListId(oldEntry.getListId());
entries.set(oldIdx, newEntry);
}
}
return false;
}
public void updateEntries(ArrayList<Entry> newEntries, boolean update) {
// Remove all items not in the new list
entries.retainAll(newEntries);
// Add new and update existing entries
for (Entry e : newEntries) {
addEntry(e, update);
}
}
public Entry getEntry(int pos) {
return entries.get(pos);
}
public void swapEntries(int fromPosition, int toPosition) {
Collections.swap(entries, fromPosition, toPosition);
}
public void removeEntry(int pos) {
entries.remove(pos);
}
public int indexOf(Entry e) {
return entries.indexOf(e);
}
public boolean isEqual(ArrayList<Entry> otherEntries) {
return entries.equals(otherEntries);
}
public ArrayList<Entry> getEntries() {
return new ArrayList<>(entries);
}
public ArrayList<Entry> getEntriesSorted(Constants.SortMode sortMode) {
return sortEntries(entries, sortMode);
}
public static ArrayList<Entry> sortEntries(ArrayList<Entry> unsortedEntries, Constants.SortMode sortMode) {
ArrayList<Entry> sorted = new ArrayList<>(unsortedEntries);
if (sortMode == Constants.SortMode.ISSUER) {
Collections.sort(sorted, new IssuerComparator());
} else if (sortMode == Constants.SortMode.LABEL) {
Collections.sort(sorted, new LabelComparator());
} else if (sortMode == Constants.SortMode.LAST_USED) {
Collections.sort(sorted, new LastUsedComparator());
} else if (sortMode == Constants.SortMode.MOST_USED) {
Collections.sort(sorted, new MostUsedComparator());
}
return sorted;
}
public ArrayList<String> getAllTags() {
HashSet<String> tags = new HashSet<>();
for(Entry entry : entries) {
tags.addAll(entry.getTags());
}
return new ArrayList<>(tags);
}
public ArrayList<Entry> getFilteredEntries(CharSequence constraint, List<Constants.SearchIncludes> filterValues, Constants.SortMode sortMode) {
ArrayList<Entry> filtered = new ArrayList<>();
if (constraint != null && constraint.length() != 0){
for (int i = 0; i < entries.size(); i++) {
if (filterValues.contains(Constants.SearchIncludes.LABEL) && entries.get(i).getLabel().toLowerCase().contains(constraint.toString().toLowerCase())) {
filtered.add(entries.get(i));
} else if (filterValues.contains(Constants.SearchIncludes.ISSUER) && entries.get(i).getIssuer().toLowerCase().contains(constraint.toString().toLowerCase())) {
filtered.add(entries.get(i));
} else if (filterValues.contains(Constants.SearchIncludes.TAGS)) {
List<String> tags = entries.get(i).getTags();
for (int j = 0; j < tags.size(); j++) {
if (tags.get(j).toLowerCase().contains(constraint.toString().toLowerCase())) {
filtered.add(entries.get(i));
break;
}
}
}
}
} else {
filtered = entries;
}
return sortEntries(filtered, sortMode);
}
public ArrayList<Entry> getEntriesFilteredByTags(List<String> tags, boolean noTags, Constants.TagFunctionality tagFunctionality, Constants.SortMode sortMode) {
ArrayList<Entry> matchingEntries = new ArrayList<>();
for(Entry e : entries) {
// Entries with no tags will always be shown
boolean foundMatchingTag = e.getTags().isEmpty() && noTags;
if(tagFunctionality == Constants.TagFunctionality.AND) {
if(e.getTags().containsAll(tags)) {
foundMatchingTag = true;
}
} else {
for (String tag : tags) {
if (e.getTags().contains(tag)) {
foundMatchingTag = true;
break;
}
}
}
if(foundMatchingTag) {
matchingEntries.add(e);
}
}
return sortEntries(matchingEntries, sortMode);
}
public static class IssuerComparator implements Comparator<Entry> {
Collator collator;
IssuerComparator(){
collator = Collator.getInstance();
collator.setStrength(Collator.PRIMARY);
}
@Override
public int compare(Entry o1, Entry o2) {
return collator.compare(o1.getIssuer(), o2.getIssuer());
}
}
public static class LabelComparator implements Comparator<Entry> {
Collator collator;
LabelComparator(){
collator = Collator.getInstance();
collator.setStrength(Collator.PRIMARY);
}
@Override
public int compare(Entry o1, Entry o2) {
return collator.compare(o1.getLabel(), o2.getLabel());
}
}
public static class LastUsedComparator implements Comparator<Entry> {
@Override
public int compare(Entry o1, Entry o2) {
return Long.compare(o2.getLastUsed(), o1.getLastUsed());
}
}
public static class MostUsedComparator implements Comparator<Entry> {
@Override
public int compare(Entry o1, Entry o2) {
return Long.compare(o2.getUsedFrequency(), o1.getUsedFrequency());
}
}
}

View file

@ -22,6 +22,7 @@
package org.shadowice.flocke.andotp.View;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
@ -38,10 +39,8 @@ import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Filter;
@ -57,6 +56,7 @@ import com.journeyapps.barcodescanner.BarcodeEncoder;
import org.shadowice.flocke.andotp.Activities.MainActivity;
import org.shadowice.flocke.andotp.Database.Entry;
import org.shadowice.flocke.andotp.Database.EntryList;
import org.shadowice.flocke.andotp.Dialogs.ManualEntryDialog;
import org.shadowice.flocke.andotp.R;
import org.shadowice.flocke.andotp.Utilities.BackupHelper;
@ -68,12 +68,8 @@ import org.shadowice.flocke.andotp.Utilities.Settings;
import org.shadowice.flocke.andotp.Utilities.Tools;
import org.shadowice.flocke.andotp.View.ItemTouchHelper.ItemTouchHelperAdapter;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@ -83,10 +79,10 @@ import static org.shadowice.flocke.andotp.Utilities.Constants.SortMode;
public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
implements ItemTouchHelperAdapter, Filterable {
private Context context;
private Handler taskHandler;
private final Context context;
private final Handler taskHandler;
private EntryFilter filter;
private ArrayList<Entry> entries;
private final EntryList entries;
private ArrayList<Entry> displayedEntries;
private Callback callback;
private List<String> tagsFilter = new ArrayList<>();
@ -94,15 +90,17 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
private SecretKey encryptionKey = null;
private SortMode sortMode = SortMode.UNSORTED;
private TagsAdapter tagsFilterAdapter;
private Settings settings;
private final TagsAdapter tagsFilterAdapter;
private final Settings settings;
public EntriesCardAdapter(Context context, TagsAdapter tagsFilterAdapter) {
this.context = context;
this.tagsFilterAdapter = tagsFilterAdapter;
this.settings = new Settings(context);
this.taskHandler = new Handler();
this.entries = new ArrayList<>();
this.entries = new EntryList();
setHasStableIds(true);
}
public void setEncryptionKey(SecretKey key) {
@ -118,8 +116,13 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
return displayedEntries.size();
}
@Override
public long getItemId(int position) {
return displayedEntries.get(position).getListId();
}
public ArrayList<Entry> getEntries() {
return entries;
return entries.getEntries();
}
public void saveAndRefresh(boolean auto_backup) {
@ -129,8 +132,7 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
}
public void addEntry(Entry e) {
if (! entries.contains(e)) {
entries.add(e);
if (entries.addEntry(e)) {
saveAndRefresh(settings.getAutoBackupEncryptedPasswordsEnabled());
} else {
Toast.makeText(context, R.string.toast_entry_exists, Toast.LENGTH_LONG).show();
@ -142,7 +144,7 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
}
private void entriesChanged() {
displayedEntries = sortEntries(entries);
displayedEntries = entries.getEntriesSorted(sortMode);
filterByTags(tagsFilter);
notifyDataSetChanged();
}
@ -170,7 +172,7 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
}
public void saveEntries(boolean auto_backup) {
DatabaseHelper.saveDatabase(context, entries, encryptionKey);
DatabaseHelper.saveDatabase(context, entries.getEntries(), encryptionKey);
if(auto_backup) {
Constants.BackupType backupType = BackupHelper.autoBackupType(context);
@ -196,44 +198,24 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
public void loadEntries() {
if (encryptionKey != null) {
entries = DatabaseHelper.loadDatabase(context, encryptionKey);
ArrayList<Entry> newEntries = DatabaseHelper.loadDatabase(context, encryptionKey);
entries.updateEntries(newEntries, true);
entriesChanged();
}
}
public void filterByTags(List<String> tags) {
displayedEntries = entries.getEntriesFilteredByTags(tags, settings.getNoTagsToggle(), settings.getTagFunctionality(), sortMode);
tagsFilter = tags;
List<Entry> matchingEntries = new ArrayList<>();
for(Entry e : entries) {
//Entries with no tags will always be shown
Boolean foundMatchingTag = e.getTags().isEmpty() && settings.getNoTagsToggle();
if(settings.getTagFunctionality() == Constants.TagFunctionality.AND) {
if(e.getTags().containsAll(tags)) {
foundMatchingTag = true;
}
} else {
for (String tag : tags) {
if (e.getTags().contains(tag)) {
foundMatchingTag = true;
}
}
}
if(foundMatchingTag) {
matchingEntries.add(e);
}
}
displayedEntries = sortEntries(matchingEntries);
notifyDataSetChanged();
}
public void updateTimeBasedTokens() {
boolean change = false;
for (Entry e : entries) {
for (Entry e : entries.getEntries()) {
if (e.isTimeBased()) {
boolean cardVisible = !settings.getTapToReveal() || e.isVisible();
@ -348,7 +330,7 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
@Override
public void onCounterClicked(int position) {
updateEntry(displayedEntries.get(position), entries.get(getRealIndex(position)), position);
updateEntry(displayedEntries.get(position), entries.getEntry(getRealIndex(position)), position);
}
@Override
@ -375,16 +357,11 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
if (entry.isVisible()) {
hideEntry(entry);
} else {
entries.get(realIndex).setHideTask(new Runnable() {
@Override
public void run() {
hideEntry(entry);
}
});
taskHandler.postDelayed(entries.get(realIndex).getHideTask(), settings.getTapToRevealTimeout() * 1000);
entries.getEntry(realIndex).setHideTask(() -> hideEntry(entry));
taskHandler.postDelayed(entries.getEntry(realIndex).getHideTask(), settings.getTapToRevealTimeout() * 1000);
if (entry.isCounterBased()) {
updateEntry(entry, entries.get(realIndex), position);
updateEntry(entry, entries.getEntry(realIndex), position);
}
entry.setVisible(true);
notifyItemChanged(position);
@ -409,9 +386,9 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
int realIndex = entries.indexOf(entry);
if (realIndex >= 0) {
entries.get(realIndex).setVisible(false);
taskHandler.removeCallbacks(entries.get(realIndex).getHideTask());
entries.get(realIndex).setHideTask(null);
entries.getEntry(realIndex).setVisible(false);
taskHandler.removeCallbacks(entries.getEntry(realIndex).getHideTask());
entries.getEntry(realIndex).setHideTask(null);
}
boolean updateNeeded = updateLastUsedAndFrequency(pos, realIndex);
@ -442,25 +419,19 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
AlertDialog dialog = builder.setTitle(R.string.dialog_title_counter)
.setView(container)
.setPositiveButton(R.string.button_save, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
int realIndex = getRealIndex(pos);
long newCounter = Long.parseLong(input.getEditableText().toString());
.setPositiveButton(R.string.button_save, (dialogInterface, i) -> {
int realIndex = getRealIndex(pos);
long newCounter = Long.parseLong(input.getEditableText().toString());
displayedEntries.get(pos).setCounter(newCounter);
notifyItemChanged(pos);
displayedEntries.get(pos).setCounter(newCounter);
notifyItemChanged(pos);
Entry e = entries.get(realIndex);
e.setCounter(newCounter);
Entry e = entries.getEntry(realIndex);
e.setCounter(newCounter);
saveEntries(settings.getAutoBackupEncryptedFullEnabled());
}
})
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {}
saveEntries(settings.getAutoBackupEncryptedFullEnabled());
})
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> {})
.create();
addCounterValidationWatcher(input, dialog);
dialog.show();
@ -497,7 +468,7 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
private boolean updateLastUsedAndFrequency(int position, int realIndex) {
long timeStamp = System.currentTimeMillis();
long entryUsedFrequency = entries.get(realIndex).getUsedFrequency();
long entryUsedFrequency = entries.getEntry(realIndex).getUsedFrequency();
if (position >= 0) {
long displayEntryUsedFrequency = displayedEntries.get(position).getUsedFrequency();
@ -505,16 +476,16 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
displayedEntries.get(position).setUsedFrequency(displayEntryUsedFrequency + 1);
}
entries.get(realIndex).setLastUsed(timeStamp);
entries.get(realIndex).setUsedFrequency(entryUsedFrequency + 1);
entries.getEntry(realIndex).setLastUsed(timeStamp);
entries.getEntry(realIndex).setUsedFrequency(entryUsedFrequency + 1);
saveEntries(false);
if (sortMode == SortMode.LAST_USED) {
displayedEntries = sortEntries(displayedEntries);
displayedEntries = EntryList.sortEntries(displayedEntries, sortMode);
notifyDataSetChanged();
return false;
} else if (sortMode == SortMode.MOST_USED) {
displayedEntries = sortEntries(displayedEntries);
displayedEntries = EntryList.sortEntries(displayedEntries, sortMode);
notifyDataSetChanged();
return false;
}
@ -524,10 +495,10 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
@Override
public boolean onItemMove(int fromPosition, int toPosition) {
if (sortMode == SortMode.UNSORTED && displayedEntries.equals(entries)) {
Collections.swap(entries, fromPosition, toPosition);
if (sortMode == SortMode.UNSORTED && entries.isEqual(displayedEntries)) {
entries.swapEntries(fromPosition, toPosition);
displayedEntries = new ArrayList<>(entries);
displayedEntries = entries.getEntries();
notifyItemMoved(fromPosition, toPosition);
saveEntries(false);
@ -543,7 +514,7 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
int marginMedium = context.getResources().getDimensionPixelSize(R.dimen.activity_margin_medium);
int realIndex = getRealIndex(pos);
final ThumbnailSelectionAdapter thumbnailAdapter = new ThumbnailSelectionAdapter(context, entries.get(realIndex).getIssuer(), entries.get(realIndex).getLabel());
final ThumbnailSelectionAdapter thumbnailAdapter = new ThumbnailSelectionAdapter(context, entries.getEntry(realIndex).getIssuer(), entries.getEntry(realIndex).getLabel());
final EditText input = new EditText(context);
input.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
@ -590,36 +561,31 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
final AlertDialog alert = builder.setTitle(R.string.menu_popup_change_image)
.setView(container)
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {}
})
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> {})
.create();
grid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int realIndex = getRealIndex(pos);
EntryThumbnail.EntryThumbnails thumbnail = EntryThumbnail.EntryThumbnails.Default;
try {
int realPos = thumbnailAdapter.getRealIndex(position);
thumbnail = EntryThumbnail.EntryThumbnails.values()[realPos];
} catch (Exception e) {
e.printStackTrace();
}
Entry e = entries.get(realIndex);
e.setThumbnail(thumbnail);
saveEntries(settings.getAutoBackupEncryptedFullEnabled());
notifyItemChanged(pos);
alert.cancel();
grid.setOnItemClickListener((parent, view, position, id) -> {
int realIndex1 = getRealIndex(pos);
EntryThumbnail.EntryThumbnails thumbnail = EntryThumbnail.EntryThumbnails.Default;
try {
int realPos = thumbnailAdapter.getRealIndex(position);
thumbnail = EntryThumbnail.EntryThumbnails.values()[realPos];
} catch (Exception e) {
e.printStackTrace();
}
Entry e = entries.getEntry(realIndex1);
e.setThumbnail(thumbnail);
saveEntries(settings.getAutoBackupEncryptedFullEnabled());
notifyItemChanged(pos);
alert.cancel();
});
alert.show();
}
@SuppressLint("StringFormatInvalid")
public void removeItem(final int pos) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
@ -628,22 +594,16 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
builder.setTitle(R.string.dialog_title_remove)
.setMessage(message)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
int realIndex = getRealIndex(pos);
.setPositiveButton(android.R.string.yes, (dialogInterface, i) -> {
int realIndex = getRealIndex(pos);
displayedEntries.remove(pos);
notifyItemRemoved(pos);
displayedEntries.remove(pos);
notifyItemRemoved(pos);
entries.remove(realIndex);
saveEntries(settings.getAutoBackupEncryptedFullEnabled());
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {}
entries.removeEntry(realIndex);
saveEntries(settings.getAutoBackupEncryptedFullEnabled());
})
.setNegativeButton(android.R.string.no, (dialogInterface, i) -> {})
.show();
}
@ -682,26 +642,23 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
MenuInflater inflate = popup.getMenuInflater();
inflate.inflate(R.menu.menu_popup, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
int id = item.getItemId();
popup.setOnMenuItemClickListener(item -> {
int id = item.getItemId();
if (id == R.id.menu_popup_edit) {
ManualEntryDialog.show((MainActivity) context, settings, EntriesCardAdapter.this, entries.get(getRealIndex(pos)));
return true;
} else if(id == R.id.menu_popup_changeImage) {
changeThumbnail(pos);
return true;
} else if (id == R.id.menu_popup_remove) {
removeItem(pos);
return true;
} else if (id == R.id.menu_popup_show_qr_code) {
showQRCode(pos);
return true;
} else {
return false;
}
if (id == R.id.menu_popup_edit) {
ManualEntryDialog.show((MainActivity) context, settings, EntriesCardAdapter.this, entries.getEntry(getRealIndex(pos)));
return true;
} else if(id == R.id.menu_popup_changeImage) {
changeThumbnail(pos);
return true;
} else if (id == R.id.menu_popup_remove) {
removeItem(pos);
return true;
} else if (id == R.id.menu_popup_show_qr_code) {
showQRCode(pos);
return true;
} else {
return false;
}
});
popup.show();
@ -716,22 +673,6 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
return this.sortMode;
}
private ArrayList<Entry> sortEntries(List<Entry> unsorted) {
ArrayList<Entry> sorted = new ArrayList<>(unsorted);
if (sortMode == SortMode.ISSUER) {
Collections.sort(sorted, new IssuerComparator());
} else if (sortMode == SortMode.LABEL) {
Collections.sort(sorted, new LabelComparator());
} else if (sortMode == SortMode.LAST_USED) {
Collections.sort(sorted, new LastUsedComparator());
} else if (sortMode == SortMode.MOST_USED) {
Collections.sort(sorted, new MostUsedComparator());
}
return sorted;
}
public void setCallback(Callback cb) {
this.callback = cb;
}
@ -749,44 +690,17 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
}
public List<String> getTags() {
HashSet<String> tags = new HashSet<String>();
for(Entry entry : entries) {
tags.addAll(entry.getTags());
}
return new ArrayList<String>(tags);
return entries.getAllTags();
}
public class EntryFilter extends Filter {
private List<Constants.SearchIncludes> filterValues = settings.getSearchValues();
private final List<Constants.SearchIncludes> filterValues = settings.getSearchValues();
@Override
protected FilterResults performFiltering(CharSequence constraint) {
ArrayList<Entry> filtered = entries.getFilteredEntries(constraint, filterValues, sortMode);
final FilterResults filterResults = new FilterResults();
ArrayList<Entry> filtered = new ArrayList<>();
if (constraint != null && constraint.length() != 0){
for (int i = 0; i < entries.size(); i++) {
if (filterValues.contains(Constants.SearchIncludes.LABEL) && entries.get(i).getLabel().toLowerCase().contains(constraint.toString().toLowerCase())) {
filtered.add(entries.get(i));
} else if (filterValues.contains(Constants.SearchIncludes.ISSUER) && entries.get(i).getIssuer().toLowerCase().contains(constraint.toString().toLowerCase())) {
filtered.add(entries.get(i));
} else if (filterValues.contains(Constants.SearchIncludes.TAGS)) {
List<String> tags = entries.get(i).getTags();
for (int j = 0; j < tags.size(); j++) {
if (tags.get(j).toLowerCase().contains(constraint.toString().toLowerCase())) {
filtered.add(entries.get(i));
break;
}
}
}
}
} else {
filtered = entries;
}
filterResults.count = filtered.size();
filterResults.values = filtered;
@ -794,54 +708,13 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntryViewHolder>
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
displayedEntries = sortEntries((ArrayList<Entry>) results.values);
@SuppressWarnings("unchecked")
protected void publishResults(CharSequence constraint, @NonNull FilterResults results) {
displayedEntries = (ArrayList<Entry>) results.values;
notifyDataSetChanged();
}
}
public class IssuerComparator implements Comparator<Entry> {
Collator collator;
IssuerComparator(){
collator = Collator.getInstance();
collator.setStrength(Collator.PRIMARY);
}
@Override
public int compare(Entry o1, Entry o2) {
return collator.compare(o1.getIssuer(), o2.getIssuer());
}
}
public class LabelComparator implements Comparator<Entry> {
Collator collator;
LabelComparator(){
collator = Collator.getInstance();
collator.setStrength(Collator.PRIMARY);
}
@Override
public int compare(Entry o1, Entry o2) {
return collator.compare(o1.getLabel(), o2.getLabel());
}
}
public class LastUsedComparator implements Comparator<Entry> {
@Override
public int compare(Entry o1, Entry o2) {
return Long.compare(o2.getLastUsed(), o1.getLastUsed());
}
}
public class MostUsedComparator implements Comparator<Entry> {
@Override
public int compare(Entry o1, Entry o2) {
return Long.compare(o2.getUsedFrequency(), o1.getUsedFrequency());
}
}
public interface Callback {
void onMoveEventStart();
void onMoveEventStop();