From e85cca23813d3eed1a0547f2edb485214e3f48f5 Mon Sep 17 00:00:00 2001 From: Otavio Stasiak Date: Wed, 2 Oct 2024 17:59:01 -0300 Subject: [PATCH 1/2] feat: crated thumbnail using expo-video-thumbnail --- .../Components/Attachments/Thumbnail.tsx | 86 +++++++++++++++++++ .../message/Components/Attachments/Video.tsx | 36 +------- 2 files changed, 89 insertions(+), 33 deletions(-) create mode 100644 app/containers/message/Components/Attachments/Thumbnail.tsx diff --git a/app/containers/message/Components/Attachments/Thumbnail.tsx b/app/containers/message/Components/Attachments/Thumbnail.tsx new file mode 100644 index 0000000000..e7054b9d93 --- /dev/null +++ b/app/containers/message/Components/Attachments/Thumbnail.tsx @@ -0,0 +1,86 @@ +import React, { useEffect, useState } from 'react'; +import { StyleSheet, View } from 'react-native'; + +import { getThumbnailAsync } from 'expo-video-thumbnails'; +import FastImage from 'react-native-fast-image'; + +import { CustomIcon } from '../../../CustomIcon'; +import OverlayComponent from '../OverlayComponent'; + +const styles = StyleSheet.create({ + container: { + flex: 1, + alignItems: 'center', + justifyContent: 'center' + }, + overlay: { + flex: 1 + }, + image: { + width: '100%', + height: '100%' + }, + playerIcon: { + position: 'absolute', + shadowColor: '#000', + shadowOpacity: 0.3, + shadowOffset: { + width: 1, + height: 1 + } + } +}); + +type Image = { + loading: boolean; + uri: string | null; +}; + +type ThumbnailProps = { + url: string; + encrypted?: boolean; +}; + +const Thumbnail = ({ url, encrypted = false }: ThumbnailProps) => { + const icon = encrypted ? 'encrypted' : 'play-filled'; + + const [image, setImage] = useState({ + loading: true, + uri: null + }); + + const generateThumbnail = async () => { + try { + if (!url) return; + + const { uri } = await getThumbnailAsync(url, { + time: 1 + }); + setImage({ + loading: false, + uri + }); + } catch (e) { + console.warn(e); + } + }; + + useEffect(() => { + generateThumbnail(); + }, [url]); + + return ( + + {image.loading || !image.uri ? ( + + ) : ( + <> + + + + )} + + ); +}; + +export default Thumbnail; diff --git a/app/containers/message/Components/Attachments/Video.tsx b/app/containers/message/Components/Attachments/Video.tsx index 23b72e6e46..42cdced03d 100644 --- a/app/containers/message/Components/Attachments/Video.tsx +++ b/app/containers/message/Components/Attachments/Video.tsx @@ -1,5 +1,5 @@ import React, { useContext } from 'react'; -import { StyleProp, StyleSheet, Text, TextStyle, View } from 'react-native'; +import { StyleProp, StyleSheet, TextStyle } from 'react-native'; import { IUserMessage } from '../../../../definitions'; import { IAttachment } from '../../../../definitions/IAttachment'; @@ -9,15 +9,13 @@ import { fileDownload, isIOS } from '../../../../lib/methods/helpers'; import EventEmitter from '../../../../lib/methods/helpers/events'; import { useTheme } from '../../../../theme'; import sharedStyles from '../../../../views/Styles'; -import { TIconsName } from '../../../CustomIcon'; import { LISTENER } from '../../../Toast'; import Markdown from '../../../markdown'; import MessageContext from '../../Context'; import Touchable from '../../Touchable'; import { useMediaAutoDownload } from '../../hooks/useMediaAutoDownload'; -import BlurComponent from '../OverlayComponent'; -import { TDownloadState } from '../../../../lib/methods/handleMediaDownload'; import messageStyles from '../../styles'; +import Thumbnail from './Thumbnail'; const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(isIOS ? [] : ['video/3gp', 'video/mkv'])]; const isTypeSupported = (type: string) => SUPPORTED_TYPES.indexOf(type) !== -1; @@ -44,34 +42,6 @@ interface IMessageVideo { msg?: string; } -const CancelIndicator = () => { - const { colors } = useTheme(); - return ( - - {I18n.t('Cancel')} - - ); -}; - -const Thumbnail = ({ status, encrypted = false }: { status: TDownloadState; encrypted: boolean }) => { - const { colors } = useTheme(); - let icon: TIconsName = status === 'downloaded' ? 'play-filled' : 'arrow-down-circle'; - if (encrypted && status === 'downloaded') { - icon = 'encrypted'; - } - - return ( - <> - - {status === 'loading' ? : null} - - ); -}; - const Video = ({ file, showAttachment, @@ -112,7 +82,7 @@ const Video = ({ <> - + ); From 4a2db10c8316e488aae8e03ae5f7ffe77a7ff758 Mon Sep 17 00:00:00 2001 From: Otavio Stasiak Date: Thu, 3 Oct 2024 13:28:31 -0300 Subject: [PATCH 2/2] fix: moved Thumbnail component to Video.tsx --- .../Components/Attachments/Thumbnail.tsx | 86 ------------------ .../message/Components/Attachments/Video.tsx | 87 ++++++++++++++++--- 2 files changed, 77 insertions(+), 96 deletions(-) delete mode 100644 app/containers/message/Components/Attachments/Thumbnail.tsx diff --git a/app/containers/message/Components/Attachments/Thumbnail.tsx b/app/containers/message/Components/Attachments/Thumbnail.tsx deleted file mode 100644 index e7054b9d93..0000000000 --- a/app/containers/message/Components/Attachments/Thumbnail.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { StyleSheet, View } from 'react-native'; - -import { getThumbnailAsync } from 'expo-video-thumbnails'; -import FastImage from 'react-native-fast-image'; - -import { CustomIcon } from '../../../CustomIcon'; -import OverlayComponent from '../OverlayComponent'; - -const styles = StyleSheet.create({ - container: { - flex: 1, - alignItems: 'center', - justifyContent: 'center' - }, - overlay: { - flex: 1 - }, - image: { - width: '100%', - height: '100%' - }, - playerIcon: { - position: 'absolute', - shadowColor: '#000', - shadowOpacity: 0.3, - shadowOffset: { - width: 1, - height: 1 - } - } -}); - -type Image = { - loading: boolean; - uri: string | null; -}; - -type ThumbnailProps = { - url: string; - encrypted?: boolean; -}; - -const Thumbnail = ({ url, encrypted = false }: ThumbnailProps) => { - const icon = encrypted ? 'encrypted' : 'play-filled'; - - const [image, setImage] = useState({ - loading: true, - uri: null - }); - - const generateThumbnail = async () => { - try { - if (!url) return; - - const { uri } = await getThumbnailAsync(url, { - time: 1 - }); - setImage({ - loading: false, - uri - }); - } catch (e) { - console.warn(e); - } - }; - - useEffect(() => { - generateThumbnail(); - }, [url]); - - return ( - - {image.loading || !image.uri ? ( - - ) : ( - <> - - - - )} - - ); -}; - -export default Thumbnail; diff --git a/app/containers/message/Components/Attachments/Video.tsx b/app/containers/message/Components/Attachments/Video.tsx index 42cdced03d..c867fe638e 100644 --- a/app/containers/message/Components/Attachments/Video.tsx +++ b/app/containers/message/Components/Attachments/Video.tsx @@ -1,5 +1,5 @@ -import React, { useContext } from 'react'; -import { StyleProp, StyleSheet, TextStyle } from 'react-native'; +import React, { useContext, useEffect, useState } from 'react'; +import { StyleProp, StyleSheet, TextStyle, View } from 'react-native'; import { IUserMessage } from '../../../../definitions'; import { IAttachment } from '../../../../definitions/IAttachment'; @@ -15,23 +15,90 @@ import MessageContext from '../../Context'; import Touchable from '../../Touchable'; import { useMediaAutoDownload } from '../../hooks/useMediaAutoDownload'; import messageStyles from '../../styles'; -import Thumbnail from './Thumbnail'; +import { getThumbnailAsync } from 'expo-video-thumbnails'; +import OverlayComponent from '../OverlayComponent'; +import FastImage from 'react-native-fast-image'; +import { CustomIcon } from '../../../CustomIcon'; 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({ - cancelContainer: { - position: 'absolute', - top: 8, - right: 8 + container: { + flex: 1, + alignItems: 'center', + justifyContent: 'center' + }, + overlay: { + flex: 1 + }, + image: { + width: '100%', + height: '100%' }, - text: { - ...sharedStyles.textRegular, - fontSize: 12 + playerIcon: { + position: 'absolute', + shadowColor: '#000', + shadowOpacity: 0.3, + shadowOffset: { + width: 1, + height: 1 + } } }); +type Image = { + loading: boolean; + uri: string | null; +}; + +type ThumbnailProps = { + url: string; + encrypted?: boolean; +}; + +const Thumbnail = ({ url, encrypted = false }: ThumbnailProps) => { + const icon = encrypted ? 'encrypted' : 'play-filled'; + + const [image, setImage] = useState({ + loading: true, + uri: null + }); + + const generateThumbnail = async () => { + try { + if (!url) return; + + const { uri } = await getThumbnailAsync(url, { + time: 1 + }); + setImage({ + loading: false, + uri + }); + } catch (e) { + console.warn(e); + } + }; + + useEffect(() => { + generateThumbnail(); + }, [url]); + + return ( + + {image.loading || !image.uri ? ( + + ) : ( + <> + + + + )} + + ); +}; + interface IMessageVideo { file: IAttachment; showAttachment?: (file: IAttachment) => void;