UNPKG

mediasfu-reactnative

Version:
264 lines 9.44 kB
// MiniAudio.tsx import { getOverlayPosition } from '../../methods/utils/getOverlayPosition'; import React, { useState, useEffect, useRef } from 'react'; import { View, Text, StyleSheet, Image, Animated, PanResponder, Platform, } from 'react-native'; /** * MiniAudio component renders a draggable audio player with customizable display options, including * optional waveform animation, overlay positioning, and background image styling. * * This component provides an animated waveform that can be toggled, and it allows for flexible styling of the name, position, and image. * The component is also draggable for convenient placement on the screen. * * @component * @param {MiniAudioOptions} props - Configuration options for the MiniAudio component. * @param {boolean} [props.visible=true] - Controls the visibility of the component. * @param {StyleProp<ViewStyle>} [props.customStyle] - Custom styles for the component container. * @param {string} props.name - Name to display on the audio player. * @param {boolean} [props.showWaveform=false] - Toggles visibility of the waveform animation. * @param {OverlayPosition} [props.overlayPosition='topLeft'] - Position of the overlay on the screen. * @param {string} [props.barColor='red'] - Color of the waveform bars. * @param {string} [props.textColor='white'] - Color of the displayed name text. * @param {StyleProp<TextStyle>} [props.nameTextStyling] - Custom styles for the name text. * @param {string} props.imageSource - URI for the background image. * @param {boolean} [props.roundedImage=false] - Determines if the background image should be rounded. * @param {StyleProp<ImageStyle>} [props.imageStyle] - Custom styles for the background image. * * @returns {JSX.Element} The MiniAudio component. * * @example * ```tsx * import React from 'react'; * import { MiniAudio } from 'mediasfu-reactnative'; * * function App() { * return ( * <MiniAudio * visible={true} * name="John Doe" * showWaveform={true} * overlayPosition="bottomRight" * barColor="blue" * textColor="white" * imageSource="https://example.com/avatar.jpg" * roundedImage={true} * /> * ); * } * * export default App; * ``` */ const MiniAudio = ({ visible = true, customStyle, name, showWaveform = false, overlayPosition = 'topLeft', barColor = 'red', textColor = 'white', nameTextStyling, imageSource, roundedImage = false, imageStyle, }) => { const pan = useRef(new Animated.ValueXY()).current; const panResponder = useRef(PanResponder.create({ onMoveShouldSetPanResponderCapture: () => true, onStartShouldSetPanResponder: () => true, onPanResponderGrant: () => { // Set the initial value to the current state pan === null || pan === void 0 ? void 0 : pan.setOffset({ x: pan.x._value, y: pan.y._value, }); }, onPanResponderMove: Animated.event([null, { dx: pan.x, dy: pan.y }], { useNativeDriver: false, }), onPanResponderRelease: () => { pan.flattenOffset(); }, })).current; const [waveformAnimations] = useState(Array.from({ length: 9 }, () => new Animated.Value(0))); useEffect(() => { if (showWaveform) { animateWaveform(); } else { resetWaveform(); } }, [showWaveform]); const animateWaveform = () => { const animations = waveformAnimations.map((animation, index) => Animated.loop(Animated.sequence([ Animated.timing(animation, { toValue: 1, duration: getAnimationDuration(index), useNativeDriver: false, }), Animated.timing(animation, { toValue: 0, duration: getAnimationDuration(index), useNativeDriver: false, }), ]))); Animated.parallel(animations).start(); }; /** * Resets the waveform animations to initial state. */ const resetWaveform = () => { waveformAnimations.forEach((animation) => animation.setValue(0)); }; /** * Retrieves the animation duration for a specific bar. * @param index - The index of the waveform bar. * @returns number - The duration in milliseconds. */ const getAnimationDuration = (index) => { const durations = [474, 433, 407, 458, 400, 427, 441, 419, 487]; return durations[index] || 0; }; return (<View style={[styles.container, { display: visible ? 'flex' : 'none' }]}> <Animated.View style={[ styles.modalContent, { transform: pan.getTranslateTransform() }, styles.modalContainer, ]} {...panResponder.panHandlers}> <View style={[styles.card, StyleSheet.flatten(customStyle)]}> {imageSource && (<Image source={{ uri: imageSource }} style={[ styles.backgroundImage, roundedImage && styles.roundedImage, imageStyle, ]} resizeMode="cover"/>)} <View> <Text style={[ styles.nameText, StyleSheet.flatten([nameTextStyling, { color: textColor }]), ]}> {name} </Text> </View> <View style={[ StyleSheet.flatten(getOverlayPosition({ position: overlayPosition })), StyleSheet.flatten(Platform.OS === 'web' ? styles.overlayWeb : styles.overlayMobile), ]}> <View> {/* <Text style={{ ...styles.nameText, color: textColor }}>{name}</Text> */} </View> <View style={Object.assign({}, (Platform.OS === 'web' ? styles.waveformWeb : styles.waveformMobile))}> {waveformAnimations.map((animation, index) => (<Animated.View key={index} style={[ styles.bar, { height: animation.interpolate({ inputRange: [0, 1], outputRange: [1, 40], }), backgroundColor: barColor, }, ]}/>))} </View> <View /> </View> </View> </Animated.View> </View>); }; export default MiniAudio; const styles = StyleSheet.create({ container: { width: 100, // Specify the desired width height: 100, // Specify the desired height justifyContent: 'center', alignItems: 'center', backgroundColor: 'transparent', margin: 0, // Remove any margin padding: 0, // Remove any padding elevation: 8, zIndex: 8, position: 'absolute', top: 0, right: 0, }, card: { width: '100%', height: '100%', margin: 0, padding: 0, backgroundColor: '#2c678f', }, overlayMobile: { position: 'absolute', width: 'auto', flexDirection: 'row', justifyContent: 'center', alignItems: 'center', }, overlayWeb: { position: 'absolute', minWidth: '100%', height: '100%', maxHeight: '100%', display: 'flex', }, nameColumn: { justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0, 0, 0, 0.5)', paddingVertical: 5, paddingHorizontal: 10, marginEnd: 2, fontSize: 14, }, nameText: { fontSize: 20, color: 'white', fontWeight: 'bold', justifyContent: 'center', alignItems: 'center', alignSelf: 'center', backgroundColor: 'rgba(0, 0, 0, 0.5)', width: '100%', display: 'flex', paddingVertical: 3, textAlign: 'center', }, waveformWeb: { display: 'flex', justifyContent: 'flex-start', alignItems: 'center', backgroundColor: 'rgba(0, 0, 0, 0.05)', padding: 0, flexDirection: 'row', }, waveformMobile: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0, 0, 0, 0.05)', maxHeight: '100%', marginLeft: 5, maxWidth: '100%', marginVertical: '30%', }, bar: { flex: 1, opacity: 0.35, marginHorizontal: 1, }, backgroundImage: Object.assign(Object.assign({}, StyleSheet.absoluteFillObject), { width: 70, height: 70, justifyContent: 'center', alignItems: 'center', alignSelf: 'center', top: '40%', left: '50%', transform: [ { translateY: -10 }, // Half of the height { translateX: -35 }, // Half of the width ] }), roundedImage: { borderRadius: 20, }, modalContainer: { // flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0, 45, 33, 0.5)', padding: 0, margin: 0, width: 100, height: 100, }, modalContent: { width: 100, // You should specify the unit, e.g., 100px or 100% height: 100, // You should specify the unit, e.g., 100px or 100% backgroundColor: 'white', borderRadius: 10, margin: 0, // Remove any margin padding: 0, // Remove any padding }, }); //# sourceMappingURL=MiniAudio.js.map