mirror of
				https://github.com/tooot-app/app
				synced 2025-06-05 22:19:13 +02:00 
			
		
		
		
	Edited posts can be viewed
This commit is contained in:
		
							
								
								
									
										12
									
								
								src/@types/mastodon.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								src/@types/mastodon.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -426,6 +426,7 @@ declare namespace Mastodon { | |||||||
|     reblogs_count: number |     reblogs_count: number | ||||||
|     favourites_count: number |     favourites_count: number | ||||||
|     replies_count: number |     replies_count: number | ||||||
|  |     edited_at?: string // FEATURE edit_post | ||||||
|     favourited: boolean |     favourited: boolean | ||||||
|     reblogged: boolean |     reblogged: boolean | ||||||
|     muted: boolean |     muted: boolean | ||||||
| @@ -443,6 +444,17 @@ declare namespace Mastodon { | |||||||
|     text?: string |     text?: string | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   type StatusHistory = { | ||||||
|  |     content: Status['content'] | ||||||
|  |     spoiler_text: Status['spoiler_text'] | ||||||
|  |     sensitive: Status['sensitive'] | ||||||
|  |     created_at: Status['created_at'] | ||||||
|  |     poll: Status['poll'] | ||||||
|  |     account: Status['account'] | ||||||
|  |     media_attachments: Status['media_attachments'] | ||||||
|  |     emojis: Status['emojis'] | ||||||
|  |   } | ||||||
|  |  | ||||||
|   type Source = { |   type Source = { | ||||||
|     // Base |     // Base | ||||||
|     note: string |     note: string | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								src/@types/untyped.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								src/@types/untyped.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4,3 +4,8 @@ declare module 'li' | |||||||
| declare module 'react-native-feather' | declare module 'react-native-feather' | ||||||
| declare module 'react-native-htmlview' | declare module 'react-native-htmlview' | ||||||
| declare module 'react-native-toast-message' | declare module 'react-native-toast-message' | ||||||
|  |  | ||||||
|  | declare module '@helpers/features' { | ||||||
|  |   const features: { feature: string; version: number; reference?: string }[] | ||||||
|  |   export default features | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| 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 { TabLocalStackParamList } from '@utils/navigation/navigators' | ||||||
| import { StyleConstants } from '@utils/styles/constants' | import { StyleConstants } from '@utils/styles/constants' | ||||||
| import { useTheme } from '@utils/styles/ThemeManager' | import { useTheme } from '@utils/styles/ThemeManager' | ||||||
| import React, { useCallback } from 'react' | import React, { useCallback } from 'react' | ||||||
| @@ -19,7 +20,7 @@ const ComponentHashtag: React.FC<Props> = ({ | |||||||
| }) => { | }) => { | ||||||
|   const { colors } = useTheme() |   const { colors } = useTheme() | ||||||
|   const navigation = |   const navigation = | ||||||
|     useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>() |     useNavigation<StackNavigationProp<TabLocalStackParamList>>() | ||||||
|  |  | ||||||
|   const onPress = useCallback(() => { |   const onPress = useCallback(() => { | ||||||
|     analytics('search_account_press', { page: origin }) |     analytics('search_account_press', { page: origin }) | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import openLink from '@components/openLink' | |||||||
| import ParseEmojis from '@components/Parse/Emojis' | import ParseEmojis from '@components/Parse/Emojis' | ||||||
| import { useNavigation, useRoute } from '@react-navigation/native' | import { useNavigation, useRoute } from '@react-navigation/native' | ||||||
| import { StackNavigationProp } from '@react-navigation/stack' | import { StackNavigationProp } from '@react-navigation/stack' | ||||||
|  | import { TabLocalStackParamList } from '@utils/navigation/navigators' | ||||||
| import { getSettingsFontsize } from '@utils/slices/settingsSlice' | import { getSettingsFontsize } from '@utils/slices/settingsSlice' | ||||||
| import { StyleConstants } from '@utils/styles/constants' | import { StyleConstants } from '@utils/styles/constants' | ||||||
| import layoutAnimation from '@utils/styles/layoutAnimation' | import layoutAnimation from '@utils/styles/layoutAnimation' | ||||||
| @@ -35,7 +36,7 @@ const renderNode = ({ | |||||||
|   index: number |   index: number | ||||||
|   adaptedFontsize: number |   adaptedFontsize: number | ||||||
|   adaptedLineheight: number |   adaptedLineheight: number | ||||||
|   navigation: StackNavigationProp<Nav.TabLocalStackParamList> |   navigation: StackNavigationProp<TabLocalStackParamList> | ||||||
|   mentions?: Mastodon.Mention[] |   mentions?: Mastodon.Mention[] | ||||||
|   tags?: Mastodon.Tag[] |   tags?: Mastodon.Tag[] | ||||||
|   showFullLink: boolean |   showFullLink: boolean | ||||||
| @@ -194,7 +195,7 @@ const ParseHTML = React.memo( | |||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     const navigation = |     const navigation = | ||||||
|       useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>() |       useNavigation<StackNavigationProp<TabLocalStackParamList>>() | ||||||
|     const route = useRoute() |     const route = useRoute() | ||||||
|     const { colors, theme } = useTheme() |     const { colors, theme } = useTheme() | ||||||
|     const { t, i18n } = useTranslation('componentParse') |     const { t, i18n } = useTranslation('componentParse') | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ import analytics from '@components/analytics' | |||||||
| import GracefullyImage from '@components/GracefullyImage' | import GracefullyImage from '@components/GracefullyImage' | ||||||
| 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 { TabLocalStackParamList } from '@utils/navigation/navigators' | ||||||
| import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | ||||||
| import { getInstanceAccount } from '@utils/slices/instancesSlice' | import { getInstanceAccount } from '@utils/slices/instancesSlice' | ||||||
| import { StyleConstants } from '@utils/styles/constants' | import { StyleConstants } from '@utils/styles/constants' | ||||||
| @@ -78,7 +79,7 @@ const TimelineConversation: React.FC<Props> = ({ | |||||||
|   }) |   }) | ||||||
|  |  | ||||||
|   const navigation = |   const navigation = | ||||||
|     useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>() |     useNavigation<StackNavigationProp<TabLocalStackParamList>>() | ||||||
|   const onPress = useCallback(() => { |   const onPress = useCallback(() => { | ||||||
|     analytics('timeline_conversation_press') |     analytics('timeline_conversation_press') | ||||||
|     if (conversation.last_status) { |     if (conversation.last_status) { | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import TimelineHeaderDefault from '@components/Timeline/Shared/HeaderDefault' | |||||||
| import TimelinePoll from '@components/Timeline/Shared/Poll' | import TimelinePoll from '@components/Timeline/Shared/Poll' | ||||||
| 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 { TabLocalStackParamList } from '@utils/navigation/navigators' | ||||||
| import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | ||||||
| import { getInstanceAccount } from '@utils/slices/instancesSlice' | import { getInstanceAccount } from '@utils/slices/instancesSlice' | ||||||
| import { StyleConstants } from '@utils/styles/constants' | import { StyleConstants } from '@utils/styles/constants' | ||||||
| @@ -17,7 +18,7 @@ import { uniqBy } from 'lodash' | |||||||
| import React, { useCallback } from 'react' | import React, { useCallback } from 'react' | ||||||
| import { Pressable, StyleSheet, View } from 'react-native' | import { Pressable, StyleSheet, View } from 'react-native' | ||||||
| import { useSelector } from 'react-redux' | import { useSelector } from 'react-redux' | ||||||
| import TimelineActionsUsers from './Shared/ActionsUsers' | import TimelineFeedback from './Shared/Feedback' | ||||||
| import TimelineFiltered, { shouldFilter } from './Shared/Filtered' | import TimelineFiltered, { shouldFilter } from './Shared/Filtered' | ||||||
| import TimelineFullConversation from './Shared/FullConversation' | import TimelineFullConversation from './Shared/FullConversation' | ||||||
| import TimelineTranslate from './Shared/Translate' | import TimelineTranslate from './Shared/Translate' | ||||||
| @@ -45,7 +46,7 @@ const TimelineDefault: React.FC<Props> = ({ | |||||||
|   const { colors } = useTheme() |   const { colors } = useTheme() | ||||||
|   const instanceAccount = useSelector(getInstanceAccount, () => true) |   const instanceAccount = useSelector(getInstanceAccount, () => true) | ||||||
|   const navigation = |   const navigation = | ||||||
|     useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>() |     useNavigation<StackNavigationProp<TabLocalStackParamList>>() | ||||||
|  |  | ||||||
|   const actualStatus = item.reblog ? item.reblog : item |   const actualStatus = item.reblog ? item.reblog : item | ||||||
|  |  | ||||||
| @@ -143,7 +144,7 @@ const TimelineDefault: React.FC<Props> = ({ | |||||||
|           <TimelineFullConversation queryKey={queryKey} status={actualStatus} /> |           <TimelineFullConversation queryKey={queryKey} status={actualStatus} /> | ||||||
|         ) : null} |         ) : null} | ||||||
|         <TimelineTranslate status={actualStatus} highlighted={highlighted} /> |         <TimelineTranslate status={actualStatus} highlighted={highlighted} /> | ||||||
|         <TimelineActionsUsers status={actualStatus} highlighted={highlighted} /> |         <TimelineFeedback status={actualStatus} highlighted={highlighted} /> | ||||||
|       </View> |       </View> | ||||||
|  |  | ||||||
|       {queryKey && !disableDetails ? ( |       {queryKey && !disableDetails ? ( | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import TimelineHeaderNotification from '@components/Timeline/Shared/HeaderNotifi | |||||||
| import TimelinePoll from '@components/Timeline/Shared/Poll' | import TimelinePoll from '@components/Timeline/Shared/Poll' | ||||||
| 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 { TabLocalStackParamList } from '@utils/navigation/navigators' | ||||||
| import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | ||||||
| import { getInstanceAccount } from '@utils/slices/instancesSlice' | import { getInstanceAccount } from '@utils/slices/instancesSlice' | ||||||
| import { StyleConstants } from '@utils/styles/constants' | import { StyleConstants } from '@utils/styles/constants' | ||||||
| @@ -44,7 +45,7 @@ const TimelineNotifications: React.FC<Props> = ({ | |||||||
|     (prev, next) => prev?.id === next?.id |     (prev, next) => prev?.id === next?.id | ||||||
|   ) |   ) | ||||||
|   const navigation = |   const navigation = | ||||||
|     useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>() |     useNavigation<StackNavigationProp<TabLocalStackParamList>>() | ||||||
|  |  | ||||||
|   const actualAccount = notification.status |   const actualAccount = notification.status | ||||||
|     ? notification.status.account |     ? notification.status.account | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ import Icon from '@components/Icon' | |||||||
| import { ParseEmojis } from '@components/Parse' | import { ParseEmojis } from '@components/Parse' | ||||||
| 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 { TabLocalStackParamList } from '@utils/navigation/navigators' | ||||||
| import { StyleConstants } from '@utils/styles/constants' | import { StyleConstants } from '@utils/styles/constants' | ||||||
| import { useTheme } from '@utils/styles/ThemeManager' | import { useTheme } from '@utils/styles/ThemeManager' | ||||||
| import React, { useCallback, useMemo } from 'react' | import React, { useCallback, useMemo } from 'react' | ||||||
| @@ -20,7 +21,7 @@ const TimelineActioned = React.memo( | |||||||
|     const { t } = useTranslation('componentTimeline') |     const { t } = useTranslation('componentTimeline') | ||||||
|     const { colors } = useTheme() |     const { colors } = useTheme() | ||||||
|     const navigation = |     const navigation = | ||||||
|       useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>() |       useNavigation<StackNavigationProp<TabLocalStackParamList>>() | ||||||
|     const name = account.display_name || account.username |     const name = account.display_name || account.username | ||||||
|     const iconColor = colors.primaryDefault |     const iconColor = colors.primaryDefault | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,108 +0,0 @@ | |||||||
| import analytics from '@components/analytics' |  | ||||||
| import { useNavigation } from '@react-navigation/native' |  | ||||||
| import { StackNavigationProp } from '@react-navigation/stack' |  | ||||||
| import { StyleConstants } from '@utils/styles/constants' |  | ||||||
| import { useTheme } from '@utils/styles/ThemeManager' |  | ||||||
| import React from 'react' |  | ||||||
| import { useTranslation } from 'react-i18next' |  | ||||||
| import { StyleSheet, Text, View } from 'react-native' |  | ||||||
|  |  | ||||||
| export interface Props { |  | ||||||
|   status: Mastodon.Status |  | ||||||
|   highlighted: boolean |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const TimelineActionsUsers = React.memo( |  | ||||||
|   ({ status, highlighted }: Props) => { |  | ||||||
|     if (!highlighted) { |  | ||||||
|       return null |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const { t } = useTranslation('componentTimeline') |  | ||||||
|     const { colors } = useTheme() |  | ||||||
|     const navigation = |  | ||||||
|       useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>() |  | ||||||
|  |  | ||||||
|     return ( |  | ||||||
|       <View style={styles.base}> |  | ||||||
|         {status.reblogs_count > 0 ? ( |  | ||||||
|           <Text |  | ||||||
|             accessibilityLabel={t( |  | ||||||
|               'shared.actionsUsers.reblogged_by.accessibilityLabel', |  | ||||||
|               { |  | ||||||
|                 count: status.reblogs_count |  | ||||||
|               } |  | ||||||
|             )} |  | ||||||
|             accessibilityHint={t( |  | ||||||
|               'shared.actionsUsers.reblogged_by.accessibilityHint' |  | ||||||
|             )} |  | ||||||
|             accessibilityRole='button' |  | ||||||
|             style={[styles.text, { color: colors.blue }]} |  | ||||||
|             onPress={() => { |  | ||||||
|               analytics('timeline_shared_actionsusers_press_boosted', { |  | ||||||
|                 count: status.reblogs_count |  | ||||||
|               }) |  | ||||||
|               navigation.push('Tab-Shared-Users', { |  | ||||||
|                 reference: 'statuses', |  | ||||||
|                 id: status.id, |  | ||||||
|                 type: 'reblogged_by', |  | ||||||
|                 count: status.reblogs_count |  | ||||||
|               }) |  | ||||||
|             }} |  | ||||||
|           > |  | ||||||
|             {t('shared.actionsUsers.reblogged_by.text', { |  | ||||||
|               count: status.reblogs_count |  | ||||||
|             })} |  | ||||||
|           </Text> |  | ||||||
|         ) : null} |  | ||||||
|         {status.favourites_count > 0 ? ( |  | ||||||
|           <Text |  | ||||||
|             accessibilityLabel={t( |  | ||||||
|               'shared.actionsUsers.favourited_by.accessibilityLabel', |  | ||||||
|               { |  | ||||||
|                 count: status.reblogs_count |  | ||||||
|               } |  | ||||||
|             )} |  | ||||||
|             accessibilityHint={t( |  | ||||||
|               'shared.actionsUsers.favourited_by.accessibilityHint' |  | ||||||
|             )} |  | ||||||
|             accessibilityRole='button' |  | ||||||
|             style={[styles.text, { color: colors.blue }]} |  | ||||||
|             onPress={() => { |  | ||||||
|               analytics('timeline_shared_actionsusers_press_boosted', { |  | ||||||
|                 count: status.favourites_count |  | ||||||
|               }) |  | ||||||
|               navigation.push('Tab-Shared-Users', { |  | ||||||
|                 reference: 'statuses', |  | ||||||
|                 id: status.id, |  | ||||||
|                 type: 'favourited_by', |  | ||||||
|                 count: status.favourites_count |  | ||||||
|               }) |  | ||||||
|             }} |  | ||||||
|           > |  | ||||||
|             {t('shared.actionsUsers.favourited_by.text', { |  | ||||||
|               count: status.favourites_count |  | ||||||
|             })} |  | ||||||
|           </Text> |  | ||||||
|         ) : null} |  | ||||||
|       </View> |  | ||||||
|     ) |  | ||||||
|   }, |  | ||||||
|   (prev, next) => |  | ||||||
|     prev.status.reblogs_count === next.status.reblogs_count && |  | ||||||
|     prev.status.favourites_count === next.status.favourites_count |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const styles = StyleSheet.create({ |  | ||||||
|   base: { |  | ||||||
|     flexDirection: 'row' |  | ||||||
|   }, |  | ||||||
|   text: { |  | ||||||
|     ...StyleConstants.FontStyle.M, |  | ||||||
|     padding: StyleConstants.Spacing.S, |  | ||||||
|     paddingLeft: 0, |  | ||||||
|     marginRight: StyleConstants.Spacing.S |  | ||||||
|   } |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| export default TimelineActionsUsers |  | ||||||
| @@ -6,6 +6,7 @@ import AttachmentImage from '@components/Timeline/Shared/Attachment/Image' | |||||||
| import AttachmentUnsupported from '@components/Timeline/Shared/Attachment/Unsupported' | import AttachmentUnsupported from '@components/Timeline/Shared/Attachment/Unsupported' | ||||||
| import AttachmentVideo from '@components/Timeline/Shared/Attachment/Video' | import AttachmentVideo from '@components/Timeline/Shared/Attachment/Video' | ||||||
| import { useNavigation } from '@react-navigation/native' | import { useNavigation } from '@react-navigation/native' | ||||||
|  | import { StackNavigationProp } from '@react-navigation/stack' | ||||||
| import { RootStackParamList } from '@utils/navigation/navigators' | import { RootStackParamList } from '@utils/navigation/navigators' | ||||||
| import { StyleConstants } from '@utils/styles/constants' | import { StyleConstants } from '@utils/styles/constants' | ||||||
| import layoutAnimation from '@utils/styles/layoutAnimation' | import layoutAnimation from '@utils/styles/layoutAnimation' | ||||||
| @@ -38,7 +39,7 @@ const TimelineAttachment = React.memo( | |||||||
|     const imageUrls = useRef< |     const imageUrls = useRef< | ||||||
|       RootStackParamList['Screen-ImagesViewer']['imageUrls'] |       RootStackParamList['Screen-ImagesViewer']['imageUrls'] | ||||||
|     >([]) |     >([]) | ||||||
|     const navigation = useNavigation() |     const navigation = useNavigation<StackNavigationProp<RootStackParamList>>() | ||||||
|     useEffect(() => { |     useEffect(() => { | ||||||
|       status.media_attachments.forEach((attachment, index) => { |       status.media_attachments.forEach((attachment, index) => { | ||||||
|         switch (attachment.type) { |         switch (attachment.type) { | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ import analytics from '@components/analytics' | |||||||
| import GracefullyImage from '@components/GracefullyImage' | import GracefullyImage from '@components/GracefullyImage' | ||||||
| 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 { TabLocalStackParamList } from '@utils/navigation/navigators' | ||||||
| import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | ||||||
| import { StyleConstants } from '@utils/styles/constants' | import { StyleConstants } from '@utils/styles/constants' | ||||||
| import React, { useCallback } from 'react' | import React, { useCallback } from 'react' | ||||||
| @@ -17,7 +18,7 @@ const TimelineAvatar = React.memo( | |||||||
|   ({ queryKey, account, highlighted }: Props) => { |   ({ queryKey, account, highlighted }: Props) => { | ||||||
|     const { t } = useTranslation('componentTimeline') |     const { t } = useTranslation('componentTimeline') | ||||||
|     const navigation = |     const navigation = | ||||||
|       useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>() |       useNavigation<StackNavigationProp<TabLocalStackParamList>>() | ||||||
|     // Need to fix go back root |     // Need to fix go back root | ||||||
|     const onPress = useCallback(() => { |     const onPress = useCallback(() => { | ||||||
|       analytics('timeline_shared_avatar_press', { |       analytics('timeline_shared_avatar_press', { | ||||||
|   | |||||||
| @@ -5,7 +5,10 @@ import { useTranslation } from 'react-i18next' | |||||||
| import { useSelector } from 'react-redux' | import { useSelector } from 'react-redux' | ||||||
|  |  | ||||||
| export interface Props { | export interface Props { | ||||||
|   status: Mastodon.Status |   status: Pick<Mastodon.Status, 'content' | 'spoiler_text' | 'emojis'> & { | ||||||
|  |     mentions?: Mastodon.Status['mentions'] | ||||||
|  |     tags?: Mastodon.Status['tags'] | ||||||
|  |   } | ||||||
|   numberOfLines?: number |   numberOfLines?: number | ||||||
|   highlighted?: boolean |   highlighted?: boolean | ||||||
|   disableDetails?: boolean |   disableDetails?: boolean | ||||||
|   | |||||||
							
								
								
									
										141
									
								
								src/components/Timeline/Shared/Feedback.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/components/Timeline/Shared/Feedback.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | |||||||
|  | import analytics from '@components/analytics' | ||||||
|  | import { useNavigation } from '@react-navigation/native' | ||||||
|  | import { StackNavigationProp } from '@react-navigation/stack' | ||||||
|  | import { TabLocalStackParamList } from '@utils/navigation/navigators' | ||||||
|  | import { useStatusHistory } from '@utils/queryHooks/statusesHistory' | ||||||
|  | import { StyleConstants } from '@utils/styles/constants' | ||||||
|  | import { useTheme } from '@utils/styles/ThemeManager' | ||||||
|  | import React from 'react' | ||||||
|  | import { useTranslation } from 'react-i18next' | ||||||
|  | import { StyleSheet, Text, View } from 'react-native' | ||||||
|  |  | ||||||
|  | export interface Props { | ||||||
|  |   status: Mastodon.Status | ||||||
|  |   highlighted: boolean | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const TimelineFeedback = React.memo( | ||||||
|  |   ({ status, highlighted }: Props) => { | ||||||
|  |     if (!highlighted) { | ||||||
|  |       return null | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const { t } = useTranslation('componentTimeline') | ||||||
|  |     const { colors } = useTheme() | ||||||
|  |     const navigation = | ||||||
|  |       useNavigation<StackNavigationProp<TabLocalStackParamList>>() | ||||||
|  |  | ||||||
|  |     const { data } = useStatusHistory({ | ||||||
|  |       id: status.id, | ||||||
|  |       options: { enabled: status.edited_at !== undefined } | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     return ( | ||||||
|  |       <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}> | ||||||
|  |         <View> | ||||||
|  |           {status.reblogs_count > 0 ? ( | ||||||
|  |             <Text | ||||||
|  |               accessibilityLabel={t( | ||||||
|  |                 'shared.actionsUsers.reblogged_by.accessibilityLabel', | ||||||
|  |                 { | ||||||
|  |                   count: status.reblogs_count | ||||||
|  |                 } | ||||||
|  |               )} | ||||||
|  |               accessibilityHint={t( | ||||||
|  |                 'shared.actionsUsers.reblogged_by.accessibilityHint' | ||||||
|  |               )} | ||||||
|  |               accessibilityRole='button' | ||||||
|  |               style={[styles.text, { color: colors.blue }]} | ||||||
|  |               onPress={() => { | ||||||
|  |                 analytics('timeline_shared_feedback_press_reblog', { | ||||||
|  |                   count: status.reblogs_count | ||||||
|  |                 }) | ||||||
|  |                 navigation.push('Tab-Shared-Users', { | ||||||
|  |                   reference: 'statuses', | ||||||
|  |                   id: status.id, | ||||||
|  |                   type: 'reblogged_by', | ||||||
|  |                   count: status.reblogs_count | ||||||
|  |                 }) | ||||||
|  |               }} | ||||||
|  |             > | ||||||
|  |               {t('shared.actionsUsers.reblogged_by.text', { | ||||||
|  |                 count: status.reblogs_count | ||||||
|  |               })} | ||||||
|  |             </Text> | ||||||
|  |           ) : null} | ||||||
|  |           {status.favourites_count > 0 ? ( | ||||||
|  |             <Text | ||||||
|  |               accessibilityLabel={t( | ||||||
|  |                 'shared.actionsUsers.favourited_by.accessibilityLabel', | ||||||
|  |                 { | ||||||
|  |                   count: status.reblogs_count | ||||||
|  |                 } | ||||||
|  |               )} | ||||||
|  |               accessibilityHint={t( | ||||||
|  |                 'shared.actionsUsers.favourited_by.accessibilityHint' | ||||||
|  |               )} | ||||||
|  |               accessibilityRole='button' | ||||||
|  |               style={[styles.text, { color: colors.blue }]} | ||||||
|  |               onPress={() => { | ||||||
|  |                 analytics('timeline_shared_feedback_press_favourite', { | ||||||
|  |                   count: status.favourites_count | ||||||
|  |                 }) | ||||||
|  |                 navigation.push('Tab-Shared-Users', { | ||||||
|  |                   reference: 'statuses', | ||||||
|  |                   id: status.id, | ||||||
|  |                   type: 'favourited_by', | ||||||
|  |                   count: status.favourites_count | ||||||
|  |                 }) | ||||||
|  |               }} | ||||||
|  |             > | ||||||
|  |               {t('shared.actionsUsers.favourited_by.text', { | ||||||
|  |                 count: status.favourites_count | ||||||
|  |               })} | ||||||
|  |             </Text> | ||||||
|  |           ) : null} | ||||||
|  |         </View> | ||||||
|  |         <View> | ||||||
|  |           {data && data.length > 1 ? ( | ||||||
|  |             <Text | ||||||
|  |               accessibilityLabel={t( | ||||||
|  |                 'shared.actionsUsers.history.accessibilityLabel', | ||||||
|  |                 { | ||||||
|  |                   count: data.length - 1 | ||||||
|  |                 } | ||||||
|  |               )} | ||||||
|  |               accessibilityHint={t( | ||||||
|  |                 'shared.actionsUsers.history.accessibilityHint' | ||||||
|  |               )} | ||||||
|  |               accessibilityRole='button' | ||||||
|  |               style={[styles.text, { marginRight: 0, color: colors.blue }]} | ||||||
|  |               onPress={() => { | ||||||
|  |                 analytics('timeline_shared_feedback_press_history', { | ||||||
|  |                   count: data.length - 1 | ||||||
|  |                 }) | ||||||
|  |                 navigation.push('Tab-Shared-History', { id: status.id }) | ||||||
|  |               }} | ||||||
|  |             > | ||||||
|  |               {t('shared.actionsUsers.history.text', { | ||||||
|  |                 count: data.length - 1 | ||||||
|  |               })} | ||||||
|  |             </Text> | ||||||
|  |           ) : null} | ||||||
|  |         </View> | ||||||
|  |       </View> | ||||||
|  |     ) | ||||||
|  |   }, | ||||||
|  |   (prev, next) => | ||||||
|  |     prev.status.reblogs_count === next.status.reblogs_count && | ||||||
|  |     prev.status.favourites_count === next.status.favourites_count | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const styles = StyleSheet.create({ | ||||||
|  |   text: { | ||||||
|  |     ...StyleConstants.FontStyle.M, | ||||||
|  |     padding: StyleConstants.Spacing.S, | ||||||
|  |     paddingLeft: 0, | ||||||
|  |     marginRight: StyleConstants.Spacing.S | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | export default TimelineFeedback | ||||||
| @@ -103,6 +103,7 @@ const HeaderConversation = React.memo( | |||||||
|             {conversation.last_status?.created_at ? ( |             {conversation.last_status?.created_at ? ( | ||||||
|               <HeaderSharedCreated |               <HeaderSharedCreated | ||||||
|                 created_at={conversation.last_status?.created_at} |                 created_at={conversation.last_status?.created_at} | ||||||
|  |                 edited_at={conversation.last_status?.edited_at} | ||||||
|               /> |               /> | ||||||
|             ) : null} |             ) : null} | ||||||
|             <HeaderSharedMuted muted={conversation.last_status?.muted} /> |             <HeaderSharedMuted muted={conversation.last_status?.muted} /> | ||||||
|   | |||||||
| @@ -1,5 +1,7 @@ | |||||||
| import Icon from '@components/Icon' | import Icon from '@components/Icon' | ||||||
| import { useNavigation } from '@react-navigation/native' | import { useNavigation } from '@react-navigation/native' | ||||||
|  | import { StackNavigationProp } from '@react-navigation/stack' | ||||||
|  | import { RootStackParamList } from '@utils/navigation/navigators' | ||||||
| import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | ||||||
| import { StyleConstants } from '@utils/styles/constants' | import { StyleConstants } from '@utils/styles/constants' | ||||||
| import { useTheme } from '@utils/styles/ThemeManager' | import { useTheme } from '@utils/styles/ThemeManager' | ||||||
| @@ -21,7 +23,7 @@ export interface Props { | |||||||
| const TimelineHeaderDefault = React.memo( | const TimelineHeaderDefault = React.memo( | ||||||
|   ({ queryKey, rootQueryKey, status }: Props) => { |   ({ queryKey, rootQueryKey, status }: Props) => { | ||||||
|     const { t } = useTranslation('componentTimeline') |     const { t } = useTranslation('componentTimeline') | ||||||
|     const navigation = useNavigation() |     const navigation = useNavigation<StackNavigationProp<RootStackParamList>>() | ||||||
|     const { colors } = useTheme() |     const { colors } = useTheme() | ||||||
|  |  | ||||||
|     return ( |     return ( | ||||||
| @@ -29,7 +31,10 @@ const TimelineHeaderDefault = React.memo( | |||||||
|         <View style={styles.accountAndMeta}> |         <View style={styles.accountAndMeta}> | ||||||
|           <HeaderSharedAccount account={status.account} /> |           <HeaderSharedAccount account={status.account} /> | ||||||
|           <View style={styles.meta}> |           <View style={styles.meta}> | ||||||
|             <HeaderSharedCreated created_at={status.created_at} /> |             <HeaderSharedCreated | ||||||
|  |               created_at={status.created_at} | ||||||
|  |               edited_at={status.edited_at} | ||||||
|  |             /> | ||||||
|             <HeaderSharedVisibility visibility={status.visibility} /> |             <HeaderSharedVisibility visibility={status.visibility} /> | ||||||
|             <HeaderSharedMuted muted={status.muted} /> |             <HeaderSharedMuted muted={status.muted} /> | ||||||
|             <HeaderSharedApplication application={status.application} /> |             <HeaderSharedApplication application={status.application} /> | ||||||
| @@ -45,7 +50,6 @@ const TimelineHeaderDefault = React.memo( | |||||||
|                 queryKey, |                 queryKey, | ||||||
|                 rootQueryKey, |                 rootQueryKey, | ||||||
|                 status, |                 status, | ||||||
|                 url: status.url || status.uri, |  | ||||||
|                 type: 'status' |                 type: 'status' | ||||||
|               }) |               }) | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -4,6 +4,8 @@ import { | |||||||
|   RelationshipOutgoing |   RelationshipOutgoing | ||||||
| } from '@components/Relationship' | } from '@components/Relationship' | ||||||
| import { useNavigation } from '@react-navigation/native' | import { useNavigation } from '@react-navigation/native' | ||||||
|  | import { StackNavigationProp } from '@react-navigation/stack' | ||||||
|  | import { RootStackParamList } from '@utils/navigation/navigators' | ||||||
| import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | import { QueryKeyTimeline } from '@utils/queryHooks/timeline' | ||||||
| import { StyleConstants } from '@utils/styles/constants' | import { StyleConstants } from '@utils/styles/constants' | ||||||
| import { useTheme } from '@utils/styles/ThemeManager' | import { useTheme } from '@utils/styles/ThemeManager' | ||||||
| @@ -22,7 +24,7 @@ export interface Props { | |||||||
|  |  | ||||||
| const TimelineHeaderNotification = React.memo( | const TimelineHeaderNotification = React.memo( | ||||||
|   ({ queryKey, notification }: Props) => { |   ({ queryKey, notification }: Props) => { | ||||||
|     const navigation = useNavigation() |     const navigation = useNavigation<StackNavigationProp<RootStackParamList>>() | ||||||
|     const { colors } = useTheme() |     const { colors } = useTheme() | ||||||
|  |  | ||||||
|     const actions = useMemo(() => { |     const actions = useMemo(() => { | ||||||
| @@ -44,8 +46,7 @@ const TimelineHeaderNotification = React.memo( | |||||||
|                 onPress={() => |                 onPress={() => | ||||||
|                   navigation.navigate('Screen-Actions', { |                   navigation.navigate('Screen-Actions', { | ||||||
|                     queryKey, |                     queryKey, | ||||||
|                     status: notification.status, |                     status: notification.status!, | ||||||
|                     url: notification.status?.url || notification.status?.uri, |  | ||||||
|                     type: 'status' |                     type: 'status' | ||||||
|                   }) |                   }) | ||||||
|                 } |                 } | ||||||
| @@ -83,7 +84,10 @@ const TimelineHeaderNotification = React.memo( | |||||||
|               notification.type === 'follow_request') && { withoutName: true })} |               notification.type === 'follow_request') && { withoutName: true })} | ||||||
|           /> |           /> | ||||||
|           <View style={styles.meta}> |           <View style={styles.meta}> | ||||||
|             <HeaderSharedCreated created_at={notification.created_at} /> |             <HeaderSharedCreated | ||||||
|  |               created_at={notification.created_at} | ||||||
|  |               edited_at={notification.status?.edited_at} | ||||||
|  |             /> | ||||||
|             {notification.status?.visibility ? ( |             {notification.status?.visibility ? ( | ||||||
|               <HeaderSharedVisibility |               <HeaderSharedVisibility | ||||||
|                 visibility={notification.status.visibility} |                 visibility={notification.status.visibility} | ||||||
|   | |||||||
| @@ -1,30 +1,43 @@ | |||||||
|  | import Icon from '@components/Icon' | ||||||
| import RelativeTime from '@components/RelativeTime' | import RelativeTime from '@components/RelativeTime' | ||||||
| import { StyleConstants } from '@utils/styles/constants' | import { StyleConstants } from '@utils/styles/constants' | ||||||
| import { useTheme } from '@utils/styles/ThemeManager' | import { useTheme } from '@utils/styles/ThemeManager' | ||||||
| import React from 'react' | import React from 'react' | ||||||
| import { StyleSheet, Text } from 'react-native' | import { useTranslation } from 'react-i18next' | ||||||
|  | import { Text } from 'react-native' | ||||||
|  |  | ||||||
| export interface Props { | export interface Props { | ||||||
|   created_at: Mastodon.Status['created_at'] | number |   created_at: Mastodon.Status['created_at'] | ||||||
|  |   edited_at?: Mastodon.Status['edited_at'] | ||||||
| } | } | ||||||
|  |  | ||||||
| const HeaderSharedCreated = React.memo( | const HeaderSharedCreated = React.memo( | ||||||
|   ({ created_at }: Props) => { |   ({ created_at, edited_at }: Props) => { | ||||||
|  |     const { t } = useTranslation('componentTimeline') | ||||||
|     const { colors } = useTheme() |     const { colors } = useTheme() | ||||||
|  |  | ||||||
|     return ( |     return ( | ||||||
|       <Text style={[styles.created_at, { color: colors.secondary }]}> |       <> | ||||||
|         <RelativeTime date={created_at} /> |         <Text | ||||||
|  |           style={{ ...StyleConstants.FontStyle.S, color: colors.secondary }} | ||||||
|  |         > | ||||||
|  |           <RelativeTime date={edited_at || created_at} /> | ||||||
|         </Text> |         </Text> | ||||||
|  |         {edited_at ? ( | ||||||
|  |           <Icon | ||||||
|  |             accessibilityLabel={t( | ||||||
|  |               'shared.header.shared.edited.accessibilityLabel' | ||||||
|  |             )} | ||||||
|  |             name='Edit' | ||||||
|  |             size={StyleConstants.Font.Size.S} | ||||||
|  |             color={colors.secondary} | ||||||
|  |             style={{ marginLeft: StyleConstants.Spacing.S }} | ||||||
|  |           /> | ||||||
|  |         ) : null} | ||||||
|  |       </> | ||||||
|     ) |     ) | ||||||
|   }, |   }, | ||||||
|   () => true |   () => true | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const styles = StyleSheet.create({ |  | ||||||
|   created_at: { |  | ||||||
|     ...StyleConstants.FontStyle.S |  | ||||||
|   } |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| export default HeaderSharedCreated | export default HeaderSharedCreated | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								src/helpers/features.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/helpers/features.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | [ | ||||||
|  |   { | ||||||
|  |     "feature": "edit_post", | ||||||
|  |     "version": 3.5, | ||||||
|  |     "reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0" | ||||||
|  |   } | ||||||
|  | ] | ||||||
| @@ -58,6 +58,12 @@ | |||||||
|         "accessibilityLabel": "{{count}} users have favourited this toot", |         "accessibilityLabel": "{{count}} users have favourited this toot", | ||||||
|         "accessibilityHint": "Tap to know the users", |         "accessibilityHint": "Tap to know the users", | ||||||
|         "text": "$t(screenTabs:shared.users.statuses.favourited_by)" |         "text": "$t(screenTabs:shared.users.statuses.favourited_by)" | ||||||
|  |       }, | ||||||
|  |       "history": { | ||||||
|  |         "accessibilityLabel": "This toot has been edited {{count}} times", | ||||||
|  |         "accessibilityHint": "Tap to know view the full history", | ||||||
|  |         "text": "{{count}} edit", | ||||||
|  |         "text_plural": "{{count}} edits" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "attachment": { |     "attachment": { | ||||||
| @@ -96,6 +102,9 @@ | |||||||
|           } |           } | ||||||
|         }, |         }, | ||||||
|         "application": "Tooted with {{application}}", |         "application": "Tooted with {{application}}", | ||||||
|  |         "edited": { | ||||||
|  |           "accessibilityLabel": "Toot edited" | ||||||
|  |         }, | ||||||
|         "muted": { |         "muted": { | ||||||
|           "accessibilityLabel": "Toot muted" |           "accessibilityLabel": "Toot muted" | ||||||
|         }, |         }, | ||||||
|   | |||||||
| @@ -331,6 +331,9 @@ | |||||||
|         "reblogged_by": "{{count}} boosted", |         "reblogged_by": "{{count}} boosted", | ||||||
|         "favourited_by": "{{count}} favourited" |         "favourited_by": "{{count}} favourited" | ||||||
|       } |       } | ||||||
|  |     }, | ||||||
|  |     "history": { | ||||||
|  |       "name": "Edit History" | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
							
								
								
									
										105
									
								
								src/screens/Tabs/Shared/History.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								src/screens/Tabs/Shared/History.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | |||||||
|  | import Icon from '@components/Icon' | ||||||
|  | import { ParseEmojis } from '@components/Parse' | ||||||
|  | import ComponentSeparator from '@components/Separator' | ||||||
|  | import TimelineAttachment from '@components/Timeline/Shared/Attachment' | ||||||
|  | import TimelineContent from '@components/Timeline/Shared/Content' | ||||||
|  | import HeaderSharedCreated from '@components/Timeline/Shared/HeaderShared/Created' | ||||||
|  | import { TabSharedStackScreenProps } from '@utils/navigation/navigators' | ||||||
|  | import { useStatusHistory } from '@utils/queryHooks/statusesHistory' | ||||||
|  | import { StyleConstants } from '@utils/styles/constants' | ||||||
|  | import { useTheme } from '@utils/styles/ThemeManager' | ||||||
|  | import React from 'react' | ||||||
|  | import { Text, View } from 'react-native' | ||||||
|  | import { ScrollView } from 'react-native-gesture-handler' | ||||||
|  |  | ||||||
|  | const ContentView = ({ | ||||||
|  |   history, | ||||||
|  |   first, | ||||||
|  |   last | ||||||
|  | }: { | ||||||
|  |   history: Mastodon.StatusHistory | ||||||
|  |   first: boolean | ||||||
|  |   last: boolean | ||||||
|  | }) => { | ||||||
|  |   const { colors } = useTheme() | ||||||
|  |   return ( | ||||||
|  |     <> | ||||||
|  |       <View | ||||||
|  |         style={{ | ||||||
|  |           padding: StyleConstants.Spacing.Global.PagePadding, | ||||||
|  |           paddingTop: first ? 0 : undefined | ||||||
|  |         }} | ||||||
|  |       > | ||||||
|  |         <HeaderSharedCreated created_at={history.created_at} /> | ||||||
|  |         {typeof history.content === 'string' && history.content.length > 0 ? ( | ||||||
|  |           <TimelineContent status={history} /> | ||||||
|  |         ) : null} | ||||||
|  |         {history.poll | ||||||
|  |           ? history.poll.options.map((option, index) => ( | ||||||
|  |               <View | ||||||
|  |                 key={index} | ||||||
|  |                 style={{ flex: 1, paddingVertical: StyleConstants.Spacing.S }} | ||||||
|  |               > | ||||||
|  |                 <View style={{ flex: 1, flexDirection: 'row' }}> | ||||||
|  |                   <Icon | ||||||
|  |                     style={{ | ||||||
|  |                       paddingTop: | ||||||
|  |                         StyleConstants.Font.LineHeight.M - | ||||||
|  |                         StyleConstants.Font.Size.M, | ||||||
|  |                       marginRight: StyleConstants.Spacing.S | ||||||
|  |                     }} | ||||||
|  |                     name='Circle' | ||||||
|  |                     size={StyleConstants.Font.Size.M} | ||||||
|  |                     color={colors.disabled} | ||||||
|  |                   /> | ||||||
|  |                   <Text style={{ flex: 1 }}> | ||||||
|  |                     <ParseEmojis | ||||||
|  |                       content={option.title} | ||||||
|  |                       emojis={history.poll?.emojis} | ||||||
|  |                     /> | ||||||
|  |                   </Text> | ||||||
|  |                 </View> | ||||||
|  |               </View> | ||||||
|  |             )) | ||||||
|  |           : null} | ||||||
|  |         {Array.isArray(history.media_attachments) && | ||||||
|  |         history.media_attachments.length ? ( | ||||||
|  |           <TimelineAttachment status={history} /> | ||||||
|  |         ) : null} | ||||||
|  |       </View> | ||||||
|  |       {!last ? <ComponentSeparator extraMarginLeft={0} /> : null} | ||||||
|  |     </> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const TabSharedHistory: React.FC< | ||||||
|  |   TabSharedStackScreenProps<'Tab-Shared-History'> | ||||||
|  | > = ({ | ||||||
|  |   route: { | ||||||
|  |     params: { id } | ||||||
|  |   } | ||||||
|  | }) => { | ||||||
|  |   const { data } = useStatusHistory({ id }) | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <ScrollView> | ||||||
|  |       {data && data.length > 0 | ||||||
|  |         ? data | ||||||
|  |             .slice(0) | ||||||
|  |             .reverse() | ||||||
|  |             .map((d, i) => | ||||||
|  |               i !== 0 ? ( | ||||||
|  |                 <ContentView | ||||||
|  |                   key={i} | ||||||
|  |                   history={d} | ||||||
|  |                   first={i === 1} | ||||||
|  |                   last={i === data.length - 1} | ||||||
|  |                 /> | ||||||
|  |               ) : null | ||||||
|  |             ) | ||||||
|  |         : null} | ||||||
|  |     </ScrollView> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default TabSharedHistory | ||||||
| @@ -4,6 +4,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack' | |||||||
| import TabSharedAccount from '@screens/Tabs/Shared/Account' | import TabSharedAccount from '@screens/Tabs/Shared/Account' | ||||||
| import TabSharedAttachments from '@screens/Tabs/Shared/Attachments' | import TabSharedAttachments from '@screens/Tabs/Shared/Attachments' | ||||||
| import TabSharedHashtag from '@screens/Tabs/Shared/Hashtag' | import TabSharedHashtag from '@screens/Tabs/Shared/Hashtag' | ||||||
|  | import TabSharedHistory from '@screens/Tabs/Shared/History' | ||||||
| import TabSharedSearch from '@screens/Tabs/Shared/Search' | import TabSharedSearch from '@screens/Tabs/Shared/Search' | ||||||
| import TabSharedToot from '@screens/Tabs/Shared/Toot' | import TabSharedToot from '@screens/Tabs/Shared/Toot' | ||||||
| import TabSharedUsers from '@screens/Tabs/Shared/Users' | import TabSharedUsers from '@screens/Tabs/Shared/Users' | ||||||
| @@ -95,6 +96,13 @@ const TabSharedRoot = ({ | |||||||
|         })} |         })} | ||||||
|       /> |       /> | ||||||
|  |  | ||||||
|  |       <Stack.Screen | ||||||
|  |         key='Tab-Shared-History' | ||||||
|  |         name='Tab-Shared-History' | ||||||
|  |         component={TabSharedHistory} | ||||||
|  |         options={{ title: t('screenTabs:shared.history.name') }} | ||||||
|  |       /> | ||||||
|  |  | ||||||
|       <Stack.Screen |       <Stack.Screen | ||||||
|         key='Tab-Shared-Search' |         key='Tab-Shared-Search' | ||||||
|         name='Tab-Shared-Search' |         name='Tab-Shared-Search' | ||||||
|   | |||||||
| @@ -70,9 +70,8 @@ export type RootStackParamList = { | |||||||
|     id: Mastodon.Attachment['id'] |     id: Mastodon.Attachment['id'] | ||||||
|   } |   } | ||||||
| } | } | ||||||
| export type RootStackScreenProps< | export type RootStackScreenProps<T extends keyof RootStackParamList> = | ||||||
|   T extends keyof RootStackParamList |   NativeStackScreenProps<RootStackParamList, T> | ||||||
| > = NativeStackScreenProps<RootStackParamList, T> |  | ||||||
|  |  | ||||||
| export type ScreenComposeStackParamList = { | export type ScreenComposeStackParamList = { | ||||||
|   'Screen-Compose-Root': undefined |   'Screen-Compose-Root': undefined | ||||||
| @@ -90,9 +89,8 @@ export type ScreenTabsStackParamList = { | |||||||
|   'Tab-Notifications': NavigatorScreenParams<TabNotificationsStackParamList> |   'Tab-Notifications': NavigatorScreenParams<TabNotificationsStackParamList> | ||||||
|   'Tab-Me': NavigatorScreenParams<TabMeStackParamList> |   'Tab-Me': NavigatorScreenParams<TabMeStackParamList> | ||||||
| } | } | ||||||
| export type ScreenTabsScreenProps< | export type ScreenTabsScreenProps<T extends keyof ScreenTabsStackParamList> = | ||||||
|   T extends keyof ScreenTabsStackParamList |   BottomTabScreenProps<ScreenTabsStackParamList, T> | ||||||
| > = BottomTabScreenProps<ScreenTabsStackParamList, T> |  | ||||||
|  |  | ||||||
| export type TabSharedStackParamList = { | export type TabSharedStackParamList = { | ||||||
|   'Tab-Shared-Account': { |   'Tab-Shared-Account': { | ||||||
| @@ -102,6 +100,9 @@ export type TabSharedStackParamList = { | |||||||
|   'Tab-Shared-Hashtag': { |   'Tab-Shared-Hashtag': { | ||||||
|     hashtag: Mastodon.Tag['name'] |     hashtag: Mastodon.Tag['name'] | ||||||
|   } |   } | ||||||
|  |   'Tab-Shared-History': { | ||||||
|  |     id: Mastodon.Status['id'] | ||||||
|  |   } | ||||||
|   'Tab-Shared-Search': { text: string | undefined } |   'Tab-Shared-Search': { text: string | undefined } | ||||||
|   'Tab-Shared-Toot': { |   'Tab-Shared-Toot': { | ||||||
|     toot: Mastodon.Status |     toot: Mastodon.Status | ||||||
| @@ -121,9 +122,8 @@ export type TabSharedStackParamList = { | |||||||
|         count: number |         count: number | ||||||
|       } |       } | ||||||
| } | } | ||||||
| export type TabSharedStackScreenProps< | export type TabSharedStackScreenProps<T extends keyof TabSharedStackParamList> = | ||||||
|   T extends keyof TabSharedStackParamList |   NativeStackScreenProps<TabSharedStackParamList, T> | ||||||
| > = NativeStackScreenProps<TabSharedStackParamList, T> |  | ||||||
|  |  | ||||||
| export type TabLocalStackParamList = { | export type TabLocalStackParamList = { | ||||||
|   'Tab-Local-Root': undefined |   'Tab-Local-Root': undefined | ||||||
| @@ -153,9 +153,8 @@ export type TabMeStackParamList = { | |||||||
|   'Tab-Me-Settings-Fontsize': undefined |   'Tab-Me-Settings-Fontsize': undefined | ||||||
|   'Tab-Me-Switch': undefined |   'Tab-Me-Switch': undefined | ||||||
| } & TabSharedStackParamList | } & TabSharedStackParamList | ||||||
| export type TabMeStackScreenProps< | export type TabMeStackScreenProps<T extends keyof TabMeStackParamList> = | ||||||
|   T extends keyof TabMeStackParamList |   NativeStackScreenProps<TabMeStackParamList, T> | ||||||
| > = NativeStackScreenProps<TabMeStackParamList, T> |  | ||||||
| export type TabMeStackNavigationProp< | export type TabMeStackNavigationProp< | ||||||
|   RouteName extends keyof TabMeStackParamList |   RouteName extends keyof TabMeStackParamList | ||||||
| > = StackNavigationProp<TabMeStackParamList, RouteName> | > = StackNavigationProp<TabMeStackParamList, RouteName> | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								src/utils/queryHooks/statusesHistory.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/utils/queryHooks/statusesHistory.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | import apiInstance from '@api/instance' | ||||||
|  | import { AxiosError } from 'axios' | ||||||
|  | import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query' | ||||||
|  |  | ||||||
|  | export type QueryKeyStatusesHistory = [ | ||||||
|  |   'StatusesHistory', | ||||||
|  |   { id: Mastodon.Status['id'] } | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | const queryFunction = async ({ | ||||||
|  |   queryKey | ||||||
|  | }: QueryFunctionContext<QueryKeyStatusesHistory>) => { | ||||||
|  |   const { id } = queryKey[1] | ||||||
|  |   const res = await apiInstance<Mastodon.StatusHistory[]>({ | ||||||
|  |     method: 'get', | ||||||
|  |     url: `statuses/${id}/history` | ||||||
|  |   }) | ||||||
|  |   return res.body | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const useStatusHistory = ({ | ||||||
|  |   options, | ||||||
|  |   ...queryKeyParams | ||||||
|  | }: QueryKeyStatusesHistory[1] & { | ||||||
|  |   options?: UseQueryOptions<Mastodon.StatusHistory[], AxiosError> | ||||||
|  | }) => { | ||||||
|  |   const queryKey: QueryKeyStatusesHistory = [ | ||||||
|  |     'StatusesHistory', | ||||||
|  |     { ...queryKeyParams } | ||||||
|  |   ] | ||||||
|  |   return useQuery(queryKey, queryFunction, options) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export { useStatusHistory } | ||||||
| @@ -1,4 +1,5 @@ | |||||||
| import analytics from '@components/analytics' | import analytics from '@components/analytics' | ||||||
|  | import features from '@helpers/features' | ||||||
| import { createSlice, PayloadAction } from '@reduxjs/toolkit' | import { createSlice, PayloadAction } from '@reduxjs/toolkit' | ||||||
| import { RootState } from '@root/store' | import { RootState } from '@root/store' | ||||||
| import { ComposeStateDraft } from '@screens/Compose/utils/types' | import { ComposeStateDraft } from '@screens/Compose/utils/types' | ||||||
| @@ -341,9 +342,17 @@ export const getInstanceUrls = ({ instances: { instances } }: RootState) => | |||||||
|  |  | ||||||
| export const getInstanceVersion = ({ instances: { instances } }: RootState) => | export const getInstanceVersion = ({ instances: { instances } }: RootState) => | ||||||
|   instances[findInstanceActive(instances)]?.version |   instances[findInstanceActive(instances)]?.version | ||||||
| export const getInstanceVersionInFloat = ({ | export const checkInstanceFeature = | ||||||
|   instances: { instances } |   (feature: string) => | ||||||
| }: RootState) => parseFloat(instances[findInstanceActive(instances)]?.version) |   ({ instances: { instances } }: RootState) => { | ||||||
|  |     return features | ||||||
|  |       .filter(f => f.feature === feature) | ||||||
|  |       .filter( | ||||||
|  |         f => | ||||||
|  |           parseFloat(instances[findInstanceActive(instances)]?.version) >= | ||||||
|  |           f.version | ||||||
|  |       ) | ||||||
|  |   } | ||||||
|  |  | ||||||
| /* Get Instance Configuration */ | /* Get Instance Configuration */ | ||||||
| export const getInstanceConfigurationStatusMaxChars = ({ | export const getInstanceConfigurationStatusMaxChars = ({ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user