Skip to content

Commit 8287bab

Browse files
committedNov 17, 2019
Инлайн клавиатура
1 parent 95bfdc3 commit 8287bab

File tree

8 files changed

+170
-136
lines changed

8 files changed

+170
-136
lines changed
 

Diff for: ‎src/components/UI/Scrolly.vue

+3-3
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,8 @@
307307
transition: opacity .3s ease;
308308
}
309309
310-
.scrolly.isScrolling .scrolly-bar,
311-
.scrolly.isActive .scrolly-bar {
310+
.scrolly.isScrolling > .scrolly-bar-wrap .scrolly-bar,
311+
.scrolly.isActive > .scrolly-bar-wrap .scrolly-bar {
312312
opacity: 1;
313313
}
314314
@@ -323,7 +323,7 @@
323323
}
324324
325325
.scrolly-bar:hover:before,
326-
.scrolly.isScrolling .scrolly-bar:before {
326+
.scrolly.isScrolling > .scrolly-bar-wrap .scrolly-bar:before {
327327
background: rgba(0, 0, 0, .4);
328328
}
329329

Diff for: ‎src/components/messages/chat/Input.vue

+10-81
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
@input="onInput"
1313
@drop.prevent
1414
@paste.prevent="paste"
15-
@keydown.enter.exact.prevent="sendMessage()"
15+
@keydown.enter.exact.prevent="send"
1616
></div>
1717
<Icon v-if="hasKeyboard"
1818
name="keyboard"
@@ -22,9 +22,9 @@
2222
/>
2323
<img class="emoji_btn" src="~assets/emoji_icon.svg">
2424
</div>
25-
<img class="send_btn" src="~assets/im_send.svg" @click="sendMessage()">
25+
<img class="send_btn" src="~assets/im_send.svg" @click="send">
2626
</div>
27-
<Keyboard v-if="hasKeyboard && showKeyboard" :keyboard="keyboard" @click="sendMessage" />
27+
<Keyboard v-if="hasKeyboard && showKeyboard" :peer_id="peer_id" :keyboard="keyboard" />
2828
</template>
2929
<Ripple v-else-if="canWrite.channel" class="chat_input_error channel" color="#e1e5f0" @click="toggleNotifications">
3030
<template v-if="peer.left">
@@ -45,8 +45,8 @@
4545

4646
<script>
4747
import electron from 'electron';
48-
import { getTextWithEmoji, getLastMsgId } from 'js/messages';
49-
import { random, throttle, escape, eventBus } from 'js/utils';
48+
import { throttle, escape } from 'js/utils';
49+
import sendMessage from 'js/sendMessage';
5050
import emoji from 'js/emoji';
5151
import vkapi from 'js/vkapi';
5252
@@ -85,82 +85,11 @@
8585
}
8686
},
8787
methods: {
88-
async sendMessage(action, author_id) {
89-
const random_id = random(-2e9, 2e9);
90-
let text;
91-
92-
if(action) {
93-
const { domain } = this.$store.state.profiles[author_id];
94-
95-
text = this.peer_id > 2e9 ? `@${domain} ${action.label}` : action.label;
96-
97-
if(this.keyboard.one_time) {
98-
this.$store.commit('messages/updateConversation', {
99-
peer: {
100-
id: this.peer_id,
101-
keyboard: {}
102-
}
103-
});
104-
}
105-
} else {
106-
text = getTextWithEmoji(this.$refs.input.childNodes);
107-
}
108-
109-
if(!text) return;
110-
111-
this.$refs.input.innerHTML = '';
112-
this.counter++;
113-
114-
try {
115-
this.$store.commit('messages/addLoadingMessage', {
116-
peer_id: this.peer_id,
117-
msg: {
118-
id: getLastMsgId() + this.counter*1e5,
119-
text,
120-
from: this.$store.getters['users/user'].id,
121-
date: (Date.now() / 1000).toFixed(),
122-
out: true,
123-
editTime: 0,
124-
fwdCount: 0,
125-
fwdMessages: [],
126-
attachments: [],
127-
random_id,
128-
isLoading: true
129-
}
130-
});
131-
132-
await this.$nextTick();
133-
134-
eventBus.emit('messages:jumpTo', {
135-
peer_id: this.peer_id,
136-
bottom: true,
137-
mark: false
138-
});
139-
140-
await vkapi('messages.send', {
141-
peer_id: this.peer_id,
142-
message: text,
143-
random_id,
144-
payload: action && action.payload
145-
});
146-
} catch(e) {
147-
this.$store.commit('messages/editLoadingMessage', {
148-
peer_id: this.peer_id,
149-
random_id,
150-
isLoadingFailed: true
151-
});
152-
153-
// 900 = Нельзя отправить пользователю из черного списка
154-
// 902 = Нельзя отправить сообщение из-за настроек приватности собеседника
155-
if([900, 902].includes(e.error_code)) {
156-
this.$store.commit('messages/updateConversation', {
157-
peer: {
158-
id: this.peer_id,
159-
canWrite: false
160-
}
161-
});
162-
}
163-
}
88+
send() {
89+
sendMessage({
90+
peer_id: this.peer_id,
91+
input: this.$refs.input
92+
});
16493
},
16594
16695
toggleNotifications() {

Diff for: ‎src/components/messages/chat/Keyboard.vue

+29-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<Scrolly vclass="keyboard">
2+
<Scrolly :vclass="['keyboard', { inline: keyboard.inline }]">
33
<div v-for="line of buttons" class="keyboard_line">
44
<Ripple v-for="({ action, color }, i) of line" :key="i"
55
:color="color == 'default' && action.type != 'vkpay' ? '#ced7e0' : 'rgba(0, 0, 0, .2)'"
@@ -22,15 +22,16 @@
2222
</template>
2323

2424
<script>
25+
import electron from 'electron';
26+
import sendMessage from 'js/sendMessage';
27+
2528
import Scrolly from '../../UI/Scrolly.vue';
2629
import Ripple from '../../UI/Ripple.vue';
27-
import emoji from 'js/emoji';
28-
import electron from 'electron';
2930
3031
const { shell } = electron.remote;
3132
3233
export default {
33-
props: ['keyboard'],
34+
props: ['peer_id', 'keyboard'],
3435
components: {
3536
Scrolly,
3637
Ripple
@@ -41,20 +42,27 @@
4142
}
4243
},
4344
methods: {
44-
emoji,
4545
click(action) {
46+
const hash = action.hash ? `#${action.hash}` : '';
47+
4648
switch(action.type) {
4749
case 'text':
48-
this.$emit('click', action, this.keyboard.author_id);
50+
sendMessage({
51+
peer_id: this.peer_id,
52+
keyboard: {
53+
action,
54+
author_id: this.keyboard.author_id,
55+
one_time: this.keyboard.one_time
56+
}
57+
});
4958
break;
5059
5160
case 'open_app':
52-
const hash = action.hash ? `#${action.hash}` : '';
5361
shell.openExternal(`https://vk.com/app${action.app_id}${hash}`);
5462
break;
5563
5664
case 'vkpay':
57-
shell.openExternal(`https://vk.com/app6217559#${action.hash}`);
65+
shell.openExternal(`https://vk.com/app6217559${hash}`);
5866
break;
5967
}
6068
}
@@ -68,6 +76,10 @@
6876
padding: 8px 12px 12px 12px;
6977
}
7078
79+
.keyboard.inline {
80+
padding: 6px 0 0 0;
81+
}
82+
7183
.keyboard_line {
7284
display: flex;
7385
}
@@ -76,6 +88,10 @@
7688
padding-bottom: 8px;
7789
}
7890
91+
.keyboard.inline .keyboard_line:not(:last-child) {
92+
padding-bottom: 6px;
93+
}
94+
7995
.keyboard_button {
8096
display: flex;
8197
align-items: center;
@@ -93,6 +109,10 @@
93109
text-overflow: ellipsis;
94110
}
95111
112+
.keyboard.inline .keyboard_button {
113+
margin: 0;
114+
}
115+
96116
.keyboard_button.default {
97117
background: #e5ebf1;
98118
color: #55677d;
@@ -110,7 +130,7 @@
110130
background: #e64646;
111131
}
112132
113-
.keyboard_button img {
133+
.keyboard_button img:not(.emoji) {
114134
height: 24px;
115135
}
116136
</style>

Diff for: ‎src/components/messages/chat/List.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@
476476
right: 0;
477477
width: fit-content;
478478
margin: 0 auto;
479-
z-index: 1;
479+
z-index: 2;
480480
background-color: #fff;
481481
border: solid 1px #cfd9e1;
482482
border-radius: 15px;

Diff for: ‎src/components/messages/chat/Message.vue

+23-15
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,27 @@
99
<img v-if="showUserData" class="message_photo" :src="photo">
1010
<div v-else-if="isChat && !msg.out && !isChannel" class="message_photo"></div>
1111

12-
<div class="message_bubble">
13-
<Reply :msg="msg" :peer_id="peer_id" />
12+
<div class="message_bubble_wrap">
13+
<div class="message_bubble">
14+
<Reply :msg="msg" :peer_id="peer_id" />
1415

15-
<div v-if="msg.isContentDeleted" class="message_text isContentDeleted">{{ l('im_content_deleted') }}</div>
16-
<div v-else class="message_text" v-emoji.push.br="msg.text"></div>
16+
<div v-if="msg.isContentDeleted" class="message_text isContentDeleted">{{ l('im_content_deleted') }}</div>
17+
<div v-else class="message_text" v-emoji.push.br="msg.text"></div>
1718

18-
<Attachments :msg="msg" />
19-
<Forwarded :msg="msg" />
19+
<Attachments :msg="msg" />
20+
<Forwarded :msg="msg" />
2021

21-
<div class="message_time_wrap">
22-
<template v-if="msg.editTime">
23-
<div class="message_edited">{{ l('im_msg_edited') }}</div>
24-
<div class="dot"></div>
25-
</template>
22+
<div class="message_time_wrap">
23+
<template v-if="msg.editTime">
24+
<div class="message_edited">{{ l('im_msg_edited') }}</div>
25+
<div class="dot"></div>
26+
</template>
2627

27-
<div class="message_time">{{ time }}</div>
28+
<div class="message_time">{{ time }}</div>
29+
</div>
2830
</div>
31+
32+
<Keyboard v-if="msg.keyboard" :peer_id="peer_id" :keyboard="msg.keyboard" />
2933
</div>
3034
</div>
3135
</div>
@@ -38,13 +42,15 @@
3842
import Attachments from './attachments/Attachments.vue';
3943
import Reply from './attachments/Reply.vue';
4044
import Forwarded from './attachments/Forwarded.vue';
45+
import Keyboard from './Keyboard.vue';
4146
4247
export default {
4348
props: ['msg', 'peer', 'peer_id', 'messageDate', 'isStartUnread', 'prevMsg'],
4449
components: {
4550
Attachments,
4651
Reply,
47-
Forwarded
52+
Forwarded,
53+
Keyboard
4854
},
4955
computed: {
5056
user() {
@@ -69,7 +75,7 @@
6975
return this.peer && (
7076
this.msg.id > this.peer.out_read || // непрочитано собеседником
7177
this.msg.id > this.peer.in_read // непрочитано мной
72-
);
78+
) || this.msg.isLoading;
7379
},
7480
showUserData() {
7581
return !this.msg.out && this.isChat && !this.isChannel && (
@@ -135,9 +141,11 @@
135141
margin-right: 10px;
136142
}
137143
138-
.message_bubble {
144+
.message_bubble_wrap {
139145
position: relative;
140146
max-width: 75%;
147+
display: flex;
148+
flex-direction: column;
141149
}
142150
143151
.message_wrap:not(.hideBubble) .message_bubble {

Diff for: ‎src/js/longpollEvents.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { timer, eventBus } from './utils';
77

88
function hasFlag(mask, flag) {
99
const flags = {
10-
unread: 1 << 0, // Приходит всегда
10+
unread: 1, // Приходит всегда
1111
outbox: 1 << 1, // Сообщение от тебя
1212
important: 1 << 3, // Важное сообщение
1313
chat: 1 << 4, // Отправка сообщения в беседу через (m.)vk.com
@@ -109,10 +109,12 @@ function getMessage(data) {
109109
const isReplyMsg = flag('reply_msg');
110110
const hasAttachment = isReplyMsg || data[6].fwd || attachments.length;
111111

112+
if(keyboard) keyboard.author_id = from_id;
113+
112114
return {
113115
peer: {
114116
id: data[2],
115-
keyboard: keyboard && Object.assign(keyboard, { author_id: from_id }),
117+
keyboard: keyboard && !keyboard.inline && keyboard,
116118
channel: from_id < 0 && data[2] > 2e9 && data[5].title === '',
117119
mentions: data[5].mentions || []
118120
},
@@ -133,7 +135,8 @@ function getMessage(data) {
133135
random_id: data[7],
134136
was_listened: false,
135137
hasAttachment: hasAttachment,
136-
isContentDeleted: !data[4] && !action && !hasAttachment
138+
isContentDeleted: !data[4] && !action && !hasAttachment,
139+
keyboard: keyboard && keyboard.inline && keyboard
137140
}
138141
};
139142
}

Diff for: ‎src/js/messages.js

+3-24
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { escape, getPhoto, fields, loadProfile, concatProfiles } from './utils';
22
import getTranslate from './getTranslate';
33
import store from './store';
4-
import emoji, { getEmojiCode } from './emoji';
4+
import emoji from './emoji';
55
import vkapi from './vkapi';
66

77
const loadedConvMembers = {};
@@ -59,7 +59,8 @@ export function parseMessage(message) {
5959
random_id: message.random_id,
6060
was_listened: !!message.was_listened,
6161
hasAttachment: hasAttachment,
62-
isContentDeleted: !message.text && !message.action && !hasAttachment
62+
isContentDeleted: !message.text && !message.action && !hasAttachment,
63+
keyboard: message.keyboard
6364
};
6465
}
6566

@@ -151,28 +152,6 @@ export function getMessagePreview(msg, peer_id, author) {
151152
}
152153
}
153154

154-
export function getTextWithEmoji(nodes) {
155-
let text = '';
156-
157-
for(const node of nodes || []) {
158-
switch(node.nodeName) {
159-
case 'IMG':
160-
text += node.alt;
161-
break;
162-
163-
case 'BR':
164-
text += '<br>';
165-
break;
166-
167-
default:
168-
text += node.data || node.innerText || '';
169-
break;
170-
}
171-
}
172-
173-
return text.replace(/\n/g, '').trim();
174-
}
175-
176155
export function getLastMsgId() {
177156
const [peer] = store.getters['messages/conversationsList'];
178157

Diff for: ‎src/js/sendMessage.js

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { random, eventBus } from './utils';
2+
import store from './store';
3+
import vkapi from './vkapi';
4+
import Vue from 'vue';
5+
6+
let counter = 0;
7+
8+
function parseInputText(nodes) {
9+
let text = '';
10+
11+
for(const node of nodes || []) {
12+
if(node.nodeName == '#text') text += node.data;
13+
if(node.nodeName == 'BR') text += '<br>';
14+
if(node.nodeName == 'IMG') text += node.alt;
15+
}
16+
17+
return text.replace(/\n/g, '').replace(/<br>/g, '\n').trim().replace(/\n/g, '<br>');
18+
}
19+
20+
export default async function sendMessage({ peer_id, input, keyboard }) {
21+
const random_id = random(-2e9, 2e9);
22+
let message;
23+
24+
if(keyboard) {
25+
const { author_id, action, one_time } = keyboard;
26+
const { domain } = store.state.profiles[author_id];
27+
28+
message = peer_id > 2e9 ? `@${domain} ${action.label}` : action.label;
29+
30+
if(one_time) {
31+
store.commit('messages/updateConversation', {
32+
peer: {
33+
id: peer_id,
34+
keyboard: {}
35+
}
36+
});
37+
}
38+
} else {
39+
message = parseInputText(input.childNodes);
40+
}
41+
42+
if(!message) return;
43+
if(input) input.innerHTML = '';
44+
45+
try {
46+
store.commit('messages/addLoadingMessage', {
47+
peer_id,
48+
msg: {
49+
id: 'loading' + counter++, // используется только как key для Vue
50+
text: message,
51+
from: store.getters['users/user'].id,
52+
date: (Date.now() / 1000).toFixed(),
53+
out: true,
54+
editTime: 0,
55+
fwdCount: 0,
56+
fwdMessages: [],
57+
attachments: [],
58+
random_id,
59+
isLoading: true
60+
}
61+
});
62+
63+
await Vue.nextTick();
64+
65+
eventBus.emit('messages:jumpTo', {
66+
peer_id,
67+
bottom: true,
68+
mark: false
69+
});
70+
71+
await vkapi('messages.send', {
72+
peer_id,
73+
message,
74+
random_id,
75+
payload: keyboard && keyboard.action.payload
76+
});
77+
} catch(e) {
78+
store.commit('messages/editLoadingMessage', {
79+
peer_id,
80+
random_id,
81+
isLoadingFailed: true
82+
});
83+
84+
// 900 = Нельзя отправить пользователю из черного списка
85+
// 902 = Нельзя отправить сообщение из-за настроек приватности собеседника
86+
if([900, 902].includes(e.error_code)) {
87+
store.commit('messages/updateConversation', {
88+
peer: {
89+
id: peer_id,
90+
canWrite: false
91+
}
92+
});
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)
Please sign in to comment.