diff --git a/package-lock.json b/package-lock.json
index 600b7aa9..b221de77 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "tinode-webapp",
- "version": "0.20.0-alpha1",
+ "version": "0.18.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "tinode-webapp",
- "version": "0.20.0-alpha1",
+ "version": "0.18.3",
"license": "Apache-2.0",
"dependencies": {
"firebase": "^9.6.7",
@@ -15,7 +15,8 @@
"react-dom": "^17.0.2",
"react-intl": "^5.20.2",
"react-intl-formatted-duration": "^4.0.0",
- "tinode-sdk": "^0.18.3"
+ "tinode-sdk": "^0.18.3",
+ "webrtc-adapter": "^8.1.1"
},
"devDependencies": {
"@babel/core": "^7.14.5",
@@ -6277,6 +6278,11 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/sdp": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.0.3.tgz",
+ "integrity": "sha512-8EkfckS+XZQaPLyChu4ey7PghrdcraCVNpJe2Gfdi2ON1ylQ7OasuKX+b37R9slnRChwIAiQgt+oj8xXGD8x+A=="
+ },
"node_modules/selenium-webdriver": {
"version": "4.0.0-rc-1",
"resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-rc-1.tgz",
@@ -6936,6 +6942,18 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/webrtc-adapter": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-8.1.1.tgz",
+ "integrity": "sha512-1yXevP7TeZGmklEXkvQVrZp3fOSJlLeXNGCA7NovQokxgP3/e2T3EVGL0eKU87S9vKppWjvRWqnJeSANEspOBg==",
+ "dependencies": {
+ "sdp": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0",
+ "npm": ">=3.10.0"
+ }
+ },
"node_modules/websocket-driver": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
@@ -11757,6 +11775,11 @@
"ajv-keywords": "^3.5.2"
}
},
+ "sdp": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.0.3.tgz",
+ "integrity": "sha512-8EkfckS+XZQaPLyChu4ey7PghrdcraCVNpJe2Gfdi2ON1ylQ7OasuKX+b37R9slnRChwIAiQgt+oj8xXGD8x+A=="
+ },
"selenium-webdriver": {
"version": "4.0.0-rc-1",
"resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-rc-1.tgz",
@@ -12231,6 +12254,14 @@
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
"dev": true
},
+ "webrtc-adapter": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-8.1.1.tgz",
+ "integrity": "sha512-1yXevP7TeZGmklEXkvQVrZp3fOSJlLeXNGCA7NovQokxgP3/e2T3EVGL0eKU87S9vKppWjvRWqnJeSANEspOBg==",
+ "requires": {
+ "sdp": "^3.0.2"
+ }
+ },
"websocket-driver": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
diff --git a/package.json b/package.json
index 003dc314..417b43fe 100644
--- a/package.json
+++ b/package.json
@@ -72,7 +72,8 @@
"react-dom": "^17.0.2",
"react-intl": "^5.20.2",
"react-intl-formatted-duration": "^4.0.0",
- "tinode-sdk": "^0.20.0-alpha1"
+ "tinode-sdk": "^0.20.0-alpha1",
+ "webrtc-adapter": "^8.1.1"
},
"devDependencies": {
"@babel/core": "^7.14.5",
diff --git a/src/views/info-view.jsx b/src/views/info-view.jsx
index 14be31b5..4a7110c9 100644
--- a/src/views/info-view.jsx
+++ b/src/views/info-view.jsx
@@ -202,11 +202,11 @@ class InfoView extends React.Component {
deleter: acs && acs.isDeleter(),
muted: acs && acs.isMuted(),
- fullName: clipStr(topic.public ? topic.public.fn : undefined, MAX_TITLE_LENGTH),
- description: clipStr(topic.public ? topic.public.note : undefined, MAX_TOPIC_DESCRIPTION_LENGTH),
+ fullName: clipStr(topic.public && topic.public.fn, MAX_TITLE_LENGTH),
+ description: clipStr(topic.public && topic.public.note, MAX_TOPIC_DESCRIPTION_LENGTH),
avatar: makeImageUrl(topic.public ? topic.public.photo : null),
trustedBadges: badges,
- private: clipStr(topic.private ? topic.private.comment : null, MAX_TITLE_LENGTH),
+ private: clipStr(topic.private && topic.private.comment, MAX_TITLE_LENGTH),
archived: topic.isArchived(),
address: topic.name,
groupTopic: topic.isGroupType(),
diff --git a/src/views/messages-view.jsx b/src/views/messages-view.jsx
index cf7dd4cc..a869c97b 100644
--- a/src/views/messages-view.jsx
+++ b/src/views/messages-view.jsx
@@ -310,9 +310,7 @@ class MessagesView extends React.Component {
});
if (nextProps.callTopic == topic.name && shouldPresentCallPanel(nextProps.callState)) {
- Object.assign(nextState, {
- rtcPanel: nextProps.callTopic,
- });
+ nextState.rtcPanel = nextProps.callTopic;
}
} else {
// Invalid topic.
@@ -330,9 +328,7 @@ class MessagesView extends React.Component {
// We are still in same topic. Show the call panel if necessary.
if (nextProps.callTopic == prevState.topic && !prevState.rtcPanel &&
shouldPresentCallPanel(nextProps.callState)) {
- Object.assign(nextState, {
- rtcPanel: nextProps.callTopic,
- });
+ nextState.rtcPanel = nextProps.callTopic;
}
}
@@ -1149,7 +1145,7 @@ class MessagesView extends React.Component {
}
let duration;
if (msg.head && isVideoCall(msg.head.mime)) {
- topic.messageVersions(msg, (cur, before, unused1, unused2) => {
+ topic.messageVersions(msg, (cur, before) => {
if (cur.content == 'finished' && before.content == 'accepted') {
duration = msg.ts - before.ts;
}
diff --git a/src/views/tinode-web.jsx b/src/views/tinode-web.jsx
index f762989d..bb31b7ad 100644
--- a/src/views/tinode-web.jsx
+++ b/src/views/tinode-web.jsx
@@ -1304,15 +1304,11 @@ class TinodeWeb extends React.Component {
// If the current URl contains the old topic name, replace it with new.
// Update the name of the selected topic first so the navigator doen't clear
// the state.
- const newTopic = {topicSelected: newName};
- this.setState(...nextState, ...newTopic, () => {
- HashNavigation.navigateTo(HashNavigation.setUrlTopic('', newName));
- });
- } else {
- this.setState(nextState, () => {
- HashNavigation.navigateTo(HashNavigation.setUrlTopic('', newName));
- });
+ nextState.topicSelected = newName;
}
+ this.setState(nextState, _ => {
+ HashNavigation.navigateTo(HashNavigation.setUrlTopic('', newName));
+ });
}
handleTopicUpdateRequest(topicName, pub, priv, defacs) {
@@ -1814,7 +1810,7 @@ class TinodeWeb extends React.Component {
case 'accept':
console.log('TinodeWeb: received accept msg ', info);
// If another my session has accepted the call.
- if (info.topic == 'me' && info.from == this.state.myUserId) {
+ if (Tinode.isMeTopicName(info.topic) && this.tinode.isMe(info.from)) {
this.setState({
callTopic: null,
callState: CALL_STATE_NONE,
diff --git a/src/widgets/call-panel.jsx b/src/widgets/call-panel.jsx
index 610309cc..ea6336f2 100644
--- a/src/widgets/call-panel.jsx
+++ b/src/widgets/call-panel.jsx
@@ -149,15 +149,15 @@ export default class CallPanel extends React.PureComponent {
this.state.pc.setRemoteDescription(desc).catch(this.reportError);
}
- reportError(errMessage) {
- console.log(`Error ${errMessage.name}: ${errMessage.message}`);
+ reportError(err) {
+ this.props.onError(err.message, 'err');
}
handleNegotiationNeededEvent() {
this.state.pc.createOffer().then(offer => {
return this.state.pc.setLocalDescription(offer);
})
- .then(() => {
+ .then(_ => {
this.props.onSendOffer(this.props.topic.name, this.props.seq, this.state.pc.localDescription.toJSON());
})
.catch(this.reportError);
@@ -196,16 +196,17 @@ export default class CallPanel extends React.PureComponent {
}
handleTrackEvent(event) {
+ // Remote video becomes available.
this.remoteRef.current.srcObject = event.streams[0];
- // Make sure we redraw the UI properly.
+ // Make sure we display the title (peer's name) over the remote video.
this.forceUpdate();
}
handleGetUserMediaError(e) {
switch(e.name) {
case 'NotFoundError':
- console.log("Unable to open your call because no camera and/or microphone" +
- "were found.");
+ // Cannot start the call b/c no camera and/or microphone found.
+ this.reportError(e);
break;
case 'SecurityError':
case 'PermissionDeniedError':
@@ -304,7 +305,7 @@ export default class CallPanel extends React.PureComponent {
}
track.enabled = !track.enabled;
});
- // Make sure we redraw the UI properly.
+ // Make sure we redraw the mute/unmute icons (e.g. mic -> mic_off).
this.forceUpdate();
}
@@ -373,7 +374,6 @@ export default class CallPanel extends React.PureComponent {
-
>
);
diff --git a/src/widgets/chat-message.jsx b/src/widgets/chat-message.jsx
index 0b66eff3..35d53d05 100644
--- a/src/widgets/chat-message.jsx
+++ b/src/widgets/chat-message.jsx
@@ -155,8 +155,8 @@ class BaseChatMessage extends React.PureComponent {
defaultMessage="Incoming Call" description="Incoming call label" /> :
;
- const isCallDropped = this.props.content == "disconnected";
- content = <>{direction}{text}
+ const isCallDropped = this.props.content == 'disconnected';
+ content = <>{direction}{text}
{ !isCallDropped && this.props.duration ?
[' (', , ')'] :
null}
diff --git a/src/widgets/contact.jsx b/src/widgets/contact.jsx
index 2802aac1..babadf4d 100644
--- a/src/widgets/contact.jsx
+++ b/src/widgets/contact.jsx
@@ -71,8 +71,8 @@ class Contact extends React.Component {
// The this.props.preview contains alreay shortened Drafty or string.
let preview;
if (this.props.previewIsVideoCall) {
- preview = <>{this.props.previewIsResponse ? 'call_received' : 'call_made'}
- video_call>;
+ preview = <>{this.props.previewIsResponse ? 'call_received' : 'call_made'}
+ video_call>;
} else if (typeof this.props.preview == 'string') {
preview = this.props.preview;
} else if (Drafty.isValid(this.props.preview)) {