UNPKG

@raishid/react-native-voice-message-player

Version:

An intuitive and customizable React Native module for playing voice messages seamlessly in chat interfaces. This package offers out-of-the-box components and easy-to-use configurations to integrate voice message playback functionality in your application.

1,038 lines (1,014 loc) 30.5 kB
var __getOwnPropNames = Object.getOwnPropertyNames; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; // src/assets/imgs/playing.png var require_playing = __commonJS({ "src/assets/imgs/playing.png"(exports, module) { module.exports = "./assets/playing-7JJDQBGU.png"; } }); // src/assets/imgs/pause.png var require_pause = __commonJS({ "src/assets/imgs/pause.png"(exports, module) { module.exports = "./assets/pause-5TL2VU7X.png"; } }); // src/assets/imgs/download.png var require_download = __commonJS({ "src/assets/imgs/download.png"(exports, module) { module.exports = "./assets/download-R6LJVGQS.png"; } }); // src/assets/imgs/loading.png var require_loading = __commonJS({ "src/assets/imgs/loading.png"(exports, module) { module.exports = "./assets/loading-OKBI45CP.png"; } }); // src/assets/imgs/error.png var require_error = __commonJS({ "src/assets/imgs/error.png"(exports, module) { module.exports = "./assets/error-7AKRDX7S.png"; } }); // src/assets/imgs/clock-loader.png var require_clock_loader = __commonJS({ "src/assets/imgs/clock-loader.png"(exports, module) { module.exports = "./assets/clock-loader-NVOFPLNM.png"; } }); // src/assets/imgs/single-check.png var require_single_check = __commonJS({ "src/assets/imgs/single-check.png"(exports, module) { module.exports = "./assets/single-check-QI6G3XSJ.png"; } }); // src/assets/imgs/double-check.png var require_double_check = __commonJS({ "src/assets/imgs/double-check.png"(exports, module) { module.exports = "./assets/double-check-5OEVGBYY.png"; } }); // src/assets/imgs/avatar.png var require_avatar = __commonJS({ "src/assets/imgs/avatar.png"(exports, module) { module.exports = "./assets/avatar-QBEUALAS.png"; } }); // src/assets/imgs/mic.png var require_mic = __commonJS({ "src/assets/imgs/mic.png"(exports, module) { module.exports = "./assets/mic-Y5FYMMZZ.png"; } }); // src/RNVoiceMessagePlayer.tsx import React6, { useState as useState3, useRef, useEffect as useEffect3, useImperativeHandle } from "react"; import { View as View5, Text as Text3, StyleSheet as StyleSheet6 } from "react-native"; import { Audio } from "expo-av"; import * as FileSystem from "expo-file-system"; // src/helpers/theme.ts var theme_default = { colors: { primary: "#FF3B30", secondary: "#F1F1F1", tertiary: "#FFFFFF", primaryBackground: "#FFFFFF", secondaryBackground: "rgba(249,249,249,0.94)", disabled: "#D1D1D6", accent: "#000", label: "rgba(60,60,67,0.3)", secondaryLabel: "rgb(150,150,150)" }, typography: { family: void 0 }, roundness: 12 }; // src/components/PlayPauseButton.tsx import React, { useEffect, useState } from "react"; import { Image, StyleSheet, TouchableOpacity } from "react-native"; import { jsx } from "react/jsx-runtime"; var defaultSources = { playing: require_playing(), pause: require_pause(), download: require_download(), loading: require_loading(), error: require_error() }; var PlayPauseButton = ({ isPlaying = false, isDownloadable = false, onPress, onDownload, disabled = false, isLoading = true, isError = false, theme = theme_default, style, configSources = {}, leftActionImgStyle }) => { disabled = disabled || isLoading; const buttonAction = isDownloadable || isError ? onDownload : onPress; const sources = { ...defaultSources, ...configSources }; const selectedTheme = { ...theme_default, ...theme }; const [icon, setIcon] = useState(sources.pause); useEffect(() => { setIcon(sources.pause); if (isLoading) setIcon(sources.loading); if (isError) setIcon(sources.error); if (isDownloadable) setIcon(sources.download); if (isPlaying) setIcon(sources.playing); }, [isPlaying, isDownloadable, isError, isLoading, isPlaying]); return /* @__PURE__ */ jsx( TouchableOpacity, { disabled, activeOpacity: 0.5, onPress: buttonAction, style: [styles.container, style], children: /* @__PURE__ */ jsx( Image, { source: icon, style: [ styles.image, { tintColor: disabled ? selectedTheme?.colors?.disabled : selectedTheme?.colors?.accent }, leftActionImgStyle ] } ) } ); }; var styles = StyleSheet.create({ container: { justifyContent: "center", alignItems: "center" }, image: { height: 18, tintColor: "black", width: 18, marginRight: 16, marginLeft: 8, marginVertical: 8, resizeMode: "contain" } }); var PlayPauseButton_default = React.memo(PlayPauseButton); // src/components/DownloadProgressBar.tsx import React2 from "react"; import { StyleSheet as StyleSheet2, View, Text } from "react-native"; import { jsx as jsx2, jsxs } from "react/jsx-runtime"; var DownloadProgressBar = ({ percentage = 0, theme = theme_default, renderComponent }) => { const selectedTheme = { ...theme_default, ...theme }; const displayPercentage = Math.min(100, Math.max(0, Math.floor(percentage))); if (renderComponent) { return renderComponent({ percentage: displayPercentage.toFixed(1), theme: selectedTheme }); } return /* @__PURE__ */ jsxs( View, { style: [ styles2.triangle, { backgroundColor: selectedTheme.colors?.secondaryBackground } ], children: [ /* @__PURE__ */ jsx2( View, { style: [ styles2.loader, { width: `${displayPercentage}%`, backgroundColor: selectedTheme.colors?.label } ] } ), /* @__PURE__ */ jsxs(Text, { style: [styles2.text, { color: selectedTheme?.colors?.accent }], children: [ "Downloading: ", displayPercentage, "%" ] }) ] } ); }; var styles2 = StyleSheet2.create({ triangle: { height: 11, flex: 1, borderRadius: 11, overflow: "hidden", position: "relative", justifyContent: "center" }, loader: { height: "100%", borderRadius: 11, opacity: 0.6 }, text: { fontSize: 7, position: "absolute", fontWeight: "bold", textAlign: "center", alignSelf: "center", textTransform: "capitalize", textDecorationLine: "none", fontStyle: "italic", opacity: 0.6 } }); var DownloadProgressBar_default = React2.memo(DownloadProgressBar); // src/components/TrackerTimers.tsx import { StyleSheet as StyleSheet3, View as View2, Text as Text2, Image as Image2 } from "react-native"; // src/helpers/secondsToTime.ts var secondsToTime = (seconds) => { const minutes = String(Math.floor(seconds / 60)).padStart(2, "0"); const remainingSeconds = String(seconds % 60).padStart(2, "0"); return `${minutes}:${remainingSeconds}`; }; var secondsToTime_default = secondsToTime; // src/components/TrackerTimers.tsx import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime"; var defaultStatusSources = { loading: require_clock_loader(), "single-check": require_single_check(), "double-check": require_double_check(), "double-check-viewed": require_double_check() }; var TrackerTimers = ({ theme = theme_default, timer, timestamp, renderTimer, renderTimestamp, status, statusSources }) => { const selectedTheme = { ...theme_default, ...theme }; statusSources = { ...defaultStatusSources, ...statusSources }; return /* @__PURE__ */ jsxs2(View2, { style: styles3.container, children: [ renderTimer ? renderTimer({ timer }) : /* @__PURE__ */ jsx3( Text2, { style: [ styles3.timerText, { color: selectedTheme?.colors?.accent, fontFamily: selectedTheme?.typography?.family } ], children: secondsToTime_default(Math.floor(timer)) } ), /* @__PURE__ */ jsxs2(View2, { style: styles3.rightContainer, children: [ renderTimestamp ? renderTimestamp({ timestamp }) : /* @__PURE__ */ jsx3( Text2, { style: [ styles3.timestampText, { color: selectedTheme?.colors?.accent, fontFamily: selectedTheme?.typography?.family } ], children: timestamp } ), status && statusSources?.[status] && /* @__PURE__ */ jsx3( Image2, { source: statusSources?.[status], style: [ styles3.statusIcon, { tintColor: status === "double-check-viewed" ? selectedTheme?.colors?.primary : selectedTheme?.colors?.secondaryLabel } ] } ) ] }) ] }); }; var styles3 = StyleSheet3.create({ container: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", flex: 1 }, timerText: { fontSize: 8 }, timestampText: { fontSize: 8 }, rightContainer: { flexDirection: "row", alignItems: "center" }, statusIcon: { height: 8, width: 10, marginLeft: 4, resizeMode: "contain" } }); var TrackerTimers_default = TrackerTimers; // src/components/TrackerLine.tsx import { useEffect as useEffect2, useState as useState2 } from "react"; import { StyleSheet as StyleSheet4, View as View3 } from "react-native"; import MultiSlider from "@ptomasroos/react-native-multi-slider"; import { jsx as jsx4 } from "react/jsx-runtime"; var TrackerLine = ({ theme = theme_default, thumbSize = 16, disabled = false, totalValue = 0, currentValue = 0, onValuesChange, onValuesChangeStart, onValuesChangeFinish, renderComponent, thumbColor }) => { if (!totalValue) return null; const selectedTheme = { ...theme_default, ...theme }; const [containerWidth, setContainerWidth] = useState2(0); const [sliderLength, setSliderSlength] = useState2(0); useEffect2(() => { setSliderSlength(containerWidth); }, [containerWidth]); if (renderComponent) { return renderComponent(); } return /* @__PURE__ */ jsx4( View3, { style: styles4.container, onLayout: (e) => { const width = e.nativeEvent.layout.width; const calculatedWidth = width - width / 100 * 10; setContainerWidth(calculatedWidth); }, children: /* @__PURE__ */ jsx4( MultiSlider, { min: 0, max: totalValue, values: [currentValue], sliderLength, onValuesChange: (val) => onValuesChange(disabled ? currentValue : val[0]), onValuesChangeStart, onValuesChangeFinish: (val) => onValuesChangeFinish(disabled ? currentValue : val[0]), selectedStyle: { borderColor: disabled ? selectedTheme?.colors?.disabled : selectedTheme?.colors?.label, height: 0, borderTopWidth: 1.5 }, step: 1, snapped: true, unselectedStyle: { borderColor: selectedTheme?.colors?.secondary, height: 0, borderTopWidth: 1.5 }, markerStyle: { ...styles4.marker, backgroundColor: disabled ? selectedTheme?.colors?.disabled : thumbColor || selectedTheme?.colors?.secondaryLabel, height: thumbSize, width: thumbSize, borderColor: selectedTheme?.colors?.primaryBackground } } ) } ); }; var styles4 = StyleSheet4.create({ container: { flex: 1, flexDirection: "row" }, marker: { shadowOpacity: 0, elevation: 0, borderWidth: 2 } }); var TrackerLine_default = TrackerLine; // src/components/extraction/Profiling.tsx import React5 from "react"; // src/components/Avatar.tsx import React4 from "react"; import { View as View4, Image as Image3, StyleSheet as StyleSheet5, TouchableOpacity as TouchableOpacity2 } from "react-native"; import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime"; var AvatarIcon = require_avatar(); var MicIcon = require_mic(); var Avatar = ({ renderMic, renderImage, theme = theme_default, disabled, micPosition = "left", onImagePress, imageSource, micSource, micColor }) => { const selectedTheme = { ...theme_default, ...theme }; return /* @__PURE__ */ jsxs3(View4, { style: styles5.container, children: [ renderImage ? imageSource && renderImage({ imageSource }) : /* @__PURE__ */ jsx5( TouchableOpacity2, { disabled: disabled || !onImagePress, activeOpacity: 0.5, onPress: onImagePress, style: [ styles5.avatarContainer, { borderColor: selectedTheme?.colors?.secondary } ], children: /* @__PURE__ */ jsx5( Image3, { source: imageSource || AvatarIcon, style: [ styles5.avatar, !imageSource && { tintColor: selectedTheme?.colors?.secondary } ] } ) } ), renderMic ? micSource && renderMic({ micSource }) : /* @__PURE__ */ jsx5( Image3, { source: micSource || MicIcon, style: [ styles5.mic, { tintColor: micColor || selectedTheme?.colors?.secondaryLabel, [micPosition]: -6 } ] } ) ] }); }; var styles5 = StyleSheet5.create({ container: { flexDirection: "row", alignItems: "center" }, avatarContainer: { height: 40, width: 40, borderRadius: 20, justifyContent: "center", alignItems: "center", backgroundColor: "transparent", borderWidth: 0.5, overflow: "hidden" }, avatar: { height: "100%", width: "100%", resizeMode: "cover", borderRadius: 20 }, mic: { height: 15, width: 15, resizeMode: "contain", position: "absolute", bottom: 3 } }); var Avatar_default = React4.memo(Avatar); // src/components/extraction/Profiling.tsx import { jsx as jsx6 } from "react/jsx-runtime"; var Profiling = React5.memo((props) => { const { micSource, imageSource, theme, isPlayed, onImagePress, ProfileImagePressDisabled, renderProfileImage, renderProfileMic, profilePosition } = props; if (props.renderProfile && typeof props.renderProfile === "function") { if (micSource && imageSource) { return props.renderProfile({ micSource, imageSource }); } } return /* @__PURE__ */ jsx6( Avatar_default, { micColor: isPlayed ? theme?.colors?.primary : theme?.colors?.secondaryLabel, micPosition: profilePosition === "right" ? "left" : "right", renderImage: renderProfileImage, renderMic: renderProfileMic, imageSource, micSource, onImagePress, disabled: ProfileImagePressDisabled } ); }); var Profiling_default = React5.memo(Profiling); // src/RNVoiceMessagePlayer.tsx import { format } from "date-fns"; import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime"; var VoicePlayerComponent = (props, ref) => { const { bottomProps: { bottomContainerStyle = {}, bottomStatusSources = {}, renderBottom, renderBottomTimer, renderBottomTimestamp } = {}, leftActionProps: { leftActionContainerStyle = {}, leftActionSources = {}, leftActionImgStyle, renderLeftAction } = {}, profileProps: { profileImageSource = {}, profileMicSource = {}, ProfileImagePressDisabled = false, onProfileImagePress, profileContainerStyle = {}, profilePosition = "right", renderProfile, renderProfileImage, renderProfileMic } = {}, trackProps: { onTrackChange, onTrackChangeComplete, onTrackChangeStart, renderTrack } = {}, chatStatusProps: { isNew = false, isPlayed = false, status = "single-check" } = {}, timestamp, autoDownload, containerStyle, customTheme, onDownload, onDownloadFailed, onDownloadSaved, onDownloadSuccess, onError, onLoadFailed, onLoadStart, onLoadSuccess, onLoading, onPause, onPlay, renderDownloadProgress, renderText, textError = "Audio is not playable", textLoading = "Loading...", textNotDownloaded = "Download voice message", source, showProfileAvatar = false, trackContainerStyle } = props || {}; const audioSrc = typeof source === "object" ? source.uri : source; const [isPlaying, setIsPlaying] = useState3(false); const [tempPause, setTempPause] = useState3(false); const [duration, setDuration] = useState3(0); const [currentTime, setCurrentTime] = useState3(0); const [isDownloading, setIsDownloading] = useState3(false); const [downloadProgress, setDownloadProgress] = useState3(0); const [isDownloaded, setIsDownloaded] = useState3(false); const [initializing, setInitializing] = useState3(false); const [error, setError] = useState3(false); const soundRef = useRef(null); const [time] = useState3(timestamp ? timestamp : format(/* @__PURE__ */ new Date(), "hh:mm")); const selectedTheme = { ...theme_default, ...customTheme }; const isURL = typeof audioSrc === "string" && audioSrc?.startsWith("http"); const timerValue = duration - currentTime >= 0 ? duration - currentTime : duration; const playSound = () => { if (soundRef.current === null) return; setIsPlaying(true); soundRef.current.playAsync().then((res) => { if (res.isLoaded && res.isPlaying) { typeof onPlay === "function" && onPlay(); } else { const errorMsg = "Playback failed due to audio decoding error"; typeof onError === "function" && onError(new Error(errorMsg)); console.error(errorMsg); return; } }); }; const pauseSound = () => { if (soundRef.current === null) return; soundRef.current.pauseAsync().then(() => { setIsPlaying(false); typeof onPause === "function" && onPause(); }); }; const downloadAndPlayAudio = async () => { if (isURL) { setIsDownloaded(false); console.log("Received URL based sound."); setIsDownloading(true); console.log("Downloading started..."); typeof onDownload === "function" && onDownload(); const timestamp2 = (/* @__PURE__ */ new Date()).getTime(); const randomNum = Math.floor(Math.random() * 1e3); const uniqueFileName = `audio_${timestamp2}_${randomNum}.mp3`; const localPath = `${FileSystem.cacheDirectory}/${uniqueFileName}`; console.log("Saving to: ", localPath); const resumableD = FileSystem.createDownloadResumable( audioSrc, localPath, {}, (downloadProgress2) => { const progress = downloadProgress2.totalBytesWritten / downloadProgress2.totalBytesExpectedToWrite; setDownloadProgress(progress); } ); resumableD.downloadAsync().then((_uri) => { setIsDownloading(false); console.info("Received URL downloaded successfully!"); typeof onDownloadSuccess === "function" && onDownloadSuccess(localPath); FileSystem.getInfoAsync(localPath).then(({ exists }) => { if (exists) { typeof onDownloadSaved === "function" && onDownloadSaved(localPath); console.info("Downloaded sound saved successfully!"); loadSound(localPath); } }); }).catch((err) => { const errorMsg = "Received URL threw error while downloading: " + err; console.error(errorMsg); setError(true); setIsDownloading(false); typeof onDownloadFailed === "function" && onDownloadFailed(new Error(errorMsg)); }); } else { setIsDownloaded(true); console.log("Received Local URL based sound."); loadSound(audioSrc); } }; const togglePlayPause = () => { if (isPlaying) { pauseSound(); } else { playSound(); } }; const playBackOnStatus = async (res) => { if (res.isLoaded && res.isPlaying) { const seg = res.positionMillis / 1e3; setCurrentTime(seg); } if (res.isLoaded && !res.isPlaying) { if (res.durationMillis && res.durationMillis <= res.positionMillis) { setCurrentTime(0); setIsPlaying(false); await soundRef.current?.pauseAsync(); await soundRef.current?.setPositionAsync(0); } } }; const loadSound = async (filePath) => { setInitializing(true); setIsDownloaded(true); typeof onLoadStart === "function" && onLoadStart(); console.log("Initializing Sound..."); let soudSource; if (typeof filePath === "string") { soudSource = { uri: filePath }; } else { soudSource = filePath; } try { const _sound = await Audio.Sound.createAsync( soudSource, { positionMillis: 0 }, playBackOnStatus ); soundRef.current = _sound.sound; const soundstatus = await _sound.sound.getStatusAsync(); if (soundstatus.isLoaded && soundstatus.durationMillis) { setDuration(soundstatus.durationMillis / 1e3); } typeof onLoadSuccess === "function" && onLoadSuccess(soundRef.current); console.info("Sound Initialized Successfully!"); setInitializing(false); } catch (err) { setInitializing(false); const errorMsg = "Sound Initialized Failed: " + err; typeof onLoadFailed === "function" && onLoadFailed(new Error(errorMsg)); typeof onError === "function" && onError(new Error(errorMsg)); console.error(errorMsg); setError(error); return; } }; const unMount = async () => { if (soundRef.current) { await soundRef.current.unloadAsync(); soundRef.current = null; } }; useEffect3(() => { if (typeof onLoading === "function") { if (initializing || isDownloading) { onLoading(); } } }, [initializing, isDownloading, onLoading]); useEffect3(() => { downloadAndPlayAudio(); return () => { unMount(); }; }, [audioSrc, autoDownload]); useImperativeHandle(ref, () => ({ play: playSound, pause: pauseSound, load: loadSound, loadWithDownload: downloadAndPlayAudio, getSoundRef: () => soundRef.current, getDuration: () => duration, getIsDownloading: () => isDownloading, getIsDownloaded: () => isDownloaded, getDownloadProgress: () => downloadProgress, getPlayingStatus: () => isPlaying, getTimerInSeconds: () => timerValue, togglePlayingStatus: () => togglePlayPause })); return /* @__PURE__ */ jsxs4( View5, { style: [ styles6.container, { backgroundColor: selectedTheme?.colors?.primaryBackground, borderRadius: selectedTheme?.roundness }, containerStyle ], children: [ showProfileAvatar && profilePosition === "left" && /* @__PURE__ */ jsx7(View5, { style: [styles6.profileContainerStyle, profileContainerStyle], children: /* @__PURE__ */ jsx7( Profiling_default, { micSource: profileMicSource, imageSource: profileImageSource, theme: selectedTheme, isPlayed, onImagePress: onProfileImagePress, ProfileImagePressDisabled, renderProfileImage, renderProfileMic, profilePosition, renderProfile } ) }), typeof renderLeftAction === "function" ? renderLeftAction({ isLoading: initializing || isDownloading, isError: error, isDownloaded, isDownloading, isPlaying }) : /* @__PURE__ */ jsx7( PlayPauseButton_default, { style: leftActionContainerStyle, theme: selectedTheme, configSources: leftActionSources, disabled: isDownloading, onDownload: downloadAndPlayAudio, isPlaying, onPress: togglePlayPause, isDownloadable: !isDownloaded, isLoading: initializing || isDownloading, isError: error, leftActionImgStyle } ), /* @__PURE__ */ jsxs4(View5, { style: [styles6.centerView, trackContainerStyle], children: [ typeof renderText === "function" ? renderText({ theme: selectedTheme, initializing, error, isDownloading, isURL, isDownloaded, autoDownload, text: textNotDownloaded }) : /* @__PURE__ */ jsx7(React6.Fragment, { children: !autoDownload && isURL && !isDownloaded && !isDownloading && textNotDownloaded && /* @__PURE__ */ jsx7( Text3, { style: [ styles6.text, { color: selectedTheme?.colors?.label, fontFamily: selectedTheme?.typography?.family } ], children: textNotDownloaded } ) }), (initializing || error) && !isDownloading ? typeof renderText === "function" ? renderText({ theme: selectedTheme, initializing, error, isDownloading, isURL, isDownloaded, autoDownload, text: textNotDownloaded }) : /* @__PURE__ */ jsx7( Text3, { style: [ styles6.text, { color: selectedTheme?.colors?.label, fontFamily: selectedTheme?.typography?.family } ], children: initializing ? textLoading : error ? textError : null } ) : /* @__PURE__ */ jsxs4(React6.Fragment, { children: [ isDownloading && (typeof renderDownloadProgress === "function" ? renderDownloadProgress({ progress: downloadProgress, theme: selectedTheme }) : /* @__PURE__ */ jsx7( DownloadProgressBar_default, { theme: selectedTheme, percentage: downloadProgress } )), !isDownloading && (typeof renderTrack === "function" ? renderTrack({ error, theme: selectedTheme, duration, currentTime, setCurrentTime, soundRef: soundRef.current }) : /* @__PURE__ */ jsx7( TrackerLine_default, { disabled: error, theme: selectedTheme, totalValue: duration, currentValue: currentTime, thumbColor: isNew ? selectedTheme?.colors?.primary : selectedTheme?.colors?.secondaryLabel, onValuesChange: async (value) => { await soundRef.current?.setPositionAsync(value * 1e3); setCurrentTime(value); typeof onTrackChange === "function" && onTrackChange(value); }, onValuesChangeStart: () => { pauseSound(); if (isPlaying) { setTempPause(true); } typeof onTrackChangeStart === "function" && onTrackChangeStart(); }, onValuesChangeFinish: (value) => { if (soundRef.current) { if (value) { setCurrentTime(value); } if (tempPause) { playSound(); setTempPause(false); } if (typeof onTrackChangeComplete === "function" && value) { onTrackChangeComplete(value); } } } } )) ] }), /* @__PURE__ */ jsx7(View5, { style: [styles6.timeContainer, bottomContainerStyle], children: typeof renderBottom === "function" ? renderBottom({ theme: selectedTheme, timer: timerValue, timestamp: time }) : /* @__PURE__ */ jsx7( TrackerTimers_default, { status, statusSources: bottomStatusSources, theme: selectedTheme, timer: timerValue, timestamp: time, renderTimer: renderBottomTimer, renderTimestamp: renderBottomTimestamp } ) }) ] }), showProfileAvatar && profilePosition === "right" && /* @__PURE__ */ jsx7( Profiling_default, { micSource: profileMicSource, imageSource: profileImageSource, theme: selectedTheme, isPlayed, onImagePress: onProfileImagePress, ProfileImagePressDisabled, renderProfileImage, renderProfileMic, profilePosition, renderProfile } ) ] } ); }; var styles6 = StyleSheet6.create({ container: { paddingVertical: 8, paddingHorizontal: 8, minHeight: 60, backgroundColor: "#FFF", marginHorizontal: 16, justifyContent: "center", alignItems: "center", flexDirection: "row" }, profileContainerStyle: { position: "relative", marginHorizontal: 8 }, centerView: { flex: 1, flexDirection: "row", position: "relative", alignItems: "center", height: 20, marginRight: 16 }, sliderContainer: { flex: 1 }, timeContainer: { position: "absolute", left: 0, right: 0, bottom: -10 }, text: { fontSize: 12 } }); var RNVoiceMessagePlayer = React6.forwardRef(VoicePlayerComponent); var RNVoiceMessagePlayer_default = RNVoiceMessagePlayer; // src/index.ts var index_default = RNVoiceMessagePlayer_default; export { TrackerTimers_default as BottomTimesComponent, DownloadProgressBar_default as DownloadProgressBarComponent, PlayPauseButton_default as LeftActionComponent, Avatar_default as ProfileComponent, TrackerLine_default as TrackerLineComponent, index_default as default, theme_default as theme };