1import React, {memo, useEffect, useState} from 'react'; 2import {Keyboard, Pressable, StyleSheet, Text, View} from 'react-native'; 3import rpx from '@/utils/rpx'; 4import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; 5import MusicQueue from '@/core/musicQueue'; 6import {Avatar, IconButton, useTheme} from 'react-native-paper'; 7import {CircularProgressBase} from 'react-native-circular-progress-indicator'; 8import {ROUTE_PATH, useNavigate} from '@/entry/router'; 9 10import musicIsPaused from '@/utils/musicIsPaused'; 11import usePanel from '../panels/usePanel'; 12import Color from 'color'; 13import ThemeText from '../base/themeText'; 14import {ImgAsset} from '@/constants/assetsConst'; 15import {useSafeAreaInsets} from 'react-native-safe-area-context'; 16 17function CircularPlayBtn() { 18 const progress = MusicQueue.useProgress(); 19 const musicState = MusicQueue.usePlaybackState(); 20 const {colors} = useTheme(); 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.text} 35 inActiveStrokeColor={Color(colors.text).alpha(0.5).toString()}> 36 {musicIsPaused(musicState) ? ( 37 <IconButton 38 icon="play" 39 size={rpx(48)} 40 onPress={async () => { 41 await MusicQueue.play(); 42 }} 43 /> 44 ) : ( 45 <IconButton 46 icon="pause" 47 size={rpx(48)} 48 onPress={async () => { 49 await MusicQueue.pause(); 50 }} 51 /> 52 )} 53 </CircularProgressBase> 54 ); 55} 56function MusicBar() { 57 const musicItem = MusicQueue.useCurrentMusicItem(); 58 59 const [showKeyboard, setKeyboardStatus] = useState(false); 60 const {showPanel} = usePanel(); 61 const navigate = useNavigate(); 62 const {colors} = useTheme(); 63 const safeAreaInsets = useSafeAreaInsets(); 64 65 useEffect(() => { 66 const showSubscription = Keyboard.addListener('keyboardDidShow', () => { 67 setKeyboardStatus(true); 68 }); 69 const hideSubscription = Keyboard.addListener('keyboardDidHide', () => { 70 setKeyboardStatus(false); 71 }); 72 73 return () => { 74 showSubscription.remove(); 75 hideSubscription.remove(); 76 }; 77 }, []); 78 79 return ( 80 <> 81 {musicItem && !showKeyboard && ( 82 <Pressable 83 style={[ 84 style.wrapper, 85 { 86 backgroundColor: Color(colors.primary) 87 .alpha(0.66) 88 .toString(), 89 paddingLeft: safeAreaInsets.left + rpx(24), 90 paddingRight: safeAreaInsets.right + rpx(24), 91 }, 92 ]} 93 onPress={() => { 94 navigate(ROUTE_PATH.MUSIC_DETAIL); 95 }}> 96 <View style={style.artworkWrapper}> 97 <Avatar.Image 98 size={rpx(96)} 99 source={ 100 musicItem?.artwork 101 ? { 102 uri: musicItem.artwork, 103 } 104 : ImgAsset.albumDefault 105 } 106 /> 107 </View> 108 <Text 109 ellipsizeMode="tail" 110 style={style.textWrapper} 111 numberOfLines={1}> 112 <ThemeText fontSize="content"> 113 {musicItem?.title} 114 </ThemeText> 115 {musicItem?.artist && ( 116 <ThemeText 117 fontSize="description" 118 fontColor="secondary"> 119 {' '} 120 -{musicItem.artist} 121 </ThemeText> 122 )} 123 </Text> 124 <View style={style.actionGroup}> 125 <CircularPlayBtn /> 126 127 <Icon 128 name="playlist-music" 129 size={rpx(56)} 130 onPress={() => { 131 showPanel('PlayList'); 132 }} 133 style={[style.actionIcon, {color: colors.text}]} 134 /> 135 </View> 136 </Pressable> 137 )} 138 </> 139 ); 140} 141 142export default memo(MusicBar, () => true); 143 144const style = StyleSheet.create({ 145 wrapper: { 146 width: '100%', 147 height: rpx(120), 148 flexDirection: 'row', 149 alignItems: 'center', 150 paddingHorizontal: rpx(24), 151 }, 152 artworkWrapper: { 153 height: rpx(120), 154 width: rpx(120), 155 }, 156 textWrapper: { 157 flexGrow: 1, 158 flexShrink: 1, 159 }, 160 actionGroup: { 161 width: rpx(200), 162 justifyContent: 'flex-end', 163 flexDirection: 'row', 164 alignItems: 'center', 165 }, 166 actionIcon: { 167 marginLeft: rpx(36), 168 }, 169}); 170