[GIFs] Restore default alt text (#3893)
* restore default alt text * factor out gif alt logic + enable require alt text setting * rm console.log * don't prefill input + esc handling * typo * Nits * shorten user alt prefix * Remove unnecessary condition, rename for clarity * Add comment --------- Co-authored-by: Dan Abramov <dan.abramov@gmail.com>zio/stable
parent
77e6c75a2c
commit
7d72dfb1cb
|
@ -0,0 +1,36 @@
|
||||||
|
// Kind of a hack. We needed some way to distinguish these.
|
||||||
|
const USER_ALT_PREFIX = 'Alt: '
|
||||||
|
const DEFAULT_ALT_PREFIX = 'ALT: '
|
||||||
|
|
||||||
|
export function createGIFDescription(
|
||||||
|
tenorDescription: string,
|
||||||
|
preferredAlt: string = '',
|
||||||
|
) {
|
||||||
|
preferredAlt = preferredAlt.trim()
|
||||||
|
if (preferredAlt !== '') {
|
||||||
|
return USER_ALT_PREFIX + preferredAlt
|
||||||
|
} else {
|
||||||
|
return DEFAULT_ALT_PREFIX + tenorDescription
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseAltFromGIFDescription(description: string): {
|
||||||
|
isPreferred: boolean
|
||||||
|
alt: string
|
||||||
|
} {
|
||||||
|
if (description.startsWith(USER_ALT_PREFIX)) {
|
||||||
|
return {
|
||||||
|
isPreferred: true,
|
||||||
|
alt: description.replace(USER_ALT_PREFIX, ''),
|
||||||
|
}
|
||||||
|
} else if (description.startsWith(DEFAULT_ALT_PREFIX)) {
|
||||||
|
return {
|
||||||
|
isPreferred: false,
|
||||||
|
alt: description.replace(DEFAULT_ALT_PREFIX, ''),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
isPreferred: false,
|
||||||
|
alt: description,
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,10 @@ import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
|
|
||||||
|
import {
|
||||||
|
createGIFDescription,
|
||||||
|
parseAltFromGIFDescription,
|
||||||
|
} from '#/lib/gif-alt-text'
|
||||||
import {LikelyType} from '#/lib/link-meta/link-meta'
|
import {LikelyType} from '#/lib/link-meta/link-meta'
|
||||||
import {logEvent} from '#/lib/statsig/statsig'
|
import {logEvent} from '#/lib/statsig/statsig'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
|
@ -211,11 +215,25 @@ export const ComposePost = observer(function ComposePost({
|
||||||
[gallery, track],
|
[gallery, track],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const isAltTextRequiredAndMissing = useMemo(() => {
|
||||||
|
if (!requireAltTextEnabled) return false
|
||||||
|
|
||||||
|
if (gallery.needsAltText) return true
|
||||||
|
if (extGif) {
|
||||||
|
if (!extLink?.meta?.description) return true
|
||||||
|
|
||||||
|
const parsedAlt = parseAltFromGIFDescription(extLink.meta.description)
|
||||||
|
if (!parsedAlt.isPreferred) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, [gallery.needsAltText, extLink, extGif, requireAltTextEnabled])
|
||||||
|
|
||||||
const onPressPublish = async () => {
|
const onPressPublish = async () => {
|
||||||
if (isProcessing || graphemeLength > MAX_GRAPHEME_LENGTH) {
|
if (isProcessing || graphemeLength > MAX_GRAPHEME_LENGTH) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (requireAltTextEnabled && gallery.needsAltText) {
|
|
||||||
|
if (isAltTextRequiredAndMissing) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,10 +316,8 @@ export const ComposePost = observer(function ComposePost({
|
||||||
}
|
}
|
||||||
|
|
||||||
const canPost = useMemo(
|
const canPost = useMemo(
|
||||||
() =>
|
() => graphemeLength <= MAX_GRAPHEME_LENGTH && !isAltTextRequiredAndMissing,
|
||||||
graphemeLength <= MAX_GRAPHEME_LENGTH &&
|
[graphemeLength, isAltTextRequiredAndMissing],
|
||||||
(!requireAltTextEnabled || !gallery.needsAltText),
|
|
||||||
[graphemeLength, requireAltTextEnabled, gallery.needsAltText],
|
|
||||||
)
|
)
|
||||||
const selectTextInputPlaceholder = replyTo
|
const selectTextInputPlaceholder = replyTo
|
||||||
? _(msg`Write your reply`)
|
? _(msg`Write your reply`)
|
||||||
|
@ -328,7 +344,7 @@ export const ComposePost = observer(function ComposePost({
|
||||||
image: gif.media_formats.preview.url,
|
image: gif.media_formats.preview.url,
|
||||||
likelyType: LikelyType.HTML,
|
likelyType: LikelyType.HTML,
|
||||||
title: gif.content_description,
|
title: gif.content_description,
|
||||||
description: '',
|
description: createGIFDescription(gif.content_description),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
setExtGif(gif)
|
setExtGif(gif)
|
||||||
|
@ -343,11 +359,11 @@ export const ComposePost = observer(function ComposePost({
|
||||||
? {
|
? {
|
||||||
...ext,
|
...ext,
|
||||||
meta: {
|
meta: {
|
||||||
...ext?.meta,
|
...ext.meta,
|
||||||
description:
|
description: createGIFDescription(
|
||||||
altText.trim().length === 0
|
ext.meta.title ?? '',
|
||||||
? ''
|
altText,
|
||||||
: `Alt text: ${altText.trim()}`,
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: ext,
|
: ext,
|
||||||
|
@ -433,7 +449,7 @@ export const ComposePost = observer(function ComposePost({
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
{requireAltTextEnabled && gallery.needsAltText && (
|
{isAltTextRequiredAndMissing && (
|
||||||
<View style={[styles.reminderLine, pal.viewLight]}>
|
<View style={[styles.reminderLine, pal.viewLight]}>
|
||||||
<View style={styles.errorIcon}>
|
<View style={styles.errorIcon}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {ExternalEmbedDraft} from '#/lib/api'
|
import {ExternalEmbedDraft} from '#/lib/api'
|
||||||
import {HITSLOP_10, MAX_ALT_TEXT} from '#/lib/constants'
|
import {HITSLOP_10, MAX_ALT_TEXT} from '#/lib/constants'
|
||||||
|
import {parseAltFromGIFDescription} from '#/lib/gif-alt-text'
|
||||||
import {
|
import {
|
||||||
EmbedPlayerParams,
|
EmbedPlayerParams,
|
||||||
parseEmbedPlayerFromUrl,
|
parseEmbedPlayerFromUrl,
|
||||||
|
@ -59,6 +60,7 @@ export function GifAltText({
|
||||||
|
|
||||||
if (!gif || !params) return null
|
if (!gif || !params) return null
|
||||||
|
|
||||||
|
const parsedAlt = parseAltFromGIFDescription(link.description)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
|
@ -80,7 +82,7 @@ export function GifAltText({
|
||||||
a.align_center,
|
a.align_center,
|
||||||
{backgroundColor: 'rgba(0, 0, 0, 0.75)'},
|
{backgroundColor: 'rgba(0, 0, 0, 0.75)'},
|
||||||
]}>
|
]}>
|
||||||
{link.description ? (
|
{parsedAlt.isPreferred ? (
|
||||||
<Check size="xs" fill={t.palette.white} style={a.ml_xs} />
|
<Check size="xs" fill={t.palette.white} style={a.ml_xs} />
|
||||||
) : (
|
) : (
|
||||||
<Plus size="sm" fill={t.palette.white} />
|
<Plus size="sm" fill={t.palette.white} />
|
||||||
|
@ -102,7 +104,7 @@ export function GifAltText({
|
||||||
onSubmit={onPressSubmit}
|
onSubmit={onPressSubmit}
|
||||||
link={link}
|
link={link}
|
||||||
params={params}
|
params={params}
|
||||||
initalValue={link.description.replace('Alt text: ', '')}
|
initialValue={parsedAlt.isPreferred ? parsedAlt.alt : ''}
|
||||||
key={link.uri}
|
key={link.uri}
|
||||||
/>
|
/>
|
||||||
</Dialog.Outer>
|
</Dialog.Outer>
|
||||||
|
@ -114,15 +116,16 @@ function AltTextInner({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
link,
|
link,
|
||||||
params,
|
params,
|
||||||
initalValue,
|
initialValue: initalValue,
|
||||||
}: {
|
}: {
|
||||||
onSubmit: (text: string) => void
|
onSubmit: (text: string) => void
|
||||||
link: AppBskyEmbedExternal.ViewExternal
|
link: AppBskyEmbedExternal.ViewExternal
|
||||||
params: EmbedPlayerParams
|
params: EmbedPlayerParams
|
||||||
initalValue: string
|
initialValue: string
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const [altText, setAltText] = useState(initalValue)
|
const [altText, setAltText] = useState(initalValue)
|
||||||
|
const control = Dialog.useDialogContext()
|
||||||
|
|
||||||
const onPressSubmit = useCallback(() => {
|
const onPressSubmit = useCallback(() => {
|
||||||
onSubmit(altText)
|
onSubmit(altText)
|
||||||
|
@ -147,6 +150,11 @@ function AltTextInner({
|
||||||
multiline
|
multiline
|
||||||
numberOfLines={3}
|
numberOfLines={3}
|
||||||
autoFocus
|
autoFocus
|
||||||
|
onKeyPress={({nativeEvent}) => {
|
||||||
|
if (nativeEvent.key === 'Escape') {
|
||||||
|
control.close()
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</TextField.Root>
|
</TextField.Root>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {HITSLOP_10} from '#/lib/constants'
|
import {HITSLOP_10} from '#/lib/constants'
|
||||||
|
import {parseAltFromGIFDescription} from '#/lib/gif-alt-text'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isWeb} from '#/platform/detection'
|
||||||
import {EmbedPlayerParams} from 'lib/strings/embed-player'
|
import {EmbedPlayerParams} from 'lib/strings/embed-player'
|
||||||
import {useAutoplayDisabled} from 'state/preferences'
|
import {useAutoplayDisabled} from 'state/preferences'
|
||||||
|
@ -116,6 +117,11 @@ export function GifEmbed({
|
||||||
playerRef.current?.toggleAsync()
|
playerRef.current?.toggleAsync()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const parsedAlt = React.useMemo(
|
||||||
|
() => parseAltFromGIFDescription(link.description),
|
||||||
|
[link],
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={[a.rounded_sm, a.overflow_hidden, a.mt_sm, {maxWidth: '100%'}]}>
|
style={[a.rounded_sm, a.overflow_hidden, a.mt_sm, {maxWidth: '100%'}]}>
|
||||||
|
@ -140,12 +146,10 @@ export function GifEmbed({
|
||||||
onPlayerStateChange={onPlayerStateChange}
|
onPlayerStateChange={onPlayerStateChange}
|
||||||
ref={playerRef}
|
ref={playerRef}
|
||||||
accessibilityHint={_(msg`Animated GIF`)}
|
accessibilityHint={_(msg`Animated GIF`)}
|
||||||
accessibilityLabel={link.description.replace('Alt text: ', '')}
|
accessibilityLabel={parsedAlt.alt}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!hideAlt && link.description.startsWith('Alt text: ') && (
|
{!hideAlt && parsedAlt.isPreferred && <AltText text={parsedAlt.alt} />}
|
||||||
<AltText text={link.description.replace('Alt text: ', '')} />
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue