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