Skip to content

Commit 82fd334

Browse files
author
evgeny-nadymov
committed
New UI for call bubbles
1 parent 83c7a92 commit 82fd334

File tree

12 files changed

+198
-31
lines changed

12 files changed

+198
-31
lines changed

src/Calls/Utils.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,58 @@
77

88
// changes ssrcs
99
import CallStore, { LOG_CALL } from '../Stores/CallStore';
10+
import LStore from '../Stores/LocalizationStore';
11+
12+
export function p2pIsCallReady(callId) {
13+
const call = CallStore.p2pGet(callId);
14+
if (!call) return false;
15+
16+
const { state } = call;
17+
if (!state) return false;
18+
19+
return state && state['@type'] === 'callStateReady';
20+
}
21+
22+
export function p2pGetCallStatus(callId) {
23+
const call = CallStore.p2pGet(callId);
24+
if (!call) return '';
25+
26+
const { state } = call;
27+
if (!state) return '';
28+
29+
switch (state['@type']) {
30+
case 'callStateDiscarded': {
31+
return '';
32+
}
33+
case 'callStateError': {
34+
return '';
35+
}
36+
case 'callStateExchangingKeys': {
37+
return LStore.getString('VoipExchangingKeys');
38+
}
39+
case 'callStateHangingUp': {
40+
return '';
41+
}
42+
case 'callStatePending': {
43+
return '';
44+
}
45+
case 'callStateReady': {
46+
return getCallEmojis(callId);
47+
}
48+
}
49+
50+
return '';
51+
}
52+
53+
export function getCallEmojis(callId) {
54+
const call = CallStore.p2pGet(callId);
55+
if (!call) return '';
56+
57+
const { state } = call;
58+
if (!state) return '';
59+
60+
return state.emojis ? state.emojis.join('') : '';
61+
}
1062

