diff --git a/src/components/ChatView.vue b/src/components/ChatView.vue index 61140929946..d8d201241a5 100644 --- a/src/components/ChatView.vue +++ b/src/components/ChatView.vue @@ -86,6 +86,7 @@ import TransitionWrapper from './TransitionWrapper.vue' import { CONVERSATION } from '../constants.js' import { EventBus } from '../services/EventBus.js' +import { useChatExtrasStore } from '../stores/chatExtras.js' export default { @@ -108,6 +109,12 @@ export default { }, }, + setup() { + return { + chatExtrasStore: useChatExtrasStore(), + } + }, + data() { return { isChatScrolledToBottom: true, @@ -126,6 +133,10 @@ export default { return !userName && this.isGuest }, + isEditingMessage() { + return this.chatExtrasStore.getMessageIdToEdit(this.token) !== undefined + }, + dropHintText() { if (this.isGuest) { return t('spreed', 'You need to be logged in to upload files') @@ -155,7 +166,7 @@ export default { watch: { container(value) { this.containerId = value - } + }, }, mounted() { @@ -166,7 +177,7 @@ export default { methods: { handleDragOver(event) { - if (event.dataTransfer.types.includes('Files')) { + if (event.dataTransfer.types.includes('Files') && !this.isEditingMessage) { this.isDraggingOver = true } }, diff --git a/src/components/MessagesList/MessagesGroup/Message/Message.vue b/src/components/MessagesList/MessagesGroup/Message/Message.vue index 98a649ab6bf..96d5586729b 100644 --- a/src/components/MessagesList/MessagesGroup/Message/Message.vue +++ b/src/components/MessagesList/MessagesGroup/Message/Message.vue @@ -178,6 +178,7 @@ the main body of the message as well as a quote. :sent-icon-tooltip="sentIconTooltip" @show-translate-dialog="isTranslateDialogOpen = true" @reply="handleReply" + @edit="handleEdit" @delete="handleDelete" />
@@ -407,6 +408,26 @@ export default { type: String, default: '', }, + + lastEditActorDisplayName: { + type: String, + default: '', + }, + + lastEditActorId: { + type: String, + default: '', + }, + + lastEditActorType: { + type: String, + default: '', + }, + + lastEditTimestamp: { + type: Number, + default: 0, + }, }, emits: ['toggle-combined-system-message'], @@ -660,6 +681,10 @@ export default { containsCodeBlocks() { return this.message.includes('```') }, + + isFileShareOnly() { + return Object.keys(Object(this.messageParameters)).some(key => key.startsWith('file')) && this.message === '{file}' + }, }, watch: { @@ -756,6 +781,17 @@ export default { EventBus.$emit('focus-chat-input') }, + handleEdit() { + this.chatExtrasStore.setMessageIdToEdit(this.token, this.id) + if (this.isFileShareOnly) { + this.chatExtrasStore.setChatEditInput({ token: this.token, text: '' }) + } else { + this.chatExtrasStore.setChatEditInput({ token: this.token, text: this.message }) + } + EventBus.$emit('editing-message') + EventBus.$emit('focus-chat-input') + }, + async handleDelete() { this.isDeleting = true try { diff --git a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue index 56f85102d7f..699756087a7 100644 --- a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue +++ b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue @@ -48,7 +48,8 @@ @open="onMenuOpen" @close="onMenuClose"> {{ t('spreed', 'Reply privately') }} + + + {{ t('spreed', 'Edit message') }} + @@ -258,6 +279,7 @@ import ArrowLeft from 'vue-material-design-icons/ArrowLeft.vue' import CalendarClock from 'vue-material-design-icons/CalendarClock.vue' import Check from 'vue-material-design-icons/Check.vue' import CheckAll from 'vue-material-design-icons/CheckAll.vue' +import ClockEditOutline from 'vue-material-design-icons/ClockEditOutline.vue' import ClockOutline from 'vue-material-design-icons/ClockOutline.vue' import CloseCircleOutline from 'vue-material-design-icons/CloseCircleOutline.vue' import ContentCopy from 'vue-material-design-icons/ContentCopy.vue' @@ -267,6 +289,7 @@ import EyeOffOutline from 'vue-material-design-icons/EyeOffOutline.vue' import File from 'vue-material-design-icons/File.vue' import Note from 'vue-material-design-icons/NoteEditOutline.vue' import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue' +import Pencil from 'vue-material-design-icons/Pencil.vue' import Plus from 'vue-material-design-icons/Plus.vue' import Reply from 'vue-material-design-icons/Reply.vue' import Share from 'vue-material-design-icons/Share.vue' @@ -277,10 +300,12 @@ import { showError, showSuccess } from '@nextcloud/dialogs' import moment from '@nextcloud/moment' import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' +import NcActionButtonGroup from '@nextcloud/vue/dist/Components/NcActionButtonGroup.js' import NcActionInput from '@nextcloud/vue/dist/Components/NcActionInput.js' import NcActionLink from '@nextcloud/vue/dist/Components/NcActionLink.js' import NcActions from '@nextcloud/vue/dist/Components/NcActions.js' import NcActionSeparator from '@nextcloud/vue/dist/Components/NcActionSeparator.js' +import NcActionText from '@nextcloud/vue/dist/Components/NcActionText.js' import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' import NcEmojiPicker from '@nextcloud/vue/dist/Components/NcEmojiPicker.js' @@ -300,10 +325,12 @@ export default { components: { MessageForwarder, + NcActionButtonGroup, NcActionButton, NcActionInput, NcActionLink, NcActionSeparator, + NcActionText, NcActions, NcButton, NcEmojiPicker, @@ -315,6 +342,7 @@ export default { CloseCircleOutline, Check, CheckAll, + ClockEditOutline, ClockOutline, ContentCopy, DeleteIcon, @@ -323,6 +351,7 @@ export default { File, Note, OpenInNewIcon, + Pencil, Plus, Reply, Share, @@ -447,7 +476,7 @@ export default { }, }, - emits: ['delete', 'update:isActionMenuOpen', 'update:isEmojiPickerOpen', 'update:isReactionsMenuOpen', 'update:isForwarderOpen', 'show-translate-dialog', 'reply'], + emits: ['delete', 'update:isActionMenuOpen', 'update:isEmojiPickerOpen', 'update:isReactionsMenuOpen', 'update:isForwarderOpen', 'show-translate-dialog', 'reply', 'edit'], setup() { const reactionsStore = useReactionsStore() @@ -482,8 +511,21 @@ export default { return this.getMessagesListScroller() }, + isModifiable() { + return !this.isConversationReadOnly && this.conversation.participantType !== PARTICIPANT.TYPE.GUEST + }, + + isEditable() { + if (!this.isModifiable || this.isObjectShare + || (!this.$store.getters.isModerator && !this.isMyMsg)) { + return false + } + + return (moment(this.timestamp * 1000).add(1, 'd')) > moment() + }, + isDeleteable() { - if (this.isConversationReadOnly || this.conversation.participantType === PARTICIPANT.TYPE.GUEST) { + if (!this.isModifiable) { return false } @@ -523,6 +565,10 @@ export default { return this.isFileShare && this.message === '{file}' }, + isObjectShare() { + return Object.keys(Object(this.messageParameters)).some(key => key.startsWith('object')) + }, + isCurrentGuest() { return this.$store.getters.getActorType() === 'guests' }, @@ -560,6 +606,10 @@ export default { return moment(this.timestamp * 1000).format('lll') }, + editedDateTime() { + return moment(this.messageObject.lastEditTimestamp * 1000).format('lll') + }, + reminderOptions() { const currentDateTime = moment() @@ -791,6 +841,10 @@ export default { setCustomReminder() { this.setReminder(this.customReminderDateTime.valueOf()) }, + + editMessage() { + this.$emit('edit') + }, }, } diff --git a/src/components/MessagesList/MessagesGroup/MessagesGroup.vue b/src/components/MessagesList/MessagesGroup/MessagesGroup.vue index 678b5664cc5..e1f683560f0 100644 --- a/src/components/MessagesList/MessagesGroup/MessagesGroup.vue +++ b/src/components/MessagesList/MessagesGroup/MessagesGroup.vue @@ -32,6 +32,9 @@
-
- +
+
+ + +