Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Weblate 2018-02-15 11:05:34 +00:00
commit e79d502972
5 changed files with 105 additions and 17 deletions

View file

@ -35,6 +35,7 @@ const TagOrderActions = {};
TagOrderActions.moveTag = function(matrixClient, tag, destinationIx) { TagOrderActions.moveTag = function(matrixClient, tag, destinationIx) {
// Only commit tags if the state is ready, i.e. not null // Only commit tags if the state is ready, i.e. not null
let tags = TagOrderStore.getOrderedTags(); let tags = TagOrderStore.getOrderedTags();
let removedTags = TagOrderStore.getRemovedTagsAccountData();
if (!tags) { if (!tags) {
return; return;
} }
@ -42,17 +43,19 @@ TagOrderActions.moveTag = function(matrixClient, tag, destinationIx) {
tags = tags.filter((t) => t !== tag); tags = tags.filter((t) => t !== tag);
tags = [...tags.slice(0, destinationIx), tag, ...tags.slice(destinationIx)]; tags = [...tags.slice(0, destinationIx), tag, ...tags.slice(destinationIx)];
removedTags = removedTags.filter((t) => t !== tag);
const storeId = TagOrderStore.getStoreId(); const storeId = TagOrderStore.getStoreId();
return asyncAction('TagOrderActions.moveTag', () => { return asyncAction('TagOrderActions.moveTag', () => {
Analytics.trackEvent('TagOrderActions', 'commitTagOrdering'); Analytics.trackEvent('TagOrderActions', 'commitTagOrdering');
return matrixClient.setAccountData( return matrixClient.setAccountData(
'im.vector.web.tag_ordering', 'im.vector.web.tag_ordering',
{tags, _storeId: storeId}, {tags, removedTags, _storeId: storeId},
); );
}, () => { }, () => {
// For an optimistic update // For an optimistic update
return {tags}; return {tags, removedTags};
}); });
}; };

View file

@ -19,6 +19,7 @@ limitations under the License.
import * as Matrix from 'matrix-js-sdk'; import * as Matrix from 'matrix-js-sdk';
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { DragDropContext } from 'react-beautiful-dnd';
import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard'; import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard';
import Notifier from '../../Notifier'; import Notifier from '../../Notifier';
@ -30,6 +31,9 @@ import sessionStore from '../../stores/SessionStore';
import MatrixClientPeg from '../../MatrixClientPeg'; import MatrixClientPeg from '../../MatrixClientPeg';
import SettingsStore from "../../settings/SettingsStore"; import SettingsStore from "../../settings/SettingsStore";
import TagOrderActions from '../../actions/TagOrderActions';
import RoomListActions from '../../actions/RoomListActions';
/** /**
* This is what our MatrixChat shows when we are logged in. The precise view is * This is what our MatrixChat shows when we are logged in. The precise view is
* determined by the page_type property. * determined by the page_type property.
@ -207,6 +211,50 @@ const LoggedInView = React.createClass({
} }
}, },
_onDragEnd: function(result) {
// Dragged to an invalid destination, not onto a droppable
if (!result.destination) {
return;
}
const dest = result.destination.droppableId;
if (dest === 'tag-panel-droppable') {
// Could be "GroupTile +groupId:domain"
const draggableId = result.draggableId.split(' ').pop();
// Dispatch synchronously so that the TagPanel receives an
// optimistic update from TagOrderStore before the previous
// state is shown.
dis.dispatch(TagOrderActions.moveTag(
this._matrixClient,
draggableId,
result.destination.index,
), true);
} else if (dest.startsWith('room-sub-list-droppable_')) {
this._onRoomTileEndDrag(result);
}
},
_onRoomTileEndDrag: function(result) {
let newTag = result.destination.droppableId.split('_')[1];
let prevTag = result.source.droppableId.split('_')[1];
if (newTag === 'undefined') newTag = undefined;
if (prevTag === 'undefined') prevTag = undefined;
const roomId = result.draggableId.split('_')[1];
const oldIndex = result.source.index;
const newIndex = result.destination.index;
dis.dispatch(RoomListActions.tagRoom(
this._matrixClient,
this._matrixClient.getRoom(roomId),
prevTag, newTag,
oldIndex, newIndex,
), true);
},
render: function() { render: function() {
const LeftPanel = sdk.getComponent('structures.LeftPanel'); const LeftPanel = sdk.getComponent('structures.LeftPanel');
const RightPanel = sdk.getComponent('structures.RightPanel'); const RightPanel = sdk.getComponent('structures.RightPanel');
@ -328,16 +376,18 @@ const LoggedInView = React.createClass({
return ( return (
<div className='mx_MatrixChat_wrapper'> <div className='mx_MatrixChat_wrapper'>
{ topBar } { topBar }
<div className={bodyClasses}> <DragDropContext onDragEnd={this._onDragEnd}>
<LeftPanel <div className={bodyClasses}>
collapsed={this.props.collapseLhs || false} <LeftPanel
disabled={this.props.leftDisabled} collapsed={this.props.collapseLhs || false}
/> disabled={this.props.leftDisabled}
<main className='mx_MatrixChat_middlePanel'> />
{ page_element } <main className='mx_MatrixChat_middlePanel'>
</main> { page_element }
{ right_panel } </main>
</div> { right_panel }
</div>
</DragDropContext>
</div> </div>
); );
}, },

View file

@ -73,8 +73,10 @@ export default withMatrixClient(React.createClass({
}); });
contentHeader = groupNodes.length > 0 ? <h3>{ _t('Your Communities') }</h3> : <div />; contentHeader = groupNodes.length > 0 ? <h3>{ _t('Your Communities') }</h3> : <div />;
content = groupNodes.length > 0 ? content = groupNodes.length > 0 ?
<GeminiScrollbar className="mx_MyGroups_joinedGroups"> <GeminiScrollbar>
{ groupNodes } <div className="mx_MyGroups_joinedGroups">
{ groupNodes }
</div>
</GeminiScrollbar> : </GeminiScrollbar> :
<div className="mx_MyGroups_placeholder"> <div className="mx_MyGroups_placeholder">
{ _t( { _t(

View file

@ -17,10 +17,12 @@ limitations under the License.
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {MatrixClient} from 'matrix-js-sdk'; import {MatrixClient} from 'matrix-js-sdk';
import { Draggable, Droppable } from 'react-beautiful-dnd';
import sdk from '../../../index'; import sdk from '../../../index';
import dis from '../../../dispatcher'; import dis from '../../../dispatcher';
import FlairStore from '../../../stores/FlairStore'; import FlairStore from '../../../stores/FlairStore';
const GroupTile = React.createClass({ const GroupTile = React.createClass({
displayName: 'GroupTile', displayName: 'GroupTile',
@ -78,9 +80,39 @@ const GroupTile = React.createClass({
profile.avatarUrl, avatarHeight, avatarHeight, "crop", profile.avatarUrl, avatarHeight, avatarHeight, "crop",
) : null; ) : null;
return <AccessibleButton className="mx_GroupTile" onClick={this.onClick}> return <AccessibleButton className="mx_GroupTile" onClick={this.onClick}>
<div className="mx_GroupTile_avatar"> <Droppable droppableId="my-groups-droppable" type="draggable-TagTile">
<BaseAvatar name={name} url={httpUrl} width={avatarHeight} height={avatarHeight} /> { (droppableProvided, droppableSnapshot) => (
</div> <div ref={droppableProvided.innerRef}>
<Draggable
key={"GroupTile " + this.props.groupId}
draggableId={"GroupTile " + this.props.groupId}
index={this.props.groupId}
type="draggable-TagTile"
>
{ (provided, snapshot) => (
<div>
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<div className="mx_GroupTile_avatar">
<BaseAvatar name={name} url={httpUrl} width={avatarHeight} height={avatarHeight} />
</div>
</div>
{ /* Instead of a blank placeholder, use a copy of the avatar itself. */ }
{ provided.placeholder ?
<div className="mx_GroupTile_avatar">
<BaseAvatar name={name} url={httpUrl} width={avatarHeight} height={avatarHeight} />
</div> :
<div />
}
</div>
) }
</Draggable>
</div>
) }
</Droppable>
<div className="mx_GroupTile_profile"> <div className="mx_GroupTile_profile">
<div className="mx_GroupTile_name">{ name }</div> <div className="mx_GroupTile_name">{ name }</div>
{ descElement } { descElement }

View file

@ -89,6 +89,7 @@ class TagOrderStore extends Store {
// Optimistic update of a moved tag // Optimistic update of a moved tag
this._setState({ this._setState({
orderedTags: payload.request.tags, orderedTags: payload.request.tags,
removedTagsAccountData: payload.request.removedTags,
}); });
break; break;
} }