mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Added push server error messaging
Also clean up <Message> component
This commit is contained in:
@ -39,7 +39,7 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
||||||
const { i18n, t } = useTranslation('screens')
|
const { t } = useTranslation('screens')
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const instanceActive = useSelector(getInstanceActive)
|
const instanceActive = useSelector(getInstanceActive)
|
||||||
const { colors, theme } = useTheme()
|
const { colors, theme } = useTheme()
|
||||||
@ -70,8 +70,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
displayMessage({
|
displayMessage({
|
||||||
message: t('localCorrupt.message'),
|
message: t('localCorrupt.message'),
|
||||||
description: localCorrupt.length ? localCorrupt : undefined,
|
description: localCorrupt.length ? localCorrupt : undefined,
|
||||||
type: 'error',
|
type: 'danger'
|
||||||
theme
|
|
||||||
})
|
})
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
navigationRef.navigate('Screen-Tabs', {
|
navigationRef.navigate('Screen-Tabs', {
|
||||||
@ -183,8 +182,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
message: t('shareError.imageNotSupported', {
|
message: t('shareError.imageNotSupported', {
|
||||||
type: mime.split('/')[1]
|
type: mime.split('/')[1]
|
||||||
}),
|
}),
|
||||||
type: 'error',
|
type: 'danger'
|
||||||
theme
|
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -196,8 +194,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
message: t('shareError.videoNotSupported', {
|
message: t('shareError.videoNotSupported', {
|
||||||
type: mime.split('/')[1]
|
type: mime.split('/')[1]
|
||||||
}),
|
}),
|
||||||
type: 'error',
|
type: 'danger'
|
||||||
theme
|
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import Icon from '@components/Icon'
|
import Icon from '@components/Icon'
|
||||||
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 { getColors, Theme } from '@utils/styles/themes'
|
|
||||||
import React, { RefObject } from 'react'
|
import React, { RefObject } from 'react'
|
||||||
import { AccessibilityInfo } from 'react-native'
|
import { AccessibilityInfo } from 'react-native'
|
||||||
import FlashMessage, { hideMessage, showMessage } from 'react-native-flash-message'
|
import FlashMessage, { MessageType, showMessage } from 'react-native-flash-message'
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||||
import haptics from './haptics'
|
import haptics from './haptics'
|
||||||
|
|
||||||
@ -15,107 +14,80 @@ const displayMessage = ({
|
|||||||
message,
|
message,
|
||||||
description,
|
description,
|
||||||
onPress,
|
onPress,
|
||||||
theme,
|
|
||||||
type
|
type
|
||||||
}:
|
}: {
|
||||||
| {
|
ref?: RefObject<FlashMessage>
|
||||||
ref?: RefObject<FlashMessage>
|
duration?: 'short' | 'long'
|
||||||
duration?: 'short' | 'long'
|
autoHide?: boolean
|
||||||
autoHide?: boolean
|
message: string
|
||||||
message: string
|
description?: string
|
||||||
description?: string
|
onPress?: () => void
|
||||||
onPress?: () => void
|
type?: MessageType
|
||||||
theme?: undefined
|
}) => {
|
||||||
type?: undefined
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
ref?: RefObject<FlashMessage>
|
|
||||||
duration?: 'short' | 'long'
|
|
||||||
autoHide?: boolean
|
|
||||||
message: string
|
|
||||||
description?: string
|
|
||||||
onPress?: () => void
|
|
||||||
theme: Theme
|
|
||||||
type: 'success' | 'error' | 'warning'
|
|
||||||
}) => {
|
|
||||||
AccessibilityInfo.announceForAccessibility(message + '.' + description)
|
AccessibilityInfo.announceForAccessibility(message + '.' + description)
|
||||||
|
|
||||||
enum iconMapping {
|
if (type && type === 'danger') {
|
||||||
success = 'CheckCircle',
|
|
||||||
error = 'XCircle',
|
|
||||||
warning = 'AlertCircle'
|
|
||||||
}
|
|
||||||
enum colorMapping {
|
|
||||||
success = 'blue',
|
|
||||||
error = 'red',
|
|
||||||
warning = 'secondary'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type && type === 'error') {
|
|
||||||
haptics('Error')
|
haptics('Error')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref) {
|
if (ref) {
|
||||||
ref.current?.showMessage({
|
ref.current?.showMessage({
|
||||||
duration: type === 'error' ? 8000 : duration === 'short' ? 3000 : 5000,
|
duration: type === 'danger' ? 8000 : duration === 'short' ? 3000 : 5000,
|
||||||
autoHide,
|
autoHide,
|
||||||
message,
|
message,
|
||||||
description,
|
description,
|
||||||
onPress,
|
onPress,
|
||||||
...(theme &&
|
type
|
||||||
type && {
|
|
||||||
renderFlashMessageIcon: () => {
|
|
||||||
return (
|
|
||||||
<Icon
|
|
||||||
name={iconMapping[type]}
|
|
||||||
size={StyleConstants.Font.LineHeight.M}
|
|
||||||
color={getColors(theme)[colorMapping[type]]}
|
|
||||||
style={{ marginRight: StyleConstants.Spacing.S }}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
showMessage({
|
showMessage({
|
||||||
duration: type === 'error' ? 8000 : duration === 'short' ? 3000 : 5000,
|
duration: type === 'danger' ? 8000 : duration === 'short' ? 3000 : 5000,
|
||||||
autoHide,
|
autoHide,
|
||||||
message,
|
message,
|
||||||
description,
|
description,
|
||||||
onPress,
|
onPress,
|
||||||
...(theme &&
|
type
|
||||||
type && {
|
|
||||||
renderFlashMessageIcon: () => {
|
|
||||||
return (
|
|
||||||
<Icon
|
|
||||||
name={iconMapping[type]}
|
|
||||||
size={StyleConstants.Font.LineHeight.M}
|
|
||||||
color={getColors(theme)[colorMapping[type]]}
|
|
||||||
style={{ marginRight: StyleConstants.Spacing.S }}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeMessage = () => {
|
|
||||||
// if (ref) {
|
|
||||||
// ref.current?.hideMessage()
|
|
||||||
// } else {
|
|
||||||
hideMessage()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
const Message = React.forwardRef<FlashMessage>((_, ref) => {
|
const Message = React.forwardRef<FlashMessage>((_, ref) => {
|
||||||
const { colors, theme } = useTheme()
|
const { colors, theme } = useTheme()
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
|
|
||||||
|
enum iconMapping {
|
||||||
|
success = 'CheckCircle',
|
||||||
|
danger = 'XCircle',
|
||||||
|
warning = 'AlertCircle',
|
||||||
|
none = '',
|
||||||
|
default = '',
|
||||||
|
info = '',
|
||||||
|
auto = ''
|
||||||
|
}
|
||||||
|
enum colorMapping {
|
||||||
|
success = 'blue',
|
||||||
|
danger = 'red',
|
||||||
|
warning = 'secondary',
|
||||||
|
none = 'secondary',
|
||||||
|
default = 'secondary',
|
||||||
|
info = 'secondary',
|
||||||
|
auto = 'secondary'
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FlashMessage
|
<FlashMessage
|
||||||
ref={ref}
|
ref={ref}
|
||||||
icon='auto'
|
icon='auto'
|
||||||
|
renderFlashMessageIcon={type => {
|
||||||
|
return typeof type === 'string' && ['success', 'danger', 'warning'].includes(type) ? (
|
||||||
|
<Icon
|
||||||
|
name={iconMapping[type]}
|
||||||
|
size={StyleConstants.Font.LineHeight.M}
|
||||||
|
color={colors[colorMapping[type]]}
|
||||||
|
style={{ marginRight: StyleConstants.Spacing.S }}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
|
}}
|
||||||
position='top'
|
position='top'
|
||||||
floating
|
floating
|
||||||
style={{
|
style={{
|
||||||
@ -142,4 +114,4 @@ const Message = React.forwardRef<FlashMessage>((_, ref) => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export { Message, displayMessage, removeMessage }
|
export { Message, displayMessage }
|
||||||
|
@ -14,7 +14,6 @@ import {
|
|||||||
useTimelineMutation
|
useTimelineMutation
|
||||||
} from '@utils/queryHooks/timeline'
|
} from '@utils/queryHooks/timeline'
|
||||||
import { getInstanceAccount } from '@utils/slices/instancesSlice'
|
import { getInstanceAccount } from '@utils/slices/instancesSlice'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Platform } from 'react-native'
|
import { Platform } from 'react-native'
|
||||||
@ -38,7 +37,6 @@ const menuAccount = ({
|
|||||||
|
|
||||||
const navigation =
|
const navigation =
|
||||||
useNavigation<NativeStackNavigationProp<TabSharedStackParamList, any, undefined>>()
|
useNavigation<NativeStackNavigationProp<TabSharedStackParamList, any, undefined>>()
|
||||||
const { theme } = useTheme()
|
|
||||||
const { t } = useTranslation('componentContextMenu')
|
const { t } = useTranslation('componentContextMenu')
|
||||||
|
|
||||||
const menus: ContextMenu[][] = [[]]
|
const menus: ContextMenu[][] = [[]]
|
||||||
@ -60,7 +58,6 @@ const menuAccount = ({
|
|||||||
queryClient.refetchQueries(['Relationship', { id: account.id }])
|
queryClient.refetchQueries(['Relationship', { id: account.id }])
|
||||||
const theParams = params as MutationVarsTimelineUpdateAccountProperty
|
const theParams = params as MutationVarsTimelineUpdateAccountProperty
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: t('common:message.success.message', {
|
message: t('common:message.success.message', {
|
||||||
function: t(`account.${theParams.payload.property}.action`, {
|
function: t(`account.${theParams.payload.property}.action`, {
|
||||||
@ -74,8 +71,7 @@ const menuAccount = ({
|
|||||||
onError: (err: any, params) => {
|
onError: (err: any, params) => {
|
||||||
const theParams = params as MutationVarsTimelineUpdateAccountProperty
|
const theParams = params as MutationVarsTimelineUpdateAccountProperty
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
type: 'danger',
|
||||||
type: 'error',
|
|
||||||
message: t('common:message.error.message', {
|
message: t('common:message.error.message', {
|
||||||
function: t(`account.${theParams.payload.property}.action`, {
|
function: t(`account.${theParams.payload.property}.action`, {
|
||||||
...(theParams.payload.property !== 'reports' && {
|
...(theParams.payload.property !== 'reports' && {
|
||||||
@ -109,8 +105,7 @@ const menuAccount = ({
|
|||||||
},
|
},
|
||||||
onError: (err: any, { payload: { action } }) => {
|
onError: (err: any, { payload: { action } }) => {
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
type: 'danger',
|
||||||
type: 'error',
|
|
||||||
message: t('common:message.error.message', {
|
message: t('common:message.error.message', {
|
||||||
function: t(`${action}.function`)
|
function: t(`${action}.function`)
|
||||||
}),
|
}),
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { displayMessage } from '@components/Message'
|
import { displayMessage } from '@components/Message'
|
||||||
import { QueryKeyTimeline, useTimelineMutation } from '@utils/queryHooks/timeline'
|
import { QueryKeyTimeline, useTimelineMutation } from '@utils/queryHooks/timeline'
|
||||||
import { getInstanceUrl } from '@utils/slices/instancesSlice'
|
import { getInstanceUrl } from '@utils/slices/instancesSlice'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Alert } from 'react-native'
|
import { Alert } from 'react-native'
|
||||||
import { useQueryClient } from 'react-query'
|
import { useQueryClient } from 'react-query'
|
||||||
@ -18,14 +17,12 @@ const menuInstance = ({
|
|||||||
}): ContextMenu[][] => {
|
}): ContextMenu[][] => {
|
||||||
if (!status || !queryKey) return []
|
if (!status || !queryKey) return []
|
||||||
|
|
||||||
const { theme } = useTheme()
|
|
||||||
const { t } = useTranslation('componentContextMenu')
|
const { t } = useTranslation('componentContextMenu')
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const mutation = useTimelineMutation({
|
const mutation = useTimelineMutation({
|
||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: t('common:message.success.message', {
|
message: t('common:message.success.message', {
|
||||||
function: t(`instance.block.action`, { instance })
|
function: t(`instance.block.action`, { instance })
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { displayMessage } from '@components/Message'
|
import { displayMessage } from '@components/Message'
|
||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Platform, Share } from 'react-native'
|
import { Platform, Share } from 'react-native'
|
||||||
|
|
||||||
@ -22,7 +21,6 @@ const menuShare = (
|
|||||||
): ContextMenu[][] => {
|
): ContextMenu[][] => {
|
||||||
if (params.type === 'status' && params.visibility === 'direct') return []
|
if (params.type === 'status' && params.visibility === 'direct') return []
|
||||||
|
|
||||||
const { theme } = useTheme()
|
|
||||||
const { t } = useTranslation('componentContextMenu')
|
const { t } = useTranslation('componentContextMenu')
|
||||||
|
|
||||||
const menus: ContextMenu[][] = [[]]
|
const menus: ContextMenu[][] = [[]]
|
||||||
@ -56,11 +54,7 @@ const menuShare = (
|
|||||||
item: {
|
item: {
|
||||||
onSelect: () => {
|
onSelect: () => {
|
||||||
Clipboard.setString(params.copiableContent?.current.content || '')
|
Clipboard.setString(params.copiableContent?.current.content || '')
|
||||||
displayMessage({
|
displayMessage({ type: 'success', message: t(`copy.succeed`) })
|
||||||
theme,
|
|
||||||
type: 'success',
|
|
||||||
message: t(`copy.succeed`)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
disabled: false,
|
disabled: false,
|
||||||
destructive: false,
|
destructive: false,
|
||||||
|
@ -178,6 +178,10 @@
|
|||||||
"direct": "Enable push notification",
|
"direct": "Enable push notification",
|
||||||
"settings": "Enable in settings"
|
"settings": "Enable in settings"
|
||||||
},
|
},
|
||||||
|
"missingServerKey": {
|
||||||
|
"message": "Server misconfigured for push",
|
||||||
|
"description": "Please contact your server admin to configure push support"
|
||||||
|
},
|
||||||
"global": {
|
"global": {
|
||||||
"heading": "Enable for {{acct}}",
|
"heading": "Enable for {{acct}}",
|
||||||
"description": "Messages are routed through tooot's server"
|
"description": "Messages are routed through tooot's server"
|
||||||
|
@ -1,123 +0,0 @@
|
|||||||
import { MenuContainer, MenuHeader, MenuRow } from '@components/Menu'
|
|
||||||
import { displayMessage } from '@components/Message'
|
|
||||||
import {
|
|
||||||
MutationVarsTimelineUpdateAccountProperty,
|
|
||||||
QueryKeyTimeline,
|
|
||||||
useTimelineMutation
|
|
||||||
} from '@utils/queryHooks/timeline'
|
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
|
||||||
import React from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { useQueryClient } from 'react-query'
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
queryKey?: QueryKeyTimeline
|
|
||||||
rootQueryKey?: QueryKeyTimeline
|
|
||||||
account: Mastodon.Account
|
|
||||||
dismiss: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const ActionsAccount: React.FC<Props> = ({
|
|
||||||
queryKey,
|
|
||||||
rootQueryKey,
|
|
||||||
account,
|
|
||||||
dismiss
|
|
||||||
}) => {
|
|
||||||
const { theme } = useTheme()
|
|
||||||
const { t } = useTranslation('componentTimeline')
|
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
|
||||||
const mutation = useTimelineMutation({
|
|
||||||
onSuccess: (_, params) => {
|
|
||||||
const theParams = params as MutationVarsTimelineUpdateAccountProperty
|
|
||||||
displayMessage({
|
|
||||||
theme,
|
|
||||||
type: 'success',
|
|
||||||
message: t('common:message.success.message', {
|
|
||||||
function: t(
|
|
||||||
`shared.header.actions.account.${theParams.payload.property}.function`,
|
|
||||||
{
|
|
||||||
acct: account.acct
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
onError: (err: any, params) => {
|
|
||||||
const theParams = params as MutationVarsTimelineUpdateAccountProperty
|
|
||||||
displayMessage({
|
|
||||||
theme,
|
|
||||||
type: 'error',
|
|
||||||
message: t('common:message.error.message', {
|
|
||||||
function: t(
|
|
||||||
`shared.header.actions.account.${theParams.payload.property}.function`
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
...(err.status &&
|
|
||||||
typeof err.status === 'number' &&
|
|
||||||
err.data &&
|
|
||||||
err.data.error &&
|
|
||||||
typeof err.data.error === 'string' && {
|
|
||||||
description: err.data.error
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
onSettled: () => {
|
|
||||||
queryKey && queryClient.invalidateQueries(queryKey)
|
|
||||||
rootQueryKey && queryClient.invalidateQueries(rootQueryKey)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MenuContainer>
|
|
||||||
<MenuHeader heading={t('shared.header.actions.account.heading')} />
|
|
||||||
<MenuRow
|
|
||||||
onPress={() => {
|
|
||||||
dismiss()
|
|
||||||
mutation.mutate({
|
|
||||||
type: 'updateAccountProperty',
|
|
||||||
queryKey,
|
|
||||||
id: account.id,
|
|
||||||
payload: { property: 'mute' }
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
iconFront='EyeOff'
|
|
||||||
title={t('shared.header.actions.account.mute.button', {
|
|
||||||
acct: account.acct
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<MenuRow
|
|
||||||
onPress={() => {
|
|
||||||
dismiss()
|
|
||||||
mutation.mutate({
|
|
||||||
type: 'updateAccountProperty',
|
|
||||||
queryKey,
|
|
||||||
id: account.id,
|
|
||||||
payload: { property: 'block' }
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
iconFront='XCircle'
|
|
||||||
title={t('shared.header.actions.account.block.button', {
|
|
||||||
acct: account.acct
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<MenuRow
|
|
||||||
onPress={() => {
|
|
||||||
dismiss()
|
|
||||||
mutation.mutate({
|
|
||||||
type: 'updateAccountProperty',
|
|
||||||
queryKey,
|
|
||||||
id: account.id,
|
|
||||||
payload: { property: 'reports' }
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
iconFront='Flag'
|
|
||||||
title={t('shared.header.actions.account.reports.button', {
|
|
||||||
acct: account.acct
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</MenuContainer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ActionsAccount
|
|
@ -1,74 +0,0 @@
|
|||||||
import MenuContainer from '@components/Menu/Container'
|
|
||||||
import MenuHeader from '@components/Menu/Header'
|
|
||||||
import MenuRow from '@components/Menu/Row'
|
|
||||||
import { displayMessage } from '@components/Message'
|
|
||||||
import { QueryKeyTimeline, useTimelineMutation } from '@utils/queryHooks/timeline'
|
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
|
||||||
import React from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { Alert } from 'react-native'
|
|
||||||
import { useQueryClient } from 'react-query'
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
queryKey: QueryKeyTimeline
|
|
||||||
rootQueryKey?: QueryKeyTimeline
|
|
||||||
domain: string
|
|
||||||
dismiss: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const ActionsDomain: React.FC<Props> = ({ queryKey, rootQueryKey, domain, dismiss }) => {
|
|
||||||
const { theme } = useTheme()
|
|
||||||
const { t } = useTranslation('componentTimeline')
|
|
||||||
const queryClient = useQueryClient()
|
|
||||||
const mutation = useTimelineMutation({
|
|
||||||
onSettled: () => {
|
|
||||||
displayMessage({
|
|
||||||
theme,
|
|
||||||
type: 'success',
|
|
||||||
message: t('common:message.success.message', {
|
|
||||||
function: t(`shared.header.actions.domain.block.function`)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
queryClient.invalidateQueries(queryKey)
|
|
||||||
rootQueryKey && queryClient.invalidateQueries(rootQueryKey)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MenuContainer>
|
|
||||||
<MenuHeader heading={t(`shared.header.actions.domain.heading`)} />
|
|
||||||
<MenuRow
|
|
||||||
onPress={() =>
|
|
||||||
Alert.alert(
|
|
||||||
t('shared.header.actions.domain.alert.title', { domain }),
|
|
||||||
t('shared.header.actions.domain.alert.message'),
|
|
||||||
[
|
|
||||||
{
|
|
||||||
text: t('shared.header.actions.domain.alert.buttons.confirm'),
|
|
||||||
style: 'destructive',
|
|
||||||
onPress: () => {
|
|
||||||
dismiss()
|
|
||||||
mutation.mutate({
|
|
||||||
type: 'domainBlock',
|
|
||||||
queryKey,
|
|
||||||
domain: domain
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: t('shared.header.actions.domain.alert.buttons.cancel'),
|
|
||||||
style: 'default'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
iconFront='CloudOff'
|
|
||||||
title={t(`shared.header.actions.domain.block.button`, {
|
|
||||||
domain
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</MenuContainer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ActionsDomain
|
|
@ -1,43 +0,0 @@
|
|||||||
import MenuContainer from '@components/Menu/Container'
|
|
||||||
import MenuHeader from '@components/Menu/Header'
|
|
||||||
import MenuRow from '@components/Menu/Row'
|
|
||||||
import React from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { Platform, Share } from 'react-native'
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
type: 'status' | 'account'
|
|
||||||
url: string
|
|
||||||
dismiss: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const ActionsShare: React.FC<Props> = ({ type, url, dismiss }) => {
|
|
||||||
const { t } = useTranslation('componentTimeline')
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MenuContainer>
|
|
||||||
<MenuHeader heading={t(`shared.header.actions.share.${type}.heading`)} />
|
|
||||||
<MenuRow
|
|
||||||
iconFront='Share2'
|
|
||||||
title={t(`shared.header.actions.share.${type}.button`)}
|
|
||||||
onPress={async () => {
|
|
||||||
switch (Platform.OS) {
|
|
||||||
case 'ios':
|
|
||||||
await Share.share({
|
|
||||||
url
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 'android':
|
|
||||||
await Share.share({
|
|
||||||
message: url
|
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
|
||||||
dismiss()
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</MenuContainer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ActionsShare
|
|
@ -1,231 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { Alert } from 'react-native'
|
|
||||||
import { useQueryClient } from 'react-query'
|
|
||||||
import { MenuContainer, MenuHeader, MenuRow } from '@components/Menu'
|
|
||||||
import {
|
|
||||||
MutationVarsTimelineUpdateStatusProperty,
|
|
||||||
QueryKeyTimeline,
|
|
||||||
useTimelineMutation
|
|
||||||
} from '@utils/queryHooks/timeline'
|
|
||||||
import { displayMessage } from '@components/Message'
|
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
|
||||||
import apiInstance from '@api/instance'
|
|
||||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
|
||||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
|
||||||
import { useSelector } from 'react-redux'
|
|
||||||
import { checkInstanceFeature } from '@utils/slices/instancesSlice'
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
navigation: NativeStackNavigationProp<RootStackParamList, 'Screen-Actions'>
|
|
||||||
queryKey: QueryKeyTimeline
|
|
||||||
rootQueryKey?: QueryKeyTimeline
|
|
||||||
status: Mastodon.Status
|
|
||||||
dismiss: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const ActionsStatus: React.FC<Props> = ({
|
|
||||||
navigation,
|
|
||||||
queryKey,
|
|
||||||
rootQueryKey,
|
|
||||||
status,
|
|
||||||
dismiss
|
|
||||||
}) => {
|
|
||||||
const { theme } = useTheme()
|
|
||||||
const { t } = useTranslation('componentTimeline')
|
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
|
||||||
const mutation = useTimelineMutation({
|
|
||||||
onMutate: true,
|
|
||||||
onError: (err: any, params, oldData) => {
|
|
||||||
const theFunction = (params as MutationVarsTimelineUpdateStatusProperty).payload
|
|
||||||
? (params as MutationVarsTimelineUpdateStatusProperty).payload.property
|
|
||||||
: 'delete'
|
|
||||||
displayMessage({
|
|
||||||
theme,
|
|
||||||
type: 'error',
|
|
||||||
message: t('common:message.error.message', {
|
|
||||||
function: t(`shared.header.actions.status.${theFunction}.function`)
|
|
||||||
}),
|
|
||||||
...(err?.status &&
|
|
||||||
typeof err.status === 'number' &&
|
|
||||||
err.data &&
|
|
||||||
err.data.error &&
|
|
||||||
typeof err.data.error === 'string' && {
|
|
||||||
description: err.data.error
|
|
||||||
})
|
|
||||||
})
|
|
||||||
queryClient.setQueryData(queryKey, oldData)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const canEditPost = useSelector(checkInstanceFeature('edit_post'))
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MenuContainer>
|
|
||||||
<MenuHeader heading={t('shared.header.actions.status.heading')} />
|
|
||||||
{canEditPost ? (
|
|
||||||
<MenuRow
|
|
||||||
onPress={async () => {
|
|
||||||
let replyToStatus: Mastodon.Status | undefined = undefined
|
|
||||||
if (status.in_reply_to_id) {
|
|
||||||
replyToStatus = await apiInstance<Mastodon.Status>({
|
|
||||||
method: 'get',
|
|
||||||
url: `statuses/${status.in_reply_to_id}`
|
|
||||||
}).then(res => res.body)
|
|
||||||
}
|
|
||||||
apiInstance<{
|
|
||||||
id: Mastodon.Status['id']
|
|
||||||
text: NonNullable<Mastodon.Status['text']>
|
|
||||||
spoiler_text: Mastodon.Status['spoiler_text']
|
|
||||||
}>({
|
|
||||||
method: 'get',
|
|
||||||
url: `statuses/${status.id}/source`
|
|
||||||
}).then(res => {
|
|
||||||
dismiss()
|
|
||||||
navigation.navigate('Screen-Compose', {
|
|
||||||
type: 'edit',
|
|
||||||
incomingStatus: {
|
|
||||||
...status,
|
|
||||||
text: res.body.text,
|
|
||||||
spoiler_text: res.body.spoiler_text
|
|
||||||
},
|
|
||||||
...(replyToStatus && { replyToStatus }),
|
|
||||||
queryKey,
|
|
||||||
rootQueryKey
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
iconFront='Edit3'
|
|
||||||
title={t('shared.header.actions.status.edit.button')}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
<MenuRow
|
|
||||||
onPress={() => {
|
|
||||||
Alert.alert(
|
|
||||||
t('shared.header.actions.status.delete.alert.title'),
|
|
||||||
t('shared.header.actions.status.delete.alert.message'),
|
|
||||||
[
|
|
||||||
{
|
|
||||||
text: t('shared.header.actions.status.delete.alert.buttons.confirm'),
|
|
||||||
style: 'destructive',
|
|
||||||
onPress: async () => {
|
|
||||||
dismiss()
|
|
||||||
mutation.mutate({
|
|
||||||
type: 'deleteItem',
|
|
||||||
source: 'statuses',
|
|
||||||
queryKey,
|
|
||||||
rootQueryKey,
|
|
||||||
id: status.id
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: t('shared.header.actions.status.delete.alert.buttons.cancel'),
|
|
||||||
style: 'default'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
iconFront='Trash'
|
|
||||||
title={t('shared.header.actions.status.delete.button')}
|
|
||||||
/>
|
|
||||||
<MenuRow
|
|
||||||
onPress={() => {
|
|
||||||
Alert.alert(
|
|
||||||
t('shared.header.actions.status.deleteEdit.alert.title'),
|
|
||||||
t('shared.header.actions.status.deleteEdit.alert.message'),
|
|
||||||
[
|
|
||||||
{
|
|
||||||
text: t('shared.header.actions.status.deleteEdit.alert.buttons.confirm'),
|
|
||||||
style: 'destructive',
|
|
||||||
onPress: async () => {
|
|
||||||
let replyToStatus: Mastodon.Status | undefined = undefined
|
|
||||||
if (status.in_reply_to_id) {
|
|
||||||
replyToStatus = await apiInstance<Mastodon.Status>({
|
|
||||||
method: 'get',
|
|
||||||
url: `statuses/${status.in_reply_to_id}`
|
|
||||||
}).then(res => res.body)
|
|
||||||
}
|
|
||||||
mutation
|
|
||||||
.mutateAsync({
|
|
||||||
type: 'deleteItem',
|
|
||||||
source: 'statuses',
|
|
||||||
queryKey,
|
|
||||||
id: status.id
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
dismiss()
|
|
||||||
navigation.navigate('Screen-Compose', {
|
|
||||||
type: 'deleteEdit',
|
|
||||||
incomingStatus: res.body as Mastodon.Status,
|
|
||||||
...(replyToStatus && { replyToStatus }),
|
|
||||||
queryKey
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: t('shared.header.actions.status.deleteEdit.alert.buttons.cancel'),
|
|
||||||
style: 'default'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
iconFront='Edit'
|
|
||||||
title={t('shared.header.actions.status.deleteEdit.button')}
|
|
||||||
/>
|
|
||||||
<MenuRow
|
|
||||||
onPress={() => {
|
|
||||||
dismiss()
|
|
||||||
mutation.mutate({
|
|
||||||
type: 'updateStatusProperty',
|
|
||||||
queryKey,
|
|
||||||
rootQueryKey,
|
|
||||||
id: status.id,
|
|
||||||
payload: {
|
|
||||||
property: 'muted',
|
|
||||||
currentValue: status.muted,
|
|
||||||
propertyCount: undefined,
|
|
||||||
countValue: undefined
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
iconFront='VolumeX'
|
|
||||||
title={
|
|
||||||
status.muted
|
|
||||||
? t('shared.header.actions.status.mute.button.negative')
|
|
||||||
: t('shared.header.actions.status.mute.button.positive')
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{/* Also note that reblogs cannot be pinned. */}
|
|
||||||
{(status.visibility === 'public' || status.visibility === 'unlisted') && (
|
|
||||||
<MenuRow
|
|
||||||
onPress={() => {
|
|
||||||
dismiss()
|
|
||||||
mutation.mutate({
|
|
||||||
type: 'updateStatusProperty',
|
|
||||||
queryKey,
|
|
||||||
rootQueryKey,
|
|
||||||
id: status.id,
|
|
||||||
payload: {
|
|
||||||
property: 'pinned',
|
|
||||||
currentValue: status.pinned,
|
|
||||||
propertyCount: undefined,
|
|
||||||
countValue: undefined
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
iconFront='Anchor'
|
|
||||||
title={
|
|
||||||
status.pinned
|
|
||||||
? t('shared.header.actions.status.pin.button.negative')
|
|
||||||
: t('shared.header.actions.status.pin.button.positive')
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</MenuContainer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ActionsStatus
|
|
@ -2,22 +2,19 @@ import haptics from '@components/haptics'
|
|||||||
import { displayMessage } from '@components/Message'
|
import { displayMessage } from '@components/Message'
|
||||||
import { CameraRoll } from '@react-native-camera-roll/camera-roll'
|
import { CameraRoll } from '@react-native-camera-roll/camera-roll'
|
||||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
import { RootStackParamList } from '@utils/navigation/navigators'
|
||||||
import { Theme } from '@utils/styles/themes'
|
|
||||||
import * as FileSystem from 'expo-file-system'
|
import * as FileSystem from 'expo-file-system'
|
||||||
import i18next from 'i18next'
|
import i18next from 'i18next'
|
||||||
import { PermissionsAndroid, Platform } from 'react-native'
|
import { PermissionsAndroid, Platform } from 'react-native'
|
||||||
|
|
||||||
type CommonProps = {
|
type CommonProps = {
|
||||||
theme: Theme
|
|
||||||
image: RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
|
image: RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveIos = async ({ theme, image }: CommonProps) => {
|
const saveIos = async ({ image }: CommonProps) => {
|
||||||
CameraRoll.save(image.url)
|
CameraRoll.save(image.url)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
haptics('Success')
|
haptics('Success')
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: i18next.t('screenImageViewer:content.save.succeed')
|
message: i18next.t('screenImageViewer:content.save.succeed')
|
||||||
})
|
})
|
||||||
@ -28,7 +25,6 @@ const saveIos = async ({ theme, image }: CommonProps) => {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
haptics('Success')
|
haptics('Success')
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: i18next.t('screenImageViewer:content.save.succeed')
|
message: i18next.t('screenImageViewer:content.save.succeed')
|
||||||
})
|
})
|
||||||
@ -36,32 +32,31 @@ const saveIos = async ({ theme, image }: CommonProps) => {
|
|||||||
.catch(() => {
|
.catch(() => {
|
||||||
haptics('Error')
|
haptics('Error')
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
type: 'danger',
|
||||||
type: 'error',
|
|
||||||
message: i18next.t('screenImageViewer:content.save.failed')
|
message: i18next.t('screenImageViewer:content.save.failed')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
haptics('Error')
|
haptics('Error')
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
type: 'danger',
|
||||||
type: 'error',
|
|
||||||
message: i18next.t('screenImageViewer:content.save.failed')
|
message: i18next.t('screenImageViewer:content.save.failed')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveAndroid = async ({ theme, image }: CommonProps) => {
|
const saveAndroid = async ({ image }: CommonProps) => {
|
||||||
const fileUri: string = `${FileSystem.documentDirectory}${image.id}.jpg`
|
const fileUri: string = `${FileSystem.documentDirectory}${image.id}.jpg`
|
||||||
const downloadedFile: FileSystem.FileSystemDownloadResult =
|
const downloadedFile: FileSystem.FileSystemDownloadResult = await FileSystem.downloadAsync(
|
||||||
await FileSystem.downloadAsync(image.url, fileUri)
|
image.url,
|
||||||
|
fileUri
|
||||||
|
)
|
||||||
|
|
||||||
if (downloadedFile.status != 200) {
|
if (downloadedFile.status != 200) {
|
||||||
haptics('Error')
|
haptics('Error')
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
type: 'danger',
|
||||||
type: 'error',
|
|
||||||
message: i18next.t('screenImageViewer:content.save.failed')
|
message: i18next.t('screenImageViewer:content.save.failed')
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@ -75,8 +70,7 @@ const saveAndroid = async ({ theme, image }: CommonProps) => {
|
|||||||
if (status !== 'granted') {
|
if (status !== 'granted') {
|
||||||
haptics('Error')
|
haptics('Error')
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
type: 'danger',
|
||||||
type: 'error',
|
|
||||||
message: i18next.t('screenImageViewer:content.save.failed')
|
message: i18next.t('screenImageViewer:content.save.failed')
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@ -87,7 +81,6 @@ const saveAndroid = async ({ theme, image }: CommonProps) => {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
haptics('Success')
|
haptics('Success')
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: i18next.t('screenImageViewer:content.save.succeed')
|
message: i18next.t('screenImageViewer:content.save.succeed')
|
||||||
})
|
})
|
||||||
@ -95,8 +88,7 @@ const saveAndroid = async ({ theme, image }: CommonProps) => {
|
|||||||
.catch(() => {
|
.catch(() => {
|
||||||
haptics('Error')
|
haptics('Error')
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
type: 'danger',
|
||||||
type: 'error',
|
|
||||||
message: i18next.t('screenImageViewer:content.save.failed')
|
message: i18next.t('screenImageViewer:content.save.failed')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -40,7 +40,7 @@ const ScreenImagesViewer = ({
|
|||||||
|
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
|
|
||||||
const { mode, theme } = useTheme()
|
const { mode } = useTheme()
|
||||||
const { t } = useTranslation('screenImageViewer')
|
const { t } = useTranslation('screenImageViewer')
|
||||||
|
|
||||||
const initialIndex = imageUrls.findIndex(image => image.id === id)
|
const initialIndex = imageUrls.findIndex(image => image.id === id)
|
||||||
@ -61,7 +61,7 @@ const ScreenImagesViewer = ({
|
|||||||
async buttonIndex => {
|
async buttonIndex => {
|
||||||
switch (buttonIndex) {
|
switch (buttonIndex) {
|
||||||
case 0:
|
case 0:
|
||||||
saveImage({ theme, image: imageUrls[currentIndex] })
|
saveImage({ image: imageUrls[currentIndex] })
|
||||||
break
|
break
|
||||||
case 1:
|
case 1:
|
||||||
switch (Platform.OS) {
|
switch (Platform.OS) {
|
||||||
@ -188,7 +188,7 @@ const ScreenImagesViewer = ({
|
|||||||
async buttonIndex => {
|
async buttonIndex => {
|
||||||
switch (buttonIndex) {
|
switch (buttonIndex) {
|
||||||
case 0:
|
case 0:
|
||||||
saveImage({ theme, image: imageUrls[currentIndex] })
|
saveImage({ image: imageUrls[currentIndex] })
|
||||||
break
|
break
|
||||||
case 1:
|
case 1:
|
||||||
switch (Platform.OS) {
|
switch (Platform.OS) {
|
||||||
|
@ -129,15 +129,11 @@ const TabMe = React.memo(
|
|||||||
name='Tab-Me-Push'
|
name='Tab-Me-Push'
|
||||||
component={TabMePush}
|
component={TabMePush}
|
||||||
options={({ navigation }) => ({
|
options={({ navigation }) => ({
|
||||||
presentation: 'modal',
|
|
||||||
headerShown: true,
|
|
||||||
title: t('me.stacks.push.name'),
|
title: t('me.stacks.push.name'),
|
||||||
...(Platform.OS === 'android' && {
|
...(Platform.OS === 'android' && {
|
||||||
headerCenter: () => <HeaderCenter content={t('me.stacks.push.name')} />
|
headerCenter: () => <HeaderCenter content={t('me.stacks.push.name')} />
|
||||||
}),
|
}),
|
||||||
headerLeft: () => (
|
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||||
<HeaderLeft content='ChevronDown' onPress={() => navigation.goBack()} />
|
|
||||||
)
|
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
|
@ -41,8 +41,7 @@ const TabMeListAccounts: React.FC<TabMeStackScreenProps<'Tab-Me-List-Accounts'>>
|
|||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
type: 'danger',
|
||||||
type: 'error',
|
|
||||||
message: t('common:message.error.message', {
|
message: t('common:message.error.message', {
|
||||||
function: t('me.listAccounts.error')
|
function: t('me.listAccounts.error')
|
||||||
})
|
})
|
||||||
|
@ -41,8 +41,7 @@ const TabMeListEdit: React.FC<TabMeStackScreenProps<'Tab-Me-List-Edit'>> = ({
|
|||||||
onError: () => {
|
onError: () => {
|
||||||
displayMessage({
|
displayMessage({
|
||||||
ref: messageRef,
|
ref: messageRef,
|
||||||
theme,
|
type: 'danger',
|
||||||
type: 'error',
|
|
||||||
message: t('common:message.error.message', {
|
message: t('common:message.error.message', {
|
||||||
function:
|
function:
|
||||||
params.type === 'add' ? t('me.stacks.listAdd.name') : t('me.stacks.listEdit.name')
|
params.type === 'add' ? t('me.stacks.listAdd.name') : t('me.stacks.listEdit.name')
|
||||||
|
@ -17,7 +17,7 @@ const TabMeList: React.FC<TabMeStackScreenProps<'Tab-Me-List'>> = ({
|
|||||||
navigation,
|
navigation,
|
||||||
route: { key, params }
|
route: { key, params }
|
||||||
}) => {
|
}) => {
|
||||||
const { colors, theme } = useTheme()
|
const { colors } = useTheme()
|
||||||
const { t } = useTranslation('screenTabs')
|
const { t } = useTranslation('screenTabs')
|
||||||
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'List', list: params.id }]
|
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'List', list: params.id }]
|
||||||
|
|
||||||
@ -30,8 +30,7 @@ const TabMeList: React.FC<TabMeStackScreenProps<'Tab-Me-List'>> = ({
|
|||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
type: 'danger',
|
||||||
type: 'error',
|
|
||||||
message: t('common:message.error.message', {
|
message: t('common:message.error.message', {
|
||||||
function: t('me.listDelete.heading')
|
function: t('me.listDelete.heading')
|
||||||
})
|
})
|
||||||
|
@ -121,7 +121,6 @@ const TabMeProfileFields: React.FC<
|
|||||||
content='Save'
|
content='Save'
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
mutateAsync({
|
mutateAsync({
|
||||||
theme,
|
|
||||||
messageRef,
|
messageRef,
|
||||||
message: {
|
message: {
|
||||||
text: 'me.profile.root.note.title',
|
text: 'me.profile.root.note.title',
|
||||||
|
@ -75,7 +75,6 @@ const TabMeProfileName: React.FC<
|
|||||||
content='Save'
|
content='Save'
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
mutateAsync({
|
mutateAsync({
|
||||||
theme,
|
|
||||||
messageRef,
|
messageRef,
|
||||||
message: {
|
message: {
|
||||||
text: 'me.profile.root.name.title',
|
text: 'me.profile.root.name.title',
|
||||||
|
@ -75,7 +75,6 @@ const TabMeProfileNote: React.FC<
|
|||||||
content='Save'
|
content='Save'
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
mutateAsync({
|
mutateAsync({
|
||||||
theme,
|
|
||||||
messageRef,
|
messageRef,
|
||||||
message: {
|
message: {
|
||||||
text: 'me.profile.root.note.title',
|
text: 'me.profile.root.note.title',
|
||||||
|
@ -5,7 +5,7 @@ import { TabMeProfileStackScreenProps } from '@utils/navigation/navigators'
|
|||||||
import { useProfileMutation, useProfileQuery } from '@utils/queryHooks/profile'
|
import { useProfileMutation, useProfileQuery } from '@utils/queryHooks/profile'
|
||||||
import { updateAccountPreferences } from '@utils/slices/instances/updateAccountPreferences'
|
import { updateAccountPreferences } from '@utils/slices/instances/updateAccountPreferences'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { RefObject, useCallback } from 'react'
|
import React, { RefObject } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import FlashMessage from 'react-native-flash-message'
|
import FlashMessage from 'react-native-flash-message'
|
||||||
import { ScrollView } from 'react-native-gesture-handler'
|
import { ScrollView } from 'react-native-gesture-handler'
|
||||||
@ -16,7 +16,7 @@ const TabMeProfileRoot: React.FC<
|
|||||||
messageRef: RefObject<FlashMessage>
|
messageRef: RefObject<FlashMessage>
|
||||||
}
|
}
|
||||||
> = ({ messageRef, navigation }) => {
|
> = ({ messageRef, navigation }) => {
|
||||||
const { mode, theme } = useTheme()
|
const { mode } = useTheme()
|
||||||
const { t } = useTranslation('screenTabs')
|
const { t } = useTranslation('screenTabs')
|
||||||
|
|
||||||
const { showActionSheetWithOptions } = useActionSheet()
|
const { showActionSheetWithOptions } = useActionSheet()
|
||||||
@ -25,90 +25,6 @@ const TabMeProfileRoot: React.FC<
|
|||||||
const { mutateAsync } = useProfileMutation()
|
const { mutateAsync } = useProfileMutation()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
const onPressVisibility = useCallback(() => {
|
|
||||||
showActionSheetWithOptions(
|
|
||||||
{
|
|
||||||
title: t('me.profile.root.visibility.title'),
|
|
||||||
options: [
|
|
||||||
t('me.profile.root.visibility.options.public'),
|
|
||||||
t('me.profile.root.visibility.options.unlisted'),
|
|
||||||
t('me.profile.root.visibility.options.private'),
|
|
||||||
t('common:buttons.cancel')
|
|
||||||
],
|
|
||||||
cancelButtonIndex: 3,
|
|
||||||
userInterfaceStyle: mode
|
|
||||||
},
|
|
||||||
async buttonIndex => {
|
|
||||||
switch (buttonIndex) {
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
const indexVisibilityMapping = ['public', 'unlisted', 'private'] as [
|
|
||||||
'public',
|
|
||||||
'unlisted',
|
|
||||||
'private'
|
|
||||||
]
|
|
||||||
if (data?.source.privacy !== indexVisibilityMapping[buttonIndex]) {
|
|
||||||
mutateAsync({
|
|
||||||
theme,
|
|
||||||
messageRef,
|
|
||||||
message: {
|
|
||||||
text: 'me.profile.root.visibility.title',
|
|
||||||
succeed: false,
|
|
||||||
failed: true
|
|
||||||
},
|
|
||||||
type: 'source[privacy]',
|
|
||||||
data: indexVisibilityMapping[buttonIndex]
|
|
||||||
}).then(() => dispatch(updateAccountPreferences()))
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}, [theme, data?.source?.privacy])
|
|
||||||
|
|
||||||
const onPressSensitive = useCallback(() => {
|
|
||||||
mutateAsync({
|
|
||||||
theme,
|
|
||||||
messageRef,
|
|
||||||
message: {
|
|
||||||
text: 'me.profile.root.sensitive.title',
|
|
||||||
succeed: false,
|
|
||||||
failed: true
|
|
||||||
},
|
|
||||||
type: 'source[sensitive]',
|
|
||||||
data: data?.source.sensitive === undefined ? true : !data.source.sensitive
|
|
||||||
}).then(() => dispatch(updateAccountPreferences()))
|
|
||||||
}, [data?.source.sensitive])
|
|
||||||
|
|
||||||
const onPressLock = useCallback(() => {
|
|
||||||
mutateAsync({
|
|
||||||
theme,
|
|
||||||
messageRef,
|
|
||||||
message: {
|
|
||||||
text: 'me.profile.root.lock.title',
|
|
||||||
succeed: false,
|
|
||||||
failed: true
|
|
||||||
},
|
|
||||||
type: 'locked',
|
|
||||||
data: data?.locked === undefined ? true : !data.locked
|
|
||||||
})
|
|
||||||
}, [theme, data?.locked])
|
|
||||||
|
|
||||||
const onPressBot = useCallback(() => {
|
|
||||||
mutateAsync({
|
|
||||||
theme,
|
|
||||||
messageRef,
|
|
||||||
message: {
|
|
||||||
text: 'me.profile.root.bot.title',
|
|
||||||
succeed: false,
|
|
||||||
failed: true
|
|
||||||
},
|
|
||||||
type: 'bot',
|
|
||||||
data: data?.bot === undefined ? true : !data.bot
|
|
||||||
})
|
|
||||||
}, [theme, data?.bot])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
<MenuContainer>
|
<MenuContainer>
|
||||||
@ -166,12 +82,62 @@ const TabMeProfileRoot: React.FC<
|
|||||||
}
|
}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
iconBack='ChevronRight'
|
iconBack='ChevronRight'
|
||||||
onPress={onPressVisibility}
|
onPress={() =>
|
||||||
|
showActionSheetWithOptions(
|
||||||
|
{
|
||||||
|
title: t('me.profile.root.visibility.title'),
|
||||||
|
options: [
|
||||||
|
t('me.profile.root.visibility.options.public'),
|
||||||
|
t('me.profile.root.visibility.options.unlisted'),
|
||||||
|
t('me.profile.root.visibility.options.private'),
|
||||||
|
t('common:buttons.cancel')
|
||||||
|
],
|
||||||
|
cancelButtonIndex: 3,
|
||||||
|
userInterfaceStyle: mode
|
||||||
|
},
|
||||||
|
async buttonIndex => {
|
||||||
|
switch (buttonIndex) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
const indexVisibilityMapping = ['public', 'unlisted', 'private'] as [
|
||||||
|
'public',
|
||||||
|
'unlisted',
|
||||||
|
'private'
|
||||||
|
]
|
||||||
|
if (data?.source.privacy !== indexVisibilityMapping[buttonIndex]) {
|
||||||
|
mutateAsync({
|
||||||
|
messageRef,
|
||||||
|
message: {
|
||||||
|
text: 'me.profile.root.visibility.title',
|
||||||
|
succeed: false,
|
||||||
|
failed: true
|
||||||
|
},
|
||||||
|
type: 'source[privacy]',
|
||||||
|
data: indexVisibilityMapping[buttonIndex]
|
||||||
|
}).then(() => dispatch(updateAccountPreferences()))
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<MenuRow
|
<MenuRow
|
||||||
title={t('me.profile.root.sensitive.title')}
|
title={t('me.profile.root.sensitive.title')}
|
||||||
switchValue={data?.source.sensitive}
|
switchValue={data?.source.sensitive}
|
||||||
switchOnValueChange={onPressSensitive}
|
switchOnValueChange={() =>
|
||||||
|
mutateAsync({
|
||||||
|
messageRef,
|
||||||
|
message: {
|
||||||
|
text: 'me.profile.root.sensitive.title',
|
||||||
|
succeed: false,
|
||||||
|
failed: true
|
||||||
|
},
|
||||||
|
type: 'source[sensitive]',
|
||||||
|
data: data?.source.sensitive === undefined ? true : !data.source.sensitive
|
||||||
|
}).then(() => dispatch(updateAccountPreferences()))
|
||||||
|
}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
/>
|
/>
|
||||||
</MenuContainer>
|
</MenuContainer>
|
||||||
@ -180,14 +146,36 @@ const TabMeProfileRoot: React.FC<
|
|||||||
title={t('me.profile.root.lock.title')}
|
title={t('me.profile.root.lock.title')}
|
||||||
description={t('me.profile.root.lock.description')}
|
description={t('me.profile.root.lock.description')}
|
||||||
switchValue={data?.locked}
|
switchValue={data?.locked}
|
||||||
switchOnValueChange={onPressLock}
|
switchOnValueChange={() =>
|
||||||
|
mutateAsync({
|
||||||
|
messageRef,
|
||||||
|
message: {
|
||||||
|
text: 'me.profile.root.lock.title',
|
||||||
|
succeed: false,
|
||||||
|
failed: true
|
||||||
|
},
|
||||||
|
type: 'locked',
|
||||||
|
data: data?.locked === undefined ? true : !data.locked
|
||||||
|
})
|
||||||
|
}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
/>
|
/>
|
||||||
<MenuRow
|
<MenuRow
|
||||||
title={t('me.profile.root.bot.title')}
|
title={t('me.profile.root.bot.title')}
|
||||||
description={t('me.profile.root.bot.description')}
|
description={t('me.profile.root.bot.description')}
|
||||||
switchValue={data?.bot}
|
switchValue={data?.bot}
|
||||||
switchOnValueChange={onPressBot}
|
switchOnValueChange={() =>
|
||||||
|
mutateAsync({
|
||||||
|
messageRef,
|
||||||
|
message: {
|
||||||
|
text: 'me.profile.root.bot.title',
|
||||||
|
succeed: false,
|
||||||
|
failed: true
|
||||||
|
},
|
||||||
|
type: 'bot',
|
||||||
|
data: data?.bot === undefined ? true : !data.bot
|
||||||
|
})
|
||||||
|
}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
/>
|
/>
|
||||||
</MenuContainer>
|
</MenuContainer>
|
||||||
|
@ -3,7 +3,6 @@ import { MenuRow } from '@components/Menu'
|
|||||||
import { displayMessage } from '@components/Message'
|
import { displayMessage } from '@components/Message'
|
||||||
import { useActionSheet } from '@expo/react-native-action-sheet'
|
import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||||
import { useProfileMutation, useProfileQuery } from '@utils/queryHooks/profile'
|
import { useProfileMutation, useProfileQuery } from '@utils/queryHooks/profile'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
|
||||||
import React, { RefObject } from 'react'
|
import React, { RefObject } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import FlashMessage from 'react-native-flash-message'
|
import FlashMessage from 'react-native-flash-message'
|
||||||
@ -14,7 +13,6 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => {
|
const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => {
|
||||||
const { theme } = useTheme()
|
|
||||||
const { t } = useTranslation('screenTabs')
|
const { t } = useTranslation('screenTabs')
|
||||||
|
|
||||||
const { showActionSheetWithOptions } = useActionSheet()
|
const { showActionSheetWithOptions } = useActionSheet()
|
||||||
@ -40,7 +38,6 @@ const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => {
|
|||||||
})
|
})
|
||||||
if (image[0].uri) {
|
if (image[0].uri) {
|
||||||
mutation.mutate({
|
mutation.mutate({
|
||||||
theme,
|
|
||||||
messageRef,
|
messageRef,
|
||||||
message: {
|
message: {
|
||||||
text: `me.profile.root.${type}.title`,
|
text: `me.profile.root.${type}.title`,
|
||||||
@ -54,8 +51,7 @@ const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => {
|
|||||||
displayMessage({
|
displayMessage({
|
||||||
ref: messageRef,
|
ref: messageRef,
|
||||||
message: t('screenTabs:me.profile.mediaSelectionFailed'),
|
message: t('screenTabs:me.profile.mediaSelectionFailed'),
|
||||||
theme: theme,
|
type: 'danger'
|
||||||
type: 'error'
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -7,7 +7,6 @@ import { useAppDispatch } from '@root/store'
|
|||||||
import * as Sentry from '@sentry/react-native'
|
import * as Sentry from '@sentry/react-native'
|
||||||
import { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice'
|
import { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice'
|
||||||
import { disableAllPushes, getInstances } from '@utils/slices/instancesSlice'
|
import { disableAllPushes, getInstances } from '@utils/slices/instancesSlice'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
|
||||||
import * as Notifications from 'expo-notifications'
|
import * as Notifications from 'expo-notifications'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -16,7 +15,6 @@ import { useSelector } from 'react-redux'
|
|||||||
|
|
||||||
const pushUseConnect = () => {
|
const pushUseConnect = () => {
|
||||||
const { t } = useTranslation('screens')
|
const { t } = useTranslation('screens')
|
||||||
const { theme } = useTheme()
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -39,8 +37,7 @@ const pushUseConnect = () => {
|
|||||||
Notifications.setBadgeCountAsync(0)
|
Notifications.setBadgeCountAsync(0)
|
||||||
if (error?.status == 404) {
|
if (error?.status == 404) {
|
||||||
displayMessage({
|
displayMessage({
|
||||||
theme,
|
type: 'danger',
|
||||||
type: 'error',
|
|
||||||
duration: 'long',
|
duration: 'long',
|
||||||
message: t('pushError.message'),
|
message: t('pushError.message'),
|
||||||
description: t('pushError.description'),
|
description: t('pushError.description'),
|
||||||
|
@ -2,15 +2,13 @@ import apiInstance from '@api/instance'
|
|||||||
import haptics from '@components/haptics'
|
import haptics from '@components/haptics'
|
||||||
import { displayMessage } from '@components/Message'
|
import { displayMessage } from '@components/Message'
|
||||||
import queryClient from '@helpers/queryClient'
|
import queryClient from '@helpers/queryClient'
|
||||||
import { Theme } from '@utils/styles/themes'
|
|
||||||
import { AxiosError } from 'axios'
|
import { AxiosError } from 'axios'
|
||||||
import i18next from 'i18next'
|
import i18next from 'i18next'
|
||||||
import { RefObject } from 'react'
|
import { RefObject } from 'react'
|
||||||
import FlashMessage from 'react-native-flash-message'
|
import FlashMessage from 'react-native-flash-message'
|
||||||
import { useMutation, useQuery, UseQueryOptions } from 'react-query'
|
import { useMutation, useQuery, UseQueryOptions } from 'react-query'
|
||||||
|
|
||||||
type AccountWithSource = Mastodon.Account &
|
type AccountWithSource = Mastodon.Account & Required<Pick<Mastodon.Account, 'source'>>
|
||||||
Required<Pick<Mastodon.Account, 'source'>>
|
|
||||||
|
|
||||||
type QueryKeyProfile = ['Profile']
|
type QueryKeyProfile = ['Profile']
|
||||||
const queryKey: QueryKeyProfile = ['Profile']
|
const queryKey: QueryKeyProfile = ['Profile']
|
||||||
@ -52,7 +50,6 @@ type MutationVarsProfileBase =
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MutationVarsProfile = MutationVarsProfileBase & {
|
type MutationVarsProfile = MutationVarsProfileBase & {
|
||||||
theme: Theme
|
|
||||||
messageRef: RefObject<FlashMessage>
|
messageRef: RefObject<FlashMessage>
|
||||||
message: {
|
message: {
|
||||||
text: string
|
text: string
|
||||||
@ -92,73 +89,70 @@ const mutationFunction = async ({ type, data }: MutationVarsProfile) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const useProfileMutation = () => {
|
const useProfileMutation = () => {
|
||||||
return useMutation<
|
return useMutation<{ body: AccountWithSource }, AxiosError, MutationVarsProfile>(
|
||||||
{ body: AccountWithSource },
|
mutationFunction,
|
||||||
AxiosError,
|
{
|
||||||
MutationVarsProfile
|
onMutate: async variables => {
|
||||||
>(mutationFunction, {
|
await queryClient.cancelQueries(queryKey)
|
||||||
onMutate: async variables => {
|
|
||||||
await queryClient.cancelQueries(queryKey)
|
|
||||||
|
|
||||||
const oldData = queryClient.getQueryData<AccountWithSource>(queryKey)
|
const oldData = queryClient.getQueryData<AccountWithSource>(queryKey)
|
||||||
|
|
||||||
queryClient.setQueryData<AccountWithSource | undefined>(queryKey, old => {
|
queryClient.setQueryData<AccountWithSource | undefined>(queryKey, old => {
|
||||||
if (old) {
|
if (old) {
|
||||||
switch (variables.type) {
|
switch (variables.type) {
|
||||||
case 'source[privacy]':
|
case 'source[privacy]':
|
||||||
return {
|
return {
|
||||||
...old,
|
...old,
|
||||||
source: { ...old.source, privacy: variables.data }
|
source: { ...old.source, privacy: variables.data }
|
||||||
}
|
}
|
||||||
case 'source[sensitive]':
|
case 'source[sensitive]':
|
||||||
return {
|
return {
|
||||||
...old,
|
...old,
|
||||||
source: { ...old.source, sensitive: variables.data }
|
source: { ...old.source, sensitive: variables.data }
|
||||||
}
|
}
|
||||||
case 'locked':
|
case 'locked':
|
||||||
return { ...old, locked: variables.data }
|
return { ...old, locked: variables.data }
|
||||||
case 'bot':
|
case 'bot':
|
||||||
return { ...old, bot: variables.data }
|
return { ...old, bot: variables.data }
|
||||||
default:
|
default:
|
||||||
return old
|
return old
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
|
|
||||||
return oldData
|
return oldData
|
||||||
},
|
},
|
||||||
onError: (err, variables, context) => {
|
onError: (err, variables, context) => {
|
||||||
queryClient.setQueryData(queryKey, context)
|
queryClient.setQueryData(queryKey, context)
|
||||||
haptics('Error')
|
haptics('Error')
|
||||||
if (variables.message.failed) {
|
if (variables.message.failed) {
|
||||||
displayMessage({
|
displayMessage({
|
||||||
ref: variables.messageRef,
|
ref: variables.messageRef,
|
||||||
message: i18next.t('screenTabs:me.profile.feedback.failed', {
|
message: i18next.t('screenTabs:me.profile.feedback.failed', {
|
||||||
type: i18next.t(`screenTabs:${variables.message.text}`)
|
type: i18next.t(`screenTabs:${variables.message.text}`)
|
||||||
}),
|
}),
|
||||||
...(err && { description: err.message }),
|
...(err && { description: err.message }),
|
||||||
theme: variables.theme,
|
type: 'danger'
|
||||||
type: 'error'
|
})
|
||||||
})
|
}
|
||||||
|
},
|
||||||
|
onSuccess: (_, variables) => {
|
||||||
|
if (variables.message.succeed) {
|
||||||
|
haptics('Success')
|
||||||
|
displayMessage({
|
||||||
|
ref: variables.messageRef,
|
||||||
|
message: i18next.t('screenTabs:me.profile.feedback.succeed', {
|
||||||
|
type: i18next.t(`screenTabs:${variables.message.text}`)
|
||||||
|
}),
|
||||||
|
type: 'success'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
queryClient.invalidateQueries(queryKey)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
onSuccess: (_, variables) => {
|
|
||||||
if (variables.message.succeed) {
|
|
||||||
haptics('Success')
|
|
||||||
displayMessage({
|
|
||||||
ref: variables.messageRef,
|
|
||||||
message: i18next.t('screenTabs:me.profile.feedback.succeed', {
|
|
||||||
type: i18next.t(`screenTabs:${variables.message.text}`)
|
|
||||||
}),
|
|
||||||
theme: variables.theme,
|
|
||||||
type: 'success'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onSettled: () => {
|
|
||||||
queryClient.invalidateQueries(queryKey)
|
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export { useProfileQuery, useProfileMutation }
|
export { useProfileQuery, useProfileMutation }
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import apiInstance from '@api/instance'
|
import apiInstance from '@api/instance'
|
||||||
import apiTooot, { TOOOT_API_DOMAIN } from '@api/tooot'
|
import apiTooot, { TOOOT_API_DOMAIN } from '@api/tooot'
|
||||||
|
import { displayMessage } from '@components/Message'
|
||||||
import i18n from '@root/i18n/i18n'
|
import i18n from '@root/i18n/i18n'
|
||||||
import { RootState } from '@root/store'
|
import { RootState } from '@root/store'
|
||||||
import * as Sentry from '@sentry/react-native'
|
import * as Sentry from '@sentry/react-native'
|
||||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||||
import { getInstance } from '@utils/slices/instancesSlice'
|
import { getInstance } from '@utils/slices/instancesSlice'
|
||||||
|
import { Theme } from '@utils/styles/themes'
|
||||||
import * as Notifications from 'expo-notifications'
|
import * as Notifications from 'expo-notifications'
|
||||||
import * as Random from 'expo-random'
|
import * as Random from 'expo-random'
|
||||||
|
import i18next from 'i18next'
|
||||||
import { Platform } from 'react-native'
|
import { Platform } from 'react-native'
|
||||||
import base64 from 'react-native-base64'
|
import base64 from 'react-native-base64'
|
||||||
import androidDefaults from './androidDefaults'
|
import androidDefaults from './androidDefaults'
|
||||||
@ -74,6 +77,12 @@ const pushRegister = async (
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!res.body.server_key?.length) {
|
if (!res.body.server_key?.length) {
|
||||||
|
displayMessage({
|
||||||
|
type: 'danger',
|
||||||
|
duration: 'long',
|
||||||
|
message: i18next.t('screenTabs:me.push.missingServerKey.message'),
|
||||||
|
description: i18next.t('screenTabs:me.push.missingServerKey.description')
|
||||||
|
})
|
||||||
Sentry.setContext('Push server key', {
|
Sentry.setContext('Push server key', {
|
||||||
instance: instanceUri,
|
instance: instanceUri,
|
||||||
resBody: res.body
|
resBody: res.body
|
||||||
|
Reference in New Issue
Block a user