新增播放详情页歌词对齐方式设置

This commit is contained in:
lyswhut 2023-03-24 12:52:52 +08:00
parent 1136b13bad
commit c8e5be3a7f
21 changed files with 211 additions and 98 deletions

View File

@ -15,6 +15,7 @@
- 新增界面字体大小设置
- 新增播放器音量大小设置,可以去播放详情页-播放器设置-音量大小更改
- 新增播放器播放速率设置,可以去播放详情页-播放器设置-播放速率更改
- 新增播放详情页歌词对齐方式设置,可以去播放详情页-播放器设置-歌词对齐方式更改
- 支持wy源flac hires歌曲类型的显示
- 添加kg源评论图片展示@helloplhm-qwq
- 支持kg源搜索列表、排行榜flac hires歌曲类型的显示@helloplhm-qwq, @Folltoshe

View File

@ -23,8 +23,12 @@ const defaultSetting: LX.AppSetting = {
'player.isShowLyricRoma': false,
'player.isShowNotificationImage': true,
'player.isS2t': false,
'player.vertical.style.lrcFontSize': 160,
'player.horizontal.style.lrcFontSize': 180,
// 'playDetail.isZoomActiveLrc': false,
// 'playDetail.isShowLyricProgressSetting': false,
'playDetail.style.align': 'center',
'playDetail.vertical.style.lrcFontSize': 176,
'playDetail.horizontal.style.lrcFontSize': 180,
'desktopLyric.enable': false,
'desktopLyric.isLock': false,

View File

@ -17,8 +17,8 @@ export default (setting: any): Partial<LX.AppSetting> => {
setting['player.isShowLyricRoma'] = setting.player?.isShowLyricRoma
setting['player.isShowNotificationImage'] = setting.player?.isShowNotificationImage
setting['player.isS2t'] = setting.player?.isS2t
setting['player.portrait.style.lrcFontSize'] = setting.player?.portrait?.style?.lrcFontSize
setting['player.landscape.style.lrcFontSize'] = setting.player?.landscape?.style?.lrcFontSize
setting['playDetail.portrait.style.lrcFontSize'] = setting.player?.portrait?.style?.lrcFontSize
setting['playDetail.landscape.style.lrcFontSize'] = setting.player?.landscape?.style?.lrcFontSize
setting['desktopLyric.enable'] = setting.desktopLyric?.enable
setting['desktopLyric.isLock'] = setting.desktopLyric?.isLock
setting['desktopLyric.width'] = setting.desktopLyric?.width

View File

@ -105,6 +105,15 @@
"pause": "Pause",
"play": "Play",
"play_all": "Play all",
"play_detail_setting_lrc_align": "Lyric Alignment",
"play_detail_setting_lrc_align_center": "Center",
"play_detail_setting_lrc_align_left": "Left",
"play_detail_setting_lrc_align_right": "Right",
"play_detail_setting_lrc_font_size": "Lyric font size",
"play_detail_setting_playback_rate": "Playback rate",
"play_detail_setting_playback_rate_reset": "reset",
"play_detail_setting_title": "Player settings",
"play_detail_setting_volume": "Volume",
"play_detail_todo_tip": "What do you want? No, this function has not been implemented yet 😛, But you can try to locate the currently playing song by long pressing (only valid for playing songs in \"My List\")",
"play_later": "Play later",
"play_list_loop": "List loop playback",
@ -120,11 +129,6 @@
"player__geting_url": "Acquiring the song link...",
"player__loading": "Music loading...",
"player__refresh_url": "The URL has expired, refreshing the URL...",
"player_setting_lrc_font_size": "Lyric font size",
"player_setting_playback_rate": "Playback rate",
"player_setting_playback_rate_reset": "reset",
"player_setting_title": "Player settings",
"player_setting_volume": "Volume",
"quality_high_quality": "HQ",
"quality_lossless": "SQ",
"quality_lossless_24bit": "Hires",

View File

@ -105,6 +105,15 @@
"pause": "暂停",
"play": "播放",
"play_all": "播放全部",
"play_detail_setting_lrc_align": "歌词对齐方式",
"play_detail_setting_lrc_align_center": "居中",
"play_detail_setting_lrc_align_left": "居左",
"play_detail_setting_lrc_align_right": "居右",
"play_detail_setting_lrc_font_size": "歌词字体大小",
"play_detail_setting_playback_rate": "播放速率",
"play_detail_setting_playback_rate_reset": "重置",
"play_detail_setting_title": "播放器设置",
"play_detail_setting_volume": "音量大小",
"play_detail_todo_tip": "你想干嘛?不可以的,这个功能还没有实现哦😛,不过你可以试着长按来定位当前播放的歌曲(仅对播放“我的列表”里的歌曲有效哦)",
"play_later": "稍后播放",
"play_list_loop": "列表循环播放",
@ -120,11 +129,6 @@
"player__geting_url": "歌曲链接获取中...",
"player__loading": "音乐加载中...",
"player__refresh_url": "URL过期正在刷新URL...",
"player_setting_lrc_font_size": "歌词字体大小",
"player_setting_playback_rate": "播放速率",
"player_setting_playback_rate_reset": "重置",
"player_setting_title": "播放器设置",
"player_setting_volume": "音量大小",
"quality_high_quality": "HQ",
"quality_lossless": "SQ",
"quality_lossless_24bit": "Hires",

View File

@ -21,21 +21,24 @@ const LrcLine = memo(({ line, lineNum, activeLine }: {
activeLine: number
}) => {
const theme = useTheme()
const playerPortraitStyle = useSettingValue('player.horizontal.style.lrcFontSize')
const playerPortraitStyle = useSettingValue('playDetail.horizontal.style.lrcFontSize')
const textAlign = useSettingValue('playDetail.style.align')
const lineHeight = scaleSizeH(setSpText(playerPortraitStyle) / 10 * 1.25)
return (
<View style={styles.line}>
<Text style={{
...styles.lineText,
textAlign,
lineHeight,
}} color={activeLine == lineNum ? theme['c-primary'] : theme['c-300']} size={playerPortraitStyle / 10}>{line.text}</Text>
}} color={activeLine == lineNum ? theme['c-primary'] : theme['c-350']} size={playerPortraitStyle / 10}>{line.text}</Text>
{
line.extendedLyrics.map((lrc, index) => {
return (<Text style={{
...styles.lineTranslationText,
textAlign,
lineHeight: lineHeight * 0.8,
}} key={index} color={activeLine == lineNum ? theme['c-primary-alpha-200'] : theme['c-300']} size={playerPortraitStyle / 10 * 0.8}>{lrc}</Text>)
}} key={index} color={activeLine == lineNum ? theme['c-primary-alpha-200'] : theme['c-350']} size={playerPortraitStyle / 10 * 0.8}>{lrc}</Text>)
})
}
</View>
@ -154,7 +157,7 @@ export default () => {
ListHeaderComponent={spaceComponent}
ListFooterComponent={spaceComponent}
onScrollBeginDrag={handleScrollBeginDrag}
fadingEdgeLength={200}
fadingEdgeLength={100}
initialNumToRender={Math.max(line + 10, 10)}
onScrollToIndexFailed={handleScrollToIndexFailed}
/>
@ -164,8 +167,8 @@ export default () => {
const styles = createStyle({
container: {
flex: 1,
paddingLeft: 10,
paddingRight: 10,
paddingLeft: 20,
paddingRight: 20,
// backgroundColor: 'rgba(0,0,0,0.1)',
},
space: {

View File

@ -4,21 +4,15 @@ import { View, StyleSheet, TouchableOpacity } from 'react-native'
import { Icon } from '@/components/common/Icon'
import { pop } from '@/navigation'
// import { AppColors } from '@/theme'
// import commonState from '@/store/common/state'
import { useTheme } from '@/store/theme/hook'
import { usePlayerMusicInfo } from '@/store/player/hook'
import Text from '@/components/common/Text'
import { scaleSizeH } from '@/utils/pixelRatio'
import { HEADER_HEIGHT as _HEADER_HEIGHT, NAV_SHEAR_NATIVE_IDS } from '@/config/constant'
import commonState from '@/store/common/state'
import Popup, { type PopupType } from '@/components/common/Popup'
import { useI18n } from '@/lang'
import CommentBtn from './CommentBtn'
import Btn from './Btn'
import SettingVolume from '../../components/SettingVolume'
import SettingPlaybackRate from '../../components/SettingPlaybackRate'
import SettingLrcFontSize from '../../components/SettingLrcFontSize'
import SettingPopup, { type SettingPopupType } from '../../components/SettingPopup'
const HEADER_HEIGHT = scaleSizeH(_HEADER_HEIGHT)
@ -36,18 +30,13 @@ const Title = () => {
}
export default memo(() => {
const t = useI18n()
// const theme = useTheme()
// const [settingVisible, setSettingVisible] = useState(false)
const popupRef = useRef<PopupType>(null)
const popupRef = useRef<SettingPopupType>(null)
const back = () => {
// navigation.goBack()
void pop(commonState.componentIds.playDetail as string)
}
const showSetting = () => {
popupRef.current?.setVisible(true)
popupRef.current?.show()
}
return (
@ -60,11 +49,7 @@ export default memo(() => {
<CommentBtn />
<Btn icon="slider" onPress={showSetting} />
</View>
<Popup ref={popupRef} position="left" title={t('player_setting_title')}>
<SettingVolume />
<SettingLrcFontSize />
<SettingPlaybackRate />
</Popup>
<SettingPopup ref={popupRef} position="left" />
</View>
)
})

View File

@ -59,21 +59,24 @@ const LrcLine = memo(({ line, lineNum, activeLine }: {
activeLine: number
}) => {
const theme = useTheme()
const playerPortraitStyle = useSettingValue('player.vertical.style.lrcFontSize')
const playerPortraitStyle = useSettingValue('playDetail.vertical.style.lrcFontSize')
const textAlign = useSettingValue('playDetail.style.align')
const lineHeight = scaleSizeH(setSpText(playerPortraitStyle) / 10 * 1.25)
return (
<View style={styles.line}>
<Text style={{
...styles.lineText,
textAlign,
lineHeight,
}} color={activeLine == lineNum ? theme['c-primary'] : theme['c-300']} size={playerPortraitStyle / 10}>{line.text}</Text>
}} color={activeLine == lineNum ? theme['c-primary'] : theme['c-350']} size={playerPortraitStyle / 10}>{line.text}</Text>
{
line.extendedLyrics.map((lrc, index) => {
return (<Text style={{
...styles.lineTranslationText,
textAlign,
lineHeight: lineHeight * 0.8,
}} key={index} color={activeLine == lineNum ? theme['c-primary-alpha-200'] : theme['c-300']} size={playerPortraitStyle / 10 * 0.8}>{lrc}</Text>)
}} key={index} color={activeLine == lineNum ? theme['c-primary-alpha-200'] : theme['c-350']} size={playerPortraitStyle / 10 * 0.8}>{lrc}</Text>)
})
}
</View>
@ -192,7 +195,7 @@ export default () => {
ListHeaderComponent={spaceComponent}
ListFooterComponent={spaceComponent}
onScrollBeginDrag={handleScrollBeginDrag}
fadingEdgeLength={200}
fadingEdgeLength={100}
initialNumToRender={Math.max(line + 10, 10)}
onScrollToIndexFailed={handleScrollToIndexFailed}
/>
@ -202,8 +205,8 @@ export default () => {
const styles = createStyle({
container: {
flex: 1,
paddingLeft: 10,
paddingRight: 10,
paddingLeft: 20,
paddingRight: 20,
// backgroundColor: 'rgba(0,0,0,0.1)',
},
space: {

View File

@ -5,8 +5,8 @@ import { createStyle } from '@/utils/tools'
import { useTheme } from '@/store/theme/hook'
import { scaleSizeW } from '@/utils/pixelRatio'
export const BTN_WIDTH = scaleSizeW(32)
export const BTN_ICON_SIZE = 22
export const BTN_WIDTH = scaleSizeW(36)
export const BTN_ICON_SIZE = 24
export default ({ icon, color, onPress }: {
icon: string

View File

@ -20,10 +20,12 @@ export default () => {
const styles = createStyle({
container: {
flexShrink: 0,
flexGrow: 0,
// flexShrink: 0,
// flexGrow: 0,
width: '100%',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-evenly',
// backgroundColor: 'rgba(0,0,0,0.1)',
},
})

View File

@ -22,7 +22,6 @@ const PlayTimeMax = memo(({ timeStr }: { timeStr: string }) => {
})
export default () => {
const theme = useTheme()
const { maxPlayTimeStr, nowPlayTimeStr, progress, maxPlayTime } = useProgress()
// console.log('render playInfo')
@ -30,16 +29,12 @@ export default () => {
<>
<View style={styles.progress}><Progress progress={progress} duration={maxPlayTime} /></View>
<View style={styles.info}>
{/* <MusicName /> */}
<PlayTimeCurrent timeStr={nowPlayTimeStr} />
<View style={styles.status} >
<Status />
</View>
<View style={{ flexGrow: 0, flexShrink: 0, flexDirection: 'row' }} >
<PlayTimeCurrent timeStr={nowPlayTimeStr} />
<Text color={theme['c-500']}> / </Text>
<PlayTimeMax timeStr={maxPlayTimeStr} />
</View>
</View>
</>
)
}
@ -61,6 +56,7 @@ const styles = createStyle({
status: {
flexGrow: 1,
flexShrink: 1,
paddingRight: 5,
paddingLeft: 10,
paddingRight: 10,
},
})

View File

@ -1,7 +1,7 @@
import React from 'react'
// import { useLrcPlay } from '@/plugins/lyric'
import { useStatusText } from '@/store/player/hook'
// import { createStyle } from '@/utils/tools'
import { createStyle } from '@/utils/tools'
import Text from '@/components/common/Text'
@ -12,11 +12,11 @@ export default () => {
// const status = playerStatus.isPlay ? text : playerStatus.statusText
return <Text numberOfLines={1} size={13}>{statusText}</Text>
return <Text style={styles.text} numberOfLines={1} size={13}>{statusText}</Text>
}
// const styles = createStyle({
// text: {
// fontSize: 10,
// },
// })
const styles = createStyle({
text: {
textAlign: 'center',
},
})

View File

@ -12,16 +12,15 @@ import { NAV_SHEAR_NATIVE_IDS } from '@/config/constant'
export default memo(() => {
return (
<View style={styles.container} nativeID={NAV_SHEAR_NATIVE_IDS.playDetail_player}>
<View style={{ ...styles.info }} >
{/* <Title /> */}
<MoreBtn />
</View>
<View style={styles.status}>
<PlayInfo />
</View>
<View style={styles.control}>
<ControlBtn />
</View>
<View style={{ ...styles.info }} >
<MoreBtn />
</View>
</View>
)
})
@ -38,10 +37,11 @@ const styles = createStyle({
},
info: {
flexDirection: 'row',
paddingBottom: 10,
paddingBottom: 5,
justifyContent: 'flex-end',
},
status: {
marginTop: 10,
flexDirection: 'column',
flexGrow: 1,
flexShrink: 1,
@ -55,8 +55,8 @@ const styles = createStyle({
flexShrink: 0,
paddingLeft: '10%',
paddingRight: '10%',
paddingTop: '9.5%',
paddingBottom: '8%',
paddingTop: '6%',
paddingBottom: '6%',
},
row: {
flexDirection: 'row',

View File

@ -4,20 +4,14 @@ import { View, StyleSheet, TouchableOpacity } from 'react-native'
import { Icon } from '@/components/common/Icon'
import { pop } from '@/navigation'
// import { AppColors } from '@/theme'
import StatusBar from '@/components/common/StatusBar'
// import commonState from '@/store/common/state'
import { useTheme } from '@/store/theme/hook'
import { usePlayerMusicInfo } from '@/store/player/hook'
import Text from '@/components/common/Text'
import { scaleSizeH } from '@/utils/pixelRatio'
import { HEADER_HEIGHT as _HEADER_HEIGHT, NAV_SHEAR_NATIVE_IDS } from '@/config/constant'
import commonState from '@/store/common/state'
import Popup, { type PopupType } from '@/components/common/Popup'
import { useI18n } from '@/lang'
import SettingVolume from '../../components/SettingVolume'
import SettingPlaybackRate from '../../components/SettingPlaybackRate'
import SettingLrcFontSize from '../../components/SettingLrcFontSize'
import SettingPopup, { type SettingPopupType } from '../../components/SettingPopup'
const HEADER_HEIGHT = scaleSizeH(_HEADER_HEIGHT)
@ -36,18 +30,13 @@ const Title = () => {
}
export default memo(() => {
const t = useI18n()
// const theme = useTheme()
// const [settingVisible, setSettingVisible] = useState(false)
const popupRef = useRef<PopupType>(null)
const popupRef = useRef<SettingPopupType>(null)
const back = () => {
// navigation.goBack()
void pop(commonState.componentIds.playDetail as string)
}
const showSetting = () => {
popupRef.current?.setVisible(true)
popupRef.current?.show()
}
return (
@ -62,11 +51,7 @@ export default memo(() => {
<Icon name="slider" size={19} />
</TouchableOpacity>
</View>
<Popup ref={popupRef} title={t('player_setting_title')}>
<SettingVolume />
<SettingLrcFontSize />
<SettingPlaybackRate />
</Popup>
<SettingPopup ref={popupRef} />
</View>
)
})

View File

@ -0,0 +1,47 @@
import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react'
import Popup, { type PopupType, type PopupProps } from '@/components/common/Popup'
import { useI18n } from '@/lang'
import SettingVolume from './settings/SettingVolume'
import SettingPlaybackRate from './settings/SettingPlaybackRate'
import SettingLrcFontSize from './settings/SettingLrcFontSize'
import SettingLrcAlign from './settings/SettingLrcAlign'
export type SettingPopupProps = Omit<PopupProps, 'children'>
export interface SettingPopupType {
show: () => void
}
export default forwardRef<SettingPopupType, SettingPopupProps>((props, ref) => {
const [visible, setVisible] = useState(false)
const popupRef = useRef<PopupType>(null)
// console.log('render import export')
const t = useI18n()
useImperativeHandle(ref, () => ({
show() {
if (visible) popupRef.current?.setVisible(true)
else {
setVisible(true)
requestAnimationFrame(() => {
popupRef.current?.setVisible(true)
})
}
},
}))
return (
visible
? (
<Popup ref={popupRef} title={t('play_detail_setting_title')} {...props}>
<SettingVolume />
<SettingPlaybackRate />
<SettingLrcFontSize />
<SettingLrcAlign />
</Popup>
)
: null
)
})

View File

@ -0,0 +1,57 @@
import React, { useMemo } from 'react'
import { View } from 'react-native'
import Text from '@/components/common/Text'
import { useSettingValue } from '@/store/setting/hook'
import { updateSetting } from '@/core/common'
import { useI18n } from '@/lang'
import styles from './style'
import CheckBox from '@/components/common/CheckBox'
type Align_Type = LX.AppSetting['playDetail.style.align']
const ALIGN_LIST = [
'left',
'center',
'right',
] as const
const useActive = (id: Align_Type) => {
const x = useSettingValue('playDetail.style.align')
const isActive = useMemo(() => x == id, [x, id])
return isActive
}
const Item = ({ id, name, change }: {
id: Align_Type
name: string
change: (id: Align_Type) => void
}) => {
const isActive = useActive(id)
// const [toggleCheckBox, setToggleCheckBox] = useState(false)
return <CheckBox marginBottom={3} check={isActive} label={name} onChange={() => { change(id) }} need />
}
export default () => {
const t = useI18n()
const list = useMemo(() => {
return ALIGN_LIST.map(id => ({ id, name: t(`play_detail_setting_lrc_align_${id}`) }))
}, [t])
const setPosition = (id: Align_Type) => {
updateSetting({ 'playDetail.style.align': id })
}
return (
<View style={styles.container}>
<Text>{t('play_detail_setting_lrc_align')}</Text>
<View style={styles.content}>
<View style={styles.list}>
{
list.map(({ id, name }) => <Item name={name} id={id} key={id} change={setPosition} />)
}
</View>
</View>
</View>
)
}

View File

@ -12,7 +12,7 @@ import styles from './style'
const LrcFontSize = () => {
const theme = useTheme()
const lrcFontSize = useSettingValue('player.vertical.style.lrcFontSize')
const lrcFontSize = useSettingValue('playDetail.vertical.style.lrcFontSize')
const [sliderSize, setSliderSize] = useState(lrcFontSize)
const [isSliding, setSliding] = useState(false)
const t = useI18n()
@ -26,12 +26,12 @@ const LrcFontSize = () => {
const handleSlidingComplete: SliderProps['onSlidingComplete'] = value => {
setSliding(false)
if (lrcFontSize == value) return
updateSetting({ 'player.vertical.style.lrcFontSize': value })
updateSetting({ 'playDetail.vertical.style.lrcFontSize': value })
}
return (
<View style={styles.container}>
<Text>{t('player_setting_lrc_font_size')}</Text>
<Text>{t('play_detail_setting_lrc_font_size')}</Text>
<View style={styles.content}>
<Text style={styles.label} color={theme['c-font-label']}>{isSliding ? sliderSize : lrcFontSize}</Text>
<Slider

View File

@ -45,7 +45,7 @@ const Volume = () => {
return (
<View style={styles.container}>
<Text>{t('player_setting_playback_rate')}</Text>
<Text>{t('play_detail_setting_playback_rate')}</Text>
<View style={styles.content}>
<Text style={styles.label} color={theme['c-font-label']}>{`${((isSliding ? sliderSize : playbackRate) / 100).toFixed(2)}x`}</Text>
<Slider
@ -58,7 +58,7 @@ const Volume = () => {
value={playbackRate}
/>
</View>
<ButtonPrimary onPress={handleReset}>{t('player_setting_playback_rate_reset')}</ButtonPrimary>
<ButtonPrimary onPress={handleReset}>{t('play_detail_setting_playback_rate_reset')}</ButtonPrimary>
</View>
)
}

View File

@ -35,7 +35,7 @@ const Volume = () => {
return (
<View style={styles.container}>
<Text>{t('player_setting_volume')}</Text>
<Text>{t('play_detail_setting_volume')}</Text>
<View style={styles.content}>
<Text style={styles.label} color={theme['c-font-label']}>{isSliding ? sliderSize : volume}</Text>
<Slider

View File

@ -21,4 +21,11 @@ export default createStyle({
flexWrap: 'nowrap',
alignItems: 'center',
},
list: {
flexGrow: 0,
flexShrink: 1,
flexDirection: 'row',
flexWrap: 'wrap',
paddingTop: 5,
},
})

View File

@ -131,15 +131,30 @@ declare global {
*/
'player.isS2t': boolean
/**
* -
*/
// 'playDetail.isZoomActiveLrc': boolean
/**
* -
*/
// 'playDetail.isShowLyricProgressSetting': boolean
/**
* -
*/
'playDetail.style.align': 'center' | 'left' | 'right'
/**
*
*/
'player.vertical.style.lrcFontSize': number
'playDetail.vertical.style.lrcFontSize': number
/**
*
*/
'player.horizontal.style.lrcFontSize': number
'playDetail.horizontal.style.lrcFontSize': number
/**
*