message/Image refactored, change the component to show the image from FastImage to Image

This commit is contained in:
Reinaldo Neto 2023-06-07 17:14:31 -03:00
parent 6f3dc60994
commit 8c0c1d7dc0
4 changed files with 81 additions and 96 deletions

View File

@ -3,10 +3,17 @@ import { Image } from 'react-native';
import { FastImageProps } from 'react-native-fast-image'; import { FastImageProps } from 'react-native-fast-image';
import { types } from './types'; import { types } from './types';
import { LOCAL_DOCUMENT_PATH } from '../../lib/methods/handleMediaDownload';
export const ImageComponent = (type?: string): React.ComponentType<Partial<Image> | FastImageProps> => { export function ImageComponent({
type,
uri
}: {
type?: string;
uri: string;
}): React.ComponentType<Partial<Image> | FastImageProps> {
let Component; let Component;
if (type === types.REACT_NATIVE_IMAGE) { if (type === types.REACT_NATIVE_IMAGE || uri.startsWith(LOCAL_DOCUMENT_PATH)) {
const { Image } = require('react-native'); const { Image } = require('react-native');
Component = Image; Component = Image;
} else { } else {
@ -14,4 +21,4 @@ export const ImageComponent = (type?: string): React.ComponentType<Partial<Image
Component = FastImage; Component = FastImage;
} }
return Component; return Component;
}; }

View File

@ -109,7 +109,7 @@ export const ImageViewer = ({ uri = '', imageComponentType, width, height, ...pr
const gesture = Gesture.Simultaneous(pinchGesture, panGesture, doubleTapGesture); const gesture = Gesture.Simultaneous(pinchGesture, panGesture, doubleTapGesture);
const Component = ImageComponent(imageComponentType); const Component = ImageComponent({ type: imageComponentType, uri });
const { colors } = useTheme(); const { colors } = useTheme();

View File

@ -72,7 +72,6 @@ const Attachments: React.FC<IMessageAttachments> = React.memo(
style={style} style={style}
isReply={isReply} isReply={isReply}
author={author} author={author}
messageId={id}
/> />
); );
} }

View File

