1
0
mirror of https://github.com/tooot-app/app synced 2025-06-05 22:19:13 +02:00

Merge branch 'main' into candidate

This commit is contained in:
xmflsct
2022-10-31 23:44:17 +01:00
7 changed files with 161 additions and 105 deletions

View File

@ -9,6 +9,7 @@ import {
import { getInstanceAccount } from '@utils/slices/instancesSlice' import { getInstanceAccount } from '@utils/slices/instancesSlice'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Platform } from 'react-native'
import { ContextMenuAction } from 'react-native-context-menu-view' import { ContextMenuAction } from 'react-native-context-menu-view'
import { useQueryClient } from 'react-query' import { useQueryClient } from 'react-query'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
@ -94,7 +95,33 @@ const contextMenuAccount = ({
context: (relationship?.muting || false).toString() context: (relationship?.muting || false).toString()
}), }),
systemIcon: 'eye.slash' systemIcon: 'eye.slash'
}
)
switch (Platform.OS) {
case 'ios':
actions.push({
id: 'account',
title: t('account.title'),
actions: [
{
id: 'account-block',
title: t('account.block.action', {
context: (relationship?.blocking || false).toString()
}),
systemIcon: 'xmark.circle',
destructive: true
}, },
{
id: 'account-reports',
title: t('account.reports.action'),
systemIcon: 'flag',
destructive: true
}
]
})
break
default:
actions.push(
{ {
id: 'account-block', id: 'account-block',
title: t('account.block.action', { title: t('account.block.action', {
@ -110,6 +137,8 @@ const contextMenuAccount = ({
destructive: true destructive: true
} }
) )
break
}
} }
return (index: number) => { return (index: number) => {

View File

@ -54,9 +54,6 @@ const EmojisList = () => {
const addedLength = spaceFront.length + shortcode.length + spaceRear.length const addedLength = spaceFront.length + shortcode.length + spaceRear.length
setSelection({ start: selection.start + addedLength }) setSelection({ start: selection.start + addedLength })
ref?.current?.setNativeProps({
selection: { start: selection.start + addedLength }
})
} }
const listItem = ({ index, item }: { item: Mastodon.Emoji[]; index: number }) => { const listItem = ({ index, item }: { item: Mastodon.Emoji[]; index: number }) => {

View File

@ -33,7 +33,7 @@ const RelationshipOutgoing = React.memo(
queryKeyRelationship, queryKeyRelationship,
[res] [res]
) )
if (action === 'follow' || action === 'block') { if (action === 'block') {
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Following' }] const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Following' }]
queryClient.invalidateQueries(queryKey) queryClient.invalidateQueries(queryKey)
} }

View File

@ -2,6 +2,7 @@ import analytics from '@components/analytics'
import Icon from '@components/Icon' import Icon from '@components/Icon'
import { displayMessage } from '@components/Message' import { displayMessage } from '@components/Message'
import CustomText from '@components/Text' import CustomText from '@components/Text'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { useNavigation } from '@react-navigation/native' import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack' import { StackNavigationProp } from '@react-navigation/stack'
import { RootStackParamList } from '@utils/navigation/navigators' import { RootStackParamList } from '@utils/navigation/navigators'
@ -48,40 +49,18 @@ const TimelineActions: React.FC<Props> = ({
const theParams = params as MutationVarsTimelineUpdateStatusProperty const theParams = params as MutationVarsTimelineUpdateStatusProperty
if ( if (
// Un-bookmark from bookmarks page // Un-bookmark from bookmarks page
(queryKey[1].page === 'Bookmarks' && (queryKey[1].page === 'Bookmarks' && theParams.payload.property === 'bookmarked') ||
theParams.payload.property === 'bookmarked') ||
// Un-favourite from favourites page // Un-favourite from favourites page
(queryKey[1].page === 'Favourites' && (queryKey[1].page === 'Favourites' && theParams.payload.property === 'favourited')
theParams.payload.property === 'favourited') ||
// Un-reblog from following page
(queryKey[1].page === 'Following' &&
theParams.payload.property === 'reblogged' &&
theParams.payload.currentValue === true)
) { ) {
queryClient.invalidateQueries(queryKey) queryClient.invalidateQueries(queryKey)
} else if (
theParams.payload.property === 'reblogged' &&
queryKey[1].page !== 'Following'
) {
// When reblogged, update cache of following page
const tempQueryKey: QueryKeyTimeline = [
'Timeline',
{ page: 'Following' }
]
queryClient.invalidateQueries(tempQueryKey)
} else if (theParams.payload.property === 'favourited') { } else if (theParams.payload.property === 'favourited') {
// When favourited, update favourited page // When favourited, update favourited page
const tempQueryKey: QueryKeyTimeline = [ const tempQueryKey: QueryKeyTimeline = ['Timeline', { page: 'Favourites' }]
'Timeline',
{ page: 'Favourites' }
]
queryClient.invalidateQueries(tempQueryKey) queryClient.invalidateQueries(tempQueryKey)
} else if (theParams.payload.property === 'bookmarked') { } else if (theParams.payload.property === 'bookmarked') {
// When bookmarked, update bookmark page // When bookmarked, update bookmark page
const tempQueryKey: QueryKeyTimeline = [ const tempQueryKey: QueryKeyTimeline = ['Timeline', { page: 'Bookmarks' }]
'Timeline',
{ page: 'Bookmarks' }
]
queryClient.invalidateQueries(tempQueryKey) queryClient.invalidateQueries(tempQueryKey)
} }
}, },
@ -91,9 +70,7 @@ const TimelineActions: React.FC<Props> = ({
theme, theme,
type: 'error', type: 'error',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t( function: t(`shared.actions.${correctParam.payload.property}.function`)
`shared.actions.${correctParam.payload.property}.function`
)
}), }),
...(err.status && ...(err.status &&
typeof err.status === 'number' && typeof err.status === 'number' &&
@ -119,7 +96,67 @@ const TimelineActions: React.FC<Props> = ({
queryKey queryKey
}) })
}, [status.replies_count]) }, [status.replies_count])
const { showActionSheetWithOptions } = useActionSheet()
const onPressReblog = useCallback(() => { const onPressReblog = useCallback(() => {
if (!status.reblogged) {
showActionSheetWithOptions(
{
title: t('shared.actions.reblogged.options.title'),
options: [
t('shared.actions.reblogged.options.public'),
t('shared.actions.reblogged.options.unlisted'),
t('common:buttons.cancel')
],
cancelButtonIndex: 2
},
(selectedIndex: number) => {
switch (selectedIndex) {
case 0:
analytics('timeline_shared_actions_reblog_public_press', {
page: queryKey[1].page,
count: status.reblogs_count,
current: status.reblogged
})
mutation.mutate({
type: 'updateStatusProperty',
queryKey,
rootQueryKey,
id: status.id,
reblog,
payload: {
property: 'reblogged',
currentValue: status.reblogged,
propertyCount: 'reblogs_count',
countValue: status.reblogs_count,
visibility: 'public'
}
})
break
case 1:
analytics('timeline_shared_actions_reblog_unlisted_press', {
page: queryKey[1].page,
count: status.reblogs_count,
current: status.reblogged
})
mutation.mutate({
type: 'updateStatusProperty',
queryKey,
rootQueryKey,
id: status.id,
reblog,
payload: {
property: 'reblogged',
currentValue: status.reblogged,
propertyCount: 'reblogs_count',
countValue: status.reblogs_count,
visibility: 'unlisted'
}
})
break
}
}
)
} else {
analytics('timeline_shared_actions_reblog_press', { analytics('timeline_shared_actions_reblog_press', {
page: queryKey[1].page, page: queryKey[1].page,
count: status.reblogs_count, count: status.reblogs_count,
@ -135,9 +172,11 @@ const TimelineActions: React.FC<Props> = ({
property: 'reblogged', property: 'reblogged',
currentValue: status.reblogged, currentValue: status.reblogged,
propertyCount: 'reblogs_count', propertyCount: 'reblogs_count',
countValue: status.reblogs_count countValue: status.reblogs_count,
visibility: 'public'
} }
}) })
}
}, [status.reblogged, status.reblogs_count]) }, [status.reblogged, status.reblogs_count])
const onPressFavourite = useCallback(() => { const onPressFavourite = useCallback(() => {
analytics('timeline_shared_actions_favourite_press', { analytics('timeline_shared_actions_favourite_press', {
@ -182,11 +221,7 @@ const TimelineActions: React.FC<Props> = ({
const childrenReply = useMemo( const childrenReply = useMemo(
() => ( () => (
<> <>
<Icon <Icon name='MessageCircle' color={iconColor} size={StyleConstants.Font.Size.L} />
name='MessageCircle'
color={iconColor}
size={StyleConstants.Font.Size.L}
/>
{status.replies_count > 0 ? ( {status.replies_count > 0 ? (
<CustomText <CustomText
style={{ style={{
@ -209,8 +244,7 @@ const TimelineActions: React.FC<Props> = ({
<Icon <Icon
name='Repeat' name='Repeat'
color={ color={
status.visibility === 'direct' || status.visibility === 'direct' || (status.visibility === 'private' && !ownAccount)
(status.visibility === 'private' && !ownAccount)
? colors.disabled ? colors.disabled
: color(status.reblogged) : color(status.reblogged)
} }
@ -237,11 +271,7 @@ const TimelineActions: React.FC<Props> = ({
const color = (state: boolean) => (state ? colors.red : colors.secondary) const color = (state: boolean) => (state ? colors.red : colors.secondary)
return ( return (
<> <>
<Icon <Icon name='Heart' color={color(status.favourited)} size={StyleConstants.Font.Size.L} />
name='Heart'
color={color(status.favourited)}
size={StyleConstants.Font.Size.L}
/>
{status.favourites_count > 0 ? ( {status.favourites_count > 0 ? (
<CustomText <CustomText
style={{ style={{
@ -260,29 +290,21 @@ const TimelineActions: React.FC<Props> = ({
const childrenBookmark = useMemo(() => { const childrenBookmark = useMemo(() => {
const color = (state: boolean) => (state ? colors.yellow : colors.secondary) const color = (state: boolean) => (state ? colors.yellow : colors.secondary)
return ( return (
<Icon <Icon name='Bookmark' color={color(status.bookmarked)} size={StyleConstants.Font.Size.L} />
name='Bookmark'
color={color(status.bookmarked)}
size={StyleConstants.Font.Size.L}
/>
) )
}, [status.bookmarked]) }, [status.bookmarked])
return ( return (
<View <View
style={{ style={{
paddingLeft: highlighted paddingLeft: highlighted ? 0 : StyleConstants.Avatar.M + StyleConstants.Spacing.S
? 0
: StyleConstants.Avatar.M + StyleConstants.Spacing.S
}} }}
> >
<View style={{ flexDirection: 'row' }}> <View style={{ flexDirection: 'row' }}>
<Pressable <Pressable
{...(highlighted {...(highlighted
? { ? {
accessibilityLabel: t( accessibilityLabel: t('shared.actions.reply.accessibilityLabel'),
'shared.actions.reply.accessibilityLabel'
),
accessibilityRole: 'button' accessibilityRole: 'button'
} }
: { accessibilityLabel: '' })} : { accessibilityLabel: '' })}
@ -294,9 +316,7 @@ const TimelineActions: React.FC<Props> = ({
<Pressable <Pressable
{...(highlighted {...(highlighted
? { ? {
accessibilityLabel: t( accessibilityLabel: t('shared.actions.reblogged.accessibilityLabel'),
'shared.actions.reblogged.accessibilityLabel'
),
accessibilityRole: 'button' accessibilityRole: 'button'
} }
: { accessibilityLabel: '' })} : { accessibilityLabel: '' })}
@ -304,17 +324,14 @@ const TimelineActions: React.FC<Props> = ({
onPress={onPressReblog} onPress={onPressReblog}
children={childrenReblog} children={childrenReblog}
disabled={ disabled={
status.visibility === 'direct' || status.visibility === 'direct' || (status.visibility === 'private' && !ownAccount)
(status.visibility === 'private' && !ownAccount)
} }
/> />
<Pressable <Pressable
{...(highlighted {...(highlighted
? { ? {
accessibilityLabel: t( accessibilityLabel: t('shared.actions.favourited.accessibilityLabel'),
'shared.actions.favourited.accessibilityLabel'
),
accessibilityRole: 'button' accessibilityRole: 'button'
} }
: { accessibilityLabel: '' })} : { accessibilityLabel: '' })}
@ -326,9 +343,7 @@ const TimelineActions: React.FC<Props> = ({
<Pressable <Pressable
{...(highlighted {...(highlighted
? { ? {
accessibilityLabel: t( accessibilityLabel: t('shared.actions.bookmarked.accessibilityLabel'),
'shared.actions.bookmarked.accessibilityLabel'
),
accessibilityRole: 'button' accessibilityRole: 'button'
} }
: { accessibilityLabel: '' })} : { accessibilityLabel: '' })}

View File

@ -38,7 +38,12 @@
}, },
"reblogged": { "reblogged": {
"accessibilityLabel": "Boost this toot", "accessibilityLabel": "Boost this toot",
"function": "Boost toot" "function": "Boost toot",
"options": {
"title": "Choose boost visibility",
"public": "Public boost",
"unlisted": "Unlist boost"
}
}, },
"favourited": { "favourited": {
"accessibilityLabel": "Add this toot to favourites", "accessibilityLabel": "Add this toot to favourites",

View File

@ -9,7 +9,7 @@ import formatText from '@screens/Compose/formatText'
import ComposeRoot from '@screens/Compose/Root' import ComposeRoot from '@screens/Compose/Root'
import * as Sentry from '@sentry/react-native' import * as Sentry from '@sentry/react-native'
import { RootStackScreenProps } from '@utils/navigation/navigators' import { RootStackScreenProps } from '@utils/navigation/navigators'
import { QueryKeyTimeline, useTimelineMutation } from '@utils/queryHooks/timeline' import { useTimelineMutation } from '@utils/queryHooks/timeline'
import { updateStoreReview } from '@utils/slices/contextsSlice' import { updateStoreReview } from '@utils/slices/contextsSlice'
import { import {
getInstanceAccount, getInstanceAccount,
@ -280,8 +280,6 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
} else { } else {
dispatch(updateStoreReview(1)) dispatch(updateStoreReview(1))
} }
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Following' }]
queryClient.invalidateQueries(queryKey)
switch (params?.type) { switch (params?.type) {
case 'edit': case 'edit':

View File

@ -293,11 +293,18 @@ export type MutationVarsTimelineUpdateStatusProperty = {
countValue: undefined countValue: undefined
} }
| { | {
property: 'favourited' | 'reblogged' property: 'favourited'
currentValue: boolean currentValue: boolean
propertyCount: 'favourites_count' | 'reblogs_count' propertyCount: 'favourites_count' | 'reblogs_count'
countValue: number countValue: number
} }
| {
property: 'reblogged'
currentValue: boolean
propertyCount: 'favourites_count' | 'reblogs_count'
countValue: number
visibility: 'public' | 'unlisted'
}
| { | {
property: 'poll' property: 'poll'
id: Mastodon.Poll['id'] id: Mastodon.Poll['id']
@ -371,11 +378,16 @@ const mutationFunction = async (params: MutationVarsTimeline) => {
...(params.payload.type === 'vote' && { body: formData }) ...(params.payload.type === 'vote' && { body: formData })
}) })
default: default:
const body = new FormData()
if (params.payload.property === 'reblogged') {
body.append('visibility', params.payload.visibility)
}
return apiInstance<Mastodon.Status>({ return apiInstance<Mastodon.Status>({
method: 'post', method: 'post',
url: `statuses/${params.id}/${ url: `statuses/${params.id}/${
params.payload.currentValue ? 'un' : '' params.payload.currentValue ? 'un' : ''
}${MapPropertyToUrl[params.payload.property]}` }${MapPropertyToUrl[params.payload.property]}`,
body
}) })
} }
case 'updateAccountProperty': case 'updateAccountProperty':