mirror of
https://github.com/ikun0014/lx-music-mobile.git
synced 2025-07-03 14:52:09 +08:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
65e8af4d6b
@ -1,4 +1,4 @@
|
||||
package com.ikunshare.music.mobile.lyric;
|
||||
package cn.toside.music.mobile.lyric;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
@ -7,8 +7,10 @@ import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -20,12 +22,14 @@ public class Lyric extends LyricPlayer {
|
||||
LyricEvent lyricEvent = null;
|
||||
ReactApplicationContext reactAppContext;
|
||||
|
||||
boolean isShowLyric = false;
|
||||
// String lastText = "LX Music Mod ^-^";
|
||||
boolean isRunPlayer = false;
|
||||
// String lastText = "LX Music ^-^";
|
||||
int lastLine = 0;
|
||||
List lines = new ArrayList();
|
||||
boolean isShowTranslation;
|
||||
boolean isShowRoma;
|
||||
boolean isShowLyricView = false;
|
||||
boolean isSendLyricTextEvent = false;
|
||||
String lyricText = "";
|
||||
String translationText = "";
|
||||
String romaLyricText = "";
|
||||
@ -36,6 +40,7 @@ public class Lyric extends LyricPlayer {
|
||||
this.isShowRoma = isShowRoma;
|
||||
this.playbackRate = playbackRate;
|
||||
registerScreenBroadcastReceiver();
|
||||
// checkA2DPConnection(reactContext);
|
||||
}
|
||||
|
||||
private void registerScreenBroadcastReceiver() {
|
||||
@ -65,8 +70,40 @@ public class Lyric extends LyricPlayer {
|
||||
reactAppContext.registerReceiver(screenOnOffReceiver, theFilter);
|
||||
}
|
||||
|
||||
// private void checkA2DPConnection(Context context) {
|
||||
// BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
|
||||
// if (bluetoothAdapter != null && bluetoothAdapter.isEnabled()) {
|
||||
// bluetoothAdapter.getProfileProxy(context, new BluetoothProfile.ServiceListener() {
|
||||
// @Override
|
||||
// public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||
// if (profile == BluetoothProfile.A2DP) {
|
||||
// List<BluetoothDevice> connectedDevices = proxy.getConnectedDevices();
|
||||
// if (!connectedDevices.isEmpty()) {
|
||||
// System.out.println("已连接的 A2DP 媒体设备:");
|
||||
// for (BluetoothDevice device : connectedDevices) {
|
||||
// System.out.println("设备名称: " + "地址: " + device.getAddress());
|
||||
// }
|
||||
// } else {
|
||||
// System.out.println("没有连接的 A2DP 媒体设备");
|
||||
// }
|
||||
// }
|
||||
// bluetoothAdapter.closeProfileProxy(profile, proxy);
|
||||
// }
|
||||
|
||||
// @Override
|
||||
// public void onServiceDisconnected(int profile) {
|
||||
// // 服务断开时的处理
|
||||
// System.out.println("蓝牙服务断开时的处理");
|
||||
// }
|
||||
// }, BluetoothProfile.A2DP);
|
||||
// } else {
|
||||
// System.out.println("蓝牙未开启或设备不支持蓝牙");
|
||||
// }
|
||||
// }
|
||||
|
||||
private void handleScreenOff() {
|
||||
if (!isShowLyric) return;
|
||||
if (!isRunPlayer || !isShowLyricView) return;
|
||||
setTempPause(true);
|
||||
|
||||
if (lyricView != null) {
|
||||
@ -77,30 +114,59 @@ public class Lyric extends LyricPlayer {
|
||||
}
|
||||
|
||||
private void handleScreenOn() {
|
||||
if (!isShowLyric) return;
|
||||
if (!isRunPlayer || !isShowLyricView) return;
|
||||
if (lyricView == null) lyricView = new LyricView(reactAppContext, lyricEvent);
|
||||
lyricView.runOnUiThread(() -> {
|
||||
lyricView.showLyricView();
|
||||
setViewLyric(lastLine);
|
||||
handleGetCurrentLyric(lastLine);
|
||||
setTempPause(false);
|
||||
});
|
||||
}
|
||||
|
||||
private void setViewLyric(int lineNum) {
|
||||
private void pausePlayer() {
|
||||
if (!isRunPlayer || isShowLyricView || isSendLyricTextEvent) return;
|
||||
isRunPlayer = false;
|
||||
this.pause();
|
||||
}
|
||||
|
||||
private void setCurrentLyric(String lyric, ArrayList<String> extendedLyrics) {
|
||||
if (isShowLyricView && lyricView != null) {
|
||||
lyricView.setLyric(lyric, extendedLyrics);
|
||||
}
|
||||
if (isSendLyricTextEvent) {
|
||||
WritableMap params = Arguments.createMap();
|
||||
params.putString("text", lyric);
|
||||
params.putArray("extendedLyrics", Arguments.makeNativeArray(extendedLyrics));
|
||||
lyricEvent.sendEvent(lyricEvent.LYRIC_Line_PLAY, params);
|
||||
}
|
||||
}
|
||||
private void handleGetCurrentLyric(int lineNum) {
|
||||
lastLine = lineNum;
|
||||
if (lyricView == null) return;
|
||||
if (lineNum >= 0 && lineNum < lines.size()) {
|
||||
HashMap line = (HashMap) lines.get(lineNum);
|
||||
if (line != null) {
|
||||
lyricView.setLyric((String) line.get("text"), (ArrayList<String>) line.get("extendedLyrics"));
|
||||
setCurrentLyric((String) line.get("text"), (ArrayList<String>) line.get("extendedLyrics"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
lyricView.setLyric("", new ArrayList<>(0));
|
||||
setCurrentLyric("", new ArrayList<>(0));
|
||||
}
|
||||
|
||||
public void showLyric(Bundle options, Promise promise) {
|
||||
public void setSendLyricTextEvent(boolean isSend) {
|
||||
if (isSendLyricTextEvent == isSend) return;
|
||||
isSendLyricTextEvent = isSend;
|
||||
if (isSend) {
|
||||
if (lyricEvent == null) lyricEvent = new LyricEvent(reactAppContext);
|
||||
isRunPlayer = true;
|
||||
} else {
|
||||
pausePlayer();
|
||||
}
|
||||
}
|
||||
|
||||
public void showDesktopLyric(Bundle options, Promise promise) {
|
||||
if (isShowLyricView) return;
|
||||
if (lyricEvent == null) lyricEvent = new LyricEvent(reactAppContext);
|
||||
isShowLyricView = true;
|
||||
if (lyricView == null) lyricView = new LyricView(reactAppContext, lyricEvent);
|
||||
try {
|
||||
lyricView.showLyricView(options);
|
||||
@ -109,24 +175,26 @@ public class Lyric extends LyricPlayer {
|
||||
Log.e("Lyric", e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
isShowLyric = true;
|
||||
isRunPlayer = true;
|
||||
promise.resolve(null);
|
||||
}
|
||||
|
||||
public void hideLyric() {
|
||||
this.pause();
|
||||
public void hideDesktopLyric() {
|
||||
if (!isShowLyricView) return;
|
||||
isShowLyricView = false;
|
||||
pausePlayer();
|
||||
if (lyricView != null) {
|
||||
lyricView.destroy();
|
||||
lyricView = null;
|
||||
}
|
||||
isShowLyric = false;
|
||||
}
|
||||
|
||||
private void refreshLyric() {
|
||||
if (!isRunPlayer) return;
|
||||
ArrayList<String> extendedLyrics = new ArrayList<>(2);
|
||||
if (isShowTranslation && !"".equals(translationText)) extendedLyrics.add(translationText);
|
||||
if (isShowRoma && !"".equals(romaLyricText)) extendedLyrics.add(romaLyricText);
|
||||
if (lyricView != null) super.setLyric(lyricText, extendedLyrics);
|
||||
super.setLyric(lyricText, extendedLyrics);
|
||||
}
|
||||
|
||||
public void setLyric(String lyric, String translation, String romaLyric) {
|
||||
@ -139,7 +207,7 @@ public class Lyric extends LyricPlayer {
|
||||
@Override
|
||||
public void onSetLyric(List lines) {
|
||||
this.lines = lines;
|
||||
setViewLyric(-1);
|
||||
handleGetCurrentLyric(-1);
|
||||
// for (int i = 0; i < lines.size(); i++) {
|
||||
// HashMap line = (HashMap) lines.get(i);
|
||||
// Log.d("Lyric", "onSetLyric: " +(String) line.get("text") + " " + line.get("extendedLyrics"));
|
||||
@ -148,14 +216,14 @@ public class Lyric extends LyricPlayer {
|
||||
|
||||
@Override
|
||||
public void onPlay(int lineNum) {
|
||||
setViewLyric(lineNum);
|
||||
handleGetCurrentLyric(lineNum);
|
||||
// Log.d("Lyric", lineNum + " " + text + " " + (String) line.get("translation"));
|
||||
}
|
||||
|
||||
public void pauseLyric() {
|
||||
pause();
|
||||
if (!isShowLyric) return;
|
||||
if (lyricView != null) lyricView.setLyric("", new ArrayList<>(0));
|
||||
if (!isRunPlayer) return;
|
||||
handleGetCurrentLyric(-1);
|
||||
}
|
||||
|
||||
public void lockLyric() {
|
||||
@ -199,14 +267,22 @@ public class Lyric extends LyricPlayer {
|
||||
}
|
||||
|
||||
public void setPlayedColor(String unplayColor, String playedColor, String shadowColor) {
|
||||
if (lyricView == null) return;
|
||||
lyricView.setColor(unplayColor, playedColor, shadowColor);
|
||||
}
|
||||
|
||||
public void setAlpha(float alpha) { lyricView.setAlpha(alpha); }
|
||||
public void setAlpha(float alpha) {
|
||||
if (lyricView == null) return;
|
||||
lyricView.setAlpha(alpha);
|
||||
}
|
||||
|
||||
public void setTextSize(float size) { lyricView.setTextSize(size); }
|
||||
public void setTextSize(float size) {
|
||||
if (lyricView == null) return;
|
||||
lyricView.setTextSize(size);
|
||||
}
|
||||
|
||||
public void setLyricTextPosition(String positionX, String positionY) {
|
||||
if (lyricView == null) return;
|
||||
lyricView.setLyricTextPosition(positionX, positionY);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.ikunshare.music.mobile.lyric;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
@ -10,12 +8,13 @@ import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
|
||||
public class LyricEvent {
|
||||
final String SET_VIEW_POSITION = "set-position";
|
||||
final String LYRIC_Line_PLAY = "lyric-line-play";
|
||||
|
||||
private final ReactApplicationContext reactContext;
|
||||
LyricEvent(ReactApplicationContext reactContext) { this.reactContext = reactContext; }
|
||||
|
||||
public void sendEvent(String eventName, @Nullable WritableMap params) {
|
||||
Log.d("Lyric", "senEvent: " + eventName);
|
||||
// Log.d("Lyric", "senEvent: " + eventName);
|
||||
reactContext
|
||||
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
||||
.emit(eventName, params);
|
||||
|
@ -66,14 +66,21 @@ public class LyricModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void showLyric(ReadableMap data, Promise promise) {
|
||||
public void showDesktopLyric(ReadableMap data, Promise promise) {
|
||||
if (lyric == null) lyric = new Lyric(reactContext, isShowTranslation, isShowRoma, playbackRate);
|
||||
lyric.showLyric(Arguments.toBundle(data), promise);
|
||||
lyric.showDesktopLyric(Arguments.toBundle(data), promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void hideLyric(Promise promise) {
|
||||
if (lyric != null) lyric.hideLyric();
|
||||
public void hideDesktopLyric(Promise promise) {
|
||||
if (lyric != null) lyric.hideDesktopLyric();
|
||||
promise.resolve(null);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setSendLyricTextEvent(boolean isSend, Promise promise) {
|
||||
if (lyric == null) lyric = new Lyric(reactContext, isShowTranslation, isShowRoma, playbackRate);
|
||||
lyric.setSendLyricTextEvent(isSend);
|
||||
promise.resolve(null);
|
||||
}
|
||||
|
||||
|
11697
package-lock.json
generated
11697
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@ -46,8 +46,8 @@
|
||||
"dependencies": {
|
||||
"@craftzdog/react-native-buffer": "^6.0.5",
|
||||
"@react-native-async-storage/async-storage": "^2.0.0",
|
||||
"@react-native-clipboard/clipboard": "^1.14.2",
|
||||
"@react-native-community/slider": "^4.5.3",
|
||||
"@react-native-clipboard/clipboard": "^1.14.3",
|
||||
"@react-native-community/slider": "^4.5.5",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"lrc-file-parser": "^2.4.1",
|
||||
"message2call": "^0.1.3",
|
||||
@ -65,20 +65,20 @@
|
||||
"react-native-quick-base64": "^2.1.2",
|
||||
"react-native-quick-md5": "^3.0.6",
|
||||
"rn-fetch-blob": "^0.12.0",
|
||||
"react-native-track-player": "github:lyswhut/react-native-track-player#409bfef00c16eb08f2aea35dfaf0b2fc40be0434",
|
||||
"react-native-track-player": "github:lyswhut/react-native-track-player#930681ab40fdb50f3d0eedff6ecd29b1666fd3ff",
|
||||
"react-native-vector-icons": "^10.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@babel/eslint-parser": "^7.25.1",
|
||||
"@babel/core": "^7.26.0",
|
||||
"@babel/eslint-parser": "^7.25.9",
|
||||
"@babel/plugin-proposal-export-namespace-from": "^7.18.9",
|
||||
"@babel/preset-env": "^7.25.4",
|
||||
"@babel/runtime": "^7.25.6",
|
||||
"@react-native/babel-preset": "^0.74.87",
|
||||
"@react-native/metro-config": "^0.74.87",
|
||||
"@react-native/typescript-config": "^0.74.87",
|
||||
"@babel/preset-env": "^7.26.0",
|
||||
"@babel/runtime": "^7.26.0",
|
||||
"@react-native/babel-preset": "^0.74.88",
|
||||
"@react-native/metro-config": "^0.74.88",
|
||||
"@react-native/typescript-config": "^0.74.88",
|
||||
"@tsconfig/react-native": "^3.0.5",
|
||||
"@types/react": "^18.3.8",
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/react-native": "^0.72.8",
|
||||
"@types/react-native-background-timer": "^2.0.2",
|
||||
"@types/react-native-vector-icons": "^6.4.18",
|
||||
@ -86,8 +86,8 @@
|
||||
"changelog-parser": "^3.0.1",
|
||||
"eslint-config-standard": "^17.1.0",
|
||||
"eslint-config-standard-with-typescript": "^43.0.1",
|
||||
"eslint-plugin-react": "^7.36.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"typescript": "^5.6.2"
|
||||
"eslint-plugin-react": "^7.37.2",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"typescript": "^5.6.3"
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
### 新增
|
||||
|
||||
- 新增蓝牙歌词支持,可以去 设置-播放设置-显示蓝牙歌词 启用(#615)
|
||||
|
||||
### 优化
|
||||
|
||||
- 首次使用的提示窗口可以点击背景或者返回键关闭(#577)
|
||||
|
@ -73,6 +73,7 @@ export const storageDataPrefix = {
|
||||
theme: '@theme',
|
||||
|
||||
cheatTip: '@cheat_tip',
|
||||
remoteLyricTip: '@remote_lyric_tip',
|
||||
|
||||
dislikeList: '@dislike_list',
|
||||
|
||||
|
@ -31,6 +31,7 @@ const defaultSetting: LX.AppSetting = {
|
||||
'player.isShowLyricRoma': false,
|
||||
'player.isShowNotificationImage': true,
|
||||
'player.isS2t': false,
|
||||
'player.isShowBluetoothLyric': false,
|
||||
|
||||
// 'playDetail.isZoomActiveLrc': false,
|
||||
// 'playDetail.isShowLyricProgressSetting': false,
|
||||
|
@ -14,7 +14,7 @@ import { saveData } from '@/plugins/storage'
|
||||
import { throttle } from '@/utils/common'
|
||||
import { getSelectedManagedFolder, saveFontSize, saveViewPrevState, setSelectedManagedFolder } from '@/utils/data'
|
||||
import { showPactModal as handleShowPactModal } from '@/navigation'
|
||||
import { hideLyric } from '@/utils/nativeModules/lyricDesktop'
|
||||
import { hideDesktopLyricView } from '@/utils/nativeModules/lyricDesktop'
|
||||
import { getPersistedUriList, selectManagedFolder } from '@/utils/fs'
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ export const exitApp = (reason: string) => {
|
||||
void Promise.all([
|
||||
hideDesktopLyric(),
|
||||
destroyPlayer(),
|
||||
hideLyric(),
|
||||
hideDesktopLyricView(),
|
||||
]).finally(() => {
|
||||
isDestroying = false
|
||||
utilExitApp()
|
||||
|
@ -1,6 +1,7 @@
|
||||
import {
|
||||
hideLyric,
|
||||
showLyric,
|
||||
hideDesktopLyricView,
|
||||
showDesktopLyricView,
|
||||
setSendLyricTextEvent,
|
||||
setLyric,
|
||||
play,
|
||||
pause,
|
||||
@ -25,10 +26,13 @@ import settingState from '@/store/setting/state'
|
||||
import playerState from '@/store/player/state'
|
||||
import { tranditionalize } from '@/utils/simplify-chinese-main'
|
||||
import { getPosition } from '@/plugins/player'
|
||||
export {
|
||||
onLyricLinePlay,
|
||||
} from '@/utils/nativeModules/lyricDesktop'
|
||||
|
||||
export const showDesktopLyric = async() => {
|
||||
const setting = settingState.setting
|
||||
await showLyric({
|
||||
await showDesktopLyricView({
|
||||
isShowToggleAnima: setting['desktopLyric.showToggleAnima'],
|
||||
isSingleLine: setting['desktopLyric.isSingleLine'],
|
||||
isLock: setting['desktopLyric.isLock'],
|
||||
@ -60,7 +64,7 @@ export const showDesktopLyric = async() => {
|
||||
}
|
||||
|
||||
export const hideDesktopLyric = async() => {
|
||||
return hideLyric()
|
||||
return hideDesktopLyricView()
|
||||
}
|
||||
|
||||
export const playDesktopLyric = play
|
||||
@ -91,3 +95,21 @@ export const openDesktopLyricOverlayPermissionActivity = openOverlayPermissionAc
|
||||
export const onDesktopLyricPositionChange = onPositionChange
|
||||
|
||||
|
||||
export const showRemoteLyric = async(isSend: boolean) => {
|
||||
await setSendLyricTextEvent(isSend)
|
||||
if (isSend) {
|
||||
let lrc = playerState.musicInfo.lrc ?? ''
|
||||
let tlrc = playerState.musicInfo.tlrc ?? ''
|
||||
let rlrc = playerState.musicInfo.rlrc ?? ''
|
||||
if (settingState.setting['player.isS2t']) {
|
||||
lrc = tranditionalize(lrc)
|
||||
tlrc = tranditionalize(tlrc)
|
||||
}
|
||||
await setLyric(lrc, tlrc, rlrc)
|
||||
if (playerState.isPlay && !global.lx.gettingUrlId) {
|
||||
void getPosition().then(position => {
|
||||
void play(position * 1000)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,10 +8,10 @@ import initLyric from './lyric'
|
||||
|
||||
export default async(setting: LX.AppSetting) => {
|
||||
await initPlayer(setting)
|
||||
await initLyric(setting)
|
||||
await initPlayInfo(setting)
|
||||
initPlayStatus()
|
||||
initPlayerEvent()
|
||||
initWatchList()
|
||||
initPlayProgress()
|
||||
await initLyric(setting)
|
||||
}
|
||||
|
@ -1,24 +1,51 @@
|
||||
import { init as initLyricPlayer, toggleTranslation, toggleRoma, play, pause, stop, setLyric, setPlaybackRate } from '@/core/lyric'
|
||||
import { updateSetting } from '@/core/common'
|
||||
import { onDesktopLyricPositionChange, showDesktopLyric } from '@/core/desktopLyric'
|
||||
import { onDesktopLyricPositionChange, showDesktopLyric, onLyricLinePlay, showRemoteLyric } from '@/core/desktopLyric'
|
||||
import playerState from '@/store/player/state'
|
||||
import { updateNowPlayingTitles } from '@/plugins/player/utils'
|
||||
import { setLastLyric } from '@/core/player/playInfo'
|
||||
import { state } from '@/plugins/player/playList'
|
||||
|
||||
const updateRemoteLyric = async(lrc?: string) => {
|
||||
setLastLyric(lrc)
|
||||
if (lrc == null) {
|
||||
void updateNowPlayingTitles((state.prevDuration || 0) * 1000, playerState.musicInfo.name, playerState.musicInfo.singer ?? '', playerState.musicInfo.album ?? '')
|
||||
} else {
|
||||
void updateNowPlayingTitles((state.prevDuration || 0) * 1000, lrc, `${playerState.musicInfo.name}${playerState.musicInfo.singer ? ` - ${playerState.musicInfo.singer}` : ''}`, playerState.musicInfo.album ?? '')
|
||||
}
|
||||
}
|
||||
|
||||
export default async(setting: LX.AppSetting) => {
|
||||
await initLyricPlayer()
|
||||
void setPlaybackRate(setting['player.playbackRate'])
|
||||
void toggleTranslation(setting['player.isShowLyricTranslation'])
|
||||
void toggleRoma(setting['player.isShowLyricRoma'])
|
||||
await Promise.all([
|
||||
setPlaybackRate(setting['player.playbackRate']),
|
||||
toggleTranslation(setting['player.isShowLyricTranslation']),
|
||||
toggleRoma(setting['player.isShowLyricRoma']),
|
||||
])
|
||||
|
||||
if (setting['desktopLyric.enable']) {
|
||||
showDesktopLyric().catch(() => {
|
||||
updateSetting({ 'desktopLyric.enable': false })
|
||||
})
|
||||
}
|
||||
if (setting['player.isShowBluetoothLyric']) {
|
||||
showRemoteLyric(true).catch(() => {
|
||||
updateSetting({ 'player.isShowBluetoothLyric': false })
|
||||
})
|
||||
}
|
||||
onDesktopLyricPositionChange(position => {
|
||||
updateSetting({
|
||||
'desktopLyric.position.x': position.x,
|
||||
'desktopLyric.position.y': position.y,
|
||||
})
|
||||
})
|
||||
onLyricLinePlay(({ text, extendedLyrics }) => {
|
||||
if (!text && !state.isPlaying) {
|
||||
void updateRemoteLyric()
|
||||
} else {
|
||||
void updateRemoteLyric(text)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
global.app_event.on('play', play)
|
||||
|
@ -19,7 +19,7 @@ export default () => {
|
||||
const setButtons = () => {
|
||||
// setPlayerAction(buttons)
|
||||
if (!playerState.playMusicInfo.musicInfo) return
|
||||
void updateMetaData(playerState.musicInfo, playerState.isPlay)
|
||||
void updateMetaData(playerState.musicInfo, playerState.isPlay, playerState.lastLyric)
|
||||
}
|
||||
// const updateCollectStatus = async() => {
|
||||
// // let status = !!playMusicInfo.musicInfo && await checkListExistMusic(LIST_ID_LOVE, playerState.playMusicInfo.musicInfo.id)
|
||||
|
@ -40,7 +40,7 @@ export default async(setting: LX.AppSetting) => {
|
||||
const updatePic = () => {
|
||||
if (!settingState.setting['player.isShowNotificationImage']) return
|
||||
if (playerState.playMusicInfo.musicInfo && playerState.musicInfo.pic) {
|
||||
delayUpdateMusicInfo(playerState.musicInfo)
|
||||
delayUpdateMusicInfo(playerState.musicInfo, playerState.lastLyric)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,10 @@ export const setLoadErrorPicUrl = (url: string) => {
|
||||
playerActions.setLoadErrorPicUrl(url)
|
||||
}
|
||||
|
||||
export const setLastLyric = (lrc?: string) => {
|
||||
playerActions.setLastLyric(lrc)
|
||||
}
|
||||
|
||||
export const setPlayListId = (listId: string | null) => {
|
||||
playerActions.setPlayListId(listId)
|
||||
}
|
||||
|
@ -348,6 +348,7 @@
|
||||
"setting_play_play_quality": "Prioritize playback sound quality (if supported)",
|
||||
"setting_play_s2t": "Convert the played lyrics to Traditional Chinese",
|
||||
"setting_play_save_play_time": "Remember playback progress",
|
||||
"setting_play_show_bluetooth_lyric": "Show bluetooth lyrics",
|
||||
"setting_play_show_notification_image": "Show song picture in notification bar",
|
||||
"setting_play_show_roma": "Show lyrics roman (if available)",
|
||||
"setting_play_show_translation": "Show lyrics translation (if available)",
|
||||
|
@ -349,6 +349,7 @@
|
||||
"setting_play_play_quality": "优先播放的音质(如果支持)",
|
||||
"setting_play_s2t": "将播放的歌词转繁体",
|
||||
"setting_play_save_play_time": "记住播放进度",
|
||||
"setting_play_show_bluetooth_lyric": "显示蓝牙歌词",
|
||||
"setting_play_show_notification_image": "在通知栏显示歌曲图片",
|
||||
"setting_play_show_roma": "显示歌词罗马音(如果可用)",
|
||||
"setting_play_show_translation": "显示歌词翻译(如果可用)",
|
||||
|
@ -10,8 +10,10 @@ const list: LX.Player.Track[] = []
|
||||
const defaultUserAgent = 'Mozilla/5.0 (Linux; Android 10; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Mobile Safari/537.36'
|
||||
const httpRxp = /^(https?:\/\/.+|\/.+)/
|
||||
|
||||
let isPlaying = false
|
||||
let prevDuration = -1
|
||||
export const state = {
|
||||
isPlaying: false,
|
||||
prevDuration: -1,
|
||||
}
|
||||
|
||||
const formatMusicInfo = (musicInfo: LX.Player.PlayMusic) => {
|
||||
return 'progress' in musicInfo ? {
|
||||
@ -106,22 +108,21 @@ export const getCurrentTrack = async() => {
|
||||
return list[currentTrackIndex]
|
||||
}
|
||||
|
||||
export const updateMetaData = async(musicInfo: LX.Player.MusicInfo, isPlay: boolean, force = false) => {
|
||||
if (!force && isPlay == isPlaying) {
|
||||
export const updateMetaData = async(musicInfo: LX.Player.MusicInfo, isPlay: boolean, lyric?: string, force = false) => {
|
||||
if (!force && isPlay == state.isPlaying) {
|
||||
const duration = await TrackPlayer.getDuration()
|
||||
// console.log('currentIsPlaying', prevDuration, duration)
|
||||
if (prevDuration != duration) {
|
||||
prevDuration = duration
|
||||
if (state.prevDuration != duration) {
|
||||
state.prevDuration = duration
|
||||
const trackInfo = await getCurrentTrack()
|
||||
if (trackInfo && musicInfo) {
|
||||
delayUpdateMusicInfo(musicInfo)
|
||||
delayUpdateMusicInfo(musicInfo, lyric)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const [duration, trackInfo] = await Promise.all([TrackPlayer.getDuration(), getCurrentTrack()])
|
||||
prevDuration = duration
|
||||
state.prevDuration = duration
|
||||
if (trackInfo && musicInfo) {
|
||||
delayUpdateMusicInfo(musicInfo)
|
||||
delayUpdateMusicInfo(musicInfo, lyric)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,7 +176,8 @@ export const playMusic = (musicInfo: LX.Player.PlayMusic, url: string, time: num
|
||||
// let musicId = null
|
||||
// let duration = 0
|
||||
let prevArtwork: string | undefined
|
||||
const updateMetaInfo = async(mInfo: LX.Player.MusicInfo) => {
|
||||
const updateMetaInfo = async(mInfo: LX.Player.MusicInfo, lyric?: string) => {
|
||||
console.log('updateMetaInfo', lyric)
|
||||
const isShowNotificationImage = settingState.setting['player.isShowNotificationImage']
|
||||
// const mInfo = formatMusicInfo(musicInfo)
|
||||
// console.log('+++++updateMusicPic+++++', track.artwork, track.duration)
|
||||
@ -189,16 +191,25 @@ const updateMetaInfo = async(mInfo: LX.Player.MusicInfo) => {
|
||||
// duration = global.playInfo.duration || 0
|
||||
// }
|
||||
// console.log('+++++updateMetaInfo+++++', mInfo.name)
|
||||
isPlaying = await TrackPlayer.getState() == State.Playing
|
||||
state.isPlaying = await TrackPlayer.getState() == State.Playing
|
||||
let artwork = isShowNotificationImage ? mInfo.pic ?? prevArtwork : undefined
|
||||
if (mInfo.pic) prevArtwork = mInfo.pic
|
||||
let name: string
|
||||
let singer: string
|
||||
if (!state.isPlaying || lyric == null) {
|
||||
name = mInfo.name ?? 'Unknow'
|
||||
singer = mInfo.singer ?? 'Unknow'
|
||||
} else {
|
||||
name = lyric
|
||||
singer = `${mInfo.name}${mInfo.singer ? ` - ${mInfo.singer}` : ''}`
|
||||
}
|
||||
await TrackPlayer.updateNowPlayingMetadata({
|
||||
title: mInfo.name ?? 'Unknow',
|
||||
artist: mInfo.singer ?? 'Unknow',
|
||||
title: name,
|
||||
artist: singer,
|
||||
album: mInfo.album ?? undefined,
|
||||
artwork,
|
||||
duration: prevDuration || 0,
|
||||
}, isPlaying)
|
||||
duration: state.prevDuration || 0,
|
||||
}, state.isPlaying)
|
||||
}
|
||||
|
||||
|
||||
@ -206,12 +217,13 @@ const updateMetaInfo = async(mInfo: LX.Player.MusicInfo) => {
|
||||
const debounceUpdateMetaInfoTools = {
|
||||
updateMetaPromise: Promise.resolve(),
|
||||
musicInfo: null as LX.Player.MusicInfo | null,
|
||||
debounce(fn: (musicInfo: LX.Player.MusicInfo) => void | Promise<void>) {
|
||||
debounce(fn: (musicInfo: LX.Player.MusicInfo, lyric?: string) => void | Promise<void>) {
|
||||
// let delayTimer = null
|
||||
let isDelayRun = false
|
||||
let timer: number | null = null
|
||||
let _musicInfo: LX.Player.MusicInfo | null = null
|
||||
return (musicInfo: LX.Player.MusicInfo) => {
|
||||
let _lyric: string | undefined
|
||||
return (musicInfo: LX.Player.MusicInfo, lyric?: string) => {
|
||||
// console.log('debounceUpdateMetaInfoTools', musicInfo)
|
||||
if (timer) {
|
||||
BackgroundTimer.clearTimeout(timer)
|
||||
@ -223,31 +235,34 @@ const debounceUpdateMetaInfoTools = {
|
||||
// }
|
||||
if (isDelayRun) {
|
||||
_musicInfo = musicInfo
|
||||
_lyric = lyric
|
||||
timer = BackgroundTimer.setTimeout(() => {
|
||||
timer = null
|
||||
let musicInfo = _musicInfo
|
||||
let lyric = _lyric
|
||||
_musicInfo = null
|
||||
_lyric = undefined
|
||||
if (!musicInfo) return
|
||||
// isDelayRun = false
|
||||
void fn(musicInfo)
|
||||
}, 1000)
|
||||
void fn(musicInfo, lyric)
|
||||
}, 500)
|
||||
} else {
|
||||
isDelayRun = true
|
||||
void fn(musicInfo)
|
||||
void fn(musicInfo, lyric)
|
||||
BackgroundTimer.setTimeout(() => {
|
||||
// delayTimer = null
|
||||
isDelayRun = false
|
||||
}, 1000)
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
},
|
||||
init() {
|
||||
return this.debounce(async(musicInfo: LX.Player.MusicInfo) => {
|
||||
return this.debounce(async(musicInfo: LX.Player.MusicInfo, lyric?: string) => {
|
||||
this.musicInfo = musicInfo
|
||||
return this.updateMetaPromise.then(() => {
|
||||
// console.log('run')
|
||||
if (this.musicInfo?.id === musicInfo.id) {
|
||||
this.updateMetaPromise = updateMetaInfo(musicInfo)
|
||||
this.updateMetaPromise = updateMetaInfo(musicInfo, lyric)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -166,6 +166,10 @@ export const setPause = async() => TrackPlayer.pause()
|
||||
export const setCurrentTime = async(time: number) => TrackPlayer.seekTo(time)
|
||||
export const setVolume = async(num: number) => TrackPlayer.setVolume(num)
|
||||
export const setPlaybackRate = async(num: number) => TrackPlayer.setRate(num)
|
||||
export const updateNowPlayingTitles = async(duration: number, title: string, artist: string, album: string) => {
|
||||
console.log('set playing titles', duration, title, artist, album)
|
||||
return TrackPlayer.updateNowPlayingTitles(duration, title, artist, album)
|
||||
}
|
||||
|
||||
export const resetPlay = async() => Promise.all([setPause(), setCurrentTime(0)])
|
||||
|
||||
|
@ -0,0 +1,44 @@
|
||||
import { updateSetting } from '@/core/common'
|
||||
import { useI18n } from '@/lang'
|
||||
import { createStyle, remoteLyricTip } from '@/utils/tools'
|
||||
import { memo } from 'react'
|
||||
import { View } from 'react-native'
|
||||
import { useSettingValue } from '@/store/setting/hook'
|
||||
|
||||
|
||||
import CheckBoxItem from '../../components/CheckBoxItem'
|
||||
import { showRemoteLyric } from '@/core/desktopLyric'
|
||||
import { setLastLyric } from '@/core/player/playInfo'
|
||||
import { updateNowPlayingTitles } from '@/plugins/player/utils'
|
||||
import playerState from '@/store/player/state'
|
||||
import { state } from '@/plugins/player/playList'
|
||||
|
||||
export default memo(() => {
|
||||
const t = useI18n()
|
||||
const isShowBluetoothLyric = useSettingValue('player.isShowBluetoothLyric')
|
||||
const setShowBluetoothLyric = async(isShowBluetoothLyric: boolean) => {
|
||||
if (isShowBluetoothLyric) {
|
||||
await remoteLyricTip()
|
||||
}
|
||||
updateSetting({ 'player.isShowBluetoothLyric': isShowBluetoothLyric })
|
||||
void showRemoteLyric(isShowBluetoothLyric)
|
||||
if (!isShowBluetoothLyric) {
|
||||
setLastLyric()
|
||||
void updateNowPlayingTitles((state.prevDuration || 0) * 1000, playerState.musicInfo.name, playerState.musicInfo.singer ?? '', playerState.musicInfo.album ?? '')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.content}>
|
||||
<CheckBoxItem check={isShowBluetoothLyric} onChange={setShowBluetoothLyric} label={t('setting_play_show_bluetooth_lyric')} />
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
const styles = createStyle({
|
||||
content: {
|
||||
marginTop: 5,
|
||||
},
|
||||
})
|
||||
|
@ -6,6 +6,7 @@ import IsPlayHighQuality from './IsPlayHighQuality'
|
||||
import IsHandleAudioFocus from './IsHandleAudioFocus'
|
||||
import IsEnableAudioOffload from './IsEnableAudioOffload'
|
||||
import IsAutoCleanPlayedList from './IsAutoCleanPlayedList'
|
||||
import IsShowBluetoothLyric from './IsShowBluetoothLyric'
|
||||
import IsShowNotificationImage from './IsShowNotificationImage'
|
||||
import IsShowLyricTranslation from './IsShowLyricTranslation'
|
||||
import IsShowLyricRoma from './IsShowLyricRoma'
|
||||
@ -25,6 +26,7 @@ export default memo(() => {
|
||||
{/* <IsPlayHighQuality /> */}
|
||||
<IsHandleAudioFocus />
|
||||
<IsEnableAudioOffload />
|
||||
<IsShowBluetoothLyric />
|
||||
<IsShowNotificationImage />
|
||||
<IsShowLyricTranslation />
|
||||
<IsShowLyricRoma />
|
||||
|
@ -37,7 +37,7 @@ export default () => {
|
||||
value = Math.trunc(value)
|
||||
const rate = value / 100
|
||||
void setLyricPlaybackRate(rate)
|
||||
void updateMetaData(playerState.musicInfo, playerState.isPlay, true) // 更新通知栏的播放速率
|
||||
void updateMetaData(playerState.musicInfo, playerState.isPlay, playerState.lastLyric, true) // 更新通知栏的播放速率
|
||||
if (playbackRate == value) return
|
||||
updateSetting({ 'player.playbackRate': rate })
|
||||
}
|
||||
@ -45,7 +45,7 @@ export default () => {
|
||||
if (settingState.setting['player.playbackRate'] == 1) return
|
||||
setSliderSize(100)
|
||||
void setPlaybackRate(1).then(() => {
|
||||
void updateMetaData(playerState.musicInfo, playerState.isPlay, true) // 更新通知栏的播放速率
|
||||
void updateMetaData(playerState.musicInfo, playerState.isPlay, playerState.lastLyric, true) // 更新通知栏的播放速率
|
||||
void setLyricPlaybackRate(1)
|
||||
})
|
||||
updateSetting({ 'player.playbackRate': 1 })
|
||||
|
@ -107,4 +107,7 @@ export default {
|
||||
setLoadErrorPicUrl(url: string) {
|
||||
state.loadErrorPicUrl = url
|
||||
},
|
||||
setLastLyric(lrc?: string) {
|
||||
state.lastLyric = lrc
|
||||
},
|
||||
}
|
||||
|
@ -34,6 +34,8 @@ export interface InitState {
|
||||
nowPlayTimeStr: string
|
||||
maxPlayTimeStr: string
|
||||
}
|
||||
|
||||
lastLyric: string | undefined
|
||||
}
|
||||
|
||||
const state: InitState = {
|
||||
@ -77,6 +79,8 @@ const state: InitState = {
|
||||
nowPlayTimeStr: '00:00',
|
||||
maxPlayTimeStr: '00:00',
|
||||
},
|
||||
|
||||
lastLyric: undefined,
|
||||
}
|
||||
|
||||
|
||||
|
5
src/types/app_setting.d.ts
vendored
5
src/types/app_setting.d.ts
vendored
@ -186,6 +186,11 @@ declare global {
|
||||
*/
|
||||
'player.isS2t': boolean
|
||||
|
||||
/**
|
||||
* 是否启用蓝牙歌词
|
||||
*/
|
||||
'player.isShowBluetoothLyric': boolean
|
||||
|
||||
/**
|
||||
* 播放详情页-是否缩放当前播放的歌词行
|
||||
*/
|
||||
|
@ -2,8 +2,6 @@ import { NativeModules, NativeEventEmitter } from 'react-native'
|
||||
|
||||
const { LyricModule } = NativeModules
|
||||
|
||||
let isShowLyric = false
|
||||
|
||||
// export const themes = [
|
||||
// { id: 'green', value: '#07c556' },
|
||||
// { id: 'yellow', value: '#fffa12' },
|
||||
@ -34,11 +32,19 @@ let isShowLyric = false
|
||||
const getAlpha = (num: number) => num / 100
|
||||
const getTextSize = (num: number) => num / 10
|
||||
|
||||
/**
|
||||
* 发送歌词事件
|
||||
* @param isShow
|
||||
* @returns
|
||||
*/
|
||||
export const setSendLyricTextEvent = async(isSend: boolean) => {
|
||||
return LyricModule.setSendLyricTextEvent(isSend)
|
||||
}
|
||||
|
||||
/**
|
||||
* show lyric
|
||||
*/
|
||||
export const showLyric = async({
|
||||
export const showDesktopLyricView = async({
|
||||
isShowToggleAnima,
|
||||
isSingleLine,
|
||||
width,
|
||||
@ -69,8 +75,7 @@ export const showLyric = async({
|
||||
textPositionX: LX.AppSetting['desktopLyric.textPosition.x']
|
||||
textPositionY: LX.AppSetting['desktopLyric.textPosition.y']
|
||||
}): Promise<void> => {
|
||||
if (isShowLyric) return Promise.resolve()
|
||||
return LyricModule.showLyric({
|
||||
return LyricModule.showDesktopLyric({
|
||||
isSingleLine,
|
||||
isShowToggleAnima,
|
||||
isLock,
|
||||
@ -85,19 +90,14 @@ export const showLyric = async({
|
||||
textY: textPositionY.toUpperCase(),
|
||||
width,
|
||||
maxLineNum,
|
||||
}).then(() => {
|
||||
isShowLyric = true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* hide lyric
|
||||
*/
|
||||
export const hideLyric = async(): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.hideLyric().then(() => {
|
||||
isShowLyric = false
|
||||
})
|
||||
export const hideDesktopLyricView = async(): Promise<void> => {
|
||||
return LyricModule.hideDesktopLyric()
|
||||
}
|
||||
|
||||
|
||||
@ -107,7 +107,6 @@ export const hideLyric = async(): Promise<void> => {
|
||||
* @returns {Promise} Promise
|
||||
*/
|
||||
export const play = async(time: number): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.play(time)
|
||||
}
|
||||
|
||||
@ -115,7 +114,6 @@ export const play = async(time: number): Promise<void> => {
|
||||
* pause lyric
|
||||
*/
|
||||
export const pause = async(): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.pause()
|
||||
}
|
||||
|
||||
@ -126,12 +124,10 @@ export const pause = async(): Promise<void> => {
|
||||
* @param romalrc lyric translation
|
||||
*/
|
||||
export const setLyric = async(lyric: string, translation: string, romalrc: string): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.setLyric(lyric, translation || '', romalrc || '')
|
||||
}
|
||||
|
||||
export const setPlaybackRate = async(rate: number): Promise<void> => {
|
||||
// if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.setPlaybackRate(rate)
|
||||
}
|
||||
|
||||
@ -140,7 +136,6 @@ export const setPlaybackRate = async(rate: number): Promise<void> => {
|
||||
* @param isShowTranslation is show translation
|
||||
*/
|
||||
export const toggleTranslation = async(isShowTranslation: boolean): Promise<void> => {
|
||||
// if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.toggleTranslation(isShowTranslation)
|
||||
}
|
||||
|
||||
@ -149,7 +144,6 @@ export const toggleTranslation = async(isShowTranslation: boolean): Promise<void
|
||||
* @param isShowRoma is show roma lyric
|
||||
*/
|
||||
export const toggleRoma = async(isShowRoma: boolean): Promise<void> => {
|
||||
// if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.toggleRoma(isShowRoma)
|
||||
}
|
||||
|
||||
@ -158,7 +152,6 @@ export const toggleRoma = async(isShowRoma: boolean): Promise<void> => {
|
||||
* @param isLock is lock lyric window
|
||||
*/
|
||||
export const toggleLock = async(isLock: boolean): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.toggleLock(isLock)
|
||||
}
|
||||
|
||||
@ -169,7 +162,6 @@ export const toggleLock = async(isLock: boolean): Promise<void> => {
|
||||
* @param shadowColor
|
||||
*/
|
||||
export const setColor = async(unplayColor: string, playedColor: string, shadowColor: string): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.setColor(unplayColor, playedColor, shadowColor)
|
||||
}
|
||||
|
||||
@ -178,7 +170,6 @@ export const setColor = async(unplayColor: string, playedColor: string, shadowCo
|
||||
* @param alpha text alpha
|
||||
*/
|
||||
export const setAlpha = async(alpha: number): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.setAlpha(getAlpha(alpha))
|
||||
}
|
||||
|
||||
@ -187,42 +178,34 @@ export const setAlpha = async(alpha: number): Promise<void> => {
|
||||
* @param size text size
|
||||
*/
|
||||
export const setTextSize = async(size: number): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.setTextSize(getTextSize(size))
|
||||
}
|
||||
|
||||
export const setShowToggleAnima = async(isShowToggleAnima: boolean): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.setShowToggleAnima(isShowToggleAnima)
|
||||
}
|
||||
|
||||
export const setSingleLine = async(isSingleLine: boolean): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.setSingleLine(isSingleLine)
|
||||
}
|
||||
|
||||
export const setPosition = async(x: number, y: number): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.setPosition(x, y)
|
||||
}
|
||||
|
||||
export const setMaxLineNum = async(maxLineNum: number): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.setMaxLineNum(maxLineNum)
|
||||
}
|
||||
|
||||
export const setWidth = async(width: number): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.setWidth(width)
|
||||
}
|
||||
|
||||
// export const fixViewPosition = async(): Promise<void> => {
|
||||
// if (!isShowLyric) return Promise.resolve()
|
||||
// return LyricModule.fixViewPosition()
|
||||
// }
|
||||
|
||||
export const setLyricTextPosition = async(textX: LX.AppSetting['desktopLyric.textPosition.x'], textY: LX.AppSetting['desktopLyric.textPosition.y']): Promise<void> => {
|
||||
if (!isShowLyric) return Promise.resolve()
|
||||
return LyricModule.setLyricTextPosition(textX.toUpperCase(), textY.toUpperCase())
|
||||
}
|
||||
|
||||
@ -246,3 +229,15 @@ export const onPositionChange = (handler: (position: { x: number, y: number }) =
|
||||
}
|
||||
}
|
||||
|
||||
export const onLyricLinePlay = (handler: (lineInfo: { text: string, extendedLyrics: string[] }) => void): () => void => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
const eventEmitter = new NativeEventEmitter(LyricModule)
|
||||
const eventListener = eventEmitter.addListener('lyric-line-play', event => {
|
||||
handler(event as { text: string, extendedLyrics: string[] })
|
||||
})
|
||||
|
||||
return () => {
|
||||
eventListener.remove()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -566,3 +566,17 @@ export const hitokoto = () => {
|
||||
return toast(data.hitokoto)
|
||||
})
|
||||
}
|
||||
|
||||
export const remoteLyricTip = async() => {
|
||||
const isRead = await getData<boolean>(storageDataPrefix.remoteLyricTip)
|
||||
if (isRead) return
|
||||
|
||||
return tipDialog({
|
||||
title: '有点温馨的提示',
|
||||
message: '若你将本功能用于汽车,请记住这个:\n道路千万条,安全第一条!\n道路千万条,安全第一条!!\n道路千万条,安全第一条!!!',
|
||||
btnText: '我知道了 (Close)',
|
||||
bgClose: true,
|
||||
}).then(() => {
|
||||
void saveData(storageDataPrefix.remoteLyricTip, true)
|
||||
})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user