@ -2,27 +2,18 @@ import React, { useContext, useLayoutEffect, useRef, useState } from 'react';
import { StyleProp, TextStyle, View } from 'react-native'; import { StyleProp, TextStyle, View } from 'react-native';
import FastImage from 'react-native-fast-image'; import FastImage from 'react-native-fast-image';
import { dequal } from 'dequal'; import { dequal } from 'dequal';
import { createImageProgress } from 'react-native-image-progress';
import * as Progress from 'react-native-progress';
import { BlurView } from '@react-native-community/blur'; import { BlurView } from '@react-native-community/blur';
import Touchable from './Touchable'; import Touchable from './Touchable';
import Markdown from '../markdown'; import Markdown from '../markdown';
import styles from './styles'; import styles from './styles';
import { themes } from '../../lib/constants';
import MessageContext from './Context'; import MessageContext from './Context';
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 { useTheme } from '../../theme';
import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl'; import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl';
import { import { cancelDownload, downloadMediaFile, isDownloadActive, searchMediaFileAsync } from '../../lib/methods/handleMediaDownload';
MediaTypes, import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference';
cancelDownload,
downloadMediaFile,
isDownloadActive,
searchMediaFileAsync
} from '../../lib/methods/handleMediaDownload';
import { isAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference';
import RCActivityIndicator from '../ActivityIndicator'; import RCActivityIndicator from '../ActivityIndicator';
import { CustomIcon } from '../CustomIcon'; import { CustomIcon } from '../CustomIcon';
@ -30,7 +21,6 @@ interface IMessageButton {
children: React.ReactElement; children: React.ReactElement;
disabled?: boolean; disabled?: boolean;
onPress: () => void; onPress: () => void;
theme: TSupportedThemes;
} }
interface IMessageImage { interface IMessageImage {
@ -41,25 +31,24 @@ interface IMessageImage {
isReply?: boolean; isReply?: boolean;
getCustomEmoji?: TGetCustomEmoji; getCustomEmoji?: TGetCustomEmoji;
author?: IUserMessage; author?: IUserMessage;
messageId: string;
} }
const ImageProgress = createImageProgress(FastImage); const Button = React.memo(({ children, onPress, disabled }: IMessageButton) => {
const { colors } = useTheme();
const Button = React.memo(({ children, onPress, disabled, theme }: IMessageButton) => ( return (
<Touchable <Touchable
disabled={disabled} disabled={disabled}
onPress={onPress} onPress={onPress}
style={styles.imageContainer} style={styles.imageContainer}
background={Touchable.Ripple(themes[theme].bannerBackground)} background={Touchable.Ripple(colors.bannerBackground)}
> >
{children} {children}
</Touchable> </Touchable>
)); );
});
const BlurComponent = ({ loading = false }: { loading: boolean }) => { const BlurComponent = ({ loading = false }: { loading: boolean }) => {
const { theme, colors } = useTheme(); const { theme, colors } = useTheme();
return ( return (
<> <>
<BlurView <BlurView
@ -75,136 +64,126 @@ const BlurComponent = ({ loading = false }: { loading: boolean }) => {
); );
}; };
export const MessageImage = React.memo( export const MessageImage = React.memo(({ imgUri, cached, loading }: { imgUri: string; cached: boolean; loading: boolean }) => {
({ imgUri, toDownload, loading }: { imgUri: string; toDownload: boolean; loading: boolean }) => { const { colors } = useTheme();
const { colors } = useTheme(); return (
<>
return ( <FastImage
<> style={[styles.image, { borderColor: colors.borderColor }]}
<ImageProgress source={{ uri: encodeURI(imgUri) }}
style={[styles.image, { borderColor: colors.borderColor }]} resizeMode={FastImage.resizeMode.cover}
source={{ uri: encodeURI(imgUri) }} />
resizeMode={FastImage.resizeMode.cover} {!cached ? <BlurComponent loading={loading} /> : null}
indicator={Progress.Pie} </>
indicatorProps={{ );
color: colors.actionTintColor });
}}
/>
{toDownload ? <BlurComponent loading={loading} /> : null}
</>
);
}
);
const ImageContainer = React.memo( const ImageContainer = React.memo(
({ file, imageUrl, showAttachment, getCustomEmoji, style, isReply, author, messageId }: IMessageImage) => { ({ file, imageUrl, showAttachment, getCustomEmoji, style, isReply, author }: IMessageImage) => {
const [newFile, setNewFile] = useState(file); const [imageCached, setImageCached] = useState(file);
const [toDownload, setToDownload] = useState(true); const [cached, setCached] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const { theme } = useTheme(); const { theme } = useTheme();
const { baseUrl, user } = useContext(MessageContext); const { baseUrl, user } = useContext(MessageContext);
const img = imageUrl || formatAttachmentUrl(file.image_url, user.id, user.token, baseUrl);
const filePath = useRef(''); const filePath = useRef('');
const getUrl = (link?: string) => imageUrl || formatAttachmentUrl(link, user.id, user.token, baseUrl);
const img = getUrl(file.image_url);
// The param file.title_link is the one that point to image with best quality, however we still need to test the imageUrl
// And we cannot be certain whether the file.title_link actually exists.
const imgUrlToCache = getUrl(imageCached.title_link || imageCached.image_url);
useLayoutEffect(() => { useLayoutEffect(() => {
const handleAutoDownload = async () => { const handleImageSearchAndDownload = async () => {
if (img) { if (img) {
const searchImageCached = await searchMediaFileAsync({ const searchImageCached = await searchMediaFileAsync({
type: MediaTypes.image, type: 'image',
mimeType: newFile.image_type, mimeType: imageCached.image_type,
messageId urlToCache: imgUrlToCache
}); });
filePath.current = searchImageCached.filePath; filePath.current = searchImageCached.filePath;
if (searchImageCached.file?.exists) { if (searchImageCached.file?.exists) {
setNewFile(prev => ({ setImageCached(prev => ({
...prev, ...prev,
title_link: searchImageCached.file?.uri title_link: searchImageCached.file?.uri
})); }));
return setToDownload(false); return setCached(true);
} }
if (isDownloadActive('image', imgUrlToCache)) {
if (isDownloadActive(MediaTypes.image, messageId)) {
return setLoading(true); return setLoading(true);
} }
await handleAutoDownload();
const autoDownload = await isAutoDownloadEnabled('imagesPreferenceDownload', { user, author });
if (autoDownload) {
await handleDownload();
}
} }
}; };
handleAutoDownload(); handleImageSearchAndDownload();
}, []); }, []);
if (!img) { if (!img) {
return null; return null;
} }
const handleAutoDownload = async () => {
const isCurrentUserAuthor = author?._id === user.id;
const autoDownload = fetchAutoDownloadEnabled('imagesPreferenceDownload');
if (autoDownload || isCurrentUserAuthor) {
await handleDownload();
}
};
const handleDownload = async () => { const handleDownload = async () => {
setLoading(true); setLoading(true);
try { try {
// The param file.title_link is the one that point to image with best quality, however we still need to test the imageUrl
// And we don't have sure that ever exists the file.title_link
const imgUrl = imageUrl || formatAttachmentUrl(newFile.title_link || newFile.image_url, user.id, user.token, baseUrl);
const imageUri = await downloadMediaFile({ const imageUri = await downloadMediaFile({
downloadUrl: imgUrl, downloadUrl: imgUrlToCache,
mediaType: MediaTypes.image, mediaType: 'image',
messageId,
path: filePath.current path: filePath.current
}); });
setImageCached(prev => ({
setNewFile(prev => ({
...prev, ...prev,
title_link: imageUri title_link: imageUri
})); }));
setToDownload(false); setCached(true);
setLoading(false); setLoading(false);
} catch (e) { } catch (e) {
setLoading(false); setLoading(false);
return setToDownload(true); return setCached(false);
} }
}; };
const onPress = () => { const onPress = () => {
if (loading && isDownloadActive(MediaTypes.image, messageId)) { if (loading && isDownloadActive('image', imgUrlToCache)) {
cancelDownload(MediaTypes.image, messageId); cancelDownload('image', imgUrlToCache);
setLoading(false); setLoading(false);
return setToDownload(true); return setCached(false);
} }
if (!cached && !loading) {
if (toDownload && !loading) {
return handleDownload(); return handleDownload();
} }
if (!showAttachment) { if (!showAttachment) {
return; return;
} }
return showAttachment(imageCached);
return showAttachment(newFile);
}; };
if (newFile.description) { if (imageCached.description) {
return ( return (
<Button disabled={isReply} theme={theme} onPress={onPress}> <Button disabled={isReply} onPress={onPress}>
<View> <View>
<Markdown <Markdown
msg={newFile.description} msg={imageCached.description}
style={[isReply && style]} style={[isReply && style]}
username={user.username} username={user.username}
getCustomEmoji={getCustomEmoji} getCustomEmoji={getCustomEmoji}
theme={theme} theme={theme}
/> />
<MessageImage imgUri={img} toDownload={toDownload} loading={loading} /> <MessageImage imgUri={img} cached={cached} loading={loading} />
</View> </View>
</Button> </Button>
); );
} }
return ( return (
<Button disabled={isReply} theme={theme} onPress={onPress}> <Button disabled={isReply} onPress={onPress}>
<> <MessageImage imgUri={img} cached={cached} loading={loading} />
<MessageImage imgUri={img} toDownload={toDownload} loading={loading} />
</>
</Button> </Button>
); );
}, },