From f85a37c667713803bd0eee133d8127c48d139f8b Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 3 Nov 2016 18:42:26 +0000 Subject: [PATCH] Factor out LoggedInView from MatrixChat The idea here is to make a layer which sits around for as long as we have a valid MatrixClient. Also it makes a plausible split for the render of MatrixChat, even if they are much too tightly bound for now. --- src/PageTypes.js | 24 +++ src/component-index.js | 2 + src/components/structures/LoggedInView.js | 240 ++++++++++++++++++++++ src/components/structures/MatrixChat.js | 225 +++----------------- 4 files changed, 292 insertions(+), 199 deletions(-) create mode 100644 src/PageTypes.js create mode 100644 src/components/structures/LoggedInView.js diff --git a/src/PageTypes.js b/src/PageTypes.js new file mode 100644 index 0000000000..b2e2ecf4bc --- /dev/null +++ b/src/PageTypes.js @@ -0,0 +1,24 @@ +/* +Copyright 2015, 2016 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/** The types of page which can be shown by the LoggedInView */ +export default { + RoomView: "room_view", + UserSettings: "user_settings", + CreateRoom: "create_room", + RoomDirectory: "room_directory", + UserView: "user_view", +}; diff --git a/src/component-index.js b/src/component-index.js index 8fbf655879..50a02e0862 100644 --- a/src/component-index.js +++ b/src/component-index.js @@ -31,6 +31,8 @@ import structures$CreateRoom from './components/structures/CreateRoom'; structures$CreateRoom && (module.exports.components['structures.CreateRoom'] = structures$CreateRoom); import structures$FilePanel from './components/structures/FilePanel'; structures$FilePanel && (module.exports.components['structures.FilePanel'] = structures$FilePanel); +import structures$LoggedInView from './components/structures/LoggedInView'; +structures$LoggedInView && (module.exports.components['structures.LoggedInView'] = structures$LoggedInView); import structures$MatrixChat from './components/structures/MatrixChat'; structures$MatrixChat && (module.exports.components['structures.MatrixChat'] = structures$MatrixChat); import structures$MessagePanel from './components/structures/MessagePanel'; diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js new file mode 100644 index 0000000000..739b74c6bf --- /dev/null +++ b/src/components/structures/LoggedInView.js @@ -0,0 +1,240 @@ +/* +Copyright 2015, 2016 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import * as Matrix from 'matrix-js-sdk'; +import React from 'react'; + +import KeyCode from '../../KeyCode'; +import Notifier from '../../Notifier'; +import PageTypes from '../../PageTypes'; +import sdk from '../../index'; + +/** + * This is what our MatrixChat shows when we are logged in. The precise view is + * determined by the page_type property. + * + * Currently it's very tightly coupled with MatrixChat. We should try to do + * something about that. + */ +export default React.createClass({ + displayName: 'LoggedInView', + + propTypes: { + matrixClient: React.PropTypes.instanceOf(Matrix.MatrixClient).isRequired, + page_type: React.PropTypes.string.isRequired, + onRoomIdResolved: React.PropTypes.func, + onRoomCreated: React.PropTypes.func, + onUserSettingsClose: React.PropTypes.func, + + // and lots and lots of other stuff. + }, + + componentWillMount: function() { + // _scrollStateMap is a map from room id to the scroll state returned by + // RoomView.getScrollState() + this._scrollStateMap = {}; + + document.addEventListener('keydown', this._onKeyDown); + }, + + componentWillUnmount: function() { + document.removeEventListener('keydown', this._onKeyDown); + }, + + componentWillReceiveProps: function(nextProps) { + if (nextProps.page_type !== this.props.page_type || + nextProps.currentRoomAlias !== this.props.currentRoomAlias || + nextProps.currentRoomId !== this.props.currentRoomId + ) { + + // stash the scroll state before we change view + this._updateScrollMap(); + } + }, + + getScrollStateForRoom: function(roomId) { + return this._scrollStateMap[roomId]; + }, + + // update scrollStateMap according to the current scroll state of the + // room view. + _updateScrollMap: function() { + if (!this.refs.roomView) { + return; + } + var roomview = this.refs.roomView; + var roomId = this.refs.roomView.getRoomId(); + if (!roomId) { + return; + } + var state = roomview.getScrollState(); + this._scrollStateMap[roomId] = state; + }, + + _onKeyDown: function(ev) { + /* + // Remove this for now as ctrl+alt = alt-gr so this breaks keyboards which rely on alt-gr for numbers + // Will need to find a better meta key if anyone actually cares about using this. + if (ev.altKey && ev.ctrlKey && ev.keyCode > 48 && ev.keyCode < 58) { + dis.dispatch({ + action: 'view_indexed_room', + roomIndex: ev.keyCode - 49, + }); + ev.stopPropagation(); + ev.preventDefault(); + return; + } + */ + + var handled = false; + + switch (ev.keyCode) { + case KeyCode.UP: + case KeyCode.DOWN: + if (ev.altKey) { + var action = ev.keyCode == KeyCode.UP ? + 'view_prev_room' : 'view_next_room'; + dis.dispatch({action: action}); + handled = true; + } + break; + + case KeyCode.PAGE_UP: + case KeyCode.PAGE_DOWN: + this._onScrollKeyPressed(ev); + handled = true; + break; + + case KeyCode.HOME: + case KeyCode.END: + if (ev.ctrlKey) { + this._onScrollKeyPressed(ev); + handled = true; + } + break; + } + + if (handled) { + ev.stopPropagation(); + ev.preventDefault(); + } + }, + + /** dispatch a page-up/page-down/etc to the appropriate component */ + _onScrollKeyPressed: function(ev) { + if (this.refs.roomView) { + this.refs.roomView.handleScrollKey(ev); + } + }, + + render: function() { + var LeftPanel = sdk.getComponent('structures.LeftPanel'); + var RightPanel = sdk.getComponent('structures.RightPanel'); + var RoomView = sdk.getComponent('structures.RoomView'); + var UserSettings = sdk.getComponent('structures.UserSettings'); + var CreateRoom = sdk.getComponent('structures.CreateRoom'); + var RoomDirectory = sdk.getComponent('structures.RoomDirectory'); + var MatrixToolbar = sdk.getComponent('globals.MatrixToolbar'); + var GuestWarningBar = sdk.getComponent('globals.GuestWarningBar'); + var NewVersionBar = sdk.getComponent('globals.NewVersionBar'); + + var page_element; + var right_panel = ''; + + switch (this.props.page_type) { + case PageTypes.RoomView: + page_element = + if (!this.props.collapse_rhs) right_panel = + break; + + case PageTypes.UserSettings: + page_element = + if (!this.props.collapse_rhs) right_panel = + break; + + case PageTypes.CreateRoom: + page_element = + if (!this.props.collapse_rhs) right_panel = + break; + + case PageTypes.RoomDirectory: + page_element = + if (!this.props.collapse_rhs) right_panel = + break; + case PageTypes.UserView: + page_element = null; // deliberately null for now + right_panel = + break; + } + + var topBar; + if (this.props.hasNewVersion) { + topBar = ; + } + else if (this.props.matrixClient.isGuest()) { + topBar = ; + } + else if (Notifier.supportsDesktopNotifications() && !Notifier.isEnabled() && !Notifier.isToolbarHidden()) { + topBar = ; + } + + var bodyClasses = 'mx_MatrixChat'; + if (topBar) { + bodyClasses += ' mx_MatrixChat_toolbarShowing'; + } + + return ( +
+ {topBar} +
+ +
+ {page_element} +
+ {right_panel} +
+
+ ); + }, +}); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 8582b85d12..e31bb201de 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -22,7 +22,6 @@ var Matrix = require("matrix-js-sdk"); var MatrixClientPeg = require("../../MatrixClientPeg"); var PlatformPeg = require("../../PlatformPeg"); var SdkConfig = require("../../SdkConfig"); -var Notifier = require("../../Notifier"); var ContextualMenu = require("./ContextualMenu"); var RoomListSorter = require("../../RoomListSorter"); var UserActivity = require("../../UserActivity"); @@ -38,8 +37,8 @@ var Tinter = require("../../Tinter"); var sdk = require('../../index'); var Rooms = require('../../Rooms'); var linkifyMatrix = require("../../linkify-matrix"); -var KeyCode = require('../../KeyCode'); var Lifecycle = require('../../Lifecycle'); +var PageTypes = require('../../PageTypes'); var createRoom = require("../../createRoom"); @@ -67,14 +66,6 @@ module.exports = React.createClass({ defaultDeviceDisplayName: React.PropTypes.string, }, - PageTypes: { - RoomView: "room_view", - UserSettings: "user_settings", - CreateRoom: "create_room", - RoomDirectory: "room_directory", - UserView: "user_view", - }, - AuxPanel: { RoomSettings: "room_settings", }, @@ -192,10 +183,6 @@ module.exports = React.createClass({ this.dispatcherRef = dis.register(this.onAction); this.focusComposer = false; - // scrollStateMap is a map from room id to the scroll state returned by - // RoomView.getScrollState() - this.scrollStateMap = {}; - document.addEventListener("keydown", this.onKeyDown); window.addEventListener("focus", this.onFocus); // this can technically be done anywhere but doing this here keeps all @@ -234,7 +221,6 @@ module.exports = React.createClass({ componentWillUnmount: function() { Lifecycle.stopMatrixClient(); dis.unregister(this.dispatcherRef); - document.removeEventListener("keydown", this.onKeyDown); window.removeEventListener("focus", this.onFocus); window.removeEventListener('resize', this.handleResize); }, @@ -399,11 +385,11 @@ module.exports = React.createClass({ } break; case 'view_user_settings': - this._setPage(this.PageTypes.UserSettings); + this._setPage(PageTypes.UserSettings); this.notifyNewScreen('settings'); break; case 'view_create_room': - //this._setPage(this.PageTypes.CreateRoom); + //this._setPage(PageTypes.CreateRoom); //this.notifyNewScreen('new'); var TextInputDialog = sdk.getComponent("dialogs.TextInputDialog"); @@ -421,7 +407,7 @@ module.exports = React.createClass({ }); break; case 'view_room_directory': - this._setPage(this.PageTypes.RoomDirectory); + this._setPage(PageTypes.RoomDirectory); this.notifyNewScreen('directory'); break; case 'view_create_chat': @@ -481,9 +467,6 @@ module.exports = React.createClass({ }, _setPage: function(pageType) { - // record the scroll state if we're in a room view. - this._updateScrollMap(); - this.setState({ page_type: pageType, }); @@ -506,16 +489,13 @@ module.exports = React.createClass({ // that has been passed out-of-band (eg. // room name and avatar from an invite email) _viewRoom: function(room_info) { - // before we switch room, record the scroll state of the current room - this._updateScrollMap(); - this.focusComposer = true; var newState = { initialEventId: room_info.event_id, highlightedEventId: room_info.event_id, initialEventPixelOffset: undefined, - page_type: this.PageTypes.RoomView, + page_type: PageTypes.RoomView, thirdPartyInvite: room_info.third_party_invite, roomOobData: room_info.oob_data, currentRoomAlias: room_info.room_alias, @@ -528,8 +508,8 @@ module.exports = React.createClass({ // if we aren't given an explicit event id, look for one in the // scrollStateMap. - if (!room_info.event_id) { - var scrollState = this.scrollStateMap[room_info.room_id]; + if (!room_info.event_id && this.refs.loggedInView) { + var scrollState = this.refs.loggedInView.getScrollStateForRoom(room_info.room_id); if (scrollState) { newState.initialEventId = scrollState.focussedEvent; newState.initialEventPixelOffset = scrollState.pixelOffset; @@ -566,10 +546,6 @@ module.exports = React.createClass({ newState.ready = true; } this.setState(newState); - - if (this.refs.roomView && room_info.showSettings) { - this.refs.roomView.showSettings(true); - } }, _createChat: function() { @@ -589,21 +565,6 @@ module.exports = React.createClass({ }); }, - // update scrollStateMap according to the current scroll state of the - // room view. - _updateScrollMap: function() { - if (!this.refs.roomView) { - return; - } - var roomview = this.refs.roomView; - var roomId = this.refs.roomView.getRoomId(); - if (!roomId) { - return; - } - var state = roomview.getScrollState(); - this.scrollStateMap[roomId] = state; - }, - /** * Called when the sessionloader has finished */ @@ -664,12 +625,12 @@ module.exports = React.createClass({ firstRoom = RoomListSorter.mostRecentActivityFirst( cli.getRooms() )[0].roomId; - self.setState({ready: true, currentRoomId: firstRoom, page_type: self.PageTypes.RoomView}); + self.setState({ready: true, currentRoomId: firstRoom, page_type: PageTypes.RoomView}); } else { - self.setState({ready: true, page_type: self.PageTypes.RoomDirectory}); + self.setState({ready: true, page_type: PageTypes.RoomDirectory}); } } else { - self.setState({ready: true, page_type: self.PageTypes.RoomView}); + self.setState({ready: true, page_type: PageTypes.RoomView}); } // we notifyNewScreen now because now the room will actually be displayed, @@ -712,62 +673,6 @@ module.exports = React.createClass({ }); }, - onKeyDown: function(ev) { - /* - // Remove this for now as ctrl+alt = alt-gr so this breaks keyboards which rely on alt-gr for numbers - // Will need to find a better meta key if anyone actually cares about using this. - if (ev.altKey && ev.ctrlKey && ev.keyCode > 48 && ev.keyCode < 58) { - dis.dispatch({ - action: 'view_indexed_room', - roomIndex: ev.keyCode - 49, - }); - ev.stopPropagation(); - ev.preventDefault(); - return; - } - */ - - var handled = false; - - switch (ev.keyCode) { - case KeyCode.UP: - case KeyCode.DOWN: - if (ev.altKey) { - var action = ev.keyCode == KeyCode.UP ? - 'view_prev_room' : 'view_next_room'; - dis.dispatch({action: action}); - handled = true; - } - break; - - case KeyCode.PAGE_UP: - case KeyCode.PAGE_DOWN: - this._onScrollKeyPressed(ev); - handled = true; - break; - - case KeyCode.HOME: - case KeyCode.END: - if (ev.ctrlKey) { - this._onScrollKeyPressed(ev); - handled = true; - } - break; - } - - if (handled) { - ev.stopPropagation(); - ev.preventDefault(); - } - }, - - /** dispatch a page-up/page-down/etc to the appropriate component */ - _onScrollKeyPressed(ev) { - if (this.refs.roomView) { - this.refs.roomView.handleScrollKey(ev); - } - }, - onFocus: function(ev) { dis.dispatch({action: 'focus_composer'}); }, @@ -845,7 +750,7 @@ module.exports = React.createClass({ } else if (screen.indexOf('user/') == 0) { var userId = screen.substring(5); this.setState({ viewUserId: userId }); - this._setPage(this.PageTypes.UserView); + this._setPage(PageTypes.UserView); this.notifyNewScreen('user/' + userId); var member = new Matrix.RoomMember(null, userId); if (member) { @@ -958,7 +863,7 @@ module.exports = React.createClass({ // the page type still unset when the MatrixClient // is started and show the Room Directory instead. //this.showScreen("view_user_settings"); - this._setPage(this.PageTypes.UserSettings); + this._setPage(PageTypes.UserSettings); }, onFinishPostRegistration: function() { @@ -1025,16 +930,8 @@ module.exports = React.createClass({ }, render: function() { - var LeftPanel = sdk.getComponent('structures.LeftPanel'); - var RoomView = sdk.getComponent('structures.RoomView'); - var RightPanel = sdk.getComponent('structures.RightPanel'); - var UserSettings = sdk.getComponent('structures.UserSettings'); - var CreateRoom = sdk.getComponent('structures.CreateRoom'); - var RoomDirectory = sdk.getComponent('structures.RoomDirectory'); - var MatrixToolbar = sdk.getComponent('globals.MatrixToolbar'); - var GuestWarningBar = sdk.getComponent('globals.GuestWarningBar'); - var NewVersionBar = sdk.getComponent('globals.NewVersionBar'); var ForgotPassword = sdk.getComponent('structures.login.ForgotPassword'); + var LoggedInView = sdk.getComponent('structures.LoggedInView'); // console.log("rendering; loading="+this.state.loading+"; screen="+this.state.screen + // "; logged_in="+this.state.logged_in+"; ready="+this.state.ready); @@ -1053,90 +950,20 @@ module.exports = React.createClass({ ); - } - else if (this.state.logged_in && this.state.ready) { - var page_element; - var right_panel = ""; - - switch (this.state.page_type) { - case this.PageTypes.RoomView: - page_element = - if (!this.state.collapse_rhs) right_panel = - break; - case this.PageTypes.UserSettings: - page_element = - if (!this.state.collapse_rhs) right_panel = - break; - case this.PageTypes.CreateRoom: - page_element = - if (!this.state.collapse_rhs) right_panel = - break; - case this.PageTypes.RoomDirectory: - page_element = - if (!this.state.collapse_rhs) right_panel = - break; - case this.PageTypes.UserView: - page_element = null; // deliberately null for now - right_panel = - break; - } - - var topBar; - if (this.state.hasNewVersion) { - topBar = ; - } - else if (MatrixClientPeg.get().isGuest()) { - topBar = ; - } - else if (Notifier.supportsDesktopNotifications() && !Notifier.isEnabled() && !Notifier.isToolbarHidden()) { - topBar = ; - } - - var bodyClasses = "mx_MatrixChat"; - if (topBar) { - bodyClasses += " mx_MatrixChat_toolbarShowing"; - } - + } else if (this.state.logged_in && this.state.ready) { + /* for now, we stuff the entirety of our props and state into the LoggedInView. + * we should go through and figure out what we actually need to pass down, as well + * as using something like redux to avoid having a billion bits of state kicking around. + */ return ( -
- {topBar} -
- -
- {page_element} -
- {right_panel} -
-
- ); + + ) } else if (this.state.logged_in) { // we think we are logged in, but are still waiting for the /sync to complete var Spinner = sdk.getComponent('elements.Spinner');