diff options
-rw-r--r-- | src/state/models/media/gallery.ts | 4 | ||||
-rw-r--r-- | src/state/models/ui/preferences.ts | 13 | ||||
-rw-r--r-- | src/view/com/composer/Composer.tsx | 36 | ||||
-rw-r--r-- | src/view/com/util/forms/ToggleButton.tsx | 5 | ||||
-rw-r--r-- | src/view/screens/Settings.tsx | 21 |
5 files changed, 76 insertions, 3 deletions
diff --git a/src/state/models/media/gallery.ts b/src/state/models/media/gallery.ts index e53e861e2..1b22fadbd 100644 --- a/src/state/models/media/gallery.ts +++ b/src/state/models/media/gallery.ts @@ -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 diff --git a/src/state/models/ui/preferences.ts b/src/state/models/ui/preferences.ts index 28c7c5666..858225a6f 100644 --- a/src/state/models/ui/preferences.ts +++ b/src/state/models/ui/preferences.ts @@ -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 + } } diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index caece3476..c6a9ecd4a 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -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, diff --git a/src/view/com/util/forms/ToggleButton.tsx b/src/view/com/util/forms/ToggleButton.tsx index 47620d0a6..02be80b31 100644 --- a/src/view/com/util/forms/ToggleButton.tsx +++ b/src/view/com/util/forms/ToggleButton.tsx @@ -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> )} diff --git a/src/view/screens/Settings.tsx b/src/view/screens/Settings.tsx index e1fb549bc..0057841b2 100644 --- a/src/view/screens/Settings.tsx +++ b/src/view/screens/Settings.tsx @@ -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, }, |