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
ce763bf420
commit
94f44a3762
4
index.js
4
index.js
@ -61,7 +61,7 @@ const init = () => {
|
|||||||
getPlayInfo().then(info => {
|
getPlayInfo().then(info => {
|
||||||
if (!info) return
|
if (!info) return
|
||||||
global.restorePlayInfo = info
|
global.restorePlayInfo = info
|
||||||
if (info.listId != LIST_ID_PLAY_TEMP && info.listId != LIST_ID_PLAY_LATER) {
|
if (info.listId != LIST_ID_PLAY_TEMP) {
|
||||||
info.list = global.allList[info.listId]
|
info.list = global.allList[info.listId]
|
||||||
if (info.list) info.list = info.list.list
|
if (info.list) info.list = info.list.list
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ const init = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
initNavigation(async() => {
|
initNavigation(() => {
|
||||||
init().then(() => {
|
init().then(() => {
|
||||||
navigations.pushHomeScreen()
|
navigations.pushHomeScreen()
|
||||||
SplashScreen.hide()
|
SplashScreen.hide()
|
||||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "lx-music-mobile",
|
"name": "lx-music-mobile",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
"collect_toplist": "Collection Toplist",
|
"collect_toplist": "Collection Toplist",
|
||||||
"play_all": "Play all",
|
"play_all": "Play all",
|
||||||
"back": "Back",
|
"back": "Back",
|
||||||
|
"name": "Name: {{name}}",
|
||||||
|
"singer": "Artist: {{name}}",
|
||||||
|
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
@ -98,10 +100,10 @@
|
|||||||
"theme_mid_autumn": "Mid-Autumn",
|
"theme_mid_autumn": "Mid-Autumn",
|
||||||
"theme_naruto": "Naruto",
|
"theme_naruto": "Naruto",
|
||||||
|
|
||||||
"version_label_latest_ver": "Latest version:",
|
"version_label_latest_ver": "Latest version: ",
|
||||||
"version_label_current_ver": "Current version:",
|
"version_label_current_ver": "Current version: ",
|
||||||
"version_label_change_log": "Update description:",
|
"version_label_change_log": "Update description: ",
|
||||||
"version_label_history": "History version:",
|
"version_label_history": "History version: ",
|
||||||
"version_tip_checking": "Checking for updates...⏳",
|
"version_tip_checking": "Checking for updates...⏳",
|
||||||
"version_tip_downloaded": "The installation package has been downloaded.",
|
"version_tip_downloaded": "The installation package has been downloaded.",
|
||||||
"version_tip_failed": "The download of the installation package failed. You can try again or go to the project address to manually download the new version update.",
|
"version_tip_failed": "The download of the installation package failed. You can try again or go to the project address to manually download the new version update.",
|
||||||
@ -170,7 +172,7 @@
|
|||||||
|
|
||||||
"setting_other": "Other",
|
"setting_other": "Other",
|
||||||
"setting_other_cache": "Cache management (including the cache of songs, lyrics, error logs, etc., it is not recommended to clean up if there is no problem related to song playback)",
|
"setting_other_cache": "Cache management (including the cache of songs, lyrics, error logs, etc., it is not recommended to clean up if there is no problem related to song playback)",
|
||||||
"setting_other_cache_size": "Currently used cache size:",
|
"setting_other_cache_size": "Currently used cache size: ",
|
||||||
"setting_other_cache_clear_btn": "Clear Cache",
|
"setting_other_cache_clear_btn": "Clear Cache",
|
||||||
"setting_other_cache_clear_success_tip": "Cache clearing completed",
|
"setting_other_cache_clear_success_tip": "Cache clearing completed",
|
||||||
"setting_other_log": "Error log (error log when the software crashes 💥)",
|
"setting_other_log": "Error log (error log when the software crashes 💥)",
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
"collect_toplist": "收藏排行榜",
|
"collect_toplist": "收藏排行榜",
|
||||||
"play_all": "播放全部",
|
"play_all": "播放全部",
|
||||||
"back": "返回",
|
"back": "返回",
|
||||||
|
"name": "歌曲名:{{name}}",
|
||||||
|
"singer": "艺术家:{{name}}",
|
||||||
|
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"confirm": "确认",
|
"confirm": "确认",
|
||||||
|
@ -3,14 +3,16 @@ import * as screenNames from './screenNames'
|
|||||||
import * as navigations from './navigation'
|
import * as navigations from './navigation'
|
||||||
|
|
||||||
import registerScreens from './registerScreens'
|
import registerScreens from './registerScreens'
|
||||||
|
import { getStore } from '@/store'
|
||||||
|
import { action as commonAction } from '@/store/modules/common'
|
||||||
|
|
||||||
// let unRegisterEvent
|
let unRegisterEvent
|
||||||
|
|
||||||
const init = callback => {
|
const init = callback => {
|
||||||
// Register all screens on launch
|
// Register all screens on launch
|
||||||
registerScreens()
|
registerScreens()
|
||||||
|
|
||||||
// if (unRegisterEvent) unRegisterEvent()
|
if (unRegisterEvent) unRegisterEvent()
|
||||||
|
|
||||||
Navigation.setDefaultOptions({
|
Navigation.setDefaultOptions({
|
||||||
animations: {
|
animations: {
|
||||||
@ -19,9 +21,10 @@ const init = callback => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
// unRegisterEvent = Navigation.events().registerCommandListener((name, params) => {
|
unRegisterEvent = Navigation.events().registerScreenPoppedListener(({ componentId }) => {
|
||||||
// console.log(name, params)
|
const store = getStore()
|
||||||
// })
|
store.dispatch(commonAction.removeComponentId(componentId))
|
||||||
|
})
|
||||||
Navigation.events().registerAppLaunchedListener(() => {
|
Navigation.events().registerAppLaunchedListener(() => {
|
||||||
console.log('Register app launched listener')
|
console.log('Register app launched listener')
|
||||||
callback()
|
callback()
|
||||||
|
@ -9,43 +9,43 @@ import IsPlayHighQuality from './IsPlayHighQuality'
|
|||||||
import MaxCache from './MaxCache'
|
import MaxCache from './MaxCache'
|
||||||
import { useTranslation } from '@/plugins/i18n'
|
import { useTranslation } from '@/plugins/i18n'
|
||||||
|
|
||||||
import DorpDownMenu from '@/components/common/DorpDownMenu'
|
// import DorpDownMenu from '@/components/common/DorpDownMenu'
|
||||||
import { useGetter, useDispatch } from '@/store'
|
// import { useGetter, useDispatch } from '@/store'
|
||||||
|
|
||||||
const playNextModes = [
|
// const playNextModes = [
|
||||||
{ label: '列表循环', action: 'listLoop' },
|
// { label: '列表循环', action: 'listLoop' },
|
||||||
{ label: '列表随机', action: 'random' },
|
// { label: '列表随机', action: 'random' },
|
||||||
{ label: '顺序播放', action: 'list' },
|
// { label: '顺序播放', action: 'list' },
|
||||||
{ label: '单曲循环', action: 'singleLoop' },
|
// { label: '单曲循环', action: 'singleLoop' },
|
||||||
]
|
// ]
|
||||||
|
|
||||||
export default memo(() => {
|
export default memo(() => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
// const [isShowModal, setIsShowModal] = useState(false)
|
// const [isShowModal, setIsShowModal] = useState(false)
|
||||||
// const hideDialog = useCallback(() => setIsShowModal(false), [setIsShowModal])
|
// const hideDialog = useCallback(() => setIsShowModal(false), [setIsShowModal])
|
||||||
const togglePlayMethod = useGetter('common', 'togglePlayMethod')
|
// const togglePlayMethod = useGetter('common', 'togglePlayMethod')
|
||||||
|
|
||||||
const togglePlayMethodName = useMemo(() => {
|
// const togglePlayMethodName = useMemo(() => {
|
||||||
const method = playNextModes.find(m => m.action == togglePlayMethod)
|
// const method = playNextModes.find(m => m.action == togglePlayMethod)
|
||||||
return method ? method.label : '未知'
|
// return method ? method.label : '未知'
|
||||||
}, [togglePlayMethod])
|
// }, [togglePlayMethod])
|
||||||
const setPlayNextMode = useDispatch('common', 'setPlayNextMode')
|
// const setPlayNextMode = useDispatch('common', 'setPlayNextMode')
|
||||||
// console.log(themeList)
|
// console.log(themeList)
|
||||||
// const handlePress = id => {
|
// const handlePress = id => {
|
||||||
// setTheme(id)
|
// setTheme(id)
|
||||||
// // console.log(AppColors)
|
// // console.log(AppColors)
|
||||||
// }
|
// }
|
||||||
const handleToggleMethodPress = ({ action }) => setPlayNextMode(action)
|
// const handleToggleMethodPress = ({ action }) => setPlayNextMode(action)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section title={t('setting_play')}>
|
<Section title={t('setting_play')}>
|
||||||
<IsPlayHighQuality />
|
<IsPlayHighQuality />
|
||||||
<MaxCache />
|
<MaxCache />
|
||||||
<View style={{ marginLeft: 15, marginBottom: 15 }}>
|
{/* <View style={{ marginLeft: 15, marginBottom: 15 }}>
|
||||||
<Text>播放歌曲切换方式</Text>
|
<Text>播放歌曲切换方式</Text>
|
||||||
<DorpDownMenu menus={playNextModes} onPress={handleToggleMethodPress}><Text style={{ padding: 10 }}>{togglePlayMethodName}</Text></DorpDownMenu>
|
<DorpDownMenu menus={playNextModes} onPress={handleToggleMethodPress}><Text style={{ padding: 10 }}>{togglePlayMethodName}</Text></DorpDownMenu>
|
||||||
</View>
|
</View> */}
|
||||||
</Section>
|
</Section>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -23,10 +23,8 @@ export default ({ playNextModes }) => {
|
|||||||
// }, [setPlayNextMode, togglePlayMethod, playNextModes])
|
// }, [setPlayNextMode, togglePlayMethod, playNextModes])
|
||||||
|
|
||||||
const btnPrev = useMemo(() => (
|
const btnPrev = useMemo(() => (
|
||||||
<TouchableOpacity activeOpacity={0.5} onPress={playPrev}>
|
<TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playPrev}>
|
||||||
<Text style={{ ...styles.cotrolBtn }}>
|
|
||||||
<Icon name='prevMusic' style={{ color: theme.secondary10 }} size={20} />
|
<Icon name='prevMusic' style={{ color: theme.secondary10 }} size={20} />
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
), [playPrev, theme])
|
), [playPrev, theme])
|
||||||
|
|
||||||
@ -46,17 +44,13 @@ export default ({ playNextModes }) => {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
const btnPlay = useMemo(() => (
|
const btnPlay = useMemo(() => (
|
||||||
<TouchableOpacity activeOpacity={0.5} onPress={() => togglePlay(playStatus)}>
|
<TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={() => togglePlay(playStatus)}>
|
||||||
<Text style={{ ...styles.cotrolBtn }}>
|
|
||||||
<Icon name={playStatus == STATUS.playing ? 'pause' : 'play'} style={{ color: theme.secondary10 }} size={20} />
|
<Icon name={playStatus == STATUS.playing ? 'pause' : 'play'} style={{ color: theme.secondary10 }} size={20} />
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
), [playStatus, theme, togglePlay])
|
), [playStatus, theme, togglePlay])
|
||||||
const btnNext = useMemo(() => (
|
const btnNext = useMemo(() => (
|
||||||
<TouchableOpacity activeOpacity={0.5} onPress={playNext}>
|
<TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playNext}>
|
||||||
<Text style={{ ...styles.cotrolBtn }}>
|
|
||||||
<Icon name='nextMusic' style={{ color: theme.secondary10 }} size={20} />
|
<Icon name='nextMusic' style={{ color: theme.secondary10 }} size={20} />
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
), [playNext, theme])
|
), [playNext, theme])
|
||||||
|
|
||||||
@ -80,8 +74,8 @@ const styles = StyleSheet.create({
|
|||||||
cotrolBtn: {
|
cotrolBtn: {
|
||||||
width: 32,
|
width: 32,
|
||||||
height: 32,
|
height: 32,
|
||||||
lineHeight: 32,
|
justifyContent: 'center',
|
||||||
textAlign: 'center',
|
alignItems: 'center',
|
||||||
|
|
||||||
// backgroundColor: '#ccc',
|
// backgroundColor: '#ccc',
|
||||||
shadowOpacity: 1,
|
shadowOpacity: 1,
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React, { useMemo } from 'react'
|
import React, { memo, useMemo } from 'react'
|
||||||
import { Text } from 'react-native'
|
import { Text } from 'react-native'
|
||||||
import { useGetter } from '@/store'
|
import { useGetter } from '@/store'
|
||||||
import { STATUS } from '@/store/modules/player'
|
import { STATUS } from '@/store/modules/player'
|
||||||
import { useLrcPlay } from '@/plugins/lyric'
|
import { useLrcPlay } from '@/plugins/lyric'
|
||||||
|
|
||||||
|
|
||||||
export default () => {
|
export default memo(() => {
|
||||||
const theme = useGetter('common', 'theme')
|
const theme = useGetter('common', 'theme')
|
||||||
const playStatus = useGetter('player', 'status')
|
const playStatus = useGetter('player', 'status')
|
||||||
const statusText = useGetter('player', 'statusText')
|
const statusText = useGetter('player', 'statusText')
|
||||||
@ -18,7 +18,7 @@ export default () => {
|
|||||||
: statusText
|
: statusText
|
||||||
), [playStatus, statusText, text])
|
), [playStatus, statusText, text])
|
||||||
return <Text numberOfLines={1} style={{ fontSize: 10, color: theme.normal10 }}>{status}</Text>
|
return <Text numberOfLines={1} style={{ fontSize: 10, color: theme.normal10 }}>{status}</Text>
|
||||||
}
|
})
|
||||||
|
|
||||||
// const styles = StyleSheet.create({
|
// const styles = StyleSheet.create({
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ export default memo(({ playNextModes }) => {
|
|||||||
// const { onLayout, ...layout } = useLayout()
|
// const { onLayout, ...layout } = useLayout()
|
||||||
const { keyboardShown } = useKeyboard()
|
const { keyboardShown } = useKeyboard()
|
||||||
const theme = useGetter('common', 'theme')
|
const theme = useGetter('common', 'theme')
|
||||||
|
const componentIds = useGetter('common', 'componentIds')
|
||||||
|
|
||||||
const playerComponent = useMemo(() => (
|
const playerComponent = useMemo(() => (
|
||||||
<View style={{ ...styles.container, backgroundColor: theme.primary, borderTopColor: theme.secondary10 }}>
|
<View style={{ ...styles.container, backgroundColor: theme.primary, borderTopColor: theme.secondary10 }}>
|
||||||
@ -33,7 +34,7 @@ export default memo(({ playNextModes }) => {
|
|||||||
|
|
||||||
// console.log(layout)
|
// console.log(layout)
|
||||||
|
|
||||||
return keyboardShown ? null : playerComponent
|
return (keyboardShown || componentIds.playDetail) ? null : playerComponent
|
||||||
})
|
})
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
@ -46,5 +46,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
img: {
|
img: {
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
|
// opacity: 0,
|
||||||
},
|
},
|
||||||
})
|
})
|
@ -0,0 +1,84 @@
|
|||||||
|
import React, { useCallback, memo, useMemo, useEffect } from 'react'
|
||||||
|
import { Text, StyleSheet, TouchableOpacity } from 'react-native'
|
||||||
|
import Icon from '@/components/common/Icon'
|
||||||
|
import { useGetter, useDispatch } from '@/store'
|
||||||
|
import { STATUS } from '@/store/modules/player'
|
||||||
|
|
||||||
|
|
||||||
|
export default ({ playNextModes }) => {
|
||||||
|
const playStatus = useGetter('player', 'status')
|
||||||
|
const playNext = useDispatch('player', 'playNext')
|
||||||
|
const playPrev = useDispatch('player', 'playPrev')
|
||||||
|
// const playMusicInfo = useGetter('player', 'playMusicInfo')
|
||||||
|
const pauseMusic = useDispatch('player', 'pauseMusic')
|
||||||
|
const playMusic = useDispatch('player', 'playMusic')
|
||||||
|
const theme = useGetter('common', 'theme')
|
||||||
|
|
||||||
|
// const togglePlayMethod = useGetter('common', 'togglePlayMethod')
|
||||||
|
// const setPlayNextMode = useDispatch('common', 'setPlayNextMode')
|
||||||
|
// const toggleNextPlayMode = useCallback(() => {
|
||||||
|
// let index = playNextModes.indexOf(togglePlayMethod)
|
||||||
|
// if (++index >= playNextModes.length) index = -1
|
||||||
|
// setPlayNextMode(playNextModes[index] || '')
|
||||||
|
// }, [setPlayNextMode, togglePlayMethod, playNextModes])
|
||||||
|
|
||||||
|
const btnPrev = useMemo(() => (
|
||||||
|
<TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playPrev}>
|
||||||
|
<Icon name='prevMusic' style={{ color: theme.secondary10 }} size={30} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
), [playPrev, theme])
|
||||||
|
|
||||||
|
const togglePlay = useCallback(playStatus => {
|
||||||
|
switch (playStatus) {
|
||||||
|
case STATUS.playing:
|
||||||
|
pauseMusic()
|
||||||
|
break
|
||||||
|
case STATUS.pause:
|
||||||
|
case STATUS.stop:
|
||||||
|
case STATUS.none:
|
||||||
|
playMusic()
|
||||||
|
break
|
||||||
|
// default:
|
||||||
|
// playMusic(playMusicInfo)
|
||||||
|
// break
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
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={30} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
), [playStatus, theme, togglePlay])
|
||||||
|
const btnNext = useMemo(() => (
|
||||||
|
<TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={playNext}>
|
||||||
|
<Icon name='nextMusic' style={{ color: theme.secondary10 }} size={30} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
), [playNext, theme])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* <TouchableOpacity activeOpacity={0.5} onPress={toggleNextPlayMode}>
|
||||||
|
<Text style={{ ...styles.cotrolBtn }}>
|
||||||
|
<Icon name={playModeIcon} style={{ color: theme.secondary10 }} size={18} />
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
*/}
|
||||||
|
{btnPrev}
|
||||||
|
{btnPlay}
|
||||||
|
{btnNext}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
cotrolBtn: {
|
||||||
|
width: 42,
|
||||||
|
height: 42,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
|
||||||
|
// backgroundColor: '#ccc',
|
||||||
|
shadowOpacity: 1,
|
||||||
|
textShadowRadius: 1,
|
||||||
|
},
|
||||||
|
})
|
@ -0,0 +1,47 @@
|
|||||||
|
import React, { useCallback, memo, useMemo, useEffect, useState, useRef } from 'react'
|
||||||
|
import { Text, StyleSheet, TouchableOpacity } from 'react-native'
|
||||||
|
import Icon from '@/components/common/Icon'
|
||||||
|
import { useGetter, useDispatch } from '@/store'
|
||||||
|
import MusicAddModal from '@/components/MusicAddModal'
|
||||||
|
|
||||||
|
|
||||||
|
export default memo(() => {
|
||||||
|
const theme = useGetter('common', 'theme')
|
||||||
|
const [visibleMusicAddModal, setVisibleMusicAddModal] = useState(false)
|
||||||
|
const playMusicInfo = useGetter('player', 'playMusicInfo')
|
||||||
|
const selectedDataRef = useRef()
|
||||||
|
const hideMusicAddModal = () => {
|
||||||
|
setVisibleMusicAddModal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleShowMusicAddModal = () => {
|
||||||
|
selectedDataRef.current = playMusicInfo.musicInfo
|
||||||
|
setVisibleMusicAddModal(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={handleShowMusicAddModal}>
|
||||||
|
<Icon name="add-music" style={{ color: theme.secondary10 }} size={24} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
<MusicAddModal
|
||||||
|
visible={visibleMusicAddModal}
|
||||||
|
hideModal={hideMusicAddModal}
|
||||||
|
musicInfo={selectedDataRef.current} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
cotrolBtn: {
|
||||||
|
marginLeft: 5,
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
|
||||||
|
// backgroundColor: '#ccc',
|
||||||
|
shadowOpacity: 1,
|
||||||
|
textShadowRadius: 1,
|
||||||
|
},
|
||||||
|
})
|
@ -0,0 +1,65 @@
|
|||||||
|
import React, { useCallback, memo, useMemo, useEffect } from 'react'
|
||||||
|
import { Text, StyleSheet, TouchableOpacity } from 'react-native'
|
||||||
|
import Icon from '@/components/common/Icon'
|
||||||
|
import { useGetter, useDispatch } from '@/store'
|
||||||
|
|
||||||
|
const playNextModes = [
|
||||||
|
'listLoop',
|
||||||
|
'random',
|
||||||
|
'list',
|
||||||
|
'singleLoop',
|
||||||
|
]
|
||||||
|
|
||||||
|
export default memo(() => {
|
||||||
|
const togglePlayMethod = useGetter('common', 'togglePlayMethod')
|
||||||
|
const theme = useGetter('common', 'theme')
|
||||||
|
const setPlayNextMode = useDispatch('common', 'setPlayNextMode')
|
||||||
|
|
||||||
|
const toggleNextPlayMode = () => {
|
||||||
|
let index = playNextModes.indexOf(togglePlayMethod)
|
||||||
|
if (++index >= playNextModes.length) index = -1
|
||||||
|
setPlayNextMode(playNextModes[index] || '')
|
||||||
|
}
|
||||||
|
|
||||||
|
const playModeIcon = useMemo(() => {
|
||||||
|
let playModeIcon = null
|
||||||
|
switch (togglePlayMethod) {
|
||||||
|
case 'listLoop':
|
||||||
|
playModeIcon = 'list-loop'
|
||||||
|
break
|
||||||
|
case 'random':
|
||||||
|
playModeIcon = 'list-random'
|
||||||
|
break
|
||||||
|
case 'list':
|
||||||
|
playModeIcon = 'list-order'
|
||||||
|
break
|
||||||
|
case 'singleLoop':
|
||||||
|
playModeIcon = 'single-loop'
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
playModeIcon = 'single'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return playModeIcon
|
||||||
|
}, [togglePlayMethod])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity style={{ ...styles.cotrolBtn }} activeOpacity={0.5} onPress={toggleNextPlayMode}>
|
||||||
|
<Icon name={playModeIcon} style={{ color: theme.secondary10 }} size={24} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
cotrolBtn: {
|
||||||
|
marginLeft: 5,
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
|
||||||
|
// backgroundColor: '#ccc',
|
||||||
|
shadowOpacity: 1,
|
||||||
|
textShadowRadius: 1,
|
||||||
|
},
|
||||||
|
})
|
@ -0,0 +1,24 @@
|
|||||||
|
import React, { useCallback, memo, useMemo, useEffect } from 'react'
|
||||||
|
import { View, StyleSheet } from 'react-native'
|
||||||
|
import PlayModeBtn from './PlayModeBtn'
|
||||||
|
import MusicAddBtn from './MusicAddBtn'
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<PlayModeBtn />
|
||||||
|
<MusicAddBtn />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexShrink: 0,
|
||||||
|
flexGrow: 0,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
// backgroundColor: 'rgba(0,0,0,0.1)',
|
||||||
|
},
|
||||||
|
})
|
52
src/screens/PlayDetail/Player/Player/components/PlayInfo.js
Normal file
52
src/screens/PlayDetail/Player/Player/components/PlayInfo.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React, { useCallback, memo, useMemo, useEffect } from 'react'
|
||||||
|
import { Text, StyleSheet, View } from 'react-native'
|
||||||
|
import { usePlayTime } from '@/utils/hooks'
|
||||||
|
import { useGetter } from '@/store'
|
||||||
|
|
||||||
|
import Progress from '@/components/player/Progress'
|
||||||
|
import Status from './Status'
|
||||||
|
|
||||||
|
const PlayTimeCurrent = ({ timeStr }) => {
|
||||||
|
const theme = useGetter('common', 'theme')
|
||||||
|
// console.log(timeStr)
|
||||||
|
return <Text style={{ fontSize: 14, color: theme.normal10 }}>{timeStr}</Text>
|
||||||
|
}
|
||||||
|
|
||||||
|
const PlayTimeMax = memo(({ timeStr }) => {
|
||||||
|
const theme = useGetter('common', 'theme')
|
||||||
|
return <Text style={{ fontSize: 14, color: theme.normal10 }}>{timeStr}</Text>
|
||||||
|
})
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const { curTimeStr, maxTimeStr, progress, bufferedProgress, duration } = usePlayTime()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<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 }} >
|
||||||
|
<Status />
|
||||||
|
</View>
|
||||||
|
<View style={{ flexGrow: 0, flexShrink: 0, flexDirection: 'row' }} >
|
||||||
|
<PlayTimeCurrent timeStr={curTimeStr} />
|
||||||
|
<Text style={{ fontSize: 14 }}> / </Text>
|
||||||
|
<PlayTimeMax timeStr={maxTimeStr} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
progress: {
|
||||||
|
flexGrow: 1,
|
||||||
|
flexShrink: 0,
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
// height:
|
||||||
|
// position: 'absolute',
|
||||||
|
// width: '100%',
|
||||||
|
// top: 0,
|
||||||
|
},
|
||||||
|
})
|
25
src/screens/PlayDetail/Player/Player/components/Status.js
Normal file
25
src/screens/PlayDetail/Player/Player/components/Status.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import React, { memo, useMemo } from 'react'
|
||||||
|
import { Text } from 'react-native'
|
||||||
|
import { useGetter } from '@/store'
|
||||||
|
import { STATUS } from '@/store/modules/player'
|
||||||
|
|
||||||
|
|
||||||
|
export default memo(() => {
|
||||||
|
const theme = useGetter('common', 'theme')
|
||||||
|
const playStatus = useGetter('player', 'status')
|
||||||
|
const statusText = useGetter('player', 'statusText')
|
||||||
|
const status = useMemo(() => {
|
||||||
|
switch (playStatus) {
|
||||||
|
case STATUS.playing:
|
||||||
|
case STATUS.pause:
|
||||||
|
case STATUS.stop:
|
||||||
|
return ''
|
||||||
|
default: return statusText
|
||||||
|
}
|
||||||
|
}, [playStatus, statusText])
|
||||||
|
return <Text numberOfLines={1} style={{ fontSize: 13, color: theme.normal10 }}>{status}</Text>
|
||||||
|
})
|
||||||
|
|
||||||
|
// const styles = StyleSheet.create({
|
||||||
|
|
||||||
|
// })
|
35
src/screens/PlayDetail/Player/Player/components/Title.js
Normal file
35
src/screens/PlayDetail/Player/Player/components/Title.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import React, { useCallback, memo, useMemo, useEffect } from 'react'
|
||||||
|
import { Text, View, StyleSheet } from 'react-native'
|
||||||
|
import { useGetter, useDispatch } from '@/store'
|
||||||
|
import { useTranslation } from '@/plugins/i18n'
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const theme = useGetter('common', 'theme')
|
||||||
|
const playMusicInfo = useGetter('player', 'playMusicInfo')
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const titleInfo = useMemo(() => {
|
||||||
|
const info = {
|
||||||
|
name: '',
|
||||||
|
singer: '',
|
||||||
|
}
|
||||||
|
if (playMusicInfo) {
|
||||||
|
info.name = t('name', { name: playMusicInfo.musicInfo.name })
|
||||||
|
info.singer = t('singer', { name: playMusicInfo.musicInfo.singer })
|
||||||
|
}
|
||||||
|
return info
|
||||||
|
}, [playMusicInfo, t])
|
||||||
|
// console.log(playMusicInfo)
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={{ width: '100%', fontSize: 14, color: theme.normal }} numberOfLines={2}>{titleInfo.name}</Text>
|
||||||
|
<Text style={{ width: '100%', fontSize: 14, color: theme.normal }} numberOfLines={2}>{titleInfo.singer}</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexShrink: 1,
|
||||||
|
flexGrow: 1,
|
||||||
|
},
|
||||||
|
})
|
69
src/screens/PlayDetail/Player/Player/index.js
Normal file
69
src/screens/PlayDetail/Player/Player/index.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
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 Title from './components/Title'
|
||||||
|
import MoreBtn from './components/MoreBtn'
|
||||||
|
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 }}>
|
||||||
|
<View style={{ ...styles.info }}>
|
||||||
|
<Title />
|
||||||
|
<MoreBtn />
|
||||||
|
</View>
|
||||||
|
<View style={styles.status}>
|
||||||
|
<PlayInfo />
|
||||||
|
</View>
|
||||||
|
<View style={styles.control}>
|
||||||
|
<ControlBtn playNextModes={playNextModes} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
width: '100%',
|
||||||
|
// paddingTop: progressContentPadding,
|
||||||
|
// marginTop: -progressContentPadding,
|
||||||
|
// backgroundColor: 'rgba(0, 0, 0, .1)',
|
||||||
|
padding: 15,
|
||||||
|
// backgroundColor: AppColors.primary,
|
||||||
|
// backgroundColor: 'red',
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
paddingBottom: 10,
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexGrow: 1,
|
||||||
|
flexShrink: 1,
|
||||||
|
paddingLeft: 5,
|
||||||
|
justifyContent: 'space-evenly',
|
||||||
|
},
|
||||||
|
control: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-evenly',
|
||||||
|
flexGrow: 0,
|
||||||
|
flexShrink: 0,
|
||||||
|
paddingLeft: '15%',
|
||||||
|
paddingRight: '15%',
|
||||||
|
paddingTop: '10%',
|
||||||
|
paddingBottom: '8%',
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flexGrow: 0,
|
||||||
|
flexShrink: 0,
|
||||||
|
},
|
||||||
|
})
|
@ -1,10 +1,10 @@
|
|||||||
import React, { useEffect, useCallback } from 'react'
|
import React, { useEffect, useCallback } from 'react'
|
||||||
import { View, StyleSheet } from 'react-native'
|
import { View, StyleSheet } from 'react-native'
|
||||||
|
|
||||||
import Header from './components/Header'
|
import Header from '../components/Header'
|
||||||
// import Aside from './components/Aside'
|
// import Aside from './components/Aside'
|
||||||
// import Main from './components/Main'
|
// import Main from './components/Main'
|
||||||
// import FooterPlayer from './components/FooterPlayer'
|
import Player from './Player'
|
||||||
import { useGetter, useDispatch } from '@/store'
|
import { useGetter, useDispatch } from '@/store'
|
||||||
import PagerView from 'react-native-pager-view'
|
import PagerView from 'react-native-pager-view'
|
||||||
import Pic from './Pic'
|
import Pic from './Pic'
|
||||||
@ -32,7 +32,7 @@ export default () => {
|
|||||||
</View>
|
</View>
|
||||||
</PagerView>
|
</PagerView>
|
||||||
<View style={styles.player}>
|
<View style={styles.player}>
|
||||||
|
<Player />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
|
@ -1,59 +1,20 @@
|
|||||||
import React, { useEffect, useCallback } from 'react'
|
import React, { useEffect, useCallback } from 'react'
|
||||||
import { View, StyleSheet } from 'react-native'
|
import { View, StyleSheet } from 'react-native'
|
||||||
|
|
||||||
import Header from './components/Header'
|
|
||||||
// import Aside from './components/Aside'
|
|
||||||
// import Main from './components/Main'
|
|
||||||
// import FooterPlayer from './components/FooterPlayer'
|
|
||||||
import { useGetter, useDispatch } from '@/store'
|
import { useGetter, useDispatch } from '@/store'
|
||||||
import PagerView from 'react-native-pager-view'
|
|
||||||
import Pic from './Pic'
|
import Player from './Player'
|
||||||
|
|
||||||
export default (props) => {
|
export default (props) => {
|
||||||
const theme = useGetter('common', 'theme')
|
// const theme = useGetter('common', 'theme')
|
||||||
const setComponentId = useDispatch('common', 'setComponentId')
|
const setComponentId = useDispatch('common', 'setComponentId')
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setComponentId({ name: 'playDetail', id: props.componentId })
|
setComponentId({ name: 'playDetail', id: props.componentId })
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const onPageScrollStateChanged = useCallback(({ nativeEvent }) => {
|
|
||||||
// console.log(nativeEvent)
|
|
||||||
if (nativeEvent.pageScrollState != 'idle') return
|
|
||||||
console.log(nativeEvent.pageScrollState)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header componentId={props.componentId} />
|
<Player />
|
||||||
<View style={{ flex: 1, flexDirection: 'column', height: '100%', backgroundColor: theme.primary }}>
|
|
||||||
<PagerView
|
|
||||||
// onPageSelected={onPageSelected}
|
|
||||||
onPageScrollStateChanged={onPageScrollStateChanged}
|
|
||||||
style={styles.pagerView}
|
|
||||||
>
|
|
||||||
<View collapsable={false} key="1" style={styles.pageStyle}>
|
|
||||||
<Pic />
|
|
||||||
</View>
|
|
||||||
</PagerView>
|
|
||||||
<View style={styles.player}>
|
|
||||||
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flexGrow: 1,
|
|
||||||
flexShrink: 1,
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
},
|
|
||||||
pagerView: {
|
|
||||||
flex: 1,
|
|
||||||
},
|
|
||||||
player: {
|
|
||||||
flex: 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
@ -13,6 +13,7 @@ import { VERSION_STATUS } from '@/config/constant'
|
|||||||
export const TYPES = {
|
export const TYPES = {
|
||||||
updateSetting: null,
|
updateSetting: null,
|
||||||
setComponentId: null,
|
setComponentId: null,
|
||||||
|
removeComponentId: null,
|
||||||
setNavActiveIndex: null,
|
setNavActiveIndex: null,
|
||||||
setNavScreenName: null,
|
setNavScreenName: null,
|
||||||
setPlayNextMode: null,
|
setPlayNextMode: null,
|
||||||
@ -106,6 +107,10 @@ export const setComponentId = data => ({
|
|||||||
type: TYPES.setComponentId,
|
type: TYPES.setComponentId,
|
||||||
payload: data,
|
payload: data,
|
||||||
})
|
})
|
||||||
|
export const removeComponentId = id => ({
|
||||||
|
type: TYPES.removeComponentId,
|
||||||
|
payload: id,
|
||||||
|
})
|
||||||
|
|
||||||
export const setNavActiveIndex = index => ({
|
export const setNavActiveIndex = index => ({
|
||||||
type: TYPES.setNavActiveIndex,
|
type: TYPES.setNavActiveIndex,
|
||||||
|
@ -65,6 +65,19 @@ const mutations = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[TYPES.removeComponentId](state, removeId) {
|
||||||
|
const newComponentIds = { ...state.componentIds }
|
||||||
|
for (const [name, id] of Object.entries(state.componentIds)) {
|
||||||
|
if (id == removeId) {
|
||||||
|
newComponentIds[name] = null
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
componentIds: newComponentIds,
|
||||||
|
}
|
||||||
|
},
|
||||||
[TYPES.setNavActiveIndex](state, index) {
|
[TYPES.setNavActiveIndex](state, index) {
|
||||||
if (index === state.nav.activeIndex) return state
|
if (index === state.nav.activeIndex) return state
|
||||||
return {
|
return {
|
||||||
|
@ -15,17 +15,13 @@ import {
|
|||||||
destroy as msDestroy,
|
destroy as msDestroy,
|
||||||
} from '@/plugins/player/utils'
|
} from '@/plugins/player/utils'
|
||||||
import { getRandom } from '@/utils'
|
import { getRandom } from '@/utils'
|
||||||
import { getMusicUrl, saveMusicUrl, getLyric, saveLyric, assertApiSupport, savePlayInfo } from '@/utils/tools'
|
import { getMusicUrl, saveMusicUrl, getLyric, saveLyric, assertApiSupport, savePlayInfo, saveList } from '@/utils/tools'
|
||||||
import { setData } from '@/plugins/storage'
|
|
||||||
import { storageDataPrefix } from '@/config'
|
|
||||||
import { playInfo as playInfoGetter } from './getter'
|
import { playInfo as playInfoGetter } from './getter'
|
||||||
import { play as lrcPlay, setLyric, pause as lrcPause } from '@/plugins/lyric'
|
import { play as lrcPlay, setLyric, pause as lrcPause } from '@/plugins/lyric'
|
||||||
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'
|
||||||
|
|
||||||
const listPrefix = storageDataPrefix.list
|
|
||||||
|
|
||||||
export const TYPES = {
|
export const TYPES = {
|
||||||
setPic: null,
|
setPic: null,
|
||||||
setList: null,
|
setList: null,
|
||||||
@ -474,7 +470,7 @@ export const getPic = musicInfo => (dispatch, getState) => {
|
|||||||
// picRequest = null
|
// picRequest = null
|
||||||
dispatch({ type: TYPES.setPic, payload: { musicInfo, url } })
|
dispatch({ type: TYPES.setPic, payload: { musicInfo, url } })
|
||||||
const state = getState()
|
const state = getState()
|
||||||
if (state.player.listInfo.id) setData(listPrefix + state.player.listInfo.id, global.allList[state.player.listInfo.id])
|
if (state.player.listInfo.id) saveList(global.allList[state.player.listInfo.id])
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
// picRequest = null
|
// picRequest = null
|
||||||
return Promise.reject(err)
|
return Promise.reject(err)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user