Remove indirection when rendering composer state (#5954)
* Simplify onPressCancel dismiss condition * Remove alias variables * Move grapheme length calculation to reducer
This commit is contained in:
@@ -59,7 +59,6 @@ import {usePalette} from '#/lib/hooks/usePalette'
|
|||||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||||
import {logEvent} from '#/lib/statsig/statsig'
|
import {logEvent} from '#/lib/statsig/statsig'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
import {shortenLinks} from '#/lib/strings/rich-text-manip'
|
|
||||||
import {colors, s} from '#/lib/styles'
|
import {colors, s} from '#/lib/styles'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {isAndroid, isIOS, isNative, isWeb} from '#/platform/detection'
|
import {isAndroid, isIOS, isNative, isWeb} from '#/platform/detection'
|
||||||
@@ -128,8 +127,6 @@ type CancelRef = {
|
|||||||
onPressCancel: () => void
|
onPressCancel: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const NO_IMAGES: ComposerImage[] = []
|
|
||||||
|
|
||||||
type Props = ComposerOpts
|
type Props = ComposerOpts
|
||||||
export const ComposePost = ({
|
export const ComposePost = ({
|
||||||
replyTo,
|
replyTo,
|
||||||
@@ -178,33 +175,10 @@ export const ComposePost = ({
|
|||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
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
|
let videoState: VideoState | NoVideoState = NO_VIDEO
|
||||||
if (draft.embed.media?.type === 'video') {
|
if (draft.embed.media?.type === 'video') {
|
||||||
videoState = draft.embed.media.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])
|
|
||||||
|
|
||||||
const selectVideo = React.useCallback(
|
const selectVideo = React.useCallback(
|
||||||
(asset: ImagePickerAsset) => {
|
(asset: ImagePickerAsset) => {
|
||||||
@@ -252,10 +226,9 @@ export const ComposePost = ({
|
|||||||
|
|
||||||
const onPressCancel = useCallback(() => {
|
const onPressCancel = useCallback(() => {
|
||||||
if (
|
if (
|
||||||
graphemeLength > 0 ||
|
draft.shortenedGraphemeLength > 0 ||
|
||||||
images.length !== 0 ||
|
draft.embed.media ||
|
||||||
extGif ||
|
draft.embed.link
|
||||||
videoState.status !== 'idle'
|
|
||||||
) {
|
) {
|
||||||
closeAllDialogs()
|
closeAllDialogs()
|
||||||
Keyboard.dismiss()
|
Keyboard.dismiss()
|
||||||
@@ -263,15 +236,7 @@ export const ComposePost = ({
|
|||||||
} else {
|
} else {
|
||||||
onClose()
|
onClose()
|
||||||
}
|
}
|
||||||
}, [
|
}, [draft, closeAllDialogs, discardPromptControl, onClose])
|
||||||
extGif,
|
|
||||||
graphemeLength,
|
|
||||||
images.length,
|
|
||||||
closeAllDialogs,
|
|
||||||
discardPromptControl,
|
|
||||||
onClose,
|
|
||||||
videoState.status,
|
|
||||||
])
|
|
||||||
|
|
||||||
useImperativeHandle(cancelRef, () => ({onPressCancel}))
|
useImperativeHandle(cancelRef, () => ({onPressCancel}))
|
||||||
|
|
||||||
@@ -296,25 +261,27 @@ export const ComposePost = ({
|
|||||||
}, [onPressCancel, closeAllDialogs, closeAllModals])
|
}, [onPressCancel, closeAllDialogs, closeAllModals])
|
||||||
|
|
||||||
const isAltTextRequiredAndMissing = useMemo(() => {
|
const isAltTextRequiredAndMissing = useMemo(() => {
|
||||||
if (!requireAltTextEnabled) return false
|
const media = draft.embed.media
|
||||||
|
if (!requireAltTextEnabled || !media) {
|
||||||
if (images.some(img => img.alt === '')) return true
|
return false
|
||||||
|
}
|
||||||
if (extGif && !extGifAlt) return true
|
if (media.type === 'images' && media.images.some(img => !img.alt)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (media.type === 'gif' && !media.alt) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}, [images, extGifAlt, extGif, requireAltTextEnabled])
|
}, [draft.embed.media, requireAltTextEnabled])
|
||||||
|
|
||||||
const isEmptyPost =
|
const isEmptyPost =
|
||||||
richtext.text.trim().length === 0 &&
|
draft.richtext.text.trim().length === 0 &&
|
||||||
images.length === 0 &&
|
!draft.embed.link &&
|
||||||
!extLink &&
|
!draft.embed.media &&
|
||||||
!extGif &&
|
!draft.embed.quote
|
||||||
!quote &&
|
|
||||||
videoState.status === 'idle'
|
|
||||||
|
|
||||||
const canPost =
|
const canPost =
|
||||||
graphemeLength <= MAX_GRAPHEME_LENGTH &&
|
draft.shortenedGraphemeLength <= MAX_GRAPHEME_LENGTH &&
|
||||||
!isAltTextRequiredAndMissing &&
|
!isAltTextRequiredAndMissing &&
|
||||||
!isEmptyPost &&
|
!isEmptyPost &&
|
||||||
videoState.status !== 'error'
|
videoState.status !== 'error'
|
||||||
@@ -341,6 +308,11 @@ export const ComposePost = ({
|
|||||||
setError('')
|
setError('')
|
||||||
setIsPublishing(true)
|
setIsPublishing(true)
|
||||||
|
|
||||||
|
const imageCount =
|
||||||
|
draft.embed.media?.type === 'images'
|
||||||
|
? draft.embed.media.images.length
|
||||||
|
: 0
|
||||||
|
|
||||||
let postUri
|
let postUri
|
||||||
try {
|
try {
|
||||||
postUri = (
|
postUri = (
|
||||||
@@ -365,7 +337,7 @@ export const ComposePost = ({
|
|||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
logger.error(e, {
|
logger.error(e, {
|
||||||
message: `Composer: create post failed`,
|
message: `Composer: create post failed`,
|
||||||
hasImages: images.length > 0,
|
hasImages: imageCount > 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
let err = cleanError(e.message)
|
let err = cleanError(e.message)
|
||||||
@@ -382,10 +354,10 @@ export const ComposePost = ({
|
|||||||
} finally {
|
} finally {
|
||||||
if (postUri) {
|
if (postUri) {
|
||||||
logEvent('post:create', {
|
logEvent('post:create', {
|
||||||
imageCount: images.length,
|
imageCount,
|
||||||
isReply: replyTo != null,
|
isReply: !!replyTo,
|
||||||
hasLink: extLink != null,
|
hasLink: !!draft.embed.link,
|
||||||
hasQuote: quote != null,
|
hasQuote: !!draft.embed.quote,
|
||||||
langs: langPrefs.postLanguage,
|
langs: langPrefs.postLanguage,
|
||||||
logContext: 'Composer',
|
logContext: 'Composer',
|
||||||
})
|
})
|
||||||
@@ -422,14 +394,12 @@ export const ComposePost = ({
|
|||||||
_,
|
_,
|
||||||
agent,
|
agent,
|
||||||
composerState.thread,
|
composerState.thread,
|
||||||
extLink,
|
draft,
|
||||||
images,
|
|
||||||
canPost,
|
canPost,
|
||||||
isPublishing,
|
isPublishing,
|
||||||
langPrefs.postLanguage,
|
langPrefs.postLanguage,
|
||||||
onClose,
|
onClose,
|
||||||
onPost,
|
onPost,
|
||||||
quote,
|
|
||||||
initQuote,
|
initQuote,
|
||||||
replyTo,
|
replyTo,
|
||||||
setLangPrefs,
|
setLangPrefs,
|
||||||
@@ -512,7 +482,7 @@ export const ComposePost = ({
|
|||||||
/>
|
/>
|
||||||
</Animated.ScrollView>
|
</Animated.ScrollView>
|
||||||
|
|
||||||
<SuggestedLanguage text={richtext.text} />
|
<SuggestedLanguage text={draft.richtext.text} />
|
||||||
|
|
||||||
<ComposerPills
|
<ComposerPills
|
||||||
isReply={!!replyTo}
|
isReply={!!replyTo}
|
||||||
@@ -524,7 +494,6 @@ export const ComposePost = ({
|
|||||||
|
|
||||||
<ComposerFooter
|
<ComposerFooter
|
||||||
draft={draft}
|
draft={draft}
|
||||||
graphemeLength={graphemeLength}
|
|
||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
onError={setError}
|
onError={setError}
|
||||||
onEmojiButtonPress={onEmojiButtonPress}
|
onEmojiButtonPress={onEmojiButtonPress}
|
||||||
@@ -930,14 +899,12 @@ function ComposerPills({
|
|||||||
function ComposerFooter({
|
function ComposerFooter({
|
||||||
draft,
|
draft,
|
||||||
dispatch,
|
dispatch,
|
||||||
graphemeLength,
|
|
||||||
onEmojiButtonPress,
|
onEmojiButtonPress,
|
||||||
onError,
|
onError,
|
||||||
onSelectVideo,
|
onSelectVideo,
|
||||||
}: {
|
}: {
|
||||||
draft: PostDraft
|
draft: PostDraft
|
||||||
dispatch: (action: PostAction) => void
|
dispatch: (action: PostAction) => void
|
||||||
graphemeLength: number
|
|
||||||
onEmojiButtonPress: () => void
|
onEmojiButtonPress: () => void
|
||||||
onError: (error: string) => void
|
onError: (error: string) => void
|
||||||
onSelectVideo: (asset: ImagePickerAsset) => void
|
onSelectVideo: (asset: ImagePickerAsset) => void
|
||||||
@@ -1017,7 +984,10 @@ function ComposerFooter({
|
|||||||
</View>
|
</View>
|
||||||
<View style={[a.flex_row, a.align_center, a.justify_between]}>
|
<View style={[a.flex_row, a.align_center, a.justify_between]}>
|
||||||
<SelectLangBtn />
|
<SelectLangBtn />
|
||||||
<CharProgress count={graphemeLength} style={{width: 65}} />
|
<CharProgress
|
||||||
|
count={draft.shortenedGraphemeLength}
|
||||||
|
style={{width: 65}}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {AppBskyFeedPostgate, RichText} from '@atproto/api'
|
|||||||
|
|
||||||
import {SelfLabel} from '#/lib/moderation'
|
import {SelfLabel} from '#/lib/moderation'
|
||||||
import {insertMentionAt} from '#/lib/strings/mention-manip'
|
import {insertMentionAt} from '#/lib/strings/mention-manip'
|
||||||
|
import {shortenLinks} from '#/lib/strings/rich-text-manip'
|
||||||
import {
|
import {
|
||||||
isBskyPostUrl,
|
isBskyPostUrl,
|
||||||
postUriToRelativePath,
|
postUriToRelativePath,
|
||||||
@@ -51,6 +52,7 @@ export type PostDraft = {
|
|||||||
richtext: RichText
|
richtext: RichText
|
||||||
labels: SelfLabel[]
|
labels: SelfLabel[]
|
||||||
embed: EmbedDraft
|
embed: EmbedDraft
|
||||||
|
shortenedGraphemeLength: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PostAction =
|
export type PostAction =
|
||||||
@@ -137,6 +139,7 @@ function postReducer(state: PostDraft, action: PostAction): PostDraft {
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
richtext: action.richtext,
|
richtext: action.richtext,
|
||||||
|
shortenedGraphemeLength: shortenLinks(action.richtext).graphemeLength,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'update_labels': {
|
case 'update_labels': {
|
||||||
@@ -425,6 +428,7 @@ export function createComposerState({
|
|||||||
posts: [
|
posts: [
|
||||||
{
|
{
|
||||||
richtext: initRichText,
|
richtext: initRichText,
|
||||||
|
shortenedGraphemeLength: 0,
|
||||||
labels: [],
|
labels: [],
|
||||||
embed: {
|
embed: {
|
||||||
quote,
|
quote,
|
||||||
|
|||||||
Reference in New Issue
Block a user