diff --git a/app/containers/message/Components/Audio/Slider.tsx b/app/containers/message/Components/Audio/Slider.tsx new file mode 100644 index 000000000..3e80e978e --- /dev/null +++ b/app/containers/message/Components/Audio/Slider.tsx @@ -0,0 +1,98 @@ +import React from 'react'; +import { LayoutChangeEvent, View, TextInput } from 'react-native'; +import { PanGestureHandler } from 'react-native-gesture-handler'; +import Animated, { + useAnimatedGestureHandler, + useAnimatedProps, + useAnimatedStyle, + useDerivedValue, + useSharedValue +} from 'react-native-reanimated'; + +import styles from './styles'; +import { useTheme } from '../../../../theme'; + +const AnimatedTextInput = Animated.createAnimatedComponent(TextInput); + +const Slider = ({ currentTime = 0, duration = 120, thumbColor = '' }) => { + console.log('🚀 ~ file: Slider.tsx:18 ~ Slider ~ currentTime:', currentTime); + const { colors } = useTheme(); + + const maxWidth = useSharedValue(1); + const x = useSharedValue(currentTime); + const current = useSharedValue('00:00'); + const scale = useSharedValue(1); + + const styleLine = useAnimatedStyle(() => ({ + width: x.value, + zIndex: 2 + })); + + const styleThumb = useAnimatedStyle(() => ({ + transform: [{ translateX: x.value }, { scale: scale.value }] + })); + + const onLayout = (event: LayoutChangeEvent) => { + const { width } = event.nativeEvent.layout; + maxWidth.value = width - 12; + }; + + const gestureHandler = useAnimatedGestureHandler({ + onStart: (_, ctx: any) => { + ctx.startX = x.value; + }, + onActive: (event, ctx: any) => { + const moveInX: number = ctx.startX + event.translationX; + if (moveInX < 0) { + x.value = 0; + } else if (moveInX > maxWidth.value) { + x.value = maxWidth.value; + } else { + x.value = moveInX; + } + + scale.value = 1.3; + }, + onEnd: () => { + scale.value = 1; + // SEND A CALLBACK TO CHANGE THE PROGRESS OF THE AUDIO + } + }); + + useDerivedValue(() => { + const cTime = (x.value * duration) / maxWidth.value; + const minutes = Math.floor(cTime / 60); + const remainingSeconds = Math.floor(cTime % 60); + const formattedMinutes = String(minutes).padStart(2, '0'); + const formattedSeconds = String(remainingSeconds).padStart(2, '0'); + current.value = `${formattedMinutes}:${formattedSeconds}`; + }, [x, maxWidth, duration]); + + const getCurrentTime = useAnimatedProps( + () => + ({ + text: current.value + } as any), + [current] + ); + + return ( + + + + + + + + + + + ); +}; + +export default Slider; diff --git a/app/containers/message/Components/Audio/index.tsx b/app/containers/message/Components/Audio/index.tsx index f7e6d2691..338e10f40 100644 --- a/app/containers/message/Components/Audio/index.tsx +++ b/app/containers/message/Components/Audio/index.tsx @@ -1,17 +1,13 @@ import React, { useContext, useEffect, useRef, useState } from 'react'; -import { StyleProp, StyleSheet, Text, TextStyle, View, useWindowDimensions } from 'react-native'; +import { StyleProp, TextStyle, View } from 'react-native'; import { Audio, AVPlaybackStatus, InterruptionModeAndroid, InterruptionModeIOS } from 'expo-av'; -import Slider from '@react-native-community/slider'; -import moment from 'moment'; import { activateKeepAwakeAsync, deactivateKeepAwake } from 'expo-keep-awake'; import { Sound } from 'expo-av/build/Audio/Sound'; import Touchable from '../../Touchable'; import Markdown from '../../../markdown'; import { CustomIcon } from '../../../CustomIcon'; -import sharedStyles from '../../../../views/Styles'; import { themes } from '../../../../lib/constants'; -import { isAndroid, isIOS } from '../../../../lib/methods/helpers'; import MessageContext from '../../Context'; import ActivityIndicator from '../../../ActivityIndicator'; import { TGetCustomEmoji } from '../../../../definitions/IEmoji'; @@ -21,6 +17,8 @@ import { downloadMediaFile, getMediaCache } from '../../../../lib/methods/handle import EventEmitter from '../../../../lib/methods/helpers/events'; import { PAUSE_AUDIO } from '../../constants'; import { fetchAutoDownloadEnabled } from '../../../../lib/methods/autoDownloadPreference'; +import styles from './styles'; +import Slider from './Slider'; interface IButton { loading: boolean; @@ -48,36 +46,6 @@ const mode = { interruptionModeAndroid: InterruptionModeAndroid.DoNotMix }; -const styles = StyleSheet.create({ - audioContainer: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - height: 56, - borderWidth: 1, - borderRadius: 4, - marginBottom: 6 - }, - playPauseButton: { - marginHorizontal: 10, - alignItems: 'center', - backgroundColor: 'transparent' - }, - audioLoading: { - marginHorizontal: 8 - }, - slider: { - flex: 1 - }, - duration: { - marginHorizontal: 12, - fontSize: 14, - ...sharedStyles.textRegular - } -}); - -const formatTime = (seconds: number) => moment.utc(seconds * 1000).format('mm:ss'); - const BUTTON_HIT_SLOP = { top: 12, right: 12, bottom: 12, left: 12 }; const Button = React.memo(({ loading, paused, onPress, disabled, cached }: IButton) => { @@ -114,7 +82,6 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage const [cached, setCached] = useState(false); const { baseUrl, user } = useContext(MessageContext); - const { scale } = useWindowDimensions(); const { theme } = useTheme(); const sound = useRef(null); @@ -150,6 +117,7 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage const onProgress = (data: AVPlaybackStatus) => { if (data.isLoaded) { const currentTime = data.positionMillis / 1000; + console.log('🚀 ~ file: index.tsx:120 ~ onProgress ~ currentTime:', currentTime); if (currentTime <= duration) { setCurrentTime(currentTime); } @@ -171,8 +139,6 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage } }; - const getDuration = () => formatTime(currentTime || duration); - const togglePlayPause = () => { setPaused(!paused); playPause(!paused); @@ -240,15 +206,6 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage handleDownload(); }; - const onValueChange = async (value: number) => { - try { - setCurrentTime(value); - await sound.current?.setPositionAsync(value * 1000); - } catch { - // Do nothing - } - }; - useEffect(() => { sound.current = new Audio.Sound(); sound.current?.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate); @@ -296,9 +253,9 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage } let thumbColor; - if (isAndroid && isReply) { + if (isReply) { thumbColor = themes[theme].tintDisabled; - } else if (isAndroid) { + } else { thumbColor = themes[theme].tintColor; } @@ -318,19 +275,8 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage ]} >