Align composer video preview with in-feed embed (#10447)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,10 +5,10 @@ import {type ImagePickerAsset} from 'expo-image-picker'
|
|||||||
import {BlueskyVideoView} from '@bsky.app/video'
|
import {BlueskyVideoView} from '@bsky.app/video'
|
||||||
|
|
||||||
import {type CompressedVideo} from '#/lib/media/video/types'
|
import {type CompressedVideo} from '#/lib/media/video/types'
|
||||||
import {clamp} from '#/lib/numbers'
|
|
||||||
import {useAutoplayDisabled} from '#/state/preferences'
|
import {useAutoplayDisabled} from '#/state/preferences'
|
||||||
import {ExternalEmbedRemoveBtn} from '#/view/com/composer/ExternalEmbedRemoveBtn'
|
import {ExternalEmbedRemoveBtn} from '#/view/com/composer/ExternalEmbedRemoveBtn'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
|
import {ConstrainedImage} from '#/components/images/AutoSizedImage'
|
||||||
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
||||||
import {VideoTranscodeBackdrop} from './VideoTranscodeBackdrop'
|
import {VideoTranscodeBackdrop} from './VideoTranscodeBackdrop'
|
||||||
|
|
||||||
@@ -23,28 +23,29 @@ export function VideoPreview({
|
|||||||
isActivePost: boolean
|
isActivePost: boolean
|
||||||
clear: () => void
|
clear: () => void
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
|
||||||
const playerRef = useRef<BlueskyVideoView>(null)
|
const playerRef = useRef<BlueskyVideoView>(null)
|
||||||
const autoplayDisabled = useAutoplayDisabled()
|
const autoplayDisabled = useAutoplayDisabled()
|
||||||
let aspectRatio = asset.width / asset.height
|
|
||||||
|
|
||||||
if (isNaN(aspectRatio)) {
|
let aspectRatio: number | undefined
|
||||||
aspectRatio = 16 / 9
|
if (asset.width && asset.height) {
|
||||||
|
const raw = asset.width / asset.height
|
||||||
|
if (!Number.isNaN(raw)) {
|
||||||
|
aspectRatio = raw
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aspectRatio = clamp(aspectRatio, 1 / 1, 3 / 1)
|
let constrained: number | undefined
|
||||||
|
if (aspectRatio !== undefined) {
|
||||||
|
const ratio = 1 / 2 // max of 1:2 ratio in feeds
|
||||||
|
constrained = Math.max(aspectRatio, ratio)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View style={[a.pt_xs]}>
|
||||||
style={[
|
<ConstrainedImage
|
||||||
a.w_full,
|
aspectRatio={constrained || 1}
|
||||||
a.rounded_sm,
|
minMobileAspectRatio={14 / 9}>
|
||||||
{aspectRatio},
|
<View style={[a.flex_1, {backgroundColor: 'black'}]}>
|
||||||
a.overflow_hidden,
|
|
||||||
a.border,
|
|
||||||
t.atoms.border_contrast_low,
|
|
||||||
{backgroundColor: 'black'},
|
|
||||||
]}>
|
|
||||||
<View style={[a.absolute, a.inset_0]}>
|
<View style={[a.absolute, a.inset_0]}>
|
||||||
<VideoTranscodeBackdrop uri={asset.uri} />
|
<VideoTranscodeBackdrop uri={asset.uri} />
|
||||||
</View>
|
</View>
|
||||||
@@ -57,6 +58,7 @@ export function VideoPreview({
|
|||||||
source={{uri: video.uri}}
|
source={{uri: video.uri}}
|
||||||
accessibilityIgnoresInvertColors
|
accessibilityIgnoresInvertColors
|
||||||
cachePolicy="none"
|
cachePolicy="none"
|
||||||
|
contentFit="contain"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<BlueskyVideoView
|
<BlueskyVideoView
|
||||||
@@ -71,10 +73,13 @@ export function VideoPreview({
|
|||||||
)}
|
)}
|
||||||
<ExternalEmbedRemoveBtn onRemove={clear} />
|
<ExternalEmbedRemoveBtn onRemove={clear} />
|
||||||
{autoplayDisabled && (
|
{autoplayDisabled && (
|
||||||
<View style={[a.absolute, a.inset_0, a.justify_center, a.align_center]}>
|
<View
|
||||||
|
style={[a.absolute, a.inset_0, a.justify_center, a.align_center]}>
|
||||||
<PlayButtonIcon />
|
<PlayButtonIcon />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
</ConstrainedImage>
|
||||||
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,22 +4,21 @@ import {msg} from '@lingui/core/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {type CompressedVideo} from '#/lib/media/video/types'
|
import {type CompressedVideo} from '#/lib/media/video/types'
|
||||||
import {clamp} from '#/lib/numbers'
|
|
||||||
import {useAutoplayDisabled} from '#/state/preferences'
|
import {useAutoplayDisabled} from '#/state/preferences'
|
||||||
import {ExternalEmbedRemoveBtn} from '#/view/com/composer/ExternalEmbedRemoveBtn'
|
import {ExternalEmbedRemoveBtn} from '#/view/com/composer/ExternalEmbedRemoveBtn'
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
|
import {ConstrainedImage} from '#/components/images/AutoSizedImage'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
||||||
|
|
||||||
export function VideoPreview({
|
export function VideoPreview({
|
||||||
asset,
|
asset,
|
||||||
video,
|
video,
|
||||||
|
|
||||||
clear,
|
clear,
|
||||||
}: {
|
}: {
|
||||||
asset: ImagePickerAsset
|
asset: ImagePickerAsset
|
||||||
video: CompressedVideo
|
video: CompressedVideo
|
||||||
|
isActivePost: boolean
|
||||||
clear: () => void
|
clear: () => void
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
@@ -27,36 +26,37 @@ export function VideoPreview({
|
|||||||
// it's not possible using an img tag -sfn
|
// it's not possible using an img tag -sfn
|
||||||
const autoplayDisabled = useAutoplayDisabled()
|
const autoplayDisabled = useAutoplayDisabled()
|
||||||
|
|
||||||
let aspectRatio = asset.width / asset.height
|
let aspectRatio: number | undefined
|
||||||
|
if (asset.width && asset.height) {
|
||||||
if (isNaN(aspectRatio)) {
|
const raw = asset.width / asset.height
|
||||||
aspectRatio = 16 / 9
|
if (!Number.isNaN(raw)) {
|
||||||
|
aspectRatio = raw
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aspectRatio = clamp(aspectRatio, 1 / 1, 3 / 1)
|
let constrained: number | undefined
|
||||||
|
if (aspectRatio !== undefined) {
|
||||||
|
const ratio = 1 / 2 // max of 1:2 ratio in feeds
|
||||||
|
constrained = Math.max(aspectRatio, ratio)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View style={[a.pt_xs]}>
|
||||||
style={[
|
<ConstrainedImage
|
||||||
a.w_full,
|
aspectRatio={constrained || 1}
|
||||||
a.rounded_sm,
|
minMobileAspectRatio={14 / 9}>
|
||||||
{aspectRatio},
|
<View style={[a.flex_1, {backgroundColor: 'black'}]}>
|
||||||
a.overflow_hidden,
|
|
||||||
{backgroundColor: 'black'},
|
|
||||||
a.relative,
|
|
||||||
]}>
|
|
||||||
<ExternalEmbedRemoveBtn onRemove={clear} />
|
|
||||||
{video.mimeType === 'image/gif' ? (
|
{video.mimeType === 'image/gif' ? (
|
||||||
<img
|
<img
|
||||||
src={video.uri}
|
src={video.uri}
|
||||||
style={{width: '100%', height: '100%', objectFit: 'cover'}}
|
style={{width: '100%', height: '100%', objectFit: 'contain'}}
|
||||||
alt="GIF"
|
alt="GIF"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<video
|
<video
|
||||||
src={video.uri}
|
src={video.uri}
|
||||||
style={{width: '100%', height: '100%', objectFit: 'cover'}}
|
style={{width: '100%', height: '100%', objectFit: 'contain'}}
|
||||||
autoPlay={!autoplayDisabled}
|
autoPlay={!autoplayDisabled}
|
||||||
loop
|
loop
|
||||||
muted
|
muted
|
||||||
@@ -71,12 +71,20 @@ export function VideoPreview({
|
|||||||
/>
|
/>
|
||||||
{autoplayDisabled && (
|
{autoplayDisabled && (
|
||||||
<View
|
<View
|
||||||
style={[a.absolute, a.inset_0, a.justify_center, a.align_center]}>
|
style={[
|
||||||
|
a.absolute,
|
||||||
|
a.inset_0,
|
||||||
|
a.justify_center,
|
||||||
|
a.align_center,
|
||||||
|
]}>
|
||||||
<PlayButtonIcon />
|
<PlayButtonIcon />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<ExternalEmbedRemoveBtn onRemove={clear} />
|
||||||
|
</View>
|
||||||
|
</ConstrainedImage>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import {View} from 'react-native'
|
|||||||
import ProgressPie from 'react-native-progress/Pie'
|
import ProgressPie from 'react-native-progress/Pie'
|
||||||
import {type ImagePickerAsset} from 'expo-image-picker'
|
import {type ImagePickerAsset} from 'expo-image-picker'
|
||||||
|
|
||||||
import {clamp} from '#/lib/numbers'
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import {ConstrainedImage} from '#/components/images/AutoSizedImage'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
import {ExternalEmbedRemoveBtn} from '../ExternalEmbedRemoveBtn'
|
import {ExternalEmbedRemoveBtn} from '../ExternalEmbedRemoveBtn'
|
||||||
import {VideoTranscodeBackdrop} from './VideoTranscodeBackdrop'
|
import {VideoTranscodeBackdrop} from './VideoTranscodeBackdrop'
|
||||||
@@ -22,22 +22,31 @@ export function VideoTranscodeProgress({
|
|||||||
|
|
||||||
if (IS_WEB) return null
|
if (IS_WEB) return null
|
||||||
|
|
||||||
let aspectRatio = asset.width / asset.height
|
let aspectRatio: number | undefined
|
||||||
|
if (asset.width && asset.height) {
|
||||||
if (isNaN(aspectRatio)) {
|
const raw = asset.width / asset.height
|
||||||
aspectRatio = 16 / 9
|
if (!Number.isNaN(raw)) {
|
||||||
|
aspectRatio = raw
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aspectRatio = clamp(aspectRatio, 1 / 1, 3 / 1)
|
let constrained: number | undefined
|
||||||
|
if (aspectRatio !== undefined) {
|
||||||
|
const ratio = 1 / 2 // max of 1:2 ratio in feeds
|
||||||
|
constrained = Math.max(aspectRatio, ratio)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<View style={[a.pt_xs]}>
|
||||||
|
<ConstrainedImage
|
||||||
|
aspectRatio={constrained || 1}
|
||||||
|
minMobileAspectRatio={14 / 9}>
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
a.w_full,
|
a.flex_1,
|
||||||
t.atoms.bg_contrast_50,
|
t.atoms.bg_contrast_50,
|
||||||
a.rounded_md,
|
a.rounded_md,
|
||||||
a.overflow_hidden,
|
a.overflow_hidden,
|
||||||
{aspectRatio},
|
|
||||||
]}>
|
]}>
|
||||||
<VideoTranscodeBackdrop uri={asset.uri} />
|
<VideoTranscodeBackdrop uri={asset.uri} />
|
||||||
<View
|
<View
|
||||||
@@ -59,5 +68,7 @@ export function VideoTranscodeProgress({
|
|||||||
</View>
|
</View>
|
||||||
<ExternalEmbedRemoveBtn onRemove={clear} />
|
<ExternalEmbedRemoveBtn onRemove={clear} />
|
||||||
</View>
|
</View>
|
||||||
|
</ConstrainedImage>
|
||||||
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user