mirror of
https://github.com/tooot-app/app
synced 2025-03-06 12:37:44 +01:00
Account actions working for #638
This commit is contained in:
parent
62df29a479
commit
6dafbc96af
2
src/@types/i18next.d.ts
vendored
2
src/@types/i18next.d.ts
vendored
@ -4,7 +4,6 @@ import common from '../i18n/en/common.json'
|
||||
import screens from '../i18n/en/screens.json'
|
||||
|
||||
import screenAccountSelection from '../i18n/en/screens/accountSelection.json'
|
||||
import screenActions from '../i18n/en/screens/actions.json'
|
||||
import screenAnnouncements from '../i18n/en/screens/announcements.json'
|
||||
import screenCompose from '../i18n/en/screens/compose.json'
|
||||
import screenImageViewer from '../i18n/en/screens/imageViewer.json'
|
||||
@ -26,7 +25,6 @@ declare module 'i18next' {
|
||||
screens: typeof screens
|
||||
|
||||
screenAccountSelection: typeof screenAccountSelection
|
||||
screenActions: typeof screenActions
|
||||
screenAnnouncements: typeof screenAnnouncements
|
||||
screenCompose: typeof screenCompose
|
||||
screenImageViewer: typeof screenImageViewer
|
||||
|
@ -168,7 +168,10 @@ const ParseHTML: React.FC<Props> = ({
|
||||
matchedMention &&
|
||||
!disableDetails &&
|
||||
!sameAccount &&
|
||||
navigation.push('Tab-Shared-Account', { account: matchedMention })
|
||||
navigation.push('Tab-Shared-Account', {
|
||||
account: matchedMention,
|
||||
isRemote: status?._remote
|
||||
})
|
||||
}
|
||||
children={node.children.map(unwrapNode).join('')}
|
||||
/>
|
||||
|
@ -37,7 +37,8 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
|
||||
/>
|
||||
)
|
||||
|
||||
const onPress = () => navigation.push('Tab-Shared-Account', { account })
|
||||
const onPress = () =>
|
||||
navigation.push('Tab-Shared-Account', { account, isRemote: status?._remote })
|
||||
|
||||
const children = () => {
|
||||
switch (action) {
|
||||
|
@ -1,8 +1,7 @@
|
||||
import Button from '@components/Button'
|
||||
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 { useTranslation } from 'react-i18next'
|
||||
import { Alert } from 'react-native'
|
||||
|
||||
export interface Props {
|
||||
sensitiveShown: boolean
|
||||
@ -14,7 +13,7 @@ const AttachmentAltText: React.FC<Props> = ({ sensitiveShown, text }) => {
|
||||
return null
|
||||
}
|
||||
|
||||
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>()
|
||||
const { t } = useTranslation('componentTimeline')
|
||||
|
||||
return !sensitiveShown ? (
|
||||
<Button
|
||||
@ -28,7 +27,7 @@ const AttachmentAltText: React.FC<Props> = ({ sensitiveShown, text }) => {
|
||||
type='text'
|
||||
content='ALT'
|
||||
fontBold
|
||||
onPress={() => navigation.navigate('Screen-Actions', { type: 'alt_text', text })}
|
||||
onPress={() => Alert.alert(t('shared.attachment.altText'), text)}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
|
@ -31,7 +31,8 @@ const TimelineAvatar: React.FC<Props> = ({ account }) => {
|
||||
})
|
||||
})}
|
||||
onPress={() =>
|
||||
!disableOnPress && navigation.push('Tab-Shared-Account', { account: actualAccount })
|
||||
!disableOnPress &&
|
||||
navigation.push('Tab-Shared-Account', { account: actualAccount, isRemote: status?._remote })
|
||||
}
|
||||
uri={{ original: actualAccount.avatar, static: actualAccount.avatar_static }}
|
||||
dimension={
|
||||
|
@ -14,7 +14,7 @@ export interface Props {
|
||||
}
|
||||
|
||||
const TimelineContent: React.FC<Props> = ({ notificationOwnToot = false, setSpoilerExpanded }) => {
|
||||
const { status, highlighted, inThread, disableDetails } = useContext(StatusContext)
|
||||
const { status, highlighted, inThread } = useContext(StatusContext)
|
||||
if (!status || typeof status.content !== 'string' || !status.content.length) return null
|
||||
|
||||
const { colors } = useTheme()
|
||||
|
@ -40,7 +40,12 @@ const HeaderSharedReplies: React.FC = () => {
|
||||
<CustomText
|
||||
style={{ color: colors.blue, paddingLeft: StyleConstants.Spacing.S }}
|
||||
children={`@${mention.username}`}
|
||||
onPress={() => navigation.push('Tab-Shared-Account', { account: mention })}
|
||||
onPress={() =>
|
||||
navigation.push('Tab-Shared-Account', {
|
||||
account: mention,
|
||||
isRemote: status?._remote
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Fragment>
|
||||
))}
|
||||
|
@ -4,6 +4,7 @@ import { useNavigation } from '@react-navigation/native'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { TabSharedStackParamList } from '@utils/navigation/navigators'
|
||||
import { useAccountQuery } from '@utils/queryHooks/account'
|
||||
import {
|
||||
QueryKeyRelationship,
|
||||
useRelationshipMutation,
|
||||
@ -34,28 +35,34 @@ const menuAccount = ({
|
||||
queryKey?: QueryKeyTimeline
|
||||
rootQueryKey?: QueryKeyTimeline
|
||||
}): ContextMenu[][] => {
|
||||
if (!account) return []
|
||||
|
||||
const navigation =
|
||||
useNavigation<NativeStackNavigationProp<TabSharedStackParamList, any, undefined>>()
|
||||
const { t } = useTranslation(['common', 'componentContextMenu', 'componentRelationship'])
|
||||
|
||||
const menus: ContextMenu[][] = [[]]
|
||||
|
||||
const ownAccount = useAccountStorage.string('auth.account.id')['0'] === account.id
|
||||
|
||||
const [enabled, setEnabled] = useState(openChange)
|
||||
useEffect(() => {
|
||||
if (!ownAccount && enabled === false && openChange === true) {
|
||||
setEnabled(true)
|
||||
}
|
||||
}, [openChange, enabled])
|
||||
const { data, isFetched } = useRelationshipQuery({ id: account.id, options: { enabled } })
|
||||
const { data: fetchedAccount } = useAccountQuery({
|
||||
remoteUrl: account?.url,
|
||||
options: { enabled: !!status?._remote && enabled }
|
||||
})
|
||||
const actualAccount = status?._remote ? fetchedAccount : account
|
||||
const { data, isFetched } = useRelationshipQuery({
|
||||
id: actualAccount?.id,
|
||||
options: { enabled: !!actualAccount?.id && enabled }
|
||||
})
|
||||
|
||||
const ownAccount = useAccountStorage.string('auth.account.id')['0'] === actualAccount?.id
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
const timelineMutation = useTimelineMutation({
|
||||
onSuccess: (_, params) => {
|
||||
queryClient.refetchQueries(['Relationship', { id: account.id }])
|
||||
queryClient.refetchQueries(['Relationship', { id: actualAccount?.id }])
|
||||
const theParams = params as MutationVarsTimelineUpdateAccountProperty
|
||||
displayMessage({
|
||||
type: 'success',
|
||||
@ -101,7 +108,7 @@ const menuAccount = ({
|
||||
rootQueryKey && queryClient.invalidateQueries(rootQueryKey)
|
||||
}
|
||||
})
|
||||
const queryKeyRelationship: QueryKeyRelationship = ['Relationship', { id: account.id }]
|
||||
const queryKeyRelationship: QueryKeyRelationship = ['Relationship', { id: actualAccount?.id }]
|
||||
const relationshipMutation = useRelationshipMutation({
|
||||
onSuccess: (res, { payload: { action } }) => {
|
||||
haptics('Success')
|
||||
@ -128,14 +135,17 @@ const menuAccount = ({
|
||||
}
|
||||
})
|
||||
|
||||
if (!account) return []
|
||||
|
||||
if (!ownAccount && Platform.OS !== 'android' && type !== 'account') {
|
||||
menus[0].push({
|
||||
key: 'account-following',
|
||||
item: {
|
||||
onSelect: () =>
|
||||
data &&
|
||||
actualAccount &&
|
||||
relationshipMutation.mutate({
|
||||
id: account.id,
|
||||
id: actualAccount.id,
|
||||
type: 'outgoing',
|
||||
payload: { action: 'follow', state: !data?.requested ? data.following : true }
|
||||
}),
|
||||
@ -173,8 +183,9 @@ const menuAccount = ({
|
||||
key: 'account-show-boosts',
|
||||
item: {
|
||||
onSelect: () =>
|
||||
actualAccount &&
|
||||
relationshipMutation.mutate({
|
||||
id: account.id,
|
||||
id: actualAccount.id,
|
||||
type: 'outgoing',
|
||||
payload: { action: 'follow', state: false, reblogs: !data?.showing_reblogs }
|
||||
}),
|
||||
@ -192,10 +203,11 @@ const menuAccount = ({
|
||||
key: 'account-mute',
|
||||
item: {
|
||||
onSelect: () =>
|
||||
actualAccount &&
|
||||
timelineMutation.mutate({
|
||||
type: 'updateAccountProperty',
|
||||
queryKey,
|
||||
id: account.id,
|
||||
id: actualAccount.id,
|
||||
payload: { property: 'mute', currentValue: data?.muting }
|
||||
}),
|
||||
disabled: Platform.OS !== 'android' ? !data || !isFetched : false,
|
||||
@ -215,17 +227,20 @@ const menuAccount = ({
|
||||
item: {
|
||||
onSelect: () =>
|
||||
Alert.alert(
|
||||
t('componentContextMenu:account.block.alert.title', { username: account.username }),
|
||||
t('componentContextMenu:account.block.alert.title', {
|
||||
username: actualAccount?.username
|
||||
}),
|
||||
undefined,
|
||||
[
|
||||
{
|
||||
text: t('common:buttons.confirm'),
|
||||
style: 'destructive',
|
||||
onPress: () =>
|
||||
actualAccount &&
|
||||
timelineMutation.mutate({
|
||||
type: 'updateAccountProperty',
|
||||
queryKey,
|
||||
id: account.id,
|
||||
id: actualAccount.id,
|
||||
payload: { property: 'block', currentValue: data?.blocking }
|
||||
})
|
||||
},
|
||||
@ -247,8 +262,13 @@ const menuAccount = ({
|
||||
{
|
||||
key: 'account-reports',
|
||||
item: {
|
||||
onSelect: () => navigation.navigate('Tab-Shared-Report', { account, status }),
|
||||
disabled: false,
|
||||
onSelect: () =>
|
||||
actualAccount &&
|
||||
navigation.navigate('Tab-Shared-Report', {
|
||||
account: actualAccount,
|
||||
status
|
||||
}),
|
||||
disabled: Platform.OS !== 'android' ? !data || !isFetched : false,
|
||||
destructive: true,
|
||||
hidden: false
|
||||
},
|
||||
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "Text alternatiu"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": ""
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "Alternativtext"
|
||||
}
|
||||
}
|
||||
}
|
@ -82,7 +82,8 @@
|
||||
"unsupported": {
|
||||
"text": "Loading error",
|
||||
"button": "Try remote link"
|
||||
}
|
||||
},
|
||||
"altText": "Alternative Text"
|
||||
},
|
||||
"avatar": {
|
||||
"accessibilityLabel": "Avatar of {{name}}",
|
||||
|
@ -3,7 +3,6 @@ export default {
|
||||
|
||||
screens: require('./screens'),
|
||||
screenAccountSelection: require('./screens/accountSelection.json'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "Alternative Text"
|
||||
}
|
||||
}
|
||||
}
|
@ -376,7 +376,11 @@
|
||||
"notFound": "Cannot find <bold>{{searchTerm}}</bold> related {{type}}"
|
||||
},
|
||||
"toot": {
|
||||
"name": "Discussions"
|
||||
"name": "Discussions",
|
||||
"remoteFetch": {
|
||||
"title": "Contains remote content",
|
||||
"message": "Federated content are not always available on local instance. These content are fetched from remote instance and marked. You can interact with these content as usual."
|
||||
}
|
||||
},
|
||||
"users": {
|
||||
"accounts": {
|
||||
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "Texto alternativo"
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "Texte de remplacement"
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "Testo descrittivo"
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "代替テキスト"
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "대체 텍스트"
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "Alternatieve tekst"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": ""
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "Texto Alternativo"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "Альтернативный текст"
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "Alternativtext"
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "Альтернативний текст"
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "Văn bản thay thế"
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "替代文本"
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"content": {
|
||||
"altText": {
|
||||
"heading": "替代文字"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
import { RootStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useEffect } from 'react'
|
||||
import { Dimensions, StyleSheet, View } from 'react-native'
|
||||
import { PanGestureHandler, State, TapGestureHandler } from 'react-native-gesture-handler'
|
||||
import Animated, {
|
||||
Extrapolate,
|
||||
interpolate,
|
||||
runOnJS,
|
||||
useAnimatedGestureHandler,
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
withTiming
|
||||
} from 'react-native-reanimated'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import ActionsAltText from './Actions/AltText'
|
||||
|
||||
const ScreenActions = ({
|
||||
route: { params },
|
||||
navigation
|
||||
}: RootStackScreenProps<'Screen-Actions'>) => {
|
||||
const { colors } = useTheme()
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
const DEFAULT_VALUE = 350
|
||||
const screenHeight = Dimensions.get('window').height
|
||||
const panY = useSharedValue(DEFAULT_VALUE)
|
||||
useEffect(() => {
|
||||
panY.value = withTiming(0)
|
||||
}, [])
|
||||
const styleTop = useAnimatedStyle(() => {
|
||||
return {
|
||||
bottom: interpolate(panY.value, [0, screenHeight], [0, -screenHeight], Extrapolate.CLAMP)
|
||||
}
|
||||
})
|
||||
const dismiss = () => navigation.goBack()
|
||||
|
||||
const onGestureEvent = useAnimatedGestureHandler({
|
||||
onActive: ({ translationY }) => {
|
||||
panY.value = translationY
|
||||
},
|
||||
onEnd: ({ velocityY }) => {
|
||||
if (velocityY > 500) {
|
||||
runOnJS(dismiss)()
|
||||
} else {
|
||||
panY.value = withTiming(0)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const actions = () => {
|
||||
switch (params.type) {
|
||||
case 'alt_text':
|
||||
return <ActionsAltText text={params.text} />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Animated.View style={{ flex: 1 }}>
|
||||
<TapGestureHandler
|
||||
onHandlerStateChange={({ nativeEvent }) => {
|
||||
if (nativeEvent.state === State.ACTIVE) {
|
||||
dismiss()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Animated.View
|
||||
style={[styles.overlay, { backgroundColor: colors.backgroundOverlayInvert }]}
|
||||
>
|
||||
<PanGestureHandler onGestureEvent={onGestureEvent}>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.container,
|
||||
styleTop,
|
||||
{
|
||||
backgroundColor: colors.backgroundDefault,
|
||||
paddingBottom: insets.bottom || StyleConstants.Spacing.L
|
||||
}
|
||||
]}
|
||||
>
|
||||
<View style={[styles.handle, { backgroundColor: colors.primaryOverlay }]} />
|
||||
{actions()}
|
||||
</Animated.View>
|
||||
</PanGestureHandler>
|
||||
</Animated.View>
|
||||
</TapGestureHandler>
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-end'
|
||||
},
|
||||
container: {
|
||||
paddingTop: StyleConstants.Spacing.M
|
||||
},
|
||||
handle: {
|
||||
alignSelf: 'center',
|
||||
width: StyleConstants.Spacing.S * 8,
|
||||
height: StyleConstants.Spacing.S / 2,
|
||||
borderRadius: 100,
|
||||
top: -StyleConstants.Spacing.M * 2
|
||||
},
|
||||
button: {
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
|
||||
}
|
||||
})
|
||||
|
||||
export default ScreenActions
|
@ -1,42 +0,0 @@
|
||||
import Button from '@components/Button'
|
||||
import MenuContainer from '@components/Menu/Container'
|
||||
import MenuHeader from '@components/Menu/Header'
|
||||
import CustomText from '@components/Text'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Dimensions } from 'react-native'
|
||||
import { ScrollView } from 'react-native-gesture-handler'
|
||||
|
||||
export interface Props {
|
||||
text: string
|
||||
}
|
||||
|
||||
const ActionsAltText: React.FC<Props> = ({ text }) => {
|
||||
const navigation = useNavigation()
|
||||
const { t } = useTranslation(['common', 'screenActions'])
|
||||
const { colors } = useTheme()
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuContainer>
|
||||
<MenuHeader heading={t(`screenActions:content.altText.heading`)} />
|
||||
<ScrollView style={{ maxHeight: Dimensions.get('window').height / 2 }}>
|
||||
<CustomText style={{ color: colors.primaryDefault }}>{text}</CustomText>
|
||||
</ScrollView>
|
||||
</MenuContainer>
|
||||
<Button
|
||||
type='text'
|
||||
content={t('common:buttons.OK')}
|
||||
onPress={() => navigation.goBack()}
|
||||
style={{
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ActionsAltText
|
@ -2,15 +2,11 @@ import AccountHeader from '@screens/Tabs/Shared/Account/Header'
|
||||
import AccountInformation from '@screens/Tabs/Shared/Account/Information'
|
||||
import React from 'react'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account | undefined
|
||||
}
|
||||
|
||||
const MyInfo: React.FC<Props> = ({ account }) => {
|
||||
const MyInfo: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<AccountHeader account={account} />
|
||||
<AccountInformation account={account} />
|
||||
<AccountHeader />
|
||||
<AccountInformation />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -5,13 +5,11 @@ import Logout from '@screens/Tabs/Me/Root/Logout'
|
||||
import MyInfo from '@screens/Tabs/Me/Root/MyInfo'
|
||||
import Settings from '@screens/Tabs/Me/Root/Settings'
|
||||
import AccountInformationSwitch from '@screens/Tabs/Me/Root/Switch'
|
||||
import AccountContext from '@screens/Tabs/Shared/Account/Context'
|
||||
import AccountNav from '@screens/Tabs/Shared/Account/Nav'
|
||||
import AccountContext from '@screens/Tabs/Shared/Account/utils/createContext'
|
||||
import accountInitialState from '@screens/Tabs/Shared/Account/utils/initialState'
|
||||
import accountReducer from '@screens/Tabs/Shared/Account/utils/reducer'
|
||||
import { useProfileQuery } from '@utils/queryHooks/profile'
|
||||
import { useGlobalStorage } from '@utils/storage/actions'
|
||||
import React, { useReducer, useRef } from 'react'
|
||||
import React, { useRef } from 'react'
|
||||
import Animated, { useAnimatedScrollHandler, useSharedValue } from 'react-native-reanimated'
|
||||
|
||||
const TabMeRoot: React.FC = () => {
|
||||
@ -24,23 +22,21 @@ const TabMeRoot: React.FC = () => {
|
||||
const scrollRef = useRef<Animated.ScrollView>(null)
|
||||
useScrollToTop(scrollRef)
|
||||
|
||||
const [accountState, accountDispatch] = useReducer(accountReducer, accountInitialState)
|
||||
|
||||
const scrollY = useSharedValue(0)
|
||||
const onScroll = useAnimatedScrollHandler(event => {
|
||||
scrollY.value = event.contentOffset.y
|
||||
})
|
||||
|
||||
return (
|
||||
<AccountContext.Provider value={{ accountState, accountDispatch }}>
|
||||
{accountActive && data ? <AccountNav scrollY={scrollY} account={data} /> : null}
|
||||
<AccountContext.Provider value={{ account: data, pageMe: true }}>
|
||||
{accountActive && data ? <AccountNav scrollY={scrollY} /> : null}
|
||||
<Animated.ScrollView
|
||||
ref={scrollRef}
|
||||
keyboardShouldPersistTaps='handled'
|
||||
onScroll={onScroll}
|
||||
scrollEventThrottle={16}
|
||||
>
|
||||
{accountActive ? <MyInfo account={data} /> : <ComponentInstance />}
|
||||
{accountActive ? <MyInfo /> : <ComponentInstance />}
|
||||
{accountActive ? <Collections /> : null}
|
||||
<Settings />
|
||||
{accountActive ? <AccountInformationSwitch /> : null}
|
||||
|
@ -7,17 +7,15 @@ import { useTimelineQuery } from '@utils/queryHooks/timeline'
|
||||
import { flattenPages } from '@utils/queryHooks/utils'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import { Dimensions, Pressable, View } from 'react-native'
|
||||
import { FlatList } from 'react-native-gesture-handler'
|
||||
import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated'
|
||||
import AccountContext from './Context'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account | undefined
|
||||
}
|
||||
const AccountAttachments: React.FC = () => {
|
||||
const { account } = useContext(AccountContext)
|
||||
|
||||
const AccountAttachments: React.FC<Props> = ({ account }) => {
|
||||
if (!account) return null
|
||||
if (account?.suspended) return null
|
||||
|
||||
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
|
||||
const { colors } = useTheme()
|
||||
@ -28,30 +26,28 @@ const AccountAttachments: React.FC<Props> = ({ account }) => {
|
||||
|
||||
const { data } = useTimelineQuery({
|
||||
page: 'Account',
|
||||
account: account.id,
|
||||
id: account?.id,
|
||||
exclude_reblogs: false,
|
||||
only_media: true
|
||||
only_media: true,
|
||||
options: { enabled: !!account?.id }
|
||||
})
|
||||
|
||||
const flattenData = flattenPages(data)
|
||||
.filter(status => !(status as Mastodon.Status).sensitive)
|
||||
.splice(0, DISPLAY_AMOUNT)
|
||||
|
||||
const styleContainer = useAnimatedStyle(() => {
|
||||
if (flattenData.length) {
|
||||
return {
|
||||
height: withTiming(width + StyleConstants.Spacing.Global.PagePadding * 2),
|
||||
if (!flattenData.length) return null
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
height: width + StyleConstants.Spacing.Global.PagePadding * 2,
|
||||
paddingVertical: StyleConstants.Spacing.Global.PagePadding,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: colors.border
|
||||
}
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
}, [flattenData.length])
|
||||
|
||||
return (
|
||||
<Animated.View style={[{ flex: 1 }, styleContainer]}>
|
||||
}}
|
||||
>
|
||||
<FlatList
|
||||
horizontal
|
||||
data={flattenData}
|
||||
@ -103,7 +99,7 @@ const AccountAttachments: React.FC<Props> = ({ account }) => {
|
||||
}}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
</Animated.View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
|
9
src/screens/Tabs/Shared/Account/Context.tsx
Normal file
9
src/screens/Tabs/Shared/Account/Context.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import { createContext } from 'react'
|
||||
|
||||
type AccountContextType = {
|
||||
account?: Mastodon.Account
|
||||
pageMe?: boolean
|
||||
}
|
||||
const AccountContext = createContext<AccountContextType>({} as AccountContextType)
|
||||
|
||||
export default AccountContext
|
@ -1,15 +1,14 @@
|
||||
import GracefullyImage from '@components/GracefullyImage'
|
||||
import navigationRef from '@utils/navigation/navigationRef'
|
||||
import { useGlobalStorage } from '@utils/storage/actions'
|
||||
import React from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import { Dimensions, Image } from 'react-native'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import AccountContext from './Context'
|
||||
|
||||
export interface Props {
|
||||
account?: Mastodon.Account
|
||||
}
|
||||
const AccountHeader: React.FC = () => {
|
||||
const { account } = useContext(AccountContext)
|
||||
|
||||
const AccountHeader: React.FC<Props> = ({ account }) => {
|
||||
const topInset = useSafeAreaInsets().top
|
||||
|
||||
useGlobalStorage.string('account.active')
|
||||
|
@ -13,11 +13,7 @@ import AccountInformationName from './Information/Name'
|
||||
import AccountInformationNote from './Information/Note'
|
||||
import AccountInformationStats from './Information/Stats'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account | undefined
|
||||
}
|
||||
|
||||
const AccountInformation: React.FC<Props> = ({ account }) => {
|
||||
const AccountInformation: React.FC = () => {
|
||||
const { colors } = useTheme()
|
||||
|
||||
const { name } = useRoute()
|
||||
@ -31,21 +27,21 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
|
||||
)}
|
||||
>
|
||||
<View style={styles.avatarAndActions}>
|
||||
<AccountInformationAvatar account={account} myInfo={myInfo} />
|
||||
<AccountInformationActions account={account} myInfo={myInfo} />
|
||||
<AccountInformationAvatar />
|
||||
<AccountInformationActions />
|
||||
</View>
|
||||
|
||||
<AccountInformationName account={account} />
|
||||
<AccountInformationName />
|
||||
|
||||
<AccountInformationAccount account={account} myInfo={myInfo} />
|
||||
<AccountInformationAccount />
|
||||
|
||||
<AccountInformationFields account={account} myInfo={myInfo} />
|
||||
<AccountInformationFields />
|
||||
|
||||
<AccountInformationNote account={account} myInfo={myInfo} />
|
||||
<AccountInformationNote />
|
||||
|
||||
<AccountInformationCreated account={account} hidden={myInfo} />
|
||||
<AccountInformationCreated />
|
||||
|
||||
<AccountInformationStats account={account} myInfo={myInfo} />
|
||||
<AccountInformationStats />
|
||||
</Placeholder>
|
||||
</View>
|
||||
)
|
||||
|
@ -4,31 +4,26 @@ import { useRelationshipQuery } from '@utils/queryHooks/relationship'
|
||||
import { getAccountStorage, useAccountStorage } from '@utils/storage/actions'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { View } from 'react-native'
|
||||
import { PlaceholderLine } from 'rn-placeholder'
|
||||
import AccountContext from '../Context'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account | undefined
|
||||
myInfo?: boolean
|
||||
}
|
||||
const AccountInformationAccount: React.FC = () => {
|
||||
const { account, pageMe } = useContext(AccountContext)
|
||||
|
||||
const AccountInformationAccount: React.FC<Props> = ({ account, myInfo }) => {
|
||||
const { t } = useTranslation('screenTabs')
|
||||
const { colors } = useTheme()
|
||||
|
||||
const [acct] = useAccountStorage.string('auth.account.acct')
|
||||
const domain = getAccountStorage.string('auth.account.domain')
|
||||
|
||||
const { data: relationship } = useRelationshipQuery({
|
||||
id: account?.id || '',
|
||||
options: { enabled: account !== undefined }
|
||||
})
|
||||
const { data: relationship } = useRelationshipQuery({ id: account?.id })
|
||||
|
||||
const localInstance = account?.acct.includes('@') ? account?.acct.includes(`@${domain}`) : true
|
||||
|
||||
if (account || localInstance) {
|
||||
if (account || pageMe) {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
@ -51,7 +46,7 @@ const AccountInformationAccount: React.FC<Props> = ({ account, myInfo }) => {
|
||||
}}
|
||||
selectable
|
||||
>
|
||||
@{myInfo ? acct : account?.acct}
|
||||
@{pageMe ? acct : account?.acct}
|
||||
{localInstance ? `@${domain}` : null}
|
||||
</CustomText>
|
||||
{relationship?.followed_by ? t('shared.account.followed_by') : null}
|
||||
|
@ -5,17 +5,15 @@ import { useNavigation } from '@react-navigation/native'
|
||||
import { useRelationshipQuery } from '@utils/queryHooks/relationship'
|
||||
import { useAccountStorage } from '@utils/storage/actions'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import React from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import * as DropdownMenu from 'zeego/dropdown-menu'
|
||||
import AccountContext from '../Context'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account | undefined
|
||||
myInfo?: boolean
|
||||
}
|
||||
const AccountInformationActions: React.FC = () => {
|
||||
const { account, pageMe } = useContext(AccountContext)
|
||||
|
||||
const AccountInformationActions: React.FC<Props> = ({ account, myInfo }) => {
|
||||
if (!account || account.suspended) {
|
||||
return null
|
||||
}
|
||||
@ -36,7 +34,7 @@ const AccountInformationActions: React.FC<Props> = ({ account, myInfo }) => {
|
||||
)
|
||||
}
|
||||
|
||||
if (myInfo) {
|
||||
if (pageMe) {
|
||||
return (
|
||||
<View style={styles.base}>
|
||||
<Button
|
||||
@ -76,7 +74,7 @@ const AccountInformationActions: React.FC<Props> = ({ account, myInfo }) => {
|
||||
{mGroup.map(menu => (
|
||||
<DropdownMenu.Item key={menu.key} {...menu.item}>
|
||||
<DropdownMenu.ItemTitle children={menu.title} />
|
||||
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
|
||||
<DropdownMenu.ItemIcon ios={{ name: menu.icon }} />
|
||||
</DropdownMenu.Item>
|
||||
))}
|
||||
</DropdownMenu.Group>
|
||||
|
@ -5,14 +5,12 @@ import navigationRef from '@utils/navigation/navigationRef'
|
||||
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||
import { useGlobalStorage } from '@utils/storage/actions'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import React from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import AccountContext from '../Context'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account | undefined
|
||||
myInfo: boolean
|
||||
}
|
||||
const AccountInformationAvatar: React.FC = () => {
|
||||
const { account, pageMe } = useContext(AccountContext)
|
||||
|
||||
const AccountInformationAvatar: React.FC<Props> = ({ account, myInfo }) => {
|
||||
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
|
||||
|
||||
useGlobalStorage.string('account.active')
|
||||
@ -29,7 +27,7 @@ const AccountInformationAvatar: React.FC<Props> = ({ account, myInfo }) => {
|
||||
uri={{ original: account?.avatar, static: account?.avatar_static }}
|
||||
onPress={() => {
|
||||
if (account) {
|
||||
if (myInfo) {
|
||||
if (pageMe) {
|
||||
navigation.push('Tab-Shared-Account', { account })
|
||||
return
|
||||
} else {
|
||||
|
@ -2,18 +2,16 @@ import Icon from '@components/Icon'
|
||||
import CustomText from '@components/Text'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { View } from 'react-native'
|
||||
import { PlaceholderLine } from 'rn-placeholder'
|
||||
import AccountContext from '../Context'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account | undefined
|
||||
hidden?: boolean
|
||||
}
|
||||
const AccountInformationCreated: React.FC = () => {
|
||||
const { account, pageMe } = useContext(AccountContext)
|
||||
|
||||
const AccountInformationCreated: React.FC<Props> = ({ account, hidden = false }) => {
|
||||
if (hidden) {
|
||||
if (pageMe) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||
import { ParseHTML } from '@components/Parse'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import AccountContext from '../Context'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account | undefined
|
||||
myInfo?: boolean
|
||||
}
|
||||
const AccountInformationFields: React.FC = () => {
|
||||
const { account, pageMe } = useContext(AccountContext)
|
||||
|
||||
const AccountInformationFields: React.FC<Props> = ({ account, myInfo }) => {
|
||||
if (account?.suspended || myInfo || !account?.fields || account.fields.length === 0) {
|
||||
if (account?.suspended || pageMe || !account?.fields || account.fields.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
@ -2,15 +2,14 @@ import { ParseEmojis } from '@components/Parse'
|
||||
import CustomText from '@components/Text'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import { View } from 'react-native'
|
||||
import { PlaceholderLine } from 'rn-placeholder'
|
||||
import AccountContext from '../Context'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account | undefined
|
||||
}
|
||||
const AccountInformationName: React.FC = () => {
|
||||
const { account } = useContext(AccountContext)
|
||||
|
||||
const AccountInformationName: React.FC<Props> = ({ account }) => {
|
||||
const { colors } = useTheme()
|
||||
|
||||
return (
|
||||
|
@ -1,17 +1,15 @@
|
||||
import { ParseHTML } from '@components/Parse'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import React from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import { View } from 'react-native'
|
||||
import AccountContext from '../Context'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account | undefined
|
||||
myInfo?: boolean
|
||||
}
|
||||
const AccountInformationNote: React.FC = () => {
|
||||
const { account, pageMe } = useContext(AccountContext)
|
||||
|
||||
const AccountInformationNote: React.FC<Props> = ({ account, myInfo }) => {
|
||||
if (
|
||||
account?.suspended ||
|
||||
myInfo ||
|
||||
pageMe ||
|
||||
!account?.note ||
|
||||
account.note.length === 0 ||
|
||||
account.note === '<p></p>'
|
||||
|
@ -4,17 +4,15 @@ 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 from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import { PlaceholderLine } from 'rn-placeholder'
|
||||
import AccountContext from '../Context'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account | undefined
|
||||
myInfo: boolean
|
||||
}
|
||||
const AccountInformationStats: React.FC = () => {
|
||||
const { account, pageMe } = useContext(AccountContext)
|
||||
|
||||
const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => {
|
||||
if (account?.suspended) {
|
||||
return null
|
||||
}
|
||||
@ -32,7 +30,7 @@ const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => {
|
||||
count: account.statuses_count || 0
|
||||
})}
|
||||
onPress={() => {
|
||||
myInfo && account && navigation.push('Tab-Shared-Account', { account })
|
||||
pageMe && account && navigation.push('Tab-Shared-Account', { account })
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
|
@ -2,17 +2,19 @@ import { ParseEmojis } from '@components/Parse'
|
||||
import CustomText from '@components/Text'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import { Dimensions, StyleSheet, View } from 'react-native'
|
||||
import Animated, { Extrapolate, interpolate, useAnimatedStyle } from 'react-native-reanimated'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import AccountContext from './Context'
|
||||
|
||||
export interface Props {
|
||||
scrollY: Animated.SharedValue<number>
|
||||
account: Mastodon.Account | undefined
|
||||
}
|
||||
|
||||
const AccountNav: React.FC<Props> = ({ scrollY, account }) => {
|
||||
const AccountNav: React.FC<Props> = ({ scrollY }) => {
|
||||
const { account } = useContext(AccountContext)
|
||||
|
||||
const { colors } = useTheme()
|
||||
const headerHeight = useSafeAreaInsets().top + 44
|
||||
|
||||
|
@ -16,6 +16,7 @@ import { Text, View } from 'react-native'
|
||||
import { useSharedValue } from 'react-native-reanimated'
|
||||
import * as DropdownMenu from 'zeego/dropdown-menu'
|
||||
import AccountAttachments from './Attachments'
|
||||
import AccountContext from './Context'
|
||||
import AccountHeader from './Header'
|
||||
import AccountInformation from './Information'
|
||||
import AccountNav from './Nav'
|
||||
@ -23,14 +24,19 @@ import AccountNav from './Nav'
|
||||
const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>> = ({
|
||||
navigation,
|
||||
route: {
|
||||
params: { account }
|
||||
params: { account, isRemote }
|
||||
}
|
||||
}) => {
|
||||
const { t } = useTranslation('screenTabs')
|
||||
const { colors, mode } = useTheme()
|
||||
|
||||
const mShare = menuShare({ type: 'account', url: account.url })
|
||||
const mAccount = menuAccount({ type: 'account', openChange: true, account })
|
||||
const { data, dataUpdatedAt } = useAccountQuery({
|
||||
id: account.id,
|
||||
...(isRemote && { remoteUrl: account.url })
|
||||
})
|
||||
|
||||
const mShare = menuShare({ type: 'account', url: data?.url })
|
||||
const mAccount = menuAccount({ type: 'account', openChange: true, account: data })
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerTransparent: true,
|
||||
@ -76,14 +82,12 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
|
||||
})
|
||||
}, [mAccount])
|
||||
|
||||
const { data } = useAccountQuery({ id: account.id })
|
||||
|
||||
const scrollY = useSharedValue(0)
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
const [queryKey, setQueryKey] = useState<QueryKeyTimeline>([
|
||||
'Timeline',
|
||||
{ page: 'Account', account: account.id, exclude_reblogs: true, only_media: false }
|
||||
{ page: 'Account', id: data?.id, exclude_reblogs: true, only_media: false }
|
||||
])
|
||||
const page = queryKey[1]
|
||||
|
||||
@ -92,9 +96,9 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
|
||||
return (
|
||||
<>
|
||||
<View style={{ borderBottomWidth: 1, borderBottomColor: colors.border }}>
|
||||
<AccountHeader account={data} />
|
||||
<AccountInformation account={data} />
|
||||
{!data?.suspended ? <AccountAttachments account={data} /> : null}
|
||||
<AccountHeader />
|
||||
<AccountInformation />
|
||||
<AccountAttachments />
|
||||
</View>
|
||||
{!data?.suspended ? (
|
||||
<SegmentedControl
|
||||
@ -110,7 +114,7 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
|
||||
{
|
||||
...page,
|
||||
page: 'Account',
|
||||
account: account.id,
|
||||
id: data?.id,
|
||||
exclude_reblogs: true,
|
||||
only_media: false
|
||||
}
|
||||
@ -122,7 +126,7 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
|
||||
{
|
||||
...page,
|
||||
page: 'Account',
|
||||
account: account.id,
|
||||
id: data?.id,
|
||||
exclude_reblogs: false,
|
||||
only_media: false
|
||||
}
|
||||
@ -158,11 +162,11 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}, [segment, data, queryKey[1].page, mode])
|
||||
}, [segment, dataUpdatedAt, mode])
|
||||
|
||||
return (
|
||||
<>
|
||||
<AccountNav scrollY={scrollY} account={data} />
|
||||
<AccountContext.Provider value={{ account: data }}>
|
||||
<AccountNav scrollY={scrollY} />
|
||||
|
||||
{data?.suspended ? (
|
||||
ListHeaderComponent
|
||||
@ -170,6 +174,7 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
|
||||
<Timeline
|
||||
queryKey={queryKey}
|
||||
disableRefresh
|
||||
queryOptions={{ enabled: isRemote ? !!data?.id : true }}
|
||||
customProps={{
|
||||
renderItem: ({ item }) => <TimelineDefault item={item} queryKey={queryKey} />,
|
||||
onScroll: ({ nativeEvent }) => (scrollY.value = nativeEvent.contentOffset.y),
|
||||
@ -180,7 +185,7 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</AccountContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { createContext, Dispatch } from 'react'
|
||||
import { AccountAction, AccountState } from './types'
|
||||
|
||||
type ContextType = {
|
||||
accountState: AccountState
|
||||
accountDispatch: Dispatch<AccountAction>
|
||||
}
|
||||
const AccountContext = createContext<ContextType>({} as ContextType)
|
||||
|
||||
export default AccountContext
|
@ -1,9 +0,0 @@
|
||||
import { AccountState } from './types'
|
||||
|
||||
const accountInitialState: AccountState = {
|
||||
headerRatio: 1 / 3,
|
||||
informationLayout: { height: 0, y: 100 },
|
||||
segmentedIndex: 0
|
||||
}
|
||||
|
||||
export default accountInitialState
|
@ -1,19 +0,0 @@
|
||||
import { AccountAction, AccountState } from "./types"
|
||||
|
||||
const accountReducer = (
|
||||
state: AccountState,
|
||||
action: AccountAction
|
||||
): AccountState => {
|
||||
switch (action.type) {
|
||||
case 'headerRatio':
|
||||
return { ...state, headerRatio: action.payload }
|
||||
case 'informationLayout':
|
||||
return { ...state, informationLayout: action.payload }
|
||||
case 'segmentedIndex':
|
||||
return { ...state, segmentedIndex: action.payload }
|
||||
default:
|
||||
throw new Error('Unexpected action')
|
||||
}
|
||||
}
|
||||
|
||||
export default accountReducer
|
22
src/screens/Tabs/Shared/Account/utils/types.d.ts
vendored
22
src/screens/Tabs/Shared/Account/utils/types.d.ts
vendored
@ -1,22 +0,0 @@
|
||||
export type AccountState = {
|
||||
headerRatio: number
|
||||
informationLayout?: {
|
||||
y: number
|
||||
height: number
|
||||
}
|
||||
segmentedIndex: number
|
||||
}
|
||||
|
||||
export type AccountAction =
|
||||
| {
|
||||
type: 'headerRatio'
|
||||
payload: AccountState['headerRatio']
|
||||
}
|
||||
| {
|
||||
type: 'informationLayout'
|
||||
payload: AccountState['informationLayout']
|
||||
}
|
||||
| {
|
||||
type: 'segmentedIndex'
|
||||
payload: AccountState['segmentedIndex']
|
||||
}
|
@ -45,7 +45,7 @@ const TabSharedAttachments: React.FC<TabSharedStackScreenProps<'Tab-Shared-Attac
|
||||
|
||||
const queryKey: QueryKeyTimeline = [
|
||||
'Timeline',
|
||||
{ page: 'Account', account: account.id, exclude_reblogs: true, only_media: true }
|
||||
{ page: 'Account', id: account.id, exclude_reblogs: true, only_media: true }
|
||||
]
|
||||
|
||||
return (
|
||||
|
@ -5,6 +5,7 @@ import CustomText from '@components/Text'
|
||||
import apiInstance from '@utils/api/instance'
|
||||
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { useRulesQuery } from '@utils/queryHooks/reports'
|
||||
import { searchFetchToot } from '@utils/queryHooks/search'
|
||||
import { getAccountStorage } from '@utils/storage/actions'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
@ -19,6 +20,7 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
|
||||
params: { account, status }
|
||||
}
|
||||
}) => {
|
||||
console.log('account', account.id)
|
||||
const { colors } = useTheme()
|
||||
const { t } = useTranslation(['common', 'screenTabs'])
|
||||
|
||||
@ -49,10 +51,19 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
|
||||
type='text'
|
||||
content={t('screenTabs:shared.report.report')}
|
||||
destructive
|
||||
onPress={() => {
|
||||
onPress={async () => {
|
||||
const body = new FormData()
|
||||
if (status) {
|
||||
if (status._remote) {
|
||||
const fetchedStatus = await searchFetchToot(status.uri)
|
||||
if (fetchedStatus) {
|
||||
body.append('status_ids[]', fetchedStatus.id)
|
||||
}
|
||||
} else {
|
||||
body.append('status_ids[]', status.id)
|
||||
}
|
||||
}
|
||||
body.append('account_id', account.id)
|
||||
status && body.append('status_ids[]', status.id)
|
||||
comment.length && body.append('comment', comment)
|
||||
body.append('forward', forward.toString())
|
||||
body.append('category', categories.find(category => category.selected)?.type || 'other')
|
||||
@ -71,7 +82,7 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
|
||||
/>
|
||||
)
|
||||
})
|
||||
}, [isReporting, comment, forward, categories, rules])
|
||||
}, [isReporting, comment, forward, categories, rules, account.id])
|
||||
|
||||
const localInstance = account?.acct.includes('@')
|
||||
? account?.acct.includes(`@${getAccountStorage.string('auth.account.domain')}`)
|
||||
|
@ -1,4 +1,3 @@
|
||||
import Button from '@components/Button'
|
||||
import { HeaderLeft } from '@components/Header'
|
||||
import Icon from '@components/Icon'
|
||||
import ComponentSeparator from '@components/Separator'
|
||||
@ -14,7 +13,7 @@ import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { FlatList, View } from 'react-native'
|
||||
import { Alert, FlatList, Pressable, View } from 'react-native'
|
||||
import { Circle } from 'react-native-animated-spinkit'
|
||||
import { Path, Svg } from 'react-native-svg'
|
||||
|
||||
@ -32,7 +31,16 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerTitle: () => (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<Pressable
|
||||
style={{ flexDirection: 'row', alignItems: 'center' }}
|
||||
disabled={!hasRemoteContent}
|
||||
onPress={() =>
|
||||
Alert.alert(
|
||||
t('screenTabs:shared.toot.remoteFetch.title'),
|
||||
t('screenTabs:shared.toot.remoteFetch.message')
|
||||
)
|
||||
}
|
||||
>
|
||||
{hasRemoteContent ? (
|
||||
<Icon
|
||||
name='Wifi'
|
||||
@ -48,7 +56,7 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
||||
numberOfLines={1}
|
||||
children={t('screenTabs:shared.toot.name')}
|
||||
/>
|
||||
</View>
|
||||
</Pressable>
|
||||
),
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||
})
|
||||
@ -57,7 +65,9 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
||||
const flRef = useRef<FlatList>(null)
|
||||
const scrolled = useRef(false)
|
||||
|
||||
const finalData = useRef<Mastodon.Status[]>([{ ...toot, _level: 0, _remote: false }])
|
||||
const finalData = useRef<Mastodon.Status[]>([
|
||||
{ ...toot, _level: 0, _remote: toot._remote }
|
||||
])
|
||||
const highlightIndex = useRef<number>(0)
|
||||
const queryKey: { local: QueryKeyTimeline; remote: QueryKeyTimeline } = {
|
||||
local: ['Timeline', { page: 'Toot', toot: toot.id, remote: false }],
|
||||
@ -96,6 +106,7 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
||||
return { pages: [{ body: statuses }] }
|
||||
},
|
||||
{
|
||||
enabled: !toot._remote,
|
||||
staleTime: 0,
|
||||
refetchOnMount: true,
|
||||
onSuccess: data => {
|
||||
@ -189,16 +200,16 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
||||
{
|
||||
enabled: toot.account.acct !== toot.account.username, // When on the same instance, these two values are the same
|
||||
staleTime: 0,
|
||||
refetchOnMount: false,
|
||||
refetchOnMount: true,
|
||||
onSuccess: data => {
|
||||
if (finalData.current.length < 1 && data.pages[0].body.length < 1) {
|
||||
navigation.goBack()
|
||||
return
|
||||
}
|
||||
|
||||
if (finalData.current?.length < data.pages[0].body.length) {
|
||||
if (finalData.current.length < data.pages[0].body.length) {
|
||||
finalData.current = data.pages[0].body.map(remote => {
|
||||
const localMatch = finalData.current?.find(local => local.uri === remote.uri)
|
||||
const localMatch = finalData.current.find(local => local.uri === remote.uri)
|
||||
if (localMatch) {
|
||||
return localMatch
|
||||
} else {
|
||||
@ -230,52 +241,6 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
||||
}
|
||||
)
|
||||
|
||||
const empty = () => {
|
||||
switch (queryLocal.status) {
|
||||
case 'error':
|
||||
return (
|
||||
<>
|
||||
<Icon name='Frown' size={StyleConstants.Font.Size.L} color={colors.primaryDefault} />
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
style={{
|
||||
marginTop: StyleConstants.Spacing.S,
|
||||
marginBottom: StyleConstants.Spacing.L,
|
||||
color: colors.primaryDefault
|
||||
}}
|
||||
>
|
||||
{t('componentTimeline:empty.error.message')}
|
||||
</CustomText>
|
||||
<Button
|
||||
type='text'
|
||||
content={t('componentTimeline:empty.error.button')}
|
||||
onPress={() => queryLocal.refetch()}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
case 'success':
|
||||
return (
|
||||
<>
|
||||
<Icon
|
||||
name='Smartphone'
|
||||
size={StyleConstants.Font.Size.L}
|
||||
color={colors.primaryDefault}
|
||||
/>
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
style={{
|
||||
marginTop: StyleConstants.Spacing.S,
|
||||
marginBottom: StyleConstants.Spacing.L,
|
||||
color: colors.secondary
|
||||
}}
|
||||
>
|
||||
{t('componentTimeline:empty.success.message')}
|
||||
</CustomText>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const heights = useRef<(number | undefined)[]>([])
|
||||
const MAX_LEVEL = 10
|
||||
const ARC = StyleConstants.Avatar.XS / 4
|
||||
@ -287,9 +252,9 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
||||
windowSize={7}
|
||||
data={finalData.current}
|
||||
renderItem={({ item, index }) => {
|
||||
const prev = finalData.current?.[index - 1]?._level || 0
|
||||
const prev = finalData.current[index - 1]?._level || 0
|
||||
const curr = item._level
|
||||
const next = finalData.current?.[index + 1]?._level || 0
|
||||
const next = finalData.current[index + 1]?._level || 0
|
||||
|
||||
return (
|
||||
<View
|
||||
@ -445,7 +410,7 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
||||
const offset = error.averageItemLength * error.index
|
||||
flRef.current?.scrollToOffset({ offset })
|
||||
try {
|
||||
error.index < (finalData.current.length || 0) &&
|
||||
error.index < finalData.current.length &&
|
||||
setTimeout(
|
||||
() =>
|
||||
flRef.current?.scrollToIndex({
|
||||
@ -456,19 +421,6 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
||||
)
|
||||
} catch {}
|
||||
}}
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
minHeight: '100%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.backgroundDefault
|
||||
}}
|
||||
>
|
||||
{empty()}
|
||||
</View>
|
||||
}
|
||||
ListFooterComponent={
|
||||
<View
|
||||
style={{
|
||||
|
@ -3,7 +3,6 @@ import { displayMessage, Message } from '@components/Message'
|
||||
import { NavigationContainer } from '@react-navigation/native'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import ScreenAccountSelection from '@screens/AccountSelection'
|
||||
import ScreenActions from '@screens/Actions'
|
||||
import ScreenAnnouncements from '@screens/Announcements'
|
||||
import ScreenCompose from '@screens/Compose'
|
||||
import ScreenImagesViewer from '@screens/ImageViewer'
|
||||
@ -261,15 +260,6 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
||||
options={{ headerShown: false }}
|
||||
/>
|
||||
|
||||
<Stack.Screen
|
||||
name='Screen-Actions'
|
||||
component={ScreenActions}
|
||||
options={{
|
||||
presentation: 'transparentModal',
|
||||
animation: 'fade',
|
||||
headerShown: false
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Screen-Announcements'
|
||||
component={ScreenAnnouncements}
|
||||
|
@ -7,14 +7,6 @@ import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
|
||||
export type RootStackParamList = {
|
||||
'Screen-Tabs': NavigatorScreenParams<ScreenTabsStackParamList>
|
||||
'Screen-Actions':
|
||||
| {
|
||||
type: 'notifications_filter'
|
||||
}
|
||||
| {
|
||||
type: 'alt_text'
|
||||
text: string
|
||||
}
|
||||
'Screen-Announcements': { showAll: boolean }
|
||||
'Screen-Compose':
|
||||
| {
|
||||
@ -93,6 +85,7 @@ export type ScreenTabsScreenProps<T extends keyof ScreenTabsStackParamList> = Bo
|
||||
export type TabSharedStackParamList = {
|
||||
'Tab-Shared-Account': {
|
||||
account: Partial<Mastodon.Account> & Pick<Mastodon.Account, 'id' | 'username' | 'acct'>
|
||||
isRemote?: boolean
|
||||
}
|
||||
'Tab-Shared-Account-In-Lists': {
|
||||
account: Pick<Mastodon.Account, 'id' | 'username'>
|
||||
@ -107,7 +100,7 @@ export type TabSharedStackParamList = {
|
||||
}
|
||||
'Tab-Shared-Report': {
|
||||
account: Partial<Mastodon.Account> & Pick<Mastodon.Account, 'id' | 'acct' | 'username'>
|
||||
status?: Pick<Mastodon.Status, 'id'>
|
||||
status?: Pick<Mastodon.Status, 'id' | '_remote' | 'uri'>
|
||||
}
|
||||
'Tab-Shared-Search': undefined
|
||||
'Tab-Shared-Toot': {
|
||||
|
@ -1,15 +1,42 @@
|
||||
import { QueryFunctionContext, useQuery, UseQueryOptions } from '@tanstack/react-query'
|
||||
import apiInstance from '@utils/api/instance'
|
||||
import { AxiosError } from 'axios'
|
||||
import { SearchResult } from './search'
|
||||
|
||||
export type QueryKeyAccount = ['Account', { id: Mastodon.Account['id'] }]
|
||||
export type QueryKeyAccount = ['Account', { id?: Mastodon.Account['id']; remoteUrl?: string }]
|
||||
|
||||
const accountQueryFunction = async ({ queryKey }: QueryFunctionContext<QueryKeyAccount>) => {
|
||||
const { id } = queryKey[1]
|
||||
const { id, remoteUrl } = queryKey[1]
|
||||
if (!id && !remoteUrl) return Promise.reject()
|
||||
|
||||
let matchedId = id
|
||||
|
||||
if (remoteUrl) {
|
||||
await apiInstance<SearchResult>({
|
||||
version: 'v2',
|
||||
method: 'get',
|
||||
url: 'search',
|
||||
params: {
|
||||
q: remoteUrl,
|
||||
type: 'accounts',
|
||||
limit: 1,
|
||||
resolve: true
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
const account = res.body.accounts[0]
|
||||
if (account.url !== remoteUrl) {
|
||||
return Promise.reject()
|
||||
} else {
|
||||
matchedId = account.id
|
||||
}
|
||||
})
|
||||
.catch(() => Promise.reject())
|
||||
}
|
||||
|
||||
const res = await apiInstance<Mastodon.Account>({
|
||||
method: 'get',
|
||||
url: `accounts/${id}`
|
||||
url: `accounts/${matchedId}`
|
||||
})
|
||||
return res.body
|
||||
}
|
||||
@ -21,7 +48,7 @@ const useAccountQuery = ({
|
||||
options?: UseQueryOptions<Mastodon.Account, AxiosError>
|
||||
}) => {
|
||||
const queryKey: QueryKeyAccount = ['Account', { ...queryKeyParams }]
|
||||
return useQuery(queryKey, accountQueryFunction, options)
|
||||
return useQuery(queryKey, accountQueryFunction, { ...options })
|
||||
}
|
||||
|
||||
/* ----- */
|
||||
@ -43,7 +70,7 @@ const accountInListsQueryFunction = async ({
|
||||
const useAccountInListsQuery = ({
|
||||
options,
|
||||
...queryKeyParams
|
||||
}: QueryKeyAccount[1] & {
|
||||
}: QueryKeyAccountInLists[1] & {
|
||||
options?: UseQueryOptions<Mastodon.List[], AxiosError>
|
||||
}) => {
|
||||
const queryKey: QueryKeyAccountInLists = ['AccountInLists', { ...queryKeyParams }]
|
||||
|
@ -1,17 +1,18 @@
|
||||
import {
|
||||
QueryFunctionContext,
|
||||
useMutation,
|
||||
UseMutationOptions,
|
||||
useQuery,
|
||||
UseQueryOptions
|
||||
QueryFunctionContext,
|
||||
useMutation,
|
||||
UseMutationOptions,
|
||||
useQuery,
|
||||
UseQueryOptions
|
||||
} from '@tanstack/react-query'
|
||||
import apiInstance from '@utils/api/instance'
|
||||
import { AxiosError } from 'axios'
|
||||
|
||||
export type QueryKeyRelationship = ['Relationship', { id: Mastodon.Account['id'] }]
|
||||
export type QueryKeyRelationship = ['Relationship', { id?: Mastodon.Account['id'] }]
|
||||
|
||||
const queryFunction = async ({ queryKey }: QueryFunctionContext<QueryKeyRelationship>) => {
|
||||
const { id } = queryKey[1]
|
||||
if (!id) return Promise.reject()
|
||||
|
||||
const res = await apiInstance<Mastodon.Relationship[]>({
|
||||
method: 'get',
|
||||
@ -32,6 +33,8 @@ const useRelationshipQuery = ({
|
||||
const queryKey: QueryKeyRelationship = ['Relationship', { ...queryKeyParams }]
|
||||
return useQuery(queryKey, queryFunction, {
|
||||
...options,
|
||||
enabled:
|
||||
(typeof options?.enabled === 'boolean' ? options.enabled : true) && !!queryKeyParams.id,
|
||||
select: data => data[0]
|
||||
})
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ export type QueryKeyTimeline = [
|
||||
}
|
||||
| {
|
||||
page: 'Account'
|
||||
account: Mastodon.Account['id']
|
||||
id?: Mastodon.Account['id']
|
||||
exclude_reblogs: boolean
|
||||
only_media: boolean
|
||||
}
|
||||
@ -131,11 +131,13 @@ const queryFunction = async ({ queryKey, pageParam }: QueryFunctionContext<Query
|
||||
})
|
||||
|
||||
case 'Account':
|
||||
if (!page.id) return Promise.reject()
|
||||
|
||||
if (page.exclude_reblogs) {
|
||||
if (pageParam && pageParam.hasOwnProperty('max_id')) {
|
||||
return apiInstance<Mastodon.Status[]>({
|
||||
method: 'get',
|
||||
url: `accounts/${page.account}/statuses`,
|
||||
url: `accounts/${page.id}/statuses`,
|
||||
params: {
|
||||
exclude_replies: 'true',
|
||||
...params
|
||||
@ -144,7 +146,7 @@ const queryFunction = async ({ queryKey, pageParam }: QueryFunctionContext<Query
|
||||
} else {
|
||||
const res1 = await apiInstance<(Mastodon.Status & { _pinned: boolean })[]>({
|
||||
method: 'get',
|
||||
url: `accounts/${page.account}/statuses`,
|
||||
url: `accounts/${page.id}/statuses`,
|
||||
params: {
|
||||
pinned: 'true'
|
||||
}
|
||||
@ -155,7 +157,7 @@ const queryFunction = async ({ queryKey, pageParam }: QueryFunctionContext<Query
|
||||
})
|
||||
const res2 = await apiInstance<Mastodon.Status[]>({
|
||||
method: 'get',
|
||||
url: `accounts/${page.account}/statuses`,
|
||||
url: `accounts/${page.id}/statuses`,
|
||||
params: {
|
||||
exclude_replies: 'true'
|
||||
}
|
||||
@ -168,7 +170,7 @@ const queryFunction = async ({ queryKey, pageParam }: QueryFunctionContext<Query
|
||||
} else {
|
||||
return apiInstance<Mastodon.Status[]>({
|
||||
method: 'get',
|
||||
url: `accounts/${page.account}/statuses`,
|
||||
url: `accounts/${page.id}/statuses`,
|
||||
params: {
|
||||
...params,
|
||||
exclude_replies: page.exclude_reblogs.toString(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user