Add iOS peek long-press context menu for image embeds (#10300)
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import {useRef} from 'react'
|
||||
import {InteractionManager, View} from 'react-native'
|
||||
import {type AnimatedRef} from 'react-native-reanimated'
|
||||
import {Image} from 'expo-image'
|
||||
@@ -8,6 +9,7 @@ import {Gallery} from '#/components/images/Gallery'
|
||||
import {ImageLayoutGrid} from '#/components/images/ImageLayoutGrid'
|
||||
import {useLightboxControls} from '#/components/Lightbox/state'
|
||||
import {type Dimensions} from '#/components/Lightbox/types'
|
||||
import {ImageContextMenu} from '#/components/Post/Embed/ImageContextMenu'
|
||||
import {PostEmbedViewContext} from '#/components/Post/Embed/types'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {type EmbedType} from '#/types/bsky/post'
|
||||
@@ -24,6 +26,11 @@ export function ImageEmbed({
|
||||
const {images} = embed.view
|
||||
const galleryEnabled = ax.features.enabled(ax.features.PostGalleryEmbedEnable)
|
||||
|
||||
// Captured from AutoSizedImage so the peek-commit handler can reuse the same
|
||||
// ref + dims that a tap would — keeps the lightbox's return animation intact.
|
||||
const singleContainerRef = useRef<AnimatedRef<any> | null>(null)
|
||||
const singleDimsRef = useRef<Dimensions | null>(null)
|
||||
|
||||
if (images.length > 0) {
|
||||
const items = images.map(img => ({
|
||||
uri: img.fullsize,
|
||||
@@ -59,24 +66,49 @@ export function ImageEmbed({
|
||||
|
||||
if (images.length === 1) {
|
||||
const image = images[0]
|
||||
const aspect =
|
||||
image.aspectRatio && image.aspectRatio.height > 0
|
||||
? image.aspectRatio.width / image.aspectRatio.height
|
||||
: undefined
|
||||
const openFromSingle = () => {
|
||||
if (singleContainerRef.current) {
|
||||
onPress(0, [singleContainerRef.current], [singleDimsRef.current])
|
||||
}
|
||||
}
|
||||
return (
|
||||
<View style={[a.mt_sm, rest.style]}>
|
||||
<AutoSizedImage
|
||||
crop={
|
||||
rest.viewContext === PostEmbedViewContext.ThreadHighlighted
|
||||
? 'none'
|
||||
: rest.viewContext ===
|
||||
PostEmbedViewContext.FeedEmbedRecordWithMedia
|
||||
? 'square'
|
||||
: 'constrained'
|
||||
}
|
||||
image={image}
|
||||
onPress={(containerRef, dims) => onPress(0, [containerRef], [dims])}
|
||||
onPressIn={() => onPressIn(0)}
|
||||
hideBadge={
|
||||
rest.viewContext === PostEmbedViewContext.FeedEmbedRecordWithMedia
|
||||
}
|
||||
/>
|
||||
<ImageContextMenu
|
||||
fullsizeUri={image.fullsize}
|
||||
thumbUri={image.thumb}
|
||||
aspectRatio={aspect}
|
||||
borderRadius={tokens.borderRadius.md}
|
||||
onPreviewPress={openFromSingle}>
|
||||
<AutoSizedImage
|
||||
crop={
|
||||
rest.viewContext === PostEmbedViewContext.ThreadHighlighted
|
||||
? 'none'
|
||||
: rest.viewContext ===
|
||||
PostEmbedViewContext.FeedEmbedRecordWithMedia
|
||||
? 'square'
|
||||
: 'constrained'
|
||||
}
|
||||
image={image}
|
||||
onContainerRef={ref => {
|
||||
singleContainerRef.current = ref
|
||||
}}
|
||||
onDimsChange={dims => {
|
||||
singleDimsRef.current = dims
|
||||
}}
|
||||
onPress={(containerRef, dims) =>
|
||||
onPress(0, [containerRef], [dims])
|
||||
}
|
||||
onPressIn={() => onPressIn(0)}
|
||||
hideBadge={
|
||||
rest.viewContext ===
|
||||
PostEmbedViewContext.FeedEmbedRecordWithMedia
|
||||
}
|
||||
/>
|
||||
</ImageContextMenu>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user