Use fastscroll library
This commit is contained in:
@@ -23,7 +23,6 @@ dependencies {
|
||||
compile 'org.commonjava.googlecode.markdown4j:markdown4j:2.2-cj-1.0'
|
||||
compile 'org.ocpsoft.prettytime:prettytime:4.0.1.Final'
|
||||
compile 'com.splitwise:tokenautocomplete:2.0.8@aar'
|
||||
compile 'se.emilsjolander:stickylistheaders:2.7.0'
|
||||
compile 'org.sufficientlysecure:html-textview:2.0'
|
||||
compile 'org.sufficientlysecure:donations:2.4'
|
||||
compile 'com.nispok:snackbar:2.11.0'
|
||||
@@ -33,7 +32,10 @@ dependencies {
|
||||
compile 'org.apache.james:apache-mime4j-dom:0.8.0'
|
||||
compile 'org.thoughtcrime.ssl.pinning:AndroidPinning:1.0.0'
|
||||
compile 'com.cocosw:bottomsheet:1.3.0@aar'
|
||||
|
||||
compile 'se.emilsjolander:stickylistheaders:2.7.0'
|
||||
compile 'com.tonicartos:superslim:0.4.13'
|
||||
compile 'com.futuremind.recyclerfastscroll:fastscroll:0.2.4'
|
||||
|
||||
// Material Drawer
|
||||
compile 'com.mikepenz:materialdrawer:5.6.0@aar'
|
||||
@@ -102,7 +104,6 @@ dependencyVerification {
|
||||
'org.commonjava.googlecode.markdown4j:markdown4j:e952e825d29e1317d96f79f346bfb6786c7c5eef50bd26e54a80823704b62e13',
|
||||
'org.ocpsoft.prettytime:prettytime:ef7098d973ae78b57d1a22dc37d3b8a771bf030301300e24055d676b6cdc5e75',
|
||||
'com.splitwise:tokenautocomplete:f921f83ee26b5265f719b312c30452ef8e219557826c5ce5bf02e29647967939',
|
||||
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
|
||||
'org.sufficientlysecure:html-textview:302c449167f9573313e5293ccab689010e028e4d09aee2ccc2682b3211227ce7',
|
||||
'org.sufficientlysecure:donations:96f8197bab26dfe41900d824f10f8f1914519cd62eedb77bdac5b223eccdf0a6',
|
||||
'com.nispok:snackbar:46b5eb9d630d329e13c2ce00ee9fb115ffb66c23c72cff32ee97eedd76824c6f',
|
||||
@@ -112,6 +113,9 @@ dependencyVerification {
|
||||
'org.apache.james:apache-mime4j-dom:e18717fe6d36f32e5c5f7cbeea1a9bf04645fdabc84e7e8374d9da10fd52e78d',
|
||||
'org.thoughtcrime.ssl.pinning:AndroidPinning:afa1d74e699257fa75cb109ff29bac50726ef269c6e306bdeffe8223cee06ef4',
|
||||
'com.cocosw:bottomsheet:4af6112a7f4cad4e2b70e5fdf1edc39f51275523a0f53011a012837dc103e597',
|
||||
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
|
||||
'com.tonicartos:superslim:ca89b5c674660cc6918a8f8fd385065bffeee27983e0d33c7c2f0ad7b34d2d49',
|
||||
'com.futuremind.recyclerfastscroll:fastscroll:ae655201885a9dbb5fabecb4adfefbb23ffdbca26a2b4ea255ec1bf6f214c606',
|
||||
'com.mikepenz:materialdrawer:8bba1428dcef5ad7c2decf49c612ad980b38e2f1031cbd66c152a8a104793929',
|
||||
'com.mikepenz:fastadapter:21d4ecb5c128bcda37b14e7998d799ed52cfc768b72cdf3d5578bb6775769ebd',
|
||||
'com.mikepenz:materialize:942ccf5e2aa1a46803aa884e8dc7bbaf2a9e8e9996a0cf92e3fe2f44a8592ba4',
|
||||
@@ -120,14 +124,14 @@ dependencyVerification {
|
||||
'com.mikepenz:fontawesome-typeface:ee47b7fe97b90412f01f2fcdd78f65a4edb0ab00006f5ef59ed00516baca9309',
|
||||
'com.mikepenz:community-material-typeface:d6035d261c5eba880cd7fe5dcb8cc00b09bfe6d41063b881b759e9897dc7b7c9',
|
||||
'com.fidesmo:nordpol-android:56f43fe2b1676817bcb4085926de14a08282ef6729c855c198d81aec62b20d65',
|
||||
// 'OpenKeychain:openpgp-api-lib:43d7e67e8ae19ae46e228393a7c4f5861da64db47da2fbb398817bde774669f7',
|
||||
// 'OpenKeychain:openkeychain-api-lib:d2e66ce4828c47cb6081cfb8e7352681cc5d337404aec87e156cbc5a6e732587',
|
||||
// 'OpenKeychain.extern.bouncycastle:core:20bd3036f93758c5ed937fc172b5e7e8d82d071e7b435bd9b6fa3869d5788095',
|
||||
// 'OpenKeychain.extern.bouncycastle:pg:97b7318ee208b8fe552425aac9ffdcc8723032a78784ecc82c999ee09161e2e8',
|
||||
// 'OpenKeychain.extern.bouncycastle:prov:76a8d07e88a557f91fad5c01f1f827085bde12ee924fa4d186a65d80e39d42a2',
|
||||
// 'OpenKeychain.extern:minidns:8183e688b754b9e64ea498b735890a3ece9af1e240d949b804bf7b12a0d5b830',
|
||||
// 'OpenKeychain:KeybaseLib:a870229a22779dfe433d6e48970822b0dfcd351c3cc885cfb94816d064c10fb0',
|
||||
// 'OpenKeychain:safeslinger-exchange:2cbff71ec5d59c824dd244042539cfc5cfbf450ab813c95b9dc83fbb50401ba9',
|
||||
// 'OpenKeychain:openpgp-api-lib:8ee931094b4c596fce55907b226616b0adae614b2877a0e530f726898bf63259',
|
||||
// 'OpenKeychain:openkeychain-api-lib:a61e822cca9f7b34ea7750532ecd3bad7e05e6872bf218583f2a25d98c8b3c68',
|
||||
// 'OpenKeychain.extern.bouncycastle:core:72c07a72f304b9ff96bc4027861df5adbfbeb5dfccc740198c1d5de393980d8b',
|
||||
// 'OpenKeychain.extern.bouncycastle:pg:f61645e289fdbcc38b24dc2c5e9186eb9460d3eb76b7607e2dd68ed3f2115202',
|
||||
// 'OpenKeychain.extern.bouncycastle:prov:2dc9e69d1a2a91096716af024b02d1e29af19243127eae71f00a957be52d7f69',
|
||||
// 'OpenKeychain.extern:minidns:5349807fe5b2134862ad05cadc8be3fd3fb7aa55c2b129d7ba8f4904faf3333b',
|
||||
// 'OpenKeychain:KeybaseLib:75c70462e244d99c647da6638dea4b790455fb9f539574398ea9da7571f5ee8f',
|
||||
// 'OpenKeychain:safeslinger-exchange:be515e3012549b07bfdf779a262d1f8bb335a98c35c059db6563c1d0b58bde75',
|
||||
// 'com.android.databinding:library:def2976cb30dd5abf9f3a35d70c70cfb5485af4fb4ae022f5b9a6e2f8cff6386',
|
||||
// 'com.android.databinding:baseLibrary:47cb0d2d4d1aae4af3f860c31540493332a26278c016bbae90d22fdde3b0b83d',
|
||||
// 'com.android.databinding:adapters:0dd06349dad760f3cb56769f8e9f46451634be6a8a1bfdb2e88a5ca10afcebd6',
|
||||
@@ -141,7 +145,6 @@ dependencyVerification {
|
||||
'com.android.support:transition:331d4152f878442b7bf92c4320335ec7f707d1f6248da2fb3667be436dd508d1',
|
||||
'com.squareup.okio:okio:114bdc1f47338a68bcbc95abf2f5cdc72beeec91812f2fcd7b521c1937876266',
|
||||
'com.fidesmo:nordpol-core:3de58e850a00bba5b4d3a604d1399bcd89f695ea191ec0b03a57222e18062d15',
|
||||
'com.tonicartos:superslim:ca89b5c674660cc6918a8f8fd385065bffeee27983e0d33c7c2f0ad7b34d2d49',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ViewAnimator;
|
||||
|
||||
import com.futuremind.recyclerviewfastscroll.FastScroller;
|
||||
import com.getbase.floatingactionbutton.FloatingActionButton;
|
||||
import com.getbase.floatingactionbutton.FloatingActionsMenu;
|
||||
import com.tonicartos.superslim.LayoutManager;
|
||||
@@ -268,6 +269,9 @@ public class KeyListFragment extends RecyclerFragment<KeySectionedListAdapter>
|
||||
setAdapter(adapter);
|
||||
setLayoutManager(new LayoutManager(getActivity()));
|
||||
|
||||
FastScroller fastScroller = (FastScroller) getActivity().findViewById(R.id.fastscroll);
|
||||
fastScroller.setRecyclerView(getRecyclerView());
|
||||
|
||||
// Prepare the loader. Either re-connect with an existing one,
|
||||
// or start a new one.
|
||||
getLoaderManager().initLoader(0, null, this);
|
||||
|
||||
@@ -15,6 +15,8 @@ import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.futuremind.recyclerviewfastscroll.SectionTitleProvider;
|
||||
|
||||
import org.openintents.openpgp.util.OpenPgpUtils;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
@@ -28,9 +30,10 @@ import org.sufficientlysecure.keychain.util.Log;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class KeySectionedListAdapter extends SectionCursorAdapter<KeySectionedListAdapter.KeyListCursor, Character,
|
||||
SectionCursorAdapter.ViewHolder, KeySectionedListAdapter.KeyHeaderViewHolder> {
|
||||
SectionCursorAdapter.ViewHolder, KeySectionedListAdapter.KeyHeaderViewHolder> implements SectionTitleProvider {
|
||||
|
||||
private static final short VIEW_ITEM_TYPE_KEY = 0x0;
|
||||
private static final short VIEW_ITEM_TYPE_DUMMY = 0x1;
|
||||
@@ -61,7 +64,7 @@ public class KeySectionedListAdapter extends SectionCursorAdapter<KeySectionedLi
|
||||
mHasDummy = false;
|
||||
mSelected.clear();
|
||||
|
||||
if(mListener != null) {
|
||||
if (mListener != null) {
|
||||
mListener.onSelectionStateChanged(0);
|
||||
}
|
||||
|
||||
@@ -116,9 +119,9 @@ public class KeySectionedListAdapter extends SectionCursorAdapter<KeySectionedLi
|
||||
|
||||
public long[] getSelectedMasterKeyIds() {
|
||||
long[] keys = new long[mSelected.size()];
|
||||
for(int i = 0; i < keys.length; i++) {
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
int index = getCursorPositionWithoutSections(mSelected.get(i));
|
||||
if(!moveCursor(index)) {
|
||||
if (!moveCursor(index)) {
|
||||
return keys;
|
||||
}
|
||||
|
||||
@@ -129,13 +132,13 @@ public class KeySectionedListAdapter extends SectionCursorAdapter<KeySectionedLi
|
||||
}
|
||||
|
||||
public boolean isAnySecretKeySelected() {
|
||||
for(int i = 0; i < mSelected.size(); i++) {
|
||||
for (int i = 0; i < mSelected.size(); i++) {
|
||||
int index = getCursorPositionWithoutSections(mSelected.get(i));
|
||||
if(!moveCursor(index)) {
|
||||
if (!moveCursor(index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(getCursor().isSecret()) {
|
||||
if (getCursor().isSecret()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -146,6 +149,7 @@ public class KeySectionedListAdapter extends SectionCursorAdapter<KeySectionedLi
|
||||
|
||||
/**
|
||||
* Returns the number of database entries displayed.
|
||||
*
|
||||
* @return The item count
|
||||
*/
|
||||
public int getCount() {
|
||||
@@ -171,7 +175,7 @@ public class KeySectionedListAdapter extends SectionCursorAdapter<KeySectionedLi
|
||||
return '#';
|
||||
} else {
|
||||
String userId = cursor.getRawUserId();
|
||||
if(TextUtils.isEmpty(userId)) {
|
||||
if (TextUtils.isEmpty(userId)) {
|
||||
return '?';
|
||||
} else {
|
||||
return Character.toUpperCase(userId.charAt(0));
|
||||
@@ -273,13 +277,40 @@ public class KeySectionedListAdapter extends SectionCursorAdapter<KeySectionedLi
|
||||
|
||||
mSelected.clear();
|
||||
|
||||
for(int i = 0; i < selected.length; i++) {
|
||||
notifyItemChanged(selected[i]);
|
||||
for (Integer aSelected : selected) {
|
||||
notifyItemChanged(aSelected);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSectionTitle(int position) {
|
||||
// this String will be shown in a bubble for specified position
|
||||
if (moveCursor(getCursorPositionWithoutSections(position))) {
|
||||
KeyListCursor cursor = getCursor();
|
||||
|
||||
if (cursor.isSecret()) {
|
||||
if (cursor.getKeyId() == 0L) {
|
||||
mHasDummy = true;
|
||||
}
|
||||
|
||||
return "My";
|
||||
} else {
|
||||
String userId = cursor.getRawUserId();
|
||||
if (TextUtils.isEmpty(userId)) {
|
||||
return null;
|
||||
} else {
|
||||
return userId.substring(0, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(Constants.TAG, "Unable to determine section title. "
|
||||
+ "Reason: Could not move cursor over dataset.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class KeyDummyViewHolder extends SectionCursorAdapter.ViewHolder
|
||||
implements View.OnClickListener{
|
||||
implements View.OnClickListener {
|
||||
|
||||
KeyDummyViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
@@ -291,7 +322,7 @@ public class KeySectionedListAdapter extends SectionCursorAdapter<KeySectionedLi
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if(mListener != null) {
|
||||
if (mListener != null) {
|
||||
mListener.onKeyDummyItemClicked();
|
||||
}
|
||||
}
|
||||
@@ -546,8 +577,11 @@ public class KeySectionedListAdapter extends SectionCursorAdapter<KeySectionedLi
|
||||
|
||||
public interface KeyListListener {
|
||||
void onKeyDummyItemClicked();
|
||||
|
||||
void onKeyItemClicked(long masterKeyId);
|
||||
|
||||
void onSlingerButtonClicked(long masterKeyId);
|
||||
|
||||
void onSelectionStateChanged(int selectedCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
package org.sufficientlysecure.keychain.ui.util.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.v4.util.SparseArrayCompat;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.tonicartos.superslim.LayoutManager;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
/**
|
||||
* @param <T> section type.
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
package org.sufficientlysecure.keychain.ui.util.recyclerview.fastscroll;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.StaggeredGridLayoutManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.tonicartos.superslim.LayoutManager;
|
||||
|
||||
public class FastScrollRecyclerView extends RecyclerView implements RecyclerView.OnItemTouchListener {
|
||||
private FastScroller mFastScroller;
|
||||
|
||||
private int mLastX;
|
||||
private int mLastY;
|
||||
|
||||
public FastScrollRecyclerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public FastScrollRecyclerView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public FastScrollRecyclerView(Context context, AttributeSet attributeSet, int defStyleAttr) {
|
||||
super(context, attributeSet, defStyleAttr);
|
||||
mFastScroller = new FastScroller(this, attributeSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
addOnItemTouchListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
mFastScroller.draw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolled(int x, int y) {
|
||||
super.onScrolled(x, y);
|
||||
mFastScroller.updateThumb(
|
||||
computeVerticalScrollOffset(),
|
||||
computeVerticalScrollExtent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
mFastScroller.updateContainer(top, right, bottom);
|
||||
mFastScroller.updateThumb(
|
||||
computeVerticalScrollOffset(),
|
||||
computeVerticalScrollExtent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrollStateChanged(int state) {
|
||||
switch (state) {
|
||||
case SCROLL_STATE_IDLE:
|
||||
mFastScroller.hideBar();
|
||||
break;
|
||||
case SCROLL_STATE_DRAGGING:
|
||||
mFastScroller.showBar();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
|
||||
if(mFastScroller.onInterceptTouchEvent(e)) {
|
||||
onTouchEvent(rv, e);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTouchEvent(RecyclerView rv, MotionEvent event) {
|
||||
int x = (int) event.getX();
|
||||
int y = (int) event.getY();
|
||||
|
||||
mFastScroller.handleTouchEvent(event.getAction(), x, y, mLastX, mLastY);
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
|
||||
}
|
||||
|
||||
private int getItemCount() {
|
||||
return getAdapter() != null ?
|
||||
getAdapter().getItemCount() : 0;
|
||||
}
|
||||
|
||||
public void scrollToFraction(float fraction) {
|
||||
int count = getItemCount();
|
||||
if (count > 0) {
|
||||
stopScroll();
|
||||
scrollToPosition((int) ((count - 1) * fraction));
|
||||
}
|
||||
}
|
||||
|
||||
public void scrollByFraction(float fraction) {
|
||||
int count = getItemCount();
|
||||
if (count > 0) {
|
||||
stopScroll();
|
||||
|
||||
int pixelsToScroll = (int) (computeVerticalScrollRange() * fraction);
|
||||
scrollBy(0, pixelsToScroll);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,268 +0,0 @@
|
||||
package org.sufficientlysecure.keychain.ui.util.recyclerview.fastscroll;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.support.v4.view.animation.FastOutLinearInInterpolator;
|
||||
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
|
||||
|
||||
public class FastScroller {
|
||||
private static final int DEFAULT_AUTO_HIDE_DELAY = 1500;
|
||||
private static final boolean DEFAULT_AUTO_HIDE_ENABLED = true;
|
||||
|
||||
private Paint mTrack;
|
||||
private Paint mThumb;
|
||||
|
||||
private int mPosX;
|
||||
private int mPosY;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
|
||||
private Rect mContainer;
|
||||
private boolean mIsDragging;
|
||||
|
||||
private int mAutoHideDelay;
|
||||
private boolean mAutoHideEnabled;
|
||||
|
||||
private final int mTrackColorNormal;
|
||||
private final int mTrackColorDragging;
|
||||
|
||||
private final int mThumbColorNormal;
|
||||
private final int mThumbColorDragging;
|
||||
|
||||
private ValueAnimator mBarAnimator;
|
||||
private final FastScrollRecyclerView mRecyclerView;
|
||||
|
||||
private final int mTouchSlop;
|
||||
private final int mTouchInset;
|
||||
private final int[] mKeyFrames;
|
||||
|
||||
//private final Runnable mHideRunnable;
|
||||
|
||||
public FastScroller(final FastScrollRecyclerView recyclerView, AttributeSet attributeSet) {
|
||||
Context context = recyclerView.getContext();
|
||||
mRecyclerView = recyclerView;
|
||||
|
||||
mTrack = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mThumb = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
mKeyFrames = new int[2];
|
||||
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
mTouchInset = FormattingUtils.dpToPx(context, 8);
|
||||
|
||||
TypedArray typedArray = context.getTheme().obtainStyledAttributes(
|
||||
attributeSet, R.styleable.FastScroller, 0, 0);
|
||||
|
||||
try {
|
||||
mWidth = typedArray.getDimensionPixelSize(
|
||||
R.styleable.FastScroller_fastScrollScrollBarWidth, FormattingUtils.dpToPx(context, 6));
|
||||
|
||||
mAutoHideDelay = typedArray.getInteger(
|
||||
R.styleable.FastScroller_fastScrollAutoHideDelay, DEFAULT_AUTO_HIDE_DELAY);
|
||||
mAutoHideEnabled = typedArray.getBoolean(
|
||||
R.styleable.FastScroller_fastScrollAutoHideEnabled, DEFAULT_AUTO_HIDE_ENABLED);
|
||||
|
||||
mTrackColorNormal = typedArray.getColor(
|
||||
R.styleable.FastScroller_fastScrollTrackColorNormal, Color.LTGRAY);
|
||||
mTrackColorDragging = typedArray.getColor(
|
||||
R.styleable.FastScroller_fastScrollTrackColorDragging, Color.GRAY);
|
||||
|
||||
mThumbColorNormal = typedArray.getColor(
|
||||
R.styleable.FastScroller_fastScrollThumbColorNormal, Color.GRAY);
|
||||
mThumbColorDragging = typedArray.getColor(
|
||||
R.styleable.FastScroller_fastScrollThumbColorDragging, Color.BLUE);
|
||||
|
||||
mTrack.setColor(mTrackColorNormal);
|
||||
mThumb.setColor(mThumbColorNormal);
|
||||
} finally {
|
||||
typedArray.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
public void hideBar() {
|
||||
if(mPosX >= mWidth || !mAutoHideEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
mKeyFrames[0] = mPosX;
|
||||
mKeyFrames[1] = mWidth;
|
||||
|
||||
prepareAnimator();
|
||||
mBarAnimator.setIntValues(mKeyFrames);
|
||||
mBarAnimator.setStartDelay(mAutoHideDelay);
|
||||
mBarAnimator.setInterpolator(new FastOutLinearInInterpolator());
|
||||
mBarAnimator.start();
|
||||
}
|
||||
|
||||
public void showBar() {
|
||||
if(mPosX < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
mKeyFrames[0] = mPosX;
|
||||
mKeyFrames[1] = 0;
|
||||
|
||||
prepareAnimator();
|
||||
mBarAnimator.setStartDelay(0);
|
||||
mBarAnimator.setIntValues(mKeyFrames);
|
||||
mBarAnimator.setInterpolator(new FastOutSlowInInterpolator());
|
||||
mBarAnimator.start();
|
||||
}
|
||||
|
||||
public boolean isAnimatingShow() {
|
||||
return mKeyFrames[1] == 0 && mBarAnimator.isStarted();
|
||||
}
|
||||
|
||||
public boolean isAnimatingHide() {
|
||||
return mKeyFrames[1] == mWidth && mBarAnimator.isStarted();
|
||||
}
|
||||
|
||||
public boolean isBarFullyShown() {
|
||||
return mPosX < 1;
|
||||
}
|
||||
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
return mContainer != null
|
||||
&& (event.getX() < mContainer.right)
|
||||
&& (event.getX() > mContainer.left - mTouchInset)
|
||||
&& (event.getY() < mContainer.bottom)
|
||||
&& (event.getY() > mContainer.top);
|
||||
}
|
||||
|
||||
private boolean isInThumb(int x, int y) {
|
||||
return x > (mContainer.left + mPosX - mTouchInset)
|
||||
&& x < (mContainer.right + mTouchInset)
|
||||
&& y > (mContainer.top + mPosY - mTouchInset)
|
||||
&& y < (mContainer.top + mPosY + mHeight + mTouchInset);
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas) {
|
||||
if(mPosX < 0 || mPosX >= mWidth) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mRecyclerView.canScrollVertically(-1)
|
||||
&& ! mRecyclerView.canScrollVertically(1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int topBound = mContainer.top + mPosY;
|
||||
int leftBound = mContainer.left + mPosX;
|
||||
|
||||
canvas.drawRect(leftBound, mContainer.top, mContainer.right, mContainer.bottom, mTrack);
|
||||
canvas.drawRect(leftBound, topBound, mContainer.right, topBound + mHeight, mThumb);
|
||||
}
|
||||
|
||||
public void updateThumb(int offset, int extent) {
|
||||
mPosY = offset;
|
||||
mHeight = extent;
|
||||
}
|
||||
|
||||
public void updateContainer(int top, int right, int bottom) {
|
||||
mPosX = 0;
|
||||
mContainer = new Rect(right - mWidth, top, right, bottom);
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private void invalidate() {
|
||||
mRecyclerView.invalidate(mContainer);
|
||||
}
|
||||
|
||||
private void prepareAnimator() {
|
||||
if (mBarAnimator != null) {
|
||||
mBarAnimator.cancel();
|
||||
} else {
|
||||
mBarAnimator = new ValueAnimator();
|
||||
mBarAnimator.setDuration(150);
|
||||
mBarAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mPosX = (Integer) animation.getAnimatedValue();
|
||||
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void handleTouchEvent(int action, int x, int y, int lastX, int lastY) {
|
||||
if(!mRecyclerView.canScrollVertically(-1)
|
||||
&& ! mRecyclerView.canScrollVertically(1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if(isBarFullyShown()) { //
|
||||
prepareAnimator(); // cancel any pending animations
|
||||
|
||||
mTrack.setColor(mTrackColorDragging);
|
||||
mThumb.setColor(mThumbColorDragging);
|
||||
|
||||
if(!isInThumb(x, y)) {
|
||||
// jump to point
|
||||
mPosY = Math.min(
|
||||
Math.max(mContainer.top, y - (mHeight / 2)),
|
||||
mContainer.bottom - mHeight
|
||||
);
|
||||
|
||||
float range = (mContainer.bottom - mContainer.top) - mHeight;
|
||||
mRecyclerView.scrollToFraction(mPosY / range);
|
||||
} else {
|
||||
invalidate();
|
||||
}
|
||||
} else {
|
||||
if(!isAnimatingShow()) {
|
||||
showBar();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if((!mIsDragging
|
||||
&& isInThumb(x, y)
|
||||
&& Math.abs(y - lastY) > mTouchSlop)
|
||||
|| mIsDragging) {
|
||||
|
||||
if(!mIsDragging) {
|
||||
mIsDragging = true;
|
||||
}
|
||||
|
||||
float dist = y - lastY;
|
||||
float range = (mContainer.bottom - mContainer.top) - mHeight;
|
||||
|
||||
if(mRecyclerView.canScrollVertically(dist < 0 ? -1 : 1)) {
|
||||
mRecyclerView.scrollByFraction(dist / range);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if(mIsDragging) {
|
||||
mIsDragging = false;
|
||||
}
|
||||
|
||||
mTrack.setColor(mTrackColorNormal);
|
||||
mThumb.setColor(mThumbColorNormal);
|
||||
|
||||
if(!mBarAnimator.isRunning()
|
||||
&& mRecyclerView.getScrollState()
|
||||
== RecyclerView.SCROLL_STATE_IDLE) {
|
||||
hideBar();
|
||||
invalidate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:fab="http://schemas.android.com/apk/res-auto"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:fab="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:custom="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@@ -10,10 +10,10 @@
|
||||
|
||||
<LinearLayout
|
||||
android:id="@android:id/progress"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center">
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ProgressBar
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@android:id/widget_frame"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone">
|
||||
|
||||
<!--rebuild functionality of ListFragment -->
|
||||
@@ -34,27 +34,37 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.sufficientlysecure.keychain.ui.util.recyclerview.fastscroll.FastScrollRecyclerView
|
||||
android:id="@android:id/list"
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingRight="32dp"
|
||||
android:paddingEnd="32dp"
|
||||
android:paddingBottom="72dp"
|
||||
android:clipToPadding="false"
|
||||
custom:fastScrollScrollBarWidth="8dp"
|
||||
custom:fastScrollThumbColorNormal="@color/selected_gray"
|
||||
custom:fastScrollThumbColorDragging="@color/accent" />
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="32dp"
|
||||
android:paddingStart="16dp" />
|
||||
|
||||
<com.futuremind.recyclerviewfastscroll.FastScroller
|
||||
android:id="@+id/fastscroll"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentRight="true"
|
||||
android:orientation="vertical"
|
||||
app:fastscroll__bubbleColor="@color/primary"
|
||||
app:fastscroll__handleColor="@color/md_white_1000" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@android:id/empty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="240dp"
|
||||
android:animateLayoutChanges="true"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:animateLayoutChanges="true" >
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
@@ -64,25 +74,25 @@
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
|
||||
android:id="@+id/search_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/search_container"
|
||||
android:inAnimation="@anim/fade_in_delayed"
|
||||
android:outAnimation="@anim/fade_out"
|
||||
android:measureAllChildren="true"
|
||||
custom:initialView="1">
|
||||
android:outAnimation="@anim/fade_out"
|
||||
app:initialView="1">
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/search_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:id="@+id/search_button"
|
||||
android:gravity="center"
|
||||
tools:text="@string/btn_search_for_query"/>
|
||||
tools:text="@string/btn_search_for_query" />
|
||||
|
||||
</org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
|
||||
|
||||
@@ -93,48 +103,48 @@
|
||||
android:id="@+id/fab_main"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
fab:fab_addButtonColorNormal="?attr/colorPrimary"
|
||||
fab:fab_addButtonColorPressed="?attr/colorPrimaryDark"
|
||||
fab:fab_addButtonSize="normal"
|
||||
fab:fab_addButtonPlusIconColor="@color/icons"
|
||||
fab:fab_addButtonSize="normal"
|
||||
fab:fab_expandDirection="up"
|
||||
fab:fab_labelStyle="@style/FabMenuStyle"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginEnd="16dp">
|
||||
fab:fab_labelStyle="@style/FabMenuStyle">
|
||||
|
||||
<com.getbase.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_add_qr_code"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
fab:fab_icon="@drawable/ic_qrcode_white_24dp"
|
||||
fab:fab_colorNormal="?attr/colorPrimary"
|
||||
fab:fab_colorPressed="?attr/colorPrimaryDark"
|
||||
fab:fab_title="@string/key_list_fab_qr_code"
|
||||
fab:fab_size="mini" />
|
||||
fab:fab_icon="@drawable/ic_qrcode_white_24dp"
|
||||
fab:fab_size="mini"
|
||||
fab:fab_title="@string/key_list_fab_qr_code" />
|
||||
|
||||
<com.getbase.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_add_cloud"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
fab:fab_icon="@drawable/ic_cloud_search_24dp"
|
||||
fab:fab_colorNormal="?attr/colorPrimary"
|
||||
fab:fab_colorPressed="?attr/colorPrimaryDark"
|
||||
fab:fab_title="@string/key_list_fab_search"
|
||||
fab:fab_size="mini" />
|
||||
fab:fab_icon="@drawable/ic_cloud_search_24dp"
|
||||
fab:fab_size="mini"
|
||||
fab:fab_title="@string/key_list_fab_search" />
|
||||
|
||||
<com.getbase.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_add_file"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
fab:fab_icon="@drawable/ic_folder_white_24dp"
|
||||
fab:fab_colorNormal="?attr/colorPrimary"
|
||||
fab:fab_colorPressed="?attr/colorPrimaryDark"
|
||||
fab:fab_title="@string/key_list_fab_import"
|
||||
fab:fab_size="mini" />
|
||||
fab:fab_icon="@drawable/ic_folder_white_24dp"
|
||||
fab:fab_size="mini"
|
||||
fab:fab_title="@string/key_list_fab_import" />
|
||||
|
||||
</com.getbase.floatingactionbutton.FloatingActionsMenu>
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -28,14 +28,4 @@
|
||||
<attr name="prefix" format="string" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="FastScroller">
|
||||
<attr name="fastScrollScrollBarWidth" format="dimension"/>
|
||||
<attr name="fastScrollAutoHideEnabled" format="boolean" />
|
||||
<attr name="fastScrollAutoHideDelay" format="integer" />
|
||||
<attr name="fastScrollThumbColorNormal" format="color" />
|
||||
<attr name="fastScrollTrackColorNormal" format="color" />
|
||||
<attr name="fastScrollThumbColorDragging" format="color" />
|
||||
<attr name="fastScrollTrackColorDragging" format="color" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
Reference in New Issue
Block a user