UI tweaks.
1. Display call duration. 2. Make mute/unmute buttons work.
This commit is contained in:
Generated
+39
@@ -13,6 +13,7 @@
|
|||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-intl": "^5.20.2",
|
"react-intl": "^5.20.2",
|
||||||
|
"react-intl-formatted-duration": "^4.0.0",
|
||||||
"tinode-sdk": "^0.18.3"
|
"tinode-sdk": "^0.18.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -4357,6 +4358,17 @@
|
|||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/intl-unofficial-duration-unit-format": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/intl-unofficial-duration-unit-format/-/intl-unofficial-duration-unit-format-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-BFelPGPIboTjbe56JfLFQ5Jfi/lYsk1Dj6Jf1TesIBHqUGxJaYnRa3IYt8L1ak7xQdH0/8sYjgs53Id+VP4lsw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"intl-messageformat": ">= 5.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-binary-path": {
|
"node_modules/is-binary-path": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
@@ -5778,6 +5790,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-intl-formatted-duration": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-intl-formatted-duration/-/react-intl-formatted-duration-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-d515Fk5T594grm8WbyPer6WKdTgKajaTFT944+4QFDnsNU7cs/ZiDLinGUwaSzn7bu/IFvBCvY0xNGpClKC4uw==",
|
||||||
|
"dependencies": {
|
||||||
|
"intl-unofficial-duration-unit-format": "3.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"intl-messageformat": ">= 2.0",
|
||||||
|
"react": ">= 16.0",
|
||||||
|
"react-intl": ">= 4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
@@ -10064,6 +10089,12 @@
|
|||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"intl-unofficial-duration-unit-format": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/intl-unofficial-duration-unit-format/-/intl-unofficial-duration-unit-format-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-BFelPGPIboTjbe56JfLFQ5Jfi/lYsk1Dj6Jf1TesIBHqUGxJaYnRa3IYt8L1ak7xQdH0/8sYjgs53Id+VP4lsw==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"is-binary-path": {
|
"is-binary-path": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
@@ -11021,6 +11052,14 @@
|
|||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-intl-formatted-duration": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-intl-formatted-duration/-/react-intl-formatted-duration-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-d515Fk5T594grm8WbyPer6WKdTgKajaTFT944+4QFDnsNU7cs/ZiDLinGUwaSzn7bu/IFvBCvY0xNGpClKC4uw==",
|
||||||
|
"requires": {
|
||||||
|
"intl-unofficial-duration-unit-format": "3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
|||||||
@@ -70,6 +70,7 @@
|
|||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-intl": "^5.20.2",
|
"react-intl": "^5.20.2",
|
||||||
|
"react-intl-formatted-duration": "^4.0.0",
|
||||||
"tinode-sdk": "^0.18.3"
|
"tinode-sdk": "^0.18.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1061,6 +1061,7 @@ class MessagesView extends React.Component {
|
|||||||
deleted={msg.hi}
|
deleted={msg.hi}
|
||||||
mimeType={msg.head ? msg.head.mime : null}
|
mimeType={msg.head ? msg.head.mime : null}
|
||||||
timestamp={msg.ts}
|
timestamp={msg.ts}
|
||||||
|
duration={msg.origTs ? msg.ts - msg.origTs : null}
|
||||||
response={isReply}
|
response={isReply}
|
||||||
seq={msg.seq}
|
seq={msg.seq}
|
||||||
isGroup={groupTopic}
|
isGroup={groupTopic}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Single message, sent or received.
|
// Single message, sent or received.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||||
|
import FormattedDuration from 'react-intl-formatted-duration';
|
||||||
import { Drafty } from 'tinode-sdk';
|
import { Drafty } from 'tinode-sdk';
|
||||||
|
|
||||||
import Attachment from './attachment.jsx';
|
import Attachment from './attachment.jsx';
|
||||||
@@ -150,7 +151,9 @@ class BaseChatMessage extends React.PureComponent {
|
|||||||
// Video calls.
|
// Video calls.
|
||||||
const direction = this.props.response ? "call_received" : "call_made";
|
const direction = this.props.response ? "call_received" : "call_made";
|
||||||
const text = this.props.response ? "Incoming Call" : "Outgoing Call";
|
const text = this.props.response ? "Incoming Call" : "Outgoing Call";
|
||||||
content = <><i className="material-icons" style={{color:this.props.content == "disconnected" ? "red" : "green"}}>{direction}</i>{text}</>
|
content = <><i className="material-icons" style={{color:this.props.content == "disconnected" ? "red" : "green"}}>{direction}</i>{text}
|
||||||
|
(<FormattedDuration seconds={this.props.duration / 1000} format="{hours} {minutes} {seconds}" />)
|
||||||
|
</>
|
||||||
} else if (typeof content != 'string') {
|
} else if (typeof content != 'string') {
|
||||||
content = <><i className="material-icons gray">warning_amber</i> <i className="gray">
|
content = <><i className="material-icons gray">warning_amber</i> <i className="gray">
|
||||||
<FormattedMessage id="invalid_content"
|
<FormattedMessage id="invalid_content"
|
||||||
|
|||||||
+14
-26
@@ -89,16 +89,6 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
componentDidUpdate(props) {
|
|
||||||
const topic = this.props.topic;
|
|
||||||
if (this.onInfo != topic.onInfo) {
|
|
||||||
this.previousOnInfo = topic.onInfo;
|
|
||||||
topic.onInfo = this.onInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const topic = this.props.topic;
|
const topic = this.props.topic;
|
||||||
this.previousOnInfo = topic.onInfo;
|
this.previousOnInfo = topic.onInfo;
|
||||||
@@ -207,8 +197,7 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleICEGatheringStateChangeEvent(event) {
|
handleICEGatheringStateChangeEvent(event) {
|
||||||
// Our sample just logs information to console here,
|
console.log('ICE gathering change state: ', event);
|
||||||
// but you can do whatever you need.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTrackEvent(event) {
|
handleTrackEvent(event) {
|
||||||
@@ -315,21 +304,18 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
this.props.onHangup(this.props.topic.name, this.props.seq);
|
this.props.onHangup(this.props.topic.name, this.props.seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mute/unmute audio/video (specified by kind).
|
||||||
toggleMedia(kind) {
|
toggleMedia(kind) {
|
||||||
const video = this.localRef.current;
|
const stream = this.state.localStream;
|
||||||
|
stream.getTracks().forEach(track => {
|
||||||
// A video's MediaStream object is available through its srcObject attribute
|
if (track.kind != kind) {
|
||||||
const mediaStream = video.srcObject;
|
return;
|
||||||
|
|
||||||
// Through the MediaStream, you can get the MediaStreamTracks with getTracks():
|
|
||||||
const tracks = mediaStream.getTracks();
|
|
||||||
|
|
||||||
// Or stop all like so:
|
|
||||||
tracks.forEach(track => {
|
|
||||||
if (track.kind == kind) {
|
|
||||||
track.stop();
|
|
||||||
}
|
}
|
||||||
|
console.log('local stream: toggling track ', track.id, track.kind, track.readyState);
|
||||||
|
track.enabled = !track.enabled;
|
||||||
});
|
});
|
||||||
|
// Make sure we redraw the UI properly.
|
||||||
|
this.forceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleToggleCameraClick() {
|
handleToggleCameraClick() {
|
||||||
@@ -346,6 +332,8 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const remoteActive = this.remoteRef.current != null && this.remoteRef.current.srcObject != null;
|
const remoteActive = this.remoteRef.current != null && this.remoteRef.current.srcObject != null;
|
||||||
|
const audioIcon = this.state.localStream != null && this.state.localStream.getAudioTracks()[0].enabled ? 'mic' : 'mic_off';
|
||||||
|
const videoIcon = this.state.localStream != null && this.state.localStream.getVideoTracks()[0].enabled ? 'videocam' : 'videocam_off';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -389,8 +377,8 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
<button id="video-call-hangup" onClick={this.handleCloseClick}>
|
<button id="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">video_camera_front</i></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.handleToggleMicClick}><i className="material-icons">mic</i></button>
|
<button className="video-call-toggle-media" onClick={this.handleToggleMicClick}><i className="material-icons">{audioIcon}</i></button>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
|
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user