mirror of
				https://github.com/tooot-app/app
				synced 2025-06-05 22:19:13 +02:00 
			
		
		
		
	Now it should finally fix #451
This commit is contained in:
		| @@ -131,6 +131,9 @@ const contextMenuAccount = ({ actions, type, queryKey, rootQueryKey, id: account | ||||
|   } | ||||
|  | ||||
|   return (index: number) => { | ||||
|     if (typeof index !== 'number' || !actions[index]) { | ||||
|       return // For Android | ||||
|     } | ||||
|     if (actions[index].id === 'account-mute') { | ||||
|       analytics('timeline_shared_headeractions_account_mute_press', { | ||||
|         page: queryKey && queryKey[1].page | ||||
|   | ||||
| @@ -1,9 +1,6 @@ | ||||
| import analytics from '@components/analytics' | ||||
| import { displayMessage } from '@components/Message' | ||||
| import { | ||||
|   QueryKeyTimeline, | ||||
|   useTimelineMutation | ||||
| } from '@utils/queryHooks/timeline' | ||||
| import { QueryKeyTimeline, useTimelineMutation } from '@utils/queryHooks/timeline' | ||||
| import { getInstanceUrl } from '@utils/slices/instancesSlice' | ||||
| import { useTheme } from '@utils/styles/ThemeManager' | ||||
| import { useTranslation } from 'react-i18next' | ||||
| @@ -19,12 +16,7 @@ export interface Props { | ||||
|   rootQueryKey?: QueryKeyTimeline | ||||
| } | ||||
|  | ||||
| const contextMenuInstance = ({ | ||||
|   actions, | ||||
|   status, | ||||
|   queryKey, | ||||
|   rootQueryKey | ||||
| }: Props) => { | ||||
| const contextMenuInstance = ({ actions, status, queryKey, rootQueryKey }: Props) => { | ||||
|   const { t } = useTranslation('componentContextMenu') | ||||
|   const { theme } = useTheme() | ||||
|  | ||||
| @@ -72,10 +64,12 @@ const contextMenuInstance = ({ | ||||
|   } | ||||
|  | ||||
|   return (index: number) => { | ||||
|     if (typeof index !== 'number' || !actions[index]) { | ||||
|       return // For Android | ||||
|     } | ||||
|     if ( | ||||
|       actions[index].id === 'instance-block' || | ||||
|       (actions[index].id === 'instance' && | ||||
|         actions[index].actions?.[0].id === 'instance-block') | ||||
|       (actions[index].id === 'instance' && actions[index].actions?.[0].id === 'instance-block') | ||||
|     ) { | ||||
|       analytics('timeline_shared_headeractions_domain_block_press', { | ||||
|         page: queryKey[1].page | ||||
|   | ||||
| @@ -25,7 +25,8 @@ const contextMenuShare = ({ copiableContent, actions, type, url }: Props) => { | ||||
|     title: t(`share.${type}.action`), | ||||
|     systemIcon: 'square.and.arrow.up' | ||||
|   }) | ||||
|   Platform.OS !== 'android' && type === 'status' && | ||||
|   Platform.OS !== 'android' && | ||||
|     type === 'status' && | ||||
|     actions.push({ | ||||
|       id: 'copy', | ||||
|       title: t(`copy.action`), | ||||
| @@ -34,6 +35,9 @@ const contextMenuShare = ({ copiableContent, actions, type, url }: Props) => { | ||||
|     }) | ||||
|  | ||||
|   return (index: number) => { | ||||
|     if (typeof index !== 'number' || !actions[index]) { | ||||
|       return // For Android | ||||
|     } | ||||
|     if (actions[index].id === 'copy') { | ||||
|       analytics('timeline_shared_headeractions_copy_press') | ||||
|       Clipboard.setString(copiableContent?.current.content || '') | ||||
|   | ||||
| @@ -9,10 +9,7 @@ import { | ||||
|   QueryKeyTimeline, | ||||
|   useTimelineMutation | ||||
| } from '@utils/queryHooks/timeline' | ||||
| import { | ||||
|   checkInstanceFeature, | ||||
|   getInstanceAccount | ||||
| } from '@utils/slices/instancesSlice' | ||||
| import { checkInstanceFeature, getInstanceAccount } from '@utils/slices/instancesSlice' | ||||
| import { useTheme } from '@utils/styles/ThemeManager' | ||||
| import { useTranslation } from 'react-i18next' | ||||
| import { Alert } from 'react-native' | ||||
| @@ -27,16 +24,8 @@ export interface Props { | ||||
|   rootQueryKey?: QueryKeyTimeline | ||||
| } | ||||
|  | ||||
| const contextMenuStatus = ({ | ||||
|   actions, | ||||
|   status, | ||||
|   queryKey, | ||||
|   rootQueryKey | ||||
| }: Props) => { | ||||
|   const navigation = | ||||
|     useNavigation< | ||||
|       NativeStackNavigationProp<RootStackParamList, 'Screen-Tabs'> | ||||
|     >() | ||||
| const contextMenuStatus = ({ actions, status, queryKey, rootQueryKey }: Props) => { | ||||
|   const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList, 'Screen-Tabs'>>() | ||||
|   const { theme } = useTheme() | ||||
|   const { t } = useTranslation('componentContextMenu') | ||||
|  | ||||
| @@ -44,8 +33,7 @@ const contextMenuStatus = ({ | ||||
|   const mutation = useTimelineMutation({ | ||||
|     onMutate: true, | ||||
|     onError: (err: any, params, oldData) => { | ||||
|       const theFunction = (params as MutationVarsTimelineUpdateStatusProperty) | ||||
|         .payload | ||||
|       const theFunction = (params as MutationVarsTimelineUpdateStatusProperty).payload | ||||
|         ? (params as MutationVarsTimelineUpdateStatusProperty).payload.property | ||||
|         : 'delete' | ||||
|       displayMessage({ | ||||
| @@ -59,17 +47,14 @@ const contextMenuStatus = ({ | ||||
|           err.data && | ||||
|           err.data.error && | ||||
|           typeof err.data.error === 'string' && { | ||||
|           description: err.data.error | ||||
|         }) | ||||
|             description: err.data.error | ||||
|           }) | ||||
|       }) | ||||
|       queryClient.setQueryData(queryKey, oldData) | ||||
|     } | ||||
|   }) | ||||
|  | ||||
|   const instanceAccount = useSelector( | ||||
|     getInstanceAccount, | ||||
|     (prev, next) => prev.id === next.id | ||||
|   ) | ||||
|   const instanceAccount = useSelector(getInstanceAccount, (prev, next) => prev.id === next.id) | ||||
|   const ownAccount = instanceAccount?.id === status?.account?.id | ||||
|  | ||||
|   if (ownAccount) { | ||||
| @@ -118,83 +103,75 @@ const contextMenuStatus = ({ | ||||
|   } | ||||
|  | ||||
|   return async (index: number) => { | ||||
|     if (typeof index !== 'number' || !actions[index]) { | ||||
|       return // For Android | ||||
|     } | ||||
|     if (actions[index].id === 'status-delete') { | ||||
|       analytics('timeline_shared_headeractions_status_delete_press', { | ||||
|         page: queryKey && queryKey[1].page | ||||
|       }) | ||||
|       Alert.alert( | ||||
|         t('status.delete.alert.title'), | ||||
|         t('status.delete.alert.message'), | ||||
|         [ | ||||
|           { | ||||
|             text: t('status.delete.alert.buttons.confirm'), | ||||
|             style: 'destructive', | ||||
|             onPress: async () => { | ||||
|               analytics('timeline_shared_headeractions_status_delete_confirm', { | ||||
|                 page: queryKey && queryKey[1].page | ||||
|               }) | ||||
|               mutation.mutate({ | ||||
|                 type: 'deleteItem', | ||||
|                 source: 'statuses', | ||||
|                 queryKey, | ||||
|                 rootQueryKey, | ||||
|                 id: status.id | ||||
|               }) | ||||
|             } | ||||
|           }, | ||||
|           { | ||||
|             text: t('common:buttons.cancel') | ||||
|       Alert.alert(t('status.delete.alert.title'), t('status.delete.alert.message'), [ | ||||
|         { | ||||
|           text: t('status.delete.alert.buttons.confirm'), | ||||
|           style: 'destructive', | ||||
|           onPress: async () => { | ||||
|             analytics('timeline_shared_headeractions_status_delete_confirm', { | ||||
|               page: queryKey && queryKey[1].page | ||||
|             }) | ||||
|             mutation.mutate({ | ||||
|               type: 'deleteItem', | ||||
|               source: 'statuses', | ||||
|               queryKey, | ||||
|               rootQueryKey, | ||||
|               id: status.id | ||||
|             }) | ||||
|           } | ||||
|         ] | ||||
|       ) | ||||
|         }, | ||||
|         { | ||||
|           text: t('common:buttons.cancel') | ||||
|         } | ||||
|       ]) | ||||
|     } | ||||
|     if (actions[index].id === 'status-delete-edit') { | ||||
|       analytics('timeline_shared_headeractions_status_deleteedit_press', { | ||||
|         page: queryKey && queryKey[1].page | ||||
|       }) | ||||
|       Alert.alert( | ||||
|         t('status.deleteEdit.alert.title'), | ||||
|         t('status.deleteEdit.alert.message'), | ||||
|         [ | ||||
|           { | ||||
|             text: t('status.deleteEdit.alert.buttons.confirm'), | ||||
|             style: 'destructive', | ||||
|             onPress: async () => { | ||||
|               analytics( | ||||
|                 'timeline_shared_headeractions_status_deleteedit_confirm', | ||||
|                 { | ||||
|                   page: queryKey && queryKey[1].page | ||||
|                 } | ||||
|               ) | ||||
|               let replyToStatus: Mastodon.Status | undefined = undefined | ||||
|               if (status.in_reply_to_id) { | ||||
|                 replyToStatus = await apiInstance<Mastodon.Status>({ | ||||
|                   method: 'get', | ||||
|                   url: `statuses/${status.in_reply_to_id}` | ||||
|                 }).then(res => res.body) | ||||
|               } | ||||
|               mutation | ||||
|                 .mutateAsync({ | ||||
|                   type: 'deleteItem', | ||||
|                   source: 'statuses', | ||||
|                   queryKey, | ||||
|                   id: status.id | ||||
|                 }) | ||||
|                 .then(res => { | ||||
|                   navigation.navigate('Screen-Compose', { | ||||
|                     type: 'deleteEdit', | ||||
|                     incomingStatus: res.body as Mastodon.Status, | ||||
|                     ...(replyToStatus && { replyToStatus }), | ||||
|                     queryKey | ||||
|                   }) | ||||
|                 }) | ||||
|       Alert.alert(t('status.deleteEdit.alert.title'), t('status.deleteEdit.alert.message'), [ | ||||
|         { | ||||
|           text: t('status.deleteEdit.alert.buttons.confirm'), | ||||
|           style: 'destructive', | ||||
|           onPress: async () => { | ||||
|             analytics('timeline_shared_headeractions_status_deleteedit_confirm', { | ||||
|               page: queryKey && queryKey[1].page | ||||
|             }) | ||||
|             let replyToStatus: Mastodon.Status | undefined = undefined | ||||
|             if (status.in_reply_to_id) { | ||||
|               replyToStatus = await apiInstance<Mastodon.Status>({ | ||||
|                 method: 'get', | ||||
|                 url: `statuses/${status.in_reply_to_id}` | ||||
|               }).then(res => res.body) | ||||
|             } | ||||
|           }, | ||||
|           { | ||||
|             text: t('common:buttons.cancel') | ||||
|             mutation | ||||
|               .mutateAsync({ | ||||
|                 type: 'deleteItem', | ||||
|                 source: 'statuses', | ||||
|                 queryKey, | ||||
|                 id: status.id | ||||
|               }) | ||||
|               .then(res => { | ||||
|                 navigation.navigate('Screen-Compose', { | ||||
|                   type: 'deleteEdit', | ||||
|                   incomingStatus: res.body as Mastodon.Status, | ||||
|                   ...(replyToStatus && { replyToStatus }), | ||||
|                   queryKey | ||||
|                 }) | ||||
|               }) | ||||
|           } | ||||
|         ] | ||||
|       ) | ||||
|         }, | ||||
|         { | ||||
|           text: t('common:buttons.cancel') | ||||
|         } | ||||
|       ]) | ||||
|     } | ||||
|     if (actions[index].id === 'status-mute') { | ||||
|       analytics('timeline_shared_headeractions_status_mute_press', { | ||||
|   | ||||
| @@ -157,15 +157,6 @@ const TimelineDefault: React.FC<Props> = ({ | ||||
|  | ||||
|   return disableOnPress ? ( | ||||
|     <View style={mainStyle}>{main()}</View> | ||||
|   ) : Platform.OS === 'android' ? ( | ||||
|     <Pressable | ||||
|       accessible={highlighted ? false : true} | ||||
|       style={mainStyle} | ||||
|       onPress={onPress} | ||||
|       onLongPress={() => {}} | ||||
|     > | ||||
|       {main()} | ||||
|     </Pressable> | ||||
|   ) : ( | ||||
|     <TimelineContextMenu | ||||
|       copiableContent={copiableContent} | ||||
|   | ||||
| @@ -3,13 +3,14 @@ import contextMenuInstance from '@components/ContextMenu/instance' | ||||
| import contextMenuShare from '@components/ContextMenu/share' | ||||
| import contextMenuStatus from '@components/ContextMenu/status' | ||||
| import Icon from '@components/Icon' | ||||
| import { useActionSheet } from '@expo/react-native-action-sheet' | ||||
| import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | ||||
| import { StyleConstants } from '@utils/styles/constants' | ||||
| import { useTheme } from '@utils/styles/ThemeManager' | ||||
| import React from 'react' | ||||
| import { useTranslation } from 'react-i18next' | ||||
| import { Pressable, View } from 'react-native' | ||||
| import ContextMenu, { ContextMenuAction } from 'react-native-context-menu-view' | ||||
| import { ContextMenuAction } from 'react-native-context-menu-view' | ||||
| import HeaderSharedAccount from './HeaderShared/Account' | ||||
| import HeaderSharedApplication from './HeaderShared/Application' | ||||
| import HeaderSharedCreated from './HeaderShared/Created' | ||||
| @@ -55,6 +56,8 @@ const TimelineHeaderDefault = ({ queryKey, status, highlighted }: Props) => { | ||||
|     queryKey | ||||
|   }) | ||||
|  | ||||
|   const { showActionSheetWithOptions } = useActionSheet() | ||||
|  | ||||
|   return ( | ||||
|     <View style={{ flex: 1, flexDirection: 'row' }}> | ||||
|       <View style={{ flex: 7 }}> | ||||
| @@ -82,25 +85,26 @@ const TimelineHeaderDefault = ({ queryKey, status, highlighted }: Props) => { | ||||
|         <Pressable | ||||
|           accessibilityHint={t('accessibilityHint')} | ||||
|           style={{ flex: 1, flexBasis: StyleConstants.Font.Size.L }} | ||||
|           onLongPress={() => null} | ||||
|         > | ||||
|           <ContextMenu | ||||
|             style={{ flex: 1, alignItems: 'center' }} | ||||
|             dropdownMenuMode | ||||
|             actions={actions} | ||||
|             onPress={({ nativeEvent: { index } }) => { | ||||
|               for (const on of [shareOnPress, statusOnPress, accountOnPress, instanceOnPress]) { | ||||
|                 on && on(index) | ||||
|           onPress={() => | ||||
|             showActionSheetWithOptions( | ||||
|               { | ||||
|                 options: actions.map(action => action.title), | ||||
|                 cancelButtonIndex: 999, | ||||
|                 destructiveButtonIndex: actions | ||||
|                   .map((action, index) => (action.destructive ? index : 999)) | ||||
|                   .filter(num => num !== 999) | ||||
|               }, | ||||
|               index => { | ||||
|                 if (index !== undefined) { | ||||
|                   for (const on of [shareOnPress, statusOnPress, accountOnPress, instanceOnPress]) { | ||||
|                     on && on(index) | ||||
|                   } | ||||
|                 } | ||||
|               } | ||||
|             }} | ||||
|             children={ | ||||
|               <Icon | ||||
|                 name='MoreHorizontal' | ||||
|                 color={colors.secondary} | ||||
|                 size={StyleConstants.Font.Size.L} | ||||
|               /> | ||||
|             } | ||||
|           /> | ||||
|             ) | ||||
|           } | ||||
|         > | ||||
|           <Icon name='MoreHorizontal' color={colors.secondary} size={StyleConstants.Font.Size.L} /> | ||||
|         </Pressable> | ||||
|       ) : null} | ||||
|     </View> | ||||
|   | ||||
| @@ -4,12 +4,13 @@ import contextMenuShare from '@components/ContextMenu/share' | ||||
| import contextMenuStatus from '@components/ContextMenu/status' | ||||
| import Icon from '@components/Icon' | ||||
| import { RelationshipIncoming, RelationshipOutgoing } from '@components/Relationship' | ||||
| import { useActionSheet } from '@expo/react-native-action-sheet' | ||||
| import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | ||||
| import { StyleConstants } from '@utils/styles/constants' | ||||
| import { useTheme } from '@utils/styles/ThemeManager' | ||||
| import React, { useMemo } from 'react' | ||||
| import { Pressable, View } from 'react-native' | ||||
| import ContextMenu, { ContextMenuAction } from 'react-native-context-menu-view' | ||||
| import { ContextMenuAction } from 'react-native-context-menu-view' | ||||
| import HeaderSharedAccount from './HeaderShared/Account' | ||||
| import HeaderSharedApplication from './HeaderShared/Application' | ||||
| import HeaderSharedCreated from './HeaderShared/Created' | ||||
| @@ -57,6 +58,8 @@ const TimelineHeaderNotification = ({ queryKey, notification }: Props) => { | ||||
|       queryKey | ||||
|     }) | ||||
|  | ||||
|   const { showActionSheetWithOptions } = useActionSheet() | ||||
|  | ||||
|   const actions = useMemo(() => { | ||||
|     switch (notification.type) { | ||||
|       case 'follow': | ||||
| @@ -68,29 +71,34 @@ const TimelineHeaderNotification = ({ queryKey, notification }: Props) => { | ||||
|           return ( | ||||
|             <Pressable | ||||
|               style={{ flex: 1, flexBasis: StyleConstants.Font.Size.L }} | ||||
|               onLongPress={() => null} | ||||
|               children={ | ||||
|                 <ContextMenu | ||||
|                   style={{ flex: 1, alignItems: 'center' }} | ||||
|                   dropdownMenuMode | ||||
|                   actions={contextMenuActions} | ||||
|                   onPress={({ nativeEvent: { index } }) => { | ||||
|                     for (const on of [ | ||||
|                       shareOnPress, | ||||
|                       statusOnPress, | ||||
|                       accountOnPress, | ||||
|                       instanceOnPress | ||||
|                     ]) { | ||||
|                       on && on(index) | ||||
|               onPress={() => | ||||
|                 showActionSheetWithOptions( | ||||
|                   { | ||||
|                     options: contextMenuActions.map(action => action.title), | ||||
|                     cancelButtonIndex: 999, | ||||
|                     destructiveButtonIndex: contextMenuActions | ||||
|                       .map((action, index) => (action.destructive ? index : 999)) | ||||
|                       .filter(num => num !== 999) | ||||
|                   }, | ||||
|                   index => { | ||||
|                     if (index !== undefined) { | ||||
|                       for (const on of [ | ||||
|                         shareOnPress, | ||||
|                         statusOnPress, | ||||
|                         accountOnPress, | ||||
|                         instanceOnPress | ||||
|                       ]) { | ||||
|                         on && on(index) | ||||
|                       } | ||||
|                     } | ||||
|                   }} | ||||
|                   children={ | ||||
|                     <Icon | ||||
|                       name='MoreHorizontal' | ||||
|                       color={colors.secondary} | ||||
|                       size={StyleConstants.Font.Size.L} | ||||
|                     /> | ||||
|                   } | ||||
|                 ) | ||||
|               } | ||||
|               children={ | ||||
|                 <Icon | ||||
|                   name='MoreHorizontal' | ||||
|                   color={colors.secondary} | ||||
|                   size={StyleConstants.Font.Size.L} | ||||
|                 /> | ||||
|               } | ||||
|             /> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user