1import React, {Fragment, 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} 55 56export default function () { 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 64 useEffect(() => { 65 const showSubscription = Keyboard.addListener('keyboardDidShow', () => { 66 setKeyboardStatus(true); 67 }); 68 const hideSubscription = Keyboard.addListener('keyboardDidHide', () => { 69 setKeyboardStatus(false); 70 }); 71 72 return () => { 73 showSubscription.remove(); 74 hideSubscription.remove(); 75 }; 76 }, []); 77 78 return ( 79 <Fragment> 80 {musicItem && !showKeyboard && ( 81 <Pressable 82 style={[ 83 style.wrapper, 84 { 85 backgroundColor: Color(colors.primary) 86 .alpha(0.66) 87 .toString(), 88 }, 89 ]} 90 onPress={() => { 91 navigate(ROUTE_PATH.MUSIC_DETAIL); 92 }}> 93 <View style={style.artworkWrapper}> 94 <Avatar.Image 95 size={rpx(96)} 96 source={ 97 musicItem.artwork 98 ? { 99 uri: musicItem.artwork, 100 } 101 : ImgAsset.albumDefault 102 } 103 /> 104 </View> 105 <Text 106 ellipsizeMode="tail" 107 style={style.textWrapper} 108 numberOfLines={1}> 109 <ThemeText fontSize="content"> 110 {musicItem.title} 111 </ThemeText> 112 {musicItem?.artist && ( 113 <ThemeText 114 fontSize="description" 115 fontColor="secondary"> 116 {' '} 117 -{musicItem.artist} 118 </ThemeText> 119 )} 120 </Text> 121 <View style={style.actionGroup}> 122 <CircularPlayBtn /> 123 124 <Icon 125 name="playlist-music" 126 size={rpx(56)} 127 onPress={() => { 128 showPanel('PlayList'); 129 }} 130 style={[style.actionIcon, {color: colors.text}]} 131 /> 132 </View> 133 </Pressable> 134 )} 135 </Fragment> 136 ); 137} 138 139const style = StyleSheet.create({ 140 wrapper: { 141 width: rpx(750), 142 height: rpx(120), 143 flexDirection: 'row', 144 alignItems: 'center', 145 paddingHorizontal: rpx(24), 146 }, 147 artworkWrapper: { 148 height: rpx(120), 149 width: rpx(120), 150 }, 151 textWrapper: { 152 flexGrow: 1, 153 maxWidth: rpx(382), 154 }, 155 actionGroup: { 156 width: rpx(200), 157 justifyContent: 'flex-end', 158 flexDirection: 'row', 159 alignItems: 'center', 160 }, 161 actionIcon: { 162 marginLeft: rpx(36), 163 }, 164}); 165