mirror of https://github.com/tooot-app/app
commit
27a9f9fdc0
|
@ -151,4 +151,8 @@ declare namespace Nav {
|
||||||
fields?: Mastodon.Source['fields']
|
fields?: Mastodon.Source['fields']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TabMePushStackParamList = {
|
||||||
|
'Tab-Me-Push-Root': undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ export interface Props {
|
||||||
start: number
|
start: number
|
||||||
end: number
|
end: number
|
||||||
}>
|
}>
|
||||||
|
maxLength?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const ComponentEmojis: React.FC<Props> = ({
|
const ComponentEmojis: React.FC<Props> = ({
|
||||||
|
@ -93,6 +94,7 @@ const ComponentEmojis: React.FC<Props> = ({
|
||||||
value,
|
value,
|
||||||
setValue,
|
setValue,
|
||||||
selectionRange,
|
selectionRange,
|
||||||
|
maxLength,
|
||||||
children
|
children
|
||||||
}) => {
|
}) => {
|
||||||
const { reduceMotionEnabled } = useAccessibility()
|
const { reduceMotionEnabled } = useAccessibility()
|
||||||
|
@ -125,9 +127,13 @@ const ComponentEmojis: React.FC<Props> = ({
|
||||||
const newTextWithSpace = ` ${emojiShortcode}${
|
const newTextWithSpace = ` ${emojiShortcode}${
|
||||||
whiteSpaceRear ? '' : ' '
|
whiteSpaceRear ? '' : ' '
|
||||||
}`
|
}`
|
||||||
setValue([contentFront, newTextWithSpace, contentRear].join(''))
|
setValue(
|
||||||
|
[contentFront, newTextWithSpace, contentRear]
|
||||||
|
.join('')
|
||||||
|
.slice(0, maxLength)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
setValue(`${emojiShortcode} `)
|
setValue(`${emojiShortcode} `.slice(0, maxLength))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[value, selectionRange.current?.start, selectionRange.current?.end]
|
[value, selectionRange.current?.start, selectionRange.current?.end]
|
||||||
|
|
|
@ -107,6 +107,7 @@ const Input: React.FC<Props> = ({
|
||||||
value={value}
|
value={value}
|
||||||
setValue={setValue}
|
setValue={setValue}
|
||||||
selectionRange={selectionRange}
|
selectionRange={selectionRange}
|
||||||
|
maxLength={options?.maxLength}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
|
|
|
@ -115,15 +115,10 @@ const TabMe = React.memo(
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Tab-Me-Push'
|
name='Tab-Me-Push'
|
||||||
component={TabMePush}
|
component={TabMePush}
|
||||||
options={({ navigation }: any) => ({
|
options={{
|
||||||
headerTitle: t('me.stacks.push.name'),
|
stackPresentation: 'modal',
|
||||||
...(Platform.OS === 'android' && {
|
headerShown: false
|
||||||
headerCenter: () => (
|
}}
|
||||||
<HeaderCenter content={t('me.stacks.push.name')} />
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
|
||||||
})}
|
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Tab-Me-Settings'
|
name='Tab-Me-Settings'
|
||||||
|
|
|
@ -6,10 +6,10 @@ import { useTranslation } from 'react-i18next'
|
||||||
import { KeyboardAvoidingView, Platform } from 'react-native'
|
import { KeyboardAvoidingView, Platform } from 'react-native'
|
||||||
import FlashMessage from 'react-native-flash-message'
|
import FlashMessage from 'react-native-flash-message'
|
||||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||||
import ScreenMeProfileFields from './Profile/Fields'
|
import TabMeProfileFields from './Profile/Fields'
|
||||||
import ScreenMeProfileName from './Profile/Name'
|
import TabMeProfileName from './Profile/Name'
|
||||||
import ScreenMeProfileNote from './Profile/Note'
|
import TabMeProfileNote from './Profile/Note'
|
||||||
import ScreenMeProfileRoot from './Profile/Root'
|
import TabMeProfileRoot from './Profile/Root'
|
||||||
|
|
||||||
const Stack = createNativeStackNavigator<Nav.TabMeProfileStackParamList>()
|
const Stack = createNativeStackNavigator<Nav.TabMeProfileStackParamList>()
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ const TabMeProfile: React.FC<StackScreenProps<
|
||||||
>
|
>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Tab-Me-Profile-Root'
|
name='Tab-Me-Profile-Root'
|
||||||
component={ScreenMeProfileRoot}
|
component={TabMeProfileRoot}
|
||||||
options={{
|
options={{
|
||||||
headerTitle: t('me.stacks.profile.name'),
|
headerTitle: t('me.stacks.profile.name'),
|
||||||
...(Platform.OS === 'android' && {
|
...(Platform.OS === 'android' && {
|
||||||
|
@ -58,7 +58,7 @@ const TabMeProfile: React.FC<StackScreenProps<
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ route, navigation }) => (
|
{({ route, navigation }) => (
|
||||||
<ScreenMeProfileName
|
<TabMeProfileName
|
||||||
messageRef={messageRef}
|
messageRef={messageRef}
|
||||||
route={route}
|
route={route}
|
||||||
navigation={navigation}
|
navigation={navigation}
|
||||||
|
@ -77,7 +77,7 @@ const TabMeProfile: React.FC<StackScreenProps<
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ route, navigation }) => (
|
{({ route, navigation }) => (
|
||||||
<ScreenMeProfileNote
|
<TabMeProfileNote
|
||||||
messageRef={messageRef}
|
messageRef={messageRef}
|
||||||
route={route}
|
route={route}
|
||||||
navigation={navigation}
|
navigation={navigation}
|
||||||
|
@ -96,7 +96,7 @@ const TabMeProfile: React.FC<StackScreenProps<
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ route, navigation }) => (
|
{({ route, navigation }) => (
|
||||||
<ScreenMeProfileFields
|
<TabMeProfileFields
|
||||||
messageRef={messageRef}
|
messageRef={messageRef}
|
||||||
route={route}
|
route={route}
|
||||||
navigation={navigation}
|
navigation={navigation}
|
||||||
|
|
|
@ -24,7 +24,7 @@ const prepareFields = (
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const ScreenMeProfileFields: React.FC<StackScreenProps<
|
const TabMeProfileFields: React.FC<StackScreenProps<
|
||||||
Nav.TabMeProfileStackParamList,
|
Nav.TabMeProfileStackParamList,
|
||||||
'Tab-Me-Profile-Fields'
|
'Tab-Me-Profile-Fields'
|
||||||
> & { messageRef: RefObject<FlashMessage> }> = ({
|
> & { messageRef: RefObject<FlashMessage> }> = ({
|
||||||
|
@ -112,7 +112,7 @@ const ScreenMeProfileFields: React.FC<StackScreenProps<
|
||||||
}, [mode, i18n.language, dirty, status, newFields])
|
}, [mode, i18n.language, dirty, status, newFields])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView style={styles.base} keyboardShouldPersistTaps='handled'>
|
<ScrollView style={styles.base} keyboardShouldPersistTaps='always'>
|
||||||
<View style={{ marginBottom: StyleConstants.Spacing.L * 2 }}>
|
<View style={{ marginBottom: StyleConstants.Spacing.L * 2 }}>
|
||||||
{Array.from(Array(4).keys()).map(index => (
|
{Array.from(Array(4).keys()).map(index => (
|
||||||
<View key={index} style={styles.group}>
|
<View key={index} style={styles.group}>
|
||||||
|
@ -168,4 +168,4 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default ScreenMeProfileFields
|
export default TabMeProfileFields
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { Alert, StyleSheet } from 'react-native'
|
||||||
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'
|
||||||
|
|
||||||
const ScreenMeProfileName: React.FC<StackScreenProps<
|
const TabMeProfileName: React.FC<StackScreenProps<
|
||||||
Nav.TabMeProfileStackParamList,
|
Nav.TabMeProfileStackParamList,
|
||||||
'Tab-Me-Profile-Name'
|
'Tab-Me-Profile-Name'
|
||||||
> & { messageRef: RefObject<FlashMessage> }> = ({
|
> & { messageRef: RefObject<FlashMessage> }> = ({
|
||||||
|
@ -94,7 +94,7 @@ const ScreenMeProfileName: React.FC<StackScreenProps<
|
||||||
}, [mode, i18n.language, dirty, status, displayName])
|
}, [mode, i18n.language, dirty, status, displayName])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView style={styles.base} keyboardShouldPersistTaps='handled'>
|
<ScrollView style={styles.base} keyboardShouldPersistTaps='always'>
|
||||||
<Input
|
<Input
|
||||||
value={displayName}
|
value={displayName}
|
||||||
setValue={setDisplayName}
|
setValue={setDisplayName}
|
||||||
|
@ -116,4 +116,4 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default ScreenMeProfileName
|
export default TabMeProfileName
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { Alert, StyleSheet, View } from 'react-native'
|
||||||
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'
|
||||||
|
|
||||||
const ScreenMeProfileNote: React.FC<StackScreenProps<
|
const TabMeProfileNote: React.FC<StackScreenProps<
|
||||||
Nav.TabMeProfileStackParamList,
|
Nav.TabMeProfileStackParamList,
|
||||||
'Tab-Me-Profile-Note'
|
'Tab-Me-Profile-Note'
|
||||||
> & { messageRef: RefObject<FlashMessage> }> = ({
|
> & { messageRef: RefObject<FlashMessage> }> = ({
|
||||||
|
@ -94,7 +94,7 @@ const ScreenMeProfileNote: React.FC<StackScreenProps<
|
||||||
}, [mode, i18n.language, dirty, status, newNote])
|
}, [mode, i18n.language, dirty, status, newNote])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView style={styles.base} keyboardShouldPersistTaps='handled'>
|
<ScrollView style={styles.base} keyboardShouldPersistTaps='always'>
|
||||||
<View style={{ marginBottom: StyleConstants.Spacing.XL * 2 }}>
|
<View style={{ marginBottom: StyleConstants.Spacing.XL * 2 }}>
|
||||||
<Input
|
<Input
|
||||||
value={newNote}
|
value={newNote}
|
||||||
|
@ -114,4 +114,4 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default ScreenMeProfileNote
|
export default TabMeProfileNote
|
||||||
|
|
|
@ -6,7 +6,7 @@ import React, { useCallback } 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'
|
||||||
|
|
||||||
const ScreenMeProfileRoot: React.FC<StackScreenProps<
|
const TabMeProfileRoot: React.FC<StackScreenProps<
|
||||||
Nav.TabMeProfileStackParamList,
|
Nav.TabMeProfileStackParamList,
|
||||||
'Tab-Me-Profile-Root'
|
'Tab-Me-Profile-Root'
|
||||||
>> = ({ navigation }) => {
|
>> = ({ navigation }) => {
|
||||||
|
@ -180,4 +180,4 @@ const ScreenMeProfileRoot: React.FC<StackScreenProps<
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ScreenMeProfileRoot
|
export default TabMeProfileRoot
|
||||||
|
|
|
@ -1,162 +1,42 @@
|
||||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
import { HeaderCenter, HeaderLeft } from '@components/Header'
|
||||||
import { updateInstancePush } from '@utils/slices/instances/updatePush'
|
|
||||||
import { updateInstancePushAlert } from '@utils/slices/instances/updatePushAlert'
|
|
||||||
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
|
|
||||||
import {
|
|
||||||
clearPushLoading,
|
|
||||||
getInstanceAccount,
|
|
||||||
getInstancePush,
|
|
||||||
getInstanceUri
|
|
||||||
} from '@utils/slices/instancesSlice'
|
|
||||||
import * as WebBrowser from 'expo-web-browser'
|
|
||||||
import * as Notifications from 'expo-notifications'
|
|
||||||
import React, { useEffect, useMemo, useState } from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { ScrollView } from 'react-native-gesture-handler'
|
|
||||||
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'
|
|
||||||
import { StackScreenProps } from '@react-navigation/stack'
|
import { StackScreenProps } from '@react-navigation/stack'
|
||||||
|
import React from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { Platform } from 'react-native'
|
||||||
|
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||||
|
import TabMePushRoot from './Push/Root'
|
||||||
|
|
||||||
|
const Stack = createNativeStackNavigator<Nav.TabMePushStackParamList>()
|
||||||
|
|
||||||
const TabMePush: React.FC<StackScreenProps<
|
const TabMePush: React.FC<StackScreenProps<
|
||||||
Nav.TabMeStackParamList,
|
Nav.TabMeStackParamList,
|
||||||
'Tab-Me-Push'
|
'Tab-Me-Push'
|
||||||
>> = () => {
|
>> = ({ navigation }) => {
|
||||||
const { t } = useTranslation('screenTabs')
|
const { t } = useTranslation('screenTabs')
|
||||||
const instanceAccount = useSelector(
|
|
||||||
getInstanceAccount,
|
|
||||||
(prev, next) => prev?.acct === next?.acct
|
|
||||||
)
|
|
||||||
const instanceUri = useSelector(getInstanceUri)
|
|
||||||
|
|
||||||
const dispatch = useDispatch()
|
|
||||||
const instancePush = useSelector(getInstancePush)
|
|
||||||
|
|
||||||
const [pushEnabled, setPushEnabled] = useState<boolean>()
|
|
||||||
const [pushCanAskAgain, setPushCanAskAgain] = useState<boolean>()
|
|
||||||
const checkPush = async () => {
|
|
||||||
const settings = await Notifications.getPermissionsAsync()
|
|
||||||
layoutAnimation()
|
|
||||||
setPushEnabled(settings.granted)
|
|
||||||
setPushCanAskAgain(settings.canAskAgain)
|
|
||||||
}
|
|
||||||
useEffect(() => {
|
|
||||||
checkPush()
|
|
||||||
AppState.addEventListener('change', checkPush)
|
|
||||||
return () => {
|
|
||||||
AppState.removeEventListener('change', checkPush)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
dispatch(clearPushLoading())
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const isLoading = instancePush?.global.loading || instancePush?.decode.loading
|
|
||||||
|
|
||||||
const alerts = useMemo(() => {
|
|
||||||
return instancePush?.alerts
|
|
||||||
? (['follow', 'favourite', 'reblog', 'mention', 'poll'] as [
|
|
||||||
'follow',
|
|
||||||
'favourite',
|
|
||||||
'reblog',
|
|
||||||
'mention',
|
|
||||||
'poll'
|
|
||||||
]).map(alert => (
|
|
||||||
<MenuRow
|
|
||||||
key={alert}
|
|
||||||
title={t(`me.push.${alert}.heading`)}
|
|
||||||
switchDisabled={
|
|
||||||
!pushEnabled || !instancePush.global.value || isLoading
|
|
||||||
}
|
|
||||||
switchValue={instancePush?.alerts[alert].value}
|
|
||||||
switchOnValueChange={() =>
|
|
||||||
dispatch(
|
|
||||||
updateInstancePushAlert({
|
|
||||||
changed: alert,
|
|
||||||
alerts: {
|
|
||||||
...instancePush?.alerts,
|
|
||||||
[alert]: {
|
|
||||||
...instancePush?.alerts[alert],
|
|
||||||
value: !instancePush?.alerts[alert].value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
: null
|
|
||||||
}, [pushEnabled, instancePush?.global, instancePush?.alerts, isLoading])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView>
|
<Stack.Navigator
|
||||||
{pushEnabled === false ? (
|
screenOptions={{ headerHideShadow: true, headerTopInsetEnabled: false }}
|
||||||
<MenuContainer>
|
>
|
||||||
<Button
|
<Stack.Screen
|
||||||
type='text'
|
name='Tab-Me-Push-Root'
|
||||||
content={
|
component={TabMePushRoot}
|
||||||
pushCanAskAgain
|
options={{
|
||||||
? t('me.push.enable.direct')
|
headerTitle: t('me.stacks.push.name'),
|
||||||
: t('me.push.enable.settings')
|
...(Platform.OS === 'android' && {
|
||||||
}
|
headerCenter: () => (
|
||||||
style={{
|
<HeaderCenter content={t('me.stacks.push.name')} />
|
||||||
marginTop: StyleConstants.Spacing.Global.PagePadding,
|
)
|
||||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
|
}),
|
||||||
}}
|
headerLeft: () => (
|
||||||
onPress={async () => {
|
<HeaderLeft
|
||||||
if (pushCanAskAgain) {
|
content='ChevronDown'
|
||||||
const result = await Notifications.requestPermissionsAsync()
|
onPress={() => navigation.goBack()}
|
||||||
setPushEnabled(result.granted)
|
/>
|
||||||
setPushCanAskAgain(result.canAskAgain)
|
)
|
||||||
} else {
|
}}
|
||||||
Linking.openSettings()
|
/>
|
||||||
}
|
</Stack.Navigator>
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</MenuContainer>
|
|
||||||
) : null}
|
|
||||||
<MenuContainer>
|
|
||||||
<MenuRow
|
|
||||||
title={t('me.push.global.heading', {
|
|
||||||
acct: `@${instanceAccount?.acct}@${instanceUri}`
|
|
||||||
})}
|
|
||||||
description={t('me.push.global.description')}
|
|
||||||
loading={instancePush?.global.loading}
|
|
||||||
switchDisabled={!pushEnabled || isLoading}
|
|
||||||
switchValue={
|
|
||||||
pushEnabled === false ? false : instancePush?.global.value
|
|
||||||
}
|
|
||||||
switchOnValueChange={() =>
|
|
||||||
dispatch(updateInstancePush(!instancePush?.global.value))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</MenuContainer>
|
|
||||||
<MenuContainer>
|
|
||||||
<MenuRow
|
|
||||||
title={t('me.push.decode.heading')}
|
|
||||||
description={t('me.push.decode.description')}
|
|
||||||
loading={instancePush?.decode.loading}
|
|
||||||
switchDisabled={
|
|
||||||
!pushEnabled || !instancePush?.global.value || isLoading
|
|
||||||
}
|
|
||||||
switchValue={instancePush?.decode.value}
|
|
||||||
switchOnValueChange={() =>
|
|
||||||
dispatch(updateInstancePushDecode(!instancePush?.decode.value))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<MenuRow
|
|
||||||
title={t('me.push.howitworks')}
|
|
||||||
iconBack='ExternalLink'
|
|
||||||
onPress={() =>
|
|
||||||
WebBrowser.openBrowserAsync('https://tooot.app/how-push-works')
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</MenuContainer>
|
|
||||||
<MenuContainer>{alerts}</MenuContainer>
|
|
||||||
</ScrollView>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||||
|
import { updateInstancePush } from '@utils/slices/instances/updatePush'
|
||||||
|
import { updateInstancePushAlert } from '@utils/slices/instances/updatePushAlert'
|
||||||
|
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
|
||||||
|
import {
|
||||||
|
clearPushLoading,
|
||||||
|
getInstanceAccount,
|
||||||
|
getInstancePush,
|
||||||
|
getInstanceUri
|
||||||
|
} from '@utils/slices/instancesSlice'
|
||||||
|
import * as WebBrowser from 'expo-web-browser'
|
||||||
|
import * as Notifications from 'expo-notifications'
|
||||||
|
import React, { useEffect, useMemo, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { ScrollView } from 'react-native-gesture-handler'
|
||||||
|
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'
|
||||||
|
import { StackScreenProps } from '@react-navigation/stack'
|
||||||
|
|
||||||
|
const TabMePushRoot: React.FC<StackScreenProps<
|
||||||
|
Nav.TabMeStackParamList,
|
||||||
|
'Tab-Me-Push'
|
||||||
|
>> = () => {
|
||||||
|
const { t } = useTranslation('screenTabs')
|
||||||
|
const instanceAccount = useSelector(
|
||||||
|
getInstanceAccount,
|
||||||
|
(prev, next) => prev?.acct === next?.acct
|
||||||
|
)
|
||||||
|
const instanceUri = useSelector(getInstanceUri)
|
||||||
|
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
const instancePush = useSelector(getInstancePush)
|
||||||
|
|
||||||
|
const [pushEnabled, setPushEnabled] = useState<boolean>()
|
||||||
|
const [pushCanAskAgain, setPushCanAskAgain] = useState<boolean>()
|
||||||
|
const checkPush = async () => {
|
||||||
|
const settings = await Notifications.getPermissionsAsync()
|
||||||
|
layoutAnimation()
|
||||||
|
setPushEnabled(settings.granted)
|
||||||
|
setPushCanAskAgain(settings.canAskAgain)
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
checkPush()
|
||||||
|
AppState.addEventListener('change', checkPush)
|
||||||
|
return () => {
|
||||||
|
AppState.removeEventListener('change', checkPush)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(clearPushLoading())
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const isLoading = instancePush?.global.loading || instancePush?.decode.loading
|
||||||
|
|
||||||
|
const alerts = useMemo(() => {
|
||||||
|
return instancePush?.alerts
|
||||||
|
? (['follow', 'favourite', 'reblog', 'mention', 'poll'] as [
|
||||||
|
'follow',
|
||||||
|
'favourite',
|
||||||
|
'reblog',
|
||||||
|
'mention',
|
||||||
|
'poll'
|
||||||
|
]).map(alert => (
|
||||||
|
<MenuRow
|
||||||
|
key={alert}
|
||||||
|
title={t(`me.push.${alert}.heading`)}
|
||||||
|
switchDisabled={
|
||||||
|
!pushEnabled || !instancePush.global.value || isLoading
|
||||||
|
}
|
||||||
|
switchValue={instancePush?.alerts[alert].value}
|
||||||
|
switchOnValueChange={() =>
|
||||||
|
dispatch(
|
||||||
|
updateInstancePushAlert({
|
||||||
|
changed: alert,
|
||||||
|
alerts: {
|
||||||
|
...instancePush?.alerts,
|
||||||
|
[alert]: {
|
||||||
|
...instancePush?.alerts[alert],
|
||||||
|
value: !instancePush?.alerts[alert].value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
: null
|
||||||
|
}, [pushEnabled, instancePush?.global, instancePush?.alerts, isLoading])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView>
|
||||||
|
{pushEnabled === false ? (
|
||||||
|
<MenuContainer>
|
||||||
|
<Button
|
||||||
|
type='text'
|
||||||
|
content={
|
||||||
|
pushCanAskAgain
|
||||||
|
? t('me.push.enable.direct')
|
||||||
|
: t('me.push.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.openSettings()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</MenuContainer>
|
||||||
|
) : null}
|
||||||
|
<MenuContainer>
|
||||||
|
<MenuRow
|
||||||
|
title={t('me.push.global.heading', {
|
||||||
|
acct: `@${instanceAccount?.acct}@${instanceUri}`
|
||||||
|
})}
|
||||||
|
description={t('me.push.global.description')}
|
||||||
|
loading={instancePush?.global.loading}
|
||||||
|
switchDisabled={!pushEnabled || isLoading}
|
||||||
|
switchValue={
|
||||||
|
pushEnabled === false ? false : instancePush?.global.value
|
||||||
|
}
|
||||||
|
switchOnValueChange={() =>
|
||||||
|
dispatch(updateInstancePush(!instancePush?.global.value))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</MenuContainer>
|
||||||
|
<MenuContainer>
|
||||||
|
<MenuRow
|
||||||
|
title={t('me.push.decode.heading')}
|
||||||
|
description={t('me.push.decode.description')}
|
||||||
|
loading={instancePush?.decode.loading}
|
||||||
|
switchDisabled={
|
||||||
|
!pushEnabled || !instancePush?.global.value || isLoading
|
||||||
|
}
|
||||||
|
switchValue={instancePush?.decode.value}
|
||||||
|
switchOnValueChange={() =>
|
||||||
|
dispatch(updateInstancePushDecode(!instancePush?.decode.value))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<MenuRow
|
||||||
|
title={t('me.push.howitworks')}
|
||||||
|
iconBack='ExternalLink'
|
||||||
|
onPress={() =>
|
||||||
|
WebBrowser.openBrowserAsync('https://tooot.app/how-push-works')
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</MenuContainer>
|
||||||
|
<MenuContainer>{alerts}</MenuContainer>
|
||||||
|
</ScrollView>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TabMePushRoot
|
|
@ -4,7 +4,7 @@ import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { KeyboardAvoidingView, Platform } from 'react-native'
|
import { KeyboardAvoidingView, Platform } from 'react-native'
|
||||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||||
import ScreenMeSwitchRoot from './Switch/Root'
|
import TabMeSwitchRoot from './Switch/Root'
|
||||||
|
|
||||||
const Stack = createNativeStackNavigator()
|
const Stack = createNativeStackNavigator()
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ const TabMeSwitch: React.FC<StackScreenProps<
|
||||||
>
|
>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Screen-Me-Switch-Root'
|
name='Screen-Me-Switch-Root'
|
||||||
component={ScreenMeSwitchRoot}
|
component={TabMeSwitchRoot}
|
||||||
options={{
|
options={{
|
||||||
headerTitle: t('me.stacks.switch.name'),
|
headerTitle: t('me.stacks.switch.name'),
|
||||||
...(Platform.OS === 'android' && {
|
...(Platform.OS === 'android' && {
|
||||||
|
|
|
@ -11,7 +11,6 @@ import {
|
||||||
} from '@utils/slices/instancesSlice'
|
} from '@utils/slices/instancesSlice'
|
||||||
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 { groupBy } from 'lodash'
|
|
||||||
import React, { useRef } from 'react'
|
import React, { useRef } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { StyleSheet, Text, View } from 'react-native'
|
import { StyleSheet, Text, View } from 'react-native'
|
||||||
|
@ -48,7 +47,7 @@ const AccountButton: React.FC<Props> = ({ instance, selected = false }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ScreenMeSwitchRoot: React.FC = () => {
|
const TabMeSwitchRoot: React.FC = () => {
|
||||||
const { t } = useTranslation('screenTabs')
|
const { t } = useTranslation('screenTabs')
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const instances = useSelector(getInstances, () => true)
|
const instances = useSelector(getInstances, () => true)
|
||||||
|
@ -137,4 +136,4 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default ScreenMeSwitchRoot
|
export default TabMeSwitchRoot
|
||||||
|
|
Loading…
Reference in New Issue