AppBarLayout scrolling awesomeness, PlayQueue layout touches interception, player's controls' margin
- made scrolling in appBarLayout awesome - PlayQueue layout was intercepting touches while it was in GONE visibility state. Now it's not gonna happen - removed margin between two lines of player's controls - when a user leaves the app with two back presses the app will not stop MainPlayer service if popup or background players play
This commit is contained in:
parent
f334a2740f
commit
a47e6dd8c5
8 changed files with 69 additions and 102 deletions
|
@ -23,14 +23,14 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean allowScroll = true;
|
private boolean allowScroll = true;
|
||||||
private Rect playQueueRect = new Rect();
|
private Rect globalRect = new Rect();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
|
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
|
||||||
ViewGroup playQueue = child.findViewById(R.id.playQueue);
|
ViewGroup playQueue = child.findViewById(R.id.playQueuePanel);
|
||||||
if (playQueue != null) {
|
if (playQueue != null) {
|
||||||
playQueue.getGlobalVisibleRect(playQueueRect);
|
boolean visible = playQueue.getGlobalVisibleRect(globalRect);
|
||||||
if (playQueueRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
|
if (visible && globalRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
|
||||||
allowScroll = false;
|
allowScroll = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -403,8 +403,9 @@ public class VideoDetailFragment
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|
||||||
if (!activity.isFinishing()) unbind();
|
// Stop the service when user leaves the app with double back press if video player is selected. Otherwise unbind
|
||||||
else stopService();
|
if (activity.isFinishing() && player != null && player.videoPlayerSelected()) stopService();
|
||||||
|
else unbind();
|
||||||
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(activity)
|
PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
.unregisterOnSharedPreferenceChangeListener(this);
|
.unregisterOnSharedPreferenceChangeListener(this);
|
||||||
|
|
|
@ -306,6 +306,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
playerCloseButton.setVisibility(View.GONE);
|
playerCloseButton.setVisibility(View.GONE);
|
||||||
getTopControlsRoot().bringToFront();
|
getTopControlsRoot().bringToFront();
|
||||||
getBottomControlsRoot().bringToFront();
|
getBottomControlsRoot().bringToFront();
|
||||||
|
onQueueClosed();
|
||||||
} else {
|
} else {
|
||||||
fullscreenButton.setVisibility(View.GONE);
|
fullscreenButton.setVisibility(View.GONE);
|
||||||
setupScreenRotationButton(service.isLandscape());
|
setupScreenRotationButton(service.isLandscape());
|
||||||
|
@ -678,7 +679,10 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
|
|
||||||
private void onQueueClosed() {
|
private void onQueueClosed() {
|
||||||
animateView(queueLayout, SLIDE_AND_ALPHA, /*visible=*/false,
|
animateView(queueLayout, SLIDE_AND_ALPHA, /*visible=*/false,
|
||||||
DEFAULT_CONTROLS_DURATION);
|
DEFAULT_CONTROLS_DURATION, 0, () -> {
|
||||||
|
// Even when queueLayout is GONE it receives touch events and ruins normal behavior of the app. This line fixes it
|
||||||
|
queueLayout.setTranslationY(-queueLayout.getHeight() * 5);
|
||||||
|
});
|
||||||
queueVisible = false;
|
queueVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,62 +4,47 @@ import android.content.Context;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
public class CustomBottomSheetBehavior extends BottomSheetBehavior {
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout> {
|
||||||
|
|
||||||
public CustomBottomSheetBehavior(Context context, AttributeSet attrs) {
|
public CustomBottomSheetBehavior(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean skippingInterception = false;
|
boolean visible;
|
||||||
|
Rect globalRect = new Rect();
|
||||||
|
private boolean skippingInterception = false;
|
||||||
|
private List<Integer> skipInterceptionOfElements = Arrays.asList(
|
||||||
|
R.id.detail_content_root_layout, R.id.relatedStreamsLayout, R.id.playQueuePanel, R.id.viewpager);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent event) {
|
public boolean onInterceptTouchEvent(@NonNull CoordinatorLayout parent, @NonNull FrameLayout child, MotionEvent event) {
|
||||||
// Behavior of globalVisibleRect is different on different APIs.
|
// Drop following when action ends
|
||||||
// For example, on API 19 getGlobalVisibleRect returns a filled rect of a collapsed view while on the latest API
|
|
||||||
// it returns empty rect in that case. So check visibility with return value too
|
|
||||||
boolean visible;
|
|
||||||
Rect rect = new Rect();
|
|
||||||
|
|
||||||
// Drop folowing when actions ends
|
|
||||||
if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP)
|
if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP)
|
||||||
skippingInterception = false;
|
skippingInterception = false;
|
||||||
|
|
||||||
// Found that user still swipping, continue folowing
|
// Found that user still swiping, continue following
|
||||||
if (skippingInterception) return false;
|
if (skippingInterception) return false;
|
||||||
|
|
||||||
// Without overriding scrolling will not work in detail_content_root_layout
|
// Without overriding scrolling will not work when user touches these elements
|
||||||
ViewGroup controls = child.findViewById(R.id.detail_content_root_layout);
|
for (Integer element : skipInterceptionOfElements) {
|
||||||
if (controls != null) {
|
ViewGroup viewGroup = child.findViewById(element);
|
||||||
visible = controls.getGlobalVisibleRect(rect);
|
if (viewGroup != null) {
|
||||||
if (rect.contains((int) event.getRawX(), (int) event.getRawY()) && visible) {
|
visible = viewGroup.getGlobalVisibleRect(globalRect);
|
||||||
|
if (visible && globalRect.contains((int) event.getRawX(), (int) event.getRawY())) {
|
||||||
skippingInterception = true;
|
skippingInterception = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Without overriding scrolling will not work on relatedStreamsLayout
|
|
||||||
ViewGroup relatedStreamsLayout = child.findViewById(R.id.relatedStreamsLayout);
|
|
||||||
if (relatedStreamsLayout != null) {
|
|
||||||
visible = relatedStreamsLayout.getGlobalVisibleRect(rect);
|
|
||||||
if (rect.contains((int) event.getRawX(), (int) event.getRawY()) && visible) {
|
|
||||||
skippingInterception = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewGroup playQueue = child.findViewById(R.id.playQueue);
|
|
||||||
if (playQueue != null) {
|
|
||||||
visible = playQueue.getGlobalVisibleRect(rect);
|
|
||||||
if (rect.contains((int) event.getRawX(), (int) event.getRawY()) && visible) {
|
|
||||||
skippingInterception = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onInterceptTouchEvent(parent, child, event);
|
return super.onInterceptTouchEvent(parent, child, event);
|
||||||
|
|
|
@ -157,7 +157,6 @@
|
||||||
android:minHeight="50dp"
|
android:minHeight="50dp"
|
||||||
android:baselineAligned="false"
|
android:baselineAligned="false"
|
||||||
android:gravity="top"
|
android:gravity="top"
|
||||||
android:layout_marginBottom="7dp"
|
|
||||||
tools:ignore="RtlHardcoded">
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
|
|
@ -22,30 +22,6 @@
|
||||||
android:layout_weight="5"
|
android:layout_weight="5"
|
||||||
android:fitsSystemWindows="true">
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
|
||||||
android:fillViewport="true">
|
|
||||||
|
|
||||||
<androidx.viewpager.widget.ViewPager
|
|
||||||
android:id="@+id/viewpager"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" >
|
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabLayout
|
|
||||||
android:id="@+id/tablayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:layout_gravity="bottom|center"
|
|
||||||
app:tabBackground="@drawable/tab_selector"
|
|
||||||
app:tabGravity="center"
|
|
||||||
app:tabIndicatorHeight="0dp"/>
|
|
||||||
|
|
||||||
</androidx.viewpager.widget.ViewPager>
|
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appbarlayout"
|
android:id="@+id/appbarlayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -541,6 +517,23 @@
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.viewpager.widget.ViewPager
|
||||||
|
android:id="@+id/viewpager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabLayout
|
||||||
|
android:id="@+id/tablayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="bottom|center"
|
||||||
|
app:tabBackground="@drawable/tab_selector"
|
||||||
|
app:tabGravity="center"
|
||||||
|
app:tabIndicatorHeight="0dp"/>
|
||||||
|
|
||||||
|
</androidx.viewpager.widget.ViewPager>
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
|
|
@ -155,7 +155,6 @@
|
||||||
android:minHeight="50dp"
|
android:minHeight="50dp"
|
||||||
android:baselineAligned="false"
|
android:baselineAligned="false"
|
||||||
android:gravity="top"
|
android:gravity="top"
|
||||||
android:layout_marginBottom="7dp"
|
|
||||||
tools:ignore="RtlHardcoded">
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
|
|
@ -13,37 +13,6 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<!--
|
|
||||||
You may wonder why this NestedScrollView locates on top of the file. That's because BottomSheetBehavior
|
|
||||||
can work well only with one element that implements nested scrolling. But we have two:
|
|
||||||
one NestedScrollView for ViewPager with id = viewpager here
|
|
||||||
second ViewPager with id = playQueue inside activity_main_player.xml.
|
|
||||||
By placing this NestedScrollView on top of the file we are getting this ViewPager working -->
|
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
|
||||||
android:fillViewport="true">
|
|
||||||
|
|
||||||
<androidx.viewpager.widget.ViewPager
|
|
||||||
android:id="@+id/viewpager"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" >
|
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabLayout
|
|
||||||
android:id="@+id/tablayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:layout_gravity="bottom|center"
|
|
||||||
app:tabBackground="@drawable/tab_selector"
|
|
||||||
app:tabGravity="center"
|
|
||||||
app:tabIndicatorHeight="0dp"/>
|
|
||||||
|
|
||||||
</androidx.viewpager.widget.ViewPager>
|
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appbarlayout"
|
android:id="@+id/appbarlayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -541,6 +510,23 @@
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.viewpager.widget.ViewPager
|
||||||
|
android:id="@+id/viewpager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabLayout
|
||||||
|
android:id="@+id/tablayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="bottom|center"
|
||||||
|
app:tabBackground="@drawable/tab_selector"
|
||||||
|
app:tabGravity="center"
|
||||||
|
app:tabIndicatorHeight="0dp"/>
|
||||||
|
|
||||||
|
</androidx.viewpager.widget.ViewPager>
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
|
Loading…
Reference in a new issue