Video calls: some more cleaup.

This commit is contained in:
aforge
2022-04-22 20:43:10 -07:00
parent 0daef53c87
commit c4d4aa77db
7 changed files with 78 additions and 68 deletions
+20 -1
View File
@@ -2633,7 +2633,12 @@ video {
padding: 20px; padding: 20px;
} }
#video-call-hangup { .video-call-accept {
border-radius: 10px;
background-color: green;
}
.video-call-hangup {
border-radius: 10px; border-radius: 10px;
background-color: red; background-color: red;
} }
@@ -2642,3 +2647,17 @@ video {
border-radius: 10px; border-radius: 10px;
background-color: gray; background-color: gray;
} }
.incoming-call-title {
text-align: center;
padding: 10px;
}
.incoming-call-badges {
text-align: center;
}
.incoming-call-actions {
text-align: center;
padding: 20px;
}
+5
View File
@@ -209,3 +209,8 @@ export function cancelablePromise(promise) {
export function isVideoCall(mime) { export function isVideoCall(mime) {
return mime == 'application/tinode-video-call'; return mime == 'application/tinode-video-call';
} }
// Clips string to the specified length.
export function clipStr(str, length) {
return str && str.substring(0, length);
}
@@ -1,6 +1,6 @@
// InfoView: panel with topic/user info. // IncomingCallView: displays Accept & Reject buttons for incoming calls.
import React from 'react'; import React from 'react';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; import { FormattedMessage, injectIntl } from 'react-intl';
import Tinode from 'tinode-sdk'; import Tinode from 'tinode-sdk';
@@ -8,18 +8,14 @@ import AvatarUpload from '../widgets/avatar-upload.jsx';
import BadgeList from '../widgets/badge-list.jsx'; import BadgeList from '../widgets/badge-list.jsx';
import MenuCancel from '../widgets/menu-cancel.jsx'; import MenuCancel from '../widgets/menu-cancel.jsx';
import { MAX_TITLE_LENGTH, MAX_TOPIC_DESCRIPTION_LENGTH, NO_ACCESS_MODE } from '../config.js'; import { CALL_STATE_INCOMING_RECEIVED, MAX_TITLE_LENGTH } from '../config.js';
import { makeImageUrl } from '../lib/blob-helpers.js'; import { makeImageUrl } from '../lib/blob-helpers.js';
import { arrayEqual, theCard } from '../lib/utils.js'; import { clipStr } from '../lib/utils.js'
function _clip(str, length) {
return str && str.substring(0, length);
}
const RING_SOUND = new Audio("audio/phone_ring.mp3"); const RING_SOUND = new Audio("audio/phone_ring.mp3");
class CallView extends React.Component { class IncomingCallView extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@@ -29,7 +25,6 @@ class CallView extends React.Component {
avatar: null, avatar: null,
trustedBadges: [], trustedBadges: [],
previousMetaDesc: undefined, previousMetaDesc: undefined,
offerSent: false,
}; };
this.resetDesc = this.resetDesc.bind(this); this.resetDesc = this.resetDesc.bind(this);
@@ -45,7 +40,7 @@ class CallView extends React.Component {
return; return;
} }
this.resetDesc(topic, this.props); this.resetDesc(topic, this.props);
if (this.props.callState == 2) { if (this.props.callState == CALL_STATE_INCOMING_RECEIVED) {
RING_SOUND.play(); RING_SOUND.play();
this.ringTimer = setInterval(() => RING_SOUND.play(), 2000); this.ringTimer = setInterval(() => RING_SOUND.play(), 2000);
this.props.onRinging(this.props.topic, this.props.seq); this.props.onRinging(this.props.topic, this.props.seq);
@@ -96,7 +91,7 @@ class CallView extends React.Component {
} }
this.setState({ this.setState({
fullName: _clip(topic.public ? topic.public.fn : undefined, MAX_TITLE_LENGTH), fullName: clipStr(topic.public ? topic.public.fn : undefined, MAX_TITLE_LENGTH),
avatar: makeImageUrl(topic.public ? topic.public.photo : null), avatar: makeImageUrl(topic.public ? topic.public.photo : null),
trustedBadges: badges, trustedBadges: badges,
}); });
@@ -126,16 +121,9 @@ class CallView extends React.Component {
render() { render() {
const {formatMessage} = this.props.intl; const {formatMessage} = this.props.intl;
let panelTitle = 'Unknown'; let panelTitle = 'Unknown';
switch (this.props.callState) { if (this.props.callState == CALL_STATE_INCOMING_RECEIVED) {
case 1: panelTitle = <FormattedMessage id="calls_incoming_title"
panelTitle = 'Calling'; defaultMessage="Incoming Call" description="Incoming call title (Incoming call view)" />;
break;
case 2:
panelTitle = 'Incoming Call From';
break;
case 3:
panelTitle = 'Call Established';
break;
} }
return ( return (
@@ -156,24 +144,22 @@ class CallView extends React.Component {
uid={this.props.topic} uid={this.props.topic}
title={this.state.fullName} /> title={this.state.fullName} />
</center> </center>
<div className="group" style={{padding: "10px", textAlign: "center"}}> <div className="group incoming-call-title">
<div className="large ellipsized">{this.state.fullName}</div> <div className="large ellipsized">{clipStr(this.state.fullName)}</div>
</div> </div>
<div className="group" style={{textAlign: "center"}}> <div className="group incoming-call-badges">
<BadgeList trustedBadges={this.state.trustedBadges} /> <BadgeList trustedBadges={this.state.trustedBadges} />
</div> </div>
<div id="actions" className="group" style={{padding: "20px", textAlign: "center"}}> <div id="actions" className="group incoming-call-actions">
{this.props.callState >= 1 && this.props.callState < 3 ? {this.props.callState == CALL_STATE_INCOMING_RECEIVED ?
<button onClick={this.handleRejectCall} style={{borderRadius: "10px", backgroundColor: "red"}}> <>
<button className="video-call-hangup" onClick={this.handleRejectCall}>
<i className="material-icons">call_end</i> <i className="material-icons">call_end</i>
</button> </button>
: <button className="video-call-accept" onClick={this.handleAcceptCall}>
null
}
{this.props.callState >= 2 && this.props.callState < 3 ?
<button onClick={this.handleAcceptCall} style={{borderRadius: "10px", backgroundColor: "green"}}>
<i className="material-icons">call</i> <i className="material-icons">call</i>
</button> </button>
</>
: :
null null
} }
@@ -185,4 +171,4 @@ class CallView extends React.Component {
} }
}; };
export default injectIntl(CallView); export default injectIntl(IncomingCallView);
+4 -8
View File
@@ -18,7 +18,7 @@ import TopicSecurity from '../widgets/topic-security.jsx';
import { MAX_TITLE_LENGTH, MAX_TOPIC_DESCRIPTION_LENGTH, NO_ACCESS_MODE } from '../config.js'; import { MAX_TITLE_LENGTH, MAX_TOPIC_DESCRIPTION_LENGTH, NO_ACCESS_MODE } from '../config.js';
import { makeImageUrl } from '../lib/blob-helpers.js'; import { makeImageUrl } from '../lib/blob-helpers.js';
import { theCard } from '../lib/utils.js'; import { theCard, clipStr } from '../lib/utils.js';
const messages = defineMessages({ const messages = defineMessages({
info: { info: {
@@ -78,10 +78,6 @@ const messages = defineMessages({
}, },
}); });
function _clip(str, length) {
return str && str.substring(0, length);
}
class InfoView extends React.Component { class InfoView extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@@ -206,11 +202,11 @@ class InfoView extends React.Component {
deleter: acs && acs.isDeleter(), deleter: acs && acs.isDeleter(),
muted: acs && acs.isMuted(), muted: acs && acs.isMuted(),
fullName: _clip(topic.public ? topic.public.fn : undefined, MAX_TITLE_LENGTH), fullName: clipStr(topic.public ? topic.public.fn : undefined, MAX_TITLE_LENGTH),
description: _clip(topic.public ? topic.public.note : undefined, MAX_TOPIC_DESCRIPTION_LENGTH), description: clipStr(topic.public ? topic.public.note : undefined, MAX_TOPIC_DESCRIPTION_LENGTH),
avatar: makeImageUrl(topic.public ? topic.public.photo : null), avatar: makeImageUrl(topic.public ? topic.public.photo : null),
trustedBadges: badges, trustedBadges: badges,
private: _clip(topic.private ? topic.private.comment : null, MAX_TITLE_LENGTH), private: clipStr(topic.private ? topic.private.comment : null, MAX_TITLE_LENGTH),
archived: topic.isArchived(), archived: topic.isArchived(),
address: topic.name, address: topic.name,
groupTopic: topic.isGroupType(), groupTopic: topic.isGroupType(),
+2 -2
View File
@@ -14,7 +14,7 @@ import Invitation from '../widgets/invitation.jsx';
import LetterTile from '../widgets/letter-tile.jsx'; import LetterTile from '../widgets/letter-tile.jsx';
import LoadSpinner from '../widgets/load-spinner.jsx'; import LoadSpinner from '../widgets/load-spinner.jsx';
import LogoView from './logo-view.jsx'; import LogoView from './logo-view.jsx';
import RtcPanel from '../widgets/rtc-panel.jsx'; import CallPanel from '../widgets/call-panel.jsx';
import SendMessage from '../widgets/send-message.jsx'; import SendMessage from '../widgets/send-message.jsx';
import { DEFAULT_P2P_ACCESS_MODE, IMAGE_PREVIEW_DIM, KEYPRESS_DELAY, import { DEFAULT_P2P_ACCESS_MODE, IMAGE_PREVIEW_DIM, KEYPRESS_DELAY,
@@ -984,7 +984,7 @@ class MessagesView extends React.Component {
} else if (this.state.rtcPanel) { } else if (this.state.rtcPanel) {
const topic = this.props.tinode.getTopic(this.state.topic); const topic = this.props.tinode.getTopic(this.state.topic);
component2 = ( component2 = (
<RtcPanel <CallPanel
topic={topic} topic={topic}
seq={this.props.callSeq} seq={this.props.callSeq}
callState={this.props.callState} callState={this.props.callState}
+2 -2
View File
@@ -12,7 +12,7 @@ import ContextMenu from '../widgets/context-menu.jsx';
import ForwardDialog from '../widgets/forward-dialog.jsx'; import ForwardDialog from '../widgets/forward-dialog.jsx';
import InfoView from './info-view.jsx'; import InfoView from './info-view.jsx';
import CallView from './call-view.jsx'; import IncomingCallView from './incoming-call-view.jsx';
import MessagesView from './messages-view.jsx'; import MessagesView from './messages-view.jsx';
import SidepanelView from './sidepanel-view.jsx'; import SidepanelView from './sidepanel-view.jsx';
@@ -2024,7 +2024,7 @@ class TinodeWeb extends React.Component {
} }
{this.state.callTopic && this.state.callState == CALL_STATE_INCOMING_RECEIVED ? {this.state.callTopic && this.state.callState == CALL_STATE_INCOMING_RECEIVED ?
<CallView <IncomingCallView
tinode={this.tinode} tinode={this.tinode}
onClose={this.handleCallClose} onClose={this.handleCallClose}
topic={this.state.callTopic} topic={this.state.callTopic}
@@ -1,11 +1,15 @@
// CallPanel: displays local and remote viewports and controls.
import React from 'react'; import React from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import LetterTile from '../widgets/letter-tile.jsx'; import LetterTile from '../widgets/letter-tile.jsx';
import { CALL_STATE_OUTGOING_INITATED, CALL_STATE_IN_PROGRESS, CALL_WEBRTC_CONFIG } from '../config.js'; import { CALL_STATE_OUTGOING_INITATED, CALL_STATE_IN_PROGRESS, CALL_WEBRTC_CONFIG,
MAX_TITLE_LENGTH } from '../config.js';
export default class RtcPanel extends React.PureComponent { import { clipStr } from '../lib/utils.js'
export default class CallPanel extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
@@ -372,13 +376,13 @@ export default class RtcPanel extends React.PureComponent {
<div className="video-elem"> <div className="video-elem">
<video id="remoteVideo" ref={this.remoteRef} autoPlay playsInline></video> <video id="remoteVideo" ref={this.remoteRef} autoPlay playsInline></video>
{remoteActive ? {remoteActive ?
<div className="video-title">{this.props.title}</div> <div className="video-title">{clipStr(this.props.title, MAX_TITLE_LENGTH)}</div>
: :
null} null}
</div> </div>
</div> </div>
<div id="video-container-controls"> <div id="video-container-controls">
<button id="video-call-hangup" onClick={this.handleCloseClick}> <button className="video-call-hangup" onClick={this.handleCloseClick}>
<i className="material-icons">call_end</i> <i className="material-icons">call_end</i>
</button> </button>
<button className="video-call-toggle-media" onClick={this.handleToggleCameraClick}><i className="material-icons">{videoIcon}</i></button> <button className="video-call-toggle-media" onClick={this.handleToggleCameraClick}><i className="material-icons">{videoIcon}</i></button>