diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/other/CoverLyricsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/other/CoverLyricsFragment.kt
new file mode 100644
index 000000000..c7aabefd1
--- /dev/null
+++ b/app/src/main/java/code/name/monkey/retromusic/fragments/other/CoverLyricsFragment.kt
@@ -0,0 +1,174 @@
+package code.name.monkey.retromusic.fragments.other
+
+import android.content.SharedPreferences
+import android.os.Bundle
+import android.text.TextUtils
+import android.view.View
+import android.widget.FrameLayout
+import android.widget.TextView
+import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
+import androidx.preference.PreferenceManager
+import code.name.monkey.retromusic.R
+import code.name.monkey.retromusic.SHOW_LYRICS
+import code.name.monkey.retromusic.databinding.FragmentCoverLyricsBinding
+import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
+import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
+import code.name.monkey.retromusic.helper.MusicPlayerRemote
+import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
+import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics
+import code.name.monkey.retromusic.model.lyrics.Lyrics
+import code.name.monkey.retromusic.util.LyricUtil
+import code.name.monkey.retromusic.util.PreferenceUtil
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import org.jaudiotagger.audio.exceptions.CannotReadException
+import java.io.File
+import java.io.FileNotFoundException
+
+class CoverLyricsFragment : AbsMusicServiceFragment(R.layout.fragment_cover_lyrics),
+ MusicProgressViewUpdateHelper.Callback, SharedPreferences.OnSharedPreferenceChangeListener {
+ private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null
+ private var _binding: FragmentCoverLyricsBinding? = null
+ private val binding get() = _binding!!
+
+ private val lyricsLayout: FrameLayout get() = binding.playerLyrics
+ private val lyricsLine1: TextView get() = binding.playerLyricsLine1
+ private val lyricsLine2: TextView get() = binding.playerLyricsLine2
+
+ private var lyrics: Lyrics? = null
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ _binding = FragmentCoverLyricsBinding.bind(view)
+ progressViewUpdateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
+ if (PreferenceUtil.showLyrics) {
+ progressViewUpdateHelper?.start()
+ }
+ }
+
+ override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
+ if (key == SHOW_LYRICS) {
+ if (sharedPreferences?.getBoolean(key, false) == true) {
+ progressViewUpdateHelper?.start()
+ binding.root.isVisible = true
+ updateLyrics()
+ } else {
+ progressViewUpdateHelper?.stop()
+ binding.root.isVisible = false
+ }
+ }
+ }
+
+ override fun onPlayingMetaChanged() {
+ super.onPlayingMetaChanged()
+ if (PreferenceUtil.showLyrics) {
+ updateLyrics()
+ }
+ }
+
+ override fun onServiceConnected() {
+ super.onServiceConnected()
+ if (PreferenceUtil.showLyrics) {
+ updateLyrics()
+ }
+ }
+
+ private fun updateLyrics() {
+ lyrics = null
+ lifecycleScope.launch(Dispatchers.IO) {
+ val song = MusicPlayerRemote.currentSong
+ lyrics = try {
+ val lrcFile: File? = LyricUtil.getSyncedLyricsFile(song)
+ val data: String = LyricUtil.getStringFromLrc(lrcFile)
+ Lyrics.parse(song,
+ if (!TextUtils.isEmpty(data)) {
+ data
+ } else {
+ // Get Embedded Lyrics
+ LyricUtil.getEmbeddedSyncedLyrics(song.data)
+ }
+ )
+ } catch (err: FileNotFoundException) {
+ null
+ } catch (e: CannotReadException) {
+ null
+ }
+ }
+
+
+ }
+
+ override fun onUpdateProgressViews(progress: Int, total: Int) {
+ if (_binding == null) return
+
+ if (!isLyricsLayoutVisible()) {
+ hideLyricsLayout()
+ return
+ }
+
+ if (lyrics !is AbsSynchronizedLyrics) return
+ val synchronizedLyrics = lyrics as AbsSynchronizedLyrics
+
+ lyricsLayout.visibility = View.VISIBLE
+ lyricsLayout.alpha = 1f
+
+ val oldLine = lyricsLine2.text.toString()
+ val line = synchronizedLyrics.getLine(progress)
+
+ if (oldLine != line || oldLine.isEmpty()) {
+ lyricsLine1.text = oldLine
+ lyricsLine2.text = line
+
+ lyricsLine1.isVisible = true
+ lyricsLine2.isVisible = true
+
+ lyricsLine2.measure(
+ View.MeasureSpec.makeMeasureSpec(
+ lyricsLine2.measuredWidth,
+ View.MeasureSpec.EXACTLY
+ ),
+ View.MeasureSpec.UNSPECIFIED
+ )
+ val h: Float = lyricsLine2.measuredHeight.toFloat()
+
+ lyricsLine1.alpha = 1f
+ lyricsLine1.translationY = 0f
+ lyricsLine1.animate().alpha(0f).translationY(-h).duration =
+ AbsPlayerFragment.VISIBILITY_ANIM_DURATION
+
+ lyricsLine2.alpha = 0f
+ lyricsLine2.translationY = h
+ lyricsLine2.animate().alpha(1f).translationY(0f).duration =
+ AbsPlayerFragment.VISIBILITY_ANIM_DURATION
+ }
+ }
+
+ private fun isLyricsLayoutVisible(): Boolean {
+ return lyrics != null && lyrics!!.isSynchronized && lyrics!!.isValid
+ }
+
+ private fun hideLyricsLayout() {
+ lyricsLayout.animate().alpha(0f).setDuration(AbsPlayerFragment.VISIBILITY_ANIM_DURATION)
+ .withEndAction {
+ if (_binding == null) return@withEndAction
+ lyricsLayout.isVisible = false
+ lyricsLine1.text = null
+ lyricsLine2.text = null
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ PreferenceManager.getDefaultSharedPreferences(requireContext())
+ .registerOnSharedPreferenceChangeListener(this)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ PreferenceManager.getDefaultSharedPreferences(requireContext())
+ .unregisterOnSharedPreferenceChangeListener(this)
+ progressViewUpdateHelper?.stop()
+ _binding = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_adaptive_player.xml b/app/src/main/res/layout/fragment_adaptive_player.xml
index 4f71baf8a..5975ae228 100644
--- a/app/src/main/res/layout/fragment_adaptive_player.xml
+++ b/app/src/main/res/layout/fragment_adaptive_player.xml
@@ -57,6 +57,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="@layout/fragment_album_full_card_cover" />
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_card_blur_player.xml b/app/src/main/res/layout/fragment_card_blur_player.xml
index 13b743113..ffc79346c 100644
--- a/app/src/main/res/layout/fragment_card_blur_player.xml
+++ b/app/src/main/res/layout/fragment_card_blur_player.xml
@@ -73,6 +73,14 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:layout="@layout/fragment_album_card_cover" />
+
+
diff --git a/app/src/main/res/layout/fragment_card_player.xml b/app/src/main/res/layout/fragment_card_player.xml
index 8318ede85..b67ed8db6 100644
--- a/app/src/main/res/layout/fragment_card_player.xml
+++ b/app/src/main/res/layout/fragment_card_player.xml
@@ -19,6 +19,13 @@
android:layout_height="match_parent"
tools:layout="@layout/fragment_album_full_cover" />
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_fit.xml b/app/src/main/res/layout/fragment_fit.xml
index b9b42ea01..6d540aef9 100644
--- a/app/src/main/res/layout/fragment_fit.xml
+++ b/app/src/main/res/layout/fragment_fit.xml
@@ -30,6 +30,15 @@
tools:layout="@layout/fragment_album_full_cover" />
+
+
+
-
-
-
-
-
-
-
+ android:elevation="20dp"
+ app:layout_constraintTop_toBottomOf="@id/playerToolbar"/>
diff --git a/app/src/main/res/layout/fragment_gradient_player.xml b/app/src/main/res/layout/fragment_gradient_player.xml
index e9aad0649..0f00d905d 100644
--- a/app/src/main/res/layout/fragment_gradient_player.xml
+++ b/app/src/main/res/layout/fragment_gradient_player.xml
@@ -58,6 +58,17 @@
layout="@layout/status_bar" />
+
+