diff --git a/package-lock.json b/package-lock.json
index 4a36d37e..2368a811 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-intl": "^5.20.2",
+ "react-intl-formatted-duration": "^4.0.0",
"tinode-sdk": "^0.18.3"
},
"devDependencies": {
@@ -4357,6 +4358,17 @@
"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": {
"version": "2.1.0",
"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": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@@ -10064,6 +10089,12 @@
"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": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -11021,6 +11052,14 @@
"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": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
diff --git a/package.json b/package.json
index 93985112..b0b09dca 100644
--- a/package.json
+++ b/package.json
@@ -70,6 +70,7 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-intl": "^5.20.2",
+ "react-intl-formatted-duration": "^4.0.0",
"tinode-sdk": "^0.18.3"
},
"devDependencies": {
diff --git a/src/views/messages-view.jsx b/src/views/messages-view.jsx
index 1e6371aa..cc80c0bd 100644
--- a/src/views/messages-view.jsx
+++ b/src/views/messages-view.jsx
@@ -1061,6 +1061,7 @@ class MessagesView extends React.Component {
deleted={msg.hi}
mimeType={msg.head ? msg.head.mime : null}
timestamp={msg.ts}
+ duration={msg.origTs ? msg.ts - msg.origTs : null}
response={isReply}
seq={msg.seq}
isGroup={groupTopic}
diff --git a/src/widgets/chat-message.jsx b/src/widgets/chat-message.jsx
index 51904a32..952cda9a 100644
--- a/src/widgets/chat-message.jsx
+++ b/src/widgets/chat-message.jsx
@@ -1,6 +1,7 @@
// Single message, sent or received.
import React from 'react';
import { FormattedMessage, injectIntl } from 'react-intl';
+import FormattedDuration from 'react-intl-formatted-duration';
import { Drafty } from 'tinode-sdk';
import Attachment from './attachment.jsx';
@@ -150,7 +151,9 @@ class BaseChatMessage extends React.PureComponent {
// Video calls.
const direction = this.props.response ? "call_received" : "call_made";
const text = this.props.response ? "Incoming Call" : "Outgoing Call";
- content = <>{direction}{text}>
+ content = <>{direction}{text}
+ ()
+ >
} else if (typeof content != 'string') {
content = <>warning_amber
{
- if (track.kind == kind) {
- track.stop();
+ const stream = this.state.localStream;
+ stream.getTracks().forEach(track => {
+ if (track.kind != kind) {
+ return;
}
+ 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() {
@@ -346,6 +332,8 @@ export default class RtcPanel extends React.PureComponent {
}
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 (
<>
@@ -389,8 +377,8 @@ export default class RtcPanel extends React.PureComponent {
-
-
+
+