From 786bd87fec212853c3c962bb24eb0c50d4848ec4 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sun, 29 Oct 2017 21:48:29 -0600 Subject: [PATCH] Support URL previews (with bugs) Known issues at this point: * The room-level setting accepts the current user's default, which is wrong * The checkboxes on RoomSettings are not independent * The checkboxes in RoomSettings need some layout fixes Signed-off-by: Travis Ralston --- src/UserSettingsStore.js | 12 -- src/components/structures/RoomView.js | 32 +--- src/components/structures/UserSettings.js | 19 +- .../views/elements/SettingsCheckbox.js | 2 +- .../views/room_settings/UrlPreviewSettings.js | 163 ++++-------------- src/settings/AccountSettingsHandler.js | 18 +- src/settings/RoomAccountSettingsHandler.js | 17 +- src/settings/RoomSettingsHandler.js | 17 +- src/settings/SettingsStore.js | 24 ++- 9 files changed, 107 insertions(+), 197 deletions(-) diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index 20c1c3d17f..e69ebf2818 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -124,16 +124,4 @@ export default { append: true, // We always append for email pushers since we don't want to stop other accounts notifying to the same email address }); }, - - getUrlPreviewsDisabled: function() { - const event = MatrixClientPeg.get().getAccountData('org.matrix.preview_urls'); - return (event && event.getContent().disable); - }, - - setUrlPreviewsDisabled: function(disabled) { - // FIXME: handle errors - return MatrixClientPeg.get().setAccountData('org.matrix.preview_urls', { - disable: disabled, - }); - }, }; diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 4256c19f4d..d44cb08b2c 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -614,38 +614,8 @@ module.exports = React.createClass({ }, _updatePreviewUrlVisibility: function(room) { - // console.log("_updatePreviewUrlVisibility"); - - // check our per-room overrides - const roomPreviewUrls = room.getAccountData("org.matrix.room.preview_urls"); - if (roomPreviewUrls && roomPreviewUrls.getContent().disable !== undefined) { - this.setState({ - showUrlPreview: !roomPreviewUrls.getContent().disable, - }); - return; - } - - // check our global disable override - const userRoomPreviewUrls = MatrixClientPeg.get().getAccountData("org.matrix.preview_urls"); - if (userRoomPreviewUrls && userRoomPreviewUrls.getContent().disable) { - this.setState({ - showUrlPreview: false, - }); - return; - } - - // check the room state event - const roomStatePreviewUrls = room.currentState.getStateEvents('org.matrix.room.preview_urls', ''); - if (roomStatePreviewUrls && roomStatePreviewUrls.getContent().disable) { - this.setState({ - showUrlPreview: false, - }); - return; - } - - // otherwise, we assume they're on. this.setState({ - showUrlPreview: true, + showUrlPreview: SettingsStore.getValue("urlPreviewsEnabled", room.roomId), }); }, diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 52fd48a6be..9bd628ed15 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -61,6 +61,7 @@ const gHVersionLabel = function(repo, token='') { // Enumerate some simple 'flip a bit' UI settings (if any). The strings provided here // must be settings defined in SettingsStore. const SIMPLE_SETTINGS = [ + { id: "urlPreviewsEnabled" }, { id: "autoplayGifsAndVideos" }, { id: "hideReadReceipts" }, { id: "dontSendTypingNotifications" }, @@ -640,7 +641,6 @@ module.exports = React.createClass({

{ _t("User Interface") }

- { this._renderUrlPreviewSelector() } { SIMPLE_SETTINGS.map( this._renderSyncedSetting ) } { THEMES.map( this._renderThemeSelector ) } @@ -663,23 +663,6 @@ module.exports = React.createClass({ ); }, - _renderUrlPreviewSelector: function() { - return
- - -
; - }, - - _onPreviewsDisabledChanged: function(e) { - UserSettingsStore.setUrlPreviewsDisabled(e.target.checked); - }, - _renderSyncedSetting: function(setting) { const SettingsCheckbox = sdk.getComponent("elements.SettingsCheckbox"); return ( diff --git a/src/components/views/elements/SettingsCheckbox.js b/src/components/views/elements/SettingsCheckbox.js index 12f23de046..cf57fe46ea 100644 --- a/src/components/views/elements/SettingsCheckbox.js +++ b/src/components/views/elements/SettingsCheckbox.js @@ -44,7 +44,7 @@ module.exports = React.createClass({ let val = SettingsStore.getValueAt(this.props.level, this.props.name, this.props.roomId); let label = this.props.label; - if (!label) label = SettingsStore.getDisplayName(this.props.name); + if (!label) label = SettingsStore.getDisplayName(this.props.name, this.props.level); else label = _t(label); let id = this.props.name; diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js index 56ae24e2f8..fe7739a645 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.js +++ b/src/components/views/room_settings/UrlPreviewSettings.js @@ -1,5 +1,6 @@ /* Copyright 2016 OpenMarket Ltd +Copyright 2017 Travis Ralston Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,13 +15,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import Promise from 'bluebird'; const React = require('react'); -const MatrixClientPeg = require('../../../MatrixClientPeg'); const sdk = require("../../../index"); -const Modal = require("../../../Modal"); -const UserSettingsStore = require('../../../UserSettingsStore'); import { _t, _tJsx } from '../../../languageHandler'; +import SettingsStore from "../../../settings/SettingsStore"; module.exports = React.createClass({ @@ -30,137 +28,52 @@ module.exports = React.createClass({ room: React.PropTypes.object, }, - getInitialState: function() { - const cli = MatrixClientPeg.get(); - const roomState = this.props.room.currentState; - - const roomPreviewUrls = this.props.room.currentState.getStateEvents('org.matrix.room.preview_urls', ''); - const userPreviewUrls = this.props.room.getAccountData("org.matrix.room.preview_urls"); - - return { - globalDisableUrlPreview: (roomPreviewUrls && roomPreviewUrls.getContent().disable) || false, - userDisableUrlPreview: (userPreviewUrls && (userPreviewUrls.getContent().disable === true)) || false, - userEnableUrlPreview: (userPreviewUrls && (userPreviewUrls.getContent().disable === false)) || false, - }; - }, - - componentDidMount: function() { - this.originalState = Object.assign({}, this.state); - }, - - saveSettings: function() { - const promises = []; - - if (this.state.globalDisableUrlPreview !== this.originalState.globalDisableUrlPreview) { - console.log("UrlPreviewSettings: Updating room's preview_urls state event"); - promises.push( - MatrixClientPeg.get().sendStateEvent( - this.props.room.roomId, "org.matrix.room.preview_urls", { - disable: this.state.globalDisableUrlPreview, - }, "", - ), - ); - } - - let content = undefined; - if (this.state.userDisableUrlPreview !== this.originalState.userDisableUrlPreview) { - console.log("UrlPreviewSettings: Disabling user's per-room preview_urls"); - content = this.state.userDisableUrlPreview ? { disable: true } : {}; - } - - if (this.state.userEnableUrlPreview !== this.originalState.userEnableUrlPreview) { - console.log("UrlPreviewSettings: Enabling user's per-room preview_urls"); - if (!content || content.disable === undefined) { - content = this.state.userEnableUrlPreview ? { disable: false } : {}; - } - } - - if (content) { - promises.push( - MatrixClientPeg.get().setRoomAccountData( - this.props.room.roomId, "org.matrix.room.preview_urls", content, - ), - ); - } - - console.log("UrlPreviewSettings: saveSettings: " + JSON.stringify(promises)); - - return promises; - }, - - onGlobalDisableUrlPreviewChange: function() { - this.setState({ - globalDisableUrlPreview: this.refs.globalDisableUrlPreview.checked ? true : false, - }); - }, - - onUserEnableUrlPreviewChange: function() { - this.setState({ - userDisableUrlPreview: false, - userEnableUrlPreview: this.refs.userEnableUrlPreview.checked ? true : false, - }); - }, - - onUserDisableUrlPreviewChange: function() { - this.setState({ - userDisableUrlPreview: this.refs.userDisableUrlPreview.checked ? true : false, - userEnableUrlPreview: false, - }); - }, - render: function() { - const self = this; - const roomState = this.props.room.currentState; - const cli = MatrixClientPeg.get(); + const SettingsCheckbox = sdk.getComponent("elements.SettingsCheckbox"); + const roomId = this.props.room.roomId; - const maySetRoomPreviewUrls = roomState.mayClientSendStateEvent('org.matrix.room.preview_urls', cli); - let disableRoomPreviewUrls; - if (maySetRoomPreviewUrls) { - disableRoomPreviewUrls = - ; - } else { - disableRoomPreviewUrls = - ; - } - - let urlPreviewText = null; - if (UserSettingsStore.getUrlPreviewsDisabled()) { - urlPreviewText = ( - _tJsx("You have disabled URL previews by default.", /(.*?)<\/a>/, (sub)=>{ sub }) - ); - } else { - urlPreviewText = ( + let previewsForAccount = null; + if (SettingsStore.getValueAt("account", "urlPreviewsEnabled")) { + previewsForAccount = ( _tJsx("You have enabled URL previews by default.", /(.*?)<\/a>/, (sub)=>{ sub }) ); + } else { + previewsForAccount = ( + _tJsx("You have disabled URL previews by default.", /(.*?)<\/a>/, (sub)=>{ sub }) + ); } + let previewsForRoom = null; + if (SettingsStore.canSetValue("urlPreviewsEnabled", roomId, "room")) { + previewsForRoom = ( + + ); + } else { + let str = "URL previews are enabled by default for participants in this room."; + if (!SettingsStore.getValueAt("room", "urlPreviewsEnabled")) { + str = "URL previews are disabled by default for participants in this room."; + } + previewsForRoom = (); + } + + let previewsForRoomAccount = ( + + ); + return (

{ _t("URL Previews") }

- - { disableRoomPreviewUrls } - - + + { previewsForRoom } +
); }, diff --git a/src/settings/AccountSettingsHandler.js b/src/settings/AccountSettingsHandler.js index db25cd0737..5bda5bd910 100644 --- a/src/settings/AccountSettingsHandler.js +++ b/src/settings/AccountSettingsHandler.js @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import Promise from 'bluebird'; import SettingsHandler from "./SettingsHandler"; import MatrixClientPeg from '../MatrixClientPeg'; @@ -24,10 +23,23 @@ import MatrixClientPeg from '../MatrixClientPeg'; */ export default class AccountSettingHandler extends SettingsHandler { getValue(settingName, roomId) { + // Special case URL previews + if (settingName === "urlPreviewsEnabled") { + const content = this._getSettings("org.matrix.preview_urls"); + return !content['disable']; + } + return this._getSettings()[settingName]; } setValue(settingName, roomId, newValue) { + // Special case URL previews + if (settingName === "urlPreviewsEnabled") { + const content = this._getSettings("org.matrix.preview_urls"); + content['disable'] = !newValue; + return MatrixClientPeg.get().setAccountData("org.matrix.preview_urls", content); + } + const content = this._getSettings(); content[settingName] = newValue; return MatrixClientPeg.get().setAccountData("im.vector.web.settings", content); @@ -41,8 +53,8 @@ export default class AccountSettingHandler extends SettingsHandler { return !!MatrixClientPeg.get(); } - _getSettings() { - const event = MatrixClientPeg.get().getAccountData("im.vector.web.settings"); + _getSettings(eventType = "im.vector.web.settings") { + const event = MatrixClientPeg.get().getAccountData(eventType); if (!event || !event.getContent()) return {}; return event.getContent(); } diff --git a/src/settings/RoomAccountSettingsHandler.js b/src/settings/RoomAccountSettingsHandler.js index e1edaffb90..d8274d2ed9 100644 --- a/src/settings/RoomAccountSettingsHandler.js +++ b/src/settings/RoomAccountSettingsHandler.js @@ -22,10 +22,23 @@ import MatrixClientPeg from '../MatrixClientPeg'; */ export default class RoomAccountSettingsHandler extends SettingsHandler { getValue(settingName, roomId) { + // Special case URL previews + if (settingName === "urlPreviewsEnabled") { + const content = this._getSettings(roomId, "org.matrix.room.preview_urls"); + return !content['disable']; + } + return this._getSettings(roomId)[settingName]; } setValue(settingName, roomId, newValue) { + // Special case URL previews + if (settingName === "urlPreviewsEnabled") { + const content = this._getSettings(roomId, "org.matrix.room.preview_urls"); + content['disable'] = !newValue; + return MatrixClientPeg.get().setRoomAccountData(roomId, "org.matrix.room.preview_urls", content); + } + const content = this._getSettings(roomId); content[settingName] = newValue; return MatrixClientPeg.get().setRoomAccountData(roomId, "im.vector.web.settings", content); @@ -40,11 +53,11 @@ export default class RoomAccountSettingsHandler extends SettingsHandler { return !!MatrixClientPeg.get(); } - _getSettings(roomId) { + _getSettings(roomId, eventType = "im.vector.settings") { const room = MatrixClientPeg.get().getRoom(roomId); if (!room) return {}; - const event = room.getAccountData("im.vector.settings"); + const event = room.getAccountData(eventType); if (!event || !event.getContent()) return {}; return event.getContent(); } diff --git a/src/settings/RoomSettingsHandler.js b/src/settings/RoomSettingsHandler.js index 63e4e11dac..00e16061ee 100644 --- a/src/settings/RoomSettingsHandler.js +++ b/src/settings/RoomSettingsHandler.js @@ -22,10 +22,23 @@ import MatrixClientPeg from '../MatrixClientPeg'; */ export default class RoomSettingsHandler extends SettingsHandler { getValue(settingName, roomId) { + // Special case URL previews + if (settingName === "urlPreviewsEnabled") { + const content = this._getSettings(roomId, "org.matrix.room.preview_urls"); + return !content['disable']; + } + return this._getSettings(roomId)[settingName]; } setValue(settingName, roomId, newValue) { + // Special case URL previews + if (settingName === "urlPreviewsEnabled") { + const content = this._getSettings(roomId, "org.matrix.room.preview_urls"); + content['disable'] = !newValue; + return MatrixClientPeg.get().setRoomAccountData(roomId, "org.matrix.room.preview_urls", content); + } + const content = this._getSettings(roomId); content[settingName] = newValue; return MatrixClientPeg.get().sendStateEvent(roomId, "im.vector.web.settings", content, ""); @@ -43,10 +56,10 @@ export default class RoomSettingsHandler extends SettingsHandler { return !!MatrixClientPeg.get(); } - _getSettings(roomId) { + _getSettings(roomId, eventType = "im.vector.web.settings") { const room = MatrixClientPeg.get().getRoom(roomId); if (!room) return {}; - const event = room.currentState.getStateEvents("im.vector.web.settings", ""); + const event = room.currentState.getStateEvents(eventType, ""); if (!event || !event.getContent()) return {}; return event.getContent(); } diff --git a/src/settings/SettingsStore.js b/src/settings/SettingsStore.js index ee30db39c5..bcaf4e234c 100644 --- a/src/settings/SettingsStore.js +++ b/src/settings/SettingsStore.js @@ -194,6 +194,15 @@ const SETTINGS = { default: false, displayName: _td('Never send encrypted messages to unverified devices from this device'), }, + "urlPreviewsEnabled": { + supportedLevels: LEVELS_PRESET_ROOM.concat("room"), + default: true, + displayName: { + "default": _td('Enable inline URL previews by default'), + "room-account": _td("Enable URL previews for this room (only affects you)"), + "room": _td("Enable URL previews by default for participants in this room"), + }, + }, }; // Convert the above into simpler formats for the handlers @@ -245,11 +254,20 @@ export default class SettingsStore { /** * Gets the translated display name for a given setting * @param {string} settingName The setting to look up. + * @param {"device"|"room-device"|"room-account"|"account"|"room"|"config"|"default"} atLevel + * The level to get the display name for; Defaults to 'default'. * @return {String} The display name for the setting, or null if not found. */ - static getDisplayName(settingName) { + static getDisplayName(settingName, atLevel = "default") { if (!SETTINGS[settingName] || !SETTINGS[settingName].displayName) return null; - return _t(SETTINGS[settingName].displayName); + + let displayName = SETTINGS[settingName].displayName; + if (displayName instanceof Object) { + if (displayName[atLevel]) displayName = displayName[atLevel]; + else displayName = displayName["default"]; + } + + return _t(displayName); } /** @@ -362,7 +380,7 @@ export default class SettingsStore { } if (!handler.canSetValue(settingName, roomId)) { - throw new Error("User cannot set " + settingName + " at level " + level); + throw new Error("User cannot set " + settingName + " at " + level + " in " + roomId); } return handler.setValue(settingName, roomId, value);