diff --git a/README.md b/README.md
index 09c5c3003..a3eb39698 100644
--- a/README.md
+++ b/README.md
@@ -46,6 +46,7 @@ Changelog is available [here](https://github.com/naman14/Timber/blob/master/Chan
* CyanogenMod's [Eleven Music Player](https://github.com/CyanogenMod/android_packages_apps_Eleven)
* [TimelyTextView](https://github.com/adnan-SM/TimelyTextView)
+* [LrcView](https://github.com/wangchenyan/lrcview)
* [MultiViewPager](https://github.com/Pixplicity/MultiViewPager)
* [PlayPauseButton](https://github.com/recruit-lifestyle/PlayPauseButton)
* [CircularSeekBar](https://github.com/devadvance/circularseekbar)
diff --git a/app/build.gradle b/app/build.gradle
index 1de8c5417..4f4d1b316 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -34,6 +34,10 @@ android {
disable 'MissingTranslation'
disable 'ExtraTranslation'
}
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
}
@@ -61,6 +65,7 @@ dependencies {
implementation 'com.squareup.okhttp:okhttp:2.3.0'
implementation 'com.google.code.gson:gson:2.3'
implementation 'de.Maxr1998:track-selector-lib:1.2'
+ implementation 'me.wcy:lrcview:2.2'
implementation 'com.afollestad.material-dialogs:core:0.9.0.2'
implementation 'com.afollestad.material-dialogs:commons:0.9.0.2'
diff --git a/app/src/main/java/com/naman14/timber/subfragments/LyricsFragment.java b/app/src/main/java/com/naman14/timber/subfragments/LyricsFragment.java
index 69d1decb9..d953ab55f 100644
--- a/app/src/main/java/com/naman14/timber/subfragments/LyricsFragment.java
+++ b/app/src/main/java/com/naman14/timber/subfragments/LyricsFragment.java
@@ -26,6 +26,7 @@
import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;
+import me.wcy.lrcview.LrcView;
/**
* Created by christoph on 10.12.16.
@@ -36,6 +37,10 @@ public class LyricsFragment extends Fragment {
private String lyrics = null;
private Toolbar toolbar;
private View rootView;
+ private String syncLyrics = null;
+ private LrcView syncLyricsView;
+ private ActionBar actionBar;
+ private long audioId = Long.MIN_VALUE;
@Nullable
@Override
@@ -43,6 +48,8 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
rootView = inflater.inflate(R.layout.fragment_lyrics,container,false);
toolbar = (Toolbar) rootView.findViewById(R.id.toolbar);
+ syncLyricsView = (LrcView) rootView.findViewById(R.id.sync_lyrics);
+
setupToolbar();
loadLyrics();
@@ -50,21 +57,68 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
return rootView;
}
+ Runnable mUpdateProgress = new Runnable() {
+
+ @Override
+ public void run() {
+
+ long position = MusicPlayer.position();
+ if (LyricsFragment.this.isResumed()) {
+ long newAudioId = MusicPlayer.getCurrentAudioId();
+ if (newAudioId != audioId) {
+ loadLyrics();
+ }
+ if (syncLyricsView.getVisibility() == View.VISIBLE) {
+ syncLyricsView.updateTime(position);
+ }
+ syncLyricsView.postDelayed(mUpdateProgress, 50);
+ }
+ }
+ };
+
private void loadLyrics() {
final View lyricsView = rootView.findViewById(R.id.lyrics);
final TextView poweredbyTextView = (TextView) lyricsView.findViewById(R.id.lyrics_makeitpersonal);
+ final LrcView syncLyricsView = (LrcView) rootView.findViewById(R.id.sync_lyrics);
poweredbyTextView.setVisibility(View.GONE);
final TextView lyricsTextView = (TextView) lyricsView.findViewById(R.id.lyrics_text);
lyricsTextView.setText(getString(R.string.lyrics_loading));
+
+ if (MusicPlayer.getTrackName() != null) {
+ actionBar.setTitle(MusicPlayer.getTrackName());
+ } else {
+ actionBar.setTitle(getString(R.string.app_name));
+ }
+ long newAudioId = MusicPlayer.getCurrentAudioId();
+ if (newAudioId != audioId) {
+ audioId = newAudioId;
+ lyrics = null;
+ syncLyrics = null;
+ }
String filename = getRealPathFromURI(Uri.parse(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + MusicPlayer.getCurrentAudioId()));
- if (filename != null && lyrics == null) {
- lyrics = LyricsExtractor.getLyrics(new File(filename));
+ if (filename != null && lyrics == null && syncLyrics == null) {
+ File mediaFile = new File(filename);
+ syncLyrics = LyricsExtractor.getSynchronizedLyrics(mediaFile);
+ if (syncLyrics == null) {
+ lyrics = LyricsExtractor.getLyrics(mediaFile);
+ }
}
- if (lyrics != null) {
+ if (syncLyrics != null) {
+ syncLyricsView.setVisibility(View.VISIBLE);
+ lyricsView.setVisibility(View.GONE);
+
+ syncLyricsView.loadLrc(syncLyrics);
+ } else if (lyrics != null) {
+ syncLyricsView.setVisibility(View.GONE);
+ lyricsView.setVisibility(View.VISIBLE);
+
lyricsTextView.setText(lyrics);
} else {
+ syncLyricsView.setVisibility(View.GONE);
+ lyricsView.setVisibility(View.VISIBLE);
+
String artist = MusicPlayer.getArtistName();
if (artist != null) {
int i = artist.lastIndexOf(" feat");
@@ -100,17 +154,15 @@ private void setupToolbar() {
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
- final ActionBar ab = ((AppCompatActivity) getActivity()).getSupportActionBar();
- ab.setDisplayHomeAsUpEnabled(true);
- if (MusicPlayer.getTrackName() != null) {
- ab.setTitle(MusicPlayer.getTrackName());
- }
+ actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+ actionBar.setDisplayHomeAsUpEnabled(true);
}
@Override
public void onResume() {
super.onResume();
toolbar.setBackgroundColor(Color.TRANSPARENT);
+ syncLyricsView.post(mUpdateProgress);
}
private String getRealPathFromURI(Uri contentUri) {
diff --git a/app/src/main/java/com/naman14/timber/utils/FileUtils.java b/app/src/main/java/com/naman14/timber/utils/FileUtils.java
new file mode 100644
index 000000000..efa79c133
--- /dev/null
+++ b/app/src/main/java/com/naman14/timber/utils/FileUtils.java
@@ -0,0 +1,14 @@
+package com.naman14.timber.utils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.util.stream.Collectors;
+
+public class FileUtils {
+ public static String readAllText(File file) throws FileNotFoundException {
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ return reader.lines().collect(Collectors.joining(System.lineSeparator()));
+ }
+}
diff --git a/app/src/main/java/com/naman14/timber/utils/LyricsExtractor.java b/app/src/main/java/com/naman14/timber/utils/LyricsExtractor.java
index 151bac513..c9992eefa 100644
--- a/app/src/main/java/com/naman14/timber/utils/LyricsExtractor.java
+++ b/app/src/main/java/com/naman14/timber/utils/LyricsExtractor.java
@@ -2,6 +2,7 @@
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
@@ -31,6 +32,20 @@ public static String getLyrics(File file){
return null;
}
+ public static String getSynchronizedLyrics(File file) {
+ String directory = file.getParent();
+ String lrcName = changeOrAppendExtension(file.getName(), ".lrc");
+ File lrcFile = new File(directory, lrcName);
+ if (!lrcFile.exists()) {
+ return null;
+ }
+ try {
+ return FileUtils.readAllText(lrcFile);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ }
+
private static int readOgg(byte[] buf, InputStream in, int bytesinpage, int skip) throws IOException {
int toread = skip!=-1?skip:buf.length;
int offset = 0;
@@ -224,4 +239,11 @@ private static int byteArrayToIntLE(byte[] b) {
return b[0] & 0xFF | (b[1] & 0xFF) << 8 | (b[2] & 0xFF) << 16 | (b[3] & 0xFF) << 24;
}
+ private static String changeOrAppendExtension(String filename, String newExtension) {
+ if (filename.lastIndexOf('.') != -1) {
+ filename = filename.substring(0, filename.lastIndexOf('.'));
+ }
+ return filename + newExtension;
+ }
+
}
diff --git a/app/src/main/res/layout/fragment_lyrics.xml b/app/src/main/res/layout/fragment_lyrics.xml
index 4c35f2988..7d6c76428 100644
--- a/app/src/main/res/layout/fragment_lyrics.xml
+++ b/app/src/main/res/layout/fragment_lyrics.xml
@@ -15,6 +15,13 @@
android:theme="@style/Theme.AppCompat"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
+
+