mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-18 22:58:18 +08:00
Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
commit
fab257798c
@ -24,8 +24,10 @@
|
||||
@import "./structures/_ViewSource.scss";
|
||||
@import "./structures/login/_Login.scss";
|
||||
@import "./views/avatars/_BaseAvatar.scss";
|
||||
@import "./views/avatars/_MemberStatusMessageAvatar.scss";
|
||||
@import "./views/context_menus/_MessageContextMenu.scss";
|
||||
@import "./views/context_menus/_RoomTileContextMenu.scss";
|
||||
@import "./views/context_menus/_StatusMessageContextMenu.scss";
|
||||
@import "./views/context_menus/_TagTileContextMenu.scss";
|
||||
@import "./views/dialogs/_BugReportDialog.scss";
|
||||
@import "./views/dialogs/_ChangelogDialog.scss";
|
||||
|
20
res/css/views/avatars/_MemberStatusMessageAvatar.scss
Normal file
20
res/css/views/avatars/_MemberStatusMessageAvatar.scss
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 2018 New Vector 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.
|
||||
*/
|
||||
|
||||
.mx_MemberStatusMessageAvatar_hasStatus {
|
||||
border: 2px solid $accent-color;
|
||||
border-radius: 40px;
|
||||
}
|
55
res/css/views/context_menus/_StatusMessageContextMenu.scss
Normal file
55
res/css/views/context_menus/_StatusMessageContextMenu.scss
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright 2018 New Vector 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.
|
||||
*/
|
||||
|
||||
.mx_StatusMessageContextMenu_message {
|
||||
display: inline-block;
|
||||
border-radius: 3px 0 0 3px;
|
||||
border: 1px solid $input-border-color;
|
||||
font-size: 13px;
|
||||
padding: 7px 7px 7px 9px;
|
||||
width: 135px;
|
||||
background-color: $primary-bg-color !important;
|
||||
}
|
||||
|
||||
.mx_StatusMessageContextMenu_submit {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.mx_StatusMessageContextMenu_submitFaded {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.mx_StatusMessageContextMenu_submit img {
|
||||
vertical-align: middle;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.mx_StatusMessageContextMenu hr {
|
||||
border: 0.5px solid $menu-border-color;
|
||||
}
|
||||
|
||||
.mx_StatusMessageContextMenu_clearIcon {
|
||||
margin: 5px 15px 5px 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_StatusMessageContextMenu_clear {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.mx_StatusMessageContextMenu_hasStatus .mx_StatusMessageContextMenu_clear {
|
||||
color: $warning-color;
|
||||
}
|
@ -111,4 +111,12 @@ limitations under the License.
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.mx_EntityTile_subtext {
|
||||
font-size: 11px;
|
||||
opacity: 0.5;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
|
||||
|
@ -110,3 +110,10 @@ limitations under the License.
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.mx_MemberInfo_statusMessage {
|
||||
font-size: 11px;
|
||||
opacity: 0.5;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
@ -35,7 +35,19 @@ limitations under the License.
|
||||
.mx_RoomTile_nameContainer {
|
||||
display: inline-block;
|
||||
width: 180px;
|
||||
height: 24px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_RoomTile_subtext {
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
padding: 0 0 0 7px;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: clip;
|
||||
position: relative;
|
||||
bottom: 4px;
|
||||
}
|
||||
|
||||
.mx_RoomTile_avatar_container {
|
||||
@ -49,10 +61,14 @@ limitations under the License.
|
||||
padding-left: 16px;
|
||||
padding-right: 6px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_RoomTile_hasSubtext .mx_RoomTile_avatar {
|
||||
padding-top: 0;
|
||||
vertical-align: super;
|
||||
}
|
||||
|
||||
.mx_RoomTile_dm {
|
||||
display: block;
|
||||
position: absolute;
|
||||
|
17
res/img/icons-checkmark.svg
Normal file
17
res/img/icons-checkmark.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Tick</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Custom-Status-Copy" transform="translate(-529.000000, -917.000000)" fill-rule="nonzero">
|
||||
<g id="Tick" transform="translate(530.000000, 918.000000)">
|
||||
<circle id="Oval" stroke="#6AAC8C" fill="#75CFA6" cx="9" cy="9" r="9"></circle>
|
||||
<g id="Glyph" transform="translate(8.949747, 7.949747) rotate(-45.000000) translate(-8.949747, -7.949747) translate(4.449747, 5.449747)" fill="#FFFFFF">
|
||||
<rect id="Rectangle" x="0" y="0" width="2" height="5"></rect>
|
||||
<rect id="Rectangle" x="0" y="3" width="9" height="2"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
120
src/components/views/avatars/MemberStatusMessageAvatar.js
Normal file
120
src/components/views/avatars/MemberStatusMessageAvatar.js
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright 2018 New Vector 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.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import MemberAvatar from '../avatars/MemberAvatar';
|
||||
import classNames from 'classnames';
|
||||
import * as ContextualMenu from "../../structures/ContextualMenu";
|
||||
import StatusMessageContextMenu from "../context_menus/StatusMessageContextMenu";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
|
||||
export default class MemberStatusMessageAvatar extends React.Component {
|
||||
static propTypes = {
|
||||
member: PropTypes.object.isRequired,
|
||||
width: PropTypes.number,
|
||||
height: PropTypes.number,
|
||||
resizeMethod: PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
width: 40,
|
||||
height: 40,
|
||||
resizeMethod: 'crop',
|
||||
};
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
if (this.props.member.userId !== MatrixClientPeg.get().getUserId()) {
|
||||
throw new Error("Cannot use MemberStatusMessageAvatar on anyone but the logged in user");
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents);
|
||||
|
||||
if (this.props.member.user) {
|
||||
this.setState({message: this.props.member.user._unstable_statusMessage});
|
||||
} else {
|
||||
this.setState({message: ""});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (MatrixClientPeg.get()) {
|
||||
MatrixClientPeg.get().removeListener("RoomState.events", this._onRoomStateEvents);
|
||||
}
|
||||
}
|
||||
|
||||
_onRoomStateEvents = (ev, state) => {
|
||||
if (ev.getStateKey() !== MatrixClientPeg.get().getUserId()) return;
|
||||
if (ev.getType() !== "im.vector.user_status") return;
|
||||
// TODO: We should be relying on `this.props.member.user._unstable_statusMessage`
|
||||
// We don't currently because the js-sdk doesn't emit a specific event for this
|
||||
// change, and we don't want to race it. This should be improved when we rip out
|
||||
// the im.vector.user_status stuff and replace it with a complete solution.
|
||||
this.setState({message: ev.getContent()["status"]});
|
||||
};
|
||||
|
||||
_onClick = (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
const elementRect = e.target.getBoundingClientRect();
|
||||
|
||||
// The window X and Y offsets are to adjust position when zoomed in to page
|
||||
const x = (elementRect.left + window.pageXOffset) - (elementRect.width / 2) + 3;
|
||||
const chevronOffset = 12;
|
||||
let y = elementRect.top + (elementRect.height / 2) + window.pageYOffset;
|
||||
y = y - (chevronOffset + 4); // where 4 is 1/4 the height of the chevron
|
||||
|
||||
ContextualMenu.createMenu(StatusMessageContextMenu, {
|
||||
chevronOffset: chevronOffset,
|
||||
chevronFace: 'bottom',
|
||||
left: x,
|
||||
top: y,
|
||||
menuWidth: 190,
|
||||
user: this.props.member.user,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
if (!SettingsStore.isFeatureEnabled("feature_custom_status")) {
|
||||
return <MemberAvatar member={this.props.member}
|
||||
width={this.props.width}
|
||||
height={this.props.height}
|
||||
resizeMethod={this.props.resizeMethod} />;
|
||||
}
|
||||
|
||||
const hasStatus = this.props.member.user ? !!this.props.member.user._unstable_statusMessage : false;
|
||||
|
||||
const classes = classNames({
|
||||
"mx_MemberStatusMessageAvatar": true,
|
||||
"mx_MemberStatusMessageAvatar_hasStatus": hasStatus,
|
||||
});
|
||||
|
||||
return <AccessibleButton onClick={this._onClick} className={classes} element="div">
|
||||
<MemberAvatar member={this.props.member}
|
||||
width={this.props.width}
|
||||
height={this.props.height}
|
||||
resizeMethod={this.props.resizeMethod} />
|
||||
</AccessibleButton>;
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright 2018 New Vector 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.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export default class StatusMessageContextMenu extends React.Component {
|
||||
static propTypes = {
|
||||
// js-sdk User object. Not required because it might not exist.
|
||||
user: PropTypes.object,
|
||||
};
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
message: props.user ? props.user._unstable_statusMessage : "",
|
||||
};
|
||||
}
|
||||
|
||||
_onClearClick = async(e) => {
|
||||
await MatrixClientPeg.get()._unstable_setStatusMessage("");
|
||||
this.setState({message: ""});
|
||||
};
|
||||
|
||||
_onSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
MatrixClientPeg.get()._unstable_setStatusMessage(this.state.message);
|
||||
};
|
||||
|
||||
_onStatusChange = (e) => {
|
||||
this.setState({message: e.target.value});
|
||||
};
|
||||
|
||||
render() {
|
||||
const formSubmitClasses = classNames({
|
||||
"mx_StatusMessageContextMenu_submit": true,
|
||||
"mx_StatusMessageContextMenu_submitFaded": !this.state.message, // no message == faded
|
||||
});
|
||||
|
||||
const form = <form className="mx_StatusMessageContextMenu_form" onSubmit={this._onSubmit} autoComplete="off">
|
||||
<input type="text" key="message" placeholder={_t("Set a new status...")} autoFocus={true}
|
||||
className="mx_StatusMessageContextMenu_message"
|
||||
value={this.state.message} onChange={this._onStatusChange} maxLength="60" />
|
||||
<AccessibleButton onClick={this._onSubmit} element="div" className={formSubmitClasses}>
|
||||
<img src="img/icons-checkmark.svg" width="22" height="22" />
|
||||
</AccessibleButton>
|
||||
</form>;
|
||||
|
||||
const clearIcon = this.state.message ? "img/cancel-red.svg" : "img/cancel.svg";
|
||||
const clearButton = <AccessibleButton onClick={this._onClearClick} disabled={!this.state.message}
|
||||
className="mx_StatusMessageContextMenu_clear">
|
||||
<img src={clearIcon} alt={_t('Clear status')} width="12" height="12"
|
||||
className="mx_filterFlipColor mx_StatusMessageContextMenu_clearIcon" />
|
||||
<span>{_t("Clear status")}</span>
|
||||
</AccessibleButton>;
|
||||
|
||||
const menuClasses = classNames({
|
||||
"mx_StatusMessageContextMenu": true,
|
||||
"mx_StatusMessageContextMenu_hasStatus": this.state.message,
|
||||
});
|
||||
|
||||
return <div className={menuClasses}>
|
||||
{ form }
|
||||
<hr />
|
||||
{ clearButton }
|
||||
</div>;
|
||||
}
|
||||
}
|
@ -70,6 +70,7 @@ const EntityTile = React.createClass({
|
||||
onClick: PropTypes.func,
|
||||
suppressOnHover: PropTypes.bool,
|
||||
showPresence: PropTypes.bool,
|
||||
subtextLabel: PropTypes.string,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
@ -129,6 +130,9 @@ const EntityTile = React.createClass({
|
||||
presenceState={this.props.presenceState} />;
|
||||
nameClasses += ' mx_EntityTile_name_hover';
|
||||
}
|
||||
if (this.props.subtextLabel) {
|
||||
presenceLabel = <span className="mx_EntityTile_subtext">{this.props.subtextLabel}</span>;
|
||||
}
|
||||
nameEl = (
|
||||
<div className="mx_EntityTile_details">
|
||||
<img className="mx_EntityTile_chevron" src="img/member_chevron.png" width="8" height="12" />
|
||||
@ -138,6 +142,15 @@ const EntityTile = React.createClass({
|
||||
{presenceLabel}
|
||||
</div>
|
||||
);
|
||||
} else if (this.props.subtextLabel) {
|
||||
nameEl = (
|
||||
<div className="mx_EntityTile_details">
|
||||
<EmojiText element="div" className="mx_EntityTile_name" dir="auto">
|
||||
{name}
|
||||
</EmojiText>
|
||||
<span className="mx_EntityTile_subtext">{this.props.subtextLabel}</span>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
nameEl = (
|
||||
<EmojiText element="div" className="mx_EntityTile_name" dir="auto">{ name }</EmojiText>
|
||||
|
@ -42,6 +42,7 @@ import AccessibleButton from '../elements/AccessibleButton';
|
||||
import RoomViewStore from '../../../stores/RoomViewStore';
|
||||
import SdkConfig from '../../../SdkConfig';
|
||||
import MultiInviter from "../../../utils/MultiInviter";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
|
||||
module.exports = withMatrixClient(React.createClass({
|
||||
displayName: 'MemberInfo',
|
||||
@ -889,11 +890,16 @@ module.exports = withMatrixClient(React.createClass({
|
||||
let presenceState;
|
||||
let presenceLastActiveAgo;
|
||||
let presenceCurrentlyActive;
|
||||
let statusMessage;
|
||||
|
||||
if (this.props.member.user) {
|
||||
presenceState = this.props.member.user.presence;
|
||||
presenceLastActiveAgo = this.props.member.user.lastActiveAgo;
|
||||
presenceCurrentlyActive = this.props.member.user.currentlyActive;
|
||||
|
||||
if (SettingsStore.isFeatureEnabled("feature_custom_status")) {
|
||||
statusMessage = this.props.member.user._unstable_statusMessage;
|
||||
}
|
||||
}
|
||||
|
||||
const room = this.props.matrixClient.getRoom(this.props.member.roomId);
|
||||
@ -915,6 +921,11 @@ module.exports = withMatrixClient(React.createClass({
|
||||
presenceState={presenceState} />;
|
||||
}
|
||||
|
||||
let statusLabel = null;
|
||||
if (statusMessage) {
|
||||
statusLabel = <span className="mx_MemberInfo_statusMessage">{ statusMessage }</span>;
|
||||
}
|
||||
|
||||
let roomMemberDetails = null;
|
||||
if (this.props.member.roomId) { // is in room
|
||||
const PowerSelector = sdk.getComponent('elements.PowerSelector');
|
||||
@ -931,6 +942,7 @@ module.exports = withMatrixClient(React.createClass({
|
||||
</div>
|
||||
<div className="mx_MemberInfo_profileField">
|
||||
{presenceLabel}
|
||||
{statusLabel}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ limitations under the License.
|
||||
|
||||
'use strict';
|
||||
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
|
||||
const React = require('react');
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
@ -85,6 +87,11 @@ module.exports = React.createClass({
|
||||
const active = -1;
|
||||
const presenceState = member.user ? member.user.presence : null;
|
||||
|
||||
let statusMessage = null;
|
||||
if (member.user && SettingsStore.isFeatureEnabled("feature_custom_status")) {
|
||||
statusMessage = member.user._unstable_statusMessage;
|
||||
}
|
||||
|
||||
const av = (
|
||||
<MemberAvatar member={member} width={36} height={36} />
|
||||
);
|
||||
@ -106,7 +113,9 @@ module.exports = React.createClass({
|
||||
presenceLastTs={member.user ? member.user.lastPresenceTs : 0}
|
||||
presenceCurrentlyActive={member.user ? member.user.currentlyActive : false}
|
||||
avatarJsx={av} title={this.getPowerLabel()} onClick={this.onClick}
|
||||
name={name} powerStatus={powerStatus} showPresence={this.props.showPresence} />
|
||||
name={name} powerStatus={powerStatus} showPresence={this.props.showPresence}
|
||||
subtextLabel={statusMessage}
|
||||
/>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
@ -291,7 +291,7 @@ export default class MessageComposer extends React.Component {
|
||||
|
||||
render() {
|
||||
const uploadInputStyle = {display: 'none'};
|
||||
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
||||
const MemberStatusMessageAvatar = sdk.getComponent('avatars.MemberStatusMessageAvatar');
|
||||
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||
const MessageComposerInput = sdk.getComponent("rooms.MessageComposerInput");
|
||||
|
||||
@ -300,7 +300,7 @@ export default class MessageComposer extends React.Component {
|
||||
if (this.state.me) {
|
||||
controls.push(
|
||||
<div key="controls_avatar" className="mx_MessageComposer_avatar">
|
||||
<MemberAvatar member={this.state.me} width={24} height={24} />
|
||||
<MemberStatusMessageAvatar member={this.state.me} width={24} height={24} />
|
||||
</div>,
|
||||
);
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import * as FormattingUtils from '../../../utils/FormattingUtils';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import ActiveRoomObserver from '../../../ActiveRoomObserver';
|
||||
import RoomViewStore from '../../../stores/RoomViewStore';
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'RoomTile',
|
||||
@ -251,6 +252,17 @@ module.exports = React.createClass({
|
||||
const mentionBadges = this.props.highlight && this._shouldShowMentionBadge();
|
||||
const badges = notifBadges || mentionBadges;
|
||||
|
||||
const isJoined = this.props.room.getMyMembership() === "join";
|
||||
const looksLikeDm = this.props.room.getInvitedAndJoinedMemberCount() === 2;
|
||||
let subtext = null;
|
||||
if (!isInvite && isJoined && looksLikeDm && SettingsStore.isFeatureEnabled("feature_custom_status")) {
|
||||
const selfId = MatrixClientPeg.get().getUserId();
|
||||
const otherMember = this.props.room.currentState.getMembersExcept([selfId])[0];
|
||||
if (otherMember && otherMember.user && otherMember.user._unstable_statusMessage) {
|
||||
subtext = otherMember.user._unstable_statusMessage;
|
||||
}
|
||||
}
|
||||
|
||||
const classes = classNames({
|
||||
'mx_RoomTile': true,
|
||||
'mx_RoomTile_selected': this.state.selected,
|
||||
@ -261,6 +273,7 @@ module.exports = React.createClass({
|
||||
'mx_RoomTile_menuDisplayed': this.state.menuDisplayed,
|
||||
'mx_RoomTile_noBadges': !badges,
|
||||
'mx_RoomTile_transparent': this.props.transparent,
|
||||
'mx_RoomTile_hasSubtext': subtext && !this.props.collapsed,
|
||||
});
|
||||
|
||||
const avatarClasses = classNames({
|
||||
@ -291,6 +304,7 @@ module.exports = React.createClass({
|
||||
|
||||
const EmojiText = sdk.getComponent('elements.EmojiText');
|
||||
let label;
|
||||
let subtextLabel;
|
||||
let tooltip;
|
||||
if (!this.props.collapsed) {
|
||||
const nameClasses = classNames({
|
||||
@ -299,6 +313,8 @@ module.exports = React.createClass({
|
||||
'mx_RoomTile_badgeShown': badges || this.state.badgeHover || this.state.menuDisplayed,
|
||||
});
|
||||
|
||||
subtextLabel = subtext ? <span className="mx_RoomTile_subtext">{ subtext }</span> : null;
|
||||
|
||||
if (this.state.selected) {
|
||||
const nameSelected = <EmojiText>{ name }</EmojiText>;
|
||||
|
||||
@ -339,6 +355,7 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
<div className="mx_RoomTile_nameContainer">
|
||||
{ label }
|
||||
{ subtextLabel }
|
||||
{ badge }
|
||||
</div>
|
||||
{ /* { incomingCallBox } */ }
|
||||
|
@ -257,6 +257,7 @@
|
||||
"Please contact your homeserver administrator.": "Please contact your homeserver administrator.",
|
||||
"Failed to join room": "Failed to join room",
|
||||
"Message Pinning": "Message Pinning",
|
||||
"Custom user status messages": "Custom user status messages",
|
||||
"Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view",
|
||||
"Backup of encryption keys to server": "Backup of encryption keys to server",
|
||||
"Disable Emoji suggestions while typing": "Disable Emoji suggestions while typing",
|
||||
@ -1061,6 +1062,8 @@
|
||||
"Forget": "Forget",
|
||||
"Low Priority": "Low Priority",
|
||||
"Direct Chat": "Direct Chat",
|
||||
"Set a new status...": "Set a new status...",
|
||||
"Clear status": "Clear status",
|
||||
"View Community": "View Community",
|
||||
"Sorry, your browser is <b>not</b> able to run Riot.": "Sorry, your browser is <b>not</b> able to run Riot.",
|
||||
"Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.",
|
||||
|
@ -83,6 +83,12 @@ export const SETTINGS = {
|
||||
supportedLevels: LEVELS_FEATURE,
|
||||
default: false,
|
||||
},
|
||||
"feature_custom_status": {
|
||||
isFeature: true,
|
||||
displayName: _td("Custom user status messages"),
|
||||
supportedLevels: LEVELS_FEATURE,
|
||||
default: false,
|
||||
},
|
||||
"feature_lazyloading": {
|
||||
isFeature: true,
|
||||
displayName: _td("Increase performance by only loading room members on first view"),
|
||||
|
Loading…
Reference in New Issue
Block a user