mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
619 restructure local storage (#628)
* To MMKV migration working * POC migrated font size settings * Moved settings to mmkv * Fix typos * Migrated contexts slice * Migrated app slice * POC instance emoji update * Migrated drafts * Migrated simple instance properties * All migrated! * Re-structure files * Tolerant of undefined settings * Can properly logging in and out including empty state
This commit is contained in:
@ -1,40 +1,39 @@
|
||||
import Button from '@components/Button'
|
||||
import Icon from '@components/Icon'
|
||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||
import { displayMessage } from '@components/Message'
|
||||
import CustomText from '@components/Text'
|
||||
import browserPackage from '@helpers/browserPackage'
|
||||
import { useAppDispatch } from '@root/store'
|
||||
import { isDevelopment } from '@utils/checkEnvironment'
|
||||
import * as Sentry from '@sentry/react-native'
|
||||
import apiInstance from '@utils/api/instance'
|
||||
import apiTooot, { TOOOT_API_DOMAIN } from '@utils/api/tooot'
|
||||
import browserPackage from '@utils/helpers/browserPackage'
|
||||
import { isDevelopment } from '@utils/helpers/checkEnvironment'
|
||||
import { PUSH_ADMIN, PUSH_DEFAULT, setChannels } from '@utils/push/constants'
|
||||
import { updateExpoToken } from '@utils/push/updateExpoToken'
|
||||
import { useAppsQuery } from '@utils/queryHooks/apps'
|
||||
import { useProfileQuery } from '@utils/queryHooks/profile'
|
||||
import { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice'
|
||||
import { PUSH_ADMIN, PUSH_DEFAULT, usePushFeatures } from '@utils/slices/instances/push/utils'
|
||||
import { updateInstancePush } from '@utils/slices/instances/updatePush'
|
||||
import { updateInstancePushAlert } from '@utils/slices/instances/updatePushAlert'
|
||||
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
|
||||
import { getInstance, getInstancePush } from '@utils/slices/instancesSlice'
|
||||
import { setAccountStorage, useAccountStorage, useGlobalStorage } from '@utils/storage/actions'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import layoutAnimation from '@utils/styles/layoutAnimation'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import * as WebBrowser from 'expo-web-browser'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { AppState, Linking, ScrollView, View } from 'react-native'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { AppState, Linking, Platform, ScrollView, View } from 'react-native'
|
||||
|
||||
const TabMePush: React.FC = () => {
|
||||
const { colors } = useTheme()
|
||||
const { t } = useTranslation('screenTabs')
|
||||
|
||||
const instance = useSelector(getInstance)
|
||||
const expoToken = useSelector(getExpoToken)
|
||||
const [expoToken] = useGlobalStorage.string('app.expo_token')
|
||||
const [push] = useAccountStorage.object('push')
|
||||
const [domain] = useAccountStorage.string('auth.domain')
|
||||
const [accountId] = useAccountStorage.string('auth.account.id')
|
||||
const [accountAcct] = useAccountStorage.string('auth.account.acct')
|
||||
|
||||
const appsQuery = useAppsQuery()
|
||||
|
||||
const dispatch = useAppDispatch()
|
||||
const instancePush = useSelector(getInstancePush)
|
||||
|
||||
const [pushAvailable, setPushAvailable] = useState<boolean>()
|
||||
const [pushEnabled, setPushEnabled] = useState<boolean>()
|
||||
const [pushCanAskAgain, setPushCanAskAgain] = useState<boolean>()
|
||||
@ -45,7 +44,7 @@ const TabMePush: React.FC = () => {
|
||||
setPushEnabled(permissions.granted)
|
||||
setPushCanAskAgain(permissions.canAskAgain)
|
||||
layoutAnimation()
|
||||
dispatch(retrieveExpoToken())
|
||||
await updateExpoToken()
|
||||
}
|
||||
|
||||
if (appsQuery.data?.vapid_key) {
|
||||
@ -54,7 +53,7 @@ const TabMePush: React.FC = () => {
|
||||
if (isDevelopment) {
|
||||
setPushAvailable(true)
|
||||
} else {
|
||||
setPushAvailable(!!expoToken)
|
||||
setPushAvailable(!!expoToken?.length)
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,26 +63,29 @@ const TabMePush: React.FC = () => {
|
||||
}
|
||||
}, [appsQuery.data?.vapid_key])
|
||||
|
||||
const pushFeatures = usePushFeatures()
|
||||
|
||||
const alerts = () =>
|
||||
instancePush?.alerts
|
||||
? PUSH_DEFAULT(pushFeatures).map(alert => (
|
||||
push?.alerts
|
||||
? PUSH_DEFAULT.map(alert => (
|
||||
<MenuRow
|
||||
key={alert}
|
||||
title={t(`me.push.${alert}.heading`)}
|
||||
switchDisabled={!pushEnabled || !instancePush.global}
|
||||
switchValue={instancePush?.alerts[alert]}
|
||||
switchOnValueChange={() =>
|
||||
dispatch(
|
||||
updateInstancePushAlert({
|
||||
alerts: {
|
||||
...instancePush?.alerts,
|
||||
[alert]: !instancePush?.alerts[alert]
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
switchDisabled={!pushEnabled || !push.global}
|
||||
switchValue={push?.alerts[alert]}
|
||||
switchOnValueChange={async () => {
|
||||
const alerts = { ...push?.alerts, [alert]: !push?.alerts[alert] }
|
||||
const formData = new FormData()
|
||||
for (const [key, value] of Object.entries(alerts)) {
|
||||
formData.append(`data[alerts][${key}]`, value.toString())
|
||||
}
|
||||
|
||||
await apiInstance<Mastodon.PushSubscription>({
|
||||
method: 'put',
|
||||
url: 'push/subscription',
|
||||
body: formData
|
||||
})
|
||||
|
||||
setAccountStorage([{ key: 'push', value: { ...push, alerts } }])
|
||||
}}
|
||||
/>
|
||||
))
|
||||
: null
|
||||
@ -91,26 +93,34 @@ const TabMePush: React.FC = () => {
|
||||
const profileQuery = useProfileQuery()
|
||||
const adminAlerts = () =>
|
||||
profileQuery.data?.role?.permissions
|
||||
? PUSH_ADMIN(pushFeatures, profileQuery.data?.role?.permissions).map(({ type }) => (
|
||||
? PUSH_ADMIN.map(({ type }) => (
|
||||
<MenuRow
|
||||
key={type}
|
||||
title={t(`me.push.${type}.heading`)}
|
||||
switchDisabled={!pushEnabled || !instancePush.global}
|
||||
switchValue={instancePush?.alerts[type]}
|
||||
switchOnValueChange={() =>
|
||||
dispatch(
|
||||
updateInstancePushAlert({
|
||||
alerts: {
|
||||
...instancePush?.alerts,
|
||||
[type]: !instancePush?.alerts[type]
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
switchDisabled={!pushEnabled || !push.global}
|
||||
switchValue={push?.alerts[type]}
|
||||
switchOnValueChange={async () => {
|
||||
const alerts = { ...push?.alerts, [type]: !push?.alerts[type] }
|
||||
const formData = new FormData()
|
||||
for (const [key, value] of Object.entries(alerts)) {
|
||||
formData.append(`data[alerts][${key}]`, value.toString())
|
||||
}
|
||||
|
||||
await apiInstance<Mastodon.PushSubscription>({
|
||||
method: 'put',
|
||||
url: 'push/subscription',
|
||||
body: formData
|
||||
})
|
||||
|
||||
setAccountStorage([{ key: 'push', value: { ...push, alerts } }])
|
||||
}}
|
||||
/>
|
||||
))
|
||||
: null
|
||||
|
||||
const pushPath = `${expoToken}/${domain}/${accountId}`
|
||||
const accountFull = `@${accountAcct}@${domain}`
|
||||
|
||||
return (
|
||||
<ScrollView>
|
||||
{!!appsQuery.data?.vapid_key ? (
|
||||
@ -142,24 +152,103 @@ const TabMePush: React.FC = () => {
|
||||
) : null}
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={t('me.push.global.heading', {
|
||||
acct: `@${instance.account.acct}@${instance.uri}`
|
||||
})}
|
||||
title={t('me.push.global.heading', { acct: `@${accountAcct}@${domain}` })}
|
||||
description={t('me.push.global.description')}
|
||||
switchDisabled={!pushEnabled}
|
||||
switchValue={pushEnabled === false ? false : instancePush?.global}
|
||||
switchOnValueChange={() => dispatch(updateInstancePush(!instancePush?.global))}
|
||||
switchValue={pushEnabled === false ? false : push?.global}
|
||||
switchOnValueChange={async () => {
|
||||
if (push.global) {
|
||||
// Turning off
|
||||
await apiInstance({
|
||||
method: 'delete',
|
||||
url: 'push/subscription'
|
||||
})
|
||||
await apiTooot({
|
||||
method: 'delete',
|
||||
url: `push/unsubscribe/${pushPath}`
|
||||
})
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
Notifications.deleteNotificationChannelGroupAsync(accountFull)
|
||||
}
|
||||
|
||||
setAccountStorage([{ key: 'push', value: { ...push, global: false } }])
|
||||
} else {
|
||||
// Turning on
|
||||
const randomPath = (Math.random() + 1).toString(36).substring(2)
|
||||
|
||||
const endpoint = `https://${TOOOT_API_DOMAIN}/push/send/${pushPath}/${randomPath}`
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append('subscription[endpoint]', endpoint)
|
||||
formData.append(
|
||||
'subscription[keys][p256dh]',
|
||||
'BMn2PLpZrMefG981elzG6SB1EY9gU7QZwmtZ/a/J2vUeWG+zXgeskMPwHh4T/bxsD4l7/8QT94F57CbZqYRRfJo='
|
||||
)
|
||||
formData.append('subscription[keys][auth]', push.key)
|
||||
for (const [key, value] of Object.entries(push.alerts)) {
|
||||
formData.append(`data[alerts][${key}]`, value.toString())
|
||||
}
|
||||
|
||||
const res = await apiInstance<Mastodon.PushSubscription>({
|
||||
method: 'post',
|
||||
url: 'push/subscription',
|
||||
body: formData
|
||||
})
|
||||
|
||||
if (!res.body.server_key?.length) {
|
||||
displayMessage({
|
||||
type: 'danger',
|
||||
duration: 'long',
|
||||
message: t('me.push.missingServerKey.message'),
|
||||
description: t('me.push.missingServerKey.description')
|
||||
})
|
||||
Sentry.setContext('Push server key', {
|
||||
instance: domain,
|
||||
resBody: res.body
|
||||
})
|
||||
Sentry.captureMessage('Push register error')
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
await apiTooot({
|
||||
method: 'post',
|
||||
url: `push/subscribe/${pushPath}`,
|
||||
body: {
|
||||
accountFull,
|
||||
serverKey: res.body.server_key,
|
||||
auth: push.decode === false ? null : push.key
|
||||
}
|
||||
})
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
setChannels(true)
|
||||
}
|
||||
|
||||
setAccountStorage([{ key: 'push', value: { ...push, global: true } }])
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</MenuContainer>
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={t('me.push.decode.heading')}
|
||||
description={t('me.push.decode.description')}
|
||||
switchDisabled={!pushEnabled || !instancePush?.global}
|
||||
switchValue={instancePush?.decode}
|
||||
switchOnValueChange={() =>
|
||||
dispatch(updateInstancePushDecode(!instancePush?.decode))
|
||||
}
|
||||
switchDisabled={!pushEnabled || !push?.global}
|
||||
switchValue={push?.decode}
|
||||
switchOnValueChange={async () => {
|
||||
await apiTooot({
|
||||
method: 'put',
|
||||
url: `push/update-decode/${pushPath}`,
|
||||
body: { auth: push?.decode ? null : push.key }
|
||||
})
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
setChannels(true)
|
||||
}
|
||||
|
||||
setAccountStorage([{ key: 'push', value: { ...push, decode: !push.decode } }])
|
||||
}}
|
||||
/>
|
||||
<MenuRow
|
||||
title={t('me.push.howitworks')}
|
||||
|
Reference in New Issue
Block a user