mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 15:23:00 +00:00 
			
		
		
		
	Merge pull request #5333 from Isira-Seneviratne/Convert_AnimationUtils_to_extensions
Convert AnimationUtils functions to extension functions.
This commit is contained in:
		| @@ -37,7 +37,7 @@ import icepick.State; | |||||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||||
| import io.reactivex.rxjava3.disposables.Disposable; | 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> { | public abstract class BaseStateFragment<I> extends BaseFragment implements ViewContract<I> { | ||||||
|     @State |     @State | ||||||
| @@ -131,35 +131,35 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC | |||||||
|     @Override |     @Override | ||||||
|     public void showLoading() { |     public void showLoading() { | ||||||
|         if (emptyStateView != null) { |         if (emptyStateView != null) { | ||||||
|             animateView(emptyStateView, false, 150); |             animate(emptyStateView, false, 150); | ||||||
|         } |         } | ||||||
|         if (loadingProgressBar != null) { |         if (loadingProgressBar != null) { | ||||||
|             animateView(loadingProgressBar, true, 400); |             animate(loadingProgressBar, true, 400); | ||||||
|         } |         } | ||||||
|         animateView(errorPanelRoot, false, 150); |         animate(errorPanelRoot, false, 150); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void hideLoading() { |     public void hideLoading() { | ||||||
|         if (emptyStateView != null) { |         if (emptyStateView != null) { | ||||||
|             animateView(emptyStateView, false, 150); |             animate(emptyStateView, false, 150); | ||||||
|         } |         } | ||||||
|         if (loadingProgressBar != null) { |         if (loadingProgressBar != null) { | ||||||
|             animateView(loadingProgressBar, false, 0); |             animate(loadingProgressBar, false, 0); | ||||||
|         } |         } | ||||||
|         animateView(errorPanelRoot, false, 150); |         animate(errorPanelRoot, false, 150); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void showEmptyState() { |     public void showEmptyState() { | ||||||
|         isLoading.set(false); |         isLoading.set(false); | ||||||
|         if (emptyStateView != null) { |         if (emptyStateView != null) { | ||||||
|             animateView(emptyStateView, true, 200); |             animate(emptyStateView, true, 200); | ||||||
|         } |         } | ||||||
|         if (loadingProgressBar != null) { |         if (loadingProgressBar != null) { | ||||||
|             animateView(loadingProgressBar, false, 0); |             animate(loadingProgressBar, false, 0); | ||||||
|         } |         } | ||||||
|         animateView(errorPanelRoot, false, 150); |         animate(errorPanelRoot, false, 150); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -174,11 +174,11 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC | |||||||
|  |  | ||||||
|         errorTextView.setText(message); |         errorTextView.setText(message); | ||||||
|         if (showRetryButton) { |         if (showRetryButton) { | ||||||
|             animateView(errorButtonRetry, true, 600); |             animate(errorButtonRetry, true, 600); | ||||||
|         } else { |         } else { | ||||||
|             animateView(errorButtonRetry, false, 0); |             animate(errorButtonRetry, false, 0); | ||||||
|         } |         } | ||||||
|         animateView(errorPanelRoot, true, 300); |         animate(errorPanelRoot, true, 300); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -76,11 +76,12 @@ import org.schabi.newpipe.fragments.BaseStateFragment; | |||||||
| import org.schabi.newpipe.fragments.EmptyFragment; | 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.local.dialog.PlaylistAppendDialog; | import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; | ||||||
| import org.schabi.newpipe.local.dialog.PlaylistCreationDialog; | import org.schabi.newpipe.local.dialog.PlaylistCreationDialog; | ||||||
| import org.schabi.newpipe.local.history.HistoryRecordManager; | import org.schabi.newpipe.local.history.HistoryRecordManager; | ||||||
| import org.schabi.newpipe.player.Player; |  | ||||||
| import org.schabi.newpipe.player.MainPlayer; | 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.OnKeyDownListener; | ||||||
| import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener; | import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener; | ||||||
| import org.schabi.newpipe.player.helper.PlayerHelper; | 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.globalScreenOrientationLocked; | ||||||
| import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired; | import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired; | ||||||
| import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET; | 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; | import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView; | ||||||
|  |  | ||||||
| public final class VideoDetailFragment | public final class VideoDetailFragment | ||||||
| @@ -745,8 +746,10 @@ public final class VideoDetailFragment | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { |             if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { | ||||||
|                 animateView(appendControlsDetail, true, 250, 0, () -> |                 animate(appendControlsDetail, true, 250, AnimationType.ALPHA, | ||||||
|                         animateView(appendControlsDetail, false, 1500, 1000)); |                         0, () -> | ||||||
|  |                         animate(appendControlsDetail, false, 1500, | ||||||
|  |                                 AnimationType.ALPHA, 1000)); | ||||||
|             } |             } | ||||||
|             return false; |             return false; | ||||||
|         }; |         }; | ||||||
| @@ -1334,8 +1337,8 @@ public final class VideoDetailFragment | |||||||
|  |  | ||||||
|         thumbnailImageView.setImageDrawable( |         thumbnailImageView.setImageDrawable( | ||||||
|                 AppCompatResources.getDrawable(requireContext(), imageResource)); |                 AppCompatResources.getDrawable(requireContext(), imageResource)); | ||||||
|         animateView(thumbnailImageView, false, 0, 0, |         animate(thumbnailImageView, false, 0, AnimationType.ALPHA, 0, | ||||||
|                 () -> animateView(thumbnailImageView, true, 500)); |                 () -> animate(thumbnailImageView, true, 500)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -1417,14 +1420,14 @@ public final class VideoDetailFragment | |||||||
|             contentRootLayoutHiding.setVisibility(View.INVISIBLE); |             contentRootLayoutHiding.setVisibility(View.INVISIBLE); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         animateView(thumbnailPlayButton, false, 50); |         animate(thumbnailPlayButton, false, 50); | ||||||
|         animateView(detailDurationView, false, 100); |         animate(detailDurationView, false, 100); | ||||||
|         animateView(detailPositionView, false, 100); |         animate(detailPositionView, false, 100); | ||||||
|         animateView(positionView, false, 50); |         animate(positionView, false, 50); | ||||||
|  |  | ||||||
|         videoTitleTextView.setText(title); |         videoTitleTextView.setText(title); | ||||||
|         videoTitleTextView.setMaxLines(1); |         videoTitleTextView.setMaxLines(1); | ||||||
|         animateView(videoTitleTextView, true, 0); |         animate(videoTitleTextView, true, 0); | ||||||
|  |  | ||||||
|         videoDescriptionRootLayout.setVisibility(View.GONE); |         videoDescriptionRootLayout.setVisibility(View.GONE); | ||||||
|         videoTitleToggleArrow.setVisibility(View.GONE); |         videoTitleToggleArrow.setVisibility(View.GONE); | ||||||
| @@ -1466,7 +1469,7 @@ public final class VideoDetailFragment | |||||||
|                         player != null && player.isFullscreen() ? View.GONE : View.VISIBLE); |                         player != null && player.isFullscreen() ? View.GONE : View.VISIBLE); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         animateView(thumbnailPlayButton, true, 200); |         animate(thumbnailPlayButton, true, 200); | ||||||
|         videoTitleTextView.setText(title); |         videoTitleTextView.setText(title); | ||||||
|  |  | ||||||
|         if (!isEmpty(info.getSubChannelName())) { |         if (!isEmpty(info.getSubChannelName())) { | ||||||
| @@ -1530,12 +1533,12 @@ public final class VideoDetailFragment | |||||||
|             detailDurationView.setText(Localization.getDurationString(info.getDuration())); |             detailDurationView.setText(Localization.getDurationString(info.getDuration())); | ||||||
|             detailDurationView.setBackgroundColor( |             detailDurationView.setBackgroundColor( | ||||||
|                     ContextCompat.getColor(activity, R.color.duration_background_color)); |                     ContextCompat.getColor(activity, R.color.duration_background_color)); | ||||||
|             animateView(detailDurationView, true, 100); |             animate(detailDurationView, true, 100); | ||||||
|         } else if (info.getStreamType() == StreamType.LIVE_STREAM) { |         } else if (info.getStreamType() == StreamType.LIVE_STREAM) { | ||||||
|             detailDurationView.setText(R.string.duration_live); |             detailDurationView.setText(R.string.duration_live); | ||||||
|             detailDurationView.setBackgroundColor( |             detailDurationView.setBackgroundColor( | ||||||
|                     ContextCompat.getColor(activity, R.color.live_duration_background_color)); |                     ContextCompat.getColor(activity, R.color.live_duration_background_color)); | ||||||
|             animateView(detailDurationView, true, 100); |             animate(detailDurationView, true, 100); | ||||||
|         } else { |         } else { | ||||||
|             detailDurationView.setVisibility(View.GONE); |             detailDurationView.setVisibility(View.GONE); | ||||||
|         } |         } | ||||||
| @@ -1703,8 +1706,8 @@ public final class VideoDetailFragment | |||||||
|                 // Show saved position from backStack if user allows it |                 // Show saved position from backStack if user allows it | ||||||
|                 showPlaybackProgress(playQueue.getItem().getRecoveryPosition(), |                 showPlaybackProgress(playQueue.getItem().getRecoveryPosition(), | ||||||
|                         playQueue.getItem().getDuration() * 1000); |                         playQueue.getItem().getDuration() * 1000); | ||||||
|                 animateView(positionView, true, 500); |                 animate(positionView, true, 500); | ||||||
|                 animateView(detailPositionView, true, 500); |                 animate(detailPositionView, true, 500); | ||||||
|             } |             } | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| @@ -1718,8 +1721,8 @@ public final class VideoDetailFragment | |||||||
|                 .observeOn(AndroidSchedulers.mainThread()) |                 .observeOn(AndroidSchedulers.mainThread()) | ||||||
|                 .subscribe(state -> { |                 .subscribe(state -> { | ||||||
|                     showPlaybackProgress(state.getProgressTime(), info.getDuration() * 1000); |                     showPlaybackProgress(state.getProgressTime(), info.getDuration() * 1000); | ||||||
|                     animateView(positionView, true, 500); |                     animate(positionView, true, 500); | ||||||
|                     animateView(detailPositionView, true, 500); |                     animate(detailPositionView, true, 500); | ||||||
|                 }, e -> { |                 }, e -> { | ||||||
|                     if (DEBUG) { |                     if (DEBUG) { | ||||||
|                         e.printStackTrace(); |                         e.printStackTrace(); | ||||||
| @@ -1747,8 +1750,8 @@ public final class VideoDetailFragment | |||||||
|             detailPositionView.setText(position); |             detailPositionView.setText(position); | ||||||
|         } |         } | ||||||
|         if (positionView.getVisibility() != View.VISIBLE) { |         if (positionView.getVisibility() != View.VISIBLE) { | ||||||
|             animateView(positionView, true, 100); |             animate(positionView, true, 100); | ||||||
|             animateView(detailPositionView, true, 100); |             animate(detailPositionView, true, 100); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1802,8 +1805,8 @@ public final class VideoDetailFragment | |||||||
|                         && player.getPlayQueue() != null |                         && player.getPlayQueue() != null | ||||||
|                         && player.getPlayQueue().getItem() != null |                         && player.getPlayQueue().getItem() != null | ||||||
|                         && player.getPlayQueue().getItem().getUrl().equals(url)) { |                         && player.getPlayQueue().getItem().getUrl().equals(url)) { | ||||||
|                     animateView(positionView, true, 100); |                     animate(positionView, true, 100); | ||||||
|                     animateView(detailPositionView, true, 100); |                     animate(detailPositionView, true, 100); | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -46,7 +46,7 @@ import java.util.Arrays; | |||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Queue; | 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> | public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> | ||||||
|         implements ListViewContract<I, N>, StateSaver.WriteRead, |         implements ListViewContract<I, N>, StateSaver.WriteRead, | ||||||
| @@ -406,23 +406,17 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> | |||||||
|     // Contract |     // Contract | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void showLoading() { |  | ||||||
|         super.showLoading(); |  | ||||||
|         // animateView(itemsList, false, 400); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void hideLoading() { |     public void hideLoading() { | ||||||
|         super.hideLoading(); |         super.hideLoading(); | ||||||
|         animateView(itemsList, true, 300); |         animate(itemsList, true, 300); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void showError(final String message, final boolean showRetryButton) { |     public void showError(final String message, final boolean showRetryButton) { | ||||||
|         super.showError(message, showRetryButton); |         super.showError(message, showRetryButton); | ||||||
|         showListFooter(false); |         showListFooter(false); | ||||||
|         animateView(itemsList, false, 200); |         animate(itemsList, false, 200); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -37,12 +37,12 @@ import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; | |||||||
| import org.schabi.newpipe.extractor.exceptions.ExtractionException; | import org.schabi.newpipe.extractor.exceptions.ExtractionException; | ||||||
| import org.schabi.newpipe.extractor.stream.StreamInfoItem; | import org.schabi.newpipe.extractor.stream.StreamInfoItem; | ||||||
| import org.schabi.newpipe.fragments.list.BaseListInfoFragment; | import org.schabi.newpipe.fragments.list.BaseListInfoFragment; | ||||||
|  | import org.schabi.newpipe.ktx.AnimationType; | ||||||
| import org.schabi.newpipe.local.subscription.SubscriptionManager; | import org.schabi.newpipe.local.subscription.SubscriptionManager; | ||||||
| import org.schabi.newpipe.player.playqueue.ChannelPlayQueue; | import org.schabi.newpipe.player.playqueue.ChannelPlayQueue; | ||||||
| import org.schabi.newpipe.player.playqueue.PlayQueue; | import org.schabi.newpipe.player.playqueue.PlayQueue; | ||||||
| import org.schabi.newpipe.report.ErrorActivity; | import org.schabi.newpipe.report.ErrorActivity; | ||||||
| import org.schabi.newpipe.report.UserAction; | import org.schabi.newpipe.report.UserAction; | ||||||
| import org.schabi.newpipe.util.AnimationUtils; |  | ||||||
| import org.schabi.newpipe.util.ExtractorHelper; | import org.schabi.newpipe.util.ExtractorHelper; | ||||||
| import org.schabi.newpipe.util.ImageDisplayConstants; | import org.schabi.newpipe.util.ImageDisplayConstants; | ||||||
| import org.schabi.newpipe.util.Localization; | 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.functions.Function; | ||||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | import io.reactivex.rxjava3.schedulers.Schedulers; | ||||||
|  |  | ||||||
| import static org.schabi.newpipe.util.AnimationUtils.animateBackgroundColor; | import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor; | ||||||
| import static org.schabi.newpipe.util.AnimationUtils.animateTextColor; | import static org.schabi.newpipe.ktx.ViewUtils.animate; | ||||||
| import static org.schabi.newpipe.util.AnimationUtils.animateView; | import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor; | ||||||
|  |  | ||||||
| public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | ||||||
|         implements View.OnClickListener { |         implements View.OnClickListener { | ||||||
| @@ -224,7 +224,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | |||||||
|  |  | ||||||
|     private void monitorSubscription(final ChannelInfo info) { |     private void monitorSubscription(final ChannelInfo info) { | ||||||
|         final Consumer<Throwable> onError = (Throwable throwable) -> { |         final Consumer<Throwable> onError = (Throwable throwable) -> { | ||||||
|             animateView(headerBinding.channelSubscribeButton, false, 100); |             animate(headerBinding.channelSubscribeButton, false, 100); | ||||||
|             showSnackBarError(throwable, UserAction.SUBSCRIPTION, |             showSnackBarError(throwable, UserAction.SUBSCRIPTION, | ||||||
|                     NewPipe.getNameOfService(currentInfo.getServiceId()), |                     NewPipe.getNameOfService(currentInfo.getServiceId()), | ||||||
|                     "Get subscription status", 0); |                     "Get subscription status", 0); | ||||||
| @@ -379,8 +379,8 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> | |||||||
|                     subscribedText); |                     subscribedText); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         animateView(headerBinding.channelSubscribeButton, AnimationUtils.Type.LIGHT_SCALE_AND_ALPHA, |         animate(headerBinding.channelSubscribeButton, true, 100, | ||||||
|                 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.channelBannerImage); | ||||||
|         IMAGE_LOADER.cancelDisplayTask(headerBinding.channelAvatarView); |         IMAGE_LOADER.cancelDisplayTask(headerBinding.channelAvatarView); | ||||||
|         IMAGE_LOADER.cancelDisplayTask(headerBinding.subChannelAvatarView); |         IMAGE_LOADER.cancelDisplayTask(headerBinding.subChannelAvatarView); | ||||||
|         animateView(headerBinding.channelSubscribeButton, false, 100); |         animate(headerBinding.channelSubscribeButton, false, 100); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -16,8 +16,8 @@ import org.schabi.newpipe.extractor.ListExtractor; | |||||||
| import org.schabi.newpipe.extractor.NewPipe; | import org.schabi.newpipe.extractor.NewPipe; | ||||||
| import org.schabi.newpipe.extractor.comments.CommentsInfo; | import org.schabi.newpipe.extractor.comments.CommentsInfo; | ||||||
| import org.schabi.newpipe.fragments.list.BaseListInfoFragment; | import org.schabi.newpipe.fragments.list.BaseListInfoFragment; | ||||||
|  | import org.schabi.newpipe.ktx.ViewUtils; | ||||||
| import org.schabi.newpipe.report.UserAction; | import org.schabi.newpipe.report.UserAction; | ||||||
| import org.schabi.newpipe.util.AnimationUtils; |  | ||||||
| import org.schabi.newpipe.util.ExtractorHelper; | import org.schabi.newpipe.util.ExtractorHelper; | ||||||
|  |  | ||||||
| import io.reactivex.rxjava3.core.Single; | import io.reactivex.rxjava3.core.Single; | ||||||
| @@ -84,17 +84,15 @@ public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> { | |||||||
|     public void handleResult(@NonNull final CommentsInfo result) { |     public void handleResult(@NonNull final CommentsInfo result) { | ||||||
|         super.handleResult(result); |         super.handleResult(result); | ||||||
|  |  | ||||||
|         AnimationUtils.slideUp(requireView(), 120, 150, 0.06f); |         ViewUtils.slideUp(requireView(), 120, 150, 0.06f); | ||||||
|  |  | ||||||
|         if (!result.getErrors().isEmpty()) { |         if (!result.getErrors().isEmpty()) { | ||||||
|             showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS, |             showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS, | ||||||
|                     NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); |                     NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (disposables != null) { |  | ||||||
|         disposables.clear(); |         disposables.clear(); | ||||||
|     } |     } | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void handleNextItems(final ListExtractor.InfoItemsPage result) { |     public void handleNextItems(final ListExtractor.InfoItemsPage result) { | ||||||
|   | |||||||
| @@ -28,7 +28,7 @@ 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.util.AnimationUtils.animateView; | import static org.schabi.newpipe.ktx.ViewUtils.animate; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Created by Christian Schabesberger on 23.09.17. |  * Created by Christian Schabesberger on 23.09.17. | ||||||
| @@ -160,7 +160,7 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> { | |||||||
|     @Override |     @Override | ||||||
|     public void showLoading() { |     public void showLoading() { | ||||||
|         super.showLoading(); |         super.showLoading(); | ||||||
|         animateView(itemsList, false, 100); |         animate(itemsList, false, 100); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -61,7 +61,7 @@ import io.reactivex.rxjava3.core.Single; | |||||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||||
| import io.reactivex.rxjava3.disposables.Disposable; | 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; | import static org.schabi.newpipe.util.ThemeHelper.resolveResourceIdFromAttr; | ||||||
|  |  | ||||||
| public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | ||||||
| @@ -261,19 +261,19 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> { | |||||||
|     @Override |     @Override | ||||||
|     public void showLoading() { |     public void showLoading() { | ||||||
|         super.showLoading(); |         super.showLoading(); | ||||||
|         animateView(headerBinding.getRoot(), false, 200); |         animate(headerBinding.getRoot(), false, 200); | ||||||
|         animateView(itemsList, false, 100); |         animate(itemsList, false, 100); | ||||||
|  |  | ||||||
|         IMAGE_LOADER.cancelDisplayTask(headerBinding.uploaderAvatarView); |         IMAGE_LOADER.cancelDisplayTask(headerBinding.uploaderAvatarView); | ||||||
|         animateView(headerBinding.uploaderLayout, false, 200); |         animate(headerBinding.uploaderLayout, false, 200); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void handleResult(@NonNull final PlaylistInfo result) { |     public void handleResult(@NonNull final PlaylistInfo result) { | ||||||
|         super.handleResult(result); |         super.handleResult(result); | ||||||
|  |  | ||||||
|         animateView(headerBinding.getRoot(), true, 100); |         animate(headerBinding.getRoot(), true, 100); | ||||||
|         animateView(headerBinding.uploaderLayout, true, 300); |         animate(headerBinding.uploaderLayout, true, 300); | ||||||
|         headerBinding.uploaderLayout.setOnClickListener(null); |         headerBinding.uploaderLayout.setOnClickListener(null); | ||||||
|         // If we have an uploader put them into the UI |         // If we have an uploader put them into the UI | ||||||
|         if (!TextUtils.isEmpty(result.getUploaderName())) { |         if (!TextUtils.isEmpty(result.getUploaderName())) { | ||||||
|   | |||||||
| @@ -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.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory; | ||||||
| import org.schabi.newpipe.fragments.BackPressable; | import org.schabi.newpipe.fragments.BackPressable; | ||||||
| import org.schabi.newpipe.fragments.list.BaseListFragment; | import org.schabi.newpipe.fragments.list.BaseListFragment; | ||||||
|  | import org.schabi.newpipe.ktx.AnimationType; | ||||||
| import org.schabi.newpipe.ktx.ExceptionUtils; | import org.schabi.newpipe.ktx.ExceptionUtils; | ||||||
| import org.schabi.newpipe.local.history.HistoryRecordManager; | import org.schabi.newpipe.local.history.HistoryRecordManager; | ||||||
| import org.schabi.newpipe.report.ErrorActivity; | import org.schabi.newpipe.report.ErrorActivity; | ||||||
| import org.schabi.newpipe.report.ErrorInfo; | import org.schabi.newpipe.report.ErrorInfo; | ||||||
| import org.schabi.newpipe.report.UserAction; | import org.schabi.newpipe.report.UserAction; | ||||||
| import org.schabi.newpipe.util.AnimationUtils; |  | ||||||
| import org.schabi.newpipe.util.Constants; | import org.schabi.newpipe.util.Constants; | ||||||
| import org.schabi.newpipe.util.DeviceUtils; | import org.schabi.newpipe.util.DeviceUtils; | ||||||
| import org.schabi.newpipe.util.ExtractorHelper; | 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 androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags; | ||||||
| import static java.util.Arrays.asList; | 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; | import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView; | ||||||
|  |  | ||||||
| public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage<?>> | public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage<?>> | ||||||
| @@ -413,7 +413,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I | |||||||
|                 searchEditText.setText(""); |                 searchEditText.setText(""); | ||||||
|                 showKeyboardSearch(); |                 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"); |             Log.d(TAG, "showSuggestionsPanel() called"); | ||||||
|         } |         } | ||||||
|         suggestionsPanelVisible = true; |         suggestionsPanelVisible = true; | ||||||
|         animateView(searchBinding.suggestionsPanel, AnimationUtils.Type.LIGHT_SLIDE_AND_ALPHA, |         animate(searchBinding.suggestionsPanel, true, 200, | ||||||
|                 true, 200); |                 AnimationType.LIGHT_SLIDE_AND_ALPHA); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void hideSuggestionsPanel() { |     private void hideSuggestionsPanel() { | ||||||
| @@ -653,8 +653,8 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I | |||||||
|             Log.d(TAG, "hideSuggestionsPanel() called"); |             Log.d(TAG, "hideSuggestionsPanel() called"); | ||||||
|         } |         } | ||||||
|         suggestionsPanelVisible = false; |         suggestionsPanelVisible = false; | ||||||
|         animateView(searchBinding.suggestionsPanel, AnimationUtils.Type.LIGHT_SLIDE_AND_ALPHA, |         animate(searchBinding.suggestionsPanel, false, 200, | ||||||
|                 false, 200); |                 AnimationType.LIGHT_SLIDE_AND_ALPHA); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void showKeyboardSearch() { |     private void showKeyboardSearch() { | ||||||
|   | |||||||
| @@ -20,8 +20,8 @@ import org.schabi.newpipe.extractor.ListExtractor; | |||||||
| import org.schabi.newpipe.extractor.NewPipe; | import org.schabi.newpipe.extractor.NewPipe; | ||||||
| import org.schabi.newpipe.extractor.stream.StreamInfo; | import org.schabi.newpipe.extractor.stream.StreamInfo; | ||||||
| import org.schabi.newpipe.fragments.list.BaseListInfoFragment; | import org.schabi.newpipe.fragments.list.BaseListInfoFragment; | ||||||
|  | import org.schabi.newpipe.ktx.ViewUtils; | ||||||
| import org.schabi.newpipe.report.UserAction; | import org.schabi.newpipe.report.UserAction; | ||||||
| import org.schabi.newpipe.util.AnimationUtils; |  | ||||||
| import org.schabi.newpipe.util.RelatedStreamInfo; | import org.schabi.newpipe.util.RelatedStreamInfo; | ||||||
|  |  | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
| @@ -123,7 +123,7 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf | |||||||
|         if (headerBinding != null) { |         if (headerBinding != null) { | ||||||
|             headerBinding.getRoot().setVisibility(View.VISIBLE); |             headerBinding.getRoot().setVisibility(View.VISIBLE); | ||||||
|         } |         } | ||||||
|         AnimationUtils.slideUp(getView(), 120, 96, 0.06f); |         ViewUtils.slideUp(requireView(), 120, 96, 0.06f); | ||||||
|  |  | ||||||
|         if (!result.getErrors().isEmpty()) { |         if (!result.getErrors().isEmpty()) { | ||||||
|             showSnackBarError(result.getErrors(), UserAction.REQUESTED_STREAM, |             showSnackBarError(result.getErrors(), UserAction.REQUESTED_STREAM, | ||||||
|   | |||||||
| @@ -13,8 +13,8 @@ import org.schabi.newpipe.extractor.InfoItem; | |||||||
| import org.schabi.newpipe.extractor.stream.StreamInfoItem; | import org.schabi.newpipe.extractor.stream.StreamInfoItem; | ||||||
| import org.schabi.newpipe.extractor.stream.StreamType; | import org.schabi.newpipe.extractor.stream.StreamType; | ||||||
| import org.schabi.newpipe.info_list.InfoItemBuilder; | import org.schabi.newpipe.info_list.InfoItemBuilder; | ||||||
|  | import org.schabi.newpipe.ktx.ViewUtils; | ||||||
| import org.schabi.newpipe.local.history.HistoryRecordManager; | import org.schabi.newpipe.local.history.HistoryRecordManager; | ||||||
| import org.schabi.newpipe.util.AnimationUtils; |  | ||||||
| import org.schabi.newpipe.util.ImageDisplayConstants; | import org.schabi.newpipe.util.ImageDisplayConstants; | ||||||
| import org.schabi.newpipe.util.Localization; | import org.schabi.newpipe.util.Localization; | ||||||
| import org.schabi.newpipe.views.AnimatedProgressBar; | import org.schabi.newpipe.views.AnimatedProgressBar; | ||||||
| @@ -125,10 +125,10 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder { | |||||||
|             } else { |             } else { | ||||||
|                 itemProgressView.setProgress((int) TimeUnit.MILLISECONDS |                 itemProgressView.setProgress((int) TimeUnit.MILLISECONDS | ||||||
|                         .toSeconds(state.getProgressTime())); |                         .toSeconds(state.getProgressTime())); | ||||||
|                 AnimationUtils.animateView(itemProgressView, true, 500); |                 ViewUtils.animate(itemProgressView, true, 500); | ||||||
|             } |             } | ||||||
|         } else if (itemProgressView.getVisibility() == View.VISIBLE) { |         } else if (itemProgressView.getVisibility() == View.VISIBLE) { | ||||||
|             AnimationUtils.animateView(itemProgressView, false, 500); |             ViewUtils.animate(itemProgressView, false, 500); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										47
									
								
								app/src/main/java/org/schabi/newpipe/ktx/TextView.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/src/main/java/org/schabi/newpipe/ktx/TextView.kt
									
									
									
									
									
										Normal 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() | ||||||
|  | } | ||||||
							
								
								
									
										324
									
								
								app/src/main/java/org/schabi/newpipe/ktx/View.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										324
									
								
								app/src/main/java/org/schabi/newpipe/ktx/View.kt
									
									
									
									
									
										Normal 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 | ||||||
|  | } | ||||||
| @@ -24,7 +24,7 @@ import org.schabi.newpipe.databinding.PignateFooterBinding; | |||||||
| import org.schabi.newpipe.fragments.BaseStateFragment; | 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.util.AnimationUtils.animateView; | import static org.schabi.newpipe.ktx.ViewUtils.animate; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * This fragment is design to be used with persistent data such as |  * 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() { |     public void showLoading() { | ||||||
|         super.showLoading(); |         super.showLoading(); | ||||||
|         if (itemsList != null) { |         if (itemsList != null) { | ||||||
|             animateView(itemsList, false, 200); |             animate(itemsList, false, 200); | ||||||
|         } |         } | ||||||
|         if (headerRootBinding != null) { |         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() { |     public void hideLoading() { | ||||||
|         super.hideLoading(); |         super.hideLoading(); | ||||||
|         if (itemsList != null) { |         if (itemsList != null) { | ||||||
|             animateView(itemsList, true, 200); |             animate(itemsList, true, 200); | ||||||
|         } |         } | ||||||
|         if (headerRootBinding != null) { |         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); |         showListFooter(false); | ||||||
|  |  | ||||||
|         if (itemsList != null) { |         if (itemsList != null) { | ||||||
|             animateView(itemsList, false, 200); |             animate(itemsList, false, 200); | ||||||
|         } |         } | ||||||
|         if (headerRootBinding != null) { |         if (headerRootBinding != null) { | ||||||
|             animateView(headerRootBinding.getRoot(), false, 200); |             animate(headerRootBinding.getRoot(), false, 200); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -42,9 +42,9 @@ import org.schabi.newpipe.database.feed.model.FeedGroupEntity | |||||||
| import org.schabi.newpipe.databinding.ErrorRetryBinding | import org.schabi.newpipe.databinding.ErrorRetryBinding | ||||||
| import org.schabi.newpipe.databinding.FragmentFeedBinding | import org.schabi.newpipe.databinding.FragmentFeedBinding | ||||||
| import org.schabi.newpipe.fragments.list.BaseListFragment | 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.local.feed.service.FeedLoadService | ||||||
| import org.schabi.newpipe.report.UserAction | import org.schabi.newpipe.report.UserAction | ||||||
| import org.schabi.newpipe.util.AnimationUtils.animateView |  | ||||||
| import org.schabi.newpipe.util.Localization | import org.schabi.newpipe.util.Localization | ||||||
| import java.util.Calendar | import java.util.Calendar | ||||||
|  |  | ||||||
| @@ -180,50 +180,50 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() { | |||||||
|     // ///////////////////////////////////////////////////////////////////////// |     // ///////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|     override fun showLoading() { |     override fun showLoading() { | ||||||
|         animateView(feedBinding.refreshRootView, false, 0) |         feedBinding.refreshRootView.animate(false, 0) | ||||||
|         animateView(feedBinding.itemsList, false, 0) |         feedBinding.itemsList.animate(false, 0) | ||||||
|  |  | ||||||
|         animateView(feedBinding.loadingProgressBar, true, 200) |         feedBinding.loadingProgressBar.animate(true, 200) | ||||||
|         animateView(feedBinding.loadingProgressText, true, 200) |         feedBinding.loadingProgressText.animate(true, 200) | ||||||
|  |  | ||||||
|         animateView(feedBinding.emptyStateView.root, false, 0) |         feedBinding.emptyStateView.root.animate(false, 0) | ||||||
|         animateView(errorBinding.root, false, 0) |         errorBinding.root.animate(false, 0) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun hideLoading() { |     override fun hideLoading() { | ||||||
|         animateView(feedBinding.refreshRootView, true, 200) |         feedBinding.refreshRootView.animate(true, 200) | ||||||
|         animateView(feedBinding.itemsList, true, 300) |         feedBinding.itemsList.animate(true, 300) | ||||||
|  |  | ||||||
|         animateView(feedBinding.loadingProgressBar, false, 0) |         feedBinding.loadingProgressBar.animate(false, 0) | ||||||
|         animateView(feedBinding.loadingProgressText, false, 0) |         feedBinding.loadingProgressText.animate(false, 0) | ||||||
|  |  | ||||||
|         animateView(feedBinding.emptyStateView.root, false, 0) |         feedBinding.emptyStateView.root.animate(false, 0) | ||||||
|         animateView(errorBinding.root, false, 0) |         errorBinding.root.animate(false, 0) | ||||||
|         feedBinding.swiperefresh.isRefreshing = false |         feedBinding.swiperefresh.isRefreshing = false | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun showEmptyState() { |     override fun showEmptyState() { | ||||||
|         animateView(feedBinding.refreshRootView, true, 200) |         feedBinding.refreshRootView.animate(true, 200) | ||||||
|         animateView(feedBinding.itemsList, false, 0) |         feedBinding.itemsList.animate(false, 0) | ||||||
|  |  | ||||||
|         animateView(feedBinding.loadingProgressBar, false, 0) |         feedBinding.loadingProgressBar.animate(false, 0) | ||||||
|         animateView(feedBinding.loadingProgressText, false, 0) |         feedBinding.loadingProgressText.animate(false, 0) | ||||||
|  |  | ||||||
|         animateView(feedBinding.emptyStateView.root, true, 800) |         feedBinding.emptyStateView.root.animate(true, 800) | ||||||
|         animateView(errorBinding.root, false, 0) |         errorBinding.root.animate(false, 0) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun showError(message: String, showRetryButton: Boolean) { |     override fun showError(message: String, showRetryButton: Boolean) { | ||||||
|         infoListAdapter.clearStreamItemList() |         infoListAdapter.clearStreamItemList() | ||||||
|         animateView(feedBinding.refreshRootView, false, 120) |         feedBinding.refreshRootView.animate(false, 120) | ||||||
|         animateView(feedBinding.itemsList, false, 120) |         feedBinding.itemsList.animate(false, 120) | ||||||
|  |  | ||||||
|         animateView(feedBinding.loadingProgressBar, false, 120) |         feedBinding.loadingProgressBar.animate(false, 120) | ||||||
|         animateView(feedBinding.loadingProgressText, false, 120) |         feedBinding.loadingProgressText.animate(false, 120) | ||||||
|  |  | ||||||
|         errorBinding.errorMessageView.text = message |         errorBinding.errorMessageView.text = message | ||||||
|         animateView(errorBinding.errorButtonRetry, showRetryButton, if (showRetryButton) 600 else 0) |         errorBinding.errorButtonRetry.animate(showRetryButton, if (showRetryButton) 600 else 0) | ||||||
|         animateView(errorBinding.root, true, 300) |         errorBinding.root.animate(true, 300) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun handleResult(result: FeedState) { |     override fun handleResult(result: FeedState) { | ||||||
|   | |||||||
| @@ -12,9 +12,9 @@ import org.schabi.newpipe.R; | |||||||
| import org.schabi.newpipe.database.LocalItem; | import org.schabi.newpipe.database.LocalItem; | ||||||
| import org.schabi.newpipe.database.playlist.PlaylistStreamEntry; | import org.schabi.newpipe.database.playlist.PlaylistStreamEntry; | ||||||
| import org.schabi.newpipe.extractor.NewPipe; | import org.schabi.newpipe.extractor.NewPipe; | ||||||
|  | import org.schabi.newpipe.ktx.ViewUtils; | ||||||
| import org.schabi.newpipe.local.LocalItemBuilder; | import org.schabi.newpipe.local.LocalItemBuilder; | ||||||
| import org.schabi.newpipe.local.history.HistoryRecordManager; | import org.schabi.newpipe.local.history.HistoryRecordManager; | ||||||
| import org.schabi.newpipe.util.AnimationUtils; |  | ||||||
| import org.schabi.newpipe.util.ImageDisplayConstants; | import org.schabi.newpipe.util.ImageDisplayConstants; | ||||||
| import org.schabi.newpipe.util.Localization; | import org.schabi.newpipe.util.Localization; | ||||||
| import org.schabi.newpipe.views.AnimatedProgressBar; | import org.schabi.newpipe.views.AnimatedProgressBar; | ||||||
| @@ -117,10 +117,10 @@ public class LocalPlaylistStreamItemHolder extends LocalItemHolder { | |||||||
|             } else { |             } else { | ||||||
|                 itemProgressView.setProgress((int) TimeUnit.MILLISECONDS |                 itemProgressView.setProgress((int) TimeUnit.MILLISECONDS | ||||||
|                         .toSeconds(item.getProgressTime())); |                         .toSeconds(item.getProgressTime())); | ||||||
|                 AnimationUtils.animateView(itemProgressView, true, 500); |                 ViewUtils.animate(itemProgressView, true, 500); | ||||||
|             } |             } | ||||||
|         } else if (itemProgressView.getVisibility() == View.VISIBLE) { |         } else if (itemProgressView.getVisibility() == View.VISIBLE) { | ||||||
|             AnimationUtils.animateView(itemProgressView, false, 500); |             ViewUtils.animate(itemProgressView, false, 500); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,9 +12,9 @@ import org.schabi.newpipe.R; | |||||||
| import org.schabi.newpipe.database.LocalItem; | import org.schabi.newpipe.database.LocalItem; | ||||||
| import org.schabi.newpipe.database.stream.StreamStatisticsEntry; | import org.schabi.newpipe.database.stream.StreamStatisticsEntry; | ||||||
| import org.schabi.newpipe.extractor.NewPipe; | import org.schabi.newpipe.extractor.NewPipe; | ||||||
|  | import org.schabi.newpipe.ktx.ViewUtils; | ||||||
| import org.schabi.newpipe.local.LocalItemBuilder; | import org.schabi.newpipe.local.LocalItemBuilder; | ||||||
| import org.schabi.newpipe.local.history.HistoryRecordManager; | import org.schabi.newpipe.local.history.HistoryRecordManager; | ||||||
| import org.schabi.newpipe.util.AnimationUtils; |  | ||||||
| import org.schabi.newpipe.util.ImageDisplayConstants; | import org.schabi.newpipe.util.ImageDisplayConstants; | ||||||
| import org.schabi.newpipe.util.Localization; | import org.schabi.newpipe.util.Localization; | ||||||
| import org.schabi.newpipe.views.AnimatedProgressBar; | import org.schabi.newpipe.views.AnimatedProgressBar; | ||||||
| @@ -148,10 +148,10 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder { | |||||||
|             } else { |             } else { | ||||||
|                 itemProgressView.setProgress((int) TimeUnit.MILLISECONDS |                 itemProgressView.setProgress((int) TimeUnit.MILLISECONDS | ||||||
|                         .toSeconds(item.getProgressTime())); |                         .toSeconds(item.getProgressTime())); | ||||||
|                 AnimationUtils.animateView(itemProgressView, true, 500); |                 ViewUtils.animate(itemProgressView, true, 500); | ||||||
|             } |             } | ||||||
|         } else if (itemProgressView.getVisibility() == View.VISIBLE) { |         } else if (itemProgressView.getVisibility() == View.VISIBLE) { | ||||||
|             AnimationUtils.animateView(itemProgressView, false, 500); |             ViewUtils.animate(itemProgressView, false, 500); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -58,14 +58,14 @@ import java.util.concurrent.TimeUnit; | |||||||
| import java.util.concurrent.atomic.AtomicBoolean; | import java.util.concurrent.atomic.AtomicBoolean; | ||||||
|  |  | ||||||
| import icepick.State; | import icepick.State; | ||||||
| import io.reactivex.rxjava3.core.Flowable; |  | ||||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; | ||||||
|  | import io.reactivex.rxjava3.core.Flowable; | ||||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||||
| import io.reactivex.rxjava3.disposables.Disposable; | import io.reactivex.rxjava3.disposables.Disposable; | ||||||
| import io.reactivex.rxjava3.schedulers.Schedulers; | import io.reactivex.rxjava3.schedulers.Schedulers; | ||||||
| import io.reactivex.rxjava3.subjects.PublishSubject; | 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> { | public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistStreamEntry>, Void> { | ||||||
|     // Save the list 10 seconds after the last change occurred |     // Save the list 10 seconds after the last change occurred | ||||||
| @@ -201,8 +201,8 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt | |||||||
|     public void showLoading() { |     public void showLoading() { | ||||||
|         super.showLoading(); |         super.showLoading(); | ||||||
|         if (headerBinding != null) { |         if (headerBinding != null) { | ||||||
|             animateView(headerBinding.getRoot(), false, 200); |             animate(headerBinding.getRoot(), false, 200); | ||||||
|             animateView(playlistControlBinding.getRoot(), false, 200); |             animate(playlistControlBinding.getRoot(), false, 200); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -210,8 +210,8 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt | |||||||
|     public void hideLoading() { |     public void hideLoading() { | ||||||
|         super.hideLoading(); |         super.hideLoading(); | ||||||
|         if (headerBinding != null) { |         if (headerBinding != null) { | ||||||
|             animateView(headerBinding.getRoot(), true, 200); |             animate(headerBinding.getRoot(), true, 200); | ||||||
|             animateView(playlistControlBinding.getRoot(), true, 200); |             animate(playlistControlBinding.getRoot(), true, 200); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -36,6 +36,7 @@ import org.schabi.newpipe.databinding.DialogTitleBinding | |||||||
| import org.schabi.newpipe.databinding.FragmentSubscriptionBinding | import org.schabi.newpipe.databinding.FragmentSubscriptionBinding | ||||||
| import org.schabi.newpipe.extractor.channel.ChannelInfoItem | import org.schabi.newpipe.extractor.channel.ChannelInfoItem | ||||||
| import org.schabi.newpipe.fragments.BaseStateFragment | 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.SubscriptionViewModel.SubscriptionState | ||||||
| import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialog | import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialog | ||||||
| import org.schabi.newpipe.local.subscription.dialog.FeedGroupReorderDialog | 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.KEY_VALUE | ||||||
| import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.PREVIOUS_EXPORT_MODE | import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.PREVIOUS_EXPORT_MODE | ||||||
| import org.schabi.newpipe.report.UserAction | import org.schabi.newpipe.report.UserAction | ||||||
| import org.schabi.newpipe.util.AnimationUtils.animateView |  | ||||||
| import org.schabi.newpipe.util.FilePickerActivityHelper | import org.schabi.newpipe.util.FilePickerActivityHelper | ||||||
| import org.schabi.newpipe.util.NavigationHelper | import org.schabi.newpipe.util.NavigationHelper | ||||||
| import org.schabi.newpipe.util.OnClickGesture | import org.schabi.newpipe.util.OnClickGesture | ||||||
| @@ -407,12 +407,12 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() { | |||||||
|  |  | ||||||
|     override fun showLoading() { |     override fun showLoading() { | ||||||
|         super.showLoading() |         super.showLoading() | ||||||
|         animateView(binding.itemsList, false, 100) |         binding.itemsList.animate(false, 100) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun hideLoading() { |     override fun hideLoading() { | ||||||
|         super.hideLoading() |         super.hideLoading() | ||||||
|         animateView(binding.itemsList, true, 200) |         binding.itemsList.animate(true, 200) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // ///////////////////////////////////////////////////////////////////////// |     // ///////////////////////////////////////////////////////////////////////// | ||||||
|   | |||||||
| @@ -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.R | ||||||
| import org.schabi.newpipe.extractor.NewPipe | import org.schabi.newpipe.extractor.NewPipe | ||||||
| import org.schabi.newpipe.extractor.exceptions.ExtractionException | 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.ServiceHelper | ||||||
| import org.schabi.newpipe.util.ThemeHelper | import org.schabi.newpipe.util.ThemeHelper | ||||||
| import org.schabi.newpipe.views.CollapsibleView | import org.schabi.newpipe.views.CollapsibleView | ||||||
| @@ -49,8 +49,7 @@ class FeedImportExportItem( | |||||||
|  |  | ||||||
|         expandIconListener?.let { viewHolder.import_export_options.removeListener(it) } |         expandIconListener?.let { viewHolder.import_export_options.removeListener(it) } | ||||||
|         expandIconListener = CollapsibleView.StateListener { newState -> |         expandIconListener = CollapsibleView.StateListener { newState -> | ||||||
|             AnimationUtils.animateRotation( |             viewHolder.import_export_expand_icon.animateRotation( | ||||||
|                 viewHolder.import_export_expand_icon, |  | ||||||
|                 250, if (newState == CollapsibleView.COLLAPSED) 0 else 180 |                 250, if (newState == CollapsibleView.COLLAPSED) 0 else 180 | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -9,8 +9,8 @@ import kotlinx.android.synthetic.main.picker_subscription_item.* | |||||||
| import kotlinx.android.synthetic.main.picker_subscription_item.view.* | import kotlinx.android.synthetic.main.picker_subscription_item.view.* | ||||||
| import org.schabi.newpipe.R | import org.schabi.newpipe.R | ||||||
| import org.schabi.newpipe.database.subscription.SubscriptionEntity | import org.schabi.newpipe.database.subscription.SubscriptionEntity | ||||||
| import org.schabi.newpipe.util.AnimationUtils | import org.schabi.newpipe.ktx.AnimationType | ||||||
| import org.schabi.newpipe.util.AnimationUtils.animateView | import org.schabi.newpipe.ktx.animate | ||||||
| import org.schabi.newpipe.util.ImageDisplayConstants | import org.schabi.newpipe.util.ImageDisplayConstants | ||||||
|  |  | ||||||
| data class PickerSubscriptionItem( | data class PickerSubscriptionItem( | ||||||
| @@ -41,9 +41,6 @@ data class PickerSubscriptionItem( | |||||||
|  |  | ||||||
|     fun updateSelected(containerView: View, isSelected: Boolean) { |     fun updateSelected(containerView: View, isSelected: Boolean) { | ||||||
|         this.isSelected = isSelected |         this.isSelected = isSelected | ||||||
|         animateView( |         containerView.selected_highlight.animate(isSelected, 150, AnimationType.LIGHT_SCALE_AND_ALPHA) | ||||||
|             containerView.selected_highlight, |  | ||||||
|             AnimationUtils.Type.LIGHT_SCALE_AND_ALPHA, isSelected, 150 |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -92,6 +92,7 @@ import org.schabi.newpipe.extractor.stream.VideoStream; | |||||||
| import org.schabi.newpipe.fragments.OnScrollBelowItemsListener; | import org.schabi.newpipe.fragments.OnScrollBelowItemsListener; | ||||||
| import org.schabi.newpipe.fragments.detail.VideoDetailFragment; | import org.schabi.newpipe.fragments.detail.VideoDetailFragment; | ||||||
| import org.schabi.newpipe.info_list.StreamSegmentAdapter; | import org.schabi.newpipe.info_list.StreamSegmentAdapter; | ||||||
|  | import org.schabi.newpipe.ktx.AnimationType; | ||||||
| import org.schabi.newpipe.local.history.HistoryRecordManager; | import org.schabi.newpipe.local.history.HistoryRecordManager; | ||||||
| import org.schabi.newpipe.player.MainPlayer.PlayerType; | import org.schabi.newpipe.player.MainPlayer.PlayerType; | ||||||
| import org.schabi.newpipe.player.event.PlayerEventListener; | 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.AudioPlaybackResolver; | ||||||
| import org.schabi.newpipe.player.resolver.MediaSourceTag; | import org.schabi.newpipe.player.resolver.MediaSourceTag; | ||||||
| import org.schabi.newpipe.player.resolver.VideoPlaybackResolver; | import org.schabi.newpipe.player.resolver.VideoPlaybackResolver; | ||||||
| import org.schabi.newpipe.util.AnimationUtils; |  | ||||||
| import org.schabi.newpipe.util.DeviceUtils; | import org.schabi.newpipe.util.DeviceUtils; | ||||||
| import org.schabi.newpipe.util.ImageDisplayConstants; | import org.schabi.newpipe.util.ImageDisplayConstants; | ||||||
| import org.schabi.newpipe.util.KoreUtil; | 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 com.google.android.exoplayer2.Player.RepeatMode; | ||||||
| import static java.util.concurrent.TimeUnit.MILLISECONDS; | import static java.util.concurrent.TimeUnit.MILLISECONDS; | ||||||
| import static org.schabi.newpipe.extractor.ServiceList.YouTube; | 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_CLOSE; | ||||||
| import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD; | import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD; | ||||||
| import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_REWIND; | 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.retrievePopupLayoutParamsFromPrefs; | ||||||
| import static org.schabi.newpipe.player.helper.PlayerHelper.retrieveSeekDurationFromPreferences; | import static org.schabi.newpipe.player.helper.PlayerHelper.retrieveSeekDurationFromPreferences; | ||||||
| import static org.schabi.newpipe.player.helper.PlayerHelper.savePlaybackParametersToPrefs; | 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.getPopupResolutionIndex; | ||||||
| import static org.schabi.newpipe.util.ListHelper.getResolutionIndex; | import static org.schabi.newpipe.util.ListHelper.getResolutionIndex; | ||||||
| import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; | import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; | ||||||
| @@ -1560,8 +1559,8 @@ public final class Player implements | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         showControls(0); |         showControls(0); | ||||||
|         animateView(binding.currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, true, |         animate(binding.currentDisplaySeek, true, DEFAULT_CONTROLS_DURATION, | ||||||
|                 DEFAULT_CONTROLS_DURATION); |                 AnimationType.SCALE_AND_ALPHA); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override // seekbar listener |     @Override // seekbar listener | ||||||
| @@ -1576,7 +1575,7 @@ public final class Player implements | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         binding.playbackCurrentTime.setText(getTimeString(seekBar.getProgress())); |         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) { |         if (currentState == STATE_PAUSED_SEEK) { | ||||||
|             changeState(STATE_BUFFERING); |             changeState(STATE_BUFFERING); | ||||||
| @@ -1682,8 +1681,8 @@ public final class Player implements | |||||||
|                 : DPAD_CONTROLS_HIDE_TIME; |                 : DPAD_CONTROLS_HIDE_TIME; | ||||||
|  |  | ||||||
|         showHideShadow(true, DEFAULT_CONTROLS_DURATION); |         showHideShadow(true, DEFAULT_CONTROLS_DURATION); | ||||||
|         animateView(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION, 0, |         animate(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION, | ||||||
|                 () -> hideControls(DEFAULT_CONTROLS_DURATION, hideTime)); |                 AnimationType.ALPHA, 0, () -> hideControls(DEFAULT_CONTROLS_DURATION, hideTime)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void showControls(final long duration) { |     public void showControls(final long duration) { | ||||||
| @@ -1694,7 +1693,7 @@ public final class Player implements | |||||||
|         showSystemUIPartially(); |         showSystemUIPartially(); | ||||||
|         controlsVisibilityHandler.removeCallbacksAndMessages(null); |         controlsVisibilityHandler.removeCallbacksAndMessages(null); | ||||||
|         showHideShadow(true, duration); |         showHideShadow(true, duration); | ||||||
|         animateView(binding.playbackControlRoot, true, duration); |         animate(binding.playbackControlRoot, true, duration); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void hideControls(final long duration, final long delay) { |     public void hideControls(final long duration, final long delay) { | ||||||
| @@ -1708,14 +1707,14 @@ public final class Player implements | |||||||
|         controlsVisibilityHandler.removeCallbacksAndMessages(null); |         controlsVisibilityHandler.removeCallbacksAndMessages(null); | ||||||
|         controlsVisibilityHandler.postDelayed(() -> { |         controlsVisibilityHandler.postDelayed(() -> { | ||||||
|             showHideShadow(false, duration); |             showHideShadow(false, duration); | ||||||
|             animateView(binding.playbackControlRoot, false, duration, 0, |             animate(binding.playbackControlRoot, false, duration, AnimationType.ALPHA, | ||||||
|                     this::hideSystemUIIfNeeded); |                     0, this::hideSystemUIIfNeeded); | ||||||
|         }, delay); |         }, delay); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void showHideShadow(final boolean show, final long duration) { |     private void showHideShadow(final boolean show, final long duration) { | ||||||
|         animateView(binding.playerTopShadow, show, duration, 0, null); |         animate(binding.playerTopShadow, show, duration, AnimationType.ALPHA, 0, null); | ||||||
|         animateView(binding.playerBottomShadow, show, duration, 0, null); |         animate(binding.playerBottomShadow, show, duration, AnimationType.ALPHA, 0, null); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void showOrHideButtons() { |     private void showOrHideButtons() { | ||||||
| @@ -1913,15 +1912,15 @@ public final class Player implements | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         controlsVisibilityHandler.removeCallbacksAndMessages(null); |         controlsVisibilityHandler.removeCallbacksAndMessages(null); | ||||||
|         animateView(binding.playbackControlRoot, false, DEFAULT_CONTROLS_DURATION); |         animate(binding.playbackControlRoot, false, DEFAULT_CONTROLS_DURATION); | ||||||
|  |  | ||||||
|         binding.playbackSeekBar.setEnabled(false); |         binding.playbackSeekBar.setEnabled(false); | ||||||
|         binding.playbackSeekBar.getThumb() |         binding.playbackSeekBar.getThumb() | ||||||
|                 .setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN)); |                 .setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN)); | ||||||
|  |  | ||||||
|         binding.loadingPanel.setBackgroundColor(Color.BLACK); |         binding.loadingPanel.setBackgroundColor(Color.BLACK); | ||||||
|         animateView(binding.loadingPanel, true, 0); |         animate(binding.loadingPanel, true, 0); | ||||||
|         animateView(binding.surfaceForeground, true, 100); |         animate(binding.surfaceForeground, true, 100); | ||||||
|  |  | ||||||
|         binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp); |         binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp); | ||||||
|         animatePlayButtons(false, 100); |         animatePlayButtons(false, 100); | ||||||
| @@ -1948,9 +1947,9 @@ public final class Player implements | |||||||
|  |  | ||||||
|         binding.loadingPanel.setVisibility(View.GONE); |         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); |                     binding.playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp); | ||||||
|                     animatePlayButtons(true, 200); |                     animatePlayButtons(true, 200); | ||||||
| @@ -1991,7 +1990,7 @@ public final class Player implements | |||||||
|         showControls(400); |         showControls(400); | ||||||
|         binding.loadingPanel.setVisibility(View.GONE); |         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); |                     binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp); | ||||||
|                     animatePlayButtons(true, 200); |                     animatePlayButtons(true, 200); | ||||||
| @@ -2029,7 +2028,7 @@ public final class Player implements | |||||||
|             Log.d(TAG, "onCompleted() called"); |             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); |                     binding.playPauseButton.setImageResource(R.drawable.ic_replay_white_24dp); | ||||||
|                     animatePlayButtons(true, DEFAULT_CONTROLS_DURATION); |                     animatePlayButtons(true, DEFAULT_CONTROLS_DURATION); | ||||||
| @@ -2051,13 +2050,13 @@ public final class Player implements | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         showControls(500); |         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); |         binding.loadingPanel.setVisibility(View.GONE); | ||||||
|         animateView(binding.surfaceForeground, true, 100); |         animate(binding.surfaceForeground, true, 100); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void animatePlayButtons(final boolean show, final int duration) { |     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; |         boolean showQueueButtons = show; | ||||||
|         if (playQueue == null) { |         if (playQueue == null) { | ||||||
| @@ -2065,18 +2064,18 @@ public final class Player implements | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!showQueueButtons || playQueue.getIndex() > 0) { |         if (!showQueueButtons || playQueue.getIndex() > 0) { | ||||||
|             animateView( |             animate( | ||||||
|                     binding.playPreviousButton, |                     binding.playPreviousButton, | ||||||
|                     AnimationUtils.Type.SCALE_AND_ALPHA, |  | ||||||
|                     showQueueButtons, |                     showQueueButtons, | ||||||
|                     duration); |                     duration, | ||||||
|  |                     AnimationType.SCALE_AND_ALPHA); | ||||||
|         } |         } | ||||||
|         if (!showQueueButtons || playQueue.getIndex() + 1 < playQueue.getStreams().size()) { |         if (!showQueueButtons || playQueue.getIndex() + 1 < playQueue.getStreams().size()) { | ||||||
|             animateView( |             animate( | ||||||
|                     binding.playNextButton, |                     binding.playNextButton, | ||||||
|                     AnimationUtils.Type.SCALE_AND_ALPHA, |  | ||||||
|                     showQueueButtons, |                     showQueueButtons, | ||||||
|                     duration); |                     duration, | ||||||
|  |                     AnimationType.SCALE_AND_ALPHA); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     //endregion |     //endregion | ||||||
| @@ -2274,7 +2273,7 @@ public final class Player implements | |||||||
|     @Override |     @Override | ||||||
|     public void onRenderedFirstFrame() { |     public void onRenderedFirstFrame() { | ||||||
|         //TODO check if this causes black screen when switching to fullscreen |         //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 |     //endregion | ||||||
|  |  | ||||||
| @@ -2871,8 +2870,8 @@ public final class Player implements | |||||||
|  |  | ||||||
|         hideControls(0, 0); |         hideControls(0, 0); | ||||||
|         binding.itemsListPanel.requestFocus(); |         binding.itemsListPanel.requestFocus(); | ||||||
|         animateView(binding.itemsListPanel, SLIDE_AND_ALPHA, true, |         animate(binding.itemsListPanel, true, DEFAULT_CONTROLS_DURATION, | ||||||
|                 DEFAULT_CONTROLS_DURATION); |                 AnimationType.SLIDE_AND_ALPHA); | ||||||
|  |  | ||||||
|         binding.itemsList.scrollToPosition(playQueue.getIndex()); |         binding.itemsList.scrollToPosition(playQueue.getIndex()); | ||||||
|     } |     } | ||||||
| @@ -2905,8 +2904,8 @@ public final class Player implements | |||||||
|  |  | ||||||
|         hideControls(0, 0); |         hideControls(0, 0); | ||||||
|         binding.itemsListPanel.requestFocus(); |         binding.itemsListPanel.requestFocus(); | ||||||
|         animateView(binding.itemsListPanel, SLIDE_AND_ALPHA, true, |         animate(binding.itemsListPanel, true, DEFAULT_CONTROLS_DURATION, | ||||||
|                 DEFAULT_CONTROLS_DURATION); |                 AnimationType.SLIDE_AND_ALPHA); | ||||||
|  |  | ||||||
|         final int adapterPosition = getNearestStreamSegmentPosition(simpleExoPlayer |         final int adapterPosition = getNearestStreamSegmentPosition(simpleExoPlayer | ||||||
|                 .getCurrentPosition()); |                 .getCurrentPosition()); | ||||||
| @@ -2942,8 +2941,8 @@ public final class Player implements | |||||||
|                 itemTouchHelper.attachToRecyclerView(null); |                 itemTouchHelper.attachToRecyclerView(null); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             animateView(binding.itemsListPanel, SLIDE_AND_ALPHA, false, |             animate(binding.itemsListPanel, false, DEFAULT_CONTROLS_DURATION, | ||||||
|                     DEFAULT_CONTROLS_DURATION, 0, () -> { |                     AnimationType.SLIDE_AND_ALPHA, 0, () -> { | ||||||
|                         // Even when queueLayout is GONE it receives touch events |                         // Even when queueLayout is GONE it receives touch events | ||||||
|                         // and ruins normal behavior of the app. This line fixes it |                         // and ruins normal behavior of the app. This line fixes it | ||||||
|                         binding.itemsListPanel.setTranslationY( |                         binding.itemsListPanel.setTranslationY( | ||||||
| @@ -3451,7 +3450,8 @@ public final class Player implements | |||||||
|         if (currentState != STATE_COMPLETED) { |         if (currentState != STATE_COMPLETED) { | ||||||
|             controlsVisibilityHandler.removeCallbacksAndMessages(null); |             controlsVisibilityHandler.removeCallbacksAndMessages(null); | ||||||
|             showHideShadow(true, DEFAULT_CONTROLS_DURATION); |             showHideShadow(true, DEFAULT_CONTROLS_DURATION); | ||||||
|             animateView(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION, 0, () -> { |             animate(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION, | ||||||
|  |                     AnimationType.ALPHA, 0, () -> { | ||||||
|                         if (currentState == STATE_PLAYING && !isSomePopupMenuVisible) { |                         if (currentState == STATE_PLAYING && !isSomePopupMenuVisible) { | ||||||
|                             if (v.getId() == binding.playPauseButton.getId() |                             if (v.getId() == binding.playPauseButton.getId() | ||||||
|                                     // Hide controls in fullscreen immediately |                                     // Hide controls in fullscreen immediately | ||||||
| @@ -3531,9 +3531,8 @@ public final class Player implements | |||||||
|  |  | ||||||
|         animateRotation(binding.moreOptionsButton, DEFAULT_CONTROLS_DURATION, |         animateRotation(binding.moreOptionsButton, DEFAULT_CONTROLS_DURATION, | ||||||
|                 isMoreControlsVisible ? 0 : 180); |                 isMoreControlsVisible ? 0 : 180); | ||||||
|         animateView(binding.secondaryControls, SLIDE_AND_ALPHA, !isMoreControlsVisible, |         animate(binding.secondaryControls, !isMoreControlsVisible, DEFAULT_CONTROLS_DURATION, | ||||||
|                 DEFAULT_CONTROLS_DURATION, 0, |                 AnimationType.SLIDE_AND_ALPHA, 0, () -> { | ||||||
|                 () -> { |  | ||||||
|                     // Fix for a ripple effect on background drawable. |                     // Fix for a ripple effect on background drawable. | ||||||
|                     // When view returns from GONE state it takes more milliseconds than returning |                     // When view returns from GONE state it takes more milliseconds than returning | ||||||
|                     // from INVISIBLE state. And the delay makes ripple background end to fast |                     // from INVISIBLE state. And the delay makes ripple background end to fast | ||||||
|   | |||||||
| @@ -7,11 +7,11 @@ import android.view.GestureDetector | |||||||
| import android.view.MotionEvent | import android.view.MotionEvent | ||||||
| import android.view.View | import android.view.View | ||||||
| import android.view.ViewConfiguration | import android.view.ViewConfiguration | ||||||
|  | import org.schabi.newpipe.ktx.animate | ||||||
| import org.schabi.newpipe.player.MainPlayer | import org.schabi.newpipe.player.MainPlayer | ||||||
| import org.schabi.newpipe.player.Player | import org.schabi.newpipe.player.Player | ||||||
| import org.schabi.newpipe.player.helper.PlayerHelper | import org.schabi.newpipe.player.helper.PlayerHelper | ||||||
| import org.schabi.newpipe.player.helper.PlayerHelper.savePopupPositionAndSizeToPrefs | import org.schabi.newpipe.player.helper.PlayerHelper.savePopupPositionAndSizeToPrefs | ||||||
| import org.schabi.newpipe.util.AnimationUtils |  | ||||||
| import kotlin.math.abs | import kotlin.math.abs | ||||||
| import kotlin.math.hypot | import kotlin.math.hypot | ||||||
| import kotlin.math.max | import kotlin.math.max | ||||||
| @@ -364,7 +364,7 @@ abstract class BasePlayerGestureListener( | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!isMovingInPopup) { |         if (!isMovingInPopup) { | ||||||
|             AnimationUtils.animateView(player.closeOverlayButton, true, 200) |             player.closeOverlayButton.animate(true, 200) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         isMovingInPopup = true |         isMovingInPopup = true | ||||||
|   | |||||||
| @@ -17,11 +17,12 @@ import org.schabi.newpipe.player.MainPlayer; | |||||||
| import org.schabi.newpipe.player.Player; | import org.schabi.newpipe.player.Player; | ||||||
| import org.schabi.newpipe.player.helper.PlayerHelper; | 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_DURATION; | ||||||
| import static org.schabi.newpipe.player.Player.DEFAULT_CONTROLS_HIDE_TIME; | 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.player.Player.STATE_PLAYING; | ||||||
| import static org.schabi.newpipe.util.AnimationUtils.animateView; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * GestureListener for the player |  * GestureListener for the player | ||||||
| @@ -123,11 +124,11 @@ public class PlayerGestureListener | |||||||
|             final View closingOverlayView = player.getClosingOverlayView(); |             final View closingOverlayView = player.getClosingOverlayView(); | ||||||
|             if (player.isInsideClosingRadius(movingEvent)) { |             if (player.isInsideClosingRadius(movingEvent)) { | ||||||
|                 if (closingOverlayView.getVisibility() == View.GONE) { |                 if (closingOverlayView.getVisibility() == View.GONE) { | ||||||
|                     animateView(closingOverlayView, true, 250); |                     animate(closingOverlayView, true, 250); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 if (closingOverlayView.getVisibility() == View.VISIBLE) { |                 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) { |         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) { |         if (player.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) { | ||||||
|             player.getBrightnessRelativeLayout().setVisibility(View.GONE); |             player.getBrightnessRelativeLayout().setVisibility(View.GONE); | ||||||
| @@ -195,7 +196,7 @@ public class PlayerGestureListener | |||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         if (player.getBrightnessRelativeLayout().getVisibility() != View.VISIBLE) { |         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) { |         if (player.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) { | ||||||
|             player.getVolumeRelativeLayout().setVisibility(View.GONE); |             player.getVolumeRelativeLayout().setVisibility(View.GONE); | ||||||
| @@ -215,21 +216,18 @@ public class PlayerGestureListener | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (player.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) { |             if (player.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) { | ||||||
|                 animateView(player.getVolumeRelativeLayout(), SCALE_AND_ALPHA, |                 animate(player.getVolumeRelativeLayout(), false, 200, SCALE_AND_ALPHA, | ||||||
|                         false, 200, 200); |                         200); | ||||||
|             } |             } | ||||||
|             if (player.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) { |             if (player.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) { | ||||||
|                 animateView(player.getBrightnessRelativeLayout(), SCALE_AND_ALPHA, |                 animate(player.getBrightnessRelativeLayout(), false, 200, SCALE_AND_ALPHA, | ||||||
|                         false, 200, 200); |                         200); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (player.isControlsVisible() && player.getCurrentState() == STATE_PLAYING) { |             if (player.isControlsVisible() && player.getCurrentState() == STATE_PLAYING) { | ||||||
|                 player.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); |                 player.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             if (player == null) { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             if (player.isControlsVisible() && player.getCurrentState() == STATE_PLAYING) { |             if (player.isControlsVisible() && player.getCurrentState() == STATE_PLAYING) { | ||||||
|                 player.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); |                 player.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); | ||||||
|             } |             } | ||||||
| @@ -237,10 +235,10 @@ public class PlayerGestureListener | |||||||
|             if (player.isInsideClosingRadius(event)) { |             if (player.isInsideClosingRadius(event)) { | ||||||
|                 player.closePopup(); |                 player.closePopup(); | ||||||
|             } else { |             } else { | ||||||
|                 animateView(player.getClosingOverlayView(), false, 0); |                 animate(player.getClosingOverlayView(), false, 0); | ||||||
|  |  | ||||||
|                 if (!player.isPopupClosing()) { |                 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.getLoadingPanel().setVisibility(View.GONE); | ||||||
|  |  | ||||||
|         player.hideControls(0, 0); |         player.hideControls(0, 0); | ||||||
|         animateView(player.getCurrentDisplaySeek(), false, 0, 0); |         animate(player.getCurrentDisplaySeek(), false, 0, ALPHA, 0); | ||||||
|         animateView(player.getResizingIndicator(), true, 200, 0); |         animate(player.getResizingIndicator(), true, 200, ALPHA, 0); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -264,7 +262,7 @@ public class PlayerGestureListener | |||||||
|         if (DEBUG) { |         if (DEBUG) { | ||||||
|             Log.d(TAG, "onPopupResizingEnd called"); |             Log.d(TAG, "onPopupResizingEnd called"); | ||||||
|         } |         } | ||||||
|         animateView(player.getResizingIndicator(), false, 100, 0); |         animate(player.getResizingIndicator(), false, 100, ALPHA, 0); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -31,7 +31,7 @@ import androidx.annotation.IntDef; | |||||||
| import androidx.annotation.Nullable; | import androidx.annotation.Nullable; | ||||||
| import androidx.annotation.RequiresApi; | import androidx.annotation.RequiresApi; | ||||||
|  |  | ||||||
| import org.schabi.newpipe.util.AnimationUtils; | import org.schabi.newpipe.ktx.ViewUtils; | ||||||
|  |  | ||||||
| import java.lang.annotation.Retention; | import java.lang.annotation.Retention; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| @@ -128,7 +128,7 @@ public class CollapsibleView extends LinearLayout { | |||||||
|         if (currentAnimator != null && currentAnimator.isRunning()) { |         if (currentAnimator != null && currentAnimator.isRunning()) { | ||||||
|             currentAnimator.cancel(); |             currentAnimator.cancel(); | ||||||
|         } |         } | ||||||
|         currentAnimator = AnimationUtils.animateHeight(this, ANIMATION_DURATION, 0); |         currentAnimator = ViewUtils.animateHeight(this, ANIMATION_DURATION, 0); | ||||||
|  |  | ||||||
|         setCurrentState(COLLAPSED); |         setCurrentState(COLLAPSED); | ||||||
|     } |     } | ||||||
| @@ -151,7 +151,7 @@ public class CollapsibleView extends LinearLayout { | |||||||
|         if (currentAnimator != null && currentAnimator.isRunning()) { |         if (currentAnimator != null && currentAnimator.isRunning()) { | ||||||
|             currentAnimator.cancel(); |             currentAnimator.cancel(); | ||||||
|         } |         } | ||||||
|         currentAnimator = AnimationUtils.animateHeight(this, ANIMATION_DURATION, this.targetHeight); |         currentAnimator = ViewUtils.animateHeight(this, ANIMATION_DURATION, this.targetHeight); | ||||||
|         setCurrentState(EXPANDED); |         setCurrentState(EXPANDED); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Stypox
					Stypox