1
0
mirror of https://github.com/tooot-app/app synced 2025-06-05 22:19:13 +02:00

Use context to provide compose state and dispatch

This commit is contained in:
Zhiyuan Zheng
2020-12-11 00:29:22 +01:00
parent c114176ee4
commit 0fa9f87f66
15 changed files with 244 additions and 307 deletions

View File

@ -1,11 +1,22 @@
import React, { ReactNode, useEffect, useReducer, useState } from 'react'
import React, {
createContext,
createRef,
Dispatch,
ReactNode,
RefObject,
useEffect,
useReducer,
useRef,
useState
} from 'react'
import {
ActivityIndicator,
Alert,
Keyboard,
KeyboardAvoidingView,
StyleSheet,
Text
Text,
TextInput
} from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
@ -67,10 +78,17 @@ export type ComposeState = {
| '604800'
| string
}
attachments: { sensitive: boolean; uploads: Mastodon.Attachment[] }
attachments: {
sensitive: boolean
uploads: (Mastodon.Attachment & { local_url?: string })[]
}
attachmentUploadProgress?: { progress: number; aspect?: number }
visibility: 'public' | 'unlisted' | 'private' | 'direct'
replyToStatus?: Mastodon.Status
textInputFocus: {
current: 'text' | 'spoiler'
refs: { text: RefObject<TextInput>; spoiler: RefObject<TextInput> }
}
}
export type PostAction =
@ -110,6 +128,10 @@ export type PostAction =
type: 'visibility'
payload: ComposeState['visibility']
}
| {
type: 'textInputFocus'
payload: Partial<ComposeState['textInputFocus']>
}
const composeInitialState: ComposeState = {
spoiler: {
@ -145,7 +167,11 @@ const composeInitialState: ComposeState = {
getLocalAccountPreferences(store.getState())[
'posting:default:visibility'
] || 'public',
replyToStatus: undefined
replyToStatus: undefined,
textInputFocus: {
current: 'text',
refs: { text: createRef(), spoiler: createRef() }
}
}
const composeExistingState = ({
type,
@ -244,11 +270,22 @@ const postReducer = (state: ComposeState, action: PostAction): ComposeState => {
}
case 'visibility':
return { ...state, visibility: action.payload }
case 'textInputFocus':
return {
...state,
textInputFocus: { ...state.textInputFocus, ...action.payload }
}
default:
throw new Error('Unexpected action')
}
}
type ContextType = {
composeState: ComposeState
composeDispatch: Dispatch<PostAction>
}
export const ComposeContext = createContext<ContextType>({} as ContextType)
export interface Props {
route: {
params:
@ -298,14 +335,14 @@ const Compose: React.FC<Props> = ({ route: { params } }) => {
case 'edit':
if (params.incomingStatus.spoiler_text) {
formatText({
origin: 'spoiler',
textInput: 'spoiler',
composeDispatch,
content: params.incomingStatus.spoiler_text,
disableDebounce: true
})
}
formatText({
origin: 'text',
textInput: 'text',
composeDispatch,
content: params.incomingStatus.text!,
disableDebounce: true
@ -313,7 +350,7 @@ const Compose: React.FC<Props> = ({ route: { params } }) => {
break
case 'reply':
formatText({
origin: 'text',
textInput: 'text',
composeDispatch,
content: `@${
params.incomingStatus.reblog
@ -429,6 +466,8 @@ const Compose: React.FC<Props> = ({ route: { params } }) => {
const totalTextCount =
(composeState.spoiler.active ? composeState.spoiler.count : 0) +
composeState.text.count
// doesn't work
const rawCount = composeState.text.raw.length
return (
<KeyboardAvoidingView behavior='padding' style={{ flex: 1 }}>
@ -475,18 +514,17 @@ const Compose: React.FC<Props> = ({ route: { params } }) => {
<HeaderRight
onPress={async () => tootPost()}
text='发嘟嘟'
disabled={
composeState.text.raw.length < 1 || totalTextCount > 500
}
disabled={rawCount < 1 || totalTextCount > 500}
/>
)
}}
>
{() => (
<ComposeRoot
composeState={composeState}
composeDispatch={composeDispatch}
/>
<ComposeContext.Provider
value={{ composeState, composeDispatch }}
>
<ComposeRoot />
</ComposeContext.Provider>
)}
</Stack.Screen>
</Stack.Navigator>
@ -502,4 +540,4 @@ const styles = StyleSheet.create({
}
})
export default React.memo(Compose, () => true)
export default Compose