Rework alt-text input to use bottom sheet (#2355)

* Rework alt-text input to use bottom sheet

* Add translations
zio/stable
Paul Frazee 2024-01-02 15:14:09 -08:00 committed by GitHub
parent 0842df3675
commit d95972c9ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 65 additions and 82 deletions

View File

@ -1,14 +1,12 @@
import React, {useMemo, useCallback, useState} from 'react' import React, {useMemo, useCallback, useState} from 'react'
import { import {
ImageStyle, ImageStyle,
KeyboardAvoidingView,
ScrollView,
StyleSheet, StyleSheet,
TextInput,
TouchableOpacity, TouchableOpacity,
View, View,
useWindowDimensions, useWindowDimensions,
} from 'react-native' } from 'react-native'
import {ScrollView, TextInput} from './util'
import {Image} from 'expo-image' import {Image} from 'expo-image'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {gradients, s} from 'lib/styles' import {gradients, s} from 'lib/styles'
@ -17,13 +15,13 @@ import {MAX_ALT_TEXT} from 'lib/constants'
import {useTheme} from 'lib/ThemeContext' import {useTheme} from 'lib/ThemeContext'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import LinearGradient from 'react-native-linear-gradient' import LinearGradient from 'react-native-linear-gradient'
import {isAndroid, isWeb} from 'platform/detection' import {isWeb} from 'platform/detection'
import {ImageModel} from 'state/models/media/image' import {ImageModel} from 'state/models/media/image'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {Trans, msg} from '@lingui/macro' import {Trans, msg} from '@lingui/macro'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
export const snapPoints = ['fullscreen'] export const snapPoints = ['100%']
interface Props { interface Props {
image: ImageModel image: ImageModel
@ -54,22 +52,24 @@ export function Component({image}: Props) {
} }
}, [image, windim]) }, [image, windim])
const onUpdate = useCallback(
(v: string) => {
v = enforceLen(v, MAX_ALT_TEXT)
setAltText(v)
image.setAltText(v)
},
[setAltText, image],
)
const onPressSave = useCallback(() => { const onPressSave = useCallback(() => {
image.setAltText(altText) image.setAltText(altText)
closeModal() closeModal()
}, [closeModal, image, altText]) }, [closeModal, image, altText])
const onPressCancel = () => {
closeModal()
}
return ( return (
<KeyboardAvoidingView
behavior={isAndroid ? 'height' : 'padding'}
style={[pal.view, styles.container]}>
<ScrollView <ScrollView
testID="altTextImageModal" testID="altTextImageModal"
style={styles.scrollContainer} style={[pal.view, styles.scrollContainer]}
keyboardShouldPersistTaps="always" keyboardShouldPersistTaps="always"
nativeID="imageAltText"> nativeID="imageAltText">
<View style={styles.scrollInner}> <View style={styles.scrollInner}>
@ -90,10 +90,10 @@ export function Component({image}: Props) {
style={[styles.textArea, pal.border, pal.text]} style={[styles.textArea, pal.border, pal.text]}
keyboardAppearance={theme.colorScheme} keyboardAppearance={theme.colorScheme}
multiline multiline
placeholder="Add alt text" placeholder={_(msg`Add alt text`)}
placeholderTextColor={pal.colors.textLight} placeholderTextColor={pal.colors.textLight}
value={altText} value={altText}
onChangeText={text => setAltText(enforceLen(text, MAX_ALT_TEXT))} onChangeText={onUpdate}
accessibilityLabel={_(msg`Image alt text`)} accessibilityLabel={_(msg`Image alt text`)}
accessibilityHint="" accessibilityHint=""
accessibilityLabelledBy="imageAltText" accessibilityLabelledBy="imageAltText"
@ -104,7 +104,7 @@ export function Component({image}: Props) {
testID="altTextImageSaveBtn" testID="altTextImageSaveBtn"
onPress={onPressSave} onPress={onPressSave}
accessibilityLabel={_(msg`Save alt text`)} accessibilityLabel={_(msg`Save alt text`)}
accessibilityHint={`Saves alt text, which reads: ${altText}`} accessibilityHint=""
accessibilityRole="button"> accessibilityRole="button">
<LinearGradient <LinearGradient
colors={[gradients.blueLight.start, gradients.blueLight.end]} colors={[gradients.blueLight.start, gradients.blueLight.end]}
@ -112,44 +112,26 @@ export function Component({image}: Props) {
end={{x: 1, y: 1}} end={{x: 1, y: 1}}
style={[styles.button]}> style={[styles.button]}>
<Text type="button-lg" style={[s.white, s.bold]}> <Text type="button-lg" style={[s.white, s.bold]}>
<Trans>Save</Trans> <Trans>Done</Trans>
</Text> </Text>
</LinearGradient> </LinearGradient>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity
testID="altTextImageCancelBtn"
onPress={onPressCancel}
accessibilityRole="button"
accessibilityLabel={_(msg`Cancel add image alt text`)}
accessibilityHint=""
onAccessibilityEscape={onPressCancel}>
<View style={[styles.button]}>
<Text type="button-lg" style={[pal.textLight]}>
<Trans>Cancel</Trans>
</Text>
</View>
</TouchableOpacity>
</View> </View>
</View> </View>
</ScrollView> </ScrollView>
</KeyboardAvoidingView>
) )
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: {
flex: 1,
height: '100%',
width: '100%',
paddingVertical: isWeb ? 0 : 18,
},
scrollContainer: { scrollContainer: {
flex: 1, flex: 1,
height: '100%', height: '100%',
paddingHorizontal: isWeb ? 0 : 12, paddingHorizontal: isWeb ? 0 : 12,
paddingVertical: isWeb ? 0 : 24,
}, },
scrollInner: { scrollInner: {
gap: 12, gap: 12,
paddingTop: isWeb ? 0 : 12,
}, },
imageContainer: { imageContainer: {
borderRadius: 8, borderRadius: 8,
@ -173,5 +155,6 @@ const styles = StyleSheet.create({
}, },
buttonControls: { buttonControls: {
gap: 8, gap: 8,
paddingBottom: isWeb ? 0 : 50,
}, },
}) })