Move remaining composer state into reducer (#5623)
Co-authored-by: Mary <git@mary.my.id> Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> Co-authored-by: Hailey <me@haileyok.com>
This commit is contained in:
@@ -42,7 +42,6 @@ import {
|
||||
AppBskyFeedGetPostThread,
|
||||
BskyAgent,
|
||||
} from '@atproto/api'
|
||||
import {RichText} from '@atproto/api'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -57,7 +56,6 @@ import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {insertMentionAt} from '#/lib/strings/mention-manip'
|
||||
import {shortenLinks} from '#/lib/strings/rich-text-manip'
|
||||
import {colors, s} from '#/lib/styles'
|
||||
import {logger} from '#/logger'
|
||||
@@ -73,11 +71,8 @@ import {
|
||||
useLanguagePrefs,
|
||||
useLanguagePrefsApi,
|
||||
} from '#/state/preferences/languages'
|
||||
import {createPostgateRecord} from '#/state/queries/postgate/util'
|
||||
import {useProfileQuery} from '#/state/queries/profile'
|
||||
import {Gif} from '#/state/queries/tenor'
|
||||
import {ThreadgateAllowUISetting} from '#/state/queries/threadgate'
|
||||
import {threadgateViewToAllowUISetting} from '#/state/queries/threadgate/util'
|
||||
import {useAgent, useSession} from '#/state/session'
|
||||
import {useComposerControls} from '#/state/shell/composer'
|
||||
import {ComposerOpts} from '#/state/shell/composer'
|
||||
@@ -168,35 +163,40 @@ export const ComposePost = ({
|
||||
const [isProcessing, setIsProcessing] = useState(false)
|
||||
const [processingState, setProcessingState] = useState('')
|
||||
const [error, setError] = useState('')
|
||||
const [richtext, setRichText] = useState(
|
||||
new RichText({
|
||||
text: initText
|
||||
? initText
|
||||
: initMention
|
||||
? insertMentionAt(
|
||||
`@${initMention}`,
|
||||
initMention.length + 1,
|
||||
`${initMention}`,
|
||||
) // insert mention if passed in
|
||||
: '',
|
||||
}),
|
||||
|
||||
const [draft, dispatch] = useReducer(
|
||||
composerReducer,
|
||||
{initImageUris, initQuoteUri: initQuote?.uri, initText, initMention},
|
||||
createComposerState,
|
||||
)
|
||||
const richtext = draft.richtext
|
||||
let quote: string | undefined
|
||||
if (draft.embed.quote) {
|
||||
quote = draft.embed.quote.uri
|
||||
}
|
||||
let images = NO_IMAGES
|
||||
if (draft.embed.media?.type === 'images') {
|
||||
images = draft.embed.media.images
|
||||
}
|
||||
let videoState: VideoState | NoVideoState = NO_VIDEO
|
||||
if (draft.embed.media?.type === 'video') {
|
||||
videoState = draft.embed.media.video
|
||||
}
|
||||
let extGif: Gif | undefined
|
||||
let extGifAlt: string | undefined
|
||||
if (draft.embed.media?.type === 'gif') {
|
||||
extGif = draft.embed.media.gif
|
||||
extGifAlt = draft.embed.media.alt
|
||||
}
|
||||
let extLink: string | undefined
|
||||
if (draft.embed.link) {
|
||||
extLink = draft.embed.link.uri
|
||||
}
|
||||
|
||||
const graphemeLength = useMemo(() => {
|
||||
return shortenLinks(richtext).graphemeLength
|
||||
}, [richtext])
|
||||
|
||||
// TODO: Move more state here.
|
||||
const [composerState, dispatch] = useReducer(
|
||||
composerReducer,
|
||||
{initImageUris, initQuoteUri: initQuote?.uri},
|
||||
createComposerState,
|
||||
)
|
||||
|
||||
let videoState: VideoState | NoVideoState = NO_VIDEO
|
||||
if (composerState.embed.media?.type === 'video') {
|
||||
videoState = composerState.embed.media.video
|
||||
}
|
||||
|
||||
const selectVideo = React.useCallback(
|
||||
(asset: ImagePickerAsset) => {
|
||||
const abortController = new AbortController()
|
||||
@@ -241,35 +241,8 @@ export const ComposePost = ({
|
||||
)
|
||||
|
||||
const hasVideo = Boolean(videoState.asset || videoState.video)
|
||||
|
||||
const [publishOnUpload, setPublishOnUpload] = useState(false)
|
||||
|
||||
const [labels, setLabels] = useState<string[]>([])
|
||||
const [threadgateAllowUISettings, onChangeThreadgateAllowUISettings] =
|
||||
useState<ThreadgateAllowUISetting[]>(
|
||||
threadgateViewToAllowUISetting(undefined),
|
||||
)
|
||||
const [postgate, setPostgate] = useState(createPostgateRecord({post: ''}))
|
||||
|
||||
let quote: string | undefined
|
||||
if (composerState.embed.quote) {
|
||||
quote = composerState.embed.quote.uri
|
||||
}
|
||||
let images = NO_IMAGES
|
||||
if (composerState.embed.media?.type === 'images') {
|
||||
images = composerState.embed.media.images
|
||||
}
|
||||
let extGif: Gif | undefined
|
||||
let extGifAlt: string | undefined
|
||||
if (composerState.embed.media?.type === 'gif') {
|
||||
extGif = composerState.embed.media.gif
|
||||
extGifAlt = composerState.embed.media.alt
|
||||
}
|
||||
let extLink: string | undefined
|
||||
if (composerState.embed.link) {
|
||||
extLink = composerState.embed.link.uri
|
||||
}
|
||||
|
||||
const onClose = useCallback(() => {
|
||||
closeComposer()
|
||||
}, [closeComposer])
|
||||
@@ -419,12 +392,8 @@ export const ComposePost = ({
|
||||
try {
|
||||
postUri = (
|
||||
await apilib.post(agent, queryClient, {
|
||||
composerState, // TODO: move more state here.
|
||||
rawText: richtext.text,
|
||||
draft: draft,
|
||||
replyTo: replyTo?.uri,
|
||||
labels,
|
||||
threadgate: threadgateAllowUISettings,
|
||||
postgate,
|
||||
onStateChange: setProcessingState,
|
||||
langs: toPostLanguages(langPrefs.postLanguage),
|
||||
})
|
||||
@@ -497,24 +466,21 @@ export const ComposePost = ({
|
||||
[
|
||||
_,
|
||||
agent,
|
||||
composerState,
|
||||
draft,
|
||||
extLink,
|
||||
images,
|
||||
graphemeLength,
|
||||
isAltTextRequiredAndMissing,
|
||||
isProcessing,
|
||||
labels,
|
||||
langPrefs.postLanguage,
|
||||
onClose,
|
||||
onPost,
|
||||
postgate,
|
||||
quote,
|
||||
initQuote,
|
||||
initQuoteCount,
|
||||
replyTo,
|
||||
richtext.text,
|
||||
setLangPrefs,
|
||||
threadgateAllowUISettings,
|
||||
videoState.asset,
|
||||
videoState.status,
|
||||
queryClient,
|
||||
@@ -615,8 +581,10 @@ export const ComposePost = ({
|
||||
) : (
|
||||
<View style={[styles.postBtnWrapper]}>
|
||||
<LabelsBtn
|
||||
labels={labels}
|
||||
onChange={setLabels}
|
||||
labels={draft.labels}
|
||||
onChange={nextLabels => {
|
||||
dispatch({type: 'update_labels', labels: nextLabels})
|
||||
}}
|
||||
hasMedia={hasMedia || Boolean(extLink)}
|
||||
/>
|
||||
{canPost ? (
|
||||
@@ -698,7 +666,9 @@ export const ComposePost = ({
|
||||
richtext={richtext}
|
||||
placeholder={selectTextInputPlaceholder}
|
||||
autoFocus
|
||||
setRichText={setRichText}
|
||||
setRichText={rt => {
|
||||
dispatch({type: 'update_richtext', richtext: rt})
|
||||
}}
|
||||
onPhotoPasted={onPhotoPasted}
|
||||
onPressPublish={() => onPressPublish()}
|
||||
onNewLink={onNewLink}
|
||||
@@ -734,7 +704,7 @@ export const ComposePost = ({
|
||||
</View>
|
||||
)}
|
||||
|
||||
{!composerState.embed.media && extLink && (
|
||||
{!draft.embed.media && extLink && (
|
||||
<View style={a.relative} key={extLink}>
|
||||
<ExternalEmbedLink
|
||||
uri={extLink}
|
||||
@@ -815,12 +785,17 @@ export const ComposePost = ({
|
||||
|
||||
{replyTo ? null : (
|
||||
<ThreadgateBtn
|
||||
postgate={postgate}
|
||||
onChangePostgate={setPostgate}
|
||||
threadgateAllowUISettings={threadgateAllowUISettings}
|
||||
onChangeThreadgateAllowUISettings={
|
||||
onChangeThreadgateAllowUISettings
|
||||
}
|
||||
postgate={draft.postgate}
|
||||
onChangePostgate={nextPostgate => {
|
||||
dispatch({type: 'update_postgate', postgate: nextPostgate})
|
||||
}}
|
||||
threadgateAllowUISettings={draft.threadgate}
|
||||
onChangeThreadgateAllowUISettings={nextThreadgate => {
|
||||
dispatch({
|
||||
type: 'update_threadgate',
|
||||
threadgate: nextThreadgate,
|
||||
})
|
||||
}}
|
||||
style={bottomBarAnimatedStyle}
|
||||
Portal={Portal.Portal}
|
||||
/>
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import {ImagePickerAsset} from 'expo-image-picker'
|
||||
import {AppBskyFeedPostgate, RichText} from '@atproto/api'
|
||||
|
||||
import {insertMentionAt} from '#/lib/strings/mention-manip'
|
||||
import {
|
||||
isBskyPostUrl,
|
||||
postUriToRelativePath,
|
||||
toBskyAppUrl,
|
||||
} from '#/lib/strings/url-helpers'
|
||||
import {ComposerImage, createInitialImages} from '#/state/gallery'
|
||||
import {createPostgateRecord} from '#/state/queries/postgate/util'
|
||||
import {Gif} from '#/state/queries/tenor'
|
||||
import {threadgateViewToAllowUISetting} from '#/state/queries/threadgate'
|
||||
import {ThreadgateAllowUISetting} from '#/state/queries/threadgate'
|
||||
import {ComposerOpts} from '#/state/shell/composer'
|
||||
import {createVideoState, VideoAction, videoReducer, VideoState} from './video'
|
||||
|
||||
@@ -41,12 +46,19 @@ export type EmbedDraft = {
|
||||
link: Link | undefined
|
||||
}
|
||||
|
||||
export type ComposerState = {
|
||||
// TODO: Other draft data.
|
||||
export type ComposerDraft = {
|
||||
richtext: RichText
|
||||
labels: string[]
|
||||
postgate: AppBskyFeedPostgate.Record
|
||||
threadgate: ThreadgateAllowUISetting[]
|
||||
embed: EmbedDraft
|
||||
}
|
||||
|
||||
export type ComposerAction =
|
||||
| {type: 'update_richtext'; richtext: RichText}
|
||||
| {type: 'update_labels'; labels: string[]}
|
||||
| {type: 'update_postgate'; postgate: AppBskyFeedPostgate.Record}
|
||||
| {type: 'update_threadgate'; threadgate: ThreadgateAllowUISetting[]}
|
||||
| {type: 'embed_add_images'; images: ComposerImage[]}
|
||||
| {type: 'embed_update_image'; image: ComposerImage}
|
||||
| {type: 'embed_remove_image'; image: ComposerImage}
|
||||
@@ -67,10 +79,34 @@ export type ComposerAction =
|
||||
export const MAX_IMAGES = 4
|
||||
|
||||
export function composerReducer(
|
||||
state: ComposerState,
|
||||
state: ComposerDraft,
|
||||
action: ComposerAction,
|
||||
): ComposerState {
|
||||
): ComposerDraft {
|
||||
switch (action.type) {
|
||||
case 'update_richtext': {
|
||||
return {
|
||||
...state,
|
||||
richtext: action.richtext,
|
||||
}
|
||||
}
|
||||
case 'update_labels': {
|
||||
return {
|
||||
...state,
|
||||
labels: action.labels,
|
||||
}
|
||||
}
|
||||
case 'update_postgate': {
|
||||
return {
|
||||
...state,
|
||||
postgate: action.postgate,
|
||||
}
|
||||
}
|
||||
case 'update_threadgate': {
|
||||
return {
|
||||
...state,
|
||||
threadgate: action.threadgate,
|
||||
}
|
||||
}
|
||||
case 'embed_add_images': {
|
||||
if (action.images.length === 0) {
|
||||
return state
|
||||
@@ -293,12 +329,16 @@ export function composerReducer(
|
||||
}
|
||||
|
||||
export function createComposerState({
|
||||
initText,
|
||||
initMention,
|
||||
initImageUris,
|
||||
initQuoteUri,
|
||||
}: {
|
||||
initText: string | undefined
|
||||
initMention: string | undefined
|
||||
initImageUris: ComposerOpts['imageUris']
|
||||
initQuoteUri: string | undefined
|
||||
}): ComposerState {
|
||||
}): ComposerDraft {
|
||||
let media: ImagesMedia | undefined
|
||||
if (initImageUris?.length) {
|
||||
media = {
|
||||
@@ -317,7 +357,22 @@ export function createComposerState({
|
||||
}
|
||||
}
|
||||
}
|
||||
const initRichText = new RichText({
|
||||
text: initText
|
||||
? initText
|
||||
: initMention
|
||||
? insertMentionAt(
|
||||
`@${initMention}`,
|
||||
initMention.length + 1,
|
||||
`${initMention}`,
|
||||
)
|
||||
: '',
|
||||
})
|
||||
return {
|
||||
richtext: initRichText,
|
||||
labels: [],
|
||||
postgate: createPostgateRecord({post: ''}),
|
||||
threadgate: threadgateViewToAllowUISetting(undefined),
|
||||
embed: {
|
||||
quote,
|
||||
media,
|
||||
|
||||
@@ -43,7 +43,7 @@ export interface TextInputRef {
|
||||
interface TextInputProps extends ComponentProps<typeof RNTextInput> {
|
||||
richtext: RichText
|
||||
placeholder: string
|
||||
setRichText: (v: RichText | ((v: RichText) => RichText)) => void
|
||||
setRichText: (v: RichText) => void
|
||||
onPhotoPasted: (uri: string) => void
|
||||
onPressPublish: (richtext: RichText) => Promise<void>
|
||||
onNewLink: (uri: string) => void
|
||||
|
||||
Reference in New Issue
Block a user