Convert AnimationUtils functions to extension functions.

This commit is contained in:
Isira Seneviratne 2021-01-16 09:02:01 +05:30
parent 0d33f8b460
commit 920e560b4b
25 changed files with 568 additions and 687 deletions

View File

@ -37,7 +37,7 @@ import icepick.State;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.Disposable;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
public abstract class BaseStateFragment<I> extends BaseFragment implements ViewContract<I> {
@State
@ -131,35 +131,35 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
@Override
public void showLoading() {
if (emptyStateView != null) {
animateView(emptyStateView, false, 150);
animate(emptyStateView, false, 150);
}
if (loadingProgressBar != null) {
animateView(loadingProgressBar, true, 400);
animate(loadingProgressBar, true, 400);
}
animateView(errorPanelRoot, false, 150);
animate(errorPanelRoot, false, 150);
}
@Override
public void hideLoading() {
if (emptyStateView != null) {
animateView(emptyStateView, false, 150);
animate(emptyStateView, false, 150);
}
if (loadingProgressBar != null) {
animateView(loadingProgressBar, false, 0);
animate(loadingProgressBar, false, 0);
}
animateView(errorPanelRoot, false, 150);
animate(errorPanelRoot, false, 150);
}
@Override
public void showEmptyState() {
isLoading.set(false);
if (emptyStateView != null) {
animateView(emptyStateView, true, 200);
animate(emptyStateView, true, 200);
}
if (loadingProgressBar != null) {
animateView(loadingProgressBar, false, 0);
animate(loadingProgressBar, false, 0);
}
animateView(errorPanelRoot, false, 150);
animate(errorPanelRoot, false, 150);
}
@Override
@ -174,11 +174,11 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
errorTextView.setText(message);
if (showRetryButton) {
animateView(errorButtonRetry, true, 600);
animate(errorButtonRetry, true, 600);
} else {
animateView(errorButtonRetry, false, 0);
animate(errorButtonRetry, false, 0);
}
animateView(errorPanelRoot, true, 300);
animate(errorPanelRoot, true, 300);
}
@Override

View File

@ -76,11 +76,12 @@ 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.videos.RelatedVideosFragment;
import org.schabi.newpipe.ktx.AnimationType;
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.local.dialog.PlaylistCreationDialog;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.MainPlayer;
import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.event.OnKeyDownListener;
import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener;
import org.schabi.newpipe.player.helper.PlayerHelper;
@ -125,7 +126,7 @@ import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
public final class VideoDetailFragment
@ -745,8 +746,10 @@ public final class VideoDetailFragment
}
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
animateView(appendControlsDetail, true, 250, 0, () ->
animateView(appendControlsDetail, false, 1500, 1000));
animate(appendControlsDetail, true, 250, AnimationType.ALPHA,
0, () ->
animate(appendControlsDetail, false, 1500,
AnimationType.ALPHA, 1000));
}
return false;
};
@ -1334,8 +1337,8 @@ public final class VideoDetailFragment
thumbnailImageView.setImageDrawable(
AppCompatResources.getDrawable(requireContext(), imageResource));
animateView(thumbnailImageView, false, 0, 0,
() -> animateView(thumbnailImageView, true, 500));
animate(thumbnailImageView, false, 0, AnimationType.ALPHA, 0,
() -> animate(thumbnailImageView, true, 500));
}
@Override
@ -1417,14 +1420,14 @@ public final class VideoDetailFragment
contentRootLayoutHiding.setVisibility(View.INVISIBLE);
}
animateView(thumbnailPlayButton, false, 50);
animateView(detailDurationView, false, 100);
animateView(detailPositionView, false, 100);
animateView(positionView, false, 50);
animate(thumbnailPlayButton, false, 50);
animate(detailDurationView, false, 100);
animate(detailPositionView, false, 100);
animate(positionView, false, 50);
videoTitleTextView.setText(title);
videoTitleTextView.setMaxLines(1);
animateView(videoTitleTextView, true, 0);
animate(videoTitleTextView, true, 0);
videoDescriptionRootLayout.setVisibility(View.GONE);
videoTitleToggleArrow.setVisibility(View.GONE);
@ -1466,7 +1469,7 @@ public final class VideoDetailFragment
player != null && player.isFullscreen() ? View.GONE : View.VISIBLE);
}
}
animateView(thumbnailPlayButton, true, 200);
animate(thumbnailPlayButton, true, 200);
videoTitleTextView.setText(title);
if (!isEmpty(info.getSubChannelName())) {
@ -1530,12 +1533,12 @@ public final class VideoDetailFragment
detailDurationView.setText(Localization.getDurationString(info.getDuration()));
detailDurationView.setBackgroundColor(
ContextCompat.getColor(activity, R.color.duration_background_color));
animateView(detailDurationView, true, 100);
animate(detailDurationView, true, 100);
} else if (info.getStreamType() == StreamType.LIVE_STREAM) {
detailDurationView.setText(R.string.duration_live);
detailDurationView.setBackgroundColor(
ContextCompat.getColor(activity, R.color.live_duration_background_color));
animateView(detailDurationView, true, 100);
animate(detailDurationView, true, 100);
} else {
detailDurationView.setVisibility(View.GONE);
}
@ -1703,8 +1706,8 @@ public final class VideoDetailFragment
// Show saved position from backStack if user allows it
showPlaybackProgress(playQueue.getItem().getRecoveryPosition(),
playQueue.getItem().getDuration() * 1000);
animateView(positionView, true, 500);
animateView(detailPositionView, true, 500);
animate(positionView, true, 500);
animate(detailPositionView, true, 500);
}
return;
}
@ -1718,8 +1721,8 @@ public final class VideoDetailFragment
.observeOn(AndroidSchedulers.mainThread())
.subscribe(state -> {
showPlaybackProgress(state.getProgressTime(), info.getDuration() * 1000);
animateView(positionView, true, 500);
animateView(detailPositionView, true, 500);
animate(positionView, true, 500);
animate(detailPositionView, true, 500);
}, e -> {
if (DEBUG) {
e.printStackTrace();
@ -1747,8 +1750,8 @@ public final class VideoDetailFragment
detailPositionView.setText(position);
}
if (positionView.getVisibility() != View.VISIBLE) {
animateView(positionView, true, 100);
animateView(detailPositionView, true, 100);
animate(positionView, true, 100);
animate(detailPositionView, true, 100);
}
}
@ -1802,8 +1805,8 @@ public final class VideoDetailFragment
&& player.getPlayQueue() != null
&& player.getPlayQueue().getItem() != null
&& player.getPlayQueue().getItem().getUrl().equals(url)) {
animateView(positionView, true, 100);
animateView(detailPositionView, true, 100);
animate(positionView, true, 100);
animate(detailPositionView, true, 100);
}
break;
}

View File

@ -46,7 +46,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Queue;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
implements ListViewContract<I, N>, StateSaver.WriteRead,
@ -406,23 +406,17 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
// Contract
//////////////////////////////////////////////////////////////////////////*/
@Override
public void showLoading() {
super.showLoading();
// animateView(itemsList, false, 400);
}
@Override
public void hideLoading() {
super.hideLoading();
animateView(itemsList, true, 300);
animate(itemsList, true, 300);
}
@Override
public void showError(final String message, final boolean showRetryButton) {
super.showError(message, showRetryButton);
showListFooter(false);
animateView(itemsList, false, 200);
animate(itemsList, false, 200);
}
@Override

View File

