Add ability to reply, repost (without quote post), and like posts using VoiceOver (#765)
Co-authored-by: Paul Frazee <pfrazee@gmail.com>zio/stable
parent
7458b6f600
commit
a9a661ab58
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react'
|
import React, {useCallback, useMemo} from 'react'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {Linking, StyleSheet, View} from 'react-native'
|
import {Linking, StyleSheet, View} from 'react-native'
|
||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
|
@ -133,6 +133,40 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
)
|
)
|
||||||
}, [item, store])
|
}, [item, store])
|
||||||
|
|
||||||
|
const accessibilityActions = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
name: 'reply',
|
||||||
|
label: 'Reply',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'repost',
|
||||||
|
label: item.post.viewer?.repost ? 'Undo repost' : 'Repost',
|
||||||
|
},
|
||||||
|
{name: 'like', label: item.post.viewer?.like ? 'Unlike' : 'Like'},
|
||||||
|
],
|
||||||
|
[item.post.viewer?.like, item.post.viewer?.repost],
|
||||||
|
)
|
||||||
|
|
||||||
|
const onAccessibilityAction = useCallback(
|
||||||
|
event => {
|
||||||
|
switch (event.nativeEvent.actionName) {
|
||||||
|
case 'like':
|
||||||
|
onPressToggleLike()
|
||||||
|
break
|
||||||
|
case 'reply':
|
||||||
|
onPressReply()
|
||||||
|
break
|
||||||
|
case 'repost':
|
||||||
|
onPressToggleRepost()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onPressReply, onPressToggleLike, onPressToggleRepost],
|
||||||
|
)
|
||||||
|
|
||||||
if (!record) {
|
if (!record) {
|
||||||
return <ErrorMessage message="Invalid or unsupported post record" />
|
return <ErrorMessage message="Invalid or unsupported post record" />
|
||||||
}
|
}
|
||||||
|
@ -154,7 +188,9 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
<PostHider
|
<PostHider
|
||||||
testID={`postThreadItem-by-${item.post.author.handle}`}
|
testID={`postThreadItem-by-${item.post.author.handle}`}
|
||||||
style={[styles.outer, styles.outerHighlighted, pal.border, pal.view]}
|
style={[styles.outer, styles.outerHighlighted, pal.border, pal.view]}
|
||||||
moderation={item.moderation.thread}>
|
moderation={item.moderation.thread}
|
||||||
|
accessibilityActions={accessibilityActions}
|
||||||
|
onAccessibilityAction={onAccessibilityAction}>
|
||||||
<View style={styles.layout}>
|
<View style={styles.layout}>
|
||||||
<View style={styles.layoutAvi}>
|
<View style={styles.layoutAvi}>
|
||||||
<Link
|
<Link
|
||||||
|
@ -324,7 +360,9 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
pal.view,
|
pal.view,
|
||||||
item._showParentReplyLine && styles.noTopBorder,
|
item._showParentReplyLine && styles.noTopBorder,
|
||||||
]}
|
]}
|
||||||
moderation={item.moderation.thread}>
|
moderation={item.moderation.thread}
|
||||||
|
accessibilityActions={accessibilityActions}
|
||||||
|
onAccessibilityAction={onAccessibilityAction}>
|
||||||
{item._showParentReplyLine && (
|
{item._showParentReplyLine && (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {useState, useEffect} from 'react'
|
import React, {useCallback, useEffect, useMemo, useState} from 'react'
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
Linking,
|
Linking,
|
||||||
|
@ -205,11 +205,47 @@ const PostLoaded = observer(
|
||||||
)
|
)
|
||||||
}, [item, setDeleted, store])
|
}, [item, setDeleted, store])
|
||||||
|
|
||||||
|
const accessibilityActions = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
name: 'reply',
|
||||||
|
label: 'Reply',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'repost',
|
||||||
|
label: item.post.viewer?.repost ? 'Undo repost' : 'Repost',
|
||||||
|
},
|
||||||
|
{name: 'like', label: item.post.viewer?.like ? 'Unlike' : 'Like'},
|
||||||
|
],
|
||||||
|
[item.post.viewer?.like, item.post.viewer?.repost],
|
||||||
|
)
|
||||||
|
|
||||||
|
const onAccessibilityAction = useCallback(
|
||||||
|
event => {
|
||||||
|
switch (event.nativeEvent.actionName) {
|
||||||
|
case 'like':
|
||||||
|
onPressToggleLike()
|
||||||
|
break
|
||||||
|
case 'reply':
|
||||||
|
onPressReply()
|
||||||
|
break
|
||||||
|
case 'repost':
|
||||||
|
onPressToggleRepost()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onPressReply, onPressToggleLike, onPressToggleRepost],
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PostHider
|
<PostHider
|
||||||
href={itemHref}
|
href={itemHref}
|
||||||
style={[styles.outer, pal.view, pal.border, style]}
|
style={[styles.outer, pal.view, pal.border, style]}
|
||||||
moderation={item.moderation.list}>
|
moderation={item.moderation.list}
|
||||||
|
accessibilityActions={accessibilityActions}
|
||||||
|
onAccessibilityAction={onAccessibilityAction}>
|
||||||
{showReplyLine && <View style={styles.replyLine} />}
|
{showReplyLine && <View style={styles.replyLine} />}
|
||||||
<View style={styles.layout}>
|
<View style={styles.layout}>
|
||||||
<View style={styles.layoutAvi}>
|
<View style={styles.layoutAvi}>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {useMemo, useState} from 'react'
|
import React, {useCallback, useMemo, useState} from 'react'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {Linking, StyleSheet, View} from 'react-native'
|
import {Linking, StyleSheet, View} from 'react-native'
|
||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
|
@ -158,12 +158,48 @@ export const FeedItem = observer(function ({
|
||||||
moderation = {behavior: ModerationBehaviorCode.Show}
|
moderation = {behavior: ModerationBehaviorCode.Show}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const accessibilityActions = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
name: 'reply',
|
||||||
|
label: 'Reply',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'repost',
|
||||||
|
label: item.post.viewer?.repost ? 'Undo repost' : 'Repost',
|
||||||
|
},
|
||||||
|
{name: 'like', label: item.post.viewer?.like ? 'Unlike' : 'Like'},
|
||||||
|
],
|
||||||
|
[item.post.viewer?.like, item.post.viewer?.repost],
|
||||||
|
)
|
||||||
|
|
||||||
|
const onAccessibilityAction = useCallback(
|
||||||
|
event => {
|
||||||
|
switch (event.nativeEvent.actionName) {
|
||||||
|
case 'like':
|
||||||
|
onPressToggleLike()
|
||||||
|
break
|
||||||
|
case 'reply':
|
||||||
|
onPressReply()
|
||||||
|
break
|
||||||
|
case 'repost':
|
||||||
|
onPressToggleRepost()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onPressReply, onPressToggleLike, onPressToggleRepost],
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PostHider
|
<PostHider
|
||||||
testID={`feedItem-by-${item.post.author.handle}`}
|
testID={`feedItem-by-${item.post.author.handle}`}
|
||||||
style={outerStyles}
|
style={outerStyles}
|
||||||
href={itemHref}
|
href={itemHref}
|
||||||
moderation={moderation}>
|
moderation={moderation}
|
||||||
|
accessibilityActions={accessibilityActions}
|
||||||
|
onAccessibilityAction={onAccessibilityAction}>
|
||||||
{isThreadChild && (
|
{isThreadChild && (
|
||||||
<View
|
<View
|
||||||
style={[styles.topReplyLine, {borderColor: pal.colors.replyLine}]}
|
style={[styles.topReplyLine, {borderColor: pal.colors.replyLine}]}
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
import React from 'react'
|
import React, {ComponentProps} from 'react'
|
||||||
import {
|
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||||
StyleProp,
|
|
||||||
StyleSheet,
|
|
||||||
TouchableOpacity,
|
|
||||||
View,
|
|
||||||
ViewStyle,
|
|
||||||
} from 'react-native'
|
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {Link} from '../Link'
|
import {Link} from '../Link'
|
||||||
|
@ -13,18 +7,21 @@ import {Text} from '../text/Text'
|
||||||
import {addStyle} from 'lib/styles'
|
import {addStyle} from 'lib/styles'
|
||||||
import {ModerationBehaviorCode, ModerationBehavior} from 'lib/labeling/types'
|
import {ModerationBehaviorCode, ModerationBehavior} from 'lib/labeling/types'
|
||||||
|
|
||||||
|
interface Props extends ComponentProps<typeof Link> {
|
||||||
|
// testID?: string
|
||||||
|
// href?: string
|
||||||
|
// style: StyleProp<ViewStyle>
|
||||||
|
moderation: ModerationBehavior
|
||||||
|
}
|
||||||
|
|
||||||
export function PostHider({
|
export function PostHider({
|
||||||
testID,
|
testID,
|
||||||
href,
|
href,
|
||||||
moderation,
|
moderation,
|
||||||
style,
|
style,
|
||||||
children,
|
children,
|
||||||
}: React.PropsWithChildren<{
|
...props
|
||||||
testID?: string
|
}: Props) {
|
||||||
href?: string
|
|
||||||
moderation: ModerationBehavior
|
|
||||||
style: StyleProp<ViewStyle>
|
|
||||||
}>) {
|
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const [override, setOverride] = React.useState(false)
|
const [override, setOverride] = React.useState(false)
|
||||||
const bg = override ? pal.viewLight : pal.view
|
const bg = override ? pal.viewLight : pal.view
|
||||||
|
@ -70,7 +67,14 @@ export function PostHider({
|
||||||
|
|
||||||
// NOTE: any further label enforcement should occur in ContentContainer
|
// NOTE: any further label enforcement should occur in ContentContainer
|
||||||
return (
|
return (
|
||||||
<Link testID={testID} style={style} href={href} noFeedback>
|
<Link
|
||||||
|
testID={testID}
|
||||||
|
style={style}
|
||||||
|
href={href}
|
||||||
|
noFeedback
|
||||||
|
accessible={true}
|
||||||
|
accessibilityRole="none"
|
||||||
|
{...props}>
|
||||||
{children}
|
{children}
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
|
|
|
@ -191,9 +191,7 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
onPress={onPressToggleLikeWrapper}
|
onPress={onPressToggleLikeWrapper}
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel={opts.isLiked ? 'Unlike' : 'Like'}
|
accessibilityLabel={opts.isLiked ? 'Unlike' : 'Like'}
|
||||||
accessibilityHint={
|
accessibilityHint="">
|
||||||
opts.isReposted ? 'Removes like from the post' : 'Like the post'
|
|
||||||
}>
|
|
||||||
{opts.isLiked ? (
|
{opts.isLiked ? (
|
||||||
<HeartIconSolid
|
<HeartIconSolid
|
||||||
style={styles.ctrlIconLiked}
|
style={styles.ctrlIconLiked}
|
||||||
|
|
|
@ -50,11 +50,7 @@ export const RepostButton = ({
|
||||||
style={styles.control}
|
style={styles.control}
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel={isReposted ? 'Undo repost' : 'Repost'}
|
accessibilityLabel={isReposted ? 'Undo repost' : 'Repost'}
|
||||||
accessibilityHint={
|
accessibilityHint="">
|
||||||
isReposted
|
|
||||||
? `Remove your repost of the post`
|
|
||||||
: `Repost or quote post the post`
|
|
||||||
}>
|
|
||||||
<RepostIcon
|
<RepostIcon
|
||||||
style={
|
style={
|
||||||
isReposted
|
isReposted
|
||||||
|
|
Loading…
Reference in New Issue