From 9b17931cd639e4dfdf28a3ebaffff70e787bab9b Mon Sep 17 00:00:00 2001 From: Karim Abou Zeid Date: Tue, 29 Mar 2016 18:17:57 +0200 Subject: [PATCH] Added a lyrics dialog. Updated the SlidingUpPanelLayout lib which fixes a few sliding issues. Fixed an issue where the sling panel would get stuck somewhere in the middle. Fixed a NPE in an asynctask onPostExecute(). --- app/build.gradle | 2 +- .../gramophone/dialogs/LyricsDialog.java | 76 +++++++++++++++ .../base/AbsSlidingMusicPanelActivity.java | 3 + .../ui/fragments/player/PlayerFragment.java | 96 +++++++++++++++++-- .../kabouzeid/gramophone/util/ViewUtil.java | 12 +++ .../ic_comment_text_outline_white_24dp.xml | 10 ++ app/src/main/res/menu/menu_player.xml | 4 + app/src/main/res/values/ids.xml | 1 + app/src/main/res/values/strings.xml | 1 + 9 files changed, 197 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/com/kabouzeid/gramophone/dialogs/LyricsDialog.java create mode 100644 app/src/main/res/drawable/ic_comment_text_outline_white_24dp.xml diff --git a/app/build.gradle b/app/build.gradle index 682baf70..78753462 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -134,7 +134,7 @@ dependencies { compile 'com.android.support:preference-v7:23.2.1' compile 'com.github.ksoichiro:android-observablescrollview:1.6.0' compile 'com.github.kabouzeid:SeekArc:1.2-kmod' - compile 'com.github.kabouzeid:AndroidSlidingUpPanel:3.3.1-kmod' + compile 'com.github.kabouzeid:AndroidSlidingUpPanel:3.3.0-kmod2' compile 'com.squareup.retrofit2:retrofit:2.0.0' compile 'com.squareup.retrofit2:converter-gson:2.0.0' compile 'com.jakewharton:butterknife:7.0.1' diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/LyricsDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/LyricsDialog.java new file mode 100644 index 00000000..711bfe6c --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/LyricsDialog.java @@ -0,0 +1,76 @@ +package com.kabouzeid.gramophone.dialogs; + +import android.app.Dialog; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; + +import com.afollestad.materialdialogs.MaterialDialog; + +import hugo.weaving.DebugLog; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public class LyricsDialog extends DialogFragment { + + public static LyricsDialog create(@NonNull LyricInfo lyricInfo) { + LyricsDialog dialog = new LyricsDialog(); + Bundle args = new Bundle(); + args.putParcelable("LyricInfo", lyricInfo); + dialog.setArguments(args); + return dialog; + } + + @DebugLog + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + LyricInfo lyricInfo = getArguments().getParcelable("LyricInfo"); + //noinspection ConstantConditions + return new MaterialDialog.Builder(getActivity()) + .title(lyricInfo.title) + .content(lyricInfo.lyrics) + .build(); + } + + public static class LyricInfo implements Parcelable { + public final String title; + public final String lyrics; + + public LyricInfo(String title, String lyrics) { + this.title = title; + this.lyrics = lyrics; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.title); + dest.writeString(this.lyrics); + } + + protected LyricInfo(Parcel in) { + this.title = in.readString(); + this.lyrics = in.readString(); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public LyricInfo createFromParcel(Parcel source) { + return new LyricInfo(source); + } + + @Override + public LyricInfo[] newArray(int size) { + return new LyricInfo[size]; + } + }; + } +} 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 07915c8e..4d018236 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 @@ -107,6 +107,9 @@ public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivi case EXPANDED: onPanelExpanded(panel); break; + case ANCHORED: + collapsePanel(); // this fixes a bug where the panel would get stuck for some reason + break; } } 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 index 8648f854..3018f93e 100644 --- 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 @@ -2,6 +2,7 @@ package com.kabouzeid.gramophone.ui.fragments.player; import android.animation.Animator; import android.animation.AnimatorSet; +import android.app.Activity; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; @@ -15,7 +16,9 @@ import android.support.v7.widget.CardView; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; +import android.text.TextUtils; import android.view.LayoutInflater; +import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewAnimationUtils; @@ -36,6 +39,7 @@ import com.kabouzeid.appthemehelper.util.ToolbarContentTintHelper; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.adapter.base.MediaEntryViewHolder; import com.kabouzeid.gramophone.adapter.song.PlayingQueueAdapter; +import com.kabouzeid.gramophone.dialogs.LyricsDialog; import com.kabouzeid.gramophone.dialogs.SongShareDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.menu.SongMenuHelper; @@ -47,6 +51,16 @@ import com.kabouzeid.gramophone.util.ViewUtil; import com.kabouzeid.gramophone.views.WidthFitSquareLayout; import com.sothree.slidinguppanel.SlidingUpPanelLayout; +import org.jaudiotagger.audio.AudioFileIO; +import org.jaudiotagger.audio.exceptions.CannotReadException; +import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; +import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; +import org.jaudiotagger.tag.FieldKey; +import org.jaudiotagger.tag.TagException; + +import java.io.File; +import java.io.IOException; + import butterknife.Bind; import butterknife.ButterKnife; @@ -79,6 +93,9 @@ public class PlayerFragment extends AbsPlayerFragment implements PlayerAlbumCove private RecyclerViewDragDropManager recyclerViewDragDropManager; private AsyncTask updateIsFavoriteTask; + private AsyncTask updateLyricsAsyncTask; + + private LyricsDialog.LyricInfo lyricsInfo; private Impl impl; @@ -160,6 +177,7 @@ public class PlayerFragment extends AbsPlayerFragment implements PlayerAlbumCove updateQueue(); updateCurrentSong(); updateIsFavorite(); + updateLyrics(); } @Override @@ -167,6 +185,7 @@ public class PlayerFragment extends AbsPlayerFragment implements PlayerAlbumCove updateCurrentSong(); updateIsFavorite(); updateQueuePosition(); + updateLyrics(); } @Override @@ -217,6 +236,17 @@ public class PlayerFragment extends AbsPlayerFragment implements PlayerAlbumCove toolbar.setOnMenuItemClickListener(this); } + @Override + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_show_lyrics: + if (lyricsInfo != null) + LyricsDialog.create(lyricsInfo).show(getFragmentManager(), "LYRICS"); + return true; + } + return super.onMenuItemClick(item); + } + private void setUpRecyclerView() { recyclerViewDragDropManager = new RecyclerViewDragDropManager(); final GeneralItemAnimator animator = new RefactoredDefaultItemAnimator(); @@ -252,16 +282,65 @@ public class PlayerFragment extends AbsPlayerFragment implements PlayerAlbumCove @Override protected void onPostExecute(Boolean isFavorite) { - int res = isFavorite ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_border_white_24dp; - int color = ToolbarContentTintHelper.toolbarContentColor(getActivity(), Color.TRANSPARENT); - Drawable drawable = TintHelper.createTintedDrawable(ContextCompat.getDrawable(getActivity(), res), color); - toolbar.getMenu().findItem(R.id.action_toggle_favorite) - .setIcon(drawable) - .setTitle(isFavorite ? getString(R.string.action_remove_from_favorites) : getString(R.string.action_add_to_favorites)); + Activity activity = getActivity(); + if (activity != null) { + int res = isFavorite ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_border_white_24dp; + int color = ToolbarContentTintHelper.toolbarContentColor(activity, Color.TRANSPARENT); + Drawable drawable = TintHelper.createTintedDrawable(ContextCompat.getDrawable(activity, res), color); + toolbar.getMenu().findItem(R.id.action_toggle_favorite) + .setIcon(drawable) + .setTitle(isFavorite ? getString(R.string.action_remove_from_favorites) : getString(R.string.action_add_to_favorites)); + } } }.execute(MusicPlayerRemote.getCurrentSong()); } + private void updateLyrics() { + if (updateLyricsAsyncTask != null) updateLyricsAsyncTask.cancel(false); + final Song song = MusicPlayerRemote.getCurrentSong(); + updateLyricsAsyncTask = new AsyncTask() { + @Override + protected void onPreExecute() { + super.onPreExecute(); + lyricsInfo = null; + toolbar.getMenu().removeItem(R.id.action_show_lyrics); + } + + @Override + protected String doInBackground(Void... params) { + try { + return AudioFileIO.read(new File(song.data)).getTagOrCreateDefault().getFirst(FieldKey.LYRICS); + } catch (IOException | CannotReadException | TagException | InvalidAudioFrameException | ReadOnlyFileException e) { + e.printStackTrace(); + } + return null; + } + + @Override + protected void onPostExecute(String lyrics) { + super.onPostExecute(lyrics); + if (TextUtils.isEmpty(lyrics)) { + lyricsInfo = null; + if (toolbar != null) { + toolbar.getMenu().removeItem(R.id.action_show_lyrics); + } + } else { + lyricsInfo = new LyricsDialog.LyricInfo(song.title, lyrics); + Activity activity = getActivity(); + if (toolbar != null && activity != null) + if (toolbar.getMenu().findItem(R.id.action_show_lyrics) == null) { + int color = ToolbarContentTintHelper.toolbarContentColor(activity, Color.TRANSPARENT); + Drawable drawable = TintHelper.createTintedDrawable(ContextCompat.getDrawable(activity, R.drawable.ic_comment_text_outline_white_24dp), color); + toolbar.getMenu() + .add(Menu.NONE, R.id.action_show_lyrics, Menu.NONE, R.string.action_show_lyrics) + .setIcon(drawable) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + } + } + } + }.execute(); + } + @Override @ColorInt public int getPaletteColor() { @@ -333,6 +412,9 @@ public class PlayerFragment extends AbsPlayerFragment implements PlayerAlbumCove case COLLAPSED: onPanelCollapsed(panel); break; + case ANCHORED: + slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); // this fixes a bug where the panel would get stuck for some reason + break; } } @@ -448,7 +530,7 @@ public class PlayerFragment extends AbsPlayerFragment implements PlayerAlbumCove int topMargin = fragment.getResources().getDimensionPixelSize(R.dimen.status_bar_padding); final int availablePanelHeight = fragment.slidingUpPanelLayout.getHeight() - fragment.getView().findViewById(R.id.player_content).getHeight() + topMargin; - final int minPanelHeight = (int) fragment.getResources().getDisplayMetrics().density * (72 + 24) + topMargin; + final int minPanelHeight = (int) ViewUtil.convertDpToPixel(72 + 24, fragment.getResources()) + topMargin; if (availablePanelHeight < minPanelHeight) { albumCoverContainer.getLayoutParams().height = albumCoverContainer.getHeight() - (minPanelHeight - availablePanelHeight); albumCoverContainer.forceSquare(false); diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/ViewUtil.java b/app/src/main/java/com/kabouzeid/gramophone/util/ViewUtil.java index 583852e4..db92315a 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/ViewUtil.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/ViewUtil.java @@ -5,6 +5,7 @@ import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.ColorStateList; +import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -13,6 +14,7 @@ import android.graphics.drawable.StateListDrawable; import android.os.Build; import android.support.annotation.ColorInt; import android.support.v4.view.ViewCompat; +import android.util.DisplayMetrics; import android.view.View; import android.view.animation.PathInterpolator; import android.widget.TextView; @@ -84,4 +86,14 @@ public class ViewUtil { recyclerView.setThumbColor(accentColor); recyclerView.setTrackColor(ColorUtil.withAlpha(ATHUtil.resolveColor(context, R.attr.colorControlNormal), 0.12f)); } + + public static float convertDpToPixel(float dp, Resources resources) { + DisplayMetrics metrics = resources.getDisplayMetrics(); + return dp * metrics.density; + } + + public static float convertPixelsToDp(float px, Resources resources) { + DisplayMetrics metrics = resources.getDisplayMetrics(); + return px / metrics.density; + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_comment_text_outline_white_24dp.xml b/app/src/main/res/drawable/ic_comment_text_outline_white_24dp.xml new file mode 100644 index 00000000..03f39dd9 --- /dev/null +++ b/app/src/main/res/drawable/ic_comment_text_outline_white_24dp.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_player.xml b/app/src/main/res/menu/menu_player.xml index 113fbb92..53cf832b 100644 --- a/app/src/main/res/menu/menu_player.xml +++ b/app/src/main/res/menu/menu_player.xml @@ -4,21 +4,25 @@ diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index e6ce922e..6ac8ad2b 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -1,4 +1,5 @@ + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 49492342..7be1f1b8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -99,6 +99,7 @@ Shuffle playlist Clear playing queue Go to start directory + Show lyrics Last opened Light Dark