Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 233 lines 6.9 kB view raw
1import {useState} from 'react' 2import {TouchableOpacity, useWindowDimensions, View} from 'react-native' 3import {msg} from '@lingui/core/macro' 4import {useLingui} from '@lingui/react' 5import {Plural, Trans} from '@lingui/react/macro' 6 7import {HITSLOP_10, MAX_ALT_TEXT} from '#/lib/constants' 8import {parseAltFromGIFDescription} from '#/lib/gif-alt-text' 9import { 10 type EmbedPlayerParams, 11 parseEmbedPlayerFromUrl, 12} from '#/lib/strings/embed-player' 13import {useResolveGifQuery} from '#/state/queries/resolve-link' 14import {type Gif} from '#/state/queries/tenor' 15import {AltTextCounterWrapper} from '#/view/com/composer/AltTextCounterWrapper' 16import {atoms as a, useTheme} from '#/alf' 17import {Button, ButtonText} from '#/components/Button' 18import * as Dialog from '#/components/Dialog' 19import {type DialogControlProps} from '#/components/Dialog' 20import * as TextField from '#/components/forms/TextField' 21import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' 22import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' 23import {PlusSmall_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' 24import {GifEmbed} from '#/components/Post/Embed/ExternalEmbed/Gif' 25import {Text} from '#/components/Typography' 26import {IS_ANDROID} from '#/env' 27import {AltTextReminder} from './photos/Gallery' 28 29export function GifAltTextDialog({ 30 gif, 31 altText, 32 onSubmit, 33}: { 34 gif: Gif 35 altText: string 36 onSubmit: (alt: string) => void 37}) { 38 const {data} = useResolveGifQuery(gif) 39 const vendorAltText = parseAltFromGIFDescription(data?.description ?? '').alt 40 const params = data ? parseEmbedPlayerFromUrl(data.uri) : undefined 41 if (!data || !params) { 42 return null 43 } 44 return ( 45 <GifAltTextDialogLoaded 46 altText={altText} 47 vendorAltText={vendorAltText} 48 thumb={data.thumb?.source.path} 49 params={params} 50 onSubmit={onSubmit} 51 /> 52 ) 53} 54 55export function GifAltTextDialogLoaded({ 56 vendorAltText, 57 altText, 58 onSubmit, 59 params, 60 thumb, 61}: { 62 vendorAltText: string 63 altText: string 64 onSubmit: (alt: string) => void 65 params: EmbedPlayerParams 66 thumb: string | undefined 67}) { 68 const control = Dialog.useDialogControl() 69 const {_} = useLingui() 70 const t = useTheme() 71 const [altTextDraft, setAltTextDraft] = useState(altText || vendorAltText) 72 const {height: minHeight} = useWindowDimensions() 73 return ( 74 <> 75 <TouchableOpacity 76 testID="altTextButton" 77 accessibilityRole="button" 78 accessibilityLabel={_(msg`Add alt text`)} 79 accessibilityHint="" 80 hitSlop={HITSLOP_10} 81 onPress={control.open} 82 style={[ 83 a.absolute, 84 {top: 8, left: 8}, 85 {borderRadius: 6}, 86 a.pl_xs, 87 a.pr_sm, 88 a.py_2xs, 89 a.flex_row, 90 a.gap_xs, 91 a.align_center, 92 {backgroundColor: 'rgba(0, 0, 0, 0.75)'}, 93 ]}> 94 {altText ? ( 95 <Check size="xs" fill={t.palette.white} style={a.ml_xs} /> 96 ) : ( 97 <Plus size="sm" fill={t.palette.white} /> 98 )} 99 <Text 100 style={[a.font_semi_bold, {color: t.palette.white}]} 101 accessible={false}> 102 <Trans>ALT</Trans> 103 </Text> 104 </TouchableOpacity> 105 106 <AltTextReminder /> 107 108 <Dialog.Outer 109 control={control} 110 onClose={() => { 111 onSubmit(altTextDraft) 112 }} 113 nativeOptions={{minHeight}}> 114 <Dialog.Handle /> 115 <AltTextInner 116 vendorAltText={vendorAltText} 117 altText={altTextDraft} 118 onChange={setAltTextDraft} 119 thumb={thumb} 120 control={control} 121 params={params} 122 /> 123 </Dialog.Outer> 124 </> 125 ) 126} 127 128function AltTextInner({ 129 vendorAltText, 130 altText, 131 onChange, 132 control, 133 params, 134 thumb, 135}: { 136 vendorAltText: string 137 altText: string 138 onChange: (text: string) => void 139 control: DialogControlProps 140 params: EmbedPlayerParams 141 thumb: string | undefined 142}) { 143 const t = useTheme() 144 const {_, i18n} = useLingui() 145 146 return ( 147 <Dialog.ScrollableInner label={_(msg`Add alt text`)}> 148 <View style={a.flex_col_reverse}> 149 <View style={[a.mt_md, a.gap_md]}> 150 <View style={[a.gap_sm]}> 151 <View style={[a.relative]}> 152 <TextField.LabelText> 153 <Trans>Descriptive alt text</Trans> 154 </TextField.LabelText> 155 <TextField.Root> 156 <Dialog.Input 157 label={_(msg`Alt text`)} 158 placeholder={vendorAltText} 159 onChangeText={onChange} 160 defaultValue={altText} 161 multiline 162 numberOfLines={3} 163 autoFocus 164 onKeyPress={({nativeEvent}) => { 165 if (nativeEvent.key === 'Escape') { 166 control.close() 167 } 168 }} 169 /> 170 </TextField.Root> 171 </View> 172 173 {altText.length > MAX_ALT_TEXT && ( 174 <View style={[a.pb_sm, a.flex_row, a.gap_xs]}> 175 <CircleInfo fill={t.palette.negative_500} /> 176 <Text 177 style={[ 178 a.italic, 179 a.leading_snug, 180 t.atoms.text_contrast_medium, 181 ]}> 182 <Trans> 183 Alt text will be truncated.{' '} 184 <Plural 185 value={MAX_ALT_TEXT} 186 other={`Limit: ${i18n.number(MAX_ALT_TEXT)} characters.`} 187 /> 188 </Trans> 189 </Text> 190 </View> 191 )} 192 </View> 193 194 <AltTextCounterWrapper altText={altText}> 195 <Button 196 label={_(msg`Save`)} 197 size="large" 198 color="primary" 199 variant="solid" 200 onPress={() => { 201 control.close() 202 }} 203 style={[a.flex_grow]}> 204 <ButtonText> 205 <Trans>Save</Trans> 206 </ButtonText> 207 </Button> 208 </AltTextCounterWrapper> 209 </View> 210 {/* below the text input to force tab order */} 211 <View> 212 <Text 213 style={[a.text_2xl, a.font_semi_bold, a.leading_tight, a.pb_sm]}> 214 <Trans>Add alt text</Trans> 215 </Text> 216 <View style={[a.align_center]}> 217 <GifEmbed 218 thumb={thumb} 219 altText={altText} 220 isPreferredAltText={true} 221 params={params} 222 hideAlt 223 style={[{height: 225}]} 224 /> 225 </View> 226 </View> 227 </View> 228 <Dialog.Close /> 229 {/* Maybe fix this later -h */} 230 {IS_ANDROID ? <View style={{height: 300}} /> : null} 231 </Dialog.ScrollableInner> 232 ) 233}