1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2024-06-25 22:53:20 +00:00

Fix views not scrollable when showing error panel

This commit is contained in:
Stypox 2021-01-15 11:26:09 +01:00
parent 463dd8ea74
commit b265cabc22
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
9 changed files with 70 additions and 48 deletions

View File

@ -1,9 +1,11 @@
package org.schabi.newpipe.fragments; package org.schabi.newpipe.fragments;
import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -135,7 +137,12 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
public void handleError() { public void handleError() {
isLoading.set(false); isLoading.set(false);
InfoCache.getInstance().clearCache(); InfoCache.getInstance().clearCache();
hideLoading(); if (emptyStateView != null) {
animateView(emptyStateView, false, 150);
}
if (loadingProgressBar != null) {
animateView(loadingProgressBar, false, 0);
}
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -178,7 +185,7 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
/** /**
* Show a SnackBar and only call * Show a SnackBar and only call
* {@link ErrorActivity.reportErrorInSnackbar(androidx.fragment.app.Fragment, ErrorInfo)} * {@link ErrorActivity#reportErrorInSnackbar(androidx.fragment.app.Fragment, ErrorInfo)}
* IF we a find a valid view (otherwise the error screen appears). * IF we a find a valid view (otherwise the error screen appears).
* *
* @param errorInfo The error information * @param errorInfo The error information

View File

@ -11,9 +11,18 @@ import org.schabi.newpipe.BaseFragment;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
public class EmptyFragment extends BaseFragment { public class EmptyFragment extends BaseFragment {
final boolean showMessage;
public EmptyFragment(final boolean showMessage) {
this.showMessage = showMessage;
}
@Override @Override
public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container, public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
final Bundle savedInstanceState) { final Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_empty, container, false); final View view = inflater.inflate(R.layout.fragment_empty, container, false);
view.findViewById(R.id.empty_state_view).setVisibility(
showMessage ? View.VISIBLE : View.GONE);
return view;
} }
} }

View File

@ -41,7 +41,6 @@ import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
@ -71,6 +70,7 @@ import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.BackPressable; import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.fragments.EmptyFragment;
import org.schabi.newpipe.fragments.list.comments.CommentsFragment; import org.schabi.newpipe.fragments.list.comments.CommentsFragment;
import org.schabi.newpipe.fragments.list.videos.RelatedVideosFragment; import org.schabi.newpipe.fragments.list.videos.RelatedVideosFragment;
import org.schabi.newpipe.ktx.AnimationType; import org.schabi.newpipe.ktx.AnimationType;
@ -926,18 +926,22 @@ public final class VideoDetailFragment
} }
if (showRelatedStreams && binding.relatedStreamsLayout == null) { if (showRelatedStreams && binding.relatedStreamsLayout == null) {
//temp empty fragment. will be updated in handleResult // temp empty fragment. will be updated in handleResult
pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG); pageAdapter.addFragment(new EmptyFragment(false), RELATED_TAB_TAG);
tabIcons.add(R.drawable.ic_art_track_white_24dp); tabIcons.add(R.drawable.ic_art_track_white_24dp);
tabContentDescriptions.add(R.string.related_streams_tab_description); tabContentDescriptions.add(R.string.related_streams_tab_description);
} }
if (showDescription) { if (showDescription) {
// temp empty fragment. will be updated in handleResult // temp empty fragment. will be updated in handleResult
pageAdapter.addFragment(new Fragment(), DESCRIPTION_TAB_TAG); pageAdapter.addFragment(new EmptyFragment(false), DESCRIPTION_TAB_TAG);
tabIcons.add(R.drawable.ic_description_white_24dp); tabIcons.add(R.drawable.ic_description_white_24dp);
tabContentDescriptions.add(R.string.description_tab_description); tabContentDescriptions.add(R.string.description_tab_description);
} }
if (pageAdapter.getCount() == 0) {
pageAdapter.addFragment(new EmptyFragment(true), EMPTY_TAB_TAG);
}
pageAdapter.notifyDataSetUpdate(); pageAdapter.notifyDataSetUpdate();
if (pageAdapter.getCount() >= 2) { if (pageAdapter.getCount() >= 2) {

View File

@ -46,6 +46,7 @@ import java.util.List;
import java.util.Queue; import java.util.Queue;
import static org.schabi.newpipe.ktx.ViewUtils.animate; import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
implements ListViewContract<I, N>, StateSaver.WriteRead, implements ListViewContract<I, N>, StateSaver.WriteRead,
@ -407,6 +408,12 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
// Contract // Contract
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override
public void showLoading() {
super.showLoading();
animateHideRecyclerViewAllowingScrolling(itemsList);
}
@Override @Override
public void hideLoading() { public void hideLoading() {
super.hideLoading(); super.hideLoading();
@ -417,6 +424,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
public void showEmptyState() { public void showEmptyState() {
super.showEmptyState(); super.showEmptyState();
showListFooter(false); showListFooter(false);
animateHideRecyclerViewAllowingScrolling(itemsList);
} }
@Override @Override
@ -437,7 +445,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
public void handleError() { public void handleError() {
super.handleError(); super.handleError();
showListFooter(false); showListFooter(false);
animate(itemsList, false, 200); animateHideRecyclerViewAllowingScrolling(itemsList);
} }
@Override @Override

View File

@ -29,8 +29,6 @@ import org.schabi.newpipe.util.Localization;
import icepick.State; import icepick.State;
import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.core.Single;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
/** /**
* Created by Christian Schabesberger on 23.09.17. * Created by Christian Schabesberger on 23.09.17.
* <p> * <p>
@ -160,12 +158,6 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
// Contract // Contract
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override
public void showLoading() {
super.showLoading();
animate(itemsList, false, 100);
}
@Override @Override
public void handleResult(@NonNull final KioskInfo result) { public void handleResult(@NonNull final KioskInfo result) {
super.handleResult(result); super.handleResult(result);

View File

@ -60,6 +60,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.disposables.Disposable;
import static org.schabi.newpipe.ktx.ViewUtils.animate; import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr; import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr;
public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
@ -264,7 +265,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
public void showLoading() { public void showLoading() {
super.showLoading(); super.showLoading();
animate(headerBinding.getRoot(), false, 200); animate(headerBinding.getRoot(), false, 200);
animate(itemsList, false, 100); animateHideRecyclerViewAllowingScrolling(itemsList);
IMAGE_LOADER.cancelDisplayTask(headerBinding.uploaderAvatarView); IMAGE_LOADER.cancelDisplayTask(headerBinding.uploaderAvatarView);
animate(headerBinding.uploaderLayout, false, 200); animate(headerBinding.uploaderLayout, false, 200);

View File

@ -35,11 +35,11 @@ inline var View.backgroundTintListCompat: ColorStateList?
*/ */
@JvmOverloads @JvmOverloads
fun View.animate( fun View.animate(
enterOrExit: Boolean, enterOrExit: Boolean,
duration: Long, duration: Long,
animationType: AnimationType = AnimationType.ALPHA, animationType: AnimationType = AnimationType.ALPHA,
delay: Long = 0, delay: Long = 0,
execOnEnd: Runnable? = null execOnEnd: Runnable? = null
) { ) {
if (MainActivity.DEBUG) { if (MainActivity.DEBUG) {
val id = try { val id = try {
@ -48,8 +48,8 @@ fun View.animate(
id.toString() id.toString()
} }
val msg = String.format( val msg = String.format(
"%8s → [%s:%s] [%s %s:%s] execOnEnd=%s", enterOrExit, "%8s → [%s:%s] [%s %s:%s] execOnEnd=%s", enterOrExit,
javaClass.simpleName, id, animationType, duration, delay, execOnEnd javaClass.simpleName, id, animationType, duration, delay, execOnEnd
) )
Log.d(TAG, "animate(): $msg") Log.d(TAG, "animate(): $msg")
} }
@ -93,10 +93,10 @@ fun View.animate(
fun View.animateBackgroundColor(duration: Long, @ColorInt colorStart: Int, @ColorInt colorEnd: Int) { fun View.animateBackgroundColor(duration: Long, @ColorInt colorStart: Int, @ColorInt colorEnd: Int) {
if (MainActivity.DEBUG) { if (MainActivity.DEBUG) {
Log.d( Log.d(
TAG, TAG,
"animateBackgroundColor() called with: " + "animateBackgroundColor() called with: " +
"view = [" + this + "], duration = [" + duration + "], " + "view = [" + this + "], duration = [" + duration + "], " +
"colorStart = [" + colorStart + "], colorEnd = [" + colorEnd + "]" "colorStart = [" + colorStart + "], colorEnd = [" + colorEnd + "]"
) )
} }
val empty = arrayOf(IntArray(0)) val empty = arrayOf(IntArray(0))
@ -121,9 +121,9 @@ fun View.animateBackgroundColor(duration: Long, @ColorInt colorStart: Int, @Colo
fun View.animateHeight(duration: Long, targetHeight: Int): ValueAnimator { fun View.animateHeight(duration: Long, targetHeight: Int): ValueAnimator {
if (MainActivity.DEBUG) { if (MainActivity.DEBUG) {
Log.d( Log.d(
TAG, TAG,
"animateHeight: duration = [" + duration + "], " + "animateHeight: duration = [" + duration + "], " +
"from " + height + " to → " + targetHeight + " in: " + this "from " + height + " to → " + targetHeight + " in: " + this
) )
} }
val animator = ValueAnimator.ofFloat(height.toFloat(), targetHeight.toFloat()) val animator = ValueAnimator.ofFloat(height.toFloat(), targetHeight.toFloat())
@ -152,9 +152,9 @@ fun View.animateHeight(duration: Long, targetHeight: Int): ValueAnimator {
fun View.animateRotation(duration: Long, targetRotation: Int) { fun View.animateRotation(duration: Long, targetRotation: Int) {
if (MainActivity.DEBUG) { if (MainActivity.DEBUG) {
Log.d( Log.d(
TAG, TAG,
"animateRotation: duration = [" + duration + "], " + "animateRotation: duration = [" + duration + "], " +
"from " + rotation + " to → " + targetRotation + " in: " + this "from " + rotation + " to → " + targetRotation + " in: " + this
) )
} }
animate().setListener(null).cancel() animate().setListener(null).cancel()
@ -319,6 +319,17 @@ fun View.slideUp(duration: Long, delay: Long, @FloatRange(from = 0.0, to = 1.0)
.start() .start()
} }
/**
* Instead of hiding normally using [animate], which would make
* the recycler view unable to capture touches after being hidden, this just animates the alpha
* value setting it to `0.0` after `200` milliseconds.
*/
fun View.animateHideRecyclerViewAllowingScrolling() {
// not hiding normally because the view needs to still capture touches and allow scroll
animate().alpha(0.0f).setDuration(200).start()
}
enum class AnimationType { enum class AnimationType {
ALPHA, SCALE_AND_ALPHA, LIGHT_SCALE_AND_ALPHA, SLIDE_AND_ALPHA, LIGHT_SLIDE_AND_ALPHA ALPHA, SCALE_AND_ALPHA, LIGHT_SCALE_AND_ALPHA, SLIDE_AND_ALPHA, LIGHT_SLIDE_AND_ALPHA
} }

View File

@ -24,6 +24,7 @@ import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.fragments.list.ListViewContract; import org.schabi.newpipe.fragments.list.ListViewContract;
import static org.schabi.newpipe.ktx.ViewUtils.animate; import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
/** /**
* This fragment is design to be used with persistent data such as * This fragment is design to be used with persistent data such as
@ -184,7 +185,7 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
public void showLoading() { public void showLoading() {
super.showLoading(); super.showLoading();
if (itemsList != null) { if (itemsList != null) {
animate(itemsList, false, 200); animateHideRecyclerViewAllowingScrolling(itemsList);
} }
if (headerRootBinding != null) { if (headerRootBinding != null) {
animate(headerRootBinding.getRoot(), false, 200); animate(headerRootBinding.getRoot(), false, 200);
@ -243,7 +244,7 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
showListFooter(false); showListFooter(false);
if (itemsList != null) { if (itemsList != null) {
animate(itemsList, false, 200); animateHideRecyclerViewAllowingScrolling(itemsList);
} }
if (headerRootBinding != null) { if (headerRootBinding != null) {
animate(headerRootBinding.getRoot(), false, 200); animate(headerRootBinding.getRoot(), false, 200);

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -14,16 +13,6 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:layout_marginTop="90dp" android:layout_marginTop="90dp" />
tools:visibility="visible" />
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>
<View
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_alignParentTop="true"
android:background="?attr/toolbar_shadow"
android:visibility="gone" />
</RelativeLayout> </RelativeLayout>