mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-04-22 06:49:12 +00:00
Add preference to switch search behavior
This commit is contained in:
parent
20c5236cfa
commit
3425256c29
8 changed files with 136 additions and 1 deletions
|
@ -33,6 +33,12 @@ public class Preferences {
|
|||
public static final int AUTO_LOCK_ON_BACK_BUTTON = 1 << 1;
|
||||
public static final int AUTO_LOCK_ON_MINIMIZE = 1 << 2;
|
||||
public static final int AUTO_LOCK_ON_DEVICE_LOCK = 1 << 3;
|
||||
|
||||
public static final int SEARCH_IN_ISSUER = 1 << 0;
|
||||
public static final int SEARCH_IN_NAME = 1 << 1;
|
||||
public static final int SEARCH_IN_NOTE = 1 << 2;
|
||||
public static final int SEARCH_IN_GROUPS = 1 << 3;
|
||||
|
||||
public static final int BACKUPS_VERSIONS_INFINITE = -1;
|
||||
|
||||
public static final int[] AUTO_LOCK_SETTINGS = {
|
||||
|
@ -41,6 +47,13 @@ public class Preferences {
|
|||
AUTO_LOCK_ON_DEVICE_LOCK
|
||||
};
|
||||
|
||||
public static final int[] SEARCH_BEHAVIOR_SETTINGS = {
|
||||
SEARCH_IN_ISSUER,
|
||||
SEARCH_IN_NAME,
|
||||
SEARCH_IN_NOTE,
|
||||
SEARCH_IN_GROUPS
|
||||
};
|
||||
|
||||
private SharedPreferences _prefs;
|
||||
|
||||
public Preferences(Context context) {
|
||||
|
@ -163,6 +176,20 @@ public class Preferences {
|
|||
return _prefs.getInt("pref_auto_lock_mask", def);
|
||||
}
|
||||
|
||||
public int getSearchBehaviorMask() {
|
||||
final int def = SEARCH_IN_ISSUER | SEARCH_IN_NAME;
|
||||
|
||||
return _prefs.getInt("pref_search_behavior_mask", def);
|
||||
}
|
||||
|
||||
public boolean isSearchBehaviorTypeEnabled(int searchBehaviorType) {
|
||||
return (getSearchBehaviorMask() & searchBehaviorType) == searchBehaviorType;
|
||||
}
|
||||
|
||||
public void setSearchBehaviorMask(int searchBehavior) {
|
||||
_prefs.edit().putInt("pref_search_behavior_mask", searchBehavior).apply();
|
||||
}
|
||||
|
||||
public boolean isAutoLockEnabled() {
|
||||
return getAutoLockMask() != AUTO_LOCK_OFF;
|
||||
}
|
||||
|
|
|
@ -195,6 +195,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
_entryListView.setSortCategory(_prefs.getCurrentSortCategory(), false);
|
||||
_entryListView.setViewMode(_prefs.getCurrentViewMode());
|
||||
_entryListView.setCopyBehavior(_prefs.getCopyBehavior());
|
||||
_entryListView.setSearchBehaviorMask(_prefs.getSearchBehaviorMask());
|
||||
_entryListView.setPrefGroupFilter(_prefs.getGroupFilter());
|
||||
|
||||
FloatingActionButton fab = findViewById(R.id.fab);
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package com.beemdevelopment.aegis.ui.fragments.preferences;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.beemdevelopment.aegis.CopyBehavior;
|
||||
import com.beemdevelopment.aegis.Preferences;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
@ -16,6 +18,51 @@ public class BehaviorPreferencesFragment extends PreferencesFragment {
|
|||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.preferences_behavior);
|
||||
|
||||
Preference currentSearchBehaviorPreference = requirePreference("pref_search_behavior");
|
||||
currentSearchBehaviorPreference.setSummary(getSearchBehaviorSummary());
|
||||
currentSearchBehaviorPreference.setOnPreferenceClickListener((preference) -> {
|
||||
final int[] items = Preferences.SEARCH_BEHAVIOR_SETTINGS;
|
||||
final String[] textItems = getResources().getStringArray(R.array.pref_search_behavior_types);
|
||||
final boolean[] checkedItems = new boolean[items.length];
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
checkedItems[i] = _prefs.isSearchBehaviorTypeEnabled(items[i]);
|
||||
}
|
||||
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.pref_search_behavior_prompt)
|
||||
.setMultiChoiceItems(textItems, checkedItems, (dialog, index, isChecked) -> {
|
||||
checkedItems[index] = isChecked;
|
||||
|
||||
boolean containsAtLeastOneCheckedItem = false;
|
||||
for(boolean b: checkedItems) {
|
||||
if (b) {
|
||||
containsAtLeastOneCheckedItem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AlertDialog alertDialog = (AlertDialog) dialog;
|
||||
Button positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
|
||||
positiveButton.setEnabled(containsAtLeastOneCheckedItem);
|
||||
})
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
int searchBehavior = 0;
|
||||
for (int i = 0; i < checkedItems.length; i++) {
|
||||
if (checkedItems[i]) {
|
||||
searchBehavior |= items[i];
|
||||
}
|
||||
}
|
||||
|
||||
_prefs.setSearchBehaviorMask(searchBehavior);
|
||||
currentSearchBehaviorPreference.setSummary(getSearchBehaviorSummary());
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null);
|
||||
|
||||
Dialogs.showSecureDialog(builder.create());
|
||||
return true;
|
||||
});
|
||||
|
||||
int currentCopyBehavior = _prefs.getCopyBehavior().ordinal();
|
||||
Preference copyBehaviorPreference = requirePreference("pref_copy_behavior");
|
||||
copyBehaviorPreference.setSummary(String.format("%s: %s", getString(R.string.selected), getResources().getStringArray(R.array.copy_behavior_titles)[currentCopyBehavior]));
|
||||
|
@ -45,4 +92,22 @@ public class BehaviorPreferencesFragment extends PreferencesFragment {
|
|||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private String getSearchBehaviorSummary() {
|
||||
final int[] settings = Preferences.SEARCH_BEHAVIOR_SETTINGS;
|
||||
final String[] descriptions = getResources().getStringArray(R.array.pref_search_behavior_types);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < settings.length; i++) {
|
||||
if (_prefs.isSearchBehaviorTypeEnabled(settings[i])) {
|
||||
if (builder.length() != 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
|
||||
builder.append(descriptions[i].toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
return getString(R.string.pref_search_behavior_summary, builder.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import com.beemdevelopment.aegis.otp.TotpInfo;
|
|||
import com.beemdevelopment.aegis.ui.models.ErrorCardInfo;
|
||||
import com.beemdevelopment.aegis.util.CollectionUtils;
|
||||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||
import com.beemdevelopment.aegis.vault.VaultGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
@ -51,6 +52,7 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
private List<VaultEntry> _entries;
|
||||
private List<VaultEntry> _shownEntries;
|
||||
private List<VaultEntry> _selectedEntries;
|
||||
private Collection<VaultGroup> _groups;
|
||||
private Map<UUID, Integer> _usageCounts;
|
||||
private Map<UUID, Long> _lastUsedTimestamps;
|
||||
private VaultEntry _focusedEntry;
|
||||
|
@ -64,6 +66,7 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
private boolean _tapToReveal;
|
||||
private int _tapToRevealTime;
|
||||
private CopyBehavior _copyBehavior;
|
||||
private int _searchBehaviorMask;
|
||||
private Set<UUID> _groupFilter;
|
||||
private SortCategory _sortCategory;
|
||||
private ViewMode _viewMode;
|
||||
|
@ -130,6 +133,8 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
|
||||
public void setCopyBehavior(CopyBehavior copyBehavior) { _copyBehavior = copyBehavior; }
|
||||
|
||||
public void setSearchBehaviorMask(int searchBehaviorMask) { _searchBehaviorMask = searchBehaviorMask; }
|
||||
|
||||
public void setPauseFocused(boolean pauseFocused) {
|
||||
_pauseFocused = pauseFocused;
|
||||
}
|
||||
|
@ -308,6 +313,7 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
Set<UUID> groups = entry.getGroups();
|
||||
String issuer = entry.getIssuer().toLowerCase();
|
||||
String name = entry.getName().toLowerCase();
|
||||
String note = entry.getNote().toLowerCase();
|
||||
|
||||
if (!_groupFilter.isEmpty()) {
|
||||
if (groups.isEmpty() && !_groupFilter.contains(null)) {
|
||||
|
@ -322,7 +328,17 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
return false;
|
||||
}
|
||||
|
||||
return !issuer.contains(_searchFilter) && !name.contains(_searchFilter);
|
||||
return ((_searchBehaviorMask & Preferences.SEARCH_IN_ISSUER) == 0 || !issuer.contains(_searchFilter))
|
||||
&& ((_searchBehaviorMask & Preferences.SEARCH_IN_NAME) == 0 || !name.contains(_searchFilter))
|
||||
&& ((_searchBehaviorMask & Preferences.SEARCH_IN_NOTE) == 0 || !note.contains(_searchFilter))
|
||||
&& ((_searchBehaviorMask & Preferences.SEARCH_IN_GROUPS) == 0 || !doesAnyGroupMatchSearchFilter(entry.getGroups(), _searchFilter));
|
||||
}
|
||||
|
||||
private boolean doesAnyGroupMatchSearchFilter(Set<UUID> entryGroupUUIDs, String searchFilter) {
|
||||
return _groups.stream()
|
||||
.filter(group -> entryGroupUUIDs.contains(group.getUUID()))
|
||||
.map(VaultGroup::getName)
|
||||
.anyMatch(groupName -> groupName.toLowerCase().contains(searchFilter.toLowerCase()));
|
||||
}
|
||||
|
||||
public void refresh(boolean hard) {
|
||||
|
@ -411,6 +427,8 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
|||
|
||||
public Map<UUID, Integer> getUsageCounts() { return _usageCounts; }
|
||||
|
||||
public void setGroups(Collection<VaultGroup> groups) { _groups = groups; }
|
||||
|
||||
public void setLastUsedTimestamps(Map<UUID, Long> lastUsedTimestamps) { _lastUsedTimestamps = lastUsedTimestamps; }
|
||||
|
||||
public Map<UUID, Long> getLastUsedTimestamps() { return _lastUsedTimestamps; }
|
||||
|
|
|
@ -222,6 +222,10 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
_adapter.setCopyBehavior(copyBehavior);
|
||||
}
|
||||
|
||||
public void setSearchBehaviorMask(int searchBehaviorMask) {
|
||||
_adapter.setSearchBehaviorMask(searchBehaviorMask);
|
||||
}
|
||||
|
||||
public List<VaultEntry> selectAllEntries() {
|
||||
return _adapter.selectAllEntries();
|
||||
}
|
||||
|
@ -599,6 +603,7 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
|
||||
public void setGroups(Collection<VaultGroup> groups) {
|
||||
_groups = groups;
|
||||
_adapter.setGroups(groups);
|
||||
_groupChip.setVisibility(_groups.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
updateDividerDecoration();
|
||||
|
||||
|
|
|
@ -125,6 +125,13 @@
|
|||
<item>@string/pref_auto_lock_type_device_lock</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_search_behavior_types">
|
||||
<item>@string/pref_search_behavior_type_issuer</item>
|
||||
<item>@string/pref_search_behavior_type_name</item>
|
||||
<item>@string/pref_search_behavior_type_note</item>
|
||||
<item>@string/pref_search_behavior_type_groups</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="export_formats">
|
||||
<item>@string/export_format_aegis</item>
|
||||
<item>@string/export_format_html</item>
|
||||
|
|
|
@ -107,6 +107,12 @@
|
|||
<string name="pref_encryption_summary">Encrypt the vault and unlock it with a password or biometrics</string>
|
||||
<string name="pref_biometrics_title">Biometric unlock</string>
|
||||
<string name="pref_biometrics_summary">Allow biometric authentication to unlock the vault</string>
|
||||
<string name="pref_search_behavior_summary">Search through: %s</string>
|
||||
<string name="pref_search_behavior_prompt">Search in any of the following fields</string>
|
||||
<string name="pref_search_behavior_type_name">Name</string>
|
||||
<string name="pref_search_behavior_type_issuer">Issuer</string>
|
||||
<string name="pref_search_behavior_type_note">Note</string>
|
||||
<string name="pref_search_behavior_type_groups">Groups</string>
|
||||
<string name="pref_set_password_title">Change password</string>
|
||||
<string name="pref_set_password_summary">Set a new password which you will need to unlock your vault</string>
|
||||
|
||||
|
@ -350,6 +356,7 @@
|
|||
<string name="pref_minimize_on_copy_title">Minimize on copy</string>
|
||||
<string name="pref_minimize_on_copy_summary">Minimize the app after copying a token</string>
|
||||
<string name="pref_copy_behavior_title">Copy tokens to the clipboard</string>
|
||||
<string name="pref_search_behavior_title">Search behavior</string>
|
||||
<string name="pref_pause_entry_title">Freeze tokens when tapped</string>
|
||||
<string name="pref_pause_entry_summary">Pause automatic refresh of tokens by tapping them. Tokens will not update as long as they are focused. Requires \"Highlight tokens when tapped\" or \"Tap to reveal\".</string>
|
||||
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
android:title="@string/pref_focus_search"
|
||||
android:summary="@string/pref_focus_search_summary"
|
||||
app:iconSpaceReserved="false"/>
|
||||
<Preference
|
||||
android:defaultValue="false"
|
||||
android:key="pref_search_behavior"
|
||||
android:title="@string/pref_search_behavior_title"
|
||||
app:iconSpaceReserved="false"/>
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="pref_minimize_on_copy"
|
||||
|
|
Loading…
Add table
Reference in a new issue