Add alt text validation option to user preferences (supersedes #913) (#914)

* Add alt text validation option to user preferences

* Fix typos/linting issues

* Update accessibility setting to match styles

* Update the required alt text reminder to go away once it's added

---------

Co-authored-by: Emma Fuller <emma@emmafuller.dev>
zio/stable
Paul Frazee 2023-07-03 15:58:07 -05:00 committed by GitHub
parent bc55241c9a
commit 696bffe832
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 3 deletions

View File

@ -23,6 +23,10 @@ export class GalleryModel {
return this.images.length
}
get needsAltText() {
return this.images.some(image => image.altText.trim() === '')
}
async add(image_: Omit<RNImage, 'size'>) {
if (this.size >= 4) {
return

View File

@ -53,6 +53,7 @@ export class PreferencesModel {
homeFeedRepliesThreshold: number = 2
homeFeedRepostsEnabled: boolean = true
homeFeedQuotePostsEnabled: boolean = true
requireAltTextEnabled: boolean = false
// used to linearize async modifications to state
lock = new AwaitLock()
@ -72,6 +73,7 @@ export class PreferencesModel {
homeFeedRepliesThreshold: this.homeFeedRepliesThreshold,
homeFeedRepostsEnabled: this.homeFeedRepostsEnabled,
homeFeedQuotePostsEnabled: this.homeFeedQuotePostsEnabled,
requireAltTextEnabled: this.requireAltTextEnabled,
}
}
@ -152,6 +154,13 @@ export class PreferencesModel {
) {
this.homeFeedQuotePostsEnabled = v.homeFeedQuotePostsEnabled
}
// check if requiring alt text is enabled in preferences, then hydrate
if (
hasProp(v, 'requireAltTextEnabled') &&
typeof v.requireAltTextEnabled === 'boolean'
) {
this.requireAltTextEnabled = v.requireAltTextEnabled
}
}
}
@ -467,4 +476,8 @@ export class PreferencesModel {
toggleHomeFeedQuotePostsEnabled() {
this.homeFeedQuotePostsEnabled = !this.homeFeedQuotePostsEnabled
}
toggleRequireAltTextEnabled() {
this.requireAltTextEnabled = !this.requireAltTextEnabled
}
}

View File

@ -156,6 +156,9 @@ export const ComposePost = observer(function ComposePost({
if (isProcessing || rt.graphemeLength > MAX_GRAPHEME_LENGTH) {
return
}
if (store.preferences.requireAltTextEnabled && gallery.needsAltText) {
return
}
setError('')
@ -220,8 +223,14 @@ export const ComposePost = observer(function ComposePost({
)
const canPost = useMemo(
() => graphemeLength <= MAX_GRAPHEME_LENGTH,
[graphemeLength],
() =>
graphemeLength <= MAX_GRAPHEME_LENGTH &&
(!store.preferences.requireAltTextEnabled || !gallery.needsAltText),
[
graphemeLength,
store.preferences.requireAltTextEnabled,
gallery.needsAltText,
],
)
const selectTextInputPlaceholder = replyTo ? 'Write your reply' : `What's up?`
@ -282,6 +291,20 @@ export const ComposePost = observer(function ComposePost({
<Text style={pal.text}>{processingState}</Text>
</View>
) : undefined}
{store.preferences.requireAltTextEnabled && gallery.needsAltText && (
<View style={[styles.reminderLine, pal.viewLight]}>
<View style={styles.errorIcon}>
<FontAwesomeIcon
icon="exclamation"
style={{color: colors.red4}}
size={10}
/>
</View>
<Text style={[pal.text, s.flex1]}>
One or more images is missing alt text.
</Text>
</View>
)}
{error !== '' && (
<View style={styles.errorLine}>
<View style={styles.errorIcon}>
@ -415,6 +438,15 @@ const styles = StyleSheet.create({
paddingVertical: 6,
marginVertical: 6,
},
reminderLine: {
flexDirection: 'row',
alignItems: 'center',
borderRadius: 6,
marginHorizontal: 15,
paddingHorizontal: 8,
paddingVertical: 6,
marginBottom: 6,
},
errorIcon: {
borderWidth: 1,
borderColor: colors.red4,

View File

@ -5,18 +5,21 @@ import {Button, ButtonType} from './Button'
import {useTheme} from 'lib/ThemeContext'
import {choose} from 'lib/functions'
import {colors} from 'lib/styles'
import {TypographyVariant} from 'lib/ThemeContext'
export function ToggleButton({
type = 'default-light',
label,
isSelected,
style,
labelType,
onPress,
}: {
type?: ButtonType
label: string
isSelected: boolean
style?: StyleProp<ViewStyle>
labelType?: TypographyVariant
onPress?: () => void
}) {
const theme = useTheme()
@ -143,7 +146,7 @@ export function ToggleButton({
/>
</View>
{label === '' ? null : (
<Text type="button" style={[labelStyle, styles.label]}>
<Text type={labelType || 'button'} style={[labelStyle, styles.label]}>
{label}
</Text>
)}

View File

@ -330,6 +330,22 @@ export const SettingsScreen = withAuthRequired(
</TouchableOpacity>
<View style={styles.spacer20} />
<Text type="xl-bold" style={[pal.text, styles.heading]}>
Accessibility
</Text>
<View style={[pal.view, styles.toggleCard]}>
<ToggleButton
type="default-light"
label="Require alt text on images"
labelType="lg"
isSelected={store.preferences.requireAltTextEnabled}
onPress={store.preferences.toggleRequireAltTextEnabled}
/>
</View>
<View style={styles.spacer20} />
<Text type="xl-bold" style={[pal.text, styles.heading]}>
Appearance
</Text>
@ -633,6 +649,11 @@ const styles = StyleSheet.create({
paddingHorizontal: 18,
marginBottom: 1,
},
toggleCard: {
paddingVertical: 8,
paddingHorizontal: 6,
marginBottom: 1,
},
avi: {
marginRight: 12,
},