align alt text behaviour between gif types (#9822)
This commit is contained in:
@@ -1,25 +1,14 @@
|
|||||||
import {useRef, useState} from 'react'
|
import {useRef, useState} from 'react'
|
||||||
import {
|
import {type StyleProp, View, type ViewStyle} from 'react-native'
|
||||||
type StyleProp,
|
import {msg} from '@lingui/macro'
|
||||||
StyleSheet,
|
|
||||||
TouchableOpacity,
|
|
||||||
View,
|
|
||||||
type ViewStyle,
|
|
||||||
} from 'react-native'
|
|
||||||
import {msg, Trans} from '@lingui/macro'
|
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {HITSLOP_20} from '#/lib/constants'
|
|
||||||
import {clamp} from '#/lib/numbers'
|
import {clamp} from '#/lib/numbers'
|
||||||
import {type EmbedPlayerParams} from '#/lib/strings/embed-player'
|
import {type EmbedPlayerParams} from '#/lib/strings/embed-player'
|
||||||
import {useAutoplayDisabled} from '#/state/preferences'
|
import {useAutoplayDisabled} from '#/state/preferences'
|
||||||
import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge'
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Fill} from '#/components/Fill'
|
import {Fill} from '#/components/Fill'
|
||||||
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
||||||
import * as Prompt from '#/components/Prompt'
|
|
||||||
import {Text} from '#/components/Typography'
|
|
||||||
import {IS_WEB} from '#/env'
|
|
||||||
import {GifView} from '../../../../../modules/expo-bluesky-gif-view'
|
import {GifView} from '../../../../../modules/expo-bluesky-gif-view'
|
||||||
import {type GifViewStateChangeEvent} from '../../../../../modules/expo-bluesky-gif-view/src/GifView.types'
|
import {type GifViewStateChangeEvent} from '../../../../../modules/expo-bluesky-gif-view/src/GifView.types'
|
||||||
import {GifPresentationControls} from '../VideoEmbed/GifPresentationControls'
|
import {GifPresentationControls} from '../VideoEmbed/GifPresentationControls'
|
||||||
@@ -94,6 +83,7 @@ export function GifEmbed({
|
|||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
isPlaying={playerState.isPlaying}
|
isPlaying={playerState.isPlaying}
|
||||||
isLoading={!playerState.isLoaded}
|
isLoading={!playerState.isLoaded}
|
||||||
|
altText={!hideAlt && isPreferredAltText ? altText : undefined}
|
||||||
/>
|
/>
|
||||||
<GifView
|
<GifView
|
||||||
source={params.playerUri}
|
source={params.playerUri}
|
||||||
@@ -115,68 +105,7 @@ export function GifEmbed({
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!hideAlt && isPreferredAltText && <AltText text={altText} />}
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function AltText({text}: {text: string}) {
|
|
||||||
const control = Prompt.usePromptControl()
|
|
||||||
const largeAltBadge = useLargeAltBadgeEnabled()
|
|
||||||
|
|
||||||
const {_} = useLingui()
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<TouchableOpacity
|
|
||||||
testID="altTextButton"
|
|
||||||
accessibilityRole="button"
|
|
||||||
accessibilityLabel={_(msg`Show alt text`)}
|
|
||||||
accessibilityHint=""
|
|
||||||
hitSlop={HITSLOP_20}
|
|
||||||
onPress={control.open}
|
|
||||||
style={styles.altContainer}>
|
|
||||||
<Text
|
|
||||||
style={[styles.alt, largeAltBadge && a.text_xs]}
|
|
||||||
accessible={false}>
|
|
||||||
<Trans>ALT</Trans>
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<Prompt.Outer control={control}>
|
|
||||||
<Prompt.Content>
|
|
||||||
<Prompt.TitleText>
|
|
||||||
<Trans>Alt Text</Trans>
|
|
||||||
</Prompt.TitleText>
|
|
||||||
<Prompt.DescriptionText selectable>{text}</Prompt.DescriptionText>
|
|
||||||
</Prompt.Content>
|
|
||||||
<Prompt.Actions>
|
|
||||||
<Prompt.Action
|
|
||||||
onPress={() => control.close()}
|
|
||||||
cta={_(msg`Close`)}
|
|
||||||
color="secondary"
|
|
||||||
/>
|
|
||||||
</Prompt.Actions>
|
|
||||||
</Prompt.Outer>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
altContainer: {
|
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
|
||||||
borderRadius: 6,
|
|
||||||
paddingHorizontal: IS_WEB ? 8 : 6,
|
|
||||||
paddingVertical: IS_WEB ? 6 : 3,
|
|
||||||
position: 'absolute',
|
|
||||||
// Related to margin/gap hack. This keeps the alt label in the same position
|
|
||||||
// on all platforms
|
|
||||||
right: IS_WEB ? 8 : 5,
|
|
||||||
bottom: IS_WEB ? 8 : 5,
|
|
||||||
zIndex: 2,
|
|
||||||
},
|
|
||||||
alt: {
|
|
||||||
color: 'white',
|
|
||||||
fontSize: IS_WEB ? 10 : 7,
|
|
||||||
fontWeight: '600',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import {Pressable, StyleSheet, View} from 'react-native'
|
import {Pressable, StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {HITSLOP_20} from '#/lib/constants'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Fill} from '#/components/Fill'
|
import {Fill} from '#/components/Fill'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
|
import * as Prompt from '#/components/Prompt'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
||||||
|
|
||||||
@@ -12,10 +14,12 @@ export function GifPresentationControls({
|
|||||||
onPress,
|
onPress,
|
||||||
isPlaying,
|
isPlaying,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
altText,
|
||||||
}: {
|
}: {
|
||||||
onPress: () => void
|
onPress: () => void
|
||||||
isPlaying: boolean
|
isPlaying: boolean
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
|
altText?: string
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
@@ -60,6 +64,46 @@ export function GifPresentationControls({
|
|||||||
<Trans>GIF</Trans>
|
<Trans>GIF</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
{altText && <AltBadge text={altText} />}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function AltBadge({text}: {text: string}) {
|
||||||
|
const control = Prompt.usePromptControl()
|
||||||
|
const {_} = useLingui()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TouchableOpacity
|
||||||
|
testID="altTextButton"
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel={_(msg`Show alt text`)}
|
||||||
|
accessibilityHint=""
|
||||||
|
hitSlop={HITSLOP_20}
|
||||||
|
onPress={control.open}
|
||||||
|
style={styles.altBadgeContainer}>
|
||||||
|
<Text
|
||||||
|
style={[{color: 'white'}, a.font_bold, a.text_xs]}
|
||||||
|
accessible={false}>
|
||||||
|
<Trans>ALT</Trans>
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<Prompt.Outer control={control}>
|
||||||
|
<Prompt.Content>
|
||||||
|
<Prompt.TitleText>
|
||||||
|
<Trans>Alt Text</Trans>
|
||||||
|
</Prompt.TitleText>
|
||||||
|
<Prompt.DescriptionText selectable>{text}</Prompt.DescriptionText>
|
||||||
|
</Prompt.Content>
|
||||||
|
<Prompt.Actions>
|
||||||
|
<Prompt.Action
|
||||||
|
onPress={() => control.close()}
|
||||||
|
cta={_(msg`Close`)}
|
||||||
|
color="secondary"
|
||||||
|
/>
|
||||||
|
</Prompt.Actions>
|
||||||
|
</Prompt.Outer>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -75,4 +119,14 @@ const styles = StyleSheet.create({
|
|||||||
bottom: 6,
|
bottom: 6,
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
},
|
},
|
||||||
|
altBadgeContainer: {
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||||||
|
borderRadius: 6,
|
||||||
|
paddingHorizontal: 4,
|
||||||
|
paddingVertical: 3,
|
||||||
|
position: 'absolute',
|
||||||
|
right: 6,
|
||||||
|
bottom: 6,
|
||||||
|
zIndex: 2,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ export function VideoEmbedInnerNative({
|
|||||||
}}
|
}}
|
||||||
isPlaying={isPlaying}
|
isPlaying={isPlaying}
|
||||||
isLoading={false}
|
isLoading={false}
|
||||||
|
altText={embed.alt}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<VideoPresentationControls
|
<VideoPresentationControls
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ export function VideoEmbedInnerWeb({
|
|||||||
fullscreenRef={containerRef}
|
fullscreenRef={containerRef}
|
||||||
hasSubtitleTrack={hasSubtitleTrack}
|
hasSubtitleTrack={hasSubtitleTrack}
|
||||||
isGif={embed.presentation === 'gif'}
|
isGif={embed.presentation === 'gif'}
|
||||||
|
altText={embed.alt}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export function Controls({
|
|||||||
hlsLoading,
|
hlsLoading,
|
||||||
hasSubtitleTrack,
|
hasSubtitleTrack,
|
||||||
isGif,
|
isGif,
|
||||||
|
altText,
|
||||||
}: {
|
}: {
|
||||||
videoRef: React.RefObject<HTMLVideoElement | null>
|
videoRef: React.RefObject<HTMLVideoElement | null>
|
||||||
hlsRef: React.RefObject<Hls | undefined | null>
|
hlsRef: React.RefObject<Hls | undefined | null>
|
||||||
@@ -58,6 +59,7 @@ export function Controls({
|
|||||||
hlsLoading: boolean
|
hlsLoading: boolean
|
||||||
hasSubtitleTrack: boolean
|
hasSubtitleTrack: boolean
|
||||||
isGif: boolean
|
isGif: boolean
|
||||||
|
altText?: string
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
play,
|
play,
|
||||||
@@ -296,6 +298,7 @@ export function Controls({
|
|||||||
isPlaying={playing}
|
isPlaying={playing}
|
||||||
isLoading={showSpinner}
|
isLoading={showSpinner}
|
||||||
onPress={onPressPlayPause}
|
onPress={onPressPlayPause}
|
||||||
|
altText={altText}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user