import React, { useContext, useLayoutEffect, useRef, useState } from 'react'; import { StyleProp, StyleSheet, TextStyle, View, Text } from 'react-native'; import { dequal } from 'dequal'; import * as FileSystem from 'expo-file-system'; import Touchable from './Touchable'; import Markdown from '../markdown'; import { isIOS } from '../../lib/methods/helpers'; import { CustomIcon } from '../CustomIcon'; import { themes } from '../../lib/constants'; import MessageContext from './Context'; import { fileDownload } from './helpers/fileDownload'; import EventEmitter from '../../lib/methods/helpers/events'; import { LISTENER } from '../Toast'; import I18n from '../../i18n'; import { IAttachment } from '../../definitions/IAttachment'; import RCActivityIndicator from '../ActivityIndicator'; import { TGetCustomEmoji } from '../../definitions/IEmoji'; import { useTheme } from '../../theme'; import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl'; import { MediaTypes, downloadMediaFile, searchMediaFileAsync } from '../../lib/methods/handleMediaDownload'; import { isAutoDownloadEnabled } from './helpers/mediaDownload/autoDownloadPreference'; import sharedStyles from '../../views/Styles'; const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(isIOS ? [] : ['video/3gp', 'video/mkv'])]; const isTypeSupported = (type: string) => SUPPORTED_TYPES.indexOf(type) !== -1; const styles = StyleSheet.create({ button: { flex: 1, borderRadius: 4, height: 150, marginBottom: 6, alignItems: 'center', justifyContent: 'center' }, cancelContainer: { position: 'absolute', top: 8, right: 8 }, text: { ...sharedStyles.textRegular, fontSize: 12 } }); interface IMessageVideo { file: IAttachment; showAttachment?: (file: IAttachment) => void; getCustomEmoji: TGetCustomEmoji; style?: StyleProp[]; isReply?: boolean; messageId: string; } const DownloadIndicator = ({ handleCancelDownload }: { handleCancelDownload(): void }) => { const { colors } = useTheme(); return ( <> {I18n.t('Cancel')} ); }; const Video = React.memo( ({ file, showAttachment, getCustomEmoji, style, isReply, messageId }: IMessageVideo) => { const [loading, setLoading] = useState(false); const { baseUrl, user } = useContext(MessageContext); const { theme } = useTheme(); const filePath = useRef(''); const downloadResumable = useRef(null); const video = formatAttachmentUrl(file.video_url, user.id, user.token, baseUrl); useLayoutEffect(() => { const handleAutoDownload = async () => { if (video) { const searchImageBestQuality = await searchMediaFileAsync({ type: MediaTypes.video, mimeType: file.video_type, messageId }); filePath.current = searchImageBestQuality.filePath; if (searchImageBestQuality.file?.exists) { file.video_url = searchImageBestQuality.file.uri; return; } // We don't pass the author to avoid auto-download what the user sent const autoDownload = await isAutoDownloadEnabled('imagesPreferenceDownload', { user }); if (autoDownload) { await handleDownload(); } } }; handleAutoDownload(); }, []); if (!baseUrl) { return null; } const handleDownload = async () => { setLoading(true); downloadResumable.current = FileSystem.createDownloadResumable(video, filePath.current); const videoUri = await downloadMediaFile({ url: video, filePath: filePath.current, downloadResumable: downloadResumable.current }); if (videoUri) { file.video_url = videoUri; } setLoading(false); }; const onPress = async () => { if (file.video_type && isTypeSupported(file.video_type) && showAttachment) { // Keep the video downloading while showing the video buffering handleDownload(); return showAttachment(file); } if (!isIOS && file.video_url) { await downloadVideo(video); return; } EventEmitter.emit(LISTENER, { message: I18n.t('Unsupported_format') }); }; const handleCancelDownload = () => { if (loading && downloadResumable.current) { return downloadResumable.current.cancelAsync(); } }; const downloadVideo = async (uri: string) => { setLoading(true); const fileDownloaded = await fileDownload(uri, file); setLoading(false); if (fileDownloaded) { EventEmitter.emit(LISTENER, { message: I18n.t('saved_to_gallery') }); return; } EventEmitter.emit(LISTENER, { message: I18n.t('error-save-video') }); }; return ( <> {loading ? ( ) : ( )} ); }, (prevProps, nextProps) => dequal(prevProps.file, nextProps.file) ); export default Video;