From e4c9a584f48da402291608ec1db0983dcdee2fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Mon, 30 Sep 2024 23:36:08 +0200 Subject: [PATCH] Add ability to show next code Co-authored-by: Alexander Bakker --- .../beemdevelopment/aegis/Preferences.java | 4 ++ .../beemdevelopment/aegis/otp/TotpInfo.java | 4 +- .../aegis/ui/MainActivity.java | 1 + .../aegis/ui/views/EntryAdapter.java | 7 ++- .../aegis/ui/views/EntryHolder.java | 31 ++++++++-- .../aegis/ui/views/EntryListView.java | 4 ++ app/src/main/res/layout/card_entry.xml | 58 ++++++++++++------ .../main/res/layout/card_entry_compact.xml | 61 +++++++++++++------ app/src/main/res/layout/card_entry_small.xml | 57 ++++++++++++----- app/src/main/res/layout/card_entry_tile.xml | 55 ++++++++++++----- app/src/main/res/values/strings.xml | 2 + .../main/res/xml/preferences_appearance.xml | 7 +++ 12 files changed, 218 insertions(+), 73 deletions(-) diff --git a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java index 10f98e73..5b4041ab 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/Preferences.java +++ b/app/src/main/java/com/beemdevelopment/aegis/Preferences.java @@ -153,6 +153,10 @@ public class Preferences { return _prefs.getBoolean("pref_show_icons", true); } + public boolean getShowNextCode() { + return _prefs.getBoolean("pref_show_next_code", false); + } + public boolean getShowExpirationState() { return _prefs.getBoolean("pref_expiration_state", true); } diff --git a/app/src/main/java/com/beemdevelopment/aegis/otp/TotpInfo.java b/app/src/main/java/com/beemdevelopment/aegis/otp/TotpInfo.java index 5e7320f4..bd43698d 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/otp/TotpInfo.java +++ b/app/src/main/java/com/beemdevelopment/aegis/otp/TotpInfo.java @@ -37,7 +37,9 @@ public class TotpInfo extends OtpInfo { } } - public String getOtp(long time) { + public String getOtp(long time) throws OtpInfoException { + checkSecret(); + try { OTP otp = TOTP.generateOTP(getSecret(), getAlgorithm(true), getDigits(), getPeriod(), time); return otp.toString(); 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 d9c03a59..88d2a538 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -208,6 +208,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene _entryListView.setAccountNamePosition(_prefs.getAccountNamePosition()); _entryListView.setShowIcon(_prefs.isIconVisible()); _entryListView.setShowExpirationState(_prefs.getShowExpirationState()); + _entryListView.setShowNextCode(_prefs.getShowNextCode()); _entryListView.setOnlyShowNecessaryAccountNames(_prefs.onlyShowNecessaryAccountNames()); _entryListView.setHighlightEntry(_prefs.isEntryHighlightEnabled()); _entryListView.setPauseFocused(_prefs.isPauseFocusedEnabled()); 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 696c7f40..cea77364 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 @@ -60,6 +60,7 @@ public class EntryAdapter extends RecyclerView.Adapter private Preferences.CodeGrouping _codeGroupSize; private AccountNamePosition _accountNamePosition; private boolean _showIcon; + private boolean _showNextCode; private boolean _showExpirationState; private boolean _onlyShowNecessaryAccountNames; private boolean _highlightEntry; @@ -116,6 +117,10 @@ public class EntryAdapter extends RecyclerView.Adapter _showIcon = showIcon; } + public void setShowNextCode(boolean showNextCode) { + _showNextCode = showNextCode; + } + public void setShowExpirationState(boolean showExpirationState) { _showExpirationState = showExpirationState; } @@ -544,7 +549,7 @@ public class EntryAdapter extends RecyclerView.Adapter } AccountNamePosition accountNamePosition = showAccountName ? _accountNamePosition : AccountNamePosition.HIDDEN; - entryHolder.setData(entry, _codeGroupSize, _viewMode, accountNamePosition, _showIcon, showProgress, hidden, paused, dimmed, _showExpirationState); + entryHolder.setData(entry, _codeGroupSize, _viewMode, accountNamePosition, _showIcon, showProgress, hidden, paused, dimmed, _showExpirationState, _showNextCode); entryHolder.setFocused(_selectedEntries.contains(entry)); entryHolder.setShowDragHandle(isEntryDraggable(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 1f44f423..1e5b9cf0 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 @@ -50,6 +50,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { private View _favoriteIndicator; private TextView _profileName; private TextView _profileCode; + private TextView _nextProfileCode; private TextView _profileIssuer; private TextView _profileCopied; private ImageView _profileDrawable; @@ -74,6 +75,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { private UiRefresher _refresher; private Handler _animationHandler; private AnimatorSet _expirationAnimSet; + private boolean _showNextCode; private boolean _showExpirationState; private Animation _scaleIn; @@ -85,6 +87,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { _view = (MaterialCardView) view; _profileName = view.findViewById(R.id.profile_account_name); _profileCode = view.findViewById(R.id.profile_code); + _nextProfileCode = view.findViewById(R.id.next_profile_code); _profileIssuer = view.findViewById(R.id.profile_issuer); _profileCopied = view.findViewById(R.id.profile_copied); _description = view.findViewById(R.id.description); @@ -115,7 +118,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { }); } - public void setData(VaultEntry entry, Preferences.CodeGrouping groupSize, ViewMode viewMode, AccountNamePosition accountNamePosition, boolean showIcon, boolean showProgress, boolean hidden, boolean paused, boolean dimmed, boolean showExpirationState) { + public void setData(VaultEntry entry, Preferences.CodeGrouping groupSize, ViewMode viewMode, AccountNamePosition accountNamePosition, boolean showIcon, boolean showProgress, boolean hidden, boolean paused, boolean dimmed, boolean showExpirationState, boolean showNextCode) { _entry = entry; _hidden = hidden; _paused = paused; @@ -131,6 +134,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { _selected.setVisibility(View.GONE); _selectedHandler.removeCallbacksAndMessages(null); _animationHandler.removeCallbacksAndMessages(null); + _showNextCode = entry.getInfo() instanceof TotpInfo && showNextCode; _showExpirationState = _entry.getInfo() instanceof TotpInfo && showExpirationState; _favoriteIndicator.setVisibility(_entry.isFavorite() ? View.VISIBLE : View.INVISIBLE); @@ -140,6 +144,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { // only show the button if this entry is of type HotpInfo _buttonRefresh.setVisibility(entry.getInfo() instanceof HotpInfo ? View.VISIBLE : View.GONE); + _nextProfileCode.setVisibility(_showNextCode ? View.VISIBLE : View.GONE); String profileIssuer = entry.getIssuer(); String profileName = entry.getName(); @@ -284,16 +289,24 @@ public class EntryHolder extends RecyclerView.ViewHolder { public void refreshCode() { if (!_hidden && !_paused) { - updateCode(); + updateCodes(); startExpirationAnimation(); } } - private void updateCode() { + private void updateCodes() { _profileCode.setText(getOtp()); + + if (_showNextCode) { + _nextProfileCode.setText(getOtp(1)); + } } private String getOtp() { + return getOtp(0); + } + + private String getOtp(int offset) { OtpInfo info = _entry.getInfo(); // In previous versions of Aegis, it was possible to import entries with an empty @@ -302,7 +315,12 @@ public class EntryHolder extends RecyclerView.ViewHolder { // the OTP, instead of crashing. String otp; try { - otp = info.getOtp(); + if (info instanceof TotpInfo) { + otp = ((TotpInfo)info).getOtp((System.currentTimeMillis() / 1000) + ((long) (offset) * ((TotpInfo) _entry.getInfo()).getPeriod())); + } else { + otp = info.getOtp(); + } + if (!(info instanceof SteamInfo || info instanceof YandexInfo)) { otp = formatCode(otp); } @@ -343,7 +361,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { } public void revealCode() { - updateCode(); + updateCodes(); startExpirationAnimation(); _hidden = false; } @@ -352,6 +370,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { String code = getOtp(); String hiddenText = code.replaceAll("\\S", Character.toString(HIDDEN_CHAR)); updateTextViewWithDots(_profileCode, hiddenText, code); + updateTextViewWithDots(_nextProfileCode, hiddenText, code); stopExpirationAnimation(); _hidden = true; } @@ -480,7 +499,7 @@ public class EntryHolder extends RecyclerView.ViewHolder { if (_paused) { stopExpirationAnimation(); } else if (!_hidden) { - updateCode(); + updateCodes(); startExpirationAnimation(); } } 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 af829d6d..002db712 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 @@ -363,6 +363,10 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { _adapter.setShowIcon(showIcon); } + public void setShowNextCode(boolean showNextCode) { + _adapter.setShowNextCode(showNextCode); + } + public void setShowExpirationState(boolean showExpirationState) { _showExpirationState = showExpirationState; _adapter.setShowExpirationState(showExpirationState); diff --git a/app/src/main/res/layout/card_entry.xml b/app/src/main/res/layout/card_entry.xml index 47b05330..11f01859 100644 --- a/app/src/main/res/layout/card_entry.xml +++ b/app/src/main/res/layout/card_entry.xml @@ -71,7 +71,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/description" - android:layout_alignStart="@+id/profile_code"> + android:layout_alignStart="@+id/profile_codes_layout"> - + android:layout_width="match_parent" + android:layout_height="match_parent"> + + + + + diff --git a/app/src/main/res/layout/card_entry_compact.xml b/app/src/main/res/layout/card_entry_compact.xml index 053e2585..7769e9d2 100644 --- a/app/src/main/res/layout/card_entry_compact.xml +++ b/app/src/main/res/layout/card_entry_compact.xml @@ -85,8 +85,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/description" - android:layout_alignStart="@+id/profile_code"> - + android:layout_alignStart="@+id/profile_codes_layout"> @@ -112,23 +112,50 @@ - + android:layout_width="match_parent" + android:layout_height="match_parent"> + + + + + + + diff --git a/app/src/main/res/layout/card_entry_small.xml b/app/src/main/res/layout/card_entry_small.xml index 104d954e..c9b2b396 100644 --- a/app/src/main/res/layout/card_entry_small.xml +++ b/app/src/main/res/layout/card_entry_small.xml @@ -85,7 +85,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/description" - android:layout_alignStart="@+id/profile_code"> + android:layout_alignStart="@+id/profile_codes_layout"> - + android:layout_width="match_parent" + android:layout_height="match_parent"> + + + + + diff --git a/app/src/main/res/layout/card_entry_tile.xml b/app/src/main/res/layout/card_entry_tile.xml index eac01a66..1f98dd40 100644 --- a/app/src/main/res/layout/card_entry_tile.xml +++ b/app/src/main/res/layout/card_entry_tile.xml @@ -104,22 +104,47 @@ tools:text=" - AccountName" /> - + android:layout_width="match_parent" + android:layout_height="match_parent"> + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bab03455..e847a4bf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -48,6 +48,8 @@ Code digit grouping Select number of digits to group codes by Show the account name + Show next code + Generate and show the next code ahead of time Indicate when codes are about to expire Change the color of the codes and have them blink when they are about to expire Change the color of the codes when they are about to expire diff --git a/app/src/main/res/xml/preferences_appearance.xml b/app/src/main/res/xml/preferences_appearance.xml index e857f4ea..b025315c 100644 --- a/app/src/main/res/xml/preferences_appearance.xml +++ b/app/src/main/res/xml/preferences_appearance.xml @@ -41,6 +41,13 @@ android:summary="@string/pref_show_icons_summary" app:iconSpaceReserved="false"/> + +