@ -37,12 +37,12 @@ import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.ktx.AnimationType;
import org.schabi.newpipe.local.subscription.SubscriptionManager;
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
@ -64,9 +64,9 @@ import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.functions.Function;
import io.reactivex.rxjava3.schedulers.Schedulers;
import static org.schabi.newpipe.util.AnimationUtils.animateBackgroundColor;
import static org.schabi.newpipe.util.AnimationUtils.animateTextColor;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor;
public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
implements View.OnClickListener {
@ -224,7 +224,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
private void monitorSubscription(final ChannelInfo info) {
final Consumer<Throwable> onError = (Throwable throwable) -> {
animateView(headerBinding.channelSubscribeButton, false, 100);
animate(headerBinding.channelSubscribeButton, false, 100);
showSnackBarError(throwable, UserAction.SUBSCRIPTION,
NewPipe.getNameOfService(currentInfo.getServiceId()),
"Get subscription status", 0);
@ -379,8 +379,8 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
subscribedText);
}
animateView(headerBinding.channelSubscribeButton, AnimationUtils.Type.LIGHT_SCALE_AND_ALPHA,
true, 100);
animate(headerBinding.channelSubscribeButton, true, 100,
AnimationType.LIGHT_SCALE_AND_ALPHA);
}
/*//////////////////////////////////////////////////////////////////////////
@ -436,7 +436,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
IMAGE_LOADER.cancelDisplayTask(headerBinding.channelBannerImage);
IMAGE_LOADER.cancelDisplayTask(headerBinding.channelAvatarView);
IMAGE_LOADER.cancelDisplayTask(headerBinding.subChannelAvatarView);
animateView(headerBinding.channelSubscribeButton, false, 100);
animate(headerBinding.channelSubscribeButton, false, 100);
}
@Override

View File

@ -16,8 +16,8 @@ import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.comments.CommentsInfo;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.ktx.ViewUtils;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ExtractorHelper;
import io.reactivex.rxjava3.core.Single;
@ -84,16 +84,14 @@ public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> {
public void handleResult(@NonNull final CommentsInfo result) {
super.handleResult(result);
AnimationUtils.slideUp(requireView(), 120, 150, 0.06f);
ViewUtils.slideUp(requireView(), 120, 150, 0.06f);
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS,
NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0);
}
if (disposables != null) {
disposables.clear();
}
disposables.clear();
}
@Override

View File

@ -28,7 +28,7 @@ import org.schabi.newpipe.util.Localization;
import icepick.State;
import io.reactivex.rxjava3.core.Single;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
/**
* Created by Christian Schabesberger on 23.09.17.
@ -160,7 +160,7 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
@Override
public void showLoading() {
super.showLoading();
animateView(itemsList, false, 100);
animate(itemsList, false, 100);
}
@Override

View File

@ -61,7 +61,7 @@ import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr;
public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
@ -261,19 +261,19 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
@Override
public void showLoading() {
super.showLoading();
animateView(headerBinding.getRoot(), false, 200);
animateView(itemsList, false, 100);
animate(headerBinding.getRoot(), false, 200);
animate(itemsList, false, 100);
IMAGE_LOADER.cancelDisplayTask(headerBinding.uploaderAvatarView);
animateView(headerBinding.uploaderLayout, false, 200);
animate(headerBinding.uploaderLayout, false, 200);
}
@Override
public void handleResult(@NonNull final PlaylistInfo result) {
super.handleResult(result);
animateView(headerBinding.getRoot(), true, 100);
animateView(headerBinding.uploaderLayout, true, 300);
animate(headerBinding.getRoot(), true, 100);
animate(headerBinding.uploaderLayout, true, 300);
headerBinding.uploaderLayout.setOnClickListener(null);
// If we have an uploader put them into the UI
if (!TextUtils.isEmpty(result.getUploaderName())) {

View File

@ -51,12 +51,12 @@ import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearch
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory;
import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.list.BaseListFragment;
import org.schabi.newpipe.ktx.AnimationType;
import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.ErrorInfo;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ExtractorHelper;
@ -82,7 +82,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject;
import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags;
import static java.util.Arrays.asList;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage<?>>
@ -413,7 +413,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
searchEditText.setText("");
showKeyboardSearch();
}
animateView(errorPanelRoot, false, 200);
animate(errorPanelRoot, false, 200);
}
}
@ -644,8 +644,8 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
Log.d(TAG, "showSuggestionsPanel() called");
}
suggestionsPanelVisible = true;
animateView(searchBinding.suggestionsPanel, AnimationUtils.Type.LIGHT_SLIDE_AND_ALPHA,
true, 200);
animate(searchBinding.suggestionsPanel, true, 200,
AnimationType.LIGHT_SLIDE_AND_ALPHA);
}
private void hideSuggestionsPanel() {
@ -653,8 +653,8 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
Log.d(TAG, "hideSuggestionsPanel() called");
}
suggestionsPanelVisible = false;
animateView(searchBinding.suggestionsPanel, AnimationUtils.Type.LIGHT_SLIDE_AND_ALPHA,
false, 200);
animate(searchBinding.suggestionsPanel, false, 200,
AnimationType.LIGHT_SLIDE_AND_ALPHA);
}
private void showKeyboardSearch() {

View File

@ -20,8 +20,8 @@ import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.ktx.ViewUtils;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.RelatedStreamInfo;
import java.io.Serializable;
@ -123,7 +123,7 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
if (headerBinding != null) {
headerBinding.getRoot().setVisibility(View.VISIBLE);
}
AnimationUtils.slideUp(getView(), 120, 96, 0.06f);
ViewUtils.slideUp(requireView(), 120, 96, 0.06f);
if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(), UserAction.REQUESTED_STREAM,

View File

@ -13,8 +13,8 @@ import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.ktx.ViewUtils;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.views.AnimatedProgressBar;
@ -125,10 +125,10 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
} else {
itemProgressView.setProgress((int) TimeUnit.MILLISECONDS
.toSeconds(state.getProgressTime()));
AnimationUtils.animateView(itemProgressView, true, 500);
ViewUtils.animate(itemProgressView, true, 500);
}
} else if (itemProgressView.getVisibility() == View.VISIBLE) {
AnimationUtils.animateView(itemProgressView, false, 500);
ViewUtils.animate(itemProgressView, false, 500);
}
}

View File

@ -0,0 +1,47 @@
@file:JvmName("TextViewUtils")
package org.schabi.newpipe.ktx
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ArgbEvaluator
import android.animation.ValueAnimator
import android.util.Log
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import org.schabi.newpipe.MainActivity
private const val TAG = "TextViewUtils"
/**
* Animate the text color of any view that extends [TextView] (Buttons, EditText...).
*
* @param duration the duration of the animation
* @param colorStart the text color to start with
* @param colorEnd the text color to end with
*/
fun TextView.animateTextColor(duration: Long, @ColorInt colorStart: Int, @ColorInt colorEnd: Int) {
if (MainActivity.DEBUG) {
Log.d(
TAG,
"animateTextColor() called with: " +
"view = [" + this + "], duration = [" + duration + "], " +
"colorStart = [" + colorStart + "], colorEnd = [" + colorEnd + "]"
)
}
val viewPropertyAnimator = ValueAnimator.ofObject(ArgbEvaluator(), colorStart, colorEnd)
viewPropertyAnimator.interpolator = FastOutSlowInInterpolator()
viewPropertyAnimator.duration = duration
viewPropertyAnimator.addUpdateListener { setTextColor(it.animatedValue as Int) }
viewPropertyAnimator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
setTextColor(colorEnd)
}
override fun onAnimationCancel(animation: Animator) {
setTextColor(colorEnd)
}
})
viewPropertyAnimator.start()
}

View File

