diff --git a/src/assets/css/chat.scss b/src/assets/css/chat.scss index e115e73..04ad1bf 100644 --- a/src/assets/css/chat.scss +++ b/src/assets/css/chat.scss @@ -377,15 +377,24 @@ $admin-fg: white; .message-operations { position: absolute; width: fit-content; - background-color: #e2e2e2; + background-color: white; + height: 40px; + border-radius: 20px; + box-shadow: 4px 4px 8px #888888; // &.incoming { // right: 30%; // } // &.outgoing { - // left: 30%; + // left: unset !important; + // right: 10px !important; // } } +.message-operations-picker { + background-color: white; + text-align: center; +} + .quick-reaction-container { position: absolute; background-color: #000000; diff --git a/src/components/Chat.vue b/src/components/Chat.vue index 40c488c..390085b 100644 --- a/src/components/Chat.vue +++ b/src/components/Chat.vue @@ -13,16 +13,19 @@ >
@@ -255,11 +258,22 @@ -
- - - -
+ +
+ + +
+
@@ -321,6 +335,7 @@ import RoomJoinRules from "./messages/RoomJoinRules.vue"; import DebugEvent from "./messages/DebugEvent.vue"; import util from "../plugins/utils"; import MessageOperations from "./messages/MessageOperations.vue"; +import MessageOperationsPicker from "./messages/MessageOperationsPicker.vue"; import ChatHeader from "./ChatHeader"; import VoiceRecorder from "./VoiceRecorder"; import RoomInfoBottomSheet from "./RoomInfoBottomSheet"; @@ -379,6 +394,7 @@ export default { RoomJoinRules, DebugEvent, MessageOperations, + MessageOperationsPicker, VoiceRecorder, RoomInfoBottomSheet, CreatedRoomWelcomeHeader @@ -430,7 +446,10 @@ export default { lastRR: null, /** If we just created this room, show a small welcome header with info */ - showCreatedRoomWelcomeHeader: false + showCreatedRoomWelcomeHeader: false, + + /** An array of recent emojis. Used in the "message operations" popup. */ + recentEmojis: [] }; }, @@ -522,6 +541,9 @@ export default { var rectChat = this.$refs.messageOperationsStrut.getBoundingClientRect(); top = rectAnchor.top - rectChat.top; left = rectAnchor.left - rectChat.left; + if (left + 250 > rectChat.right) { + left = rectChat.right - 250; // Pretty ugly, but we want to make sure it does not escape the screen, and we don't have the exakt width of it (yet)! + } } } return "top:" + top + "px;left:" + left + "px"; @@ -713,6 +735,7 @@ export default { * Triggered when our "long tap" timer hits. */ touchTimerElapsed() { + this.updateRecentEmojis(); this.showContextMenu = true; }, @@ -1040,6 +1063,10 @@ export default { }); }, + showMoreMessageOperations(e) { + this.addReaction(e); + }, + addReaction(e) { const event = e.event; // Store the event we are reacting to, so that we know where to @@ -1048,6 +1075,10 @@ export default { this.showEmojiPicker = true; }, + addQuickReaction(e) { + this.sendQuickReaction({ reaction: e.emoji, event: e.event }); + }, + addReply(event) { this.replyToEvent = event; this.$refs.messageInput.focus(); @@ -1124,6 +1155,7 @@ export default { console.log("Got the ref", ref); } this.selectedEvent = event; + this.updateRecentEmojis(); this.showContextMenu = true; this.showContextMenuAnchor = e.anchor; }, @@ -1258,7 +1290,16 @@ export default { // can see all messages). this.onScroll(); }); + }, + + updateRecentEmojis() { + if (this.$refs.emojiPicker) { + this.recentEmojis = this.$refs.emojiPicker.mapEmojis["Frequently"]; + return; + } + this.recentEmojis = []; } + }, }; diff --git a/src/components/messages/MessageOperations.vue b/src/components/messages/MessageOperations.vue index 0727887..3260bba 100644 --- a/src/components/messages/MessageOperations.vue +++ b/src/components/messages/MessageOperations.vue @@ -1,86 +1,54 @@ \ No newline at end of file diff --git a/src/components/messages/MessageOperationsPicker.vue b/src/components/messages/MessageOperationsPicker.vue new file mode 100644 index 0000000..61b450e --- /dev/null +++ b/src/components/messages/MessageOperationsPicker.vue @@ -0,0 +1,51 @@ + + + + + \ No newline at end of file diff --git a/src/components/messages/messageMixin.js b/src/components/messages/messageMixin.js index 3065e00..e23496d 100644 --- a/src/components/messages/messageMixin.js +++ b/src/components/messages/messageMixin.js @@ -62,6 +62,10 @@ export default { } }, computed: { + incoming() { + return this.event && this.event.getSender() != this.$matrix.currentUserId; + }, + /** * Don't show sender and time if the next event is within 2 minutes and also from us (= back to back messages) */ diff --git a/src/components/messages/messageOperationsMixin.js b/src/components/messages/messageOperationsMixin.js new file mode 100644 index 0000000..c151228 --- /dev/null +++ b/src/components/messages/messageOperationsMixin.js @@ -0,0 +1,49 @@ + +export default { + computed: { + isEditable() { + return !this.incoming && this.event.getContent().msgtype == "m.text"; + }, + isDownloadable() { + const msgtype = this.event.getContent().msgtype; + return ['m.video','m.audio','m.image','m.file'].includes(msgtype); + }, + isRedactable() { + const room = this.$matrix.matrixClient.getRoom(this.event.getRoomId()); + if (room && room.currentState && room.currentState.maySendRedactionForEvent(this.event, this.$matrix.currentUserId)) { + return true; + } + return false; + } + }, + methods: { + addReaction() { + this.$emit("close"); + this.$emit("addreaction", {event:this.event}); + }, + addQuickReaction(emoji) { + this.$emit("close"); + this.$emit("addquickreaction", {event:this.event,emoji:emoji}); + }, + addReply() { + this.$emit("close"); + this.$emit("addreply", {event:this.event}); + }, + edit() { + this.$emit("close"); + this.$emit("edit", {event:this.event}); + }, + redact() { + this.$emit("close"); + this.$emit("redact", {event:this.event}); + }, + download() { + this.$emit("close"); + this.$emit("download", {event:this.event}); + }, + more() { + this.$emit("close"); + this.$emit("more", {event:this.event}); + }, + } +} \ No newline at end of file