import { HeaderLeft, HeaderRight } from '@components/Header' import haptics from '@root/components/haptics' import { store } from '@root/store' import layoutAnimation from '@root/utils/styles/layoutAnimation' import formatText from '@screens/Shared/Compose/formatText' import ComposeRoot from '@screens/Shared/Compose/Root' import { getLocalAccountPreferences } from '@utils/slices/instancesSlice' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import React, { useCallback, useEffect, useReducer, useState } from 'react' import { Alert, Keyboard, KeyboardAvoidingView, StyleSheet, Text } from 'react-native' import { SafeAreaView } from 'react-native-safe-area-context' import { createNativeStackNavigator } from 'react-native-screens/native-stack' import { useQueryClient } from 'react-query' import ComposeEditAttachment from './Compose/EditAttachment' import ComposeContext from './Compose/utils/createContext' import composeInitialState from './Compose/utils/initialState' import composeParseState from './Compose/utils/parseState' import composePost from './Compose/utils/post' import composeReducer from './Compose/utils/reducer' import { ComposeState } from './Compose/utils/types' const Stack = createNativeStackNavigator() export interface Props { route: { params: | { type?: 'reply' | 'conversation' | 'edit' incomingStatus: Mastodon.Status visibilityLock?: boolean } | undefined } navigation: any } const Compose: React.FC = ({ route: { params }, navigation }) => { const { theme } = useTheme() const queryClient = useQueryClient() 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) } const [composeState, composeDispatch] = useReducer( composeReducer, params?.type && params?.incomingStatus ? composeParseState({ type: params.type, incomingStatus: params.incomingStatus, visibilityLock: params.visibilityLock }) : { ...composeInitialState, visibility: getLocalAccountPreferences(store.getState())[ 'posting:default:visibility' ] as ComposeState['visibility'] } ) const [isSubmitting, setIsSubmitting] = useState(false) useEffect(() => { switch (params?.type) { case 'edit': if (params.incomingStatus.spoiler_text) { formatText({ textInput: 'spoiler', composeDispatch, content: params.incomingStatus.spoiler_text, disableDebounce: true }) } formatText({ textInput: 'text', composeDispatch, content: params.incomingStatus.text!, disableDebounce: true }) break case 'reply': const actualStatus = params.incomingStatus.reblog || params.incomingStatus formatText({ textInput: 'text', composeDispatch, content: `@${actualStatus.account.acct} `, disableDebounce: true }) break case 'conversation': formatText({ textInput: 'text', composeDispatch, content: `@${params.incomingStatus.account.acct} `, disableDebounce: true }) break } }, [params?.type]) const totalTextCount = (composeState.spoiler.active ? composeState.spoiler.count : 0) + composeState.text.count const postButtonText = { conversation: '回复私信', reply: '发布回复', edit: '发嘟嘟' } const headerLeft = useCallback( () => ( Alert.alert('确认取消编辑?', '', [ { text: '退出编辑', style: 'destructive', onPress: () => navigation.goBack() }, { text: '继续编辑', style: 'cancel' } ]) } /> ), [] ) const headerCenter = useCallback( () => ( 500 ? theme.red : theme.secondary } ]} > {totalTextCount} / 500 ), [totalTextCount] ) const headerRight = useCallback( () => ( { layoutAnimation() setIsSubmitting(true) composePost(params, composeState) .then(() => { haptics('Success') queryClient.invalidateQueries(['Following', {}]) if ( params?.type && (params.type === 'reply' || params.type === 'conversation') ) { queryClient.invalidateQueries( [ 'Toot', { toot: params.incomingStatus.reblog ? params.incomingStatus.reblog.id : params.incomingStatus.id } ], { exact: true, active: true } ) } navigation.goBack() }) .catch(() => { haptics('Error') setIsSubmitting(false) Alert.alert('发布失败', '', [ { text: '返回重试' } ]) }) }} loading={isSubmitting} disabled={composeState.text.raw.length < 1 || totalTextCount > 500} /> ), [isSubmitting, totalTextCount, composeState] ) return ( ) } const styles = StyleSheet.create({ count: { textAlign: 'center', ...StyleConstants.FontStyle.M } }) export default Compose