From 39c628d4a15e9907c99961a35d54c192172210cb Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 14 Dec 2015 23:37:34 +0000 Subject: [PATCH] implement the 'correct' voip calling design --- src/components/structures/RoomView.js | 99 +++++++++++-- src/components/views/rooms/MessageComposer.js | 45 +++++- src/components/views/rooms/RoomHeader.js | 136 +----------------- 3 files changed, 134 insertions(+), 146 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 36ee4b8733..5401cd6e12 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -59,6 +59,7 @@ module.exports = React.createClass({ searchResults: null, syncState: MatrixClientPeg.get().getSyncState(), hasUnsentMessages: this._hasUnsentMessages(room), + callState: null, } }, @@ -114,7 +115,17 @@ module.exports = React.createClass({ this.forceUpdate(); break; case 'call_state': - if (CallHandler.getCallForRoom(this.props.roomId)) { + // don't filter out payloads for room IDs other than props.room because + // we may be interested in the conf 1:1 room + + if (!payload.room_id) { + return; + } + + var call = CallHandler.getCallForRoom(payload.room_id); + var callState; + + if (call) { // Call state has changed so we may be loading video elements // which will obscure the message log. // scroll to bottom @@ -122,11 +133,20 @@ module.exports = React.createClass({ if (scrollNode) { scrollNode.scrollTop = scrollNode.scrollHeight; } + callState = call.call_state; + } + else { + callState = "ended"; } // possibly remove the conf call notification if we're now in // the conf this._updateConfCallNotification(); + + this.setState({ + callState: callState + }); + break; case 'user_activity': this.sendReadReceipt(); @@ -276,6 +296,12 @@ module.exports = React.createClass({ this.fillSpace(); } + var call = CallHandler.getCallForRoom(this.props.roomId); + var callState = call ? call.call_state : "ended"; + this.setState({ + callState: callState + }); + this._updateConfCallNotification(); window.addEventListener('resize', this.onResize); @@ -972,6 +998,30 @@ module.exports = React.createClass({ } }, + onMuteAudioClick: function() { + var call = CallHandler.getCallForRoom(this.props.roomId); + if (!call) { + return; + } + var newState = !call.isMicrophoneMuted(); + call.setMicrophoneMuted(newState); + this.setState({ + audioMuted: newState + }); + }, + + onMuteVideoClick: function() { + var call = CallHandler.getCallForRoom(this.props.roomId); + if (!call) { + return; + } + var newState = !call.isLocalVideoMuted(); + call.setLocalVideoMuted(newState); + this.setState({ + videoMuted: newState + }); + }, + render: function() { var RoomHeader = sdk.getComponent('rooms.RoomHeader'); var MessageComposer = sdk.getComponent('rooms.MessageComposer'); @@ -1029,9 +1079,7 @@ module.exports = React.createClass({ loading: this.state.paginating }); - var statusBar = ( -
- ); + var statusBar; // for testing UI... // this.state.upload = { @@ -1043,7 +1091,7 @@ module.exports = React.createClass({ if (ContentMessages.getCurrentUploads().length > 0) { var UploadBar = sdk.getComponent('structures.UploadBar'); statusBar = - } else { + } else if (!this.state.searchResults) { var typingString = this.getWhoIsTypingString(); // typingString = "S͚͍̭̪̤͙̱͙̖̥͙̥̤̻̙͕͓͂̌ͬ͐̂k̜̝͎̰̥̻̼̂̌͛͗͊̅̒͂̊̍̍͌̈̈́͌̋̊ͬa͉̯͚̺̗̳̩ͪ̋̑͌̓̆̍̂̉̏̅̆ͧ̌̑v̲̲̪̝ͥ̌ͨͮͭ̊͆̾ͮ̍ͮ͑̚e̮̙͈̱̘͕̼̮͒ͩͨͫ̃͗̇ͩ͒ͣͦ͒̄̍͐ͣ̿ͥṘ̗̺͇̺̺͔̄́̊̓͊̍̃ͨ̚ā̼͎̘̟̼͎̜̪̪͚̋ͨͨͧ̓ͦͯͤ̄͆̋͂ͩ͌ͧͅt̙̙̹̗̦͖̞ͫͪ͑̑̅ͪ̃̚ͅ is typing..."; var unreadMsgs = this.getUnreadMessagesString(); @@ -1142,7 +1190,7 @@ module.exports = React.createClass({ var messageComposer, searchInfo; if (!this.state.searchResults) { messageComposer = - + } else { searchInfo = { @@ -1152,8 +1200,43 @@ module.exports = React.createClass({ } } + var call = CallHandler.getCallForRoom(this.props.roomId); + var inCall = false; + if (call && this.state.callState != 'ended') { + inCall = true; + //var muteVideoButton; + var voiceMuteButton, videoMuteButton; + + if (call.type === "video") { + videoMuteButton = +
+ +
+ } + voiceMuteButton = +
+ +
+ + if (!statusBar) { + statusBar = +
+ + Active call +
; + } + + statusBar = +
+ { voiceMuteButton } + { videoMuteButton } + { statusBar } + +
+ } + return ( -
+
{ fileDropTarget } @@ -1174,7 +1257,7 @@ module.exports = React.createClass({
- { this.state.searchResults ? null : statusBar } + { statusBar }
{ messageComposer } diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 045b633403..73f553af6e 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ var React = require("react"); + var marked = require("marked"); marked.setOptions({ renderer: new marked.Renderer(), @@ -25,9 +26,11 @@ marked.setOptions({ smartLists: true, smartypants: false }); + var MatrixClientPeg = require("../../../MatrixClientPeg"); var SlashCommands = require("../../../SlashCommands"); var Modal = require("../../../Modal"); +var CallHandler = require('../../../CallHandler'); var sdk = require('../../../index'); var dis = require("../../../dispatcher"); @@ -524,6 +527,19 @@ module.exports = React.createClass({ this.refs.uploadInput.value = null; }, + onHangupClick: function() { + var call = CallHandler.getCallForRoom(this.props.room.roomId); + if (!call) { + return; + } + dis.dispatch({ + action: 'hangup', + // hangup the call for this room, which may not be the room in props + // (e.g. conferences which will hangup the 1:1 room instead) + room_id: call.roomId + }); + }, + onCallClick: function(ev) { dis.dispatch({ action: 'place_call', @@ -544,6 +560,26 @@ module.exports = React.createClass({ var me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId); var uploadInputStyle = {display: 'none'}; var MemberAvatar = sdk.getComponent('avatars.MemberAvatar'); + + var callButton, videoCallButton, hangupButton; + var call = CallHandler.getCallForRoom(this.props.room.roomId); + if (this.props.callState && this.props.callState !== 'ended') { + hangupButton = +
+ Hangup +
; + } + else { + callButton = +
+ Voice call +
+ videoCallButton = +
+ Video call +
+ } + return (
@@ -558,12 +594,9 @@ module.exports = React.createClass({ Upload file
-
- Voice call -
-
- Video call -
+ { hangupButton } + { callButton } + { videoCallButton }
diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index 07b2521b27..e410d7c6e4 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -16,15 +16,9 @@ limitations under the License. 'use strict'; -/* - * State vars: - * this.state.call_state = the UI state of the call (see CallHandler) - */ - var React = require('react'); var sdk = require('../../../index'); var dis = require("../../../dispatcher"); -var CallHandler = require("../../../CallHandler"); var MatrixClientPeg = require('../../../MatrixClientPeg'); module.exports = React.createClass({ @@ -47,34 +41,6 @@ module.exports = React.createClass({ }; }, - componentDidMount: function() { - this.dispatcherRef = dis.register(this.onAction); - if (this.props.room) { - var call = CallHandler.getCallForRoom(this.props.room.roomId); - var callState = call ? call.call_state : "ended"; - this.setState({ - call_state: callState - }); - } - }, - - componentWillUnmount: function() { - dis.unregister(this.dispatcherRef); - }, - - onAction: function(payload) { - // don't filter out payloads for room IDs other than props.room because - // we may be interested in the conf 1:1 room - if (payload.action !== 'call_state' || !payload.room_id) { - return; - } - var call = CallHandler.getCallForRoom(payload.room_id); - var callState = call ? call.call_state : "ended"; - this.setState({ - call_state: callState - }); - }, - onVideoClick: function(e) { dis.dispatch({ action: 'place_call', @@ -82,6 +48,7 @@ module.exports = React.createClass({ room_id: this.props.room.roomId }); }, + onVoiceClick: function() { dis.dispatch({ action: 'place_call', @@ -89,38 +56,6 @@ module.exports = React.createClass({ room_id: this.props.room.roomId }); }, - onHangupClick: function() { - var call = CallHandler.getCallForRoom(this.props.room.roomId); - if (!call) { return; } - dis.dispatch({ - action: 'hangup', - // hangup the call for this room, which may not be the room in props - // (e.g. conferences which will hangup the 1:1 room instead) - room_id: call.roomId - }); - }, - onMuteAudioClick: function() { - var call = CallHandler.getCallForRoom(this.props.room.roomId); - if (!call) { - return; - } - var newState = !call.isMicrophoneMuted(); - call.setMicrophoneMuted(newState); - this.setState({ - audioMuted: newState - }); - }, - onMuteVideoClick: function() { - var call = CallHandler.getCallForRoom(this.props.room.roomId); - if (!call) { - return; - } - var newState = !call.isLocalVideoMuted(); - call.setLocalVideoMuted(newState); - this.setState({ - videoMuted: newState - }); - }, onNameChange: function(new_name) { if (this.props.room.name != new_name && new_name) { @@ -152,42 +87,6 @@ module.exports = React.createClass({ else { var topic = this.props.room.currentState.getStateEvents('m.room.topic', ''); - var call_buttons; - if (this.state && this.state.call_state != 'ended') { - //var muteVideoButton; - var activeCall = ( - CallHandler.getCallForRoom(this.props.room.roomId) - ); -/* - if (activeCall && activeCall.type === "video") { - muteVideoButton = ( -
- { - (activeCall.isLocalVideoMuted() ? - "Unmute" : "Mute") + " video" - } -
- ); - } - {muteVideoButton} -
- { - (activeCall && activeCall.isMicrophoneMuted() ? - "Unmute" : "Mute") + " audio" - } -
-*/ - - call_buttons = ( -
- End call -
- ); - } - var name = null; var searchStatus = null; var topic_el = null; @@ -230,32 +129,9 @@ module.exports = React.createClass({ ); } - var zoom_button, video_button, voice_button; - if (activeCall) { - if (activeCall.type == "video") { - zoom_button = ( -
- Fullscreen -
- ); - } - video_button = -
- Video call -
; - var img = "img/voip.png"; - if (activeCall.isMicrophoneMuted()) { - img = "img/voip-mute.png"; - } - voice_button = -
- VoIP call -
; - } - - var exit_button; + var leave_button; if (this.props.onLeaveClick) { - exit_button = + leave_button =
Leave room
; @@ -272,14 +148,10 @@ module.exports = React.createClass({ { topic_el }
- {call_buttons} {cancel_button} {save_button}
- { video_button } - { voice_button } - { zoom_button } - { exit_button } + { leave_button }
Search