diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsSlidingMusicPanelActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsSlidingMusicPanelActivity.java index 7e35c538..1352fdcb 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsSlidingMusicPanelActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsSlidingMusicPanelActivity.java @@ -55,7 +55,8 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi }); } - setUpSlidingPanel(); + slidingUpPanelLayout.setPanelSlideListener(this); + playerFragment.resetShowControlsAnimation(); slidingUpPanelLayout.post(new Runnable() { @Override @@ -76,10 +77,6 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi super.onServiceConnected(name, service); } - private void setUpSlidingPanel() { - slidingUpPanelLayout.setPanelSlideListener(this); - } - @Override public void onPanelSlide(View view, @FloatRange(from = 0, to = 1) float slideOffset) { setMiniPlayerAlphaProgress(slideOffset); diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlaybackControlsFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlaybackControlsFragment.java new file mode 100644 index 00000000..301a9bb2 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlaybackControlsFragment.java @@ -0,0 +1,390 @@ +package com.kabouzeid.gramophone.ui.fragments; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.app.Fragment; +import android.support.v7.widget.CardView; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewAnimationUtils; +import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.afollestad.materialdialogs.internal.ThemeSingleton; +import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.helper.PlayPauseButtonOnClickHandler; +import com.kabouzeid.gramophone.interfaces.MusicServiceEventListener; +import com.kabouzeid.gramophone.misc.FloatingActionButtonProperties; +import com.kabouzeid.gramophone.misc.SimpleAnimatorListener; +import com.kabouzeid.gramophone.model.Song; +import com.kabouzeid.gramophone.service.MusicService; +import com.kabouzeid.gramophone.ui.activities.base.AbsMusicServiceActivity; +import com.kabouzeid.gramophone.util.ColorUtil; +import com.kabouzeid.gramophone.util.PreferenceUtil; +import com.kabouzeid.gramophone.util.Util; +import com.kabouzeid.gramophone.util.ViewUtil; +import com.kabouzeid.gramophone.views.PlayPauseDrawable; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public class PlaybackControlsFragment extends Fragment implements MusicServiceEventListener, SharedPreferences.OnSharedPreferenceChangeListener { + private static final int FAB_CIRCULAR_REVEAL_ANIMATION_TIME = 1000; + + @Bind(R.id.player_play_pause_fab) + FloatingActionButton playPauseFab; + + @Bind(R.id.player_title) + TextView songTitle; + @Bind(R.id.player_text) + TextView songText; + @Bind(R.id.player_footer) + LinearLayout footer; + @Bind(R.id.player_playback_controller_card) + CardView playbackControllerCard; + @Bind(R.id.player_prev_button) + ImageButton prevButton; + @Bind(R.id.player_next_button) + ImageButton nextButton; + @Bind(R.id.player_repeat_button) + ImageButton repeatButton; + @Bind(R.id.player_shuffle_button) + ImageButton shuffleButton; + @Bind(R.id.player_media_controller_container) + RelativeLayout mediaControllerContainer; + @Bind(R.id.player_media_controller_container_background) + View mediaControllerContainerBackground; + + private int lastFooterColor; + private int lastPlaybackControlsColor; + private int lastTitleTextColor; + private int lastCaptionTextColor; + + private PlayPauseDrawable playerFabPlayPauseDrawable; + private AnimatorSet colorTransitionAnimator; + + private AbsMusicServiceActivity activity; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + try { + activity = (AbsMusicServiceActivity) context; + } catch (ClassCastException e) { + throw new RuntimeException(context.getClass().getSimpleName() + " must be an instance of " + AbsMusicServiceActivity.class.getSimpleName()); + } + } + + @Override + public void onDetach() { + super.onDetach(); + activity = null; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_playback_controls, container, false); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + ButterKnife.bind(this, view); + PreferenceUtil.getInstance(getContext()).registerOnSharedPreferenceChangedListener(this); + activity.addMusicServiceEventListener(this); + + setUpMusicControllers(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + activity.removeMusicServiceEventListener(this); + PreferenceUtil.getInstance(activity).unregisterOnSharedPreferenceChangedListener(this); + ButterKnife.unbind(this); + } + + @Override + public void onPlayingMetaChanged() { + updateMetaTexts(); + } + + @Override + public void onPlayStateChanged() { + updatePlayPauseDrawableState(true); + } + + @Override + public void onRepeatModeChanged() { + updateRepeatState(); + } + + @Override + public void onShuffleModeChanged() { + updateShuffleState(); + } + + @Override + public void onMediaStoreChanged() { + + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + switch (key) { + case PreferenceUtil.PLAYBACK_CONTROLLER_CARD_NOW_PLAYING: + updatePlaybackControllerCardVisibility(); + break; + case PreferenceUtil.COLOR_PLAYBACK_CONTROLS_NOW_PLAYING: + updateRepeatState(); + updateShuffleState(); + updatePlayPauseFabTint(); + break; + case PreferenceUtil.LARGER_TITLE_BOX_NOW_PLAYING: + updateTitleBoxSize(); + break; + } + } + + public void setColor(int color) { + animateColorChange(color); + } + + private void setUpPlayPauseFab() { + updatePlayPauseDrawableState(false); + playPauseFab.setImageDrawable(playerFabPlayPauseDrawable); + updatePlayPauseFabTint(); + playPauseFab.setOnClickListener(new PlayPauseButtonOnClickHandler()); + playPauseFab.post(new Runnable() { + @Override + public void run() { + playPauseFab.setPivotX(playPauseFab.getWidth() / 2); + playPauseFab.setPivotY(playPauseFab.getHeight() / 2); + } + }); + } + + private void updatePlayPauseFabTint() { + int fabColor = PreferenceUtil.getInstance(activity).colorPlaybackControlsNowPlaying() ? lastPlaybackControlsColor : activity.getThemeColorAccent(); + FloatingActionButtonProperties.COLOR.set(playPauseFab, fabColor); + } + + protected void updatePlayPauseDrawableState(boolean animate) { + if (playerFabPlayPauseDrawable == null) { + playerFabPlayPauseDrawable = new PlayPauseDrawable(activity); + } + if (MusicPlayerRemote.isPlaying()) { + playerFabPlayPauseDrawable.setPause(animate); + } else { + playerFabPlayPauseDrawable.setPlay(animate); + } + } + + private void updateTitleBoxSize() { + boolean largerTitleBox = PreferenceUtil.getInstance(activity).largerTitleBoxNowPlaying(); + int paddingTopBottom = largerTitleBox ? getResources().getDimensionPixelSize(R.dimen.title_box_padding_large) : getResources().getDimensionPixelSize(R.dimen.title_box_padding_small); + footer.setPadding(footer.getPaddingLeft(), paddingTopBottom, footer.getPaddingRight(), paddingTopBottom); + + songTitle.setPadding(songTitle.getPaddingLeft(), songTitle.getPaddingTop(), songTitle.getPaddingRight(), largerTitleBox ? getResources().getDimensionPixelSize(R.dimen.title_box_text_spacing_large) : getResources().getDimensionPixelSize(R.dimen.title_box_text_spacing_small)); + songText.setPadding(songText.getPaddingLeft(), largerTitleBox ? getResources().getDimensionPixelSize(R.dimen.title_box_text_spacing_large) : getResources().getDimensionPixelSize(R.dimen.title_box_text_spacing_small), songText.getPaddingRight(), songText.getPaddingBottom()); + + songTitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, largerTitleBox ? getResources().getDimensionPixelSize(R.dimen.title_box_title_text_size_large) : getResources().getDimensionPixelSize(R.dimen.title_box_title_text_size_small)); + songText.setTextSize(TypedValue.COMPLEX_UNIT_PX, largerTitleBox ? getResources().getDimensionPixelSize(R.dimen.title_box_caption_text_size_large) : getResources().getDimensionPixelSize(R.dimen.title_box_caption_text_size_small)); + } + + private void updatePlaybackControllerCardVisibility() { + boolean showPlaybackControllerCard = PreferenceUtil.getInstance(activity).playbackControllerCardNowPlaying(); + playbackControllerCard.setVisibility(showPlaybackControllerCard ? View.VISIBLE : View.GONE); + mediaControllerContainerBackground.setVisibility(showPlaybackControllerCard ? View.GONE : View.VISIBLE); + } + + private void setUpMusicControllers() { + setUpPlayPauseFab(); + setUpPrevNext(); + setUpRepeatButton(); + setUpShuffleButton(); + } + + private void setUpPrevNext() { + int themedDrawableColor = ColorUtil.resolveColor(activity, android.R.attr.textColorSecondary); + nextButton.setImageDrawable(Util.getTintedDrawable(activity, + R.drawable.ic_skip_next_white_36dp, themedDrawableColor)); + prevButton.setImageDrawable(Util.getTintedDrawable(activity, + R.drawable.ic_skip_previous_white_36dp, themedDrawableColor)); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MusicPlayerRemote.playNextSong(); + } + }); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MusicPlayerRemote.back(); + } + }); + } + + private void setUpShuffleButton() { + updateShuffleState(); + shuffleButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MusicPlayerRemote.toggleShuffleMode(); + } + }); + } + + private void updateShuffleState() { + switch (MusicPlayerRemote.getShuffleMode()) { + case MusicService.SHUFFLE_MODE_SHUFFLE: + shuffleButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_shuffle_white_36dp, + getActivatedIconColor())); + break; + default: + shuffleButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_shuffle_white_36dp, + getDeactivatedIconColor())); + break; + } + } + + private void setUpRepeatButton() { + updateRepeatState(); + repeatButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MusicPlayerRemote.cycleRepeatMode(); + } + }); + } + + private void updateRepeatState() { + switch (MusicPlayerRemote.getRepeatMode()) { + case MusicService.REPEAT_MODE_ALL: + repeatButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_repeat_white_36dp, + getActivatedIconColor())); + break; + case MusicService.REPEAT_MODE_THIS: + repeatButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_repeat_one_white_36dp, + getActivatedIconColor())); + break; + default: + repeatButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_repeat_white_36dp, + getDeactivatedIconColor())); + break; + } + } + + private int getActivatedIconColor() { + if (PreferenceUtil.getInstance(activity).colorPlaybackControlsNowPlaying()) { + return ensureActivatedColorVisibleIfNecessary(lastPlaybackControlsColor); + } else { + return ThemeSingleton.get().positiveColor.getDefaultColor(); + } + } + + private int getDeactivatedIconColor() { + return ColorUtil.resolveColor(activity, android.R.attr.textColorSecondary); + } + + /** + * @return If the activated color wont have enough difference to the deactivated color Color.WHITE / Color.BLACK (depending on the theme), + * else the unmodified accentColor. + */ + private int ensureActivatedColorVisibleIfNecessary(int activatedColor) { + // Not optimal, but much easier then computing the opaque deactivated color on the background color every time. + int preBlendedDeactivatedIconColor = ThemeSingleton.get().darkTheme ? Color.argb(255, 188, 188, 188) : Color.argb(255, 115, 115, 115); + if (ColorUtil.getColorDifference(activatedColor, preBlendedDeactivatedIconColor) <= 30d) { + return ThemeSingleton.get().darkTheme ? Color.WHITE : Color.BLACK; + } + return activatedColor; + } + + private void updateMetaTexts() { + final Song song = MusicPlayerRemote.getCurrentSong(); + songTitle.setText(song.title); + songText.setText(song.artistName); + } + + private void animateColorChange(final int newColor) { + if (colorTransitionAnimator != null && colorTransitionAnimator.isStarted()) { + colorTransitionAnimator.cancel(); + } + colorTransitionAnimator = new AnimatorSet(); + AnimatorSet.Builder animatorSetBuilder = colorTransitionAnimator.play(ViewUtil.createBackgroundColorTransition(footer, lastFooterColor, newColor)); + + int titleTextColor = ColorUtil.getPrimaryTextColorForBackground(activity, newColor); + int captionTextColor = ColorUtil.getSecondaryTextColorForBackground(activity, newColor); + + animatorSetBuilder.with(ViewUtil.createTextColorTransition(songTitle, lastTitleTextColor, titleTextColor)); + animatorSetBuilder.with(ViewUtil.createTextColorTransition(songText, lastCaptionTextColor, captionTextColor)); + + colorTransitionAnimator.addListener(new SimpleAnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + if (newColor == ColorUtil.resolveColor(activity, R.attr.default_bar_color) && ThemeSingleton.get().darkTheme) { + lastPlaybackControlsColor = Color.WHITE; + } else { + lastPlaybackControlsColor = newColor; + } + updateRepeatState(); + updateShuffleState(); + updatePlayPauseFabTint(); + } + }); + + colorTransitionAnimator.start(); + + lastFooterColor = newColor; + lastTitleTextColor = titleTextColor; + lastCaptionTextColor = captionTextColor; + } + + public void showControls() { + playPauseFab.animate() + .scaleX(1f) + .scaleY(1f) + .rotation(360f) + .setInterpolator(new DecelerateInterpolator()) + .start(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (mediaControllerContainer.getVisibility() == View.INVISIBLE) { + int cx = (playPauseFab.getLeft() + playPauseFab.getRight()) / 2; + int cy = (playPauseFab.getTop() + playPauseFab.getBottom()) / 2; + int finalRadius = Math.max(mediaControllerContainer.getWidth(), mediaControllerContainer.getHeight()); + + final Animator animator = ViewAnimationUtils.createCircularReveal(mediaControllerContainer, cx, cy, 0, finalRadius); + animator.setInterpolator(new DecelerateInterpolator()); + animator.setDuration(FAB_CIRCULAR_REVEAL_ANIMATION_TIME); + animator.start(); + mediaControllerContainer.setVisibility(View.VISIBLE); + } + } + } + + public void resetShowControlsAnimation() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + mediaControllerContainer.setVisibility(View.INVISIBLE); + } + playPauseFab.setScaleX(0f); + playPauseFab.setScaleY(0f); + playPauseFab.setRotation(0f); + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayerAlbumCoverFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayerAlbumCoverFragment.java new file mode 100644 index 00000000..c7b226fd --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayerAlbumCoverFragment.java @@ -0,0 +1,225 @@ +package com.kabouzeid.gramophone.ui.fragments; + +import android.animation.Animator; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.support.annotation.ColorInt; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.OvershootInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.interfaces.MusicServiceEventListener; +import com.kabouzeid.gramophone.misc.SimpleAnimatorListener; +import com.kabouzeid.gramophone.ui.activities.base.AbsMusicServiceActivity; +import com.kabouzeid.gramophone.util.ColorUtil; +import com.kabouzeid.gramophone.util.MusicUtil; +import com.kabouzeid.gramophone.util.PreferenceUtil; +import com.kabouzeid.gramophone.util.ViewUtil; +import com.kabouzeid.gramophone.views.SquareIfPlaceImageView; +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.assist.FailReason; +import com.nostra13.universalimageloader.core.assist.LoadedFrom; +import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer; +import com.nostra13.universalimageloader.core.imageaware.ImageAware; +import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; +import com.nostra13.universalimageloader.core.process.BitmapProcessor; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public class PlayerAlbumCoverFragment extends Fragment implements MusicServiceEventListener, SharedPreferences.OnSharedPreferenceChangeListener { + + @Bind(R.id.player_image) + SquareIfPlaceImageView albumArt; + @Bind(R.id.player_favorite_icon) + ImageView favoriteIcon; + @Bind(R.id.player_album_art_frame) + FrameLayout albumArtFrame; + + private boolean forceSquareAlbumArt; + + private AbsMusicServiceActivity activity; + private OnColorChangedListener onColorChangedListener; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + try { + activity = (AbsMusicServiceActivity) context; + } catch (ClassCastException e) { + throw new RuntimeException(context.getClass().getSimpleName() + " must be an instance of " + AbsMusicServiceActivity.class.getSimpleName()); + } + } + + @Override + public void onDetach() { + super.onDetach(); + activity = null; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_player_album_cover, container, false); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + ButterKnife.bind(this, view); + + albumArt.forceSquare(forceSquareAlbumArt); + + PreferenceUtil.getInstance(getContext()).registerOnSharedPreferenceChangedListener(this); + activity.addMusicServiceEventListener(this); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + activity.removeMusicServiceEventListener(this); + PreferenceUtil.getInstance(activity).unregisterOnSharedPreferenceChangedListener(this); + ButterKnife.unbind(this); + } + + @Override + public void onPlayingMetaChanged() { + loadAlbumCover(); + } + + @Override + public void onPlayStateChanged() { + + } + + @Override + public void onRepeatModeChanged() { + + } + + @Override + public void onShuffleModeChanged() { + + } + + @Override + public void onMediaStoreChanged() { + + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + switch (key) { + case PreferenceUtil.FORCE_SQUARE_ALBUM_ART: + forceSquareAlbumArt = PreferenceUtil.getInstance(activity).forceAlbumArtSquared(); + albumArt.forceSquare(forceSquareAlbumArt); + break; + } + } + + private static class ColorHolder { + @ColorInt + public int color; + } + + private void loadAlbumCover() { + final ColorHolder colorHolder = new ColorHolder(); + ImageLoader.getInstance().displayImage( + MusicUtil.getSongImageLoaderString(MusicPlayerRemote.getCurrentSong()), + albumArt, + new DisplayImageOptions.Builder() + .cacheInMemory(true) + .showImageOnFail(R.drawable.default_album_art) + .postProcessor(new BitmapProcessor() { + @Override + public Bitmap process(Bitmap bitmap) { + colorHolder.color = ColorUtil.generateColor(activity, bitmap); + return bitmap; + } + }) + .displayer(new FadeInBitmapDisplayer(ViewUtil.DEFAULT_COLOR_ANIMATION_DURATION) { + @Override + public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) { + super.display(bitmap, imageAware, loadedFrom); + setColor(colorHolder.color); + } + }) + .build(), + new SimpleImageLoadingListener() { + @Override + public void onLoadingFailed(String imageUri, View view, @Nullable FailReason failReason) { + FadeInBitmapDisplayer.animate(view, ViewUtil.DEFAULT_COLOR_ANIMATION_DURATION); + setColor(ColorUtil.resolveColor(activity, R.attr.default_bar_color)); + } + + @Override + public void onLoadingComplete(String imageUri, View view, @Nullable Bitmap loadedImage) { + if (loadedImage == null) { + onLoadingFailed(imageUri, view, null); + } + } + } + ); + } + + public void showHeart() { + favoriteIcon.clearAnimation(); + + favoriteIcon.setAlpha(0f); + favoriteIcon.setScaleX(0f); + favoriteIcon.setScaleY(0f); + favoriteIcon.setVisibility(View.VISIBLE); + favoriteIcon.setPivotX(favoriteIcon.getWidth() / 2); + favoriteIcon.setPivotY(favoriteIcon.getHeight() / 2); + + favoriteIcon.animate() + .setDuration(600) + .setInterpolator(new OvershootInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f) + .setListener(new SimpleAnimatorListener() { + @Override + public void onAnimationCancel(Animator animation) { + favoriteIcon.setVisibility(View.INVISIBLE); + } + }) + .withEndAction(new Runnable() { + @Override + public void run() { + favoriteIcon.animate() + .setDuration(300) + .setInterpolator(new DecelerateInterpolator()) + .alpha(0f) + .start(); + } + }) + .start(); + } + + private void setColor(int color) { + if (onColorChangedListener != null) onColorChangedListener.onColorChanged(color); + } + + public void setOnColorChangedListener(OnColorChangedListener listener) { + onColorChangedListener = listener; + } + + interface OnColorChangedListener { + void onColorChanged(int color); + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayerFragment.java index b157f50e..ab195d76 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayerFragment.java @@ -1,40 +1,19 @@ package com.kabouzeid.gramophone.ui.fragments; -import android.animation.Animator; import android.animation.AnimatorSet; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.content.res.ColorStateList; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; -import android.os.Build; import android.os.Bundle; import android.support.annotation.ColorInt; -import android.support.annotation.Nullable; -import android.support.design.widget.FloatingActionButton; import android.support.v4.app.Fragment; -import android.support.v7.widget.CardView; import android.support.v7.widget.Toolbar; -import android.util.TypedValue; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; -import android.view.ViewAnimationUtils; import android.view.ViewGroup; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.OvershootInterpolator; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.SeekBar; -import android.widget.TextView; -import com.afollestad.materialdialogs.internal.ThemeSingleton; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog; import com.kabouzeid.gramophone.dialogs.PlayingQueueDialog; @@ -43,15 +22,10 @@ import com.kabouzeid.gramophone.dialogs.SongDetailDialog; import com.kabouzeid.gramophone.dialogs.SongShareDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.MusicProgressViewUpdateHelper; -import com.kabouzeid.gramophone.helper.PlayPauseButtonOnClickHandler; import com.kabouzeid.gramophone.interfaces.MusicServiceEventListener; import com.kabouzeid.gramophone.interfaces.PaletteColorHolder; import com.kabouzeid.gramophone.loader.SongLoader; -import com.kabouzeid.gramophone.misc.FloatingActionButtonProperties; -import com.kabouzeid.gramophone.misc.SimpleAnimatorListener; -import com.kabouzeid.gramophone.misc.SimpleOnSeekbarChangeListener; import com.kabouzeid.gramophone.model.Song; -import com.kabouzeid.gramophone.service.MusicService; import com.kabouzeid.gramophone.ui.activities.base.AbsMusicServiceActivity; import com.kabouzeid.gramophone.ui.activities.tageditor.AbsTagEditorActivity; import com.kabouzeid.gramophone.ui.activities.tageditor.SongTagEditorActivity; @@ -61,87 +35,32 @@ import com.kabouzeid.gramophone.util.NavigationUtil; import com.kabouzeid.gramophone.util.PreferenceUtil; import com.kabouzeid.gramophone.util.Util; import com.kabouzeid.gramophone.util.ViewUtil; -import com.kabouzeid.gramophone.views.PlayPauseDrawable; -import com.kabouzeid.gramophone.views.SquareIfPlaceImageView; -import com.nostra13.universalimageloader.core.DisplayImageOptions; -import com.nostra13.universalimageloader.core.ImageLoader; -import com.nostra13.universalimageloader.core.assist.FailReason; -import com.nostra13.universalimageloader.core.assist.LoadedFrom; -import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer; -import com.nostra13.universalimageloader.core.imageaware.ImageAware; -import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; -import com.nostra13.universalimageloader.core.process.BitmapProcessor; import butterknife.Bind; import butterknife.ButterKnife; -public class PlayerFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener, MusicServiceEventListener, Toolbar.OnMenuItemClickListener, PaletteColorHolder, MusicProgressViewUpdateHelper.Callback { +public class PlayerFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener, MusicServiceEventListener, Toolbar.OnMenuItemClickListener, PaletteColorHolder, MusicProgressViewUpdateHelper.Callback, PlayerAlbumCoverFragment.OnColorChangedListener { public static final String TAG = PlayerFragment.class.getSimpleName(); - private static final int FAB_CIRCULAR_REVEAL_ANIMATION_TIME = 1000; - - @Bind(R.id.player_play_pause_fab) - FloatingActionButton playPauseFab; - - @Bind(R.id.player_title) - TextView songTitle; - @Bind(R.id.player_text) - TextView songText; - @Bind(R.id.player_footer) - LinearLayout footer; - @Bind(R.id.player_playback_controller_card) - CardView playbackControllerCard; - @Bind(R.id.player_prev_button) - ImageButton prevButton; - @Bind(R.id.player_next_button) - ImageButton nextButton; - @Bind(R.id.player_repeat_button) - ImageButton repeatButton; - @Bind(R.id.player_shuffle_button) - ImageButton shuffleButton; - @Bind(R.id.player_media_controller_container) - RelativeLayout mediaControllerContainer; - @Bind(R.id.player_media_controller_container_background) - View mediaControllerContainerBackground; - @Bind(R.id.player_image) - SquareIfPlaceImageView albumArt; @Bind(R.id.player_status_bar) View statusbar; @Bind(R.id.player_toolbar) Toolbar toolbar; - @Bind(R.id.player_favorite_icon) - ImageView favoriteIcon; - @Bind(R.id.player_album_art_frame) - FrameLayout albumArtFrame; - TextView songCurrentProgress; - TextView songTotalTime; - SeekBar progressSlider; - - private int lastFooterColor; + private AnimatorSet colorTransitionAnimator; + private int lastColor; private int lastPlaybackControlsColor; - private int lastTitleTextColor; - private int lastCaptionTextColor; - - private MusicProgressViewUpdateHelper progressViewUpdateHelper; - - private boolean opaqueStatusBar; - private boolean opaqueToolBar; - private boolean forceSquareAlbumArt; - private boolean largerTitleBox; - private boolean alternativeProgressSlider; - private boolean showPlaybackControllerCard; - private boolean colorPlaybackControls; private Song song; - private PlayPauseDrawable playerFabPlayPauseDrawable; - - private AnimatorSet colorTransitionAnimator; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; private AbsMusicServiceActivity activity; private Callbacks callbacks; + private PlaybackControlsFragment playbackControlsFragment; + private PlayerAlbumCoverFragment playerAlbumCoverFragment; + @Override public void onAttach(Context context) { super.onAttach(context); @@ -163,7 +82,6 @@ public class PlayerFragment extends Fragment implements SharedPreferences.OnShar @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - initAppearanceVarsFromSharedPrefs(); progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); } @@ -178,14 +96,13 @@ public class PlayerFragment extends Fragment implements SharedPreferences.OnShar super.onViewCreated(view, savedInstanceState); ButterKnife.bind(this, view); - resetShowControlsAnimation(); - setUpPlayPauseFab(); - adjustTitleBoxSize(); - setUpPlaybackControllerCard(); - setUpMusicControllers(); - setUpAlbumArtViews(); + playbackControlsFragment = (PlaybackControlsFragment) getChildFragmentManager().findFragmentById(R.id.playback_controls_fragment); + playerAlbumCoverFragment = (PlayerAlbumCoverFragment) getChildFragmentManager().findFragmentById(R.id.player_album_cover_fragment); + playerAlbumCoverFragment.setOnColorChangedListener(this); + +// alignAlbumArt(); setUpPlayerToolbar(); - setUpPlayerStatusBarElevation(); +// setUpPlayerStatusBarElevation(); PreferenceUtil.getInstance(getContext()).registerOnSharedPreferenceChangedListener(this); activity.addMusicServiceEventListener(this); @@ -216,14 +133,19 @@ public class PlayerFragment extends Fragment implements SharedPreferences.OnShar updateCurrentSong(); } + @Override + public void onPlayStateChanged() { + + } + @Override public void onRepeatModeChanged() { - updateRepeatState(); + } @Override public void onShuffleModeChanged() { - updateShuffleState(); + } @Override @@ -234,326 +156,135 @@ public class PlayerFragment extends Fragment implements SharedPreferences.OnShar @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { switch (key) { - case PreferenceUtil.OPAQUE_STATUSBAR_NOW_PLAYING: - opaqueStatusBar = PreferenceUtil.getInstance(activity).opaqueStatusbarNowPlaying(); - // do not break here - case PreferenceUtil.OPAQUE_TOOLBAR_NOW_PLAYING: - opaqueToolBar = opaqueStatusBar && PreferenceUtil.getInstance(activity).opaqueToolbarNowPlaying(); - setUpPlayerStatusBarElevation(); - animateColorChange(lastFooterColor); - if (opaqueStatusBar) { - if (opaqueToolBar) { - alignAlbumArtToToolbar(); - } else { - alignAlbumArtToStatusBar(); - } - } else { - alignAlbumArtToTop(); - } - break; - case PreferenceUtil.FORCE_SQUARE_ALBUM_ART: - forceSquareAlbumArt = PreferenceUtil.getInstance(activity).forceAlbumArtSquared(); - albumArt.forceSquare(forceSquareAlbumArt); - break; - case PreferenceUtil.LARGER_TITLE_BOX_NOW_PLAYING: - largerTitleBox = PreferenceUtil.getInstance(activity).largerTitleBoxNowPlaying(); - adjustTitleBoxSize(); - break; - case PreferenceUtil.ALTERNATIVE_PROGRESS_SLIDER_NOW_PLAYING: - alternativeProgressSlider = PreferenceUtil.getInstance(activity).alternativeProgressSliderNowPlaying(); - setUpProgressSlider(); - break; - case PreferenceUtil.PLAYBACK_CONTROLLER_CARD_NOW_PLAYING: - showPlaybackControllerCard = PreferenceUtil.getInstance(activity).playbackControllerCardNowPlaying(); - setUpPlaybackControllerCard(); - break; - case PreferenceUtil.COLOR_PLAYBACK_CONTROLS_NOW_PLAYING: - colorPlaybackControls = PreferenceUtil.getInstance(activity).colorPlaybackControlsNowPlaying(); - updateRepeatState(); - updateShuffleState(); - setUpProgressSliderTint(); - setUpPlayerPlayPauseFabTint(); - break; +// case PreferenceUtil.OPAQUE_STATUSBAR_NOW_PLAYING: +// opaqueStatusBar = PreferenceUtil.getInstance(activity).opaqueStatusbarNowPlaying(); +// // do not break here +// case PreferenceUtil.OPAQUE_TOOLBAR_NOW_PLAYING: +// opaqueToolBar = opaqueStatusBar && PreferenceUtil.getInstance(activity).opaqueToolbarNowPlaying(); +// setUpPlayerStatusBarElevation(); +// animateColorChange(lastColor); +// alignAlbumArt(); +// break; +// case PreferenceUtil.ALTERNATIVE_PROGRESS_SLIDER_NOW_PLAYING: +// alternativeProgressSlider = PreferenceUtil.getInstance(activity).alternativeProgressSliderNowPlaying(); +// setUpProgressSlider(); +// break; } } - private void setUpPlayPauseFab() { - updatePlayPauseDrawableState(false); - playPauseFab.setImageDrawable(playerFabPlayPauseDrawable); - setUpPlayerPlayPauseFabTint(); - playPauseFab.setOnClickListener(new PlayPauseButtonOnClickHandler()); - playPauseFab.post(new Runnable() { - @Override - public void run() { - playPauseFab.setPivotX(playPauseFab.getWidth() / 2); - playPauseFab.setPivotY(playPauseFab.getHeight() / 2); - } - }); - } +// private void initProgressSliderDependentViews() { +// if (getView() == null) return; +// if (alternativeProgressSlider) { +// getView().findViewById(R.id.player_default_progress_container).setVisibility(View.GONE); +// getView().findViewById(R.id.player_default_progress_slider).setVisibility(View.GONE); +// getView().findViewById(R.id.player_alternative_progress_container).setVisibility(View.VISIBLE); +// +// songCurrentProgress = (TextView) getView().findViewById(R.id.player_alternative_song_current_progress); +// songTotalTime = (TextView) getView().findViewById(R.id.player_alternative_song_total_time); +// progressSlider = (SeekBar) getView().findViewById(R.id.player_alternative_progress_slider); +// } else { +// getView().findViewById(R.id.player_default_progress_container).setVisibility(View.VISIBLE); +// getView().findViewById(R.id.player_default_progress_slider).setVisibility(View.VISIBLE); +// getView().findViewById(R.id.player_alternative_progress_container).setVisibility(View.GONE); +// +// songCurrentProgress = (TextView) getView().findViewById(R.id.player_default_song_current_progress); +// songTotalTime = (TextView) getView().findViewById(R.id.player_default_song_total_time); +// progressSlider = (SeekBar) getView().findViewById(R.id.player_default_progress_slider); +// } +// } +// +// private void moveProgressSliderIntoPlace() { +// if (!alternativeProgressSlider) { +// RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) progressSlider.getLayoutParams(); +// progressSlider.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); +// final int seekBarMarginLeftRight = getResources().getDimensionPixelSize(R.dimen.seek_bar_margin_left_right); +// lp.setMargins(seekBarMarginLeftRight, 0, seekBarMarginLeftRight, -(progressSlider.getMeasuredHeight() / 2)); +// progressSlider.setLayoutParams(lp); +// } +// } - private void setUpPlayerPlayPauseFabTint() { - int fabColor = colorPlaybackControls ? lastPlaybackControlsColor : activity.getThemeColorAccent(); - FloatingActionButtonProperties.COLOR.set(playPauseFab, fabColor); - } +// private void updateProgressSliderTint() { +// int thumbColor; +// int progressColor; +// if (alternativeProgressSlider) { +// if (colorPlaybackControls) { +// thumbColor = lastPlaybackControlsColor; +// } else { +// thumbColor = ThemeSingleton.get().positiveColor.getDefaultColor(); +// } +// progressColor = Color.TRANSPARENT; +// } else { +// if (colorPlaybackControls) { +// if (ColorUtil.useDarkTextColorOnBackground(lastPlaybackControlsColor)) { +// thumbColor = ColorUtil.shiftColor(lastPlaybackControlsColor, 1.2f); +// } else { +// thumbColor = ColorUtil.shiftColor(lastPlaybackControlsColor, 0.8f); +// } +// } else { +// thumbColor = activity.getThemeColorAccent(); +// } +// progressColor = thumbColor; +// } +// setSeekBarTint(progressSlider, thumbColor, progressColor); +// } +// +// private static void setSeekBarTint(SeekBar seekBar, @ColorInt int thumbColor, @ColorInt int progressColor) { +// seekBar.getThumb().mutate().setColorFilter(thumbColor, PorterDuff.Mode.SRC_IN); +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { +// // this will only tint the left part of the progress bar +// seekBar.setProgressTintList(ColorStateList.valueOf(progressColor)); +// } else { +// seekBar.getProgressDrawable().mutate().setColorFilter(progressColor, PorterDuff.Mode.SRC_IN); +// } +// } - protected void updatePlayPauseDrawableState(boolean animate) { - if (playerFabPlayPauseDrawable == null) { - playerFabPlayPauseDrawable = new PlayPauseDrawable(activity); - } - if (MusicPlayerRemote.isPlaying()) { - playerFabPlayPauseDrawable.setPause(animate); - } else { - playerFabPlayPauseDrawable.setPlay(animate); - } - } +// private void setUpProgressSlider() { +// initProgressSliderDependentViews(); +// moveProgressSliderIntoPlace(); +// updateProgressSliderTint(); +// progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { +// @Override +// public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { +// if (fromUser) { +// MusicPlayerRemote.seekTo(progress); +// onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), MusicPlayerRemote.getSongDurationMillis()); +// } +// } +// }); +// } - @Override - public void onPlayStateChanged() { - updatePlayPauseDrawableState(true); - } - - private void initAppearanceVarsFromSharedPrefs() { - opaqueStatusBar = PreferenceUtil.getInstance(activity).opaqueStatusbarNowPlaying(); - opaqueToolBar = opaqueStatusBar && PreferenceUtil.getInstance(activity).opaqueToolbarNowPlaying(); - forceSquareAlbumArt = PreferenceUtil.getInstance(activity).forceAlbumArtSquared(); - largerTitleBox = PreferenceUtil.getInstance(activity).largerTitleBoxNowPlaying(); - alternativeProgressSlider = PreferenceUtil.getInstance(activity).alternativeProgressSliderNowPlaying(); - showPlaybackControllerCard = PreferenceUtil.getInstance(activity).playbackControllerCardNowPlaying(); - colorPlaybackControls = PreferenceUtil.getInstance(activity).colorPlaybackControlsNowPlaying(); - } - - private void initProgressSliderDependentViews() { - if (getView() == null) return; - if (alternativeProgressSlider) { - getView().findViewById(R.id.player_default_progress_container).setVisibility(View.GONE); - getView().findViewById(R.id.player_default_progress_slider).setVisibility(View.GONE); - getView().findViewById(R.id.player_alternative_progress_container).setVisibility(View.VISIBLE); - - songCurrentProgress = (TextView) getView().findViewById(R.id.player_alternative_song_current_progress); - songTotalTime = (TextView) getView().findViewById(R.id.player_alternative_song_total_time); - progressSlider = (SeekBar) getView().findViewById(R.id.player_alternative_progress_slider); - } else { - getView().findViewById(R.id.player_default_progress_container).setVisibility(View.VISIBLE); - getView().findViewById(R.id.player_default_progress_slider).setVisibility(View.VISIBLE); - getView().findViewById(R.id.player_alternative_progress_container).setVisibility(View.GONE); - - songCurrentProgress = (TextView) getView().findViewById(R.id.player_default_song_current_progress); - songTotalTime = (TextView) getView().findViewById(R.id.player_default_song_total_time); - progressSlider = (SeekBar) getView().findViewById(R.id.player_default_progress_slider); - } - } - - private void moveProgressSliderIntoPlace() { - if (!alternativeProgressSlider) { - RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) progressSlider.getLayoutParams(); - progressSlider.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); - final int seekBarMarginLeftRight = getResources().getDimensionPixelSize(R.dimen.seek_bar_margin_left_right); - lp.setMargins(seekBarMarginLeftRight, 0, seekBarMarginLeftRight, -(progressSlider.getMeasuredHeight() / 2)); - progressSlider.setLayoutParams(lp); - } - } - - private void adjustTitleBoxSize() { - int paddingTopBottom = largerTitleBox ? getResources().getDimensionPixelSize(R.dimen.title_box_padding_large) : getResources().getDimensionPixelSize(R.dimen.title_box_padding_small); - footer.setPadding(footer.getPaddingLeft(), paddingTopBottom, footer.getPaddingRight(), paddingTopBottom); - - songTitle.setPadding(songTitle.getPaddingLeft(), songTitle.getPaddingTop(), songTitle.getPaddingRight(), largerTitleBox ? getResources().getDimensionPixelSize(R.dimen.title_box_text_spacing_large) : getResources().getDimensionPixelSize(R.dimen.title_box_text_spacing_small)); - songText.setPadding(songText.getPaddingLeft(), largerTitleBox ? getResources().getDimensionPixelSize(R.dimen.title_box_text_spacing_large) : getResources().getDimensionPixelSize(R.dimen.title_box_text_spacing_small), songText.getPaddingRight(), songText.getPaddingBottom()); - - songTitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, largerTitleBox ? getResources().getDimensionPixelSize(R.dimen.title_box_title_text_size_large) : getResources().getDimensionPixelSize(R.dimen.title_box_title_text_size_small)); - songText.setTextSize(TypedValue.COMPLEX_UNIT_PX, largerTitleBox ? getResources().getDimensionPixelSize(R.dimen.title_box_caption_text_size_large) : getResources().getDimensionPixelSize(R.dimen.title_box_caption_text_size_small)); - } - - private void setUpPlaybackControllerCard() { - playbackControllerCard.setVisibility(showPlaybackControllerCard ? View.VISIBLE : View.GONE); - mediaControllerContainerBackground.setVisibility(showPlaybackControllerCard ? View.GONE : View.VISIBLE); - } - - private void setUpMusicControllers() { - setUpPrevNext(); - setUpRepeatButton(); - setUpShuffleButton(); - setUpProgressSlider(); - } - - private void setUpProgressSliderTint() { - int thumbColor; - int progressColor; - if (alternativeProgressSlider) { - if (colorPlaybackControls) { - thumbColor = lastPlaybackControlsColor; - } else { - thumbColor = ThemeSingleton.get().positiveColor.getDefaultColor(); - } - progressColor = Color.TRANSPARENT; - } else { - if (colorPlaybackControls) { - if (ColorUtil.useDarkTextColorOnBackground(lastPlaybackControlsColor)) { - thumbColor = ColorUtil.shiftColor(lastPlaybackControlsColor, 1.2f); - } else { - thumbColor = ColorUtil.shiftColor(lastPlaybackControlsColor, 0.8f); - } - } else { - thumbColor = activity.getThemeColorAccent(); - } - progressColor = thumbColor; - } - setSeekBarTint(progressSlider, thumbColor, progressColor); - } - - private static void setSeekBarTint(SeekBar seekBar, @ColorInt int thumbColor, @ColorInt int progressColor) { - seekBar.getThumb().mutate().setColorFilter(thumbColor, PorterDuff.Mode.SRC_IN); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - // this will only tint the left part of the progress bar - seekBar.setProgressTintList(ColorStateList.valueOf(progressColor)); - } else { - seekBar.getProgressDrawable().mutate().setColorFilter(progressColor, PorterDuff.Mode.SRC_IN); - } - } - - private void setUpProgressSlider() { - initProgressSliderDependentViews(); - moveProgressSliderIntoPlace(); - setUpProgressSliderTint(); - progressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if (fromUser) { - MusicPlayerRemote.seekTo(progress); - onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), MusicPlayerRemote.getSongDurationMillis()); - } - } - }); - } - - private void setUpPrevNext() { - int themedDrawableColor = ColorUtil.resolveColor(activity, android.R.attr.textColorSecondary); - nextButton.setImageDrawable(Util.getTintedDrawable(activity, - R.drawable.ic_skip_next_white_36dp, themedDrawableColor)); - prevButton.setImageDrawable(Util.getTintedDrawable(activity, - R.drawable.ic_skip_previous_white_36dp, themedDrawableColor)); - nextButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - MusicPlayerRemote.playNextSong(); - } - }); - prevButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - MusicPlayerRemote.back(); - } - }); - } - - private void setUpShuffleButton() { - updateShuffleState(); - shuffleButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - MusicPlayerRemote.toggleShuffleMode(); - } - }); - } - - private void updateShuffleState() { - switch (MusicPlayerRemote.getShuffleMode()) { - case MusicService.SHUFFLE_MODE_SHUFFLE: - shuffleButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_shuffle_white_36dp, - getActivatedIconColor())); - break; - default: - shuffleButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_shuffle_white_36dp, - getDeactivatedIconColor())); - break; - } - } - - private void setUpRepeatButton() { - updateRepeatState(); - repeatButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - MusicPlayerRemote.cycleRepeatMode(); - } - }); - } - - private void updateRepeatState() { - switch (MusicPlayerRemote.getRepeatMode()) { - case MusicService.REPEAT_MODE_ALL: - repeatButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_repeat_white_36dp, - getActivatedIconColor())); - break; - case MusicService.REPEAT_MODE_THIS: - repeatButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_repeat_one_white_36dp, - getActivatedIconColor())); - break; - default: - repeatButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_repeat_white_36dp, - getDeactivatedIconColor())); - break; - } - } - - private int getActivatedIconColor() { - if (colorPlaybackControls) { - return ensureActivatedColorVisibleIfNecessary(lastPlaybackControlsColor); - } else { - return ThemeSingleton.get().positiveColor.getDefaultColor(); - } - } - - private int getDeactivatedIconColor() { - return ColorUtil.resolveColor(activity, android.R.attr.textColorSecondary); - } - - /** - * @return If the activated color wont have enough difference to the deactivated color Color.WHITE / Color.BLACK (depending on the theme), - * else the unmodified accentColor. - */ - private int ensureActivatedColorVisibleIfNecessary(int activatedColor) { - // Not optimal, but much easier then computing the opaque deactivated color on the background color every time. - int preBlendedDeactivatedIconColor = ThemeSingleton.get().darkTheme ? Color.argb(255, 188, 188, 188) : Color.argb(255, 115, 115, 115); - if (ColorUtil.getColorDifference(activatedColor, preBlendedDeactivatedIconColor) <= 30d) { - return ThemeSingleton.get().darkTheme ? Color.WHITE : Color.BLACK; - } - return activatedColor; - } - - private void setUpAlbumArtViews() { - albumArt.forceSquare(forceSquareAlbumArt); - if (opaqueStatusBar) { - if (opaqueToolBar) { - alignAlbumArtToToolbar(); - } else { - alignAlbumArtToStatusBar(); - } - } else { - alignAlbumArtToTop(); - } - } - - private void alignAlbumArtToTop() { - RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) albumArtFrame.getLayoutParams(); - if (Build.VERSION.SDK_INT > 16) { - params.removeRule(RelativeLayout.BELOW); - } else { - params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - params.addRule(RelativeLayout.ABOVE, R.id.player_footer_frame); - } - } - - private void alignAlbumArtToToolbar() { - RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) albumArtFrame.getLayoutParams(); - params.addRule(RelativeLayout.BELOW, R.id.player_toolbar); - } - - private void alignAlbumArtToStatusBar() { - RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) albumArtFrame.getLayoutParams(); - params.addRule(RelativeLayout.BELOW, R.id.player_status_bar); - } +// private void alignAlbumArt() { +// if (opaqueStatusBar) { +// if (opaqueToolBar) { +// alignAlbumArtToToolbar(); +// } else { +// alignAlbumArtToStatusBar(); +// } +// } else { +// alignAlbumArtToTop(); +// } +// } +// +// private void alignAlbumArtToTop() { +// RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) albumArtFrame.getLayoutParams(); +// if (Build.VERSION.SDK_INT > 16) { +// params.removeRule(RelativeLayout.BELOW); +// } else { +// params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, +// ViewGroup.LayoutParams.MATCH_PARENT); +// params.addRule(RelativeLayout.ABOVE, R.id.player_footer_frame); +// } +// } +// +// private void alignAlbumArtToToolbar() { +// RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) albumArtFrame.getLayoutParams(); +// params.addRule(RelativeLayout.BELOW, R.id.player_toolbar); +// } +// +// private void alignAlbumArtToStatusBar() { +// RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) albumArtFrame.getLayoutParams(); +// params.addRule(RelativeLayout.BELOW, R.id.player_status_bar); +// } private void setUpPlayerToolbar() { toolbar.inflateMenu(R.menu.menu_player); @@ -567,19 +298,19 @@ public class PlayerFragment extends Fragment implements SharedPreferences.OnShar toolbar.setOnMenuItemClickListener(this); } - private void setUpPlayerStatusBarElevation() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (opaqueToolBar) { - statusbar.setElevation(getResources().getDimensionPixelSize(R.dimen.toolbar_elevation)); - } else { - statusbar.setElevation(0); - } - } - } +// private void setUpPlayerStatusBarElevation() { +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { +// if (opaqueToolBar) { +// statusbar.setElevation(getResources().getDimensionPixelSize(R.dimen.toolbar_elevation)); +// } else { +// statusbar.setElevation(0); +// } +// } +// } private void updatePlayerMenu() { boolean isFavorite = MusicUtil.isFavorite(activity, song); - Drawable favoriteIcon = Util.getTintedDrawable(activity, isFavorite ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_outline_white_24dp, ViewUtil.getToolbarIconColor(activity, opaqueToolBar && ColorUtil.useDarkTextColorOnBackground(lastFooterColor))); + Drawable favoriteIcon = Util.getTintedDrawable(activity, isFavorite ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_outline_white_24dp, ViewUtil.getToolbarIconColor(activity, PreferenceUtil.getInstance(activity).opaqueToolbarNowPlaying() && ColorUtil.useDarkTextColorOnBackground(lastColor))); toolbar.getMenu().findItem(R.id.action_toggle_favorite) .setIcon(favoriteIcon) .setTitle(isFavorite ? getString(R.string.action_remove_from_favorites) : getString(R.string.action_add_to_favorites)); @@ -587,8 +318,6 @@ public class PlayerFragment extends Fragment implements SharedPreferences.OnShar private void updateCurrentSong() { getCurrentSong(); - updateMetaTexts(); - setUpAlbumArtAndApplyPalette(); updatePlayerMenu(); } @@ -596,128 +325,62 @@ public class PlayerFragment extends Fragment implements SharedPreferences.OnShar song = MusicPlayerRemote.getCurrentSong(); } - private void updateMetaTexts() { - songTitle.setText(song.title); - songText.setText(song.artistName); - } - @Override @ColorInt public int getPaletteColor() { - return lastFooterColor; + return lastColor; } @Override public void onUpdateProgressViews(int progress, int total) { - progressSlider.setMax(total); - progressSlider.setProgress(progress); - songTotalTime.setText(MusicUtil.getReadableDurationString(total)); - songCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); - } - - private static class ColorHolder { - @ColorInt - public int color; - } - - private void setUpAlbumArtAndApplyPalette() { - final ColorHolder colorHolder = new ColorHolder(); - ImageLoader.getInstance().displayImage( - MusicUtil.getSongImageLoaderString(song), - albumArt, - new DisplayImageOptions.Builder() - .cacheInMemory(true) - .showImageOnFail(R.drawable.default_album_art) - .postProcessor(new BitmapProcessor() { - @Override - public Bitmap process(Bitmap bitmap) { - colorHolder.color = ColorUtil.generateColor(activity, bitmap); - return bitmap; - } - }) - .displayer(new FadeInBitmapDisplayer(ViewUtil.DEFAULT_COLOR_ANIMATION_DURATION) { - @Override - public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) { - super.display(bitmap, imageAware, loadedFrom); - setColors(colorHolder.color); - } - }) - .build(), - new SimpleImageLoadingListener() { - @Override - public void onLoadingFailed(String imageUri, View view, @Nullable FailReason failReason) { - FadeInBitmapDisplayer.animate(view, ViewUtil.DEFAULT_COLOR_ANIMATION_DURATION); - setColors(ColorUtil.resolveColor(activity, R.attr.default_bar_color)); - } - - @Override - public void onLoadingComplete(String imageUri, View view, @Nullable Bitmap loadedImage) { - if (loadedImage == null) { - onLoadingFailed(imageUri, view, null); - } - } - } - ); - } - - private void setColors(int color) { - animateColorChange(color); - callbacks.onPaletteColorChanged(); +// progressSlider.setMax(total); +// progressSlider.setProgress(progress); +// songTotalTime.setText(MusicUtil.getReadableDurationString(total)); +// songCurrentProgress.setText(MusicUtil.getReadableDurationString(progress)); } private void animateColorChange(final int newColor) { - if (colorTransitionAnimator != null && colorTransitionAnimator.isStarted()) { - colorTransitionAnimator.cancel(); - } - colorTransitionAnimator = new AnimatorSet(); - AnimatorSet.Builder animatorSetBuilder = colorTransitionAnimator.play(ViewUtil.createBackgroundColorTransition(footer, lastFooterColor, newColor)); +// if (colorTransitionAnimator != null && colorTransitionAnimator.isStarted()) { +// colorTransitionAnimator.cancel(); +// } +// colorTransitionAnimator = new AnimatorSet(); +// AnimatorSet.Builder animatorSetBuilder = colorTransitionAnimator.play(ViewUtil.createBackgroundColorTransition(footer, lastColor, newColor)); +// +// if (opaqueToolBar) { +// animatorSetBuilder.with(ViewUtil.createBackgroundColorTransition(toolbar, lastColor, newColor)); +// ViewUtil.setToolbarContentColorForBackground(activity, toolbar, newColor); +// } else { +// toolbar.setBackgroundColor(Color.TRANSPARENT); +// ViewUtil.setToolbarContentDark(activity, toolbar, false); +// } +// +// if (opaqueStatusBar) { +// int newStatusbarColor = newColor; +// int oldStatusbarColor = lastColor; +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { +// newStatusbarColor = ColorUtil.shiftColorDown(newStatusbarColor); +// oldStatusbarColor = ColorUtil.shiftColorDown(oldStatusbarColor); +// } +// animatorSetBuilder.with(ViewUtil.createBackgroundColorTransition(statusbar, oldStatusbarColor, newStatusbarColor)); +// } else { +// statusbar.setBackgroundColor(Color.TRANSPARENT); +// } +// +// colorTransitionAnimator.addListener(new SimpleAnimatorListener() { +// @Override +// public void onAnimationStart(Animator animation) { +// if (newColor == ColorUtil.resolveColor(activity, R.attr.default_bar_color) && ThemeSingleton.get().darkTheme) { +// lastPlaybackControlsColor = Color.WHITE; +// } else { +// lastPlaybackControlsColor = newColor; +// } +// updateProgressSliderTint(); +// } +// }); +// +// colorTransitionAnimator.start(); - if (opaqueToolBar) { - animatorSetBuilder.with(ViewUtil.createBackgroundColorTransition(toolbar, lastFooterColor, newColor)); - ViewUtil.setToolbarContentColorForBackground(activity, toolbar, newColor); - } else { - toolbar.setBackgroundColor(Color.TRANSPARENT); - ViewUtil.setToolbarContentDark(activity, toolbar, false); - } - - if (opaqueStatusBar) { - int newStatusbarColor = newColor; - int oldStatusbarColor = lastFooterColor; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - newStatusbarColor = ColorUtil.shiftColorDown(newStatusbarColor); - oldStatusbarColor = ColorUtil.shiftColorDown(oldStatusbarColor); - } - animatorSetBuilder.with(ViewUtil.createBackgroundColorTransition(statusbar, oldStatusbarColor, newStatusbarColor)); - } else { - statusbar.setBackgroundColor(Color.TRANSPARENT); - } - - int titleTextColor = ColorUtil.getPrimaryTextColorForBackground(activity, newColor); - int captionTextColor = ColorUtil.getSecondaryTextColorForBackground(activity, newColor); - - animatorSetBuilder.with(ViewUtil.createTextColorTransition(songTitle, lastTitleTextColor, titleTextColor)); - animatorSetBuilder.with(ViewUtil.createTextColorTransition(songText, lastCaptionTextColor, captionTextColor)); - - colorTransitionAnimator.addListener(new SimpleAnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - if (newColor == ColorUtil.resolveColor(activity, R.attr.default_bar_color) && ThemeSingleton.get().darkTheme) { - lastPlaybackControlsColor = Color.WHITE; - } else { - lastPlaybackControlsColor = newColor; - } - updateRepeatState(); - updateShuffleState(); - setUpProgressSliderTint(); - setUpPlayerPlayPauseFabTint(); - } - }); - - colorTransitionAnimator.start(); - - lastFooterColor = newColor; - lastTitleTextColor = titleTextColor; - lastCaptionTextColor = captionTextColor; + lastColor = newColor; } @Override @@ -729,7 +392,7 @@ public class PlayerFragment extends Fragment implements SharedPreferences.OnShar case R.id.action_toggle_favorite: MusicUtil.toggleFavorite(activity, song); if (MusicUtil.isFavorite(activity, song)) { - animateSetFavorite(); + playerAlbumCoverFragment.showHeart(); } updatePlayerMenu(); return true; @@ -766,71 +429,19 @@ public class PlayerFragment extends Fragment implements SharedPreferences.OnShar return false; } - private void animateSetFavorite() { - favoriteIcon.clearAnimation(); - - favoriteIcon.setAlpha(0f); - favoriteIcon.setScaleX(0f); - favoriteIcon.setScaleY(0f); - favoriteIcon.setVisibility(View.VISIBLE); - favoriteIcon.setPivotX(favoriteIcon.getWidth() / 2); - favoriteIcon.setPivotY(favoriteIcon.getHeight() / 2); - - favoriteIcon.animate() - .setDuration(600) - .setInterpolator(new OvershootInterpolator()) - .scaleX(1f) - .scaleY(1f) - .alpha(1f) - .setListener(new SimpleAnimatorListener() { - @Override - public void onAnimationCancel(Animator animation) { - favoriteIcon.setVisibility(View.INVISIBLE); - } - }) - .withEndAction(new Runnable() { - @Override - public void run() { - favoriteIcon.animate() - .setDuration(300) - .setInterpolator(new DecelerateInterpolator()) - .alpha(0f) - .start(); - } - }) - .start(); - } - public void showControls() { - playPauseFab.animate() - .scaleX(1f) - .scaleY(1f) - .rotation(360f) - .setInterpolator(new DecelerateInterpolator()) - .start(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (mediaControllerContainer.getVisibility() == View.INVISIBLE) { - int cx = (playPauseFab.getLeft() + playPauseFab.getRight()) / 2; - int cy = (playPauseFab.getTop() + playPauseFab.getBottom()) / 2; - int finalRadius = Math.max(mediaControllerContainer.getWidth(), mediaControllerContainer.getHeight()); - - final Animator animator = ViewAnimationUtils.createCircularReveal(mediaControllerContainer, cx, cy, 0, finalRadius); - animator.setInterpolator(new DecelerateInterpolator()); - animator.setDuration(FAB_CIRCULAR_REVEAL_ANIMATION_TIME); - animator.start(); - mediaControllerContainer.setVisibility(View.VISIBLE); - } - } + playbackControlsFragment.showControls(); } public void resetShowControlsAnimation() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - mediaControllerContainer.setVisibility(View.INVISIBLE); - } - playPauseFab.setScaleX(0f); - playPauseFab.setScaleY(0f); - playPauseFab.setRotation(0f); + playbackControlsFragment.resetShowControlsAnimation(); + } + + @Override + public void onColorChanged(int color) { + animateColorChange(color); + playbackControlsFragment.setColor(color); + callbacks.onPaletteColorChanged(); } public interface Callbacks { diff --git a/app/src/main/res/layout-land/fragment_player.xml b/app/src/main/res/layout-land/fragment_player.xml new file mode 100644 index 00000000..1761bcd2 --- /dev/null +++ b/app/src/main/res/layout-land/fragment_player.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_playback_controls.xml b/app/src/main/res/layout/fragment_playback_controls.xml new file mode 100644 index 00000000..50929e98 --- /dev/null +++ b/app/src/main/res/layout/fragment_playback_controls.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_player.xml b/app/src/main/res/layout/fragment_player.xml index 286627c2..73e0704e 100644 --- a/app/src/main/res/layout/fragment_player.xml +++ b/app/src/main/res/layout/fragment_player.xml @@ -1,277 +1,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_above="@+id/playback_controls_fragment" + tools:layout="@layout/fragment_player_album_cover" /> - - - - - - - - - - - - - - - - - - + @@ -287,7 +35,7 @@ android:id="@+id/player_toolbar" style="@style/Toolbar" android:layout_below="@id/player_status_bar" - android:background="#00000000" + android:background="@android:color/transparent" tools:ignore="UnusedAttribute" /> diff --git a/app/src/main/res/layout/fragment_player_album_cover.xml b/app/src/main/res/layout/fragment_player_album_cover.xml new file mode 100644 index 00000000..92092f5c --- /dev/null +++ b/app/src/main/res/layout/fragment_player_album_cover.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file