1import React, {memo, useEffect, useState} from 'react'; 2import {Keyboard, StyleSheet, View} from 'react-native'; 3import rpx from '@/utils/rpx'; 4import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; 5import {CircularProgressBase} from 'react-native-circular-progress-indicator'; 6 7import {useSafeAreaInsets} from 'react-native-safe-area-context'; 8import {showPanel} from '../panels/usePanel'; 9import useColors from '@/hooks/useColors'; 10import IconButton from '../base/iconButton'; 11import TrackPlayer from '@/core/trackPlayer'; 12import {musicIsPaused} from '@/utils/trackUtils'; 13import MusicInfo from './musicInfo'; 14 15function CircularPlayBtn() { 16 const progress = TrackPlayer.useProgress(); 17 const musicState = TrackPlayer.useMusicState(); 18 const colors = useColors(); 19 20 const isPaused = musicIsPaused(musicState); 21 22 return ( 23 <CircularProgressBase 24 activeStrokeWidth={rpx(4)} 25 inActiveStrokeWidth={rpx(2)} 26 inActiveStrokeOpacity={0.2} 27 value={ 28 progress?.duration 29 ? (100 * progress.position) / progress.duration 30 : 0 31 } 32 duration={100} 33 radius={rpx(36)} 34 activeStrokeColor={colors.musicBarText} 35 inActiveStrokeColor={colors.textSecondary}> 36 <IconButton 37 accessibilityLabel={'播放或暂停歌曲'} 38 name={isPaused ? 'play' : 'pause'} 39 sizeType={'normal'} 40 color={colors.musicBarText} 41 onPress={async () => { 42 if (isPaused) { 43 await TrackPlayer.play(); 44 } else { 45 await TrackPlayer.pause(); 46 } 47 }} 48 /> 49 </CircularProgressBase> 50 ); 51} 52function MusicBar() { 53 const musicItem = TrackPlayer.useCurrentMusic(); 54 55 const [showKeyboard, setKeyboardStatus] = useState(false); 56 57 const colors = useColors(); 58 const safeAreaInsets = useSafeAreaInsets(); 59 60 useEffect(() => { 61 const showSubscription = Keyboard.addListener('keyboardDidShow', () => { 62 setKeyboardStatus(true); 63 }); 64 const hideSubscription = Keyboard.addListener('keyboardDidHide', () => { 65 setKeyboardStatus(false); 66 }); 67 68 return () => { 69 showSubscription.remove(); 70 hideSubscription.remove(); 71 }; 72 }, []); 73 74 return ( 75 <> 76 {musicItem && !showKeyboard && ( 77 <View 78 style={[ 79 style.wrapper, 80 { 81 backgroundColor: colors.musicBar, 82 paddingRight: safeAreaInsets.right + rpx(24), 83 }, 84 ]} 85 accessible 86 accessibilityLabel={`歌曲: ${musicItem.title} 歌手: ${musicItem.artist}`} 87 // onPress={() => { 88 // navigate(ROUTE_PATH.MUSIC_DETAIL); 89 // }} 90 > 91 <MusicInfo musicItem={musicItem} /> 92 <View style={style.actionGroup}> 93 <CircularPlayBtn /> 94 <Icon 95 accessible 96 accessibilityLabel="播放列表" 97 name="playlist-music" 98 size={rpx(56)} 99 onPress={() => { 100 showPanel('PlayList'); 101 }} 102 style={[ 103 style.actionIcon, 104 {color: colors.musicBarText}, 105 ]} 106 /> 107 </View> 108 </View> 109 )} 110 </> 111 ); 112} 113 114export default memo(MusicBar, () => true); 115 116const style = StyleSheet.create({ 117 wrapper: { 118 width: '100%', 119 height: rpx(132), 120 flexDirection: 'row', 121 alignItems: 'center', 122 paddingRight: rpx(24), 123 }, 124 actionGroup: { 125 width: rpx(200), 126 justifyContent: 'flex-end', 127 flexDirection: 'row', 128 alignItems: 'center', 129 }, 130 actionIcon: { 131 marginLeft: rpx(36), 132 }, 133}); 134