diff --git a/src/view/com/composer/drafts/DraftItem.tsx b/src/view/com/composer/drafts/DraftItem.tsx index 474e572b06..b394b87a86 100644 --- a/src/view/com/composer/drafts/DraftItem.tsx +++ b/src/view/com/composer/drafts/DraftItem.tsx @@ -1,12 +1,20 @@ -import {useCallback, useEffect, useState} from 'react' -import {Image, Pressable, View} from 'react-native' +import {useCallback, useEffect, useMemo, useState} from 'react' +import {Pressable, View} from 'react-native' +import {Image} from 'expo-image' +import {type AppBskyEmbedImages} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {isNative} from '#/platform/detection' -import {type DraftPostDisplay, type DraftSummary} from '#/state/drafts' +import { + type DraftPostDisplay, + type DraftSummary, + type LocalMediaRef, +} from '#/state/drafts' import {useCurrentAccountProfile} from '#/state/queries/useCurrentAccountProfile' import {useSession} from '#/state/session' +import {AutoSizedImage} from '#/view/com/util/images/AutoSizedImage' +import {ImageLayoutGrid} from '#/view/com/util/images/ImageLayoutGrid' import {TimeElapsed} from '#/view/com/util/TimeElapsed' import {UserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, useTheme} from '#/alf' @@ -134,13 +142,13 @@ function DraftPostRow({ {/* Content column */} - + {/* Header row: name, handle, timestamp, menu */} {displayName && ( {displayName} @@ -197,10 +205,15 @@ function DraftPostRow({ ) } +type LoadedImage = { + url: string + meta: LocalMediaRef +} + function DraftMediaPreview({post}: {post: DraftPostDisplay}) { const t = useTheme() const {currentAccount} = useSession() - const [imageUrls, setImageUrls] = useState([]) + const [loadedImages, setLoadedImages] = useState([]) const [gifUrl, setGifUrl] = useState(null) useEffect(() => { @@ -209,20 +222,20 @@ function DraftMediaPreview({post}: {post: DraftPostDisplay}) { // Load images if (post.images && post.images.length > 0) { - const urls: string[] = [] + const loaded: LoadedImage[] = [] for (const image of post.images) { try { const url = await storage.loadMediaFromLocal( currentAccount.did, image.localId, ) - urls.push(url) + loaded.push({url, meta: image}) } catch (e) { // Image might not exist anymore console.warn('Failed to load draft image', e) } } - setImageUrls(urls) + setLoadedImages(loaded) } // GIFs have a URL directly @@ -234,52 +247,50 @@ function DraftMediaPreview({post}: {post: DraftPostDisplay}) { loadMedia() }, [currentAccount?.did, post.images, post.gif]) + // Convert loaded images to ViewImage format for the embed components + const viewImages = useMemo(() => { + return loadedImages.map(({url, meta}) => ({ + thumb: url, + fullsize: url, + alt: meta.altText || '', + aspectRatio: + meta.width && meta.height + ? {width: meta.width, height: meta.height} + : undefined, + })) + }, [loadedImages]) + // Nothing to show - if (imageUrls.length === 0 && !gifUrl && !post.video) { + if (viewImages.length === 0 && !gifUrl && !post.video) { return null } return ( - - {/* Images grid */} - {imageUrls.length > 0 && ( - - {imageUrls.map((url, index) => ( - - - - ))} - + + {/* Images - use real embed components */} + {viewImages.length === 1 && ( + )} + {viewImages.length > 1 && } {/* GIF preview */} {gifUrl && ( @@ -289,12 +300,17 @@ function DraftMediaPreview({post}: {post: DraftPostDisplay}) { {post.video && ( Video attached