removed the sound manipulation from Slider to manipulate only in the index
This commit is contained in:
parent
9c00ce08f4
commit
9066432ca2
|
@ -5,7 +5,7 @@ import styles from './styles';
|
||||||
import { useTheme } from '../../../../theme';
|
import { useTheme } from '../../../../theme';
|
||||||
import Touchable from '../../Touchable';
|
import Touchable from '../../Touchable';
|
||||||
|
|
||||||
const AudioRate = ({ onChange }: { onChange: (value: number) => void }) => {
|
const AudioRate = ({ onChange, loaded = false }: { onChange: (value: number) => void; loaded: boolean }) => {
|
||||||
const [rate, setRate] = useState(1.0);
|
const [rate, setRate] = useState(1.0);
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
|
|
||||||
|
@ -16,7 +16,11 @@ const AudioRate = ({ onChange }: { onChange: (value: number) => void }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Touchable onPress={onPress} style={[styles.containerAudioRate, { backgroundColor: colors.audioRateBackground }]}>
|
<Touchable
|
||||||
|
disabled={!loaded}
|
||||||
|
onPress={onPress}
|
||||||
|
style={[styles.containerAudioRate, { backgroundColor: colors.audioRateBackground }]}
|
||||||
|
>
|
||||||
<Text style={[styles.audioRateText, { color: colors.audioRateText }]}>{rate}x</Text>
|
<Text style={[styles.audioRateText, { color: colors.audioRateText }]}>{rate}x</Text>
|
||||||
</Touchable>
|
</Touchable>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React 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, {
|
||||||
|
SharedValue,
|
||||||
runOnJS,
|
runOnJS,
|
||||||
useAnimatedGestureHandler,
|
useAnimatedGestureHandler,
|
||||||
useAnimatedProps,
|
useAnimatedProps,
|
||||||
|
@ -9,8 +10,6 @@ import Animated, {
|
||||||
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';
|
||||||
|
@ -18,18 +17,15 @@ import { useTheme } from '../../../../theme';
|
||||||
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
|
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
|
||||||
|
|
||||||
interface ISlider {
|
interface ISlider {
|
||||||
thumbColor: string;
|
duration: SharedValue<number>;
|
||||||
sound: Sound | null;
|
currentTime: SharedValue<number>;
|
||||||
onEndCallback: () => void;
|
loaded: boolean;
|
||||||
|
onChangeTime: (time: number) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Slider = ({ thumbColor = '', sound, onEndCallback }: ISlider) => {
|
const Slider = ({ currentTime, duration, loaded = false, onChangeTime }: 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(0);
|
const x = useSharedValue(0);
|
||||||
const current = useSharedValue('00:00');
|
const current = useSharedValue('00:00');
|
||||||
|
@ -37,46 +33,6 @@ const Slider = ({ thumbColor = '', sound, onEndCallback }: ISlider) => {
|
||||||
const isHandlePan = useSharedValue(false);
|
const isHandlePan = useSharedValue(false);
|
||||||
const onEndGestureHandler = useSharedValue(false);
|
const onEndGestureHandler = useSharedValue(false);
|
||||||
|
|
||||||
const onPlaybackStatusUpdate = (status: AVPlaybackStatus) => {
|
|
||||||
if (status) {
|
|
||||||
onLoad(status);
|
|
||||||
onProgress(status);
|
|
||||||
onEnd(status);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (sound) {
|
|
||||||
sound.setOnPlaybackStatusUpdate(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) {
|
|
||||||
currentTime.value = currentSecond;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onEnd = (data: AVPlaybackStatus) => {
|
|
||||||
if (data.isLoaded) {
|
|
||||||
if (data.didJustFinish) {
|
|
||||||
onEndCallback();
|
|
||||||
currentTime.value = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const styleLine = useAnimatedStyle(() => ({
|
const styleLine = useAnimatedStyle(() => ({
|
||||||
width: x.value,
|
width: x.value,
|
||||||
zIndex: 2
|
zIndex: 2
|
||||||
|
@ -116,7 +72,7 @@ const Slider = ({ thumbColor = '', sound, onEndCallback }: ISlider) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const wrapper = async (time: number) => {
|
const wrapper = async (time: number) => {
|
||||||
await sound?.setPositionAsync(Math.round(time * 1000));
|
await onChangeTime(Math.round(time * 1000));
|
||||||
onEndGestureHandler.value = false;
|
onEndGestureHandler.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -153,6 +109,8 @@ const Slider = ({ thumbColor = '', sound, onEndCallback }: ISlider) => {
|
||||||
[current]
|
[current]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const thumbColor = loaded ? colors.audioPlayerPrimary : colors.tintDisabled;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.sliderContainer}>
|
<View style={styles.sliderContainer}>
|
||||||
<AnimatedTextInput
|
<AnimatedTextInput
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||||
import { StyleProp, TextStyle, View } from 'react-native';
|
import { StyleProp, TextStyle, View } from 'react-native';
|
||||||
import { Audio, InterruptionModeAndroid, InterruptionModeIOS } from 'expo-av';
|
import { AVPlaybackStatus, Audio, InterruptionModeAndroid, InterruptionModeIOS } from 'expo-av';
|
||||||
import { activateKeepAwakeAsync, deactivateKeepAwake } from 'expo-keep-awake';
|
import { activateKeepAwakeAsync, deactivateKeepAwake } from 'expo-keep-awake';
|
||||||
import { Sound } from 'expo-av/build/Audio/Sound';
|
import { Sound } from 'expo-av/build/Audio/Sound';
|
||||||
|
import { useSharedValue } from 'react-native-reanimated';
|
||||||
|
|
||||||
import Touchable from '../../Touchable';
|
import Touchable from '../../Touchable';
|
||||||
import Markdown from '../../../markdown';
|
import Markdown from '../../../markdown';
|
||||||
|
@ -79,12 +80,65 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
|
||||||
const [paused, setPaused] = useState(true);
|
const [paused, setPaused] = useState(true);
|
||||||
const [cached, setCached] = useState(false);
|
const [cached, setCached] = useState(false);
|
||||||
|
|
||||||
|
const duration = useSharedValue(0);
|
||||||
|
const currentTime = useSharedValue(0);
|
||||||
|
|
||||||
const { baseUrl, user } = useContext(MessageContext);
|
const { baseUrl, user } = useContext(MessageContext);
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
|
|
||||||
const sound = useRef<Sound | null>(null);
|
const sound = useRef<Sound | null>(null);
|
||||||
|
|
||||||
|
const onPlaybackStatusUpdate = (status: AVPlaybackStatus) => {
|
||||||
|
if (status) {
|
||||||
|
onLoad(status);
|
||||||
|
onProgress(status);
|
||||||
|
onEnd(status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadAudio = async (audio: string) => {
|
||||||
|
const { sound: soundLoaded } = await Audio.Sound.createAsync({ uri: audio });
|
||||||
|
sound.current = soundLoaded;
|
||||||
|
sound.current.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onLoad = (data: AVPlaybackStatus) => {
|
||||||
|
if (data.isLoaded && data.durationMillis) {
|
||||||
|
const durationSeconds = data.durationMillis / 1000;
|
||||||
|
duration.value = durationSeconds > 0 ? durationSeconds : 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onProgress = (data: AVPlaybackStatus) => {
|
||||||
|
if (data.isLoaded) {
|
||||||
|
const currentSecond = data.positionMillis / 1000;
|
||||||
|
if (currentSecond <= duration.value) {
|
||||||
|
currentTime.value = currentSecond;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onEnd = async (data: AVPlaybackStatus) => {
|
||||||
|
if (data.isLoaded) {
|
||||||
|
if (data.didJustFinish) {
|
||||||
|
try {
|
||||||
|
await sound.current?.stopAsync();
|
||||||
|
setPaused(true);
|
||||||
|
EventEmitter.removeListener(PAUSE_AUDIO, pauseSound);
|
||||||
|
currentTime.value = 0;
|
||||||
|
} catch {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setPosition = async (time: number) => {
|
||||||
|
await sound.current?.setPositionAsync(time);
|
||||||
|
};
|
||||||
|
|
||||||
const pauseSound = () => {
|
const pauseSound = () => {
|
||||||
|
console.log('🚀🚀🚀🚀🚀🚀🚀 ~ file: index.tsx:141 ~ pauseSound ~ pauseSound:');
|
||||||
EventEmitter.removeListener(PAUSE_AUDIO, pauseSound);
|
EventEmitter.removeListener(PAUSE_AUDIO, pauseSound);
|
||||||
setPaused(true);
|
setPaused(true);
|
||||||
playPause(true);
|
playPause(true);
|
||||||
|
@ -98,17 +152,8 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
|
||||||
return url;
|
return url;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onEnd = async () => {
|
|
||||||
try {
|
|
||||||
await sound.current?.stopAsync();
|
|
||||||
setPaused(true);
|
|
||||||
EventEmitter.removeListener(PAUSE_AUDIO, pauseSound);
|
|
||||||
} catch {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const togglePlayPause = () => {
|
const togglePlayPause = () => {
|
||||||
|
console.log('🚀 ~ file: index.tsx:156 ~ togglePlayPause ~ paused:', paused);
|
||||||
setPaused(!paused);
|
setPaused(!paused);
|
||||||
playPause(!paused);
|
playPause(!paused);
|
||||||
};
|
};
|
||||||
|
@ -143,7 +188,7 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
|
||||||
type: 'audio',
|
type: 'audio',
|
||||||
mimeType: file.audio_type
|
mimeType: file.audio_type
|
||||||
});
|
});
|
||||||
await sound.current?.loadAsync({ uri: audio });
|
await loadAudio(audio);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setCached(true);
|
setCached(true);
|
||||||
}
|
}
|
||||||
|
@ -190,8 +235,7 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
|
||||||
urlToCache: getUrl()
|
urlToCache: getUrl()
|
||||||
});
|
});
|
||||||
if (cachedAudioResult?.exists) {
|
if (cachedAudioResult?.exists) {
|
||||||
const { sound: soundLoaded } = await Audio.Sound.createAsync({ uri: cachedAudioResult.uri });
|
await loadAudio(cachedAudioResult.uri);
|
||||||
sound.current = soundLoaded;
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setCached(true);
|
setCached(true);
|
||||||
return;
|
return;
|
||||||
|
@ -228,14 +272,6 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
|
||||||
if (!baseUrl) {
|
if (!baseUrl) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let thumbColor;
|
|
||||||
if (isReply) {
|
|
||||||
thumbColor = colors.tintDisabled;
|
|
||||||
} else {
|
|
||||||
thumbColor = colors.audioPlayerPrimary;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Markdown msg={file.description} style={[isReply && style]} username={user.username} getCustomEmoji={getCustomEmoji} />
|
<Markdown msg={file.description} style={[isReply && style]} username={user.username} getCustomEmoji={getCustomEmoji} />
|
||||||
|
@ -246,8 +282,8 @@ 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 sound={sound.current} thumbColor={thumbColor} onEndCallback={onEnd} />
|
<Slider currentTime={currentTime} duration={duration} loaded={!isReply && cached} onChangeTime={setPosition} />
|
||||||
<AudioRate onChange={setRate} />
|
<AudioRate onChange={setRate} loaded={!isReply && cached} />
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue