From afcb8f4fcbb292b3095f974883664f32376fa038 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Mon, 20 Apr 2026 14:28:40 +0300 Subject: [PATCH] add peek menu to media preview --- src/components/MediaPreview.tsx | 70 ++++++++++++++++--- .../notifications/NotificationFeedItem.tsx | 1 + 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/components/MediaPreview.tsx b/src/components/MediaPreview.tsx index 530c85ae66..9aad6da864 100644 --- a/src/components/MediaPreview.tsx +++ b/src/components/MediaPreview.tsx @@ -1,11 +1,16 @@ import {type StyleProp, StyleSheet, View, type ViewStyle} from 'react-native' import {Image} from 'expo-image' -import {type AppBskyFeedDefs} from '@atproto/api' -import {Trans} from '@lingui/react/macro' +import {type AppBskyEmbedImages, type AppBskyFeedDefs} from '@atproto/api' +import {Trans, useLingui} from '@lingui/react/macro' +import {shareImageModal} from '#/lib/media/manip' +import {useSaveImageToMediaLibrary} from '#/lib/media/save-image' import {isGifEmbed} from '#/lib/strings/embed-player' -import {atoms as a, useTheme} from '#/alf' +import {atoms as a, tokens, useTheme} from '#/alf' +import {ArrowShareRight_Stroke2_Corner2_Rounded as ShareIcon} from '#/components/icons/ArrowShareRight' +import {Download_Stroke2_Corner0_Rounded as DownloadIcon} from '#/components/icons/Download' import {MediaInsetBorder} from '#/components/MediaInsetBorder' +import * as PeekMenu from '#/components/PeekMenu' import {Text} from '#/components/Typography' import {PlayButtonIcon} from '#/components/video/PlayButtonIcon' import * as bsky from '#/types/bsky' @@ -16,9 +21,11 @@ import * as bsky from '#/types/bsky' export function Embed({ embed, style, + peekable = false, }: { embed: AppBskyFeedDefs.PostView['embed'] style?: StyleProp + peekable?: boolean }) { const e = bsky.post.parseEmbed(embed) @@ -27,13 +34,17 @@ export function Embed({ if (e.type === 'images') { return ( - {e.view.images.map(image => ( - - ))} + {e.view.images.map(image => + peekable ? ( + + ) : ( + + ), + )} ) } else if (e.type === 'link') { @@ -156,6 +167,45 @@ export function VideoItem({ ) } +function PeekableImageItem({image}: {image: AppBskyEmbedImages.ViewImage}) { + const {t: l} = useLingui() + const saveImage = useSaveImageToMediaLibrary() + + const aspect = + image.aspectRatio && image.aspectRatio.height > 0 + ? image.aspectRatio.width / image.aspectRatio.height + : undefined + + return ( + + 0 ? aspect : 1, + }} + borderRadius={tokens.borderRadius.xs}> + + + + void saveImage(image.fullsize)}> + + {l`Save image`} + + void shareImageModal({uri: image.fullsize})}> + + {l`Share`} + + + + ) +} + const styles = StyleSheet.create({ altContainer: { backgroundColor: 'rgba(0, 0, 0, 0.75)', diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx index 5f337044e5..ac1488e4b3 100644 --- a/src/view/com/notifications/NotificationFeedItem.tsx +++ b/src/view/com/notifications/NotificationFeedItem.tsx @@ -1093,6 +1093,7 @@ function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) { )