package com.marverenic.music.viewmodel; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.content.Context; import android.databinding.BaseObservable; import android.databinding.Bindable; import android.databinding.ObservableFloat; import android.databinding.ObservableInt; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; import android.support.v4.content.ContextCompat; import android.support.v4.view.animation.FastOutLinearInInterpolator; import android.support.v4.view.animation.LinearOutSlowInInterpolator; import android.view.View; import com.marverenic.music.BR; import com.marverenic.music.JockeyApplication; import com.marverenic.music.R; import com.marverenic.music.activity.BaseActivity; import com.marverenic.music.player.PlayerController; import javax.inject.Inject; import timber.log.Timber; public class BaseLibraryActivityViewModel extends BaseObservable { private Context mContext; @Inject PlayerController mPlayerController; private final boolean mFitSystemWindows; private final int mExpandedHeight; private final ObservableInt mMiniplayerHeight; private final ObservableFloat mMiniplayerAlpha; private final ObservableFloat mNowPlayingToolbarAlpha; private final ColorDrawable mNowPlayingBackground; private int mBottomSheetState; private boolean mAnimateSlideInOut; public BaseLibraryActivityViewModel(BaseActivity activity, boolean fitSystemWindows) { mContext = activity; JockeyApplication.getComponent(mContext).inject(this); mFitSystemWindows = fitSystemWindows; mExpandedHeight = mContext.getResources().getDimensionPixelSize(R.dimen.miniplayer_height); mAnimateSlideInOut = false; mMiniplayerHeight = new ObservableInt(0); mMiniplayerAlpha = new ObservableFloat(1.0f); mNowPlayingToolbarAlpha = new ObservableFloat(0.0f); int backgroundColor = ContextCompat.getColor(activity, R.color.background); mNowPlayingBackground = new ColorDrawable(backgroundColor); setPlaybackOngoing(false); mPlayerController.getNowPlaying() .compose(activity.bindToLifecycle()) .map(nowPlaying -> nowPlaying != null) .subscribe(this::setPlaybackOngoing, throwable -> { Timber.e(throwable, "Failed to set playback state"); }); } private void setPlaybackOngoing(boolean isPlaybackOngoing) { if (mAnimateSlideInOut) { animateTranslation(isPlaybackOngoing); } else { mMiniplayerHeight.set((isPlaybackOngoing) ? mExpandedHeight : 0); } } public void onActivityExitForeground() { mAnimateSlideInOut = false; } public void onActivityEnterForeground() { mAnimateSlideInOut = true; } private void animateTranslation(boolean isPlaybackOngoing) { int startOffset = mMiniplayerHeight.get(); int endOffset; TimeInterpolator interpolator; if (isPlaybackOngoing) { endOffset = mExpandedHeight; interpolator = new LinearOutSlowInInterpolator(); } else { endOffset = 0; interpolator = new FastOutLinearInInterpolator(); } ObjectAnimator slideAnimation = ObjectAnimator.ofInt( mMiniplayerHeight, "", startOffset, endOffset); slideAnimation.setInterpolator(interpolator); slideAnimation.setDuration(225); slideAnimation.start(); } @Bindable public int getStatusBarHeight() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { return 0; } int statusBarHeightResId = mContext.getResources().getIdentifier( "status_bar_height", "dimen", "android"); if (statusBarHeightResId < 0) { return 0; } return mContext.getResources().getDimensionPixelSize(statusBarHeightResId); } @Bindable public int getContentStatusBarHeight() { if (!mFitSystemWindows) { return 0; } else { return getStatusBarHeight(); } } @Bindable public ObservableInt getMiniplayerHeight() { return mMiniplayerHeight; } @Bindable public ObservableFloat getMiniplayerAlpha() { return mMiniplayerAlpha; } @Bindable public ObservableFloat getToolbarAlpha() { return mNowPlayingToolbarAlpha; } @Bindable public boolean isToolbarExpanded() { return mBottomSheetState == BottomSheetBehavior.STATE_COLLAPSED; } @Bindable public int getMiniplayerVisibility() { return (mBottomSheetState == BottomSheetBehavior.STATE_EXPANDED) ? View.GONE : View.VISIBLE; } @Bindable public int getMainContentVisibillity() { return (mBottomSheetState == BottomSheetBehavior.STATE_EXPANDED) ? View.GONE : View.VISIBLE; } @Bindable public int getNowPlayingContentVisibility() { return (mBottomSheetState == BottomSheetBehavior.STATE_COLLAPSED) ? View.INVISIBLE : View.VISIBLE; } @Bindable public Drawable getNowPlayingContentBackground() { if (mBottomSheetState == BottomSheetBehavior.STATE_EXPANDED) { return null; } else { return mNowPlayingBackground; } } @Bindable public BottomSheetBehavior.BottomSheetCallback getBottomSheetCallback() { return new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { mBottomSheetState = newState; notifyPropertyChanged(BR.miniplayerVisibility); notifyPropertyChanged(BR.mainContentVisibillity); notifyPropertyChanged(BR.nowPlayingContentVisibility); notifyPropertyChanged(BR.nowPlayingContentBackground); notifyPropertyChanged(BR.toolbarExpanded); if (newState == BottomSheetBehavior.STATE_EXPANDED) { mNowPlayingToolbarAlpha.set(1.0f); mMiniplayerAlpha.set(0.0f); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { if (mBottomSheetState == BottomSheetBehavior.STATE_EXPANDED || mBottomSheetState == BottomSheetBehavior.STATE_COLLAPSED) { onStateChanged(bottomSheet, BottomSheetBehavior.STATE_DRAGGING); } mMiniplayerAlpha.set(1.0f - 2 * slideOffset); mNowPlayingToolbarAlpha.set(2 * slideOffset - 1.0f); } }; } @Bindable public View.OnClickListener getMiniplayerClickListener() { return v -> { View bottomSheet = (View) v.getParent(); BottomSheetBehavior<View> behavior = BottomSheetBehavior.from(bottomSheet); behavior.setState(BottomSheetBehavior.STATE_EXPANDED); }; } }