From 51a0a16afbedaf32feb481e49a7980b7a44799de Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Sat, 7 Sep 2019 22:26:34 +0200 Subject: [PATCH] Add the option to highlight entries when tapped This adds an option to highlight tapped entries, so that it's easier to distinguisch between the one you're trying to enter into a website and the other ones. Only one entry can be highlighted at a time. Perhaps it would make sense to change our tap to reveal functionality to behave the same, so that the two features are nicely in sync. I can address that in a separate PR if we decide to do so. --- .../beemdevelopment/aegis/Preferences.java | 8 ++- .../aegis/ui/MainActivity.java | 3 + .../aegis/ui/PreferencesFragment.java | 8 ++- .../aegis/ui/views/EntryAdapter.java | 69 ++++++++++++++++--- .../aegis/ui/views/EntryHolder.java | 29 ++++++-- .../aegis/ui/views/EntryListView.java | 22 +++--- app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/preferences.xml | 6 ++ 8 files changed, 123 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java index 20d4bc9d..304474f2 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java +++ b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java @@ -19,7 +19,13 @@ public class Preferences { return _prefs.getBoolean("pref_tap_to_reveal", false); } - public boolean isSearchAccountNameEnabled() { return _prefs.getBoolean("pref_search_names", false); } + public boolean isSearchAccountNameEnabled() { + return _prefs.getBoolean("pref_search_names", false); + } + + public boolean isEntryHighlightEnabled() { + return _prefs.getBoolean("pref_highlight_entry", false); + } public boolean isSecureScreenEnabled() { // screen security should be enabled by default, but not for debug builds diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java index 5cfe3da9..2547f535 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -102,6 +102,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene _entryListView.setListener(this); _entryListView.setShowAccountName(getPreferences().isAccountNameVisible()); _entryListView.setSearchAccountName(getPreferences().isSearchAccountNameEnabled()); + _entryListView.setHighlightEntry(getPreferences().isEntryHighlightEnabled()); _entryListView.setTapToReveal(getPreferences().isTapToRevealEnabled()); _entryListView.setTapToRevealTime(getPreferences().getTapToRevealTime()); _entryListView.setSortCategory(getPreferences().getCurrentSortCategory(), false); @@ -218,11 +219,13 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene } else if (data.getBooleanExtra("needsRefresh", false)) { boolean showAccountName = getPreferences().isAccountNameVisible(); boolean searchAccountName = getPreferences().isSearchAccountNameEnabled(); + boolean highlightEntry = getPreferences().isEntryHighlightEnabled(); boolean tapToReveal = getPreferences().isTapToRevealEnabled(); int tapToRevealTime = getPreferences().getTapToRevealTime(); ViewMode viewMode = getPreferences().getCurrentViewMode(); _entryListView.setShowAccountName(showAccountName); _entryListView.setSearchAccountName(searchAccountName); + _entryListView.setHighlightEntry(highlightEntry); _entryListView.setTapToReveal(tapToReveal); _entryListView.setTapToRevealTime(tapToRevealTime); _entryListView.setViewMode(viewMode); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesFragment.java index 87013bf8..7a9ef2df 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesFragment.java @@ -207,6 +207,12 @@ public class PreferencesFragment extends PreferenceFragmentCompat { return true; }); + Preference entryHighlightPreference = findPreference("pref_highlight_entry"); + entryHighlightPreference.setOnPreferenceChangeListener((preference, newValue) -> { + _result.putExtra("needsRefresh", true); + return true; + }); + Preference tapToRevealPreference = findPreference("pref_tap_to_reveal"); tapToRevealPreference.setOnPreferenceChangeListener((preference, newValue) -> { _result.putExtra("needsRefresh", true); @@ -348,7 +354,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat { } @Override - public void onActivityCreated (Bundle savedInstanceState) { + public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); updateEncryptionPreferences(); } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java index 5bee676d..c3fe7648 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryAdapter.java @@ -1,9 +1,12 @@ package com.beemdevelopment.aegis.ui.views; +import android.os.Handler; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.recyclerview.widget.RecyclerView; + import com.beemdevelopment.aegis.R; import com.beemdevelopment.aegis.SortCategory; import com.beemdevelopment.aegis.ViewMode; @@ -19,15 +22,15 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -import androidx.recyclerview.widget.RecyclerView; - public class EntryAdapter extends RecyclerView.Adapter implements ItemTouchHelperAdapter { private EntryListView _view; private List _entries; private List _shownEntries; private DatabaseEntry _selectedEntry; + private DatabaseEntry _highlightedEntry; private boolean _showAccountName; private boolean _searchAccountName; + private boolean _highlightEntry; private boolean _tapToReveal; private int _tapToRevealTime; private String _groupFilter; @@ -35,6 +38,7 @@ public class EntryAdapter extends RecyclerView.Adapter implements I private ViewMode _viewMode; private String _searchFilter; private boolean _isPeriodUniform = true; + private Handler _dimHandler; // keeps track of the viewholders that are currently bound private List _holders; @@ -43,6 +47,7 @@ public class EntryAdapter extends RecyclerView.Adapter implements I _entries = new ArrayList<>(); _shownEntries = new ArrayList<>(); _holders = new ArrayList<>(); + _dimHandler = new Handler(); _view = view; } @@ -65,7 +70,13 @@ public class EntryAdapter extends RecyclerView.Adapter implements I _tapToRevealTime = number; } - public void setSearchAccountName(boolean searchAccountName) { _searchAccountName = searchAccountName; } + public void setSearchAccountName(boolean searchAccountName) { + _searchAccountName = searchAccountName; + } + + public void setHighlightEntry(boolean highlightEntry) { + _highlightEntry = highlightEntry; + } public DatabaseEntry getEntryAt(int position) { return _shownEntries.get(position); @@ -293,19 +304,34 @@ public class EntryAdapter extends RecyclerView.Adapter implements I DatabaseEntry entry = _shownEntries.get(position); holder.setFocused(entry == _selectedEntry); + boolean dimmed = _highlightedEntry != null && _highlightedEntry != entry; boolean showProgress = !isPeriodUniform() && entry.getInfo() instanceof TotpInfo; - holder.setData(entry, _showAccountName, showProgress, _tapToReveal); + holder.setData(entry, _showAccountName, showProgress, _tapToReveal, dimmed); holder.setTapToRevealTime(_tapToRevealTime); holder.loadIcon(_view); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - int position = holder.getAdapterPosition(); - if (_tapToReveal && holder.isCodeHidden() && _selectedEntry == null) { - holder.revealCode(); - } else { - _view.onEntryClick(_shownEntries.get(position)); + boolean handled = false; + + if (_selectedEntry == null) { + if (_tapToReveal && holder.isCodeHidden()) { + holder.revealCode(); + } + + if (_highlightEntry) { + if (_highlightedEntry == entry) { + resetHighlight(); + handled = true; + } else { + highlightEntry(entry); + } + } + } + + if (!handled) { + _view.onEntryClick(entry); } } }); @@ -384,9 +410,34 @@ public class EntryAdapter extends RecyclerView.Adapter implements I return period; } + private void highlightEntry(DatabaseEntry entry) { + _highlightedEntry = entry; + _dimHandler.removeCallbacksAndMessages(null); + + for (EntryHolder holder : _holders) { + if (holder.getEntry() != _highlightedEntry) { + holder.dim(); + } else { + holder.highlight(); + } + } + + _dimHandler.postDelayed(this::resetHighlight, _tapToRevealTime * 1000); + } + + private void resetHighlight() { + _highlightedEntry = null; + + for (EntryHolder holder : _holders) { + holder.highlight(); + } + } + public void setSelectedEntry(DatabaseEntry entry) { if (entry == null) { notifyItemChanged(_shownEntries.indexOf(_selectedEntry)); + } else if (_highlightEntry) { + resetHighlight(); } _selectedEntry = entry; diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java index cc1dc427..5b0831a7 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryHolder.java @@ -6,6 +6,9 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.RecyclerView; + import com.amulyakhare.textdrawable.TextDrawable; import com.beemdevelopment.aegis.R; import com.beemdevelopment.aegis.db.DatabaseEntry; @@ -19,10 +22,10 @@ import com.beemdevelopment.aegis.otp.TotpInfo; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; -import androidx.fragment.app.Fragment; -import androidx.recyclerview.widget.RecyclerView; - public class EntryHolder extends RecyclerView.ViewHolder { + private static final float DEFAULT_ALPHA = 1.0f; + private static final float DIMMED_ALPHA = 0.2f; + private TextView _profileName; private TextView _profileCode; private TextView _profileIssuer; @@ -74,7 +77,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { _hiddenHandler = new Handler(); } - public void setData(DatabaseEntry entry, boolean showAccountName, boolean showProgress, boolean hidden) { + public void setData(DatabaseEntry entry, boolean showAccountName, boolean showProgress, boolean hidden, boolean dimmed) { _entry = entry; _hidden = hidden; @@ -98,6 +101,12 @@ public class EntryHolder extends RecyclerView.ViewHolder { } else { refreshCode(); } + + itemView.setAlpha(dimmed ? DIMMED_ALPHA : DEFAULT_ALPHA); + } + + public DatabaseEntry getEntry() { + return _entry; } public void loadIcon(Fragment fragment) { @@ -191,6 +200,18 @@ public class EntryHolder extends RecyclerView.ViewHolder { _hidden = false; } + public void dim() { + animateAlphaTo(DIMMED_ALPHA); + } + + public void highlight() { + animateAlphaTo(DEFAULT_ALPHA); + } + + private void animateAlphaTo(float alpha) { + itemView.animate().alpha(alpha).setDuration(200).start(); + } + private void hideCode() { _profileCode.setText(R.string.tap_to_reveal); _hidden = true; diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java index 085b73e7..67d359b8 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java @@ -10,6 +10,15 @@ import android.view.animation.AnimationUtils; import android.view.animation.LayoutAnimationController; import android.widget.LinearLayout; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.beemdevelopment.aegis.R; import com.beemdevelopment.aegis.SortCategory; import com.beemdevelopment.aegis.ViewMode; @@ -27,15 +36,6 @@ import com.bumptech.glide.util.ViewPreloadSizeProvider; import java.util.Collections; import java.util.List; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; -import androidx.fragment.app.Fragment; -import androidx.recyclerview.widget.DividerItemDecoration; -import androidx.recyclerview.widget.ItemTouchHelper; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - public class EntryListView extends Fragment implements EntryAdapter.Listener { private EntryAdapter _adapter; private Listener _listener; @@ -215,6 +215,10 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { _adapter.setSearchAccountName(searchAccountName); } + public void setHighlightEntry(boolean highlightEntry) { + _adapter.setHighlightEntry(highlightEntry); + } + public void setTapToReveal(boolean tapToReveal) { _adapter.setTapToReveal(tapToReveal); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4a312b27..e7f258ff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -160,6 +160,8 @@ Manage and delete your groups here Search in account names Include account name matches in the search results + Highlight tokens when tapped + Make tokens easier to distinguish from each other by temporarily highlighting them when tapped Hidden Selected Dark theme diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 0c8f2006..9e25838b 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -51,6 +51,12 @@ android:title="@string/pref_search_name_title" android:summary="@string/pref_search_name_summary" app:iconSpaceReserved="false"/> +