Merge remote-tracking branch 'newpipe/dev' into rebase
This commit is contained in:
commit
c42f5eca87
265 changed files with 12286 additions and 8976 deletions
|
|
@ -1,64 +1,66 @@
|
|||
package org.schabi.newpipe.views;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Transformation;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public final class AnimatedProgressBar extends ProgressBar {
|
||||
@Nullable
|
||||
private ProgressBarAnimation animation = null;
|
||||
|
||||
@Nullable
|
||||
private ProgressBarAnimation animation = null;
|
||||
public AnimatedProgressBar(final Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public AnimatedProgressBar(Context context) {
|
||||
super(context);
|
||||
}
|
||||
public AnimatedProgressBar(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public AnimatedProgressBar(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
public AnimatedProgressBar(final Context context, final AttributeSet attrs,
|
||||
final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public AnimatedProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
public synchronized void setProgressAnimated(final int progress) {
|
||||
cancelAnimation();
|
||||
animation = new ProgressBarAnimation(this, getProgress(), progress);
|
||||
startAnimation(animation);
|
||||
}
|
||||
|
||||
public synchronized void setProgressAnimated(int progress) {
|
||||
cancelAnimation();
|
||||
animation = new ProgressBarAnimation(this, getProgress(), progress);
|
||||
startAnimation(animation);
|
||||
}
|
||||
private void cancelAnimation() {
|
||||
if (animation != null) {
|
||||
animation.cancel();
|
||||
animation = null;
|
||||
}
|
||||
clearAnimation();
|
||||
}
|
||||
|
||||
private void cancelAnimation() {
|
||||
if (animation != null) {
|
||||
animation.cancel();
|
||||
animation = null;
|
||||
}
|
||||
clearAnimation();
|
||||
}
|
||||
private static class ProgressBarAnimation extends Animation {
|
||||
|
||||
private static class ProgressBarAnimation extends Animation {
|
||||
private final AnimatedProgressBar progressBar;
|
||||
private final float from;
|
||||
private final float to;
|
||||
|
||||
private final AnimatedProgressBar progressBar;
|
||||
private final float from;
|
||||
private final float to;
|
||||
ProgressBarAnimation(final AnimatedProgressBar progressBar, final float from,
|
||||
final float to) {
|
||||
super();
|
||||
this.progressBar = progressBar;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
setDuration(500);
|
||||
setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
}
|
||||
|
||||
ProgressBarAnimation(AnimatedProgressBar progressBar, float from, float to) {
|
||||
super();
|
||||
this.progressBar = progressBar;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
setDuration(500);
|
||||
setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
super.applyTransformation(interpolatedTime, t);
|
||||
float value = from + (to - from) * interpolatedTime;
|
||||
progressBar.setProgress((int) value);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void applyTransformation(final float interpolatedTime, final Transformation t) {
|
||||
super.applyTransformation(interpolatedTime, t);
|
||||
float value = from + (to - from) * interpolatedTime;
|
||||
progressBar.setProgress((int) value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,13 +23,14 @@ import android.animation.ValueAnimator;
|
|||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Parcelable;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import org.schabi.newpipe.util.AnimationUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
|
@ -48,20 +49,36 @@ import static org.schabi.newpipe.MainActivity.DEBUG;
|
|||
public class CollapsibleView extends LinearLayout {
|
||||
private static final String TAG = CollapsibleView.class.getSimpleName();
|
||||
|
||||
public CollapsibleView(Context context) {
|
||||
private static final int ANIMATION_DURATION = 420;
|
||||
|
||||
public static final int COLLAPSED = 0;
|
||||
public static final int EXPANDED = 1;
|
||||
|
||||
@State
|
||||
@ViewMode
|
||||
int currentState = COLLAPSED;
|
||||
private boolean readyToChangeState;
|
||||
|
||||
private int targetHeight = -1;
|
||||
private ValueAnimator currentAnimator;
|
||||
private final List<StateListener> listeners = new ArrayList<>();
|
||||
|
||||
public CollapsibleView(final Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public CollapsibleView(Context context, @Nullable AttributeSet attrs) {
|
||||
public CollapsibleView(final Context context, @Nullable final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public CollapsibleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
public CollapsibleView(final Context context, @Nullable final AttributeSet attrs,
|
||||
final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public CollapsibleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
public CollapsibleView(final Context context, final AttributeSet attrs, final int defStyleAttr,
|
||||
final int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
|
|
@ -69,20 +86,6 @@ public class CollapsibleView extends LinearLayout {
|
|||
// Collapse/expand logic
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private static final int ANIMATION_DURATION = 420;
|
||||
public static final int COLLAPSED = 0, EXPANDED = 1;
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef({COLLAPSED, EXPANDED})
|
||||
public @interface ViewMode {}
|
||||
|
||||
@State @ViewMode int currentState = COLLAPSED;
|
||||
private boolean readyToChangeState;
|
||||
|
||||
private int targetHeight = -1;
|
||||
private ValueAnimator currentAnimator;
|
||||
private final List<StateListener> listeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* This method recalculates the height of this view so it <b>must</b> be called when
|
||||
* some child changes (e.g. add new views, change text).
|
||||
|
|
@ -92,7 +95,8 @@ public class CollapsibleView extends LinearLayout {
|
|||
Log.d(TAG, getDebugLogString("ready() called"));
|
||||
}
|
||||
|
||||
measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), MeasureSpec.UNSPECIFIED);
|
||||
measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
|
||||
MeasureSpec.UNSPECIFIED);
|
||||
targetHeight = getMeasuredHeight();
|
||||
|
||||
getLayoutParams().height = currentState == COLLAPSED ? 0 : targetHeight;
|
||||
|
|
@ -111,7 +115,9 @@ public class CollapsibleView extends LinearLayout {
|
|||
Log.d(TAG, getDebugLogString("collapse() called"));
|
||||
}
|
||||
|
||||
if (!readyToChangeState) return;
|
||||
if (!readyToChangeState) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int height = getHeight();
|
||||
if (height == 0) {
|
||||
|
|
@ -119,7 +125,9 @@ public class CollapsibleView extends LinearLayout {
|
|||
return;
|
||||
}
|
||||
|
||||
if (currentAnimator != null && currentAnimator.isRunning()) currentAnimator.cancel();
|
||||
if (currentAnimator != null && currentAnimator.isRunning()) {
|
||||
currentAnimator.cancel();
|
||||
}
|
||||
currentAnimator = AnimationUtils.animateHeight(this, ANIMATION_DURATION, 0);
|
||||
|
||||
setCurrentState(COLLAPSED);
|
||||
|
|
@ -130,7 +138,9 @@ public class CollapsibleView extends LinearLayout {
|
|||
Log.d(TAG, getDebugLogString("expand() called"));
|
||||
}
|
||||
|
||||
if (!readyToChangeState) return;
|
||||
if (!readyToChangeState) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int height = getHeight();
|
||||
if (height == this.targetHeight) {
|
||||
|
|
@ -138,13 +148,17 @@ public class CollapsibleView extends LinearLayout {
|
|||
return;
|
||||
}
|
||||
|
||||
if (currentAnimator != null && currentAnimator.isRunning()) currentAnimator.cancel();
|
||||
if (currentAnimator != null && currentAnimator.isRunning()) {
|
||||
currentAnimator.cancel();
|
||||
}
|
||||
currentAnimator = AnimationUtils.animateHeight(this, ANIMATION_DURATION, this.targetHeight);
|
||||
setCurrentState(EXPANDED);
|
||||
}
|
||||
|
||||
public void switchState() {
|
||||
if (!readyToChangeState) return;
|
||||
if (!readyToChangeState) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentState == COLLAPSED) {
|
||||
expand();
|
||||
|
|
@ -158,7 +172,7 @@ public class CollapsibleView extends LinearLayout {
|
|||
return currentState;
|
||||
}
|
||||
|
||||
public void setCurrentState(@ViewMode int currentState) {
|
||||
public void setCurrentState(@ViewMode final int currentState) {
|
||||
this.currentState = currentState;
|
||||
broadcastState();
|
||||
}
|
||||
|
|
@ -171,6 +185,7 @@ public class CollapsibleView extends LinearLayout {
|
|||
|
||||
/**
|
||||
* Add a listener which will be listening for changes in this view (i.e. collapsed or expanded).
|
||||
* @param listener {@link StateListener} to be added
|
||||
*/
|
||||
public void addListener(final StateListener listener) {
|
||||
if (listeners.contains(listener)) {
|
||||
|
|
@ -182,24 +197,12 @@ public class CollapsibleView extends LinearLayout {
|
|||
|
||||
/**
|
||||
* Remove a listener so it doesn't receive more state changes.
|
||||
* @param listener {@link StateListener} to be removed
|
||||
*/
|
||||
public void removeListener(final StateListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple interface used for listening state changes of the {@link CollapsibleView}.
|
||||
*/
|
||||
public interface StateListener {
|
||||
/**
|
||||
* Called when the state changes.
|
||||
*
|
||||
* @param newState the state that the {@link CollapsibleView} transitioned to,<br/>
|
||||
* it's an integer being either {@link #COLLAPSED} or {@link #EXPANDED}
|
||||
*/
|
||||
void onStateChanged(@ViewMode int newState);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// State Saving
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
|
@ -211,7 +214,7 @@ public class CollapsibleView extends LinearLayout {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
public void onRestoreInstanceState(final Parcelable state) {
|
||||
super.onRestoreInstanceState(Icepick.restoreInstanceState(this, state));
|
||||
|
||||
ready();
|
||||
|
|
@ -221,10 +224,29 @@ public class CollapsibleView extends LinearLayout {
|
|||
// Internal
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
public String getDebugLogString(String description) {
|
||||
public String getDebugLogString(final String description) {
|
||||
return String.format("%-100s → %s",
|
||||
description, "readyToChangeState = [" + readyToChangeState + "], currentState = [" + currentState + "], targetHeight = [" + targetHeight + "]," +
|
||||
" mW x mH = [" + getMeasuredWidth() + "x" + getMeasuredHeight() + "]" +
|
||||
" W x H = [" + getWidth() + "x" + getHeight() + "]");
|
||||
description, "readyToChangeState = [" + readyToChangeState + "], "
|
||||
+ "currentState = [" + currentState + "], "
|
||||
+ "targetHeight = [" + targetHeight + "], "
|
||||
+ "mW x mH = [" + getMeasuredWidth() + "x" + getMeasuredHeight() + "], "
|
||||
+ "W x H = [" + getWidth() + "x" + getHeight() + "]");
|
||||
}
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef({COLLAPSED, EXPANDED})
|
||||
public @interface ViewMode { }
|
||||
|
||||
/**
|
||||
* Simple interface used for listening state changes of the {@link CollapsibleView}.
|
||||
*/
|
||||
public interface StateListener {
|
||||
/**
|
||||
* Called when the state changes.
|
||||
*
|
||||
* @param newState the state that the {@link CollapsibleView} transitioned to,<br/>
|
||||
* it's an integer being either {@link #COLLAPSED} or {@link #EXPANDED}
|
||||
*/
|
||||
void onStateChanged(@ViewMode int newState);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,20 +30,20 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
|||
public final class FocusAwareCoordinator extends CoordinatorLayout {
|
||||
private final Rect childFocus = new Rect();
|
||||
|
||||
public FocusAwareCoordinator(@NonNull Context context) {
|
||||
public FocusAwareCoordinator(@NonNull final Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public FocusAwareCoordinator(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
public FocusAwareCoordinator(@NonNull final Context context, @Nullable final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public FocusAwareCoordinator(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
public FocusAwareCoordinator(@NonNull final Context context, @Nullable final AttributeSet attrs, final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestChildFocus(View child, View focused) {
|
||||
public void requestChildFocus(final View child, final View focused) {
|
||||
super.requestChildFocus(child, focused);
|
||||
|
||||
if (!isInTouchMode()) {
|
||||
|
|
|
|||
|
|
@ -33,20 +33,20 @@ import androidx.drawerlayout.widget.DrawerLayout;
|
|||
import java.util.ArrayList;
|
||||
|
||||
public final class FocusAwareDrawerLayout extends DrawerLayout {
|
||||
public FocusAwareDrawerLayout(@NonNull Context context) {
|
||||
public FocusAwareDrawerLayout(@NonNull final Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public FocusAwareDrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
public FocusAwareDrawerLayout(@NonNull final Context context, @Nullable final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public FocusAwareDrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
|
||||
public FocusAwareDrawerLayout(@NonNull final Context context, @Nullable final AttributeSet attrs, final int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
|
||||
protected boolean onRequestFocusInDescendants(final int direction, final Rect previouslyFocusedRect) {
|
||||
// SDK implementation of this method picks whatever visible View takes the focus first without regard to addFocusables
|
||||
// if the open drawer is temporarily empty, the focus escapes outside of it, which can be confusing
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ public final class FocusAwareDrawerLayout extends DrawerLayout {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
|
||||
public void addFocusables(final ArrayList<View> views, final int direction, final int focusableMode) {
|
||||
boolean hasOpenPanels = false;
|
||||
View content = null;
|
||||
|
||||
|
|
@ -98,16 +98,17 @@ public final class FocusAwareDrawerLayout extends DrawerLayout {
|
|||
}
|
||||
}
|
||||
|
||||
// this override isn't strictly necessary, but it is helpful when DrawerLayout isn't the topmost
|
||||
// view in hierarchy (such as when system or builtin appcompat ActionBar is used)
|
||||
// this override isn't strictly necessary, but it is helpful when DrawerLayout isn't
|
||||
// the topmost view in hierarchy (such as when system or builtin appcompat ActionBar is used)
|
||||
@Override
|
||||
@SuppressLint("RtlHardcoded")
|
||||
public void openDrawer(@NonNull View drawerView, boolean animate) {
|
||||
public void openDrawer(@NonNull final View drawerView, final boolean animate) {
|
||||
super.openDrawer(drawerView, animate);
|
||||
|
||||
LayoutParams params = (LayoutParams) drawerView.getLayoutParams();
|
||||
|
||||
int gravity = GravityCompat.getAbsoluteGravity(params.gravity, ViewCompat.getLayoutDirection(this));
|
||||
int gravity = GravityCompat.getAbsoluteGravity(
|
||||
params.gravity, ViewCompat.getLayoutDirection(this));
|
||||
|
||||
int direction = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -37,27 +37,27 @@ public final class FocusAwareSeekBar extends AppCompatSeekBar {
|
|||
|
||||
private ViewTreeObserver treeObserver;
|
||||
|
||||
public FocusAwareSeekBar(Context context) {
|
||||
public FocusAwareSeekBar(final Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public FocusAwareSeekBar(Context context, AttributeSet attrs) {
|
||||
public FocusAwareSeekBar(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public FocusAwareSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
public FocusAwareSeekBar(final Context context, final AttributeSet attrs, final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {
|
||||
public void setOnSeekBarChangeListener(final OnSeekBarChangeListener l) {
|
||||
this.listener = l == null ? null : new NestedListener(l);
|
||||
|
||||
super.setOnSeekBarChangeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
public boolean onKeyDown(final int keyCode, final KeyEvent event) {
|
||||
if (!isInTouchMode() && AndroidTvUtils.isConfirmKey(keyCode)) {
|
||||
releaseTrack();
|
||||
}
|
||||
|
|
@ -66,7 +66,7 @@ public final class FocusAwareSeekBar extends AppCompatSeekBar {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
|
||||
protected void onFocusChanged(final boolean gainFocus, final int direction, final Rect previouslyFocusedRect) {
|
||||
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
|
||||
|
||||
if (!isInTouchMode() && !gainFocus) {
|
||||
|
|
@ -74,7 +74,11 @@ public final class FocusAwareSeekBar extends AppCompatSeekBar {
|
|||
}
|
||||
}
|
||||
|
||||
private final ViewTreeObserver.OnTouchModeChangeListener touchModeListener = isInTouchMode -> { if (isInTouchMode) releaseTrack(); };
|
||||
private final ViewTreeObserver.OnTouchModeChangeListener touchModeListener = isInTouchMode -> {
|
||||
if (isInTouchMode) {
|
||||
releaseTrack();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
|
|
@ -107,12 +111,12 @@ public final class FocusAwareSeekBar extends AppCompatSeekBar {
|
|||
|
||||
boolean isSeeking;
|
||||
|
||||
private NestedListener(OnSeekBarChangeListener delegate) {
|
||||
private NestedListener(final OnSeekBarChangeListener delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
public void onProgressChanged(final SeekBar seekBar, final int progress, final boolean fromUser) {
|
||||
if (!seekBar.isInTouchMode() && !isSeeking && fromUser) {
|
||||
isSeeking = true;
|
||||
|
||||
|
|
@ -123,14 +127,14 @@ public final class FocusAwareSeekBar extends AppCompatSeekBar {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
public void onStartTrackingTouch(final SeekBar seekBar) {
|
||||
isSeeking = true;
|
||||
|
||||
delegate.onStartTrackingTouch(seekBar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
public void onStopTrackingTouch(final SeekBar seekBar) {
|
||||
isSeeking = false;
|
||||
|
||||
delegate.onStopTrackingTouch(seekBar);
|
||||
|
|
|
|||
|
|
@ -59,21 +59,21 @@ public final class FocusOverlayView extends Drawable implements
|
|||
|
||||
private final Handler animator = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
public void handleMessage(final Message msg) {
|
||||
updateRect();
|
||||
}
|
||||
};
|
||||
|
||||
private WeakReference<View> focused;
|
||||
|
||||
public FocusOverlayView(Context context) {
|
||||
public FocusOverlayView(final Context context) {
|
||||
rectPaint.setStyle(Paint.Style.STROKE);
|
||||
rectPaint.setStrokeWidth(2);
|
||||
rectPaint.setColor(context.getResources().getColor(R.color.white));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
|
||||
public void onGlobalFocusChanged(final View oldFocus, final View newFocus) {
|
||||
int l = focusRect.left;
|
||||
int r = focusRect.right;
|
||||
int t = focusRect.top;
|
||||
|
|
@ -89,7 +89,8 @@ public final class FocusOverlayView extends Drawable implements
|
|||
focused = null;
|
||||
}
|
||||
|
||||
if (l != focusRect.left || r != focusRect.right || t != focusRect.top || b != focusRect.bottom) {
|
||||
if (l != focusRect.left || r != focusRect.right
|
||||
|| t != focusRect.top || b != focusRect.bottom) {
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
|
|
@ -103,20 +104,21 @@ public final class FocusOverlayView extends Drawable implements
|
|||
return;
|
||||
}
|
||||
|
||||
View focused = this.focused.get();
|
||||
View focusedView = this.focused.get();
|
||||
|
||||
int l = focusRect.left;
|
||||
int r = focusRect.right;
|
||||
int t = focusRect.top;
|
||||
int b = focusRect.bottom;
|
||||
|
||||
if (focused != null) {
|
||||
focused.getGlobalVisibleRect(focusRect);
|
||||
if (focusedView != null) {
|
||||
focusedView.getGlobalVisibleRect(focusRect);
|
||||
} else {
|
||||
focusRect.setEmpty();
|
||||
}
|
||||
|
||||
if (l != focusRect.left || r != focusRect.right || t != focusRect.top || b != focusRect.bottom) {
|
||||
if (l != focusRect.left || r != focusRect.right
|
||||
|| t != focusRect.top || b != focusRect.bottom) {
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
|
@ -142,28 +144,28 @@ public final class FocusOverlayView extends Drawable implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onTouchModeChanged(boolean isInTouchMode) {
|
||||
this.isInTouchMode = isInTouchMode;
|
||||
public void onTouchModeChanged(final boolean inTouchMode) {
|
||||
this.isInTouchMode = inTouchMode;
|
||||
|
||||
if (isInTouchMode) {
|
||||
if (inTouchMode) {
|
||||
updateRect();
|
||||
} else {
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
public void setCurrentFocus(View focused) {
|
||||
if (focused == null) {
|
||||
public void setCurrentFocus(final View newFocus) {
|
||||
if (newFocus == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isInTouchMode = focused.isInTouchMode();
|
||||
this.isInTouchMode = newFocus.isInTouchMode();
|
||||
|
||||
onGlobalFocusChanged(null, focused);
|
||||
onGlobalFocusChanged(null, newFocus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
public void draw(@NonNull final Canvas canvas) {
|
||||
if (!isInTouchMode && focusRect.width() != 0) {
|
||||
canvas.drawRect(focusRect, rectPaint);
|
||||
}
|
||||
|
|
@ -175,14 +177,14 @@ public final class FocusOverlayView extends Drawable implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
public void setAlpha(final int alpha) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) {
|
||||
public void setColorFilter(final ColorFilter colorFilter) {
|
||||
}
|
||||
|
||||
public static void setupFocusObserver(Dialog dialog) {
|
||||
public static void setupFocusObserver(final Dialog dialog) {
|
||||
Rect displayRect = new Rect();
|
||||
|
||||
Window window = dialog.getWindow();
|
||||
|
|
@ -197,7 +199,7 @@ public final class FocusOverlayView extends Drawable implements
|
|||
setupOverlay(window, overlay);
|
||||
}
|
||||
|
||||
public static void setupFocusObserver(Activity activity) {
|
||||
public static void setupFocusObserver(final Activity activity) {
|
||||
Rect displayRect = new Rect();
|
||||
|
||||
Window window = activity.getWindow();
|
||||
|
|
@ -210,7 +212,7 @@ public final class FocusOverlayView extends Drawable implements
|
|||
setupOverlay(window, overlay);
|
||||
}
|
||||
|
||||
private static void setupOverlay(Window window, FocusOverlayView overlay) {
|
||||
private static void setupOverlay(final Window window, final FocusOverlayView overlay) {
|
||||
ViewGroup decor = (ViewGroup) window.getDecorView();
|
||||
decor.getOverlay().add(overlay);
|
||||
|
||||
|
|
@ -232,7 +234,7 @@ public final class FocusOverlayView extends Drawable implements
|
|||
// receiving keys from Window.
|
||||
window.setCallback(new WindowCallbackWrapper(window.getCallback()) {
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
public boolean dispatchKeyEvent(final KeyEvent event) {
|
||||
boolean res = super.dispatchKeyEvent(event);
|
||||
overlay.onKey(event);
|
||||
return res;
|
||||
|
|
@ -240,7 +242,7 @@ public final class FocusOverlayView extends Drawable implements
|
|||
});
|
||||
}
|
||||
|
||||
private void onKey(KeyEvent event) {
|
||||
private void onKey(final KeyEvent event) {
|
||||
if (event.getAction() != KeyEvent.ACTION_DOWN) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -250,11 +252,12 @@ public final class FocusOverlayView extends Drawable implements
|
|||
animator.sendEmptyMessageDelayed(0, 100);
|
||||
}
|
||||
|
||||
private static void fixFocusHierarchy(View decor) {
|
||||
// During Android 8 development some dumb ass decided, that action bar has to be a keyboard focus cluster.
|
||||
// Unfortunately, keyboard clusters do not work for primary auditory of key navigation — Android TV users
|
||||
// (Android TV remotes do not have keyboard META key for moving between clusters). We have to fix this
|
||||
// unfortunate accident. While we are at it, let's deal with touchscreenBlocksFocus too.
|
||||
private static void fixFocusHierarchy(final View decor) {
|
||||
// During Android 8 development some dumb ass decided, that action bar has to be
|
||||
// a keyboard focus cluster. Unfortunately, keyboard clusters do not work for primary
|
||||
// auditory of key navigation — Android TV users (Android TV remotes do not have
|
||||
// keyboard META key for moving between clusters). We have to fix this unfortunate accident
|
||||
// While we are at it, let's deal with touchscreenBlocksFocus too.
|
||||
|
||||
if (Build.VERSION.SDK_INT < 26) {
|
||||
return;
|
||||
|
|
@ -268,7 +271,7 @@ public final class FocusOverlayView extends Drawable implements
|
|||
}
|
||||
|
||||
@RequiresApi(api = 26)
|
||||
private static void clearFocusObstacles(ViewGroup viewGroup) {
|
||||
private static void clearFocusObstacles(final ViewGroup viewGroup) {
|
||||
viewGroup.setTouchscreenBlocksFocus(false);
|
||||
|
||||
if (viewGroup.isKeyboardNavigationCluster()) {
|
||||
|
|
|
|||
|
|
@ -33,19 +33,23 @@ import android.widget.TextView;
|
|||
public class LargeTextMovementMethod extends LinkMovementMethod {
|
||||
private final Rect visibleRect = new Rect();
|
||||
|
||||
private int dir;
|
||||
private int direction;
|
||||
|
||||
@Override
|
||||
public void onTakeFocus(TextView view, Spannable text, int dir) {
|
||||
public void onTakeFocus(final TextView view, final Spannable text, final int dir) {
|
||||
Selection.removeSelection(text);
|
||||
|
||||
super.onTakeFocus(view, text, dir);
|
||||
|
||||
this.dir = dirToRelative(dir);
|
||||
this.direction = dirToRelative(dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handleMovementKey(TextView widget, Spannable buffer, int keyCode, int movementMetaState, KeyEvent event) {
|
||||
protected boolean handleMovementKey(final TextView widget,
|
||||
final Spannable buffer,
|
||||
final int keyCode,
|
||||
final int movementMetaState,
|
||||
final KeyEvent event) {
|
||||
if (!doHandleMovement(widget, buffer, keyCode, movementMetaState, event)) {
|
||||
// clear selection to make sure, that it does not confuse focus handling code
|
||||
Selection.removeSelection(buffer);
|
||||
|
|
@ -55,14 +59,18 @@ public class LargeTextMovementMethod extends LinkMovementMethod {
|
|||
return true;
|
||||
}
|
||||
|
||||
private boolean doHandleMovement(TextView widget, Spannable buffer, int keyCode, int movementMetaState, KeyEvent event) {
|
||||
private boolean doHandleMovement(final TextView widget,
|
||||
final Spannable buffer,
|
||||
final int keyCode,
|
||||
final int movementMetaState,
|
||||
final KeyEvent event) {
|
||||
int newDir = keyToDir(keyCode);
|
||||
|
||||
if (dir != 0 && newDir != dir) {
|
||||
if (direction != 0 && newDir != direction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.dir = 0;
|
||||
this.direction = 0;
|
||||
|
||||
ViewGroup root = findScrollableParent(widget);
|
||||
|
||||
|
|
@ -74,7 +82,7 @@ public class LargeTextMovementMethod extends LinkMovementMethod {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean up(TextView widget, Spannable buffer) {
|
||||
protected boolean up(final TextView widget, final Spannable buffer) {
|
||||
if (gotoPrev(widget, buffer)) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -83,7 +91,7 @@ public class LargeTextMovementMethod extends LinkMovementMethod {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean left(TextView widget, Spannable buffer) {
|
||||
protected boolean left(final TextView widget, final Spannable buffer) {
|
||||
if (gotoPrev(widget, buffer)) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -92,7 +100,7 @@ public class LargeTextMovementMethod extends LinkMovementMethod {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean right(TextView widget, Spannable buffer) {
|
||||
protected boolean right(final TextView widget, final Spannable buffer) {
|
||||
if (gotoNext(widget, buffer)) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -101,7 +109,7 @@ public class LargeTextMovementMethod extends LinkMovementMethod {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean down(TextView widget, Spannable buffer) {
|
||||
protected boolean down(final TextView widget, final Spannable buffer) {
|
||||
if (gotoNext(widget, buffer)) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -109,7 +117,7 @@ public class LargeTextMovementMethod extends LinkMovementMethod {
|
|||
return super.down(widget, buffer);
|
||||
}
|
||||
|
||||
private boolean gotoPrev(TextView view, Spannable buffer) {
|
||||
private boolean gotoPrev(final TextView view, final Spannable buffer) {
|
||||
Layout layout = view.getLayout();
|
||||
if (layout == null) {
|
||||
return false;
|
||||
|
|
@ -130,9 +138,12 @@ public class LargeTextMovementMethod extends LinkMovementMethod {
|
|||
|
||||
// when deciding whether to pass "focus" to span, account for one more line
|
||||
// this ensures, that focus is never passed to spans partially outside scroll window
|
||||
int visibleStart = firstVisibleLineNumber == 0 ? 0 : layout.getLineStart(firstVisibleLineNumber - 1);
|
||||
int visibleStart = firstVisibleLineNumber == 0
|
||||
? 0
|
||||
: layout.getLineStart(firstVisibleLineNumber - 1);
|
||||
|
||||
ClickableSpan[] candidates = buffer.getSpans(visibleStart, buffer.length(), ClickableSpan.class);
|
||||
ClickableSpan[] candidates = buffer.getSpans(
|
||||
visibleStart, buffer.length(), ClickableSpan.class);
|
||||
|
||||
if (candidates.length != 0) {
|
||||
int a = Selection.getSelectionStart(buffer);
|
||||
|
|
@ -172,7 +183,7 @@ public class LargeTextMovementMethod extends LinkMovementMethod {
|
|||
return view.requestRectangleOnScreen(visibleRect);
|
||||
}
|
||||
|
||||
private boolean gotoNext(TextView view, Spannable buffer) {
|
||||
private boolean gotoNext(final TextView view, final Spannable buffer) {
|
||||
Layout layout = view.getLayout();
|
||||
if (layout == null) {
|
||||
return false;
|
||||
|
|
@ -197,7 +208,9 @@ public class LargeTextMovementMethod extends LinkMovementMethod {
|
|||
|
||||
// when deciding whether to pass "focus" to span, account for one more line
|
||||
// this ensures, that focus is never passed to spans partially outside scroll window
|
||||
int visibleEnd = lastVisibleLineNumber == lineCount - 1 ? buffer.length() : layout.getLineEnd(lastVisibleLineNumber - 1);
|
||||
int visibleEnd = lastVisibleLineNumber == lineCount - 1
|
||||
? buffer.length()
|
||||
: layout.getLineEnd(lastVisibleLineNumber - 1);
|
||||
|
||||
ClickableSpan[] candidates = buffer.getSpans(0, visibleEnd, ClickableSpan.class);
|
||||
|
||||
|
|
@ -242,7 +255,7 @@ public class LargeTextMovementMethod extends LinkMovementMethod {
|
|||
return view.requestRectangleOnScreen(visibleRect);
|
||||
}
|
||||
|
||||
private ViewGroup findScrollableParent(View view) {
|
||||
private ViewGroup findScrollableParent(final View view) {
|
||||
View current = view;
|
||||
|
||||
ViewParent parent;
|
||||
|
|
@ -262,7 +275,7 @@ public class LargeTextMovementMethod extends LinkMovementMethod {
|
|||
while (true);
|
||||
}
|
||||
|
||||
private int dirToRelative(int dir) {
|
||||
private static int dirToRelative(final int dir) {
|
||||
switch (dir) {
|
||||
case View.FOCUS_DOWN:
|
||||
case View.FOCUS_RIGHT:
|
||||
|
|
@ -275,7 +288,7 @@ public class LargeTextMovementMethod extends LinkMovementMethod {
|
|||
return dir;
|
||||
}
|
||||
|
||||
private int keyToDir(int keyCode) {
|
||||
private int keyToDir(final int keyCode) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_DPAD_UP:
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||
|
|
|
|||
|
|
@ -38,19 +38,19 @@ public class NewPipeRecyclerView extends RecyclerView {
|
|||
|
||||
private boolean allowDpadScroll = true;
|
||||
|
||||
public NewPipeRecyclerView(@NonNull Context context) {
|
||||
public NewPipeRecyclerView(@NonNull final Context context) {
|
||||
super(context);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
public NewPipeRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
public NewPipeRecyclerView(@NonNull final Context context, @Nullable final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
public NewPipeRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
|
||||
public NewPipeRecyclerView(@NonNull final Context context, @Nullable final AttributeSet attrs, final int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
init();
|
||||
|
|
@ -62,12 +62,12 @@ public class NewPipeRecyclerView extends RecyclerView {
|
|||
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
|
||||
}
|
||||
|
||||
public void setFocusScrollAllowed(boolean allowDpadScroll) {
|
||||
this.allowDpadScroll = allowDpadScroll;
|
||||
public void setFocusScrollAllowed(final boolean allowed) {
|
||||
this.allowDpadScroll = allowed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View focusSearch(View focused, int direction) {
|
||||
public View focusSearch(final View focused, final int direction) {
|
||||
// RecyclerView has buggy focusSearch(), that calls into Adapter several times,
|
||||
// but ultimately fails to produce correct results in many cases. To add insult to injury,
|
||||
// it's focusSearch() hard-codes several behaviors, incompatible with widely accepted focus
|
||||
|
|
@ -78,7 +78,7 @@ public class NewPipeRecyclerView extends RecyclerView {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void removeDetachedView(View child, boolean animate) {
|
||||
protected void removeDetachedView(final View child, final boolean animate) {
|
||||
if (child.hasFocus()) {
|
||||
// If the focused child is being removed (can happen during very fast scrolling),
|
||||
// temporarily give focus to ourselves. This will usually result in another child
|
||||
|
|
@ -95,7 +95,7 @@ public class NewPipeRecyclerView extends RecyclerView {
|
|||
// happens when loading additional contents is in progress
|
||||
|
||||
@Override
|
||||
public boolean dispatchUnhandledMove(View focused, int direction) {
|
||||
public boolean dispatchUnhandledMove(final View focused, final int direction) {
|
||||
tempFocus.setEmpty();
|
||||
|
||||
// save focus rect before further manipulation (both focusSearch() and scrollBy()
|
||||
|
|
@ -138,7 +138,7 @@ public class NewPipeRecyclerView extends RecyclerView {
|
|||
return super.dispatchUnhandledMove(focused, direction);
|
||||
}
|
||||
|
||||
private boolean tryFocusFinder(int direction) {
|
||||
private boolean tryFocusFinder(final int direction) {
|
||||
if (Build.VERSION.SDK_INT >= 28) {
|
||||
// Android 9 implemented bunch of handy changes to focus, that render code below less useful, and
|
||||
// also broke findNextFocusFromRect in way, that render this hack useless
|
||||
|
|
@ -180,7 +180,7 @@ public class NewPipeRecyclerView extends RecyclerView {
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean arrowScroll(int direction) {
|
||||
private boolean arrowScroll(final int direction) {
|
||||
switch (direction) {
|
||||
case FOCUS_DOWN:
|
||||
if (!canScrollVertically(1)) {
|
||||
|
|
@ -213,7 +213,7 @@ public class NewPipeRecyclerView extends RecyclerView {
|
|||
return true;
|
||||
}
|
||||
|
||||
private boolean isOutside(View view) {
|
||||
private boolean isOutside(final View view) {
|
||||
return findContainingItemView(view) == null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
package org.schabi.newpipe.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayout.Tab;
|
||||
|
||||
/**
|
||||
* A TabLayout that is scrollable when tabs exceed its width.
|
||||
|
|
@ -21,34 +18,36 @@ public class ScrollableTabLayout extends TabLayout {
|
|||
private int layoutWidth = 0;
|
||||
private int prevVisibility = View.GONE;
|
||||
|
||||
public ScrollableTabLayout(Context context) {
|
||||
public ScrollableTabLayout(final Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ScrollableTabLayout(Context context, AttributeSet attrs) {
|
||||
public ScrollableTabLayout(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ScrollableTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
public ScrollableTabLayout(final Context context, final AttributeSet attrs,
|
||||
final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
protected void onLayout(final boolean changed, final int l, final int t, final int r,
|
||||
final int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
|
||||
remeasureTabs();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
|
||||
layoutWidth = w;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(@NonNull Tab tab, int position, boolean setSelected) {
|
||||
public void addTab(@NonNull final Tab tab, final int position, final boolean setSelected) {
|
||||
super.addTab(tab, position, setSelected);
|
||||
|
||||
hasMultipleTabs();
|
||||
|
|
@ -60,22 +59,23 @@ public class ScrollableTabLayout extends TabLayout {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void removeTabAt(int position) {
|
||||
public void removeTabAt(final int position) {
|
||||
super.removeTabAt(position);
|
||||
|
||||
hasMultipleTabs();
|
||||
|
||||
// Removing a tab won't increase total tabs' width so tabMode won't have to change to SCROLLABLE
|
||||
// Removing a tab won't increase total tabs' width
|
||||
// so tabMode won't have to change to SCROLLABLE
|
||||
if (getTabMode() != MODE_FIXED) {
|
||||
remeasureTabs();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onVisibilityChanged(View changedView, int visibility) {
|
||||
protected void onVisibilityChanged(final View changedView, final int visibility) {
|
||||
super.onVisibilityChanged(changedView, visibility);
|
||||
|
||||
// Recheck content width in case some tabs have been added or removed while ScrollableTabLayout was invisible
|
||||
// Check width if some tabs have been added/removed while ScrollableTabLayout was invisible
|
||||
// We don't have to check if it was GONE because then requestLayout() will be called
|
||||
if (changedView == this) {
|
||||
if (prevVisibility == View.INVISIBLE) {
|
||||
|
|
@ -85,14 +85,16 @@ public class ScrollableTabLayout extends TabLayout {
|
|||
}
|
||||
}
|
||||
|
||||
private void setMode(int mode) {
|
||||
if (mode == getTabMode()) return;
|
||||
private void setMode(final int mode) {
|
||||
if (mode == getTabMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTabMode(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make ScrollableTabLayout not visible if there are less than two tabs
|
||||
* Make ScrollableTabLayout not visible if there are less than two tabs.
|
||||
*/
|
||||
private void hasMultipleTabs() {
|
||||
if (getTabCount() > 1) {
|
||||
|
|
@ -103,11 +105,15 @@ public class ScrollableTabLayout extends TabLayout {
|
|||
}
|
||||
|
||||
/**
|
||||
* Calculate minimal width required by tabs and set tabMode accordingly
|
||||
* Calculate minimal width required by tabs and set tabMode accordingly.
|
||||
*/
|
||||
private void remeasureTabs() {
|
||||
if (prevVisibility != View.VISIBLE) return;
|
||||
if (layoutWidth == 0) return;
|
||||
if (prevVisibility != View.VISIBLE) {
|
||||
return;
|
||||
}
|
||||
if (layoutWidth == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int count = getTabCount();
|
||||
int contentWidth = 0;
|
||||
|
|
|
|||
|
|
@ -34,12 +34,12 @@ public final class SuperScrollLayoutManager extends LinearLayoutManager {
|
|||
|
||||
private final ArrayList<View> focusables = new ArrayList<>();
|
||||
|
||||
public SuperScrollLayoutManager(Context context) {
|
||||
public SuperScrollLayoutManager(final Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requestChildRectangleOnScreen(@NonNull RecyclerView parent, @NonNull View child, @NonNull Rect rect, boolean immediate, boolean focusedChildVisible) {
|
||||
public boolean requestChildRectangleOnScreen(@NonNull final RecyclerView parent, @NonNull final View child, @NonNull final Rect rect, final boolean immediate, final boolean focusedChildVisible) {
|
||||
if (!parent.isInTouchMode()) {
|
||||
// only activate when in directional navigation mode (Android TV etc) — fine grained
|
||||
// touch scrolling is better served by nested scroll system
|
||||
|
|
@ -58,7 +58,7 @@ public final class SuperScrollLayoutManager extends LinearLayoutManager {
|
|||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onInterceptFocusSearch(@NonNull View focused, int direction) {
|
||||
public View onInterceptFocusSearch(@NonNull final View focused, final int direction) {
|
||||
View focusedItem = findContainingItemView(focused);
|
||||
if (focusedItem == null) {
|
||||
return super.onInterceptFocusSearch(focused, direction);
|
||||
|
|
@ -121,7 +121,7 @@ public final class SuperScrollLayoutManager extends LinearLayoutManager {
|
|||
return preferred;
|
||||
}
|
||||
|
||||
private int getAbsoluteDirection(int direction) {
|
||||
private int getAbsoluteDirection(final int direction) {
|
||||
switch (direction) {
|
||||
default:
|
||||
break;
|
||||
|
|
@ -154,7 +154,7 @@ public final class SuperScrollLayoutManager extends LinearLayoutManager {
|
|||
return 0;
|
||||
}
|
||||
|
||||
private int getDistance(int sourcePosition, View candidate, int direction) {
|
||||
private int getDistance(final int sourcePosition, final View candidate, final int direction) {
|
||||
View itemView = findContainingItemView(candidate);
|
||||
if (itemView == null) {
|
||||
return -1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue