Bluesky app fork with some witchin' additions 💫

align alt text behaviour between gif types (#9822)

authored by samuel.fm and committed by

GitHub e6c4a539 965b17ff

+63 -75
+3 -74
src/components/Post/Embed/ExternalEmbed/Gif.tsx
··· 1 import {useRef, useState} from 'react' 2 - import { 3 - type StyleProp, 4 - StyleSheet, 5 - TouchableOpacity, 6 - View, 7 - type ViewStyle, 8 - } from 'react-native' 9 - import {msg, Trans} from '@lingui/macro' 10 import {useLingui} from '@lingui/react' 11 12 - import {HITSLOP_20} from '#/lib/constants' 13 import {clamp} from '#/lib/numbers' 14 import {type EmbedPlayerParams} from '#/lib/strings/embed-player' 15 import {useAutoplayDisabled} from '#/state/preferences' 16 - import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge' 17 import {atoms as a, useTheme} from '#/alf' 18 import {Fill} from '#/components/Fill' 19 import {MediaInsetBorder} from '#/components/MediaInsetBorder' 20 - import * as Prompt from '#/components/Prompt' 21 - import {Text} from '#/components/Typography' 22 - import {IS_WEB} from '#/env' 23 import {GifView} from '../../../../../modules/expo-bluesky-gif-view' 24 import {type GifViewStateChangeEvent} from '../../../../../modules/expo-bluesky-gif-view/src/GifView.types' 25 import {GifPresentationControls} from '../VideoEmbed/GifPresentationControls' ··· 94 onPress={onPress} 95 isPlaying={playerState.isPlaying} 96 isLoading={!playerState.isLoaded} 97 /> 98 <GifView 99 source={params.playerUri} ··· 115 ]} 116 /> 117 )} 118 - {!hideAlt && isPreferredAltText && <AltText text={altText} />} 119 </View> 120 </View> 121 ) 122 } 123 - 124 - function AltText({text}: {text: string}) { 125 - const control = Prompt.usePromptControl() 126 - const largeAltBadge = useLargeAltBadgeEnabled() 127 - 128 - const {_} = useLingui() 129 - return ( 130 - <> 131 - <TouchableOpacity 132 - testID="altTextButton" 133 - accessibilityRole="button" 134 - accessibilityLabel={_(msg`Show alt text`)} 135 - accessibilityHint="" 136 - hitSlop={HITSLOP_20} 137 - onPress={control.open} 138 - style={styles.altContainer}> 139 - <Text 140 - style={[styles.alt, largeAltBadge && a.text_xs]} 141 - accessible={false}> 142 - <Trans>ALT</Trans> 143 - </Text> 144 - </TouchableOpacity> 145 - <Prompt.Outer control={control}> 146 - <Prompt.Content> 147 - <Prompt.TitleText> 148 - <Trans>Alt Text</Trans> 149 - </Prompt.TitleText> 150 - <Prompt.DescriptionText selectable>{text}</Prompt.DescriptionText> 151 - </Prompt.Content> 152 - <Prompt.Actions> 153 - <Prompt.Action 154 - onPress={() => control.close()} 155 - cta={_(msg`Close`)} 156 - color="secondary" 157 - /> 158 - </Prompt.Actions> 159 - </Prompt.Outer> 160 - </> 161 - ) 162 - } 163 - 164 - const styles = StyleSheet.create({ 165 - altContainer: { 166 - backgroundColor: 'rgba(0, 0, 0, 0.75)', 167 - borderRadius: 6, 168 - paddingHorizontal: IS_WEB ? 8 : 6, 169 - paddingVertical: IS_WEB ? 6 : 3, 170 - position: 'absolute', 171 - // Related to margin/gap hack. This keeps the alt label in the same position 172 - // on all platforms 173 - right: IS_WEB ? 8 : 5, 174 - bottom: IS_WEB ? 8 : 5, 175 - zIndex: 2, 176 - }, 177 - alt: { 178 - color: 'white', 179 - fontSize: IS_WEB ? 10 : 7, 180 - fontWeight: '600', 181 - }, 182 - })
··· 1 import {useRef, useState} from 'react' 2 + import {type StyleProp, View, type ViewStyle} from 'react-native' 3 + import {msg} from '@lingui/macro' 4 import {useLingui} from '@lingui/react' 5 6 import {clamp} from '#/lib/numbers' 7 import {type EmbedPlayerParams} from '#/lib/strings/embed-player' 8 import {useAutoplayDisabled} from '#/state/preferences' 9 import {atoms as a, useTheme} from '#/alf' 10 import {Fill} from '#/components/Fill' 11 import {MediaInsetBorder} from '#/components/MediaInsetBorder' 12 import {GifView} from '../../../../../modules/expo-bluesky-gif-view' 13 import {type GifViewStateChangeEvent} from '../../../../../modules/expo-bluesky-gif-view/src/GifView.types' 14 import {GifPresentationControls} from '../VideoEmbed/GifPresentationControls' ··· 83 onPress={onPress} 84 isPlaying={playerState.isPlaying} 85 isLoading={!playerState.isLoaded} 86 + altText={!hideAlt && isPreferredAltText ? altText : undefined} 87 /> 88 <GifView 89 source={params.playerUri} ··· 105 ]} 106 /> 107 )} 108 </View> 109 </View> 110 ) 111 }
+55 -1
src/components/Post/Embed/VideoEmbed/GifPresentationControls.tsx
··· 1 - import {Pressable, StyleSheet, View} from 'react-native' 2 import {msg, Trans} from '@lingui/macro' 3 import {useLingui} from '@lingui/react' 4 5 import {atoms as a, useTheme} from '#/alf' 6 import {Fill} from '#/components/Fill' 7 import {Loader} from '#/components/Loader' 8 import {Text} from '#/components/Typography' 9 import {PlayButtonIcon} from '#/components/video/PlayButtonIcon' 10 ··· 12 onPress, 13 isPlaying, 14 isLoading, 15 }: { 16 onPress: () => void 17 isPlaying: boolean 18 isLoading?: boolean 19 }) { 20 const {_} = useLingui() 21 const t = useTheme() ··· 60 <Trans>GIF</Trans> 61 </Text> 62 </View> 63 </> 64 ) 65 } ··· 72 paddingVertical: 3, 73 position: 'absolute', 74 left: 6, 75 bottom: 6, 76 zIndex: 2, 77 },
··· 1 + import {Pressable, StyleSheet, TouchableOpacity, View} from 'react-native' 2 import {msg, Trans} from '@lingui/macro' 3 import {useLingui} from '@lingui/react' 4 5 + import {HITSLOP_20} from '#/lib/constants' 6 import {atoms as a, useTheme} from '#/alf' 7 import {Fill} from '#/components/Fill' 8 import {Loader} from '#/components/Loader' 9 + import * as Prompt from '#/components/Prompt' 10 import {Text} from '#/components/Typography' 11 import {PlayButtonIcon} from '#/components/video/PlayButtonIcon' 12 ··· 14 onPress, 15 isPlaying, 16 isLoading, 17 + altText, 18 }: { 19 onPress: () => void 20 isPlaying: boolean 21 isLoading?: boolean 22 + altText?: string 23 }) { 24 const {_} = useLingui() 25 const t = useTheme() ··· 64 <Trans>GIF</Trans> 65 </Text> 66 </View> 67 + {altText && <AltBadge text={altText} />} 68 + </> 69 + ) 70 + } 71 + 72 + function AltBadge({text}: {text: string}) { 73 + const control = Prompt.usePromptControl() 74 + const {_} = useLingui() 75 + 76 + return ( 77 + <> 78 + <TouchableOpacity 79 + testID="altTextButton" 80 + accessibilityRole="button" 81 + accessibilityLabel={_(msg`Show alt text`)} 82 + accessibilityHint="" 83 + hitSlop={HITSLOP_20} 84 + onPress={control.open} 85 + style={styles.altBadgeContainer}> 86 + <Text 87 + style={[{color: 'white'}, a.font_bold, a.text_xs]} 88 + accessible={false}> 89 + <Trans>ALT</Trans> 90 + </Text> 91 + </TouchableOpacity> 92 + <Prompt.Outer control={control}> 93 + <Prompt.Content> 94 + <Prompt.TitleText> 95 + <Trans>Alt Text</Trans> 96 + </Prompt.TitleText> 97 + <Prompt.DescriptionText selectable>{text}</Prompt.DescriptionText> 98 + </Prompt.Content> 99 + <Prompt.Actions> 100 + <Prompt.Action 101 + onPress={() => control.close()} 102 + cta={_(msg`Close`)} 103 + color="secondary" 104 + /> 105 + </Prompt.Actions> 106 + </Prompt.Outer> 107 </> 108 ) 109 } ··· 116 paddingVertical: 3, 117 position: 'absolute', 118 left: 6, 119 + bottom: 6, 120 + zIndex: 2, 121 + }, 122 + altBadgeContainer: { 123 + backgroundColor: 'rgba(0, 0, 0, 0.75)', 124 + borderRadius: 6, 125 + paddingHorizontal: 4, 126 + paddingVertical: 3, 127 + position: 'absolute', 128 + right: 6, 129 bottom: 6, 130 zIndex: 2, 131 },
+1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx
··· 92 }} 93 isPlaying={isPlaying} 94 isLoading={false} 95 /> 96 ) : ( 97 <VideoPresentationControls
··· 92 }} 93 isPlaying={isPlaying} 94 isLoading={false} 95 + altText={embed.alt} 96 /> 97 ) : ( 98 <VideoPresentationControls
+1
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerWeb.tsx
··· 101 fullscreenRef={containerRef} 102 hasSubtitleTrack={hasSubtitleTrack} 103 isGif={embed.presentation === 'gif'} 104 /> 105 </div> 106 </View>
··· 101 fullscreenRef={containerRef} 102 hasSubtitleTrack={hasSubtitleTrack} 103 isGif={embed.presentation === 'gif'} 104 + altText={embed.alt} 105 /> 106 </div> 107 </View>
+3
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx
··· 46 hlsLoading, 47 hasSubtitleTrack, 48 isGif, 49 }: { 50 videoRef: React.RefObject<HTMLVideoElement | null> 51 hlsRef: React.RefObject<Hls | undefined | null> ··· 58 hlsLoading: boolean 59 hasSubtitleTrack: boolean 60 isGif: boolean 61 }) { 62 const { 63 play, ··· 296 isPlaying={playing} 297 isLoading={showSpinner} 298 onPress={onPressPlayPause} 299 /> 300 ) 301 }
··· 46 hlsLoading, 47 hasSubtitleTrack, 48 isGif, 49 + altText, 50 }: { 51 videoRef: React.RefObject<HTMLVideoElement | null> 52 hlsRef: React.RefObject<Hls | undefined | null> ··· 59 hlsLoading: boolean 60 hasSubtitleTrack: boolean 61 isGif: boolean 62 + altText?: string 63 }) { 64 const { 65 play, ··· 298 isPlaying={playing} 299 isLoading={showSpinner} 300 onPress={onPressPlayPause} 301 + altText={altText} 302 /> 303 ) 304 }