@ -0,0 +1,324 @@
@file:JvmName("ViewUtils")
package org.schabi.newpipe.ktx
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ArgbEvaluator
import android.animation.ValueAnimator
import android.content.res.ColorStateList
import android.util.Log
import android.view.View
import androidx.annotation.ColorInt
import androidx.annotation.FloatRange
import androidx.core.view.ViewCompat
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import org.schabi.newpipe.MainActivity
private const val TAG = "ViewUtils"
inline var View.backgroundTintListCompat: ColorStateList?
get() = ViewCompat.getBackgroundTintList(this)
set(value) = ViewCompat.setBackgroundTintList(this, value)
/**
* Animate the view.
*
* @param enterOrExit true to enter, false to exit
* @param duration how long the animation will take, in milliseconds
* @param animationType Type of the animation
* @param delay how long the animation will wait to start, in milliseconds
* @param execOnEnd runnable that will be executed when the animation ends
*/
@JvmOverloads
fun View.animate(
enterOrExit: Boolean,
duration: Long,
animationType: AnimationType = AnimationType.ALPHA,
delay: Long = 0,
execOnEnd: Runnable? = null
) {
if (MainActivity.DEBUG) {
val id = try {
resources.getResourceEntryName(id)
} catch (e: Exception) {
id.toString() + ""
}
val msg = String.format(
"%8s → [%s:%s] [%s %s:%s] execOnEnd=%s", enterOrExit,
javaClass.simpleName, id, animationType, duration, delay, execOnEnd
)
Log.d(TAG, "animate(): $msg")
}
if (isVisible && enterOrExit) {
if (MainActivity.DEBUG) {
Log.d(TAG, "animate(): view was already visible > view = [$this]")
}
animate().setListener(null).cancel()
isVisible = true
alpha = 1f
execOnEnd?.run()
return
} else if ((isGone || isInvisible) && !enterOrExit) {
if (MainActivity.DEBUG) {
Log.d(TAG, "animate(): view was already gone > view = [$this]")
}
animate().setListener(null).cancel()
isGone = true
alpha = 0f
execOnEnd?.run()
return
}
animate().setListener(null).cancel()
isVisible = true
when (animationType) {
AnimationType.ALPHA -> animateAlpha(enterOrExit, duration, delay, execOnEnd)
AnimationType.SCALE_AND_ALPHA -> animateScaleAndAlpha(enterOrExit, duration, delay, execOnEnd)
AnimationType.LIGHT_SCALE_AND_ALPHA -> animateLightScaleAndAlpha(enterOrExit, duration, delay, execOnEnd)
AnimationType.SLIDE_AND_ALPHA -> animateSlideAndAlpha(enterOrExit, duration, delay, execOnEnd)
AnimationType.LIGHT_SLIDE_AND_ALPHA -> animateLightSlideAndAlpha(enterOrExit, duration, delay, execOnEnd)
}
}
/**
* Animate the background color of a view.
*
* @param duration the duration of the animation
* @param colorStart the background color to start with
* @param colorEnd the background color to end with
*/
fun View.animateBackgroundColor(duration: Long, @ColorInt colorStart: Int, @ColorInt colorEnd: Int) {
if (MainActivity.DEBUG) {
Log.d(
TAG,
"animateBackgroundColor() called with: " +
"view = [" + this + "], duration = [" + duration + "], " +
"colorStart = [" + colorStart + "], colorEnd = [" + colorEnd + "]"
)
}
val empty = arrayOf(IntArray(0))
val viewPropertyAnimator = ValueAnimator.ofObject(ArgbEvaluator(), colorStart, colorEnd)
viewPropertyAnimator.interpolator = FastOutSlowInInterpolator()
viewPropertyAnimator.duration = duration
viewPropertyAnimator.addUpdateListener { animation: ValueAnimator ->
backgroundTintListCompat = ColorStateList(empty, intArrayOf(animation.animatedValue as Int))
}
viewPropertyAnimator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
backgroundTintListCompat = ColorStateList(empty, intArrayOf(colorEnd))
}
override fun onAnimationCancel(animation: Animator) {
onAnimationEnd(animation)
}
})
viewPropertyAnimator.start()
}
fun View.animateHeight(duration: Long, targetHeight: Int): ValueAnimator {
if (MainActivity.DEBUG) {
Log.d(
TAG,
"animateHeight: duration = [" + duration + "], " +
"from " + height + " to → " + targetHeight + " in: " + this
)
}
val animator = ValueAnimator.ofFloat(height.toFloat(), targetHeight.toFloat())
animator.interpolator = FastOutSlowInInterpolator()
animator.duration = duration
animator.addUpdateListener { animation: ValueAnimator ->
val value = animation.animatedValue as Float
layoutParams.height = value.toInt()
requestLayout()
}
animator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
layoutParams.height = targetHeight
requestLayout()
}
override fun onAnimationCancel(animation: Animator) {
layoutParams.height = targetHeight
requestLayout()
}
})
animator.start()
return animator
}
fun View.animateRotation(duration: Long, targetRotation: Int) {
if (MainActivity.DEBUG) {
Log.d(
TAG,
"animateRotation: duration = [" + duration + "], " +
"from " + rotation + " to → " + targetRotation + " in: " + this
)
}
animate().setListener(null).cancel()
animate()
.rotation(targetRotation.toFloat()).setDuration(duration)
.setInterpolator(FastOutSlowInInterpolator())
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationCancel(animation: Animator) {
rotation = targetRotation.toFloat()
}
override fun onAnimationEnd(animation: Animator) {
rotation = targetRotation.toFloat()
}
}).start()
}
private fun View.animateAlpha(enterOrExit: Boolean, duration: Long, delay: Long, execOnEnd: Runnable?) {
if (enterOrExit) {
animate().setInterpolator(FastOutSlowInInterpolator()).alpha(1f)
.setDuration(duration).setStartDelay(delay)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
execOnEnd?.run()
}
}).start()
} else {
animate().setInterpolator(FastOutSlowInInterpolator()).alpha(0f)
.setDuration(duration).setStartDelay(delay)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
isGone = true
execOnEnd?.run()
}
}).start()
}
}
private fun View.animateScaleAndAlpha(enterOrExit: Boolean, duration: Long, delay: Long, execOnEnd: Runnable?) {
if (enterOrExit) {
scaleX = .8f
scaleY = .8f
animate()
.setInterpolator(FastOutSlowInInterpolator())
.alpha(1f).scaleX(1f).scaleY(1f)
.setDuration(duration).setStartDelay(delay)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
execOnEnd?.run()
}
}).start()
} else {
scaleX = 1f
scaleY = 1f
animate()
.setInterpolator(FastOutSlowInInterpolator())
.alpha(0f).scaleX(.8f).scaleY(.8f)
.setDuration(duration).setStartDelay(delay)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
isGone = true
execOnEnd?.run()
}
}).start()
}
}
private fun View.animateLightScaleAndAlpha(enterOrExit: Boolean, duration: Long, delay: Long, execOnEnd: Runnable?) {
if (enterOrExit) {
alpha = .5f
scaleX = .95f
scaleY = .95f
animate()
.setInterpolator(FastOutSlowInInterpolator())
.alpha(1f).scaleX(1f).scaleY(1f)
.setDuration(duration).setStartDelay(delay)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
execOnEnd?.run()
}
}).start()
} else {
alpha = 1f
scaleX = 1f
scaleY = 1f
animate()
.setInterpolator(FastOutSlowInInterpolator())
.alpha(0f).scaleX(.95f).scaleY(.95f)
.setDuration(duration).setStartDelay(delay)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
isGone = true
execOnEnd?.run()
}
}).start()
}
}
private fun View.animateSlideAndAlpha(enterOrExit: Boolean, duration: Long, delay: Long, execOnEnd: Runnable?) {
if (enterOrExit) {
translationY = -height.toFloat()
alpha = 0f
animate()
.setInterpolator(FastOutSlowInInterpolator()).alpha(1f).translationY(0f)
.setDuration(duration).setStartDelay(delay)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
execOnEnd?.run()
}
}).start()
} else {
animate()
.setInterpolator(FastOutSlowInInterpolator())
.alpha(0f).translationY(-height.toFloat())
.setDuration(duration).setStartDelay(delay)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
isGone = true
execOnEnd?.run()
}
}).start()
}
}
private fun View.animateLightSlideAndAlpha(enterOrExit: Boolean, duration: Long, delay: Long, execOnEnd: Runnable?) {
if (enterOrExit) {
translationY = -height / 2.0f
alpha = 0f
animate()
.setInterpolator(FastOutSlowInInterpolator()).alpha(1f).translationY(0f)
.setDuration(duration).setStartDelay(delay)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
execOnEnd?.run()
}
}).start()
} else {
animate().setInterpolator(FastOutSlowInInterpolator())
.alpha(0f).translationY(-height / 2.0f)
.setDuration(duration).setStartDelay(delay)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
isGone = true
execOnEnd?.run()
}
}).start()
}
}
fun View.slideUp(duration: Long, delay: Long, @FloatRange(from = 0.0, to = 1.0) translationPercent: Float) {
val newTranslationY = (resources.displayMetrics.heightPixels * translationPercent).toInt()
animate().setListener(null).cancel()
alpha = 0f
translationY = newTranslationY.toFloat()
visibility = View.VISIBLE
animate()
.alpha(1f)
.translationY(0f)
.setStartDelay(delay)
.setDuration(duration)
.setInterpolator(FastOutSlowInInterpolator())
.start()
}
enum class AnimationType {
ALPHA, SCALE_AND_ALPHA, LIGHT_SCALE_AND_ALPHA, SLIDE_AND_ALPHA, LIGHT_SLIDE_AND_ALPHA
}

View File

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

View File

@ -42,9 +42,9 @@ import org.schabi.newpipe.database.feed.model.FeedGroupEntity
import org.schabi.newpipe.databinding.ErrorRetryBinding
import org.schabi.newpipe.databinding.FragmentFeedBinding
import org.schabi.newpipe.fragments.list.BaseListFragment
import org.schabi.newpipe.ktx.animate
import org.schabi.newpipe.local.feed.service.FeedLoadService
import org.schabi.newpipe.report.UserAction
import org.schabi.newpipe.util.AnimationUtils.animateView
import org.schabi.newpipe.util.Localization
import java.util.Calendar
@ -180,50 +180,50 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() {
// /////////////////////////////////////////////////////////////////////////
override fun showLoading() {
animateView(feedBinding.refreshRootView, false, 0)
animateView(feedBinding.itemsList, false, 0)
feedBinding.refreshRootView.animate(false, 0)
feedBinding.itemsList.animate(false, 0)
animateView(feedBinding.loadingProgressBar, true, 200)
animateView(feedBinding.loadingProgressText, true, 200)
feedBinding.loadingProgressBar.animate(true, 200)
feedBinding.loadingProgressText.animate(true, 200)
animateView(feedBinding.emptyStateView.root, false, 0)
animateView(errorBinding.root, false, 0)
feedBinding.emptyStateView.root.animate(false, 0)
errorBinding.root.animate(false, 0)
}
override fun hideLoading() {
animateView(feedBinding.refreshRootView, true, 200)
animateView(feedBinding.itemsList, true, 300)
feedBinding.refreshRootView.animate(true, 200)
feedBinding.itemsList.animate(true, 300)
animateView(feedBinding.loadingProgressBar, false, 0)
animateView(feedBinding.loadingProgressText, false, 0)
feedBinding.loadingProgressBar.animate(false, 0)
feedBinding.loadingProgressText.animate(false, 0)
animateView(feedBinding.emptyStateView.root, false, 0)
animateView(errorBinding.root, false, 0)
feedBinding.emptyStateView.root.animate(false, 0)
errorBinding.root.animate(false, 0)
feedBinding.swiperefresh.isRefreshing = false
}
override fun showEmptyState() {
animateView(feedBinding.refreshRootView, true, 200)
animateView(feedBinding.itemsList, false, 0)
feedBinding.refreshRootView.animate(true, 200)
feedBinding.itemsList.animate(false, 0)
animateView(feedBinding.loadingProgressBar, false, 0)
animateView(feedBinding.loadingProgressText, false, 0)
feedBinding.loadingProgressBar.animate(false, 0)
feedBinding.loadingProgressText.animate(false, 0)
animateView(feedBinding.emptyStateView.root, true, 800)
animateView(errorBinding.root, false, 0)
feedBinding.emptyStateView.root.animate(true, 800)
errorBinding.root.animate(false, 0)
}
override fun showError(message: String, showRetryButton: Boolean) {
infoListAdapter.clearStreamItemList()
animateView(feedBinding.refreshRootView, false, 120)
animateView(feedBinding.itemsList, false, 120)
feedBinding.refreshRootView.animate(false, 120)
feedBinding.itemsList.animate(false, 120)
animateView(feedBinding.loadingProgressBar, false, 120)
animateView(feedBinding.loadingProgressText, false, 120)
feedBinding.loadingProgressBar.animate(false, 120)
feedBinding.loadingProgressText.animate(false, 120)
errorBinding.errorMessageView.text = message
animateView(errorBinding.errorButtonRetry, showRetryButton, if (showRetryButton) 600 else 0)
animateView(errorBinding.root, true, 300)
errorBinding.errorButtonRetry.animate(showRetryButton, if (showRetryButton) 600 else 0)
errorBinding.root.animate(true, 300)
}
override fun handleResult(result: FeedState) {

View File

@ -12,9 +12,9 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.ktx.ViewUtils;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.views.AnimatedProgressBar;
@ -117,10 +117,10 @@ public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
} else {
itemProgressView.setProgress((int) TimeUnit.MILLISECONDS
.toSeconds(item.getProgressTime()));
AnimationUtils.animateView(itemProgressView, true, 500);
ViewUtils.animate(itemProgressView, true, 500);
}
} else if (itemProgressView.getVisibility() == View.VISIBLE) {
AnimationUtils.animateView(itemProgressView, false, 500);
ViewUtils.animate(itemProgressView, false, 500);
}
}

View File

@ -12,9 +12,9 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.ktx.ViewUtils;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.views.AnimatedProgressBar;
@ -148,10 +148,10 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
} else {
itemProgressView.setProgress((int) TimeUnit.MILLISECONDS
.toSeconds(item.getProgressTime()));
AnimationUtils.animateView(itemProgressView, true, 500);
ViewUtils.animate(itemProgressView, true, 500);
}
} else if (itemProgressView.getVisibility() == View.VISIBLE) {
AnimationUtils.animateView(itemProgressView, false, 500);
ViewUtils.animate(itemProgressView, false, 500);
}
}
}

View File

