Merge branch 'develop' into matthew/redesign

This commit is contained in:
David Baker 2015-10-30 11:50:34 +00:00
commit ffb9ce89c7
15 changed files with 100 additions and 23 deletions

View file

@ -1,3 +1,14 @@
Changes in vector v0.1.2 (2015-10-28)
======================================
* Support Room Avatars
* Fullscreen video calls
* Mute mic in VoIP calls
* Fix bug with multiple desktop notifications
* Context menu on messages
* Better hover-over on member list
* Support CAS auth
* Many other bug fixes
Changes in vector v0.1.1 (2015-08-10) Changes in vector v0.1.1 (2015-08-10)
====================================== ======================================

View file

@ -1,6 +1,6 @@
{ {
"name": "vector-web", "name": "vector-web",
"version": "0.0.1", "version": "0.1.2",
"description": "Vector webapp", "description": "Vector webapp",
"author": "matrix.org", "author": "matrix.org",
"repository": { "repository": {
@ -27,8 +27,8 @@
"filesize": "^3.1.2", "filesize": "^3.1.2",
"flux": "~2.0.3", "flux": "~2.0.3",
"linkifyjs": "^2.0.0-beta.4", "linkifyjs": "^2.0.0-beta.4",
"matrix-js-sdk": "^0.2.2", "matrix-js-sdk": "^0.3.0",
"matrix-react-sdk": "^0.0.1", "matrix-react-sdk": "^0.0.2",
"q": "^1.4.1", "q": "^1.4.1",
"react": "^0.13.3", "react": "^0.13.3",
"react-loader": "^1.4.0", "react-loader": "^1.4.0",

View file

@ -90,6 +90,7 @@ module.exports = {
else { else {
this.getVideoView().getLocalVideoElement().style.display = "none"; this.getVideoView().getLocalVideoElement().style.display = "none";
this.getVideoView().getRemoteVideoElement().style.display = "none"; this.getVideoView().getRemoteVideoElement().style.display = "none";
dis.dispatch({action: 'video_fullscreen', fullscreen: false});
} }
} }
}; };

View file

@ -34,6 +34,7 @@ module.exports = {
cli.on("Room.timeline", this.onRoomTimeline); cli.on("Room.timeline", this.onRoomTimeline);
cli.on("Room.name", this.onRoomName); cli.on("Room.name", this.onRoomName);
cli.on("RoomState.events", this.onRoomStateEvents); cli.on("RoomState.events", this.onRoomStateEvents);
cli.on("RoomMember.name", this.onRoomMemberName);
var s = this.getRoomLists(); var s = this.getRoomLists();
s.activityMap = {}; s.activityMap = {};
@ -112,6 +113,10 @@ module.exports = {
setTimeout(this.refreshRoomList, 0); setTimeout(this.refreshRoomList, 0);
}, },
onRoomMemberName: function(ev, member) {
setTimeout(this.refreshRoomList, 0);
},
refreshRoomList: function() { refreshRoomList: function() {
this.setState(this.getRoomLists()); this.setState(this.getRoomLists());

View file

@ -86,6 +86,10 @@ a:visited {
cursor: pointer; cursor: pointer;
} }
.mx_ContextualMenu_spinner {
display: block;
margin: 0 auto;
}
.mx_Dialog_background { .mx_Dialog_background {
position: fixed; position: fixed;

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View file

@ -17,7 +17,6 @@ limitations under the License.
'use strict'; 'use strict';
var React = require('react'); var React = require('react');
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var RoomAvatarController = require('matrix-react-sdk/lib/controllers/atoms/RoomAvatar') var RoomAvatarController = require('matrix-react-sdk/lib/controllers/atoms/RoomAvatar')

View file

@ -0,0 +1,34 @@
/*
Copyright 2015 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.
*/
'use strict';
var React = require('react');
module.exports = React.createClass({
displayName: 'Spinner',
render: function() {
var w = this.props.w || 32;
var h = this.props.h || 32;
var imgClass = this.props.imgClassName || "";
return (
<div>
<img src="img/spinner.gif" width={w} height={h} className={imgClass}/>
</div>
);
}
});

View file

@ -18,7 +18,6 @@ limitations under the License.
var React = require('react'); var React = require('react');
var sdk = require('matrix-react-sdk')
var TextForEvent = require('matrix-react-sdk/lib/TextForEvent'); var TextForEvent = require('matrix-react-sdk/lib/TextForEvent');
module.exports = React.createClass({ module.exports = React.createClass({

View file

@ -70,8 +70,6 @@ module.exports = React.createClass({
var SenderProfile = sdk.getComponent('molecules.SenderProfile'); var SenderProfile = sdk.getComponent('molecules.SenderProfile');
var MemberAvatar = sdk.getComponent('atoms.MemberAvatar'); var MemberAvatar = sdk.getComponent('atoms.MemberAvatar');
var UnknownMessageTile = sdk.getComponent('molecules.UnknownMessageTile');
var content = this.props.mxEvent.getContent(); var content = this.props.mxEvent.getContent();
var msgtype = content.msgtype; var msgtype = content.msgtype;
@ -79,7 +77,7 @@ module.exports = React.createClass({
// This shouldn't happen: the caller should check we support this type // This shouldn't happen: the caller should check we support this type
// before trying to instantiate us // before trying to instantiate us
if (!EventTileType) { if (!EventTileType) {
return null; throw new Error("Event type not supported");
} }
var classes = classNames({ var classes = classNames({

View file

@ -17,6 +17,7 @@ limitations under the License.
'use strict'; 'use strict';
var React = require('react'); var React = require('react');
var Loader = require("../atoms/Spinner");
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var sdk = require('matrix-react-sdk') var sdk = require('matrix-react-sdk')
@ -37,7 +38,7 @@ module.exports = React.createClass({
}, },
render: function() { render: function() {
var interactButton, kickButton, banButton, muteButton, giveModButton; var interactButton, kickButton, banButton, muteButton, giveModButton, spinner;
if (this.props.member.userId === MatrixClientPeg.get().credentials.userId) { if (this.props.member.userId === MatrixClientPeg.get().credentials.userId) {
interactButton = <div className="mx_MemberInfo_field" onClick={this.onLeaveClick}>Leave room</div>; interactButton = <div className="mx_MemberInfo_field" onClick={this.onLeaveClick}>Leave room</div>;
} }
@ -45,6 +46,10 @@ module.exports = React.createClass({
interactButton = <div className="mx_MemberInfo_field" onClick={this.onChatClick}>Start chat</div>; interactButton = <div className="mx_MemberInfo_field" onClick={this.onChatClick}>Start chat</div>;
} }
if (this.state.creatingRoom) {
spinner = <Loader imgClassName="mx_ContextualMenu_spinner"/>;
}
if (this.state.can.kick) { if (this.state.can.kick) {
kickButton = <div className="mx_MemberInfo_field" onClick={this.onKick}> kickButton = <div className="mx_MemberInfo_field" onClick={this.onKick}>
Kick Kick
@ -88,6 +93,7 @@ module.exports = React.createClass({
{kickButton} {kickButton}
{banButton} {banButton}
{giveModButton} {giveModButton}
{spinner}
</div> </div>
</div> </div>
); );

View file

@ -17,12 +17,10 @@ limitations under the License.
'use strict'; 'use strict';
var React = require('react'); var React = require('react');
var classNames = require("classnames");
var sdk = require('matrix-react-sdk') var sdk = require('matrix-react-sdk')
var MessageTileController = require('matrix-react-sdk/lib/controllers/molecules/MessageTile') var MessageTileController = require('matrix-react-sdk/lib/controllers/molecules/MessageTile')
var ContextualMenu = require('../../../../ContextualMenu');
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'MessageTile', displayName: 'MessageTile',

View file

@ -39,7 +39,7 @@ module.exports = React.createClass({
}, },
onFullscreenClick: function() { onFullscreenClick: function() {
dis.dispatch({action: 'video_fullscreen'}, true); dis.dispatch({action: 'video_fullscreen', fullscreen: true}, true);
}, },
render: function() { render: function() {
@ -60,7 +60,7 @@ module.exports = React.createClass({
var call_buttons; var call_buttons;
if (this.state && this.state.call_state != 'ended') { if (this.state && this.state.call_state != 'ended') {
var muteVideoButton; //var muteVideoButton;
var activeCall = ( var activeCall = (
CallHandler.getCallForRoom(this.props.room.roomId) CallHandler.getCallForRoom(this.props.room.roomId)
); );

View file

@ -31,24 +31,28 @@ module.exports = React.createClass({
}, },
render: function() { render: function() {
// NB: This block MUST have a "key" so React doesn't clobber the elements
// between in-call / not-in-call.
var audioBlock = (
<audio ref="ringAudio" key="voip_ring_audio" loop>
<source src="media/ring.ogg" type="audio/ogg" />
<source src="media/ring.mp3" type="audio/mpeg" />
</audio>
);
if (!this.state.incomingCall || !this.state.incomingCall.roomId) { if (!this.state.incomingCall || !this.state.incomingCall.roomId) {
return ( return (
<div> <div>
<audio ref="ringAudio" loop> {audioBlock}
<source src="media/ring.ogg" type="audio/ogg" />
<source src="media/ring.mp3" type="audio/mpeg" />
</audio>
</div> </div>
); );
} }
var caller = MatrixClientPeg.get().getRoom(this.state.incomingCall.roomId).name; var caller = MatrixClientPeg.get().getRoom(this.state.incomingCall.roomId).name;
return ( return (
<div className="mx_IncomingCallBox"> <div className="mx_IncomingCallBox">
{audioBlock}
<img className="mx_IncomingCallBox_chevron" src="img/chevron-left.png" width="9" height="16" /> <img className="mx_IncomingCallBox_chevron" src="img/chevron-left.png" width="9" height="16" />
<audio ref="ringAudio" loop>
<source src="media/ring.ogg" type="audio/ogg" />
<source src="media/ring.mp3" type="audio/mpeg" />
</audio>
<div className="mx_IncomingCallBox_title"> <div className="mx_IncomingCallBox_title">
Incoming { this.state.incomingCall ? this.state.incomingCall.type : '' } call from { caller } Incoming { this.state.incomingCall ? this.state.incomingCall.type : '' } call from { caller }
</div> </div>

View file

@ -51,8 +51,26 @@ module.exports = React.createClass({
return; return;
} }
var element = this.container.getDOMNode(); var element = this.container.getDOMNode();
var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullscreen; if (payload.fullscreen) {
requestMethod.call(element); var requestMethod = (
element.requestFullScreen ||
element.webkitRequestFullScreen ||
element.mozRequestFullScreen ||
element.msRequestFullscreen
);
requestMethod.call(element);
}
else {
var exitMethod = (
document.exitFullscreen ||
document.mozCancelFullScreen ||
document.webkitExitFullscreen ||
document.msExitFullscreen
);
if (exitMethod) {
exitMethod.call(document);
}
}
break; break;
} }
}, },