From aa8f0922fb4dc85ed37f9de9322e05c37b3089c7 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Tue, 2 Jan 2024 12:22:40 +0900 Subject: [PATCH] refs #4653 Show characters count in compose --- locales/en/translation.json | 8 +++++-- renderer/components/compose/Compose.tsx | 32 ++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/locales/en/translation.json b/locales/en/translation.json index 0ac29dc0..8d424231 100644 --- a/locales/en/translation.json +++ b/locales/en/translation.json @@ -109,9 +109,13 @@ }, "alert": { "validation": { - "attachment_type": "You can attach only images or videos" + "attachment_type": "You can attach only images or videos", + "attachment_length": "You can't attach over {limit} files" }, - "upload_error": "Failed to upload the file" + "upload_error": "Failed to upload the file", + "compose": { + "post_failed": "Failed to post a status" + } }, "profile": { "follow": "Follow", diff --git a/renderer/components/compose/Compose.tsx b/renderer/components/compose/Compose.tsx index dcf4199d..f8105d7d 100644 --- a/renderer/components/compose/Compose.tsx +++ b/renderer/components/compose/Compose.tsx @@ -63,12 +63,25 @@ export default function Compose(props: Props) { const [poll, setPoll] = useState(null) const [loading, setLoading] = useState(false) const [editMedia, setEditMedia] = useState() + const [maxCharacters, setMaxCharacters] = useState(null) + const [remaining, setRemaining] = useState(null) const { formatMessage } = useIntl() const uploaderRef = useRef(null) const showToast = useToast() const textareaRef = useRef(null) + useEffect(() => { + if (!props.client) return + const f = async () => { + const instance = await props.client.getInstance() + if (instance.data.configuration.statuses.max_characters) { + setMaxCharacters(instance.data.configuration.statuses.max_characters) + } + } + f() + }, [props.client]) + useEffect(() => { if (!cw) { setSpoiler('') @@ -89,6 +102,12 @@ export default function Compose(props: Props) { } }, [props.in_reply_to]) + useEffect(() => { + if (maxCharacters) { + setRemaining(maxCharacters - body.length - spoiler.length) + } + }, [maxCharacters, body, spoiler]) + const post = async () => { if (body.length === 0) return let options = { visibility: visibility } @@ -117,6 +136,9 @@ export default function Compose(props: Props) { try { await props.client.postStatus(body, options) reset() + } catch (err) { + console.error(err) + showToast({ text: formatMessage({ id: 'alert.compose.post_failed' }), type: 'failure' }) } finally { setLoading(false) } @@ -128,6 +150,7 @@ export default function Compose(props: Props) { setCW(false) setAttachments([]) setPoll(null) + setMaxCharacters(null) } const handleKeyPress = useCallback( @@ -158,6 +181,10 @@ export default function Compose(props: Props) { if (file === null || file === undefined) { return } + if (attachments.length >= 4) { + showToast({ text: formatMessage({ id: 'alert.validation.attachment_length' }, { limit: 4 }), type: 'failure' }) + return + } if (!file.type.includes('image') && !file.type.includes('video')) { showToast({ text: formatMessage({ id: 'alert.validation.attachment_type' }), type: 'failure' }) return @@ -302,7 +329,10 @@ export default function Compose(props: Props) { )}
- {loading ? : } + {remaining} +