Use dropdown for web reposting and quote posting (#607)
* Use dropdown for web reposting and quote posting * Remove collateral damage * Tune the repost dropdown positioning * Move postctrls into their own folder * Factor out repost button into native/web build --------- Co-authored-by: Paul Frazee <pfrazee@gmail.com>zio/stable
parent
0a0afdf2c2
commit
628d877325
|
@ -21,7 +21,7 @@ import {pluralize} from 'lib/strings/helpers'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {PostMeta} from '../util/PostMeta'
|
import {PostMeta} from '../util/PostMeta'
|
||||||
import {PostEmbeds} from '../util/post-embeds'
|
import {PostEmbeds} from '../util/post-embeds'
|
||||||
import {PostCtrls} from '../util/PostCtrls'
|
import {PostCtrls} from '../util/post-ctrls/PostCtrls'
|
||||||
import {PostHider} from '../util/moderation/PostHider'
|
import {PostHider} from '../util/moderation/PostHider'
|
||||||
import {ContentHider} from '../util/moderation/ContentHider'
|
import {ContentHider} from '../util/moderation/ContentHider'
|
||||||
import {ImageHider} from '../util/moderation/ImageHider'
|
import {ImageHider} from '../util/moderation/ImageHider'
|
||||||
|
|
|
@ -20,7 +20,7 @@ import {Link} from '../util/Link'
|
||||||
import {UserInfoText} from '../util/UserInfoText'
|
import {UserInfoText} from '../util/UserInfoText'
|
||||||
import {PostMeta} from '../util/PostMeta'
|
import {PostMeta} from '../util/PostMeta'
|
||||||
import {PostEmbeds} from '../util/post-embeds'
|
import {PostEmbeds} from '../util/post-embeds'
|
||||||
import {PostCtrls} from '../util/PostCtrls'
|
import {PostCtrls} from '../util/post-ctrls/PostCtrls'
|
||||||
import {PostHider} from '../util/moderation/PostHider'
|
import {PostHider} from '../util/moderation/PostHider'
|
||||||
import {ContentHider} from '../util/moderation/ContentHider'
|
import {ContentHider} from '../util/moderation/ContentHider'
|
||||||
import {ImageHider} from '../util/moderation/ImageHider'
|
import {ImageHider} from '../util/moderation/ImageHider'
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {Link, DesktopWebTextLink} from '../util/Link'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
import {UserInfoText} from '../util/UserInfoText'
|
import {UserInfoText} from '../util/UserInfoText'
|
||||||
import {PostMeta} from '../util/PostMeta'
|
import {PostMeta} from '../util/PostMeta'
|
||||||
import {PostCtrls} from '../util/PostCtrls'
|
import {PostCtrls} from '../util/post-ctrls/PostCtrls'
|
||||||
import {PostEmbeds} from '../util/post-embeds'
|
import {PostEmbeds} from '../util/post-embeds'
|
||||||
import {PostHider} from '../util/moderation/PostHider'
|
import {PostHider} from '../util/moderation/PostHider'
|
||||||
import {ContentHider} from '../util/moderation/ContentHider'
|
import {ContentHider} from '../util/moderation/ContentHider'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react'
|
import React, {useCallback} from 'react'
|
||||||
import {
|
import {
|
||||||
StyleProp,
|
StyleProp,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
|
@ -18,18 +18,14 @@ import ReactNativeHapticFeedback, {
|
||||||
// TriggerableAnimated,
|
// TriggerableAnimated,
|
||||||
// TriggerableAnimatedRef,
|
// TriggerableAnimatedRef,
|
||||||
// } from './anim/TriggerableAnimated'
|
// } from './anim/TriggerableAnimated'
|
||||||
import {Text} from './text/Text'
|
import {Text} from '../text/Text'
|
||||||
import {PostDropdownBtn} from './forms/DropdownButton'
|
import {PostDropdownBtn} from '../forms/DropdownButton'
|
||||||
import {
|
import {HeartIcon, HeartIconSolid, CommentBottomArrow} from 'lib/icons'
|
||||||
HeartIcon,
|
|
||||||
HeartIconSolid,
|
|
||||||
RepostIcon,
|
|
||||||
CommentBottomArrow,
|
|
||||||
} from 'lib/icons'
|
|
||||||
import {s, colors} from 'lib/styles'
|
import {s, colors} from 'lib/styles'
|
||||||
import {useTheme} from 'lib/ThemeContext'
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {isIOS} from 'platform/detection'
|
import {isIOS, isNative} from 'platform/detection'
|
||||||
|
import {RepostButton} from './RepostButton'
|
||||||
|
|
||||||
interface PostCtrlsOpts {
|
interface PostCtrlsOpts {
|
||||||
itemUri: string
|
itemUri: string
|
||||||
|
@ -112,10 +108,12 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
// DISABLED see #135
|
// DISABLED see #135
|
||||||
// const repostRef = React.useRef<TriggerableAnimatedRef | null>(null)
|
// const repostRef = React.useRef<TriggerableAnimatedRef | null>(null)
|
||||||
// const likeRef = React.useRef<TriggerableAnimatedRef | null>(null)
|
// const likeRef = React.useRef<TriggerableAnimatedRef | null>(null)
|
||||||
const onRepost = () => {
|
const onRepost = useCallback(() => {
|
||||||
store.shell.closeModal()
|
store.shell.closeModal()
|
||||||
if (!opts.isReposted) {
|
if (!opts.isReposted) {
|
||||||
|
if (isNative) {
|
||||||
ReactNativeHapticFeedback.trigger(hapticImpact)
|
ReactNativeHapticFeedback.trigger(hapticImpact)
|
||||||
|
}
|
||||||
opts.onPressToggleRepost().catch(_e => undefined)
|
opts.onPressToggleRepost().catch(_e => undefined)
|
||||||
// DISABLED see #135
|
// DISABLED see #135
|
||||||
// repostRef.current?.trigger(
|
// repostRef.current?.trigger(
|
||||||
|
@ -128,9 +126,9 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
} else {
|
} else {
|
||||||
opts.onPressToggleRepost().catch(_e => undefined)
|
opts.onPressToggleRepost().catch(_e => undefined)
|
||||||
}
|
}
|
||||||
}
|
}, [opts, store.shell])
|
||||||
|
|
||||||
const onQuote = () => {
|
const onQuote = useCallback(() => {
|
||||||
store.shell.closeModal()
|
store.shell.closeModal()
|
||||||
store.shell.openComposer({
|
store.shell.openComposer({
|
||||||
quote: {
|
quote: {
|
||||||
|
@ -141,17 +139,18 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
indexedAt: opts.indexedAt,
|
indexedAt: opts.indexedAt,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (isNative) {
|
||||||
ReactNativeHapticFeedback.trigger(hapticImpact)
|
ReactNativeHapticFeedback.trigger(hapticImpact)
|
||||||
}
|
}
|
||||||
|
}, [
|
||||||
const onPressToggleRepostWrapper = () => {
|
opts.author,
|
||||||
store.shell.openModal({
|
opts.indexedAt,
|
||||||
name: 'repost',
|
opts.itemCid,
|
||||||
onRepost: onRepost,
|
opts.itemUri,
|
||||||
onQuote: onQuote,
|
opts.text,
|
||||||
isReposted: opts.isReposted,
|
store.shell,
|
||||||
})
|
])
|
||||||
}
|
|
||||||
|
|
||||||
const onPressToggleLikeWrapper = async () => {
|
const onPressToggleLikeWrapper = async () => {
|
||||||
if (!opts.isLiked) {
|
if (!opts.isLiked) {
|
||||||
|
@ -181,7 +180,7 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
onPress={opts.onPressReply}
|
onPress={opts.onPressReply}
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel="Reply"
|
accessibilityLabel="Reply"
|
||||||
accessibilityHint="Opens reply composer">
|
accessibilityHint="reply composer">
|
||||||
<CommentBottomArrow
|
<CommentBottomArrow
|
||||||
style={[defaultCtrlColor, opts.big ? s.mt2 : styles.mt1]}
|
style={[defaultCtrlColor, opts.big ? s.mt2 : styles.mt1]}
|
||||||
strokeWidth={3}
|
strokeWidth={3}
|
||||||
|
@ -193,39 +192,7 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
</Text>
|
</Text>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity
|
<RepostButton {...opts} onRepost={onRepost} onQuote={onQuote} />
|
||||||
testID="repostBtn"
|
|
||||||
hitSlop={HITSLOP}
|
|
||||||
onPress={onPressToggleRepostWrapper}
|
|
||||||
style={styles.ctrl}
|
|
||||||
accessibilityRole="button"
|
|
||||||
accessibilityLabel={opts.isReposted ? 'Undo repost' : 'Repost'}
|
|
||||||
accessibilityHint={
|
|
||||||
opts.isReposted
|
|
||||||
? `Remove your repost of ${opts.author}'s post`
|
|
||||||
: `Repost or quote post ${opts.author}'s post`
|
|
||||||
}>
|
|
||||||
<RepostIcon
|
|
||||||
style={
|
|
||||||
opts.isReposted
|
|
||||||
? (styles.ctrlIconReposted as StyleProp<ViewStyle>)
|
|
||||||
: defaultCtrlColor
|
|
||||||
}
|
|
||||||
strokeWidth={2.4}
|
|
||||||
size={opts.big ? 24 : 20}
|
|
||||||
/>
|
|
||||||
{typeof opts.repostCount !== 'undefined' ? (
|
|
||||||
<Text
|
|
||||||
testID="repostCount"
|
|
||||||
style={
|
|
||||||
opts.isReposted
|
|
||||||
? [s.bold, s.green3, s.f15, s.ml5]
|
|
||||||
: [defaultCtrlColor, s.f15, s.ml5]
|
|
||||||
}>
|
|
||||||
{opts.repostCount}
|
|
||||||
</Text>
|
|
||||||
) : undefined}
|
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
testID="likeBtn"
|
testID="likeBtn"
|
||||||
style={styles.ctrl}
|
style={styles.ctrl}
|
||||||
|
@ -234,9 +201,7 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel={opts.isLiked ? 'Unlike' : 'Like'}
|
accessibilityLabel={opts.isLiked ? 'Unlike' : 'Like'}
|
||||||
accessibilityHint={
|
accessibilityHint={
|
||||||
opts.isReposted
|
opts.isReposted ? `Removes like from the post` : `Like the post`
|
||||||
? `Removes like from ${opts.author}'s post`
|
|
||||||
: `Like ${opts.author}'s post`
|
|
||||||
}>
|
}>
|
||||||
{opts.isLiked ? (
|
{opts.isLiked ? (
|
||||||
<HeartIconSolid
|
<HeartIconSolid
|
||||||
|
@ -309,9 +274,6 @@ const styles = StyleSheet.create({
|
||||||
padding: 5,
|
padding: 5,
|
||||||
margin: -5,
|
margin: -5,
|
||||||
},
|
},
|
||||||
ctrlIconReposted: {
|
|
||||||
color: colors.green3,
|
|
||||||
},
|
|
||||||
ctrlIconLiked: {
|
ctrlIconLiked: {
|
||||||
color: colors.red3,
|
color: colors.red3,
|
||||||
},
|
},
|
|
@ -0,0 +1,95 @@
|
||||||
|
import React, {useCallback} from 'react'
|
||||||
|
import {StyleProp, StyleSheet, TouchableOpacity, ViewStyle} from 'react-native'
|
||||||
|
import {RepostIcon} from 'lib/icons'
|
||||||
|
import {s, colors} from 'lib/styles'
|
||||||
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
|
import {Text} from '../text/Text'
|
||||||
|
import {useStores} from 'state/index'
|
||||||
|
|
||||||
|
const HITSLOP = {top: 5, left: 5, bottom: 5, right: 5}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isReposted: boolean
|
||||||
|
repostCount?: number
|
||||||
|
big?: boolean
|
||||||
|
onRepost: () => void
|
||||||
|
onQuote: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RepostButton = ({
|
||||||
|
isReposted,
|
||||||
|
repostCount,
|
||||||
|
big,
|
||||||
|
onRepost,
|
||||||
|
onQuote,
|
||||||
|
}: Props) => {
|
||||||
|
const store = useStores()
|
||||||
|
const theme = useTheme()
|
||||||
|
|
||||||
|
const defaultControlColor = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
color: theme.palette.default.postCtrl,
|
||||||
|
}),
|
||||||
|
[theme],
|
||||||
|
)
|
||||||
|
|
||||||
|
const onPressToggleRepostWrapper = useCallback(() => {
|
||||||
|
store.shell.openModal({
|
||||||
|
name: 'repost',
|
||||||
|
onRepost: onRepost,
|
||||||
|
onQuote: onQuote,
|
||||||
|
isReposted,
|
||||||
|
})
|
||||||
|
}, [onRepost, onQuote, isReposted, store.shell])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
testID="repostBtn"
|
||||||
|
hitSlop={HITSLOP}
|
||||||
|
onPress={onPressToggleRepostWrapper}
|
||||||
|
style={styles.control}
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel={isReposted ? 'Undo repost' : 'Repost'}
|
||||||
|
accessibilityHint={
|
||||||
|
isReposted
|
||||||
|
? `Remove your repost of the post`
|
||||||
|
: `Repost or quote post the post`
|
||||||
|
}>
|
||||||
|
<RepostIcon
|
||||||
|
style={
|
||||||
|
isReposted
|
||||||
|
? (styles.reposted as StyleProp<ViewStyle>)
|
||||||
|
: defaultControlColor
|
||||||
|
}
|
||||||
|
strokeWidth={2.4}
|
||||||
|
size={big ? 24 : 20}
|
||||||
|
/>
|
||||||
|
{typeof repostCount !== 'undefined' ? (
|
||||||
|
<Text
|
||||||
|
testID="repostCount"
|
||||||
|
style={
|
||||||
|
isReposted
|
||||||
|
? [s.bold, s.green3, s.f15, s.ml5]
|
||||||
|
: [defaultControlColor, s.f15, s.ml5]
|
||||||
|
}>
|
||||||
|
{repostCount}
|
||||||
|
</Text>
|
||||||
|
) : undefined}
|
||||||
|
</TouchableOpacity>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
control: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: 5,
|
||||||
|
margin: -5,
|
||||||
|
},
|
||||||
|
reposted: {
|
||||||
|
color: colors.green3,
|
||||||
|
},
|
||||||
|
repostCount: {
|
||||||
|
color: 'currentColor',
|
||||||
|
},
|
||||||
|
})
|
|
@ -0,0 +1,86 @@
|
||||||
|
import React, {useMemo} from 'react'
|
||||||
|
import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
|
||||||
|
import {RepostIcon} from 'lib/icons'
|
||||||
|
import {DropdownButton} from '../forms/DropdownButton'
|
||||||
|
import {colors} from 'lib/styles'
|
||||||
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
|
import {Text} from '../text/Text'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isReposted: boolean
|
||||||
|
repostCount?: number
|
||||||
|
big?: boolean
|
||||||
|
onRepost: () => void
|
||||||
|
onQuote: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RepostButton = ({
|
||||||
|
isReposted,
|
||||||
|
repostCount,
|
||||||
|
big,
|
||||||
|
onRepost,
|
||||||
|
onQuote,
|
||||||
|
}: Props) => {
|
||||||
|
const theme = useTheme()
|
||||||
|
|
||||||
|
const defaultControlColor = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
color: theme.palette.default.postCtrl,
|
||||||
|
}),
|
||||||
|
[theme],
|
||||||
|
)
|
||||||
|
|
||||||
|
const items = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
label: isReposted ? 'Undo repost' : 'Repost',
|
||||||
|
icon: 'retweet' as const,
|
||||||
|
onPress: onRepost,
|
||||||
|
},
|
||||||
|
{label: 'Quote post', icon: 'quote-left' as const, onPress: onQuote},
|
||||||
|
],
|
||||||
|
[isReposted, onRepost, onQuote],
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownButton
|
||||||
|
type="bare"
|
||||||
|
items={items}
|
||||||
|
bottomOffset={4}
|
||||||
|
openToRight
|
||||||
|
rightOffset={-40}>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.control,
|
||||||
|
(isReposted
|
||||||
|
? styles.reposted
|
||||||
|
: defaultControlColor) as StyleProp<ViewStyle>,
|
||||||
|
]}>
|
||||||
|
<RepostIcon strokeWidth={2.4} size={big ? 24 : 20} />
|
||||||
|
{typeof repostCount !== 'undefined' ? (
|
||||||
|
<Text
|
||||||
|
testID="repostCount"
|
||||||
|
type={isReposted ? 'md-bold' : 'md-medium'}
|
||||||
|
style={styles.repostCount}>
|
||||||
|
{repostCount ?? 0}
|
||||||
|
</Text>
|
||||||
|
) : undefined}
|
||||||
|
</View>
|
||||||
|
</DropdownButton>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
control: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 4,
|
||||||
|
},
|
||||||
|
reposted: {
|
||||||
|
color: colors.green3,
|
||||||
|
},
|
||||||
|
repostCount: {
|
||||||
|
color: 'currentColor',
|
||||||
|
},
|
||||||
|
})
|
Loading…
Reference in New Issue