mirror of
https://github.com/tooot-app/app
synced 2025-05-10 23:09:08 +02:00
Edited posts can be viewed
This commit is contained in:
parent
bceb70e805
commit
95ec76f411
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 = ({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user