tooot/src/components/Timeline/Shared/Actions.tsx

341 lines
11 KiB
TypeScript
Raw Normal View History

import Icon from '@components/Icon'
2021-02-28 22:49:55 +01:00
import { displayMessage } from '@components/Message'
import CustomText from '@components/Text'
2022-10-31 23:43:42 +01:00
import { useActionSheet } from '@expo/react-native-action-sheet'
2022-12-19 22:36:30 +01:00
import { androidActionSheetStyles } from '@helpers/androidActionSheetStyles'
2020-12-07 12:31:40 +01:00
import { useNavigation } from '@react-navigation/native'
2022-04-30 21:47:17 +02:00
import { StackNavigationProp } from '@react-navigation/stack'
import { RootStackParamList } from '@utils/navigation/navigators'
2021-01-11 21:36:57 +01:00
import {
MutationVarsTimelineUpdateStatusProperty,
QueryKeyTimeline,
useTimelineMutation
} from '@utils/queryHooks/timeline'
2022-12-03 20:47:11 +01:00
import { getInstanceAccount } from '@utils/slices/instancesSlice'
2021-01-01 16:48:16 +01:00
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
2022-12-03 20:47:11 +01:00
import { uniqBy } from 'lodash'
import React, { useCallback, useContext, useMemo } from 'react'
2021-01-01 23:10:47 +01:00
import { useTranslation } from 'react-i18next'
import { Pressable, StyleSheet, View } from 'react-native'
import { useQueryClient } from '@tanstack/react-query'
2022-12-03 20:47:11 +01:00
import { useSelector } from 'react-redux'
import StatusContext from './Context'
2022-12-03 20:47:11 +01:00
const TimelineActions: React.FC = () => {
2022-12-05 14:50:03 +01:00
const { queryKey, rootQueryKey, status, reblogStatus, ownAccount, highlighted, disableDetails } =
2022-12-03 20:47:11 +01:00
useContext(StatusContext)
if (!queryKey || !status || disableDetails) return null
2022-04-30 21:47:17 +02:00
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>()
2022-12-23 15:53:40 +01:00
const { t } = useTranslation(['common', 'componentTimeline'])
2022-02-12 14:51:01 +01:00
const { colors, theme } = useTheme()
const iconColor = colors.secondary
2020-11-23 00:07:32 +01:00
const queryClient = useQueryClient()
const mutation = useTimelineMutation({
onMutate: true,
onSuccess: (_, params) => {
const theParams = params as MutationVarsTimelineUpdateStatusProperty
if (
// Un-bookmark from bookmarks page
2022-10-31 21:54:24 +01:00
(queryKey[1].page === 'Bookmarks' && theParams.payload.property === 'bookmarked') ||
// Un-favourite from favourites page
2022-10-31 21:54:24 +01:00
(queryKey[1].page === 'Favourites' && theParams.payload.property === 'favourited')
) {
2021-01-12 00:12:44 +01:00
queryClient.invalidateQueries(queryKey)
} else if (theParams.payload.property === 'favourited') {
// When favourited, update favourited page
2022-10-31 21:54:24 +01:00
const tempQueryKey: QueryKeyTimeline = ['Timeline', { page: 'Favourites' }]
queryClient.invalidateQueries(tempQueryKey)
} else if (theParams.payload.property === 'bookmarked') {
// When bookmarked, update bookmark page
2022-10-31 21:54:24 +01:00
const tempQueryKey: QueryKeyTimeline = ['Timeline', { page: 'Bookmarks' }]
queryClient.invalidateQueries(tempQueryKey)
2021-01-24 02:25:43 +01:00
}
},
2022-12-23 15:53:40 +01:00
onError: (err: any, params) => {
const correctParam = params as MutationVarsTimelineUpdateStatusProperty
displayMessage({
2022-02-12 14:51:01 +01:00
theme,
type: 'error',
2021-03-28 23:31:10 +02:00
message: t('common:message.error.message', {
2022-12-23 15:53:40 +01:00
function: t(`componentTimeline:shared.actions.${correctParam.payload.property}.function`)
}),
...(err.status &&
typeof err.status === 'number' &&
err.data &&
err.data.error &&
typeof err.data.error === 'string' && {
description: err.data.error
})
2021-03-06 21:01:38 +01:00
})
queryClient.invalidateQueries(queryKey)
}
})
2022-12-03 20:47:11 +01:00
const instanceAccount = useSelector(getInstanceAccount, () => true)
const onPressReply = useCallback(() => {
const accts = uniqBy(
([status.account] as Mastodon.Account[] & Mastodon.Mention[])
.concat(status.mentions)
.filter(d => d?.id !== instanceAccount?.id),
d => d?.id
).map(d => d?.acct)
navigation.navigate('Screen-Compose', {
type: 'reply',
incomingStatus: status,
accts,
queryKey
})
}, [status.replies_count])
2022-10-31 23:43:42 +01:00
const { showActionSheetWithOptions } = useActionSheet()
const onPressReblog = useCallback(() => {
2022-10-31 23:43:42 +01:00
if (!status.reblogged) {
showActionSheetWithOptions(
{
2022-12-23 15:53:40 +01:00
title: t('componentTimeline:shared.actions.reblogged.options.title'),
2022-10-31 23:43:42 +01:00
options: [
2022-12-23 15:53:40 +01:00
t('componentTimeline:shared.actions.reblogged.options.public'),
t('componentTimeline:shared.actions.reblogged.options.unlisted'),
2022-10-31 23:43:42 +01:00
t('common:buttons.cancel')
],
2022-12-19 22:36:30 +01:00
cancelButtonIndex: 2,
...androidActionSheetStyles(colors)
2022-10-31 23:43:42 +01:00
},
(selectedIndex: number) => {
switch (selectedIndex) {
case 0:
mutation.mutate({
type: 'updateStatusProperty',
queryKey,
rootQueryKey,
id: status.id,
2022-12-05 14:50:03 +01:00
isReblog: !!reblogStatus,
2022-10-31 23:43:42 +01:00
payload: {
property: 'reblogged',
currentValue: status.reblogged,
propertyCount: 'reblogs_count',
countValue: status.reblogs_count,
visibility: 'public'
}
})
break
case 1:
mutation.mutate({
type: 'updateStatusProperty',
queryKey,
rootQueryKey,
id: status.id,
2022-12-05 14:50:03 +01:00
isReblog: !!reblogStatus,
2022-10-31 23:43:42 +01:00
payload: {
property: 'reblogged',
currentValue: status.reblogged,
propertyCount: 'reblogs_count',
countValue: status.reblogs_count,
visibility: 'unlisted'
}
})
break
}
}
)
} else {
mutation.mutate({
type: 'updateStatusProperty',
queryKey,
rootQueryKey,
id: status.id,
2022-12-05 14:50:03 +01:00
isReblog: !!reblogStatus,
2022-10-31 23:43:42 +01:00
payload: {
property: 'reblogged',
currentValue: status.reblogged,
propertyCount: 'reblogs_count',
countValue: status.reblogs_count,
visibility: 'public'
}
})
}
}, [status.reblogged, status.reblogs_count])
const onPressFavourite = useCallback(() => {
mutation.mutate({
type: 'updateStatusProperty',
queryKey,
rootQueryKey,
id: status.id,
2022-12-05 14:50:03 +01:00
isReblog: !!reblogStatus,
payload: {
property: 'favourited',
currentValue: status.favourited,
propertyCount: 'favourites_count',
countValue: status.favourites_count
}
})
}, [status.favourited, status.favourites_count])
const onPressBookmark = useCallback(() => {
mutation.mutate({
type: 'updateStatusProperty',
queryKey,
rootQueryKey,
id: status.id,
2022-12-05 14:50:03 +01:00
isReblog: !!reblogStatus,
payload: {
property: 'bookmarked',
currentValue: status.bookmarked,
propertyCount: undefined,
countValue: undefined
}
})
}, [status.bookmarked])
2021-03-06 21:01:38 +01:00
const childrenReply = useMemo(
() => (
<>
2022-10-31 21:54:24 +01:00
<Icon name='MessageCircle' color={iconColor} size={StyleConstants.Font.Size.L} />
2021-06-11 23:07:41 +02:00
{status.replies_count > 0 ? (
<CustomText
style={{
2022-02-12 14:51:01 +01:00
color: colors.secondary,
fontSize: StyleConstants.Font.Size.M,
marginLeft: StyleConstants.Spacing.XS
}}
>
{status.replies_count}
</CustomText>
2021-06-11 23:07:41 +02:00
) : null}
</>
),
[status.replies_count]
)
const childrenReblog = useMemo(() => {
2022-02-12 14:51:01 +01:00
const color = (state: boolean) => (state ? colors.green : colors.secondary)
return (
<>
<Icon
name='Repeat'
color={
2022-10-31 21:54:24 +01:00
status.visibility === 'direct' || (status.visibility === 'private' && !ownAccount)
2022-02-12 14:51:01 +01:00
? colors.disabled
: color(status.reblogged)
}
size={StyleConstants.Font.Size.L}
/>
2021-06-11 23:07:41 +02:00
{status.reblogs_count > 0 ? (
<CustomText
style={{
color:
status.visibility === 'private' && !ownAccount
? colors.disabled
: color(status.reblogged),
fontSize: StyleConstants.Font.Size.M,
marginLeft: StyleConstants.Spacing.XS
}}
>
{status.reblogs_count}
</CustomText>
2021-06-11 23:07:41 +02:00
) : null}
</>
2021-03-06 21:01:38 +01:00
)
}, [status.reblogged, status.reblogs_count])
const childrenFavourite = useMemo(() => {
2022-02-12 14:51:01 +01:00
const color = (state: boolean) => (state ? colors.red : colors.secondary)
return (
<>
2022-10-31 21:54:24 +01:00
<Icon name='Heart' color={color(status.favourited)} size={StyleConstants.Font.Size.L} />
2021-06-11 23:07:41 +02:00
{status.favourites_count > 0 ? (
<CustomText
style={{
color: color(status.favourited),
fontSize: StyleConstants.Font.Size.M,
marginLeft: StyleConstants.Spacing.XS,
marginTop: 0
}}
>
{status.favourites_count}
</CustomText>
2021-06-11 23:07:41 +02:00
) : null}
</>
)
}, [status.favourited, status.favourites_count])
const childrenBookmark = useMemo(() => {
2022-02-12 14:51:01 +01:00
const color = (state: boolean) => (state ? colors.yellow : colors.secondary)
2021-03-06 21:01:38 +01:00
return (
2022-10-31 21:54:24 +01:00
<Icon name='Bookmark' color={color(status.bookmarked)} size={StyleConstants.Font.Size.L} />
)
}, [status.bookmarked])
return (
2022-12-18 23:15:58 +01:00
<View style={{ flexDirection: 'row' }}>
<Pressable
{...(highlighted
? {
2022-12-23 15:53:40 +01:00
accessibilityLabel: t('componentTimeline:shared.actions.reply.accessibilityLabel'),
2022-12-18 23:15:58 +01:00
accessibilityRole: 'button'
}
: { accessibilityLabel: '' })}
style={styles.action}
onPress={onPressReply}
children={childrenReply}
/>
2022-12-18 23:15:58 +01:00
<Pressable
{...(highlighted
? {
2022-12-23 15:53:40 +01:00
accessibilityLabel: t(
'componentTimeline:shared.actions.reblogged.accessibilityLabel'
),
2022-12-18 23:15:58 +01:00
accessibilityRole: 'button'
}
: { accessibilityLabel: '' })}
style={styles.action}
onPress={onPressReblog}
children={childrenReblog}
disabled={
status.visibility === 'direct' || (status.visibility === 'private' && !ownAccount)
}
/>
2022-12-18 23:15:58 +01:00
<Pressable
{...(highlighted
? {
2022-12-23 15:53:40 +01:00
accessibilityLabel: t(
'componentTimeline:shared.actions.favourited.accessibilityLabel'
),
2022-12-18 23:15:58 +01:00
accessibilityRole: 'button'
}
: { accessibilityLabel: '' })}
style={styles.action}
onPress={onPressFavourite}
children={childrenFavourite}
/>
2022-12-18 23:15:58 +01:00
<Pressable
{...(highlighted
? {
2022-12-23 15:53:40 +01:00
accessibilityLabel: t(
'componentTimeline:shared.actions.bookmarked.accessibilityLabel'
),
2022-12-18 23:15:58 +01:00
accessibilityRole: 'button'
}
: { accessibilityLabel: '' })}
style={styles.action}
onPress={onPressBookmark}
children={childrenBookmark}
/>
</View>
)
}
const styles = StyleSheet.create({
action: {
2021-01-19 01:13:45 +01:00
flex: 1,
flexDirection: 'row',
2021-01-01 16:48:16 +01:00
justifyContent: 'center',
2021-01-20 00:39:39 +01:00
alignItems: 'center',
2021-05-19 23:28:01 +02:00
minHeight: StyleConstants.Font.Size.L + StyleConstants.Spacing.S * 3,
2021-03-15 00:18:44 +01:00
marginHorizontal: StyleConstants.Spacing.S
}
})
2020-12-03 01:28:56 +01:00
export default TimelineActions