Merge branch 'rav/roomview_works' into rav/read_marker
Conflicts: src/components/structures/RoomView.jspull/21833/head
						commit
						c9f9ccc43f
					
				|  | @ -72,6 +72,7 @@ module.exports.components['views.messages.TextualEvent'] = require('./components | |||
| module.exports.components['views.messages.UnknownBody'] = require('./components/views/messages/UnknownBody'); | ||||
| module.exports.components['views.room_settings.AliasSettings'] = require('./components/views/room_settings/AliasSettings'); | ||||
| module.exports.components['views.room_settings.ColorSettings'] = require('./components/views/room_settings/ColorSettings'); | ||||
| module.exports.components['views.rooms.AuxPanel'] = require('./components/views/rooms/AuxPanel'); | ||||
| module.exports.components['views.rooms.EntityTile'] = require('./components/views/rooms/EntityTile'); | ||||
| module.exports.components['views.rooms.EventTile'] = require('./components/views/rooms/EventTile'); | ||||
| module.exports.components['views.rooms.InviteMemberList'] = require('./components/views/rooms/InviteMemberList'); | ||||
|  |  | |||
|  | @ -61,11 +61,13 @@ module.exports = React.createClass({ | |||
|     getInitialState: function() { | ||||
|         return { | ||||
|             syncState: MatrixClientPeg.get().getSyncState(), | ||||
|             whoisTypingString: WhoIsTyping.whoIsTypingString(this.props.room), | ||||
|         }; | ||||
|     }, | ||||
| 
 | ||||
|     componentWillMount: function() { | ||||
|         MatrixClientPeg.get().on("sync", this.onSyncStateChange); | ||||
|         MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping); | ||||
|     }, | ||||
| 
 | ||||
|     componentDidUpdate: function(prevProps, prevState) { | ||||
|  | @ -76,8 +78,10 @@ module.exports = React.createClass({ | |||
| 
 | ||||
|     componentWillUnmount: function() { | ||||
|         // we may have entirely lost our client as we're logging out before clicking login on the guest bar...
 | ||||
|         if (MatrixClientPeg.get()) { | ||||
|             MatrixClientPeg.get().removeListener("sync", this.onSyncStateChange); | ||||
|         var client = MatrixClientPeg.get(); | ||||
|         if (client) { | ||||
|             client.removeListener("sync", this.onSyncStateChange); | ||||
|             client.removeListener("RoomMember.typing", this.onRoomMemberTyping); | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|  | @ -90,6 +94,12 @@ module.exports = React.createClass({ | |||
|         }); | ||||
|     }, | ||||
| 
 | ||||
|     onRoomMemberTyping: function(ev, member) { | ||||
|         this.setState({ | ||||
|             whoisTypingString: WhoIsTyping.whoIsTypingString(this.props.room), | ||||
|         }); | ||||
|     }, | ||||
| 
 | ||||
|     // determine if we need to call onResize
 | ||||
|     _checkForResize: function(prevProps, prevState) { | ||||
|         // figure out the old height and the new height of the status bar. We
 | ||||
|  | @ -235,7 +245,7 @@ module.exports = React.createClass({ | |||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         var typingString = WhoIsTyping.whoIsTypingString(this.props.room); | ||||
|         var typingString = this.state.whoisTypingString; | ||||
|         if (typingString) { | ||||
|             return ( | ||||
|                 <div className="mx_RoomStatusBar_typingBar"> | ||||
|  |  | |||
|  | @ -15,7 +15,6 @@ limitations under the License. | |||
| */ | ||||
| 
 | ||||
| // TODO: This component is enormous! There's several things which could stand-alone:
 | ||||
| //  - Aux component
 | ||||
| //  - Search results component
 | ||||
| //  - Drag and drop
 | ||||
| //  - File uploading - uploadFile()
 | ||||
|  | @ -92,6 +91,8 @@ module.exports = React.createClass({ | |||
|             atEndOfLiveTimeline: true, | ||||
| 
 | ||||
|             showTopUnreadMessagesBar: false, | ||||
| 
 | ||||
|             auxPanelMaxHeight: undefined, | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|  | @ -101,7 +102,6 @@ module.exports = React.createClass({ | |||
|         MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline); | ||||
|         MatrixClientPeg.get().on("Room.name", this.onRoomName); | ||||
|         MatrixClientPeg.get().on("Room.accountData", this.onRoomAccountData); | ||||
|         MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping); | ||||
|         MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember); | ||||
|         // xchat-style tab complete, add a colon if tab
 | ||||
|         // completing at the start of the text
 | ||||
|  | @ -173,7 +173,6 @@ module.exports = React.createClass({ | |||
|             MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline); | ||||
|             MatrixClientPeg.get().removeListener("Room.name", this.onRoomName); | ||||
|             MatrixClientPeg.get().removeListener("Room.accountData", this.onRoomAccountData); | ||||
|             MatrixClientPeg.get().removeListener("RoomMember.typing", this.onRoomMemberTyping); | ||||
|             MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember); | ||||
|         } | ||||
| 
 | ||||
|  | @ -342,10 +341,6 @@ module.exports = React.createClass({ | |||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     onRoomMemberTyping: function(ev, member) { | ||||
|         this.forceUpdate(); | ||||
|     }, | ||||
| 
 | ||||
|     onRoomStateMember: function(ev, state, member) { | ||||
|         if (member.roomId === this.props.roomId) { | ||||
|             // a member state changed in this room, refresh the tab complete list
 | ||||
|  | @ -878,14 +873,6 @@ module.exports = React.createClass({ | |||
|         }); | ||||
|     }, | ||||
| 
 | ||||
|     onConferenceNotificationClick: function() { | ||||
|         dis.dispatch({ | ||||
|             action: 'place_call', | ||||
|             type: "video", | ||||
|             room_id: this.props.roomId | ||||
|         }); | ||||
|     }, | ||||
| 
 | ||||
|     // jump down to the bottom of this room, where new events are arriving
 | ||||
|     jumpToLiveTimeline: function() { | ||||
|         this.refs.messagePanel.jumpToLiveTimeline(); | ||||
|  | @ -983,25 +970,10 @@ module.exports = React.createClass({ | |||
|         // but it's better than the video going missing entirely
 | ||||
|         if (auxPanelMaxHeight < 50) auxPanelMaxHeight = 50; | ||||
| 
 | ||||
|         if (this.refs.callView) { | ||||
|             var fullscreenElement = | ||||
|                 (document.fullscreenElement || | ||||
|                  document.mozFullScreenElement || | ||||
|                  document.webkitFullscreenElement); | ||||
|             if (!fullscreenElement) { | ||||
|                 var video = this.refs.callView.getVideoView().getRemoteVideoElement(); | ||||
|                 video.style.maxHeight = auxPanelMaxHeight + "px"; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // we need to do this for general auxPanels too
 | ||||
|         if (this.refs.auxPanel) { | ||||
|             this.refs.auxPanel.style.maxHeight = auxPanelMaxHeight + "px"; | ||||
|         } | ||||
| 
 | ||||
|         // the above might have made the aux panel resize itself, so now
 | ||||
|         // we need to tell the gemini panel to adapt.
 | ||||
|         this.onChildResize(); | ||||
|         // we may need to resize the gemini panel after changing the aux panel
 | ||||
|         // size, so add a callback to onChildResize.
 | ||||
|         this.setState({auxPanelMaxHeight: auxPanelMaxHeight}, | ||||
|                       this.onChildResize); | ||||
|     }, | ||||
| 
 | ||||
|     onFullscreenClick: function() { | ||||
|  | @ -1035,11 +1007,6 @@ module.exports = React.createClass({ | |||
|         }); | ||||
|     }, | ||||
| 
 | ||||
|     onCallViewResize: function() { | ||||
|         this.onChildResize(); | ||||
|         this.onResize(); | ||||
|     }, | ||||
| 
 | ||||
|     onChildResize: function() { | ||||
|         // When the video, status bar, or the message composer resizes, the
 | ||||
|         // scroll panel also changes size.  Work around GeminiScrollBar fail by
 | ||||
|  | @ -1062,8 +1029,8 @@ module.exports = React.createClass({ | |||
|     render: function() { | ||||
|         var RoomHeader = sdk.getComponent('rooms.RoomHeader'); | ||||
|         var MessageComposer = sdk.getComponent('rooms.MessageComposer'); | ||||
|         var CallView = sdk.getComponent("voip.CallView"); | ||||
|         var RoomSettings = sdk.getComponent("rooms.RoomSettings"); | ||||
|         var AuxPanel = sdk.getComponent("rooms.AuxPanel"); | ||||
|         var SearchBar = sdk.getComponent("rooms.SearchBar"); | ||||
|         var ScrollPanel = sdk.getComponent("structures.ScrollPanel"); | ||||
|         var TintableSvg = sdk.getComponent("elements.TintableSvg"); | ||||
|  | @ -1206,28 +1173,16 @@ module.exports = React.createClass({ | |||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         var conferenceCallNotification = null; | ||||
|         if (this.state.displayConfCallNotification) { | ||||
|             var supportedText; | ||||
|             if (!MatrixClientPeg.get().supportsVoip()) { | ||||
|                 supportedText = " (unsupported)"; | ||||
|             } | ||||
|             conferenceCallNotification = ( | ||||
|                 <div className="mx_RoomView_ongoingConfCallNotification" onClick={this.onConferenceNotificationClick}> | ||||
|                     Ongoing conference call {supportedText} | ||||
|                 </div> | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         var fileDropTarget = null; | ||||
|         if (this.state.draggingFile) { | ||||
|             fileDropTarget = <div className="mx_RoomView_fileDropTarget"> | ||||
|                                 <div className="mx_RoomView_fileDropTargetLabel" title="Drop File Here"> | ||||
|                                     <TintableSvg src="img/upload-big.svg" width="45" height="59"/><br/> | ||||
|                                     Drop file here to upload | ||||
|                                 </div> | ||||
|                              </div>; | ||||
|         } | ||||
|         var auxPanel = ( | ||||
|             <AuxPanel ref="auxPanel" room={this.state.room} | ||||
|               conferenceHandler={this.props.ConferenceHandler} | ||||
|               draggingFile={this.state.draggingFile} | ||||
|               displayConfCallNotification={this.state.displayConfCallNotification} | ||||
|               maxHeight={this.state.auxPanelMaxHeight} | ||||
|               onCallViewVideoRezize={this.onChildResize} > | ||||
|                 { aux } | ||||
|             </AuxPanel> | ||||
|         ); | ||||
| 
 | ||||
|         var messageComposer, searchInfo; | ||||
|         var canSpeak = ( | ||||
|  | @ -1345,13 +1300,7 @@ module.exports = React.createClass({ | |||
|                     onLeaveClick={ | ||||
|                         (myMember && myMember.membership === "join") ? this.onLeaveClick : null | ||||
|                     } /> | ||||
|                 <div className="mx_RoomView_auxPanel" ref="auxPanel"> | ||||
|                     { fileDropTarget }     | ||||
|                     <CallView ref="callView" room={this.state.room} ConferenceHandler={this.props.ConferenceHandler} | ||||
|                         onResize={this.onCallViewResize} /> | ||||
|                     { conferenceCallNotification } | ||||
|                     { aux } | ||||
|                 </div> | ||||
|                 { auxPanel } | ||||
|                 { topUnreadMessagesBar } | ||||
|                 { messagePanel } | ||||
|                 { searchResultsPanel } | ||||
|  |  | |||
|  | @ -0,0 +1,104 @@ | |||
| /* | ||||
| Copyright 2015, 2016 OpenMarket Ltd | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| var React = require('react'); | ||||
| var MatrixClientPeg = require("../../../MatrixClientPeg"); | ||||
| var sdk = require('../../../index'); | ||||
| var dis = require("../../../dispatcher"); | ||||
| 
 | ||||
| module.exports = React.createClass({ | ||||
|     displayName: 'AuxPanel', | ||||
| 
 | ||||
|     propTypes: { | ||||
|         // js-sdk room object
 | ||||
|         room: React.PropTypes.object.isRequired, | ||||
| 
 | ||||
|         // Conference Handler implementation
 | ||||
|         conferenceHandler: React.PropTypes.object, | ||||
| 
 | ||||
|         // set to true to show the file drop target
 | ||||
|         draggingFile: React.PropTypes.bool, | ||||
| 
 | ||||
|         // set to true to show the 'active conf call' banner
 | ||||
|         displayConfCallNotification: React.PropTypes.bool, | ||||
| 
 | ||||
|         // maxHeight attribute for the aux panel and the video
 | ||||
|         // therein
 | ||||
|         maxHeight: React.PropTypes.number, | ||||
| 
 | ||||
|         // a callback which is called when the video element in a voip call is
 | ||||
|         // resized due to a change in video metadata
 | ||||
|         onCallViewVideoResize: React.PropTypes.func, | ||||
|     }, | ||||
| 
 | ||||
|     onConferenceNotificationClick: function() { | ||||
|         dis.dispatch({ | ||||
|             action: 'place_call', | ||||
|             type: "video", | ||||
|             room_id: this.props.room.roomId, | ||||
|         }); | ||||
|     }, | ||||
| 
 | ||||
|     render: function() { | ||||
|         var CallView = sdk.getComponent("voip.CallView"); | ||||
|         var TintableSvg = sdk.getComponent("elements.TintableSvg"); | ||||
| 
 | ||||
|         var fileDropTarget = null; | ||||
|         if (this.props.draggingFile) { | ||||
|             fileDropTarget = ( | ||||
|                 <div className="mx_RoomView_fileDropTarget"> | ||||
|                     <div className="mx_RoomView_fileDropTargetLabel" | ||||
|                       title="Drop File Here"> | ||||
|                         <TintableSvg src="img/upload-big.svg" width="45" height="59"/> | ||||
|                         <br/> | ||||
|                         Drop file here to upload | ||||
|                     </div> | ||||
|                 </div> | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         var conferenceCallNotification = null; | ||||
|         if (this.props.displayConfCallNotification) { | ||||
|             var supportedText; | ||||
|             if (!MatrixClientPeg.get().supportsVoip()) { | ||||
|                 supportedText = " (unsupported)"; | ||||
|             } | ||||
|             conferenceCallNotification = ( | ||||
|                 <div className="mx_RoomView_ongoingConfCallNotification" | ||||
|                         onClick={this.onConferenceNotificationClick}> | ||||
|                     Ongoing conference call {supportedText} | ||||
|                 </div> | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         var callView = ( | ||||
|             <CallView ref="callView" room={this.props.room} | ||||
|                 ConferenceHandler={this.props.conferenceHandler} | ||||
|                 onResize={this.props.onCallViewVideoResize} | ||||
|                 maxVideoHeight={this.props.maxHeight} | ||||
|             /> | ||||
|         ); | ||||
| 
 | ||||
|         return ( | ||||
|             <div className="mx_RoomView_auxPanel" style={{maxHeight: this.props.maxHeight}} > | ||||
|                 { fileDropTarget } | ||||
|                 { callView } | ||||
|                 { conferenceCallNotification } | ||||
|                 { this.props.children } | ||||
|             </div> | ||||
|         ); | ||||
|     }, | ||||
| }); | ||||
|  | @ -19,38 +19,32 @@ var CallHandler = require("../../../CallHandler"); | |||
| var sdk = require('../../../index'); | ||||
| var MatrixClientPeg = require("../../../MatrixClientPeg"); | ||||
| 
 | ||||
| /* | ||||
|  * State vars: | ||||
|  * this.state.call = MatrixCall|null | ||||
|  * | ||||
|  * Props: | ||||
|  * this.props.room = Room (JS SDK) | ||||
|  * this.props.ConferenceHandler = A Conference Handler implementation | ||||
|  *                                Must have a function signature: | ||||
|  *                                getConferenceCallForRoom(roomId: string): MatrixCall | ||||
|  */ | ||||
| 
 | ||||
| module.exports = React.createClass({ | ||||
|     displayName: 'CallView', | ||||
| 
 | ||||
|     propTypes: { | ||||
|         // a callback which is called when the video within the callview
 | ||||
|         // due to a change in video metadata
 | ||||
|         // js-sdk room object
 | ||||
|         room: React.PropTypes.object.isRequired, | ||||
| 
 | ||||
|         // A Conference Handler implementation
 | ||||
|         // Must have a function signature:
 | ||||
|         //  getConferenceCallForRoom(roomId: string): MatrixCall
 | ||||
|         ConferenceHandler: React.PropTypes.object, | ||||
| 
 | ||||
|         // maxHeight style attribute for the video panel
 | ||||
|         maxVideoHeight: React.PropTypes.number, | ||||
| 
 | ||||
|         // a callback which is called when the user clicks on the video div
 | ||||
|         onClick: React.PropTypes.func, | ||||
| 
 | ||||
|         // a callback which is called when the video within the callview is
 | ||||
|         // resized due to a change in video metadata
 | ||||
|         onResize: React.PropTypes.func, | ||||
|     }, | ||||
| 
 | ||||
|     componentDidMount: function() { | ||||
|         this.dispatcherRef = dis.register(this.onAction); | ||||
|         if (this.props.room) { | ||||
|             this.showCall(this.props.room.roomId); | ||||
|         } | ||||
|         else { | ||||
|             // XXX: why would we ever not have a this.props.room?
 | ||||
|             var call = CallHandler.getAnyActiveCall(); | ||||
|             if (call) { | ||||
|                 this.showCall(call.roomId); | ||||
|             } | ||||
|         } | ||||
|         this.showCall(this.props.room.roomId); | ||||
|     }, | ||||
| 
 | ||||
|     componentWillUnmount: function() { | ||||
|  | @ -103,7 +97,10 @@ module.exports = React.createClass({ | |||
|     render: function(){ | ||||
|         var VideoView = sdk.getComponent('voip.VideoView'); | ||||
|         return ( | ||||
|             <VideoView ref="video" onClick={ this.props.onClick } onResize={ this.props.onResize }/> | ||||
|             <VideoView ref="video" onClick={ this.props.onClick } | ||||
|                 onResize={ this.props.onResize } | ||||
|                 maxHeight={ this.props.maxVideoHeight } | ||||
|             /> | ||||
|         ); | ||||
|     } | ||||
| }); | ||||
|  |  | |||
|  | @ -22,6 +22,9 @@ module.exports = React.createClass({ | |||
|     displayName: 'VideoFeed', | ||||
| 
 | ||||
|     propTypes: { | ||||
|         // maxHeight style attribute for the video element
 | ||||
|         maxHeight: React.PropTypes.number, | ||||
| 
 | ||||
|         // a callback which is called when the video element is resized
 | ||||
|         // due to a change in video metadata
 | ||||
|         onResize: React.PropTypes.func, | ||||
|  | @ -43,7 +46,7 @@ module.exports = React.createClass({ | |||
| 
 | ||||
|     render: function() { | ||||
|         return ( | ||||
|             <video ref="vid"> | ||||
|             <video ref="vid" style={{maxHeight: this.props.maxHeight}}> | ||||
|             </video> | ||||
|         ); | ||||
|     }, | ||||
|  |  | |||
|  | @ -25,6 +25,18 @@ var dis = require('../../../dispatcher'); | |||
| module.exports = React.createClass({ | ||||
|     displayName: 'VideoView', | ||||
| 
 | ||||
|     propTypes: { | ||||
|         // maxHeight style attribute for the video element
 | ||||
|         maxHeight: React.PropTypes.number, | ||||
| 
 | ||||
|         // a callback which is called when the user clicks on the video div
 | ||||
|         onClick: React.PropTypes.func, | ||||
| 
 | ||||
|         // a callback which is called when the video element is resized due to
 | ||||
|         // a change in video metadata
 | ||||
|         onResize: React.PropTypes.func, | ||||
|     }, | ||||
| 
 | ||||
|     componentDidMount: function() { | ||||
|         this.dispatcherRef = dis.register(this.onAction); | ||||
|     }, | ||||
|  | @ -64,7 +76,6 @@ module.exports = React.createClass({ | |||
|                         element.msRequestFullscreen | ||||
|                     ); | ||||
|                     requestMethod.call(element); | ||||
|                     this.getRemoteVideoElement().style.maxHeight = "inherit"; | ||||
|                 } | ||||
|                 else { | ||||
|                     var exitMethod = ( | ||||
|  | @ -83,10 +94,18 @@ module.exports = React.createClass({ | |||
| 
 | ||||
|     render: function() { | ||||
|         var VideoFeed = sdk.getComponent('voip.VideoFeed'); | ||||
| 
 | ||||
|         // if we're fullscreen, we don't want to set a maxHeight on the video element.
 | ||||
|         var fullscreenElement = (document.fullscreenElement || | ||||
|                  document.mozFullScreenElement || | ||||
|                  document.webkitFullscreenElement); | ||||
|         var maxVideoHeight = fullscreenElement ? null : this.props.maxHeight; | ||||
| 
 | ||||
|         return ( | ||||
|             <div className="mx_VideoView" ref={this.setContainer} onClick={ this.props.onClick }> | ||||
|                 <div className="mx_VideoView_remoteVideoFeed"> | ||||
|                     <VideoFeed ref="remote" onResize={this.props.onResize}/> | ||||
|                     <VideoFeed ref="remote" onResize={this.props.onResize} | ||||
|                         maxHeight={maxVideoHeight} /> | ||||
|                     <audio ref="remoteAudio"/> | ||||
|                 </div> | ||||
|                 <div className="mx_VideoView_localVideoFeed">                 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Richard van der Hoff
						Richard van der Hoff