2023-05-15 18:10:43 +00:00
|
|
|
import React, { useContext, useLayoutEffect, useRef, useState } from 'react';
|
2022-03-21 20:44:06 +00:00
|
|
|
import { StyleProp, TextStyle, View } from 'react-native';
|
2022-05-31 16:08:18 +00:00
|
|
|
import FastImage from 'react-native-fast-image';
|
2021-09-13 20:41:05 +00:00
|
|
|
import { dequal } from 'dequal';
|
2023-05-17 00:31:53 +00:00
|
|
|
import { BlurView } from '@react-native-community/blur';
|
2021-09-13 20:41:05 +00:00
|
|
|
|
|
|
|
import Touchable from './Touchable';
|
|
|
|
import Markdown from '../markdown';
|
|
|
|
import styles from './styles';
|
|
|
|
import MessageContext from './Context';
|
2022-02-17 15:27:01 +00:00
|
|
|
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
2023-05-11 23:20:48 +00:00
|
|
|
import { IAttachment, IUserMessage } from '../../definitions';
|
2023-06-07 20:14:31 +00:00
|
|
|
import { useTheme } from '../../theme';
|
2022-04-07 13:13:19 +00:00
|
|
|
import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl';
|
2023-07-03 17:28:22 +00:00
|
|
|
import { cancelDownload, downloadMediaFile, isDownloadActive, getMediaCache } from '../../lib/methods/handleMediaDownload';
|
2023-06-07 20:14:31 +00:00
|
|
|
import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference';
|
2023-05-17 00:31:53 +00:00
|
|
|
import RCActivityIndicator from '../ActivityIndicator';
|
|
|
|
import { CustomIcon } from '../CustomIcon';
|
2021-09-13 20:41:05 +00:00
|
|
|
|
2022-04-01 21:52:38 +00:00
|
|
|
interface IMessageButton {
|
|
|
|
children: React.ReactElement;
|
2022-03-21 20:44:06 +00:00
|
|
|
disabled?: boolean;
|
2022-04-01 21:52:38 +00:00
|
|
|
onPress: () => void;
|
|
|
|
}
|
2021-09-13 20:41:05 +00:00
|
|
|
|
|
|
|
interface IMessageImage {
|
2022-03-21 20:44:06 +00:00
|
|
|
file: IAttachment;
|
2021-09-13 20:41:05 +00:00
|
|
|
imageUrl?: string;
|
2022-04-01 21:52:38 +00:00
|
|
|
showAttachment?: (file: IAttachment) => void;
|
2022-03-21 20:44:06 +00:00
|
|
|
style?: StyleProp<TextStyle>[];
|
|
|
|
isReply?: boolean;
|
2022-03-29 20:06:50 +00:00
|
|
|
getCustomEmoji?: TGetCustomEmoji;
|
2023-05-11 23:20:48 +00:00
|
|
|
author?: IUserMessage;
|
2021-09-13 20:41:05 +00:00
|
|
|
}
|
|
|
|
|
2023-06-07 20:14:31 +00:00
|
|
|
const Button = React.memo(({ children, onPress, disabled }: IMessageButton) => {
|
|
|
|
const { colors } = useTheme();
|
|
|
|
return (
|
|
|
|
<Touchable
|
|
|
|
disabled={disabled}
|
|
|
|
onPress={onPress}
|
|
|
|
style={styles.imageContainer}
|
|
|
|
background={Touchable.Ripple(colors.bannerBackground)}
|
|
|
|
>
|
|
|
|
{children}
|
|
|
|
</Touchable>
|
|
|
|
);
|
|
|
|
});
|
2021-09-13 20:41:05 +00:00
|
|
|
|
2023-05-17 00:31:53 +00:00
|
|
|
const BlurComponent = ({ loading = false }: { loading: boolean }) => {
|
|
|
|
const { theme, colors } = useTheme();
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<BlurView
|
|
|
|
style={[styles.image, styles.imageBlur]}
|
|
|
|
blurType={theme === 'light' ? 'light' : 'dark'}
|
|
|
|
blurAmount={10}
|
|
|
|
reducedTransparencyFallbackColor='white'
|
|
|
|
/>
|
|
|
|
<View style={[styles.image, styles.imageIndicator]}>
|
|
|
|
{loading ? <RCActivityIndicator /> : <CustomIcon color={colors.buttonText} name='arrow-down-circle' size={54} />}
|
|
|
|
</View>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2023-06-07 20:14:31 +00:00
|
|
|
export const MessageImage = React.memo(({ imgUri, cached, loading }: { imgUri: string; cached: boolean; loading: boolean }) => {
|
|
|
|
const { colors } = useTheme();
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<FastImage
|
|
|
|
style={[styles.image, { borderColor: colors.borderColor }]}
|
|
|
|
source={{ uri: encodeURI(imgUri) }}
|
|
|
|
resizeMode={FastImage.resizeMode.cover}
|
|
|
|
/>
|
|
|
|
{!cached ? <BlurComponent loading={loading} /> : null}
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
});
|
2023-05-15 18:10:43 +00:00
|
|
|
|
2021-09-13 20:41:05 +00:00
|
|
|
const ImageContainer = React.memo(
|
2023-06-07 20:14:31 +00:00
|
|
|
({ file, imageUrl, showAttachment, getCustomEmoji, style, isReply, author }: IMessageImage) => {
|
|
|
|
const [imageCached, setImageCached] = useState(file);
|
|
|
|
const [cached, setCached] = useState(false);
|
2023-07-03 17:28:22 +00:00
|
|
|
const [loading, setLoading] = useState(true);
|
2022-03-29 20:06:50 +00:00
|
|
|
const { theme } = useTheme();
|
2021-09-13 20:41:05 +00:00
|
|
|
const { baseUrl, user } = useContext(MessageContext);
|
2023-05-15 18:10:43 +00:00
|
|
|
const filePath = useRef('');
|
2023-06-07 20:14:31 +00:00
|
|
|
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);
|
2023-05-15 18:10:43 +00:00
|
|
|
|
|
|
|
useLayoutEffect(() => {
|
2023-07-03 17:28:22 +00:00
|
|
|
const handleCache = async () => {
|
2023-05-15 18:10:43 +00:00
|
|
|
if (img) {
|
2023-07-03 17:28:22 +00:00
|
|
|
const cachedImageResult = await getMediaCache({
|
2023-06-07 20:14:31 +00:00
|
|
|
type: 'image',
|
|
|
|
mimeType: imageCached.image_type,
|
|
|
|
urlToCache: imgUrlToCache
|
2023-05-15 18:10:43 +00:00
|
|
|
});
|
2023-06-07 21:56:36 +00:00
|
|
|
filePath.current = cachedImageResult.filePath;
|
|
|
|
if (cachedImageResult.file?.exists) {
|
2023-06-07 20:14:31 +00:00
|
|
|
setImageCached(prev => ({
|
2023-05-19 05:42:21 +00:00
|
|
|
...prev,
|
2023-06-07 21:56:36 +00:00
|
|
|
title_link: cachedImageResult.file?.uri
|
2023-05-19 05:42:21 +00:00
|
|
|
}));
|
2023-07-03 17:28:22 +00:00
|
|
|
setLoading(false);
|
|
|
|
setCached(true);
|
|
|
|
return;
|
2023-05-15 18:10:43 +00:00
|
|
|
}
|
2023-07-03 17:28:22 +00:00
|
|
|
if (isReply) {
|
|
|
|
setLoading(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (isDownloadActive(imgUrlToCache)) {
|
|
|
|
return;
|
2023-05-19 05:42:21 +00:00
|
|
|
}
|
2023-06-07 20:14:31 +00:00
|
|
|
await handleAutoDownload();
|
2023-05-15 18:10:43 +00:00
|
|
|
}
|
|
|
|
};
|
2023-07-03 17:28:22 +00:00
|
|
|
handleCache();
|
2023-05-15 18:10:43 +00:00
|
|
|
}, []);
|
2022-04-01 21:52:38 +00:00
|
|
|
|
2021-09-13 20:41:05 +00:00
|
|
|
if (!img) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2023-06-07 20:14:31 +00:00
|
|
|
const handleAutoDownload = async () => {
|
|
|
|
const isCurrentUserAuthor = author?._id === user.id;
|
2023-06-07 21:15:37 +00:00
|
|
|
const isAutoDownloadEnabled = fetchAutoDownloadEnabled('imagesPreferenceDownload');
|
|
|
|
if (isAutoDownloadEnabled || isCurrentUserAuthor) {
|
2023-06-07 20:14:31 +00:00
|
|
|
await handleDownload();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-05-15 18:10:43 +00:00
|
|
|
const handleDownload = async () => {
|
2023-05-19 14:35:36 +00:00
|
|
|
try {
|
|
|
|
const imageUri = await downloadMediaFile({
|
2023-06-07 20:14:31 +00:00
|
|
|
downloadUrl: imgUrlToCache,
|
2023-05-19 14:35:36 +00:00
|
|
|
path: filePath.current
|
|
|
|
});
|
2023-06-07 20:14:31 +00:00
|
|
|
setImageCached(prev => ({
|
2023-05-19 14:35:36 +00:00
|
|
|
...prev,
|
|
|
|
title_link: imageUri
|
|
|
|
}));
|
2023-06-07 20:14:31 +00:00
|
|
|
setCached(true);
|
2023-05-19 14:35:36 +00:00
|
|
|
setLoading(false);
|
|
|
|
} catch (e) {
|
2023-05-15 18:31:24 +00:00
|
|
|
setLoading(false);
|
2023-07-03 17:28:22 +00:00
|
|
|
setCached(false);
|
2023-05-15 18:31:24 +00:00
|
|
|
}
|
2023-05-15 18:10:43 +00:00
|
|
|
};
|
2023-05-11 23:20:48 +00:00
|
|
|
|
2022-03-21 20:44:06 +00:00
|
|
|
const onPress = () => {
|
2023-07-03 17:28:22 +00:00
|
|
|
if (loading && isDownloadActive(imgUrlToCache)) {
|
|
|
|
cancelDownload(imgUrlToCache);
|
2023-05-19 05:42:21 +00:00
|
|
|
setLoading(false);
|
2023-07-03 17:28:22 +00:00
|
|
|
setCached(false);
|
|
|
|
return;
|
2023-05-15 18:10:43 +00:00
|
|
|
}
|
2023-06-07 20:14:31 +00:00
|
|
|
if (!cached && !loading) {
|
2023-07-03 17:28:22 +00:00
|
|
|
handleDownload();
|
|
|
|
return;
|
2023-05-15 18:10:43 +00:00
|
|
|
}
|
2022-03-21 20:44:06 +00:00
|
|
|
if (!showAttachment) {
|
|
|
|
return;
|
|
|
|
}
|
2023-07-03 17:28:22 +00:00
|
|
|
showAttachment(imageCached);
|
2022-03-21 20:44:06 +00:00
|
|
|
};
|
2021-09-13 20:41:05 +00:00
|
|
|
|
2023-06-07 20:14:31 +00:00
|
|
|
if (imageCached.description) {
|
2021-09-13 20:41:05 +00:00
|
|
|
return (
|
2023-06-07 20:14:31 +00:00
|
|
|
<Button disabled={isReply} onPress={onPress}>
|
2021-09-13 20:41:05 +00:00
|
|
|
<View>
|
|
|
|
<Markdown
|
2023-06-07 20:14:31 +00:00
|
|
|
msg={imageCached.description}
|
2022-03-21 20:44:06 +00:00
|
|
|
style={[isReply && style]}
|
2021-09-13 20:41:05 +00:00
|
|
|
username={user.username}
|
|
|
|
getCustomEmoji={getCustomEmoji}
|
2022-07-04 18:10:14 +00:00
|
|
|
theme={theme}
|
2021-09-13 20:41:05 +00:00
|
|
|
/>
|
2023-06-07 20:14:31 +00:00
|
|
|
<MessageImage imgUri={img} cached={cached} loading={loading} />
|
2021-09-13 20:41:05 +00:00
|
|
|
</View>
|
|
|
|
</Button>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2023-06-07 20:14:31 +00:00
|
|
|
<Button disabled={isReply} onPress={onPress}>
|
|
|
|
<MessageImage imgUri={img} cached={cached} loading={loading} />
|
2021-09-13 20:41:05 +00:00
|
|
|
</Button>
|
|
|
|
);
|
|
|
|
},
|
2022-03-29 20:06:50 +00:00
|
|
|
(prevProps, nextProps) => dequal(prevProps.file, nextProps.file)
|
2021-09-13 20:41:05 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
ImageContainer.displayName = 'MessageImageContainer';
|
|
|
|
MessageImage.displayName = 'MessageImage';
|
|
|
|
|
|
|
|
export default ImageContainer;
|