Compare commits

...
27 Commits
Author SHA1 Message Date
or-else c94b397222 merge fixes from devel 2022-06-30 11:05:53 -07:00
or-else c013885bec rebuild with the SDK fix + better error reporting 2022-06-30 10:54:33 -07:00
or-else 4a2667015f merged fix of password change 2022-06-29 18:40:16 -07:00
or-else e209ef2483 fix crash on attempt to change password 2022-06-29 18:39:00 -07:00
or-else 2a00791a1b simplified code a little bit 2022-06-29 12:20:43 -07:00
or-else dcf9e1d47e use topic.latestMsgVersion instead of iteration over versions 2022-06-29 10:15:57 -07:00
or-else 6c0612dc8f releasing v0.19.2 2022-06-28 14:37:15 -07:00
aforge 315631f67c Treat new webrtc:started messages as call invite.
In order to reduce redundancy, {info what=call event=invite}
will not be used as call invite any longer (and will be dropped soon).
2022-06-28 21:34:47 +03:00
or-else c31c0c2c07 fix clipping of a host name 2022-06-27 17:48:38 -07:00
aforge c7c2cffbbf Reject new incoming calls when a call is in progress. 2022-06-27 18:26:21 +03:00
or-else e77e8441cf recv ackns moved to the SDK 2022-06-26 19:29:51 -07:00
or-else d95c53ed24 add catch() to play(), otherwise it throws 2022-06-26 19:29:11 -07:00
or-else 300b4f8d64 typo 2022-06-23 16:23:22 -07:00
or-else 36977b429b small UI and metadata fixes 2022-06-23 13:23:06 -07:00
or-else 0d7643ee42 add video call screenshot 2022-06-19 16:43:43 -07:00
or-else 145ac78de8 bump version to 0.20.0-beta2 and rebuild 2022-06-19 12:55:34 -07:00
or-else 245603e8b9 dialing sound added 2022-06-19 12:53:09 -07:00
or-else 3eab7ec09b support for "ringing" 2022-06-19 11:52:07 -07:00
or-else a50261ab42 Merge branch 'master' into devel 2022-06-16 12:45:53 -07:00
or-else 8cd8ffb659 prevent crash when app is run under http, #763 2022-06-16 12:43:40 -07:00
Gene 932ab0a047 Ask to use index-dev.html instead of index.html 2022-06-16 19:44:00 +03:00
or-else b5686f45b3 bump version to 0.19.1 and rebuild 2022-06-14 09:32:46 -07:00
or-else 88c4cb42cd fix scroll bug in messages panel 2022-06-13 21:39:20 -07:00
or-else cd6a87037d bug fix: keep message panel at the bottom on new messages 2022-06-13 21:37:15 -07:00
or-else deaea078ea rebuilt 2022-06-13 15:32:32 -07:00
or-else bdfe163ecf clean up 2022-06-13 15:32:10 -07:00
or-else 1fb3a233a2 updated dependencies and rebuilt 2022-06-13 10:19:47 -07:00
27 changed files with 3098 additions and 2498 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ If applicable, add screenshots to help explain your problem.
- TinodeWeb Version [e.g. 0.16.6] - TinodeWeb Version [e.g. 0.16.6]
**Console log** **Console log**
Please attach or insert console log which illustrates the problem. Please attach or insert console log which illustrates the problem. Please use the log produced by `index-dev.html`, not `index.html`; `index.html` uses minified javascript which produces unusable logs.
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.
+1 -1
View File
@@ -68,5 +68,5 @@ More translations are welcome. See [instructions](https://github.com/tinode/chat
### Mobile screenshots ### Mobile screenshots
<p align="center"> <p align="center">
<kbd><img src="web-mob-contacts.png" alt="Mobile web: contacts" width=250 /></kbd> <kbd><img src="web-mob-chat.png" alt="Mobile web: chat" width=250 /></kbd> <kbd><img src="web-mob-info.png" alt="Mobile web: topic info" width=250 /></kbd> <kbd><img src="web-mob-forward.png" alt="Mobile web: forward message" width=250 /></kbd> <kbd><img src="web-mob-acc-settings.png" alt="Mobile web: account settings" width=250 /></kbd> <kbd><img src="web-mob-avatar.png" alt="Mobile web: change avatar" width=250 /></kbd> <kbd><img src="web-mob-contacts.png" alt="Mobile web: contacts" width=250 /></kbd> <kbd><img src="web-mob-chat.png" alt="Mobile web: chat" width=250 /></kbd> <kbd><img src="web-mob-info.png" alt="Mobile web: topic info" width=250 /></kbd> <kbd><img src="web-mob-forward.png" alt="Mobile web: forward message" width=250 /></kbd> <kbd><img src="web-mob-video-call.png" alt="Mobile web: video call" width=250 /></kbd> <kbd><img src="web-mob-avatar.png" alt="Mobile web: change avatar" width=250 /></kbd>
</p> </p>
BIN
View File
Binary file not shown.
+5 -3
View File
@@ -838,6 +838,10 @@ table.permission-editor td.checkbox {
padding-left: 0.5rem; padding-left: 0.5rem;
} }
input#host-name {
width: 15rem;
}
/* Input with a search icon on the left */ /* Input with a search icon on the left */
input.search { input.search {
text-indent: 1.4rem; text-indent: 1.4rem;
@@ -1667,7 +1671,7 @@ video {
.caller-card.pulse img.avatar, .caller-card.pulse img.avatar,
.caller-card.pulse .lettertile { .caller-card.pulse .lettertile {
animation: active-call 1.5s linear infinite;; animation: active-call 1.5s linear infinite;
} }
.caller-card .avatar-box .material-icons { .caller-card .avatar-box .material-icons {
@@ -1753,14 +1757,12 @@ video {
@keyframes active-call { @keyframes active-call {
0% { 0% {
box-shadow: box-shadow:
0 0 0 0 rgba(33, 150, 243, 0.3),
0 0 0 0.1rem rgba(33, 150, 243, 0.3), 0 0 0 0.1rem rgba(33, 150, 243, 0.3),
0 0 0 0.3rem rgba(33, 150, 243, 0.3), 0 0 0 0.3rem rgba(33, 150, 243, 0.3),
0 0 0 0.5rem rgba(33, 150, 243, 0.3); 0 0 0 0.5rem rgba(33, 150, 243, 0.3);
} }
100% { 100% {
box-shadow: box-shadow:
0 0 0 0 rgba(33, 150, 243, 0.3),
0 0 0 0.4rem rgba(33, 150, 243, 0.3), 0 0 0 0.4rem rgba(33, 150, 243, 0.3),
0 0 0 2rem rgba(33, 150, 243, 0), 0 0 0 2rem rgba(33, 150, 243, 0),
0 0 0 3rem rgba(33, 150, 243, 0); 0 0 0 3rem rgba(33, 150, 243, 0);
+1 -1
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -16,6 +16,7 @@
<meta name="og:url" content="https://web.tinode.co/"> <meta name="og:url" content="https://web.tinode.co/">
<meta name="og:title" content="Tinode Web Development"> <meta name="og:title" content="Tinode Web Development">
<meta name="og:image" content="img/og-logo.jpeg"> <meta name="og:image" content="img/og-logo.jpeg">
<meta name="og:description" content="Tinode instant messenger, development version" />
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<link rel="manifest" href="manifest.json" /> <link rel="manifest" href="manifest.json" />
+2 -1
View File
@@ -5,7 +5,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="application-name" content="Tinode Web" /> <meta name="application-name" content="Tinode Web" />
<meta name="description" content="Tinode instant messaging in a browser" /> <meta name="description" content="Tinode instant messenger in a browser" />
<meta name="application-url" content="https://web.tinode.co/"> <meta name="application-url" content="https://web.tinode.co/">
<meta name="theme-color" content="#3949AB" /> <meta name="theme-color" content="#3949AB" />
<meta name="google" value="notranslate" /> <meta name="google" value="notranslate" />
@@ -13,6 +13,7 @@
<meta name="og:url" content="https://web.tinode.co/"> <meta name="og:url" content="https://web.tinode.co/">
<meta name="og:title" content="Tinode Web"> <meta name="og:title" content="Tinode Web">
<meta name="og:image" content="img/og-logo.jpeg"> <meta name="og:image" content="img/og-logo.jpeg">
<meta name="og:description" content="Tinode instant messenger in a browser" />
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<link rel="manifest" href="manifest.json" /> <link rel="manifest" href="manifest.json" />
+2219 -2055
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,7 +1,7 @@
{ {
"name": "tinode-webapp", "name": "tinode-webapp",
"description": "Tinode messenger for the web", "description": "Tinode messenger for the web",
"version": "0.20.0-beta1", "version": "0.20.0-beta2",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/tinode/example-react-js.git" "url": "https://github.com/tinode/example-react-js.git"
@@ -71,7 +71,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",
"tinode-sdk": "^0.20.0-beta1", "tinode-sdk": "^0.20.0-beta2",
"webrtc-adapter": "^8.1.1" "webrtc-adapter": "^8.1.1"
}, },
"devDependencies": { "devDependencies": {
@@ -84,7 +84,7 @@
"browserslist": "^4.16.5", "browserslist": "^4.16.5",
"copy-webpack-plugin": "^10.0.0", "copy-webpack-plugin": "^10.0.0",
"cssnano": "^5.0.6", "cssnano": "^5.0.6",
"glob": "^7.1.7", "glob": "^8.0.3",
"mkdirp": "^1.0.4", "mkdirp": "^1.0.4",
"postcss": "^8.3.2", "postcss": "^8.3.2",
"postcss-cli": "^9.0.2", "postcss-cli": "^9.0.2",
+1 -3
View File
@@ -17,10 +17,8 @@ export const LOGGING_ENABLED = true;
// Minimum time between two keypress notifications, milliseconds. // Minimum time between two keypress notifications, milliseconds.
export const KEYPRESS_DELAY = 3_000; export const KEYPRESS_DELAY = 3_000;
// Delay before sending a {note} for reciving a message, milliseconds.
export const RECEIVED_DELAY = 500;
// Delay before sending a read notification, milliseconds. // Delay before sending a read notification, milliseconds.
export const READ_DELAY = 1000; export const READ_DELAY = 1_500;
// The default shortest allowed tag length. Matches the value on the server. // The default shortest allowed tag length. Matches the value on the server.
export const MIN_TAG_LENGTH = 2; export const MIN_TAG_LENGTH = 2;
+1 -1
View File
@@ -1,3 +1,3 @@
// This is a generated file. Don't edit. // This is a generated file. Don't edit.
export const PACKAGE_VERSION = "0.20.0-beta1"; export const PACKAGE_VERSION = "0.20.0-beta2";
+7 -4
View File
@@ -134,6 +134,8 @@ class MessagesView extends React.Component {
this.readNotificationQueue = []; this.readNotificationQueue = [];
this.readNotificationTimer = null; this.readNotificationTimer = null;
this.keyPressTimer = null;
} }
getOrCreateMessageRef(seqId) { getOrCreateMessageRef(seqId) {
@@ -515,7 +517,7 @@ class MessagesView extends React.Component {
// Set up the timer if it's not running already. // Set up the timer if it's not running already.
if (!this.readNotificationTimer) { if (!this.readNotificationTimer) {
this.readNotificationTimer = setInterval(() => { this.readNotificationTimer = setInterval(_ => {
if (this.readNotificationQueue.length == 0) { if (this.readNotificationQueue.length == 0) {
// Shut down the timer if the queue is empty. // Shut down the timer if the queue is empty.
clearInterval(this.readNotificationTimer); clearInterval(this.readNotificationTimer);
@@ -604,17 +606,18 @@ class MessagesView extends React.Component {
} }
clearTimeout(this.keyPressTimer) clearTimeout(this.keyPressTimer)
this.setState({messageCount: topic.messageCount(), typingIndicator: false}); this.setState({messageCount: topic.messageCount(), typingIndicator: false}, _ => {
// Scroll to the bottom if the message is added to the end of the message // Scroll to the bottom if the message is added to the end of the message
// list if already at the bottom, otherwise show [go to latest] button. // list if already at the bottom, otherwise show [go to latest] button.
// Implemented as a callback to be sure the scroll height has been updated.
if (topic.isNewMessage(msg.seq)) { if (topic.isNewMessage(msg.seq)) {
if (this.state.scrollPosition > SHOW_GO_TO_LAST_DIST) { if (this.state.scrollPosition > SHOW_GO_TO_LAST_DIST) {
this.setState({showGoToLastButton: true}); this.setState({showGoToLastButton: true});
} else { } else {
this.setState({scrollPosition: 0}); this.goToLatestMessage();
} }
} }
});
// Aknowledge messages except own messages. They are // Aknowledge messages except own messages. They are
// automatically assumed to be read and recived. // automatically assumed to be read and recived.
+49 -29
View File
@@ -18,7 +18,7 @@ import MessagesView from './messages-view.jsx';
import SidepanelView from './sidepanel-view.jsx'; import SidepanelView from './sidepanel-view.jsx';
import { API_KEY, APP_NAME, DEFAULT_P2P_ACCESS_MODE, FORWARDED_PREVIEW_LENGTH, LOGGING_ENABLED, import { API_KEY, APP_NAME, DEFAULT_P2P_ACCESS_MODE, FORWARDED_PREVIEW_LENGTH, LOGGING_ENABLED,
MEDIA_BREAKPOINT, RECEIVED_DELAY } from '../config.js'; MEDIA_BREAKPOINT } from '../config.js';
import { CALL_STATE_NONE, CALL_STATE_OUTGOING_INITATED, import { CALL_STATE_NONE, CALL_STATE_OUTGOING_INITATED,
CALL_STATE_INCOMING_RECEIVED, CALL_STATE_IN_PROGRESS, CALL_STATE_INCOMING_RECEIVED, CALL_STATE_IN_PROGRESS,
CALL_HEAD_STARTED } from '../constants.js'; CALL_HEAD_STARTED } from '../constants.js';
@@ -156,6 +156,7 @@ class TinodeWeb extends React.Component {
this.handleStartVideoCall = this.handleStartVideoCall.bind(this); this.handleStartVideoCall = this.handleStartVideoCall.bind(this);
this.handleInfoMessage = this.handleInfoMessage.bind(this); this.handleInfoMessage = this.handleInfoMessage.bind(this);
this.handleDataMessage = this.handleDataMessage.bind(this);
this.handleCallClose = this.handleCallClose.bind(this); this.handleCallClose = this.handleCallClose.bind(this);
this.handleCallInvite = this.handleCallInvite.bind(this); this.handleCallInvite = this.handleCallInvite.bind(this);
@@ -168,6 +169,9 @@ class TinodeWeb extends React.Component {
this.handleCallAcceptCall = this.handleCallAcceptCall.bind(this); this.handleCallAcceptCall = this.handleCallAcceptCall.bind(this);
this.sendMessageToTopic = this.sendMessageToTopic.bind(this); this.sendMessageToTopic = this.sendMessageToTopic.bind(this);
// FIXME: this is unused.
this.callTimeoutTimer = null;
} }
getBlankState() { getBlankState() {
@@ -284,6 +288,7 @@ class TinodeWeb extends React.Component {
this.tinode.onDisconnect = this.handleDisconnect; this.tinode.onDisconnect = this.handleDisconnect;
this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration; this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration;
this.tinode.onInfoMessage = this.handleInfoMessage; this.tinode.onInfoMessage = this.handleInfoMessage;
this.tinode.onDataMessage = this.handleDataMessage;
}).then(() => { }).then(() => {
// Initialize desktop alerts. // Initialize desktop alerts.
if (this.state.desktopAlertsEnabled) { if (this.state.desktopAlertsEnabled) {
@@ -783,7 +788,9 @@ class TinodeWeb extends React.Component {
if (cont.unread > 0 && this.state.messageSounds && !archived) { if (cont.unread > 0 && this.state.messageSounds && !archived) {
// Skip update if the topic is currently open, otherwise the badge will annoyingly flash. // Skip update if the topic is currently open, otherwise the badge will annoyingly flash.
if (document.hidden || this.state.topicSelected != cont.topic) { if (document.hidden || this.state.topicSelected != cont.topic) {
POP_SOUND.play(); POP_SOUND.play().catch(_ => {
// play() throws if the user did not click the app first: https://goo.gl/xX8pDD.
});
} }
} }
// Reorder contact list to use possibly updated 'touched'. // Reorder contact list to use possibly updated 'touched'.
@@ -806,12 +813,12 @@ class TinodeWeb extends React.Component {
} }
} else if (what == 'del') { } else if (what == 'del') {
// TODO: messages deleted (hard or soft) -- update pill counter. // TODO: messages deleted (hard or soft) -- update pill counter.
} else if (what == 'upd') { } else if (what == 'upd' || what == 'call') {
// upd - handled by the SDK. Explicitly ignoring here. // upd, call - handled by the SDK. Explicitly ignoring here.
} else { } else {
// TODO(gene): handle other types of notifications: // TODO(gene): handle other types of notifications:
// * ua -- user agent changes (maybe display a pictogram for mobile/desktop). // * ua -- user agent changes (maybe display a pictogram for mobile/desktop).
console.info("Unsupported (yet) presence update:" + what + " in: " + cont.topic); console.info("Unsupported (yet) presence update:", what, "in", cont.topic);
} }
} }
@@ -880,16 +887,7 @@ class TinodeWeb extends React.Component {
this.setState(newState); this.setState(newState);
} }
// Sending "received" notifications
tnData(data) { tnData(data) {
const topic = this.tinode.getTopic(data.topic);
if (topic.msgStatus(data, true) >= Tinode.MESSAGE_STATUS_SENT && data.from != this.state.myUserId) {
clearTimeout(this.receivedTimer);
this.receivedTimer = setTimeout(() => {
this.receivedTimer = undefined;
topic.noteRecv(data.seq);
}, RECEIVED_DELAY);
}
} }
/* Fnd topic: find contacts by tokens */ /* Fnd topic: find contacts by tokens */
@@ -1331,7 +1329,9 @@ class TinodeWeb extends React.Component {
handleUnarchive(topicName) { handleUnarchive(topicName) {
const topic = this.tinode.getTopic(topicName); const topic = this.tinode.getTopic(topicName);
if (topic) { if (topic) {
topic.archive(false); topic.archive(false).catch((err) => {
this.handleError(err.message, 'err');
});
} }
} }
@@ -1753,9 +1753,8 @@ class TinodeWeb extends React.Component {
} }
handleCallClose() { handleCallClose() {
if (this.state.callTimeout) { if (this.callTimeoutTimer) {
console.log('closing call timeout ', this.state.callTimeout); clearTimeout(this.callTimeoutTimer);
clearTimeout(this.state.callTimeout);
} }
this.setState({ this.setState({
callTopic: undefined, callTopic: undefined,
@@ -1786,18 +1785,7 @@ class TinodeWeb extends React.Component {
return; return;
} }
switch (info.event) { switch (info.event) {
case 'invite':
if (info.from != this.state.myUserId) {
// Incoming call.
this.setState({
callTopic: info.src,
callState: CALL_STATE_INCOMING_RECEIVED,
callSeq: info.seq
});
}
break;
case 'accept': case 'accept':
console.log('TinodeWeb: received accept msg ', info);
// If another my session has accepted the call. // If another my session has accepted the call.
if (Tinode.isMeTopicName(info.topic) && this.tinode.isMe(info.from)) { if (Tinode.isMeTopicName(info.topic) && this.tinode.isMe(info.from)) {
this.setState({ this.setState({
@@ -1819,6 +1807,38 @@ class TinodeWeb extends React.Component {
} }
} }
handleDataMessage(data) {
if (data.head && data.head.webrtc && data.head.webrtc == CALL_HEAD_STARTED) {
// If it's a video call invite message.
// See if we need to display incoming call UI.
const topic = this.tinode.getTopic(data.topic);
if (topic) {
// Check if a later version of the message exists (which means the call
// has been either accepted or finished already).
const msg = topic.latestMsgVersion(data.seq) || data;
if (msg.head && msg.head.webrtc && msg.head.webrtc == CALL_HEAD_STARTED) {
// This is a legit new call.
if (data.from != this.state.myUserId) {
if (this.state.callState == CALL_STATE_NONE) {
// Incoming call.
this.setState({
callTopic: data.topic,
callState: CALL_STATE_INCOMING_RECEIVED,
callSeq: data.seq
});
} else {
// Another call is either in progress or being established.
// Reject the incoming call.
this.handleCallHangup(data.topic, data.seq);
}
}
}
} else {
console.warn("Received vc data message from unknown topic", data.topic);
}
}
}
render() { render() {
return ( return (
<div id="app-container" ref={this.selfRef}> <div id="app-container" ref={this.selfRef}>
+3 -2
View File
@@ -39,8 +39,9 @@ export default class CallIncoming extends React.Component {
this.resetDesc(topic, this.props); this.resetDesc(topic, this.props);
if (this.props.callState == CALL_STATE_INCOMING_RECEIVED) { if (this.props.callState == CALL_STATE_INCOMING_RECEIVED) {
RING_SOUND.play(); // play() throws if the user did not click the app first: https://goo.gl/xX8pDD.
this.ringTimer = setInterval(() => RING_SOUND.play(), 2000); RING_SOUND.play().catch(_ => {});
this.ringTimer = setInterval(_ => {RING_SOUND.play().catch(_ => {})}, 2000);
this.props.onRinging(this.props.topic, this.props.seq); this.props.onRinging(this.props.topic, this.props.seq);
} }
} }
+15 -7
View File
@@ -13,6 +13,7 @@ const RING_SOUND = new Audio('audio/call-out.m4a');
RING_SOUND.loop = true; RING_SOUND.loop = true;
const CALL_ENDED_SOUND = new Audio('audio/call-end.m4a'); const CALL_ENDED_SOUND = new Audio('audio/call-end.m4a');
CALL_ENDED_SOUND.loop = true; CALL_ENDED_SOUND.loop = true;
const DIALING_SOUND = new Audio('audio/dialing.m4a');
const messages = defineMessages({ const messages = defineMessages({
already_in_call: { already_in_call: {
@@ -107,9 +108,6 @@ class CallPanel extends React.PureComponent {
case 'accept': case 'accept':
this.handleVideoCallAccepted(info); this.handleVideoCallAccepted(info);
break; break;
case 'offer':
this.handleVideoOfferMsg(info);
break;
case 'answer': case 'answer':
this.handleVideoAnswerMsg(info); this.handleVideoAnswerMsg(info);
break; break;
@@ -119,6 +117,16 @@ class CallPanel extends React.PureComponent {
case 'hang-up': case 'hang-up':
this.handleRemoteHangup(info); this.handleRemoteHangup(info);
break; break;
case 'offer':
this.handleVideoOfferMsg(info);
break;
case 'ringing':
// play() throws if the user did not click the app first: https://goo.gl/xX8pDD.
RING_SOUND.play().catch(_ => {});
break;
default:
console.warn("Unknown call event", info.event);
break;
} }
} }
@@ -141,7 +149,7 @@ class CallPanel extends React.PureComponent {
this.setState({localStream: stream, waitingForPeer: true}); this.setState({localStream: stream, waitingForPeer: true});
this.localRef.current.srcObject = stream; this.localRef.current.srcObject = stream;
RING_SOUND.play(); DIALING_SOUND.play();
// Send call invitation. // Send call invitation.
this.props.onInvite(this.props.topic, this.props.seq, this.props.callState); this.props.onInvite(this.props.topic, this.props.seq, this.props.callState);
@@ -256,7 +264,7 @@ class CallPanel extends React.PureComponent {
} }
handleICEGatheringStateChangeEvent(event) { handleICEGatheringStateChangeEvent(event) {
console.log('ICE gathering change state: ', event); // console.log('ICE gathering change state: ', event);
} }
handleTrackEvent(event) { handleTrackEvent(event) {
@@ -278,7 +286,7 @@ class CallPanel extends React.PureComponent {
break; break;
default: default:
this.reportError(e.message); this.reportError(e.message);
console.error('Error opening your camera and/or microphone: ' + e.message); console.error("Error opening your camera and/or microphone:", e.message);
break; break;
} }
@@ -329,7 +337,7 @@ class CallPanel extends React.PureComponent {
RING_SOUND.pause(); RING_SOUND.pause();
RING_SOUND.currentTime = 0; RING_SOUND.currentTime = 0;
CALL_ENDED_SOUND.loop = true; CALL_ENDED_SOUND.loop = true;
CALL_ENDED_SOUND.play(); CALL_ENDED_SOUND.play().catch(_ => {});
setTimeout(_ => { setTimeout(_ => {
this.handleCloseClick(); this.handleCloseClick();
}, 2000); }, 2000);
+1 -1
View File
@@ -110,6 +110,7 @@ export default class InPlaceEdit extends React.Component {
attr.type = this.props.type || 'text'; attr.type = this.props.type || 'text';
} }
attr.value = this.state.value; attr.value = this.state.value;
attr.ref = this.selfRef;
attr.onChange = this.handeTextChange; attr.onChange = this.handeTextChange;
attr.onKeyDown = this.handleKeyDown; attr.onKeyDown = this.handleKeyDown;
attr.onBlur = this.handleEditingFinished; attr.onBlur = this.handleEditingFinished;
@@ -118,7 +119,6 @@ export default class InPlaceEdit extends React.Component {
attr.required = this.props.required ? 'required' : ''; attr.required = this.props.required ? 'required' : '';
attr.autoComplete = this.props.autoComplete; attr.autoComplete = this.props.autoComplete;
attr.autoFocus = true; attr.autoFocus = true;
attr.ref = this.selfRef;
return React.createElement(element, attr, null); return React.createElement(element, attr, null);
} }
+1 -1
View File
@@ -45,7 +45,7 @@ class SendMessage extends React.PureComponent {
quote: null, quote: null,
message: '', message: '',
audioRec: false, audioRec: false,
audioAvailable: !!navigator.mediaDevices.getUserMedia, audioAvailable: !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia),
// Make initial keypress time as if it happened 5001 milliseconds in the past. // Make initial keypress time as if it happened 5001 milliseconds in the past.
keypressTimestamp: new Date().getTime() - KEYPRESS_DELAY - 1 keypressTimestamp: new Date().getTime() - KEYPRESS_DELAY - 1
}; };
+9 -3
View File
@@ -5,6 +5,8 @@ export default class VisiblePassword extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.inputRef = React.createRef();
this.state = { this.state = {
value: this.props.value, value: this.props.value,
visible: false visible: false
@@ -16,6 +18,10 @@ export default class VisiblePassword extends React.PureComponent {
this.handleEditingFinished = this.handleEditingFinished.bind(this); this.handleEditingFinished = this.handleEditingFinished.bind(this);
} }
componentDidMount() {
this.inputRef.current.focus();
}
handeTextChange(e) { handeTextChange(e) {
this.setState({value: e.target.value}); this.setState({value: e.target.value});
if (this.props.onChange) { if (this.props.onChange) {
@@ -58,8 +64,7 @@ export default class VisiblePassword extends React.PureComponent {
render() { render() {
return ( return (
<div tabIndex="-1" className="group-focus" <div tabIndex="-1" className="group-focus" onBlur={this.handleEditingFinished}>
onBlur={this.handleEditingFinished}>
<input className="with-visibility" <input className="with-visibility"
type={this.state.visible ? "text" : "password"} type={this.state.visible ? "text" : "password"}
value={this.state.value} value={this.state.value}
@@ -68,7 +73,8 @@ export default class VisiblePassword extends React.PureComponent {
autoFocus={this.props.autoFocus ? 'autoFocus' : ''} autoFocus={this.props.autoFocus ? 'autoFocus' : ''}
autoComplete={this.props.autoComplete} autoComplete={this.props.autoComplete}
onChange={this.handeTextChange} onChange={this.handeTextChange}
onKeyDown={this.handleKeyDown} /> onKeyDown={this.handleKeyDown}
ref={this.inputRef} />
<span onClick={this.handleVisibility}> <span onClick={this.handleVisibility}>
<i className="material-icons clickable light-gray"> <i className="material-icons clickable light-gray">
{this.state.visible ? 'visibility' : 'visibility_off'} {this.state.visible ? 'visibility' : 'visibility_off'}
+447 -257
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+230 -24
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,3 +1,3 @@
// This is a generated file. Don't edit. // This is a generated file. Don't edit.
const PACKAGE_VERSION = "0.20.0-beta1"; const PACKAGE_VERSION = "0.20.0-beta2";
Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 KiB