summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Henneke <FabianHenneke@users.noreply.github.com>2020-04-29 08:53:27 +0200
committerGitHub <noreply@github.com>2020-04-29 08:53:27 +0200
commitc41100eff984a3e05f6c51e004c8b69975425db7 (patch)
tree4c281c5e653dcb5aa6dcb2b503f15045f04dd788
parentedc6dcda88a46cb3cd963d89145f48fb1ef0a189 (diff)
Use official FastScroll fix and refactor PasswordFragment (#753)
-rw-r--r--app/src/main/java/androidx/recyclerview/widget/FixOnItemTouchDispatchRecyclerView.java341
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt17
-rw-r--r--app/src/main/res/layout/password_recycler_view.xml2
-rw-r--r--dependencies.gradle2
4 files changed, 8 insertions, 354 deletions
diff --git a/app/src/main/java/androidx/recyclerview/widget/FixOnItemTouchDispatchRecyclerView.java b/app/src/main/java/androidx/recyclerview/widget/FixOnItemTouchDispatchRecyclerView.java
deleted file mode 100644
index 58590a66..00000000
--- a/app/src/main/java/androidx/recyclerview/widget/FixOnItemTouchDispatchRecyclerView.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright 2020 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.recyclerview.widget;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-
-import androidx.annotation.AttrRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import me.zhanghai.android.fastscroll.FastScroller;
-import me.zhanghai.android.fastscroll.PopupTextProvider;
-import me.zhanghai.android.fastscroll.Predicate;
-import me.zhanghai.android.fastscroll.ViewHelperProvider;
-
-public class FixOnItemTouchDispatchRecyclerView extends RecyclerView implements ViewHelperProvider {
-
- @NonNull
- private final ViewHelper mViewHelper = new ViewHelper(this);
-
- @Nullable
- private OnItemTouchListener mPhantomOnItemTouchListener = null;
- private OnItemTouchListener mInterceptingOnItemTouchListener = null;
-
- public FixOnItemTouchDispatchRecyclerView(@NonNull Context context) {
- super(context);
- }
-
- public FixOnItemTouchDispatchRecyclerView(@NonNull Context context,
- @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- public FixOnItemTouchDispatchRecyclerView(@NonNull Context context,
- @Nullable AttributeSet attrs,
- @AttrRes int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @NonNull
- @Override
- public FastScroller.ViewHelper getViewHelper() {
- return mViewHelper;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent e) {
- mInterceptingOnItemTouchListener = null;
- if (findInterceptingOnItemTouchListener(e)) {
- cancelScroll();
- return true;
- }
- return super.onInterceptTouchEvent(e);
- }
-
- @SuppressLint("ClickableViewAccessibility")
- @Override
- public boolean onTouchEvent(MotionEvent e) {
- if (dispatchOnItemTouchListeners(e)) {
- cancelScroll();
- return true;
- }
- return super.onTouchEvent(e);
- }
-
- @Override
- public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
- if (mPhantomOnItemTouchListener != null) {
- mPhantomOnItemTouchListener.onRequestDisallowInterceptTouchEvent(disallowIntercept);
- }
- super.requestDisallowInterceptTouchEvent(disallowIntercept);
- }
-
- private void cancelScroll() {
- MotionEvent syntheticCancel = MotionEvent.obtain(
- 0, 0, MotionEvent.ACTION_CANCEL, 0f, 0f, 0);
- super.onInterceptTouchEvent(syntheticCancel);
- syntheticCancel.recycle();
- }
-
- private boolean dispatchOnItemTouchListeners(@NonNull MotionEvent e) {
- if (mInterceptingOnItemTouchListener == null) {
- if (e.getAction() == MotionEvent.ACTION_DOWN) {
- return false;
- }
- return findInterceptingOnItemTouchListener(e);
- } else {
- mInterceptingOnItemTouchListener.onTouchEvent(this, e);
- final int action = e.getAction();
- if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
- mInterceptingOnItemTouchListener = null;
- }
- return true;
- }
- }
-
- private boolean findInterceptingOnItemTouchListener(@NonNull MotionEvent e) {
- int action = e.getAction();
- if (mPhantomOnItemTouchListener != null
- && mPhantomOnItemTouchListener.onInterceptTouchEvent(this, e)
- && action != MotionEvent.ACTION_CANCEL) {
- mInterceptingOnItemTouchListener = mPhantomOnItemTouchListener;
- return true;
- }
- return false;
- }
-
- private static class RecyclerViewHelper implements FastScroller.ViewHelper {
-
- @NonNull
- private final RecyclerView mView;
-
- @NonNull
- private final Rect mTempRect = new Rect();
-
- public RecyclerViewHelper(@NonNull RecyclerView view) {
- mView = view;
- }
-
- @Override
- public void addOnPreDrawListener(@NonNull Runnable onPreDraw) {
- mView.addItemDecoration(new RecyclerView.ItemDecoration() {
- @Override
- public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent,
- @NonNull RecyclerView.State state) {
- onPreDraw.run();
- }
- });
- }
-
- @Override
- public void addOnScrollChangedListener(@NonNull Runnable onScrollChanged) {
- mView.addOnScrollListener(new RecyclerView.OnScrollListener() {
- @Override
- public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
- onScrollChanged.run();
- }
- });
- }
-
- @Override
- public void addOnTouchEventListener(@NonNull Predicate<MotionEvent> onTouchEvent) {
- mView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
- @Override
- public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView,
- @NonNull MotionEvent event) {
- return onTouchEvent.test(event);
- }
- @Override
- public void onTouchEvent(@NonNull RecyclerView recyclerView,
- @NonNull MotionEvent event) {
- onTouchEvent.test(event);
- }
- });
- }
-
- @Override
- public int getScrollRange() {
- int itemCount = getItemCount();
- if (itemCount == 0) {
- return 0;
- }
- int itemHeight = getItemHeight();
- if (itemHeight == 0) {
- return 0;
- }
- return mView.getPaddingTop() + itemCount * itemHeight + mView.getPaddingBottom();
- }
-
- @Override
- public int getScrollOffset() {
- int firstItemPosition = getFirstItemPosition();
- if (firstItemPosition == RecyclerView.NO_POSITION) {
- return 0;
- }
- int itemHeight = getItemHeight();
- int firstItemTop = getFirstItemOffset();
- return mView.getPaddingTop() + firstItemPosition * itemHeight - firstItemTop;
- }
-
- @Override
- public void scrollTo(int offset) {
- // Stop any scroll in progress for RecyclerView.
- mView.stopScroll();
- offset -= mView.getPaddingTop();
- int itemHeight = getItemHeight();
- // firstItemPosition should be non-negative even if paddingTop is greater than item height.
- int firstItemPosition = Math.max(0, offset / itemHeight);
- int firstItemTop = firstItemPosition * itemHeight - offset;
- scrollToPositionWithOffset(firstItemPosition, firstItemTop);
- }
-
- @Nullable
- @Override
- public String getPopupText() {
- RecyclerView.Adapter<?> adapter = mView.getAdapter();
- if (!(adapter instanceof PopupTextProvider)) {
- return null;
- }
- PopupTextProvider popupTextProvider = (PopupTextProvider) adapter;
- int position = getFirstItemAdapterPosition();
- if (position == RecyclerView.NO_POSITION) {
- return null;
- }
- return popupTextProvider.getPopupText(position);
- }
-
- private int getItemCount() {
- LinearLayoutManager linearLayoutManager = getVerticalLinearLayoutManager();
- if (linearLayoutManager == null) {
- return 0;
- }
- int itemCount = linearLayoutManager.getItemCount();
- if (itemCount == 0) {
- return 0;
- }
- if (linearLayoutManager instanceof GridLayoutManager) {
- GridLayoutManager gridLayoutManager = (GridLayoutManager) linearLayoutManager;
- itemCount = (itemCount - 1) / gridLayoutManager.getSpanCount() + 1;
- }
- return itemCount;
- }
-
- private int getItemHeight() {
- if (mView.getChildCount() == 0) {
- return 0;
- }
- View itemView = mView.getChildAt(0);
- mView.getDecoratedBoundsWithMargins(itemView, mTempRect);
- return mTempRect.height();
- }
-
- private int getFirstItemPosition() {
- int position = getFirstItemAdapterPosition();
- LinearLayoutManager linearLayoutManager = getVerticalLinearLayoutManager();
- if (linearLayoutManager == null) {
- return RecyclerView.NO_POSITION;
- }
- if (linearLayoutManager instanceof GridLayoutManager) {
- GridLayoutManager gridLayoutManager = (GridLayoutManager) linearLayoutManager;
- position /= gridLayoutManager.getSpanCount();
- }
- return position;
- }
-
- private int getFirstItemAdapterPosition() {
- if (mView.getChildCount() == 0) {
- return RecyclerView.NO_POSITION;
- }
- View itemView = mView.getChildAt(0);
- LinearLayoutManager linearLayoutManager = getVerticalLinearLayoutManager();
- if (linearLayoutManager == null) {
- return RecyclerView.NO_POSITION;
- }
- return linearLayoutManager.getPosition(itemView);
- }
-
- private int getFirstItemOffset() {
- if (mView.getChildCount() == 0) {
- return RecyclerView.NO_POSITION;
- }
- View itemView = mView.getChildAt(0);
- mView.getDecoratedBoundsWithMargins(itemView, mTempRect);
- return mTempRect.top;
- }
-
- private void scrollToPositionWithOffset(int position, int offset) {
- LinearLayoutManager linearLayoutManager = getVerticalLinearLayoutManager();
- if (linearLayoutManager == null) {
- return;
- }
- if (linearLayoutManager instanceof GridLayoutManager) {
- GridLayoutManager gridLayoutManager = (GridLayoutManager) linearLayoutManager;
- position *= gridLayoutManager.getSpanCount();
- }
- // LinearLayoutManager actually takes offset from paddingTop instead of top of RecyclerView.
- offset -= mView.getPaddingTop();
- linearLayoutManager.scrollToPositionWithOffset(position, offset);
- }
-
- @Nullable
- private LinearLayoutManager getVerticalLinearLayoutManager() {
- RecyclerView.LayoutManager layoutManager = mView.getLayoutManager();
- if (!(layoutManager instanceof LinearLayoutManager)) {
- return null;
- }
- LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
- if (linearLayoutManager.getOrientation() != RecyclerView.VERTICAL) {
- return null;
- }
- return linearLayoutManager;
- }
- }
-
- private class ViewHelper extends RecyclerViewHelper {
-
- ViewHelper(@NonNull RecyclerView view) {
- super(view);
- }
-
- @Override
- public void addOnTouchEventListener(@NonNull Predicate<MotionEvent> onTouchEvent) {
- mPhantomOnItemTouchListener = new RecyclerView.SimpleOnItemTouchListener() {
- @Override
- public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView,
- @NonNull MotionEvent event) {
- return onTouchEvent.test(event);
- }
-
- @Override
- public void onTouchEvent(@NonNull RecyclerView recyclerView,
- @NonNull MotionEvent event) {
- onTouchEvent.test(event);
- }
- };
- }
- }
-}
diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt
index 1b9d3f9c..ecf1a887 100644
--- a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt
@@ -19,9 +19,7 @@ import androidx.appcompat.view.ActionMode
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.observe
-import androidx.recyclerview.widget.FixOnItemTouchDispatchRecyclerView
import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.google.android.material.snackbar.Snackbar
import com.zeapo.pwdstore.databinding.PasswordRecyclerViewBinding
import com.zeapo.pwdstore.git.BaseGitActivity
@@ -38,9 +36,7 @@ import me.zhanghai.android.fastscroll.FastScrollerBuilder
class PasswordFragment : Fragment() {
private lateinit var recyclerAdapter: PasswordItemRecyclerAdapter
- private lateinit var recyclerView: FixOnItemTouchDispatchRecyclerView
private lateinit var listener: OnFragmentInteractionListener
- private lateinit var swipeRefresher: SwipeRefreshLayout
private var recyclerViewStateToRestore: Parcelable? = null
private var actionMode: ActionMode? = null
@@ -67,8 +63,7 @@ class PasswordFragment : Fragment() {
}
private fun initializePasswordList() {
- swipeRefresher = binding.swipeRefresher
- swipeRefresher.setOnRefreshListener {
+ binding.swipeRefresher.setOnRefreshListener {
if (!PasswordRepository.isGitRepo()) {
Snackbar.make(binding.root, getString(R.string.clone_git_repo), Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.clone_button) {
@@ -77,7 +72,7 @@ class PasswordFragment : Fragment() {
startActivityForResult(intent, BaseGitActivity.REQUEST_CLONE)
}
.show()
- swipeRefresher.isRefreshing = false
+ binding.swipeRefresher.isRefreshing = false
} else {
val intent = Intent(context, GitOperationActivity::class.java)
intent.putExtra(BaseGitActivity.REQUEST_ARG_OP, BaseGitActivity.REQUEST_SYNC)
@@ -92,7 +87,7 @@ class PasswordFragment : Fragment() {
.onSelectionChanged { selection ->
// In order to not interfere with drag selection, we disable the SwipeRefreshLayout
// once an item is selected.
- swipeRefresher.isEnabled = selection.isEmpty
+ binding.swipeRefresher.isEnabled = selection.isEmpty
if (actionMode == null)
actionMode = requireStore().startSupportActionMode(actionModeCallback)
@@ -105,7 +100,7 @@ class PasswordFragment : Fragment() {
actionMode!!.finish()
}
}
- recyclerView = binding.passRecycler
+ val recyclerView = binding.passRecycler
recyclerView.apply {
layoutManager = LinearLayoutManager(requireContext())
itemAnimator = OnOffItemAnimator()
@@ -232,7 +227,7 @@ class PasswordFragment : Fragment() {
requireStore().clearSearch()
model.navigateTo(
item.file,
- recyclerViewState = recyclerView.layoutManager!!.onSaveInstanceState()
+ recyclerViewState = binding.passRecycler.layoutManager!!.onSaveInstanceState()
)
requireStore().supportActionBar?.setDisplayHomeAsUpEnabled(true)
} else {
@@ -250,7 +245,7 @@ class PasswordFragment : Fragment() {
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- swipeRefresher.isRefreshing = false
+ binding.swipeRefresher.isRefreshing = false
}
/**
diff --git a/app/src/main/res/layout/password_recycler_view.xml b/app/src/main/res/layout/password_recycler_view.xml
index ca2b6550..05707f04 100644
--- a/app/src/main/res/layout/password_recycler_view.xml
+++ b/app/src/main/res/layout/password_recycler_view.xml
@@ -15,7 +15,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <androidx.recyclerview.widget.FixOnItemTouchDispatchRecyclerView
+ <me.zhanghai.android.fastscroll.FixOnItemTouchListenerRecyclerView
android:id="@+id/pass_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/dependencies.gradle b/dependencies.gradle
index 13da81cf..0b175a83 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -48,7 +48,7 @@ ext.deps = [
third_party: [
commons_io: 'commons-io:commons-io:2.5',
commons_codec: 'commons-codec:commons-codec:1.13',
- fastscroll: 'me.zhanghai.android.fastscroll:library:1.1.2',
+ fastscroll: 'me.zhanghai.android.fastscroll:library:1.1.3',
jsch: 'com.jcraft:jsch:0.1.55',
jgit: 'org.eclipse.jgit:org.eclipse.jgit:3.7.1.201504261725-r',
leakcanary: 'com.squareup.leakcanary:leakcanary-android:2.2',