mirror of
https://github.com/ikun0014/lx-music-mobile.git
synced 2025-07-05 21:58:56 +08:00
新增播放详情页歌词字体大小调整设置,调整横屏下的播放详情页布局
This commit is contained in:
parent
e51b1b0ee2
commit
5877d69bf7
Binary file not shown.
@ -1,11 +1,13 @@
|
||||
### 新增
|
||||
|
||||
- 同步功能新增对列表位置调整的支持(若你使用同步功能,请务必升级到此版本以上,不然会有问题)
|
||||
- 新增播放详情页歌词字体大小调整设置,可在详情页右上角的按钮进行调整
|
||||
|
||||
### 优化
|
||||
|
||||
- 修改对播放模块的调用,杜绝应用显示正在播放的歌曲与实际播放歌曲不一致的问题(这是播放模块歌曲队列与应用内歌曲队列在某些情况下出现不一致时导致的)
|
||||
- 支持PC端同步功能添加对列表顺序调整的控制,确保手动调整位置后的列表与不同的电脑同步时,列表位置不会被还原
|
||||
- 调整横屏下的播放详情页布局,提高屏幕空间利用率并使其更易操作
|
||||
|
||||
### 修复
|
||||
|
||||
|
126
src/components/common/Popup.js
Normal file
126
src/components/common/Popup.js
Normal file
@ -0,0 +1,126 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import { StyleSheet, View, Text, TouchableOpacity, StatusBar } from 'react-native'
|
||||
|
||||
import Modal from './Modal'
|
||||
import Icon from './Icon'
|
||||
import { useGetter } from '@/store'
|
||||
import { useKeyboard } from '@/utils/hooks'
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
centeredView: {
|
||||
flex: 1,
|
||||
// justifyContent: 'flex-end',
|
||||
// alignItems: 'center',
|
||||
},
|
||||
modalView: {
|
||||
elevation: 3,
|
||||
},
|
||||
header: {
|
||||
flexGrow: 0,
|
||||
flexShrink: 0,
|
||||
flexDirection: 'row',
|
||||
borderTopLeftRadius: 8,
|
||||
borderTopRightRadius: 8,
|
||||
},
|
||||
title: {
|
||||
fontSize: 13,
|
||||
paddingLeft: 5,
|
||||
paddingRight: 25,
|
||||
lineHeight: 20,
|
||||
},
|
||||
closeBtn: {
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
// borderTopRightRadius: 8,
|
||||
flexGrow: 0,
|
||||
flexShrink: 0,
|
||||
height: 30,
|
||||
width: 30,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
// backgroundColor: '#eee',
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
export default ({
|
||||
visible = false,
|
||||
hideDialog = () => {},
|
||||
keyHide = true,
|
||||
bgHide = true,
|
||||
closeBtn = true,
|
||||
position = 'bottom',
|
||||
title = '',
|
||||
children,
|
||||
}) => {
|
||||
const theme = useGetter('common', 'theme')
|
||||
const { keyboardShown, keyboardHeight } = useKeyboard()
|
||||
|
||||
const closeBtnComponent = useMemo(() => closeBtn ? <TouchableOpacity style={styles.closeBtn} onPress={hideDialog}><Icon name="close" style={{ color: theme.normal50, fontSize: 12 }} /></TouchableOpacity> : null, [closeBtn, hideDialog, theme])
|
||||
|
||||
const [centeredViewStyle, modalViewStyle] = useMemo(() => {
|
||||
switch (position) {
|
||||
case 'top':
|
||||
return [
|
||||
{ justifyContent: 'flex-start' },
|
||||
{
|
||||
width: '100%',
|
||||
maxHeight: '78%',
|
||||
minHeight: '20%',
|
||||
backgroundColor: 'white',
|
||||
paddingTop: StatusBar.currentHeight,
|
||||
},
|
||||
]
|
||||
case 'left':
|
||||
return [
|
||||
{ flexDirection: 'row', justifyContent: 'flex-start' },
|
||||
{
|
||||
minWidth: '45%',
|
||||
maxWidth: '78%',
|
||||
height: '100%',
|
||||
backgroundColor: 'white',
|
||||
paddingTop: StatusBar.currentHeight,
|
||||
},
|
||||
]
|
||||
case 'right':
|
||||
return [
|
||||
{ flexDirection: 'row', justifyContent: 'flex-end' },
|
||||
{
|
||||
minWidth: '45%',
|
||||
maxWidth: '78%',
|
||||
height: '100%',
|
||||
backgroundColor: 'white',
|
||||
paddingTop: StatusBar.currentHeight,
|
||||
},
|
||||
]
|
||||
case 'bottom':
|
||||
default:
|
||||
return [
|
||||
{ justifyContent: 'flex-end' },
|
||||
{
|
||||
width: '100%',
|
||||
maxHeight: '78%',
|
||||
minHeight: '20%',
|
||||
backgroundColor: 'white',
|
||||
borderTopLeftRadius: 8,
|
||||
borderTopRightRadius: 8,
|
||||
},
|
||||
]
|
||||
}
|
||||
}, [position])
|
||||
|
||||
return (
|
||||
<Modal visible={visible} hideModal={hideDialog} keyHide={keyHide} bgHide={bgHide} bgColor="rgba(0,0,0,0.2)">
|
||||
<StatusBar backgroundColor="rgba(0,0,0,0)" barStyle="dark-content" translucent={true} />
|
||||
<View style={{ ...styles.centeredView, ...centeredViewStyle, paddingBottom: keyboardShown ? keyboardHeight : 0 }}>
|
||||
<View style={{ ...styles.modalView, ...modalViewStyle, backgroundColor: theme.primary }} onStartShouldSetResponder={() => true}>
|
||||
<View style={styles.header}>
|
||||
<Text style={{ ...styles.title, color: theme.normal }} numberOfLines={1}>{title}</Text>
|
||||
{closeBtnComponent}
|
||||
</View>
|
||||
{children}
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
)
|
||||
}
|
37
src/components/common/Slider.js
Normal file
37
src/components/common/Slider.js
Normal file
@ -0,0 +1,37 @@
|
||||
import React, { memo } from 'react'
|
||||
|
||||
import Slider from '@react-native-community/slider'
|
||||
import { StyleSheet } from 'react-native'
|
||||
import { useGetter } from '@/store'
|
||||
|
||||
export default memo(({ value, minimumValue, maximumValue, onSlidingStart, onSlidingComplete, onValueChange, step }) => {
|
||||
const theme = useGetter('common', 'theme')
|
||||
|
||||
return (
|
||||
<Slider
|
||||
value={value}
|
||||
style={styles.slider}
|
||||
minimumValue={minimumValue}
|
||||
maximumValue={maximumValue}
|
||||
minimumTrackTintColor={theme.secondary30}
|
||||
maximumTrackTintColor={theme.secondary30}
|
||||
thumbTintColor={theme.secondary}
|
||||
onSlidingStart={onSlidingStart}
|
||||
onSlidingComplete={onSlidingComplete}
|
||||
onValueChange={onValueChange}
|
||||
step={step}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
slider: {
|
||||
flexShrink: 0,
|
||||
flexGrow: 1,
|
||||
// width: '100%',
|
||||
// maxWidth: 300,
|
||||
height: 40,
|
||||
// backgroundColor: '#eee',
|
||||
},
|
||||
})
|
@ -3,7 +3,7 @@
|
||||
// const { isMac } = require('./utils')
|
||||
|
||||
const defaultSetting = {
|
||||
version: '1.14',
|
||||
version: '1.15',
|
||||
player: {
|
||||
togglePlayMethod: 'listLoop',
|
||||
highQuality: false,
|
||||
@ -13,6 +13,16 @@ const defaultSetting = {
|
||||
timeoutExitPlayed: true,
|
||||
isHandleAudioFocus: true,
|
||||
isShowLyricTranslation: false,
|
||||
portrait: {
|
||||
style: {
|
||||
lrcFontSize: 160,
|
||||
},
|
||||
},
|
||||
landscape: {
|
||||
style: {
|
||||
lrcFontSize: 180,
|
||||
},
|
||||
},
|
||||
},
|
||||
desktopLyric: {
|
||||
enable: false,
|
||||
|
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -24,7 +24,7 @@ export default ({ playNextModes }) => {
|
||||
|
||||
const btnPrev = useMemo(() => (
|
||||
<TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playPrev}>
|
||||
<Icon name='prevMusic' style={{ color: theme.secondary10 }} size={24} />
|
||||
<Icon name='prevMusic' style={{ color: theme.secondary10 }} size={26} />
|
||||
</TouchableOpacity>
|
||||
), [playPrev, theme])
|
||||
|
||||
@ -45,12 +45,12 @@ export default ({ playNextModes }) => {
|
||||
}, [])
|
||||
const btnPlay = useMemo(() => (
|
||||
<TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={() => togglePlay(playStatus)}>
|
||||
<Icon name={playStatus == STATUS.playing ? 'pause' : 'play'} style={{ color: theme.secondary10 }} size={24} />
|
||||
<Icon name={playStatus == STATUS.playing ? 'pause' : 'play'} style={{ color: theme.secondary10 }} size={26} />
|
||||
</TouchableOpacity>
|
||||
), [playStatus, theme, togglePlay])
|
||||
const btnNext = useMemo(() => (
|
||||
<TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playNext}>
|
||||
<Icon name='nextMusic' style={{ color: theme.secondary10 }} size={24} />
|
||||
<Icon name='nextMusic' style={{ color: theme.secondary10 }} size={26} />
|
||||
</TouchableOpacity>
|
||||
), [playNext, theme])
|
||||
|
||||
@ -75,16 +75,16 @@ const styles = StyleSheet.create({
|
||||
flexGrow: 0,
|
||||
flexDirection: 'row',
|
||||
paddingLeft: 15,
|
||||
paddingRight: 15,
|
||||
// paddingRight: 15,
|
||||
},
|
||||
cotrolBtn: {
|
||||
width: 42,
|
||||
height: 42,
|
||||
width: 52,
|
||||
height: 52,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
|
||||
// backgroundColor: '#ccc',
|
||||
shadowOpacity: 1,
|
||||
textShadowRadius: 1,
|
||||
// backgroundColor: '#eee',
|
||||
},
|
||||
})
|
@ -9,13 +9,24 @@ import { onNavigationComponentDidDisappearEvent } from '@/navigation'
|
||||
|
||||
const LrcLine = memo(({ lrc, line, activeLine }) => {
|
||||
const theme = useGetter('common', 'theme')
|
||||
const playerLandscapeStyle = useGetter('common', 'playerLandscapeStyle')
|
||||
|
||||
return (
|
||||
<View style={styles.line}>
|
||||
<Text style={{ ...styles.lineText, color: activeLine == line ? theme.secondary : theme.normal30 }}>{lrc.text}</Text>
|
||||
<Text style={{
|
||||
...styles.lineText,
|
||||
fontSize: playerLandscapeStyle.lrcFontSize / 10,
|
||||
lineHeight: playerLandscapeStyle.lrcFontSize / 10 * 1.25,
|
||||
color: activeLine == line ? theme.secondary : theme.normal30,
|
||||
}}>{lrc.text}</Text>
|
||||
{
|
||||
lrc.translation
|
||||
? <Text style={{ ...styles.lineTranslationText, color: activeLine == line ? theme.secondary : theme.normal30 }}>{lrc.translation}</Text>
|
||||
? <Text style={{
|
||||
...styles.lineTranslationText,
|
||||
fontSize: playerLandscapeStyle.lrcFontSize / 10 * 0.8,
|
||||
lineHeight: playerLandscapeStyle.lrcFontSize / 10 * 0.8 * 1.25,
|
||||
color: activeLine == line ? theme.secondary : theme.normal30,
|
||||
}}>{lrc.translation}</Text>
|
||||
: null
|
||||
}
|
||||
</View>
|
||||
|
@ -34,7 +34,7 @@ export default memo(() => {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
cotrolBtn: {
|
||||
marginLeft: 5,
|
||||
marginRight: 5,
|
||||
width: 28,
|
||||
height: 28,
|
||||
justifyContent: 'center',
|
||||
|
@ -74,7 +74,7 @@ export default memo(() => {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
cotrolBtn: {
|
||||
marginLeft: 5,
|
||||
marginRight: 5,
|
||||
width: 28,
|
||||
height: 28,
|
||||
justifyContent: 'center',
|
||||
|
@ -143,7 +143,7 @@ export default memo(() => {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
cotrolBtn: {
|
||||
marginLeft: 5,
|
||||
marginRight: 5,
|
||||
width: 28,
|
||||
height: 28,
|
||||
justifyContent: 'center',
|
||||
|
@ -21,6 +21,9 @@ const styles = StyleSheet.create({
|
||||
flexGrow: 0,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingLeft: 10,
|
||||
paddingTop: 5,
|
||||
paddingBottom: 5,
|
||||
// backgroundColor: 'rgba(0,0,0,0.1)',
|
||||
},
|
||||
})
|
||||
|
@ -21,7 +21,7 @@ export default () => {
|
||||
const { curTimeStr, maxTimeStr, progress, bufferedProgress, duration } = usePlayTime()
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.container} nativeID="player">
|
||||
<View style={styles.progress}><Progress progress={progress} bufferedProgress={bufferedProgress} duration={duration} /></View>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
||||
<View style={{ flexGrow: 1, flexShrink: 1, paddingRight: 5 }} >
|
||||
@ -40,9 +40,9 @@ export default () => {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flexGrow: 1,
|
||||
flexGrow: 0,
|
||||
paddingLeft: 15,
|
||||
paddingRight: 15,
|
||||
// paddingRight: 15,
|
||||
},
|
||||
progress: {
|
||||
flexGrow: 1,
|
@ -1,34 +0,0 @@
|
||||
import React, { useCallback, memo, useMemo, useEffect } from 'react'
|
||||
import { View, Text, StyleSheet } from 'react-native'
|
||||
import { useLayout, useKeyboard } from '@/utils/hooks'
|
||||
import { useGetter, useDispatch } from '@/store'
|
||||
import { BorderWidths } from '@/theme'
|
||||
|
||||
import PlayInfo from './components/PlayInfo'
|
||||
import ControlBtn from './components/ControlBtn'
|
||||
|
||||
|
||||
export default memo(({ playNextModes }) => {
|
||||
// const { onLayout, ...layout } = useLayout()
|
||||
const theme = useGetter('common', 'theme')
|
||||
|
||||
return (
|
||||
<View style={{ ...styles.container, backgroundColor: theme.primary }} nativeID="player">
|
||||
<PlayInfo />
|
||||
<ControlBtn playNextModes={playNextModes} />
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
width: '100%',
|
||||
flexDirection: 'row',
|
||||
// paddingTop: progressContentPadding,
|
||||
// marginTop: -progressContentPadding,
|
||||
// backgroundColor: 'rgba(0, 0, 0, .1)',
|
||||
padding: 5,
|
||||
// backgroundColor: AppColors.primary,
|
||||
// backgroundColor: 'red',
|
||||
},
|
||||
})
|
@ -1,30 +1,104 @@
|
||||
import React, { memo } from 'react'
|
||||
import React, { memo, useState, useCallback } from 'react'
|
||||
|
||||
import { View, StyleSheet, StatusBar, TouchableOpacity, Text } from 'react-native'
|
||||
|
||||
import Icon from '@/components/common/Icon'
|
||||
import { useGetter, useDispatch } from '@/store'
|
||||
import { pop } from '@/navigation'
|
||||
|
||||
import Popup from '@/components/common/Popup'
|
||||
import Slider from '@/components/common/Slider'
|
||||
// import { AppColors } from '@/theme'
|
||||
|
||||
const LrcFontSizeStyles = StyleSheet.create({
|
||||
content: {
|
||||
flexGrow: 0,
|
||||
flexShrink: 1,
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'nowrap',
|
||||
alignItems: 'center',
|
||||
paddingLeft: 15,
|
||||
paddingRight: 15,
|
||||
paddingTop: 15,
|
||||
},
|
||||
})
|
||||
const LrcFontSize = () => {
|
||||
const theme = useGetter('common', 'theme')
|
||||
const playerLandscapeStyle = useGetter('common', 'playerLandscapeStyle')
|
||||
const setPlayerLandscapeStyle = useDispatch('common', 'setPlayerLandscapeStyle')
|
||||
const [sliderSize, setSliderSize] = useState(playerLandscapeStyle.lrcFontSize)
|
||||
const [isSliding, setSliding] = useState(false)
|
||||
|
||||
const handleSlidingStart = useCallback(value => {
|
||||
setSliding(true)
|
||||
}, [])
|
||||
const handleValueChange = useCallback(value => {
|
||||
setSliderSize(value)
|
||||
}, [])
|
||||
const handleSlidingComplete = useCallback(value => {
|
||||
if (playerLandscapeStyle.lrcFontSize == value) return
|
||||
setPlayerLandscapeStyle({ ...playerLandscapeStyle, lrcFontSize: value })
|
||||
setSliding(false)
|
||||
}, [playerLandscapeStyle, setPlayerLandscapeStyle])
|
||||
|
||||
return (
|
||||
<View style={LrcFontSizeStyles.content}>
|
||||
<Text style={{ color: theme.secondary10 }}>{isSliding ? sliderSize : playerLandscapeStyle.lrcFontSize}</Text>
|
||||
<Slider
|
||||
minimumValue={120}
|
||||
maximumValue={380}
|
||||
onSlidingComplete={handleSlidingComplete}
|
||||
onValueChange={handleValueChange}
|
||||
onSlidingStart={handleSlidingStart}
|
||||
step={2}
|
||||
value={playerLandscapeStyle.lrcFontSize}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const Setting = ({ visible, hide }) => {
|
||||
return (
|
||||
<Popup
|
||||
visible={visible}
|
||||
hideDialog={hide}
|
||||
position='left'
|
||||
style={{ width: '35%' }}
|
||||
>
|
||||
<LrcFontSize />
|
||||
</Popup>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(() => {
|
||||
const theme = useGetter('common', 'theme')
|
||||
const playMusicInfo = useGetter('player', 'playMusicInfo')
|
||||
const componentIds = useGetter('common', 'componentIds')
|
||||
|
||||
const [settingVisible, setSettingVisible] = useState(false)
|
||||
|
||||
const back = () => {
|
||||
pop(componentIds.playDetail)
|
||||
}
|
||||
const showSetting = () => {
|
||||
setSettingVisible(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={{ ...styles.header, backgroundColor: theme.primary }} nativeID="header">
|
||||
<StatusBar backgroundColor="rgba(0,0,0,0)" barStyle="dark-content" translucent={true} />
|
||||
<View style={{ ...styles.container }}>
|
||||
<TouchableOpacity onPress={back} style={{ ...styles.button }}>
|
||||
<TouchableOpacity onPress={back} style={styles.button}>
|
||||
<Icon name="chevron-left" style={{ color: theme.normal }} size={24} />
|
||||
</TouchableOpacity>
|
||||
{/* <Text style={{ ...styles.title, color: theme.normal }}></Text> */}
|
||||
<View style={styles.titleContent}>
|
||||
<Text numberOfLines={1} style={{ ...styles.title, color: theme.normal10 }}>{playMusicInfo.musicInfo?.name}</Text>
|
||||
<Text numberOfLines={1} style={{ ...styles.title, color: theme.normal20, fontSize: 12 }}>{playMusicInfo.musicInfo?.singer}</Text>
|
||||
</View>
|
||||
<TouchableOpacity onPress={showSetting} style={styles.button}>
|
||||
<Icon name="font-size" style={{ color: theme.normal30 }} size={24} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<Setting visible={settingVisible} hide={() => setSettingVisible(false)} />
|
||||
</View>
|
||||
)
|
||||
})
|
||||
@ -39,18 +113,20 @@ const styles = StyleSheet.create({
|
||||
flexDirection: 'row',
|
||||
// justifyContent: 'center',
|
||||
height: 40,
|
||||
paddingRight: 40,
|
||||
},
|
||||
button: {
|
||||
width: 40,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flex: 0,
|
||||
},
|
||||
titleContent: {
|
||||
flex: 1,
|
||||
},
|
||||
title: {
|
||||
flex: 1,
|
||||
lineHeight: 40,
|
||||
textAlign: 'center',
|
||||
fontSize: 16,
|
||||
// textAlign: 'center',
|
||||
fontSize: 15,
|
||||
},
|
||||
icon: {
|
||||
paddingLeft: 4,
|
||||
|
@ -6,9 +6,9 @@ import { onNavigationComponentDidDisappearEvent } from '@/navigation'
|
||||
|
||||
import Header from './components/Header'
|
||||
import Pic from './Pic'
|
||||
import Title from './Title'
|
||||
import ControlBtn from './ControlBtn'
|
||||
import Lyric from './Lyric'
|
||||
import Player from './Player'
|
||||
import PlayBar from './PlayBar'
|
||||
import MoreBtn from './MoreBtn'
|
||||
|
||||
export default memo(({ componentId, animated }) => {
|
||||
@ -38,23 +38,19 @@ export default memo(({ componentId, animated }) => {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<View style={{ flex: 1, backgroundColor: theme.primary }}>
|
||||
<View style={styles.container}>
|
||||
<View style={{ ...styles.container, backgroundColor: theme.primary }}>
|
||||
<View style={styles.left}>
|
||||
<Pic componentId={componentId} animated={animated} />
|
||||
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }} nativeID="pageIndicator">
|
||||
<Title />
|
||||
<View>
|
||||
<View style={styles.controlBtn} nativeID="pageIndicator">
|
||||
<MoreBtn />
|
||||
<ControlBtn />
|
||||
</View>
|
||||
</View>
|
||||
<PlayBar />
|
||||
</View>
|
||||
<View style={styles.right}>
|
||||
<Lyric />
|
||||
</View>
|
||||
</View>
|
||||
<Player />
|
||||
</View>
|
||||
</>
|
||||
)
|
||||
}, [animated, componentId, theme])
|
||||
@ -69,7 +65,8 @@ const styles = StyleSheet.create({
|
||||
left: {
|
||||
flex: 1,
|
||||
width: '45%',
|
||||
paddingLeft: 20,
|
||||
// paddingLeft: 15,
|
||||
paddingBottom: 10,
|
||||
// backgroundColor: '#eee',
|
||||
},
|
||||
right: {
|
||||
@ -77,4 +74,11 @@ const styles = StyleSheet.create({
|
||||
flexGrow: 0,
|
||||
flexShrink: 0,
|
||||
},
|
||||
controlBtn: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
// backgroundColor: '#eee',
|
||||
},
|
||||
})
|
||||
|
@ -8,13 +8,24 @@ import { useLrcPlay, useLrcSet } from '@/plugins/lyric'
|
||||
|
||||
const LrcLine = memo(({ lrc, line, activeLine }) => {
|
||||
const theme = useGetter('common', 'theme')
|
||||
const playerPortraitStyle = useGetter('common', 'playerPortraitStyle')
|
||||
|
||||
return (
|
||||
<View style={styles.line}>
|
||||
<Text style={{ ...styles.lineText, color: activeLine == line ? theme.secondary : theme.normal30 }}>{lrc.text}</Text>
|
||||
<Text style={{
|
||||
...styles.lineText,
|
||||
fontSize: playerPortraitStyle.lrcFontSize / 10,
|
||||
lineHeight: playerPortraitStyle.lrcFontSize / 10 * 1.25,
|
||||
color: activeLine == line ? theme.secondary : theme.normal30,
|
||||
}}>{lrc.text}</Text>
|
||||
{
|
||||
lrc.translation
|
||||
? <Text style={{ ...styles.lineTranslationText, color: activeLine == line ? theme.secondary : theme.normal30 }}>{lrc.translation}</Text>
|
||||
? <Text style={{
|
||||
...styles.lineTranslationText,
|
||||
fontSize: playerPortraitStyle.lrcFontSize / 10 * 0.8,
|
||||
lineHeight: playerPortraitStyle.lrcFontSize / 10 * 0.8 * 1.25,
|
||||
color: activeLine == line ? theme.secondary : theme.normal30,
|
||||
}}>{lrc.translation}</Text>
|
||||
: null
|
||||
}
|
||||
</View>
|
||||
@ -36,7 +47,6 @@ export default memo(() => {
|
||||
const lineRef = useRef(0)
|
||||
const linesRef = useRef([])
|
||||
const isFirstSetLrc = useRef(true)
|
||||
// const playMusicInfo = useGetter('player', 'playMusicInfo')
|
||||
// const [imgUrl, setImgUrl] = useState(null)
|
||||
// const theme = useGetter('common', 'theme')
|
||||
// const { onLayout, ...layout } = useLayout()
|
||||
@ -162,16 +172,16 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
lineText: {
|
||||
textAlign: 'center',
|
||||
fontSize: 16,
|
||||
lineHeight: 20,
|
||||
// fontSize: 16,
|
||||
// lineHeight: 20,
|
||||
// paddingTop: 5,
|
||||
// paddingBottom: 5,
|
||||
// opacity: 0,
|
||||
},
|
||||
lineTranslationText: {
|
||||
textAlign: 'center',
|
||||
fontSize: 13,
|
||||
lineHeight: 17,
|
||||
// fontSize: 13,
|
||||
// lineHeight: 17,
|
||||
paddingTop: 5,
|
||||
// paddingBottom: 5,
|
||||
},
|
||||
|
@ -4,7 +4,7 @@ import { useLayout, useKeyboard } from '@/utils/hooks'
|
||||
import { useGetter, useDispatch } from '@/store'
|
||||
import { BorderWidths } from '@/theme'
|
||||
|
||||
import Title from './components/Title'
|
||||
// import Title from './components/Title'
|
||||
import MoreBtn from './components/MoreBtn'
|
||||
import PlayInfo from './components/PlayInfo'
|
||||
import ControlBtn from './components/ControlBtn'
|
||||
@ -17,7 +17,7 @@ export default memo(({ playNextModes }) => {
|
||||
return (
|
||||
<View style={{ ...styles.container, backgroundColor: theme.primary }}>
|
||||
<View style={{ ...styles.info }} >
|
||||
<Title />
|
||||
{/* <Title /> */}
|
||||
<MoreBtn />
|
||||
</View>
|
||||
<View style={styles.status}>
|
||||
@ -43,6 +43,7 @@ const styles = StyleSheet.create({
|
||||
info: {
|
||||
flexDirection: 'row',
|
||||
paddingBottom: 10,
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
status: {
|
||||
flexDirection: 'column',
|
||||
|
@ -1,30 +1,102 @@
|
||||
import React, { memo } from 'react'
|
||||
import React, { memo, useState, useCallback } from 'react'
|
||||
|
||||
import { View, StyleSheet, StatusBar, TouchableOpacity, Text } from 'react-native'
|
||||
|
||||
import Icon from '@/components/common/Icon'
|
||||
import { useGetter, useDispatch } from '@/store'
|
||||
import { pop } from '@/navigation'
|
||||
|
||||
import Popup from '@/components/common/Popup'
|
||||
import Slider from '@/components/common/Slider'
|
||||
// import { AppColors } from '@/theme'
|
||||
|
||||
const LrcFontSizeStyles = StyleSheet.create({
|
||||
content: {
|
||||
flexGrow: 0,
|
||||
flexShrink: 1,
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'nowrap',
|
||||
alignItems: 'center',
|
||||
paddingLeft: 15,
|
||||
paddingRight: 15,
|
||||
},
|
||||
})
|
||||
const LrcFontSize = () => {
|
||||
const theme = useGetter('common', 'theme')
|
||||
const playerPortraitStyle = useGetter('common', 'playerPortraitStyle')
|
||||
const setPlayerPortraitStyle = useDispatch('common', 'setPlayerPortraitStyle')
|
||||
const [sliderSize, setSliderSize] = useState(playerPortraitStyle.lrcFontSize)
|
||||
const [isSliding, setSliding] = useState(false)
|
||||
|
||||
const handleSlidingStart = useCallback(value => {
|
||||
setSliding(true)
|
||||
}, [])
|
||||
const handleValueChange = useCallback(value => {
|
||||
setSliderSize(value)
|
||||
}, [])
|
||||
const handleSlidingComplete = useCallback(value => {
|
||||
if (playerPortraitStyle.lrcFontSize == value) return
|
||||
setPlayerPortraitStyle({ ...playerPortraitStyle, lrcFontSize: value })
|
||||
setSliding(false)
|
||||
}, [playerPortraitStyle, setPlayerPortraitStyle])
|
||||
|
||||
return (
|
||||
<View style={LrcFontSizeStyles.content}>
|
||||
<Text style={{ color: theme.secondary10 }}>{isSliding ? sliderSize : playerPortraitStyle.lrcFontSize}</Text>
|
||||
<Slider
|
||||
minimumValue={100}
|
||||
maximumValue={300}
|
||||
onSlidingComplete={handleSlidingComplete}
|
||||
onValueChange={handleValueChange}
|
||||
onSlidingStart={handleSlidingStart}
|
||||
step={2}
|
||||
value={playerPortraitStyle.lrcFontSize}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const Setting = ({ visible, hide }) => {
|
||||
return (
|
||||
<Popup
|
||||
visible={visible}
|
||||
hideDialog={hide}
|
||||
title=''
|
||||
>
|
||||
<LrcFontSize />
|
||||
</Popup>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(() => {
|
||||
const theme = useGetter('common', 'theme')
|
||||
const playMusicInfo = useGetter('player', 'playMusicInfo')
|
||||
const componentIds = useGetter('common', 'componentIds')
|
||||
|
||||
const [settingVisible, setSettingVisible] = useState(false)
|
||||
|
||||
const back = () => {
|
||||
pop(componentIds.playDetail)
|
||||
}
|
||||
const showSetting = () => {
|
||||
setSettingVisible(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={{ ...styles.header, backgroundColor: theme.primary }} nativeID="header">
|
||||
<StatusBar backgroundColor="rgba(0,0,0,0)" barStyle="dark-content" translucent={true} />
|
||||
<View style={{ ...styles.container }}>
|
||||
<TouchableOpacity onPress={back} style={{ ...styles.button }}>
|
||||
<TouchableOpacity onPress={back} style={styles.button}>
|
||||
<Icon name="chevron-left" style={{ color: theme.normal }} size={24} />
|
||||
</TouchableOpacity>
|
||||
{/* <Text style={{ ...styles.title, color: theme.normal }}></Text> */}
|
||||
<View style={styles.titleContent}>
|
||||
<Text numberOfLines={1} style={{ ...styles.title, color: theme.normal10 }}>{playMusicInfo.musicInfo?.name}</Text>
|
||||
<Text numberOfLines={1} style={{ ...styles.title, color: theme.normal20, fontSize: 12 }}>{playMusicInfo.musicInfo?.singer}</Text>
|
||||
</View>
|
||||
<TouchableOpacity onPress={showSetting} style={styles.button}>
|
||||
<Icon name="font-size" style={{ color: theme.normal30 }} size={24} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<Setting visible={settingVisible} hide={() => setSettingVisible(false)} />
|
||||
</View>
|
||||
)
|
||||
})
|
||||
@ -39,18 +111,20 @@ const styles = StyleSheet.create({
|
||||
flexDirection: 'row',
|
||||
// justifyContent: 'center',
|
||||
height: 40,
|
||||
paddingRight: 40,
|
||||
},
|
||||
button: {
|
||||
width: 40,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flex: 0,
|
||||
},
|
||||
titleContent: {
|
||||
flex: 1,
|
||||
},
|
||||
title: {
|
||||
flex: 1,
|
||||
lineHeight: 40,
|
||||
textAlign: 'center',
|
||||
fontSize: 16,
|
||||
fontSize: 15,
|
||||
},
|
||||
icon: {
|
||||
paddingLeft: 4,
|
||||
|
@ -43,6 +43,8 @@ export const TYPES = {
|
||||
setDesktopLyricPosition: null,
|
||||
setDesktopLyricTextPosition: null,
|
||||
setDesktopLyricStyle: null,
|
||||
setPlayerPortraitStyle: null,
|
||||
setPlayerLandscapeStyle: null,
|
||||
}
|
||||
for (const key of Object.keys(TYPES)) {
|
||||
TYPES[key] = `common__${key}`
|
||||
@ -369,3 +371,21 @@ export const setSyncStatus = statusInfo => async(dispatch, getState) => {
|
||||
payload: statusInfo,
|
||||
})
|
||||
}
|
||||
|
||||
export const setPlayerPortraitStyle = style => async(dispatch, getState) => {
|
||||
dispatch({
|
||||
type: TYPES.setPlayerPortraitStyle,
|
||||
payload: style,
|
||||
})
|
||||
const { common } = getState()
|
||||
await setData(settingKey, common.setting)
|
||||
}
|
||||
|
||||
export const setPlayerLandscapeStyle = style => async(dispatch, getState) => {
|
||||
dispatch({
|
||||
type: TYPES.setPlayerLandscapeStyle,
|
||||
payload: style,
|
||||
})
|
||||
const { common } = getState()
|
||||
await setData(settingKey, common.setting)
|
||||
}
|
||||
|
@ -66,3 +66,6 @@ const apiSourceListFormated = apiSourceInfo.map(api => ({
|
||||
export const apiSourceList = state => apiSourceListFormated
|
||||
|
||||
export const supportQualitys = state => apiSourceInfo.find(s => s.id == state.common.setting.apiSource).supportQualitys
|
||||
|
||||
export const playerPortraitStyle = state => state.common.setting.player.portrait.style
|
||||
export const playerLandscapeStyle = state => state.common.setting.player.landscape.style
|
||||
|
@ -413,6 +413,36 @@ const mutations = {
|
||||
if (message != null) newState.syncStatus.message = message
|
||||
return newState
|
||||
},
|
||||
[TYPES.setPlayerPortraitStyle](state, style) {
|
||||
return {
|
||||
...state,
|
||||
setting: {
|
||||
...state.setting,
|
||||
player: {
|
||||
...state.setting.player,
|
||||
portrait: {
|
||||
...state.setting.player.portrait,
|
||||
style,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
[TYPES.setPlayerLandscapeStyle](state, style) {
|
||||
return {
|
||||
...state,
|
||||
setting: {
|
||||
...state.setting,
|
||||
player: {
|
||||
...state.setting.player,
|
||||
landscape: {
|
||||
...state.setting.player.landscape,
|
||||
style,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default (state = initialState, action) =>
|
||||
|
Loading…
x
Reference in New Issue
Block a user