refactor audio component

This commit is contained in:
Reinaldo Neto 2023-10-03 19:05:24 -03:00
parent 8b053f630e
commit 2b379ee281
3 changed files with 109 additions and 99 deletions

View File

@ -11,18 +11,18 @@ interface IButton {
paused: boolean;
disabled?: boolean;
onPress: () => void;
cached: boolean;
isReadyToPlay: boolean;
}
const BUTTON_HIT_SLOP = { top: 12, right: 12, bottom: 12, left: 12 };
type TCustomIconName = 'arrow-down' | 'play-shape-filled' | 'pause-shape-filled';
const PlayButton = React.memo(({ loading, paused, onPress, disabled, cached }: IButton) => {
const PlayButton = React.memo(({ loading, paused, onPress, disabled, isReadyToPlay }: IButton) => {
const { colors } = useTheme();
let customIconName: TCustomIconName = 'arrow-down';
if (cached) {
if (isReadyToPlay) {
customIconName = paused ? 'play-shape-filled' : 'pause-shape-filled';
}
return (

View File

@ -1,13 +1,10 @@
import React, { useEffect, useRef, useState } from 'react';
import { StyleProp, TextStyle, View } from 'react-native';
import { View } from 'react-native';
import { AVPlaybackStatus } from 'expo-av';
import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
import { useSharedValue } from 'react-native-reanimated';
import { IAttachment, IUserMessage } from '../../definitions';
import { useTheme } from '../../theme';
import { downloadMediaFile, getMediaCache } from '../../lib/methods/handleMediaDownload';
import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference';
import styles from './styles';
import Seek from './Seek';
import PlaybackSpeed from './PlaybackSpeed';
@ -15,19 +12,21 @@ import PlayButton from './PlayButton';
import audioPlayer from '../../lib/methods/audioPlayer';
interface IAudioPlayerProps {
file: IAttachment;
isReply?: boolean;
style?: StyleProp<TextStyle>[];
author?: IUserMessage;
msg?: string;
baseUrl: string;
user: any;
fileUri: string;
loading: boolean;
isReadyToPlay: boolean;
disabled?: boolean;
onPressCallback?: Function;
}
const AudioPlayer = ({ file, author, isReply = false, baseUrl, user }: IAudioPlayerProps) => {
const [loading, setLoading] = useState(true);
const AudioPlayer = ({
fileUri,
disabled = false,
loading = true,
isReadyToPlay = false,
onPressCallback = () => {}
}: IAudioPlayerProps) => {
const [paused, setPaused] = useState(true);
const [cached, setCached] = useState(false);
const [rate, setRate] = useState(1);
const duration = useSharedValue(0);
@ -45,12 +44,6 @@ const AudioPlayer = ({ file, author, isReply = false, baseUrl, user }: IAudioPla
}
};
const loadAudio = async (audio: string) => {
await audioPlayer.loadAudio(audio);
audioUri.current = audio;
audioPlayer.setOnPlaybackStatusUpdate(audio, onPlaybackStatusUpdate);
};
const onPlaying = (data: AVPlaybackStatus) => {
if (data.isLoaded && data.isPlaying) {
setPaused(false);
@ -88,14 +81,6 @@ const AudioPlayer = ({ file, author, isReply = false, baseUrl, user }: IAudioPla
await audioPlayer.setPositionAsync(audioUri.current, time);
};
const getUrl = () => {
let url = file.audio_url;
if (url && !url.startsWith('http')) {
url = `${baseUrl}${file.audio_url}`;
}
return url;
};
const togglePlayPause = async () => {
try {
if (!paused) {
@ -112,76 +97,24 @@ const AudioPlayer = ({ file, author, isReply = false, baseUrl, user }: IAudioPla
await audioPlayer.setRateAsync(audioUri.current, value);
};
const handleDownload = async () => {
setLoading(true);
try {
const url = getUrl();
if (url) {
const audio = await downloadMediaFile({
downloadUrl: `${url}?rc_uid=${user.id}&rc_token=${user.token}`,
type: 'audio',
mimeType: file.audio_type
});
await loadAudio(audio);
setLoading(false);
setCached(true);
}
} catch {
setLoading(false);
setCached(false);
}
};
const handleAutoDownload = async () => {
const url = getUrl();
try {
if (url) {
const isCurrentUserAuthor = author?._id === user.id;
const isAutoDownloadEnabled = fetchAutoDownloadEnabled('audioPreferenceDownload');
if (isAutoDownloadEnabled || isCurrentUserAuthor) {
await handleDownload();
return;
}
setLoading(false);
setCached(false);
}
} catch {
// Do nothing
}
};
const onPress = () => {
onPressCallback();
if (loading) {
return;
}
if (cached) {
if (isReadyToPlay) {
togglePlayPause();
return;
}
handleDownload();
};
useEffect(() => {
const handleCache = async () => {
const cachedAudioResult = await getMediaCache({
type: 'audio',
mimeType: file.audio_type,
urlToCache: getUrl()
});
if (cachedAudioResult?.exists) {
await loadAudio(cachedAudioResult.uri);
setLoading(false);
setCached(true);
return;
}
if (isReply) {
setLoading(false);
return;
}
await handleAutoDownload();
const loadAudio = async (audio: string) => {
await audioPlayer.loadAudio(audio);
audioUri.current = audio;
audioPlayer.setOnPlaybackStatusUpdate(audio, onPlaybackStatusUpdate);
};
handleCache();
}, []);
loadAudio(fileUri);
}, [fileUri]);
useEffect(() => {
if (paused) {
@ -191,15 +124,12 @@ const AudioPlayer = ({ file, author, isReply = false, baseUrl, user }: IAudioPla
}
}, [paused]);
if (!baseUrl) {
return null;
}
return (
<>
<View style={[styles.audioContainer, { backgroundColor: colors.surfaceTint, borderColor: colors.strokeExtraLight }]}>
<PlayButton disabled={isReply} loading={loading} paused={paused} cached={cached} onPress={onPress} />
<Seek currentTime={currentTime} duration={duration} loaded={!isReply && cached} onChangeTime={setPosition} />
<PlaybackSpeed onChange={onChangeRate} loaded={!isReply && cached} rate={rate} />
<PlayButton disabled={disabled} loading={loading} paused={paused} isReadyToPlay={isReadyToPlay} onPress={onPress} />
<Seek currentTime={currentTime} duration={duration} loaded={!disabled && isReadyToPlay} onChangeTime={setPosition} />
<PlaybackSpeed onChange={onChangeRate} loaded={!disabled && isReadyToPlay} rate={rate} />
</View>
</>
);

View File

@ -1,10 +1,12 @@
import React, { useContext } from 'react';
import React, { useContext, useEffect, useState } from 'react';
import { StyleProp, TextStyle } from 'react-native';
import Markdown from '../../../markdown';
import MessageContext from '../../Context';
import { TGetCustomEmoji } from '../../../../definitions/IEmoji';
import { IAttachment, IUserMessage } from '../../../../definitions';
import { downloadMediaFile, getMediaCache } from '../../../../lib/methods/handleMediaDownload';
import { fetchAutoDownloadEnabled } from '../../../../lib/methods/autoDownloadPreference';
import AudioPlayer from '../../../AudioPlayer';
interface IMessageAudioProps {
@ -17,15 +19,93 @@ interface IMessageAudioProps {
}
const MessageAudio = ({ file, getCustomEmoji, author, isReply, style, msg }: IMessageAudioProps) => {
const [loading, setLoading] = useState(true);
const [cached, setCached] = useState(false);
const [fileUri, setFileUri] = useState('');
const { baseUrl, user } = useContext(MessageContext);
const getUrl = () => {
let url = file.audio_url;
if (url && !url.startsWith('http')) {
url = `${baseUrl}${file.audio_url}`;
}
return url;
};
const onPress = () => {
if (!cached) {
handleDownload();
}
};
const handleDownload = async () => {
setLoading(true);
try {
const url = getUrl();
if (url) {
const audio = await downloadMediaFile({
downloadUrl: `${url}?rc_uid=${user.id}&rc_token=${user.token}`,
type: 'audio',
mimeType: file.audio_type
});
setFileUri(audio);
setLoading(false);
setCached(true);
}
} catch {
setLoading(false);
setCached(false);
}
};
const handleAutoDownload = async () => {
const url = getUrl();
try {
if (url) {
const isCurrentUserAuthor = author?._id === user.id;
const isAutoDownloadEnabled = fetchAutoDownloadEnabled('audioPreferenceDownload');
if (isAutoDownloadEnabled || isCurrentUserAuthor) {
await handleDownload();
return;
}
setLoading(false);
setCached(false);
}
} catch {
// Do nothing
}
};
useEffect(() => {
const handleCache = async () => {
const cachedAudioResult = await getMediaCache({
type: 'audio',
mimeType: file.audio_type,
urlToCache: getUrl()
});
if (cachedAudioResult?.exists) {
setFileUri(cachedAudioResult.uri);
setLoading(false);
setCached(true);
return;
}
if (isReply) {
setLoading(false);
return;
}
await handleAutoDownload();
};
handleCache();
}, []);
if (!baseUrl) {
return null;
}
return (
<>
<Markdown msg={msg} style={[isReply && style]} username={user.username} getCustomEmoji={getCustomEmoji} />
<AudioPlayer file={file} baseUrl={baseUrl} user={user} author={author} isReply={isReply} />
<AudioPlayer fileUri={fileUri} isReadyToPlay={cached} loading={loading} disabled={isReply} onPressCallback={onPress} />
</>
);
};