Merge branch 'experimental' into bwindels/searchmakeover

This commit is contained in:
Bruno Windels 2019-01-16 11:17:38 +01:00
commit 899ee265e3
18 changed files with 325 additions and 157 deletions

View file

@ -48,7 +48,6 @@ src/components/views/rooms/LinkPreviewWidget.js
src/components/views/rooms/MemberDeviceInfo.js
src/components/views/rooms/MemberInfo.js
src/components/views/rooms/MemberList.js
src/components/views/rooms/MemberTile.js
src/components/views/rooms/MessageComposer.js
src/components/views/rooms/PinnedEventTile.js
src/components/views/rooms/RoomList.js

View file

@ -30,8 +30,8 @@ limitations under the License.
}
.mx_ContextualMenu {
border-radius: 2px;
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.21);
border-radius: 4px;
box-shadow: 4px 4px 12px 0 rgba(118, 131, 156, 0.6);;
background-color: $menu-bg-color;
color: $primary-fg-color;
position: absolute;

View file

@ -14,8 +14,16 @@ 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;
padding-right: 0 !important; /* Override AccessibleButton styling */
.mx_MessageComposer_avatar .mx_BaseAvatar {
padding: 2px;
border: 1px solid transparent;
border-radius: 15px;
}
.mx_MessageComposer_avatar .mx_BaseAvatar_initial {
left: 2px;
}
.mx_MemberStatusMessageAvatar_hasStatus .mx_BaseAvatar {
border-color: $accent-color;
}

View file

@ -14,42 +14,43 @@ 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;
.mx_StatusMessageContextMenu {
padding: 10px;
}
.mx_StatusMessageContextMenu_form {
display: flex;
flex-direction: column;
}
input.mx_StatusMessageContextMenu_message {
border-radius: 4px;
border: 1px solid $input-border-color;
font-size: 13px;
padding: 7px 7px 7px 9px;
width: 135px;
background-color: $primary-bg-color !important;
padding: 6.5px 11px;
background-color: $primary-bg-color;
font-weight: normal;
margin: 0 0 10px;
}
.mx_StatusMessageContextMenu_submit {
display: inline-block;
.mx_StatusMessageContextMenu_message::placeholder {
color: $memberstatus-placeholder-color;
}
.mx_StatusMessageContextMenu_submitFaded {
opacity: 0.5;
.mx_StatusMessageContextMenu_submit,
.mx_StatusMessageContextMenu_clear {
@mixin mx_DialogButton;
align-self: start;
font-size: 12px;
padding: 6px 1em;
border: 1px solid transparent;
}
.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_submit[disabled] {
opacity: 0.49;
}
.mx_StatusMessageContextMenu_clear {
padding: 2px;
}
.mx_StatusMessageContextMenu_hasStatus .mx_StatusMessageContextMenu_clear {
color: $warning-color;
background-color: transparent;
border: 1px solid $warning-color;
}

View file

@ -58,17 +58,13 @@ limitations under the License.
}
.mx_MessageComposer .mx_MessageComposer_avatar {
padding: 0 28px;
padding: 0 27px;
}
.mx_MessageComposer .mx_MessageComposer_avatar .mx_BaseAvatar {
display: block;
}
.mx_MessageComposer .mx_AccessibleButton {
padding: 0 12px 0 0;
}
.mx_MessageComposer_composecontrols {
width: 100%;
}
@ -185,7 +181,7 @@ limitations under the License.
/*display: table-cell;*/
/*vertical-align: middle;*/
/*padding-left: 10px;*/
padding-right: 5px;
padding-right: 12px;
cursor: pointer;
padding-top: 4px;
}

View file

@ -1,17 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -68,7 +68,7 @@ $event-selected-color: #f7f7f7;
$primary-hairline-color: #e5e5e5;
// used for the border of input text fields
$input-border-color: #f0f0f0;
$input-border-color: #e7e7e7;
$input-darker-bg-color: rgba(193, 201, 214, 0.29);
$input-darker-fg-color: #9fa9ba;
$input-lighter-bg-color: #f2f5f8;
@ -192,6 +192,8 @@ $progressbar-color: #000;
$room-warning-bg-color: #fff8e3;
$memberstatus-placeholder-color: $roomtile-name-color;
/*** form elements ***/
// .mx_textinput is a container for a text input

View file

@ -188,6 +188,8 @@ $progressbar-color: #000;
$room-warning-bg-color: #fff8e3;
$memberstatus-placeholder-color: $roomtile-name-color;
// ***** Mixins! *****
@define-mixin mx_DialogButton {

View file

@ -34,6 +34,9 @@ import { _t } from '../../languageHandler';
import {instanceForInstanceId, protocolNameForInstanceId} from '../../utils/DirectoryUtils';
const MAX_NAME_LENGTH = 80;
const MAX_TOPIC_LENGTH = 160;
linkifyMatrix(linkify);
module.exports = React.createClass({
@ -390,7 +393,6 @@ module.exports = React.createClass({
const self = this;
let guestRead; let guestJoin; let perms;
for (let i = 0; i < rooms.length; i++) {
const name = rooms[i].name || get_display_alias_for_room(rooms[i]) || _t('Unnamed room');
guestRead = null;
guestJoin = null;
@ -410,7 +412,15 @@ module.exports = React.createClass({
perms = <div className="mx_RoomDirectory_perms">{guestRead}{guestJoin}</div>;
}
let name = rooms[i].name || get_display_alias_for_room(rooms[i]) || _t('Unnamed room');
if (name.length > MAX_NAME_LENGTH) {
name = `${name.substring(0, MAX_NAME_LENGTH)}...`;
}
let topic = rooms[i].topic || '';
if (topic.length > MAX_TOPIC_LENGTH) {
topic = `${topic.substring(0, MAX_TOPIC_LENGTH)}...`;
}
topic = linkifyString(sanitizeHtml(topic));
rows.push(

View file

@ -82,11 +82,10 @@ const SIMPLE_SETTINGS = [
{ id: "VideoView.flipVideoHorizontally" },
{ id: "TagPanel.disableTagPanel" },
{ id: "enableWidgetScreenshots" },
{ id: "RoomSubList.showEmpty" },
{ id: "pinMentionedRooms" },
{ id: "pinUnreadRooms" },
{ id: "showDeveloperTools" },
{ id: "alwaysRetryInvites" },
{ id: "alwaysInviteUnknownUsers" },
];
// These settings must be defined in SettingsStore

View file

@ -40,38 +40,50 @@ export default class MemberStatusMessageAvatar extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
hasStatus: this.hasStatus,
};
}
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: ""});
if (!SettingsStore.isFeatureEnabled("feature_custom_status")) {
return;
}
}
componentWillUnmount() {
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("RoomState.events", this._onRoomStateEvents);
const { user } = this.props.member;
if (!user) {
return;
}
user.on("User._unstable_statusMessage", this._onStatusMessageCommitted);
}
_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"]});
componentWillUmount() {
const { user } = this.props.member;
if (!user) {
return;
}
user.removeListener(
"User._unstable_statusMessage",
this._onStatusMessageCommitted,
);
}
get hasStatus() {
const { user } = this.props.member;
if (!user) {
return false;
}
return !!user._unstable_statusMessage;
}
_onStatusMessageCommitted = () => {
// The `User` object has observed a status message change.
this.setState({
hasStatus: this.hasStatus,
});
};
_onClick = (e) => {
@ -79,42 +91,43 @@ export default class MemberStatusMessageAvatar extends React.Component {
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
const x = (elementRect.left + window.pageXOffset);
const chevronWidth = 16; // See .mx_ContextualMenu_chevron_bottom
const chevronOffset = (elementRect.width - chevronWidth) / 2;
const chevronMargin = 1; // Add some spacing away from target
const y = elementRect.top + window.pageYOffset - chevronMargin;
ContextualMenu.createMenu(StatusMessageContextMenu, {
chevronOffset: chevronOffset,
chevronFace: 'bottom',
left: x,
top: y,
menuWidth: 190,
menuWidth: 226,
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 avatar = <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;
if (!SettingsStore.isFeatureEnabled("feature_custom_status")) {
return avatar;
}
const classes = classNames({
"mx_MemberStatusMessageAvatar": true,
"mx_MemberStatusMessageAvatar_hasStatus": hasStatus,
"mx_MemberStatusMessageAvatar_hasStatus": this.state.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} />
return <AccessibleButton className={classes}
element="div" onClick={this._onClick}
>
{avatar}
</AccessibleButton>;
}
}

View file

@ -19,7 +19,6 @@ 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 = {
@ -31,13 +30,42 @@ export default class StatusMessageContextMenu extends React.Component {
super(props, context);
this.state = {
message: props.user ? props.user._unstable_statusMessage : "",
message: this.comittedStatusMessage,
};
}
componentWillMount() {
const { user } = this.props;
if (!user) {
return;
}
user.on("User._unstable_statusMessage", this._onStatusMessageCommitted);
}
componentWillUmount() {
const { user } = this.props;
if (!user) {
return;
}
user.removeListener(
"User._unstable_statusMessage",
this._onStatusMessageCommitted,
);
}
get comittedStatusMessage() {
return this.props.user ? this.props.user._unstable_statusMessage : "";
}
_onStatusMessageCommitted = () => {
// The `User` object has observed a status message change.
this.setState({
message: this.comittedStatusMessage,
});
};
_onClearClick = async (e) => {
await MatrixClientPeg.get()._unstable_setStatusMessage("");
this.setState({message: ""});
};
_onSubmit = (e) => {
@ -46,41 +74,49 @@ export default class StatusMessageContextMenu extends React.Component {
};
_onStatusChange = (e) => {
this.setState({message: e.target.value});
// The input field's value was changed.
this.setState({
message: e.target.value,
});
};
render() {
const formSubmitClasses = classNames({
"mx_StatusMessageContextMenu_submit": true,
"mx_StatusMessageContextMenu_submitFaded": !this.state.message, // no message == faded
});
let actionButton;
if (this.comittedStatusMessage) {
if (this.state.message === this.comittedStatusMessage) {
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_clear"
onClick={this._onClearClick}
>
<span>{_t("Clear status")}</span>
</AccessibleButton>;
} else {
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_submit"
onClick={this._onSubmit}
>
<span>{_t("Update status")}</span>
</AccessibleButton>;
}
} else {
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_submit"
disabled={!this.state.message} onClick={this._onSubmit}
>
<span>{_t("Set status")}</span>
</AccessibleButton>;
}
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>
const form = <form className="mx_StatusMessageContextMenu_form"
autoComplete="off" onSubmit={this._onSubmit}
>
<input type="text" className="mx_StatusMessageContextMenu_message"
key="message" placeholder={_t("Set a new status...")}
autoFocus={true} maxLength="60" value={this.state.message}
onChange={this._onStatusChange}
/>
{actionButton}
</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}>
return <div className="mx_StatusMessageContextMenu">
{ form }
<hr />
{ clearButton }
</div>;
}
}

View file

@ -36,7 +36,7 @@ export default class ChangelogDialog extends React.Component {
for (let i=0; i<REPOS.length; i++) {
const oldVersion = version2[2*i];
const newVersion = version[2*i];
const url = `https://api.github.com/repos/${REPOS[i]}/compare/${oldVersion}...${newVersion}`;
const url = `https://riot.im/github/repos/${REPOS[i]}/compare/${oldVersion}...${newVersion}`;
request(url, (err, response, body) => {
if (response.statusCode < 200 || response.statusCode >= 300) {
this.setState({ [REPOS[i]]: response.statusText });

View file

@ -21,10 +21,8 @@ import SettingsStore from "../../../settings/SettingsStore";
const React = require('react');
import PropTypes from 'prop-types';
const MatrixClientPeg = require('../../../MatrixClientPeg');
const sdk = require('../../../index');
const dis = require('../../../dispatcher');
const Modal = require("../../../Modal");
import { _t } from '../../../languageHandler';
module.exports = React.createClass({
@ -42,7 +40,46 @@ module.exports = React.createClass({
},
getInitialState: function() {
return {};
return {
statusMessage: this.getStatusMessage(),
};
},
componentDidMount() {
if (!SettingsStore.isFeatureEnabled("feature_custom_status")) {
return;
}
const { user } = this.props.member;
if (!user) {
return;
}
user.on("User._unstable_statusMessage", this._onStatusMessageCommitted);
},
componentWillUmount() {
const { user } = this.props.member;
if (!user) {
return;
}
user.removeListener(
"User._unstable_statusMessage",
this._onStatusMessageCommitted,
);
},
getStatusMessage() {
const { user } = this.props.member;
if (!user) {
return "";
}
return user._unstable_statusMessage;
},
_onStatusMessageCommitted() {
// The `User` object has observed a status message change.
this.setState({
statusMessage: this.getStatusMessage(),
});
},
shouldComponentUpdate: function(nextProps, nextState) {
@ -74,22 +111,23 @@ module.exports = React.createClass({
},
getPowerLabel: function() {
return _t("%(userName)s (power %(powerLevelNumber)s)", {userName: this.props.member.userId, powerLevelNumber: this.props.member.powerLevel});
return _t("%(userName)s (power %(powerLevelNumber)s)", {
userName: this.props.member.userId,
powerLevelNumber: this.props.member.powerLevel,
});
},
render: function() {
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
const EntityTile = sdk.getComponent('rooms.EntityTile');
const member = this.props.member;
const name = this._getDisplayName();
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;
statusMessage = this.state.statusMessage;
}
const av = (

View file

@ -62,6 +62,7 @@ module.exports = React.createClass({
notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
notificationCount: this.props.room.getUnreadNotificationCount(),
selected: this.props.room.roomId === ActiveRoomObserver.getActiveRoomId(),
statusMessage: this._getStatusMessage(),
});
},
@ -79,6 +80,33 @@ module.exports = React.createClass({
return Boolean(dmRooms);
},
_shouldShowStatusMessage() {
if (!SettingsStore.isFeatureEnabled("feature_custom_status")) {
return false;
}
const isInvite = this.props.room.getMyMembership() === "invite";
const isJoined = this.props.room.getMyMembership() === "join";
const looksLikeDm = this.props.room.getInvitedAndJoinedMemberCount() === 2;
return !isInvite && isJoined && looksLikeDm;
},
_getStatusMessageUser() {
const selfId = MatrixClientPeg.get().getUserId();
const otherMember = this.props.room.currentState.getMembersExcept([selfId])[0];
if (!otherMember) {
return null;
}
return otherMember.user;
},
_getStatusMessage() {
const statusUser = this._getStatusMessageUser();
if (!statusUser) {
return "";
}
return statusUser._unstable_statusMessage;
},
onRoomTimeline: function(ev, room) {
if (room !== this.props.room) return;
this.setState({
@ -112,7 +140,13 @@ module.exports = React.createClass({
this.setState({
notificationCount: this.props.room.getUnreadNotificationCount(),
});
break;
break;
// RoomTiles are one of the few components that may show custom status and
// also remain on screen while in Settings toggling the feature. This ensures
// you can clearly see the status hide and show when toggling the feature.
case 'feature_custom_status_changed':
this.forceUpdate();
break;
}
},
@ -128,6 +162,16 @@ module.exports = React.createClass({
MatrixClientPeg.get().on("Room.name", this.onRoomName);
ActiveRoomObserver.addListener(this.props.room.roomId, this._onActiveRoomChange);
this.dispatcherRef = dis.register(this.onAction);
if (this._shouldShowStatusMessage()) {
const statusUser = this._getStatusMessageUser();
if (statusUser) {
statusUser.on(
"User._unstable_statusMessage",
this._onStatusMessageCommitted,
);
}
}
},
componentWillUnmount: function() {
@ -139,6 +183,16 @@ module.exports = React.createClass({
}
ActiveRoomObserver.removeListener(this.props.room.roomId, this._onActiveRoomChange);
dis.unregister(this.dispatcherRef);
if (this._shouldShowStatusMessage()) {
const statusUser = this._getStatusMessageUser();
if (statusUser) {
statusUser.removeListener(
"User._unstable_statusMessage",
this._onStatusMessageCommitted,
);
}
}
},
componentWillReceiveProps: function(props) {
@ -166,6 +220,13 @@ module.exports = React.createClass({
return false;
},
_onStatusMessageCommitted() {
// The status message `User` object has observed a message change.
this.setState({
statusMessage: this._getStatusMessage(),
});
},
onClick: function(ev) {
if (this.props.onClick) {
this.props.onClick(this.props.room.roomId, ev);
@ -251,15 +312,9 @@ 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;
}
if (this._shouldShowStatusMessage()) {
subtext = this.state.statusMessage;
}
const classes = classNames({

View file

@ -296,7 +296,6 @@
"Pin rooms I'm mentioned in to the top of the room list": "Pin rooms I'm mentioned in to the top of the room list",
"Pin unread rooms to the top of the room list": "Pin unread rooms to the top of the room list",
"Enable widget screenshots on supported widgets": "Enable widget screenshots on supported widgets",
"Show empty room list headings": "Show empty room list headings",
"Always invite users which may not exist": "Always invite users which may not exist",
"Show developer tools": "Show developer tools",
"Collecting app version information": "Collecting app version information",
@ -1088,8 +1087,10 @@
"Forget": "Forget",
"Low Priority": "Low Priority",
"Direct Chat": "Direct Chat",
"Set a new status...": "Set a new status...",
"Clear status": "Clear status",
"Update status": "Update status",
"Set status": "Set status",
"Set a new status...": "Set a new status...",
"View as Grid": "View as Grid",
"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.",

View file

@ -22,6 +22,7 @@ import {
NotificationsEnabledController,
} from "./controllers/NotificationControllers";
import LazyLoadingController from "./controllers/LazyLoadingController";
import CustomStatusController from "./controllers/CustomStatusController";
// These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
const LEVELS_ROOM_SETTINGS = ['device', 'room-device', 'room-account', 'account', 'config'];
@ -88,6 +89,7 @@ export const SETTINGS = {
displayName: _td("Custom user status messages"),
supportedLevels: LEVELS_FEATURE,
default: false,
controller: new CustomStatusController(),
},
"feature_lazyloading": {
isFeature: true,
@ -324,11 +326,6 @@ export const SETTINGS = {
supportedLevels: ['room-device'],
default: false,
},
"RoomSubList.showEmpty": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Show empty room list headings'),
default: true,
},
"alwaysInviteUnknownUsers": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Always invite users which may not exist'),

View file

@ -0,0 +1,28 @@
/*
Copyright 2019 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 SettingController from "./SettingController";
import dis from "../../dispatcher";
export default class CustomStatusController extends SettingController {
onChange(level, roomId, newValue) {
// Dispatch setting change so that some components that are still visible when the
// Settings page is open (such as RoomTiles) can reflect the change.
dis.dispatch({
action: "feature_custom_status_changed",
});
}
}