Skip to content

Commit

Permalink
Merge branch 'dev' into feat/focus-input-field
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulDremanovich committed Feb 26, 2024
2 parents 427814d + f6e4008 commit 895e583
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 33 deletions.
81 changes: 76 additions & 5 deletions src/components/AChat/AChatForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,20 @@
density="compact"
color="primary"
v-on="listeners"
autofocus
>
<template #prepend-inner>
<chat-emojis
@keydown.capture.esc="closeElement"
:open="emojiPickerOpen"
@onChange="onToggleEmojiPicker"
@get-emoji-picture="emojiPicture"
></chat-emojis>
</template>
<template v-if="showSendButton" #append-inner>
<slot name="append" />
<v-icon class="a-chat__send-icon" icon="mdi-send" size="28" />
</template>
<template #prepend>
<slot name="prepend" />
</template>
</v-textarea>

<div v-if="showSendButton" class="a-chat__form-send-area" @click="submitMessage" />
Expand All @@ -33,8 +40,10 @@

<script>
import { nextTick } from 'vue'
import ChatEmojis from '@/components/Chat/ChatEmojis.vue'
export default {
components: { ChatEmojis },
props: {
partnerId: {
default: '',
Expand Down Expand Up @@ -70,7 +79,8 @@ export default {
},
emits: ['message', 'esc', 'error'],
data: () => ({
message: ''
message: '',
emojiPickerOpen: false
}),
computed: {
className: () => 'a-chat',
Expand Down Expand Up @@ -129,14 +139,74 @@ export default {
} else if (!this.$isMobile) {
this.focus()
}
this.attachKeyCommandListener()
},
beforeUnmount() {
this.destroyKeyCommandListener()
},
methods: {
attachKeyCommandListener() {
window.addEventListener('keydown', this.onKeyCommand)
},
destroyKeyCommandListener() {
window.removeEventListener('keydown', this.onKeyCommand)
},
onKeyCommand: function (event) {
if (event.ctrlKey && event.shiftKey && event.code === 'Digit1') {
this.openElement()
}
},
openElement() {
this.emojiPickerOpen = true
},
closeElement() {
this.emojiPickerOpen = false
setTimeout(() => this.focus(), 0)
},
onInput: function () {
this.$store.commit('draftMessage/saveMessage', {
message: this.message,
partnerId: this.partnerId
})
},
emojiPicture(emoji) {
const caretPosition = this.$refs.messageTextarea.selectionStart
let before = this.message.slice(0, caretPosition)
const after = this.message.slice(caretPosition)
let emojiLength = emoji.length
if (
(before.length > 0 &&
!/\s|[[{(\n]/.test(before.slice(-1)) && // Check for a space, newline or parentheses before the emoji
!before
.slice(-2)
.match(
/[\p{Emoji_Presentation}\p{Emoji}\p{Emoji_Modifier_Base}\p{Emoji_Component}]/gu
)) ||
/[\d]/.test(before.slice(-1))
) {
before += ' '
emojiLength += 1
}
this.message = before + emoji + after
this.closeElement()
// Set the cursor position to after the newly inserted text
const newCaretPosition = caretPosition + emojiLength
this.focus()
this.$nextTick(() => {
this.$refs.messageTextarea.setSelectionRange(newCaretPosition, newCaretPosition)
})
this.onInput()
},
onToggleEmojiPicker(state) {
this.emojiPickerOpen = state
this.focus()
},
submitMessage() {
const error = this.validator(this.message)
if (error === false) {
Expand Down Expand Up @@ -189,7 +259,8 @@ export default {
margin-inline-end: 9px;
padding-top: 0;
}
.v-field__append-inner {
.v-field__append-inner,
.v-field__prepend-inner {
margin-top: auto;
padding-top: 0;
margin-bottom: 4px;
Expand Down
17 changes: 14 additions & 3 deletions src/components/AppSnackbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
v-model="show"
:timeout="timeout"
:color="color"
:class="className"
variant="elevated"
:class="[className, { outlined: variant === 'outlined' }]"
:variant="variant"
location="bottom"
width="100%"
:multi-line="message.length > 50"
@click:outside="show = false"
>
<div :class="`${className}__container`">
{{ message }}
<v-btn
v-if="timeout === 0 || timeout > 2000"
v-if="timeout === 0 || timeout > 2000 || timeout === -1"
size="x-small"
variant="text"
fab
Expand Down Expand Up @@ -48,6 +49,9 @@ export default {
},
timeout() {
return this.$store.state.snackbar.timeout
},
variant() {
return this.$store.state.snackbar.variant
}
}
}
Expand All @@ -65,6 +69,7 @@ export default {
margin: 0 auto;
border-radius: 0;
max-width: 300px;
border: 2px solid transparent;
}
:deep(.v-snackbar__content) {
Expand All @@ -83,6 +88,12 @@ export default {
padding: 0;
width: 36px;
}
&.outlined {
:deep(.v-snackbar__wrapper) {
border-color: map-get($adm-colors, 'danger');
}
}
}
.v-theme--light.app-snackbar {
Expand Down
22 changes: 9 additions & 13 deletions src/components/Chat/Chat.vue
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@
:show-send-button="true"
:send-on-enter="sendMessageOnEnter"
:show-divider="true"
:label="chatFormLabel"
:label="$t('chats.message')"
:message-text="
$route.query.messageText || $store.getters['draftMessage/draftMessage'](this.partnerId)
"
Expand All @@ -215,8 +215,9 @@
:validator="messageValidator.bind(this)"
:partner-id="partnerId"
>
<template #prepend>
<template #append>
<chat-menu
class="chat-menu"
:partner-id="partnerId"
:reply-to-id="replyMessageId > -1 ? replyMessageId : undefined"
/>
Expand Down Expand Up @@ -265,7 +266,6 @@ import AChatReactions from '@/components/AChat/AChatReactions/AChatReactions.vue
import { emojiWeight } from '@/lib/chat/emoji-weight/emojiWeight'
import { vibrate } from '@/lib/vibrate'
import { nextTick } from 'vue'
import { detect } from 'detect-browser'
import Visibility from 'visibilityjs'
import copyToClipboard from 'copy-to-clipboard'
Expand All @@ -292,6 +292,7 @@ import formatDate from '@/filters/date'
import CryptoIcon from '@/components/icons/CryptoIcon.vue'
import FreeTokensDialog from '@/components/FreeTokensDialog.vue'
import { isStringEqualCI } from '@/lib/textHelpers'
import { isMobile } from '@/lib/display-mobile'
import { isWelcomeChat, isWelcomeMessage } from '@/lib/chat/meta/utils'
import ProgressIndicator from '@/components/ProgressIndicator.vue'
Expand Down Expand Up @@ -377,7 +378,6 @@ export default {
},
emits: ['click:chat-avatar'],
data: () => ({
chatFormLabel: '',
loading: false,
replyLoadingChatHistory: false,
noMoreMessages: false,
Expand Down Expand Up @@ -480,13 +480,8 @@ export default {
this.visibilityId = Visibility.change((event, state) => {
if (state === 'visible' && this.isScrolledToBottom) this.markAsRead()
})
this.chatFormLabel =
{
'Mac OS': this.$t('chats.message_mac_os'),
'Windows 10': this.$t('chats.message_windows_10')
}[detect().os] || this.$t('chats.message')
const draftMessage = this.$store.getters['draftMessage/draftReplyTold'](this.partnerId)
const draftMessage = this.$store.getters['draftMessage/draftReplyTold'](this.partnerId)
if (draftMessage) {
this.replyMessageId = draftMessage
}
Expand Down Expand Up @@ -664,9 +659,7 @@ export default {
}
},
handleClickReactions(transaction) {
const isMobile = window.innerWidth < 600
if (isMobile) {
if (isMobile()) {
this.openActionsMenu(transaction)
} else {
this.toggleActionsDropdown(true, transaction)
Expand Down Expand Up @@ -792,6 +785,9 @@ export default {
</script>

<style scoped lang="scss">
.chat-menu {
margin-right: 8px;
}
.chat {
height: 100vh;
box-shadow: none;
Expand Down
56 changes: 56 additions & 0 deletions src/components/Chat/ChatEmojis.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<template>
<v-menu
:model-value="open"
@update:model-value="toggleMenu"
:close-on-content-click="false"
transition="slide-y-reverse-transition"
>
<template #activator="{ props }">
<v-icon class="chat-emojis__icon" icon="mdi-emoticon-outline" size="28" v-bind="props" />
</template>

<emoji-picker @emoji:select="getEmoji"></emoji-picker>
</v-menu>
</template>
<script>
import EmojiPicker from '@/components/EmojiPicker.vue'
export default {
props: {
open: {
type: Boolean,
required: true
}
},
emits: ['onChange', 'get-emoji-picture'],
methods: {
getEmoji(emoji) {
this.$emit('get-emoji-picture', emoji)
},
toggleMenu(state) {
this.$emit('onChange', state)
}
},
components: {
EmojiPicker
}
}
</script>
<style lang="scss" scoped>
@import 'vuetify/settings';
/** Themes **/
.v-theme--light {
.chat-emojis {
&__icon {
color: map-get($grey, 'darken-1');
}
}
}
.v-theme--dark {
.chat-emojis {
&__icon {
color: map-get($shades, 'white');
}
}
}
</style>
3 changes: 3 additions & 0 deletions src/components/EmojiPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { useTheme } from '@/hooks/useTheme'
import axios from 'axios'
import { defineComponent, onMounted, ref } from 'vue'
import { Picker } from 'emoji-mart'
import { isMobile } from '@/lib/display-mobile'
const className = 'emoji-picker'
const classes = {
root: className
Expand All @@ -36,6 +38,7 @@ export default defineComponent({
picker.value = new Picker({
data,
autoFocus: !isMobile(), // disable autofocus on mobile devices
dynamicWidth: true,
navPosition: 'none',
previewPosition: 'none',
Expand Down
8 changes: 8 additions & 0 deletions src/lib/display-mobile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { detect } from 'detect-browser'

export function isMobile(): boolean {
const browser = detect()
const isMobileDevice =
browser && browser.os ? ['android', 'ios'].includes(browser.os.toLowerCase()) : false
return isMobileDevice || window.innerWidth < 450
}
2 changes: 0 additions & 2 deletions src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
"estimate_fee": "Voraussichtliche Gebühr",
"incorrect_address": "Fehlerhafte Empfängeradresse",
"message": "Gib deine Nachricht ein",
"message_mac_os": "Type a message. Cmd + Ctrl + Space for Emoji picker",
"message_windows_10": "Type a message. Win + . for Emoji picker",
"new_chat": "Starte neuen Chat",
"new_chat_tooltip": "Klicke hier um eine neue Konversation zu starten",
"no_address": "Bitte gib die Empfängeradresse an",
Expand Down
2 changes: 0 additions & 2 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
"unable_to_retrieve_no_public_key": "`Unable to decrypt message: no partner's public key`",
"me": "Me",
"message": "Type a message",
"message_mac_os": "Type a message. Cmd + Ctrl + Space for Emoji picker",
"message_windows_10": "Type a message. Win + . for Emoji picker",
"my_qr_code": "My QR code",
"new_chat": "Start a new chat",
"no_connection": "No Internet connection",
Expand Down
2 changes: 0 additions & 2 deletions src/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
"unable_to_retrieve_no_public_key": "`Не могу прочитать сообщение: нет публичного ключа собеседника`",
"me": "Я",
"message": "Введите сообщение",
"message_mac_os": "Введите сообщение. Cmd + Ctrl + Space для выбора смайлика",
"message_windows_10": "Введите сообщение. Win + . для выбора смайлика",
"my_qr_code": "Мой QR-код",
"new_chat": "Начать новый чат",
"no_connection": "Нет подключения к Интернету",
Expand Down
2 changes: 0 additions & 2 deletions src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
"unable_to_retrieve_no_public_key": "`无法解密消息:没有合作伙伴的公钥`",
"me": "",
"message": "键入消息",
"message_mac_os": "键入消息。Cmd+Ctrl+Space for表情符号选取器",
"message_windows_10": "为表情符号选取器键入消息.Win+.",
"my_qr_code": "我的二维码",
"new_chat": "开始新的聊天",
"no_connection": "没有Internet连接",
Expand Down
Loading

0 comments on commit 895e583

Please sign in to comment.