Merge branch 'develop' into bwindels/stylepreviewbar
This commit is contained in:
commit
22874f62ab
25 changed files with 280 additions and 139 deletions
|
@ -52,7 +52,7 @@ export default class RoomSettingsDialog extends React.Component {
|
|||
tabs.push(new Tab(
|
||||
_td("Advanced"),
|
||||
"mx_RoomSettingsDialog_warningIcon",
|
||||
<AdvancedRoomSettingsTab roomId={this.props.roomId} />,
|
||||
<AdvancedRoomSettingsTab roomId={this.props.roomId} closeSettingsFn={this.props.onFinished} />,
|
||||
));
|
||||
|
||||
return tabs;
|
||||
|
|
|
@ -19,23 +19,30 @@ limitations under the License.
|
|||
|
||||
import React from 'react';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import dis from '../../../dispatcher';
|
||||
import HeaderButton from './HeaderButton';
|
||||
import HeaderButtons from './HeaderButtons';
|
||||
import RightPanel from '../../structures/RightPanel';
|
||||
|
||||
const GROUP_PHASES = [
|
||||
RightPanel.Phase.GroupMemberInfo,
|
||||
RightPanel.Phase.GroupMemberList,
|
||||
];
|
||||
const ROOM_PHASES = [
|
||||
RightPanel.Phase.GroupRoomList,
|
||||
RightPanel.Phase.GroupRoomInfo,
|
||||
];
|
||||
|
||||
export default class GroupHeaderButtons extends HeaderButtons {
|
||||
constructor(props) {
|
||||
super(props, RightPanel.Phase.GroupMemberList);
|
||||
this._onMembersClicked = this._onMembersClicked.bind(this);
|
||||
this._onRoomsClicked = this._onRoomsClicked.bind(this);
|
||||
}
|
||||
|
||||
onAction(payload) {
|
||||
super.onAction(payload);
|
||||
|
||||
if (payload.action === "view_user") {
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
});
|
||||
if (payload.member) {
|
||||
this.setPhase(RightPanel.Phase.RoomMemberInfo, {member: payload.member});
|
||||
} else {
|
||||
|
@ -54,27 +61,26 @@ export default class GroupHeaderButtons extends HeaderButtons {
|
|||
}
|
||||
}
|
||||
|
||||
renderButtons() {
|
||||
const groupPhases = [
|
||||
RightPanel.Phase.GroupMemberInfo,
|
||||
RightPanel.Phase.GroupMemberList,
|
||||
];
|
||||
const roomPhases = [
|
||||
RightPanel.Phase.GroupRoomList,
|
||||
RightPanel.Phase.GroupRoomInfo,
|
||||
];
|
||||
_onMembersClicked() {
|
||||
this.togglePhase(RightPanel.Phase.GroupMemberList, GROUP_PHASES);
|
||||
}
|
||||
|
||||
_onRoomsClicked() {
|
||||
this.togglePhase(RightPanel.Phase.GroupRoomList, ROOM_PHASES);
|
||||
}
|
||||
|
||||
renderButtons() {
|
||||
return [
|
||||
<HeaderButton key="groupMembersButton" name="groupMembersButton"
|
||||
title={_t('Members')}
|
||||
isHighlighted={this.isPhase(groupPhases)}
|
||||
clickPhase={RightPanel.Phase.GroupMemberList}
|
||||
isHighlighted={this.isPhase(GROUP_PHASES)}
|
||||
onClick={this._onMembersClicked}
|
||||
analytics={['Right Panel', 'Group Member List Button', 'click']}
|
||||
/>,
|
||||
<HeaderButton key="roomsButton" name="roomsButton"
|
||||
title={_t('Rooms')}
|
||||
isHighlighted={this.isPhase(roomPhases)}
|
||||
clickPhase={RightPanel.Phase.GroupRoomList}
|
||||
isHighlighted={this.isPhase(ROOM_PHASES)}
|
||||
onClick={this._onRoomsClicked}
|
||||
analytics={['Right Panel', 'Group Room List Button', 'click']}
|
||||
/>,
|
||||
];
|
||||
|
|
|
@ -20,7 +20,6 @@ limitations under the License.
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import dis from '../../../dispatcher';
|
||||
import Analytics from '../../../Analytics';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
|
||||
|
@ -32,11 +31,7 @@ export default class HeaderButton extends React.Component {
|
|||
|
||||
onClick(ev) {
|
||||
Analytics.trackEvent(...this.props.analytics);
|
||||
dis.dispatch({
|
||||
action: 'view_right_panel_phase',
|
||||
phase: this.props.clickPhase,
|
||||
fromHeader: true,
|
||||
});
|
||||
this.props.onClick();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -59,9 +54,8 @@ export default class HeaderButton extends React.Component {
|
|||
HeaderButton.propTypes = {
|
||||
// Whether this button is highlighted
|
||||
isHighlighted: PropTypes.bool.isRequired,
|
||||
// The phase to swap to when the button is clicked
|
||||
clickPhase: PropTypes.string.isRequired,
|
||||
|
||||
// click handler
|
||||
onClick: PropTypes.func.isRequired,
|
||||
// The badge to display above the icon
|
||||
badge: PropTypes.node,
|
||||
// The parameters to track the click event
|
||||
|
|
|
@ -40,14 +40,36 @@ export default class HeaderButtons extends React.Component {
|
|||
dis.unregister(this.dispatcherRef);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (!prevProps.collapsedRhs && this.props.collapsedRhs) {
|
||||
this.setState({
|
||||
phase: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setPhase(phase, extras) {
|
||||
// TODO: delay?
|
||||
if (this.props.collapsedRhs) {
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
});
|
||||
}
|
||||
dis.dispatch(Object.assign({
|
||||
action: 'view_right_panel_phase',
|
||||
phase: phase,
|
||||
}, extras));
|
||||
}
|
||||
|
||||
togglePhase(phase, validPhases = [phase]) {
|
||||
if (validPhases.includes(this.state.phase)) {
|
||||
dis.dispatch({
|
||||
action: 'hide_right_panel',
|
||||
});
|
||||
} else {
|
||||
this.setPhase(phase);
|
||||
}
|
||||
}
|
||||
|
||||
isPhase(phases) {
|
||||
if (this.props.collapsedRhs) {
|
||||
return false;
|
||||
|
@ -61,28 +83,9 @@ export default class HeaderButtons extends React.Component {
|
|||
|
||||
onAction(payload) {
|
||||
if (payload.action === "view_right_panel_phase") {
|
||||
// only actions coming from header buttons should collapse the right panel
|
||||
if (this.state.phase === payload.phase && payload.fromHeader) {
|
||||
dis.dispatch({
|
||||
action: 'hide_right_panel',
|
||||
});
|
||||
this.setState({
|
||||
phase: null,
|
||||
});
|
||||
} else {
|
||||
if (this.props.collapsedRhs && payload.fromHeader) {
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
});
|
||||
// emit payload again as the RightPanel didn't exist up
|
||||
// till show_right_panel, just without the fromHeader flag
|
||||
// as that would hide the right panel again
|
||||
dis.dispatch(Object.assign({}, payload, {fromHeader: false}));
|
||||
}
|
||||
this.setState({
|
||||
phase: payload.phase,
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
phase: payload.phase,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,28 +19,33 @@ limitations under the License.
|
|||
|
||||
import React from 'react';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import dis from '../../../dispatcher';
|
||||
import HeaderButton from './HeaderButton';
|
||||
import HeaderButtons from './HeaderButtons';
|
||||
import RightPanel from '../../structures/RightPanel';
|
||||
|
||||
const MEMBER_PHASES = [
|
||||
RightPanel.Phase.RoomMemberList,
|
||||
RightPanel.Phase.RoomMemberInfo,
|
||||
RightPanel.Phase.Room3pidMemberInfo,
|
||||
];
|
||||
|
||||
export default class RoomHeaderButtons extends HeaderButtons {
|
||||
constructor(props) {
|
||||
super(props, RightPanel.Phase.RoomMemberList);
|
||||
this._onMembersClicked = this._onMembersClicked.bind(this);
|
||||
this._onFilesClicked = this._onFilesClicked.bind(this);
|
||||
this._onNotificationsClicked = this._onNotificationsClicked.bind(this);
|
||||
}
|
||||
|
||||
onAction(payload) {
|
||||
super.onAction(payload);
|
||||
if (payload.action === "view_user") {
|
||||
dis.dispatch({
|
||||
action: 'show_right_panel',
|
||||
});
|
||||
if (payload.member) {
|
||||
this.setPhase(RightPanel.Phase.RoomMemberInfo, {member: payload.member});
|
||||
} else {
|
||||
this.setPhase(RightPanel.Phase.RoomMemberList);
|
||||
}
|
||||
} else if (payload.action === "view_room") {
|
||||
} else if (payload.action === "view_room" && !this.props.collapsedRhs) {
|
||||
this.setPhase(RightPanel.Phase.RoomMemberList);
|
||||
} else if (payload.action === "view_3pid_invite") {
|
||||
if (payload.event) {
|
||||
|
@ -51,30 +56,36 @@ export default class RoomHeaderButtons extends HeaderButtons {
|
|||
}
|
||||
}
|
||||
|
||||
renderButtons() {
|
||||
const membersPhases = [
|
||||
RightPanel.Phase.RoomMemberList,
|
||||
RightPanel.Phase.RoomMemberInfo,
|
||||
RightPanel.Phase.Room3pidMemberInfo,
|
||||
];
|
||||
_onMembersClicked() {
|
||||
this.togglePhase(RightPanel.Phase.RoomMemberList, MEMBER_PHASES);
|
||||
}
|
||||
|
||||
_onFilesClicked() {
|
||||
this.togglePhase(RightPanel.Phase.FilePanel);
|
||||
}
|
||||
|
||||
_onNotificationsClicked() {
|
||||
this.togglePhase(RightPanel.Phase.NotificationPanel);
|
||||
}
|
||||
|
||||
renderButtons() {
|
||||
return [
|
||||
<HeaderButton key="membersButton" name="membersButton"
|
||||
title={_t('Members')}
|
||||
isHighlighted={this.isPhase(membersPhases)}
|
||||
clickPhase={RightPanel.Phase.RoomMemberList}
|
||||
isHighlighted={this.isPhase(MEMBER_PHASES)}
|
||||
onClick={this._onMembersClicked}
|
||||
analytics={['Right Panel', 'Member List Button', 'click']}
|
||||
/>,
|
||||
<HeaderButton key="filesButton" name="filesButton"
|
||||
title={_t('Files')}
|
||||
isHighlighted={this.isPhase(RightPanel.Phase.FilePanel)}
|
||||
clickPhase={RightPanel.Phase.FilePanel}
|
||||
onClick={this._onFilesClicked}
|
||||
analytics={['Right Panel', 'File List Button', 'click']}
|
||||
/>,
|
||||
<HeaderButton key="notifsButton" name="notifsButton"
|
||||
title={_t('Notifications')}
|
||||
isHighlighted={this.isPhase(RightPanel.Phase.NotificationPanel)}
|
||||
clickPhase={RightPanel.Phase.NotificationPanel}
|
||||
onClick={this._onNotificationsClicked}
|
||||
analytics={['Right Panel', 'Notification List Button', 'click']}
|
||||
/>,
|
||||
];
|
||||
|
|
|
@ -33,12 +33,7 @@ const MAX_ROOMS = 20;
|
|||
export default class RoomBreadcrumbs extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const tolerances = SettingsStore.getValue("breadcrumb_scroll_tolerances");
|
||||
this.state = {rooms: [], scrollTolerances: tolerances};
|
||||
|
||||
// Record this for debugging purposes
|
||||
console.log("Breadcrumbs scroll tolerances:", tolerances);
|
||||
this.state = {rooms: []};
|
||||
|
||||
this.onAction = this.onAction.bind(this);
|
||||
this._dispatcherRef = null;
|
||||
|
@ -343,8 +338,7 @@ export default class RoomBreadcrumbs extends React.Component {
|
|||
});
|
||||
return (
|
||||
<IndicatorScrollbar ref="scroller" className="mx_RoomBreadcrumbs"
|
||||
trackHorizontalOverflow={true} verticalScrollsHorizontally={true}
|
||||
scrollTolerances={this.state.scrollTolerances}>
|
||||
trackHorizontalOverflow={true} verticalScrollsHorizontally={true}>
|
||||
{ avatars }
|
||||
</IndicatorScrollbar>
|
||||
);
|
||||
|
|
|
@ -187,12 +187,17 @@ export default class KeyBackupPanel extends React.PureComponent {
|
|||
clientBackupStatus = <div>
|
||||
<p>{encryptedMessageAreEncrypted}</p>
|
||||
<p>{_t(
|
||||
"This device is <b>not backing up your keys</b>.", {},
|
||||
"This device is <b>not backing up your keys</b>, " +
|
||||
"but you do have an existing backup you can restore from " +
|
||||
"and add to going forward.", {},
|
||||
{b: sub => <b>{sub}</b>},
|
||||
)}</p>
|
||||
<p>{_t("Back up your keys before signing out to avoid losing them.")}</p>
|
||||
<p>{_t(
|
||||
"Connect this device to key backup before signing out to avoid " +
|
||||
"losing any keys that may only be on this device.",
|
||||
)}</p>
|
||||
</div>;
|
||||
restoreButtonCaption = _t("Use key backup");
|
||||
restoreButtonCaption = _t("Connect this device to Key Backup");
|
||||
}
|
||||
|
||||
let uploadStatus;
|
||||
|
@ -221,7 +226,10 @@ export default class KeyBackupPanel extends React.PureComponent {
|
|||
{sub}
|
||||
</span>;
|
||||
const device = sub => <span className="mx_KeyBackupPanel_deviceName">{deviceName}</span>;
|
||||
const fromThisDevice = sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key();
|
||||
const fromThisDevice = (
|
||||
sig.device &&
|
||||
sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()
|
||||
);
|
||||
let sigStatus;
|
||||
if (!sig.device) {
|
||||
sigStatus = _t(
|
||||
|
|
|
@ -21,10 +21,12 @@ import MatrixClientPeg from "../../../../../MatrixClientPeg";
|
|||
import sdk from "../../../../..";
|
||||
import AccessibleButton from "../../../elements/AccessibleButton";
|
||||
import Modal from "../../../../../Modal";
|
||||
import dis from "../../../../../dispatcher";
|
||||
|
||||
export default class AdvancedRoomSettingsTab extends React.Component {
|
||||
static propTypes = {
|
||||
roomId: PropTypes.string.isRequired,
|
||||
closeSettingsFn: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
constructor() {
|
||||
|
@ -41,9 +43,21 @@ export default class AdvancedRoomSettingsTab extends React.Component {
|
|||
const room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||
room.getRecommendedVersion().then((v) => {
|
||||
const tombstone = room.currentState.getStateEvents("m.room.tombstone", "");
|
||||
|
||||
const additionalStateChanges = {};
|
||||
const createEvent = room.currentState.getStateEvents("m.room.create", "");
|
||||
const predecessor = createEvent ? createEvent.getContent().predecessor : null;
|
||||
if (predecessor && predecessor.room_id) {
|
||||
additionalStateChanges['oldRoomId'] = predecessor.room_id;
|
||||
additionalStateChanges['oldEventId'] = predecessor.event_id;
|
||||
additionalStateChanges['hasPreviousRoom'] = true;
|
||||
}
|
||||
|
||||
|
||||
this.setState({
|
||||
upgraded: tombstone && tombstone.getContent().replacement_room,
|
||||
upgradeRecommendation: v,
|
||||
...additionalStateChanges,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -59,6 +73,18 @@ export default class AdvancedRoomSettingsTab extends React.Component {
|
|||
Modal.createDialog(DevtoolsDialog, {roomId: this.props.roomId});
|
||||
};
|
||||
|
||||
_onOldRoomClicked = (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
room_id: this.state.oldRoomId,
|
||||
event_id: this.state.oldEventId,
|
||||
});
|
||||
this.props.closeSettingsFn();
|
||||
};
|
||||
|
||||
render() {
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = client.getRoom(this.props.roomId);
|
||||
|
@ -91,6 +117,18 @@ export default class AdvancedRoomSettingsTab extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
let oldRoomLink;
|
||||
if (this.state.hasPreviousRoom) {
|
||||
let name = _t("this room");
|
||||
const room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||
if (room && room.name) name = room.name;
|
||||
oldRoomLink = (
|
||||
<AccessibleButton element='a' onClick={this._onOldRoomClicked}>
|
||||
{_t("View older messages in %(roomName)s.", {roomName: name})}
|
||||
</AccessibleButton>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_SettingsTab">
|
||||
<div className="mx_SettingsTab_heading">{_t("Advanced")}</div>
|
||||
|
@ -108,6 +146,7 @@ export default class AdvancedRoomSettingsTab extends React.Component {
|
|||
<span>{_t("Room version:")}</span>
|
||||
{room.getVersion()}
|
||||
</div>
|
||||
{oldRoomLink}
|
||||
{roomUpgradeButton}
|
||||
</div>
|
||||
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
|
||||
|
|
|
@ -136,7 +136,7 @@ export default class HelpUserSettingsTab extends React.Component {
|
|||
<li>
|
||||
The <a href="themes/riot/img/backgrounds/valley.jpg" rel="noopener" target="_blank">
|
||||
default cover photo</a> is (C)
|
||||
<a href="https://www.flickr.com/golan" rel="noopener" target="_blank">Jesús Roncero</a>
|
||||
<a href="https://www.flickr.com/golan" rel="noopener" target="_blank">Jesús Roncero</a>{' '}
|
||||
used under the terms of
|
||||
<a href="https://creativecommons.org/licenses/by-sa/4.0/" rel="noopener" target="_blank">
|
||||
CC-BY-SA 4.0</a>. No warranties are given.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue