Skip to content

Commit

Permalink
Show when codes are about to expire
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelschattgen committed Sep 18, 2024
1 parent 17f106f commit e8baa5e
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 2 deletions.
4 changes: 4 additions & 0 deletions app/src/main/java/com/beemdevelopment/aegis/Preferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ public boolean isIconVisible() {
return _prefs.getBoolean("pref_show_icons", true);
}

public boolean getShowExpirationState() {
return _prefs.getBoolean("pref_expiration_state", true);
}

public CodeGrouping getCodeGroupSize() {
String value = _prefs.getString("pref_code_group_size_string", "GROUPING_THREES");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ protected void onCreate(Bundle savedInstanceState) {
_entryListView.setCodeGroupSize(_prefs.getCodeGroupSize());
_entryListView.setAccountNamePosition(_prefs.getAccountNamePosition());
_entryListView.setShowIcon(_prefs.isIconVisible());
_entryListView.setShowExpirationState(_prefs.getShowExpirationState());
_entryListView.setOnlyShowNecessaryAccountNames(_prefs.onlyShowNecessaryAccountNames());
_entryListView.setHighlightEntry(_prefs.isEntryHighlightEnabled());
_entryListView.setPauseFocused(_prefs.isPauseFocusedEnabled());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class EntryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
private Preferences.CodeGrouping _codeGroupSize;
private AccountNamePosition _accountNamePosition;
private boolean _showIcon;
private boolean _showExpirationState;
private boolean _onlyShowNecessaryAccountNames;
private boolean _highlightEntry;
private boolean _tempHighlightEntry;
Expand Down Expand Up @@ -115,6 +116,10 @@ public void setShowIcon(boolean showIcon) {
_showIcon = showIcon;
}

public void setShowExpirationState(boolean showExpirationState) {
_showExpirationState = showExpirationState;
}

public void setTapToReveal(boolean tapToReveal) {
_tapToReveal = tapToReveal;
}
Expand Down Expand Up @@ -348,6 +353,15 @@ public void refresh(boolean hard) {
for (EntryHolder holder : _holders) {
holder.refresh();
holder.showIcon(_showIcon);
holder.setShowExpirationState(_showExpirationState);
}
}
}

public void startExpiringAnimation() {
for (EntryHolder holder : _holders) {
if(holder.getEntry().getInfo() instanceof TotpInfo) {
holder.updateExpirationState();
}
}
}
Expand Down Expand Up @@ -539,7 +553,7 @@ public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position)
}

AccountNamePosition accountNamePosition = showAccountName ? _accountNamePosition : AccountNamePosition.HIDDEN;
entryHolder.setData(entry, _codeGroupSize, _viewMode, accountNamePosition, _showIcon, showProgress, hidden, paused, dimmed);
entryHolder.setData(entry, _codeGroupSize, _viewMode, accountNamePosition, _showIcon, showProgress, hidden, paused, dimmed, _showExpirationState);
entryHolder.setFocused(_selectedEntries.contains(entry));
entryHolder.setShowDragHandle(isEntryDraggable(entry));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.beemdevelopment.aegis.ui.views;

import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
Expand Down Expand Up @@ -35,6 +37,7 @@
import com.beemdevelopment.aegis.vault.VaultEntry;
import com.bumptech.glide.Glide;
import com.google.android.material.card.MaterialCardView;
import com.google.android.material.color.MaterialColors;

public class EntryHolder extends RecyclerView.ViewHolder {
private static final float DEFAULT_ALPHA = 1.0f;
Expand Down Expand Up @@ -66,6 +69,7 @@ public class EntryHolder extends RecyclerView.ViewHolder {
private MaterialCardView _view;

private UiRefresher _refresher;
private UiRefresher _expiringRefresher;
private Handler _animationHandler;

private Animation _scaleIn;
Expand Down Expand Up @@ -107,14 +111,72 @@ public long getMillisTillNextRefresh() {
return ((TotpInfo) _entry.getInfo()).getMillisTillNextRotation();
}
});

