diff --git a/src/RichText.js b/src/RichText.js index 4bc3815d25..b61ba0b9a4 100644 --- a/src/RichText.js +++ b/src/RichText.js @@ -67,8 +67,14 @@ function unicodeToEmojiUri(str) { // if the unicodeChar doesnt exist just return the entire match return unicodeChar; } else { + // Remove variant selector VS16 (explicitly emoji) as it is unnecessary and leads to an incorrect URL below + if(unicodeChar.length == 2 && unicodeChar[1] == '\ufe0f') { + unicodeChar = unicodeChar[0]; + } + // get the unicode codepoint from the actual char unicode = emojione.jsEscapeMap[unicodeChar]; + return emojione.imagePathSVG+unicode+'.svg'+emojione.cacheBustParam; } }); diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index 9b7554bda2..050e28e5b7 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2017 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. @@ -17,33 +18,42 @@ limitations under the License. import Promise from 'bluebird'; import MatrixClientPeg from './MatrixClientPeg'; import Notifier from './Notifier'; -import { _t } from './languageHandler'; +import { _t, _td } from './languageHandler'; +import SdkConfig from './SdkConfig'; /* * TODO: Make things use this. This is all WIP - see UserSettings.js for usage. */ +const FEATURES = [ + { + id: 'feature_groups', + name: _td("Groups"), + }, +]; + export default { - LABS_FEATURES: [ - { - name: "-", - id: 'matrix_apps', - default: true, + getLabsFeatures() { + const featuresConfig = SdkConfig.get()['features'] || {}; - // XXX: Always use default, ignore localStorage and remove from labs - override: true, - }, - { - name: "-", - id: 'feature_groups', - default: false, - }, - ], + return FEATURES.filter((f) => { + const sdkConfigValue = featuresConfig[f.id]; + if (!['enable', 'disable'].includes(sdkConfigValue)) { + return true; + } + }).map((f) => { + return f.id; + }); + }, - // horrible but it works. The locality makes this somewhat more palatable. - doTranslations: function() { - this.LABS_FEATURES[0].name = _t("Matrix Apps"); - this.LABS_FEATURES[1].name = _t("Groups"); + translatedNameForFeature(featureId) { + const feature = FEATURES.filter((f) => { + return f.id === featureId; + })[0]; + + if (feature === undefined) return null; + + return _t(feature.name); }, loadProfileInfo: function() { @@ -180,33 +190,30 @@ export default { localStorage.setItem('mx_local_settings', JSON.stringify(settings)); }, - getFeatureById(feature: string) { - for (let i = 0; i < this.LABS_FEATURES.length; i++) { - const f = this.LABS_FEATURES[i]; - if (f.id === feature) { - return f; - } - } - return null; - }, - isFeatureEnabled: function(featureId: string): boolean { - // Disable labs for guests. - if (MatrixClientPeg.get().isGuest()) return false; + const featuresConfig = SdkConfig.get()['features']; - const feature = this.getFeatureById(featureId); - if (!feature) { - console.warn(`Unknown feature "${featureId}"`); + let sdkConfigValue = 'labs'; + if (featuresConfig && featuresConfig[featureId] !== undefined) { + sdkConfigValue = featuresConfig[featureId]; + } + + if (sdkConfigValue === 'enable') { + return true; + } else if (sdkConfigValue === 'disable') { + return false; + } else if (sdkConfigValue === 'labs') { + if (!MatrixClientPeg.get().isGuest()) { + // Make it explicit that guests get the defaults (although they shouldn't + // have been able to ever toggle the flags anyway) + const userValue = localStorage.getItem(`mx_labs_feature_${featureId}`); + return userValue === 'true'; + } + return false; + } else { + console.warn(`Unknown features config for ${featureId}: ${sdkConfigValue}`); return false; } - // Return the default if this feature has an override to be the default value or - // if the feature has never been toggled and is therefore not in localStorage - if (Object.keys(feature).includes('override') || - localStorage.getItem(`mx_labs_feature_${featureId}`) === null - ) { - return feature.default; - } - return localStorage.getItem(`mx_labs_feature_${featureId}`) === 'true'; }, setFeatureEnabled: function(featureId: string, enabled: boolean) { diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 49522747cd..7e6fc05599 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -1,6 +1,7 @@ /* Copyright 2015, 2016 OpenMarket Ltd Copyright 2017 Vector Creations Ltd +Copyright 2017 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. @@ -250,7 +251,6 @@ export default React.createClass({ page_element = ; diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 04d43e1f44..3d3537e067 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -117,6 +117,7 @@ module.exports = React.createClass({ guestsCanJoin: false, canPeek: false, showApps: false, + isPeeking: false, // error object, as from the matrix client/server API // If we failed to load information about the room, @@ -266,6 +267,7 @@ module.exports = React.createClass({ console.log("Attempting to peek into room %s", roomId); this.setState({ peekLoading: true, + isPeeking: true, // this will change to false if peeking fails }); MatrixClientPeg.get().peekInRoom(roomId).then((room) => { this.setState({ @@ -274,6 +276,11 @@ module.exports = React.createClass({ }); this._onRoomLoaded(room); }, (err) => { + // Stop peeking if anything went wrong + this.setState({ + isPeeking: false, + }); + // This won't necessarily be a MatrixError, but we duck-type // here and say if it's got an 'errcode' key with the right value, // it means we can't peek. @@ -290,6 +297,7 @@ module.exports = React.createClass({ } else if (room) { // Stop peeking because we have joined this room previously MatrixClientPeg.get().stopPeeking(); + this.setState({isPeeking: false}); } }, @@ -735,6 +743,17 @@ module.exports = React.createClass({ _getUnsentMessageError: function(room) { const unsentMessages = this._getUnsentMessages(room); if (!unsentMessages.length) return ""; + + if ( + unsentMessages.length === 1 && + unsentMessages[0].error && + unsentMessages[0].error.data && + unsentMessages[0].error.data.error && + unsentMessages[0].error.name !== "UnknownDeviceError" + ) { + return unsentMessages[0].error.data.error; + } + for (const event of unsentMessages) { if (!event.error || event.error.name !== "UnknownDeviceError") { return _t("Some of your messages have not been sent."); @@ -1717,8 +1736,8 @@ module.exports = React.createClass({