Merge branch 'develop' into kegan/translation-tamarin

This commit is contained in:
Kegan Dougal 2017-06-08 14:19:56 +01:00
commit c57823a31d
51 changed files with 2759 additions and 795 deletions

View file

@ -375,11 +375,7 @@ module.exports = WithMatrixClient(React.createClass({
console.log("Mod toggle success");
}, function(err) {
if (err.errcode == 'M_GUEST_ACCESS_FORBIDDEN') {
var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
Modal.createDialog(NeedToRegisterDialog, {
title: _t("Please Register"),
description: _t("This action cannot be performed by a guest user. Please register to be able to do this."),
});
dis.dispatch({action: 'view_set_mxid'});
} else {
console.error("Toggle moderator error:" + err);
Modal.createDialog(ErrorDialog, {

View file

@ -91,11 +91,7 @@ export default class MessageComposer extends React.Component {
onUploadClick(ev) {
if (MatrixClientPeg.get().isGuest()) {
let NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
Modal.createDialog(NeedToRegisterDialog, {
title: _t('Please Register'),
description: _t('Guest users can\'t upload files. Please register to upload.'),
});
dis.dispatch({action: 'view_set_mxid'});
return;
}

View file

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -30,7 +31,14 @@ var Rooms = require('../../../Rooms');
import DMRoomMap from '../../../utils/DMRoomMap';
var Receipt = require('../../../utils/Receipt');
var HIDE_CONFERENCE_CHANS = true;
const HIDE_CONFERENCE_CHANS = true;
const VERBS = {
'm.favourite': 'favourite',
'im.vector.fake.direct': 'tag direct chat',
'im.vector.fake.recent': 'restore',
'm.lowpriority': 'demote',
};
module.exports = React.createClass({
displayName: 'RoomList',
@ -45,6 +53,7 @@ module.exports = React.createClass({
getInitialState: function() {
return {
isLoadingLeftRooms: false,
totalRoomCount: null,
lists: {},
incomingCall: null,
};
@ -64,8 +73,14 @@ module.exports = React.createClass({
cli.on("RoomMember.name", this.onRoomMemberName);
cli.on("accountData", this.onAccountData);
var s = this.getRoomLists();
this.setState(s);
this.refreshRoomList();
// order of the sublists
//this.listOrder = [];
// loop count to stop a stack overflow if the user keeps waggling the
// mouse for >30s in a row, or if running under mocha
this._delayedRefreshRoomListLoopCount = 0
},
componentDidMount: function() {
@ -203,31 +218,33 @@ module.exports = React.createClass({
}, 500),
refreshRoomList: function() {
// console.log("DEBUG: Refresh room list delta=%s ms",
// (!this._lastRefreshRoomListTs ? "-" : (Date.now() - this._lastRefreshRoomListTs))
// );
// TODO: rather than bluntly regenerating and re-sorting everything
// every time we see any kind of room change from the JS SDK
// we could do incremental updates on our copy of the state
// based on the room which has actually changed. This would stop
// us re-rendering all the sublists every time anything changes anywhere
// in the state of the client.
this.setState(this.getRoomLists());
// TODO: ideally we'd calculate this once at start, and then maintain
// any changes to it incrementally, updating the appropriate sublists
// as needed.
// Alternatively we'd do something magical with Immutable.js or similar.
const lists = this.getRoomLists();
let totalRooms = 0;
for (const l of Object.values(lists)) {
totalRooms += l.length;
}
this.setState({
lists: this.getRoomLists(),
totalRoomCount: totalRooms,
});
// this._lastRefreshRoomListTs = Date.now();
},
getRoomLists: function() {
var self = this;
var s = { lists: {} };
const lists = {};
s.lists["im.vector.fake.invite"] = [];
s.lists["m.favourite"] = [];
s.lists["im.vector.fake.recent"] = [];
s.lists["im.vector.fake.direct"] = [];
s.lists["m.lowpriority"] = [];
s.lists["im.vector.fake.archived"] = [];
lists["im.vector.fake.invite"] = [];
lists["m.favourite"] = [];
lists["im.vector.fake.recent"] = [];
lists["im.vector.fake.direct"] = [];
lists["m.lowpriority"] = [];
lists["im.vector.fake.archived"] = [];
const dmRoomMap = new DMRoomMap(MatrixClientPeg.get());
@ -241,7 +258,7 @@ module.exports = React.createClass({
// ", prevMembership = " + me.events.member.getPrevContent().membership);
if (me.membership == "invite") {
s.lists["im.vector.fake.invite"].push(room);
lists["im.vector.fake.invite"].push(room);
}
else if (HIDE_CONFERENCE_CHANS && Rooms.isConfCallRoom(room, me, self.props.ConferenceHandler)) {
// skip past this room & don't put it in any lists
@ -255,20 +272,20 @@ module.exports = React.createClass({
if (tagNames.length) {
for (var i = 0; i < tagNames.length; i++) {
var tagName = tagNames[i];
s.lists[tagName] = s.lists[tagName] || [];
s.lists[tagNames[i]].push(room);
lists[tagName] = lists[tagName] || [];
lists[tagName].push(room);
}
}
else if (dmRoomMap.getUserIdForRoomId(room.roomId)) {
// "Direct Message" rooms (that we're still in and that aren't otherwise tagged)
s.lists["im.vector.fake.direct"].push(room);
lists["im.vector.fake.direct"].push(room);
}
else {
s.lists["im.vector.fake.recent"].push(room);
lists["im.vector.fake.recent"].push(room);
}
}
else if (me.membership === "leave") {
s.lists["im.vector.fake.archived"].push(room);
lists["im.vector.fake.archived"].push(room);
}
else {
console.error("unrecognised membership: " + me.membership + " - this should never happen");
@ -277,7 +294,22 @@ module.exports = React.createClass({
// we actually apply the sorting to this when receiving the prop in RoomSubLists.
return s;
// we'll need this when we get to iterating through lists programatically - e.g. ctrl-shift-up/down
/*
this.listOrder = [
"im.vector.fake.invite",
"m.favourite",
"im.vector.fake.recent",
"im.vector.fake.direct",
Object.keys(otherTagNames).filter(tagName=>{
return (!tagName.match(/^m\.(favourite|lowpriority)$/));
}).sort(),
"m.lowpriority",
"im.vector.fake.archived"
];
*/
return lists;
},
_getScrollNode: function() {
@ -431,6 +463,62 @@ module.exports = React.createClass({
this.refs.gemscroll.forceUpdate();
},
_getEmptyContent: function(section) {
const RoomDropTarget = sdk.getComponent('rooms.RoomDropTarget');
if (this.props.collapsed) {
return <RoomDropTarget label="" />;
}
const StartChatButton = sdk.getComponent('elements.StartChatButton');
const RoomDirectoryButton = sdk.getComponent('elements.RoomDirectoryButton');
const CreateRoomButton = sdk.getComponent('elements.CreateRoomButton');
const TintableSvg = sdk.getComponent('elements.TintableSvg');
switch (section) {
case 'im.vector.fake.direct':
return <div className="mx_RoomList_emptySubListTip">
Press
<StartChatButton size="16" callout={true}/>
to start a chat with someone
</div>;
case 'im.vector.fake.recent':
return <div className="mx_RoomList_emptySubListTip">
You're not in any rooms yet! Press
<CreateRoomButton size="16" callout={true}/>
to make a room or
<RoomDirectoryButton size="16" callout={true}/>
to browse the directory
</div>;
}
// We don't want to display drop targets if there are no room tiles to drag'n'drop
if (this.state.totalRoomCount === 0) {
return null;
}
const labelText = 'Drop here to ' + (VERBS[section] || 'tag ' + section);
return <RoomDropTarget label={labelText} />;
},
_getHeaderItems: function(section) {
const StartChatButton = sdk.getComponent('elements.StartChatButton');
const RoomDirectoryButton = sdk.getComponent('elements.RoomDirectoryButton');
const CreateRoomButton = sdk.getComponent('elements.CreateRoomButton');
switch (section) {
case 'im.vector.fake.direct':
return <span className="mx_RoomList_headerButtons">
<StartChatButton size="16" />
</span>;
case 'im.vector.fake.recent':
return <span className="mx_RoomList_headerButtons">
<RoomDirectoryButton size="16" />
<CreateRoomButton size="16" />
</span>;
}
},
render: function() {
var RoomSubList = sdk.getComponent('structures.RoomSubList');
var self = this;
@ -452,7 +540,7 @@ module.exports = React.createClass({
<RoomSubList list={ self.state.lists['m.favourite'] }
label={ _t('Favourites') }
tagName="m.favourite"
verb={ _t('to favourite') }
emptyContent={this._getEmptyContent('m.favourite')}
editable={ true }
order="manual"
selectedRoom={ self.props.selectedRoom }
@ -465,7 +553,8 @@ module.exports = React.createClass({
<RoomSubList list={ self.state.lists['im.vector.fake.direct'] }
label={ _t('People') }
tagName="im.vector.fake.direct"
verb={ _t('to tag direct chat') }
emptyContent={this._getEmptyContent('im.vector.fake.direct')}
headerItems={this._getHeaderItems('im.vector.fake.direct')}
editable={ true }
order="recent"
selectedRoom={ self.props.selectedRoom }
@ -479,7 +568,8 @@ module.exports = React.createClass({
<RoomSubList list={ self.state.lists['im.vector.fake.recent'] }
label={ _t('Rooms') }
editable={ true }
verb={ _t('to restore') }
emptyContent={this._getEmptyContent('im.vector.fake.recent')}
headerItems={this._getHeaderItems('im.vector.fake.recent')}
order="recent"
selectedRoom={ self.props.selectedRoom }
incomingCall={ self.state.incomingCall }
@ -488,13 +578,13 @@ module.exports = React.createClass({
onHeaderClick={ self.onSubListHeaderClick }
onShowMoreRooms={ self.onShowMoreRooms } />
{ Object.keys(self.state.lists).map(function(tagName) {
{ Object.keys(self.state.lists).map((tagName) => {
if (!tagName.match(/^(m\.(favourite|lowpriority)|im\.vector\.fake\.(invite|recent|direct|archived))$/)) {
return <RoomSubList list={ self.state.lists[tagName] }
key={ tagName }
label={ tagName }
tagName={ tagName }
verb={ _t('to tag as %(tagName)s', {tagName: tagName}) }
emptyContent={this._getEmptyContent(tagName)}
editable={ true }
order="manual"
selectedRoom={ self.props.selectedRoom }
@ -510,7 +600,7 @@ module.exports = React.createClass({
<RoomSubList list={ self.state.lists['m.lowpriority'] }
label={ _t('Low priority') }
tagName="m.lowpriority"
verb={ _t('to demote') }
emptyContent={this._getEmptyContent('m.lowpriority')}
editable={ true }
order="recent"
selectedRoom={ self.props.selectedRoom }