2021-01-24 02:25:43 +01:00
|
|
|
import analytics from '@components/analytics'
|
2020-12-29 16:19:04 +01:00
|
|
|
import { HeaderLeft, HeaderRight } from '@components/Header'
|
2020-12-30 14:33:33 +01:00
|
|
|
import haptics from '@root/components/haptics'
|
2020-12-29 16:19:04 +01:00
|
|
|
import { store } from '@root/store'
|
|
|
|
import formatText from '@screens/Shared/Compose/formatText'
|
|
|
|
import ComposeRoot from '@screens/Shared/Compose/Root'
|
2021-01-11 21:36:57 +01:00
|
|
|
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
2021-01-18 00:23:40 +01:00
|
|
|
import { updateStoreReview } from '@utils/slices/contextsSlice'
|
2021-01-07 19:13:09 +01:00
|
|
|
import { getLocalAccount } from '@utils/slices/instancesSlice'
|
2020-12-29 16:19:04 +01:00
|
|
|
import { StyleConstants } from '@utils/styles/constants'
|
|
|
|
import { useTheme } from '@utils/styles/ThemeManager'
|
2021-01-01 17:52:14 +01:00
|
|
|
import React, { useCallback, useEffect, useReducer, useState } from 'react'
|
2021-01-19 01:13:45 +01:00
|
|
|
import { useTranslation } from 'react-i18next'
|
2020-12-06 23:51:13 +01:00
|
|
|
import {
|
|
|
|
Alert,
|
|
|
|
Keyboard,
|
|
|
|
KeyboardAvoidingView,
|
2021-01-14 00:43:35 +01:00
|
|
|
Platform,
|
2020-12-06 23:51:13 +01:00
|
|
|
StyleSheet,
|
2020-12-30 00:56:25 +01:00
|
|
|
Text
|
2020-12-06 23:51:13 +01:00
|
|
|
} from 'react-native'
|
2020-11-15 23:33:01 +01:00
|
|
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
2020-11-08 01:10:38 +01:00
|
|
|
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
2020-12-20 17:53:24 +01:00
|
|
|
import { useQueryClient } from 'react-query'
|
2021-01-18 00:23:40 +01:00
|
|
|
import { useDispatch } from 'react-redux'
|
2021-01-22 01:34:20 +01:00
|
|
|
import * as Sentry from 'sentry-expo'
|
2020-12-30 00:56:25 +01:00
|
|
|
import ComposeEditAttachment from './Compose/EditAttachment'
|
2021-01-01 17:52:14 +01:00
|
|
|
import ComposeContext from './Compose/utils/createContext'
|
2020-12-30 00:56:25 +01:00
|
|
|
import composeInitialState from './Compose/utils/initialState'
|
|
|
|
import composeParseState from './Compose/utils/parseState'
|
2021-01-01 23:10:47 +01:00
|
|
|
import composePost from './Compose/utils/post'
|
2020-12-30 00:56:25 +01:00
|
|
|
import composeReducer from './Compose/utils/reducer'
|
2021-01-07 22:18:14 +01:00
|
|
|
import { SharedComposeProp } from './sharedScreens'
|
2020-11-08 01:10:38 +01:00
|
|
|
|
2020-11-15 20:29:43 +01:00
|
|
|
const Stack = createNativeStackNavigator()
|
2020-11-08 01:10:38 +01:00
|
|
|
|
2021-01-07 22:18:14 +01:00
|
|
|
const Compose: React.FC<SharedComposeProp> = ({
|
|
|
|
route: { params },
|
|
|
|
navigation
|
|
|
|
}) => {
|
2021-01-19 01:13:45 +01:00
|
|
|
const { t } = useTranslation('sharedCompose')
|
2020-12-07 12:31:40 +01:00
|
|
|
const { theme } = useTheme()
|
2020-12-20 17:53:24 +01:00
|
|
|
const queryClient = useQueryClient()
|
2020-12-06 23:51:13 +01:00
|
|
|
|
2020-11-15 23:33:01 +01:00
|
|
|
const [hasKeyboard, setHasKeyboard] = useState(false)
|
|
|
|
useEffect(() => {
|
|
|
|
Keyboard.addListener('keyboardWillShow', _keyboardDidShow)
|
|
|
|
Keyboard.addListener('keyboardWillHide', _keyboardDidHide)
|
|
|
|
|
|
|
|
// cleanup function
|
|
|
|
return () => {
|
|
|
|
Keyboard.removeListener('keyboardWillShow', _keyboardDidShow)
|
|
|
|
Keyboard.removeListener('keyboardWillHide', _keyboardDidHide)
|
|
|
|
}
|
|
|
|
}, [])
|
|
|
|
const _keyboardDidShow = () => {
|
|
|
|
setHasKeyboard(true)
|
|
|
|
}
|
|
|
|
const _keyboardDidHide = () => {
|
|
|
|
setHasKeyboard(false)
|
|
|
|
}
|
|
|
|
|
2021-01-07 19:13:09 +01:00
|
|
|
const localAccount = getLocalAccount(store.getState())
|
2020-12-07 12:31:40 +01:00
|
|
|
const [composeState, composeDispatch] = useReducer(
|
2020-12-17 09:44:03 +01:00
|
|
|
composeReducer,
|
2021-01-14 22:53:01 +01:00
|
|
|
params
|
|
|
|
? composeParseState(params)
|
2020-12-13 22:31:55 +01:00
|
|
|
: {
|
|
|
|
...composeInitialState,
|
2021-01-07 19:13:09 +01:00
|
|
|
visibility:
|
|
|
|
localAccount?.preferences &&
|
|
|
|
localAccount.preferences['posting:default:visibility']
|
|
|
|
? localAccount.preferences['posting:default:visibility']
|
|
|
|
: 'public'
|
2020-12-13 22:31:55 +01:00
|
|
|
}
|
2020-12-07 12:31:40 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
switch (params?.type) {
|
|
|
|
case 'edit':
|
|
|
|
if (params.incomingStatus.spoiler_text) {
|
|
|
|
formatText({
|
2020-12-11 00:29:22 +01:00
|
|
|
textInput: 'spoiler',
|
2020-12-07 12:31:40 +01:00
|
|
|
composeDispatch,
|
|
|
|
content: params.incomingStatus.spoiler_text,
|
|
|
|
disableDebounce: true
|
|
|
|
})
|
|
|
|
}
|
|
|
|
formatText({
|
2020-12-11 00:29:22 +01:00
|
|
|
textInput: 'text',
|
2020-12-07 12:31:40 +01:00
|
|
|
composeDispatch,
|
|
|
|
content: params.incomingStatus.text!,
|
|
|
|
disableDebounce: true
|
|
|
|
})
|
|
|
|
break
|
|
|
|
case 'reply':
|
2020-12-21 21:47:15 +01:00
|
|
|
case 'conversation':
|
|
|
|
formatText({
|
|
|
|
textInput: 'text',
|
|
|
|
composeDispatch,
|
2021-01-24 02:25:43 +01:00
|
|
|
content: params.accts.map(acct => `@${acct}`).join(' ') + ' ',
|
2020-12-21 21:47:15 +01:00
|
|
|
disableDebounce: true
|
|
|
|
})
|
|
|
|
break
|
2020-12-07 12:31:40 +01:00
|
|
|
}
|
|
|
|
}, [params?.type])
|
2020-11-15 22:33:09 +01:00
|
|
|
|
2020-12-06 23:51:13 +01:00
|
|
|
const totalTextCount =
|
2020-12-07 12:31:40 +01:00
|
|
|
(composeState.spoiler.active ? composeState.spoiler.count : 0) +
|
|
|
|
composeState.text.count
|
2020-12-06 23:51:13 +01:00
|
|
|
|
2020-12-26 00:53:49 +01:00
|
|
|
const headerLeft = useCallback(
|
|
|
|
() => (
|
|
|
|
<HeaderLeft
|
2020-12-26 23:27:53 +01:00
|
|
|
type='text'
|
2021-01-19 01:13:45 +01:00
|
|
|
content={t('heading.left.button')}
|
2021-01-17 22:37:05 +01:00
|
|
|
onPress={() => {
|
2021-01-24 02:25:43 +01:00
|
|
|
analytics('compose_header_back_press')
|
2021-01-17 22:37:05 +01:00
|
|
|
if (
|
|
|
|
totalTextCount === 0 &&
|
|
|
|
composeState.attachments.uploads.length === 0 &&
|
|
|
|
composeState.poll.active === false
|
|
|
|
) {
|
2021-01-24 02:25:43 +01:00
|
|
|
analytics('compose_header_back_empty')
|
2021-01-17 22:37:05 +01:00
|
|
|
navigation.goBack()
|
|
|
|
return
|
|
|
|
} else {
|
2021-01-24 02:25:43 +01:00
|
|
|
analytics('compose_header_back_state_occupied')
|
2021-01-19 01:13:45 +01:00
|
|
|
Alert.alert(t('heading.left.alert.title'), undefined, [
|
2021-01-17 22:37:05 +01:00
|
|
|
{
|
2021-01-19 01:13:45 +01:00
|
|
|
text: t('heading.left.alert.buttons.exit'),
|
2021-01-17 22:37:05 +01:00
|
|
|
style: 'destructive',
|
2021-01-24 02:25:43 +01:00
|
|
|
onPress: () => {
|
|
|
|
analytics('compose_header_back_occupied_confirm')
|
|
|
|
navigation.goBack()
|
|
|
|
}
|
2021-01-17 22:37:05 +01:00
|
|
|
},
|
2021-01-19 01:13:45 +01:00
|
|
|
{
|
|
|
|
text: t('heading.left.alert.buttons.continue'),
|
2021-01-24 02:25:43 +01:00
|
|
|
style: 'cancel',
|
|
|
|
onPress: () => {
|
|
|
|
analytics('compose_header_back_occupied_cancel')
|
|
|
|
}
|
2021-01-19 01:13:45 +01:00
|
|
|
}
|
2021-01-17 22:37:05 +01:00
|
|
|
])
|
|
|
|
}
|
|
|
|
}}
|
2020-12-26 00:53:49 +01:00
|
|
|
/>
|
|
|
|
),
|
2021-01-22 01:34:20 +01:00
|
|
|
[totalTextCount, composeState]
|
2020-12-26 00:53:49 +01:00
|
|
|
)
|
|
|
|
const headerCenter = useCallback(
|
|
|
|
() => (
|
|
|
|
<Text
|
|
|
|
style={[
|
|
|
|
styles.count,
|
|
|
|
{
|
|
|
|
color: totalTextCount > 500 ? theme.red : theme.secondary
|
|
|
|
}
|
|
|
|
]}
|
|
|
|
>
|
|
|
|
{totalTextCount} / 500
|
|
|
|
</Text>
|
|
|
|
),
|
|
|
|
[totalTextCount]
|
|
|
|
)
|
2021-01-18 00:23:40 +01:00
|
|
|
const dispatch = useDispatch()
|
2020-12-26 00:53:49 +01:00
|
|
|
const headerRight = useCallback(
|
2020-12-26 23:27:53 +01:00
|
|
|
() => (
|
|
|
|
<HeaderRight
|
|
|
|
type='text'
|
2021-01-19 01:13:45 +01:00
|
|
|
content={
|
|
|
|
params?.type
|
|
|
|
? t(`heading.right.button.${params.type}`)
|
|
|
|
: t('heading.right.button.default')
|
|
|
|
}
|
2020-12-30 00:56:25 +01:00
|
|
|
onPress={() => {
|
2021-01-24 02:25:43 +01:00
|
|
|
analytics('compose_header_post_press')
|
2021-01-14 22:53:01 +01:00
|
|
|
composeDispatch({ type: 'posting', payload: true })
|
|
|
|
|
2021-01-01 23:10:47 +01:00
|
|
|
composePost(params, composeState)
|
2020-12-30 00:56:25 +01:00
|
|
|
.then(() => {
|
2020-12-30 14:33:33 +01:00
|
|
|
haptics('Success')
|
2021-01-18 00:23:40 +01:00
|
|
|
dispatch(updateStoreReview(1))
|
2021-01-11 21:36:57 +01:00
|
|
|
const queryKey: QueryKeyTimeline = [
|
|
|
|
'Timeline',
|
|
|
|
{ page: 'Following' }
|
|
|
|
]
|
|
|
|
queryClient.invalidateQueries(queryKey)
|
2021-01-14 22:53:01 +01:00
|
|
|
|
2021-01-24 02:25:43 +01:00
|
|
|
switch (params?.type) {
|
|
|
|
case 'edit':
|
|
|
|
case 'reply':
|
|
|
|
if (params?.queryKey && params.queryKey[1].page === 'Toot') {
|
|
|
|
queryClient.invalidateQueries(params.queryKey)
|
|
|
|
}
|
|
|
|
break
|
2021-01-04 14:55:34 +01:00
|
|
|
}
|
2020-12-30 00:56:25 +01:00
|
|
|
navigation.goBack()
|
|
|
|
})
|
2021-01-22 01:34:20 +01:00
|
|
|
.catch(error => {
|
2021-01-24 02:25:43 +01:00
|
|
|
Sentry.Native.captureException(error)
|
2020-12-30 14:33:33 +01:00
|
|
|
haptics('Error')
|
2021-01-14 22:53:01 +01:00
|
|
|
composeDispatch({ type: 'posting', payload: false })
|
2021-01-19 01:13:45 +01:00
|
|
|
Alert.alert(t('heading.right.alert.title'), undefined, [
|
2020-12-30 00:56:25 +01:00
|
|
|
{
|
2021-01-19 01:13:45 +01:00
|
|
|
text: t('heading.right.alert.button')
|
2020-12-30 00:56:25 +01:00
|
|
|
}
|
|
|
|
])
|
|
|
|
})
|
|
|
|
}}
|
2021-01-14 22:53:01 +01:00
|
|
|
loading={composeState.posting}
|
2021-01-22 01:34:20 +01:00
|
|
|
disabled={
|
|
|
|
composeState.text.raw.length < 1 ||
|
|
|
|
totalTextCount > 500 ||
|
|
|
|
(composeState.attachments.uploads.length > 0 &&
|
|
|
|
composeState.attachments.uploads.filter(upload => upload.uploading)
|
|
|
|
.length > 0)
|
|
|
|
}
|
2020-12-26 23:27:53 +01:00
|
|
|
/>
|
|
|
|
),
|
2021-01-14 22:53:01 +01:00
|
|
|
[totalTextCount, composeState]
|
2020-12-29 16:19:04 +01:00
|
|
|
)
|
|
|
|
|
2020-11-08 01:10:38 +01:00
|
|
|
return (
|
2021-01-14 00:43:35 +01:00
|
|
|
<KeyboardAvoidingView
|
|
|
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
|
|
|
style={{ flex: 1 }}
|
|
|
|
>
|
2020-11-15 23:33:01 +01:00
|
|
|
<SafeAreaView
|
|
|
|
style={{ flex: 1 }}
|
|
|
|
edges={hasKeyboard ? ['left', 'right'] : ['left', 'right', 'bottom']}
|
|
|
|
>
|
2020-12-30 00:56:25 +01:00
|
|
|
<ComposeContext.Provider value={{ composeState, composeDispatch }}>
|
2021-01-13 01:03:46 +01:00
|
|
|
<Stack.Navigator screenOptions={{ headerTopInsetEnabled: false }}>
|
2020-12-30 00:56:25 +01:00
|
|
|
<Stack.Screen
|
|
|
|
name='Screen-Shared-Compose-Root'
|
|
|
|
component={ComposeRoot}
|
|
|
|
options={{ headerLeft, headerCenter, headerRight }}
|
|
|
|
/>
|
|
|
|
<Stack.Screen
|
|
|
|
name='Screen-Shared-Compose-EditAttachment'
|
|
|
|
component={ComposeEditAttachment}
|
2021-01-14 00:43:35 +01:00
|
|
|
options={{ stackPresentation: 'modal', headerShown: false }}
|
2020-12-30 00:56:25 +01:00
|
|
|
/>
|
|
|
|
</Stack.Navigator>
|
|
|
|
</ComposeContext.Provider>
|
2020-11-15 23:33:01 +01:00
|
|
|
</SafeAreaView>
|
|
|
|
</KeyboardAvoidingView>
|
2020-11-08 01:10:38 +01:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-12-06 23:51:13 +01:00
|
|
|
const styles = StyleSheet.create({
|
|
|
|
count: {
|
|
|
|
textAlign: 'center',
|
2020-12-29 00:21:05 +01:00
|
|
|
...StyleConstants.FontStyle.M
|
2020-12-06 23:51:13 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2020-12-11 00:29:22 +01:00
|
|
|
export default Compose
|