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

307 lines
9.4 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'
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 { useQueryClient } from '@tanstack/react-query'
import { androidActionSheetStyles } from '@utils/helpers/androidActionSheetStyles'
2023-01-04 22:39:29 +01:00
import { RootStackParamList, useNavState } from '@utils/navigation/navigators'
2021-01-11 21:36:57 +01:00
import {
MutationVarsTimelineUpdateStatusProperty,
QueryKeyTimeline,
useTimelineMutation
} from '@utils/queryHooks/timeline'
import { useAccountStorage } from '@utils/storage/actions'
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, { useContext } from 'react'
2021-01-01 23:10:47 +01:00
import { useTranslation } from 'react-i18next'
import { Pressable, StyleSheet, View } from 'react-native'
2022-12-03 20:47:11 +01:00
import StatusContext from './Context'
2022-12-03 20:47:11 +01:00
const TimelineActions: React.FC = () => {
const { queryKey, status, isMyAccount, highlighted, disableDetails } = useContext(StatusContext)
2022-12-03 20:47:11 +01:00
if (!queryKey || !status || disableDetails) return null
2023-01-04 22:39:29 +01:00
const navigationState = useNavState()
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'])
2023-01-08 16:59:35 +01:00
const { colors } = useTheme()
2022-02-12 14:51:01 +01:00
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
2023-01-01 18:37:05 +01:00
(queryKey[1].page === 'Bookmarks' && theParams.payload.type === 'bookmarked') ||
// Un-favourite from favourites page
2023-01-01 18:37:05 +01:00
(queryKey[1].page === 'Favourites' && theParams.payload.type === 'favourited')
) {
2021-01-12 00:12:44 +01:00
queryClient.invalidateQueries(queryKey)
2023-01-01 18:37:05 +01:00
} else if (theParams.payload.type === 'favourited') {
// When favourited, update favourited page
2022-10-31 21:54:24 +01:00
const tempQueryKey: QueryKeyTimeline = ['Timeline', { page: 'Favourites' }]
queryClient.invalidateQueries(tempQueryKey)
2023-01-01 18:37:05 +01:00
} else if (theParams.payload.type === '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({
type: 'error',
2021-03-28 23:31:10 +02:00
message: t('common:message.error.message', {
2022-12-23 18:49:50 +01:00
function: t(
2023-01-01 18:37:05 +01:00
`componentTimeline:shared.actions.${correctParam.payload.type}.function` as any
2022-12-23 18:49:50 +01:00
)
}),
...(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)
}
})
const [accountId] = useAccountStorage.string('auth.account.id')
const onPressReply = () => {
2022-12-03 20:47:11 +01:00
const accts = uniqBy(
([status.account] as Mastodon.Account[] & Mastodon.Mention[])
.concat(status.mentions)
.filter(d => d?.id !== accountId),
2022-12-03 20:47:11 +01:00
d => d?.id
).map(d => d?.acct)
navigation.navigate('Screen-Compose', {
type: 'reply',
incomingStatus: status,
accts,
2023-01-04 22:39:29 +01:00
navigationState
2022-12-03 20:47:11 +01:00
})
}
2022-10-31 23:43:42 +01:00
const { showActionSheetWithOptions } = useActionSheet()
const onPressReblog = () => {
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
},
2023-02-11 22:04:32 +01:00
selectedIndex => {
2022-10-31 23:43:42 +01:00
switch (selectedIndex) {
case 0:
mutation.mutate({
type: 'updateStatusProperty',
2023-01-01 18:37:05 +01:00
status,
2022-10-31 23:43:42 +01:00
payload: {
2023-01-01 18:37:05 +01:00
type: 'reblogged',
2023-01-02 23:18:22 +01:00
visibility: 'public',
to: true
2022-10-31 23:43:42 +01:00
}
})
break
case 1:
mutation.mutate({
type: 'updateStatusProperty',
2023-01-01 18:37:05 +01:00
status,
2022-10-31 23:43:42 +01:00
payload: {
2023-01-01 18:37:05 +01:00
type: 'reblogged',
2023-01-02 23:18:22 +01:00
visibility: 'unlisted',
to: true
2022-10-31 23:43:42 +01:00
}
})
break
}
}
)
} else {
mutation.mutate({
type: 'updateStatusProperty',
2023-01-01 18:37:05 +01:00
status,
2022-10-31 23:43:42 +01:00
payload: {
2023-01-01 18:37:05 +01:00
type: 'reblogged',
2023-01-02 23:18:22 +01:00
visibility: 'public',
to: false
2022-10-31 23:43:42 +01:00
}
})
}
}
const onPressFavourite = () => {
mutation.mutate({
type: 'updateStatusProperty',
2023-01-01 18:37:05 +01:00
status,
payload: {
2023-01-02 23:18:22 +01:00
type: 'favourited',
to: !status.favourited
}
})
}
const onPressBookmark = () => {
mutation.mutate({
type: 'updateStatusProperty',
2023-01-01 18:37:05 +01:00
status,
payload: {
2023-01-02 23:18:22 +01:00
type: 'bookmarked',
to: !status.bookmarked
}
})
}
2021-03-06 21:01:38 +01:00
const childrenReply = () => (
<>
<Icon name='message-circle' color={iconColor} size={StyleConstants.Font.Size.L} />
{status.replies_count > 0 ? (
<CustomText
2023-01-06 01:08:27 +01:00
fontStyle='S'
style={{
color: colors.secondary,
marginLeft: StyleConstants.Spacing.XS
}}
>
{status.replies_count}
</CustomText>
) : null}
</>
)
const childrenReblog = () => {
2022-02-12 14:51:01 +01:00
const color = (state: boolean) => (state ? colors.green : colors.secondary)
const disabled =
status.visibility === 'direct' || (status.visibility === 'private' && !isMyAccount)
return (
<>
<Icon
name='repeat'
color={disabled ? colors.disabled : color(status.reblogged)}
crossOut={disabled}
size={StyleConstants.Font.Size.L}
/>
2021-06-11 23:07:41 +02:00
{status.reblogs_count > 0 ? (
<CustomText
2023-01-06 01:08:27 +01:00
fontStyle='S'
style={{
color:
status.visibility === 'private' && !isMyAccount
? colors.disabled
: color(status.reblogged),
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
)
}
const childrenFavourite = () => {
2022-02-12 14:51:01 +01:00
const color = (state: boolean) => (state ? colors.red : colors.secondary)
return (
<>
<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
2023-01-06 01:08:27 +01:00
fontStyle='S'
style={{ color: color(status.favourited), marginLeft: StyleConstants.Spacing.XS }}
>
{status.favourites_count}
</CustomText>
2021-06-11 23:07:41 +02:00
) : null}
</>
)
}
const childrenBookmark = () => {
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 (
<Icon name='bookmark' color={color(status.bookmarked)} size={StyleConstants.Font.Size.L} />
)
}
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
/>
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()}
2022-12-18 23:15:58 +01:00
disabled={
status.visibility === 'direct' || (status.visibility === 'private' && !isMyAccount)
2022-12-18 23:15:58 +01:00
}
/>
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
/>
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()}
2022-12-18 23:15:58 +01:00
/>
</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',
2022-12-31 00:07:28 +01:00
paddingVertical: StyleConstants.Spacing.S * 1.5
}
})
2020-12-03 01:28:56 +01:00
export default TimelineActions