An ATproto social media client -- with an independent Appview.
6
fork

Configure Feed

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

Add ability to reply, repost (without quote post), and like posts using VoiceOver (#765)

Co-authored-by: Paul Frazee <pfrazee@gmail.com>

authored by

Ollie H
Paul Frazee
and committed by
GitHub
a9a661ab 7458b6f6

+138 -30
+41 -3
src/view/com/post-thread/PostThreadItem.tsx
··· 1 - import React from 'react' 1 + import React, {useCallback, useMemo} from 'react' 2 2 import {observer} from 'mobx-react-lite' 3 3 import {Linking, StyleSheet, View} from 'react-native' 4 4 import Clipboard from '@react-native-clipboard/clipboard' ··· 133 133 ) 134 134 }, [item, store]) 135 135 136 + const accessibilityActions = useMemo( 137 + () => [ 138 + { 139 + name: 'reply', 140 + label: 'Reply', 141 + }, 142 + { 143 + name: 'repost', 144 + label: item.post.viewer?.repost ? 'Undo repost' : 'Repost', 145 + }, 146 + {name: 'like', label: item.post.viewer?.like ? 'Unlike' : 'Like'}, 147 + ], 148 + [item.post.viewer?.like, item.post.viewer?.repost], 149 + ) 150 + 151 + const onAccessibilityAction = useCallback( 152 + event => { 153 + switch (event.nativeEvent.actionName) { 154 + case 'like': 155 + onPressToggleLike() 156 + break 157 + case 'reply': 158 + onPressReply() 159 + break 160 + case 'repost': 161 + onPressToggleRepost() 162 + break 163 + default: 164 + break 165 + } 166 + }, 167 + [onPressReply, onPressToggleLike, onPressToggleRepost], 168 + ) 169 + 136 170 if (!record) { 137 171 return <ErrorMessage message="Invalid or unsupported post record" /> 138 172 } ··· 154 188 <PostHider 155 189 testID={`postThreadItem-by-${item.post.author.handle}`} 156 190 style={[styles.outer, styles.outerHighlighted, pal.border, pal.view]} 157 - moderation={item.moderation.thread}> 191 + moderation={item.moderation.thread} 192 + accessibilityActions={accessibilityActions} 193 + onAccessibilityAction={onAccessibilityAction}> 158 194 <View style={styles.layout}> 159 195 <View style={styles.layoutAvi}> 160 196 <Link ··· 324 360 pal.view, 325 361 item._showParentReplyLine && styles.noTopBorder, 326 362 ]} 327 - moderation={item.moderation.thread}> 363 + moderation={item.moderation.thread} 364 + accessibilityActions={accessibilityActions} 365 + onAccessibilityAction={onAccessibilityAction}> 328 366 {item._showParentReplyLine && ( 329 367 <View 330 368 style={[
+38 -2
src/view/com/post/Post.tsx
··· 1 - import React, {useState, useEffect} from 'react' 1 + import React, {useCallback, useEffect, useMemo, useState} from 'react' 2 2 import { 3 3 ActivityIndicator, 4 4 Linking, ··· 205 205 ) 206 206 }, [item, setDeleted, store]) 207 207 208 + const accessibilityActions = useMemo( 209 + () => [ 210 + { 211 + name: 'reply', 212 + label: 'Reply', 213 + }, 214 + { 215 + name: 'repost', 216 + label: item.post.viewer?.repost ? 'Undo repost' : 'Repost', 217 + }, 218 + {name: 'like', label: item.post.viewer?.like ? 'Unlike' : 'Like'}, 219 + ], 220 + [item.post.viewer?.like, item.post.viewer?.repost], 221 + ) 222 + 223 + const onAccessibilityAction = useCallback( 224 + event => { 225 + switch (event.nativeEvent.actionName) { 226 + case 'like': 227 + onPressToggleLike() 228 + break 229 + case 'reply': 230 + onPressReply() 231 + break 232 + case 'repost': 233 + onPressToggleRepost() 234 + break 235 + default: 236 + break 237 + } 238 + }, 239 + [onPressReply, onPressToggleLike, onPressToggleRepost], 240 + ) 241 + 208 242 return ( 209 243 <PostHider 210 244 href={itemHref} 211 245 style={[styles.outer, pal.view, pal.border, style]} 212 - moderation={item.moderation.list}> 246 + moderation={item.moderation.list} 247 + accessibilityActions={accessibilityActions} 248 + onAccessibilityAction={onAccessibilityAction}> 213 249 {showReplyLine && <View style={styles.replyLine} />} 214 250 <View style={styles.layout}> 215 251 <View style={styles.layoutAvi}>
+38 -2
src/view/com/posts/FeedItem.tsx
··· 1 - import React, {useMemo, useState} from 'react' 1 + import React, {useCallback, useMemo, useState} from 'react' 2 2 import {observer} from 'mobx-react-lite' 3 3 import {Linking, StyleSheet, View} from 'react-native' 4 4 import Clipboard from '@react-native-clipboard/clipboard' ··· 158 158 moderation = {behavior: ModerationBehaviorCode.Show} 159 159 } 160 160 161 + const accessibilityActions = useMemo( 162 + () => [ 163 + { 164 + name: 'reply', 165 + label: 'Reply', 166 + }, 167 + { 168 + name: 'repost', 169 + label: item.post.viewer?.repost ? 'Undo repost' : 'Repost', 170 + }, 171 + {name: 'like', label: item.post.viewer?.like ? 'Unlike' : 'Like'}, 172 + ], 173 + [item.post.viewer?.like, item.post.viewer?.repost], 174 + ) 175 + 176 + const onAccessibilityAction = useCallback( 177 + event => { 178 + switch (event.nativeEvent.actionName) { 179 + case 'like': 180 + onPressToggleLike() 181 + break 182 + case 'reply': 183 + onPressReply() 184 + break 185 + case 'repost': 186 + onPressToggleRepost() 187 + break 188 + default: 189 + break 190 + } 191 + }, 192 + [onPressReply, onPressToggleLike, onPressToggleRepost], 193 + ) 194 + 161 195 return ( 162 196 <PostHider 163 197 testID={`feedItem-by-${item.post.author.handle}`} 164 198 style={outerStyles} 165 199 href={itemHref} 166 - moderation={moderation}> 200 + moderation={moderation} 201 + accessibilityActions={accessibilityActions} 202 + onAccessibilityAction={onAccessibilityAction}> 167 203 {isThreadChild && ( 168 204 <View 169 205 style={[styles.topReplyLine, {borderColor: pal.colors.replyLine}]}
+19 -15
src/view/com/util/moderation/PostHider.tsx
··· 1 - import React from 'react' 2 - import { 3 - StyleProp, 4 - StyleSheet, 5 - TouchableOpacity, 6 - View, 7 - ViewStyle, 8 - } from 'react-native' 1 + import React, {ComponentProps} from 'react' 2 + import {StyleSheet, TouchableOpacity, View} from 'react-native' 9 3 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 10 4 import {usePalette} from 'lib/hooks/usePalette' 11 5 import {Link} from '../Link' ··· 13 7 import {addStyle} from 'lib/styles' 14 8 import {ModerationBehaviorCode, ModerationBehavior} from 'lib/labeling/types' 15 9 10 + interface Props extends ComponentProps<typeof Link> { 11 + // testID?: string 12 + // href?: string 13 + // style: StyleProp<ViewStyle> 14 + moderation: ModerationBehavior 15 + } 16 + 16 17 export function PostHider({ 17 18 testID, 18 19 href, 19 20 moderation, 20 21 style, 21 22 children, 22 - }: React.PropsWithChildren<{ 23 - testID?: string 24 - href?: string 25 - moderation: ModerationBehavior 26 - style: StyleProp<ViewStyle> 27 - }>) { 23 + ...props 24 + }: Props) { 28 25 const pal = usePalette('default') 29 26 const [override, setOverride] = React.useState(false) 30 27 const bg = override ? pal.viewLight : pal.view ··· 70 67 71 68 // NOTE: any further label enforcement should occur in ContentContainer 72 69 return ( 73 - <Link testID={testID} style={style} href={href} noFeedback> 70 + <Link 71 + testID={testID} 72 + style={style} 73 + href={href} 74 + noFeedback 75 + accessible={true} 76 + accessibilityRole="none" 77 + {...props}> 74 78 {children} 75 79 </Link> 76 80 )
+1 -3
src/view/com/util/post-ctrls/PostCtrls.tsx
··· 191 191 onPress={onPressToggleLikeWrapper} 192 192 accessibilityRole="button" 193 193 accessibilityLabel={opts.isLiked ? 'Unlike' : 'Like'} 194 - accessibilityHint={ 195 - opts.isReposted ? 'Removes like from the post' : 'Like the post' 196 - }> 194 + accessibilityHint=""> 197 195 {opts.isLiked ? ( 198 196 <HeartIconSolid 199 197 style={styles.ctrlIconLiked}
+1 -5
src/view/com/util/post-ctrls/RepostButton.tsx
··· 50 50 style={styles.control} 51 51 accessibilityRole="button" 52 52 accessibilityLabel={isReposted ? 'Undo repost' : 'Repost'} 53 - accessibilityHint={ 54 - isReposted 55 - ? `Remove your repost of the post` 56 - : `Repost or quote post the post` 57 - }> 53 + accessibilityHint=""> 58 54 <RepostIcon 59 55 style={ 60 56 isReposted