diff --git a/README.md b/README.md index 1e170a5c..f80e731c 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ Background pattern from http://subtlepatterns.com/, commercial and non-commercia * Cannot send images or other media. * Cannot delete messages. -* No typing indicators. * No indication of chat status (muted, blocked, etc.). * Browser push notifications are missing. * No encryption. diff --git a/css/base.css b/css/base.css index 6977804e..75bfc322 100644 --- a/css/base.css +++ b/css/base.css @@ -628,6 +628,24 @@ table.permission-editor td.checkbox { background-color: #C0C0C0; } +/* Typing indicator: animation of the online dot */ +.online.typing { + animation: typing 1.5s infinite; +} + +@keyframes typing { + 0% { background-color: #40C040; } + 25% { background-image: radial-gradient(#30D030 0%, #40C040 67%); } + 33.3% { background-image: radial-gradient(#10EE10 0%, #40C040 50%); } + 41.7% { background-image: radial-gradient(#00FF00 0%, #40C040 35%); } + 50% { background-image: radial-gradient(#30D030 0%, #40C040 67%); } + 58.3% { background-image: radial-gradient(#10EE10 0%, #40C040 50%); } + 66.7% { background-image: radial-gradient(#00FF00 0%, #40C040 35%); } + 75% { background-image: radial-gradient(#30D030 0%, #40C040 67%); } + 83.3% { background-image: radial-gradient(#10EE10 0%, #40C040 50%); } + 91.6% { background-image: radial-gradient(#00FF00 0%, #40C040 35%); } +} + .contact-box .checkmark.material-icons { display: inline-block; width: 1.5rem; @@ -1474,11 +1492,6 @@ ul.tabbar li.active > a:after { animation: spin 1.5s linear infinite; } -@-webkit-keyframes spin { - 0% { -webkit-transform: rotate(0deg); } - 100% { -webkit-transform: rotate(360deg); } -} - @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } diff --git a/index.html b/index.html index 0aa3ddb3..949f86ee 100644 --- a/index.html +++ b/index.html @@ -36,7 +36,7 @@ var API_KEY = "AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K"; // Minimum time between two keypress notifications, milliseconds. - var KEYPRESS_DELAY = 5*1000; + var KEYPRESS_DELAY = 3*1000; // Delay before sending a {note} for reciving a message, milliseconds. var RECEIVED_DELAY = 500; @@ -2352,7 +2352,8 @@ topic: '', title: '', avatar: null, - scrollPosition: 0 + scrollPosition: 0, + typingIndicator: false }; }, @@ -2500,9 +2501,17 @@ }, handleInfoReceipt: function(info) { switch (info.what) { - case "kp": - console.log("show typing notification"); + case "kp": { + clearTimeout(this.keyPressTimer); + var instance = this; + this.keyPressTimer = setTimeout(function() { + instance.setState({typingIndicator: false}); + }, KEYPRESS_DELAY + 1000); + if (!this.state.typingIndicator) { + this.setState({typingIndicator: true}); + } break; + } case "read": case "recv": // Redraw due to changed recv/read status. @@ -2583,11 +2592,12 @@ if (cont.online) { lastSeen = "online now"; } else if (cont.seen) { - lastSeen = "Last seen: " + shortDateFormat(cont.seen.when); + lastSeen = "Last active: " + shortDateFormat(cont.seen.when); // TODO(gene): also handle user agent in c.seen.ua } } var avatar = this.state.avatar || true; + var online = cont && cont.online ? "online" + (this.state.typingIndicator ? " typing" : "") : "offline"; component = (