1163
export function getTransport(joinResponse) {
1264
const { payload, candidates } = joinResponse;

src/Components/Calls/CallPanel.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ import VideocamIcon from '@material-ui/icons/VideocamOutlined';
1818
import VideocamOffIcon from '@material-ui/icons/VideocamOffOutlined';
1919
import CallEndIcon from '../../Assets/Icons/CallEnd';
2020
import CloseIcon from '../../Assets/Icons/Close';
21-
import GroupCallPanelButtons from './GroupCallPanelButtons';
2221
import GroupCallSettings from './GroupCallSettings';
2322
import MenuIcon from '../../Assets/Icons/More';
2423
import MicIcon from '../../Assets/Icons/Mic';
2524
import MicOffIcon from '../../Assets/Icons/MicOff';
25+
import { p2pGetCallStatus, p2pIsCallReady } from '../../Calls/Utils';
2626
import { getUserFullName } from '../../Utils/User';
2727
import { stopPropagation } from '../../Utils/Message';
2828
import CallStore from '../../Stores/CallStore';
@@ -251,7 +251,9 @@ class CallPanel extends React.Component {
251251
</div>
252252
<div className='group-call-panel-caption'>
253253
<div className='group-call-title'>{getUserFullName(userId, null)}</div>
254-
{/*<GroupCallSubtitle groupCallId={groupCallId} participantsOnly={true}/>*/}
254+
<div className='group-call-join-panel-subtitle'>
255+
{p2pGetCallStatus(callId)}
256+
</div>
255257
</div>
256258
<div className='group-call-panel-caption-button' onMouseDown={stopPropagation} onClick={this.handleOpenContextMenu}>
257259
<MenuIcon />
@@ -333,7 +335,7 @@ class CallPanel extends React.Component {
333335
<CallEndIcon />
334336
</div>
335337
<div className='group-call-panel-button-text'>
336-
{t('VoipDeclineCall')}
338+
{(p2pIsCallReady(callId) || is_outgoing) ? t('VoipEndCall') : t('VoipDeclineCall')}
337339
</div>
338340
</div>
339341
{!is_outgoing && state['@type'] === 'callStatePending' && (

src/Components/ColumnMiddle/MainMenuButton.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class MainMenuButton extends React.Component {
139139
this.handleMenuClose();
140140

141141
const userId = getChatUserId(AppStore.getChatId());
142+
142143
CallStore.p2pStartCall(userId, false);
143144
};
144145

src/Components/MainPage.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,6 @@ class MainPage extends React.Component {
210210
isSmallWidth
211211
} = this.state;
212212

213-
console.log('[p2p] mainPage.render', callId);
214-
215213
return (
216214
<>
217215
<div

src/Components/Message/Media/Call.css

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,14 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
.call-button {
9-
padding: 7px;
8+
.call-button-root {
9+
font-size: 32px;
10+
padding: 8px;
11+
color: var(--color-accent-main);
12+
}
13+
14+
.light .message-out .call-button-root {
15+
color: var(--message-out-subtle-color);
1016
}
1117

1218
.call-tile {
@@ -27,3 +33,26 @@
2733
.call .document-title {
2834
margin-top: 0;
2935
}
36+
37+
.call .meta-text {
38+
position: static;
39+
display: inline;
40+
font-size: inherit;
41+
line-height: inherit;
42+
}
43+
44+
.call-outgoing {
45+
display: inline-block;
46+
transform: rotate(-45deg);
47+
color: #00B700;
48+
}
49+
50+
.call-incoming {
51+
display: inline-block;
52+
transform: rotate(135deg);
53+
color: #00B700;
54+
}
55+
56+
.call-incoming-missed {
57+
color: #ED5041;
58+
}

src/Components/Message/Media/Call.js

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import React from 'react';
99
import PropTypes from 'prop-types';
1010
import { withTranslation } from 'react-i18next';
1111
import classNames from 'classnames';
12-
import IconButton from '@material-ui/core/IconButton';
1312
import CallIcon from '@material-ui/icons/Call';
13+
import VideocamIcon from '@material-ui/icons/Videocam';
1414
import { getCallContent } from '../../../Utils/Message';
1515
import LStore from '../../../Stores/LocalizationStore';
1616
import MessageStore from '../../../Stores/MessageStore';
@@ -19,28 +19,35 @@ import './Call.css';
1919
class Call extends React.Component {
2020
render() {
2121
const { chatId, messageId, call, openMedia, title, meta } = this.props;
22+
if (!call) return null;
2223

2324
const message = MessageStore.get(chatId, messageId);
2425
if (!message) return null;
2526

26-
const { sender, content } = message;
27+
const { duration, is_video, discard_reason } = call;
28+
const { sender, content, is_outgoing } = message;
2729

2830
const callTitle = getCallContent(sender, content);
29-
const durationString = call.duration > 0 ? LStore.formatCallDuration(Math.floor(call.duration || 0)) : null;
31+
const durationString = duration > 0 ? ', ' + LStore.formatCallDuration(Math.floor(duration || 0)) : '';
3032

3133
return (
32-
<div className={classNames('call', 'document', { 'media-title': title })}>
33-
<IconButton className='call-button' color='primary' aria-label='Call'>
34-
<CallIcon fontSize='large' />
35-
</IconButton>
34+
<div className={classNames('call', 'document', { 'media-title': title })} onClick={openMedia}>
35+
{is_video ? (
36+
<VideocamIcon classes={{ root: 'call-button-root' }} />
37+
) : (
38+
<CallIcon classes={{ root: 'call-button-root' }} />
39+
)}
3640
<div className='document-content'>
3741
<div className='document-title'>{callTitle}</div>
38-
{ durationString && (
39-
<div className='document-action'>
40-
{durationString}
41-
{meta}
42-
</div>
43-
)}
42+
<div className='document-action'>
43+
<span className={classNames({
44+
'call-outgoing': is_outgoing,
45+
'call-incoming': !is_outgoing,
46+
'call-incoming-missed': !is_outgoing && discard_reason && discard_reason['@type'] === 'callDiscardReasonMissed'
47+
})}>&#x2794;</span>
48+
{meta}
49+
{durationString}
50+
</div>
4451
</div>
4552
</div>
4653
);

src/Components/Message/Message.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,8 @@ class Message extends Component {
453453
content['@type'] === 'messageVideo' ||
454454
content['@type'] === 'messagePhoto' ||
455455
content['@type'] === 'messageInvoice' && content.photo) || reply_markup && reply_markup['@type'] === 'replyMarkupInlineKeyboard';
456+
const showMeta = withBubble && content['@type'] !== 'messageCall';
457+
456458

457459
// console.log('[p] m.render id=' + message.id);
458460

@@ -537,7 +539,7 @@ class Message extends Component {
537539
meta={inlineMeta}
538540
/>
539541
)}
540-
{withBubble && meta}
542+
{showMeta && meta}
541543
</div>
542544
{reply_markup && (
543545
<ReplyMarkup

src/Components/Message/Meta.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import PinIcon from '../../Assets/Icons/PinFilled';
1313
import VisibilityIcon from '@material-ui/icons/Visibility';
1414
import Status from './Status';
1515
import { albumHistoryEquals } from '../../Utils/Common';
16-
import { getDate, getDateHint, getViews } from '../../Utils/Message';
16+
import { getDate, getDateHint, getViews, isCallMessage } from '../../Utils/Message';
1717
import MessageStore from '../../Stores/MessageStore';
1818
import './Meta.css';
1919

@@ -108,9 +108,10 @@ class Meta extends React.Component {
108108
const dateHintStr = getDateHint(date);
109109
const viewsStr = getViews(views);
110110

111+
const isCall = isCallMessage(chatId, messageId);
112+
111113
return (
112114
<div className={classNames('meta', className)} style={style}>
113-
{/*{messageId}*/}
114115
<span>&ensp;</span>
115116
{views > 0 && (
116117
<>
@@ -132,7 +133,7 @@ class Meta extends React.Component {
132133
<a onClick={onDateClick}>
133134
<span title={dateHintStr}>{dateStr}</span>
134135
</a>
135-
{isOutgoing && <Status chatId={chatId} messageId={messageId} />}
136+
{isOutgoing && !isCall && <Status chatId={chatId} messageId={messageId} />}
136137
</div>
137138
);
138139
}

src/Stores/CallStore.js

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,24 @@ class CallStore extends EventEmitter {
100100
if (call) {
101101
switch (state['@type']) {
102102
case 'callStateDiscarded': {
103-
// if (!is_outgoing) {
104-
closeCallPanel();
105-
// }
103+
closeCallPanel();
106104
this.p2pHangUp(id);
107105
break;
108106
}
109107
case 'callStateError': {
108+
const { error } = state;
109+
if (error) {
110+
const { code, message } = error;
111+
if (code === 403 && message === 'USER_PRIVACY_RESTRICTED') {
112+
const { user_id } = call;
113+
showAlert({
114+
title: LStore.getString('VoipFailed'),
115+
message: LStore.replaceTags(LStore.formatString('CallNotAvailable', getUserFullName(user_id, null))),
116+
ok: LStore.getString('OK')
117+
});
118+
}
119+
}
120+
110121
closeCallPanel();
111122
this.p2pHangUp(id);
112123
break;
@@ -115,6 +126,7 @@ class CallStore extends EventEmitter {
115126
break;
116127
}
117128
case 'callStateHangingUp': {
129+
closeCallPanel();
118130
break;
119131
}
120132
case 'callStatePending': {
@@ -1430,13 +1442,28 @@ class CallStore extends EventEmitter {
14301442
p2pStartCall(userId, isVideo) {
14311443
LOG_P2P_CALL('p2pStartCall', userId, isVideo);
14321444

1445+
const fullInfo = UserStore.getFullInfo(userId);
1446+
if (!fullInfo) return;
1447+
1448+
const { can_be_called, has_private_calls, supports_video_calls } = fullInfo;
1449+
LOG_P2P_CALL('p2pStartCall fullInfo', fullInfo, can_be_called, has_private_calls, supports_video_calls);
1450+
// if (!can_be_called || has_private_calls) {
1451+
// showAlert({
1452+
// title: LStore.getString('VoipFailed'),
1453+
// message: LStore.replaceTags(LStore.formatString('CallNotAvailable', getUserFullName(userId, null))),
1454+
// // LStore.getString('CallNotAvailable'), getUserFullName(userId, null)),
1455+
// ok: LStore.getString('OK')
1456+
// });
1457+
// return;
1458+
// }
1459+
14331460
const protocol = this.p2pGetProtocol();
1434-
LOG_P2P_CALL('[tdlib] createCall', userId, protocol, isVideo);
1461+
LOG_P2P_CALL('[tdlib] createCall', userId, protocol, isVideo, supports_video_calls);
14351462
TdLibController.send({
14361463
'@type': 'createCall',
14371464
user_id: userId,
14381465
protocol,
1439-
is_video: isVideo
1466+
is_video: isVideo && supports_video_calls
14401467
});
14411468
}
14421469

src/TelegramApp.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import KeyboardManager, { KeyboardHandler } from './Components/Additional/Keyboa
2929
import { openChatList, openPinnedChat } from './Actions/Chat';
3030
import { modalManager } from './Utils/Modal';
3131
import { clearSelection, editMessage, replyMessage, searchChat } from './Actions/Client';
32+
import { isSafari } from './Utils/Common';
3233
import { OPTIMIZATIONS_FIRST_START, STORAGE_REGISTER_KEY, STORAGE_REGISTER_TEST_KEY } from './Constants';
3334
import UserStore from './Stores/UserStore';
3435
import AppStore from './Stores/ApplicationStore';
@@ -420,6 +421,22 @@ window.onpopstate = function() {
420421
window.history.go(1);
421422
};
422423

424+
async function unlockAudio() {
425+
try {
426+
const sound = new Audio('sounds/sound_a.mp3');
427+
sound.autoplay = true;
428+
sound.pause();
429+
} finally {
430+
document.body.removeEventListener('click', unlockAudio)
431+
document.body.removeEventListener('touchstart', unlockAudio)
432+
}
433+
}
434+
435+
// if (isSafari()) {
436+
document.body.addEventListener('click', unlockAudio);
437+
document.body.addEventListener('touchstart', unlockAudio);
438+
// }
439+
423440
const enhance = compose(
424441
withLanguage,
425442
withTranslation(),

0 commit comments

Comments
 (0)