@ -58,14 +58,14 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import icepick.State;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import io.reactivex.rxjava3.subjects.PublishSubject;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistStreamEntry>, Void> {
// Save the list 10 seconds after the last change occurred
@ -201,8 +201,8 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
public void showLoading() {
super.showLoading();
if (headerBinding != null) {
animateView(headerBinding.getRoot(), false, 200);
animateView(playlistControlBinding.getRoot(), false, 200);
animate(headerBinding.getRoot(), false, 200);
animate(playlistControlBinding.getRoot(), false, 200);
}
}
@ -210,8 +210,8 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
public void hideLoading() {
super.hideLoading();
if (headerBinding != null) {
animateView(headerBinding.getRoot(), true, 200);
animateView(playlistControlBinding.getRoot(), true, 200);
animate(headerBinding.getRoot(), true, 200);
animate(playlistControlBinding.getRoot(), true, 200);
}
}

View File

@ -36,6 +36,7 @@ import org.schabi.newpipe.databinding.DialogTitleBinding
import org.schabi.newpipe.databinding.FragmentSubscriptionBinding
import org.schabi.newpipe.extractor.channel.ChannelInfoItem
import org.schabi.newpipe.fragments.BaseStateFragment
import org.schabi.newpipe.ktx.animate
import org.schabi.newpipe.local.subscription.SubscriptionViewModel.SubscriptionState
import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialog
import org.schabi.newpipe.local.subscription.dialog.FeedGroupReorderDialog
@ -56,7 +57,6 @@ import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.KEY_VALUE
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.PREVIOUS_EXPORT_MODE
import org.schabi.newpipe.report.UserAction
import org.schabi.newpipe.util.AnimationUtils.animateView
import org.schabi.newpipe.util.FilePickerActivityHelper
import org.schabi.newpipe.util.NavigationHelper
import org.schabi.newpipe.util.OnClickGesture
@ -407,12 +407,12 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
override fun showLoading() {
super.showLoading()
animateView(binding.itemsList, false, 100)
binding.itemsList.animate(false, 100)
}
override fun hideLoading() {
super.hideLoading()
animateView(binding.itemsList, true, 200)
binding.itemsList.animate(true, 200)
}
// /////////////////////////////////////////////////////////////////////////

View File

@ -17,7 +17,7 @@ import kotlinx.android.synthetic.main.feed_import_export_group.import_from_optio
import org.schabi.newpipe.R
import org.schabi.newpipe.extractor.NewPipe
import org.schabi.newpipe.extractor.exceptions.ExtractionException
import org.schabi.newpipe.util.AnimationUtils
import org.schabi.newpipe.ktx.animateRotation
import org.schabi.newpipe.util.ServiceHelper
import org.schabi.newpipe.util.ThemeHelper
import org.schabi.newpipe.views.CollapsibleView
@ -49,8 +49,7 @@ class FeedImportExportItem(
expandIconListener?.let { viewHolder.import_export_options.removeListener(it) }
expandIconListener = CollapsibleView.StateListener { newState ->
AnimationUtils.animateRotation(
viewHolder.import_export_expand_icon,
viewHolder.import_export_expand_icon.animateRotation(
250, if (newState == CollapsibleView.COLLAPSED) 0 else 180
)
}

View File

@ -9,8 +9,8 @@ import kotlinx.android.synthetic.main.picker_subscription_item.*
import kotlinx.android.synthetic.main.picker_subscription_item.view.*
import org.schabi.newpipe.R
import org.schabi.newpipe.database.subscription.SubscriptionEntity
import org.schabi.newpipe.util.AnimationUtils
import org.schabi.newpipe.util.AnimationUtils.animateView
import org.schabi.newpipe.ktx.AnimationType
import org.schabi.newpipe.ktx.animate
import org.schabi.newpipe.util.ImageDisplayConstants
data class PickerSubscriptionItem(
@ -41,9 +41,6 @@ data class PickerSubscriptionItem(
fun updateSelected(containerView: View, isSelected: Boolean) {
this.isSelected = isSelected
animateView(
containerView.selected_highlight,
AnimationUtils.Type.LIGHT_SCALE_AND_ALPHA, isSelected, 150
)
containerView.selected_highlight.animate(isSelected, 150, AnimationType.LIGHT_SCALE_AND_ALPHA)
}
}

View File

@ -92,6 +92,7 @@ import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.info_list.StreamSegmentAdapter;
import org.schabi.newpipe.ktx.AnimationType;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.player.MainPlayer.PlayerType;
import org.schabi.newpipe.player.event.PlayerEventListener;
@ -116,7 +117,6 @@ import org.schabi.newpipe.player.playqueue.PlayQueueItemTouchCallback;
import org.schabi.newpipe.player.resolver.AudioPlaybackResolver;
import org.schabi.newpipe.player.resolver.MediaSourceTag;
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.KoreUtil;
@ -150,6 +150,8 @@ import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE;
import static com.google.android.exoplayer2.Player.RepeatMode;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateRotation;
import static org.schabi.newpipe.player.MainPlayer.ACTION_CLOSE;
import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD;
import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_REWIND;
@ -176,9 +178,6 @@ import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePlayerTypeFr
import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePopupLayoutParamsFromPrefs;
import static org.schabi.newpipe.player.helper.PlayerHelper.retrieveSeekDurationFromPreferences;
import static org.schabi.newpipe.player.helper.PlayerHelper.savePlaybackParametersToPrefs;
import static org.schabi.newpipe.util.AnimationUtils.Type.SLIDE_AND_ALPHA;
import static org.schabi.newpipe.util.AnimationUtils.animateRotation;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
import static org.schabi.newpipe.util.ListHelper.getPopupResolutionIndex;
import static org.schabi.newpipe.util.ListHelper.getResolutionIndex;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
@ -1560,8 +1559,8 @@ public final class Player implements
}
showControls(0);
animateView(binding.currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, true,
DEFAULT_CONTROLS_DURATION);
animate(binding.currentDisplaySeek, true, DEFAULT_CONTROLS_DURATION,
AnimationType.SCALE_AND_ALPHA);
}
@Override // seekbar listener
@ -1576,7 +1575,7 @@ public final class Player implements
}
binding.playbackCurrentTime.setText(getTimeString(seekBar.getProgress()));
animateView(binding.currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200);
animate(binding.currentDisplaySeek, false, 200, AnimationType.SCALE_AND_ALPHA);
if (currentState == STATE_PAUSED_SEEK) {
changeState(STATE_BUFFERING);
@ -1682,8 +1681,8 @@ public final class Player implements
: DPAD_CONTROLS_HIDE_TIME;
showHideShadow(true, DEFAULT_CONTROLS_DURATION);
animateView(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION, 0,
() -> hideControls(DEFAULT_CONTROLS_DURATION, hideTime));
animate(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION,
AnimationType.ALPHA, 0, () -> hideControls(DEFAULT_CONTROLS_DURATION, hideTime));
}
public void showControls(final long duration) {
@ -1694,7 +1693,7 @@ public final class Player implements
showSystemUIPartially();
controlsVisibilityHandler.removeCallbacksAndMessages(null);
showHideShadow(true, duration);
animateView(binding.playbackControlRoot, true, duration);
animate(binding.playbackControlRoot, true, duration);
}
public void hideControls(final long duration, final long delay) {
@ -1708,14 +1707,14 @@ public final class Player implements
controlsVisibilityHandler.removeCallbacksAndMessages(null);
controlsVisibilityHandler.postDelayed(() -> {
showHideShadow(false, duration);
animateView(binding.playbackControlRoot, false, duration, 0,
this::hideSystemUIIfNeeded);
animate(binding.playbackControlRoot, false, duration, AnimationType.ALPHA,
0, this::hideSystemUIIfNeeded);
}, delay);
}
private void showHideShadow(final boolean show, final long duration) {
animateView(binding.playerTopShadow, show, duration, 0, null);
animateView(binding.playerBottomShadow, show, duration, 0, null);
animate(binding.playerTopShadow, show, duration, AnimationType.ALPHA, 0, null);
animate(binding.playerBottomShadow, show, duration, AnimationType.ALPHA, 0, null);
}
private void showOrHideButtons() {
@ -1913,15 +1912,15 @@ public final class Player implements
}
controlsVisibilityHandler.removeCallbacksAndMessages(null);
animateView(binding.playbackControlRoot, false, DEFAULT_CONTROLS_DURATION);
animate(binding.playbackControlRoot, false, DEFAULT_CONTROLS_DURATION);
binding.playbackSeekBar.setEnabled(false);
binding.playbackSeekBar.getThumb()
.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN));
binding.loadingPanel.setBackgroundColor(Color.BLACK);
animateView(binding.loadingPanel, true, 0);
animateView(binding.surfaceForeground, true, 100);
animate(binding.loadingPanel, true, 0);
animate(binding.surfaceForeground, true, 100);
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp);
animatePlayButtons(false, 100);
@ -1948,9 +1947,9 @@ public final class Player implements
binding.loadingPanel.setVisibility(View.GONE);
animateView(binding.currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200);
animate(binding.currentDisplaySeek, false, 200, AnimationType.SCALE_AND_ALPHA);
animateView(binding.playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0,
animate(binding.playPauseButton, false, 80, AnimationType.SCALE_AND_ALPHA, 0,
() -> {
binding.playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp);
animatePlayButtons(true, 200);
@ -1991,7 +1990,7 @@ public final class Player implements
showControls(400);
binding.loadingPanel.setVisibility(View.GONE);
animateView(binding.playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0,
animate(binding.playPauseButton, false, 80, AnimationType.SCALE_AND_ALPHA, 0,
() -> {
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp);
animatePlayButtons(true, 200);
@ -2029,7 +2028,7 @@ public final class Player implements
Log.d(TAG, "onCompleted() called");
}
animateView(binding.playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0,
animate(binding.playPauseButton, false, 0, AnimationType.SCALE_AND_ALPHA, 0,
() -> {
binding.playPauseButton.setImageResource(R.drawable.ic_replay_white_24dp);
animatePlayButtons(true, DEFAULT_CONTROLS_DURATION);
@ -2051,13 +2050,13 @@ public final class Player implements
}
showControls(500);
animateView(binding.currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200);
animate(binding.currentDisplaySeek, false, 200, AnimationType.SCALE_AND_ALPHA);
binding.loadingPanel.setVisibility(View.GONE);
animateView(binding.surfaceForeground, true, 100);
animate(binding.surfaceForeground, true, 100);
}
private void animatePlayButtons(final boolean show, final int duration) {
animateView(binding.playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration);
animate(binding.playPauseButton, show, duration, AnimationType.SCALE_AND_ALPHA);
boolean showQueueButtons = show;
if (playQueue == null) {
@ -2065,18 +2064,18 @@ public final class Player implements
}
if (!showQueueButtons || playQueue.getIndex() > 0) {
animateView(
animate(
binding.playPreviousButton,
AnimationUtils.Type.SCALE_AND_ALPHA,
showQueueButtons,
duration);
duration,
AnimationType.SCALE_AND_ALPHA);
}
if (!showQueueButtons || playQueue.getIndex() + 1 < playQueue.getStreams().size()) {
animateView(
animate(
binding.playNextButton,
AnimationUtils.Type.SCALE_AND_ALPHA,
showQueueButtons,
duration);
duration,
AnimationType.SCALE_AND_ALPHA);
}
}
//endregion
@ -2274,7 +2273,7 @@ public final class Player implements
@Override
public void onRenderedFirstFrame() {
//TODO check if this causes black screen when switching to fullscreen
animateView(binding.surfaceForeground, false, DEFAULT_CONTROLS_DURATION);
animate(binding.surfaceForeground, false, DEFAULT_CONTROLS_DURATION);
}
//endregion
@ -2871,8 +2870,8 @@ public final class Player implements
hideControls(0, 0);
binding.itemsListPanel.requestFocus();
animateView(binding.itemsListPanel, SLIDE_AND_ALPHA, true,
DEFAULT_CONTROLS_DURATION);
animate(binding.itemsListPanel, true, DEFAULT_CONTROLS_DURATION,
AnimationType.SLIDE_AND_ALPHA);
binding.itemsList.scrollToPosition(playQueue.getIndex());
}
@ -2905,8 +2904,8 @@ public final class Player implements
hideControls(0, 0);
binding.itemsListPanel.requestFocus();
animateView(binding.itemsListPanel, SLIDE_AND_ALPHA, true,
DEFAULT_CONTROLS_DURATION);
animate(binding.itemsListPanel, true, DEFAULT_CONTROLS_DURATION,
AnimationType.SLIDE_AND_ALPHA);
final int adapterPosition = getNearestStreamSegmentPosition(simpleExoPlayer
.getCurrentPosition());
@ -2942,8 +2941,8 @@ public final class Player implements
itemTouchHelper.attachToRecyclerView(null);
}
animateView(binding.itemsListPanel, SLIDE_AND_ALPHA, false,
DEFAULT_CONTROLS_DURATION, 0, () -> {
animate(binding.itemsListPanel, false, DEFAULT_CONTROLS_DURATION,
AnimationType.SLIDE_AND_ALPHA, 0, () -> {
// Even when queueLayout is GONE it receives touch events
// and ruins normal behavior of the app. This line fixes it
binding.itemsListPanel.setTranslationY(
@ -3451,18 +3450,19 @@ public final class Player implements
if (currentState != STATE_COMPLETED) {
controlsVisibilityHandler.removeCallbacksAndMessages(null);
showHideShadow(true, DEFAULT_CONTROLS_DURATION);
animateView(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION, 0, () -> {
if (currentState == STATE_PLAYING && !isSomePopupMenuVisible) {
if (v.getId() == binding.playPauseButton.getId()
// Hide controls in fullscreen immediately
|| (v.getId() == binding.screenRotationButton.getId()
&& isFullscreen)) {
hideControls(0, 0);
} else {
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
}
}
});
animate(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION,
AnimationType.ALPHA, 0, () -> {
if (currentState == STATE_PLAYING && !isSomePopupMenuVisible) {
if (v.getId() == binding.playPauseButton.getId()
// Hide controls in fullscreen immediately
|| (v.getId() == binding.screenRotationButton.getId()
&& isFullscreen)) {
hideControls(0, 0);
} else {
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
}
}
});
}
}
@ -3531,9 +3531,8 @@ public final class Player implements
animateRotation(binding.moreOptionsButton, DEFAULT_CONTROLS_DURATION,
isMoreControlsVisible ? 0 : 180);
animateView(binding.secondaryControls, SLIDE_AND_ALPHA, !isMoreControlsVisible,
DEFAULT_CONTROLS_DURATION, 0,
() -> {
animate(binding.secondaryControls, !isMoreControlsVisible, DEFAULT_CONTROLS_DURATION,
AnimationType.SLIDE_AND_ALPHA, 0, () -> {
// Fix for a ripple effect on background drawable.
// When view returns from GONE state it takes more milliseconds than returning
// from INVISIBLE state. And the delay makes ripple background end to fast

View File

@ -7,11 +7,11 @@ import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import org.schabi.newpipe.ktx.animate
import org.schabi.newpipe.player.MainPlayer
import org.schabi.newpipe.player.Player
import org.schabi.newpipe.player.helper.PlayerHelper
import org.schabi.newpipe.player.helper.PlayerHelper.savePopupPositionAndSizeToPrefs
import org.schabi.newpipe.util.AnimationUtils
import kotlin.math.abs
import kotlin.math.hypot
import kotlin.math.max
@ -364,7 +364,7 @@ abstract class BasePlayerGestureListener(
}
if (!isMovingInPopup) {
AnimationUtils.animateView(player.closeOverlayButton, true, 200)
player.closeOverlayButton.animate(true, 200)
}
isMovingInPopup = true

View File

@ -17,11 +17,12 @@ import org.schabi.newpipe.player.MainPlayer;
import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.helper.PlayerHelper;
import static org.schabi.newpipe.player.Player.STATE_PLAYING;
import static org.schabi.newpipe.ktx.AnimationType.ALPHA;
import static org.schabi.newpipe.ktx.AnimationType.SCALE_AND_ALPHA;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.player.Player.DEFAULT_CONTROLS_DURATION;
import static org.schabi.newpipe.player.Player.DEFAULT_CONTROLS_HIDE_TIME;
import static org.schabi.newpipe.util.AnimationUtils.Type.SCALE_AND_ALPHA;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
import static org.schabi.newpipe.player.Player.STATE_PLAYING;
/**
* GestureListener for the player
@ -123,11 +124,11 @@ public class PlayerGestureListener
final View closingOverlayView = player.getClosingOverlayView();
if (player.isInsideClosingRadius(movingEvent)) {
if (closingOverlayView.getVisibility() == View.GONE) {
animateView(closingOverlayView, true, 250);
animate(closingOverlayView, true, 250);
}
} else {
if (closingOverlayView.getVisibility() == View.VISIBLE) {
animateView(closingOverlayView, false, 0);
animate(closingOverlayView, false, 0);
}
}
}
@ -153,7 +154,7 @@ public class PlayerGestureListener
);
if (player.getVolumeRelativeLayout().getVisibility() != View.VISIBLE) {
animateView(player.getVolumeRelativeLayout(), SCALE_AND_ALPHA, true, 200);
animate(player.getVolumeRelativeLayout(), true, 200, SCALE_AND_ALPHA);
}
if (player.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
player.getBrightnessRelativeLayout().setVisibility(View.GONE);
@ -195,7 +196,7 @@ public class PlayerGestureListener
);
if (player.getBrightnessRelativeLayout().getVisibility() != View.VISIBLE) {
animateView(player.getBrightnessRelativeLayout(), SCALE_AND_ALPHA, true, 200);
animate(player.getBrightnessRelativeLayout(), true, 200, SCALE_AND_ALPHA);
}
if (player.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) {
player.getVolumeRelativeLayout().setVisibility(View.GONE);
@ -215,21 +216,18 @@ public class PlayerGestureListener
}
if (player.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) {
animateView(player.getVolumeRelativeLayout(), SCALE_AND_ALPHA,
false, 200, 200);
animate(player.getVolumeRelativeLayout(), false, 200, SCALE_AND_ALPHA,
200);
}
if (player.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
animateView(player.getBrightnessRelativeLayout(), SCALE_AND_ALPHA,
false, 200, 200);
animate(player.getBrightnessRelativeLayout(), false, 200, SCALE_AND_ALPHA,
200);
}
if (player.isControlsVisible() && player.getCurrentState() == STATE_PLAYING) {
player.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
}
} else {
if (player == null) {
return;
}
if (player.isControlsVisible() && player.getCurrentState() == STATE_PLAYING) {
player.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
}
@ -237,10 +235,10 @@ public class PlayerGestureListener
if (player.isInsideClosingRadius(event)) {
player.closePopup();
} else {
animateView(player.getClosingOverlayView(), false, 0);
animate(player.getClosingOverlayView(), false, 0);
if (!player.isPopupClosing()) {
animateView(player.getCloseOverlayButton(), false, 200);
animate(player.getCloseOverlayButton(), false, 200);
}
}
}
@ -255,8 +253,8 @@ public class PlayerGestureListener
player.getLoadingPanel().setVisibility(View.GONE);
player.hideControls(0, 0);
animateView(player.getCurrentDisplaySeek(), false, 0, 0);
animateView(player.getResizingIndicator(), true, 200, 0);
animate(player.getCurrentDisplaySeek(), false, 0, ALPHA, 0);
animate(player.getResizingIndicator(), true, 200, ALPHA, 0);
}
@Override
@ -264,7 +262,7 @@ public class PlayerGestureListener
if (DEBUG) {
Log.d(TAG, "onPopupResizingEnd called");
}
animateView(player.getResizingIndicator(), false, 100, 0);
animate(player.getResizingIndicator(), false, 100, ALPHA, 0);
}
}

View File

@ -1,478 +0,0 @@
/*
* Copyright 2018 Mauricio Colli <mauriciocolli@outlook.com>
* AnimationUtils.java is part of NewPipe
*
* License: GPL-3.0+
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.schabi.newpipe.util;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.content.res.ColorStateList;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;
import androidx.core.view.ViewCompat;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import org.schabi.newpipe.MainActivity;
public final class AnimationUtils {
private static final String TAG = "AnimationUtils";
private static final boolean DEBUG = MainActivity.DEBUG;
private AnimationUtils() { }
public static void animateView(final View view, final boolean enterOrExit,
final long duration) {
animateView(view, Type.ALPHA, enterOrExit, duration, 0, null);
}
public static void animateView(final View view, final boolean enterOrExit,
final long duration, final long delay) {
animateView(view, Type.ALPHA, enterOrExit, duration, delay, null);
}
public static void animateView(final View view, final boolean enterOrExit, final long duration,
final long delay, final Runnable execOnEnd) {
animateView(view, Type.ALPHA, enterOrExit, duration, delay, execOnEnd);
}
public static void animateView(final View view, final Type animationType,
final boolean enterOrExit, final long duration) {
animateView(view, animationType, enterOrExit, duration, 0, null);
}
public static void animateView(final View view, final Type animationType,
final boolean enterOrExit, final long duration,
final long delay) {
animateView(view, animationType, enterOrExit, duration, delay, null);
}
/**
* Animate the view.
*
* @param view view that will be animated
* @param animationType {@link Type} of the animation
* @param enterOrExit true to enter, false to exit
* @param duration how long the animation will take, in milliseconds
* @param delay how long the animation will wait to start, in milliseconds
* @param execOnEnd runnable that will be executed when the animation ends
*/
public static void animateView(final View view, final Type animationType,
final boolean enterOrExit, final long duration,
final long delay, final Runnable execOnEnd) {
if (DEBUG) {
String id;
try {
id = view.getResources().getResourceEntryName(view.getId());
} catch (final Exception e) {
id = view.getId() + "";
}
final String msg = String.format("%8s → [%s:%s] [%s %s:%s] execOnEnd=%s", enterOrExit,
view.getClass().getSimpleName(), id, animationType, duration, delay, execOnEnd);
Log.d(TAG, "animateView()" + msg);
}
if (view.getVisibility() == View.VISIBLE && enterOrExit) {
if (DEBUG) {
Log.d(TAG, "animateView() view was already visible > view = [" + view + "]");
}
view.animate().setListener(null).cancel();
view.setVisibility(View.VISIBLE);
view.setAlpha(1f);
if (execOnEnd != null) {
execOnEnd.run();
}
return;
} else if ((view.getVisibility() == View.GONE || view.getVisibility() == View.INVISIBLE)
&& !enterOrExit) {
if (DEBUG) {
Log.d(TAG, "animateView() view was already gone > view = [" + view + "]");
}
view.animate().setListener(null).cancel();
view.setVisibility(View.GONE);
view.setAlpha(0f);
if (execOnEnd != null) {
execOnEnd.run();
}
return;
}
view.animate().setListener(null).cancel();
view.setVisibility(View.VISIBLE);
switch (animationType) {
case ALPHA:
animateAlpha(view, enterOrExit, duration, delay, execOnEnd);
break;
case SCALE_AND_ALPHA:
animateScaleAndAlpha(view, enterOrExit, duration, delay, execOnEnd);
break;
case LIGHT_SCALE_AND_ALPHA:
animateLightScaleAndAlpha(view, enterOrExit, duration, delay, execOnEnd);
break;
case SLIDE_AND_ALPHA:
animateSlideAndAlpha(view, enterOrExit, duration, delay, execOnEnd);
break;
case LIGHT_SLIDE_AND_ALPHA:
animateLightSlideAndAlpha(view, enterOrExit, duration, delay, execOnEnd);
break;
}
}
/**
* Animate the background color of a view.
*
* @param view the view to animate
* @param duration the duration of the animation
* @param colorStart the background color to start with
* @param colorEnd the background color to end with
*/
public static void animateBackgroundColor(final View view, final long duration,
@ColorInt final int colorStart,
@ColorInt final int colorEnd) {
if (DEBUG) {
Log.d(TAG, "animateBackgroundColor() called with: "
+ "view = [" + view + "], duration = [" + duration + "], "
+ "colorStart = [" + colorStart + "], colorEnd = [" + colorEnd + "]");
}
final int[][] empty = {new int[0]};
final ValueAnimator viewPropertyAnimator = ValueAnimator
.ofObject(new ArgbEvaluator(), colorStart, colorEnd);
viewPropertyAnimator.setInterpolator(new FastOutSlowInInterpolator());
viewPropertyAnimator.setDuration(duration);
viewPropertyAnimator.addUpdateListener(animation ->
ViewCompat.setBackgroundTintList(view,
new ColorStateList(empty, new int[]{(int) animation.getAnimatedValue()})));
viewPropertyAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
ViewCompat.setBackgroundTintList(view,
new ColorStateList(empty, new int[]{colorEnd}));
}
@Override
public void onAnimationCancel(final Animator animation) {
onAnimationEnd(animation);
}
});
viewPropertyAnimator.start();
}
/**
* Animate the text color of any view that extends {@link TextView} (Buttons, EditText...).
*
* @param view the text view to animate
* @param duration the duration of the animation
* @param colorStart the text color to start with
* @param colorEnd the text color to end with
*/
public static void animateTextColor(final TextView view, final long duration,
@ColorInt final int colorStart,
@ColorInt final int colorEnd) {
if (DEBUG) {
Log.d(TAG, "animateTextColor() called with: "
+ "view = [" + view + "], duration = [" + duration + "], "
+ "colorStart = [" + colorStart + "], colorEnd = [" + colorEnd + "]");
}
final ValueAnimator viewPropertyAnimator = ValueAnimator
.ofObject(new ArgbEvaluator(), colorStart, colorEnd);
viewPropertyAnimator.setInterpolator(new FastOutSlowInInterpolator());
viewPropertyAnimator.setDuration(duration);
viewPropertyAnimator.addUpdateListener(animation ->
view.setTextColor((int) animation.getAnimatedValue()));
viewPropertyAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
view.setTextColor(colorEnd);
}
@Override
public void onAnimationCancel(final Animator animation) {
view.setTextColor(colorEnd);
}
});
viewPropertyAnimator.start();
}
public static ValueAnimator animateHeight(final View view, final long duration,
final int targetHeight) {
final int height = view.getHeight();
if (DEBUG) {
Log.d(TAG, "animateHeight: duration = [" + duration + "], "
+ "from " + height + " to → " + targetHeight + " in: " + view);
}
final ValueAnimator animator = ValueAnimator.ofFloat(height, targetHeight);
animator.setInterpolator(new FastOutSlowInInterpolator());
animator.setDuration(duration);
animator.addUpdateListener(animation -> {
final float value = (float) animation.getAnimatedValue();
view.getLayoutParams().height = (int) value;
view.requestLayout();
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
view.getLayoutParams().height = targetHeight;
view.requestLayout();
}
@Override
public void onAnimationCancel(final Animator animation) {
view.getLayoutParams().height = targetHeight;
view.requestLayout();
}
});
animator.start();
return animator;
}
public static void animateRotation(final View view, final long duration,
final int targetRotation) {
if (DEBUG) {
Log.d(TAG, "animateRotation: duration = [" + duration + "], "
+ "from " + view.getRotation() + " to → " + targetRotation + " in: " + view);
}
view.animate().setListener(null).cancel();
view.animate()
.rotation(targetRotation).setDuration(duration)
.setInterpolator(new FastOutSlowInInterpolator())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(final Animator animation) {
view.setRotation(targetRotation);
}
@Override
public void onAnimationEnd(final Animator animation) {
view.setRotation(targetRotation);
}
}).start();
}
private static void animateAlpha(final View view, final boolean enterOrExit,
final long duration, final long delay,
final Runnable execOnEnd) {
if (enterOrExit) {
view.animate().setInterpolator(new FastOutSlowInInterpolator()).alpha(1f)
.setDuration(duration).setStartDelay(delay)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
if (execOnEnd != null) {
execOnEnd.run();
}
}
}).start();
} else {
view.animate().setInterpolator(new FastOutSlowInInterpolator()).alpha(0f)
.setDuration(duration).setStartDelay(delay)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
view.setVisibility(View.GONE);
if (execOnEnd != null) {
execOnEnd.run();
}
}
}).start();
}
}
/*//////////////////////////////////////////////////////////////////////////
// Internals
//////////////////////////////////////////////////////////////////////////*/
private static void animateScaleAndAlpha(final View view, final boolean enterOrExit,
final long duration, final long delay,
final Runnable execOnEnd) {
if (enterOrExit) {
view.setScaleX(.8f);
view.setScaleY(.8f);
view.animate()
.setInterpolator(new FastOutSlowInInterpolator())
.alpha(1f).scaleX(1f).scaleY(1f)
.setDuration(duration).setStartDelay(delay)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
if (execOnEnd != null) {
execOnEnd.run();
}
}
}).start();
} else {
view.setScaleX(1f);
view.setScaleY(1f);
view.animate()
.setInterpolator(new FastOutSlowInInterpolator())
.alpha(0f).scaleX(.8f).scaleY(.8f)
.setDuration(duration).setStartDelay(delay)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
view.setVisibility(View.GONE);
if (execOnEnd != null) {
execOnEnd.run();
}
}
}).start();
}
}
private static void animateLightScaleAndAlpha(final View view, final boolean enterOrExit,
final long duration, final long delay,
final Runnable execOnEnd) {
if (enterOrExit) {
view.setAlpha(.5f);
view.setScaleX(.95f);
view.setScaleY(.95f);
view.animate()
.setInterpolator(new FastOutSlowInInterpolator())
.alpha(1f).scaleX(1f).scaleY(1f)
.setDuration(duration).setStartDelay(delay)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
if (execOnEnd != null) {
execOnEnd.run();
}
}
}).start();
} else {
view.setAlpha(1f);
view.setScaleX(1f);
view.setScaleY(1f);
view.animate()
.setInterpolator(new FastOutSlowInInterpolator())
.alpha(0f).scaleX(.95f).scaleY(.95f)
.setDuration(duration).setStartDelay(delay)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
view.setVisibility(View.GONE);
if (execOnEnd != null) {
execOnEnd.run();
}
}
}).start();
}
}
private static void animateSlideAndAlpha(final View view, final boolean enterOrExit,
final long duration, final long delay,
final Runnable execOnEnd) {
if (enterOrExit) {
view.setTranslationY(-view.getHeight());
view.setAlpha(0f);
view.animate()
.setInterpolator(new FastOutSlowInInterpolator()).alpha(1f).translationY(0)
.setDuration(duration).setStartDelay(delay)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
if (execOnEnd != null) {
execOnEnd.run();
}
}
}).start();
} else {
view.animate()
.setInterpolator(new FastOutSlowInInterpolator())
.alpha(0f).translationY(-view.getHeight())
.setDuration(duration).setStartDelay(delay)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
view.setVisibility(View.GONE);
if (execOnEnd != null) {
execOnEnd.run();
}
}
}).start();
}
}
private static void animateLightSlideAndAlpha(final View view, final boolean enterOrExit,
final long duration, final long delay,
final Runnable execOnEnd) {
if (enterOrExit) {
view.setTranslationY(-view.getHeight() / 2.0f);
view.setAlpha(0f);
view.animate()
.setInterpolator(new FastOutSlowInInterpolator()).alpha(1f).translationY(0)
.setDuration(duration).setStartDelay(delay)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
if (execOnEnd != null) {
execOnEnd.run();
}
}
}).start();
} else {
view.animate().setInterpolator(new FastOutSlowInInterpolator())
.alpha(0f).translationY(-view.getHeight() / 2.0f)
.setDuration(duration).setStartDelay(delay)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(final Animator animation) {
view.setVisibility(View.GONE);
if (execOnEnd != null) {
execOnEnd.run();
}
}
}).start();
}
}
public static void slideUp(final View view, final long duration, final long delay,
@FloatRange(from = 0.0f, to = 1.0f)
final float translationPercent) {
final int translationY = (int) (view.getResources().getDisplayMetrics().heightPixels
* (translationPercent));
view.animate().setListener(null).cancel();
view.setAlpha(0f);
view.setTranslationY(translationY);
view.setVisibility(View.VISIBLE);
view.animate()
.alpha(1f)
.translationY(0)
.setStartDelay(delay)
.setDuration(duration)
.setInterpolator(new FastOutSlowInInterpolator())
.start();
}
public enum Type {
ALPHA,
SCALE_AND_ALPHA, LIGHT_SCALE_AND_ALPHA,
SLIDE_AND_ALPHA, LIGHT_SLIDE_AND_ALPHA
}
}

View File

@ -31,7 +31,7 @@ import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.ktx.ViewUtils;
import java.lang.annotation.Retention;
import java.util.ArrayList;
@ -128,7 +128,7 @@ public class CollapsibleView extends LinearLayout {
if (currentAnimator != null && currentAnimator.isRunning()) {
currentAnimator.cancel();
}
currentAnimator = AnimationUtils.animateHeight(this, ANIMATION_DURATION, 0);
currentAnimator = ViewUtils.animateHeight(this, ANIMATION_DURATION, 0);
setCurrentState(COLLAPSED);
}
@ -151,7 +151,7 @@ public class CollapsibleView extends LinearLayout {
if (currentAnimator != null && currentAnimator.isRunning()) {
currentAnimator.cancel();
}
currentAnimator = AnimationUtils.animateHeight(this, ANIMATION_DURATION, this.targetHeight);
currentAnimator = ViewUtils.animateHeight(this, ANIMATION_DURATION, this.targetHeight);
setCurrentState(EXPANDED);
}