package io.hefuyi.listener.listener;
import android.animation.ArgbEvaluator;
import android.animation.FloatEvaluator;
import android.animation.IntEvaluator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.design.widget.CoordinatorLayout;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
import net.steamcrafted.materialiconlib.MaterialIconView;
import io.hefuyi.listener.MusicPlayer;
import io.hefuyi.listener.R;
import io.hefuyi.listener.RxBus;
import io.hefuyi.listener.event.MetaChangedEvent;
import io.hefuyi.listener.ui.fragment.QuickControlsFragment;
import io.hefuyi.listener.util.ATEUtil;
import io.hefuyi.listener.util.DensityUtil;
import io.hefuyi.listener.util.ImageUtil;
import io.hefuyi.listener.util.ScrimUtil;
import io.hefuyi.listener.widget.ForegroundImageView;
import io.hefuyi.listener.widget.LyricView;
import io.hefuyi.listener.widget.PlayPauseView;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
/**
* Created by hefuyi on 2016/11/7.
*/
public class PanelSlideListener implements SlidingUpPanelLayout.PanelSlideListener{
private static final String TAG = PanelSlideListener.class.getSimpleName();
private final SlidingUpPanelLayout mPanelLayout;
private final Context mContext;
private View nowPlayingCard;
private RelativeLayout toolbar;
private LinearLayout content;
private ProgressBar progressBar;
private TextView title;
private TextView artist;
private ForegroundImageView albumImage;
private Drawable albumImageDrawable;
private RelativeLayout iconContainer;
private MaterialIconView heart;
private MaterialIconView previous;
private PlayPauseView playPause;
private MaterialIconView next;
private MaterialIconView playqueue;
private LyricView lyricView;
private SeekBar seekbar;
private int screenWidth;
private int screenHeight;
private int titleEndTranslationX;
private int artistEndTranslationX;
private int artistNormalEndTranslationY;
private int artistFullEndTranslationY;
private int contentNormalEndTranslationY;
private int contentFullEndTranslationY;
private int lyricLineHeight;
private int lyricFullHeight;
private int lyricLineStartTranslationY;
private int lyricLineEndTranslationY;
private int lyricFullTranslationY;
private int heartStartX;
private int previousStartX;
private int playPauseStartX;
private int nextStartX;
private int playqueueStartX;
private int playPauseEndX;
private int previousEndX;
private int heartEndX;
private int nextEndX;
private int playqueueEndX;
private int iconContainerStartY;
private int iconContainerEndY;
private IntEvaluator intEvaluator = new IntEvaluator();
private FloatEvaluator floatEvaluator = new FloatEvaluator();
private ArgbEvaluator colorEvaluator = new ArgbEvaluator();
private int nowPlayingCardColor;
private int playpauseDrawableColor;
private Status mStatus = Status.COLLAPSED;
public enum Status {
EXPANDED,
COLLAPSED,
FULLSCREEN
}
public PanelSlideListener(SlidingUpPanelLayout slidingUpPanelLayout) {
mPanelLayout = slidingUpPanelLayout;
nowPlayingCard = mPanelLayout.findViewById(R.id.topContainer);
toolbar = (RelativeLayout) nowPlayingCard.findViewById(R.id.custom_toolbar);
mContext = mPanelLayout.getContext();
albumImage = (ForegroundImageView) nowPlayingCard.findViewById(R.id.album_art);
content = (LinearLayout) nowPlayingCard.findViewById(R.id.content);
progressBar = (ProgressBar) nowPlayingCard.findViewById(R.id.song_progress_normal);
title = (TextView) nowPlayingCard.findViewById(R.id.title);
artist = (TextView) nowPlayingCard.findViewById(R.id.artist);
screenWidth = DensityUtil.getScreenWidth(mContext);
screenHeight = DensityUtil.getScreenHeight(mContext);
iconContainer = (RelativeLayout) nowPlayingCard.findViewById(R.id.icon_container);
heart = (MaterialIconView) nowPlayingCard.findViewById(R.id.heart);
previous = (MaterialIconView) nowPlayingCard.findViewById(R.id.previous);
playPause = (PlayPauseView) nowPlayingCard.findViewById(R.id.play_pause);
next = (MaterialIconView) nowPlayingCard.findViewById(R.id.next);
playqueue = (MaterialIconView) nowPlayingCard.findViewById(R.id.ic_play_queue);
lyricView = (LyricView) nowPlayingCard.findViewById(R.id.lyric_view);
playpauseDrawableColor = ATEUtil.getThemeAccentColor(mContext);
seekbar = (SeekBar) mPanelLayout.findViewById(R.id.seek_song_touch);
QuickControlsFragment.setPaletteColorChangeListener(new PaletteColorChangeListener() {
@Override
public void onPaletteColorChange(int paletteColor, int blackWhiteColor) {
nowPlayingCardColor = paletteColor;
playpauseDrawableColor = blackWhiteColor;
if (mPanelLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
playPause.setCircleAlpah(0);
playPause.setDrawableColor(playpauseDrawableColor);
}else {
playPause.setCircleAlpah(255);
playPause.setDrawableColor(nowPlayingCardColor);
}
switch (mStatus) {
case FULLSCREEN:
albumImageDrawable = albumImage.getDrawable();
setBlurredAlbumArt();
}
}
});
if (MusicPlayer.getQueueSize() == 0) {
mPanelLayout.setTouchEnabled(false);
}
caculateTitleAndArtist();
caculateIcons();
caculateLyricView();
subscribeMetaChangedEvent();
}
@Override
public void onPanelSlide(View panel, float slideOffset) {
CoordinatorLayout.LayoutParams frameLayout = (CoordinatorLayout.LayoutParams) albumImage.getLayoutParams();
//animate albumImage
int tempt = intEvaluator.evaluate(slideOffset, DensityUtil.dip2px(nowPlayingCard.getContext(), 55), screenWidth);
frameLayout.width = tempt;
frameLayout.height = tempt;
albumImage.setLayoutParams(frameLayout);
//animate title and artist
title.setTranslationX(floatEvaluator.evaluate(slideOffset, 0, titleEndTranslationX));
artist.setTranslationX(floatEvaluator.evaluate(slideOffset, 0, artistEndTranslationX));
artist.setTranslationY(floatEvaluator.evaluate(slideOffset, 0, artistNormalEndTranslationY));
content.setTranslationY(floatEvaluator.evaluate(slideOffset, 0, contentNormalEndTranslationY));
//aniamte icons
playPause.setX(intEvaluator.evaluate(slideOffset, playPauseStartX, playPauseEndX));
playPause.setCircleAlpah(intEvaluator.evaluate(slideOffset, 0, 255));
playPause.setDrawableColor((int) colorEvaluator.evaluate(slideOffset, playpauseDrawableColor, nowPlayingCardColor));
previous.setX(intEvaluator.evaluate(slideOffset, previousStartX, previousEndX));
heart.setX(intEvaluator.evaluate(slideOffset, heartStartX, heartEndX));
next.setX(intEvaluator.evaluate(slideOffset, nextStartX, nextEndX));
playqueue.setX(intEvaluator.evaluate(slideOffset, playqueueStartX, playqueueEndX));
heart.setAlpha(floatEvaluator.evaluate(slideOffset, 0, 1));
previous.setAlpha(floatEvaluator.evaluate(slideOffset, 0, 1));
iconContainer.setY(intEvaluator.evaluate(slideOffset, iconContainerStartY, iconContainerEndY));
//animate lyric view
lyricView.setTranslationY(lyricLineStartTranslationY - (lyricLineStartTranslationY - lyricLineEndTranslationY) * slideOffset);
}
@Override
public void onPanelStateChanged(View panel, SlidingUpPanelLayout.PanelState previousState, SlidingUpPanelLayout.PanelState newState) {
if (previousState == SlidingUpPanelLayout.PanelState.COLLAPSED) {
progressBar.setVisibility(View.INVISIBLE);
heart.setVisibility(View.VISIBLE);
previous.setVisibility(View.VISIBLE);
} else if (previousState == SlidingUpPanelLayout.PanelState.EXPANDED) {
if (mStatus == Status.FULLSCREEN) {
animateToNormal();
}
}
if (newState == SlidingUpPanelLayout.PanelState.EXPANDED) {
mStatus = Status.EXPANDED;
toolbarSlideIn();
heart.setClickable(true);
previous.setClickable(true);
nowPlayingCard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mStatus==Status.EXPANDED){
animateToFullscreen();
}else if (mStatus==Status.FULLSCREEN){
animateToNormal();
}else {
mPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
}
}
});
} else if (newState == SlidingUpPanelLayout.PanelState.COLLAPSED) {
mStatus = Status.COLLAPSED;
progressBar.setVisibility(View.VISIBLE);
heart.setVisibility(View.GONE);
previous.setVisibility(View.GONE);
nowPlayingCard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mPanelLayout.isTouchEnabled()) {
mPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.EXPANDED);
}
}
});
} else if (newState == SlidingUpPanelLayout.PanelState.DRAGGING) {
toolbar.setVisibility(View.INVISIBLE);
}
}
private void caculateTitleAndArtist() {
Rect titleBounds = new Rect();
title.getPaint().getTextBounds(title.getText().toString(), 0, title.getText().length(), titleBounds);
int titleWidth = titleBounds.width();
Rect artistBounds = new Rect();
artist.getPaint().getTextBounds(artist.getText().toString(), 0, artist.getText().length(), artistBounds);
int artistWidth = artistBounds.width();
titleEndTranslationX = (screenWidth / 2) - (titleWidth / 2) - DensityUtil.dip2px(mContext, 67);
artistEndTranslationX = (screenWidth / 2) - (artistWidth / 2) - DensityUtil.dip2px(mContext, 67);
artistNormalEndTranslationY = DensityUtil.dip2px(mContext, 12);
artistFullEndTranslationY = 0;
contentNormalEndTranslationY = screenWidth + DensityUtil.dip2px(mContext, 32);
contentFullEndTranslationY = DensityUtil.dip2px(mContext, 32);
if (mStatus==Status.COLLAPSED) {
title.setTranslationX(0);
artist.setTranslationX(0);
}else {
title.setTranslationX(titleEndTranslationX);
artist.setTranslationX(artistEndTranslationX);
}
}
private void caculateIcons() {
heartStartX = heart.getLeft();
previousStartX = previous.getLeft();
playPauseStartX = playPause.getLeft();
nextStartX = next.getLeft();
playqueueStartX = playqueue.getLeft();
int size = DensityUtil.dip2px(mContext, 36);
int gap = (screenWidth - 5 * (size)) / 6;
playPauseEndX = (screenWidth / 2) - (size / 2);
previousEndX = playPauseEndX - gap - size;
heartEndX = previousEndX - gap - size;
nextEndX = playPauseEndX + gap + size;
playqueueEndX = nextEndX + gap + size;
iconContainerStartY = iconContainer.getTop();
iconContainerEndY = screenHeight - iconContainer.getHeight() - seekbar.getHeight();
}
private void caculateLyricView() {
int lyricFullMarginTop = toolbar.getTop() + toolbar.getHeight() + DensityUtil.dip2px(mContext, 32);
int lyricFullMarginBottom = iconContainer.getBottom() + iconContainer.getHeight()
+ DensityUtil.dip2px(mContext, 32);
lyricLineHeight = DensityUtil.dip2px(mContext, 32);
lyricFullHeight = screenHeight - lyricFullMarginTop - lyricFullMarginBottom;
lyricLineStartTranslationY = screenHeight;
int gapBetweenArtistAndLyric = iconContainerEndY - contentNormalEndTranslationY - content.getHeight();
lyricLineEndTranslationY = iconContainerEndY - gapBetweenArtistAndLyric / 2 - lyricLineHeight / 2;
lyricFullTranslationY = toolbar.getTop() + toolbar.getHeight() + DensityUtil.dip2px(mContext, 32);
}
private void setBlurredAlbumArt() {
Observable.create(new Observable.OnSubscribe<Drawable>() {
@Override
public void call(Subscriber<? super Drawable> subscriber) {
Bitmap bitmap = ((BitmapDrawable)albumImage.getDrawable()).getBitmap();
Drawable drawable = ImageUtil.createBlurredImageFromBitmap(bitmap, mContext, 3);
subscriber.onNext(drawable);
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Drawable>() {
@Override
public void call(Drawable drawable) {
CoordinatorLayout.LayoutParams imageLayout = (CoordinatorLayout.LayoutParams) albumImage.getLayoutParams();
imageLayout.height = FrameLayout.LayoutParams.MATCH_PARENT;
imageLayout.width = FrameLayout.LayoutParams.MATCH_PARENT;
albumImage.setLayoutParams(imageLayout);
albumImage.setImageDrawable(drawable);
if(Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
ColorDrawable colorDrawable = new ColorDrawable(nowPlayingCardColor);
colorDrawable.setAlpha(200);
albumImage.setForeground(colorDrawable);
}
}
});
}
private void toolbarSlideIn() {
toolbar.post(new Runnable() {
@Override
public void run() {
Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.toolbar_slide_in);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
toolbar.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
toolbar.startAnimation(animation);
}
});
}
private void animateToFullscreen(){
//album art fullscreen
albumImageDrawable = albumImage.getDrawable();
setBlurredAlbumArt();
//animate title and artist
Animation contentAnimation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
content.setTranslationY(contentNormalEndTranslationY - (contentNormalEndTranslationY - contentFullEndTranslationY) * interpolatedTime);
artist.setTranslationY(artistNormalEndTranslationY - (artistNormalEndTranslationY - artistFullEndTranslationY) * interpolatedTime);
}
};
contentAnimation.setDuration(150);
artist.startAnimation(contentAnimation);
//animate lyric
Animation lyricAnimation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
CoordinatorLayout.LayoutParams lyricLayout = (CoordinatorLayout.LayoutParams) lyricView.getLayoutParams();
lyricLayout.height = (int) (lyricLineHeight + (lyricFullHeight - lyricLineHeight) * interpolatedTime);
lyricView.setLayoutParams(lyricLayout);
lyricView.setTranslationY(lyricLineEndTranslationY - (lyricLineEndTranslationY - lyricFullTranslationY) * interpolatedTime);
}
};
lyricAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
lyricView.setHighLightTextColor(ATEUtil.getThemeAccentColor(mContext));
lyricView.setPlayable(true);
lyricView.setTouchable(true);
lyricView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animateToNormal();
}
});
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
lyricAnimation.setDuration(150);
lyricView.startAnimation(lyricAnimation);
mStatus = Status.FULLSCREEN;
}
private void animateToNormal() {
//album art
CoordinatorLayout.LayoutParams imageLayout = (CoordinatorLayout.LayoutParams) albumImage.getLayoutParams();
imageLayout.height = screenWidth;
imageLayout.width = screenWidth;
albumImage.setImageDrawable(albumImageDrawable);
albumImage.setLayoutParams(imageLayout);
if(Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
albumImage.setForeground(
ScrimUtil.makeCubicGradientScrimDrawable(
nowPlayingCardColor, //颜色
8, //渐变层数
Gravity.CENTER_HORIZONTAL)); //起始方向
}
//animate title and artist
Animation contentAnimation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
content.setTranslationY(contentFullEndTranslationY + (contentNormalEndTranslationY - contentFullEndTranslationY) * interpolatedTime);
artist.setTranslationY(artistFullEndTranslationY + (artistNormalEndTranslationY - artistFullEndTranslationY) * interpolatedTime);
}
};
contentAnimation.setDuration(300);
artist.startAnimation(contentAnimation);
//adjust lyricview
Animation lyricAnimation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) lyricView.getLayoutParams();
layoutParams.height = (int) (lyricFullHeight - (lyricFullHeight - lyricLineHeight) * interpolatedTime);
lyricView.setLayoutParams(layoutParams);
lyricView.setTranslationY(lyricFullTranslationY + (lyricLineEndTranslationY - lyricFullTranslationY) * interpolatedTime);
}
};
lyricAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
lyricView.setPlayable(false);
lyricView.setHighLightTextColor(lyricView.getDefaultColor());
lyricView.setTouchable(false);
lyricView.setClickable(false);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
lyricAnimation.setDuration(300);
lyricView.setPlayable(false);
lyricView.startAnimation(lyricAnimation);
mStatus = Status.EXPANDED;
}
private void subscribeMetaChangedEvent() {
Subscription subscription = RxBus.getInstance()
.toObservable(MetaChangedEvent.class)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.distinctUntilChanged()
.subscribe(new Action1<MetaChangedEvent>() {
@Override
public void call(MetaChangedEvent event) {
caculateTitleAndArtist();
if (TextUtils.isEmpty(MusicPlayer.getTrackName()) || TextUtils.isEmpty(MusicPlayer.getArtistName())) {
if (mStatus == Status.EXPANDED || mStatus == Status.FULLSCREEN) {
mPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
}
mPanelLayout.setTouchEnabled(false);
} else {
mPanelLayout.setTouchEnabled(true);
}
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
}
});
RxBus.getInstance().addSubscription(this, subscription);
}
}