diff --git a/app/src/main/java/code/name/monkey/retromusic/lyrics/CoverLrcView.kt b/app/src/main/java/code/name/monkey/retromusic/lyrics/CoverLrcView.kt index c74c5bbdc..d772a1eb6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/lyrics/CoverLrcView.kt +++ b/app/src/main/java/code/name/monkey/retromusic/lyrics/CoverLrcView.kt @@ -19,7 +19,6 @@ import android.content.Context import android.graphics.Canvas import android.graphics.Paint import android.graphics.drawable.Drawable -import android.os.AsyncTask import android.os.Looper import android.text.Layout import android.text.StaticLayout @@ -35,14 +34,15 @@ import android.widget.Scroller import androidx.core.content.ContextCompat import androidx.core.graphics.withSave import code.name.monkey.retromusic.R +import kotlinx.coroutines.* import java.io.File +import java.lang.Runnable import kotlin.math.abs /** * 歌词 Created by wcy on 2015/11/9. */ @SuppressLint("StaticFieldLeak") -@Suppress("deprecation") class CoverLrcView @JvmOverloads constructor( context: Context?, attrs: AttributeSet? = null, @@ -72,7 +72,6 @@ class CoverLrcView @JvmOverloads constructor( private var mScroller: Scroller? = null private var mOffset = 0f private var mCurrentLine = 0 - private var flag: Any? = null private var isShowTimeline = false private var isTouching = false private var isFling = false @@ -85,9 +84,8 @@ class CoverLrcView @JvmOverloads constructor( } } - /** - * 手势监听器 - */ + private val viewScope = CoroutineScope(Dispatchers.Main + Job()) + private val mSimpleOnGestureListener: SimpleOnGestureListener = object : SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { @@ -251,42 +249,31 @@ class CoverLrcView @JvmOverloads constructor( mScroller = Scroller(context) } - /** 设置非当前行歌词字体颜色 */ fun setNormalColor(normalColor: Int) { mNormalTextColor = normalColor postInvalidate() } - /** 设置当前行歌词的字体颜色 */ fun setCurrentColor(currentColor: Int) { mCurrentTextColor = currentColor postInvalidate() } - /** 设置拖动歌词时选中歌词的字体颜色 */ fun setTimelineTextColor(timelineTextColor: Int) { mTimelineTextColor = timelineTextColor postInvalidate() } - /** 设置拖动歌词时时间线的颜色 */ fun setTimelineColor(timelineColor: Int) { mTimelineColor = timelineColor postInvalidate() } - /** 设置拖动歌词时右侧时间字体颜色 */ fun setTimeTextColor(timeTextColor: Int) { mTimeTextColor = timeTextColor postInvalidate() } - /** - * 设置歌词是否允许拖动 - * - * @param draggable 是否允许拖动 - * @param onPlayClickListener 设置歌词拖动后播放按钮点击监听器,如果允许拖动,则不能为 null - */ fun setDraggable(draggable: Boolean, onPlayClickListener: OnPlayClickListener?) { mOnPlayClickListener = if (draggable) { requireNotNull(onPlayClickListener) { "if draggable == true, onPlayClickListener must not be null" } @@ -296,17 +283,6 @@ class CoverLrcView @JvmOverloads constructor( } } - /** - * 设置播放按钮点击监听器 - * - * @param onPlayClickListener 如果为非 null ,则激活歌词拖动功能,否则将将禁用歌词拖动功能 - */ - @Deprecated("use {@link #setDraggable(boolean, OnPlayClickListener)} instead") - fun setOnPlayClickListener(onPlayClickListener: OnPlayClickListener?) { - mOnPlayClickListener = onPlayClickListener - } - - /** 设置歌词为空时屏幕中央显示的文字,如“暂无歌词” */ fun setLabel(label: String?) { runOnUi { mDefaultLabel = label @@ -314,106 +290,40 @@ class CoverLrcView @JvmOverloads constructor( } } - /** - * 加载歌词文件 - * - * @param lrcFile 歌词文件 - */ fun loadLrc(lrcFile: File) { - loadLrc(lrcFile, null) - } - - /** - * 加载双语歌词文件,两种语言的歌词时间戳需要一致 - * - * @param mainLrcFile 第一种语言歌词文件 - * @param secondLrcFile 第二种语言歌词文件 - */ - private fun loadLrc(mainLrcFile: File, secondLrcFile: File?) { runOnUi { reset() - val sb = StringBuilder("file://") - sb.append(mainLrcFile.path) - if (secondLrcFile != null) { - sb.append("#").append(secondLrcFile.path) + viewScope.launch(Dispatchers.IO) { + val lrcEntries = LrcUtils.parseLrc(arrayOf(lrcFile, null)) + withContext(Dispatchers.Main) { + onLrcLoaded(lrcEntries) + } } - val flag = sb.toString() - this.flag = flag - object : AsyncTask>() { - override fun doInBackground(vararg params: File?): List? { - return LrcUtils.parseLrc(params) - } - - override fun onPostExecute(lrcEntries: List) { - if (flag == flag) { - onLrcLoaded(lrcEntries) - this@CoverLrcView.flag = null - } - } - }.execute(mainLrcFile, secondLrcFile) } } - /** - * 加载歌词文本 - * - * @param lrcText 歌词文本 - */ fun loadLrc(lrcText: String?) { - loadLrc(lrcText, null) - } - - /** - * 加载双语歌词文本,两种语言的歌词时间戳需要一致 - * - * @param mainLrcText 第一种语言歌词文本 - * @param secondLrcText 第二种语言歌词文本 - */ - private fun loadLrc(mainLrcText: String?, secondLrcText: String?) { runOnUi { reset() - val sb = StringBuilder("file://") - sb.append(mainLrcText) - if (secondLrcText != null) { - sb.append("#").append(secondLrcText) + viewScope.launch(Dispatchers.IO) { + val lrcEntries = LrcUtils.parseLrc(arrayOf(lrcText, null)) + withContext(Dispatchers.Main) { + onLrcLoaded(lrcEntries) + } } - val flag = sb.toString() - this.flag = flag - object : AsyncTask>() { - override fun doInBackground(vararg params: String?): List? { - return LrcUtils.parseLrc(params) - } - - override fun onPostExecute(lrcEntries: List) { - if (flag == flag) { - onLrcLoaded(lrcEntries) - this@CoverLrcView.flag = null - } - } - }.execute(mainLrcText, secondLrcText) } } - /** - * 歌词是否有效 - * - * @return true,如果歌词有效,否则false - */ fun hasLrc(): Boolean { return mLrcEntryList.isNotEmpty() } - /** - * 刷新歌词 - * - * @param time 当前播放时间 - */ fun updateTime(time: Long) { runOnUi { if (!hasLrc()) { return@runOnUi } - val line = findShowLine(time) + val line = findShowLine(time - 300L) if (line != mCurrentLine) { mCurrentLine = line if (!isShowTimeline) { @@ -441,9 +351,9 @@ class CoverLrcView @JvmOverloads constructor( super.onDraw(canvas) val centerY = height / 2 - // 无歌词文件 if (!hasLrc()) { mLrcPaint.color = mCurrentTextColor + @Suppress("Deprecation") @SuppressLint("DrawAllocation") val staticLayout = StaticLayout( mDefaultLabel, mLrcPaint, @@ -485,11 +395,6 @@ class CoverLrcView @JvmOverloads constructor( } } - /** - * 画一行歌词 - * - * @param y 歌词中心 Y 坐标 - */ private fun drawText(canvas: Canvas, staticLayout: StaticLayout, y: Float) { canvas.withSave { translate(mLrcPadding, y - (staticLayout.height shr 1)) @@ -539,6 +444,7 @@ class CoverLrcView @JvmOverloads constructor( override fun onDetachedFromWindow() { removeCallbacks(hideTimelineRunnable) + viewScope.cancel() super.onDetachedFromWindow() } @@ -582,12 +488,10 @@ class CoverLrcView @JvmOverloads constructor( invalidate() } - /** 将中心行微调至正中心 */ private fun adjustCenter() { smoothScrollTo(centerLine, ADJUST_DURATION) } - /** 滚动到某一行 */ private fun smoothScrollTo(line: Int, duration: Long = mAnimationDuration) { val offset = getOffset(line) endAnimation() @@ -602,14 +506,12 @@ class CoverLrcView @JvmOverloads constructor( } } - /** 结束滚动动画 */ private fun endAnimation() { if (mAnimator != null && mAnimator!!.isRunning) { mAnimator!!.end() } } - /** 二分法查找当前时间应该显示的行数(最后一个 <= time 的行数) */ private fun findShowLine(time: Long): Int { var left = 0 var right = mLrcEntryList.size @@ -628,7 +530,6 @@ class CoverLrcView @JvmOverloads constructor( return 0 } - /** 获取当前在视图中央的行数 */ private val centerLine: Int get() { var centerLine = 0 @@ -642,7 +543,6 @@ class CoverLrcView @JvmOverloads constructor( return centerLine } - /** 获取歌词距离视图顶部的距离 采用懒加载方式 */ private fun getOffset(line: Int): Float { if (mLrcEntryList.isEmpty()) return 0F if (mLrcEntryList[line].offset == Float.MIN_VALUE) { @@ -656,11 +556,9 @@ class CoverLrcView @JvmOverloads constructor( return mLrcEntryList[line].offset } - /** 获取歌词宽度 */ private val lrcWidth: Float get() = width - mLrcPadding * 2 - /** 在主线程中运行 */ private fun runOnUi(r: Runnable) { if (Looper.myLooper() == Looper.getMainLooper()) { r.run() @@ -669,13 +567,7 @@ class CoverLrcView @JvmOverloads constructor( } } - /** 播放按钮点击监听器,点击后应该跳转到指定播放位置 */ fun interface OnPlayClickListener { - /** - * 播放按钮被点击,应该跳转到指定播放位置 - * - * @return 是否成功消费该事件,如果成功消费,则会更新UI - */ fun onPlayClick(time: Long): Boolean } diff --git a/app/src/main/java/code/name/monkey/retromusic/lyrics/LrcView.java b/app/src/main/java/code/name/monkey/retromusic/lyrics/LrcView.java index ca450b621..64844828b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/lyrics/LrcView.java +++ b/app/src/main/java/code/name/monkey/retromusic/lyrics/LrcView.java @@ -35,6 +35,8 @@ import android.view.View; import android.view.animation.LinearInterpolator; import android.widget.Scroller; +import androidx.core.content.ContextCompat; + import java.io.File; import java.util.ArrayList; import java.util.Collections; @@ -48,731 +50,600 @@ import code.name.monkey.retromusic.R; */ @SuppressLint("StaticFieldLeak") public class LrcView extends View { - private static final long ADJUST_DURATION = 100; - private static final long TIMELINE_KEEP_TIME = 4 * DateUtils.SECOND_IN_MILLIS; + private static final long ADJUST_DURATION = 100; + private static final long TIMELINE_KEEP_TIME = 4 * DateUtils.SECOND_IN_MILLIS; - private final List mLrcEntryList = new ArrayList<>(); - private final TextPaint mLrcPaint = new TextPaint(); - private final TextPaint mTimePaint = new TextPaint(); - private Paint.FontMetrics mTimeFontMetrics; - private Drawable mPlayDrawable; - private float mDividerHeight; - private long mAnimationDuration; - private int mNormalTextColor; - private float mNormalTextSize; - private int mCurrentTextColor; - private float mCurrentTextSize; - private int mTimelineTextColor; - private int mTimelineColor; - private int mTimeTextColor; - private int mDrawableWidth; - private int mTimeTextWidth; - private String mDefaultLabel; - private float mLrcPadding; - private OnPlayClickListener mOnPlayClickListener; - private ValueAnimator mAnimator; - private GestureDetector mGestureDetector; - private Scroller mScroller; - private float mOffset; - private int mCurrentLine; - private Object mFlag; - private boolean isShowTimeline; - private boolean isTouching; - private boolean isFling; - private int mTextGravity; // 歌词显示位置,靠左/居中/靠右 - private final Runnable hideTimelineRunnable = - new Runnable() { - @Override - public void run() { - if (hasLrc() && isShowTimeline) { - isShowTimeline = false; - smoothScrollTo(mCurrentLine); - } - } - }; - /** - * 手势监听器 - */ - private final GestureDetector.SimpleOnGestureListener mSimpleOnGestureListener = - new GestureDetector.SimpleOnGestureListener() { - @Override - public boolean onDown(MotionEvent e) { - if (hasLrc() && mOnPlayClickListener != null) { - mScroller.forceFinished(true); - removeCallbacks(hideTimelineRunnable); - isTouching = true; - isShowTimeline = true; - invalidate(); - return true; - } - return super.onDown(e); - } + private final List mLrcEntryList = new ArrayList<>(); + private final TextPaint mLrcPaint = new TextPaint(); + private final TextPaint mTimePaint = new TextPaint(); + private Paint.FontMetrics mTimeFontMetrics; + private Drawable mPlayDrawable; + private float mDividerHeight; + private long mAnimationDuration; + private int mNormalTextColor; + private float mNormalTextSize; + private int mCurrentTextColor; + private float mCurrentTextSize; + private int mTimelineTextColor; + private int mTimelineColor; + private int mTimeTextColor; + private int mDrawableWidth; + private int mTimeTextWidth; + private String mDefaultLabel; + private float mLrcPadding; + private OnPlayClickListener mOnPlayClickListener; + private ValueAnimator mAnimator; + private GestureDetector mGestureDetector; + private Scroller mScroller; + private float mOffset; + private int mCurrentLine; + private Object mFlag; + private boolean isShowTimeline; + private boolean isTouching; + private boolean isFling; + private int mTextGravity; // 歌词显示位置,靠左/居中/靠右 + private final Runnable hideTimelineRunnable = + new Runnable() { + @Override + public void run() { + if (hasLrc() && isShowTimeline) { + isShowTimeline = false; + smoothScrollTo(mCurrentLine); + } + } + }; - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (hasLrc()) { - mOffset += -distanceY; - mOffset = Math.min(mOffset, getOffset(0)); - mOffset = Math.max(mOffset, getOffset(mLrcEntryList.size() - 1)); - invalidate(); - getParent().requestDisallowInterceptTouchEvent(true); - return true; - } - return super.onScroll(e1, e2, distanceX, distanceY); - } + private final GestureDetector.SimpleOnGestureListener mSimpleOnGestureListener = + new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onDown(MotionEvent e) { + if (hasLrc() && mOnPlayClickListener != null) { + mScroller.forceFinished(true); + removeCallbacks(hideTimelineRunnable); + isTouching = true; + isShowTimeline = true; + invalidate(); + return true; + } + return super.onDown(e); + } - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - if (hasLrc()) { - mScroller.fling( - 0, - (int) mOffset, - 0, - (int) velocityY, - 0, - 0, - (int) getOffset(mLrcEntryList.size() - 1), - (int) getOffset(0)); - isFling = true; - return true; - } - return super.onFling(e1, e2, velocityX, velocityY); - } + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + if (hasLrc()) { + mOffset -= distanceY; + mOffset = Math.min(mOffset, getOffset(0)); + mOffset = Math.max(mOffset, getOffset(mLrcEntryList.size() - 1)); + invalidate(); + getParent().requestDisallowInterceptTouchEvent(true); + return true; + } + return super.onScroll(e1, e2, distanceX, distanceY); + } - @Override - public boolean onSingleTapConfirmed(MotionEvent e) { - if (hasLrc() - && isShowTimeline - && mPlayDrawable.getBounds().contains((int) e.getX(), (int) e.getY())) { - int centerLine = getCenterLine(); - long centerLineTime = mLrcEntryList.get(centerLine).getTime(); - // onPlayClick 消费了才更新 UI - if (mOnPlayClickListener != null && mOnPlayClickListener.onPlayClick(centerLineTime)) { - isShowTimeline = false; - removeCallbacks(hideTimelineRunnable); - mCurrentLine = centerLine; - invalidate(); - return true; - } - } - return super.onSingleTapConfirmed(e); - } - }; + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (hasLrc()) { + mScroller.fling( + 0, + (int) mOffset, + 0, + (int) velocityY, + 0, + 0, + (int) getOffset(mLrcEntryList.size() - 1), + (int) getOffset(0)); + isFling = true; + return true; + } + return super.onFling(e1, e2, velocityX, velocityY); + } - public LrcView(Context context) { - this(context, null); - } + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + if (hasLrc() + && isShowTimeline + && mPlayDrawable.getBounds().contains((int) e.getX(), (int) e.getY())) { + int centerLine = getCenterLine(); + long centerLineTime = mLrcEntryList.get(centerLine).getTime(); + // onPlayClick 消费了才更新 UI + if (mOnPlayClickListener != null && mOnPlayClickListener.onPlayClick(centerLineTime)) { + isShowTimeline = false; + removeCallbacks(hideTimelineRunnable); + mCurrentLine = centerLine; + invalidate(); + return true; + } + } + return super.onSingleTapConfirmed(e); + } + }; - public LrcView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public LrcView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(attrs); - } - - private void init(AttributeSet attrs) { - TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.LrcView); - mCurrentTextSize = - ta.getDimension( - R.styleable.LrcView_lrcTextSize, getResources().getDimension(R.dimen.lrc_text_size)); - mNormalTextSize = - ta.getDimension( - R.styleable.LrcView_lrcNormalTextSize, - getResources().getDimension(R.dimen.lrc_text_size)); - if (mNormalTextSize == 0) { - mNormalTextSize = mCurrentTextSize; + public LrcView(Context context) { + this(context, null); } - mDividerHeight = - ta.getDimension( - R.styleable.LrcView_lrcDividerHeight, - getResources().getDimension(R.dimen.lrc_divider_height)); - int defDuration = getResources().getInteger(R.integer.lrc_animation_duration); - mAnimationDuration = ta.getInt(R.styleable.LrcView_lrcAnimationDuration, defDuration); - mAnimationDuration = (mAnimationDuration < 0) ? defDuration : mAnimationDuration; - mNormalTextColor = - ta.getColor( - R.styleable.LrcView_lrcNormalTextColor, - getResources().getColor(R.color.lrc_normal_text_color)); - mCurrentTextColor = - ta.getColor( - R.styleable.LrcView_lrcCurrentTextColor, - getResources().getColor(R.color.lrc_current_text_color)); - mTimelineTextColor = - ta.getColor( - R.styleable.LrcView_lrcTimelineTextColor, - getResources().getColor(R.color.lrc_timeline_text_color)); - mDefaultLabel = ta.getString(R.styleable.LrcView_lrcLabel); - mDefaultLabel = - TextUtils.isEmpty(mDefaultLabel) ? getContext().getString(R.string.empty) : mDefaultLabel; - mLrcPadding = ta.getDimension(R.styleable.LrcView_lrcPadding, 0); - mTimelineColor = - ta.getColor( - R.styleable.LrcView_lrcTimelineColor, - getResources().getColor(R.color.lrc_timeline_color)); - float timelineHeight = - ta.getDimension( - R.styleable.LrcView_lrcTimelineHeight, - getResources().getDimension(R.dimen.lrc_timeline_height)); - mPlayDrawable = ta.getDrawable(R.styleable.LrcView_lrcPlayDrawable); - mPlayDrawable = - (mPlayDrawable == null) - ? getResources().getDrawable(R.drawable.ic_play_arrow) - : mPlayDrawable; - mTimeTextColor = - ta.getColor( - R.styleable.LrcView_lrcTimeTextColor, - getResources().getColor(R.color.lrc_time_text_color)); - float timeTextSize = - ta.getDimension( - R.styleable.LrcView_lrcTimeTextSize, - getResources().getDimension(R.dimen.lrc_time_text_size)); - mTextGravity = ta.getInteger(R.styleable.LrcView_lrcTextGravity, LrcEntry.GRAVITY_CENTER); - - ta.recycle(); - - mDrawableWidth = (int) getResources().getDimension(R.dimen.lrc_drawable_width); - mTimeTextWidth = (int) getResources().getDimension(R.dimen.lrc_time_width); - - mLrcPaint.setAntiAlias(true); - mLrcPaint.setTextSize(mCurrentTextSize); - mLrcPaint.setTextAlign(Paint.Align.LEFT); - mTimePaint.setAntiAlias(true); - mTimePaint.setTextSize(timeTextSize); - mTimePaint.setTextAlign(Paint.Align.CENTER); - //noinspection SuspiciousNameCombination - mTimePaint.setStrokeWidth(timelineHeight); - mTimePaint.setStrokeCap(Paint.Cap.ROUND); - mTimeFontMetrics = mTimePaint.getFontMetrics(); - - mGestureDetector = new GestureDetector(getContext(), mSimpleOnGestureListener); - mGestureDetector.setIsLongpressEnabled(false); - mScroller = new Scroller(getContext()); - } - - /** 设置非当前行歌词字体颜色 */ - public void setNormalColor(int normalColor) { - mNormalTextColor = normalColor; - postInvalidate(); - } - - /** 普通歌词文本字体大小 */ - public void setNormalTextSize(float size) { - mNormalTextSize = size; - } - - /** 当前歌词文本字体大小 */ - public void setCurrentTextSize(float size) { - mCurrentTextSize = size; - } - - /** 设置当前行歌词的字体颜色 */ - public void setCurrentColor(int currentColor) { - mCurrentTextColor = currentColor; - postInvalidate(); - } - - /** 设置拖动歌词时选中歌词的字体颜色 */ - public void setTimelineTextColor(int timelineTextColor) { - mTimelineTextColor = timelineTextColor; - postInvalidate(); - } - - /** 设置拖动歌词时时间线的颜色 */ - public void setTimelineColor(int timelineColor) { - mTimelineColor = timelineColor; - postInvalidate(); - } - - /** 设置拖动歌词时右侧时间字体颜色 */ - public void setTimeTextColor(int timeTextColor) { - mTimeTextColor = timeTextColor; - postInvalidate(); - } - - /** - * 设置歌词是否允许拖动 - * - * @param draggable 是否允许拖动 - * @param onPlayClickListener 设置歌词拖动后播放按钮点击监听器,如果允许拖动,则不能为 null - */ - public void setDraggable(boolean draggable, OnPlayClickListener onPlayClickListener) { - if (draggable) { - if (onPlayClickListener == null) { - throw new IllegalArgumentException( - "if draggable == true, onPlayClickListener must not be null"); - } - mOnPlayClickListener = onPlayClickListener; - } else { - mOnPlayClickListener = null; + public LrcView(Context context, AttributeSet attrs) { + this(context, attrs, 0); } - } - /** - * 设置播放按钮点击监听器 - * - * @param onPlayClickListener 如果为非 null ,则激活歌词拖动功能,否则将将禁用歌词拖动功能 - * @deprecated use {@link #setDraggable(boolean, OnPlayClickListener)} instead - */ - @Deprecated - public void setOnPlayClickListener(OnPlayClickListener onPlayClickListener) { - mOnPlayClickListener = onPlayClickListener; - } + public LrcView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(attrs); + } - /** 设置歌词为空时屏幕中央显示的文字,如“暂无歌词” */ - public void setLabel(String label) { - runOnUi( - () -> { - mDefaultLabel = label; - invalidate(); - }); - } - - /** - * 加载歌词文件 - * - * @param lrcFile 歌词文件 - */ - public void loadLrc(File lrcFile) { - loadLrc(lrcFile, null); - } - - /** - * 加载双语歌词文件,两种语言的歌词时间戳需要一致 - * - * @param mainLrcFile 第一种语言歌词文件 - * @param secondLrcFile 第二种语言歌词文件 - */ - public void loadLrc(File mainLrcFile, File secondLrcFile) { - runOnUi( - () -> { - reset(); - - StringBuilder sb = new StringBuilder("file://"); - sb.append(mainLrcFile.getPath()); - if (secondLrcFile != null) { - sb.append("#").append(secondLrcFile.getPath()); - } - String flag = sb.toString(); - setFlag(flag); - new AsyncTask>() { - @Override - protected List doInBackground(File... params) { - return LrcUtils.parseLrc(params); - } - - @Override - protected void onPostExecute(List lrcEntries) { - if (getFlag() == flag) { - onLrcLoaded(lrcEntries); - setFlag(null); - } - } - }.execute(mainLrcFile, secondLrcFile); - }); - } - - /** - * 加载歌词文本 - * - * @param lrcText 歌词文本 - */ - public void loadLrc(String lrcText) { - loadLrc(lrcText, null); - } - - /** - * 加载双语歌词文本,两种语言的歌词时间戳需要一致 - * - * @param mainLrcText 第一种语言歌词文本 - * @param secondLrcText 第二种语言歌词文本 - */ - public void loadLrc(String mainLrcText, String secondLrcText) { - runOnUi( - () -> { - reset(); - - StringBuilder sb = new StringBuilder("file://"); - sb.append(mainLrcText); - if (secondLrcText != null) { - sb.append("#").append(secondLrcText); - } - String flag = sb.toString(); - setFlag(flag); - new AsyncTask>() { - @Override - protected List doInBackground(String... params) { - return LrcUtils.parseLrc(params); - } - - @Override - protected void onPostExecute(List lrcEntries) { - if (getFlag() == flag) { - onLrcLoaded(lrcEntries); - setFlag(null); - } - } - }.execute(mainLrcText, secondLrcText); - }); - } - - /** - * 加载在线歌词,默认使用 utf-8 编码 - * - * @param lrcUrl 歌词文件的网络地址 - */ - public void loadLrcByUrl(String lrcUrl) { - loadLrcByUrl(lrcUrl, "utf-8"); - } - - /** - * 加载在线歌词 - * - * @param lrcUrl 歌词文件的网络地址 - * @param charset 编码格式 - */ - public void loadLrcByUrl(String lrcUrl, String charset) { - String flag = "url://" + lrcUrl; - setFlag(flag); - new AsyncTask() { - @Override - protected String doInBackground(String... params) { - return LrcUtils.getContentFromNetwork(params[0], params[1]); - } - - @Override - protected void onPostExecute(String lrcText) { - if (getFlag() == flag) { - loadLrc(lrcText); + private void init(AttributeSet attrs) { + TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.LrcView); + mCurrentTextSize = + ta.getDimension( + R.styleable.LrcView_lrcTextSize, getResources().getDimension(R.dimen.lrc_text_size)); + mNormalTextSize = + ta.getDimension( + R.styleable.LrcView_lrcNormalTextSize, + getResources().getDimension(R.dimen.lrc_text_size)); + if (mNormalTextSize == 0) { + mNormalTextSize = mCurrentTextSize; } - } - }.execute(lrcUrl, charset); - } - /** - * 歌词是否有效 - * - * @return true,如果歌词有效,否则false - */ - public boolean hasLrc() { - return !mLrcEntryList.isEmpty(); - } + mDividerHeight = + ta.getDimension( + R.styleable.LrcView_lrcDividerHeight, + getResources().getDimension(R.dimen.lrc_divider_height)); + int defDuration = getResources().getInteger(R.integer.lrc_animation_duration); + mAnimationDuration = ta.getInt(R.styleable.LrcView_lrcAnimationDuration, defDuration); + mAnimationDuration = (mAnimationDuration < 0) ? defDuration : mAnimationDuration; + mNormalTextColor = + ta.getColor( + R.styleable.LrcView_lrcNormalTextColor, + getResources().getColor(R.color.lrc_normal_text_color)); + mCurrentTextColor = + ta.getColor( + R.styleable.LrcView_lrcCurrentTextColor, + getResources().getColor(R.color.lrc_current_text_color)); + mTimelineTextColor = + ta.getColor( + R.styleable.LrcView_lrcTimelineTextColor, + getResources().getColor(R.color.lrc_timeline_text_color)); + mDefaultLabel = ta.getString(R.styleable.LrcView_lrcLabel); + mDefaultLabel = + TextUtils.isEmpty(mDefaultLabel) ? getContext().getString(R.string.empty) : mDefaultLabel; + mLrcPadding = ta.getDimension(R.styleable.LrcView_lrcPadding, 0); + mTimelineColor = + ta.getColor( + R.styleable.LrcView_lrcTimelineColor, + getResources().getColor(R.color.lrc_timeline_color)); + float timelineHeight = + ta.getDimension( + R.styleable.LrcView_lrcTimelineHeight, + getResources().getDimension(R.dimen.lrc_timeline_height)); + mPlayDrawable = ta.getDrawable(R.styleable.LrcView_lrcPlayDrawable); + mPlayDrawable = + (mPlayDrawable == null) + ? ContextCompat.getDrawable(getContext(), R.drawable.ic_play_arrow) + : mPlayDrawable; + mTimeTextColor = + ta.getColor( + R.styleable.LrcView_lrcTimeTextColor, + getResources().getColor(R.color.lrc_time_text_color)); + float timeTextSize = + ta.getDimension( + R.styleable.LrcView_lrcTimeTextSize, + getResources().getDimension(R.dimen.lrc_time_text_size)); + mTextGravity = ta.getInteger(R.styleable.LrcView_lrcTextGravity, LrcEntry.GRAVITY_CENTER); - /** - * 刷新歌词 - * - * @param time 当前播放时间 - */ - public void updateTime(long time) { - runOnUi( - () -> { - if (!hasLrc()) { - return; - } + ta.recycle(); - int line = findShowLine(time); - if (line != mCurrentLine) { - mCurrentLine = line; - if (!isShowTimeline) { - smoothScrollTo(line); - } else { - invalidate(); - } - } - }); - } + mDrawableWidth = (int) getResources().getDimension(R.dimen.lrc_drawable_width); + mTimeTextWidth = (int) getResources().getDimension(R.dimen.lrc_time_width); - /** - * 将歌词滚动到指定时间 - * - * @param time 指定的时间 - * @deprecated 请使用 {@link #updateTime(long)} 代替 - */ - @Deprecated - public void onDrag(long time) { - updateTime(time); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - if (changed) { - initPlayDrawable(); - initEntryList(); - if (hasLrc()) { - smoothScrollTo(mCurrentLine, 0L); - } - } - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - int centerY = getHeight() / 2; - - // 无歌词文件 - if (!hasLrc()) { - mLrcPaint.setColor(mCurrentTextColor); - @SuppressLint("DrawAllocation") - StaticLayout staticLayout = - new StaticLayout( - mDefaultLabel, - mLrcPaint, - (int) getLrcWidth(), - Layout.Alignment.ALIGN_CENTER, - 1f, - 0f, - false); - drawText(canvas, staticLayout, centerY); - return; - } - - int centerLine = getCenterLine(); - - if (isShowTimeline) { - mPlayDrawable.draw(canvas); - - mTimePaint.setColor(mTimelineColor); - canvas.drawLine(mTimeTextWidth, centerY, getWidth() - mTimeTextWidth, centerY, mTimePaint); - - mTimePaint.setColor(mTimeTextColor); - String timeText = LrcUtils.formatTime(mLrcEntryList.get(centerLine).getTime()); - float timeX = getWidth() - mTimeTextWidth / 2; - float timeY = centerY - (mTimeFontMetrics.descent + mTimeFontMetrics.ascent) / 2; - canvas.drawText(timeText, timeX, timeY, mTimePaint); - } - - canvas.translate(0, mOffset); - - float y = 0; - for (int i = 0; i < mLrcEntryList.size(); i++) { - if (i > 0) { - y += - ((mLrcEntryList.get(i - 1).getHeight() + mLrcEntryList.get(i).getHeight()) >> 1) - + mDividerHeight; - } - if (BuildConfig.DEBUG) { - // mLrcPaint.setTypeface(ResourcesCompat.getFont(getContext(), R.font.sans)); - } - if (i == mCurrentLine) { + mLrcPaint.setAntiAlias(true); mLrcPaint.setTextSize(mCurrentTextSize); - mLrcPaint.setColor(mCurrentTextColor); - } else if (isShowTimeline && i == centerLine) { - mLrcPaint.setColor(mTimelineTextColor); - } else { - mLrcPaint.setTextSize(mNormalTextSize); - mLrcPaint.setColor(mNormalTextColor); - } - drawText(canvas, mLrcEntryList.get(i).getStaticLayout(), y); - } - } + mLrcPaint.setTextAlign(Paint.Align.LEFT); + mTimePaint.setAntiAlias(true); + mTimePaint.setTextSize(timeTextSize); + mTimePaint.setTextAlign(Paint.Align.CENTER); + //noinspection SuspiciousNameCombination + mTimePaint.setStrokeWidth(timelineHeight); + mTimePaint.setStrokeCap(Paint.Cap.ROUND); + mTimeFontMetrics = mTimePaint.getFontMetrics(); - /** - * 画一行歌词 - * - * @param y 歌词中心 Y 坐标 - */ - private void drawText(Canvas canvas, StaticLayout staticLayout, float y) { - canvas.save(); - canvas.translate(mLrcPadding, y - (staticLayout.getHeight() >> 1)); - staticLayout.draw(canvas); - canvas.restore(); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP - || event.getAction() == MotionEvent.ACTION_CANCEL) { - isTouching = false; - if (hasLrc() && !isFling) { - adjustCenter(); - postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME); - } - } - return mGestureDetector.onTouchEvent(event); - } - - @Override - public void computeScroll() { - if (mScroller.computeScrollOffset()) { - mOffset = mScroller.getCurrY(); - invalidate(); + mGestureDetector = new GestureDetector(getContext(), mSimpleOnGestureListener); + mGestureDetector.setIsLongpressEnabled(false); + mScroller = new Scroller(getContext()); } - if (isFling && mScroller.isFinished()) { - isFling = false; - if (hasLrc() && !isTouching) { - adjustCenter(); - postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME); - } - } - } - - @Override - protected void onDetachedFromWindow() { - removeCallbacks(hideTimelineRunnable); - super.onDetachedFromWindow(); - } - - private void onLrcLoaded(List entryList) { - if (entryList != null && !entryList.isEmpty()) { - mLrcEntryList.addAll(entryList); + public void setCurrentColor(int currentColor) { + mCurrentTextColor = currentColor; + postInvalidate(); } - Collections.sort(mLrcEntryList); - - initEntryList(); - invalidate(); - } - - private void initPlayDrawable() { - int l = (mTimeTextWidth - mDrawableWidth) / 2; - int t = getHeight() / 2 - mDrawableWidth / 2; - int r = l + mDrawableWidth; - int b = t + mDrawableWidth; - mPlayDrawable.setBounds(l, t, r, b); - } - - private void initEntryList() { - if (!hasLrc() || getWidth() == 0) { - return; + public void setTimelineTextColor(int timelineTextColor) { + mTimelineTextColor = timelineTextColor; + postInvalidate(); } - for (LrcEntry lrcEntry : mLrcEntryList) { - lrcEntry.init(mLrcPaint, (int) getLrcWidth(), mTextGravity); + public void setTimelineColor(int timelineColor) { + mTimelineColor = timelineColor; + postInvalidate(); } - mOffset = getHeight() / 2; - } - private void reset() { - endAnimation(); - mScroller.forceFinished(true); - isShowTimeline = false; - isTouching = false; - isFling = false; - removeCallbacks(hideTimelineRunnable); - mLrcEntryList.clear(); - mOffset = 0; - mCurrentLine = 0; - invalidate(); - } + public void setTimeTextColor(int timeTextColor) { + mTimeTextColor = timeTextColor; + postInvalidate(); + } - /** 将中心行微调至正中心 */ - private void adjustCenter() { - smoothScrollTo(getCenterLine(), ADJUST_DURATION); - } - /** 滚动到某一行 */ - private void smoothScrollTo(int line) { - smoothScrollTo(line, mAnimationDuration); - } + public void setDraggable(boolean draggable, OnPlayClickListener onPlayClickListener) { + if (draggable) { + if (onPlayClickListener == null) { + throw new IllegalArgumentException( + "if draggable == true, onPlayClickListener must not be null"); + } + mOnPlayClickListener = onPlayClickListener; + } else { + mOnPlayClickListener = null; + } + } - /** 滚动到某一行 */ - private void smoothScrollTo(int line, long duration) { - float offset = getOffset(line); - endAnimation(); + public void setLabel(String label) { + runOnUi( + () -> { + mDefaultLabel = label; + invalidate(); + }); + } - mAnimator = ValueAnimator.ofFloat(mOffset, offset); - mAnimator.setDuration(duration); - mAnimator.setInterpolator(new LinearInterpolator()); - mAnimator.addUpdateListener( - animation -> { - mOffset = (float) animation.getAnimatedValue(); - invalidate(); + public void loadLrc(File lrcFile) { + loadLrc(lrcFile, null); + } + + public void loadLrc(File mainLrcFile, File secondLrcFile) { + runOnUi(() -> { + reset(); + + StringBuilder sb = new StringBuilder("file://"); + sb.append(mainLrcFile.getPath()); + if (secondLrcFile != null) { + sb.append("#").append(secondLrcFile.getPath()); + } + String flag = sb.toString(); + setFlag(flag); + new AsyncTask>() { + @Override + protected List doInBackground(File... params) { + return LrcUtils.parseLrc(params); + } + + @Override + protected void onPostExecute(List lrcEntries) { + if (getFlag() == flag) { + onLrcLoaded(lrcEntries); + setFlag(null); + } + } + }.execute(mainLrcFile, secondLrcFile); }); - mAnimator.start(); - } - - /** 结束滚动动画 */ - private void endAnimation() { - if (mAnimator != null && mAnimator.isRunning()) { - mAnimator.end(); } - } - /** 二分法查找当前时间应该显示的行数(最后一个 <= time 的行数) */ - private int findShowLine(long time) { - int left = 0; - int right = mLrcEntryList.size(); - while (left <= right) { - int middle = (left + right) / 2; - long middleTime = mLrcEntryList.get(middle).getTime(); + public void loadLrc(String lrcText) { + loadLrc(lrcText, null); + } - if (time < middleTime) { - right = middle - 1; - } else { - if (middle + 1 >= mLrcEntryList.size() || time < mLrcEntryList.get(middle + 1).getTime()) { - return middle; + public void loadLrc(String mainLrcText, String secondLrcText) { + runOnUi( + () -> { + reset(); + + StringBuilder sb = new StringBuilder("file://"); + sb.append(mainLrcText); + if (secondLrcText != null) { + sb.append("#").append(secondLrcText); + } + String flag = sb.toString(); + setFlag(flag); + new AsyncTask>() { + @Override + protected List doInBackground(String... params) { + return LrcUtils.parseLrc(params); + } + + @Override + protected void onPostExecute(List lrcEntries) { + if (getFlag() == flag) { + onLrcLoaded(lrcEntries); + setFlag(null); + } + } + }.execute(mainLrcText, secondLrcText); + }); + } + + public boolean hasLrc() { + return !mLrcEntryList.isEmpty(); + } + + public void updateTime(long time) { + runOnUi( + () -> { + if (!hasLrc()) { + return; + } + + int line = findShowLine(time); + if (line != mCurrentLine) { + mCurrentLine = line; + if (!isShowTimeline) { + smoothScrollTo(line); + } else { + invalidate(); + } + } + }); + } + + @Deprecated + public void onDrag(long time) { + updateTime(time); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed) { + initPlayDrawable(); + initEntryList(); + if (hasLrc()) { + smoothScrollTo(mCurrentLine, 0L); + } + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + int centerY = getHeight() / 2; + + if (!hasLrc()) { + mLrcPaint.setColor(mCurrentTextColor); + @SuppressLint("DrawAllocation") + StaticLayout staticLayout = + new StaticLayout( + mDefaultLabel, + mLrcPaint, + (int) getLrcWidth(), + Layout.Alignment.ALIGN_CENTER, + 1f, + 0f, + false); + drawText(canvas, staticLayout, centerY); + return; } - left = middle + 1; - } + int centerLine = getCenterLine(); + + if (isShowTimeline) { + mPlayDrawable.draw(canvas); + + mTimePaint.setColor(mTimelineColor); + canvas.drawLine(mTimeTextWidth, centerY, getWidth() - mTimeTextWidth, centerY, mTimePaint); + + mTimePaint.setColor(mTimeTextColor); + String timeText = LrcUtils.formatTime(mLrcEntryList.get(centerLine).getTime()); + float timeX = getWidth() - mTimeTextWidth / 2; + float timeY = centerY - (mTimeFontMetrics.descent + mTimeFontMetrics.ascent) / 2; + canvas.drawText(timeText, timeX, timeY, mTimePaint); + } + + canvas.translate(0, mOffset); + + float y = 0; + for (int i = 0; i < mLrcEntryList.size(); i++) { + if (i > 0) { + y += + ((mLrcEntryList.get(i - 1).getHeight() + mLrcEntryList.get(i).getHeight()) >> 1) + + mDividerHeight; + } + if (BuildConfig.DEBUG) { + // mLrcPaint.setTypeface(ResourcesCompat.getFont(getContext(), R.font.sans)); + } + if (i == mCurrentLine) { + mLrcPaint.setTextSize(mCurrentTextSize); + mLrcPaint.setColor(mCurrentTextColor); + } else if (isShowTimeline && i == centerLine) { + mLrcPaint.setColor(mTimelineTextColor); + } else { + mLrcPaint.setTextSize(mNormalTextSize); + mLrcPaint.setColor(mNormalTextColor); + } + drawText(canvas, mLrcEntryList.get(i).getStaticLayout(), y); + } } - return 0; - } - - /** 获取当前在视图中央的行数 */ - private int getCenterLine() { - int centerLine = 0; - float minDistance = Float.MAX_VALUE; - for (int i = 0; i < mLrcEntryList.size(); i++) { - if (Math.abs(mOffset - getOffset(i)) < minDistance) { - minDistance = Math.abs(mOffset - getOffset(i)); - centerLine = i; - } - } - return centerLine; - } - - /** 获取歌词距离视图顶部的距离 采用懒加载方式 */ - private float getOffset(int line) { - if (mLrcEntryList.get(line).getOffset() == Float.MIN_VALUE) { - float offset = getHeight() / 2; - for (int i = 1; i <= line; i++) { - offset -= - ((mLrcEntryList.get(i - 1).getHeight() + mLrcEntryList.get(i).getHeight()) >> 1) - + mDividerHeight; - } - mLrcEntryList.get(line).setOffset(offset); + private void drawText(Canvas canvas, StaticLayout staticLayout, float y) { + canvas.save(); + canvas.translate(mLrcPadding, y - (staticLayout.getHeight() >> 1)); + staticLayout.draw(canvas); + canvas.restore(); } - return mLrcEntryList.get(line).getOffset(); - } - - /** 获取歌词宽度 */ - private float getLrcWidth() { - return getWidth() - mLrcPadding * 2; - } - - /** 在主线程中运行 */ - private void runOnUi(Runnable r) { - if (Looper.myLooper() == Looper.getMainLooper()) { - r.run(); - } else { - post(r); + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP + || event.getAction() == MotionEvent.ACTION_CANCEL) { + isTouching = false; + if (hasLrc() && !isFling) { + adjustCenter(); + postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME); + } + } + return mGestureDetector.onTouchEvent(event); } - } - private Object getFlag() { - return mFlag; - } + @Override + public void computeScroll() { + if (mScroller.computeScrollOffset()) { + mOffset = mScroller.getCurrY(); + invalidate(); + } - private void setFlag(Object flag) { - this.mFlag = flag; - } + if (isFling && mScroller.isFinished()) { + isFling = false; + if (hasLrc() && !isTouching) { + adjustCenter(); + postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME); + } + } + } - /** 播放按钮点击监听器,点击后应该跳转到指定播放位置 */ - public interface OnPlayClickListener { - /** - * 播放按钮被点击,应该跳转到指定播放位置 - * - * @return 是否成功消费该事件,如果成功消费,则会更新UI - */ - boolean onPlayClick(long time); - } + @Override + protected void onDetachedFromWindow() { + removeCallbacks(hideTimelineRunnable); + super.onDetachedFromWindow(); + } + + private void onLrcLoaded(List entryList) { + if (entryList != null && !entryList.isEmpty()) { + mLrcEntryList.addAll(entryList); + } + + Collections.sort(mLrcEntryList); + + initEntryList(); + invalidate(); + } + + private void initPlayDrawable() { + int l = (mTimeTextWidth - mDrawableWidth) / 2; + int t = getHeight() / 2 - mDrawableWidth / 2; + int r = l + mDrawableWidth; + int b = t + mDrawableWidth; + mPlayDrawable.setBounds(l, t, r, b); + } + + private void initEntryList() { + if (!hasLrc() || getWidth() == 0) { + return; + } + + for (LrcEntry lrcEntry : mLrcEntryList) { + lrcEntry.init(mLrcPaint, (int) getLrcWidth(), mTextGravity); + } + + mOffset = getHeight() / 2; + } + + private void reset() { + endAnimation(); + mScroller.forceFinished(true); + isShowTimeline = false; + isTouching = false; + isFling = false; + removeCallbacks(hideTimelineRunnable); + mLrcEntryList.clear(); + mOffset = 0; + mCurrentLine = 0; + invalidate(); + } + + private void adjustCenter() { + smoothScrollTo(getCenterLine(), ADJUST_DURATION); + } + + private void smoothScrollTo(int line) { + smoothScrollTo(line, mAnimationDuration); + } + + private void smoothScrollTo(int line, long duration) { + float offset = getOffset(line); + endAnimation(); + + mAnimator = ValueAnimator.ofFloat(mOffset, offset); + mAnimator.setDuration(duration); + mAnimator.setInterpolator(new LinearInterpolator()); + mAnimator.addUpdateListener( + animation -> { + mOffset = (float) animation.getAnimatedValue(); + invalidate(); + }); + mAnimator.start(); + } + + private void endAnimation() { + if (mAnimator != null && mAnimator.isRunning()) { + mAnimator.end(); + } + } + + private int findShowLine(long time) { + int left = 0; + int right = mLrcEntryList.size(); + while (left <= right) { + int middle = (left + right) / 2; + long middleTime = mLrcEntryList.get(middle).getTime(); + + if (time < middleTime) { + right = middle - 1; + } else { + if (middle + 1 >= mLrcEntryList.size() || time < mLrcEntryList.get(middle + 1).getTime()) { + return middle; + } + + left = middle + 1; + } + } + + return 0; + } + + private int getCenterLine() { + int centerLine = 0; + float minDistance = Float.MAX_VALUE; + for (int i = 0; i < mLrcEntryList.size(); i++) { + if (Math.abs(mOffset - getOffset(i)) < minDistance) { + minDistance = Math.abs(mOffset - getOffset(i)); + centerLine = i; + } + } + return centerLine; + } + + private float getOffset(int line) { + if (mLrcEntryList.get(line).getOffset() == Float.MIN_VALUE) { + float offset = getHeight() / 2; + for (int i = 1; i <= line; i++) { + offset -= + ((mLrcEntryList.get(i - 1).getHeight() + mLrcEntryList.get(i).getHeight()) >> 1) + + mDividerHeight; + } + mLrcEntryList.get(line).setOffset(offset); + } + + return mLrcEntryList.get(line).getOffset(); + } + + private float getLrcWidth() { + return getWidth() - mLrcPadding * 2; + } + + private void runOnUi(Runnable r) { + if (Looper.myLooper() == Looper.getMainLooper()) { + r.run(); + } else { + post(r); + } + } + + private Object getFlag() { + return mFlag; + } + + private void setFlag(Object flag) { + this.mFlag = flag; + } + + public interface OnPlayClickListener { + boolean onPlayClick(long time); + } } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt index 6db2a55c1..2f7aff94c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt @@ -117,7 +117,7 @@ object LyricUtil { return "$lrcRootPath$title - $artist.lrc" } - fun getLrcOriginalPath(filePath: String): String { + private fun getLrcOriginalPath(filePath: String): String { return filePath.replace(filePath.substring(filePath.lastIndexOf(".") + 1), "lrc") } @@ -160,9 +160,9 @@ object LyricUtil { } fun getEmbeddedSyncedLyrics(data: String): String? { - val embeddedLyrics = try{ - AudioFileIO.read(File(data)).tagOrCreateDefault.getFirst(FieldKey.LYRICS) - } catch(e: Exception){ + val embeddedLyrics = try { + AudioFileIO.read(File(data)).tagOrCreateDefault.getFirst(FieldKey.LYRICS) + } catch (e: Exception) { return null } return if (AbsSynchronizedLyrics.isSynchronized(embeddedLyrics)) { diff --git a/app/src/main/res/menu/menu_search.xml b/app/src/main/res/menu/menu_lyrics.xml similarity index 100% rename from app/src/main/res/menu/menu_search.xml rename to app/src/main/res/menu/menu_lyrics.xml