about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/state/models/media/gallery.ts4
-rw-r--r--src/state/models/ui/preferences.ts13
-rw-r--r--src/view/com/composer/Composer.tsx36
-rw-r--r--src/view/com/util/forms/ToggleButton.tsx5
-rw-r--r--src/view/screens/Settings.tsx21
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,
   },