Handle undefined metadata all over the app (#7244)

* Handle undefined metadata on Markdown Table Images

* Add missing change

* Handle undefined image metadata all over the app
This commit is contained in:
Daniel Espino García 2023-03-31 09:41:28 +02:00 committed by GitHub
parent 61010b8368
commit 720ac22070
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 49 additions and 36 deletions

View file

@ -55,7 +55,7 @@ type MarkdownProps = {
disableTables?: boolean;
enableLatex: boolean;
enableInlineLatex: boolean;
imagesMetadata?: Record<string, PostImage>;
imagesMetadata?: Record<string, PostImage | undefined>;
isEdited?: boolean;
isReplyPost?: boolean;
isSearchResult?: boolean;

View file

@ -36,7 +36,7 @@ import type {GalleryItemType} from '@typings/screens/gallery';
type MarkdownImageProps = {
disabled?: boolean;
errorTextStyle: StyleProp<TextStyle>;
imagesMetadata: Record<string, PostImage>;
imagesMetadata: Record<string, PostImage | undefined>;
isReplyPost?: boolean;
linkDestination?: string;
layoutHeight?: number;
@ -90,7 +90,7 @@ const MarkdownImage = ({
const fileInfo = useMemo(() => {
const link = decodeURIComponent(uri);
let filename = parseUrl(link.substr(link.lastIndexOf('/'))).pathname.replace('/', '');
let extension = metadata.format || filename.split('.').pop();
let extension = metadata?.format || filename.split('.').pop();
if (extension === filename) {
const ext = filename.indexOf('.') === -1 ? '.png' : filename.substring(filename.lastIndexOf('.'));
filename = `${filename}${ext}`;

View file

@ -18,7 +18,7 @@ import type {GalleryItemType} from '@typings/screens/gallery';
type MarkdownTableImageProps = {
disabled?: boolean;
imagesMetadata: Record<string, PostImage>;
imagesMetadata: Record<string, PostImage | undefined>;
location?: string;
postId: string;
serverURL?: string;
@ -55,7 +55,8 @@ const MarkTableImage = ({disabled, imagesMetadata, location, postId, serverURL,
};
const getFileInfo = () => {
const {height, width} = metadata;
const height = metadata?.height || 0;
const width = metadata?.width || 0;
const link = decodeURIComponent(getImageSource());
let filename = parseUrl(link.substr(link.lastIndexOf('/'))).pathname.replace('/', '');
let extension = filename.split('.').pop();
@ -109,7 +110,7 @@ const MarkTableImage = ({disabled, imagesMetadata, location, postId, serverURL,
/>
);
} else {
const {height, width} = calculateDimensions(metadata.height, metadata.width, 100, 100);
const {height, width} = calculateDimensions(metadata?.height, metadata?.width, 100, 100);
image = (
<TouchableWithoutFeedback
disabled={disabled}

View file

@ -27,7 +27,7 @@ type ImagePreviewProps = {
link: string;
layoutWidth?: number;
location: string;
metadata: PostMetadata;
metadata: PostMetadata | undefined | null;
postId: string;
theme: Theme;
}
@ -54,8 +54,8 @@ const ImagePreview = ({expandedLink, isReplyPost, layoutWidth, link, location, m
const fileId = useRef(generateId('uid')).current;
const [imageUrl, setImageUrl] = useState(expandedLink || link);
const isTablet = useIsTablet();
const imageProps = metadata.images![link];
const dimensions = calculateDimensions(imageProps.height, imageProps.width, layoutWidth || getViewPortWidth(isReplyPost, isTablet));
const imageProps = metadata?.images?.[link];
const dimensions = calculateDimensions(imageProps?.height, imageProps?.width, layoutWidth || getViewPortWidth(isReplyPost, isTablet));
const onError = useCallback(() => {
setError(true);
@ -66,8 +66,8 @@ const ImagePreview = ({expandedLink, isReplyPost, layoutWidth, link, location, m
id: fileId,
postId,
uri: imageUrl,
width: imageProps.width,
height: imageProps.height,
width: imageProps?.width || 0,
height: imageProps?.height || 0,
name: extractFilenameFromUrl(imageUrl) || 'imagePreview.png',
mime_type: lookupMimeType(imageUrl) || 'image/png',
type: 'image',

View file

@ -12,8 +12,8 @@ import ImagePreview from './image_preview';
import type {WithDatabaseArgs} from '@typings/database/database';
const enhance = withObservables(['metadata'], ({database, metadata}: WithDatabaseArgs & {metadata: PostMetadata}) => {
const link = metadata.embeds?.[0].url;
const enhance = withObservables(['metadata'], ({database, metadata}: WithDatabaseArgs & {metadata: PostMetadata | undefined | null}) => {
const link = metadata?.embeds?.[0].url;
return {
expandedLink: observeExpandedLinks(database).pipe(

View file

@ -46,7 +46,7 @@ const Content = ({isReplyPost, layoutWidth, location, post, theme}: ContentProps
isReplyPost={isReplyPost}
layoutWidth={layoutWidth}
location={location}
metadata={post.metadata!}
metadata={post.metadata}
postId={post.id}
theme={theme}
/>
@ -57,7 +57,7 @@ const Content = ({isReplyPost, layoutWidth, location, post, theme}: ContentProps
<YouTube
isReplyPost={isReplyPost}
layoutWidth={layoutWidth}
metadata={post.metadata!}
metadata={post.metadata}
/>
);
}
@ -67,7 +67,7 @@ const Content = ({isReplyPost, layoutWidth, location, post, theme}: ContentProps
isReplyPost={isReplyPost}
layoutWidth={layoutWidth}
location={location}
metadata={post.metadata!}
metadata={post.metadata}
postId={post.id}
removeLinkPreview={post.props?.remove_link_preview === 'true'}
theme={theme}
@ -81,7 +81,7 @@ const Content = ({isReplyPost, layoutWidth, location, post, theme}: ContentProps
channelId={post.channelId}
layoutWidth={layoutWidth}
location={location}
metadata={post.metadata!}
metadata={post.metadata}
postId={post.id}
theme={theme}
/>

View file

@ -15,7 +15,7 @@ type Props = {
channelId: string;
fields: MessageAttachmentField[];
location: string;
metadata?: PostMetadata;
metadata?: PostMetadata | null;
textStyles?: MarkdownTextStyles;
theme: Theme;
}

View file

@ -13,7 +13,7 @@ type Props = {
blockStyles?: MarkdownBlockStyles;
channelId: string;
location: string;
metadata?: PostMetadata;
metadata?: PostMetadata | null;
textStyles?: MarkdownTextStyles;
theme: Theme;
value?: string;

View file

@ -17,7 +17,7 @@ type Props = {
channelId: string;
hasThumbnail?: boolean;
location: string;
metadata?: PostMetadata;
metadata?: PostMetadata | null;
textStyles?: MarkdownTextStyles;
theme: Theme;
value?: string;

View file

@ -11,7 +11,7 @@ type Props = {
channelId: string;
layoutWidth?: number;
location: string;
metadata?: PostMetadata;
metadata?: PostMetadata | undefined | null;
postId: string;
theme: Theme;
}

View file

@ -24,7 +24,7 @@ type Props = {
channelId: string;
layoutWidth?: number;
location: string;
metadata?: PostMetadata;
metadata?: PostMetadata | null;
postId: string;
theme: Theme;
}
@ -142,7 +142,7 @@ export default function MessageAttachment({attachment, channelId, layoutWidth, l
{Boolean(metadata?.images?.[attachment.image_url]) &&
<AttachmentImage
imageUrl={attachment.image_url}
imageMetadata={metadata!.images![attachment.image_url]}
imageMetadata={metadata!.images![attachment.image_url]!}
layoutWidth={layoutWidth}
location={location}
postId={postId}

View file

@ -14,7 +14,7 @@ type OpengraphProps = {
isReplyPost: boolean;
layoutWidth?: number;
location: string;
metadata: PostMetadata;
metadata: PostMetadata | undefined | null;
postId: string;
showLinkPreviews: boolean;
theme: Theme;
@ -49,8 +49,8 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
};
});
const selectOpenGraphData = (url: string, metadata: PostMetadata) => {
if (!metadata.embeds) {
const selectOpenGraphData = (url: string, metadata: PostMetadata | undefined | null) => {
if (!metadata?.embeds) {
return undefined;
}
@ -61,7 +61,7 @@ const selectOpenGraphData = (url: string, metadata: PostMetadata) => {
const Opengraph = ({isReplyPost, layoutWidth, location, metadata, postId, showLinkPreviews, theme}: OpengraphProps) => {
const intl = useIntl();
const link = metadata.embeds![0]!.url;
const link = metadata?.embeds![0]!.url || '';
const openGraphData = selectOpenGraphData(link, metadata);
if (!showLinkPreviews || !openGraphData) {
@ -73,7 +73,7 @@ const Opengraph = ({isReplyPost, layoutWidth, location, metadata, postId, showLi
openGraphData?.images &&
openGraphData.images instanceof Array &&
openGraphData.images.length &&
metadata.images);
metadata?.images);
const goToLink = () => {
const onError = () => {

View file

@ -23,7 +23,7 @@ type OpengraphImageProps = {
isReplyPost: boolean;
layoutWidth?: number;
location: string;
metadata: PostMetadata;
metadata: PostMetadata | undefined | null;
openGraphImages: never[];
postId: string;
theme: Theme;
@ -68,7 +68,7 @@ const OpengraphImage = ({isReplyPost, layoutWidth, location, metadata, openGraph
}), [isReplyPost, dimensions]);
const bestImage = getNearestPoint(bestDimensions, openGraphImages, 'width', 'height');
const imageUrl = (bestImage.secure_url || bestImage.url)!;
const imagesMetadata = metadata.images;
const imagesMetadata = metadata?.images;
let ogImage;
if (imagesMetadata && imagesMetadata[imageUrl]) {

View file

@ -18,7 +18,7 @@ import YouTubeLogo from './youtube.svg';
type YouTubeProps = {
isReplyPost: boolean;
layoutWidth?: number;
metadata: PostMetadata;
metadata: PostMetadata | undefined | null;
}
const MAX_YOUTUBE_IMAGE_HEIGHT = 280;
@ -61,7 +61,7 @@ const YouTube = ({isReplyPost, layoutWidth, metadata}: YouTubeProps) => {
const isTablet = useIsTablet();
const theme = useTheme();
const styles = getStyleSheet(theme);
const link = metadata.embeds![0].url;
const link = metadata?.embeds![0].url;
const videoId = getYouTubeVideoId(link);
const dimensions = calculateDimensions(
MAX_YOUTUBE_IMAGE_HEIGHT,
@ -70,6 +70,10 @@ const YouTube = ({isReplyPost, layoutWidth, metadata}: YouTubeProps) => {
);
const playYouTubeVideo = useCallback(() => {
if (!link) {
return;
}
const onError = () => {
Alert.alert(
intl.formatMessage({
@ -87,7 +91,7 @@ const YouTube = ({isReplyPost, layoutWidth, metadata}: YouTubeProps) => {
}, [link, intl.locale]);
let imgUrl;
if (metadata.images) {
if (metadata?.images) {
imgUrl = Object.keys(metadata.images)[0];
}
@ -96,6 +100,10 @@ const YouTube = ({isReplyPost, layoutWidth, metadata}: YouTubeProps) => {
imgUrl = `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`;
}
if (!link) {
return null;
}
return (
<TouchableOpacity
style={[styles.imageContainer, {height: dimensions.height, width: dimensions.width}]}

View file

@ -7,7 +7,7 @@ import 'react-native-reanimated';
import {View} from '@constants';
import {IMAGE_MAX_HEIGHT, IMAGE_MIN_DIMENSION, MAX_GIF_SIZE, VIEWPORT_IMAGE_OFFSET, VIEWPORT_IMAGE_REPLY_OFFSET} from '@constants/image';
export const calculateDimensions = (height: number, width: number, viewPortWidth = 0, viewPortHeight = 0) => {
export const calculateDimensions = (height?: number, width?: number, viewPortWidth = 0, viewPortHeight = 0) => {
'worklet';
if (!height || !width) {

View file

@ -150,7 +150,11 @@ export function getScheme(url: string) {
return match && match[1];
}
export function getYouTubeVideoId(link: string) {
export function getYouTubeVideoId(link?: string) {
if (!link) {
return '';
}
// https://youtube.com/watch?v=<id>
let match = (/youtube\.com\/watch\?\S*\bv=([a-zA-Z0-9_-]{6,11})/g).exec(link);
if (match) {

View file

@ -41,7 +41,7 @@ type PostMetadata = {
embeds?: PostEmbed[];
emojis?: CustomEmoji[];
files?: FileInfo[];
images?: Dictionary<PostImage>;
images?: Dictionary<PostImage | undefined>;
reactions?: Reaction[];
priority?: PostPriorityData;
};