mirror of
https://github.com/tooot-app/app
synced 2025-04-15 10:47:46 +02:00
Push error tolerance
This commit is contained in:
parent
32aaf08574
commit
82cefdc80c
@ -58,7 +58,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
|
|
||||||
// Update Expo Token to server
|
// Update Expo Token to server
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(connectInstancesPush())
|
dispatch(connectInstancesPush({ mode, t }))
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// Prevent screenshot alert
|
// Prevent screenshot alert
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
export default {
|
export default {
|
||||||
heading: '推送通知',
|
heading: '推送通知',
|
||||||
content: {
|
content: {
|
||||||
|
enable: {
|
||||||
|
direct: '启用tooot推送通知',
|
||||||
|
settings: '去系统设置启用'
|
||||||
|
},
|
||||||
global: {
|
global: {
|
||||||
heading: '启用通知',
|
heading: '启用通知',
|
||||||
description: '通知消息将经由tooot服务器转发'
|
description: '通知消息将经由tooot服务器转发'
|
||||||
},
|
},
|
||||||
decode: {
|
decode: {
|
||||||
heading: '显示通知内容',
|
heading: '显示通知内容',
|
||||||
description: '经由tooot服务器中转的通知消息已被加密,但可以允许tooot服务器解密并转发消息。tooot消息服务器源码开源,且不留存任何日志。'
|
description:
|
||||||
|
'经由tooot服务器中转的通知消息已被加密,但可以允许tooot服务器解密并转发消息。tooot消息服务器源码开源,且不留存任何日志。'
|
||||||
},
|
},
|
||||||
follow: {
|
follow: {
|
||||||
heading: '新关注者'
|
heading: '新关注者'
|
||||||
@ -25,5 +30,9 @@ export default {
|
|||||||
heading: '投票'
|
heading: '投票'
|
||||||
},
|
},
|
||||||
howitworks: '了解通知消息转发如何工作'
|
howitworks: '了解通知消息转发如何工作'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
message: '推送服务器错误',
|
||||||
|
description: '请在设置中重新尝试启用推送通知'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,39 @@ import { updateInstancePushAlert } from '@utils/slices/instances/updatePushAlert
|
|||||||
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
|
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
|
||||||
import { getInstancePush } from '@utils/slices/instancesSlice'
|
import { getInstancePush } from '@utils/slices/instancesSlice'
|
||||||
import * as WebBrowser from 'expo-web-browser'
|
import * as WebBrowser from 'expo-web-browser'
|
||||||
import React, { useMemo } from 'react'
|
import * as Notifications from 'expo-notifications'
|
||||||
|
import React, { useEffect, useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ScrollView } from 'react-native-gesture-handler'
|
import { ScrollView } from 'react-native-gesture-handler'
|
||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
|
import layoutAnimation from '@utils/styles/layoutAnimation'
|
||||||
|
import Button from '@components/Button'
|
||||||
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
|
import { AppState, Linking } from 'react-native'
|
||||||
|
|
||||||
const ScreenMeSettingsPush: React.FC = () => {
|
const ScreenMeSettingsPush: React.FC = () => {
|
||||||
const { t } = useTranslation('meSettingsPush')
|
const { t } = useTranslation('meSettingsPush')
|
||||||
|
|
||||||
|
const [appStateVisible, setAppStateVisible] = useState(AppState.currentState)
|
||||||
|
useEffect(() => {
|
||||||
|
AppState.addEventListener('change', state => setAppStateVisible(state))
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
AppState.removeEventListener('change', state => setAppStateVisible(state))
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
const [pushEnabled, setPushEnabled] = useState<boolean>()
|
||||||
|
const [pushCanAskAgain, setPushCanAskAgain] = useState<boolean>()
|
||||||
|
useEffect(() => {
|
||||||
|
const checkPush = async () => {
|
||||||
|
const settings = await Notifications.getPermissionsAsync()
|
||||||
|
layoutAnimation()
|
||||||
|
setPushEnabled(settings.granted)
|
||||||
|
setPushCanAskAgain(settings.canAskAgain)
|
||||||
|
}
|
||||||
|
checkPush()
|
||||||
|
}, [appStateVisible])
|
||||||
|
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const instancePush = useSelector(getInstancePush)
|
const instancePush = useSelector(getInstancePush)
|
||||||
|
|
||||||
@ -28,7 +54,9 @@ const ScreenMeSettingsPush: React.FC = () => {
|
|||||||
<MenuRow
|
<MenuRow
|
||||||
key={alert}
|
key={alert}
|
||||||
title={t(`content.${alert}.heading`)}
|
title={t(`content.${alert}.heading`)}
|
||||||
switchDisabled={!instancePush.global.value || isLoading}
|
switchDisabled={
|
||||||
|
!pushEnabled || !instancePush.global.value || isLoading
|
||||||
|
}
|
||||||
switchValue={instancePush?.alerts[alert].value}
|
switchValue={instancePush?.alerts[alert].value}
|
||||||
switchOnValueChange={() =>
|
switchOnValueChange={() =>
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -51,13 +79,40 @@ const ScreenMeSettingsPush: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
|
{pushEnabled === false ? (
|
||||||
|
<MenuContainer>
|
||||||
|
<Button
|
||||||
|
type='text'
|
||||||
|
content={
|
||||||
|
pushCanAskAgain
|
||||||
|
? t('content.enable.direct')
|
||||||
|
: t('content.enable.settings')
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
marginTop: StyleConstants.Spacing.Global.PagePadding,
|
||||||
|
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
|
||||||
|
}}
|
||||||
|
onPress={async () => {
|
||||||
|
if (pushCanAskAgain) {
|
||||||
|
const result = await Notifications.requestPermissionsAsync()
|
||||||
|
setPushEnabled(result.granted)
|
||||||
|
setPushCanAskAgain(result.canAskAgain)
|
||||||
|
} else {
|
||||||
|
Linking.openURL('app-settings:')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</MenuContainer>
|
||||||
|
) : null}
|
||||||
<MenuContainer>
|
<MenuContainer>
|
||||||
<MenuRow
|
<MenuRow
|
||||||
title={t('content.global.heading')}
|
title={t('content.global.heading')}
|
||||||
description={t('content.global.description')}
|
description={t('content.global.description')}
|
||||||
loading={instancePush?.global.loading}
|
loading={instancePush?.global.loading}
|
||||||
switchDisabled={isLoading}
|
switchDisabled={!pushEnabled || isLoading}
|
||||||
switchValue={instancePush?.global.value}
|
switchValue={
|
||||||
|
pushEnabled === false ? false : instancePush?.global.value
|
||||||
|
}
|
||||||
switchOnValueChange={() =>
|
switchOnValueChange={() =>
|
||||||
dispatch(updateInstancePush(!instancePush?.global.value))
|
dispatch(updateInstancePush(!instancePush?.global.value))
|
||||||
}
|
}
|
||||||
@ -68,7 +123,9 @@ const ScreenMeSettingsPush: React.FC = () => {
|
|||||||
title={t('content.decode.heading')}
|
title={t('content.decode.heading')}
|
||||||
description={t('content.decode.description')}
|
description={t('content.decode.description')}
|
||||||
loading={instancePush?.decode.loading}
|
loading={instancePush?.decode.loading}
|
||||||
switchDisabled={!instancePush?.global.value || isLoading}
|
switchDisabled={
|
||||||
|
!pushEnabled || !instancePush?.global.value || isLoading
|
||||||
|
}
|
||||||
switchValue={instancePush?.decode.value}
|
switchValue={instancePush?.decode.value}
|
||||||
switchOnValueChange={() =>
|
switchOnValueChange={() =>
|
||||||
dispatch(updateInstancePushDecode(!instancePush?.decode.value))
|
dispatch(updateInstancePushDecode(!instancePush?.decode.value))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Button from '@components/Button'
|
import Button from '@components/Button'
|
||||||
import haptics from '@root/components/haptics'
|
import haptics from '@root/components/haptics'
|
||||||
import removeInstance from '@utils/slices/instances/remove'
|
import removeInstance from '@utils/slices/instances/remove'
|
||||||
import { getInstance, getInstanceActive } from '@utils/slices/instancesSlice'
|
import { getInstance } from '@utils/slices/instancesSlice'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
@ -2,11 +2,15 @@ import apiGeneral from '@api/general'
|
|||||||
import { createAsyncThunk } from '@reduxjs/toolkit'
|
import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||||
import { RootState } from '@root/store'
|
import { RootState } from '@root/store'
|
||||||
import * as Notifications from 'expo-notifications'
|
import * as Notifications from 'expo-notifications'
|
||||||
|
import { TFunction } from 'react-i18next'
|
||||||
import { PUSH_SERVER } from '../instancesSlice'
|
import { PUSH_SERVER } from '../instancesSlice'
|
||||||
|
|
||||||
export const connectInstancesPush = createAsyncThunk(
|
export const connectInstancesPush = createAsyncThunk(
|
||||||
'instances/connectPush',
|
'instances/connectPush',
|
||||||
async (_, { getState }): Promise<any> => {
|
async (
|
||||||
|
{ mode, t }: { mode: 'light' | 'dark'; t: TFunction<'common'> },
|
||||||
|
{ getState }
|
||||||
|
): Promise<any> => {
|
||||||
const state = getState() as RootState
|
const state = getState() as RootState
|
||||||
const pushEnabled = state.instances.instances.filter(
|
const pushEnabled = state.instances.instances.filter(
|
||||||
instance => instance.push.global.value
|
instance => instance.push.global.value
|
||||||
|
@ -110,16 +110,30 @@ const pushRegister = async (
|
|||||||
removeKeys: instancePush.decode.value === false
|
removeKeys: instancePush.decode.value === false
|
||||||
})
|
})
|
||||||
|
|
||||||
return Promise.resolve(serverRes.body.keys)
|
if (Platform.OS === 'android') {
|
||||||
|
Notifications.setNotificationChannelAsync('follow', {
|
||||||
|
name: 'Follow',
|
||||||
|
importance: Notifications.AndroidImportance.DEFAULT
|
||||||
|
})
|
||||||
|
Notifications.setNotificationChannelAsync('favourite', {
|
||||||
|
name: 'Favourite',
|
||||||
|
importance: Notifications.AndroidImportance.DEFAULT
|
||||||
|
})
|
||||||
|
Notifications.setNotificationChannelAsync('reblog', {
|
||||||
|
name: 'Reblog',
|
||||||
|
importance: Notifications.AndroidImportance.DEFAULT
|
||||||
|
})
|
||||||
|
Notifications.setNotificationChannelAsync('mention', {
|
||||||
|
name: 'Mention',
|
||||||
|
importance: Notifications.AndroidImportance.DEFAULT
|
||||||
|
})
|
||||||
|
Notifications.setNotificationChannelAsync('poll', {
|
||||||
|
name: 'Poll',
|
||||||
|
importance: Notifications.AndroidImportance.DEFAULT
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// if (Platform.OS === 'android') {
|
return Promise.resolve(serverRes.body.keys)
|
||||||
// Notifications.setNotificationChannelAsync('default', {
|
|
||||||
// name: 'default',
|
|
||||||
// importance: Notifications.AndroidImportance.MAX,
|
|
||||||
// vibrationPattern: [0, 250, 250, 250],
|
|
||||||
// lightColor: '#FF231F7C'
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default pushRegister
|
export default pushRegister
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import analytics from '@components/analytics'
|
import analytics from '@components/analytics'
|
||||||
|
import { displayMessage } from '@components/Message'
|
||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||||
import { RootState } from '@root/store'
|
import { RootState } from '@root/store'
|
||||||
import { ComposeStateDraft } from '@screens/Compose/utils/types'
|
import { ComposeStateDraft } from '@screens/Compose/utils/types'
|
||||||
import { findIndex } from 'lodash'
|
import { findIndex } from 'lodash'
|
||||||
|
import { Appearance } from 'react-native'
|
||||||
import addInstance from './instances/add'
|
import addInstance from './instances/add'
|
||||||
|
import { connectInstancesPush } from './instances/connectPush'
|
||||||
import removeInstance from './instances/remove'
|
import removeInstance from './instances/remove'
|
||||||
import { updateAccountPreferences } from './instances/updateAccountPreferences'
|
import { updateAccountPreferences } from './instances/updateAccountPreferences'
|
||||||
import { updateInstancePush } from './instances/updatePush'
|
import { updateInstancePush } from './instances/updatePush'
|
||||||
@ -264,6 +267,22 @@ const instancesSlice = createSlice({
|
|||||||
action.meta.arg.changed
|
action.meta.arg.changed
|
||||||
].loading = true
|
].loading = true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// If Expo token does not exist on the server, disable all existing ones
|
||||||
|
.addCase(connectInstancesPush.rejected, (state, action) => {
|
||||||
|
state.instances = state.instances.map(instance => {
|
||||||
|
let newInstance = instance
|
||||||
|
newInstance.push.global.value = false
|
||||||
|
displayMessage({
|
||||||
|
mode: action.meta.arg.mode,
|
||||||
|
type: 'error',
|
||||||
|
autoHide: false,
|
||||||
|
message: action.meta.arg.t('meSettingsPush:error.message'),
|
||||||
|
description: action.meta.arg.t('meSettingsPush:error.description')
|
||||||
|
})
|
||||||
|
return newInstance
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user