From dbb6250c06bb78b163b5bf127b69f72a81b07873 Mon Sep 17 00:00:00 2001 From: tkashkin Date: Thu, 18 May 2017 15:06:27 +0300 Subject: [PATCH 01/12] Add synchronized lyrics support (only LRC format at the moment) --- .../model/lyrics/SynchronizedLyrics.java | 32 +++++++++ .../model/lyrics/SynchronizedLyricsLRC.java | 47 ++++++++++++++ .../player/PlayerAlbumCoverFragment.java | 65 ++++++++++++++++++- .../player/card/CardPlayerFragment.java | 3 + .../player/flat/FlatPlayerFragment.java | 3 + .../layout/fragment_player_album_cover.xml | 35 ++++++++++ 6 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyrics.java create mode 100644 app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyrics.java new file mode 100644 index 00000000..d0a6d748 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyrics.java @@ -0,0 +1,32 @@ +package com.kabouzeid.gramophone.model.lyrics; + +import android.util.SparseArray; + +public abstract class SynchronizedLyrics { + public final SparseArray lines = new SparseArray<>(); + + public static SynchronizedLyrics parse(String data) + { + return new SynchronizedLyricsLRC(data); // no another formats at the moment + } + + public String getLine(int time) + { + time += 500; // small time adjustment to display line before it actually starts + + int lastLineTime = lines.keyAt(0); + + for(int i = 0; i < lines.size(); i++) { + int lineTime = lines.keyAt(i); + + if(time >= lineTime) { + lastLineTime = lineTime; + } + else { + break; + } + } + + return lines.get(lastLineTime); + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java new file mode 100644 index 00000000..b59ebb9b --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java @@ -0,0 +1,47 @@ +package com.kabouzeid.gramophone.model.lyrics; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SynchronizedLyricsLRC extends SynchronizedLyrics { + private static Pattern LRC_LINE_PATTERN = Pattern.compile("((?:\\[.*?\\])+)(.*)"); + private static Pattern LRC_TIME_PATTERN = Pattern.compile("\\[(\\d\\d):(\\d\\d)(?:\\.(\\d\\d))\\]"); + + public SynchronizedLyricsLRC(String data) + { + if(data == null || data.isEmpty()) { + return; + } + + String[] lines = data.split("\r?\n"); + + for(String line : lines) { + line = line.trim(); + if(line.isEmpty()) { + continue; + } + + Matcher matcher = SynchronizedLyricsLRC.LRC_LINE_PATTERN.matcher(line); + if(matcher.find()) { + String time = matcher.group(1); + String text = matcher.group(2); + + Matcher timeMatcher = SynchronizedLyricsLRC.LRC_TIME_PATTERN.matcher(time); + while(timeMatcher.find()) { + int m = 0, s = 0, x = 0; + try { + m = Integer.parseInt(timeMatcher.group(1)); + s = Integer.parseInt(timeMatcher.group(2)); + x = Integer.parseInt(timeMatcher.group(3)); + } catch (NumberFormatException ex) { + ex.printStackTrace(); + } + int ms = x*10 + s*1000 + m*60000; + + this.lines.append(ms, text); + } + } + } + } + +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java index 2503281d..388b5a83 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java @@ -10,12 +10,16 @@ import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; +import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.TextView; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.adapter.AlbumCoverPagerAdapter; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.helper.MusicProgressViewUpdateHelper; import com.kabouzeid.gramophone.misc.SimpleAnimatorListener; +import com.kabouzeid.gramophone.model.lyrics.SynchronizedLyrics; import com.kabouzeid.gramophone.ui.fragments.AbsMusicServiceFragment; import com.kabouzeid.gramophone.util.ViewUtil; @@ -26,7 +30,7 @@ import butterknife.Unbinder; /** * @author Karim Abou Zeid (kabouzeid) */ -public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements ViewPager.OnPageChangeListener { +public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements ViewPager.OnPageChangeListener, MusicProgressViewUpdateHelper.Callback { public static final String TAG = PlayerAlbumCoverFragment.class.getSimpleName(); private Unbinder unbinder; @@ -36,9 +40,19 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements @BindView(R.id.player_favorite_icon) ImageView favoriteIcon; + @BindView(R.id.player_lyrics) + FrameLayout lyrics; + @BindView(R.id.player_lyrics_line1) + TextView lyricsLine1; + @BindView(R.id.player_lyrics_line2) + TextView lyricsLine2; + private Callbacks callbacks; private int currentPosition; + private SynchronizedLyrics synchronizedLyrics; + private MusicProgressViewUpdateHelper progressViewUpdateHelper; + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -68,6 +82,8 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements return gestureDetector.onTouchEvent(event); } }); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + progressViewUpdateHelper.start(); } @Override @@ -75,6 +91,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements super.onDestroyView(); viewPager.removeOnPageChangeListener(this); unbinder.unbind(); + progressViewUpdateHelper.stop(); } @Override @@ -163,6 +180,22 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements .start(); } + public void setSynchronizedLyrics(SynchronizedLyrics sLyrics) + { + if(sLyrics == null || sLyrics.lines.size() == 0) + { + synchronizedLyrics = null; + lyrics.setVisibility(View.GONE); + lyricsLine1.setText(null); + lyricsLine2.setText(null); + return; + } + + synchronizedLyrics = sLyrics; + + lyrics.setVisibility(View.VISIBLE); + } + private void notifyColorChange(int color) { if (callbacks != null) callbacks.onColorChanged(color); } @@ -171,6 +204,36 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements callbacks = listener; } + @Override + public void onUpdateProgressViews(int progress, int total) { + if(synchronizedLyrics == null || synchronizedLyrics.lines.size() == 0) { + lyricsLine1.setText(null); + lyricsLine2.setText(null); + return; + } + + String oldLine = lyricsLine2.getText().toString(); + String line = synchronizedLyrics.getLine(progress); + + if(!oldLine.equals(line) || oldLine.isEmpty()) + { + lyricsLine1.setText(oldLine); + lyricsLine2.setText(line); + lyricsLine1.setVisibility(View.VISIBLE); + lyricsLine2.setVisibility(View.VISIBLE); + int l1h = lyricsLine1.getMeasuredHeight(); + int l2h = lyricsLine2.getMeasuredHeight(); + + this.lyricsLine1.setAlpha(1f); + this.lyricsLine1.setTranslationY(0f); + this.lyricsLine1.animate().alpha(0f).translationY(-l1h).setDuration(300); + + this.lyricsLine2.setAlpha(0f); + this.lyricsLine2.setTranslationY(l2h); + this.lyricsLine2.animate().alpha(1f).translationY(0f).setDuration(300); + } + } + public interface Callbacks { void onColorChanged(int color); diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java index 3d002a18..ee1aa02f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java @@ -42,6 +42,7 @@ import com.kabouzeid.gramophone.dialogs.SongShareDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.menu.SongMenuHelper; import com.kabouzeid.gramophone.model.Song; +import com.kabouzeid.gramophone.model.lyrics.SynchronizedLyrics; import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity; import com.kabouzeid.gramophone.ui.fragments.player.AbsPlayerFragment; import com.kabouzeid.gramophone.ui.fragments.player.PlayerAlbumCoverFragment; @@ -309,6 +310,7 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum protected void onPreExecute() { super.onPreExecute(); lyricsInfo = null; + playerAlbumCoverFragment.setSynchronizedLyrics(null); toolbar.getMenu().removeItem(R.id.action_show_lyrics); } @@ -333,6 +335,7 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum } } else { lyricsInfo = new LyricsDialog.LyricInfo(song.title, lyrics); + playerAlbumCoverFragment.setSynchronizedLyrics(SynchronizedLyrics.parse(lyrics)); Activity activity = getActivity(); if (toolbar != null && activity != null) if (toolbar.getMenu().findItem(R.id.action_show_lyrics) == null) { diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java index 434849ba..c52c2dfd 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java @@ -40,6 +40,7 @@ import com.kabouzeid.gramophone.dialogs.SongShareDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.menu.SongMenuHelper; import com.kabouzeid.gramophone.model.Song; +import com.kabouzeid.gramophone.model.lyrics.SynchronizedLyrics; import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity; import com.kabouzeid.gramophone.ui.fragments.player.AbsPlayerFragment; import com.kabouzeid.gramophone.ui.fragments.player.PlayerAlbumCoverFragment; @@ -305,6 +306,7 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum protected void onPreExecute() { super.onPreExecute(); lyricsInfo = null; + playerAlbumCoverFragment.setSynchronizedLyrics(null); toolbar.getMenu().removeItem(R.id.action_show_lyrics); } @@ -329,6 +331,7 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum } } else { lyricsInfo = new LyricsDialog.LyricInfo(song.title, lyrics); + playerAlbumCoverFragment.setSynchronizedLyrics(SynchronizedLyrics.parse(lyrics)); Activity activity = getActivity(); if (toolbar != null && activity != null) if (toolbar.getMenu().findItem(R.id.action_show_lyrics) == null) { diff --git a/app/src/main/res/layout/fragment_player_album_cover.xml b/app/src/main/res/layout/fragment_player_album_cover.xml index 03c14fc4..a47b37d7 100644 --- a/app/src/main/res/layout/fragment_player_album_cover.xml +++ b/app/src/main/res/layout/fragment_player_album_cover.xml @@ -10,6 +10,41 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> + + + + + + + + Date: Mon, 12 Jun 2017 03:30:56 +0300 Subject: [PATCH 02/12] Add synchronized lyrics preference Fix animations --- .../helper/MusicProgressViewUpdateHelper.java | 14 +++++++++-- ...Lyrics.java => AbsSynchronizedLyrics.java} | 4 ++-- .../model/lyrics/SynchronizedLyricsLRC.java | 2 +- .../player/PlayerAlbumCoverFragment.java | 24 ++++++++++++------- .../player/card/CardPlayerFragment.java | 4 ++-- .../player/flat/FlatPlayerFragment.java | 4 ++-- .../gramophone/util/PreferenceUtil.java | 6 +++++ app/src/main/res/values-ru/strings.xml | 2 ++ app/src/main/res/values/strings.xml | 2 ++ .../main/res/xml/pref_now_playing_screen.xml | 6 +++++ 10 files changed, 50 insertions(+), 18 deletions(-) rename app/src/main/java/com/kabouzeid/gramophone/model/lyrics/{SynchronizedLyrics.java => AbsSynchronizedLyrics.java} (87%) diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicProgressViewUpdateHelper.java b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicProgressViewUpdateHelper.java index dfa801f9..4f912e89 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicProgressViewUpdateHelper.java +++ b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicProgressViewUpdateHelper.java @@ -15,6 +15,8 @@ public class MusicProgressViewUpdateHelper extends Handler { private static final int UPDATE_INTERVAL_PAUSED = 500; private Callback callback; + private int intervalPlaying; + private int intervalPaused; public void start() { queueNextRefresh(1); @@ -26,6 +28,14 @@ public class MusicProgressViewUpdateHelper extends Handler { public MusicProgressViewUpdateHelper(Callback callback) { this.callback = callback; + this.intervalPlaying = UPDATE_INTERVAL_PLAYING; + this.intervalPaused = UPDATE_INTERVAL_PAUSED; + } + + public MusicProgressViewUpdateHelper(Callback callback, int intervalPlaying, int intervalPaused) { + this.callback = callback; + this.intervalPlaying = intervalPlaying; + this.intervalPaused = intervalPaused; } @Override @@ -43,10 +53,10 @@ public class MusicProgressViewUpdateHelper extends Handler { callback.onUpdateProgressViews(progressMillis, totalMillis); if (!MusicPlayerRemote.isPlaying()) { - return UPDATE_INTERVAL_PAUSED; + return intervalPaused; } - final int remainingMillis = UPDATE_INTERVAL_PLAYING - progressMillis % UPDATE_INTERVAL_PLAYING; + final int remainingMillis = intervalPlaying - progressMillis % intervalPlaying; return Math.max(MIN_INTERVAL, remainingMillis); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java similarity index 87% rename from app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyrics.java rename to app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java index d0a6d748..d3052045 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java @@ -2,10 +2,10 @@ package com.kabouzeid.gramophone.model.lyrics; import android.util.SparseArray; -public abstract class SynchronizedLyrics { +public abstract class AbsSynchronizedLyrics { public final SparseArray lines = new SparseArray<>(); - public static SynchronizedLyrics parse(String data) + public static AbsSynchronizedLyrics parse(String data) { return new SynchronizedLyricsLRC(data); // no another formats at the moment } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java index b59ebb9b..e0b43eda 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java @@ -3,7 +3,7 @@ package com.kabouzeid.gramophone.model.lyrics; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class SynchronizedLyricsLRC extends SynchronizedLyrics { +public class SynchronizedLyricsLRC extends AbsSynchronizedLyrics { private static Pattern LRC_LINE_PATTERN = Pattern.compile("((?:\\[.*?\\])+)(.*)"); private static Pattern LRC_TIME_PATTERN = Pattern.compile("\\[(\\d\\d):(\\d\\d)(?:\\.(\\d\\d))\\]"); diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java index 388b5a83..8e5c957d 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java @@ -19,8 +19,9 @@ import com.kabouzeid.gramophone.adapter.AlbumCoverPagerAdapter; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.MusicProgressViewUpdateHelper; import com.kabouzeid.gramophone.misc.SimpleAnimatorListener; -import com.kabouzeid.gramophone.model.lyrics.SynchronizedLyrics; +import com.kabouzeid.gramophone.model.lyrics.AbsSynchronizedLyrics; import com.kabouzeid.gramophone.ui.fragments.AbsMusicServiceFragment; +import com.kabouzeid.gramophone.util.PreferenceUtil; import com.kabouzeid.gramophone.util.ViewUtil; import butterknife.BindView; @@ -50,7 +51,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements private Callbacks callbacks; private int currentPosition; - private SynchronizedLyrics synchronizedLyrics; + private AbsSynchronizedLyrics synchronizedLyrics; private MusicProgressViewUpdateHelper progressViewUpdateHelper; @Override @@ -82,7 +83,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements return gestureDetector.onTouchEvent(event); } }); - progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this); + progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this, 500, 1000); progressViewUpdateHelper.start(); } @@ -180,7 +181,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements .start(); } - public void setSynchronizedLyrics(SynchronizedLyrics sLyrics) + public void setSynchronizedLyrics(AbsSynchronizedLyrics sLyrics) { if(sLyrics == null || sLyrics.lines.size() == 0) { @@ -206,12 +207,15 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements @Override public void onUpdateProgressViews(int progress, int total) { - if(synchronizedLyrics == null || synchronizedLyrics.lines.size() == 0) { + if(synchronizedLyrics == null || synchronizedLyrics.lines.size() == 0 || !PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow()) { + lyrics.setVisibility(View.GONE); lyricsLine1.setText(null); lyricsLine2.setText(null); return; } + lyrics.setVisibility(View.VISIBLE); + String oldLine = lyricsLine2.getText().toString(); String line = synchronizedLyrics.getLine(progress); @@ -219,17 +223,19 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements { lyricsLine1.setText(oldLine); lyricsLine2.setText(line); + lyricsLine1.setVisibility(View.VISIBLE); lyricsLine2.setVisibility(View.VISIBLE); - int l1h = lyricsLine1.getMeasuredHeight(); - int l2h = lyricsLine2.getMeasuredHeight(); + + lyricsLine2.measure(View.MeasureSpec.makeMeasureSpec(lyricsLine2.getMeasuredWidth(), View.MeasureSpec.EXACTLY), View.MeasureSpec.UNSPECIFIED); + int h = lyricsLine2.getMeasuredHeight(); this.lyricsLine1.setAlpha(1f); this.lyricsLine1.setTranslationY(0f); - this.lyricsLine1.animate().alpha(0f).translationY(-l1h).setDuration(300); + this.lyricsLine1.animate().alpha(0f).translationY(-h).setDuration(300); this.lyricsLine2.setAlpha(0f); - this.lyricsLine2.setTranslationY(l2h); + this.lyricsLine2.setTranslationY(h); this.lyricsLine2.animate().alpha(1f).translationY(0f).setDuration(300); } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java index ee1aa02f..bb7c9b4e 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java @@ -42,7 +42,7 @@ import com.kabouzeid.gramophone.dialogs.SongShareDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.menu.SongMenuHelper; import com.kabouzeid.gramophone.model.Song; -import com.kabouzeid.gramophone.model.lyrics.SynchronizedLyrics; +import com.kabouzeid.gramophone.model.lyrics.AbsSynchronizedLyrics; import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity; import com.kabouzeid.gramophone.ui.fragments.player.AbsPlayerFragment; import com.kabouzeid.gramophone.ui.fragments.player.PlayerAlbumCoverFragment; @@ -335,7 +335,7 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum } } else { lyricsInfo = new LyricsDialog.LyricInfo(song.title, lyrics); - playerAlbumCoverFragment.setSynchronizedLyrics(SynchronizedLyrics.parse(lyrics)); + playerAlbumCoverFragment.setSynchronizedLyrics(AbsSynchronizedLyrics.parse(lyrics)); Activity activity = getActivity(); if (toolbar != null && activity != null) if (toolbar.getMenu().findItem(R.id.action_show_lyrics) == null) { diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java index c52c2dfd..af4a65b2 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java @@ -40,7 +40,7 @@ import com.kabouzeid.gramophone.dialogs.SongShareDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.menu.SongMenuHelper; import com.kabouzeid.gramophone.model.Song; -import com.kabouzeid.gramophone.model.lyrics.SynchronizedLyrics; +import com.kabouzeid.gramophone.model.lyrics.AbsSynchronizedLyrics; import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity; import com.kabouzeid.gramophone.ui.fragments.player.AbsPlayerFragment; import com.kabouzeid.gramophone.ui.fragments.player.PlayerAlbumCoverFragment; @@ -331,7 +331,7 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum } } else { lyricsInfo = new LyricsDialog.LyricInfo(song.title, lyrics); - playerAlbumCoverFragment.setSynchronizedLyrics(SynchronizedLyrics.parse(lyrics)); + playerAlbumCoverFragment.setSynchronizedLyrics(AbsSynchronizedLyrics.parse(lyrics)); Activity activity = getActivity(); if (toolbar != null && activity != null) if (toolbar.getMenu().findItem(R.id.action_show_lyrics) == null) { diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtil.java b/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtil.java index a893218c..565df23e 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtil.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtil.java @@ -69,6 +69,8 @@ public final class PreferenceUtil { public static final String START_DIRECTORY = "start_directory"; + public static final String SYNCHRONIZED_LYRICS_SHOW = "synchronized_lyrics_show"; + private static PreferenceUtil sInstance; private final SharedPreferences mPreferences; @@ -400,4 +402,8 @@ public final class PreferenceUtil { editor.putString(START_DIRECTORY, file.getPath()); editor.apply(); } + + public final boolean synchronizedLyricsShow() { + return mPreferences.getBoolean(SYNCHRONIZED_LYRICS_SHOW, true); + } } diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 2dee984d..cd4b66b1 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -135,6 +135,7 @@ Показывать подложку под кнопками Окрашенные кнопки управления воспроизведением Уменьшить громкость при уведомлених + Показывать синхронизированные тексты Эквалайзер не найден. "Сначала воспроизведите песню, а затем попробуйте снова." Удалить @@ -173,6 +174,7 @@ Окрашивает панель навигации в основной цвет. Окрашивает шорткаты в основной цвет. Уведомления, навигация, т.д. + Показывать синхронизированные тексты песен при их наличии "\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0443\u044e \u043e\u0431\u043b\u043e\u0436\u043a\u0443 \u0430\u043b\u044c\u0431\u043e\u043c\u0430." Поиск библиотеки... Повторное сканирование медиа... diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f50e1172..e03e2380 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -146,6 +146,7 @@ Colored playback controls Reduce volume on focus loss Last added playlist interval + Show synchronized lyrics No equalizer found. "Play a song first, then try again." Delete @@ -185,6 +186,7 @@ Colors the navigation bar in the primary color. Colors the app shortcuts in the primary color. Notifications, navigation etc. + Show synchronized lyrics for song if available "Couldn\u2019t download a matching album cover." Search your library… Rescanning media… diff --git a/app/src/main/res/xml/pref_now_playing_screen.xml b/app/src/main/res/xml/pref_now_playing_screen.xml index 33a1f66c..83f548a1 100644 --- a/app/src/main/res/xml/pref_now_playing_screen.xml +++ b/app/src/main/res/xml/pref_now_playing_screen.xml @@ -7,6 +7,12 @@ android:key="now_playing_screen_id" android:title="@string/pref_title_now_playing_screen_appearance" /> + + \ No newline at end of file From 1ee7d8c7b6d015ac7598ddf964b289848728f9bc Mon Sep 17 00:00:00 2001 From: tkashkin Date: Mon, 12 Jun 2017 04:59:07 +0300 Subject: [PATCH 03/12] Try to load lyrics from file if tag is empty --- .../player/card/CardPlayerFragment.java | 13 +---- .../player/flat/FlatPlayerFragment.java | 13 +---- .../kabouzeid/gramophone/util/FileUtil.java | 30 +++++++++++ .../kabouzeid/gramophone/util/MusicUtil.java | 54 +++++++++++++++++++ 4 files changed, 86 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java index bb7c9b4e..ae3a47db 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java @@ -52,11 +52,6 @@ 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.tag.FieldKey; - -import java.io.File; - import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; @@ -316,13 +311,7 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum @Override protected String doInBackground(Void... params) { - try { - return AudioFileIO.read(new File(song.data)).getTagOrCreateDefault().getFirst(FieldKey.LYRICS); - } catch (Exception e) { - e.printStackTrace(); - cancel(false); - return null; - } + return MusicUtil.getLyrics(song); } @Override diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java index af4a65b2..f07a8267 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java @@ -50,11 +50,6 @@ 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.tag.FieldKey; - -import java.io.File; - import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; @@ -312,13 +307,7 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum @Override protected String doInBackground(Void... params) { - try { - return AudioFileIO.read(new File(song.data)).getTagOrCreateDefault().getFirst(FieldKey.LYRICS); - } catch (Exception e) { - e.printStackTrace(); - cancel(false); - return null; - } + return MusicUtil.getLyrics(song); } @Override diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/FileUtil.java b/app/src/main/java/com/kabouzeid/gramophone/util/FileUtil.java index 7563f12c..df54e766 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/FileUtil.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/FileUtil.java @@ -11,9 +11,13 @@ import com.kabouzeid.gramophone.loader.SongLoader; import com.kabouzeid.gramophone.loader.SortedCursor; import com.kabouzeid.gramophone.model.Song; +import java.io.BufferedReader; import java.io.File; import java.io.FileFilter; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -160,4 +164,30 @@ public final class FileUtil { } return false; } + + public static String stripExtension(String str) { + if (str == null) return null; + int pos = str.lastIndexOf('.'); + if (pos == -1) return str; + return str.substring(0, pos); + } + + public static String readFromStream(InputStream is) throws Exception { + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + if (sb.length() > 0) sb.append("\n"); + sb.append(line); + } + reader.close(); + return sb.toString(); + } + + public static String read(File file) throws Exception { + FileInputStream fin = new FileInputStream(file); + String ret = readFromStream(fin); + fin.close(); + return ret; + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/MusicUtil.java b/app/src/main/java/com/kabouzeid/gramophone/util/MusicUtil.java index 8b11a85e..db71af1c 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/MusicUtil.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/MusicUtil.java @@ -25,9 +25,15 @@ import com.kabouzeid.gramophone.model.Artist; import com.kabouzeid.gramophone.model.Playlist; import com.kabouzeid.gramophone.model.Song; +import org.jaudiotagger.audio.AudioFileIO; +import org.jaudiotagger.tag.FieldKey; + import java.io.File; +import java.io.FileFilter; import java.io.IOException; +import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; /** * @author Karim Abou Zeid (kabouzeid) @@ -255,4 +261,52 @@ public class MusicUtil { if (musicMediaTitle.isEmpty()) return ""; return String.valueOf(musicMediaTitle.charAt(0)).toUpperCase(); } + + @Nullable + public static String getLyrics(Song song) { + String lyrics = null; + + File file = new File(song.data); + + try { + lyrics = AudioFileIO.read(file).getTagOrCreateDefault().getFirst(FieldKey.LYRICS); + } catch (Exception e) { + e.printStackTrace(); + } + + if (lyrics == null || lyrics.trim().isEmpty()) { + File dir = file.getAbsoluteFile().getParentFile(); + + if (dir != null && dir.exists() && dir.isDirectory()) { + final ArrayList patterns = new ArrayList<>(); + patterns.add(Pattern.compile(String.format(".*%s.*\\.(lrc|txt)", FileUtil.stripExtension(file.getName())), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE)); + patterns.add(Pattern.compile(String.format(".*%s.*\\.(lrc|txt)", song.title), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE)); + + File[] files = dir.listFiles(new FileFilter() { + @Override + public boolean accept(File f) { + for (Pattern pattern : patterns) { + if (pattern.matcher(f.getName()).matches()) return true; + } + return false; + } + }); + + if (files != null && files.length > 0) { + for (File f : files) { + try { + lyrics = FileUtil.read(f); + if (lyrics != null && !lyrics.trim().isEmpty()) { + return lyrics; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + } + + return lyrics; + } } From 21eb8e0127f8093915de569fb7a23d8dfc482aa4 Mon Sep 17 00:00:00 2001 From: tkashkin Date: Mon, 12 Jun 2017 06:17:37 +0300 Subject: [PATCH 04/12] Change string --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e03e2380..b4a69299 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -186,7 +186,7 @@ Colors the navigation bar in the primary color. Colors the app shortcuts in the primary color. Notifications, navigation etc. - Show synchronized lyrics for song if available + Show synchronized lyrics for a song if available "Couldn\u2019t download a matching album cover." Search your library… Rescanning media… From 1a7195093016b9a1cfe0cd8bb1c7e8611ff4883c Mon Sep 17 00:00:00 2001 From: tkashkin Date: Wed, 14 Jun 2017 18:49:11 +0300 Subject: [PATCH 05/12] Fix loading LRC files with regex control characters in name Fix non-standart LRC timestamps --- .../model/lyrics/AbsSynchronizedLyrics.java | 25 +++++++++++------- .../model/lyrics/SynchronizedLyricsLRC.java | 26 ++++++++++--------- .../kabouzeid/gramophone/util/MusicUtil.java | 20 +++++++++----- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java index d3052045..93daf296 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java @@ -4,25 +4,32 @@ import android.util.SparseArray; public abstract class AbsSynchronizedLyrics { public final SparseArray lines = new SparseArray<>(); + public boolean isValid = false; - public static AbsSynchronizedLyrics parse(String data) - { - return new SynchronizedLyricsLRC(data); // no another formats at the moment + public static AbsSynchronizedLyrics parse(String data, boolean justCheck) { + return new SynchronizedLyricsLRC(data, justCheck); // no another formats at the moment } - public String getLine(int time) - { + public static AbsSynchronizedLyrics parse(String data) { + return parse(data, false); + } + + public static boolean isSynchronized(String data) { + AbsSynchronizedLyrics lyrics = parse(data, true); + return lyrics.isValid; + } + + public String getLine(int time) { time += 500; // small time adjustment to display line before it actually starts int lastLineTime = lines.keyAt(0); - for(int i = 0; i < lines.size(); i++) { + for (int i = 0; i < lines.size(); i++) { int lineTime = lines.keyAt(i); - if(time >= lineTime) { + if (time >= lineTime) { lastLineTime = lineTime; - } - else { + } else { break; } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java index e0b43eda..92a979aa 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java @@ -5,38 +5,40 @@ import java.util.regex.Pattern; public class SynchronizedLyricsLRC extends AbsSynchronizedLyrics { private static Pattern LRC_LINE_PATTERN = Pattern.compile("((?:\\[.*?\\])+)(.*)"); - private static Pattern LRC_TIME_PATTERN = Pattern.compile("\\[(\\d\\d):(\\d\\d)(?:\\.(\\d\\d))\\]"); + private static Pattern LRC_TIME_PATTERN = Pattern.compile("\\[(\\d+):(\\d{2}(?:\\.\\d+)?)\\]"); - public SynchronizedLyricsLRC(String data) - { - if(data == null || data.isEmpty()) { + public SynchronizedLyricsLRC(String data, boolean justCheck) { + if (data == null || data.isEmpty()) { return; } String[] lines = data.split("\r?\n"); - for(String line : lines) { + for (String line : lines) { line = line.trim(); - if(line.isEmpty()) { + if (line.isEmpty()) { continue; } Matcher matcher = SynchronizedLyricsLRC.LRC_LINE_PATTERN.matcher(line); - if(matcher.find()) { + if (matcher.find()) { String time = matcher.group(1); String text = matcher.group(2); Matcher timeMatcher = SynchronizedLyricsLRC.LRC_TIME_PATTERN.matcher(time); - while(timeMatcher.find()) { - int m = 0, s = 0, x = 0; + while (timeMatcher.find()) { + int m = 0; + float s = 0f; try { m = Integer.parseInt(timeMatcher.group(1)); - s = Integer.parseInt(timeMatcher.group(2)); - x = Integer.parseInt(timeMatcher.group(3)); + s = Float.parseFloat(timeMatcher.group(2)); } catch (NumberFormatException ex) { ex.printStackTrace(); } - int ms = x*10 + s*1000 + m*60000; + int ms = (int) (s * 1000f) + m * 60000; + + this.isValid = true; + if (justCheck) return; this.lines.append(ms, text); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/MusicUtil.java b/app/src/main/java/com/kabouzeid/gramophone/util/MusicUtil.java index db71af1c..656d6873 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/MusicUtil.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/MusicUtil.java @@ -24,6 +24,7 @@ import com.kabouzeid.gramophone.loader.SongLoader; import com.kabouzeid.gramophone.model.Artist; import com.kabouzeid.gramophone.model.Playlist; import com.kabouzeid.gramophone.model.Song; +import com.kabouzeid.gramophone.model.lyrics.AbsSynchronizedLyrics; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; @@ -274,13 +275,17 @@ public class MusicUtil { e.printStackTrace(); } - if (lyrics == null || lyrics.trim().isEmpty()) { + if (lyrics == null || lyrics.trim().isEmpty() || !AbsSynchronizedLyrics.isSynchronized(lyrics)) { File dir = file.getAbsoluteFile().getParentFile(); if (dir != null && dir.exists() && dir.isDirectory()) { + String format = ".*%s.*\\.(lrc|txt)"; + String filename = Pattern.quote(FileUtil.stripExtension(file.getName())); + String songtitle = Pattern.quote(song.title); + final ArrayList patterns = new ArrayList<>(); - patterns.add(Pattern.compile(String.format(".*%s.*\\.(lrc|txt)", FileUtil.stripExtension(file.getName())), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE)); - patterns.add(Pattern.compile(String.format(".*%s.*\\.(lrc|txt)", song.title), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE)); + patterns.add(Pattern.compile(String.format(format, filename), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE)); + patterns.add(Pattern.compile(String.format(format, songtitle), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE)); File[] files = dir.listFiles(new FileFilter() { @Override @@ -295,9 +300,12 @@ public class MusicUtil { if (files != null && files.length > 0) { for (File f : files) { try { - lyrics = FileUtil.read(f); - if (lyrics != null && !lyrics.trim().isEmpty()) { - return lyrics; + String newLyrics = FileUtil.read(f); + if (newLyrics != null && !newLyrics.trim().isEmpty()) { + if (AbsSynchronizedLyrics.isSynchronized(newLyrics)) { + return newLyrics; + } + lyrics = newLyrics; } } catch (Exception e) { e.printStackTrace(); From 3122923d5f3ae5dffa628a16d033074f249a938d Mon Sep 17 00:00:00 2001 From: tkashkin Date: Sat, 8 Jul 2017 04:52:35 +0300 Subject: [PATCH 06/12] Add lyrics offset time support Some refactoring and formatting --- .../model/lyrics/AbsSynchronizedLyrics.java | 10 ++- .../model/lyrics/SynchronizedLyricsLRC.java | 64 +++++++++++++------ .../player/PlayerAlbumCoverFragment.java | 15 ++--- 3 files changed, 59 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java index 93daf296..e1c95bd4 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java @@ -3,9 +3,17 @@ package com.kabouzeid.gramophone.model.lyrics; import android.util.SparseArray; public abstract class AbsSynchronizedLyrics { + private static final int TIME_OFFSET_MS = 500; // time adjustment to display line before it actually starts + public final SparseArray lines = new SparseArray<>(); public boolean isValid = false; + public int offset = 0; + /** + * @param data Lyrics string + * @param justCheck Set isValid = true and stop parsing if lyrics appears to be valid + * and has at least 1 line + */ public static AbsSynchronizedLyrics parse(String data, boolean justCheck) { return new SynchronizedLyricsLRC(data, justCheck); // no another formats at the moment } @@ -20,7 +28,7 @@ public abstract class AbsSynchronizedLyrics { } public String getLine(int time) { - time += 500; // small time adjustment to display line before it actually starts + time += offset + AbsSynchronizedLyrics.TIME_OFFSET_MS; int lastLineTime = lines.keyAt(0); diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java index 92a979aa..8536cb53 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java @@ -4,9 +4,18 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class SynchronizedLyricsLRC extends AbsSynchronizedLyrics { - private static Pattern LRC_LINE_PATTERN = Pattern.compile("((?:\\[.*?\\])+)(.*)"); - private static Pattern LRC_TIME_PATTERN = Pattern.compile("\\[(\\d+):(\\d{2}(?:\\.\\d+)?)\\]"); + private static final Pattern LRC_LINE_PATTERN = Pattern.compile("((?:\\[.*?\\])+)(.*)"); + private static final Pattern LRC_TIME_PATTERN = Pattern.compile("\\[(\\d+):(\\d{2}(?:\\.\\d+)?)\\]"); + private static final Pattern LRC_ATTRIBUTE_PATTERN = Pattern.compile("\\[(\\D+):(.+)\\]"); + private static final float LRC_SECONDS_TO_MS_MULTIPLIER = 1000f; + private static final int LRC_MINUTES_TO_MS_MULTIPLIER = 60000; + + /** + * @param data Lyrics string + * @param justCheck Set isValid = true and stop parsing if lyrics appears to be valid + * and has at least 1 line + */ public SynchronizedLyricsLRC(String data, boolean justCheck) { if (data == null || data.isEmpty()) { return; @@ -20,27 +29,42 @@ public class SynchronizedLyricsLRC extends AbsSynchronizedLyrics { continue; } - Matcher matcher = SynchronizedLyricsLRC.LRC_LINE_PATTERN.matcher(line); - if (matcher.find()) { - String time = matcher.group(1); - String text = matcher.group(2); - - Matcher timeMatcher = SynchronizedLyricsLRC.LRC_TIME_PATTERN.matcher(time); - while (timeMatcher.find()) { - int m = 0; - float s = 0f; - try { - m = Integer.parseInt(timeMatcher.group(1)); - s = Float.parseFloat(timeMatcher.group(2)); - } catch (NumberFormatException ex) { - ex.printStackTrace(); + Matcher attrMatcher = SynchronizedLyricsLRC.LRC_ATTRIBUTE_PATTERN.matcher(line); + if (attrMatcher.find()) { + try { + String attr = attrMatcher.group(1).toLowerCase().trim(); + String value = attrMatcher.group(2).toLowerCase().trim(); + switch (attr) { + case "offset": + this.offset = Integer.parseInt(value); + break; } - int ms = (int) (s * 1000f) + m * 60000; + } catch (Exception ex) { + ex.printStackTrace(); + } + } else { + Matcher matcher = SynchronizedLyricsLRC.LRC_LINE_PATTERN.matcher(line); + if (matcher.find()) { + String time = matcher.group(1); + String text = matcher.group(2); - this.isValid = true; - if (justCheck) return; + Matcher timeMatcher = SynchronizedLyricsLRC.LRC_TIME_PATTERN.matcher(time); + while (timeMatcher.find()) { + int m = 0; + float s = 0f; + try { + m = Integer.parseInt(timeMatcher.group(1)); + s = Float.parseFloat(timeMatcher.group(2)); + } catch (NumberFormatException ex) { + ex.printStackTrace(); + } + int ms = (int) (s * LRC_SECONDS_TO_MS_MULTIPLIER) + m * LRC_MINUTES_TO_MS_MULTIPLIER; - this.lines.append(ms, text); + this.isValid = true; + if (justCheck) return; + + this.lines.append(ms, text); + } } } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java index 8e5c957d..816114d9 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java @@ -41,7 +41,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements @BindView(R.id.player_favorite_icon) ImageView favoriteIcon; - @BindView(R.id.player_lyrics) + @BindView(R.id.player_lyrics) FrameLayout lyrics; @BindView(R.id.player_lyrics_line1) TextView lyricsLine1; @@ -91,8 +91,8 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements public void onDestroyView() { super.onDestroyView(); viewPager.removeOnPageChangeListener(this); - unbinder.unbind(); progressViewUpdateHelper.stop(); + unbinder.unbind(); } @Override @@ -181,10 +181,8 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements .start(); } - public void setSynchronizedLyrics(AbsSynchronizedLyrics sLyrics) - { - if(sLyrics == null || sLyrics.lines.size() == 0) - { + public void setSynchronizedLyrics(AbsSynchronizedLyrics sLyrics) { + if (sLyrics == null || sLyrics.lines.size() == 0) { synchronizedLyrics = null; lyrics.setVisibility(View.GONE); lyricsLine1.setText(null); @@ -207,7 +205,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements @Override public void onUpdateProgressViews(int progress, int total) { - if(synchronizedLyrics == null || synchronizedLyrics.lines.size() == 0 || !PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow()) { + if (synchronizedLyrics == null || synchronizedLyrics.lines.size() == 0 || !PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow()) { lyrics.setVisibility(View.GONE); lyricsLine1.setText(null); lyricsLine2.setText(null); @@ -219,8 +217,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements String oldLine = lyricsLine2.getText().toString(); String line = synchronizedLyrics.getLine(progress); - if(!oldLine.equals(line) || oldLine.isEmpty()) - { + if (!oldLine.equals(line) || oldLine.isEmpty()) { lyricsLine1.setText(oldLine); lyricsLine2.setText(line); From c047ea96a79887b02c1b0b6063395ad6afc34b95 Mon Sep 17 00:00:00 2001 From: tkashkin Date: Sat, 8 Jul 2017 16:29:50 +0300 Subject: [PATCH 07/12] LyricsDialog displays lyrics without timestamps Refactoring --- .../gramophone/dialogs/LyricsDialog.java | 52 +++---------------- .../model/lyrics/AbsSynchronizedLyrics.java | 50 +++++++++++------- .../gramophone/model/lyrics/Lyrics.java | 49 +++++++++++++++++ .../model/lyrics/SynchronizedLyricsLRC.java | 31 ++++++----- .../player/PlayerAlbumCoverFragment.java | 26 ++++++---- .../player/card/CardPlayerFragment.java | 23 ++++---- .../player/flat/FlatPlayerFragment.java | 23 ++++---- 7 files changed, 142 insertions(+), 112 deletions(-) create mode 100644 app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/LyricsDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/LyricsDialog.java index 874d47e6..ed8cc2ce 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/LyricsDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/LyricsDialog.java @@ -2,22 +2,21 @@ 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 com.kabouzeid.gramophone.model.lyrics.Lyrics; /** * @author Karim Abou Zeid (kabouzeid) */ public class LyricsDialog extends DialogFragment { - - public static LyricsDialog create(@NonNull LyricInfo lyricInfo) { + public static LyricsDialog create(@NonNull Lyrics lyrics) { LyricsDialog dialog = new LyricsDialog(); Bundle args = new Bundle(); - args.putParcelable("LyricInfo", lyricInfo); + args.putString("title", lyrics.song.title); + args.putString("lyrics", lyrics.getText()); dialog.setArguments(args); return dialog; } @@ -25,49 +24,10 @@ public class LyricsDialog extends DialogFragment { @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) + .title(getArguments().getString("title")) + .content(getArguments().getString("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/model/lyrics/AbsSynchronizedLyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java index e1c95bd4..cb7e4478 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java @@ -2,29 +2,16 @@ package com.kabouzeid.gramophone.model.lyrics; import android.util.SparseArray; -public abstract class AbsSynchronizedLyrics { +import com.kabouzeid.gramophone.model.Song; + +public abstract class AbsSynchronizedLyrics extends Lyrics { private static final int TIME_OFFSET_MS = 500; // time adjustment to display line before it actually starts public final SparseArray lines = new SparseArray<>(); - public boolean isValid = false; public int offset = 0; - /** - * @param data Lyrics string - * @param justCheck Set isValid = true and stop parsing if lyrics appears to be valid - * and has at least 1 line - */ - public static AbsSynchronizedLyrics parse(String data, boolean justCheck) { - return new SynchronizedLyricsLRC(data, justCheck); // no another formats at the moment - } - - public static AbsSynchronizedLyrics parse(String data) { - return parse(data, false); - } - - public static boolean isSynchronized(String data) { - AbsSynchronizedLyrics lyrics = parse(data, true); - return lyrics.isValid; + AbsSynchronizedLyrics(Song song, String data) { + super(song, data); } public String getLine(int time) { @@ -44,4 +31,31 @@ public abstract class AbsSynchronizedLyrics { return lines.get(lastLineTime); } + + public boolean isSynchronized() { + return true; + } + + public boolean isValid() { + this.parse(true); + return this.valid; + } + + @Override + public String getText() { + if (isValid()) { + parse(false); + + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < lines.size(); i++) { + String line = lines.valueAt(i); + sb.append(line).append('\n'); + } + + return sb.toString(); + } + + return super.getText(); + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java new file mode 100644 index 00000000..8317ab48 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java @@ -0,0 +1,49 @@ +package com.kabouzeid.gramophone.model.lyrics; + +import com.kabouzeid.gramophone.model.Song; + +public class Lyrics { + public Song song; + public String data; + + boolean parsed = false; + boolean valid = false; + + public Lyrics(Song song, String data) { + this.song = song; + this.data = data; + } + + public static Lyrics parse(Song song, String data) { + Lyrics lyrics = new SynchronizedLyricsLRC(song, data); + if (lyrics.isValid()) { + return lyrics.parse(false); + } else { + return new Lyrics(song, data).parse(false); + } + } + + public static boolean isSynchronized(String data) { + Lyrics lyrics = new SynchronizedLyricsLRC(null, data); + return lyrics.isValid(); + } + + public Lyrics parse(boolean check) { + this.valid = true; + this.parsed = true; + return this; + } + + public boolean isSynchronized() { + return false; + } + + public boolean isValid() { + this.parse(true); + return this.valid; + } + + public String getText() { + return this.data; + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java index 8536cb53..49bdf54f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java @@ -1,9 +1,11 @@ package com.kabouzeid.gramophone.model.lyrics; +import com.kabouzeid.gramophone.model.Song; + import java.util.regex.Matcher; import java.util.regex.Pattern; -public class SynchronizedLyricsLRC extends AbsSynchronizedLyrics { +class SynchronizedLyricsLRC extends AbsSynchronizedLyrics { private static final Pattern LRC_LINE_PATTERN = Pattern.compile("((?:\\[.*?\\])+)(.*)"); private static final Pattern LRC_TIME_PATTERN = Pattern.compile("\\[(\\d+):(\\d{2}(?:\\.\\d+)?)\\]"); private static final Pattern LRC_ATTRIBUTE_PATTERN = Pattern.compile("\\[(\\D+):(.+)\\]"); @@ -11,17 +13,17 @@ public class SynchronizedLyricsLRC extends AbsSynchronizedLyrics { private static final float LRC_SECONDS_TO_MS_MULTIPLIER = 1000f; private static final int LRC_MINUTES_TO_MS_MULTIPLIER = 60000; - /** - * @param data Lyrics string - * @param justCheck Set isValid = true and stop parsing if lyrics appears to be valid - * and has at least 1 line - */ - public SynchronizedLyricsLRC(String data, boolean justCheck) { - if (data == null || data.isEmpty()) { - return; + SynchronizedLyricsLRC(Song song, String data) { + super(song, data); + } + + @Override + public SynchronizedLyricsLRC parse(boolean check) { + if (this.parsed || this.data == null || this.data.isEmpty()) { + return this; } - String[] lines = data.split("\r?\n"); + String[] lines = this.data.split("\r?\n"); for (String line : lines) { line = line.trim(); @@ -60,14 +62,17 @@ public class SynchronizedLyricsLRC extends AbsSynchronizedLyrics { } int ms = (int) (s * LRC_SECONDS_TO_MS_MULTIPLIER) + m * LRC_MINUTES_TO_MS_MULTIPLIER; - this.isValid = true; - if (justCheck) return; + this.valid = true; + if (check) return this; this.lines.append(ms, text); } } } } - } + this.parsed = true; + + return this; + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java index 816114d9..526c2f7f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java @@ -20,6 +20,7 @@ import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.MusicProgressViewUpdateHelper; import com.kabouzeid.gramophone.misc.SimpleAnimatorListener; import com.kabouzeid.gramophone.model.lyrics.AbsSynchronizedLyrics; +import com.kabouzeid.gramophone.model.lyrics.Lyrics; import com.kabouzeid.gramophone.ui.fragments.AbsMusicServiceFragment; import com.kabouzeid.gramophone.util.PreferenceUtil; import com.kabouzeid.gramophone.util.ViewUtil; @@ -42,7 +43,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements ImageView favoriteIcon; @BindView(R.id.player_lyrics) - FrameLayout lyrics; + FrameLayout lyricsLayout; @BindView(R.id.player_lyrics_line1) TextView lyricsLine1; @BindView(R.id.player_lyrics_line2) @@ -51,7 +52,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements private Callbacks callbacks; private int currentPosition; - private AbsSynchronizedLyrics synchronizedLyrics; + private Lyrics lyrics; private MusicProgressViewUpdateHelper progressViewUpdateHelper; @Override @@ -181,18 +182,18 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements .start(); } - public void setSynchronizedLyrics(AbsSynchronizedLyrics sLyrics) { - if (sLyrics == null || sLyrics.lines.size() == 0) { - synchronizedLyrics = null; - lyrics.setVisibility(View.GONE); + public void setLyrics(Lyrics l) { + if (l == null || !l.isSynchronized() || !l.isValid()) { + lyrics = null; + lyricsLayout.setVisibility(View.GONE); lyricsLine1.setText(null); lyricsLine2.setText(null); return; } - synchronizedLyrics = sLyrics; + lyrics = l; - lyrics.setVisibility(View.VISIBLE); + lyricsLayout.setVisibility(View.VISIBLE); } private void notifyColorChange(int color) { @@ -205,14 +206,17 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements @Override public void onUpdateProgressViews(int progress, int total) { - if (synchronizedLyrics == null || synchronizedLyrics.lines.size() == 0 || !PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow()) { - lyrics.setVisibility(View.GONE); + if (lyrics == null || !lyrics.isSynchronized() || !lyrics.isValid() || !PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow()) { + lyricsLayout.setVisibility(View.GONE); lyricsLine1.setText(null); lyricsLine2.setText(null); return; } - lyrics.setVisibility(View.VISIBLE); + if (!(lyrics instanceof AbsSynchronizedLyrics)) return; + AbsSynchronizedLyrics synchronizedLyrics = (AbsSynchronizedLyrics) lyrics; + + lyricsLayout.setVisibility(View.VISIBLE); String oldLine = lyricsLine2.getText().toString(); String line = synchronizedLyrics.getLine(progress); diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java index ae3a47db..651d77f8 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java @@ -42,7 +42,7 @@ import com.kabouzeid.gramophone.dialogs.SongShareDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.menu.SongMenuHelper; import com.kabouzeid.gramophone.model.Song; -import com.kabouzeid.gramophone.model.lyrics.AbsSynchronizedLyrics; +import com.kabouzeid.gramophone.model.lyrics.Lyrics; import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity; import com.kabouzeid.gramophone.ui.fragments.player.AbsPlayerFragment; import com.kabouzeid.gramophone.ui.fragments.player.PlayerAlbumCoverFragment; @@ -89,7 +89,7 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum private AsyncTask updateIsFavoriteTask; private AsyncTask updateLyricsAsyncTask; - private LyricsDialog.LyricInfo lyricsInfo; + private Lyrics lyrics; private Impl impl; @@ -236,8 +236,8 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.action_show_lyrics: - if (lyricsInfo != null) - LyricsDialog.create(lyricsInfo).show(getFragmentManager(), "LYRICS"); + if (lyrics != null) + LyricsDialog.create(lyrics).show(getFragmentManager(), "LYRICS"); return true; } return super.onMenuItemClick(item); @@ -304,8 +304,8 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum @Override protected void onPreExecute() { super.onPreExecute(); - lyricsInfo = null; - playerAlbumCoverFragment.setSynchronizedLyrics(null); + lyrics = null; + playerAlbumCoverFragment.setLyrics(null); toolbar.getMenu().removeItem(R.id.action_show_lyrics); } @@ -315,16 +315,15 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum } @Override - protected void onPostExecute(String lyrics) { - super.onPostExecute(lyrics); - if (TextUtils.isEmpty(lyrics)) { - lyricsInfo = null; + protected void onPostExecute(String data) { + if (TextUtils.isEmpty(data)) { + lyrics = null; if (toolbar != null) { toolbar.getMenu().removeItem(R.id.action_show_lyrics); } } else { - lyricsInfo = new LyricsDialog.LyricInfo(song.title, lyrics); - playerAlbumCoverFragment.setSynchronizedLyrics(AbsSynchronizedLyrics.parse(lyrics)); + lyrics = Lyrics.parse(song, data); + playerAlbumCoverFragment.setLyrics(lyrics); Activity activity = getActivity(); if (toolbar != null && activity != null) if (toolbar.getMenu().findItem(R.id.action_show_lyrics) == null) { diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java index f07a8267..337ca50f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java @@ -40,7 +40,7 @@ import com.kabouzeid.gramophone.dialogs.SongShareDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.menu.SongMenuHelper; import com.kabouzeid.gramophone.model.Song; -import com.kabouzeid.gramophone.model.lyrics.AbsSynchronizedLyrics; +import com.kabouzeid.gramophone.model.lyrics.Lyrics; import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity; import com.kabouzeid.gramophone.ui.fragments.player.AbsPlayerFragment; import com.kabouzeid.gramophone.ui.fragments.player.PlayerAlbumCoverFragment; @@ -86,7 +86,7 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum private AsyncTask updateIsFavoriteTask; private AsyncTask updateLyricsAsyncTask; - private LyricsDialog.LyricInfo lyricsInfo; + private Lyrics lyrics; private Impl impl; @@ -232,8 +232,8 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.action_show_lyrics: - if (lyricsInfo != null) - LyricsDialog.create(lyricsInfo).show(getFragmentManager(), "LYRICS"); + if (lyrics != null) + LyricsDialog.create(lyrics).show(getFragmentManager(), "LYRICS"); return true; } return super.onMenuItemClick(item); @@ -300,8 +300,8 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum @Override protected void onPreExecute() { super.onPreExecute(); - lyricsInfo = null; - playerAlbumCoverFragment.setSynchronizedLyrics(null); + lyrics = null; + playerAlbumCoverFragment.setLyrics(null); toolbar.getMenu().removeItem(R.id.action_show_lyrics); } @@ -311,16 +311,15 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum } @Override - protected void onPostExecute(String lyrics) { - super.onPostExecute(lyrics); - if (TextUtils.isEmpty(lyrics)) { - lyricsInfo = null; + protected void onPostExecute(String data) { + if (TextUtils.isEmpty(data)) { + lyrics = null; if (toolbar != null) { toolbar.getMenu().removeItem(R.id.action_show_lyrics); } } else { - lyricsInfo = new LyricsDialog.LyricInfo(song.title, lyrics); - playerAlbumCoverFragment.setSynchronizedLyrics(AbsSynchronizedLyrics.parse(lyrics)); + lyrics = Lyrics.parse(song, data); + playerAlbumCoverFragment.setLyrics(lyrics); Activity activity = getActivity(); if (toolbar != null && activity != null) if (toolbar.getMenu().findItem(R.id.action_show_lyrics) == null) { From 6086011d8db2ea0902773867c556fc8038b93bf4 Mon Sep 17 00:00:00 2001 From: tkashkin Date: Sat, 8 Jul 2017 18:38:29 +0300 Subject: [PATCH 08/12] Add lyrics format list --- .../model/lyrics/AbsSynchronizedLyrics.java | 6 ---- .../gramophone/model/lyrics/Lyrics.java | 35 ++++++++++++++----- .../model/lyrics/SynchronizedLyricsLRC.java | 6 ---- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java index cb7e4478..e3116bfa 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java @@ -2,18 +2,12 @@ package com.kabouzeid.gramophone.model.lyrics; import android.util.SparseArray; -import com.kabouzeid.gramophone.model.Song; - public abstract class AbsSynchronizedLyrics extends Lyrics { private static final int TIME_OFFSET_MS = 500; // time adjustment to display line before it actually starts public final SparseArray lines = new SparseArray<>(); public int offset = 0; - AbsSynchronizedLyrics(Song song, String data) { - super(song, data); - } - public String getLine(int time) { time += offset + AbsSynchronizedLyrics.TIME_OFFSET_MS; diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java index 8317ab48..82fb5855 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java @@ -2,30 +2,45 @@ package com.kabouzeid.gramophone.model.lyrics; import com.kabouzeid.gramophone.model.Song; +import java.util.ArrayList; + public class Lyrics { + private static final ArrayList> FORMATS = new ArrayList<>(); + public Song song; public String data; boolean parsed = false; boolean valid = false; - public Lyrics(Song song, String data) { + public Lyrics setData(Song song, String data) { this.song = song; this.data = data; + return this; } public static Lyrics parse(Song song, String data) { - Lyrics lyrics = new SynchronizedLyricsLRC(song, data); - if (lyrics.isValid()) { - return lyrics.parse(false); - } else { - return new Lyrics(song, data).parse(false); + for (Class format : Lyrics.FORMATS) { + try { + Lyrics lyrics = format.newInstance().setData(song, data); + if (lyrics.isValid()) return lyrics; + } catch (Exception e) { + e.printStackTrace(); + } } + return new Lyrics().setData(song, data); } public static boolean isSynchronized(String data) { - Lyrics lyrics = new SynchronizedLyricsLRC(null, data); - return lyrics.isValid(); + for (Class format : Lyrics.FORMATS) { + try { + Lyrics lyrics = format.newInstance().setData(null, data); + if (lyrics.isValid()) return true; + } catch (Exception e) { + e.printStackTrace(); + } + } + return false; } public Lyrics parse(boolean check) { @@ -46,4 +61,8 @@ public class Lyrics { public String getText() { return this.data; } + + static { + Lyrics.FORMATS.add(SynchronizedLyricsLRC.class); + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java index 49bdf54f..3d1e3632 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java @@ -1,7 +1,5 @@ package com.kabouzeid.gramophone.model.lyrics; -import com.kabouzeid.gramophone.model.Song; - import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -13,10 +11,6 @@ class SynchronizedLyricsLRC extends AbsSynchronizedLyrics { private static final float LRC_SECONDS_TO_MS_MULTIPLIER = 1000f; private static final int LRC_MINUTES_TO_MS_MULTIPLIER = 60000; - SynchronizedLyricsLRC(Song song, String data) { - super(song, data); - } - @Override public SynchronizedLyricsLRC parse(boolean check) { if (this.parsed || this.data == null || this.data.isEmpty()) { From ecdc9bb870914f9f940b6191913c188ee1269af7 Mon Sep 17 00:00:00 2001 From: tkashkin Date: Wed, 12 Jul 2017 11:18:53 +0300 Subject: [PATCH 09/12] Fix some UI bugs Add animations --- .../model/lyrics/AbsSynchronizedLyrics.java | 8 ++-- .../gramophone/model/lyrics/Lyrics.java | 4 +- .../player/PlayerAlbumCoverFragment.java | 48 ++++++++++++------- .../player/card/CardPlayerFragment.java | 21 ++++---- .../player/flat/FlatPlayerFragment.java | 21 ++++---- .../layout/fragment_player_album_cover.xml | 3 +- 6 files changed, 64 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java index e3116bfa..99a5328f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java @@ -31,15 +31,15 @@ public abstract class AbsSynchronizedLyrics extends Lyrics { } public boolean isValid() { - this.parse(true); - return this.valid; + parse(true); + return valid; } @Override public String getText() { - if (isValid()) { - parse(false); + parse(false); + if (valid) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < lines.size(); i++) { diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java index 82fb5855..1ed589b8 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java @@ -23,12 +23,12 @@ public class Lyrics { for (Class format : Lyrics.FORMATS) { try { Lyrics lyrics = format.newInstance().setData(song, data); - if (lyrics.isValid()) return lyrics; + if (lyrics.isValid()) return lyrics.parse(false); } catch (Exception e) { e.printStackTrace(); } } - return new Lyrics().setData(song, data); + return new Lyrics().setData(song, data).parse(false); } public static boolean isSynchronized(String data) { diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java index 526c2f7f..33bdc143 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java @@ -35,6 +35,8 @@ import butterknife.Unbinder; public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements ViewPager.OnPageChangeListener, MusicProgressViewUpdateHelper.Callback { public static final String TAG = PlayerAlbumCoverFragment.class.getSimpleName(); + public static final int LYRICS_ANIM_DURATION = 300; + private Unbinder unbinder; @BindView(R.id.player_album_cover_viewpager) @@ -183,17 +185,25 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements } public void setLyrics(Lyrics l) { - if (l == null || !l.isSynchronized() || !l.isValid()) { - lyrics = null; - lyricsLayout.setVisibility(View.GONE); - lyricsLine1.setText(null); - lyricsLine2.setText(null); + lyrics = l; + + if (!PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow() || l == null || !l.isSynchronized() || !l.isValid()) { + lyricsLayout.animate().alpha(0f).setDuration(PlayerAlbumCoverFragment.LYRICS_ANIM_DURATION).withEndAction(new Runnable() { + @Override + public void run() { + lyricsLayout.setVisibility(View.GONE); + lyricsLine1.setText(null); + lyricsLine2.setText(null); + } + }); return; } - lyrics = l; + lyricsLine1.setText(null); + lyricsLine2.setText(null); lyricsLayout.setVisibility(View.VISIBLE); + lyricsLayout.animate().alpha(1f).setDuration(PlayerAlbumCoverFragment.LYRICS_ANIM_DURATION); } private void notifyColorChange(int color) { @@ -206,10 +216,15 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements @Override public void onUpdateProgressViews(int progress, int total) { - if (lyrics == null || !lyrics.isSynchronized() || !lyrics.isValid() || !PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow()) { - lyricsLayout.setVisibility(View.GONE); - lyricsLine1.setText(null); - lyricsLine2.setText(null); + if (!PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow() || lyrics == null || !lyrics.isSynchronized() || !lyrics.isValid()) { + lyricsLayout.animate().alpha(0f).setDuration(PlayerAlbumCoverFragment.LYRICS_ANIM_DURATION).withEndAction(new Runnable() { + @Override + public void run() { + lyricsLayout.setVisibility(View.GONE); + lyricsLine1.setText(null); + lyricsLine2.setText(null); + } + }); return; } @@ -217,6 +232,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements AbsSynchronizedLyrics synchronizedLyrics = (AbsSynchronizedLyrics) lyrics; lyricsLayout.setVisibility(View.VISIBLE); + lyricsLayout.setAlpha(1f); String oldLine = lyricsLine2.getText().toString(); String line = synchronizedLyrics.getLine(progress); @@ -231,13 +247,13 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements lyricsLine2.measure(View.MeasureSpec.makeMeasureSpec(lyricsLine2.getMeasuredWidth(), View.MeasureSpec.EXACTLY), View.MeasureSpec.UNSPECIFIED); int h = lyricsLine2.getMeasuredHeight(); - this.lyricsLine1.setAlpha(1f); - this.lyricsLine1.setTranslationY(0f); - this.lyricsLine1.animate().alpha(0f).translationY(-h).setDuration(300); + lyricsLine1.setAlpha(1f); + lyricsLine1.setTranslationY(0f); + lyricsLine1.animate().alpha(0f).translationY(-h).setDuration(PlayerAlbumCoverFragment.LYRICS_ANIM_DURATION); - this.lyricsLine2.setAlpha(0f); - this.lyricsLine2.setTranslationY(h); - this.lyricsLine2.animate().alpha(1f).translationY(0f).setDuration(300); + lyricsLine2.setAlpha(0f); + lyricsLine2.setTranslationY(h); + lyricsLine2.animate().alpha(1f).translationY(0f).setDuration(PlayerAlbumCoverFragment.LYRICS_ANIM_DURATION); } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java index 651d77f8..c939bf1d 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/card/CardPlayerFragment.java @@ -300,7 +300,7 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum private void updateLyrics() { if (updateLyricsAsyncTask != null) updateLyricsAsyncTask.cancel(false); final Song song = MusicPlayerRemote.getCurrentSong(); - updateLyricsAsyncTask = new AsyncTask() { + updateLyricsAsyncTask = new AsyncTask() { @Override protected void onPreExecute() { super.onPreExecute(); @@ -310,20 +310,23 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum } @Override - protected String doInBackground(Void... params) { - return MusicUtil.getLyrics(song); + protected Lyrics doInBackground(Void... params) { + String data = MusicUtil.getLyrics(song); + if (TextUtils.isEmpty(data)) { + return null; + } + return Lyrics.parse(song, data); } @Override - protected void onPostExecute(String data) { - if (TextUtils.isEmpty(data)) { - lyrics = null; + protected void onPostExecute(Lyrics l) { + lyrics = l; + playerAlbumCoverFragment.setLyrics(lyrics); + if (lyrics == null) { if (toolbar != null) { toolbar.getMenu().removeItem(R.id.action_show_lyrics); } } else { - lyrics = Lyrics.parse(song, data); - playerAlbumCoverFragment.setLyrics(lyrics); Activity activity = getActivity(); if (toolbar != null && activity != null) if (toolbar.getMenu().findItem(R.id.action_show_lyrics) == null) { @@ -338,7 +341,7 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum } @Override - protected void onCancelled(String s) { + protected void onCancelled(Lyrics s) { onPostExecute(null); } }.execute(); diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java index 337ca50f..16adf455 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/flat/FlatPlayerFragment.java @@ -296,7 +296,7 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum private void updateLyrics() { if (updateLyricsAsyncTask != null) updateLyricsAsyncTask.cancel(false); final Song song = MusicPlayerRemote.getCurrentSong(); - updateLyricsAsyncTask = new AsyncTask() { + updateLyricsAsyncTask = new AsyncTask() { @Override protected void onPreExecute() { super.onPreExecute(); @@ -306,20 +306,23 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum } @Override - protected String doInBackground(Void... params) { - return MusicUtil.getLyrics(song); + protected Lyrics doInBackground(Void... params) { + String data = MusicUtil.getLyrics(song); + if (TextUtils.isEmpty(data)) { + return null; + } + return Lyrics.parse(song, data); } @Override - protected void onPostExecute(String data) { - if (TextUtils.isEmpty(data)) { - lyrics = null; + protected void onPostExecute(Lyrics l) { + lyrics = l; + playerAlbumCoverFragment.setLyrics(lyrics); + if (lyrics == null) { if (toolbar != null) { toolbar.getMenu().removeItem(R.id.action_show_lyrics); } } else { - lyrics = Lyrics.parse(song, data); - playerAlbumCoverFragment.setLyrics(lyrics); Activity activity = getActivity(); if (toolbar != null && activity != null) if (toolbar.getMenu().findItem(R.id.action_show_lyrics) == null) { @@ -334,7 +337,7 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum } @Override - protected void onCancelled(String s) { + protected void onCancelled(Lyrics s) { onPostExecute(null); } }.execute(); diff --git a/app/src/main/res/layout/fragment_player_album_cover.xml b/app/src/main/res/layout/fragment_player_album_cover.xml index a47b37d7..17e13007 100644 --- a/app/src/main/res/layout/fragment_player_album_cover.xml +++ b/app/src/main/res/layout/fragment_player_album_cover.xml @@ -18,7 +18,8 @@ android:background="@drawable/shadow_up" android:padding="16dp" android:clipToPadding="false" - android:visibility="gone"> + android:visibility="gone" + android:alpha="0"> Date: Fri, 14 Jul 2017 01:07:08 +0300 Subject: [PATCH 10/12] Fix crash on screen rotation change --- .../ui/fragments/player/PlayerAlbumCoverFragment.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java index 33bdc143..4eff07cf 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java @@ -187,10 +187,13 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements public void setLyrics(Lyrics l) { lyrics = l; + if (lyricsLayout == null || lyricsLine1 == null || lyricsLine2 == null) return; + if (!PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow() || l == null || !l.isSynchronized() || !l.isValid()) { lyricsLayout.animate().alpha(0f).setDuration(PlayerAlbumCoverFragment.LYRICS_ANIM_DURATION).withEndAction(new Runnable() { @Override public void run() { + if (lyricsLayout == null || lyricsLine1 == null || lyricsLine2 == null) return; lyricsLayout.setVisibility(View.GONE); lyricsLine1.setText(null); lyricsLine2.setText(null); @@ -216,10 +219,13 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements @Override public void onUpdateProgressViews(int progress, int total) { + if (lyricsLayout == null || lyricsLine1 == null || lyricsLine2 == null) return; + if (!PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow() || lyrics == null || !lyrics.isSynchronized() || !lyrics.isValid()) { lyricsLayout.animate().alpha(0f).setDuration(PlayerAlbumCoverFragment.LYRICS_ANIM_DURATION).withEndAction(new Runnable() { @Override public void run() { + if (lyricsLayout == null || lyricsLine1 == null || lyricsLine2 == null) return; lyricsLayout.setVisibility(View.GONE); lyricsLine1.setText(null); lyricsLine2.setText(null); From aabd0367b9a45f8bba939cf9dc81d4b9a18a080c Mon Sep 17 00:00:00 2001 From: tkashkin Date: Fri, 14 Jul 2017 14:05:21 +0300 Subject: [PATCH 11/12] Trim newlines at start/end of lyrics Collapse more than one empty lines into one --- .../gramophone/model/lyrics/AbsSynchronizedLyrics.java | 4 ++-- .../java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java index 99a5328f..b41d6daa 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java @@ -44,10 +44,10 @@ public abstract class AbsSynchronizedLyrics extends Lyrics { for (int i = 0; i < lines.size(); i++) { String line = lines.valueAt(i); - sb.append(line).append('\n'); + sb.append(line).append("\r\n"); } - return sb.toString(); + return sb.toString().trim().replaceAll("(\r?\n){3,}", "\r\n\r\n"); } return super.getText(); diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java index 1ed589b8..734e9015 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java @@ -59,7 +59,7 @@ public class Lyrics { } public String getText() { - return this.data; + return this.data.trim().replaceAll("(\r?\n){3,}", "\r\n\r\n"); } static { From 8a57d32214ceec56da76c2a8c5b5bbf3caeca109 Mon Sep 17 00:00:00 2001 From: tkashkin Date: Fri, 14 Jul 2017 21:22:54 +0300 Subject: [PATCH 12/12] Refactoring --- .../model/lyrics/AbsSynchronizedLyrics.java | 4 +- .../gramophone/model/lyrics/Lyrics.java | 4 +- .../player/PlayerAlbumCoverFragment.java | 48 ++++++++++--------- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java index b41d6daa..6ae8de9a 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java @@ -5,8 +5,8 @@ import android.util.SparseArray; public abstract class AbsSynchronizedLyrics extends Lyrics { private static final int TIME_OFFSET_MS = 500; // time adjustment to display line before it actually starts - public final SparseArray lines = new SparseArray<>(); - public int offset = 0; + protected final SparseArray lines = new SparseArray<>(); + protected int offset = 0; public String getLine(int time) { time += offset + AbsSynchronizedLyrics.TIME_OFFSET_MS; diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java index 734e9015..fb38ca25 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/Lyrics.java @@ -10,8 +10,8 @@ public class Lyrics { public Song song; public String data; - boolean parsed = false; - boolean valid = false; + protected boolean parsed = false; + protected boolean valid = false; public Lyrics setData(Song song, String data) { this.song = song; diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java index 4eff07cf..60cf18e3 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java @@ -184,21 +184,33 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements .start(); } + private boolean isLyricsLayoutVisible() { + return lyrics != null && lyrics.isSynchronized() && lyrics.isValid() && PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow(); + } + + private boolean isLyricsLayoutBound() { + return lyricsLayout != null && lyricsLine1 != null && lyricsLine2 != null; + } + + private void hideLyricsLayout() { + lyricsLayout.animate().alpha(0f).setDuration(PlayerAlbumCoverFragment.LYRICS_ANIM_DURATION).withEndAction(new Runnable() { + @Override + public void run() { + if (!isLyricsLayoutBound()) return; + lyricsLayout.setVisibility(View.GONE); + lyricsLine1.setText(null); + lyricsLine2.setText(null); + } + }); + } + public void setLyrics(Lyrics l) { lyrics = l; - if (lyricsLayout == null || lyricsLine1 == null || lyricsLine2 == null) return; + if (!isLyricsLayoutBound()) return; - if (!PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow() || l == null || !l.isSynchronized() || !l.isValid()) { - lyricsLayout.animate().alpha(0f).setDuration(PlayerAlbumCoverFragment.LYRICS_ANIM_DURATION).withEndAction(new Runnable() { - @Override - public void run() { - if (lyricsLayout == null || lyricsLine1 == null || lyricsLine2 == null) return; - lyricsLayout.setVisibility(View.GONE); - lyricsLine1.setText(null); - lyricsLine2.setText(null); - } - }); + if (!isLyricsLayoutVisible()) { + hideLyricsLayout(); return; } @@ -219,18 +231,10 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements @Override public void onUpdateProgressViews(int progress, int total) { - if (lyricsLayout == null || lyricsLine1 == null || lyricsLine2 == null) return; + if (!isLyricsLayoutBound()) return; - if (!PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow() || lyrics == null || !lyrics.isSynchronized() || !lyrics.isValid()) { - lyricsLayout.animate().alpha(0f).setDuration(PlayerAlbumCoverFragment.LYRICS_ANIM_DURATION).withEndAction(new Runnable() { - @Override - public void run() { - if (lyricsLayout == null || lyricsLine1 == null || lyricsLine2 == null) return; - lyricsLayout.setVisibility(View.GONE); - lyricsLine1.setText(null); - lyricsLine2.setText(null); - } - }); + if (!isLyricsLayoutVisible()) { + hideLyricsLayout(); return; }