1*62e73a5eS猫头猫import React, {memo, useLayoutEffect, useMemo} from 'react'; 2f511aee9S猫头猫import {StyleSheet, Text, View} from 'react-native'; 3f511aee9S猫头猫import rpx from '@/utils/rpx'; 4f511aee9S猫头猫import FastImage from '../base/fastImage'; 5f511aee9S猫头猫import {ImgAsset} from '@/constants/assetsConst'; 6f511aee9S猫头猫import Color from 'color'; 7f511aee9S猫头猫import ThemeText from '../base/themeText'; 8f511aee9S猫头猫import useColors from '@/hooks/useColors'; 9f511aee9S猫头猫import {ROUTE_PATH, useNavigate} from '@/entry/router'; 10f511aee9S猫头猫import {Gesture, GestureDetector} from 'react-native-gesture-handler'; 11f511aee9S猫头猫import TrackPlayer from '@/core/trackPlayer'; 12f511aee9S猫头猫import Animated, { 13f511aee9S猫头猫 SharedValue, 14f511aee9S猫头猫 runOnJS, 15f511aee9S猫头猫 useAnimatedStyle, 16f511aee9S猫头猫 useSharedValue, 17f511aee9S猫头猫 withTiming, 18f511aee9S猫头猫} from 'react-native-reanimated'; 19f511aee9S猫头猫import {useSafeAreaInsets} from 'react-native-safe-area-context'; 20f511aee9S猫头猫import {timingConfig} from '@/constants/commonConst'; 21f511aee9S猫头猫 22f511aee9S猫头猫interface IBarMusicItemProps { 23f511aee9S猫头猫 musicItem: IMusic.IMusicItem | null; 24f511aee9S猫头猫 activeIndex: number; // 当前展示的是0/1/2 25f511aee9S猫头猫 transformSharedValue: SharedValue<number>; 26f511aee9S猫头猫} 27f511aee9S猫头猫function _BarMusicItem(props: IBarMusicItemProps) { 28f511aee9S猫头猫 const {musicItem, activeIndex, transformSharedValue} = props; 29f511aee9S猫头猫 const colors = useColors(); 30f511aee9S猫头猫 const safeAreaInsets = useSafeAreaInsets(); 31f511aee9S猫头猫 32f511aee9S猫头猫 const animatedStyles = useAnimatedStyle(() => { 33f511aee9S猫头猫 return { 34f511aee9S猫头猫 left: `${(transformSharedValue.value + activeIndex) * 100}%`, 35f511aee9S猫头猫 }; 36f511aee9S猫头猫 }, [activeIndex]); 37f511aee9S猫头猫 38f511aee9S猫头猫 if (!musicItem) { 39f511aee9S猫头猫 return null; 40f511aee9S猫头猫 } 41f511aee9S猫头猫 42f511aee9S猫头猫 return ( 43f511aee9S猫头猫 <Animated.View 44f511aee9S猫头猫 style={[ 45f511aee9S猫头猫 styles.container, 46f511aee9S猫头猫 { 47f511aee9S猫头猫 paddingLeft: rpx(24) + safeAreaInsets.left, 48f511aee9S猫头猫 }, 49f511aee9S猫头猫 animatedStyles, 50f511aee9S猫头猫 ]}> 51f511aee9S猫头猫 <FastImage 52f511aee9S猫头猫 style={styles.artworkImg} 53f511aee9S猫头猫 uri={musicItem.artwork} 54f511aee9S猫头猫 emptySrc={ImgAsset.albumDefault} 55f511aee9S猫头猫 /> 56f511aee9S猫头猫 <Text 57f511aee9S猫头猫 ellipsizeMode="tail" 58f511aee9S猫头猫 accessible={false} 59f511aee9S猫头猫 style={styles.textWrapper} 60f511aee9S猫头猫 numberOfLines={1}> 61f511aee9S猫头猫 <ThemeText fontSize="content" fontColor="musicBarText"> 62f511aee9S猫头猫 {musicItem?.title} 63f511aee9S猫头猫 </ThemeText> 64f511aee9S猫头猫 {musicItem?.artist && ( 65f511aee9S猫头猫 <ThemeText 66f511aee9S猫头猫 fontSize="description" 67f511aee9S猫头猫 color={Color(colors.musicBarText) 68f511aee9S猫头猫 .alpha(0.6) 69f511aee9S猫头猫 .toString()}> 70f511aee9S猫头猫 {' '} 71f511aee9S猫头猫 -{musicItem.artist} 72f511aee9S猫头猫 </ThemeText> 73f511aee9S猫头猫 )} 74f511aee9S猫头猫 </Text> 75f511aee9S猫头猫 </Animated.View> 76f511aee9S猫头猫 ); 77f511aee9S猫头猫} 78f511aee9S猫头猫 79f511aee9S猫头猫const BarMusicItem = memo( 80f511aee9S猫头猫 _BarMusicItem, 81f511aee9S猫头猫 (prev, curr) => 82f511aee9S猫头猫 prev.musicItem === curr.musicItem && 83f511aee9S猫头猫 prev.activeIndex === curr.activeIndex, 84f511aee9S猫头猫); 85f511aee9S猫头猫 86f511aee9S猫头猫const styles = StyleSheet.create({ 87f511aee9S猫头猫 container: { 88f511aee9S猫头猫 flexDirection: 'row', 89f511aee9S猫头猫 width: '100%', 90f511aee9S猫头猫 alignItems: 'center', 91f511aee9S猫头猫 position: 'absolute', 92f511aee9S猫头猫 }, 93f511aee9S猫头猫 textWrapper: { 94f511aee9S猫头猫 flexGrow: 1, 95f511aee9S猫头猫 flexShrink: 1, 96f511aee9S猫头猫 }, 97f511aee9S猫头猫 artworkImg: { 98f511aee9S猫头猫 width: rpx(96), 99f511aee9S猫头猫 height: rpx(96), 100f511aee9S猫头猫 borderRadius: rpx(48), 101f511aee9S猫头猫 marginRight: rpx(24), 102f511aee9S猫头猫 }, 103f511aee9S猫头猫}); 104f511aee9S猫头猫 105f511aee9S猫头猫interface IMusicInfoProps { 106f511aee9S猫头猫 musicItem: IMusic.IMusicItem | null; 107f511aee9S猫头猫 paddingLeft?: number; 108f511aee9S猫头猫} 109f511aee9S猫头猫 110f511aee9S猫头猫function skipMusicItem(direction: number) { 111f511aee9S猫头猫 if (direction === -1) { 112f511aee9S猫头猫 TrackPlayer.skipToNext(); 113f511aee9S猫头猫 } else if (direction === 1) { 114f511aee9S猫头猫 TrackPlayer.skipToPrevious(); 115f511aee9S猫头猫 } 116f511aee9S猫头猫} 117f511aee9S猫头猫 118f511aee9S猫头猫export default function MusicInfo(props: IMusicInfoProps) { 119f511aee9S猫头猫 const {musicItem} = props; 120f511aee9S猫头猫 const navigate = useNavigate(); 121c78b5264S猫头猫 const playLists = TrackPlayer.usePlayList(); 122f511aee9S猫头猫 const siblingMusicItems = useMemo(() => { 123f511aee9S猫头猫 if (!musicItem) { 124f511aee9S猫头猫 return { 125f511aee9S猫头猫 prev: null, 126f511aee9S猫头猫 next: null, 127f511aee9S猫头猫 }; 128f511aee9S猫头猫 } 129f511aee9S猫头猫 return { 130f511aee9S猫头猫 prev: TrackPlayer.getPreviousMusic(), 131f511aee9S猫头猫 next: TrackPlayer.getNextMusic(), 132f511aee9S猫头猫 }; 133c78b5264S猫头猫 }, [musicItem, playLists]); 134f511aee9S猫头猫 135f511aee9S猫头猫 // +- 1 136f511aee9S猫头猫 const transformSharedValue = useSharedValue(0); 137f511aee9S猫头猫 138*62e73a5eS猫头猫 const musicItemWidthValue = useSharedValue(0); 139f511aee9S猫头猫 140f511aee9S猫头猫 const tapGesture = Gesture.Tap() 141f511aee9S猫头猫 .onStart(() => { 142f511aee9S猫头猫 navigate(ROUTE_PATH.MUSIC_DETAIL); 143f511aee9S猫头猫 }) 144f511aee9S猫头猫 .runOnJS(true); 145f511aee9S猫头猫 146f511aee9S猫头猫 useLayoutEffect(() => { 147f511aee9S猫头猫 transformSharedValue.value = 0; 148f511aee9S猫头猫 }, [musicItem]); 149f511aee9S猫头猫 150f511aee9S猫头猫 const panGesture = Gesture.Pan() 151f511aee9S猫头猫 .minPointers(1) 152f511aee9S猫头猫 .maxPointers(1) 153f511aee9S猫头猫 .onUpdate(e => { 154*62e73a5eS猫头猫 if (musicItemWidthValue.value) { 155f511aee9S猫头猫 transformSharedValue.value = 156*62e73a5eS猫头猫 e.translationX / musicItemWidthValue.value; 157f511aee9S猫头猫 } 158f511aee9S猫头猫 }) 159f511aee9S猫头猫 .onEnd((e, success) => { 160f511aee9S猫头猫 if (!success) { 161f511aee9S猫头猫 // 还原到原始位置 162f511aee9S猫头猫 transformSharedValue.value = withTiming( 163f511aee9S猫头猫 0, 164f511aee9S猫头猫 timingConfig.animationFast, 165f511aee9S猫头猫 ); 166f511aee9S猫头猫 } else { 167f511aee9S猫头猫 // fling 168f511aee9S猫头猫 const deltaX = e.translationX; 169f511aee9S猫头猫 const vX = e.velocityX; 170f511aee9S猫头猫 171f511aee9S猫头猫 let skip = 0; 172*62e73a5eS猫头猫 if (musicItemWidthValue.value) { 173*62e73a5eS猫头猫 const rate = deltaX / musicItemWidthValue.value; 174f511aee9S猫头猫 175f511aee9S猫头猫 if (Math.abs(rate) > 0.3) { 176f511aee9S猫头猫 // 先判断距离 177f511aee9S猫头猫 skip = vX > 0 ? 1 : -1; 178f511aee9S猫头猫 transformSharedValue.value = withTiming( 179f511aee9S猫头猫 skip, 180f511aee9S猫头猫 timingConfig.animationFast, 181f511aee9S猫头猫 () => { 182f511aee9S猫头猫 runOnJS(skipMusicItem)(skip); 183f511aee9S猫头猫 }, 184f511aee9S猫头猫 ); 185f511aee9S猫头猫 } else if (Math.abs(vX) > 1500) { 186f511aee9S猫头猫 // 再判断速度 187f511aee9S猫头猫 skip = vX > 0 ? 1 : -1; 188f511aee9S猫头猫 transformSharedValue.value = skip; 189f511aee9S猫头猫 runOnJS(skipMusicItem)(skip); 190f511aee9S猫头猫 } else { 191f511aee9S猫头猫 transformSharedValue.value = withTiming( 192f511aee9S猫头猫 0, 193f511aee9S猫头猫 timingConfig.animationFast, 194f511aee9S猫头猫 ); 195f511aee9S猫头猫 } 196f511aee9S猫头猫 } else { 197f511aee9S猫头猫 transformSharedValue.value = 0; 198f511aee9S猫头猫 } 199f511aee9S猫头猫 } 200f511aee9S猫头猫 }); 201f511aee9S猫头猫 202f511aee9S猫头猫 const gesture = Gesture.Race(panGesture, tapGesture); 203f511aee9S猫头猫 204f511aee9S猫头猫 return ( 205f511aee9S猫头猫 <GestureDetector gesture={gesture}> 206f511aee9S猫头猫 <View 207f511aee9S猫头猫 style={musicInfoStyles.infoContainer} 208f511aee9S猫头猫 onLayout={e => { 209*62e73a5eS猫头猫 musicItemWidthValue.value = e.nativeEvent.layout.width; 210f511aee9S猫头猫 }}> 211f511aee9S猫头猫 <BarMusicItem 212f511aee9S猫头猫 transformSharedValue={transformSharedValue} 213f511aee9S猫头猫 musicItem={siblingMusicItems.prev} 214f511aee9S猫头猫 activeIndex={-1} 215f511aee9S猫头猫 /> 216f511aee9S猫头猫 <BarMusicItem 217f511aee9S猫头猫 transformSharedValue={transformSharedValue} 218f511aee9S猫头猫 musicItem={musicItem} 219f511aee9S猫头猫 activeIndex={0} 220f511aee9S猫头猫 /> 221f511aee9S猫头猫 <BarMusicItem 222f511aee9S猫头猫 transformSharedValue={transformSharedValue} 223f511aee9S猫头猫 musicItem={siblingMusicItems.next} 224f511aee9S猫头猫 activeIndex={1} 225f511aee9S猫头猫 /> 226f511aee9S猫头猫 </View> 227f511aee9S猫头猫 </GestureDetector> 228f511aee9S猫头猫 ); 229f511aee9S猫头猫} 230f511aee9S猫头猫 231f511aee9S猫头猫const musicInfoStyles = StyleSheet.create({ 232f511aee9S猫头猫 infoContainer: { 233f511aee9S猫头猫 flex: 1, 234f511aee9S猫头猫 height: '100%', 235f511aee9S猫头猫 alignItems: 'center', 236f511aee9S猫头猫 flexDirection: 'row', 237f511aee9S猫头猫 overflow: 'hidden', 238f511aee9S猫头猫 }, 239f511aee9S猫头猫}); 240