mirror of https://github.com/tooot-app/app
Allow push count badge
This commit is contained in:
parent
9b109ba1bb
commit
31a3e87963
15
src/App.tsx
15
src/App.tsx
|
@ -17,10 +17,9 @@ import {
|
|||
} from '@utils/slices/settingsSlice'
|
||||
import ThemeManager from '@utils/styles/ThemeManager'
|
||||
import 'expo-asset'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import * as SplashScreen from 'expo-splash-screen'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import { AppState, LogBox, Platform } from 'react-native'
|
||||
import { LogBox, Platform } from 'react-native'
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
||||
import 'react-native-image-keyboard'
|
||||
import { enableFreeze } from 'react-native-screens'
|
||||
|
@ -44,18 +43,6 @@ const App: React.FC = () => {
|
|||
log('log', 'App', 'rendering App')
|
||||
const [localCorrupt, setLocalCorrupt] = useState<string>()
|
||||
|
||||
const appStateEffect = useCallback(() => {
|
||||
Notifications.setBadgeCountAsync(0)
|
||||
Notifications.dismissAllNotificationsAsync()
|
||||
}, [])
|
||||
useEffect(() => {
|
||||
const appStateListener = AppState.addEventListener('change', appStateEffect)
|
||||
|
||||
return () => {
|
||||
appStateListener.remove()
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const delaySplash = async () => {
|
||||
log('log', 'App', 'delay splash')
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
import {
|
||||
getVersionUpdate,
|
||||
retriveVersionLatest
|
||||
} from '@utils/slices/versionSlice'
|
||||
} from '@utils/slices/appSlice'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback, useEffect, useMemo } from 'react'
|
||||
import { Platform } from 'react-native'
|
||||
|
|
|
@ -5,6 +5,7 @@ import { MenuContainer, MenuRow } from '@components/Menu'
|
|||
import CustomText from '@components/Text'
|
||||
import { useAppDispatch } from '@root/store'
|
||||
import { isDevelopment } from '@utils/checkEnvironment'
|
||||
import { getExpoToken } from '@utils/slices/appSlice'
|
||||
import { updateInstancePush } from '@utils/slices/instances/updatePush'
|
||||
import { updateInstancePushAlert } from '@utils/slices/instances/updatePushAlert'
|
||||
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
|
||||
|
@ -45,16 +46,12 @@ const TabMePush: React.FC = () => {
|
|||
setPushEnabled(settings.granted)
|
||||
setPushCanAskAgain(settings.canAskAgain)
|
||||
}
|
||||
const expoToken = useSelector(getExpoToken)
|
||||
useEffect(() => {
|
||||
if (isDevelopment) {
|
||||
setPushAvailable(true)
|
||||
} else {
|
||||
Notifications.getExpoPushTokenAsync({
|
||||
experienceId: '@xmflsct/tooot',
|
||||
applicationId: 'com.xmflsct.app.tooot'
|
||||
})
|
||||
.then(data => setPushAvailable(!!data))
|
||||
.catch(() => setPushAvailable(false))
|
||||
setPushAvailable(!!expoToken)
|
||||
}
|
||||
|
||||
checkPush()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||
import { getVersionUpdate } from '@utils/slices/versionSlice'
|
||||
import { getVersionUpdate } from '@utils/slices/appSlice'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Linking, Platform } from 'react-native'
|
||||
|
|
|
@ -4,10 +4,10 @@ import { AnyAction, configureStore, Reducer } from '@reduxjs/toolkit'
|
|||
import contextsMigration from '@utils/migrations/contexts/migration'
|
||||
import instancesMigration from '@utils/migrations/instances/migration'
|
||||
import settingsMigration from '@utils/migrations/settings/migration'
|
||||
import appSlice from '@utils/slices/appSlice'
|
||||
import contextsSlice, { ContextsState } from '@utils/slices/contextsSlice'
|
||||
import instancesSlice, { InstancesState } from '@utils/slices/instancesSlice'
|
||||
import settingsSlice, { SettingsState } from '@utils/slices/settingsSlice'
|
||||
import versionSlice from '@utils/slices/versionSlice'
|
||||
import { Platform } from 'react-native'
|
||||
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
|
||||
import {
|
||||
|
@ -67,7 +67,7 @@ const store = configureStore({
|
|||
SettingsState,
|
||||
AnyAction
|
||||
>,
|
||||
version: versionSlice
|
||||
app: appSlice
|
||||
},
|
||||
middleware: getDefaultMiddleware =>
|
||||
getDefaultMiddleware({
|
||||
|
|
|
@ -3,13 +3,15 @@ import apiTooot from '@api/tooot'
|
|||
import { displayMessage } from '@components/Message'
|
||||
import navigationRef from '@helpers/navigationRef'
|
||||
import { useAppDispatch } from '@root/store'
|
||||
import { isDevelopment } from '@utils/checkEnvironment'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
import { getExpoToken, retriveExpoToken } from '@utils/slices/appSlice'
|
||||
import { disableAllPushes } from '@utils/slices/instancesSlice'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import { useEffect } from 'react'
|
||||
import { TFunction } from 'react-i18next'
|
||||
import { AppState } from 'react-native'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
export interface Params {
|
||||
t: TFunction<'screens'>
|
||||
|
@ -19,69 +21,84 @@ export interface Params {
|
|||
const pushUseConnect = ({ t, instances }: Params) => {
|
||||
const dispatch = useAppDispatch()
|
||||
const { theme } = useTheme()
|
||||
useEffect(() => {
|
||||
dispatch(retriveExpoToken())
|
||||
}, [])
|
||||
|
||||
const expoToken = useSelector(getExpoToken)
|
||||
|
||||
const connect = () => {
|
||||
apiTooot({
|
||||
method: 'get',
|
||||
url: `push/connect/${expoToken}`,
|
||||
sentry: true
|
||||
}).catch(error => {
|
||||
if (error?.status == 404) {
|
||||
displayMessage({
|
||||
theme,
|
||||
type: 'error',
|
||||
duration: 'long',
|
||||
message: t('pushError.message'),
|
||||
description: t('pushError.description'),
|
||||
onPress: () => {
|
||||
navigationRef.navigate('Screen-Tabs', {
|
||||
screen: 'Tab-Me',
|
||||
params: {
|
||||
screen: 'Tab-Me-Root'
|
||||
}
|
||||
})
|
||||
navigationRef.navigate('Screen-Tabs', {
|
||||
screen: 'Tab-Me',
|
||||
params: {
|
||||
screen: 'Tab-Me-Settings'
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
dispatch(disableAllPushes())
|
||||
|
||||
instances.forEach(instance => {
|
||||
if (instance.push.global.value) {
|
||||
apiGeneral<{}>({
|
||||
method: 'delete',
|
||||
domain: instance.url,
|
||||
url: 'api/v1/push/subscription',
|
||||
headers: {
|
||||
Authorization: `Bearer ${instance.token}`
|
||||
}
|
||||
}).catch(() => console.log('error!!!'))
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const pushEnabled = instances.filter(instance => instance.push.global.value)
|
||||
|
||||
useEffect(() => {
|
||||
const appStateListener = AppState.addEventListener('change', state => {
|
||||
console.log('changing state to', state)
|
||||
if (expoToken && pushEnabled.length && state === 'active') {
|
||||
Notifications.getBadgeCountAsync().then(count => {
|
||||
if (count > 0) {
|
||||
Notifications.setBadgeCountAsync(0)
|
||||
connect()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return () => {
|
||||
appStateListener.remove()
|
||||
}
|
||||
}, [expoToken, pushEnabled.length])
|
||||
|
||||
return useEffect(() => {
|
||||
const connect = async () => {
|
||||
const expoToken = isDevelopment
|
||||
? 'DEVELOPMENT_TOKEN_1'
|
||||
: (
|
||||
await Notifications.getExpoPushTokenAsync({
|
||||
experienceId: '@xmflsct/tooot',
|
||||
applicationId: 'com.xmflsct.app.tooot'
|
||||
})
|
||||
).data
|
||||
|
||||
apiTooot({
|
||||
method: 'get',
|
||||
url: `push/connect/${expoToken}`,
|
||||
sentry: true
|
||||
}).catch(error => {
|
||||
if (error?.status == 404) {
|
||||
displayMessage({
|
||||
theme,
|
||||
type: 'error',
|
||||
duration: 'long',
|
||||
message: t('pushError.message'),
|
||||
description: t('pushError.description'),
|
||||
onPress: () => {
|
||||
navigationRef.navigate('Screen-Tabs', {
|
||||
screen: 'Tab-Me',
|
||||
params: {
|
||||
screen: 'Tab-Me-Root'
|
||||
}
|
||||
})
|
||||
navigationRef.navigate('Screen-Tabs', {
|
||||
screen: 'Tab-Me',
|
||||
params: {
|
||||
screen: 'Tab-Me-Settings'
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
dispatch(disableAllPushes())
|
||||
|
||||
instances.forEach(instance => {
|
||||
if (instance.push.global.value) {
|
||||
apiGeneral<{}>({
|
||||
method: 'delete',
|
||||
domain: instance.url,
|
||||
url: 'api/v1/push/subscription',
|
||||
headers: {
|
||||
Authorization: `Bearer ${instance.token}`
|
||||
}
|
||||
}).catch(() => console.log('error!!!'))
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const pushEnabled = instances.filter(instance => instance.push.global.value)
|
||||
if (pushEnabled.length) {
|
||||
if (expoToken && pushEnabled.length) {
|
||||
connect()
|
||||
}
|
||||
}, [instances])
|
||||
}, [expoToken, pushEnabled.length])
|
||||
}
|
||||
|
||||
export default pushUseConnect
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
import apiGeneral from '@api/general'
|
||||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
|
||||
import { RootState } from '@root/store'
|
||||
import { isDevelopment } from '@utils/checkEnvironment'
|
||||
import Constants from 'expo-constants'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
|
||||
export const retriveExpoToken = createAsyncThunk(
|
||||
'app/expoToken',
|
||||
async (): Promise<string> => {
|
||||
if (isDevelopment) {
|
||||
return 'DEVELOPMENT_TOKEN_1'
|
||||
}
|
||||
|
||||
const res = await Notifications.getExpoPushTokenAsync({
|
||||
experienceId: '@xmflsct/tooot',
|
||||
applicationId: 'com.xmflsct.app.tooot'
|
||||
})
|
||||
return res.data
|
||||
}
|
||||
)
|
||||
|
||||
export const retriveVersionLatest = createAsyncThunk(
|
||||
'app/versionUpdate',
|
||||
async (): Promise<string> => {
|
||||
const res = await apiGeneral<{ latest: string }>({
|
||||
method: 'get',
|
||||
domain: 'tooot.app',
|
||||
url: 'version.json'
|
||||
})
|
||||
return res.body.latest
|
||||
}
|
||||
)
|
||||
|
||||
export type AppState = {
|
||||
expoToken?: string
|
||||
versionUpdate: boolean
|
||||
}
|
||||
|
||||
export const appInitialState: AppState = {
|
||||
expoToken: undefined,
|
||||
versionUpdate: false
|
||||
}
|
||||
|
||||
const appSlice = createSlice({
|
||||
name: 'app',
|
||||
initialState: appInitialState,
|
||||
reducers: {},
|
||||
extraReducers: builder => {
|
||||
builder
|
||||
.addCase(retriveExpoToken.fulfilled, (state, action) => {
|
||||
if (action.payload) {
|
||||
state.expoToken = action.payload
|
||||
}
|
||||
})
|
||||
.addCase(retriveVersionLatest.fulfilled, (state, action) => {
|
||||
if (action.payload && Constants.manifest?.version) {
|
||||
if (
|
||||
parseFloat(action.payload) > parseFloat(Constants.manifest.version)
|
||||
) {
|
||||
state.versionUpdate = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
export const getExpoToken = (state: RootState) => state.app.expoToken
|
||||
export const getVersionUpdate = (state: RootState) => state.app.versionUpdate
|
||||
|
||||
export default appSlice.reducer
|
|
@ -48,8 +48,9 @@ const pushRegister = async (
|
|||
|
||||
const accountId = instanceAccount.id
|
||||
const accountFull = `@${instanceAccount.acct}@${instanceUri}`
|
||||
const randomPath = (Math.random() + 1).toString(36).substring(2)
|
||||
|
||||
const endpoint = `https://${TOOOT_API_DOMAIN}/push/send/${expoToken}/${instanceUrl}/${accountId}`
|
||||
const endpoint = `https://${TOOOT_API_DOMAIN}/push/send/${expoToken}/${instanceUrl}/${accountId}/${randomPath}`
|
||||
const auth = base64.encodeFromByteArray(Random.getRandomBytes(16))
|
||||
|
||||
const alerts = instancePush.alerts
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||
import { RootState } from '@root/store'
|
||||
import { isDevelopment } from '@utils/checkEnvironment'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import pushRegister from './push/register'
|
||||
import pushUnregister from './push/unregister'
|
||||
|
||||
|
@ -13,14 +11,10 @@ export const updateInstancePush = createAsyncThunk(
|
|||
{ getState }
|
||||
): Promise<InstanceLatest['push']['keys']['auth'] | undefined> => {
|
||||
const state = getState() as RootState
|
||||
const expoToken = isDevelopment
|
||||
? 'DEVELOPMENT_TOKEN_1'
|
||||
: (
|
||||
await Notifications.getExpoPushTokenAsync({
|
||||
experienceId: '@xmflsct/tooot',
|
||||
applicationId: 'com.xmflsct.app.tooot'
|
||||
})
|
||||
).data
|
||||
const expoToken = state.app.expoToken
|
||||
if (!expoToken) {
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
if (disable) {
|
||||
return await pushRegister(state, expoToken)
|
||||
|
|
|
@ -2,7 +2,6 @@ import apiTooot from '@api/tooot'
|
|||
import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||
import i18n from '@root/i18n/i18n'
|
||||
import { RootState } from '@root/store'
|
||||
import { isDevelopment } from '@utils/checkEnvironment'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import { Platform } from 'react-native'
|
||||
|
@ -21,14 +20,10 @@ export const updateInstancePushDecode = createAsyncThunk(
|
|||
return Promise.reject()
|
||||
}
|
||||
|
||||
const expoToken = isDevelopment
|
||||
? 'DEVELOPMENT_TOKEN_1'
|
||||
: (
|
||||
await Notifications.getExpoPushTokenAsync({
|
||||
experienceId: '@xmflsct/tooot',
|
||||
applicationId: 'com.xmflsct.app.tooot'
|
||||
})
|
||||
).data
|
||||
const expoToken = state.app.expoToken
|
||||
if (!expoToken) {
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
await apiTooot({
|
||||
method: 'put',
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
import apiGeneral from '@api/general'
|
||||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
|
||||
import { RootState } from '@root/store'
|
||||
import Constants from 'expo-constants'
|
||||
|
||||
export const retriveVersionLatest = createAsyncThunk(
|
||||
'version/latest',
|
||||
async () => {
|
||||
const res = await apiGeneral<{ latest: string }>({
|
||||
method: 'get',
|
||||
domain: 'tooot.app',
|
||||
url: 'version.json'
|
||||
})
|
||||
return res.body.latest
|
||||
}
|
||||
)
|
||||
|
||||
export type VersionState = {
|
||||
update: boolean
|
||||
}
|
||||
|
||||
export const versionInitialState = {
|
||||
update: false
|
||||
}
|
||||
|
||||
const versionSlice = createSlice({
|
||||
name: 'version',
|
||||
initialState: versionInitialState,
|
||||
reducers: {},
|
||||
extraReducers: builder => {
|
||||
builder.addCase(retriveVersionLatest.fulfilled, (state, action) => {
|
||||
if (action.payload && Constants.manifest?.version) {
|
||||
if (parseFloat(action.payload) > parseFloat(Constants.manifest.version)) {
|
||||
state.update = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
export const getVersionUpdate = (state: RootState) => state.version.update
|
||||
|
||||
export default versionSlice.reducer
|
Loading…
Reference in New Issue