Edited posts can be viewed

This commit is contained in:
Zhiyuan Zheng 2022-04-29 23:57:18 +02:00
parent bceb70e805
commit 95ec76f411
25 changed files with 411 additions and 154 deletions

View File

@ -426,6 +426,7 @@ declare namespace Mastodon {
reblogs_count: number
favourites_count: number
replies_count: number
edited_at?: string // FEATURE edit_post
favourited: boolean
reblogged: boolean
muted: boolean
@ -443,6 +444,17 @@ declare namespace Mastodon {
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 = {
// Base
note: string

View File

@ -4,3 +4,8 @@ declare module 'li'
declare module 'react-native-feather'
declare module 'react-native-htmlview'
declare module 'react-native-toast-message'
declare module '@helpers/features' {
const features: { feature: string; version: number; reference?: string }[]
export default features
}

View File

@ -1,5 +1,6 @@
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback } from 'react'
@ -19,7 +20,7 @@ const ComponentHashtag: React.FC<Props> = ({
}) => {
const { colors } = useTheme()
const navigation =
useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
useNavigation<StackNavigationProp<TabLocalStackParamList>>()
const onPress = useCallback(() => {
analytics('search_account_press', { page: origin })

View File

@ -4,6 +4,7 @@ import openLink from '@components/openLink'
import ParseEmojis from '@components/Parse/Emojis'
import { useNavigation, useRoute } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { getSettingsFontsize } from '@utils/slices/settingsSlice'
import { StyleConstants } from '@utils/styles/constants'
import layoutAnimation from '@utils/styles/layoutAnimation'
@ -35,7 +36,7 @@ const renderNode = ({
index: number
adaptedFontsize: number
adaptedLineheight: number
navigation: StackNavigationProp<Nav.TabLocalStackParamList>
navigation: StackNavigationProp<TabLocalStackParamList>
mentions?: Mastodon.Mention[]
tags?: Mastodon.Tag[]
showFullLink: boolean
@ -194,7 +195,7 @@ const ParseHTML = React.memo(
)
const navigation =
useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
useNavigation<StackNavigationProp<TabLocalStackParamList>>()
const route = useRoute()
const { colors, theme } = useTheme()
const { t, i18n } = useTranslation('componentParse')

View File

@ -3,6 +3,7 @@ import analytics from '@components/analytics'
import GracefullyImage from '@components/GracefullyImage'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { getInstanceAccount } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
@ -78,7 +79,7 @@ const TimelineConversation: React.FC<Props> = ({
})
const navigation =
useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
useNavigation<StackNavigationProp<TabLocalStackParamList>>()
const onPress = useCallback(() => {
analytics('timeline_conversation_press')
if (conversation.last_status) {

View File

@ -9,6 +9,7 @@ import TimelineHeaderDefault from '@components/Timeline/Shared/HeaderDefault'
import TimelinePoll from '@components/Timeline/Shared/Poll'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { getInstanceAccount } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
@ -17,7 +18,7 @@ import { uniqBy } from 'lodash'
import React, { useCallback } from 'react'
import { Pressable, StyleSheet, View } from 'react-native'
import { useSelector } from 'react-redux'
import TimelineActionsUsers from './Shared/ActionsUsers'
import TimelineFeedback from './Shared/Feedback'
import TimelineFiltered, { shouldFilter } from './Shared/Filtered'
import TimelineFullConversation from './Shared/FullConversation'
import TimelineTranslate from './Shared/Translate'
@ -45,7 +46,7 @@ const TimelineDefault: React.FC<Props> = ({
const { colors } = useTheme()
const instanceAccount = useSelector(getInstanceAccount, () => true)
const navigation =
useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
useNavigation<StackNavigationProp<TabLocalStackParamList>>()
const actualStatus = item.reblog ? item.reblog : item
@ -143,7 +144,7 @@ const TimelineDefault: React.FC<Props> = ({
<TimelineFullConversation queryKey={queryKey} status={actualStatus} />
) : null}
<TimelineTranslate status={actualStatus} highlighted={highlighted} />
<TimelineActionsUsers status={actualStatus} highlighted={highlighted} />
<TimelineFeedback status={actualStatus} highlighted={highlighted} />
</View>
{queryKey && !disableDetails ? (

View File

@ -9,6 +9,7 @@ import TimelineHeaderNotification from '@components/Timeline/Shared/HeaderNotifi
import TimelinePoll from '@components/Timeline/Shared/Poll'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { getInstanceAccount } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
@ -44,7 +45,7 @@ const TimelineNotifications: React.FC<Props> = ({
(prev, next) => prev?.id === next?.id
)
const navigation =
useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
useNavigation<StackNavigationProp<TabLocalStackParamList>>()
const actualAccount = notification.status
? notification.status.account

View File

@ -3,6 +3,7 @@ import Icon from '@components/Icon'
import { ParseEmojis } from '@components/Parse'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useMemo } from 'react'
@ -20,7 +21,7 @@ const TimelineActioned = React.memo(
const { t } = useTranslation('componentTimeline')
const { colors } = useTheme()
const navigation =
useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
useNavigation<StackNavigationProp<TabLocalStackParamList>>()
const name = account.display_name || account.username
const iconColor = colors.primaryDefault

View File

@ -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

View File

@ -6,6 +6,7 @@ import AttachmentImage from '@components/Timeline/Shared/Attachment/Image'
import AttachmentUnsupported from '@components/Timeline/Shared/Attachment/Unsupported'
import AttachmentVideo from '@components/Timeline/Shared/Attachment/Video'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { RootStackParamList } from '@utils/navigation/navigators'
import { StyleConstants } from '@utils/styles/constants'
import layoutAnimation from '@utils/styles/layoutAnimation'
@ -38,7 +39,7 @@ const TimelineAttachment = React.memo(
const imageUrls = useRef<
RootStackParamList['Screen-ImagesViewer']['imageUrls']
>([])
const navigation = useNavigation()
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>()
useEffect(() => {
status.media_attachments.forEach((attachment, index) => {
switch (attachment.type) {

View File

@ -2,6 +2,7 @@ import analytics from '@components/analytics'
import GracefullyImage from '@components/GracefullyImage'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { StyleConstants } from '@utils/styles/constants'
import React, { useCallback } from 'react'
@ -17,7 +18,7 @@ const TimelineAvatar = React.memo(
({ queryKey, account, highlighted }: Props) => {
const { t } = useTranslation('componentTimeline')
const navigation =
useNavigation<StackNavigationProp<Nav.TabLocalStackParamList>>()
useNavigation<StackNavigationProp<TabLocalStackParamList>>()
// Need to fix go back root
const onPress = useCallback(() => {
analytics('timeline_shared_avatar_press', {

View File

@ -5,7 +5,10 @@ import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
export interface Props {
status: Mastodon.Status
status: Pick<Mastodon.Status, 'content' | 'spoiler_text' | 'emojis'> & {
mentions?: Mastodon.Status['mentions']
tags?: Mastodon.Status['tags']
}
numberOfLines?: number
highlighted?: boolean
disableDetails?: boolean

View 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

View File

@ -103,6 +103,7 @@ const HeaderConversation = React.memo(
{conversation.last_status?.created_at ? (
<HeaderSharedCreated
created_at={conversation.last_status?.created_at}
edited_at={conversation.last_status?.edited_at}
/>
) : null}
<HeaderSharedMuted muted={conversation.last_status?.muted} />

View File

@ -1,5 +1,7 @@
import Icon from '@components/Icon'
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 { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@ -21,7 +23,7 @@ export interface Props {
const TimelineHeaderDefault = React.memo(
({ queryKey, rootQueryKey, status }: Props) => {
const { t } = useTranslation('componentTimeline')
const navigation = useNavigation()
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>()
const { colors } = useTheme()
return (
@ -29,7 +31,10 @@ const TimelineHeaderDefault = React.memo(
<View style={styles.accountAndMeta}>
<HeaderSharedAccount account={status.account} />
<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} />
<HeaderSharedMuted muted={status.muted} />
<HeaderSharedApplication application={status.application} />
@ -45,7 +50,6 @@ const TimelineHeaderDefault = React.memo(
queryKey,
rootQueryKey,
status,
url: status.url || status.uri,
type: 'status'
})
}

View File

@ -4,6 +4,8 @@ import {
RelationshipOutgoing
} from '@components/Relationship'
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 { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@ -22,7 +24,7 @@ export interface Props {
const TimelineHeaderNotification = React.memo(
({ queryKey, notification }: Props) => {
const navigation = useNavigation()
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>()
const { colors } = useTheme()
const actions = useMemo(() => {
@ -44,8 +46,7 @@ const TimelineHeaderNotification = React.memo(
onPress={() =>
navigation.navigate('Screen-Actions', {
queryKey,
status: notification.status,
url: notification.status?.url || notification.status?.uri,
status: notification.status!,
type: 'status'
})
}
@ -83,7 +84,10 @@ const TimelineHeaderNotification = React.memo(
notification.type === 'follow_request') && { withoutName: true })}
/>
<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 ? (
<HeaderSharedVisibility
visibility={notification.status.visibility}

View File

@ -1,30 +1,43 @@
import Icon from '@components/Icon'
import RelativeTime from '@components/RelativeTime'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import { StyleSheet, Text } from 'react-native'
import { useTranslation } from 'react-i18next'
import { Text } from 'react-native'
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(
({ created_at }: Props) => {
({ created_at, edited_at }: Props) => {
const { t } = useTranslation('componentTimeline')
const { colors } = useTheme()
return (
<Text style={[styles.created_at, { color: colors.secondary }]}>
<RelativeTime date={created_at} />
</Text>
<>
<Text
style={{ ...StyleConstants.FontStyle.S, color: colors.secondary }}
>
<RelativeTime date={edited_at || created_at} />
</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
)
const styles = StyleSheet.create({
created_at: {
...StyleConstants.FontStyle.S
}
})
export default HeaderSharedCreated

View File

@ -0,0 +1,7 @@
[
{
"feature": "edit_post",
"version": 3.5,
"reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
}
]

View File

@ -58,6 +58,12 @@
"accessibilityLabel": "{{count}} users have favourited this toot",
"accessibilityHint": "Tap to know the users",
"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": {
@ -96,6 +102,9 @@
}
},
"application": "Tooted with {{application}}",
"edited": {
"accessibilityLabel": "Toot edited"
},
"muted": {
"accessibilityLabel": "Toot muted"
},

View File

@ -331,6 +331,9 @@
"reblogged_by": "{{count}} boosted",
"favourited_by": "{{count}} favourited"
}
},
"history": {
"name": "Edit History"
}
}
}

View 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

View File

@ -4,6 +4,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack'
import TabSharedAccount from '@screens/Tabs/Shared/Account'
import TabSharedAttachments from '@screens/Tabs/Shared/Attachments'
import TabSharedHashtag from '@screens/Tabs/Shared/Hashtag'
import TabSharedHistory from '@screens/Tabs/Shared/History'
import TabSharedSearch from '@screens/Tabs/Shared/Search'
import TabSharedToot from '@screens/Tabs/Shared/Toot'
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
key='Tab-Shared-Search'
name='Tab-Shared-Search'

View File

@ -70,9 +70,8 @@ export type RootStackParamList = {
id: Mastodon.Attachment['id']
}
}
export type RootStackScreenProps<
T extends keyof RootStackParamList
> = NativeStackScreenProps<RootStackParamList, T>
export type RootStackScreenProps<T extends keyof RootStackParamList> =
NativeStackScreenProps<RootStackParamList, T>
export type ScreenComposeStackParamList = {
'Screen-Compose-Root': undefined
@ -90,9 +89,8 @@ export type ScreenTabsStackParamList = {
'Tab-Notifications': NavigatorScreenParams<TabNotificationsStackParamList>
'Tab-Me': NavigatorScreenParams<TabMeStackParamList>
}
export type ScreenTabsScreenProps<
T extends keyof ScreenTabsStackParamList
> = BottomTabScreenProps<ScreenTabsStackParamList, T>
export type ScreenTabsScreenProps<T extends keyof ScreenTabsStackParamList> =
BottomTabScreenProps<ScreenTabsStackParamList, T>
export type TabSharedStackParamList = {
'Tab-Shared-Account': {
@ -102,6 +100,9 @@ export type TabSharedStackParamList = {
'Tab-Shared-Hashtag': {
hashtag: Mastodon.Tag['name']
}
'Tab-Shared-History': {
id: Mastodon.Status['id']
}
'Tab-Shared-Search': { text: string | undefined }
'Tab-Shared-Toot': {
toot: Mastodon.Status
@ -121,9 +122,8 @@ export type TabSharedStackParamList = {
count: number
}
}
export type TabSharedStackScreenProps<
T extends keyof TabSharedStackParamList
> = NativeStackScreenProps<TabSharedStackParamList, T>
export type TabSharedStackScreenProps<T extends keyof TabSharedStackParamList> =
NativeStackScreenProps<TabSharedStackParamList, T>
export type TabLocalStackParamList = {
'Tab-Local-Root': undefined
@ -153,9 +153,8 @@ export type TabMeStackParamList = {
'Tab-Me-Settings-Fontsize': undefined
'Tab-Me-Switch': undefined
} & TabSharedStackParamList
export type TabMeStackScreenProps<
T extends keyof TabMeStackParamList
> = NativeStackScreenProps<TabMeStackParamList, T>
export type TabMeStackScreenProps<T extends keyof TabMeStackParamList> =
NativeStackScreenProps<TabMeStackParamList, T>
export type TabMeStackNavigationProp<
RouteName extends keyof TabMeStackParamList
> = StackNavigationProp<TabMeStackParamList, RouteName>

View 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 }

View File

@ -1,4 +1,5 @@
import analytics from '@components/analytics'
import features from '@helpers/features'
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { RootState } from '@root/store'
import { ComposeStateDraft } from '@screens/Compose/utils/types'
@ -341,9 +342,17 @@ export const getInstanceUrls = ({ instances: { instances } }: RootState) =>
export const getInstanceVersion = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.version
export const getInstanceVersionInFloat = ({
instances: { instances }
}: RootState) => parseFloat(instances[findInstanceActive(instances)]?.version)
export const checkInstanceFeature =
(feature: string) =>
({ instances: { instances } }: RootState) => {
return features
.filter(f => f.feature === feature)
.filter(
f =>
parseFloat(instances[findInstanceActive(instances)]?.version) >=
f.version
)
}
/* Get Instance Configuration */
export const getInstanceConfigurationStatusMaxChars = ({