diff --git a/src/components/ContextMenu/account.ts b/src/components/ContextMenu/account.ts index 02b851b5..53a9aa44 100644 --- a/src/components/ContextMenu/account.ts +++ b/src/components/ContextMenu/account.ts @@ -9,6 +9,7 @@ import { import { getInstanceAccount } from '@utils/slices/instancesSlice' import { useTheme } from '@utils/styles/ThemeManager' import { useTranslation } from 'react-i18next' +import { Platform } from 'react-native' import { ContextMenuAction } from 'react-native-context-menu-view' import { useQueryClient } from 'react-query' import { useSelector } from 'react-redux' @@ -94,22 +95,50 @@ const contextMenuAccount = ({ context: (relationship?.muting || false).toString() }), systemIcon: 'eye.slash' - }, - { - 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 } ) + 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', + 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 + } } return (index: number) => { diff --git a/src/components/Emojis/List.tsx b/src/components/Emojis/List.tsx index 0ccb2c55..bf3d2281 100644 --- a/src/components/Emojis/List.tsx +++ b/src/components/Emojis/List.tsx @@ -54,9 +54,6 @@ const EmojisList = () => { const addedLength = spaceFront.length + shortcode.length + spaceRear.length setSelection({ start: selection.start + addedLength }) - ref?.current?.setNativeProps({ - selection: { start: selection.start + addedLength } - }) } const listItem = ({ index, item }: { item: Mastodon.Emoji[]; index: number }) => { diff --git a/src/components/Relationship/Outgoing.tsx b/src/components/Relationship/Outgoing.tsx index 13c9b229..123ac90d 100644 --- a/src/components/Relationship/Outgoing.tsx +++ b/src/components/Relationship/Outgoing.tsx @@ -33,7 +33,7 @@ const RelationshipOutgoing = React.memo( queryKeyRelationship, [res] ) - if (action === 'follow' || action === 'block') { + if (action === 'block') { const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Following' }] queryClient.invalidateQueries(queryKey) } diff --git a/src/components/Timeline/Shared/Actions.tsx b/src/components/Timeline/Shared/Actions.tsx index 654c47ec..46e98e1b 100644 --- a/src/components/Timeline/Shared/Actions.tsx +++ b/src/components/Timeline/Shared/Actions.tsx @@ -2,6 +2,7 @@ import analytics from '@components/analytics' import Icon from '@components/Icon' import { displayMessage } from '@components/Message' import CustomText from '@components/Text' +import { useActionSheet } from '@expo/react-native-action-sheet' import { useNavigation } from '@react-navigation/native' import { StackNavigationProp } from '@react-navigation/stack' import { RootStackParamList } from '@utils/navigation/navigators' @@ -48,40 +49,18 @@ const TimelineActions: React.FC = ({ const theParams = params as MutationVarsTimelineUpdateStatusProperty if ( // Un-bookmark from bookmarks page - (queryKey[1].page === 'Bookmarks' && - theParams.payload.property === 'bookmarked') || + (queryKey[1].page === 'Bookmarks' && theParams.payload.property === 'bookmarked') || // Un-favourite from favourites page - (queryKey[1].page === 'Favourites' && - theParams.payload.property === 'favourited') || - // Un-reblog from following page - (queryKey[1].page === 'Following' && - theParams.payload.property === 'reblogged' && - theParams.payload.currentValue === true) + (queryKey[1].page === 'Favourites' && theParams.payload.property === 'favourited') ) { 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') { // When favourited, update favourited page - const tempQueryKey: QueryKeyTimeline = [ - 'Timeline', - { page: 'Favourites' } - ] + const tempQueryKey: QueryKeyTimeline = ['Timeline', { page: 'Favourites' }] queryClient.invalidateQueries(tempQueryKey) } else if (theParams.payload.property === 'bookmarked') { // When bookmarked, update bookmark page - const tempQueryKey: QueryKeyTimeline = [ - 'Timeline', - { page: 'Bookmarks' } - ] + const tempQueryKey: QueryKeyTimeline = ['Timeline', { page: 'Bookmarks' }] queryClient.invalidateQueries(tempQueryKey) } }, @@ -91,9 +70,7 @@ const TimelineActions: React.FC = ({ theme, type: 'error', message: t('common:message.error.message', { - function: t( - `shared.actions.${correctParam.payload.property}.function` - ) + function: t(`shared.actions.${correctParam.payload.property}.function`) }), ...(err.status && typeof err.status === 'number' && @@ -119,25 +96,87 @@ const TimelineActions: React.FC = ({ queryKey }) }, [status.replies_count]) + const { showActionSheetWithOptions } = useActionSheet() const onPressReblog = useCallback(() => { - analytics('timeline_shared_actions_reblog_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 - } - }) + 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', { + 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' + } + }) + } }, [status.reblogged, status.reblogs_count]) const onPressFavourite = useCallback(() => { analytics('timeline_shared_actions_favourite_press', { @@ -182,11 +221,7 @@ const TimelineActions: React.FC = ({ const childrenReply = useMemo( () => ( <> - + {status.replies_count > 0 ? ( = ({ = ({ const color = (state: boolean) => (state ? colors.red : colors.secondary) return ( <> - + {status.favourites_count > 0 ? ( = ({ const childrenBookmark = useMemo(() => { const color = (state: boolean) => (state ? colors.yellow : colors.secondary) return ( - + ) }, [status.bookmarked]) return ( = ({ = ({ onPress={onPressReblog} children={childrenReblog} disabled={ - status.visibility === 'direct' || - (status.visibility === 'private' && !ownAccount) + status.visibility === 'direct' || (status.visibility === 'private' && !ownAccount) } /> = ({ > = ({ } else { dispatch(updateStoreReview(1)) } - const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Following' }] - queryClient.invalidateQueries(queryKey) switch (params?.type) { case 'edit': diff --git a/src/utils/queryHooks/timeline.ts b/src/utils/queryHooks/timeline.ts index d7e1b131..440969e9 100644 --- a/src/utils/queryHooks/timeline.ts +++ b/src/utils/queryHooks/timeline.ts @@ -293,11 +293,18 @@ export type MutationVarsTimelineUpdateStatusProperty = { countValue: undefined } | { - property: 'favourited' | 'reblogged' + property: 'favourited' currentValue: boolean propertyCount: 'favourites_count' | 'reblogs_count' countValue: number } + | { + property: 'reblogged' + currentValue: boolean + propertyCount: 'favourites_count' | 'reblogs_count' + countValue: number + visibility: 'public' | 'unlisted' + } | { property: 'poll' id: Mastodon.Poll['id'] @@ -371,11 +378,16 @@ const mutationFunction = async (params: MutationVarsTimeline) => { ...(params.payload.type === 'vote' && { body: formData }) }) default: + const body = new FormData() + if (params.payload.property === 'reblogged') { + body.append('visibility', params.payload.visibility) + } return apiInstance({ method: 'post', url: `statuses/${params.id}/${ params.payload.currentValue ? 'un' : '' - }${MapPropertyToUrl[params.payload.property]}` + }${MapPropertyToUrl[params.payload.property]}`, + body }) } case 'updateAccountProperty':