_expiringRefresher = new UiRefresher(new UiRefresher.Listener() {
@Override
public void onRefresh() {
updateExpirationState();
}

public long getMillisTillNextRefresh() {
long millisTillNextRotation = ((TotpInfo) _entry.getInfo()).getMillisTillNextRotation();
if (millisTillNextRotation > 7000) {
stopExpirationAnimation();
return millisTillNextRotation - 7000;
} else {
return 1000;
}
}
});
}

public void updateExpirationState() {
long millisTillNextRotation = ((TotpInfo) _entry.getInfo()).getMillisTillNextRotation();
if (!_hidden && !_paused) {
if (millisTillNextRotation <= 7000) {
setExpirationColor();
}

if (millisTillNextRotation <= 3000) {
startExpirationAnimation();
}
}
}

private void setExpirationColor() {
int colorFrom = _profileCode.getCurrentTextColor();
int colorTo = MaterialColors.getColor(_profileCode, com.google.android.material.R.attr.colorError);

ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.setDuration(300);
colorAnimation.addUpdateListener(animator -> _profileCode.setTextColor((int) animator.getAnimatedValue()));
colorAnimation.start();
}

public void setData(VaultEntry entry, Preferences.CodeGrouping groupSize, ViewMode viewMode, AccountNamePosition accountNamePosition, boolean showIcon, boolean showProgress, boolean hidden, boolean paused, boolean dimmed) {

private void startExpirationAnimation() {
_profileCode.setAlpha(1f);

_profileCode.animate().alpha(0.5f).setDuration(500).withEndAction(() -> {
long animationDuration = Math.min(((TotpInfo) _entry.getInfo()).getMillisTillNextRotation(), 500);
_profileCode.animate().alpha(1f).setDuration(animationDuration).start();
}).start();
}

private void stopExpirationAnimation() {
int colorTo = MaterialColors.getColor(_profileCode, R.attr.colorCode);
_profileCode.setTextColor(colorTo);
_profileCode.clearAnimation();
_profileCode.setAlpha(1f);
}

public void setData(VaultEntry entry, Preferences.CodeGrouping groupSize, ViewMode viewMode, AccountNamePosition accountNamePosition, boolean showIcon, boolean showProgress, boolean hidden, boolean paused, boolean dimmed, boolean showExpirationState) {
_entry = entry;
_hidden = hidden;
_paused = paused;
_codeGrouping = groupSize;
_viewMode = viewMode;

_accountNamePosition = accountNamePosition;
if (viewMode.equals(ViewMode.TILES) && _accountNamePosition == AccountNamePosition.END) {
_accountNamePosition = AccountNamePosition.BELOW;
Expand All @@ -129,6 +191,7 @@ public void setData(VaultEntry entry, Preferences.CodeGrouping groupSize, ViewMo

// only show the progress bar if there is no uniform period and the entry type is TotpInfo
setShowProgress(showProgress);
setShowExpirationState(showExpirationState);

// only show the button if this entry is of type HotpInfo
_buttonRefresh.setVisibility(entry.getInfo() instanceof HotpInfo ? View.VISIBLE : View.GONE);
Expand Down Expand Up @@ -258,6 +321,7 @@ public void setFocusedAndAnimate(boolean focused) {

public void destroy() {
_refresher.destroy();
_expiringRefresher.destroy();
}

public void startRefreshLoop() {
Expand All @@ -270,6 +334,14 @@ public void stopRefreshLoop() {
_progressBar.stop();
}

public void startExpirationStateLoop() {
_expiringRefresher.start();
}

public void stopExpirationStateLoop() {
_expiringRefresher.stop();
}

public void refresh() {
_progressBar.restart();
refreshCode();
Expand All @@ -278,6 +350,8 @@ public void refresh() {
public void refreshCode() {
if (!_hidden && !_paused) {
updateCode();

stopExpirationAnimation();
}
}

Expand Down Expand Up @@ -395,6 +469,18 @@ public void showIcon(boolean show) {
}
}

public void setShowExpirationState(boolean showExpirationState) {
if (_entry.getInfo() instanceof HotpInfo) {
showExpirationState = false;
}

if (showExpirationState) {
startExpirationStateLoop();
} else {
stopExpirationStateLoop();
}
}

public boolean isHidden() {
return _hidden;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,12 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
private ViewPreloadSizeProvider<VaultEntry> _preloadSizeProvider;
private TotpProgressBar _progressBar;
private boolean _showProgress;
private boolean _showExpirationState;
private ViewMode _viewMode;
private LinearLayout _emptyStateView;

private UiRefresher _refresher;
private UiRefresher _expiringRefresher;

@Override
public void onCreate(Bundle savedInstanceState) {
Expand Down Expand Up @@ -150,6 +152,23 @@ public long getMillisTillNextRefresh() {
}
});

_expiringRefresher = new UiRefresher(new UiRefresher.Listener() {
@Override
public void onRefresh() {
_adapter.startExpiringAnimation();
}

@Override
public long getMillisTillNextRefresh() {
long millisTillNextRotation = TotpInfo.getMillisTillNextRotation(_adapter.getMostFrequentPeriod());
if (millisTillNextRotation > 7000) {
return millisTillNextRotation - 7000;
} else {
return 1000;
}
}
});

_emptyStateView = view.findViewById(R.id.vEmptyList);
return view;
}
Expand All @@ -161,6 +180,7 @@ public void setPreloadView(View view) {
@Override
public void onDestroyView() {
_refresher.destroy();
_expiringRefresher.destroy();
super.onDestroyView();
}

Expand Down Expand Up @@ -335,10 +355,18 @@ public void onPeriodUniformityChanged(boolean isUniform, int period) {
_progressBar.setPeriod(period);
_progressBar.start();
_refresher.start();

if(_showExpirationState) {
_expiringRefresher.start();
}
} else {
_progressBar.setVisibility(View.GONE);
_progressBar.stop();
_refresher.stop();

if(_showExpirationState) {
_expiringRefresher.stop();
}
}
}

Expand All @@ -365,6 +393,11 @@ public void setShowIcon(boolean showIcon) {
_adapter.setShowIcon(showIcon);
}

public void setShowExpirationState(boolean showExpirationState) {
_showExpirationState = showExpirationState;
_adapter.setShowExpirationState(showExpirationState);
}

public void setHighlightEntry(boolean highlightEntry) {
_adapter.setHighlightEntry(highlightEntry);
}
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
<string name="pref_code_group_size_title">Code digit grouping</string>
<string name="pref_code_group_size_summary">Select number of digits to group codes by</string>
<string name="pref_account_name_position_title">Show the account name</string>
<string name="pref_expiration_state_title">Show when codes are about to expire</string>
<string name="pref_expiration_state_summary">Change the color of the code and have the codes blink when they are about to expire</string>
<string name="pref_shared_issuer_account_name_title">Only show account name when necessary</string>
<string name="pref_shared_issuer_account_name_summary">Only show account names whenever they share the same issuer. Other account names will be hidden.</string>
<string name="pref_account_name_position_summary_override">This setting is overridden by the tiles view mode. Account name will be shown below the issuer.</string>
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/res/xml/preferences_appearance.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@
android:summary="@string/pref_show_icons_summary"
app:iconSpaceReserved="false"/>

<androidx.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="pref_expiration_state"
android:title="@string/pref_expiration_state_title"
android:summary="@string/pref_expiration_state_summary"
app:iconSpaceReserved="false"/>

<Preference
android:key="pref_code_group_size_string"
android:title="@string/pref_code_group_size_title"
Expand Down

0 comments on commit e8baa5e

Please sign in to comment.