Implement Keyboard and DPAD navigation in lists.

This commit is contained in:
Mikhail Barashkov 2022-08-29 19:37:53 +03:00
parent 0209bb42a2
commit 23543e9ff1
3 changed files with 92 additions and 50 deletions

View file

@ -45,6 +45,7 @@ import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.ActionBar;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Cells.ArchiveHintCell;
import org.telegram.ui.Cells.BaseCell;
import org.telegram.ui.Cells.DialogCell;
import org.telegram.ui.Cells.DialogMeUrlCell;
import org.telegram.ui.Cells.DialogsEmptyCell;
@ -413,6 +414,9 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter {
DialogCell dialogCell = new DialogCell(parentFragment, mContext, true, false, currentAccount, null);
dialogCell.setArchivedPullAnimation(pullForegroundDrawable);
dialogCell.setPreloader(preloader);
if(viewGroup instanceof BaseCell.BaseCellDelegate) {
dialogCell.setDelegate((BaseCell.BaseCellDelegate) viewGroup);
}
view = dialogCell;
}
break;

View file

@ -11,11 +11,19 @@ package org.telegram.ui.Cells;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
public abstract class BaseCell extends ViewGroup {
public interface BaseCellDelegate {
default void didEnterWithKeyboard(BaseCell cell) {
}
}
private BaseCellDelegate delegate;
public void setDelegate(BaseCellDelegate delegate) { this.delegate = delegate; }
private final class CheckForTap implements Runnable {
public void run() {
@ -48,6 +56,27 @@ public abstract class BaseCell extends ViewGroup {
private int pressCount = 0;
private CheckForTap pendingCheckForTap = null;
private boolean isSelectButton(int keycode) {
switch(keycode) {
case KeyEvent.KEYCODE_BUTTON_SELECT:
case KeyEvent.KEYCODE_BUTTON_A:
case KeyEvent.KEYCODE_ENTER:
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_NUMPAD_ENTER:
return true;
default:
return false;
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(isSelectButton(keyCode)) {
delegate.didEnterWithKeyboard(this);
}
return super.onKeyDown(keyCode, event);
}
public BaseCell(Context context) {
super(context);
setWillNotDraw(false);

View file

@ -55,6 +55,7 @@ import org.telegram.messenger.FileLog;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.R;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Cells.BaseCell;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -63,7 +64,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
public class RecyclerListView extends RecyclerView {
public class RecyclerListView extends RecyclerView implements BaseCell.BaseCellDelegate {
public final static int SECTIONS_TYPE_SIMPLE = 0,
SECTIONS_TYPE_STICKY_HEADERS = 1,
SECTIONS_TYPE_DATE = 2,
@ -925,6 +926,63 @@ public class RecyclerListView extends RecyclerView {
}
@Override
public void didEnterWithKeyboard(BaseCell cell) {
currentChildView = cell;
currentChildPosition = getChildLayoutPosition(currentChildView);
MotionEvent e = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, cell.getX(), cell.getY(), 0);
onPressItem(cell, e);
}
private void onPressItem(View cv, MotionEvent e) {
if (cv != null && (onItemClickListener != null || onItemClickListenerExtended != null)) {
final float x = e.getX();
final float y = e.getY();
onChildPressed(cv, x, y, true);
final View view = cv;
final int position = currentChildPosition;
if (instantClick && position != -1) {
view.playSoundEffect(SoundEffectConstants.CLICK);
view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
if (onItemClickListener != null) {
onItemClickListener.onItemClick(view, position);
} else if (onItemClickListenerExtended != null) {
onItemClickListenerExtended.onItemClick(view, position, x - view.getX(), y - view.getY());
}
}
AndroidUtilities.runOnUIThread(clickRunnable = new Runnable() {
@Override
public void run() {
if (this == clickRunnable) {
clickRunnable = null;
}
if (view != null) {
onChildPressed(view, 0, 0, false);
if (!instantClick) {
view.playSoundEffect(SoundEffectConstants.CLICK);
view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
if (position != -1) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(view, position);
} else if (onItemClickListenerExtended != null) {
onItemClickListenerExtended.onItemClick(view, position, x - view.getX(), y - view.getY());
}
}
}
}
}
}, ViewConfiguration.getPressedStateDuration());
if (selectChildRunnable != null) {
AndroidUtilities.cancelRunOnUIThread(selectChildRunnable);
selectChildRunnable = null;
currentChildView = null;
interceptedByChild = false;
removeSelection(cv, e);
}
}
}
private class RecyclerListViewItemClickListener implements OnItemTouchListener {
public RecyclerListViewItemClickListener(Context context) {
@ -966,55 +1024,6 @@ public class RecyclerListView extends RecyclerView {
return false;
}
private void onPressItem(View cv, MotionEvent e) {
if (cv != null && (onItemClickListener != null || onItemClickListenerExtended != null)) {
final float x = e.getX();
final float y = e.getY();
onChildPressed(cv, x, y, true);
final View view = cv;
final int position = currentChildPosition;
if (instantClick && position != -1) {
view.playSoundEffect(SoundEffectConstants.CLICK);
view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
if (onItemClickListener != null) {
onItemClickListener.onItemClick(view, position);
} else if (onItemClickListenerExtended != null) {
onItemClickListenerExtended.onItemClick(view, position, x - view.getX(), y - view.getY());
}
}
AndroidUtilities.runOnUIThread(clickRunnable = new Runnable() {
@Override
public void run() {
if (this == clickRunnable) {
clickRunnable = null;
}
if (view != null) {
onChildPressed(view, 0, 0, false);
if (!instantClick) {
view.playSoundEffect(SoundEffectConstants.CLICK);
view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
if (position != -1) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(view, position);
} else if (onItemClickListenerExtended != null) {
onItemClickListenerExtended.onItemClick(view, position, x - view.getX(), y - view.getY());
}
}
}
}
}
}, ViewConfiguration.getPressedStateDuration());
if (selectChildRunnable != null) {
AndroidUtilities.cancelRunOnUIThread(selectChildRunnable);
selectChildRunnable = null;
currentChildView = null;
interceptedByChild = false;
removeSelection(cv, e);
}
}
}
@Override
public void onLongPress(MotionEvent event) {
if (currentChildView == null || currentChildPosition == -1 || onItemLongClickListener == null && onItemLongClickListenerExtended == null) {