Missing file
This commit is contained in:
parent
2b81b7f01e
commit
4f929ceb4b
@ -0,0 +1,339 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 2.x
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2015.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Components;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import android.view.GestureDetector;
|
||||||
|
import android.view.HapticFeedbackConstants;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.SoundEffectConstants;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
|
|
||||||
|
import org.telegram.android.AndroidUtilities;
|
||||||
|
import org.telegram.android.support.widget.RecyclerView;
|
||||||
|
import org.telegram.messenger.FileLog;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
public class RecyclerListView extends RecyclerView {
|
||||||
|
|
||||||
|
private OnItemClickListener onItemClickListener;
|
||||||
|
private OnItemLongClickListener onItemLongClickListener;
|
||||||
|
private RecyclerView.OnScrollListener onScrollListener;
|
||||||
|
private OnInterceptTouchListener onInterceptTouchListener;
|
||||||
|
private View emptyView;
|
||||||
|
private Runnable selectChildRunnable;
|
||||||
|
|
||||||
|
private GestureDetector mGestureDetector;
|
||||||
|
private View currentChildView;
|
||||||
|
private int currentChildPosition;
|
||||||
|
private boolean interceptedByChild;
|
||||||
|
private boolean wasPressed;
|
||||||
|
private boolean disallowInterceptTouchEvents;
|
||||||
|
private boolean instantClick;
|
||||||
|
|
||||||
|
private static int[] attributes;
|
||||||
|
private static boolean gotAttributes;
|
||||||
|
|
||||||
|
public interface OnItemClickListener {
|
||||||
|
void onItemClick(View view, int position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnItemLongClickListener {
|
||||||
|
void onItemClick(View view, int position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnInterceptTouchListener {
|
||||||
|
boolean onInterceptTouchEvent(MotionEvent event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RecyclerListViewItemClickListener implements RecyclerView.OnItemTouchListener {
|
||||||
|
|
||||||
|
public RecyclerListViewItemClickListener(Context context) {
|
||||||
|
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onSingleTapUp(MotionEvent e) {
|
||||||
|
if (currentChildView != null && onItemClickListener != null) {
|
||||||
|
currentChildView.setPressed(true);
|
||||||
|
final View view = currentChildView;
|
||||||
|
if (instantClick) {
|
||||||
|
view.playSoundEffect(SoundEffectConstants.CLICK);
|
||||||
|
onItemClickListener.onItemClick(view, currentChildPosition);
|
||||||
|
}
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (view != null) {
|
||||||
|
view.setPressed(false);
|
||||||
|
if (!instantClick) {
|
||||||
|
view.playSoundEffect(SoundEffectConstants.CLICK);
|
||||||
|
if (onItemClickListener != null) {
|
||||||
|
onItemClickListener.onItemClick(view, currentChildPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, ViewConfiguration.getPressedStateDuration());
|
||||||
|
|
||||||
|
if (selectChildRunnable != null) {
|
||||||
|
AndroidUtilities.cancelRunOnUIThread(selectChildRunnable);
|
||||||
|
selectChildRunnable = null;
|
||||||
|
currentChildView = null;
|
||||||
|
interceptedByChild = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLongPress(MotionEvent e) {
|
||||||
|
if (currentChildView != null && onItemLongClickListener != null) {
|
||||||
|
currentChildView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||||
|
onItemLongClickListener.onItemClick(currentChildView, currentChildPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
|
||||||
|
int action = e.getActionMasked();
|
||||||
|
boolean isScrollIdle = RecyclerListView.this.getScrollState() == RecyclerListView.SCROLL_STATE_IDLE;
|
||||||
|
|
||||||
|
if ((action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) && currentChildView == null && isScrollIdle) {
|
||||||
|
currentChildView = view.findChildViewUnder(e.getX(), e.getY());
|
||||||
|
currentChildPosition = -1;
|
||||||
|
if (currentChildView != null) {
|
||||||
|
currentChildPosition = view.getChildPosition(currentChildView);
|
||||||
|
MotionEvent childEvent = MotionEvent.obtain(0, 0, e.getActionMasked(), e.getX() - currentChildView.getLeft(), e.getY() - currentChildView.getTop(), 0);
|
||||||
|
if (currentChildView.onTouchEvent(childEvent)) {
|
||||||
|
interceptedByChild = true;
|
||||||
|
}
|
||||||
|
childEvent.recycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentChildView != null && !interceptedByChild) {
|
||||||
|
try {
|
||||||
|
if (e != null) {
|
||||||
|
mGestureDetector.onTouchEvent(e);
|
||||||
|
}
|
||||||
|
} catch (Exception ev) {
|
||||||
|
FileLog.e("tmessages", ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||||
|
if (!interceptedByChild && currentChildView != null) {
|
||||||
|
selectChildRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (selectChildRunnable != null && currentChildView != null) {
|
||||||
|
currentChildView.setPressed(true);
|
||||||
|
selectChildRunnable = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
AndroidUtilities.runOnUIThread(selectChildRunnable, ViewConfiguration.getTapTimeout());
|
||||||
|
}
|
||||||
|
} else if (currentChildView != null && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_CANCEL || !isScrollIdle)) {
|
||||||
|
if (selectChildRunnable != null) {
|
||||||
|
AndroidUtilities.cancelRunOnUIThread(selectChildRunnable);
|
||||||
|
selectChildRunnable = null;
|
||||||
|
}
|
||||||
|
currentChildView.setPressed(false);
|
||||||
|
currentChildView = null;
|
||||||
|
interceptedByChild = false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTouchEvent(RecyclerView view, MotionEvent e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AdapterDataObserver observer = new AdapterDataObserver() {
|
||||||
|
@Override
|
||||||
|
public void onChanged() {
|
||||||
|
checkIfEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onItemRangeInserted(int positionStart, int itemCount) {
|
||||||
|
checkIfEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onItemRangeRemoved(int positionStart, int itemCount) {
|
||||||
|
checkIfEmpty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public int[] getResourceDeclareStyleableIntArray(String packageName, String name) {
|
||||||
|
try {
|
||||||
|
Field f = Class.forName(packageName + ".R$styleable").getField(name);
|
||||||
|
if (f != null) {
|
||||||
|
return (int[]) f.get(null);
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecyclerListView(Context context) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!gotAttributes) {
|
||||||
|
attributes = getResourceDeclareStyleableIntArray("com.android.internal", "View");
|
||||||
|
gotAttributes = true;
|
||||||
|
}
|
||||||
|
TypedArray a = context.getTheme().obtainStyledAttributes(attributes);
|
||||||
|
Method initializeScrollbars = android.view.View.class.getDeclaredMethod("initializeScrollbars", TypedArray.class);
|
||||||
|
initializeScrollbars.invoke(this, a);
|
||||||
|
a.recycle();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.setOnScrollListener(new OnScrollListener() {
|
||||||
|
@Override
|
||||||
|
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
|
||||||
|
if (newState != SCROLL_STATE_IDLE && currentChildView != null) {
|
||||||
|
if (selectChildRunnable != null) {
|
||||||
|
AndroidUtilities.cancelRunOnUIThread(selectChildRunnable);
|
||||||
|
selectChildRunnable = null;
|
||||||
|
}
|
||||||
|
MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0);
|
||||||
|
try {
|
||||||
|
mGestureDetector.onTouchEvent(event);
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
currentChildView.onTouchEvent(event);
|
||||||
|
event.recycle();
|
||||||
|
currentChildView.setPressed(false);
|
||||||
|
currentChildView = null;
|
||||||
|
interceptedByChild = false;
|
||||||
|
}
|
||||||
|
if (onScrollListener != null) {
|
||||||
|
onScrollListener.onScrollStateChanged(recyclerView, newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
||||||
|
if (onScrollListener != null) {
|
||||||
|
onScrollListener.onScrolled(recyclerView, dx, dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
addOnItemTouchListener(new RecyclerListViewItemClickListener(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) {
|
||||||
|
if (attributes != null) {
|
||||||
|
super.setVerticalScrollBarEnabled(verticalScrollBarEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnItemClickListener(OnItemClickListener listener) {
|
||||||
|
onItemClickListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnItemLongClickListener(OnItemLongClickListener listener) {
|
||||||
|
onItemLongClickListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmptyView(View view) {
|
||||||
|
if (emptyView == view) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emptyView = view;
|
||||||
|
checkIfEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getEmptyView() {
|
||||||
|
return emptyView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalidateViews() {
|
||||||
|
int count = getChildCount();
|
||||||
|
for (int a = 0; a < count; a++) {
|
||||||
|
getChildAt(a).invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(MotionEvent e) {
|
||||||
|
if (disallowInterceptTouchEvents) {
|
||||||
|
requestDisallowInterceptTouchEvent(true);
|
||||||
|
}
|
||||||
|
return onInterceptTouchListener != null && onInterceptTouchListener.onInterceptTouchEvent(e) || super.onInterceptTouchEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkIfEmpty() {
|
||||||
|
if (emptyView == null || getAdapter() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean emptyViewVisible = getAdapter().getItemCount() == 0;
|
||||||
|
emptyView.setVisibility(emptyViewVisible ? VISIBLE : INVISIBLE);
|
||||||
|
setVisibility(emptyViewVisible ? INVISIBLE : VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOnScrollListener(OnScrollListener listener) {
|
||||||
|
onScrollListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnInterceptTouchListener(OnInterceptTouchListener listener) {
|
||||||
|
onInterceptTouchListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInstantClick(boolean value) {
|
||||||
|
instantClick = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisallowInterceptTouchEvents(boolean value) {
|
||||||
|
disallowInterceptTouchEvents = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAdapter(Adapter adapter) {
|
||||||
|
final Adapter oldAdapter = getAdapter();
|
||||||
|
if (oldAdapter != null) {
|
||||||
|
oldAdapter.unregisterAdapterDataObserver(observer);
|
||||||
|
}
|
||||||
|
super.setAdapter(adapter);
|
||||||
|
if (adapter != null) {
|
||||||
|
adapter.registerAdapterDataObserver(observer);
|
||||||
|
}
|
||||||
|
checkIfEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopScroll() {
|
||||||
|
try {
|
||||||
|
super.stopScroll();
|
||||||
|
} catch (NullPointerException exception) {
|
||||||
|
/**
|
||||||
|
* The mLayout has been disposed of before the
|
||||||
|
* RecyclerView and this stops the application
|
||||||
|
* from crashing.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user