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