play/pause button, currentTime equal the sound, can change the slider and reflect to the sound

This commit is contained in:
Reinaldo Neto 2023-08-08 18:24:46 -03:00
parent f344c9e97f
commit 5bb14cb1e3
2 changed files with 90 additions and 31 deletions

View File

@ -1,27 +1,80 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import { LayoutChangeEvent, View, TextInput } from 'react-native'; import { LayoutChangeEvent, View, TextInput } from 'react-native';
import { PanGestureHandler } from 'react-native-gesture-handler'; import { PanGestureHandler } from 'react-native-gesture-handler';
import Animated, { import Animated, {
runOnJS,
useAnimatedGestureHandler, useAnimatedGestureHandler,
useAnimatedProps, useAnimatedProps,
useAnimatedStyle, useAnimatedStyle,
useDerivedValue, useDerivedValue,
useSharedValue useSharedValue
} from 'react-native-reanimated'; } from 'react-native-reanimated';
import { Sound } from 'expo-av/build/Audio/Sound';
import { AVPlaybackStatus } from 'expo-av';
import styles from './styles'; import styles from './styles';
import { useTheme } from '../../../../theme'; import { useTheme } from '../../../../theme';
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput); const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
const Slider = ({ currentTime = 0, duration = 120, thumbColor = '' }) => { interface ISlider {
console.log('🚀 ~ file: Slider.tsx:18 ~ Slider ~ currentTime:', currentTime); currentTime: number;
duration: number;
thumbColor: string;
sound: Sound | null;
}
const Slider = ({ thumbColor = '', sound }: ISlider) => {
const [loaded, setLoaded] = useState(false);
const { colors } = useTheme(); const { colors } = useTheme();
const duration = useSharedValue(0);
const currentTime = useSharedValue(0);
const maxWidth = useSharedValue(1); const maxWidth = useSharedValue(1);
const x = useSharedValue(currentTime); const x = useSharedValue(0);
const current = useSharedValue('00:00'); const current = useSharedValue('00:00');
const scale = useSharedValue(1); const scale = useSharedValue(1);
const isHandlePan = useSharedValue(false);
const onEndGestureHandler = useSharedValue(false);
const onPlaybackStatusUpdate = (status: AVPlaybackStatus) => {
console.log('🚀 ~ file: Slider.tsx:42 ~ onPlaybackStatusUpdate ~ status:', status);
if (status) {
onLoad(status);
onProgress(status);
onEnd(status);
}
};
useEffect(() => {
if (sound) {
sound.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate);
}
}, [onPlaybackStatusUpdate, sound]);
const onLoad = (data: AVPlaybackStatus) => {
if (data.isLoaded && data.durationMillis) {
const durationSeconds = data.durationMillis / 1000;
duration.value = durationSeconds > 0 ? durationSeconds : 0;
setLoaded(true);
}
};
const onProgress = (data: AVPlaybackStatus) => {
if (data.isLoaded) {
const currentSecond = data.positionMillis / 1000;
if (currentSecond <= duration.value) {
console.log('🚀 ~ file: Slider.tsx:68 ~ onProgress ~ duration.value:', duration.value);
console.log('🚀 ~ file: Slider.tsx:70 ~ onProgress ~ currentTime.value:', currentTime.value);
currentTime.value = currentSecond;
}
}
};
const onEnd = (data: AVPlaybackStatus) => {
// FIX HERE
};
const styleLine = useAnimatedStyle(() => ({ const styleLine = useAnimatedStyle(() => ({
width: x.value, width: x.value,
@ -40,6 +93,7 @@ const Slider = ({ currentTime = 0, duration = 120, thumbColor = '' }) => {
const gestureHandler = useAnimatedGestureHandler({ const gestureHandler = useAnimatedGestureHandler({
onStart: (_, ctx: any) => { onStart: (_, ctx: any) => {
ctx.startX = x.value; ctx.startX = x.value;
isHandlePan.value = true;
}, },
onActive: (event, ctx: any) => { onActive: (event, ctx: any) => {
const moveInX: number = ctx.startX + event.translationX; const moveInX: number = ctx.startX + event.translationX;
@ -55,18 +109,41 @@ const Slider = ({ currentTime = 0, duration = 120, thumbColor = '' }) => {
}, },
onEnd: () => { onEnd: () => {
scale.value = 1; scale.value = 1;
isHandlePan.value = false;
onEndGestureHandler.value = true;
// SEND A CALLBACK TO CHANGE THE PROGRESS OF THE AUDIO // SEND A CALLBACK TO CHANGE THE PROGRESS OF THE AUDIO
} }
}); });
const wrapper = async (time: number) => {
await sound?.setPositionAsync(Math.round(time * 1000));
onEndGestureHandler.value = false;
};
useDerivedValue(() => { useDerivedValue(() => {
const cTime = (x.value * duration) / maxWidth.value; if (onEndGestureHandler.value) {
const minutes = Math.floor(cTime / 60); runOnJS(wrapper)(currentTime.value);
const remainingSeconds = Math.floor(cTime % 60); }
});
useDerivedValue(() => {
let minutes;
let remainingSeconds;
if (isHandlePan.value) {
const cTime = (x.value * duration.value) / maxWidth.value || 0;
currentTime.value = cTime;
minutes = Math.floor(cTime / 60);
remainingSeconds = Math.floor(cTime % 60);
} else {
const xTime = (currentTime.value * maxWidth.value) / duration.value || 0;
x.value = xTime;
minutes = Math.floor(currentTime.value / 60);
remainingSeconds = Math.floor(currentTime.value % 60);
}
const formattedMinutes = String(minutes).padStart(2, '0'); const formattedMinutes = String(minutes).padStart(2, '0');
const formattedSeconds = String(remainingSeconds).padStart(2, '0'); const formattedSeconds = String(remainingSeconds).padStart(2, '0');
current.value = `${formattedMinutes}:${formattedSeconds}`; current.value = `${formattedMinutes}:${formattedSeconds}`;
}, [x, maxWidth, duration]); }, [x, maxWidth, duration, isHandlePan, currentTime]);
const getCurrentTime = useAnimatedProps( const getCurrentTime = useAnimatedProps(
() => () =>
@ -87,7 +164,7 @@ const Slider = ({ currentTime = 0, duration = 120, thumbColor = '' }) => {
<View style={styles.slider} onLayout={onLayout}> <View style={styles.slider} onLayout={onLayout}>
<View style={[styles.line, { backgroundColor: colors.auxiliaryText }]} /> <View style={[styles.line, { backgroundColor: colors.auxiliaryText }]} />
<Animated.View style={[styles.line, styleLine, { backgroundColor: colors.tintColor }]} /> <Animated.View style={[styles.line, styleLine, { backgroundColor: colors.tintColor }]} />
<PanGestureHandler onGestureEvent={gestureHandler}> <PanGestureHandler enabled={loaded} onGestureEvent={gestureHandler}>
<Animated.View style={[styles.thumbSlider, { backgroundColor: thumbColor }, styleThumb]} /> <Animated.View style={[styles.thumbSlider, { backgroundColor: thumbColor }, styleThumb]} />
</PanGestureHandler> </PanGestureHandler>
</View> </View>

View File

@ -77,7 +77,6 @@ Button.displayName = 'MessageAudioButton';
const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessageAudioProps) => { const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessageAudioProps) => {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [currentTime, setCurrentTime] = useState(0); const [currentTime, setCurrentTime] = useState(0);
const [duration, setDuration] = useState(0);
const [paused, setPaused] = useState(true); const [paused, setPaused] = useState(true);
const [cached, setCached] = useState(false); const [cached, setCached] = useState(false);
@ -93,8 +92,8 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
const onPlaybackStatusUpdate = (status: AVPlaybackStatus) => { const onPlaybackStatusUpdate = (status: AVPlaybackStatus) => {
if (status) { if (status) {
onLoad(status); // onLoad(status);
onProgress(status); // onProgress(status);
onEnd(status); onEnd(status);
} }
}; };
@ -107,23 +106,6 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
return url; return url;
}; };
const onLoad = (data: AVPlaybackStatus) => {
if (data.isLoaded && data.durationMillis) {
const duration = data.durationMillis / 1000;
setDuration(duration > 0 ? duration : 0);
}
};
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);
}
}
};
const onEnd = async (data: AVPlaybackStatus) => { const onEnd = async (data: AVPlaybackStatus) => {
if (data.isLoaded) { if (data.isLoaded) {
if (data.didJustFinish) { if (data.didJustFinish) {
@ -275,11 +257,11 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
]} ]}
> >
<Button disabled={isReply} loading={loading} paused={paused} cached={cached} onPress={onPress} /> <Button disabled={isReply} loading={loading} paused={paused} cached={cached} onPress={onPress} />
<Slider currentTime={currentTime} duration={duration} thumbColor={thumbColor} /> <Slider sound={sound.current} currentTime={currentTime} thumbColor={thumbColor} />
<View style={{ width: 36, height: 24, backgroundColor: '#999', borderRadius: 4, marginRight: 16 }} /> <View style={{ width: 36, height: 24, backgroundColor: '#999', borderRadius: 4, marginRight: 16 }} />
</View> </View>
</> </>
); );
}; };;
export default MessageAudio; export default MessageAudio;