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 {PostMeta} from '../util/PostMeta'
|
||||
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 {ContentHider} from '../util/moderation/ContentHider'
|
||||
import {ImageHider} from '../util/moderation/ImageHider'
|
||||
|
|
|
@ -20,7 +20,7 @@ import {Link} from '../util/Link'
|
|||
import {UserInfoText} from '../util/UserInfoText'
|
||||
import {PostMeta} from '../util/PostMeta'
|
||||
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 {ContentHider} from '../util/moderation/ContentHider'
|
||||
import {ImageHider} from '../util/moderation/ImageHider'
|
||||
|
|
|
@ -13,7 +13,7 @@ import {Link, DesktopWebTextLink} from '../util/Link'
|
|||
import {Text} from '../util/text/Text'
|
||||
import {UserInfoText} from '../util/UserInfoText'
|
||||
import {PostMeta} from '../util/PostMeta'
|
||||
import {PostCtrls} from '../util/PostCtrls'
|
||||
import {PostCtrls} from '../util/post-ctrls/PostCtrls'
|
||||
import {PostEmbeds} from '../util/post-embeds'
|
||||
import {PostHider} from '../util/moderation/PostHider'
|
||||
import {ContentHider} from '../util/moderation/ContentHider'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react'
|
||||
import React, {useCallback} from 'react'
|
||||
import {
|
||||
StyleProp,
|
||||
StyleSheet,
|
||||
|
@ -18,18 +18,14 @@ import ReactNativeHapticFeedback, {
|
|||
// TriggerableAnimated,
|
||||
// TriggerableAnimatedRef,
|
||||
// } from './anim/TriggerableAnimated'
|
||||
import {Text} from './text/Text'
|
||||
import {PostDropdownBtn} from './forms/DropdownButton'
|
||||
import {
|
||||
HeartIcon,
|
||||
HeartIconSolid,
|
||||
RepostIcon,
|
||||
CommentBottomArrow,
|
||||
} from 'lib/icons'
|
||||
import {Text} from '../text/Text'
|
||||
import {PostDropdownBtn} from '../forms/DropdownButton'
|
||||
import {HeartIcon, HeartIconSolid, CommentBottomArrow} from 'lib/icons'
|
||||
import {s, colors} from 'lib/styles'
|
||||
import {useTheme} from 'lib/ThemeContext'
|
||||
import {useStores} from 'state/index'
|
||||
import {isIOS} from 'platform/detection'
|
||||
import {isIOS, isNative} from 'platform/detection'
|
||||
import {RepostButton} from './RepostButton'
|
||||
|
||||
interface PostCtrlsOpts {
|
||||
itemUri: string
|
||||
|
@ -112,10 +108,12 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
|||
// DISABLED see #135
|
||||
// const repostRef = React.useRef<TriggerableAnimatedRef | null>(null)
|
||||
// const likeRef = React.useRef<TriggerableAnimatedRef | null>(null)
|
||||
const onRepost = () => {
|
||||
const onRepost = useCallback(() => {
|
||||
store.shell.closeModal()
|
||||
if (!opts.isReposted) {
|
||||
ReactNativeHapticFeedback.trigger(hapticImpact)
|
||||
if (isNative) {
|
||||
ReactNativeHapticFeedback.trigger(hapticImpact)
|
||||
}
|
||||
opts.onPressToggleRepost().catch(_e => undefined)
|
||||
// DISABLED see #135
|
||||
// repostRef.current?.trigger(
|
||||
|
@ -128,9 +126,9 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
|||
} else {
|
||||
opts.onPressToggleRepost().catch(_e => undefined)
|
||||
}
|
||||
}
|
||||
}, [opts, store.shell])
|
||||
|
||||
const onQuote = () => {
|
||||
const onQuote = useCallback(() => {
|
||||
store.shell.closeModal()
|
||||
store.shell.openComposer({
|
||||
quote: {
|
||||
|
@ -141,17 +139,18 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
|||
indexedAt: opts.indexedAt,
|
||||
},
|
||||
})
|
||||
ReactNativeHapticFeedback.trigger(hapticImpact)
|
||||
}
|
||||
|
||||
const onPressToggleRepostWrapper = () => {
|
||||
store.shell.openModal({
|
||||
name: 'repost',
|
||||
onRepost: onRepost,
|
||||
onQuote: onQuote,
|
||||
isReposted: opts.isReposted,
|
||||
})
|
||||
}
|
||||
if (isNative) {
|
||||
ReactNativeHapticFeedback.trigger(hapticImpact)
|
||||
}
|
||||
}, [
|
||||
opts.author,
|
||||
opts.indexedAt,
|
||||
opts.itemCid,
|
||||
opts.itemUri,
|
||||
opts.text,
|
||||
store.shell,
|
||||
])
|
||||
|
||||
const onPressToggleLikeWrapper = async () => {
|
||||
if (!opts.isLiked) {
|
||||
|
@ -181,7 +180,7 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
|||
onPress={opts.onPressReply}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Reply"
|
||||
accessibilityHint="Opens reply composer">
|
||||
accessibilityHint="reply composer">
|
||||
<CommentBottomArrow
|
||||
style={[defaultCtrlColor, opts.big ? s.mt2 : styles.mt1]}
|
||||
strokeWidth={3}
|
||||
|
@ -193,39 +192,7 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
|||
</Text>
|
||||
) : undefined}
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
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>
|
||||
<RepostButton {...opts} onRepost={onRepost} onQuote={onQuote} />
|
||||
<TouchableOpacity
|
||||
testID="likeBtn"
|
||||
style={styles.ctrl}
|
||||
|
@ -234,9 +201,7 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
|||
accessibilityRole="button"
|
||||
accessibilityLabel={opts.isLiked ? 'Unlike' : 'Like'}
|
||||
accessibilityHint={
|
||||
opts.isReposted
|
||||
? `Removes like from ${opts.author}'s post`
|
||||
: `Like ${opts.author}'s post`
|
||||
opts.isReposted ? `Removes like from the post` : `Like the post`
|
||||
}>
|
||||
{opts.isLiked ? (
|
||||
<HeartIconSolid
|
||||
|
@ -309,9 +274,6 @@ const styles = StyleSheet.create({
|
|||
padding: 5,
|
||||
margin: -5,
|
||||
},
|
||||
ctrlIconReposted: {
|
||||
color: colors.green3,
|
||||
},
|
||||
ctrlIconLiked: {
|
||||
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