Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client
122
fork

Configure Feed

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

Add disable autoplay preference and group related settings into a dedicated page (#3626)

* add autoplay preference

* group accessibility settings into a dedicated page

* fix gray background on web

* Put a11y first

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>

authored by

Samuel Newman
Dan Abramov
and committed by
GitHub
8b33ffdf ade2ea61

+263 -82
+1
bskyweb/cmd/bskyweb/server.go
··· 190 190 e.GET("/settings/saved-feeds", server.WebGeneric) 191 191 e.GET("/settings/threads", server.WebGeneric) 192 192 e.GET("/settings/external-embeds", server.WebGeneric) 193 + e.GET("/settings/accessibility", server.WebGeneric) 193 194 e.GET("/sys/debug", server.WebGeneric) 194 195 e.GET("/sys/debug-mod", server.WebGeneric) 195 196 e.GET("/sys/log", server.WebGeneric)
+9
src/Navigation.tsx
··· 53 53 setEmailConfirmationRequested, 54 54 shouldRequestEmailConfirmation, 55 55 } from './state/shell/reminders' 56 + import {AccessibilitySettingsScreen} from './view/screens/AccessibilitySettings' 56 57 import {CommunityGuidelinesScreen} from './view/screens/CommunityGuidelines' 57 58 import {CopyrightPolicyScreen} from './view/screens/CopyrightPolicy' 58 59 import {DebugModScreen} from './view/screens/DebugMod' ··· 273 274 getComponent={() => PreferencesExternalEmbeds} 274 275 options={{ 275 276 title: title(msg`External Media Preferences`), 277 + requireAuth: true, 278 + }} 279 + /> 280 + <Stack.Screen 281 + name="AccessibilitySettings" 282 + getComponent={() => AccessibilitySettingsScreen} 283 + options={{ 284 + title: title(msg`Accessibility Settings`), 276 285 requireAuth: true, 277 286 }} 278 287 />
+1
src/lib/routes/types.ts
··· 35 35 PreferencesFollowingFeed: undefined 36 36 PreferencesThreads: undefined 37 37 PreferencesExternalEmbeds: undefined 38 + AccessibilitySettings: undefined 38 39 Search: {q?: string} 39 40 Hashtag: {tag: string; author?: string} 40 41 }
+1
src/routes.ts
··· 29 29 PreferencesFollowingFeed: '/settings/following-feed', 30 30 PreferencesThreads: '/settings/threads', 31 31 PreferencesExternalEmbeds: '/settings/external-embeds', 32 + AccessibilitySettings: '/settings/accessibility', 32 33 SavedFeeds: '/settings/saved-feeds', 33 34 Support: '/support', 34 35 PrivacyPolicy: '/support/privacy',
+2
src/state/persisted/schema.ts
··· 60 60 lastSelectedHomeFeed: z.string().optional(), 61 61 pdsAddressHistory: z.array(z.string()).optional(), 62 62 disableHaptics: z.boolean().optional(), 63 + disableAutoplay: z.boolean().optional(), 63 64 }) 64 65 export type Schema = z.infer<typeof schema> 65 66 ··· 96 97 lastSelectedHomeFeed: undefined, 97 98 pdsAddressHistory: [], 98 99 disableHaptics: false, 100 + disableAutoplay: false, 99 101 }
+42
src/state/preferences/autoplay.tsx
··· 1 + import React from 'react' 2 + 3 + import * as persisted from '#/state/persisted' 4 + 5 + type StateContext = boolean 6 + type SetContext = (v: boolean) => void 7 + 8 + const stateContext = React.createContext<StateContext>( 9 + Boolean(persisted.defaults.disableAutoplay), 10 + ) 11 + const setContext = React.createContext<SetContext>((_: boolean) => {}) 12 + 13 + export function Provider({children}: {children: React.ReactNode}) { 14 + const [state, setState] = React.useState( 15 + Boolean(persisted.get('disableAutoplay')), 16 + ) 17 + 18 + const setStateWrapped = React.useCallback( 19 + (autoplayDisabled: persisted.Schema['disableAutoplay']) => { 20 + setState(Boolean(autoplayDisabled)) 21 + persisted.write('disableAutoplay', autoplayDisabled) 22 + }, 23 + [setState], 24 + ) 25 + 26 + React.useEffect(() => { 27 + return persisted.onUpdate(() => { 28 + setState(Boolean(persisted.get('disableAutoplay'))) 29 + }) 30 + }, [setStateWrapped]) 31 + 32 + return ( 33 + <stateContext.Provider value={state}> 34 + <setContext.Provider value={setStateWrapped}> 35 + {children} 36 + </setContext.Provider> 37 + </stateContext.Provider> 38 + ) 39 + } 40 + 41 + export const useAutoplayDisabled = () => React.useContext(stateContext) 42 + export const useSetAutoplayDisabled = () => React.useContext(setContext)
+8 -3
src/state/preferences/index.tsx
··· 1 1 import React from 'react' 2 2 3 - import {Provider as AltTextRequiredProvider} from '../preferences/alt-text-required' 4 - import {Provider as HiddenPostsProvider} from '../preferences/hidden-posts' 3 + import {Provider as AltTextRequiredProvider} from './alt-text-required' 4 + import {Provider as AutoplayProvider} from './autoplay' 5 5 import {Provider as DisableHapticsProvider} from './disable-haptics' 6 6 import {Provider as ExternalEmbedsProvider} from './external-embeds-prefs' 7 + import {Provider as HiddenPostsProvider} from './hidden-posts' 7 8 import {Provider as InAppBrowserProvider} from './in-app-browser' 8 9 import {Provider as LanguagesProvider} from './languages' 9 10 ··· 11 12 useRequireAltTextEnabled, 12 13 useSetRequireAltTextEnabled, 13 14 } from './alt-text-required' 15 + export {useAutoplayDisabled, useSetAutoplayDisabled} from './autoplay' 16 + export {useHapticsDisabled, useSetHapticsDisabled} from './disable-haptics' 14 17 export { 15 18 useExternalEmbedsPrefs, 16 19 useSetExternalEmbedPref, ··· 26 29 <ExternalEmbedsProvider> 27 30 <HiddenPostsProvider> 28 31 <InAppBrowserProvider> 29 - <DisableHapticsProvider>{children}</DisableHapticsProvider> 32 + <DisableHapticsProvider> 33 + <AutoplayProvider>{children}</AutoplayProvider> 34 + </DisableHapticsProvider> 30 35 </InAppBrowserProvider> 31 36 </HiddenPostsProvider> 32 37 </ExternalEmbedsProvider>
+38 -37
src/view/icons/index.tsx
··· 1 1 import {library} from '@fortawesome/fontawesome-svg-core' 2 - 3 2 import {faAddressCard} from '@fortawesome/free-regular-svg-icons' 3 + import {faBell as farBell} from '@fortawesome/free-regular-svg-icons/faBell' 4 + import {faBookmark as farBookmark} from '@fortawesome/free-regular-svg-icons/faBookmark' 5 + import {faCalendar as farCalendar} from '@fortawesome/free-regular-svg-icons/faCalendar' 6 + import {faCircle} from '@fortawesome/free-regular-svg-icons/faCircle' 7 + import {faCircleCheck as farCircleCheck} from '@fortawesome/free-regular-svg-icons/faCircleCheck' 8 + import {faCirclePlay} from '@fortawesome/free-regular-svg-icons/faCirclePlay' 9 + import {faCircleUser} from '@fortawesome/free-regular-svg-icons/faCircleUser' 10 + import {faClone as farClone} from '@fortawesome/free-regular-svg-icons/faClone' 11 + import {faComment} from '@fortawesome/free-regular-svg-icons/faComment' 12 + import {faComments} from '@fortawesome/free-regular-svg-icons/faComments' 13 + import {faCompass} from '@fortawesome/free-regular-svg-icons/faCompass' 14 + import {faEyeSlash as farEyeSlash} from '@fortawesome/free-regular-svg-icons/faEyeSlash' 15 + import {faFaceSmile} from '@fortawesome/free-regular-svg-icons/faFaceSmile' 16 + import {faFloppyDisk} from '@fortawesome/free-regular-svg-icons/faFloppyDisk' 17 + import {faHand as farHand} from '@fortawesome/free-regular-svg-icons/faHand' 18 + import {faHeart} from '@fortawesome/free-regular-svg-icons/faHeart' 19 + import {faImage as farImage} from '@fortawesome/free-regular-svg-icons/faImage' 20 + import {faMessage} from '@fortawesome/free-regular-svg-icons/faMessage' 21 + import {faPaste} from '@fortawesome/free-regular-svg-icons/faPaste' 22 + import {faSquare} from '@fortawesome/free-regular-svg-icons/faSquare' 23 + import {faSquareCheck} from '@fortawesome/free-regular-svg-icons/faSquareCheck' 24 + import {faSquarePlus} from '@fortawesome/free-regular-svg-icons/faSquarePlus' 25 + import {faTrashCan} from '@fortawesome/free-regular-svg-icons/faTrashCan' 26 + import {faUser} from '@fortawesome/free-regular-svg-icons/faUser' 27 + import {faFlask} from '@fortawesome/free-solid-svg-icons' 28 + import {faUniversalAccess} from '@fortawesome/free-solid-svg-icons' 4 29 import {faAngleDown} from '@fortawesome/free-solid-svg-icons/faAngleDown' 5 30 import {faAngleLeft} from '@fortawesome/free-solid-svg-icons/faAngleLeft' 6 31 import {faAngleRight} from '@fortawesome/free-solid-svg-icons/faAngleRight' 7 32 import {faAngleUp} from '@fortawesome/free-solid-svg-icons/faAngleUp' 33 + import {faArrowDown} from '@fortawesome/free-solid-svg-icons/faArrowDown' 8 34 import {faArrowLeft} from '@fortawesome/free-solid-svg-icons/faArrowLeft' 9 35 import {faArrowRight} from '@fortawesome/free-solid-svg-icons/faArrowRight' 36 + import {faArrowRightFromBracket} from '@fortawesome/free-solid-svg-icons/faArrowRightFromBracket' 37 + import {faArrowRotateLeft} from '@fortawesome/free-solid-svg-icons/faArrowRotateLeft' 38 + import {faArrowsRotate} from '@fortawesome/free-solid-svg-icons/faArrowsRotate' 39 + import {faArrowTrendUp} from '@fortawesome/free-solid-svg-icons/faArrowTrendUp' 10 40 import {faArrowUp} from '@fortawesome/free-solid-svg-icons/faArrowUp' 11 - import {faArrowDown} from '@fortawesome/free-solid-svg-icons/faArrowDown' 12 - import {faArrowRightFromBracket} from '@fortawesome/free-solid-svg-icons/faArrowRightFromBracket' 13 41 import {faArrowUpFromBracket} from '@fortawesome/free-solid-svg-icons/faArrowUpFromBracket' 14 42 import {faArrowUpRightFromSquare} from '@fortawesome/free-solid-svg-icons/faArrowUpRightFromSquare' 15 - import {faArrowRotateLeft} from '@fortawesome/free-solid-svg-icons/faArrowRotateLeft' 16 - import {faArrowTrendUp} from '@fortawesome/free-solid-svg-icons/faArrowTrendUp' 17 - import {faArrowsRotate} from '@fortawesome/free-solid-svg-icons/faArrowsRotate' 18 43 import {faAt} from '@fortawesome/free-solid-svg-icons/faAt' 44 + import {faBan} from '@fortawesome/free-solid-svg-icons/faBan' 19 45 import {faBars} from '@fortawesome/free-solid-svg-icons/faBars' 20 - import {faBan} from '@fortawesome/free-solid-svg-icons/faBan' 21 46 import {faBell} from '@fortawesome/free-solid-svg-icons/faBell' 22 - import {faBell as farBell} from '@fortawesome/free-regular-svg-icons/faBell' 23 47 import {faBookmark} from '@fortawesome/free-solid-svg-icons/faBookmark' 24 - import {faBookmark as farBookmark} from '@fortawesome/free-regular-svg-icons/faBookmark' 25 - import {faCalendar as farCalendar} from '@fortawesome/free-regular-svg-icons/faCalendar' 26 48 import {faCamera} from '@fortawesome/free-solid-svg-icons/faCamera' 27 49 import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck' 50 + import {faChevronDown} from '@fortawesome/free-solid-svg-icons/faChevronDown' 28 51 import {faChevronRight} from '@fortawesome/free-solid-svg-icons/faChevronRight' 29 - import {faCircle} from '@fortawesome/free-regular-svg-icons/faCircle' 30 - import {faCircleCheck as farCircleCheck} from '@fortawesome/free-regular-svg-icons/faCircleCheck' 31 52 import {faCircleCheck} from '@fortawesome/free-solid-svg-icons/faCircleCheck' 32 53 import {faCircleDot} from '@fortawesome/free-solid-svg-icons/faCircleDot' 33 54 import {faCircleExclamation} from '@fortawesome/free-solid-svg-icons/faCircleExclamation' 34 - import {faCirclePlay} from '@fortawesome/free-regular-svg-icons/faCirclePlay' 35 - import {faCircleUser} from '@fortawesome/free-regular-svg-icons/faCircleUser' 36 55 import {faClone} from '@fortawesome/free-solid-svg-icons/faClone' 37 - import {faClone as farClone} from '@fortawesome/free-regular-svg-icons/faClone' 38 - import {faComment} from '@fortawesome/free-regular-svg-icons/faComment' 39 56 import {faCommentSlash} from '@fortawesome/free-solid-svg-icons/faCommentSlash' 40 - import {faComments} from '@fortawesome/free-regular-svg-icons/faComments' 41 - import {faCompass} from '@fortawesome/free-regular-svg-icons/faCompass' 42 57 import {faDownload} from '@fortawesome/free-solid-svg-icons/faDownload' 43 58 import {faEllipsis} from '@fortawesome/free-solid-svg-icons/faEllipsis' 44 59 import {faEnvelope} from '@fortawesome/free-solid-svg-icons/faEnvelope' 45 60 import {faExclamation} from '@fortawesome/free-solid-svg-icons/faExclamation' 46 61 import {faEye} from '@fortawesome/free-solid-svg-icons/faEye' 47 - import {faEyeSlash as farEyeSlash} from '@fortawesome/free-regular-svg-icons/faEyeSlash' 48 - import {faFaceSmile} from '@fortawesome/free-regular-svg-icons/faFaceSmile' 62 + import {faFilter} from '@fortawesome/free-solid-svg-icons/faFilter' 49 63 import {faFire} from '@fortawesome/free-solid-svg-icons/faFire' 50 - import {faFlask} from '@fortawesome/free-solid-svg-icons' 51 - import {faFloppyDisk} from '@fortawesome/free-regular-svg-icons/faFloppyDisk' 52 64 import {faGear} from '@fortawesome/free-solid-svg-icons/faGear' 53 65 import {faGlobe} from '@fortawesome/free-solid-svg-icons/faGlobe' 54 66 import {faHand} from '@fortawesome/free-solid-svg-icons/faHand' 55 - import {faHand as farHand} from '@fortawesome/free-regular-svg-icons/faHand' 56 67 import {faHashtag} from '@fortawesome/free-solid-svg-icons/faHashtag' 57 - import {faHeart} from '@fortawesome/free-regular-svg-icons/faHeart' 58 68 import {faHeart as fasHeart} from '@fortawesome/free-solid-svg-icons/faHeart' 59 69 import {faHouse} from '@fortawesome/free-solid-svg-icons/faHouse' 60 - import {faImage as farImage} from '@fortawesome/free-regular-svg-icons/faImage' 61 70 import {faImage} from '@fortawesome/free-solid-svg-icons/faImage' 62 71 import {faInfo} from '@fortawesome/free-solid-svg-icons/faInfo' 63 72 import {faLanguage} from '@fortawesome/free-solid-svg-icons/faLanguage' ··· 66 75 import {faListUl} from '@fortawesome/free-solid-svg-icons/faListUl' 67 76 import {faLock} from '@fortawesome/free-solid-svg-icons/faLock' 68 77 import {faMagnifyingGlass} from '@fortawesome/free-solid-svg-icons/faMagnifyingGlass' 69 - import {faMessage} from '@fortawesome/free-regular-svg-icons/faMessage' 70 78 import {faNoteSticky} from '@fortawesome/free-solid-svg-icons/faNoteSticky' 71 79 import {faPause} from '@fortawesome/free-solid-svg-icons/faPause' 72 - import {faPaste} from '@fortawesome/free-regular-svg-icons/faPaste' 73 80 import {faPen} from '@fortawesome/free-solid-svg-icons/faPen' 74 81 import {faPenNib} from '@fortawesome/free-solid-svg-icons/faPenNib' 75 82 import {faPenToSquare} from '@fortawesome/free-solid-svg-icons/faPenToSquare' ··· 87 94 import {faShield} from '@fortawesome/free-solid-svg-icons/faShield' 88 95 import {faSignal} from '@fortawesome/free-solid-svg-icons/faSignal' 89 96 import {faSliders} from '@fortawesome/free-solid-svg-icons/faSliders' 90 - import {faSquare} from '@fortawesome/free-regular-svg-icons/faSquare' 91 - import {faSquareCheck} from '@fortawesome/free-regular-svg-icons/faSquareCheck' 92 - import {faSquarePlus} from '@fortawesome/free-regular-svg-icons/faSquarePlus' 93 97 import {faThumbtack} from '@fortawesome/free-solid-svg-icons/faThumbtack' 94 98 import {faTicket} from '@fortawesome/free-solid-svg-icons/faTicket' 95 - import {faTrashCan} from '@fortawesome/free-regular-svg-icons/faTrashCan' 96 - import {faUser} from '@fortawesome/free-regular-svg-icons/faUser' 99 + import {faUserCheck} from '@fortawesome/free-solid-svg-icons/faUserCheck' 100 + import {faUserPlus} from '@fortawesome/free-solid-svg-icons/faUserPlus' 97 101 import {faUsers} from '@fortawesome/free-solid-svg-icons/faUsers' 98 - import {faUserCheck} from '@fortawesome/free-solid-svg-icons/faUserCheck' 99 102 import {faUserSlash} from '@fortawesome/free-solid-svg-icons/faUserSlash' 100 - import {faUserPlus} from '@fortawesome/free-solid-svg-icons/faUserPlus' 103 + import {faUsersSlash} from '@fortawesome/free-solid-svg-icons/faUsersSlash' 101 104 import {faUserXmark} from '@fortawesome/free-solid-svg-icons/faUserXmark' 102 - import {faUsersSlash} from '@fortawesome/free-solid-svg-icons/faUsersSlash' 103 105 import {faX} from '@fortawesome/free-solid-svg-icons/faX' 104 106 import {faXmark} from '@fortawesome/free-solid-svg-icons/faXmark' 105 - import {faChevronDown} from '@fortawesome/free-solid-svg-icons/faChevronDown' 106 - import {faFilter} from '@fortawesome/free-solid-svg-icons/faFilter' 107 107 108 108 library.add( 109 109 faAddressCard, ··· 196 196 faSquare, 197 197 faSquareCheck, 198 198 faSquarePlus, 199 + faUniversalAccess, 199 200 faUser, 200 201 faUsers, 201 202 faUserCheck,
+132
src/view/screens/AccessibilitySettings.tsx
··· 1 + import React from 'react' 2 + import {StyleSheet, View} from 'react-native' 3 + import {msg, Trans} from '@lingui/macro' 4 + import {useLingui} from '@lingui/react' 5 + import {useFocusEffect} from '@react-navigation/native' 6 + 7 + import {isNative} from '#/platform/detection' 8 + import {useSetMinimalShellMode} from '#/state/shell' 9 + import {useAnalytics} from 'lib/analytics/analytics' 10 + import {usePalette} from 'lib/hooks/usePalette' 11 + import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' 12 + import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types' 13 + import {s} from 'lib/styles' 14 + import { 15 + useAutoplayDisabled, 16 + useHapticsDisabled, 17 + useRequireAltTextEnabled, 18 + useSetAutoplayDisabled, 19 + useSetHapticsDisabled, 20 + useSetRequireAltTextEnabled, 21 + } from 'state/preferences' 22 + import {ToggleButton} from 'view/com/util/forms/ToggleButton' 23 + import {SimpleViewHeader} from '../com/util/SimpleViewHeader' 24 + import {Text} from '../com/util/text/Text' 25 + import {ScrollView} from '../com/util/Views' 26 + 27 + type Props = NativeStackScreenProps< 28 + CommonNavigatorParams, 29 + 'AccessibilitySettings' 30 + > 31 + export function AccessibilitySettingsScreen({}: Props) { 32 + const pal = usePalette('default') 33 + const setMinimalShellMode = useSetMinimalShellMode() 34 + const {screen} = useAnalytics() 35 + const {isMobile} = useWebMediaQueries() 36 + const {_} = useLingui() 37 + 38 + const requireAltTextEnabled = useRequireAltTextEnabled() 39 + const setRequireAltTextEnabled = useSetRequireAltTextEnabled() 40 + const autoplayDisabled = useAutoplayDisabled() 41 + const setAutoplayDisabled = useSetAutoplayDisabled() 42 + const hapticsDisabled = useHapticsDisabled() 43 + const setHapticsDisabled = useSetHapticsDisabled() 44 + 45 + useFocusEffect( 46 + React.useCallback(() => { 47 + screen('PreferencesExternalEmbeds') 48 + setMinimalShellMode(false) 49 + }, [screen, setMinimalShellMode]), 50 + ) 51 + 52 + return ( 53 + <View style={s.hContentRegion} testID="accessibilitySettingsScreen"> 54 + <SimpleViewHeader 55 + showBackButton={isMobile} 56 + style={[ 57 + pal.border, 58 + {borderBottomWidth: 1}, 59 + !isMobile && {borderLeftWidth: 1, borderRightWidth: 1}, 60 + ]}> 61 + <View style={{flex: 1}}> 62 + <Text type="title-lg" style={[pal.text, {fontWeight: 'bold'}]}> 63 + <Trans>Accessibility Settings</Trans> 64 + </Text> 65 + </View> 66 + </SimpleViewHeader> 67 + <ScrollView 68 + // @ts-ignore web only -prf 69 + dataSet={{'stable-gutters': 1}} 70 + style={s.flex1} 71 + contentContainerStyle={[ 72 + s.flex1, 73 + {paddingBottom: 200}, 74 + isMobile && pal.viewLight, 75 + ]}> 76 + <Text type="xl-bold" style={[pal.text, styles.heading]}> 77 + <Trans>Alt text</Trans> 78 + </Text> 79 + <View style={[pal.view, styles.toggleCard]}> 80 + <ToggleButton 81 + type="default-light" 82 + label={_(msg`Require alt text before posting`)} 83 + labelType="lg" 84 + isSelected={requireAltTextEnabled} 85 + onPress={() => setRequireAltTextEnabled(!requireAltTextEnabled)} 86 + /> 87 + </View> 88 + <Text type="xl-bold" style={[pal.text, styles.heading]}> 89 + <Trans>Media</Trans> 90 + </Text> 91 + <View style={[pal.view, styles.toggleCard]}> 92 + <ToggleButton 93 + type="default-light" 94 + label={_(msg`Disable autoplay for GIFs`)} 95 + labelType="lg" 96 + isSelected={autoplayDisabled} 97 + onPress={() => setAutoplayDisabled(!autoplayDisabled)} 98 + /> 99 + </View> 100 + {isNative && ( 101 + <> 102 + <Text type="xl-bold" style={[pal.text, styles.heading]}> 103 + <Trans>Haptics</Trans> 104 + </Text> 105 + <View style={[pal.view, styles.toggleCard]}> 106 + <ToggleButton 107 + type="default-light" 108 + label={_(msg`Disable haptic feedback`)} 109 + labelType="lg" 110 + isSelected={hapticsDisabled} 111 + onPress={() => setHapticsDisabled(!hapticsDisabled)} 112 + /> 113 + </View> 114 + </> 115 + )} 116 + </ScrollView> 117 + </View> 118 + ) 119 + } 120 + 121 + const styles = StyleSheet.create({ 122 + heading: { 123 + paddingHorizontal: 18, 124 + paddingTop: 14, 125 + paddingBottom: 6, 126 + }, 127 + toggleCard: { 128 + paddingVertical: 8, 129 + paddingHorizontal: 6, 130 + marginBottom: 1, 131 + }, 132 + })
+29 -42
src/view/screens/Settings/index.tsx
··· 20 20 import {useFocusEffect, useNavigation} from '@react-navigation/native' 21 21 import {useQueryClient} from '@tanstack/react-query' 22 22 23 - import {isIOS, isNative} from '#/platform/detection' 23 + import {isNative} from '#/platform/detection' 24 24 import {useModalControls} from '#/state/modals' 25 25 import {clearLegacyStorage} from '#/state/persisted/legacy' 26 26 import {clear as clearStorage} from '#/state/persisted/store' 27 - import { 28 - useRequireAltTextEnabled, 29 - useSetRequireAltTextEnabled, 30 - } from '#/state/preferences' 31 27 import { 32 28 useInAppBrowser, 33 29 useSetInAppBrowser, ··· 56 52 import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types' 57 53 import {NavigationProp} from 'lib/routes/types' 58 54 import {colors, s} from 'lib/styles' 59 - import { 60 - useHapticsDisabled, 61 - useSetHapticsDisabled, 62 - } from 'state/preferences/disable-haptics' 63 55 import {AccountDropdownBtn} from 'view/com/util/AccountDropdownBtn' 64 56 import {SelectableBtn} from 'view/com/util/forms/SelectableBtn' 65 57 import {ToggleButton} from 'view/com/util/forms/ToggleButton' ··· 162 154 const pal = usePalette('default') 163 155 const {_} = useLingui() 164 156 const setMinimalShellMode = useSetMinimalShellMode() 165 - const requireAltTextEnabled = useRequireAltTextEnabled() 166 - const setRequireAltTextEnabled = useSetRequireAltTextEnabled() 167 157 const inAppBrowserPref = useInAppBrowser() 168 158 const setUseInAppBrowser = useSetInAppBrowser() 169 - const isHapticsDisabled = useHapticsDisabled() 170 - const setHapticsDisabled = useSetHapticsDisabled() 171 159 const onboardingDispatch = useOnboardingDispatch() 172 160 const navigation = useNavigation<NavigationProp>() 173 161 const {isMobile} = useWebMediaQueries() ··· 280 268 281 269 const onPressSavedFeeds = React.useCallback(() => { 282 270 navigation.navigate('SavedFeeds') 271 + }, [navigation]) 272 + 273 + const onPressAccessibilitySettings = React.useCallback(() => { 274 + navigation.navigate('AccessibilitySettings') 283 275 }, [navigation]) 284 276 285 277 const onPressStatusPage = React.useCallback(() => { ··· 318 310 </View> 319 311 </SimpleViewHeader> 320 312 <ScrollView 321 - style={[s.hContentRegion]} 313 + style={s.hContentRegion} 322 314 contentContainerStyle={isMobile && pal.viewLight} 323 315 scrollIndicatorInsets={{right: 1}} 324 316 // @ts-ignore web only -prf ··· 418 410 <View style={styles.spacer20} /> 419 411 420 412 <Text type="xl-bold" style={[pal.text, styles.heading]}> 421 - <Trans>Accessibility</Trans> 422 - </Text> 423 - <View style={[pal.view, styles.toggleCard]}> 424 - <ToggleButton 425 - type="default-light" 426 - label={_(msg`Require alt text before posting`)} 427 - labelType="lg" 428 - isSelected={requireAltTextEnabled} 429 - onPress={() => setRequireAltTextEnabled(!requireAltTextEnabled)} 430 - /> 431 - </View> 432 - 433 - <View style={styles.spacer20} /> 434 - 435 - <Text type="xl-bold" style={[pal.text, styles.heading]}> 436 413 <Trans>Appearance</Trans> 437 414 </Text> 438 415 <View> ··· 493 470 <Trans>Basics</Trans> 494 471 </Text> 495 472 <TouchableOpacity 473 + testID="accessibilitySettingsBtn" 474 + style={[ 475 + styles.linkCard, 476 + pal.view, 477 + isSwitchingAccounts && styles.dimmed, 478 + ]} 479 + onPress={ 480 + isSwitchingAccounts ? undefined : onPressAccessibilitySettings 481 + } 482 + accessibilityRole="button" 483 + accessibilityLabel={_(msg`Accessibility settings`)} 484 + accessibilityHint={_(msg`Opens accessibility settings`)}> 485 + <View style={[styles.iconContainer, pal.btn]}> 486 + <FontAwesomeIcon 487 + icon="universal-access" 488 + style={pal.text as FontAwesomeIconStyle} 489 + /> 490 + </View> 491 + <Text type="lg" style={pal.text}> 492 + <Trans>Accessibility</Trans> 493 + </Text> 494 + </TouchableOpacity> 495 + <TouchableOpacity 496 496 testID="preferencesHomeFeedButton" 497 497 style={[ 498 498 styles.linkCard, ··· 686 686 labelType="lg" 687 687 isSelected={inAppBrowserPref ?? false} 688 688 onPress={() => setUseInAppBrowser(!inAppBrowserPref)} 689 - /> 690 - </View> 691 - )} 692 - {isNative && ( 693 - <View style={[pal.view, styles.toggleCard]}> 694 - <ToggleButton 695 - type="default-light" 696 - label={ 697 - isIOS ? _(msg`Disable haptics`) : _(msg`Disable vibrations`) 698 - } 699 - labelType="lg" 700 - isSelected={isHapticsDisabled} 701 - onPress={() => setHapticsDisabled(!isHapticsDisabled)} 702 689 /> 703 690 </View> 704 691 )}