video player gif presentation style
This commit is contained in:
@@ -0,0 +1,85 @@
|
|||||||
|
import {Pressable, StyleSheet, View} from 'react-native'
|
||||||
|
import {msg, Trans} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import {Fill} from '#/components/Fill'
|
||||||
|
import {Loader} from '#/components/Loader'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
||||||
|
|
||||||
|
export function GifPresentationControls({
|
||||||
|
onPress,
|
||||||
|
isPlaying,
|
||||||
|
isLoading,
|
||||||
|
}: {
|
||||||
|
onPress: () => void
|
||||||
|
isPlaying: boolean
|
||||||
|
isLoading?: boolean
|
||||||
|
}) {
|
||||||
|
const {_} = useLingui()
|
||||||
|
const t = useTheme()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Pressable
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityHint={_(msg`Plays or pauses the GIF`)}
|
||||||
|
accessibilityLabel={isPlaying ? _(msg`Pause`) : _(msg`Play`)}
|
||||||
|
style={[
|
||||||
|
a.absolute,
|
||||||
|
a.align_center,
|
||||||
|
a.justify_center,
|
||||||
|
a.inset_0,
|
||||||
|
a.w_full,
|
||||||
|
a.h_full,
|
||||||
|
{
|
||||||
|
zIndex: 2,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
onPress={onPress}>
|
||||||
|
{isLoading ? (
|
||||||
|
<View style={[a.align_center, a.justify_center]}>
|
||||||
|
<Loader size="xl" />
|
||||||
|
</View>
|
||||||
|
) : !isPlaying ? (
|
||||||
|
<PlayButtonIcon />
|
||||||
|
) : undefined}
|
||||||
|
</Pressable>
|
||||||
|
{!isPlaying && (
|
||||||
|
<Fill
|
||||||
|
style={[
|
||||||
|
t.name === 'light' ? t.atoms.bg_contrast_975 : t.atoms.bg,
|
||||||
|
{
|
||||||
|
opacity: 0.3,
|
||||||
|
zIndex: 1,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<View style={styles.gifBadgeContainer}>
|
||||||
|
<Text style={styles.gifBadge}>
|
||||||
|
<Trans>GIF</Trans>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
gifBadgeContainer: {
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||||||
|
borderRadius: 6,
|
||||||
|
paddingHorizontal: 6,
|
||||||
|
paddingVertical: 3,
|
||||||
|
position: 'absolute',
|
||||||
|
right: 5,
|
||||||
|
bottom: 5,
|
||||||
|
zIndex: 2,
|
||||||
|
},
|
||||||
|
gifBadge: {
|
||||||
|
color: 'white',
|
||||||
|
fontSize: 7,
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -15,6 +15,7 @@ import {Play_Filled_Corner0_Rounded as PlayIcon} from '#/components/icons/Play'
|
|||||||
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
|
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
|
||||||
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
||||||
import {useVideoMuteState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
|
import {useVideoMuteState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
|
||||||
|
import {GifPresentationControls} from '../GifPresentationControls'
|
||||||
import {TimeIndicator} from './TimeIndicator'
|
import {TimeIndicator} from './TimeIndicator'
|
||||||
|
|
||||||
export function VideoEmbedInnerNative({
|
export function VideoEmbedInnerNative({
|
||||||
@@ -50,6 +51,8 @@ export function VideoEmbedInnerNative({
|
|||||||
throw new Error(error)
|
throw new Error(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isGif = embed.presentation === 'gif'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[a.flex_1, a.relative]}>
|
<View style={[a.flex_1, a.relative]}>
|
||||||
<BlueskyVideoView
|
<BlueskyVideoView
|
||||||
@@ -82,25 +85,35 @@ export function VideoEmbedInnerNative({
|
|||||||
}
|
}
|
||||||
accessibilityHint=""
|
accessibilityHint=""
|
||||||
/>
|
/>
|
||||||
<VideoControls
|
{isGif ? (
|
||||||
enterFullscreen={() => {
|
<GifPresentationControls
|
||||||
videoRef.current?.enterFullscreen(true)
|
onPress={() => {
|
||||||
}}
|
videoRef.current?.togglePlayback()
|
||||||
toggleMuted={() => {
|
}}
|
||||||
videoRef.current?.toggleMuted()
|
isPlaying={isPlaying}
|
||||||
}}
|
isLoading={false}
|
||||||
togglePlayback={() => {
|
/>
|
||||||
videoRef.current?.togglePlayback()
|
) : (
|
||||||
}}
|
<VideoPresentationControls
|
||||||
isPlaying={isPlaying}
|
enterFullscreen={() => {
|
||||||
timeRemaining={timeRemaining}
|
videoRef.current?.enterFullscreen(true)
|
||||||
/>
|
}}
|
||||||
|
toggleMuted={() => {
|
||||||
|
videoRef.current?.toggleMuted()
|
||||||
|
}}
|
||||||
|
togglePlayback={() => {
|
||||||
|
videoRef.current?.togglePlayback()
|
||||||
|
}}
|
||||||
|
isPlaying={isPlaying}
|
||||||
|
timeRemaining={timeRemaining}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<MediaInsetBorder />
|
<MediaInsetBorder />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function VideoControls({
|
function VideoPresentationControls({
|
||||||
enterFullscreen,
|
enterFullscreen,
|
||||||
toggleMuted,
|
toggleMuted,
|
||||||
togglePlayback,
|
togglePlayback,
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ export function VideoEmbedInnerWeb({
|
|||||||
onScreen={onScreen}
|
onScreen={onScreen}
|
||||||
fullscreenRef={containerRef}
|
fullscreenRef={containerRef}
|
||||||
hasSubtitleTrack={hasSubtitleTrack}
|
hasSubtitleTrack={hasSubtitleTrack}
|
||||||
|
isGif={embed.presentation === 'gif'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {Play_Filled_Corner0_Rounded as PlayIcon} from '#/components/icons/Play'
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {IS_WEB_MOBILE_IOS, IS_WEB_TOUCH_DEVICE} from '#/env'
|
import {IS_WEB_MOBILE_IOS, IS_WEB_TOUCH_DEVICE} from '#/env'
|
||||||
|
import {GifPresentationControls} from '../../GifPresentationControls'
|
||||||
import {TimeIndicator} from '../TimeIndicator'
|
import {TimeIndicator} from '../TimeIndicator'
|
||||||
import {ControlButton} from './ControlButton'
|
import {ControlButton} from './ControlButton'
|
||||||
import {Scrubber} from './Scrubber'
|
import {Scrubber} from './Scrubber'
|
||||||
@@ -44,6 +45,7 @@ export function Controls({
|
|||||||
fullscreenRef,
|
fullscreenRef,
|
||||||
hlsLoading,
|
hlsLoading,
|
||||||
hasSubtitleTrack,
|
hasSubtitleTrack,
|
||||||
|
isGif,
|
||||||
}: {
|
}: {
|
||||||
videoRef: React.RefObject<HTMLVideoElement | null>
|
videoRef: React.RefObject<HTMLVideoElement | null>
|
||||||
hlsRef: React.RefObject<Hls | undefined | null>
|
hlsRef: React.RefObject<Hls | undefined | null>
|
||||||
@@ -55,6 +57,7 @@ export function Controls({
|
|||||||
fullscreenRef: React.RefObject<HTMLDivElement | null>
|
fullscreenRef: React.RefObject<HTMLDivElement | null>
|
||||||
hlsLoading: boolean
|
hlsLoading: boolean
|
||||||
hasSubtitleTrack: boolean
|
hasSubtitleTrack: boolean
|
||||||
|
isGif: boolean
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
play,
|
play,
|
||||||
@@ -287,6 +290,16 @@ export function Controls({
|
|||||||
((focused || autoplayDisabled) && !playing) ||
|
((focused || autoplayDisabled) && !playing) ||
|
||||||
(interactingViaKeypress ? hasFocus : hovered)
|
(interactingViaKeypress ? hasFocus : hovered)
|
||||||
|
|
||||||
|
if (isGif) {
|
||||||
|
return (
|
||||||
|
<GifPresentationControls
|
||||||
|
isPlaying={playing}
|
||||||
|
isLoading={showSpinner}
|
||||||
|
onPress={onPressPlayPause}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ export function VideoEmbed({embed}: {embed: AppBskyEmbedVideo.View}) {
|
|||||||
setActive={setActive}
|
setActive={setActive}
|
||||||
onScreen={onScreen}
|
onScreen={onScreen}
|
||||||
lastKnownTime={lastKnownTime}
|
lastKnownTime={lastKnownTime}
|
||||||
|
isGif={embed.presentation === 'gif'}
|
||||||
/>
|
/>
|
||||||
</OnlyNearScreen>
|
</OnlyNearScreen>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
|
|||||||
Reference in New Issue
Block a user