Factor out a separate auxpanel, and cleanup the maxHeight management

Basically two changes here:

1. Factor out auxpanel from RoomView
2. Rather than setting maxHeight attributes by poking directly into the DOM,
pass them down as properties.
This commit is contained in:
Richard van der Hoff 2016-02-23 15:46:27 +00:00
parent bb6a36b911
commit 7a20fda7e7
6 changed files with 169 additions and 90 deletions

View file

@ -70,6 +70,7 @@ module.exports.components['views.messages.TextualEvent'] = require('./components
module.exports.components['views.messages.UnknownBody'] = require('./components/views/messages/UnknownBody'); 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.AliasSettings'] = require('./components/views/room_settings/AliasSettings');
module.exports.components['views.room_settings.ColorSettings'] = require('./components/views/room_settings/ColorSettings'); 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.EntityTile'] = require('./components/views/rooms/EntityTile');
module.exports.components['views.rooms.EventTile'] = require('./components/views/rooms/EventTile'); module.exports.components['views.rooms.EventTile'] = require('./components/views/rooms/EventTile');
module.exports.components['views.rooms.InviteMemberList'] = require('./components/views/rooms/InviteMemberList'); module.exports.components['views.rooms.InviteMemberList'] = require('./components/views/rooms/InviteMemberList');

View file

@ -15,7 +15,6 @@ limitations under the License.
*/ */
// TODO: This component is enormous! There's several things which could stand-alone: // TODO: This component is enormous! There's several things which could stand-alone:
// - Aux component
// - Search results component // - Search results component
// - Drag and drop // - Drag and drop
// - File uploading - uploadFile() // - File uploading - uploadFile()
@ -106,6 +105,8 @@ module.exports = React.createClass({
// the end of the live timeline. It has the effect of hiding the // the end of the live timeline. It has the effect of hiding the
// 'scroll to bottom' knob, among a couple of other things. // 'scroll to bottom' knob, among a couple of other things.
atEndOfLiveTimeline: true, atEndOfLiveTimeline: true,
auxPanelMaxHeight: undefined,
} }
}, },
@ -1294,14 +1295,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 // jump down to the bottom of this room, where new events are arriving
jumpToLiveTimeline: function() { jumpToLiveTimeline: function() {
// if we can't forward-paginate the existing timeline, then there // if we can't forward-paginate the existing timeline, then there
@ -1386,25 +1379,10 @@ module.exports = React.createClass({
// but it's better than the video going missing entirely // but it's better than the video going missing entirely
if (auxPanelMaxHeight < 50) auxPanelMaxHeight = 50; if (auxPanelMaxHeight < 50) auxPanelMaxHeight = 50;
if (this.refs.callView) { // we may need to resize the gemini panel after changing the aux panel
var fullscreenElement = // size, so add a callback to onChildResize.
(document.fullscreenElement || this.setState({auxPanelMaxHeight: auxPanelMaxHeight},
document.mozFullScreenElement || this.onChildResize);
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();
}, },
onFullscreenClick: function() { onFullscreenClick: function() {
@ -1438,11 +1416,6 @@ module.exports = React.createClass({
}); });
}, },
onCallViewResize: function() {
this.onChildResize();
this.onResize();
},
onChildResize: function() { onChildResize: function() {
// When the video or the message composer resizes, the scroll panel // When the video or the message composer resizes, the scroll panel
// also changes size. Work around GeminiScrollBar fail by telling it // also changes size. Work around GeminiScrollBar fail by telling it
@ -1464,8 +1437,8 @@ module.exports = React.createClass({
render: function() { render: function() {
var RoomHeader = sdk.getComponent('rooms.RoomHeader'); var RoomHeader = sdk.getComponent('rooms.RoomHeader');
var MessageComposer = sdk.getComponent('rooms.MessageComposer'); var MessageComposer = sdk.getComponent('rooms.MessageComposer');
var CallView = sdk.getComponent("voip.CallView");
var RoomSettings = sdk.getComponent("rooms.RoomSettings"); var RoomSettings = sdk.getComponent("rooms.RoomSettings");
var AuxPanel = sdk.getComponent("rooms.AuxPanel");
var SearchBar = sdk.getComponent("rooms.SearchBar"); var SearchBar = sdk.getComponent("rooms.SearchBar");
var ScrollPanel = sdk.getComponent("structures.ScrollPanel"); var ScrollPanel = sdk.getComponent("structures.ScrollPanel");
var TintableSvg = sdk.getComponent("elements.TintableSvg"); var TintableSvg = sdk.getComponent("elements.TintableSvg");
@ -1607,28 +1580,16 @@ module.exports = React.createClass({
); );
} }
var conferenceCallNotification = null; var auxPanel = (
if (this.state.displayConfCallNotification) { <AuxPanel ref="auxPanel" room={this.state.room}
var supportedText; conferenceHandler={this.props.ConferenceHandler}
if (!MatrixClientPeg.get().supportsVoip()) { draggingFile={this.state.draggingFile}
supportedText = " (unsupported)"; displayConfCallNotification={this.state.displayConfCallNotification}
} maxHeight={this.state.auxPanelMaxHeight}
conferenceCallNotification = ( onCallViewVideoRezize={this.onChildResize} >
<div className="mx_RoomView_ongoingConfCallNotification" onClick={this.onConferenceNotificationClick}> { aux }
Ongoing conference call {supportedText} </AuxPanel>
</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 messageComposer, searchInfo; var messageComposer, searchInfo;
var canSpeak = ( var canSpeak = (
@ -1759,13 +1720,7 @@ module.exports = React.createClass({
onLeaveClick={ onLeaveClick={
(myMember && myMember.membership === "join") ? this.onLeaveClick : null (myMember && myMember.membership === "join") ? this.onLeaveClick : null
} /> } />
<div className="mx_RoomView_auxPanel" ref="auxPanel"> { auxPanel }
{ fileDropTarget }
<CallView ref="callView" room={this.state.room} ConferenceHandler={this.props.ConferenceHandler}
onResize={this.onCallViewResize} />
{ conferenceCallNotification }
{ aux }
</div>
{ messagePanel } { messagePanel }
{ searchResultsPanel } { searchResultsPanel }
<div className="mx_RoomView_statusArea"> <div className="mx_RoomView_statusArea">

View file

@ -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>
);
},
});

View file

@ -19,38 +19,32 @@ var CallHandler = require("../../../CallHandler");
var sdk = require('../../../index'); var sdk = require('../../../index');
var MatrixClientPeg = require("../../../MatrixClientPeg"); 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({ module.exports = React.createClass({
displayName: 'CallView', displayName: 'CallView',
propTypes: { propTypes: {
// a callback which is called when the video within the callview // js-sdk room object
// due to a change in video metadata 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, onResize: React.PropTypes.func,
}, },
componentDidMount: function() { componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
if (this.props.room) { this.showCall(this.props.room.roomId);
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);
}
}
}, },
componentWillUnmount: function() { componentWillUnmount: function() {
@ -103,7 +97,10 @@ module.exports = React.createClass({
render: function(){ render: function(){
var VideoView = sdk.getComponent('voip.VideoView'); var VideoView = sdk.getComponent('voip.VideoView');
return ( 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 }
/>
); );
} }
}); });

View file

@ -22,6 +22,9 @@ module.exports = React.createClass({
displayName: 'VideoFeed', displayName: 'VideoFeed',
propTypes: { propTypes: {
// maxHeight style attribute for the video element
maxHeight: React.PropTypes.number,
// a callback which is called when the video element is resized // a callback which is called when the video element is resized
// due to a change in video metadata // due to a change in video metadata
onResize: React.PropTypes.func, onResize: React.PropTypes.func,
@ -43,7 +46,7 @@ module.exports = React.createClass({
render: function() { render: function() {
return ( return (
<video ref="vid"> <video ref="vid" style={{maxHeight: this.props.maxHeight}}>
</video> </video>
); );
}, },

View file

@ -25,6 +25,18 @@ var dis = require('../../../dispatcher');
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'VideoView', 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() { componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
}, },
@ -64,7 +76,6 @@ module.exports = React.createClass({
element.msRequestFullscreen element.msRequestFullscreen
); );
requestMethod.call(element); requestMethod.call(element);
this.getRemoteVideoElement().style.maxHeight = "inherit";
} }
else { else {
var exitMethod = ( var exitMethod = (
@ -83,10 +94,18 @@ module.exports = React.createClass({
render: function() { render: function() {
var VideoFeed = sdk.getComponent('voip.VideoFeed'); 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 ( return (
<div className="mx_VideoView" ref={this.setContainer} onClick={ this.props.onClick }> <div className="mx_VideoView" ref={this.setContainer} onClick={ this.props.onClick }>
<div className="mx_VideoView_remoteVideoFeed"> <div className="mx_VideoView_remoteVideoFeed">
<VideoFeed ref="remote" onResize={this.props.onResize}/> <VideoFeed ref="remote" onResize={this.props.onResize}
maxHeight={maxVideoHeight} />
<audio ref="remoteAudio"/> <audio ref="remoteAudio"/>
</div> </div>
<div className="mx_VideoView_localVideoFeed"> <div className="mx_VideoView_localVideoFeed">