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:
parent
61010b8368
commit
720ac22070
17 changed files with 49 additions and 36 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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}`;
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ type Props = {
|
|||
channelId: string;
|
||||
fields: MessageAttachmentField[];
|
||||
location: string;
|
||||
metadata?: PostMetadata;
|
||||
metadata?: PostMetadata | null;
|
||||
textStyles?: MarkdownTextStyles;
|
||||
theme: Theme;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ type Props = {
|
|||
blockStyles?: MarkdownBlockStyles;
|
||||
channelId: string;
|
||||
location: string;
|
||||
metadata?: PostMetadata;
|
||||
metadata?: PostMetadata | null;
|
||||
textStyles?: MarkdownTextStyles;
|
||||
theme: Theme;
|
||||
value?: string;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ type Props = {
|
|||
channelId: string;
|
||||
hasThumbnail?: boolean;
|
||||
location: string;
|
||||
metadata?: PostMetadata;
|
||||
metadata?: PostMetadata | null;
|
||||
textStyles?: MarkdownTextStyles;
|
||||
theme: Theme;
|
||||
value?: string;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ type Props = {
|
|||
channelId: string;
|
||||
layoutWidth?: number;
|
||||
location: string;
|
||||
metadata?: PostMetadata;
|
||||
metadata?: PostMetadata | undefined | null;
|
||||
postId: string;
|
||||
theme: Theme;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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 = () => {
|
||||
|
|
|
|||
|
|
@ -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]) {
|
||||
|
|
|
|||
|
|
@ -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}]}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
2
types/api/posts.d.ts
vendored
2
types/api/posts.d.ts
vendored
|
|
@ -41,7 +41,7 @@ type PostMetadata = {
|
|||
embeds?: PostEmbed[];
|
||||
emojis?: CustomEmoji[];
|
||||
files?: FileInfo[];
|
||||
images?: Dictionary<PostImage>;
|
||||
images?: Dictionary<PostImage | undefined>;
|
||||
reactions?: Reaction[];
|
||||
priority?: PostPriorityData;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue