Merge branch 'main' into candidate

This commit is contained in:
xmflsct 2022-11-23 21:32:12 +01:00
commit 6ba272c628
6 changed files with 80 additions and 96 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "tooot", "name": "tooot",
"version": "4.6.3", "version": "4.6.4",
"description": "tooot for Mastodon", "description": "tooot for Mastodon",
"author": "xmflsct <me@xmflsct.com>", "author": "xmflsct <me@xmflsct.com>",
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",

View File

@ -50,9 +50,9 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
// Push hooks // Push hooks
const instances = useSelector(getInstances, (prev, next) => prev.length === next.length) const instances = useSelector(getInstances, (prev, next) => prev.length === next.length)
pushUseConnect({ t, instances }) pushUseConnect()
pushUseReceive({ instances }) pushUseReceive()
pushUseRespond({ instances }) pushUseRespond()
// Prevent screenshot alert // Prevent screenshot alert
useEffect(() => { useEffect(() => {

View File

@ -12,7 +12,6 @@ export type Params = {
} }
headers?: { [key: string]: string } headers?: { [key: string]: string }
body?: FormData | Object body?: FormData | Object
sentry?: boolean
} }
export const TOOOT_API_DOMAIN = mapEnvironment({ export const TOOOT_API_DOMAIN = mapEnvironment({
@ -26,16 +25,15 @@ const apiTooot = async <T = unknown>({
url, url,
params, params,
headers, headers,
body, body
sentry = true
}: Params): Promise<{ body: T }> => { }: Params): Promise<{ body: T }> => {
console.log( console.log(
ctx.bgGreen.bold(' API tooot ') + ctx.bgGreen.bold(' API tooot ') +
' ' + ' ' +
method + method +
ctx.green(' -> ') + ctx.green(' -> ') +
`/${url}` + `/${url}` +
(params ? ctx.green(' -> ') : ''), (params ? ctx.green(' -> ') : ''),
params ? params : '' params ? params : ''
) )
@ -46,10 +44,7 @@ const apiTooot = async <T = unknown>({
url: `${url}`, url: `${url}`,
params, params,
headers: { headers: {
'Content-Type': 'Content-Type': body && body instanceof FormData ? 'multipart/form-data' : 'application/json',
body && body instanceof FormData
? 'multipart/form-data'
: 'application/json',
Accept: '*/*', Accept: '*/*',
...userAgent, ...userAgent,
...headers ...headers
@ -62,14 +57,14 @@ const apiTooot = async <T = unknown>({
}) })
}) })
.catch(error => { .catch(error => {
if (sentry) { Sentry.setExtras({
Sentry.setExtras({ API: 'tooot',
API: 'tooot', request: { url, params, body },
...(error?.response && { response: error.response }), ...(error?.response && { response: error.response })
...(error?.request && { request: error.request }) })
}) Sentry.captureMessage('API error', {
Sentry.captureException(error) contexts: { errorObject: error }
} })
return handleError(error) return handleError(error)
}) })

View File

@ -4,44 +4,43 @@ import { displayMessage } from '@components/Message'
import navigationRef from '@helpers/navigationRef' import navigationRef from '@helpers/navigationRef'
import { useAppDispatch } from '@root/store' import { useAppDispatch } 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 { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice' import { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice'
import { disableAllPushes } from '@utils/slices/instancesSlice' import { disableAllPushes, getInstances } from '@utils/slices/instancesSlice'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import * as Notifications from 'expo-notifications' import * as Notifications from 'expo-notifications'
import { TFunction } from 'i18next'
import { useEffect } from 'react' import { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { AppState } from 'react-native' import { AppState } from 'react-native'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
export interface Params { const pushUseConnect = () => {
t: TFunction<'screens'> const { t } = useTranslation('screen')
instances: InstanceLatest[]
}
const pushUseConnect = ({ t, instances }: Params) => {
const dispatch = useAppDispatch()
const { theme } = useTheme() const { theme } = useTheme()
const dispatch = useAppDispatch()
useEffect(() => { useEffect(() => {
dispatch(retrieveExpoToken()) dispatch(retrieveExpoToken())
}, []) }, [])
const expoToken = useSelector(getExpoToken) const expoToken = useSelector(getExpoToken)
const instances = useSelector(getInstances, (prev, next) => prev.length === next.length)
const pushEnabled = instances.filter(instance => instance.push.global.value)
const connect = () => { const connect = () => {
apiTooot({ apiTooot({
method: 'get', method: 'get',
url: `push/connect/${expoToken}`, url: `/push/connect/${expoToken}`
sentry: true
}) })
.then(() => Notifications.setBadgeCountAsync(0)) .then(() => Notifications.setBadgeCountAsync(0))
.catch(error => { .catch(error => {
Sentry.setExtras({ Sentry.setExtras({
API: 'tooot', API: 'tooot',
...(error?.response && { response: error.response }), expoToken,
...(error?.request && { request: error.request }) ...(error?.response && { response: error.response })
})
Sentry.captureMessage('Push connect error', {
contexts: { errorObject: error }
}) })
Sentry.captureException(error)
Notifications.setBadgeCountAsync(0) Notifications.setBadgeCountAsync(0)
if (error?.status == 404) { if (error?.status == 404) {
displayMessage({ displayMessage({
@ -84,9 +83,16 @@ const pushUseConnect = ({ t, instances }: Params) => {
}) })
} }
const pushEnabled = instances.filter(instance => instance.push.global.value)
useEffect(() => { useEffect(() => {
Sentry.setExtras({
expoToken,
pushEnabledCount: pushEnabled
})
if (expoToken && pushEnabled.length) {
connect()
}
const appStateListener = AppState.addEventListener('change', state => { const appStateListener = AppState.addEventListener('change', state => {
if (expoToken && pushEnabled.length && state === 'active') { if (expoToken && pushEnabled.length && state === 'active') {
Notifications.getBadgeCountAsync().then(count => { Notifications.getBadgeCountAsync().then(count => {
@ -101,12 +107,6 @@ const pushUseConnect = ({ t, instances }: Params) => {
appStateListener.remove() appStateListener.remove()
} }
}, [expoToken, pushEnabled.length]) }, [expoToken, pushEnabled.length])
return useEffect(() => {
if (expoToken && pushEnabled.length) {
connect()
}
}, [expoToken, pushEnabled.length])
} }
export default pushUseConnect export default pushUseConnect

View File

@ -1,52 +1,45 @@
import { displayMessage } from '@components/Message' import { displayMessage } from '@components/Message'
import queryClient from '@helpers/queryClient' import queryClient from '@helpers/queryClient'
import initQuery from '@utils/initQuery' import initQuery from '@utils/initQuery'
import { InstanceLatest } from '@utils/migrations/instances/migration'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline' import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { getInstances } from '@utils/slices/instancesSlice'
import * as Notifications from 'expo-notifications' import * as Notifications from 'expo-notifications'
import { useEffect } from 'react' import { useEffect } from 'react'
import { useSelector } from 'react-redux'
import pushUseNavigate from './useNavigate' import pushUseNavigate from './useNavigate'
export interface Params { const pushUseReceive = () => {
instances: InstanceLatest[] const instances = useSelector(getInstances, (prev, next) => prev.length === next.length)
}
const pushUseReceive = ({ instances }: Params) => { useEffect(() => {
return useEffect(() => { const subscription = Notifications.addNotificationReceivedListener(notification => {
const subscription = Notifications.addNotificationReceivedListener( const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Notifications' }]
notification => { queryClient.invalidateQueries(queryKey)
const queryKey: QueryKeyTimeline = [ const payloadData = notification.request.content.data as {
'Timeline', notification_id?: string
{ page: 'Notifications' } instanceUrl: string
] accountId: string
queryClient.invalidateQueries(queryKey)
const payloadData = notification.request.content.data as {
notification_id?: string
instanceUrl: string
accountId: string
}
const notificationIndex = instances.findIndex(
instance =>
instance.url === payloadData.instanceUrl &&
instance.account.id === payloadData.accountId
)
displayMessage({
duration: 'long',
message: notification.request.content.title!,
description: notification.request.content.body!,
onPress: () => {
if (notificationIndex !== -1) {
initQuery({
instance: instances[notificationIndex],
prefetch: { enabled: true }
})
}
pushUseNavigate(payloadData.notification_id)
}
})
} }
)
const notificationIndex = instances.findIndex(
instance =>
instance.url === payloadData.instanceUrl && instance.account.id === payloadData.accountId
)
displayMessage({
duration: 'long',
message: notification.request.content.title!,
description: notification.request.content.body!,
onPress: () => {
if (notificationIndex !== -1) {
initQuery({
instance: instances[notificationIndex],
prefetch: { enabled: true }
})
}
pushUseNavigate(payloadData.notification_id)
}
})
})
return () => subscription.remove() return () => subscription.remove()
}, [instances]) }, [instances])
} }

View File

@ -1,23 +1,19 @@
import queryClient from '@helpers/queryClient' import queryClient from '@helpers/queryClient'
import initQuery from '@utils/initQuery' import initQuery from '@utils/initQuery'
import { InstanceLatest } from '@utils/migrations/instances/migration'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline' import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { getInstances } from '@utils/slices/instancesSlice'
import * as Notifications from 'expo-notifications' import * as Notifications from 'expo-notifications'
import { useEffect } from 'react' import { useEffect } from 'react'
import { useSelector } from 'react-redux'
import pushUseNavigate from './useNavigate' import pushUseNavigate from './useNavigate'
export interface Params { const pushUseRespond = () => {
instances: InstanceLatest[] const instances = useSelector(getInstances, (prev, next) => prev.length === next.length)
}
const pushUseRespond = ({ instances }: Params) => { useEffect(() => {
return useEffect(() => {
const subscription = Notifications.addNotificationResponseReceivedListener( const subscription = Notifications.addNotificationResponseReceivedListener(
({ notification }) => { ({ notification }) => {
const queryKey: QueryKeyTimeline = [ const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Notifications' }]
'Timeline',
{ page: 'Notifications' }
]
queryClient.invalidateQueries(queryKey) queryClient.invalidateQueries(queryKey)
const payloadData = notification.request.content.data as { const payloadData = notification.request.content.data as {
notification_id?: string notification_id?: string