Skip to content

Commit

Permalink
Merge pull request #1458 from michaelschattgen/fix/hidden-dots-size
Browse files Browse the repository at this point in the history
Fix sizing inconsistency of the dots in hidden view
  • Loading branch information
alexbakker authored Aug 23, 2024
2 parents a46c816 + 4ddc42e commit 9eae773
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.beemdevelopment.aegis.helpers;

import android.graphics.Rect;
import android.text.TextPaint;
import android.text.style.MetricAffectingSpan;

import androidx.annotation.NonNull;

public class CenterVerticalSpan extends MetricAffectingSpan {
Rect _substringBounds;

public CenterVerticalSpan(Rect substringBounds) {
_substringBounds = substringBounds;
}

@Override
public void updateMeasureState(@NonNull TextPaint textPaint) {
applyBaselineShift(textPaint);
}

@Override
public void updateDrawState(@NonNull TextPaint textPaint) {
applyBaselineShift(textPaint);
}

private void applyBaselineShift(TextPaint textPaint) {
float topDifference = textPaint.getFontMetrics().top - _substringBounds.top;
textPaint.baselineShift -= (topDifference / 2f);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package com.beemdevelopment.aegis.ui.views;

import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.RelativeSizeSpan;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
Expand All @@ -17,6 +22,7 @@
import com.beemdevelopment.aegis.R;
import com.beemdevelopment.aegis.ViewMode;
import com.beemdevelopment.aegis.helpers.AnimationsHelper;
import com.beemdevelopment.aegis.helpers.CenterVerticalSpan;
import com.beemdevelopment.aegis.helpers.SimpleAnimationEndListener;
import com.beemdevelopment.aegis.helpers.UiRefresher;
import com.beemdevelopment.aegis.otp.HotpInfo;
Expand Down Expand Up @@ -276,6 +282,10 @@ public void refreshCode() {
}

private void updateCode() {
_profileCode.setText(getOtp());
}

private String getOtp() {
OtpInfo info = _entry.getInfo();

// In previous versions of Aegis, it was possible to import entries with an empty
Expand All @@ -292,7 +302,7 @@ private void updateCode() {
otp = _view.getResources().getString(R.string.error_all_caps);
}

_profileCode.setText(otp);
return otp;
}

private String formatCode(String code) {
Expand Down Expand Up @@ -330,12 +340,53 @@ public void revealCode() {
}

public void hideCode() {
String hiddenText = new String(new char[_entry.getInfo().getDigits()]).replace("\0", Character.toString(HIDDEN_CHAR));
hiddenText = formatCode(hiddenText);
_profileCode.setText(hiddenText);
String code = getOtp();
String hiddenText = code.replaceAll("\\S", Character.toString(HIDDEN_CHAR));
updateTextViewWithDots(_profileCode, hiddenText, code);

_hidden = true;
}

private void updateTextViewWithDots(TextView textView, String hiddenCode, String code) {
Paint paint = new Paint();
paint.setTextSize(_profileCode.getTextSize());

// Calculate the difference between the actual code width and the dots width
float codeWidth = paint.measureText(code);
float dotsWidth = paint.measureText(hiddenCode);
float scaleFactor = codeWidth / dotsWidth;
scaleFactor = (float)(Math.round(scaleFactor * 10.0) / 10.0);

// If scale is higher or equal to 0.8, do nothing and proceed with the normal text rendering
if (scaleFactor >= 0.8) {
textView.setText(hiddenCode);
return;
}

// We need to use an invisible character in order to get the height of the profileCode textview consistent
// Tokens without a space (ie Steam TOTP) will get misaligned without this
SpannableString dotsString = new SpannableString("\u200B" + hiddenCode);

// Only scale the digits/characters, skip the spaces
int start = 1;
for (int i = 0; i <= dotsString.length(); i++) {
if (i == dotsString.length() || dotsString.charAt(i) == ' ') {
if (i > start) {
dotsString.setSpan(new RelativeSizeSpan(scaleFactor), start, i, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}

start = i + 1;
}
}

Rect dotsRectBounds = new Rect();
paint.getTextBounds(hiddenCode, 1, hiddenCode.length(), dotsRectBounds);

// Use custom CenterVerticalSpan to make sure the dots are vertically aligned
dotsString.setSpan(new CenterVerticalSpan(dotsRectBounds), 1, dotsString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(dotsString);
}

public void showIcon(boolean show) {
if (show) {
_profileDrawable.setVisibility(View.VISIBLE);
Expand Down

0 comments on commit 9eae773

Please sign in to comment.