Fix emoji picker

This commit is contained in:
N-Pex 2025-05-12 17:15:11 +02:00
parent bde99dc242
commit d766f9a0e3
7 changed files with 124 additions and 45 deletions

View file

@ -305,7 +305,14 @@
</div>
<MessageOperationsBottomSheet ref="messageOperationsSheet">
<EmojiPicker ref="emojiPicker" @select="emojiSelected" :i18n="i18nEmoji"/>
<EmojiPicker ref="emojiPicker"
@select="emojiSelected"
:additional-groups="additionalEmojiGroups"
:group-names="emojiGroupNames"
:group-icons="additionalEmojiGroupIcons"
:group-order="['recently_used']"
disable-skin-tones
:static-texts="{ placeholder: $t('emoji.search')}"/>
</MessageOperationsBottomSheet>
<StickerPickerBottomSheet ref="stickerPickerSheet" v-on:selectSticker="sendSticker" />
@ -358,6 +365,7 @@
<script>
import { TimelineWindow, EventTimeline } from "matrix-js-sdk";
import { toRaw } from "vue";
import util, { ROOM_TYPE_VOICE_MODE, ROOM_TYPE_FILE_MODE, ROOM_TYPE_CHANNEL } from "../plugins/utils";
import MessageOperations from "./messages/MessageOperations.vue";
import ChatHeader from "./ChatHeader";
@ -388,8 +396,10 @@ import { imageSize } from "image-size";
import prettyBytes from "pretty-bytes";
import RoomExport from "./RoomExport.vue";
import EmojiPicker from 'vue3-emoji-picker';
import 'vue3-emoji-picker/css';
import emitter from 'tiny-emitter/instance';
import { markRaw } from "vue";
import timerIcon from '@/assets/icons/ic_timer.svg';
const READ_RECEIPT_TIMEOUT = 5000; /* How long a message must have been visible before the read marker is updated */
const WINDOW_BUFFER_SIZE = 0.3; /** Relative window height of when we start paginating. Always keep this much loaded before and after our scroll position! */
@ -512,19 +522,16 @@ export default {
opStyle: "",
isEmojiQuickReaction: true,
i18nEmoji: {
search: this.$t("emoji.search"),
categories: {
Activity: this.$t("emoji.categories.activity"),
Flags: this.$t("emoji.categories.flags"),
Foods: this.$t("emoji.categories.foods"),
Frequently: this.$t("emoji.categories.frequently"),
Objects: this.$t("emoji.categories.objects"),
Nature: this.$t("emoji.categories.nature"),
Peoples: this.$t("emoji.categories.peoples"),
Symbols: this.$t("emoji.categories.symbols"),
Places: this.$t("emoji.categories.places")
}
emojiGroupNames: {
"smileys_people": this.$t("emoji.categories.peoples"),
"animals_nature": this.$t("emoji.categories.nature"),
"food_drink": this.$t("emoji.categories.foods"),
"activities": this.$t("emoji.categories.activity"),
"travel_places": this.$t("emoji.categories.places"),
"objects": this.$t("emoji.categories.objects"),
"symbols": this.$t("emoji.categories.symbols"),
"flags": this.$t("emoji.categories.flags"),
"recently_used": this.$t("emoji.categories.frequently"),
},
/**
@ -570,6 +577,12 @@ export default {
},
computed: {
additionalEmojiGroups() {
return { 'recently_used': this.recentEmojis }
},
additionalEmojiGroupIcons() {
return { 'recently_used': timerIcon }
},
latestReply() {
const contents = this.replyToEvent ? this.replyToEvent.getContent().body : "";
const contentArr = contents.split("\n").reverse();
@ -1229,7 +1242,6 @@ export default {
* Triggered when our "long tap" timer hits.
*/
touchTimerElapsed() {
this.updateRecentEmojis();
this.showContextMenu = true;
},
@ -1817,14 +1829,25 @@ export default {
if (this.selectedEvent) {
const event = this.selectedEvent;
this.selectedEvent = null;
this.sendQuickReaction({ reaction: e.data, event: event });
this.sendQuickReaction({ reaction: e.i, event: event });
}
} else {
// When text input emoji picker is clicked
this.currentInput = `${this.currentInput} ${e.data}`;
this.currentInput = `${this.currentInput} ${e.i}`;
this.$refs.messageInput.focus();
}
let emojis = this.recentEmojis;
const existingIdx = emojis.findIndex(emoji => emoji.u == e.u);
if (existingIdx >= 0) {
emojis.splice(existingIdx, 1);
}
emojis.splice(0, 0, markRaw(e));
if (emojis.length > 5) {
emojis.splice(5, emojis.length - 5);
}
this.recentEmojis = emojis;
this.showEmojiPicker = false;
this.$refs.messageOperationsSheet.close();
},
@ -1895,7 +1918,6 @@ export default {
this.showContextMenu = false;
this.$nextTick(() => {
this.selectedEvent = event;
this.updateRecentEmojis();
this.showContextMenuAnchor = e.anchor;
this.showContextMenu = true;
})
@ -2033,20 +2055,6 @@ export default {
});
},
updateRecentEmojis() {
if (this.$refs.emojiPicker) {
this.recentEmojis = this.$refs.emojiPicker.mapEmojis["Frequently"];
if (this.recentEmojis.length < 20) {
let peoples = this.$refs.emojiPicker.mapEmojis["Peoples"];
for (var p of peoples) {
this.recentEmojis.push(p);
}
}
return;
}
this.recentEmojis = [];
},
formatBytes(bytes) {
return prettyBytes(bytes);
},

View file

@ -111,6 +111,8 @@ export default {
}
.card {
padding: 0px !important;
display: flex;
flex-direction: column;
&[data-state="half"] {
top: 100px !important;

View file

@ -58,7 +58,7 @@ import ReadMarker from "./messages/ReadMarker.vue";
import roomDisplayOptionsMixin from "./roomDisplayOptionsMixin";
import roomTypeMixin from "./roomTypeMixin";
export const ROOM_READ_MARKER_EVENT_PLACEHOLDER = { getId: () => "ROOM_READ_MARKER" };
export const ROOM_READ_MARKER_EVENT_PLACEHOLDER = { getId: () => "ROOM_READ_MARKER", getTs: () => Date.now() };
export default {
mixins: [ roomDisplayOptionsMixin, roomTypeMixin ],

View file

@ -1,8 +1,8 @@
<template>
<div :class="{'message-operations':true,'incoming':incoming,'outgoing':!incoming}">
<template v-for="(item,index) in getEmojis" :key="item.data">
<v-btn v-if="userCanSendReactionAndAnswerPoll && index < maxRecents" id="btn-quick-reaction" icon @click.stop="addQuickReaction(item.data)" class="ma-0 pa-0" density="compact">
<span class="recent-emoji">{{ item.data }}</span>
<template v-for="(item,index) in getEmojis" :key="item.i">
<v-btn v-if="userCanSendReactionAndAnswerPoll && index < maxRecents" id="btn-quick-reaction" icon @click.stop="addQuickReaction(item.i)" class="ma-0 pa-0" density="compact">
<span class="recent-emoji">{{ item.i }}</span>
</v-btn>
</template>
<v-btn v-if="userCanSendReactionAndAnswerPoll" id="btn-more" icon @click.stop="more" class="ma-0 pa-0">