remove mediaType and refactor audio and image

This commit is contained in:
Reinaldo Neto 2023-07-03 14:28:22 -03:00
parent 1be2326686
commit b6ae55e57f
5 changed files with 99 additions and 92 deletions

View File

@ -19,7 +19,7 @@ import { withDimensions } from '../../dimensions';
import { TGetCustomEmoji } from '../../definitions/IEmoji'; import { TGetCustomEmoji } from '../../definitions/IEmoji';
import { IAttachment, IUserMessage } from '../../definitions'; import { IAttachment, IUserMessage } from '../../definitions';
import { TSupportedThemes, useTheme } from '../../theme'; import { TSupportedThemes, useTheme } from '../../theme';
import { downloadMediaFile, searchMediaFileAsync } from '../../lib/methods/handleMediaDownload'; import { downloadMediaFile, getMediaCache } from '../../lib/methods/handleMediaDownload';
import EventEmitter from '../../lib/methods/helpers/events'; import EventEmitter from '../../lib/methods/helpers/events';
import { PAUSE_AUDIO } from './constants'; import { PAUSE_AUDIO } from './constants';
import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference'; import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference';
@ -130,7 +130,7 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
currentTime: 0, currentTime: 0,
duration: 0, duration: 0,
paused: true, paused: true,
cached: true cached: false
}; };
this.sound = new Audio.Sound(); this.sound = new Audio.Sound();
@ -144,7 +144,7 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
async componentDidMount() { async componentDidMount() {
const { file, isReply } = this.props; const { file, isReply } = this.props;
const cachedAudioResult = await searchMediaFileAsync({ const cachedAudioResult = await getMediaCache({
type: 'audio', type: 'audio',
mimeType: file.audio_type, mimeType: file.audio_type,
urlToCache: this.getUrl() urlToCache: this.getUrl()
@ -152,45 +152,16 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
this.filePath = cachedAudioResult.filePath; this.filePath = cachedAudioResult.filePath;
if (cachedAudioResult?.file?.exists) { if (cachedAudioResult?.file?.exists) {
await this.sound.loadAsync({ uri: cachedAudioResult.file.uri }); await this.sound.loadAsync({ uri: cachedAudioResult.file.uri });
return this.setState({ loading: false }); this.setState({ loading: false, cached: true });
return;
}
if (isReply) {
this.setState({ loading: false });
return;
} }
if (isReply) return;
await this.handleAutoDownload(); await this.handleAutoDownload();
} }
getUrl = () => {
const { file } = this.props;
// @ts-ignore can't use declare to type this
const { baseUrl } = this.context;
let url = file.audio_url;
if (url && !url.startsWith('http')) {
url = `${baseUrl}${file.audio_url}`;
}
return url as string;
};
handleAutoDownload = async () => {
const { author } = this.props;
// @ts-ignore can't use declare to type this
const { user } = this.context;
const url = this.getUrl();
try {
if (url) {
const isCurrentUserAuthor = author?._id === user.id;
const isAutoDownloadEnabled = fetchAutoDownloadEnabled('audioPreferenceDownload');
if (isAutoDownloadEnabled || isCurrentUserAuthor) {
await this.handleDownload();
return;
}
return this.setState({ loading: false, cached: false });
}
} catch {
// Do nothing
}
};
shouldComponentUpdate(nextProps: IMessageAudioProps, nextState: IMessageAudioState) { shouldComponentUpdate(nextProps: IMessageAudioProps, nextState: IMessageAudioState) {
const { currentTime, duration, paused, loading, cached } = this.state; const { currentTime, duration, paused, loading, cached } = this.state;
const { file, theme } = this.props; const { file, theme } = this.props;
@ -236,6 +207,39 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
} }
} }
getUrl = () => {
const { file } = this.props;
// @ts-ignore can't use declare to type this
const { baseUrl } = this.context;
let url = file.audio_url;
if (url && !url.startsWith('http')) {
url = `${baseUrl}${file.audio_url}`;
}
return url;
};
handleAutoDownload = async () => {
const { author } = this.props;
// @ts-ignore can't use declare to type this
const { user } = this.context;
const url = this.getUrl();
try {
if (url) {
const isCurrentUserAuthor = author?._id === user.id;
const isAutoDownloadEnabled = fetchAutoDownloadEnabled('audioPreferenceDownload');
if (isAutoDownloadEnabled || isCurrentUserAuthor) {
await this.handleDownload();
return;
}
this.setState({ loading: false, cached: false });
}
} catch {
// Do nothing
}
};
onPlaybackStatusUpdate = (status: AVPlaybackStatus) => { onPlaybackStatusUpdate = (status: AVPlaybackStatus) => {
if (status) { if (status) {
this.onLoad(status); this.onLoad(status);
@ -294,21 +298,24 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
if (url && this.filePath) { if (url && this.filePath) {
const audio = await downloadMediaFile({ const audio = await downloadMediaFile({
downloadUrl: `${url}?rc_uid=${user.id}&rc_token=${user.token}`, downloadUrl: `${url}?rc_uid=${user.id}&rc_token=${user.token}`,
mediaType: 'audio',
path: this.filePath path: this.filePath
}); });
await this.sound.loadAsync({ uri: audio }); await this.sound.loadAsync({ uri: audio });
return this.setState({ loading: false, cached: true }); this.setState({ loading: false, cached: true });
} }
} catch { } catch {
return this.setState({ loading: false, cached: false }); this.setState({ loading: false, cached: false });
} }
}; };
onPress = () => { onPress = () => {
const { cached } = this.state; const { cached } = this.state;
return cached ? this.togglePlayPause() : this.handleDownload(); if (cached) {
this.togglePlayPause();
return;
}
this.handleDownload();
}; };
playPause = async () => { playPause = async () => {

View File

@ -12,7 +12,7 @@ import { TGetCustomEmoji } from '../../definitions/IEmoji';
import { IAttachment, IUserMessage } from '../../definitions'; import { IAttachment, IUserMessage } from '../../definitions';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl'; import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl';
import { cancelDownload, downloadMediaFile, isDownloadActive, searchMediaFileAsync } from '../../lib/methods/handleMediaDownload'; import { cancelDownload, downloadMediaFile, isDownloadActive, getMediaCache } from '../../lib/methods/handleMediaDownload';
import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference'; import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference';
import RCActivityIndicator from '../ActivityIndicator'; import RCActivityIndicator from '../ActivityIndicator';
import { CustomIcon } from '../CustomIcon'; import { CustomIcon } from '../CustomIcon';
@ -82,7 +82,7 @@ const ImageContainer = React.memo(
({ file, imageUrl, showAttachment, getCustomEmoji, style, isReply, author }: IMessageImage) => { ({ file, imageUrl, showAttachment, getCustomEmoji, style, isReply, author }: IMessageImage) => {
const [imageCached, setImageCached] = useState(file); const [imageCached, setImageCached] = useState(file);
const [cached, setCached] = useState(false); const [cached, setCached] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(true);
const { theme } = useTheme(); const { theme } = useTheme();
const { baseUrl, user } = useContext(MessageContext); const { baseUrl, user } = useContext(MessageContext);
const filePath = useRef(''); const filePath = useRef('');
@ -93,9 +93,9 @@ const ImageContainer = React.memo(
const imgUrlToCache = getUrl(imageCached.title_link || imageCached.image_url); const imgUrlToCache = getUrl(imageCached.title_link || imageCached.image_url);
useLayoutEffect(() => { useLayoutEffect(() => {
const handleImageSearchAndDownload = async () => { const handleCache = async () => {
if (img) { if (img) {
const cachedImageResult = await searchMediaFileAsync({ const cachedImageResult = await getMediaCache({
type: 'image', type: 'image',
mimeType: imageCached.image_type, mimeType: imageCached.image_type,
urlToCache: imgUrlToCache urlToCache: imgUrlToCache
@ -106,16 +106,21 @@ const ImageContainer = React.memo(
...prev, ...prev,
title_link: cachedImageResult.file?.uri title_link: cachedImageResult.file?.uri
})); }));
return setCached(true); setLoading(false);
setCached(true);
return;
} }
if (isReply) return; if (isReply) {
if (isDownloadActive('image', imgUrlToCache)) { setLoading(false);
return setLoading(true); return;
}
if (isDownloadActive(imgUrlToCache)) {
return;
} }
await handleAutoDownload(); await handleAutoDownload();
} }
}; };
handleImageSearchAndDownload(); handleCache();
}, []); }, []);
if (!img) { if (!img) {
@ -131,11 +136,9 @@ const ImageContainer = React.memo(
}; };
const handleDownload = async () => { const handleDownload = async () => {
setLoading(true);
try { try {
const imageUri = await downloadMediaFile({ const imageUri = await downloadMediaFile({
downloadUrl: imgUrlToCache, downloadUrl: imgUrlToCache,
mediaType: 'image',
path: filePath.current path: filePath.current
}); });
setImageCached(prev => ({ setImageCached(prev => ({
@ -146,23 +149,25 @@ const ImageContainer = React.memo(
setLoading(false); setLoading(false);
} catch (e) { } catch (e) {
setLoading(false); setLoading(false);
return setCached(false); setCached(false);
} }
}; };
const onPress = () => { const onPress = () => {
if (loading && isDownloadActive('image', imgUrlToCache)) { if (loading && isDownloadActive(imgUrlToCache)) {
cancelDownload('image', imgUrlToCache); cancelDownload(imgUrlToCache);
setLoading(false); setLoading(false);
return setCached(false); setCached(false);
return;
} }
if (!cached && !loading) { if (!cached && !loading) {
return handleDownload(); handleDownload();
return;
} }
if (!showAttachment) { if (!showAttachment) {
return; return;
} }
return showAttachment(imageCached); showAttachment(imageCached);
}; };
if (imageCached.description) { if (imageCached.description) {

View File

@ -22,7 +22,7 @@ import {
cancelDownload, cancelDownload,
downloadMediaFile, downloadMediaFile,
isDownloadActive, isDownloadActive,
searchMediaFileAsync getMediaCache
} from '../../lib/methods/handleMediaDownload'; } from '../../lib/methods/handleMediaDownload';
import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference'; import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference';
import sharedStyles from '../../views/Styles'; import sharedStyles from '../../views/Styles';
@ -84,20 +84,20 @@ const Video = React.memo(
useEffect(() => { useEffect(() => {
const handleVideoSearchAndDownload = async () => { const handleVideoSearchAndDownload = async () => {
if (video) { if (video) {
const cachedVideoResult = await searchMediaFileAsync({ const cachedVideoResult = await getMediaCache({
type: 'video', type: 'video',
mimeType: file.video_type, mimeType: file.video_type,
urlToCache: video urlToCache: video
}); });
filePath.current = cachedVideoResult.filePath; filePath.current = cachedVideoResult.filePath;
const downloadActive = isDownloadActive('video', video); const downloadActive = isDownloadActive(video);
if (cachedVideoResult.file?.exists) { if (cachedVideoResult.file?.exists) {
setVideoCached(prev => ({ setVideoCached(prev => ({
...prev, ...prev,
video_url: cachedVideoResult.file?.uri video_url: cachedVideoResult.file?.uri
})); }));
if (downloadActive) { if (downloadActive) {
cancelDownload('video', video); cancelDownload(video);
} }
return; return;
} }
@ -125,7 +125,6 @@ const Video = React.memo(
try { try {
const videoUri = await downloadMediaFile({ const videoUri = await downloadMediaFile({
downloadUrl: video, downloadUrl: video,
mediaType: 'video',
path: filePath.current path: filePath.current
}); });
setVideoCached(prev => ({ setVideoCached(prev => ({
@ -154,7 +153,7 @@ const Video = React.memo(
const handleCancelDownload = () => { const handleCancelDownload = () => {
if (loading) { if (loading) {
cancelDownload('video', video); cancelDownload(video);
return setLoading(false); return setLoading(false);
} }
}; };

View File

@ -15,21 +15,22 @@ export const fetchAutoDownloadEnabled = (mediaType: TMediaType) => {
const { netInfoState } = store.getState().app; const { netInfoState } = store.getState().app;
const mediaDownloadPreference = userPreferences.getString(mediaType) as MediaDownloadOption; const mediaDownloadPreference = userPreferences.getString(mediaType) as MediaDownloadOption;
let defaultValueByMediaType = false; if (mediaDownloadPreference === 'wifi_mobile_data') {
return true;
}
if (mediaDownloadPreference === 'wifi' && netInfoState === NetInfoStateType.wifi) {
return true;
}
if (mediaDownloadPreference === null) { if (mediaDownloadPreference === null) {
if (mediaType === 'imagesPreferenceDownload') { if (mediaType === 'imagesPreferenceDownload') {
// The same as 'wifi_mobile_data' return true;
defaultValueByMediaType = true;
} }
if (mediaType === 'audioPreferenceDownload' || mediaType === 'videoPreferenceDownload') { if (mediaType === 'audioPreferenceDownload' || mediaType === 'videoPreferenceDownload') {
// The same as 'wifi' return netInfoState === NetInfoStateType.wifi;
defaultValueByMediaType = netInfoState === NetInfoStateType.wifi;
} }
} }
return ( return false;
(mediaDownloadPreference === 'wifi' && netInfoState === NetInfoStateType.wifi) ||
mediaDownloadPreference === 'wifi_mobile_data' ||
defaultValueByMediaType
);
}; };

View File

@ -22,14 +22,14 @@ const defaultType = {
const downloadQueue: { [index: string]: FileSystem.DownloadResumable } = {}; const downloadQueue: { [index: string]: FileSystem.DownloadResumable } = {};
export const mediaDownloadKey = (mediaType: MediaTypes, downloadUrl: string) => `${mediaType}-${sanitizeString(downloadUrl)}`; export const mediaDownloadKey = (messageUrl: string) => `${sanitizeString(messageUrl)}`;
export function isDownloadActive(mediaType: MediaTypes, messageId: string): boolean { export function isDownloadActive(messageUrl: string): boolean {
return !!downloadQueue[mediaDownloadKey(mediaType, messageId)]; return !!downloadQueue[mediaDownloadKey(messageUrl)];
} }
export async function cancelDownload(mediaType: MediaTypes, messageId: string): Promise<void> { export async function cancelDownload(messageUrl: string): Promise<void> {
const downloadKey = mediaDownloadKey(mediaType, messageId); const downloadKey = mediaDownloadKey(messageUrl);
if (!isEmpty(downloadQueue[downloadKey])) { if (!isEmpty(downloadQueue[downloadKey])) {
try { try {
await downloadQueue[downloadKey].cancelAsync(); await downloadQueue[downloadKey].cancelAsync();
@ -40,18 +40,10 @@ export async function cancelDownload(mediaType: MediaTypes, messageId: string):
} }
} }
export function downloadMediaFile({ export function downloadMediaFile({ downloadUrl, path }: { downloadUrl: string; path: string }): Promise<string> {
mediaType,
downloadUrl,
path
}: {
mediaType: MediaTypes;
downloadUrl: string;
path: string;
}): Promise<string> {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
const downloadKey = mediaDownloadKey(mediaType, downloadUrl); const downloadKey = mediaDownloadKey(downloadUrl);
downloadQueue[downloadKey] = FileSystem.createDownloadResumable(downloadUrl, path); downloadQueue[downloadKey] = FileSystem.createDownloadResumable(downloadUrl, path);
const result = await downloadQueue[downloadKey].downloadAsync(); const result = await downloadQueue[downloadKey].downloadAsync();
if (result?.uri) { if (result?.uri) {
@ -101,15 +93,18 @@ const ensureDirAsync = async (dir: string, intermediates = true): Promise<void>
return ensureDirAsync(dir, intermediates); return ensureDirAsync(dir, intermediates);
}; };
export const searchMediaFileAsync = async ({ export const getMediaCache = async ({
type, type,
mimeType, mimeType,
urlToCache urlToCache
}: { }: {
type: MediaTypes; type: MediaTypes;
mimeType?: string; mimeType?: string;
urlToCache: string; urlToCache?: string;
}) => { }) => {
if (!urlToCache) {
return { file: null, filePath: '' };
}
try { try {
const serverUrl = store.getState().server.server; const serverUrl = store.getState().server.server;
const serverUrlParsed = serverUrlParsedAsPath(serverUrl); const serverUrlParsed = serverUrlParsedAsPath(serverUrl);