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}
+