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" /> + +