diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index 2b57d4e9e2..30cc55377c 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -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 diff --git a/res/css/structures/_ContextualMenu.scss b/res/css/structures/_ContextualMenu.scss index fa69c6fb90..a01cd896a8 100644 --- a/res/css/structures/_ContextualMenu.scss +++ b/res/css/structures/_ContextualMenu.scss @@ -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; diff --git a/res/css/views/avatars/_MemberStatusMessageAvatar.scss b/res/css/views/avatars/_MemberStatusMessageAvatar.scss index 29cae9df34..c101a5d8a8 100644 --- a/res/css/views/avatars/_MemberStatusMessageAvatar.scss +++ b/res/css/views/avatars/_MemberStatusMessageAvatar.scss @@ -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; } diff --git a/res/css/views/context_menus/_StatusMessageContextMenu.scss b/res/css/views/context_menus/_StatusMessageContextMenu.scss index 873ad99495..8b25f3a122 100644 --- a/res/css/views/context_menus/_StatusMessageContextMenu.scss +++ b/res/css/views/context_menus/_StatusMessageContextMenu.scss @@ -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; } diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index 39640575ba..4a052482ad 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -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; } diff --git a/res/img/icons-checkmark.svg b/res/img/icons-checkmark.svg deleted file mode 100644 index 3c5392003d..0000000000 --- a/res/img/icons-checkmark.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - Tick - Created with Sketch. - - - - - - - - - - - - diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 732cabf494..73dc0a71e4 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -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 diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 10a8fcd1e5..cf539bd1f2 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -188,6 +188,8 @@ $progressbar-color: #000; $room-warning-bg-color: #fff8e3; +$memberstatus-placeholder-color: $roomtile-name-color; + // ***** Mixins! ***** @define-mixin mx_DialogButton { diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index 4c7d004015..762185146c 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -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 =
{guestRead}{guestJoin}
; } + 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( diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 15b9181d21..56b23c63f2 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -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 diff --git a/src/components/views/avatars/MemberStatusMessageAvatar.js b/src/components/views/avatars/MemberStatusMessageAvatar.js index aebd1741b7..0258c4b0c8 100644 --- a/src/components/views/avatars/MemberStatusMessageAvatar.js +++ b/src/components/views/avatars/MemberStatusMessageAvatar.js @@ -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 ; - } + const avatar = ; - 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 - + return + {avatar} ; } } diff --git a/src/components/views/context_menus/StatusMessageContextMenu.js b/src/components/views/context_menus/StatusMessageContextMenu.js index d062fc2a3e..9916f5d347 100644 --- a/src/components/views/context_menus/StatusMessageContextMenu.js +++ b/src/components/views/context_menus/StatusMessageContextMenu.js @@ -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 = + {_t("Clear status")} + ; + } else { + actionButton = + {_t("Update status")} + ; + } + } else { + actionButton = + {_t("Set status")} + ; + } - const form =
- - - - + const form = + + {actionButton}
; - const clearIcon = this.state.message ? "img/cancel-red.svg" : "img/cancel.svg"; - const clearButton = - {_t('Clear - {_t("Clear status")} - ; - - const menuClasses = classNames({ - "mx_StatusMessageContextMenu": true, - "mx_StatusMessageContextMenu_hasStatus": this.state.message, - }); - - return
+ return
{ form } -
- { clearButton }
; } } diff --git a/src/components/views/dialogs/ChangelogDialog.js b/src/components/views/dialogs/ChangelogDialog.js index 3c9414fd88..965029c069 100644 --- a/src/components/views/dialogs/ChangelogDialog.js +++ b/src/components/views/dialogs/ChangelogDialog.js @@ -36,7 +36,7 @@ export default class ChangelogDialog extends React.Component { for (let i=0; i { if (response.statusCode < 200 || response.statusCode >= 300) { this.setState({ [REPOS[i]]: response.statusText }); diff --git a/src/components/views/rooms/MemberTile.js b/src/components/views/rooms/MemberTile.js index ba951792d0..926734a767 100644 --- a/src/components/views/rooms/MemberTile.js +++ b/src/components/views/rooms/MemberTile.js @@ -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 = ( diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index 95073b7be8..1f9c0c1523 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -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({ diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0086ed0378..ef0ff1ebf7 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -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 not able to run Riot.": "Sorry, your browser is not able to run Riot.", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index a04301e31e..836e906b6e 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -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'), diff --git a/src/settings/controllers/CustomStatusController.js b/src/settings/controllers/CustomStatusController.js new file mode 100644 index 0000000000..0fc6619d92 --- /dev/null +++ b/src/settings/controllers/CustomStatusController.js @@ -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", + }); + } +}