Finish work on the single progressbar for db's with uniform periods

This commit is contained in:
Alexander Bakker 2018-06-05 18:52:31 +02:00
parent 8a8cb94c16
commit 3f3863a187
9 changed files with 175 additions and 155 deletions

View file

@ -42,7 +42,11 @@ public class KeyInfo implements Serializable {
}
public long getMillisTillNextRotation() {
long p = _period * 1000;
return KeyInfo.getMillisTillNextRotation(_period);
}
public static long getMillisTillNextRotation(int period) {
long p = period * 1000;
return p - (System.currentTimeMillis() % p);
}

View file

@ -1,22 +1,17 @@
package me.impy.aegis.ui;
import android.Manifest;
import android.animation.ObjectAnimator;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.os.Handler;
import android.support.design.widget.BottomSheetDialog;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.getbase.floatingactionbutton.FloatingActionsMenu;
@ -50,12 +45,9 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen
private AegisApplication _app;
private DatabaseManager _db;
private KeyProfileView _keyProfileView;
private ProgressBar _progressBar;
private Menu _menu;
private FloatingActionsMenu _fabMenu;
private Handler _uiHandler;
private boolean _running = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -63,8 +55,6 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen
_app = (AegisApplication) getApplication();
_db = _app.getDatabaseManager();
_uiHandler = new Handler();
// set up the main view
setContentView(R.layout.activity_main);
@ -73,10 +63,6 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen
_keyProfileView.setListener(this);
_keyProfileView.setShowIssuer(getPreferences().isIssuerVisible());
_progressBar = findViewById(R.id.progressBar);
int primaryColorId = getResources().getColor(R.color.colorPrimary);
_progressBar.getProgressDrawable().setColorFilter(primaryColorId, PorterDuff.Mode.SRC_IN);
// set up the floating action button
_fabMenu = findViewById(R.id.fab);
findViewById(R.id.fab_enter).setOnClickListener(view -> {
@ -431,52 +417,6 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen
for (DatabaseEntry entry : _db.getKeys()) {
_keyProfileView.addKey(new KeyProfile(entry));
}
if(_keyProfileView.allSamePeriod())
{
startRefreshLoop();
}
}
public void refreshCode()
{
_keyProfileView.refresh();
KeyProfile keyProfile = _keyProfileView.getKeyProfile(0);
// reset the progress bar
int maxProgress = _progressBar.getMax();
_progressBar.setProgress(maxProgress);
// calculate the progress the bar should start at
long millisTillRotation = keyProfile.getEntry().getInfo().getMillisTillNextRotation();
long period = keyProfile.getEntry().getInfo().getPeriod() * maxProgress;
int currentProgress = maxProgress - (int) ((((double) period - millisTillRotation) / period) * maxProgress);
// start progress animation
ObjectAnimator animation = ObjectAnimator.ofInt(_progressBar, "progress", currentProgress, 0);
animation.setDuration(millisTillRotation);
animation.setInterpolator(new LinearInterpolator());
animation.start();
}
public void startRefreshLoop() {
if (_running) {
return;
}
_running = true;
KeyProfile keyProfile = _keyProfileView.getKeyProfile(0);
refreshCode();
_uiHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (_running) {
refreshCode();
_uiHandler.postDelayed(this, keyProfile.getEntry().getInfo().getMillisTillNextRotation());
}
}
}, keyProfile.getEntry().getInfo().getMillisTillNextRotation());
}
private void updateLockIcon() {

View file

@ -49,10 +49,6 @@ public class KeyProfileAdapter extends RecyclerView.Adapter<KeyProfileHolder> im
notifyDataSetChanged();
}
public ArrayList<KeyProfile> getKeys() {
return _keyProfiles;
}
public void replaceKey(KeyProfile newProfile) {
KeyProfile oldProfile = getKeyByUUID(newProfile.getEntry().getUUID());
int position = _keyProfiles.indexOf(oldProfile);
@ -60,13 +56,6 @@ public class KeyProfileAdapter extends RecyclerView.Adapter<KeyProfileHolder> im
notifyItemChanged(position);
}
public void refresh() {
for (KeyProfile profile : _keyProfiles) {
profile.refreshCode();
}
notifyDataSetChanged();
}
private KeyProfile getKeyByUUID(UUID uuid) {
for (KeyProfile profile : _keyProfiles) {
if (profile.getEntry().getUUID().equals(uuid)) {
@ -104,17 +93,16 @@ public class KeyProfileAdapter extends RecyclerView.Adapter<KeyProfileHolder> im
@Override
public void onViewRecycled(KeyProfileHolder holder) {
holder.setData(null, _showIssuer);
holder.stopRefreshLoop();
super.onViewRecycled(holder);
}
@Override
public void onBindViewHolder(final KeyProfileHolder holder, int position) {
boolean uniform = isPeriodUniform();
final KeyProfile profile = _keyProfiles.get(position);
holder.setData(profile, _showIssuer);
if(!allSamePeriod())
{
holder.setData(profile, _showIssuer, !uniform);
if (!uniform) {
holder.startRefreshLoop();
}
@ -134,19 +122,23 @@ public class KeyProfileAdapter extends RecyclerView.Adapter<KeyProfileHolder> im
});
}
public boolean allSamePeriod()
{
ArrayList<KeyProfile> profiles = getKeys();
int period = profiles.get(0).getEntry().getInfo().getPeriod();
public int getUniformPeriod() {
if (_keyProfiles.isEmpty()) {
return -1;
}
for (KeyProfile profile : profiles) {
if(period != profile.getEntry().getInfo().getPeriod())
{
return false;
int period = _keyProfiles.get(0).getEntry().getInfo().getPeriod();
for (KeyProfile profile : _keyProfiles) {
if (period != profile.getEntry().getInfo().getPeriod()) {
return -1;
}
}
return true;
return period;
}
public boolean isPeriodUniform() {
return getUniformPeriod() != -1;
}
@Override

View file

@ -1,14 +1,10 @@
package me.impy.aegis.ui.views;
import android.animation.ObjectAnimator;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.os.Handler;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable;
@ -21,7 +17,8 @@ public class KeyProfileHolder extends RecyclerView.ViewHolder {
private TextView _profileIssuer;
private ImageView _profileDrawable;
private KeyProfile _profile;
private ProgressBar _progressBar;
private PeriodProgressBar _progressBar;
private Handler _uiHandler;
private boolean _running = false;
@ -39,16 +36,15 @@ public class KeyProfileHolder extends RecyclerView.ViewHolder {
_progressBar.getProgressDrawable().setColorFilter(primaryColorId, PorterDuff.Mode.SRC_IN);
}
public void setData(KeyProfile profile, boolean showIssuer) {
if (profile == null) {
_profile = null;
_running = false;
return;
}
public void setData(KeyProfile profile, boolean showIssuer, boolean showProgress) {
_profile = profile;
_progressBar.setVisibility(showProgress ? View.VISIBLE : View.INVISIBLE);
if (showProgress) {
_progressBar.setPeriod(profile.getEntry().getInfo().getPeriod());
}
_profileName.setText(profile.getEntry().getName());
_profileCode.setText(profile.getCode());
_profileIssuer.setText("");
if (showIssuer) {
_profileIssuer.setText(" - " + profile.getEntry().getInfo().getIssuer());
@ -56,6 +52,8 @@ public class KeyProfileHolder extends RecyclerView.ViewHolder {
TextDrawable drawable = profile.getDrawable();
_profileDrawable.setImageDrawable(drawable);
refreshCode();
}
public void startRefreshLoop() {
@ -64,35 +62,29 @@ public class KeyProfileHolder extends RecyclerView.ViewHolder {
}
_running = true;
refreshCode();
refresh();
_uiHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (_running) {
refreshCode();
refresh();
_uiHandler.postDelayed(this, _profile.getEntry().getInfo().getMillisTillNextRotation());
}
}
}, _profile.getEntry().getInfo().getMillisTillNextRotation());
}
public void refreshCode() {
public void stopRefreshLoop() {
_running = false;
}
private void refresh() {
refreshCode();
_progressBar.refresh();
}
private void refreshCode() {
String otp = _profile.refreshCode();
// reset the progress bar
int maxProgress = _progressBar.getMax();
_progressBar.setProgress(maxProgress);
_profileCode.setText(otp.substring(0, otp.length() / 2) + " " + otp.substring(otp.length() / 2));
// calculate the progress the bar should start at
long millisTillRotation = _profile.getEntry().getInfo().getMillisTillNextRotation();
long period = _profile.getEntry().getInfo().getPeriod() * maxProgress;
int currentProgress = maxProgress - (int) ((((double) period - millisTillRotation) / period) * maxProgress);
// start progress animation
ObjectAnimator animation = ObjectAnimator.ofInt(_progressBar, "progress", currentProgress, 0);
animation.setDuration(millisTillRotation);
animation.setInterpolator(new LinearInterpolator());
animation.start();
}
}

View file

@ -1,6 +1,8 @@
package me.impy.aegis.ui.views;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
@ -9,10 +11,8 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.lang.reflect.Array;
import java.util.ArrayList;
import me.impy.aegis.R;
import me.impy.aegis.crypto.KeyInfo;
import me.impy.aegis.db.DatabaseEntry;
import me.impy.aegis.helpers.SimpleItemTouchHelperCallback;
@ -20,6 +20,11 @@ public class KeyProfileView extends Fragment implements KeyProfileAdapter.Listen
private KeyProfileAdapter _adapter;
private Listener _listener;
private PeriodProgressBar _progressBar;
private Handler _uiHandler;
private boolean _running = false;
private boolean _showProgress = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -30,6 +35,11 @@ public class KeyProfileView extends Fragment implements KeyProfileAdapter.Listen
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_keyprofile_view, container, false);
_uiHandler = new Handler();
_progressBar = view.findViewById(R.id.progressBar);
int primaryColorId = getResources().getColor(R.color.colorPrimary);
_progressBar.getProgressDrawable().setColorFilter(primaryColorId, PorterDuff.Mode.SRC_IN);
// set up the recycler view
RecyclerView rvKeyProfiles = view.findViewById(R.id.rvKeyProfiles);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(view.getContext());
@ -42,6 +52,53 @@ public class KeyProfileView extends Fragment implements KeyProfileAdapter.Listen
return view;
}
public void refresh() {
if (_showProgress) {
_progressBar.refresh();
}
_adapter.notifyDataSetChanged();
}
private void checkPeriodUniformity() {
boolean uniform = _adapter.isPeriodUniform();
if (uniform == _showProgress) {
return;
}
_showProgress = uniform;
if (_showProgress) {
_progressBar.setVisibility(View.VISIBLE);
_progressBar.setPeriod(_adapter.getUniformPeriod());
startRefreshLoop();
} else {
_progressBar.setVisibility(View.INVISIBLE);
stopRefreshLoop();
}
}
public void startRefreshLoop() {
if (_running) {
return;
}
_running = true;
refresh();
_uiHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (_running) {
refresh();
_uiHandler.postDelayed(this, KeyInfo.getMillisTillNextRotation(_adapter.getUniformPeriod()));
}
}
}, KeyInfo.getMillisTillNextRotation(_adapter.getUniformPeriod()));
}
private void stopRefreshLoop() {
refresh();
_running = false;
}
public void setListener(Listener listener) {
_listener = listener;
}
@ -71,34 +128,24 @@ public class KeyProfileView extends Fragment implements KeyProfileAdapter.Listen
_adapter.notifyDataSetChanged();
}
public boolean allSamePeriod()
{
return _adapter.allSamePeriod();
}
public KeyProfile getKeyProfile(int index)
{
return _adapter.getKeys().get(index);
}
public void addKey(KeyProfile profile) {
_adapter.addKey(profile);
checkPeriodUniformity();
}
public void removeKey(KeyProfile profile) {
_adapter.removeKey(profile);
checkPeriodUniformity();
}
public void clearKeys() {
_adapter.clearKeys();
checkPeriodUniformity();
}
public void replaceKey(KeyProfile profile) {
_adapter.replaceKey(profile);
}
public void refresh() {
_adapter.refresh();
checkPeriodUniformity();
}
public interface Listener {

View file

@ -0,0 +1,53 @@
package me.impy.aegis.ui.views;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.animation.LinearInterpolator;
import android.widget.ProgressBar;
import me.impy.aegis.crypto.KeyInfo;
public class PeriodProgressBar extends ProgressBar {
private int _period;
public PeriodProgressBar(Context context) {
super(context);
}
public PeriodProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PeriodProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public PeriodProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void setPeriod(int period) {
_period = period;
}
public void refresh() {
// reset the progress bar
int maxProgress = getMax();
setProgress(maxProgress);
// calculate the progress the bar should start at
long millisTillRotation = KeyInfo.getMillisTillNextRotation(_period);
long period = _period * maxProgress;
int currentProgress = maxProgress - (int) ((((double) period - millisTillRotation) / period) * maxProgress);
// start progress animation
ObjectAnimator animation = ObjectAnimator.ofInt(this, "progress", currentProgress, 0);
animation.setDuration(millisTillRotation);
animation.setInterpolator(new LinearInterpolator());
animation.start();
}
}

View file

@ -15,23 +15,6 @@
android:layout_width="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<LinearLayout
android:orientation="horizontal"
android:padding="0dp"
android:layout_margin="0dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="4dp"
android:id="@+id/progressBar"
android:max="1000"
android:layout_weight="1"/>
</LinearLayout>
<!-- note: the fab should always be the last element to be sure it's displayed on top -->
<com.getbase.floatingactionbutton.FloatingActionsMenu
android:id="@+id/fab"

View file

@ -104,12 +104,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
<me.impy.aegis.ui.views.PeriodProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="4dp"
android:id="@+id/progressBar"
android:visibility="invisible"
android:max="1000"
android:layout_weight="1"/>
</LinearLayout>

View file

@ -3,10 +3,20 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/background">
android:background="?attr/background"
android:orientation="vertical">
<me.impy.aegis.ui.views.PeriodProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="4dp"
android:id="@+id/progressBar"
android:max="1000"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="0dp"
android:scrollbars="vertical"
android:id="@+id/rvKeyProfiles"/>
android:id="@+id/rvKeyProfiles"
android:layout_weight="1"/>
</LinearLayout>