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().

This commit is contained in:
Karim Abou Zeid 2016-03-29 18:17:57 +02:00
commit 9b17931cd6
9 changed files with 197 additions and 8 deletions

View file

@ -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'

View file

@ -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<LyricInfo> CREATOR = new Parcelable.Creator<LyricInfo>() {
@Override
public LyricInfo createFromParcel(Parcel source) {
return new LyricInfo(source);
}
@Override
public LyricInfo[] newArray(int size) {
return new LyricInfo[size];
}
};
}
}

View file

@ -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;
}
}

View file

@ -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<Void, Void, String>() {
@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);

View file

@ -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;
}
}

View file

@ -0,0 +1,10 @@
<!-- drawable/comment_text_outline.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M9,22A1,1 0 0,1 8,21V18H4A2,2 0 0,1 2,16V4C2,2.89 2.9,2 4,2H20A2,2 0 0,1 22,4V16A2,2 0 0,1 20,18H13.9L10.2,21.71C10,21.9 9.75,22 9.5,22V22H9M10,16V19.08L13.08,16H20V4H4V16H10M6,7H18V9H6V7M6,11H15V13H6V11Z" />
</vector>

View file

@ -4,21 +4,25 @@
<item
android:id="@+id/action_toggle_favorite"
android:icon="@drawable/ic_favorite_border_white_24dp"
android:orderInCategory="1"
android:title="@string/action_add_to_favorites"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_shuffle_all"
android:orderInCategory="1"
android:title="@string/action_shuffle_all"
app:showAsAction="never" />
<item
android:id="@+id/action_clear_playing_queue"
android:orderInCategory="1"
android:title="@string/action_clear_playing_queue"
app:showAsAction="never" />
<item
android:id="@+id/action_sleep_timer"
android:orderInCategory="1"
android:title="@string/action_sleep_timer"
app:showAsAction="never" />

View file

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="action_new_playlist" type="id" />
<item name="action_show_lyrics" type="id" />
</resources>

View file

@ -99,6 +99,7 @@
<string name="action_shuffle_playlist">Shuffle playlist</string>
<string name="action_clear_playing_queue">Clear playing queue</string>
<string name="action_go_to_start_directory">Go to start directory</string>
<string name="action_show_lyrics">Show lyrics</string>
<string name="last_opened">Last opened</string>
<string name="light_theme_name">Light</string>
<string name="dark_theme_name">Dark</string>