Merge pull request #2504 from matrix-org/travis/settings/positive

Be more positive with setting labels
This commit is contained in:
Travis Ralston 2019-01-28 09:00:52 -07:00 committed by GitHub
commit 6683a9989a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 250 additions and 98 deletions

View file

@ -184,7 +184,7 @@ class MatrixClientPeg {
userId: creds.userId, userId: creds.userId,
deviceId: creds.deviceId, deviceId: creds.deviceId,
timelineSupport: true, timelineSupport: true,
forceTURN: SettingsStore.getValue('webRtcForceTURN', false), forceTURN: !SettingsStore.getValue('webRtcForcePeerToPeer', false),
verificationMethods: [verificationMethods.SAS] verificationMethods: [verificationMethods.SAS]
}; };

View file

@ -97,7 +97,7 @@ export default class EmojiProvider extends AutocompleteProvider {
} }
async getCompletions(query: string, selection: SelectionRange, force?: boolean): Array<Completion> { async getCompletions(query: string, selection: SelectionRange, force?: boolean): Array<Completion> {
if (SettingsStore.getValue("MessageComposerInput.dontSuggestEmoji")) { if (!SettingsStore.getValue("MessageComposerInput.suggestEmoji")) {
return []; // don't give any suggestions if the user doesn't want them return []; // don't give any suggestions if the user doesn't want them
} }

View file

@ -170,7 +170,7 @@ module.exports = React.createClass({
const SettingsButton = sdk.getComponent('elements.SettingsButton'); const SettingsButton = sdk.getComponent('elements.SettingsButton');
const GroupsButton = sdk.getComponent('elements.GroupsButton'); const GroupsButton = sdk.getComponent('elements.GroupsButton');
const groupsButton = SettingsStore.getValue("TagPanel.disableTagPanel") ? const groupsButton = !SettingsStore.getValue("TagPanel.enableTagPanel") ?
<GroupsButton tooltip={true} /> : null; <GroupsButton tooltip={true} /> : null;
return ( return (

View file

@ -187,7 +187,7 @@ const LeftPanel = React.createClass({
const SearchBox = sdk.getComponent('structures.SearchBox'); const SearchBox = sdk.getComponent('structures.SearchBox');
const CallPreview = sdk.getComponent('voip.CallPreview'); const CallPreview = sdk.getComponent('voip.CallPreview');
const tagPanelEnabled = !SettingsStore.getValue("TagPanel.disableTagPanel"); const tagPanelEnabled = SettingsStore.getValue("TagPanel.enableTagPanel");
const tagPanel = tagPanelEnabled ? <TagPanel /> : <div />; const tagPanel = tagPanelEnabled ? <TagPanel /> : <div />;
const containerClasses = classNames( const containerClasses = classNames(

View file

@ -1838,7 +1838,7 @@ module.exports = React.createClass({
const messagePanel = ( const messagePanel = (
<TimelinePanel ref={this._gatherTimelinePanelRef} <TimelinePanel ref={this._gatherTimelinePanelRef}
timelineSet={this.state.room.getUnfilteredTimelineSet()} timelineSet={this.state.room.getUnfilteredTimelineSet()}
showReadReceipts={!SettingsStore.getValue('hideReadReceipts')} showReadReceipts={SettingsStore.getValue('showReadReceipts')}
manageReadReceipts={!this.state.isPeeking} manageReadReceipts={!this.state.isPeeking}
manageReadMarkers={!this.state.isPeeking} manageReadMarkers={!this.state.isPeeking}
hidden={hideMessagePanel} hidden={hideMessagePanel}

View file

@ -65,22 +65,22 @@ const SIMPLE_SETTINGS = [
{ id: "autoplayGifsAndVideos" }, { id: "autoplayGifsAndVideos" },
{ id: "alwaysShowEncryptionIcons" }, { id: "alwaysShowEncryptionIcons" },
{ id: "showRoomRecoveryReminder" }, { id: "showRoomRecoveryReminder" },
{ id: "hideReadReceipts" }, { id: "showReadReceipts" },
{ id: "dontSendTypingNotifications" }, { id: "sendTypingNotifications" },
{ id: "alwaysShowTimestamps" }, { id: "alwaysShowTimestamps" },
{ id: "showTwelveHourTimestamps" }, { id: "showTwelveHourTimestamps" },
{ id: "hideJoinLeaves" }, { id: "showJoinLeaves" },
{ id: "hideAvatarChanges" }, { id: "showAvatarChanges" },
{ id: "hideDisplaynameChanges" }, { id: "showDisplaynameChanges" },
{ id: "useCompactLayout" }, { id: "useCompactLayout" },
{ id: "hideRedactions" }, { id: "showRedactions" },
{ id: "enableSyntaxHighlightLanguageDetection" }, { id: "enableSyntaxHighlightLanguageDetection" },
{ id: "MessageComposerInput.autoReplaceEmoji" }, { id: "MessageComposerInput.autoReplaceEmoji" },
{ id: "MessageComposerInput.dontSuggestEmoji" }, { id: "MessageComposerInput.suggestEmoji" },
{ id: "Pill.shouldHidePillAvatar" }, { id: "Pill.shouldShowPillAvatar" },
{ id: "TextualBody.disableBigEmoji" }, { id: "TextualBody.enableBigEmoji" },
{ id: "VideoView.flipVideoHorizontally" }, { id: "VideoView.flipVideoHorizontally" },
{ id: "TagPanel.disableTagPanel" }, { id: "TagPanel.enableTagPanel" },
{ id: "enableWidgetScreenshots" }, { id: "enableWidgetScreenshots" },
{ id: "pinMentionedRooms" }, { id: "pinMentionedRooms" },
{ id: "pinUnreadRooms" }, { id: "pinUnreadRooms" },
@ -101,9 +101,9 @@ const ANALYTICS_SETTINGS = [
// These settings must be defined in SettingsStore // These settings must be defined in SettingsStore
const WEBRTC_SETTINGS = [ const WEBRTC_SETTINGS = [
{ {
id: 'webRtcForceTURN', id: 'webRtcForcePeerToPeer',
fn: (val) => { fn: (val) => {
MatrixClientPeg.get().setForceTURN(val); MatrixClientPeg.get().setForceTURN(!val);
}, },
}, },
]; ];

View file

@ -174,7 +174,7 @@ module.exports = React.createClass({
}, },
pillifyLinks: function(nodes) { pillifyLinks: function(nodes) {
const shouldShowPillAvatar = !SettingsStore.getValue("Pill.shouldHidePillAvatar"); const shouldShowPillAvatar = SettingsStore.getValue("Pill.shouldShowPillAvatar");
let node = nodes[0]; let node = nodes[0];
while (node) { while (node) {
let pillified = false; let pillified = false;
@ -436,7 +436,7 @@ module.exports = React.createClass({
const stripReply = ReplyThread.getParentEventId(mxEvent); const stripReply = ReplyThread.getParentEventId(mxEvent);
let body = HtmlUtils.bodyToHtml(content, this.props.highlights, { let body = HtmlUtils.bodyToHtml(content, this.props.highlights, {
disableBigEmoji: SettingsStore.getValue('TextualBody.disableBigEmoji'), disableBigEmoji: !SettingsStore.getValue('TextualBody.enableBigEmoji'),
// Part of Replies fallback support // Part of Replies fallback support
stripReplyFallback: stripReply, stripReplyFallback: stripReply,
}); });

View file

@ -486,7 +486,7 @@ export default class MessageComposerInput extends React.Component {
} }
sendTyping(isTyping) { sendTyping(isTyping) {
if (SettingsStore.getValue('dontSendTypingNotifications')) return; if (!SettingsStore.getValue('sendTypingNotifications')) return;
MatrixClientPeg.get().sendTyping( MatrixClientPeg.get().sendTyping(
this.props.room.roomId, this.props.room.roomId,
this.isTyping, TYPING_SERVER_TIMEOUT, this.isTyping, TYPING_SERVER_TIMEOUT,
@ -1443,7 +1443,7 @@ export default class MessageComposerInput extends React.Component {
const url = data.get('href'); const url = data.get('href');
const completion = data.get('completion'); const completion = data.get('completion');
const shouldShowPillAvatar = !SettingsStore.getValue("Pill.shouldHidePillAvatar"); const shouldShowPillAvatar = SettingsStore.getValue("Pill.shouldShowPillAvatar");
const Pill = sdk.getComponent('elements.Pill'); const Pill = sdk.getComponent('elements.Pill');
if (completion === '@room') { if (completion === '@room') {

View file

@ -26,8 +26,8 @@ const PlatformPeg = require("../../../../PlatformPeg");
export default class PreferencesSettingsTab extends React.Component { export default class PreferencesSettingsTab extends React.Component {
static COMPOSER_SETTINGS = [ static COMPOSER_SETTINGS = [
'MessageComposerInput.autoReplaceEmoji', 'MessageComposerInput.autoReplaceEmoji',
'MessageComposerInput.dontSuggestEmoji', // TODO: Positive wording 'MessageComposerInput.suggestEmoji',
'dontSendTypingNotifications', // TODO: Positive wording 'sendTypingNotifications',
]; ];
static ROOM_LIST_SETTINGS = [ static ROOM_LIST_SETTINGS = [
@ -38,21 +38,21 @@ export default class PreferencesSettingsTab extends React.Component {
static TIMELINE_SETTINGS = [ static TIMELINE_SETTINGS = [
'autoplayGifsAndVideos', 'autoplayGifsAndVideos',
'urlPreviewsEnabled', 'urlPreviewsEnabled',
'TextualBody.disableBigEmoji', // TODO: Positive wording 'TextualBody.enableBigEmoji',
'hideReadReceipts', // TODO: Positive wording 'showReadReceipts',
'showTwelveHourTimestamps', 'showTwelveHourTimestamps',
'alwaysShowTimestamps', 'alwaysShowTimestamps',
'hideRedactions', // TODO: Positive wording ("Show a placeholder for removed messages") 'showRedactions',
'enableSyntaxHighlightLanguageDetection', 'enableSyntaxHighlightLanguageDetection',
'hideJoinLeaves', // TODO: Positive wording 'showJoinLeaves',
'hideAvatarChanges', // TODO: Positive wording 'showAvatarChanges',
'hideDisplaynameChanges', // TODO: Positive wording 'showDisplaynameChanges',
]; ];
static ADVANCED_SETTINGS = [ static ADVANCED_SETTINGS = [
'alwaysShowEncryptionIcons', 'alwaysShowEncryptionIcons',
'Pill.shouldHidePillAvatar', // TODO: Positive wording 'Pill.shouldShowPillAvatar',
'TagPanel.disableTagPanel', // TODO: Positive wording 'TagPanel.enableTagPanel',
'promptBeforeInviteUnknownUsers', 'promptBeforeInviteUnknownUsers',
// Start automatically after startup (electron-only) // Start automatically after startup (electron-only)
// Autocomplete delay (niche text box) // Autocomplete delay (niche text box)

View file

@ -80,8 +80,8 @@ export default class VoiceSettingsTab extends React.Component {
CallMediaHandler.setVideoInput(e.target.value); CallMediaHandler.setVideoInput(e.target.value);
}; };
_setForceTurn = (forced) => { _changeWebRtcMethod = (p2p) => {
MatrixClientPeg.get().setForceTURN(forced); MatrixClientPeg.get().setForceTURN(!p2p);
}; };
_renderDeviceOptions(devices, category) { _renderDeviceOptions(devices, category) {
@ -159,7 +159,6 @@ export default class VoiceSettingsTab extends React.Component {
} }
} }
// TODO: Make 'webRtcForceTURN' be positively worded
return ( return (
<div className="mx_SettingsTab mx_VoiceSettingsTab"> <div className="mx_SettingsTab mx_VoiceSettingsTab">
<div className="mx_SettingsTab_heading">{_t("Voice & Video")}</div> <div className="mx_SettingsTab_heading">{_t("Voice & Video")}</div>
@ -169,7 +168,7 @@ export default class VoiceSettingsTab extends React.Component {
{microphoneDropdown} {microphoneDropdown}
{webcamDropdown} {webcamDropdown}
<SettingsFlag name='VideoView.flipVideoHorizontally' level={SettingLevel.ACCOUNT} /> <SettingsFlag name='VideoView.flipVideoHorizontally' level={SettingLevel.ACCOUNT} />
<SettingsFlag name='webRtcForceTURN' level={SettingLevel.DEVICE} onChange={this._setForceTurn} /> <SettingsFlag name='webRtcForcePeerToPeer' level={SettingLevel.DEVICE} onChange={this._changeWebRtcMethod} />
</div> </div>
</div> </div>
); );

View file

@ -267,26 +267,26 @@
"Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view", "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", "Backup of encryption keys to server": "Backup of encryption keys to server",
"Render simple counters in room header": "Render simple counters in room header", "Render simple counters in room header": "Render simple counters in room header",
"Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing",
"Two-way device verification using short text": "Two-way device verification using short text", "Two-way device verification using short text": "Two-way device verification using short text",
"Disable Emoji suggestions while typing": "Disable Emoji suggestions while typing",
"Use compact timeline layout": "Use compact timeline layout", "Use compact timeline layout": "Use compact timeline layout",
"Hide removed messages": "Hide removed messages", "Show a placeholder for removed messages": "Show a placeholder for removed messages",
"Hide join/leave messages (invites/kicks/bans unaffected)": "Hide join/leave messages (invites/kicks/bans unaffected)", "Show join/leave messages (invites/kicks/bans unaffected)": "Show join/leave messages (invites/kicks/bans unaffected)",
"Hide avatar changes": "Hide avatar changes", "Show avatar changes": "Show avatar changes",
"Hide display name changes": "Hide display name changes", "Show display name changes": "Show display name changes",
"Hide read receipts": "Hide read receipts", "Show read receipts": "Show read receipts",
"Show timestamps in 12 hour format (e.g. 2:30pm)": "Show timestamps in 12 hour format (e.g. 2:30pm)", "Show timestamps in 12 hour format (e.g. 2:30pm)": "Show timestamps in 12 hour format (e.g. 2:30pm)",
"Always show message timestamps": "Always show message timestamps", "Always show message timestamps": "Always show message timestamps",
"Autoplay GIFs and videos": "Autoplay GIFs and videos", "Autoplay GIFs and videos": "Autoplay GIFs and videos",
"Always show encryption icons": "Always show encryption icons", "Always show encryption icons": "Always show encryption icons",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "Show a reminder to enable Secure Message Recovery in encrypted rooms", "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Show a reminder to enable Secure Message Recovery in encrypted rooms",
"Enable automatic language detection for syntax highlighting": "Enable automatic language detection for syntax highlighting", "Enable automatic language detection for syntax highlighting": "Enable automatic language detection for syntax highlighting",
"Hide avatars in user and room mentions": "Hide avatars in user and room mentions", "Show avatars in user and room mentions": "Show avatars in user and room mentions",
"Disable big emoji in chat": "Disable big emoji in chat", "Enable big emoji in chat": "Enable big emoji in chat",
"Don't send typing notifications": "Don't send typing notifications", "Send typing notifications": "Send typing notifications",
"Automatically replace plain text Emoji": "Automatically replace plain text Emoji", "Automatically replace plain text Emoji": "Automatically replace plain text Emoji",
"Mirror local video feed": "Mirror local video feed", "Mirror local video feed": "Mirror local video feed",
"Disable Community Filter Panel": "Disable Community Filter Panel", "Enable Community Filter Panel": "Enable Community Filter Panel",
"Disable Peer-to-Peer for 1:1 calls": "Disable Peer-to-Peer for 1:1 calls", "Disable Peer-to-Peer for 1:1 calls": "Disable Peer-to-Peer for 1:1 calls",
"Send analytics data": "Send analytics data", "Send analytics data": "Send analytics data",
"Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device", "Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device",

View file

@ -77,6 +77,15 @@ export const SETTINGS = {
// // settings. The first element is treated as "most preferred". The "default" // // settings. The first element is treated as "most preferred". The "default"
// // level is always appended to the end. // // level is always appended to the end.
// supportedLevelsAreOrdered: false, // supportedLevelsAreOrdered: false,
//
// // Optional value to invert a boolean setting's value. The string given will
// // be read as the setting's ID instead of the one provided as the key for the
// // setting definition. By setting this, the returned value will automatically
// // be inverted, except for when the default value is returned. Inversion will
// // occur after the controller is asked for an override. This should be used by
// // historical settings which we don't want existing user's values be wiped. Do
// // not use this for new settings.
// invertedSettingName: "my-negative-setting",
// }, // },
"feature_pinning": { "feature_pinning": {
isFeature: true, isFeature: true,
@ -122,40 +131,46 @@ export const SETTINGS = {
supportedLevels: LEVELS_FEATURE, supportedLevels: LEVELS_FEATURE,
default: false, default: false,
}, },
"MessageComposerInput.dontSuggestEmoji": { "MessageComposerInput.suggestEmoji": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS, supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Disable Emoji suggestions while typing'), displayName: _td('Enable Emoji suggestions while typing'),
default: false, default: true,
invertedSettingName: 'MessageComposerInput.dontSuggestEmoji',
}, },
"useCompactLayout": { "useCompactLayout": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS, supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Use compact timeline layout'), displayName: _td('Use compact timeline layout'),
default: false, default: false,
}, },
"hideRedactions": { "showRedactions": {
supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM, supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM,
displayName: _td('Hide removed messages'), displayName: _td('Show a placeholder for removed messages'),
default: false, default: true,
invertedSettingName: 'hideRedactions',
}, },
"hideJoinLeaves": { "showJoinLeaves": {
supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM, supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM,
displayName: _td('Hide join/leave messages (invites/kicks/bans unaffected)'), displayName: _td('Show join/leave messages (invites/kicks/bans unaffected)'),
default: false, default: true,
invertedSettingName: 'hideJoinLeaves',
}, },
"hideAvatarChanges": { "showAvatarChanges": {
supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM, supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM,
displayName: _td('Hide avatar changes'), displayName: _td('Show avatar changes'),
default: false, default: true,
invertedSettingName: 'hideAvatarChanges',
}, },
"hideDisplaynameChanges": { "showDisplaynameChanges": {
supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM, supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM,
displayName: _td('Hide display name changes'), displayName: _td('Show display name changes'),
default: false, default: true,
invertedSettingName: 'hideDisplaynameChanges',
}, },
"hideReadReceipts": { "showReadReceipts": {
supportedLevels: LEVELS_ROOM_SETTINGS, supportedLevels: LEVELS_ROOM_SETTINGS,
displayName: _td('Hide read receipts'), displayName: _td('Show read receipts'),
default: false, default: true,
invertedSettingName: 'hideReadReceipts',
}, },
"showTwelveHourTimestamps": { "showTwelveHourTimestamps": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS, supportedLevels: LEVELS_ACCOUNT_SETTINGS,
@ -187,15 +202,17 @@ export const SETTINGS = {
displayName: _td('Enable automatic language detection for syntax highlighting'), displayName: _td('Enable automatic language detection for syntax highlighting'),
default: false, default: false,
}, },
"Pill.shouldHidePillAvatar": { "Pill.shouldShowPillAvatar": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS, supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Hide avatars in user and room mentions'), displayName: _td('Show avatars in user and room mentions'),
default: false, default: true,
invertedSettingName: 'Pill.shouldHidePillAvatar',
}, },
"TextualBody.disableBigEmoji": { "TextualBody.enableBigEmoji": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS, supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Disable big emoji in chat'), displayName: _td('Enable big emoji in chat'),
default: false, default: true,
invertedSettingName: 'TextualBody.disableBigEmoji',
}, },
"MessageComposerInput.isRichTextEnabled": { "MessageComposerInput.isRichTextEnabled": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS, supportedLevels: LEVELS_ACCOUNT_SETTINGS,
@ -205,10 +222,11 @@ export const SETTINGS = {
supportedLevels: LEVELS_ACCOUNT_SETTINGS, supportedLevels: LEVELS_ACCOUNT_SETTINGS,
default: false, default: false,
}, },
"dontSendTypingNotifications": { "sendTypingNotifications": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS, supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td("Don't send typing notifications"), displayName: _td("Send typing notifications"),
default: false, default: true,
invertedSettingName: 'dontSendTypingNotifications',
}, },
"MessageComposerInput.autoReplaceEmoji": { "MessageComposerInput.autoReplaceEmoji": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS, supportedLevels: LEVELS_ACCOUNT_SETTINGS,
@ -220,19 +238,21 @@ export const SETTINGS = {
displayName: _td('Mirror local video feed'), displayName: _td('Mirror local video feed'),
default: false, default: false,
}, },
"TagPanel.disableTagPanel": { "TagPanel.enableTagPanel": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS, supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Disable Community Filter Panel'), displayName: _td('Enable Community Filter Panel'),
default: false, default: true,
invertedSettingName: 'TagPanel.disableTagPanel',
}, },
"theme": { "theme": {
supportedLevels: ['config'], supportedLevels: ['config'],
default: "dharma", default: "dharma",
}, },
"webRtcForceTURN": { "webRtcForcePeerToPeer": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td('Disable Peer-to-Peer for 1:1 calls'), displayName: _td('Disable Peer-to-Peer for 1:1 calls'),
default: false, default: true,
invertedSettingName: 'webRtcForceTURN',
}, },
"webrtc_audiooutput": { "webrtc_audiooutput": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,

View file

@ -43,10 +43,16 @@ export const SettingLevel = {
// Convert the settings to easier to manage objects for the handlers // Convert the settings to easier to manage objects for the handlers
const defaultSettings = {}; const defaultSettings = {};
const invertedDefaultSettings = {};
const featureNames = []; const featureNames = [];
for (const key of Object.keys(SETTINGS)) { for (const key of Object.keys(SETTINGS)) {
defaultSettings[key] = SETTINGS[key].default; defaultSettings[key] = SETTINGS[key].default;
if (SETTINGS[key].isFeature) featureNames.push(key); if (SETTINGS[key].isFeature) featureNames.push(key);
if (SETTINGS[key].invertedSettingName) {
// Invert now so that the rest of the system will invert it back
// to what was intended.
invertedDefaultSettings[key] = !SETTINGS[key].default;
}
} }
const LEVEL_HANDLERS = { const LEVEL_HANDLERS = {
@ -56,7 +62,7 @@ const LEVEL_HANDLERS = {
"account": new AccountSettingsHandler(), "account": new AccountSettingsHandler(),
"room": new RoomSettingsHandler(), "room": new RoomSettingsHandler(),
"config": new ConfigSettingsHandler(), "config": new ConfigSettingsHandler(),
"default": new DefaultSettingsHandler(defaultSettings), "default": new DefaultSettingsHandler(defaultSettings, invertedDefaultSettings),
}; };
// Wrap all the handlers with local echo // Wrap all the handlers with local echo
@ -200,11 +206,11 @@ export default class SettingsStore {
*/ */
static getValueAt(level, settingName, roomId = null, explicit = false, excludeDefault = false) { static getValueAt(level, settingName, roomId = null, explicit = false, excludeDefault = false) {
// Verify that the setting is actually a setting // Verify that the setting is actually a setting
if (!SETTINGS[settingName]) { const setting = SETTINGS[settingName];
if (!setting) {
throw new Error("Setting '" + settingName + "' does not appear to be a setting."); throw new Error("Setting '" + settingName + "' does not appear to be a setting.");
} }
const setting = SETTINGS[settingName];
const levelOrder = (setting.supportedLevelsAreOrdered ? setting.supportedLevels : LEVEL_ORDER); const levelOrder = (setting.supportedLevelsAreOrdered ? setting.supportedLevels : LEVEL_ORDER);
if (!levelOrder.includes("default")) levelOrder.push("default"); // always include default if (!levelOrder.includes("default")) levelOrder.push("default"); // always include default
@ -220,11 +226,20 @@ export default class SettingsStore {
const handlers = SettingsStore._getHandlers(settingName); const handlers = SettingsStore._getHandlers(settingName);
// Check if we need to invert the setting at all. Do this after we get the setting
// handlers though, otherwise we'll fail to read the value.
if (setting.invertedSettingName) {
//console.warn(`Inverting ${settingName} to be ${setting.invertedSettingName} - legacy setting`);
settingName = setting.invertedSettingName;
}
if (explicit) { if (explicit) {
const handler = handlers[level]; const handler = handlers[level];
if (!handler) return SettingsStore._tryControllerOverride(settingName, level, roomId, null, null); if (!handler) {
return SettingsStore._getFinalValue(setting, level, roomId, null, null);
}
const value = handler.getValue(settingName, roomId); const value = handler.getValue(settingName, roomId);
return SettingsStore._tryControllerOverride(settingName, level, roomId, value, level); return SettingsStore._getFinalValue(setting, level, roomId, value, level);
} }
for (let i = minIndex; i < levelOrder.length; i++) { for (let i = minIndex; i < levelOrder.length; i++) {
@ -234,20 +249,24 @@ export default class SettingsStore {
const value = handler.getValue(settingName, roomId); const value = handler.getValue(settingName, roomId);
if (value === null || value === undefined) continue; if (value === null || value === undefined) continue;
return SettingsStore._tryControllerOverride(settingName, level, roomId, value, levelOrder[i]); return SettingsStore._getFinalValue(setting, level, roomId, value, levelOrder[i]);
} }
return SettingsStore._tryControllerOverride(settingName, level, roomId, null, null); return SettingsStore._getFinalValue(setting, level, roomId, null, null);
} }
static _tryControllerOverride(settingName, level, roomId, calculatedValue, calculatedAtLevel) { static _getFinalValue(setting, level, roomId, calculatedValue, calculatedAtLevel) {
const controller = SETTINGS[settingName].controller; let resultingValue = calculatedValue;
if (!controller) return calculatedValue;
const actualValue = controller.getValueOverride(level, roomId, calculatedValue, calculatedAtLevel); if (setting.controller) {
if (actualValue !== undefined && actualValue !== null) return actualValue; const actualValue = setting.controller.getValueOverride(level, roomId, calculatedValue, calculatedAtLevel);
return calculatedValue; if (actualValue !== undefined && actualValue !== null) resultingValue = actualValue;
}
if (setting.invertedSettingName) resultingValue = !resultingValue;
return resultingValue;
} }
/* eslint-disable valid-jsdoc */ //https://github.com/eslint/eslint/issues/7307 /* eslint-disable valid-jsdoc */ //https://github.com/eslint/eslint/issues/7307
/** /**
* Sets the value for a setting. The room ID is optional if the setting is not being * Sets the value for a setting. The room ID is optional if the setting is not being
@ -263,7 +282,8 @@ export default class SettingsStore {
/* eslint-enable valid-jsdoc */ /* eslint-enable valid-jsdoc */
static async setValue(settingName, roomId, level, value) { static async setValue(settingName, roomId, level, value) {
// Verify that the setting is actually a setting // Verify that the setting is actually a setting
if (!SETTINGS[settingName]) { const setting = SETTINGS[settingName];
if (!setting) {
throw new Error("Setting '" + settingName + "' does not appear to be a setting."); throw new Error("Setting '" + settingName + "' does not appear to be a setting.");
} }
@ -272,13 +292,22 @@ export default class SettingsStore {
throw new Error("Setting " + settingName + " does not have a handler for " + level); throw new Error("Setting " + settingName + " does not have a handler for " + level);
} }
if (setting.invertedSettingName) {
// Note: We can't do this when the `level` is "default", however we also
// know that the user can't possible change the default value through this
// function so we don't bother checking it.
//console.warn(`Inverting ${settingName} to be ${setting.invertedSettingName} - legacy setting`);
settingName = setting.invertedSettingName;
value = !value;
}
if (!handler.canSetValue(settingName, roomId)) { if (!handler.canSetValue(settingName, roomId)) {
throw new Error("User cannot set " + settingName + " at " + level + " in " + roomId); throw new Error("User cannot set " + settingName + " at " + level + " in " + roomId);
} }
await handler.setValue(settingName, roomId, value); await handler.setValue(settingName, roomId, value);
const controller = SETTINGS[settingName].controller; const controller = setting.controller;
if (controller) { if (controller) {
controller.onChange(level, roomId, value); controller.onChange(level, roomId, value);
} }
@ -316,6 +345,101 @@ export default class SettingsStore {
return LEVEL_HANDLERS[level].isSupported(); return LEVEL_HANDLERS[level].isSupported();
} }
/**
* Debugging function for reading explicit setting values without going through the
* complicated/biased functions in the SettingsStore. This will print information to
* the console for analysis. Not intended to be used within the application.
* @param {string} realSettingName The setting name to try and read.
* @param {string} roomId Optional room ID to test the setting in.
*/
static debugSetting(realSettingName, roomId) {
console.log(`--- DEBUG ${realSettingName}`);
// Note: we intentionally use JSON.stringify here to avoid the console masking the
// problem if there's a type representation issue. Also, this way it is guaranteed
// to show up in a rageshake if required.
const def = SETTINGS[realSettingName];
console.log(`--- definition: ${def ? JSON.stringify(def) : '<NOT_FOUND>'}`);
console.log(`--- default level order: ${JSON.stringify(LEVEL_ORDER)}`);
console.log(`--- registered handlers: ${JSON.stringify(Object.keys(LEVEL_HANDLERS))}`);
const doChecks = (settingName) => {
for (const handlerName of Object.keys(LEVEL_HANDLERS)) {
const handler = LEVEL_HANDLERS[handlerName];
try {
const value = handler.getValue(settingName, roomId);
console.log(`--- ${handlerName}@${roomId || '<no_room>'} = ${JSON.stringify(value)}`);
} catch (e) {
console.log(`--- ${handler}@${roomId || '<no_room>'} THREW ERROR: ${e.message}`);
console.error(e);
}
if (roomId) {
try {
const value = handler.getValue(settingName, null);
console.log(`--- ${handlerName}@<no_room> = ${JSON.stringify(value)}`);
} catch (e) {
console.log(`--- ${handler}@<no_room> THREW ERROR: ${e.message}`);
console.error(e);
}
}
}
console.log(`--- calculating as returned by SettingsStore`);
console.log(`--- these might not match if the setting uses a controller - be warned!`);
try {
const value = SettingsStore.getValue(settingName, roomId);
console.log(`--- SettingsStore#generic@${roomId || '<no_room>'} = ${JSON.stringify(value)}`);
} catch (e) {
console.log(`--- SettingsStore#generic@${roomId || '<no_room>'} THREW ERROR: ${e.message}`);
console.error(e);
}
if (roomId) {
try {
const value = SettingsStore.getValue(settingName, null);
console.log(`--- SettingsStore#generic@<no_room> = ${JSON.stringify(value)}`);
} catch (e) {
console.log(`--- SettingsStore#generic@$<no_room> THREW ERROR: ${e.message}`);
console.error(e);
}
}
for (const level of LEVEL_ORDER) {
try {
const value = SettingsStore.getValueAt(level, settingName, roomId);
console.log(`--- SettingsStore#${level}@${roomId || '<no_room>'} = ${JSON.stringify(value)}`);
} catch (e) {
console.log(`--- SettingsStore#${level}@${roomId || '<no_room>'} THREW ERROR: ${e.message}`);
console.error(e);
}
if (roomId) {
try {
const value = SettingsStore.getValueAt(level, settingName, null);
console.log(`--- SettingsStore#${level}@<no_room> = ${JSON.stringify(value)}`);
} catch (e) {
console.log(`--- SettingsStore#${level}@$<no_room> THREW ERROR: ${e.message}`);
console.error(e);
}
}
}
};
doChecks(realSettingName);
if (def.invertedSettingName) {
console.log(`--- TESTING INVERTED SETTING NAME`);
console.log(`--- inverted: ${def.invertedSettingName}`);
doChecks(def.invertedSettingName);
}
console.log(`--- END DEBUG`);
}
static _getHandler(settingName, level) { static _getHandler(settingName, level) {
const handlers = SettingsStore._getHandlers(settingName); const handlers = SettingsStore._getHandlers(settingName);
if (!handlers[level]) return null; if (!handlers[level]) return null;
@ -355,3 +479,6 @@ export default class SettingsStore {
return featureState; return featureState;
} }
} }
// For debugging purposes
global.mxSettingsStore = SettingsStore;

View file

@ -24,14 +24,20 @@ export default class DefaultSettingsHandler extends SettingsHandler {
/** /**
* Creates a new default settings handler with the given defaults * Creates a new default settings handler with the given defaults
* @param {object} defaults The default setting values, keyed by setting name. * @param {object} defaults The default setting values, keyed by setting name.
* @param {object} invertedDefaults The default inverted setting values, keyed by setting name.
*/ */
constructor(defaults) { constructor(defaults, invertedDefaults) {
super(); super();
this._defaults = defaults; this._defaults = defaults;
this._invertedDefaults = invertedDefaults;
} }
getValue(settingName, roomId) { getValue(settingName, roomId) {
return this._defaults[settingName]; let value = this._defaults[settingName];
if (value === undefined) {
value = this._invertedDefaults[settingName];
}
return value;
} }
setValue(settingName, roomId, newValue) { setValue(settingName, roomId, newValue) {

View file

@ -44,14 +44,14 @@ export default function shouldHideEvent(ev) {
const isEnabled = (name) => SettingsStore.getValue(name, ev.getRoomId()); const isEnabled = (name) => SettingsStore.getValue(name, ev.getRoomId());
// Hide redacted events // Hide redacted events
if (ev.isRedacted() && isEnabled('hideRedactions')) return true; if (ev.isRedacted() && !isEnabled('showRedactions')) return true;
const eventDiff = memberEventDiff(ev); const eventDiff = memberEventDiff(ev);
if (eventDiff.isMemberEvent) { if (eventDiff.isMemberEvent) {
if ((eventDiff.isJoin || eventDiff.isPart) && isEnabled('hideJoinLeaves')) return true; if ((eventDiff.isJoin || eventDiff.isPart) && !isEnabled('showJoinLeaves')) return true;
if (eventDiff.isAvatarChange && isEnabled('hideAvatarChanges')) return true; if (eventDiff.isAvatarChange && !isEnabled('showAvatarChanges')) return true;
if (eventDiff.isDisplaynameChange && isEnabled('hideDisplaynameChanges')) return true; if (eventDiff.isDisplaynameChange && !isEnabled('showDisplaynameChanges')) return true;
} }
return false; return false;