mirror of
https://github.com/ikun0014/lx-music-mobile.git
synced 2025-05-23 22:37:41 +08:00
完善桌面歌词
This commit is contained in:
parent
6bd59b800f
commit
7f344631a8
@ -1,17 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="cn.toside.music.mobile">
|
package="cn.toside.music.mobile">
|
||||||
|
|
||||||
<!--获取读写外置存储权限-->
|
<!-- 获取读写外置存储权限 -->
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".MainApplication"
|
android:name=".MainApplication"
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package com.lxmusicmobile.lyric;
|
package com.lxmusicmobile.lyric;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReactApplicationContext;
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
@ -9,20 +13,92 @@ import java.util.List;
|
|||||||
|
|
||||||
public class Lyric extends LyricPlayer {
|
public class Lyric extends LyricPlayer {
|
||||||
LyricView lyricView = null;
|
LyricView lyricView = null;
|
||||||
|
LyricEvent lyricEvent = null;
|
||||||
|
ReactApplicationContext reactAppContext;
|
||||||
|
|
||||||
public void showLyric(ReactApplicationContext reactContext, boolean isLock) {
|
boolean isShowLyric = false;
|
||||||
if (lyricView == null) {
|
boolean isLock = false;
|
||||||
lyricView = new LyricView(reactContext);
|
String themeColor = "#07c556";
|
||||||
|
String lastText = "LX Music ^-^";
|
||||||
|
int lyricViewX = 0;
|
||||||
|
int lyricViewY = 0;
|
||||||
|
|
||||||
|
Lyric(ReactApplicationContext reactContext) {
|
||||||
|
this.reactAppContext = reactContext;
|
||||||
|
registerScreenBroadcastReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerScreenBroadcastReceiver() {
|
||||||
|
final IntentFilter theFilter = new IntentFilter();
|
||||||
|
/** System Defined Broadcast */
|
||||||
|
theFilter.addAction(Intent.ACTION_SCREEN_ON);
|
||||||
|
theFilter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||||
|
|
||||||
|
BroadcastReceiver screenOnOffReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String strAction = intent.getAction();
|
||||||
|
|
||||||
|
switch (strAction) {
|
||||||
|
case Intent.ACTION_SCREEN_OFF:
|
||||||
|
Log.d("Lyric", "ACTION_SCREEN_OFF");
|
||||||
|
handleScreenOff();
|
||||||
|
break;
|
||||||
|
case Intent.ACTION_SCREEN_ON:
|
||||||
|
Log.d("Lyric", "ACTION_SCREEN_ON");
|
||||||
|
handleScreenOn();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
reactAppContext.registerReceiver(screenOnOffReceiver, theFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleScreenOff() {
|
||||||
|
if (!isShowLyric) return;
|
||||||
|
setTempPause(true);
|
||||||
|
|
||||||
|
if (lyricView != null) {
|
||||||
|
lyricView.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
lyricView.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
lyricView.showLyricView(isLock);
|
}
|
||||||
|
|
||||||
|
private void handleScreenOn() {
|
||||||
|
if (!isShowLyric) return;
|
||||||
|
if (lyricView == null) lyricView = new LyricView(reactAppContext, lyricEvent);
|
||||||
|
lyricView.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
lyricView.showLyricView(isLock, themeColor, lyricViewX, lyricViewY);
|
||||||
|
lyricView.setLyric(lastText);
|
||||||
|
setTempPause(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showLyric(boolean isLock, String themeColor, int lyricViewX, int lyricViewY) {
|
||||||
|
if (lyricEvent == null) lyricEvent = new LyricEvent(reactAppContext);
|
||||||
|
if (lyricView == null) lyricView = new LyricView(reactAppContext, lyricEvent);
|
||||||
|
this.isLock = isLock;
|
||||||
|
this.themeColor = themeColor;
|
||||||
|
this.lyricViewX = lyricViewX;
|
||||||
|
this.lyricViewY = lyricViewY;
|
||||||
|
lyricView.showLyricView(isLock, themeColor, lyricViewX, lyricViewY);
|
||||||
|
isShowLyric = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void hideLyric() {
|
public void hideLyric() {
|
||||||
this.pause();
|
this.pause();
|
||||||
if (lyricView != null) {
|
if (lyricView != null) {
|
||||||
lyricView.destroy();
|
lyricView.destroy();
|
||||||
lyricView = null;
|
|
||||||
}
|
}
|
||||||
|
isShowLyric = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -34,29 +110,37 @@ public class Lyric extends LyricPlayer {
|
|||||||
public void onSetLyric(List lines) {
|
public void onSetLyric(List lines) {
|
||||||
for (int i = 0; i < lines.size(); i++) {
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
HashMap line = (HashMap) lines.get(i);
|
HashMap line = (HashMap) lines.get(i);
|
||||||
Log.e("Lyric", (String) line.get("text") + " " + (String) line.get("translation"));
|
// Log.d("Lyric", (String) line.get("text") + " " + (String) line.get("translation"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlay(int lineNum, String text) {
|
public void onPlay(int lineNum, String text) {
|
||||||
HashMap line = (HashMap) lines.get(lineNum);
|
// HashMap line = (HashMap) lines.get(lineNum);
|
||||||
|
lastText = text;
|
||||||
if (lyricView == null) return;
|
if (lyricView == null) return;
|
||||||
lyricView.setLyric(text);
|
lyricView.setLyric(text);
|
||||||
Log.e("Lyric", lineNum + " " + text + " " + (String) line.get("translation"));
|
// Log.d("Lyric", lineNum + " " + text + " " + (String) line.get("translation"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void lockLyric() {
|
public void lockLyric() {
|
||||||
if (lyricView == null) return;
|
if (lyricView == null) return;
|
||||||
|
this.isLock = true;
|
||||||
lyricView.lockView();
|
lyricView.lockView();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unlockLyric() {
|
public void unlockLyric() {
|
||||||
if (lyricView == null) return;
|
if (lyricView == null) return;
|
||||||
|
this.isLock = false;
|
||||||
lyricView.unlockView();
|
lyricView.unlockView();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleTranslation(boolean isShowTranslation) {
|
public void toggleTranslation(boolean isShowTranslation) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setColor(String color) {
|
||||||
|
lyricView.setColor(color);
|
||||||
|
this.themeColor = color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.lxmusicmobile.lyric;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
|
import com.facebook.react.bridge.WritableMap;
|
||||||
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||||
|
|
||||||
|
public class LyricEvent {
|
||||||
|
final String SET_VIEW_POSITION = "set-position";
|
||||||
|
|
||||||
|
private final ReactApplicationContext reactContext;
|
||||||
|
LyricEvent(ReactApplicationContext reactContext) { this.reactContext = reactContext; }
|
||||||
|
|
||||||
|
public void sendEvent(String eventName, @Nullable WritableMap params) {
|
||||||
|
Log.d("Lyric", "senEvent: " + eventName);
|
||||||
|
reactContext
|
||||||
|
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
||||||
|
.emit(eventName, params);
|
||||||
|
}
|
||||||
|
}
|
@ -10,11 +10,20 @@ import com.facebook.react.bridge.ReactMethod;
|
|||||||
public class LyricModule extends ReactContextBaseJavaModule {
|
public class LyricModule extends ReactContextBaseJavaModule {
|
||||||
private final ReactApplicationContext reactContext;
|
private final ReactApplicationContext reactContext;
|
||||||
Lyric lyric;
|
Lyric lyric;
|
||||||
|
// final Map<String, Object> constants = new HashMap<>();
|
||||||
|
|
||||||
LyricModule(ReactApplicationContext reactContext) {
|
LyricModule(ReactApplicationContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
this.reactContext = reactContext;
|
this.reactContext = reactContext;
|
||||||
lyric = new Lyric();
|
|
||||||
|
// constants.put("THEME_GREEN", "#07c556");
|
||||||
|
// constants.put("THEME_YELLOW", "#fffa12");
|
||||||
|
// constants.put("THEME_BLUE", "#19b5fe");
|
||||||
|
// constants.put("THEME_RED", "#ff1222");
|
||||||
|
// constants.put("THEME_PINK", "#f1828d");
|
||||||
|
// constants.put("THEME_PURPLE", "#c851d4");
|
||||||
|
// constants.put("THEME_ORANGE", "#fffa12");
|
||||||
|
// constants.put("THEME_GREY", "#bdc3c7");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -22,9 +31,15 @@ public class LyricModule extends ReactContextBaseJavaModule {
|
|||||||
return "LyricModule";
|
return "LyricModule";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public Map<String, Object> getConstants() {
|
||||||
|
// return constants;
|
||||||
|
// }
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void showLyric(boolean isLook, Promise promise) {
|
public void showLyric(boolean isLook, String themeColor, int lyricViewX, int lyricViewY, Promise promise) {
|
||||||
lyric.showLyric(reactContext, isLook);
|
if (lyric == null) lyric = new Lyric(reactContext);
|
||||||
|
lyric.showLyric(isLook, themeColor, lyricViewX, lyricViewY);
|
||||||
promise.resolve(null);
|
promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,8 +52,8 @@ public class LyricModule extends ReactContextBaseJavaModule {
|
|||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void setLyric(String lyric, String translation, Promise promise) {
|
public void setLyric(String lyric, String translation, Promise promise) {
|
||||||
Log.e("Lyric", "set lyric: " + lyric);
|
// Log.d("Lyric", "set lyric: " + lyric);
|
||||||
Log.e("Lyric", "set lyric translation: " + translation);
|
// Log.d("Lyric", "set lyric translation: " + translation);
|
||||||
this.lyric.setLyric(lyric, translation);
|
this.lyric.setLyric(lyric, translation);
|
||||||
promise.resolve(null);
|
promise.resolve(null);
|
||||||
}
|
}
|
||||||
@ -51,14 +66,14 @@ public class LyricModule extends ReactContextBaseJavaModule {
|
|||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void play(int time, Promise promise) {
|
public void play(int time, Promise promise) {
|
||||||
Log.e("Lyric", "play lyric: " + time);
|
Log.d("Lyric", "play lyric: " + time);
|
||||||
lyric.play(time);
|
lyric.play(time);
|
||||||
promise.resolve(null);
|
promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void pause(Promise promise) {
|
public void pause(Promise promise) {
|
||||||
Log.e("Lyric", "play pause");
|
Log.d("Lyric", "play pause");
|
||||||
lyric.pause();
|
lyric.pause();
|
||||||
promise.resolve(null);
|
promise.resolve(null);
|
||||||
}
|
}
|
||||||
@ -70,5 +85,12 @@ public class LyricModule extends ReactContextBaseJavaModule {
|
|||||||
} else {
|
} else {
|
||||||
lyric.unlockLyric();
|
lyric.unlockLyric();
|
||||||
}
|
}
|
||||||
|
promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void setColor(String themeColor, Promise promise) {
|
||||||
|
lyric.setColor(themeColor);
|
||||||
|
promise.resolve(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package com.lxmusicmobile.lyric;
|
package com.lxmusicmobile.lyric;
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@ -26,10 +24,12 @@ public class LyricPlayer {
|
|||||||
int curLineNum = 0;
|
int curLineNum = 0;
|
||||||
int maxLine = 0;
|
int maxLine = 0;
|
||||||
int offset = 150;
|
int offset = 150;
|
||||||
boolean isOffseted = false;
|
boolean isOffered = false;
|
||||||
long performanceTime = 0;
|
long performanceTime = 0;
|
||||||
int delay = 0;
|
int delay = 0;
|
||||||
Object tid = null;
|
Object tid = null;
|
||||||
|
boolean tempPause = false;
|
||||||
|
boolean tempPaused = false;
|
||||||
|
|
||||||
LyricPlayer() {
|
LyricPlayer() {
|
||||||
// tagRegMap = new HashMap<String, String>();
|
// tagRegMap = new HashMap<String, String>();
|
||||||
@ -43,6 +43,17 @@ public class LyricPlayer {
|
|||||||
timePattern = Pattern.compile(timeExp);
|
timePattern = Pattern.compile(timeExp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTempPause(boolean isPaused) {
|
||||||
|
if (isPaused) {
|
||||||
|
tempPause = true;
|
||||||
|
} else {
|
||||||
|
tempPause = false;
|
||||||
|
if (tempPaused) {
|
||||||
|
tempPaused = false;
|
||||||
|
if (isPlay) refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @RequiresApi(api = Build.VERSION_CODES.N)
|
// @RequiresApi(api = Build.VERSION_CODES.N)
|
||||||
// private void initTag() {
|
// private void initTag() {
|
||||||
@ -167,7 +178,8 @@ public class LyricPlayer {
|
|||||||
public void pause() {
|
public void pause() {
|
||||||
if (!isPlay) return;
|
if (!isPlay) return;
|
||||||
isPlay = false;
|
isPlay = false;
|
||||||
isOffseted = false;
|
isOffered = false;
|
||||||
|
tempPaused = false;
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
if (curLineNum == maxLine) return;
|
if (curLineNum == maxLine) return;
|
||||||
int curLineNum = this.findCurLineNum(getCurrentTime());
|
int curLineNum = this.findCurLineNum(getCurrentTime());
|
||||||
@ -192,7 +204,7 @@ public class LyricPlayer {
|
|||||||
private int findCurLineNum(int curTime) {
|
private int findCurLineNum(int curTime) {
|
||||||
int length = lines.size();
|
int length = lines.size();
|
||||||
for (int index = 0; index < length; index++) {
|
for (int index = 0; index < length; index++) {
|
||||||
if (curTime <= (Integer) ((HashMap)lines.get(index)).get("time")) return index == 0 ? 0 : index - 1;
|
if (curTime <= (int) ((HashMap)lines.get(index)).get("time")) return index == 0 ? 0 : index - 1;
|
||||||
}
|
}
|
||||||
return length - 1;
|
return length - 1;
|
||||||
}
|
}
|
||||||
@ -203,6 +215,9 @@ public class LyricPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void refresh() {
|
private void refresh() {
|
||||||
|
if (tempPaused) tempPaused = false;
|
||||||
|
// Log.d("Lyric", "refresh: " + curLineNum);
|
||||||
|
|
||||||
curLineNum++;
|
curLineNum++;
|
||||||
if (curLineNum == maxLine) {
|
if (curLineNum == maxLine) {
|
||||||
handleMaxLine();
|
handleMaxLine();
|
||||||
@ -211,20 +226,26 @@ public class LyricPlayer {
|
|||||||
HashMap curLine = lines.get(curLineNum);
|
HashMap curLine = lines.get(curLineNum);
|
||||||
HashMap nextLine = lines.get(curLineNum + 1);
|
HashMap nextLine = lines.get(curLineNum + 1);
|
||||||
int currentTime = getCurrentTime();
|
int currentTime = getCurrentTime();
|
||||||
int driftTime = currentTime - (Integer) curLine.get("time");
|
int driftTime = currentTime - (int) curLine.get("time");
|
||||||
Log.e("Lyric", "driftTime: " + driftTime);
|
// Log.d("Lyric", "driftTime: " + driftTime);
|
||||||
|
|
||||||
if (driftTime >= 0 || curLineNum == 0) {
|
if (driftTime >= 0 || curLineNum == 0) {
|
||||||
delay = (Integer) nextLine.get("time") - (Integer) curLine.get("time") - driftTime;
|
delay = (int) nextLine.get("time") - (int) curLine.get("time") - driftTime;
|
||||||
Log.e("Lyric", "delay: " + delay + " driftTime: " + driftTime);
|
// Log.d("Lyric", "delay: " + delay + " driftTime: " + driftTime);
|
||||||
if (delay > 0) {
|
if (delay > 0) {
|
||||||
if (!isOffseted && delay >= offset) {
|
if (!isOffered && delay >= offset) {
|
||||||
delay -= offset;
|
delay -= offset;
|
||||||
isOffseted = true;
|
isOffered = true;
|
||||||
|
}
|
||||||
|
if (isPlay) {
|
||||||
|
startTimeout(() -> {
|
||||||
|
if (tempPause) {
|
||||||
|
tempPaused = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
refresh();
|
||||||
|
}, delay);
|
||||||
}
|
}
|
||||||
startTimeout(() -> {
|
|
||||||
refresh();
|
|
||||||
}, delay);
|
|
||||||
onPlay(curLineNum, (String) curLine.get("text"));
|
onPlay(curLineNum, (String) curLine.get("text"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5,20 +5,29 @@ import android.content.Context;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
|
import android.util.TypedValue;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.Arguments;
|
||||||
import com.facebook.react.bridge.ReactApplicationContext;
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
|
import com.facebook.react.bridge.WritableMap;
|
||||||
|
|
||||||
|
import cn.toside.music.mobile.R;
|
||||||
|
|
||||||
|
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
|
||||||
public class LyricView extends Activity implements View.OnTouchListener {
|
public class LyricView extends Activity implements View.OnTouchListener {
|
||||||
TextView textView = null;
|
TextView textView = null;
|
||||||
WindowManager windowManager = null;
|
WindowManager windowManager = null;
|
||||||
WindowManager.LayoutParams layoutParams = null;
|
WindowManager.LayoutParams layoutParams = null;
|
||||||
ReactApplicationContext reactContext;
|
final private ReactApplicationContext reactContext;
|
||||||
|
final private LyricEvent lyricEvent;
|
||||||
|
|
||||||
private int winWidth = 0;
|
private int winWidth = 0;
|
||||||
|
|
||||||
@ -28,14 +37,22 @@ public class LyricView extends Activity implements View.OnTouchListener {
|
|||||||
private float nowY;
|
private float nowY;
|
||||||
private float tranX; //悬浮窗移动位置的相对值
|
private float tranX; //悬浮窗移动位置的相对值
|
||||||
private float tranY;
|
private float tranY;
|
||||||
|
private int prevViewX = 0;
|
||||||
|
private int prevViewY = 0;
|
||||||
|
|
||||||
private float preY = 0;
|
private float preY = 0;
|
||||||
// private static boolean isVibrated = false;
|
// private static boolean isVibrated = false;
|
||||||
|
|
||||||
public static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE = 5469;
|
LyricView(ReactApplicationContext reactContext, LyricEvent lyricEvent) {
|
||||||
|
|
||||||
LyricView(ReactApplicationContext reactContext) {
|
|
||||||
this.reactContext = reactContext;
|
this.reactContext = reactContext;
|
||||||
|
this.lyricEvent = lyricEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendPositionEvent(int x, int y) {
|
||||||
|
WritableMap params = Arguments.createMap();
|
||||||
|
params.putInt("x", x);
|
||||||
|
params.putInt("y", y);
|
||||||
|
lyricEvent.sendEvent(lyricEvent.SET_VIEW_POSITION, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void permission(){
|
// public void permission(){
|
||||||
@ -58,7 +75,7 @@ public class LyricView extends Activity implements View.OnTouchListener {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public void showLyricView(boolean isLock) {
|
public void showLyricView(boolean isLock, String themeColor, int lyricViewX, int lyricViewY) {
|
||||||
if (windowManager == null) {
|
if (windowManager == null) {
|
||||||
windowManager = (WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE);
|
windowManager = (WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE);
|
||||||
//设置TextView的属性
|
//设置TextView的属性
|
||||||
@ -66,7 +83,7 @@ public class LyricView extends Activity implements View.OnTouchListener {
|
|||||||
|
|
||||||
DisplayMetrics outMetrics = new DisplayMetrics();
|
DisplayMetrics outMetrics = new DisplayMetrics();
|
||||||
windowManager.getDefaultDisplay().getMetrics(outMetrics);
|
windowManager.getDefaultDisplay().getMetrics(outMetrics);
|
||||||
winWidth = (int)(outMetrics.widthPixels * 0.6);
|
winWidth = (int)(outMetrics.widthPixels * 0.92);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注意,悬浮窗只有一个,而当打开应用的时候才会产生悬浮窗,所以要判断悬浮窗是否已经存在,
|
// 注意,悬浮窗只有一个,而当打开应用的时候才会产生悬浮窗,所以要判断悬浮窗是否已经存在,
|
||||||
@ -77,14 +94,15 @@ public class LyricView extends Activity implements View.OnTouchListener {
|
|||||||
// 使用Application context
|
// 使用Application context
|
||||||
// 创建UI控件,避免Activity销毁导致上下文出现问题,因为现在的悬浮窗是系统级别的,不依赖与Activity存在
|
// 创建UI控件,避免Activity销毁导致上下文出现问题,因为现在的悬浮窗是系统级别的,不依赖与Activity存在
|
||||||
//创建自定义的TextView
|
//创建自定义的TextView
|
||||||
View view = new View(reactContext);
|
|
||||||
textView = new TextView(reactContext);
|
textView = new TextView(reactContext);
|
||||||
textView.setText("LX Music ^-^");
|
textView.setText("LX Music ^-^");
|
||||||
textView.setTextColor(Color.rgb(205, 220, 57));
|
textView.setTextSize(18);
|
||||||
|
// textView.setGravity(Gravity.CENTER);
|
||||||
|
textView.setTextColor(Color.parseColor(themeColor));
|
||||||
textView.setShadowLayer(1, 0, 0, Color.BLACK);
|
textView.setShadowLayer(1, 0, 0, Color.BLACK);
|
||||||
|
textView.setMaxLines(2);
|
||||||
|
textView.setEllipsize(TextUtils.TruncateAt.END);
|
||||||
|
|
||||||
|
|
||||||
// textView.setBackgroundColor(0x66000000);
|
|
||||||
//监听 OnTouch 事件 为了实现"移动歌词"功能
|
//监听 OnTouch 事件 为了实现"移动歌词"功能
|
||||||
textView.setOnTouchListener(this);
|
textView.setOnTouchListener(this);
|
||||||
|
|
||||||
@ -94,9 +112,16 @@ public class LyricView extends Activity implements View.OnTouchListener {
|
|||||||
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT :
|
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT :
|
||||||
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||||
|
|
||||||
layoutParams.flags = isLock
|
// layoutParams.flags = isLock
|
||||||
? WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
|
// ? WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
|
||||||
: WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
|
// : WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
|
||||||
|
if (isLock) {
|
||||||
|
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||||
|
textView.setBackgroundColor(Color.TRANSPARENT);
|
||||||
|
} else {
|
||||||
|
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
|
||||||
|
textView.setBackgroundResource(R.drawable.rounded_corner);
|
||||||
|
}
|
||||||
|
|
||||||
// TYPE_SYSTEM_ALERT 系统提示,它总是出现在应用程序窗口之上
|
// TYPE_SYSTEM_ALERT 系统提示,它总是出现在应用程序窗口之上
|
||||||
// TYPE_SYSTEM_OVERLAY 系统顶层窗口。显示在其他一切内容之上。此窗口不能获得输入焦点,否则影响锁屏
|
// TYPE_SYSTEM_OVERLAY 系统顶层窗口。显示在其他一切内容之上。此窗口不能获得输入焦点,否则影响锁屏
|
||||||
@ -105,15 +130,16 @@ public class LyricView extends Activity implements View.OnTouchListener {
|
|||||||
layoutParams.gravity = Gravity.TOP | Gravity.CENTER_VERTICAL; //显示在屏幕上中部
|
layoutParams.gravity = Gravity.TOP | Gravity.CENTER_VERTICAL; //显示在屏幕上中部
|
||||||
|
|
||||||
//显示位置与指定位置的相对位置差
|
//显示位置与指定位置的相对位置差
|
||||||
layoutParams.x = 0;
|
layoutParams.x = this.prevViewX = lyricViewX;
|
||||||
layoutParams.y = 0;
|
layoutParams.y = this.prevViewY = lyricViewY;
|
||||||
//悬浮窗的宽高
|
//悬浮窗的宽高
|
||||||
// layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
// layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
// layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
// layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
// layoutParams.width= DisplayUtil.dp2px(mContext,55);
|
// layoutParams.width= DisplayUtil.dp2px(mContext,55);
|
||||||
// layoutParams.height= DisplayUtil.dp2px(mContext,55);
|
// layoutParams.height= DisplayUtil.dp2px(mContext,55);
|
||||||
layoutParams.width = winWidth;
|
layoutParams.width = MATCH_PARENT;
|
||||||
layoutParams.height = 80;
|
// layoutParams.height = 100;
|
||||||
|
layoutParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, reactContext.getResources().getDisplayMetrics());
|
||||||
|
|
||||||
//设置透明
|
//设置透明
|
||||||
layoutParams.format = PixelFormat.TRANSPARENT;
|
layoutParams.format = PixelFormat.TRANSPARENT;
|
||||||
@ -123,6 +149,7 @@ public class LyricView extends Activity implements View.OnTouchListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setLyric(String text) {
|
public void setLyric(String text) {
|
||||||
|
if (textView == null) return;
|
||||||
textView.setText(text);
|
textView.setText(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +185,7 @@ public class LyricView extends Activity implements View.OnTouchListener {
|
|||||||
break;
|
break;
|
||||||
case MotionEvent.ACTION_UP:
|
case MotionEvent.ACTION_UP:
|
||||||
// float dy = nowY - preY;
|
// float dy = nowY - preY;
|
||||||
// Log.e("Lyric","dy: " + dy);
|
// Log.d("Lyric","dy: " + dy);
|
||||||
// if (isVibrated){
|
// if (isVibrated){
|
||||||
// if (dy > 10){
|
// if (dy > 10){
|
||||||
// //down
|
// //down
|
||||||
@ -175,6 +202,11 @@ public class LyricView extends Activity implements View.OnTouchListener {
|
|||||||
//根据移动的位置来判断
|
//根据移动的位置来判断
|
||||||
// dy = 0;
|
// dy = 0;
|
||||||
tranY = 0;
|
tranY = 0;
|
||||||
|
if (layoutParams.x != prevViewX || layoutParams.y != prevViewX) {
|
||||||
|
prevViewX = layoutParams.x;
|
||||||
|
prevViewY = layoutParams.y;
|
||||||
|
sendPositionEvent(prevViewX, prevViewY);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -183,12 +215,20 @@ public class LyricView extends Activity implements View.OnTouchListener {
|
|||||||
public void lockView() {
|
public void lockView() {
|
||||||
if (windowManager == null || textView == null) return;
|
if (windowManager == null || textView == null) return;
|
||||||
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||||
|
textView.setBackgroundColor(Color.TRANSPARENT);
|
||||||
windowManager.updateViewLayout(textView, layoutParams);
|
windowManager.updateViewLayout(textView, layoutParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unlockView() {
|
public void unlockView() {
|
||||||
if (windowManager == null || textView == null) return;
|
if (windowManager == null || textView == null) return;
|
||||||
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
|
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
|
||||||
|
textView.setBackgroundResource(R.drawable.rounded_corner);
|
||||||
|
windowManager.updateViewLayout(textView, layoutParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(String color) {
|
||||||
|
if (windowManager == null || textView == null) return;
|
||||||
|
textView.setTextColor(Color.parseColor(color));
|
||||||
windowManager.updateViewLayout(textView, layoutParams);
|
windowManager.updateViewLayout(textView, layoutParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
android/app/src/main/res/drawable/rounded_corner.xml
Normal file
12
android/app/src/main/res/drawable/rounded_corner.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="#29000000" />
|
||||||
|
|
||||||
|
<padding
|
||||||
|
android:left="1dp"
|
||||||
|
android:right="1dp"
|
||||||
|
android:bottom="1dp"
|
||||||
|
android:top="1dp" />
|
||||||
|
|
||||||
|
<corners android:radius="4dp" />
|
||||||
|
</shape>
|
7
index.js
7
index.js
@ -17,7 +17,7 @@ import { action as playerAction } from '@/store/modules/player'
|
|||||||
import { action as listAction } from '@/store/modules/list'
|
import { action as listAction } from '@/store/modules/list'
|
||||||
import { init as initMusicTools } from '@/utils/music'
|
import { init as initMusicTools } from '@/utils/music'
|
||||||
import { init as initLyric, toggleTranslation } from '@/utils/lyric'
|
import { init as initLyric, toggleTranslation } from '@/utils/lyric'
|
||||||
import { showLyric } from '@/utils/lyricDesktop'
|
import { showLyric, onPositionChange } from '@/utils/lyricDesktop'
|
||||||
import { init as initI18n, supportedLngs } from '@/plugins/i18n'
|
import { init as initI18n, supportedLngs } from '@/plugins/i18n'
|
||||||
import { deviceLanguage, getPlayInfo, toast } from '@/utils/tools'
|
import { deviceLanguage, getPlayInfo, toast } from '@/utils/tools'
|
||||||
import { LIST_ID_PLAY_TEMP } from '@/config/constant'
|
import { LIST_ID_PLAY_TEMP } from '@/config/constant'
|
||||||
@ -44,7 +44,10 @@ const init = () => {
|
|||||||
let setting = store.getState().common.setting
|
let setting = store.getState().common.setting
|
||||||
toggleTranslation(setting.player.isShowTranslation)
|
toggleTranslation(setting.player.isShowTranslation)
|
||||||
if (setting.sync.enable) connect()
|
if (setting.sync.enable) connect()
|
||||||
if (setting.desktopLyric.enable) showLyric(setting.desktopLyric.isLock)
|
if (setting.desktopLyric.enable) showLyric(setting.desktopLyric.isLock, setting.desktopLyric.theme, setting.desktopLyric.position.x, setting.desktopLyric.position.y)
|
||||||
|
onPositionChange(position => {
|
||||||
|
store.dispatch(commonAction.setDesktopLyricPosition(position))
|
||||||
|
})
|
||||||
|
|
||||||
let lang = setting.langId
|
let lang = setting.langId
|
||||||
let needSetLang = false
|
let needSetLang = false
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// const { isMac } = require('./utils')
|
// const { isMac } = require('./utils')
|
||||||
|
|
||||||
const defaultSetting = {
|
const defaultSetting = {
|
||||||
version: '1.8',
|
version: '1.10',
|
||||||
player: {
|
player: {
|
||||||
togglePlayMethod: 'listLoop',
|
togglePlayMethod: 'listLoop',
|
||||||
highQuality: false,
|
highQuality: false,
|
||||||
@ -17,11 +17,13 @@ const defaultSetting = {
|
|||||||
desktopLyric: {
|
desktopLyric: {
|
||||||
enable: false,
|
enable: false,
|
||||||
isLock: false,
|
isLock: false,
|
||||||
|
theme: 'green',
|
||||||
// width: 380,
|
// width: 380,
|
||||||
// height: 420,
|
// height: 420,
|
||||||
// x: null,
|
position: {
|
||||||
// y: null,
|
x: 0,
|
||||||
// theme: 0,
|
y: 0,
|
||||||
|
},
|
||||||
// style: {
|
// style: {
|
||||||
// fontSize: 120,
|
// fontSize: 120,
|
||||||
// opacity: 95,
|
// opacity: 95,
|
||||||
|
68
src/screens/Home/Setting/LyricDesktop/Theme.js
Normal file
68
src/screens/Home/Setting/LyricDesktop/Theme.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import React, { memo, useMemo } from 'react'
|
||||||
|
|
||||||
|
import { StyleSheet, View, TouchableOpacity } from 'react-native'
|
||||||
|
import { useGetter, useDispatch } from '@/store'
|
||||||
|
|
||||||
|
import SubTitle from '../components/SubTitle'
|
||||||
|
import { useTranslation } from '@/plugins/i18n'
|
||||||
|
import { themes } from '@/utils/lyricDesktop'
|
||||||
|
|
||||||
|
const useActive = id => {
|
||||||
|
const themeDesktopLyric = useGetter('common', 'themeDesktopLyric')
|
||||||
|
const isActive = useMemo(() => themeDesktopLyric == id, [themeDesktopLyric, id])
|
||||||
|
return isActive
|
||||||
|
}
|
||||||
|
|
||||||
|
const ThemeItem = ({ id, color, setTheme }) => {
|
||||||
|
const theme = useGetter('common', 'theme')
|
||||||
|
const isActive = useActive(id)
|
||||||
|
return (
|
||||||
|
<TouchableOpacity style={styles.item} activeOpacity={0.5} onPress={() => setTheme(id)}>
|
||||||
|
<View style={{ ...styles.colorContent, backgroundColor: theme.primary, borderColor: isActive ? color : 'transparent' }}>
|
||||||
|
<View style={{ ...styles.image, backgroundColor: color }}></View>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(() => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const setThemeDesktopLyric = useDispatch('common', 'setThemeDesktopLyric')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SubTitle title={t('setting_basic_theme')}>
|
||||||
|
<View style={styles.list}>
|
||||||
|
{
|
||||||
|
themes.map(({ id, value }) => <ThemeItem key={id} color={value} id={id} setTheme={setThemeDesktopLyric} />)
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
</SubTitle>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
list: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
marginRight: 15,
|
||||||
|
marginTop: 5,
|
||||||
|
alignItems: 'center',
|
||||||
|
width: 26,
|
||||||
|
// backgroundColor: 'rgba(0,0,0,0.2)',
|
||||||
|
},
|
||||||
|
colorContent: {
|
||||||
|
width: 26,
|
||||||
|
height: 26,
|
||||||
|
borderRadius: 4,
|
||||||
|
borderWidth: 1.6,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
borderRadius: 4,
|
||||||
|
},
|
||||||
|
})
|
@ -3,6 +3,7 @@ import React, { memo } from 'react'
|
|||||||
import Section from '../components/Section'
|
import Section from '../components/Section'
|
||||||
import IsShowLyric from './IsShowLyric'
|
import IsShowLyric from './IsShowLyric'
|
||||||
import IsLockLyric from './IsLockLyric'
|
import IsLockLyric from './IsLockLyric'
|
||||||
|
import Theme from './Theme'
|
||||||
import { useTranslation } from '@/plugins/i18n'
|
import { useTranslation } from '@/plugins/i18n'
|
||||||
|
|
||||||
export default memo(() => {
|
export default memo(() => {
|
||||||
@ -12,6 +13,7 @@ export default memo(() => {
|
|||||||
<Section title={t('setting_lyric_desktop')}>
|
<Section title={t('setting_lyric_desktop')}>
|
||||||
<IsShowLyric />
|
<IsShowLyric />
|
||||||
<IsLockLyric />
|
<IsLockLyric />
|
||||||
|
<Theme />
|
||||||
</Section>
|
</Section>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -39,6 +39,8 @@ export const TYPES = {
|
|||||||
setSyncStatus: null,
|
setSyncStatus: null,
|
||||||
setIsShowDesktopLyric: null,
|
setIsShowDesktopLyric: null,
|
||||||
setIsLockDesktopLyric: null,
|
setIsLockDesktopLyric: null,
|
||||||
|
setThemeDesktopLyric: null,
|
||||||
|
setDesktopLyricPosition: null,
|
||||||
}
|
}
|
||||||
for (const key of Object.keys(TYPES)) {
|
for (const key of Object.keys(TYPES)) {
|
||||||
TYPES[key] = `common__${key}`
|
TYPES[key] = `common__${key}`
|
||||||
@ -313,6 +315,23 @@ export const setIsLockDesktopLyric = flag => async(dispatch, getState) => {
|
|||||||
const { common } = getState()
|
const { common } = getState()
|
||||||
await setData(settingKey, common.setting)
|
await setData(settingKey, common.setting)
|
||||||
}
|
}
|
||||||
|
export const setThemeDesktopLyric = theme => async(dispatch, getState) => {
|
||||||
|
dispatch(playerAction.setDesktopLyricTheme(theme))
|
||||||
|
dispatch({
|
||||||
|
type: TYPES.setThemeDesktopLyric,
|
||||||
|
payload: theme,
|
||||||
|
})
|
||||||
|
const { common } = getState()
|
||||||
|
await setData(settingKey, common.setting)
|
||||||
|
}
|
||||||
|
export const setDesktopLyricPosition = position => async(dispatch, getState) => {
|
||||||
|
dispatch({
|
||||||
|
type: TYPES.setDesktopLyricPosition,
|
||||||
|
payload: position,
|
||||||
|
})
|
||||||
|
const { common } = getState()
|
||||||
|
await setData(settingKey, common.setting)
|
||||||
|
}
|
||||||
|
|
||||||
export const setIsEnableSync = flag => async(dispatch, getState) => {
|
export const setIsEnableSync = flag => async(dispatch, getState) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
|
@ -44,6 +44,8 @@ export const sourceNameType = state => state.common.setting.sourceNameType
|
|||||||
|
|
||||||
export const isEnableDesktopLyric = state => state.common.setting.desktopLyric.enable
|
export const isEnableDesktopLyric = state => state.common.setting.desktopLyric.enable
|
||||||
export const isLockDesktopLyric = state => state.common.setting.desktopLyric.isLock
|
export const isLockDesktopLyric = state => state.common.setting.desktopLyric.isLock
|
||||||
|
export const themeDesktopLyric = state => state.common.setting.desktopLyric.theme
|
||||||
|
export const desktopLyricPosition = state => state.common.setting.desktopLyric.position
|
||||||
|
|
||||||
export const timeoutExit = state => state.common.setting.player.timeoutExit
|
export const timeoutExit = state => state.common.setting.player.timeoutExit
|
||||||
export const timeoutExitPlayed = state => state.common.setting.player.timeoutExitPlayed
|
export const timeoutExitPlayed = state => state.common.setting.player.timeoutExitPlayed
|
||||||
|
@ -314,6 +314,30 @@ const mutations = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[TYPES.setThemeDesktopLyric](state, theme) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
setting: {
|
||||||
|
...state.setting,
|
||||||
|
desktopLyric: {
|
||||||
|
...state.setting.desktopLyric,
|
||||||
|
theme,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[TYPES.setDesktopLyricPosition](state, position) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
setting: {
|
||||||
|
...state.setting,
|
||||||
|
desktopLyric: {
|
||||||
|
...state.setting.desktopLyric,
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
[TYPES.setVersionInfo](state, versionInfo) {
|
[TYPES.setVersionInfo](state, versionInfo) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
@ -18,7 +18,7 @@ import { getRandom } from '@/utils'
|
|||||||
import { getMusicUrl, saveMusicUrl, getLyric, saveLyric, assertApiSupport, savePlayInfo, saveList } from '@/utils/tools'
|
import { getMusicUrl, saveMusicUrl, getLyric, saveLyric, assertApiSupport, savePlayInfo, saveList } from '@/utils/tools'
|
||||||
import { playInfo as playInfoGetter } from './getter'
|
import { playInfo as playInfoGetter } from './getter'
|
||||||
import { play as lrcPlay, setLyric, pause as lrcPause, toggleTranslation as lrcToggleTranslation } from '@/utils/lyric'
|
import { play as lrcPlay, setLyric, pause as lrcPause, toggleTranslation as lrcToggleTranslation } from '@/utils/lyric'
|
||||||
import { showLyric, hideLyric, setLyric as lrcdSetLyric, toggleLock } from '@/utils/lyricDesktop'
|
import { showLyric, hideLyric, setLyric as lrcdSetLyric, toggleLock, setTheme } from '@/utils/lyricDesktop'
|
||||||
import { action as listAction } from '@/store/modules/list'
|
import { action as listAction } from '@/store/modules/list'
|
||||||
import { LIST_ID_PLAY_LATER } from '@/config/constant'
|
import { LIST_ID_PLAY_LATER } from '@/config/constant'
|
||||||
// import { defaultList } from '../list/getter'
|
// import { defaultList } from '../list/getter'
|
||||||
@ -782,11 +782,12 @@ export const toggleTranslation = isShow => async(dispatch, getState) => {
|
|||||||
export const toggleDesktopLyric = isShow => async(dispatch, getState) => {
|
export const toggleDesktopLyric = isShow => async(dispatch, getState) => {
|
||||||
if (isShow) {
|
if (isShow) {
|
||||||
const { common, player } = getState()
|
const { common, player } = getState()
|
||||||
|
const desktopLyric = common.setting.desktopLyric
|
||||||
const [{ lyric, tlyric }] = await Promise.all([
|
const [{ lyric, tlyric }] = await Promise.all([
|
||||||
_playMusicInfo
|
_playMusicInfo
|
||||||
? getLyric(_playMusicInfo).catch(() => ({ lyric: '', tlyric: '' }))
|
? getLyric(_playMusicInfo).catch(() => ({ lyric: '', tlyric: '' }))
|
||||||
: Promise.resolve({ lyric: '', tlyric: '' }),
|
: Promise.resolve({ lyric: '', tlyric: '' }),
|
||||||
showLyric(common.setting.desktopLyric.isLock),
|
showLyric(desktopLyric.isLock, desktopLyric.theme, desktopLyric.position.x, desktopLyric.position.y),
|
||||||
])
|
])
|
||||||
await lrcdSetLyric(lyric, tlyric)
|
await lrcdSetLyric(lyric, tlyric)
|
||||||
if (player.status == STATUS.playing && !player.isGettingUrl) {
|
if (player.status == STATUS.playing && !player.isGettingUrl) {
|
||||||
@ -802,6 +803,9 @@ export const toggleDesktopLyric = isShow => async(dispatch, getState) => {
|
|||||||
export const toggleDesktopLyricLock = isLock => async(dispatch, getState) => {
|
export const toggleDesktopLyricLock = isLock => async(dispatch, getState) => {
|
||||||
toggleLock(isLock)
|
toggleLock(isLock)
|
||||||
}
|
}
|
||||||
|
export const setDesktopLyricTheme = theme => async(dispatch, getState) => {
|
||||||
|
setTheme(theme)
|
||||||
|
}
|
||||||
|
|
||||||
export const checkPlayList = listIds => async(dispatch, getState) => {
|
export const checkPlayList = listIds => async(dispatch, getState) => {
|
||||||
const { player, list: listState } = getState()
|
const { player, list: listState } = getState()
|
||||||
|
@ -1,17 +1,31 @@
|
|||||||
import { NativeModules } from 'react-native'
|
import { NativeModules, NativeEventEmitter } from 'react-native'
|
||||||
|
|
||||||
const { LyricModule } = NativeModules
|
const { LyricModule } = NativeModules
|
||||||
|
|
||||||
let isShowLyric = false
|
let isShowLyric = false
|
||||||
|
|
||||||
|
|
||||||
|
export const themes = [
|
||||||
|
{ id: 'green', value: '#07c556' },
|
||||||
|
{ id: 'yellow', value: '#fffa12' },
|
||||||
|
{ id: 'blue', value: '#19b5fe' },
|
||||||
|
{ id: 'red', value: '#ff1222' },
|
||||||
|
{ id: 'pink', value: '#f1828d' },
|
||||||
|
{ id: 'purple', value: '#c851d4' },
|
||||||
|
{ id: 'orange', value: '#ffad12' },
|
||||||
|
{ id: 'grey', value: '#bdc3c7' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const getThemeColor = themeId => (themes.find(t => t.id == themeId) || themes[0]).value
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* show lyric
|
* show lyric
|
||||||
* @param {Number} isLock is lock lyric window
|
* @param {Number} isLock is lock lyric window
|
||||||
* @returns {Promise} Promise
|
* @returns {Promise} Promise
|
||||||
*/
|
*/
|
||||||
export const showLyric = (isLock = false) => {
|
export const showLyric = (isLock = false, themeId, lyricViewX, lyricViewY) => {
|
||||||
if (isShowLyric) return Promise.resolve()
|
if (isShowLyric) return Promise.resolve()
|
||||||
return LyricModule.showLyric(isLock).then(() => {
|
return LyricModule.showLyric(isLock, getThemeColor(themeId), lyricViewX, lyricViewY).then(() => {
|
||||||
isShowLyric = true
|
isShowLyric = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -78,3 +92,20 @@ export const toggleLock = isLock => {
|
|||||||
return LyricModule.toggleLock(isLock)
|
return LyricModule.toggleLock(isLock)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const setTheme = themeId => {
|
||||||
|
if (!isShowLyric) return Promise.resolve()
|
||||||
|
return LyricModule.setColor(getThemeColor(themeId))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const onPositionChange = callback => {
|
||||||
|
console.log('onPositionChange')
|
||||||
|
const eventEmitter = new NativeEventEmitter(LyricModule)
|
||||||
|
const eventListener = eventEmitter.addListener('set-position', event => {
|
||||||
|
callback(event)
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
eventListener.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user