diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 32762a081c..83c7fe01bb 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -891,7 +891,7 @@ module.exports = React.createClass({ */ _onSetTheme: function(theme) { if (!theme) { - theme = this.props.config.default_theme || 'light'; + theme = SettingsStore.getValueAt(SettingLevel.DEFAULT, "theme"); } // look for the stylesheet elements. diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index d88eb5c7f8..933f90523a 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -613,8 +613,7 @@ module.exports = React.createClass({ onLanguageChange: function(newLang) { if (this.state.language !== newLang) { - // We intentionally promote this to the account level at this point - SettingsStore.setValue("language", null, SettingLevel.ACCOUNT, newLang); + SettingsStore.setValue("language", null, SettingLevel.DEVICE, newLang); this.setState({ language: newLang, }); diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js index ec690f76e8..6491bb0e09 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.js +++ b/src/components/views/room_settings/UrlPreviewSettings.js @@ -17,7 +17,7 @@ limitations under the License. const React = require('react'); const sdk = require("../../../index"); -import { _t } from '../../../languageHandler'; +import { _t, _td } from '../../../languageHandler'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; @@ -63,9 +63,9 @@ module.exports = React.createClass({ ); } else { - let str = "URL previews are enabled by default for participants in this room."; + let str = _td("URL previews are enabled by default for participants in this room."); if (!SettingsStore.getValueAt(SettingLevel.ROOM, "urlPreviewsEnabled")) { - str = "URL previews are disabled by default for participants in this room."; + str = _td("URL previews are disabled by default for participants in this room."); } previewsForRoom = (); } diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index 51d12c4f76..3407ea159d 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -33,22 +33,30 @@ const ObjectUtils = require('../../../ObjectUtils'); const eventTileTypes = { 'm.room.message': 'messages.MessageEvent', - 'm.room.member': 'messages.TextualEvent', 'm.call.invite': 'messages.TextualEvent', 'm.call.answer': 'messages.TextualEvent', 'm.call.hangup': 'messages.TextualEvent', +}; + +const stateEventTileTypes = { + 'm.room.member': 'messages.TextualEvent', 'm.room.name': 'messages.TextualEvent', 'm.room.avatar': 'messages.RoomAvatarEvent', - 'm.room.topic': 'messages.TextualEvent', 'm.room.third_party_invite': 'messages.TextualEvent', 'm.room.history_visibility': 'messages.TextualEvent', 'm.room.encryption': 'messages.TextualEvent', + 'm.room.topic': 'messages.TextualEvent', 'm.room.power_levels': 'messages.TextualEvent', 'm.room.pinned_events': 'messages.TextualEvent', 'im.vector.modular.widgets': 'messages.TextualEvent', }; +function getHandlerTile(ev) { + const type = ev.getType(); + return ev.isState() ? stateEventTileTypes[type] : eventTileTypes[type]; +} + const MAX_READ_AVATARS = 5; // Our component structure for EventTiles on the timeline is: @@ -433,7 +441,7 @@ module.exports = withMatrixClient(React.createClass({ // Info messages are basically information about commands processed on a room const isInfoMessage = (eventType !== 'm.room.message'); - const EventTileType = sdk.getComponent(eventTileTypes[eventType]); + const EventTileType = sdk.getComponent(getHandlerTile(this.props.mxEvent)); // This shouldn't happen: the caller should check we support this type // before trying to instantiate us if (!EventTileType) { @@ -600,8 +608,10 @@ module.exports = withMatrixClient(React.createClass({ module.exports.haveTileForEvent = function(e) { // Only messages have a tile (black-rectangle) if redacted if (e.isRedacted() && e.getType() !== 'm.room.message') return false; - if (eventTileTypes[e.getType()] == undefined) return false; - if (eventTileTypes[e.getType()] == 'messages.TextualEvent') { + + const handler = getHandlerTile(e); + if (handler === undefined) return false; + if (handler === 'messages.TextualEvent') { return TextForEvent.textForEvent(e) !== ''; } else { return true; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 7624a60c94..128a07bc15 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -227,6 +227,8 @@ "Delete": "Delete", "Disable Notifications": "Disable Notifications", "Enable Notifications": "Enable Notifications", + "URL previews are enabled by default for participants in this room.": "URL previews are enabled by default for participants in this room.", + "URL previews are disabled by default for participants in this room.": "URL previews are disabled by default for participants in this room.", "Cannot add any more widgets": "Cannot add any more widgets", "The maximum permitted number of widgets have already been added to this room.": "The maximum permitted number of widgets have already been added to this room.", "Add a widget": "Add a widget", diff --git a/src/settings/SettingsStore.js b/src/settings/SettingsStore.js index b6343c4a96..d93a48005d 100644 --- a/src/settings/SettingsStore.js +++ b/src/settings/SettingsStore.js @@ -176,13 +176,21 @@ export default class SettingsStore { * @return {*} The value, or null if not found */ static getValue(settingName, roomId = null, excludeDefault = false) { - return SettingsStore.getValueAt(LEVEL_ORDER[0], settingName, roomId, false, excludeDefault); + // Verify that the setting is actually a setting + if (!SETTINGS[settingName]) { + throw new Error("Setting '" + settingName + "' does not appear to be a setting."); + } + + const setting = SETTINGS[settingName]; + const levelOrder = (setting.supportedLevelsAreOrdered ? setting.supportedLevels : LEVEL_ORDER); + + return SettingsStore.getValueAt(levelOrder[0], settingName, roomId, false, excludeDefault); } /** * Gets a setting's value at a particular level, ignoring all levels that are more specific. - * @param {"device"|"room-device"|"room-account"|"account"|"room"} level The level to - * look at. + * @param {"device"|"room-device"|"room-account"|"account"|"room"|"config"|"default"} level The + * level to look at. * @param {string} settingName The name of the setting to read. * @param {String} roomId The room ID to read the setting value in, may be null. * @param {boolean} explicit If true, this method will not consider other levels, just the one diff --git a/src/settings/controllers/NotificationControllers.js b/src/settings/controllers/NotificationControllers.js index 261e194d74..9dcf78e26b 100644 --- a/src/settings/controllers/NotificationControllers.js +++ b/src/settings/controllers/NotificationControllers.js @@ -15,12 +15,35 @@ limitations under the License. */ import SettingController from "./SettingController"; +import MatrixClientPeg from '../../MatrixClientPeg'; + +// XXX: This feels wrong. +import PushProcessor from "matrix-js-sdk/lib/pushprocessor"; + +function isMasterRuleEnabled() { + // Return the value of the master push rule as a default + const processor = new PushProcessor(MatrixClientPeg.get()); + const masterRule = processor.getPushRuleById(".m.rule.master"); + + if (!masterRule) { + console.warn("No master push rule! Notifications are disabled for this user."); + return false; + } + + // Why enabled == false means "enabled" is beyond me. + return !masterRule.enabled; +} export class NotificationsEnabledController extends SettingController { getValueOverride(level, roomId, calculatedValue) { const Notifier = require('../../Notifier'); // avoids cyclical references + if (!Notifier.isPossible()) return false; - return calculatedValue && Notifier.isPossible(); + if (calculatedValue === null) { + return isMasterRuleEnabled(); + } + + return calculatedValue; } onChange(level, roomId, newValue) { @@ -35,15 +58,22 @@ export class NotificationsEnabledController extends SettingController { export class NotificationBodyEnabledController extends SettingController { getValueOverride(level, roomId, calculatedValue) { const Notifier = require('../../Notifier'); // avoids cyclical references + if (!Notifier.isPossible()) return false; - return calculatedValue && Notifier.isEnabled(); + if (calculatedValue === null) { + return isMasterRuleEnabled(); + } + + return calculatedValue; } } export class AudioNotificationsEnabledController extends SettingController { getValueOverride(level, roomId, calculatedValue) { const Notifier = require('../../Notifier'); // avoids cyclical references + if (!Notifier.isPossible()) return false; - return calculatedValue && Notifier.isEnabled(); + // Note: Audio notifications are *not* enabled by default. + return calculatedValue; } } diff --git a/src/settings/handlers/AccountSettingsHandler.js b/src/settings/handlers/AccountSettingsHandler.js index fe0ad2a500..e50358a728 100644 --- a/src/settings/handlers/AccountSettingsHandler.js +++ b/src/settings/handlers/AccountSettingsHandler.js @@ -26,6 +26,9 @@ export default class AccountSettingHandler extends SettingsHandler { // Special case URL previews if (settingName === "urlPreviewsEnabled") { const content = this._getSettings("org.matrix.preview_urls"); + + // Check to make sure that we actually got a boolean + if (typeof(content['disable']) !== "boolean") return null; return !content['disable']; } diff --git a/src/settings/handlers/DeviceSettingsHandler.js b/src/settings/handlers/DeviceSettingsHandler.js index 7b5ec6a5dd..22f6140a80 100644 --- a/src/settings/handlers/DeviceSettingsHandler.js +++ b/src/settings/handlers/DeviceSettingsHandler.js @@ -40,11 +40,17 @@ export default class DeviceSettingsHandler extends SettingsHandler { // Special case notifications if (settingName === "notificationsEnabled") { - return localStorage.getItem("notifications_enabled") === "true"; + const value = localStorage.getItem("notifications_enabled"); + if (typeof(value) === "string") return value === "true"; + return null; // wrong type or otherwise not set } else if (settingName === "notificationBodyEnabled") { - return localStorage.getItem("notifications_body_enabled") === "true"; + const value = localStorage.getItem("notifications_body_enabled"); + if (typeof(value) === "string") return value === "true"; + return null; // wrong type or otherwise not set } else if (settingName === "audioNotificationsEnabled") { - return localStorage.getItem("audio_notifications_enabled") === "true"; + const value = localStorage.getItem("audio_notifications_enabled"); + if (typeof(value) === "string") return value === "true"; + return null; // wrong type or otherwise not set } return this._getSettings()[settingName]; diff --git a/src/settings/handlers/RoomAccountSettingsHandler.js b/src/settings/handlers/RoomAccountSettingsHandler.js index 503d5de6c4..e946581807 100644 --- a/src/settings/handlers/RoomAccountSettingsHandler.js +++ b/src/settings/handlers/RoomAccountSettingsHandler.js @@ -25,6 +25,9 @@ export default class RoomAccountSettingsHandler extends SettingsHandler { // Special case URL previews if (settingName === "urlPreviewsEnabled") { const content = this._getSettings(roomId, "org.matrix.room.preview_urls"); + + // Check to make sure that we actually got a boolean + if (typeof(content['disable']) !== "boolean") return null; return !content['disable']; } diff --git a/src/settings/handlers/RoomSettingsHandler.js b/src/settings/handlers/RoomSettingsHandler.js index 3aee0dd6eb..cb3e836c7f 100644 --- a/src/settings/handlers/RoomSettingsHandler.js +++ b/src/settings/handlers/RoomSettingsHandler.js @@ -25,6 +25,9 @@ export default class RoomSettingsHandler extends SettingsHandler { // Special case URL previews if (settingName === "urlPreviewsEnabled") { const content = this._getSettings(roomId, "org.matrix.room.preview_urls"); + + // Check to make sure that we actually got a boolean + if (typeof(content['disable']) !== "boolean") return null; return !content['disable']; }