diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index 9bb1388e76..305994aa0e 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -112,4 +112,12 @@ module.exports = { append: true, // We always append for email pushers since we don't want to stop other accounts notifying to the same email address }); }, + + isFeatureEnabled: function(feature: string): boolean { + return localStorage.getItem(`mx_labs_feature_${feature}`) === 'true'; + }, + + setFeatureEnabled: function(feature: string, enabled: boolean) { + localStorage.setItem(`mx_labs_feature_${feature}`, enabled); + } }; diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 39deb57d8c..b70c89e2d8 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -392,6 +392,10 @@ module.exports = React.createClass({ }); break; case 'view_room': + // Takes both room ID and room alias: if switching to a room the client is already + // know to be in (eg. user clicks on a room in the recents panel), supply only the + // ID. If the user is clicking on a room in the context of the alias being presented + // to them, supply the room alias and optionally the room ID. this._viewRoom( payload.room_id, payload.room_alias, payload.show_settings, payload.event_id, payload.third_party_invite, payload.oob_data @@ -423,42 +427,6 @@ module.exports = React.createClass({ this._viewRoom(allRooms[roomIndex].roomId); } break; - case 'view_room_alias': - if (!this.state.logged_in) { - this.starting_room_alias_payload = payload; - // Login is the default screen, so we'd do this anyway, - // but this will set the URL bar appropriately. - dis.dispatch({ action: 'start_login' }); - return; - } - - var foundRoom = MatrixTools.getRoomForAlias( - MatrixClientPeg.get().getRooms(), payload.room_alias - ); - if (foundRoom) { - dis.dispatch({ - action: 'view_room', - room_id: foundRoom.roomId, - room_alias: payload.room_alias, - event_id: payload.event_id, - third_party_invite: payload.third_party_invite, - oob_data: payload.oob_data, - }); - return; - } - // resolve the alias and *then* view it - MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias).done( - function(result) { - dis.dispatch({ - action: 'view_room', - room_id: result.room_id, - room_alias: payload.room_alias, - event_id: payload.event_id, - third_party_invite: payload.third_party_invite, - oob_data: payload.oob_data, - }); - }); - break; case 'view_user_settings': this._setPage(this.PageTypes.UserSettings); this.notifyNewScreen('settings'); @@ -532,8 +500,6 @@ module.exports = React.createClass({ this.focusComposer = true; var newState = { - currentRoom: roomId, - currentRoomAlias: roomAlias, initialEventId: eventId, highlightedEventId: eventId, initialEventPixelOffset: undefined, @@ -542,6 +508,18 @@ module.exports = React.createClass({ roomOobData: oob_data, }; + // If an alias has been provided, we use that and only that, + // since otherwise we'll prefer to pass in an ID to RoomView + // but if we're not in the room, we should join by alias rather + // than ID. + if (roomAlias) { + newState.currentRoomAlias = roomAlias; + newState.currentRoom = null; + } else { + newState.currentRoomAlias = null; + newState.currentRoom = roomId; + } + // if we aren't given an explicit event id, look for one in the // scrollStateMap. if (!eventId) { @@ -818,22 +796,28 @@ module.exports = React.createClass({ inviterName: params.inviter_name, }; + var payload = { + action: 'view_room', + event_id: eventId, + third_party_invite: third_party_invite, + oob_data: oob_data, + }; if (roomString[0] == '#') { - dis.dispatch({ - action: 'view_room_alias', - room_alias: roomString, - event_id: eventId, - third_party_invite: third_party_invite, - oob_data: oob_data, - }); + payload.room_alias = roomString; } else { - dis.dispatch({ - action: 'view_room', - room_id: roomString, - event_id: eventId, - third_party_invite: third_party_invite, - oob_data: oob_data, - }); + payload.room_id = roomString; + } + + // we can't view a room unless we're logged in + // (a guest account is fine) + if (!this.state.logged_in) { + this.starting_room_alias_payload = payload; + // Login is the default screen, so we'd do this anyway, + // but this will set the URL bar appropriately. + dis.dispatch({ action: 'start_login' }); + return; + } else { + dis.dispatch(payload); } } else { @@ -849,7 +833,7 @@ module.exports = React.createClass({ onAliasClick: function(event, alias) { event.preventDefault(); - dis.dispatch({action: 'view_room_alias', room_alias: alias}); + dis.dispatch({action: 'view_room', room_alias: alias}); }, onUserClick: function(event, userId) { @@ -1044,7 +1028,7 @@ module.exports = React.createClass({ oobData={this.state.roomOobData} highlightedEventId={this.state.highlightedEventId} eventPixelOffset={this.state.initialEventPixelOffset} - key={this.state.currentRoom} + key={this.state.currentRoom || this.state.currentRoomAlias} opacity={this.state.middleOpacity} ConferenceHandler={this.props.ConferenceHandler} /> ); diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 77080b5a75..9fc335236c 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -39,6 +39,7 @@ var dis = require("../../dispatcher"); var Tinter = require("../../Tinter"); var rate_limited_func = require('../../ratelimitedfunc'); var ObjectUtils = require('../../ObjectUtils'); +var MatrixTools = require('../../MatrixTools'); var DEBUG = false; @@ -55,13 +56,6 @@ module.exports = React.createClass({ ConferenceHandler: React.PropTypes.any, // the ID for this room (or, if we don't know it, an alias for it) - // - // XXX: if this is an alias, we will display a 'join' dialogue, - // regardless of whether we are already a member, or if the room is - // peekable. Currently there is a big mess, where at least four - // different components (RoomView, MatrixChat, RoomDirectory, - // SlashCommands) have logic for turning aliases into rooms, and each - // of them do it differently and have different edge cases. roomAddress: React.PropTypes.string.isRequired, // An object representing a third party invite to join this room @@ -100,7 +94,14 @@ module.exports = React.createClass({ }, getInitialState: function() { - var room = MatrixClientPeg.get().getRoom(this.props.roomAddress); + var room; + if (this.props.roomAddress[0] == '!') { + room = MatrixClientPeg.get().getRoom(this.props.roomAddress); + } else { + room = MatrixTools.getRoomForAlias( + MatrixClientPeg.get().getRooms(), this.props.roomAddress + ); + } return { room: room, roomLoading: !room, diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 635f9c5413..a320a02da8 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -26,6 +26,17 @@ var GeminiScrollbar = require('react-gemini-scrollbar'); var Email = require('../../email'); var AddThreepid = require('../../AddThreepid'); +const LABS_FEATURES = [ + { + name: 'Rich Text Editor', + id: 'rich_text_editor' + }, + { + name: 'End-to-End Encryption', + id: 'e2e_encryption' + } +]; + module.exports = React.createClass({ displayName: 'UserSettings', @@ -357,6 +368,30 @@ module.exports = React.createClass({ ); } + this._renderLabs = function () { + let features = LABS_FEATURES.map(feature => ( +
+ UserSettingsStore.setFeatureEnabled(feature.id, e.target.checked)} /> + +
+ )); + return ( +
+

Labs

+ +
+

These are experimental features that may break in unexpected ways. Use with caution.

+ {features} +
+
+ ) + }; + return (
@@ -411,6 +446,8 @@ module.exports = React.createClass({ {this._renderDeviceInfo()} + {this._renderLabs()} +

Advanced