diff --git a/app/build.gradle b/app/build.gradle index db0ac695..d1c3940a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -125,6 +125,7 @@ dependencies { compile 'com.squareup.okhttp:okhttp:2.5.0' compile 'com.github.kabouzeid:Android-Universal-Image-Loader:c2894ad9f1' compile 'com.jakewharton:butterknife:7.0.1' + compile 'org.solovyev.android.views:linear-layout-manager:0.5@aar' //noinspection GradleDynamicVersion compile 'com.anjlab.android.iab.v3:library:1.0.+@aar' } 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 1352fdcb..e62da28b 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 @@ -12,8 +12,8 @@ import android.view.ViewGroup; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; -import com.kabouzeid.gramophone.ui.fragments.MiniPlayerFragment; -import com.kabouzeid.gramophone.ui.fragments.PlayerFragment; +import com.kabouzeid.gramophone.ui.fragments.player.MiniPlayerFragment; +import com.kabouzeid.gramophone.ui.fragments.player.PlayerFragment; import com.sothree.slidinguppanel.SlidingUpPanelLayout; import butterknife.Bind; 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 deleted file mode 100644 index e98f0185..00000000 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayerFragment.java +++ /dev/null @@ -1,411 +0,0 @@ -package com.kabouzeid.gramophone.ui.fragments; - -import android.animation.AnimatorSet; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.annotation.ColorInt; -import android.support.v4.app.Fragment; -import android.support.v7.widget.Toolbar; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; - -import com.kabouzeid.gramophone.R; -import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog; -import com.kabouzeid.gramophone.dialogs.PlayingQueueDialog; -import com.kabouzeid.gramophone.dialogs.SleepTimerDialog; -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.interfaces.MusicServiceEventListener; -import com.kabouzeid.gramophone.interfaces.PaletteColorHolder; -import com.kabouzeid.gramophone.loader.SongLoader; -import com.kabouzeid.gramophone.model.Song; -import com.kabouzeid.gramophone.ui.activities.base.AbsMusicServiceActivity; -import com.kabouzeid.gramophone.ui.activities.tageditor.AbsTagEditorActivity; -import com.kabouzeid.gramophone.ui.activities.tageditor.SongTagEditorActivity; -import com.kabouzeid.gramophone.util.ColorUtil; -import com.kabouzeid.gramophone.util.MusicUtil; -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 butterknife.Bind; -import butterknife.ButterKnife; - -public class PlayerFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener, MusicServiceEventListener, Toolbar.OnMenuItemClickListener, PaletteColorHolder, MusicProgressViewUpdateHelper.Callback, PlayerAlbumCoverFragment.OnColorChangedListener { - public static final String TAG = PlayerFragment.class.getSimpleName(); - - @Bind(R.id.player_toolbar) - Toolbar toolbar; - - private AnimatorSet colorTransitionAnimator; - private int lastColor; - private int lastPlaybackControlsColor; - - private Song song; - - private MusicProgressViewUpdateHelper progressViewUpdateHelper; - - private AbsMusicServiceActivity activity; - private Callbacks callbacks; - - private PlaybackControlsFragment playbackControlsFragment; - private PlayingInfoFragment playingInfoFragment; - private PlayerAlbumCoverFragment playerAlbumCoverFragment; - - @Override - public void onAttach(Context context) { - super.onAttach(context); - try { - activity = (AbsMusicServiceActivity) context; - callbacks = (Callbacks) context; - } catch (ClassCastException e) { - throw new RuntimeException(context.getClass().getSimpleName() + " must be an instance of " + AbsMusicServiceActivity.class.getSimpleName() + " and implement " + Callbacks.class.getSimpleName()); - } - } - - @Override - public void onDetach() { - super.onDetach(); - activity = null; - callbacks = null; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_player, container, false); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - ButterKnife.bind(this, view); - - playbackControlsFragment = (PlaybackControlsFragment) getChildFragmentManager().findFragmentById(R.id.playback_controls_fragment); - playingInfoFragment = (PlayingInfoFragment) getChildFragmentManager().findFragmentById(R.id.playing_info_fragment); - playerAlbumCoverFragment = (PlayerAlbumCoverFragment) getChildFragmentManager().findFragmentById(R.id.player_album_cover_fragment); - playerAlbumCoverFragment.setOnColorChangedListener(this); - -// alignAlbumArt(); - setUpPlayerToolbar(); -// setUpPlayerStatusBarElevation(); - - 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 onResume() { - super.onResume(); - progressViewUpdateHelper.start(); - } - - @Override - public void onPause() { - super.onPause(); - progressViewUpdateHelper.stop(); - } - - @Override - public void onPlayingMetaChanged() { - updateCurrentSong(); - } - - @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.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 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 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); -// } -// } - -// 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()); -// } -// } -// }); -// } - -// 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); - toolbar.setNavigationIcon(R.drawable.ic_close_white_24dp); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - activity.onBackPressed(); - } - }); - 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 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, 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)); - } - - private void updateCurrentSong() { - getCurrentSong(); - updatePlayerMenu(); - } - - private void getCurrentSong() { - song = MusicPlayerRemote.getCurrentSong(); - } - - @Override - @ColorInt - public int getPaletteColor() { - 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 void animateColorChange(final int newColor) { - getView().setBackgroundColor(newColor); - lastColor = newColor; - } - - @Override - public boolean onMenuItemClick(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_sleep_timer: - new SleepTimerDialog().show(getFragmentManager(), "SET_SLEEP_TIMER"); - return true; - case R.id.action_toggle_favorite: - MusicUtil.toggleFavorite(activity, song); - if (MusicUtil.isFavorite(activity, song)) { - playerAlbumCoverFragment.showHeart(); - } - updatePlayerMenu(); - return true; - case R.id.action_share: - SongShareDialog.create(song).show(getFragmentManager(), "SHARE_SONG"); - return true; - case R.id.action_equalizer: - NavigationUtil.openEqualizer(activity); - return true; - case R.id.action_shuffle_all: - MusicPlayerRemote.openAndShuffleQueue(SongLoader.getAllSongs(activity), true); - return true; - case R.id.action_add_to_playlist: - AddToPlaylistDialog.create(song).show(getFragmentManager(), "ADD_PLAYLIST"); - return true; - case R.id.action_playing_queue: - PlayingQueueDialog.create().show(getFragmentManager(), "PLAY_QUEUE"); - return true; - case R.id.action_tag_editor: - Intent intent = new Intent(activity, SongTagEditorActivity.class); - intent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id); - startActivity(intent); - return true; - case R.id.action_details: - SongDetailDialog.create(song).show(getFragmentManager(), "SONG_DETAIL"); - return true; - case R.id.action_go_to_album: - NavigationUtil.goToAlbum(activity, song.albumId); - return true; - case R.id.action_go_to_artist: - NavigationUtil.goToArtist(activity, song.artistId); - return true; - } - return false; - } - - public void showControls() { - playbackControlsFragment.showControls(); - } - - public void resetShowControlsAnimation() { - playbackControlsFragment.resetShowControlsAnimation(); - } - - @Override - public void onColorChanged(int color) { - animateColorChange(color); - playbackControlsFragment.setColor(color); - callbacks.onPaletteColorChanged(); - } - - public interface Callbacks { - void onPaletteColorChanged(); - } -} diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayingInfoFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayingInfoFragment.java deleted file mode 100644 index c41cbc29..00000000 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayingInfoFragment.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.kabouzeid.gramophone.ui.fragments; - - -import android.content.Context; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.kabouzeid.gramophone.R; -import com.kabouzeid.gramophone.interfaces.MusicServiceEventListener; -import com.kabouzeid.gramophone.ui.activities.base.AbsMusicServiceActivity; - -import butterknife.ButterKnife; - -/** - * @author Karim Abou Zeid (kabouzeid) - */ -public class PlayingInfoFragment extends Fragment implements MusicServiceEventListener { - - - 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_playing_info, container, false); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - ButterKnife.bind(this, view); - activity.addMusicServiceEventListener(this); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - activity.removeMusicServiceEventListener(this); - ButterKnife.unbind(this); - } - - @Override - public void onPlayingMetaChanged() { - - } - - @Override - public void onPlayStateChanged() { - } - - @Override - public void onRepeatModeChanged() { - } - - @Override - public void onShuffleModeChanged() { - } - - @Override - public void onMediaStoreChanged() { - } - -} diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/MiniPlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/MiniPlayerFragment.java similarity index 99% rename from app/src/main/java/com/kabouzeid/gramophone/ui/fragments/MiniPlayerFragment.java rename to app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/MiniPlayerFragment.java index 4ca804e7..eca87784 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/MiniPlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/MiniPlayerFragment.java @@ -1,4 +1,4 @@ -package com.kabouzeid.gramophone.ui.fragments; +package com.kabouzeid.gramophone.ui.fragments.player; import android.content.Context; import android.graphics.PorterDuff; diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlaybackControlsFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlaybackControlsFragment.java similarity index 98% rename from app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlaybackControlsFragment.java rename to app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlaybackControlsFragment.java index 640864ec..dc0aa342 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlaybackControlsFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlaybackControlsFragment.java @@ -1,4 +1,4 @@ -package com.kabouzeid.gramophone.ui.fragments; +package com.kabouzeid.gramophone.ui.fragments.player; import android.content.Context; import android.graphics.Color; @@ -229,7 +229,7 @@ public class PlaybackControlsFragment extends Fragment implements MusicServiceEv lastPlaybackControlsColor)); break; default: - shuffleButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_shuffle_white_36dp, + shuffleButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_trending_flat_white_36dp, lastPlaybackControlsColor)); break; } @@ -256,7 +256,7 @@ public class PlaybackControlsFragment extends Fragment implements MusicServiceEv lastPlaybackControlsColor)); break; default: - repeatButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_repeat_white_36dp, + repeatButton.setImageDrawable(Util.getTintedDrawable(activity, R.drawable.ic_repeat_off_white_36dp, lastPlaybackControlsColor)); break; } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayerAlbumCoverFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java similarity index 99% rename from app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayerAlbumCoverFragment.java rename to app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java index ecd94d7c..42ebedd4 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/PlayerAlbumCoverFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java @@ -1,4 +1,4 @@ -package com.kabouzeid.gramophone.ui.fragments; +package com.kabouzeid.gramophone.ui.fragments.player; import android.animation.Animator; import android.content.Context; diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerFragment.java new file mode 100644 index 00000000..1a03a82a --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerFragment.java @@ -0,0 +1,277 @@ +package com.kabouzeid.gramophone.ui.fragments.player; + +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.annotation.ColorInt; +import android.support.v4.app.Fragment; +import android.support.v7.widget.CardView; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.widget.RelativeLayout; + +import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.adapter.song.SongAdapter; +import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog; +import com.kabouzeid.gramophone.dialogs.PlayingQueueDialog; +import com.kabouzeid.gramophone.dialogs.SleepTimerDialog; +import com.kabouzeid.gramophone.dialogs.SongDetailDialog; +import com.kabouzeid.gramophone.dialogs.SongShareDialog; +import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.interfaces.MusicServiceEventListener; +import com.kabouzeid.gramophone.interfaces.PaletteColorHolder; +import com.kabouzeid.gramophone.loader.SongLoader; +import com.kabouzeid.gramophone.model.Song; +import com.kabouzeid.gramophone.ui.activities.MainActivity; +import com.kabouzeid.gramophone.ui.activities.base.AbsMusicServiceActivity; +import com.kabouzeid.gramophone.ui.activities.tageditor.AbsTagEditorActivity; +import com.kabouzeid.gramophone.ui.activities.tageditor.SongTagEditorActivity; +import com.kabouzeid.gramophone.util.ColorUtil; +import com.kabouzeid.gramophone.util.MusicUtil; +import com.kabouzeid.gramophone.util.NavigationUtil; +import com.kabouzeid.gramophone.util.Util; +import com.kabouzeid.gramophone.util.ViewUtil; +import com.kabouzeid.gramophone.views.SquareLayout; +import com.sothree.slidinguppanel.SlidingUpPanelLayout; + +import org.solovyev.android.views.llm.LinearLayoutManager; + +import butterknife.Bind; +import butterknife.ButterKnife; + +public class PlayerFragment extends Fragment implements MusicServiceEventListener, Toolbar.OnMenuItemClickListener, PaletteColorHolder, PlayerAlbumCoverFragment.OnColorChangedListener { + public static final String TAG = PlayerFragment.class.getSimpleName(); + + @Bind(R.id.player_toolbar) + Toolbar toolbar; + @Bind(R.id.player_sliding_layout) + SlidingUpPanelLayout slidingUpPanelLayout; + @Bind(R.id.player_recycler_view) + RecyclerView recyclerView; + @Bind(R.id.playing_queue_card) + CardView playingQueueCard; + @Bind(R.id.album_cover_container) + SquareLayout albumCoverContainer; + @Bind(R.id.player_content) + RelativeLayout playerContent; + + private int lastColor; + + private AbsMusicServiceActivity activity; + private Callbacks callbacks; + + private PlaybackControlsFragment playbackControlsFragment; + private PlayerAlbumCoverFragment playerAlbumCoverFragment; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + try { + activity = (AbsMusicServiceActivity) context; + callbacks = (Callbacks) context; + } catch (ClassCastException e) { + throw new RuntimeException(context.getClass().getSimpleName() + " must be an instance of " + AbsMusicServiceActivity.class.getSimpleName() + " and implement " + Callbacks.class.getSimpleName()); + } + } + + @Override + public void onDetach() { + super.onDetach(); + activity = null; + callbacks = null; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_player, container, false); + } + + @Override + public void onViewCreated(final View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + ButterKnife.bind(this, view); + + setUpPlayerToolbar(); + setUpSubFragments(); + + recyclerView.setAdapter(new SongAdapter( + ((MainActivity) getActivity()), + SongLoader.getAllSongs(getActivity()), + R.layout.item_list, + false, + ((MainActivity) getActivity()))); + + // TODO set child size + recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + + view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + view.getViewTreeObserver().removeOnGlobalLayoutListener(this); + setUpPanelAndAlbumCoverHeight(); + } + }); + + + + activity.addMusicServiceEventListener(this); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + activity.removeMusicServiceEventListener(this); + ButterKnife.unbind(this); + } + + @Override + public void onPlayingMetaChanged() { + updatePlayerMenu(); + } + + @Override + public void onPlayStateChanged() { + + } + + @Override + public void onRepeatModeChanged() { + + } + + @Override + public void onShuffleModeChanged() { + + } + + @Override + public void onMediaStoreChanged() { + + } + + private void setUpPanelAndAlbumCoverHeight() { + final int availablePanelHeight = slidingUpPanelLayout.getHeight() - playerContent.getHeight(); + final int minPanelHeight = (int) getResources().getDisplayMetrics().density * (72 + 32); + if (availablePanelHeight < minPanelHeight) { + albumCoverContainer.getLayoutParams().height = albumCoverContainer.getHeight() - (minPanelHeight - availablePanelHeight); + albumCoverContainer.forceSquare(false); + } + slidingUpPanelLayout.setPanelHeight(Math.max(minPanelHeight, availablePanelHeight)); + } + + private void setUpSubFragments() { + playbackControlsFragment = (PlaybackControlsFragment) getChildFragmentManager().findFragmentById(R.id.playback_controls_fragment); + playerAlbumCoverFragment = (PlayerAlbumCoverFragment) getChildFragmentManager().findFragmentById(R.id.player_album_cover_fragment); + + playerAlbumCoverFragment.setOnColorChangedListener(this); + } + + private void setUpPlayerToolbar() { + toolbar.inflateMenu(R.menu.menu_player); + toolbar.setNavigationIcon(R.drawable.ic_close_white_24dp); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + activity.onBackPressed(); + } + }); + toolbar.setOnMenuItemClickListener(this); + } + + private void updatePlayerMenu() { + boolean isFavorite = MusicUtil.isFavorite(activity, MusicPlayerRemote.getCurrentSong()); + Drawable favoriteIcon = Util.getTintedDrawable(activity, isFavorite ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_outline_white_24dp, ViewUtil.getToolbarIconColor(activity, 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)); + } + + @Override + @ColorInt + public int getPaletteColor() { + return lastColor; + } + + private void animateColorChange(final int newColor) { + getView().setBackgroundColor(newColor); + lastColor = newColor; + } + + @Override + public boolean onMenuItemClick(MenuItem item) { + final Song song = MusicPlayerRemote.getCurrentSong(); + switch (item.getItemId()) { + case R.id.action_sleep_timer: + new SleepTimerDialog().show(getFragmentManager(), "SET_SLEEP_TIMER"); + return true; + case R.id.action_toggle_favorite: + MusicUtil.toggleFavorite(activity, song); + if (MusicUtil.isFavorite(activity, song)) { + playerAlbumCoverFragment.showHeart(); + } + updatePlayerMenu(); + return true; + case R.id.action_share: + SongShareDialog.create(song).show(getFragmentManager(), "SHARE_SONG"); + return true; + case R.id.action_equalizer: + NavigationUtil.openEqualizer(activity); + return true; + case R.id.action_shuffle_all: + MusicPlayerRemote.openAndShuffleQueue(SongLoader.getAllSongs(activity), true); + return true; + case R.id.action_add_to_playlist: + AddToPlaylistDialog.create(song).show(getFragmentManager(), "ADD_PLAYLIST"); + return true; + case R.id.action_playing_queue: + PlayingQueueDialog.create().show(getFragmentManager(), "PLAY_QUEUE"); + return true; + case R.id.action_tag_editor: + Intent intent = new Intent(activity, SongTagEditorActivity.class); + intent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id); + startActivity(intent); + return true; + case R.id.action_details: + SongDetailDialog.create(song).show(getFragmentManager(), "SONG_DETAIL"); + return true; + case R.id.action_go_to_album: + NavigationUtil.goToAlbum(activity, song.albumId); + return true; + case R.id.action_go_to_artist: + NavigationUtil.goToArtist(activity, song.artistId); + return true; + } + return false; + } + + public void showControls() { + playbackControlsFragment.showControls(); + } + + public void resetShowControlsAnimation() { + playbackControlsFragment.resetShowControlsAnimation(); + } + + @Override + public void onColorChanged(int color) { + animateColorChange(color); + playbackControlsFragment.setColor(color); + callbacks.onPaletteColorChanged(); + } + + public interface Callbacks { + void onPaletteColorChanged(); + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/views/SquareLayout.java b/app/src/main/java/com/kabouzeid/gramophone/views/SquareLayout.java new file mode 100644 index 00000000..7414545a --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/views/SquareLayout.java @@ -0,0 +1,43 @@ +package com.kabouzeid.gramophone.views; + +import android.annotation.TargetApi; +import android.content.Context; +import android.os.Build; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public class SquareLayout extends FrameLayout { + + private boolean forceSquare = true; + + public SquareLayout(Context context) { + super(context); + } + + public SquareLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public SquareLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public SquareLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + //noinspection SuspiciousNameCombination + super.onMeasure(widthMeasureSpec, forceSquare ? widthMeasureSpec : heightMeasureSpec); + } + + public void forceSquare(boolean forceSquare) { + this.forceSquare = forceSquare; + requestLayout(); + } +} diff --git a/app/src/main/res/drawable-hdpi/ic_repeat_off_white_36dp.png b/app/src/main/res/drawable-hdpi/ic_repeat_off_white_36dp.png new file mode 100644 index 00000000..1b83e734 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_repeat_off_white_36dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_trending_flat_white_36dp.png b/app/src/main/res/drawable-hdpi/ic_trending_flat_white_36dp.png new file mode 100644 index 00000000..d9a840d5 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_trending_flat_white_36dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_repeat_off_white_36dp.png b/app/src/main/res/drawable-mdpi/ic_repeat_off_white_36dp.png new file mode 100644 index 00000000..4149dc54 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_repeat_off_white_36dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_trending_flat_white_36dp.png b/app/src/main/res/drawable-mdpi/ic_trending_flat_white_36dp.png new file mode 100644 index 00000000..ea5d1e18 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_trending_flat_white_36dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_repeat_off_white_36dp.png b/app/src/main/res/drawable-xhdpi/ic_repeat_off_white_36dp.png new file mode 100644 index 00000000..009f7a6e Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_repeat_off_white_36dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_trending_flat_white_36dp.png b/app/src/main/res/drawable-xhdpi/ic_trending_flat_white_36dp.png new file mode 100644 index 00000000..28ede2eb Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_trending_flat_white_36dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_repeat_off_white_36dp.png b/app/src/main/res/drawable-xxhdpi/ic_repeat_off_white_36dp.png new file mode 100644 index 00000000..42ab374b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_repeat_off_white_36dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_trending_flat_white_36dp.png b/app/src/main/res/drawable-xxhdpi/ic_trending_flat_white_36dp.png new file mode 100644 index 00000000..cdf966ee Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_trending_flat_white_36dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_repeat_off_white_36dp.png b/app/src/main/res/drawable-xxxhdpi/ic_repeat_off_white_36dp.png new file mode 100644 index 00000000..59b70a15 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_repeat_off_white_36dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_trending_flat_white_36dp.png b/app/src/main/res/drawable-xxxhdpi/ic_trending_flat_white_36dp.png new file mode 100644 index 00000000..0da7c185 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_trending_flat_white_36dp.png differ diff --git a/app/src/main/res/layout-land/fragment_player.xml b/app/src/main/res/layout-land/fragment_player.xml deleted file mode 100644 index d26d1bbe..00000000 --- a/app/src/main/res/layout-land/fragment_player.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_playback_controls.xml b/app/src/main/res/layout/fragment_playback_controls.xml index fc8bf331..37203991 100644 --- a/app/src/main/res/layout/fragment_playback_controls.xml +++ b/app/src/main/res/layout/fragment_playback_controls.xml @@ -8,7 +8,7 @@ android:orientation="vertical"> diff --git a/app/src/main/res/layout/fragment_player.xml b/app/src/main/res/layout/fragment_player.xml index 1eeb223e..27a8467a 100644 --- a/app/src/main/res/layout/fragment_player.xml +++ b/app/src/main/res/layout/fragment_player.xml @@ -1,48 +1,80 @@ - + + android:focusable="true" + android:clickable="false" + android:gravity="bottom" + sothree:umanoDragView="@+id/player_panel" + sothree:umanoFadeColor="#00000000" + sothree:umanoOverlay="true" + sothree:umanoPanelHeight="0dp" + sothree:umanoScrollableView="@+id/player_recycler_view" + sothree:umanoParallaxOffset="32dp" + sothree:umanoShadowHeight="0dp"> - + android:layout_alignParentTop="true"> + + + + + android:layout_below="@id/album_cover_container" /> - + + - + - + - + + + + + + + diff --git a/app/src/main/res/layout/fragment_playing_info.xml b/app/src/main/res/layout/fragment_playing_info.xml deleted file mode 100644 index cc876390..00000000 --- a/app/src/main/res/layout/fragment_playing_info.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/sliding_music_panel_layout.xml b/app/src/main/res/layout/sliding_music_panel_layout.xml index e025d048..315af03e 100644 --- a/app/src/main/res/layout/sliding_music_panel_layout.xml +++ b/app/src/main/res/layout/sliding_music_panel_layout.xml @@ -5,6 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="bottom" + sothree:umanoScrollableView="@+id/sliding_panel" sothree:umanoDragView="@+id/sliding_panel" sothree:umanoPanelHeight="@dimen/mini_player_height" sothree:umanoShadowHeight="@dimen/card_elevation"> @@ -18,19 +19,17 @@ android:id="@+id/sliding_panel" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?android:colorBackground" - android:clickable="true" - android:focusable="false"> + android:background="?android:colorBackground">