From 7bd6bb6eb652c4c88a8f2d004383ab7a789260f9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Nov 2018 13:19:29 +0100 Subject: [PATCH 01/42] make MatrixDispatcher constructor public so we can create one for each open room --- src/dispatcher.js | 36 ++------------------------- src/matrix-dispatcher.js | 53 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 34 deletions(-) create mode 100644 src/matrix-dispatcher.js diff --git a/src/dispatcher.js b/src/dispatcher.js index 48c8dc86e9..4dc6e1e37d 100644 --- a/src/dispatcher.js +++ b/src/dispatcher.js @@ -17,42 +17,10 @@ limitations under the License. 'use strict'; -const flux = require("flux"); - -class MatrixDispatcher extends flux.Dispatcher { - /** - * @param {Object|function} payload Required. The payload to dispatch. - * If an Object, must contain at least an 'action' key. - * If a function, must have the signature (dispatch) => {...}. - * @param {boolean=} sync Optional. Pass true to dispatch - * synchronously. This is useful for anything triggering - * an operation that the browser requires user interaction - * for. - */ - dispatch(payload, sync) { - // Allow for asynchronous dispatching by accepting payloads that have the - // type `function (dispatch) {...}` - if (typeof payload === 'function') { - payload((action) => { - this.dispatch(action, sync); - }); - return; - } - - if (sync) { - super.dispatch(payload); - } else { - // Unless the caller explicitly asked for us to dispatch synchronously, - // we always set a timeout to do this: The flux dispatcher complains - // if you dispatch from within a dispatch, so rather than action - // handlers having to worry about not calling anything that might - // then dispatch, we just do dispatches asynchronously. - setTimeout(super.dispatch.bind(this, payload), 0); - } - } -} +import MatrixDispatcher from "./matrix-dispatcher"; if (global.mxDispatcher === undefined) { global.mxDispatcher = new MatrixDispatcher(); } + module.exports = global.mxDispatcher; diff --git a/src/matrix-dispatcher.js b/src/matrix-dispatcher.js new file mode 100644 index 0000000000..fb81ed837f --- /dev/null +++ b/src/matrix-dispatcher.js @@ -0,0 +1,53 @@ +/* +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. +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. +*/ + +'use strict'; + +const flux = require("flux"); + +export default class MatrixDispatcher extends flux.Dispatcher { + /** + * @param {Object|function} payload Required. The payload to dispatch. + * If an Object, must contain at least an 'action' key. + * If a function, must have the signature (dispatch) => {...}. + * @param {boolean=} sync Optional. Pass true to dispatch + * synchronously. This is useful for anything triggering + * an operation that the browser requires user interaction + * for. + */ + dispatch(payload, sync) { + // Allow for asynchronous dispatching by accepting payloads that have the + // type `function (dispatch) {...}` + if (typeof payload === 'function') { + payload((action) => { + this.dispatch(action, sync); + }); + return; + } + + if (sync) { + super.dispatch(payload); + } else { + // Unless the caller explicitly asked for us to dispatch synchronously, + // we always set a timeout to do this: The flux dispatcher complains + // if you dispatch from within a dispatch, so rather than action + // handlers having to worry about not calling anything that might + // then dispatch, we just do dispatches asynchronously. + setTimeout(super.dispatch.bind(this, payload), 0); + } + } +} From 869c81eb9059900d2a6ac1d99aab5a4acd407253 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Nov 2018 13:21:14 +0100 Subject: [PATCH 02/42] cram OpenRoomsStore between RoomViewStore and dispatcher the idea is that it will keep a RoomViewStore for every room on the screen, and also keep track of which one is the current one. For now, it just replicates the existing functionality of having just 1 room on the screen. Since the RoomViewStore just has access to a local dispatcher and not the global anymore, all dispatching of actions needs to be moved to the OpenRoomsStore, so room alias resolving, event forwarding, ... is moved there. --- src/stores/OpenRoomsStore.js | 166 +++++++++++++++++++++++++++++++++++ src/stores/RoomViewStore.js | 45 ++-------- 2 files changed, 174 insertions(+), 37 deletions(-) create mode 100644 src/stores/OpenRoomsStore.js diff --git a/src/stores/OpenRoomsStore.js b/src/stores/OpenRoomsStore.js new file mode 100644 index 0000000000..f82671e58d --- /dev/null +++ b/src/stores/OpenRoomsStore.js @@ -0,0 +1,166 @@ +/* +Copyright 2018 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. +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 MatrixDispatcher from '../matrix-dispatcher'; +import dis from '../dispatcher'; +import {RoomViewStore} from './RoomViewStore'; +import {Store} from 'flux/utils'; +import MatrixClientPeg from '../MatrixClientPeg'; + +/** + * A class for keeping track of the RoomViewStores of the rooms shown on the screen. + * Routes the dispatcher actions to the store of currently active room. + */ +class OpenRoomsStore extends Store { + constructor() { + super(dis); + + // Initialise state + this._state = { + room: { + store: null, + dispatcher: null + }, + }; + + this._forwardingEvent = null; + } + + getRoomStore() { + return this._state.room.store; + } + + getCurrentRoomStore() { + return this.getRoomStore(); // just one room for now + } + + _setState(newState) { + this._state = Object.assign(this._state, newState); + this.__emitChange(); + } + + _cleanupRoom() { + const room = this._state.room; + room.dispatcher.unregister(room.store.getDispatchToken()); + this._setState({ + room: { + store: null, + dispatcher: null + }, + }); + } + + _createRoom() { + const dispatcher = new MatrixDispatcher(); + this._setState({ + room: { + store: new RoomViewStore(dispatcher), + dispatcher, + }, + }); + } + + _forwardAction(payload) { + if (this._state.room.dispatcher) { + this._state.room.dispatcher.dispatch(payload, true); + } + } + + async _resolveRoomAlias(payload) { + try { + const result = await MatrixClientPeg.get() + .getRoomIdForAlias(payload.room_alias); + dis.dispatch({ + action: 'view_room', + room_id: result.room_id, + event_id: payload.event_id, + highlighted: payload.highlighted, + room_alias: payload.room_alias, + auto_join: payload.auto_join, + oob_data: payload.oob_data, + }); + } catch(err) { + this._forwardAction({ + action: 'view_room_error', + room_id: null, + room_alias: payload.room_alias, + err: err, + }); + } + } + + __onDispatch(payload) { + switch (payload.action) { + // view_room: + // - room_alias: '#somealias:matrix.org' + // - room_id: '!roomid123:matrix.org' + // - event_id: '$213456782:matrix.org' + // - event_offset: 100 + // - highlighted: true + case 'view_room': + console.log("!!! OpenRoomsStore: view_room", payload); + if (!payload.room_id && payload.room_alias) { + this._resolveRoomAlias(payload); + } + const currentStore = this.getCurrentRoomStore(); + if (currentStore && + (!payload.room_alias || payload.room_alias !== currentStore.getRoomAlias()) && + (!currentStore.getRoomId() || payload.room_id !== currentStore.getRoomId()) + ) { + console.log("OpenRoomsStore: _cleanupRoom"); + this._cleanupRoom(); + } + if (!this._state.room.store) { + console.log("OpenRoomsStore: _createRoom"); + this._createRoom(); + } + console.log("OpenRoomsStore: _forwardAction"); + this._forwardAction(payload); + if (this._forwardingEvent) { + dis.dispatch({ + action: 'send_event', + room_id: payload.room_id, + event: this._forwardingEvent, + }); + this._forwardingEvent = null; + } + break; + case 'view_my_groups': + case 'view_group': + this._forwardAction(payload); + this._cleanupRoom(); + break; + case 'will_join': + case 'cancel_join': + case 'join_room': + case 'join_room_error': + case 'on_logged_out': + case 'reply_to_event': + case 'open_room_settings': + case 'close_settings': + this._forwardAction(payload); + break; + case 'forward_event': + this._forwardingEvent = payload.event; + break; + } + } +} + +let singletonOpenRoomsStore = null; +if (!singletonOpenRoomsStore) { + singletonOpenRoomsStore = new OpenRoomsStore(); +} +module.exports = singletonOpenRoomsStore; diff --git a/src/stores/RoomViewStore.js b/src/stores/RoomViewStore.js index f15925f480..43964bc6c3 100644 --- a/src/stores/RoomViewStore.js +++ b/src/stores/RoomViewStore.js @@ -53,8 +53,8 @@ const INITIAL_STATE = { * with a subset of the js-sdk. * ``` */ -class RoomViewStore extends Store { - constructor() { +export class RoomViewStore extends Store { + constructor(dis) { super(dis); // Initialise state @@ -85,6 +85,8 @@ class RoomViewStore extends Store { }); break; case 'view_room_error': + // should not go over dispatcher anymore + // but be internal to RoomViewStore this._viewRoomError(payload); break; case 'will_join': @@ -150,22 +152,11 @@ class RoomViewStore extends Store { // pull the user out of Room Settings isEditingSettings: false, }; - - if (this._state.forwardingEvent) { - dis.dispatch({ - action: 'send_event', - room_id: newState.roomId, - event: this._state.forwardingEvent, - }); - } - this._setState(newState); - if (payload.auto_join) { this._joinRoom(payload); } } else if (payload.room_alias) { - // Resolve the alias and then do a second dispatch with the room ID acquired this._setState({ roomId: null, initialEventId: null, @@ -175,25 +166,6 @@ class RoomViewStore extends Store { roomLoading: true, roomLoadError: null, }); - MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias).done( - (result) => { - dis.dispatch({ - action: 'view_room', - room_id: result.room_id, - event_id: payload.event_id, - highlighted: payload.highlighted, - room_alias: payload.room_alias, - auto_join: payload.auto_join, - oob_data: payload.oob_data, - }); - }, (err) => { - dis.dispatch({ - action: 'view_room_error', - room_id: null, - room_alias: payload.room_alias, - err: err, - }); - }); } } @@ -330,8 +302,7 @@ class RoomViewStore extends Store { } } -let singletonRoomViewStore = null; -if (!singletonRoomViewStore) { - singletonRoomViewStore = new RoomViewStore(); -} -module.exports = singletonRoomViewStore; +const MatrixDispatcher = require("../matrix-dispatcher"); +const blubber = new RoomViewStore(new MatrixDispatcher()); + +export default blubber; From df8539d6bc59c0857fdaf8613da891558bd70445 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Nov 2018 13:24:35 +0100 Subject: [PATCH 03/42] pass the RoomViewStore down with a prop instead of global var. this will allow to have more than 1 RoomView further on --- src/components/structures/LoggedInView.js | 1 + src/components/structures/RightPanel.js | 2 +- src/components/structures/RoomView.js | 33 ++++++++++--------- src/components/views/rooms/MemberInfo.js | 4 +-- src/components/views/rooms/MessageComposer.js | 11 ++++--- .../views/rooms/MessageComposerInput.js | 6 ++-- src/components/views/rooms/ReplyPreview.js | 5 ++- 7 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 635c5de44e..b81597a901 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -429,6 +429,7 @@ const LoggedInView = React.createClass({ switch (this.props.page_type) { case PageTypes.RoomView: page_element = ; } else if (this.state.phase === RightPanel.Phase.RoomMemberInfo) { - panel = ; + panel = ; } else if (this.state.phase === RightPanel.Phase.GroupMemberInfo) { panel = { try { await cli.invite(roomId, member.userId); diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index dc927f0e0a..5ac788fb1d 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -22,7 +22,6 @@ import MatrixClientPeg from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; import sdk from '../../../index'; import dis from '../../../dispatcher'; -import RoomViewStore from '../../../stores/RoomViewStore'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import Stickerpicker from './Stickerpicker'; import { makeRoomPermalink } from '../../../matrix-to'; @@ -63,7 +62,7 @@ export default class MessageComposer extends React.Component { isRichTextEnabled: SettingsStore.getValue('MessageComposerInput.isRichTextEnabled'), }, showFormatting: SettingsStore.getValue('MessageComposer.showFormatting'), - isQuoting: Boolean(RoomViewStore.getQuotingEvent()), + isQuoting: Boolean(this.props.roomViewStore.getQuotingEvent()), tombstone: this._getRoomTombstone(), }; } @@ -75,7 +74,7 @@ export default class MessageComposer extends React.Component { // XXX: fragile as all hell - fixme somehow, perhaps with a dedicated Room.encryption event or something. MatrixClientPeg.get().on("event", this.onEvent); MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents); - this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate); + this._roomStoreToken = this.props.roomViewStore.addListener(this._onRoomViewStoreUpdate); this._waitForOwnMember(); } @@ -124,7 +123,7 @@ export default class MessageComposer extends React.Component { } _onRoomViewStoreUpdate() { - const isQuoting = Boolean(RoomViewStore.getQuotingEvent()); + const isQuoting = Boolean(this.props.roomViewStore.getQuotingEvent()); if (this.state.isQuoting === isQuoting) return; this.setState({ isQuoting }); } @@ -153,7 +152,7 @@ export default class MessageComposer extends React.Component { ); } - const isQuoting = Boolean(RoomViewStore.getQuotingEvent()); + const isQuoting = Boolean(this.props.roomViewStore.getQuotingEvent()); let replyToWarning = null; if (isQuoting) { replyToWarning =

{ @@ -357,6 +356,7 @@ export default class MessageComposer extends React.Component { controls.push( this.messageComposerInput = c} key="controls_input" onResize={this.props.onResize} @@ -461,4 +461,5 @@ MessageComposer.propTypes = { // string representing the current room app drawer state showApps: PropTypes.bool, + roomViewStore: PropTypes.object.isRequired, }; diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 14d394ab41..da41dba212 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -58,7 +58,6 @@ import {asciiRegexp, unicodeRegexp, shortnameToUnicode, emojioneList, asciiList, import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import {makeUserPermalink} from "../../../matrix-to"; import ReplyPreview from "./ReplyPreview"; -import RoomViewStore from '../../../stores/RoomViewStore'; import ReplyThread from "../elements/ReplyThread"; import {ContentHelpers} from 'matrix-js-sdk'; @@ -150,6 +149,7 @@ export default class MessageComposerInput extends React.Component { onFilesPasted: PropTypes.func, onInputStateChanged: PropTypes.func, + roomViewStore: PropTypes.object.isRequired, }; client: MatrixClient; @@ -1120,7 +1120,7 @@ export default class MessageComposerInput extends React.Component { return true; } - const replyingToEv = RoomViewStore.getQuotingEvent(); + const replyingToEv = this.props.roomViewStore.getQuotingEvent(); const mustSendHTML = Boolean(replyingToEv); if (this.state.isRichTextEnabled) { @@ -1589,7 +1589,7 @@ export default class MessageComposerInput extends React.Component { return (

- + this.autocomplete = e} room={this.props.room} diff --git a/src/components/views/rooms/ReplyPreview.js b/src/components/views/rooms/ReplyPreview.js index 46e2826634..04ff9d0778 100644 --- a/src/components/views/rooms/ReplyPreview.js +++ b/src/components/views/rooms/ReplyPreview.js @@ -18,7 +18,6 @@ import React from 'react'; import dis from '../../../dispatcher'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; -import RoomViewStore from '../../../stores/RoomViewStore'; import SettingsStore from "../../../settings/SettingsStore"; function cancelQuoting() { @@ -38,7 +37,7 @@ export default class ReplyPreview extends React.Component { this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this); - this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate); + this._roomStoreToken = this.props.roomViewStore.addListener(this._onRoomViewStoreUpdate); this._onRoomViewStoreUpdate(); } @@ -50,7 +49,7 @@ export default class ReplyPreview extends React.Component { } _onRoomViewStoreUpdate() { - const event = RoomViewStore.getQuotingEvent(); + const event = this.props.roomViewStore.getQuotingEvent(); if (this.state.event !== event) { this.setState({ event }); } From 43efa29ef8d284da1286867fb48525166196bd52 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Nov 2018 13:25:42 +0100 Subject: [PATCH 04/42] track active room with OpenRoomsStore --- src/ActiveRoomObserver.js | 15 ++++++++------- src/components/views/rooms/RoomTile.js | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/ActiveRoomObserver.js b/src/ActiveRoomObserver.js index d6fbb460b5..ee3212f611 100644 --- a/src/ActiveRoomObserver.js +++ b/src/ActiveRoomObserver.js @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import RoomViewStore from './stores/RoomViewStore'; +import OpenRoomsStore from './stores/OpenRoomsStore'; /** - * Consumes changes from the RoomViewStore and notifies specific things + * Consumes changes from the OpenRoomsStore and notifies specific things * about when the active room changes. Unlike listening for RoomViewStore * changes, you can subscribe to only changes relevant to a particular * room. @@ -28,11 +28,11 @@ import RoomViewStore from './stores/RoomViewStore'; class ActiveRoomObserver { constructor() { this._listeners = {}; - - this._activeRoomId = RoomViewStore.getRoomId(); + const roomStore = OpenRoomsStore.getCurrentRoomStore(); + this._activeRoomId = roomStore && roomStore.getRoomId(); // TODO: We could self-destruct when the last listener goes away, or at least // stop listening. - this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate.bind(this)); + this._roomStoreToken = OpenRoomsStore.addListener(this._onOpenRoomsStoreUpdate.bind(this)); } addListener(roomId, listener) { @@ -59,12 +59,13 @@ class ActiveRoomObserver { } } - _onRoomViewStoreUpdate() { + _onOpenRoomsStoreUpdate() { // emit for the old room ID if (this._activeRoomId) this._emit(this._activeRoomId); + const activeRoomStore = OpenRoomsStore.getCurrentRoomStore(); // update our cache - this._activeRoomId = RoomViewStore.getRoomId(); + this._activeRoomId = activeRoomStore && activeRoomStore.getRoomId(); // and emit for the new one if (this._activeRoomId) this._emit(this._activeRoomId); diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index faa08c7001..71be2df5a4 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -116,9 +116,9 @@ module.exports = React.createClass({ } }, - _onActiveRoomChange: function() { + _onActiveRoomChange: function(activeRoomId) { this.setState({ - selected: this.props.room.roomId === RoomViewStore.getRoomId(), + selected: this.props.room.roomId === activeRoomId, }); }, From 78d5d7ac0c55e0b6c50a0a56ec170795d0ef8dd9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Nov 2018 16:28:58 +0100 Subject: [PATCH 05/42] correctly detected collapsed rhs --- src/components/structures/MainSplit.js | 2 +- src/components/structures/RoomGridView.js | 92 +++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/components/structures/RoomGridView.js diff --git a/src/components/structures/MainSplit.js b/src/components/structures/MainSplit.js index 6fd0274f1a..5c69ef6745 100644 --- a/src/components/structures/MainSplit.js +++ b/src/components/structures/MainSplit.js @@ -55,7 +55,7 @@ export default class MainSplit extends React.Component { } componentDidMount() { - if (this.props.panel && !this.collapsedRhs) { + if (this.props.panel && !this.props.collapsedRhs) { this._createResizer(); } } diff --git a/src/components/structures/RoomGridView.js b/src/components/structures/RoomGridView.js new file mode 100644 index 0000000000..d472767dbb --- /dev/null +++ b/src/components/structures/RoomGridView.js @@ -0,0 +1,92 @@ +/* +Copyright 2017 Vector Creations Ltd. +Copyright 2017, 2018 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. +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 React from 'react'; +import PropTypes from 'prop-types'; + +export default class RoomGridView extends React.Component { + /* displayName: 'GroupView', + + propTypes: { + groupId: PropTypes.string.isRequired, + }, + + childContextTypes = { + groupStore: PropTypes.instanceOf(GroupStore), + };*/ + + getInitialState() { + return { + rooms: [], + }; + } + + componentWillMount() { + this._unmounted = false; + this._initGroupStore(this.props.groupId); + this._dispatcherRef = dis.register(this._onAction); + } + + componentWillUnmount() { + this._unmounted = true; + if (this._groupStoreRegistration) { + this._groupStoreRegistration.unregister(); + } + dis.unregister(this._dispatcherRef); + } + + componentWillReceiveProps(newProps) { + if (this.props.groupId != newProps.groupId) { + this.setState(this.getInitialState(), () => { + this._initGroupStore(newProps.groupId); + }); + } + } + + _initGroupStore(groupId) { + if (this._groupStoreRegistration) { + this._groupStoreRegistration.unregister(); + } + this._groupStoreRegistration = GroupStore.registerListener(groupId, this.onGroupStoreUpdated); + } + + onGroupStoreUpdated() { + if (this._unmounted) return; + this.setState({ + rooms: GroupStore.getGroupRooms(this.props.groupId), + }); + } + + _onAction(payload) { + switch (payload.action) { + default: + break; + } + } + + render() { + const rooms = this.state.rooms.slice(0, 6); + return
+ { rooms.map(room => { +
+ +
+ }) } +
+ } + +} From 720bc11aa403e98650cf3952232518c9628bd3d5 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Nov 2018 16:29:17 +0100 Subject: [PATCH 06/42] avoid using roomviewstore for detecting selected room --- src/ActiveRoomObserver.js | 4 ++++ src/components/views/rooms/RoomTile.js | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ActiveRoomObserver.js b/src/ActiveRoomObserver.js index ee3212f611..2561a2e6a3 100644 --- a/src/ActiveRoomObserver.js +++ b/src/ActiveRoomObserver.js @@ -35,6 +35,10 @@ class ActiveRoomObserver { this._roomStoreToken = OpenRoomsStore.addListener(this._onOpenRoomsStoreUpdate.bind(this)); } + getActiveRoomId() { + return this._activeRoomId; + } + addListener(roomId, listener) { if (!this._listeners[roomId]) this._listeners[roomId] = []; this._listeners[roomId].push(listener); diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index 71be2df5a4..2bc06ecc7a 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -29,7 +29,6 @@ import * as RoomNotifs from '../../../RoomNotifs'; import * as FormattingUtils from '../../../utils/FormattingUtils'; import AccessibleButton from '../elements/AccessibleButton'; import ActiveRoomObserver from '../../../ActiveRoomObserver'; -import RoomViewStore from '../../../stores/RoomViewStore'; module.exports = React.createClass({ displayName: 'RoomTile', @@ -61,7 +60,7 @@ module.exports = React.createClass({ roomName: this.props.room.name, notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId), notificationCount: this.props.room.getUnreadNotificationCount(), - selected: this.props.room.roomId === RoomViewStore.getRoomId(), + selected: this.props.room.roomId === ActiveRoomObserver.getActiveRoomId(), }); }, From f95b26179fbc558c1200f6e5c3e8476a5969084a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Nov 2018 16:30:02 +0100 Subject: [PATCH 07/42] make copy of initial state, as there can be multiple instances now --- src/stores/RoomViewStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stores/RoomViewStore.js b/src/stores/RoomViewStore.js index 43964bc6c3..5ec0c67f2d 100644 --- a/src/stores/RoomViewStore.js +++ b/src/stores/RoomViewStore.js @@ -58,7 +58,7 @@ export class RoomViewStore extends Store { super(dis); // Initialise state - this._state = INITIAL_STATE; + this._state = Object.assign({}, INITIAL_STATE); } _setState(newState) { From d7924ad1a8e4876ab8f016f535c7b91165326a08 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Nov 2018 16:30:29 +0100 Subject: [PATCH 08/42] less ambigious name for local dispatcher --- src/stores/RoomViewStore.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stores/RoomViewStore.js b/src/stores/RoomViewStore.js index 5ec0c67f2d..af1264921a 100644 --- a/src/stores/RoomViewStore.js +++ b/src/stores/RoomViewStore.js @@ -54,8 +54,8 @@ const INITIAL_STATE = { * ``` */ export class RoomViewStore extends Store { - constructor(dis) { - super(dis); + constructor(dispatcher) { + super(dispatcher); // Initialise state this._state = Object.assign({}, INITIAL_STATE); From 6ec6303b973c0fd51928e61591472784a85563b3 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Nov 2018 16:32:12 +0100 Subject: [PATCH 09/42] support opening all rooms of a group in OpenRoomsStore using new view_group_grid action --- src/stores/OpenRoomsStore.js | 112 +++++++++++++++++++++++++++-------- 1 file changed, 87 insertions(+), 25 deletions(-) diff --git a/src/stores/OpenRoomsStore.js b/src/stores/OpenRoomsStore.js index f82671e58d..6904689157 100644 --- a/src/stores/OpenRoomsStore.js +++ b/src/stores/OpenRoomsStore.js @@ -16,9 +16,21 @@ limitations under the License. import MatrixDispatcher from '../matrix-dispatcher'; import dis from '../dispatcher'; import {RoomViewStore} from './RoomViewStore'; +import GroupStore from './GroupStore'; import {Store} from 'flux/utils'; import MatrixClientPeg from '../MatrixClientPeg'; + +function matchesRoom(payload, roomStore) { + if (!roomStore) { + return false; + } + if (payload.room_alias) { + return payload.room_alias === roomStore.getRoomAlias(); + } + return payload.room_id === roomStore.getRoomId(); +} + /** * A class for keeping track of the RoomViewStores of the rooms shown on the screen. * Routes the dispatcher actions to the store of currently active room. @@ -29,21 +41,30 @@ class OpenRoomsStore extends Store { // Initialise state this._state = { - room: { - store: null, - dispatcher: null - }, + rooms: [], + currentIndex: null, + group_id: null, }; this._forwardingEvent = null; } - getRoomStore() { - return this._state.room.store; + getRoomStores() { + return this._state.rooms.map((r) => r.store); } getCurrentRoomStore() { - return this.getRoomStore(); // just one room for now + const currentRoom = this._getCurrentRoom(); + if (currentRoom) { + return currentRoom.store; + } + } + + _getCurrentRoom() { + const index = this._state.currentIndex; + if (index !== null && index < this._state.rooms.length) { + return this._state.rooms[index]; + } } _setState(newState) { @@ -51,30 +72,41 @@ class OpenRoomsStore extends Store { this.__emitChange(); } - _cleanupRoom() { + _hasRoom(payload) { + return this._roomIndex(payload) !== -1; + } + + _roomIndex(payload) { + return this._state.rooms.findIndex((r) => matchesRoom(payload, r.store)); + } + + _cleanupRooms() { const room = this._state.room; - room.dispatcher.unregister(room.store.getDispatchToken()); + this._state.rooms.forEach((room) => { + room.dispatcher.unregister(room.store.getDispatchToken()); + }); this._setState({ - room: { - store: null, - dispatcher: null - }, + rooms: [], + group_id: null, + currentIndex: null }); } _createRoom() { const dispatcher = new MatrixDispatcher(); this._setState({ - room: { + rooms: [{ store: new RoomViewStore(dispatcher), dispatcher, - }, + }], + currentIndex: 0, }); } _forwardAction(payload) { - if (this._state.room.dispatcher) { - this._state.room.dispatcher.dispatch(payload, true); + const currentRoom = this._getCurrentRoom(); + if (currentRoom) { + currentRoom.dispatcher.dispatch(payload, true); } } @@ -101,6 +133,10 @@ class OpenRoomsStore extends Store { } } + _setCurrentGroupRoom(index) { + this._setState({currentIndex: index}); + } + __onDispatch(payload) { switch (payload.action) { // view_room: @@ -115,14 +151,15 @@ class OpenRoomsStore extends Store { this._resolveRoomAlias(payload); } const currentStore = this.getCurrentRoomStore(); - if (currentStore && - (!payload.room_alias || payload.room_alias !== currentStore.getRoomAlias()) && - (!currentStore.getRoomId() || payload.room_id !== currentStore.getRoomId()) - ) { - console.log("OpenRoomsStore: _cleanupRoom"); - this._cleanupRoom(); + if (matchesRoom(payload, currentStore)) { + if (this._hasRoom(payload)) { + const roomIndex = this._roomIndex(payload); + this._setState({currentIndex: roomIndex}); + } else { + this._cleanupRooms(); + } } - if (!this._state.room.store) { + if (!this.getCurrentRoomStore()) { console.log("OpenRoomsStore: _createRoom"); this._createRoom(); } @@ -140,7 +177,7 @@ class OpenRoomsStore extends Store { case 'view_my_groups': case 'view_group': this._forwardAction(payload); - this._cleanupRoom(); + this._cleanupRooms(); break; case 'will_join': case 'cancel_join': @@ -155,6 +192,31 @@ class OpenRoomsStore extends Store { case 'forward_event': this._forwardingEvent = payload.event; break; + case 'view_group_grid': + if (payload.group_id !== this._state.group_id) { + this._cleanupRooms(); + // TODO: register to GroupStore updates + const rooms = GroupStore.getGroupRooms(payload.group_id); + const roomStores = rooms.map((room) => { + const dispatcher = new MatrixDispatcher(); + const store = new RoomViewStore(dispatcher); + // set room id of store + dispatcher.dispatch({ + action: 'view_room', + room_id: room.roomId + }, true); + return { + store, + dispatcher, + }; + }); + this._setState({ + rooms: roomStores, + group_id: payload.group_id, + }); + this._setCurrentGroupRoom(0); + } + break; } } } From d4748c91df73a6b1e96daf9c46afe4446966d55e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Nov 2018 16:33:14 +0100 Subject: [PATCH 10/42] add first draft of RoomGridView --- res/css/_components.scss | 1 + res/css/structures/_GroupGridView.scss | 65 +++++++++++++++ src/components/structures/GroupGridView.js | 84 ++++++++++++++++++++ src/components/structures/RoomGridView.js | 92 ---------------------- 4 files changed, 150 insertions(+), 92 deletions(-) create mode 100644 res/css/structures/_GroupGridView.scss create mode 100644 src/components/structures/GroupGridView.js delete mode 100644 src/components/structures/RoomGridView.js diff --git a/res/css/_components.scss b/res/css/_components.scss index 92e243e8d1..16bb4938c1 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -5,6 +5,7 @@ @import "./structures/_ContextualMenu.scss"; @import "./structures/_CreateRoom.scss"; @import "./structures/_FilePanel.scss"; +@import "./structures/_GroupGridView.scss"; @import "./structures/_GroupView.scss"; @import "./structures/_HomePage.scss"; @import "./structures/_LeftPanel.scss"; diff --git a/res/css/structures/_GroupGridView.scss b/res/css/structures/_GroupGridView.scss new file mode 100644 index 0000000000..ed0d824388 --- /dev/null +++ b/res/css/structures/_GroupGridView.scss @@ -0,0 +1,65 @@ +/* +Copyright 2017 Vector Creations 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. +*/ + +.mx_GroupGridView { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-template-rows: 1fr 1fr; + grid-column-gap: 10px; + grid-row-gap: 10px; + background-color: red; +} + +.mx_RoomGridView_emptyTile::before { + display: block; + margin-top: 100px; + text-align: center; + content: "no room in this tile yet"; +} + +.mx_RoomGridView_tile > .mx_RoomView { + height: 100%; +} + +.mx_GroupGridView > *:nth-child(1) { + grid-column: 1; + grid-row: 1; +} + +.mx_GroupGridView > *:nth-child(2) { + grid-column: 2; + grid-row: 1; +} + +.mx_GroupGridView > *:nth-child(3) { + grid-column: 3; + grid-row: 1; +} + +.mx_GroupGridView > *:nth-child(4) { + grid-column: 1; + grid-row: 2; +} + +.mx_GroupGridView > *:nth-child(5) { + grid-column: 2; + grid-row: 2; +} + +.mx_GroupGridView > *:nth-child(6) { + grid-column: 3; + grid-row: 2; +} diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js new file mode 100644 index 0000000000..282919f019 --- /dev/null +++ b/src/components/structures/GroupGridView.js @@ -0,0 +1,84 @@ +/* +Copyright 2017 Vector Creations Ltd. +Copyright 2017, 2018 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. +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 React from 'react'; +import PropTypes from 'prop-types'; +import OpenRoomsStore from '../../stores/OpenRoomsStore'; +import dis from '../../dispatcher'; +import RoomView from './RoomView'; + +export default class RoomGridView extends React.Component { + + constructor(props) { + super(props); + this.state = { + roomStores: OpenRoomsStore.getRoomStores(), + }; + } + + componentWillMount() { + this._unmounted = false; + this._openRoomsStoreRegistration = OpenRoomsStore.addListener(this.onRoomsChanged); + this._dispatcherRef = dis.register(this._onAction); + } + + componentWillUnmount() { + this._unmounted = true; + if (this._openRoomsStoreRegistration) { + this._openRoomsStoreRegistration.unregister(); + } + dis.unregister(this._dispatcherRef); + } + + onRoomsChanged() { + if (this._unmounted) return; + this.setState({ + roomStores: OpenRoomsStore.getRoomStores(), + }); + } + + _onAction(payload) { + switch (payload.action) { + default: + break; + } + } + + render() { + let roomStores = this.state.roomStores.slice(0, 6); + const emptyCount = 6 - roomStores.length; + if (emptyCount) { + const emptyTiles = Array.from({length: emptyCount}, () => null); + roomStores = roomStores.concat(emptyTiles); + } + return (
+ { roomStores.map(roomStore => { + if (roomStore) { + return (
+ +
); + } else { + return (
); + } + }) } +
); + } + +} diff --git a/src/components/structures/RoomGridView.js b/src/components/structures/RoomGridView.js deleted file mode 100644 index d472767dbb..0000000000 --- a/src/components/structures/RoomGridView.js +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd. -Copyright 2017, 2018 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. -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 React from 'react'; -import PropTypes from 'prop-types'; - -export default class RoomGridView extends React.Component { - /* displayName: 'GroupView', - - propTypes: { - groupId: PropTypes.string.isRequired, - }, - - childContextTypes = { - groupStore: PropTypes.instanceOf(GroupStore), - };*/ - - getInitialState() { - return { - rooms: [], - }; - } - - componentWillMount() { - this._unmounted = false; - this._initGroupStore(this.props.groupId); - this._dispatcherRef = dis.register(this._onAction); - } - - componentWillUnmount() { - this._unmounted = true; - if (this._groupStoreRegistration) { - this._groupStoreRegistration.unregister(); - } - dis.unregister(this._dispatcherRef); - } - - componentWillReceiveProps(newProps) { - if (this.props.groupId != newProps.groupId) { - this.setState(this.getInitialState(), () => { - this._initGroupStore(newProps.groupId); - }); - } - } - - _initGroupStore(groupId) { - if (this._groupStoreRegistration) { - this._groupStoreRegistration.unregister(); - } - this._groupStoreRegistration = GroupStore.registerListener(groupId, this.onGroupStoreUpdated); - } - - onGroupStoreUpdated() { - if (this._unmounted) return; - this.setState({ - rooms: GroupStore.getGroupRooms(this.props.groupId), - }); - } - - _onAction(payload) { - switch (payload.action) { - default: - break; - } - } - - render() { - const rooms = this.state.rooms.slice(0, 6); - return
- { rooms.map(room => { -
- -
- }) } -
- } - -} From 399d3c5c24da0f8f7ac5c1e47464f14560375b3a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Nov 2018 16:34:10 +0100 Subject: [PATCH 11/42] wire up view_group_grid action from community context menu to new view --- src/PageTypes.js | 1 + src/components/structures/LoggedInView.js | 12 +++++++++++- src/components/structures/MatrixChat.js | 10 ++++++++++ .../views/context_menus/TagTileContextMenu.js | 12 ++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/PageTypes.js b/src/PageTypes.js index 60111723fb..e4e1916c8b 100644 --- a/src/PageTypes.js +++ b/src/PageTypes.js @@ -19,6 +19,7 @@ limitations under the License. export default { HomePage: "home_page", RoomView: "room_view", + GroupGridView: "group_grid_view", UserSettings: "user_settings", RoomDirectory: "room_directory", UserView: "user_view", diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index b81597a901..8c6f192016 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -31,6 +31,7 @@ import sessionStore from '../../stores/SessionStore'; import MatrixClientPeg from '../../MatrixClientPeg'; import SettingsStore from "../../settings/SettingsStore"; import RoomListStore from "../../stores/RoomListStore"; +import OpenRoomsStore from "../../stores/OpenRoomsStore"; import TagOrderActions from '../../actions/TagOrderActions'; import RoomListActions from '../../actions/RoomListActions'; @@ -416,6 +417,7 @@ const LoggedInView = React.createClass({ const RoomDirectory = sdk.getComponent('structures.RoomDirectory'); const HomePage = sdk.getComponent('structures.HomePage'); const GroupView = sdk.getComponent('structures.GroupView'); + const GroupGridView = sdk.getComponent('structures.GroupGridView'); const MyGroups = sdk.getComponent('structures.MyGroups'); const MatrixToolbar = sdk.getComponent('globals.MatrixToolbar'); const CookieBar = sdk.getComponent('globals.CookieBar'); @@ -428,6 +430,12 @@ const LoggedInView = React.createClass({ switch (this.props.page_type) { case PageTypes.RoomView: + if (!OpenRoomsStore.getCurrentRoomStore()) { + console.warn(`LoggedInView: getCurrentRoomStore not set!`); + } + else if (OpenRoomsStore.getCurrentRoomStore().getRoomId() !== this.props.currentRoomId) { + console.warn(`LoggedInView: room id in store not the same as in props: ${OpenRoomsStore.getCurrentRoomStore().getRoomId()} & ${this.props.currentRoomId}`); + } page_element = ; break; - + case PageTypes.GroupGridView: + page_element = ; + break; case PageTypes.UserSettings: page_element = @@ -65,6 +74,9 @@ export default class TagTileContextMenu extends React.Component { /> { _t('View Community') }
+
+ { _t('View as grid') } +

From fdd324a9437793bbdfb66c4e228cfca9f95f3c4d Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Nov 2018 11:06:26 +0100 Subject: [PATCH 12/42] basic divider lines for tiles --- res/css/structures/_GroupGridView.scss | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_GroupGridView.scss b/res/css/structures/_GroupGridView.scss index ed0d824388..4c54cb49b1 100644 --- a/res/css/structures/_GroupGridView.scss +++ b/res/css/structures/_GroupGridView.scss @@ -18,8 +18,6 @@ limitations under the License. display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: 1fr 1fr; - grid-column-gap: 10px; - grid-row-gap: 10px; background-color: red; } @@ -30,6 +28,11 @@ limitations under the License. content: "no room in this tile yet"; } +.mx_RoomGridView_tile { + border-right: 1px solid $panel-divider-color; + border-bottom: 1px solid $panel-divider-color; +} + .mx_RoomGridView_tile > .mx_RoomView { height: 100%; } From b68df0420b29769aacb4f2790da16ea8a01c1efe Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Nov 2018 12:25:36 +0100 Subject: [PATCH 13/42] fix errors when trying to switch room --- src/components/structures/GroupGridView.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index 282919f019..b72e689bc5 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -28,6 +28,7 @@ export default class RoomGridView extends React.Component { this.state = { roomStores: OpenRoomsStore.getRoomStores(), }; + this.onRoomsChanged = this.onRoomsChanged.bind(this); } componentWillMount() { @@ -39,7 +40,7 @@ export default class RoomGridView extends React.Component { componentWillUnmount() { this._unmounted = true; if (this._openRoomsStoreRegistration) { - this._openRoomsStoreRegistration.unregister(); + this._openRoomsStoreRegistration.remove(); } dis.unregister(this._dispatcherRef); } From cf0f75cad4eaf7050a8cc106f74ce3c3c0b8f147 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 21 Nov 2018 14:04:25 +0000 Subject: [PATCH 14/42] allow changing active room in grid by clicking it --- res/css/structures/_GroupGridView.scss | 11 ++++++++--- src/components/structures/GroupGridView.js | 13 ++++++++++--- src/components/structures/MatrixChat.js | 2 +- src/components/structures/RoomView.js | 6 +++++- .../views/context_menus/TagTileContextMenu.js | 2 +- src/stores/OpenRoomsStore.js | 16 ++++++++++------ 6 files changed, 35 insertions(+), 15 deletions(-) diff --git a/res/css/structures/_GroupGridView.scss b/res/css/structures/_GroupGridView.scss index 4c54cb49b1..130d3e89f6 100644 --- a/res/css/structures/_GroupGridView.scss +++ b/res/css/structures/_GroupGridView.scss @@ -21,19 +21,24 @@ limitations under the License. background-color: red; } -.mx_RoomGridView_emptyTile::before { + +.mx_GroupGridView_emptyTile::before { display: block; margin-top: 100px; text-align: center; content: "no room in this tile yet"; } -.mx_RoomGridView_tile { +.mx_GroupGridView_tile { border-right: 1px solid $panel-divider-color; border-bottom: 1px solid $panel-divider-color; } -.mx_RoomGridView_tile > .mx_RoomView { +.mx_GroupGridView_activeTile { + border: 1px solid red !important; +} + +.mx_GroupGridView_tile > .mx_RoomView { height: 100%; } diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index b72e689bc5..09bc0e300a 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -20,6 +20,7 @@ import PropTypes from 'prop-types'; import OpenRoomsStore from '../../stores/OpenRoomsStore'; import dis from '../../dispatcher'; import RoomView from './RoomView'; +import classNames from 'classnames'; export default class RoomGridView extends React.Component { @@ -49,6 +50,7 @@ export default class RoomGridView extends React.Component { if (this._unmounted) return; this.setState({ roomStores: OpenRoomsStore.getRoomStores(), + currentRoomStore: OpenRoomsStore.getCurrentRoomStore(), }); } @@ -67,16 +69,21 @@ export default class RoomGridView extends React.Component { roomStores = roomStores.concat(emptyTiles); } return (
- { roomStores.map(roomStore => { + { roomStores.map((roomStore) => { if (roomStore) { - return (
+ const isActive = roomStore === this.state.currentRoomStore; + const tileClasses = classNames({ + "mx_GroupGridView_tile": true, + "mx_GroupGridView_activeTile": isActive, + }); + return (
); } else { - return (
); + return (
); } }) }
); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index c42daf2923..3d3aa52e57 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -627,7 +627,7 @@ export default React.createClass({ case 'view_group': this._viewGroup(payload); break; - case 'view_group_grid': + case 'group_grid_view': this._viewGroupGrid(payload); break; case 'view_home_page': diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index b1730ed96a..c7a0677262 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1470,6 +1470,10 @@ module.exports = React.createClass({ } }, + _onMainClicked: function() { + dis.dispatch({action: 'group_grid_set_active', room_id: this.state.room.roomId }); + }, + render: function() { const RoomHeader = sdk.getComponent('rooms.RoomHeader'); const MessageComposer = sdk.getComponent('rooms.MessageComposer'); @@ -1817,7 +1821,7 @@ module.exports = React.createClass({ const rightPanel = this.state.room ? : undefined; return ( -
+
Date: Thu, 22 Nov 2018 10:18:11 +0000 Subject: [PATCH 15/42] also give empty tiles a key --- src/components/structures/GroupGridView.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index 09bc0e300a..7a51604f0d 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -69,7 +69,7 @@ export default class RoomGridView extends React.Component { roomStores = roomStores.concat(emptyTiles); } return (
- { roomStores.map((roomStore) => { + { roomStores.map((roomStore, i) => { if (roomStore) { const isActive = roomStore === this.state.currentRoomStore; const tileClasses = classNames({ @@ -83,7 +83,7 @@ export default class RoomGridView extends React.Component { /> ); } else { - return (
); + return (
); } }) }
); From 2ceef0094437b3c3269d341c373138af964b2a70 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 11:01:19 +0000 Subject: [PATCH 16/42] style active room rect, and make it not jump --- res/css/structures/_GroupGridView.scss | 27 +++++++++++++++++++++++++- res/css/structures/_MatrixChat.scss | 3 ++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_GroupGridView.scss b/res/css/structures/_GroupGridView.scss index 130d3e89f6..9e5c5c3379 100644 --- a/res/css/structures/_GroupGridView.scss +++ b/res/css/structures/_GroupGridView.scss @@ -35,9 +35,34 @@ limitations under the License. } .mx_GroupGridView_activeTile { - border: 1px solid red !important; + position: relative; } +.mx_GroupGridView_activeTile:before, +.mx_GroupGridView_activeTile:after { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + content: ""; + pointer-events: none; + z-index: 10000; +} + +.mx_GroupGridView_activeTile:before { + border-radius: 14px; + border: 8px solid rgba(134, 193, 165, 0.5); + margin: -8px; +} + +.mx_GroupGridView_activeTile:after { + border-radius: 8px; + border: 2px solid rgba(134, 193, 165, 1); + margin: -2px; +} + + .mx_GroupGridView_tile > .mx_RoomView { height: 100%; } diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index 1ccbd19391..a843bb7fee 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -80,7 +80,8 @@ limitations under the License. Empirically this stops the MessagePanel's width exploding outwards when gemini is in 'prevented' mode */ - overflow-x: auto; + // disabling this for now as it clips the active room rect on the grid view + // overflow-x: auto; /* To fix https://github.com/vector-im/riot-web/issues/3298 where Safari needed height 100% all the way down to the HomePage. Height does not From fbfbefe4fe76b2344b568dbc2d747bf3da74ecae Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 12:23:07 +0000 Subject: [PATCH 17/42] also forward actions from room dispatcher to global one avoiding replay if the action would be forwarded back to the same room dispatcher also some fixing & renaming in OpenRoomsStore --- src/ActiveRoomObserver.js | 4 +- src/components/structures/GroupGridView.js | 4 +- src/components/structures/LoggedInView.js | 8 +- src/stores/OpenRoomsStore.js | 161 +++++++++++++-------- 4 files changed, 105 insertions(+), 72 deletions(-) diff --git a/src/ActiveRoomObserver.js b/src/ActiveRoomObserver.js index 2561a2e6a3..f3850dd87c 100644 --- a/src/ActiveRoomObserver.js +++ b/src/ActiveRoomObserver.js @@ -28,7 +28,7 @@ import OpenRoomsStore from './stores/OpenRoomsStore'; class ActiveRoomObserver { constructor() { this._listeners = {}; - const roomStore = OpenRoomsStore.getCurrentRoomStore(); + const roomStore = OpenRoomsStore.getActiveRoomStore(); this._activeRoomId = roomStore && roomStore.getRoomId(); // TODO: We could self-destruct when the last listener goes away, or at least // stop listening. @@ -67,7 +67,7 @@ class ActiveRoomObserver { // emit for the old room ID if (this._activeRoomId) this._emit(this._activeRoomId); - const activeRoomStore = OpenRoomsStore.getCurrentRoomStore(); + const activeRoomStore = OpenRoomsStore.getActiveRoomStore(); // update our cache this._activeRoomId = activeRoomStore && activeRoomStore.getRoomId(); diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index 7a51604f0d..e6c0dfd31e 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -50,7 +50,7 @@ export default class RoomGridView extends React.Component { if (this._unmounted) return; this.setState({ roomStores: OpenRoomsStore.getRoomStores(), - currentRoomStore: OpenRoomsStore.getCurrentRoomStore(), + activeRoomStore: OpenRoomsStore.getActiveRoomStore(), }); } @@ -71,7 +71,7 @@ export default class RoomGridView extends React.Component { return (
{ roomStores.map((roomStore, i) => { if (roomStore) { - const isActive = roomStore === this.state.currentRoomStore; + const isActive = roomStore === this.state.activeRoomStore; const tileClasses = classNames({ "mx_GroupGridView_tile": true, "mx_GroupGridView_activeTile": isActive, diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 8c6f192016..56f3fc89f4 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -430,14 +430,14 @@ const LoggedInView = React.createClass({ switch (this.props.page_type) { case PageTypes.RoomView: - if (!OpenRoomsStore.getCurrentRoomStore()) { + if (!OpenRoomsStore.getActiveRoomStore()) { console.warn(`LoggedInView: getCurrentRoomStore not set!`); } - else if (OpenRoomsStore.getCurrentRoomStore().getRoomId() !== this.props.currentRoomId) { - console.warn(`LoggedInView: room id in store not the same as in props: ${OpenRoomsStore.getCurrentRoomStore().getRoomId()} & ${this.props.currentRoomId}`); + else if (OpenRoomsStore.getActiveRoomStore().getRoomId() !== this.props.currentRoomId) { + console.warn(`LoggedInView: room id in store not the same as in props: ${OpenRoomsStore.getActiveRoomStore().getRoomId()} & ${this.props.currentRoomId}`); } page_element = r.store); } - getCurrentRoomStore() { - const currentRoom = this._getCurrentRoom(); - if (currentRoom) { - return currentRoom.store; + getActiveRoomStore() { + const openRoom = this._getActiveOpenRoom(); + if (openRoom) { + return openRoom.store; } } - _getCurrentRoom() { + _getActiveOpenRoom() { const index = this._state.currentIndex; if (index !== null && index < this._state.rooms.length) { return this._state.rooms[index]; @@ -80,31 +80,79 @@ class OpenRoomsStore extends Store { return this._state.rooms.findIndex((r) => matchesRoom(payload, r.store)); } - _cleanupRooms() { - const room = this._state.room; + _cleanupOpenRooms() { this._state.rooms.forEach((room) => { + room.dispatcher.unregister(room.dispatcherRef); room.dispatcher.unregister(room.store.getDispatchToken()); }); this._setState({ rooms: [], group_id: null, - currentIndex: null + currentIndex: null, }); } - _createRoom() { + _createOpenRoom(room_id, room_alias) { const dispatcher = new MatrixDispatcher(); + // forward all actions coming from the room dispatcher + // to the global one + const dispatcherRef = dispatcher.register((action) => { + action.grid_src_room_id = room_id; + action.grid_src_room_alias = room_alias; + this.getDispatcher().dispatch(action); + }); + const openRoom = { + store: new RoomViewStore(dispatcher), + dispatcher, + dispatcherRef, + }; + + dispatcher.dispatch({ + action: 'view_room', + room_id: room_id, + room_alias: room_alias, + }, true); + + return openRoom; + } + + _setSingleOpenRoom(payload) { this._setState({ - rooms: [{ - store: new RoomViewStore(dispatcher), - dispatcher, - }], + rooms: [this._createOpenRoom(payload.room_id, payload.room_alias)], + currentIndex: 0, + }); + } + + _setGroupOpenRooms(group_id) { + this._cleanupOpenRooms(); + // TODO: register to GroupStore updates + const rooms = GroupStore.getGroupRooms(group_id); + const openRooms = rooms.map((room) => { + return this._createOpenRoom(room.roomId); + }); + this._setState({ + rooms: openRooms, + group_id: group_id, currentIndex: 0, }); } _forwardAction(payload) { - const currentRoom = this._getCurrentRoom(); + // don't forward an event to a room dispatcher + // if the event originated from that dispatcher, as this + // would cause the event to be observed twice in that + // dispatcher + if (payload.grid_src_room_id || payload.grid_src_room_alias) { + const srcPayload = { + room_id: payload.grid_src_room_id, + room_alias: payload.grid_src_room_alias, + }; + const srcIndex = this._roomIndex(srcPayload); + if (srcIndex === this._state.currentIndex) { + return; + } + } + const currentRoom = this._getActiveOpenRoom(); if (currentRoom) { currentRoom.dispatcher.dispatch(payload, true); } @@ -114,7 +162,7 @@ class OpenRoomsStore extends Store { try { const result = await MatrixClientPeg.get() .getRoomIdForAlias(payload.room_alias); - dis.dispatch({ + this.getDispatcher().dispatch({ action: 'view_room', room_id: result.room_id, event_id: payload.event_id, @@ -133,6 +181,36 @@ class OpenRoomsStore extends Store { } } + _viewRoom(payload) { + console.log("!!! OpenRoomsStore: view_room", payload); + if (!payload.room_id && payload.room_alias) { + this._resolveRoomAlias(payload); + } + const currentStore = this.getActiveRoomStore(); + if (!matchesRoom(payload, currentStore)) { + if (this._hasRoom(payload)) { + const roomIndex = this._roomIndex(payload); + this._setState({currentIndex: roomIndex}); + } else { + this._cleanupOpenRooms(); + } + } + if (!this.getActiveRoomStore()) { + console.log("OpenRoomsStore: _setSingleOpenRoom"); + this._setSingleOpenRoom(payload); + } + console.log("OpenRoomsStore: _forwardAction"); + this._forwardAction(payload); + if (this._forwardingEvent) { + this.getDispatcher().dispatch({ + action: 'send_event', + room_id: payload.room_id, + event: this._forwardingEvent, + }); + this._forwardingEvent = null; + } + } + __onDispatch(payload) { switch (payload.action) { // view_room: @@ -142,38 +220,12 @@ class OpenRoomsStore extends Store { // - event_offset: 100 // - highlighted: true case 'view_room': - console.log("!!! OpenRoomsStore: view_room", payload); - if (!payload.room_id && payload.room_alias) { - this._resolveRoomAlias(payload); - } - const currentStore = this.getCurrentRoomStore(); - if (matchesRoom(payload, currentStore)) { - if (this._hasRoom(payload)) { - const roomIndex = this._roomIndex(payload); - this._setState({currentIndex: roomIndex}); - } else { - this._cleanupRooms(); - } - } - if (!this.getCurrentRoomStore()) { - console.log("OpenRoomsStore: _createRoom"); - this._createRoom(); - } - console.log("OpenRoomsStore: _forwardAction"); - this._forwardAction(payload); - if (this._forwardingEvent) { - dis.dispatch({ - action: 'send_event', - room_id: payload.room_id, - event: this._forwardingEvent, - }); - this._forwardingEvent = null; - } + this._viewRoom(payload); break; case 'view_my_groups': case 'view_group': this._forwardAction(payload); - this._cleanupRooms(); + this._cleanupOpenRooms(); break; case 'will_join': case 'cancel_join': @@ -183,6 +235,7 @@ class OpenRoomsStore extends Store { case 'reply_to_event': case 'open_room_settings': case 'close_settings': + case 'focus_composer': this._forwardAction(payload); break; case 'forward_event': @@ -198,27 +251,7 @@ class OpenRoomsStore extends Store { break; case 'group_grid_view': if (payload.group_id !== this._state.group_id) { - this._cleanupRooms(); - // TODO: register to GroupStore updates - const rooms = GroupStore.getGroupRooms(payload.group_id); - const roomStores = rooms.map((room) => { - const dispatcher = new MatrixDispatcher(); - const store = new RoomViewStore(dispatcher); - // set room id of store - dispatcher.dispatch({ - action: 'view_room', - room_id: room.roomId - }, true); - return { - store, - dispatcher, - }; - }); - this._setState({ - rooms: roomStores, - group_id: payload.group_id, - currentIndex: 0, - }); + this._setGroupOpenRooms(payload.group_id); } break; } From 9a24249fb5805bdbf9c623d2b5cbe5997ef0d85a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 15:13:03 +0000 Subject: [PATCH 18/42] emit focus_composer after updating the active room in GroupGridView also change the active room from there so RoomView is oblivious to grid view stuff --- src/components/structures/GroupGridView.js | 25 +++++++++++++++++++++- src/components/structures/RoomView.js | 6 +----- src/stores/OpenRoomsStore.js | 6 ++++++ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index e6c0dfd31e..0181966d49 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -28,10 +28,22 @@ export default class RoomGridView extends React.Component { super(props); this.state = { roomStores: OpenRoomsStore.getRoomStores(), + activeRoomStore: OpenRoomsStore.getActiveRoomStore(), }; this.onRoomsChanged = this.onRoomsChanged.bind(this); } + componentDidUpdate(_, prevState) { + const store = this.state.activeRoomStore; + if (store) { + store.getDispatcher().dispatch({action: 'focus_composer'}); + } + } + + componentDidMount() { + this.componentDidUpdate(); + } + componentWillMount() { this._unmounted = false; this._openRoomsStoreRegistration = OpenRoomsStore.addListener(this.onRoomsChanged); @@ -61,6 +73,16 @@ export default class RoomGridView extends React.Component { } } + _setActive(i) { + const store = OpenRoomsStore.getRoomStoreAt(i); + if (store !== this.state.activeRoomStore) { + dis.dispatch({ + action: 'group_grid_set_active', + room_id: store.getRoomId(), + }); + } + } + render() { let roomStores = this.state.roomStores.slice(0, 6); const emptyCount = 6 - roomStores.length; @@ -76,10 +98,11 @@ export default class RoomGridView extends React.Component { "mx_GroupGridView_tile": true, "mx_GroupGridView_activeTile": isActive, }); - return (
+ return (
{this._setActive(i)}} key={roomStore.getRoomId()} className={tileClasses}>
); } else { diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index c7a0677262..b1730ed96a 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1470,10 +1470,6 @@ module.exports = React.createClass({ } }, - _onMainClicked: function() { - dis.dispatch({action: 'group_grid_set_active', room_id: this.state.room.roomId }); - }, - render: function() { const RoomHeader = sdk.getComponent('rooms.RoomHeader'); const MessageComposer = sdk.getComponent('rooms.MessageComposer'); @@ -1821,7 +1817,7 @@ module.exports = React.createClass({ const rightPanel = this.state.room ? : undefined; return ( -
+
= 0 && index < this._state.rooms.length) { + return this._state.rooms[index].store; + } + } + _getActiveOpenRoom() { const index = this._state.currentIndex; if (index !== null && index < this._state.rooms.length) { From 44200a6f78b025041e8a6a090e145d611bf1d312 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 15:15:24 +0000 Subject: [PATCH 19/42] only listen and dispatch to room-local dispatcher in room view, composer --- src/components/structures/RoomView.js | 59 +++++++++---------- src/components/views/rooms/MessageComposer.js | 10 ++-- .../views/rooms/MessageComposerInput.js | 12 ++-- 3 files changed, 39 insertions(+), 42 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index b1730ed96a..f6b9381080 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -35,7 +35,6 @@ const ContentMessages = require("../../ContentMessages"); const Modal = require("../../Modal"); const sdk = require('../../index'); const CallHandler = require('../../CallHandler'); -const dis = require("../../dispatcher"); const Tinter = require("../../Tinter"); const rate_limited_func = require('../../ratelimitedfunc'); const ObjectUtils = require('../../ObjectUtils'); @@ -151,7 +150,7 @@ module.exports = React.createClass({ }, componentWillMount: function() { - this.dispatcherRef = dis.register(this.onAction); + this.dispatcherRef = this.props.roomViewStore.getDispatcher().register(this.onAction); MatrixClientPeg.get().on("Room", this.onRoom); MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline); MatrixClientPeg.get().on("Room.name", this.onRoomName); @@ -200,7 +199,7 @@ module.exports = React.createClass({ editingRoomSettings: store.isEditingSettings(), }; - if (this.state.editingRoomSettings && !newState.editingRoomSettings) dis.dispatch({action: 'focus_composer'}); + if (this.state.editingRoomSettings && !newState.editingRoomSettings) this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'}); // Temporary logging to diagnose https://github.com/vector-im/riot-web/issues/4307 console.log( @@ -362,7 +361,7 @@ module.exports = React.createClass({ // XXX: EVIL HACK to autofocus inviting on empty rooms. // We use the setTimeout to avoid racing with focus_composer. - if (this.state.room && + if (this.props.isActive !== false && this.state.room && this.state.room.getJoinedMemberCount() == 1 && this.state.room.getLiveTimeline() && this.state.room.getLiveTimeline().getEvents() && @@ -416,7 +415,7 @@ module.exports = React.createClass({ roomView.removeEventListener('dragleave', this.onDragLeaveOrEnd); roomView.removeEventListener('dragend', this.onDragLeaveOrEnd); } - dis.unregister(this.dispatcherRef); + this.props.roomViewStore.getDispatcher().unregister(this.dispatcherRef); if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener("Room", this.onRoom); MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline); @@ -791,7 +790,7 @@ module.exports = React.createClass({ }, onSearchResultsResize: function() { - dis.dispatch({ action: 'timeline_resize' }, true); + this.props.roomViewStore.getDispatcher().dispatch({ action: 'timeline_resize' }, true); }, onSearchResultsFillRequest: function(backwards) { @@ -812,7 +811,7 @@ module.exports = React.createClass({ onInviteButtonClick: function() { // call AddressPickerDialog - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'view_invite', roomId: this.state.room.roomId, }); @@ -834,7 +833,7 @@ module.exports = React.createClass({ // Join this room once the user has registered and logged in const signUrl = this.props.thirdPartyInvite ? this.props.thirdPartyInvite.inviteSignUrl : undefined; - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'do_after_sync_prepared', deferred_action: { action: 'join_room', @@ -844,7 +843,7 @@ module.exports = React.createClass({ // Don't peek whilst registering otherwise getPendingEventList complains // Do this by indicating our intention to join - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'will_join', }); @@ -855,20 +854,20 @@ module.exports = React.createClass({ if (submitted) { this.props.onRegistered(credentials); } else { - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'cancel_after_sync_prepared', }); - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'cancel_join', }); } }, onDifferentServerClicked: (ev) => { - dis.dispatch({action: 'start_registration'}); + this.props.roomViewStore.getDispatcher().dispatch({action: 'start_registration'}); close(); }, onLoginClick: (ev) => { - dis.dispatch({action: 'start_login'}); + this.props.roomViewStore.getDispatcher().dispatch({action: 'start_login'}); close(); }, }).close; @@ -878,7 +877,7 @@ module.exports = React.createClass({ Promise.resolve().then(() => { const signUrl = this.props.thirdPartyInvite ? this.props.thirdPartyInvite.inviteSignUrl : undefined; - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'join_room', opts: { inviteSignUrl: signUrl, viaServers: this.props.viaServers }, }); @@ -934,10 +933,10 @@ module.exports = React.createClass({ }, uploadFile: async function(file) { - dis.dispatch({action: 'focus_composer'}); + this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'}); if (MatrixClientPeg.get().isGuest()) { - dis.dispatch({action: 'require_registration'}); + this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'}); return; } @@ -961,14 +960,14 @@ module.exports = React.createClass({ } // Send message_sent callback, for things like _checkIfAlone because after all a file is still a message. - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'message_sent', }); }, injectSticker: function(url, info, text) { if (MatrixClientPeg.get().isGuest()) { - dis.dispatch({action: 'require_registration'}); + this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'}); return; } @@ -1169,7 +1168,7 @@ module.exports = React.createClass({ }, onSettingsClick: function() { - dis.dispatch({ action: 'open_room_settings' }); + this.props.roomViewStore.getDispatcher().dispatch({ action: 'open_room_settings' }); }, onSettingsSaveClick: function() { @@ -1202,31 +1201,31 @@ module.exports = React.createClass({ }); // still editing room settings } else { - dis.dispatch({ action: 'close_settings' }); + this.props.roomViewStore.getDispatcher().dispatch({ action: 'close_settings' }); } }).finally(() => { this.setState({ uploadingRoomSettings: false, }); - dis.dispatch({ action: 'close_settings' }); + this.props.roomViewStore.getDispatcher().dispatch({ action: 'close_settings' }); }).done(); }, onCancelClick: function() { console.log("updateTint from onCancelClick"); this.updateTint(); - dis.dispatch({ action: 'close_settings' }); + this.props.roomViewStore.getDispatcher().dispatch({ action: 'close_settings' }); if (this.state.forwardingEvent) { - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'forward_event', event: null, }); } - dis.dispatch({action: 'focus_composer'}); + this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'}); }, onLeaveClick: function() { - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'leave_room', room_id: this.state.room.roomId, }); @@ -1234,7 +1233,7 @@ module.exports = React.createClass({ onForgetClick: function() { MatrixClientPeg.get().forget(this.state.room.roomId).done(function() { - dis.dispatch({ action: 'view_next_room' }); + this.props.roomViewStore.getDispatcher().dispatch({ action: 'view_next_room' }); }, function(err) { const errCode = err.errcode || _t("unknown error code"); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); @@ -1251,7 +1250,7 @@ module.exports = React.createClass({ rejecting: true, }); MatrixClientPeg.get().leave(this.state.roomId).done(function() { - dis.dispatch({ action: 'view_next_room' }); + this.props.roomViewStore.getDispatcher().dispatch({ action: 'view_next_room' }); self.setState({ rejecting: false, }); @@ -1277,7 +1276,7 @@ module.exports = React.createClass({ // using /leave rather than /join. In the short term though, we // just ignore them. // https://github.com/vector-im/vector-web/issues/1134 - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'view_room_directory', }); }, @@ -1296,7 +1295,7 @@ module.exports = React.createClass({ // jump down to the bottom of this room, where new events are arriving jumpToLiveTimeline: function() { this.refs.messagePanel.jumpToLiveTimeline(); - dis.dispatch({action: 'focus_composer'}); + this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'}); }, // jump up to wherever our read marker is @@ -1386,7 +1385,7 @@ module.exports = React.createClass({ }, onFullscreenClick: function() { - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'video_fullscreen', fullscreen: true, }, true); diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 5ac788fb1d..acbaea9ddc 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -130,7 +130,7 @@ export default class MessageComposer extends React.Component { onUploadClick(ev) { if (MatrixClientPeg.get().isGuest()) { - dis.dispatch({action: 'require_registration'}); + this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'}); return; } @@ -192,7 +192,7 @@ export default class MessageComposer extends React.Component { if (!call) { return; } - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'hangup', // hangup the call for this room, which may not be the room in props // (e.g. conferences which will hangup the 1:1 room instead) @@ -201,7 +201,7 @@ export default class MessageComposer extends React.Component { } onCallClick(ev) { - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'place_call', type: ev.shiftKey ? "screensharing" : "video", room_id: this.props.room.roomId, @@ -209,7 +209,7 @@ export default class MessageComposer extends React.Component { } onVoiceCallClick(ev) { - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'place_call', type: "voice", room_id: this.props.room.roomId, @@ -245,7 +245,7 @@ export default class MessageComposer extends React.Component { ev.preventDefault(); const replacementRoomId = this.state.tombstone.getContent()['replacement_room']; - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'view_room', highlighted: true, room_id: replacementRoomId, diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index da41dba212..c54c0b1ab6 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -41,8 +41,6 @@ import sdk from '../../../index'; import { _t, _td } from '../../../languageHandler'; import Analytics from '../../../Analytics'; -import dis from '../../../dispatcher'; - import * as RichText from '../../../RichText'; import * as HtmlUtils from '../../../HtmlUtils'; import Autocomplete from './Autocomplete'; @@ -120,7 +118,7 @@ function onSendMessageFailed(err, room) { // XXX: temporary logging to try to diagnose // https://github.com/vector-im/riot-web/issues/3148 console.log('MessageComposer got send failure: ' + err.name + '('+err+')'); - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'message_send_failed', }); } @@ -344,12 +342,12 @@ export default class MessageComposerInput extends React.Component { } componentWillMount() { - this.dispatcherRef = dis.register(this.onAction); + this.dispatcherRef = this.props.roomViewStore.getDispatcher().register(this.onAction); this.historyManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_'); } componentWillUnmount() { - dis.unregister(this.dispatcherRef); + this.props.roomViewStore.getDispatcher().unregister(this.dispatcherRef); } _collectEditor = (e) => { @@ -1208,14 +1206,14 @@ export default class MessageComposerInput extends React.Component { // Clear reply_to_event as we put the message into the queue // if the send fails, retry will handle resending. - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'reply_to_event', event: null, }); } this.client.sendMessage(this.props.room.roomId, content).then((res) => { - dis.dispatch({ + this.props.roomViewStore.getDispatcher().dispatch({ action: 'message_sent', }); }).catch((e) => { From 74becf71d8c889bc5710076f02f5ab06166f521b Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 16:00:11 +0000 Subject: [PATCH 20/42] add right panel back to grid view --- res/css/structures/_GroupGridView.scss | 25 ++++++++---- src/components/structures/GroupGridView.js | 45 +++++++++++++--------- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/res/css/structures/_GroupGridView.scss b/res/css/structures/_GroupGridView.scss index 9e5c5c3379..8795f958eb 100644 --- a/res/css/structures/_GroupGridView.scss +++ b/res/css/structures/_GroupGridView.scss @@ -14,13 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_GroupGridView { +.mx_GroupGridView_rooms { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: 1fr 1fr; - background-color: red; + flex: 1 1 0; } +.mx_GroupGridView { + display: flex; + flex-direction: column; +} + +.mx_GroupGridView > .mx_MainSplit { + flex: 1 1 0; + display: flex; +} .mx_GroupGridView_emptyTile::before { display: block; @@ -67,32 +76,32 @@ limitations under the License. height: 100%; } -.mx_GroupGridView > *:nth-child(1) { +.mx_GroupGridView_rooms > *:nth-child(1) { grid-column: 1; grid-row: 1; } -.mx_GroupGridView > *:nth-child(2) { +.mx_GroupGridView_rooms > *:nth-child(2) { grid-column: 2; grid-row: 1; } -.mx_GroupGridView > *:nth-child(3) { +.mx_GroupGridView_rooms > *:nth-child(3) { grid-column: 3; grid-row: 1; } -.mx_GroupGridView > *:nth-child(4) { +.mx_GroupGridView_rooms > *:nth-child(4) { grid-column: 1; grid-row: 2; } -.mx_GroupGridView > *:nth-child(5) { +.mx_GroupGridView_rooms > *:nth-child(5) { grid-column: 2; grid-row: 2; } -.mx_GroupGridView > *:nth-child(6) { +.mx_GroupGridView_rooms > *:nth-child(6) { grid-column: 3; grid-row: 2; } diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index 0181966d49..d6268ff14c 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -21,6 +21,8 @@ import OpenRoomsStore from '../../stores/OpenRoomsStore'; import dis from '../../dispatcher'; import RoomView from './RoomView'; import classNames from 'classnames'; +import MainSplit from './MainSplit'; +import RightPanel from './RightPanel'; export default class RoomGridView extends React.Component { @@ -90,25 +92,32 @@ export default class RoomGridView extends React.Component { const emptyTiles = Array.from({length: emptyCount}, () => null); roomStores = roomStores.concat(emptyTiles); } + const activeRoomId = this.state.activeRoomStore && this.state.activeRoomStore.getRoomId(); + const rightPanel = activeRoomId ? : undefined; + return (
- { roomStores.map((roomStore, i) => { - if (roomStore) { - const isActive = roomStore === this.state.activeRoomStore; - const tileClasses = classNames({ - "mx_GroupGridView_tile": true, - "mx_GroupGridView_activeTile": isActive, - }); - return (
{this._setActive(i)}} key={roomStore.getRoomId()} className={tileClasses}> - -
); - } else { - return (
); - } - }) } + +
+ { roomStores.map((roomStore, i) => { + if (roomStore) { + const isActive = roomStore === this.state.activeRoomStore; + const tileClasses = classNames({ + "mx_GroupGridView_tile": true, + "mx_GroupGridView_activeTile": isActive, + }); + return (
{this._setActive(i)}} key={roomStore.getRoomId()} className={tileClasses}> + +
); + } else { + return (
); + } + }) } +
+
); } From ec070ea782af50fcd3bf537bd713484a4056097f Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 16:06:05 +0000 Subject: [PATCH 21/42] use % instead of fr units for grid, make size independant of content --- res/css/structures/_GroupGridView.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_GroupGridView.scss b/res/css/structures/_GroupGridView.scss index 8795f958eb..14c46d1370 100644 --- a/res/css/structures/_GroupGridView.scss +++ b/res/css/structures/_GroupGridView.scss @@ -16,8 +16,8 @@ limitations under the License. .mx_GroupGridView_rooms { display: grid; - grid-template-columns: 1fr 1fr 1fr; - grid-template-rows: 1fr 1fr; + grid-template-columns: repeat(3, calc(100% / 3)); + grid-template-rows: repeat(2, calc(100% / 2)); flex: 1 1 0; } From f593bff3c30113c6eb94e3309716cf62e5b2aabd Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 17:03:23 +0000 Subject: [PATCH 22/42] show right panel tabs inside panel instead of room header in grid mode --- res/css/structures/_GroupGridView.scss | 26 +++++++++++++++++++++- res/css/views/rooms/_MemberList.scss | 4 ++++ src/components/structures/GroupGridView.js | 13 +++++++++-- src/components/structures/RoomView.js | 7 +++++- src/components/views/rooms/RoomHeader.js | 2 +- 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/res/css/structures/_GroupGridView.scss b/res/css/structures/_GroupGridView.scss index 14c46d1370..0464026ed4 100644 --- a/res/css/structures/_GroupGridView.scss +++ b/res/css/structures/_GroupGridView.scss @@ -14,6 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ +.mx_GroupGridView { + display: flex; + flex-direction: column; +} + .mx_GroupGridView_rooms { display: grid; grid-template-columns: repeat(3, calc(100% / 3)); @@ -21,11 +26,30 @@ limitations under the License. flex: 1 1 0; } -.mx_GroupGridView { + +.mx_GroupGridView_rightPanel { display: flex; flex-direction: column; + + .mx_GroupGridView_tabs { + flex: 0 0 52px; + border-bottom: 1px solid $primary-hairline-color; + display: flex; + align-items: center; + + > div { + justify-content: flex-end; + width: 100%; + margin-right: 10px; + } + } + + .mx_RightPanel { + flex: 1 0 auto !important; + } } + .mx_GroupGridView > .mx_MainSplit { flex: 1 1 0; display: flex; diff --git a/res/css/views/rooms/_MemberList.scss b/res/css/views/rooms/_MemberList.scss index 2695ebcf31..8e59eb85d5 100644 --- a/res/css/views/rooms/_MemberList.scss +++ b/res/css/views/rooms/_MemberList.scss @@ -53,6 +53,10 @@ limitations under the License. .mx_MemberList_query, .mx_GroupMemberList_query, .mx_GroupRoomList_query { + flex: 0 0 auto; +} + +.mx_MemberList .gm-scrollbar-container { flex: 1 1 0; } diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index d6268ff14c..abfd343309 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -23,6 +23,7 @@ import RoomView from './RoomView'; import classNames from 'classnames'; import MainSplit from './MainSplit'; import RightPanel from './RightPanel'; +import RoomHeaderButtons from '../views/right_panel/RoomHeaderButtons'; export default class RoomGridView extends React.Component { @@ -93,7 +94,15 @@ export default class RoomGridView extends React.Component { roomStores = roomStores.concat(emptyTiles); } const activeRoomId = this.state.activeRoomStore && this.state.activeRoomStore.getRoomId(); - const rightPanel = activeRoomId ? : undefined; + let rightPanel; + if (activeRoomId) { + rightPanel = ( +
+
+ +
+ ); + } return (
@@ -107,7 +116,7 @@ export default class RoomGridView extends React.Component { }); return (
{this._setActive(i)}} key={roomStore.getRoomId()} className={tileClasses}> diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index f6b9381080..af389c804a 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1509,6 +1509,7 @@ module.exports = React.createClass({
@@ -1555,6 +1556,7 @@ module.exports = React.createClass({
@@ -1813,11 +1815,14 @@ module.exports = React.createClass({ }, ); - const rightPanel = this.state.room ? : undefined; + const rightPanel = this.state.room && !this.props.isGrid ? + : + undefined; return (
+ { !this.props.isGrid ? : undefined }
); From c8243357eac5509d6e920df0928450c939165d98 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 18:32:57 +0000 Subject: [PATCH 23/42] disable editor history/persistence when in grid to avoid pesky bug --- src/components/structures/RoomView.js | 1 + src/components/views/rooms/MessageComposer.js | 1 + .../views/rooms/MessageComposerInput.js | 21 ++++++++++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index af389c804a..681b1221e1 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1690,6 +1690,7 @@ module.exports = React.createClass({ this.messageComposerInput = c} key="controls_input" + isGrid={this.props.isGrid} onResize={this.props.onResize} room={this.props.room} placeholder={placeholderText} diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index c54c0b1ab6..0740667242 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -132,6 +132,18 @@ function rangeEquals(a: Range, b: Range): boolean { && a.isBackward === b.isBackward); } +class NoopHistoryManager { + getItem() {} + save() {} + + get currentIndex() { return 0; } + set currentIndex(_) {} + + get history() { return []; } + set history(_) {} +} + + /* * The textInput part of the MessageComposer */ @@ -343,7 +355,14 @@ export default class MessageComposerInput extends React.Component { componentWillMount() { this.dispatcherRef = this.props.roomViewStore.getDispatcher().register(this.onAction); - this.historyManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_'); + if (this.props.isGrid) { + + + + this.historyManager = new NoopHistoryManager(); + } else { + this.historyManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_'); + } } componentWillUnmount() { From b0c84591d7300df0c46f948cc1b461c7b930b9a4 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 18:35:14 +0000 Subject: [PATCH 24/42] show focus glow below dialogs (at z-index 4000) --- res/css/structures/_GroupGridView.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/structures/_GroupGridView.scss b/res/css/structures/_GroupGridView.scss index 0464026ed4..9e51af25f9 100644 --- a/res/css/structures/_GroupGridView.scss +++ b/res/css/structures/_GroupGridView.scss @@ -80,7 +80,7 @@ limitations under the License. bottom: 0; content: ""; pointer-events: none; - z-index: 10000; + z-index: 3500; } .mx_GroupGridView_activeTile:before { From 0ffd77762acd0283faa5bee217343328db9d7261 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 18:54:27 +0000 Subject: [PATCH 25/42] make menu option look somewhat better --- res/img/icons-gridview.svg | 103 ++++++++++++++++++ .../views/context_menus/TagTileContextMenu.js | 6 + src/i18n/strings/en_EN.json | 3 +- 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 res/img/icons-gridview.svg diff --git a/res/img/icons-gridview.svg b/res/img/icons-gridview.svg new file mode 100644 index 0000000000..862ca63765 --- /dev/null +++ b/res/img/icons-gridview.svg @@ -0,0 +1,103 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/components/views/context_menus/TagTileContextMenu.js b/src/components/views/context_menus/TagTileContextMenu.js index b8930efefe..5cd5aea27a 100644 --- a/src/components/views/context_menus/TagTileContextMenu.js +++ b/src/components/views/context_menus/TagTileContextMenu.js @@ -75,6 +75,12 @@ export default class TagTileContextMenu extends React.Component { { _t('View Community') }
+ { _t('View as grid') }

diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index c137253a43..f592ad6441 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1348,5 +1348,6 @@ "Import": "Import", "Failed to set direct chat tag": "Failed to set direct chat tag", "Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room", - "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room" + "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room", + "View as grid": "View as grid" } From 368ef9e8e89b0e75c26e4912049002d4558a495f Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 18:57:07 +0000 Subject: [PATCH 26/42] hack so we don't revert to single room view when viewing grid --- src/stores/OpenRoomsStore.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/stores/OpenRoomsStore.js b/src/stores/OpenRoomsStore.js index f67108d35a..764f54d7c2 100644 --- a/src/stores/OpenRoomsStore.js +++ b/src/stores/OpenRoomsStore.js @@ -102,10 +102,15 @@ class OpenRoomsStore extends Store { const dispatcher = new MatrixDispatcher(); // forward all actions coming from the room dispatcher // to the global one - const dispatcherRef = dispatcher.register((action) => { - action.grid_src_room_id = room_id; - action.grid_src_room_alias = room_alias; - this.getDispatcher().dispatch(action); + const dispatcherRef = dispatcher.register((payload) => { + // block a view_room action for the same room because it will switch to + // single room mode in MatrixChat + if (payload.action === 'view_room' && room_id === payload.room_id) { + return; + } + payload.grid_src_room_id = room_id; + payload.grid_src_room_alias = room_alias; + this.getDispatcher().dispatch(payload); }); const openRoom = { store: new RoomViewStore(dispatcher), From 04bb13bb7b1d711c3a51b86d46640475ff130f60 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 18:57:37 +0000 Subject: [PATCH 27/42] emit join error over own dispatcher, meh --- src/stores/RoomViewStore.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/stores/RoomViewStore.js b/src/stores/RoomViewStore.js index af1264921a..1e0f5c6a4f 100644 --- a/src/stores/RoomViewStore.js +++ b/src/stores/RoomViewStore.js @@ -14,7 +14,6 @@ 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 dis from '../dispatcher'; import {Store} from 'flux/utils'; import MatrixClientPeg from '../MatrixClientPeg'; import sdk from '../index'; @@ -191,7 +190,7 @@ export class RoomViewStore extends Store { // stream yet, and that's the point at which we'd consider // the user joined to the room. }, (err) => { - dis.dispatch({ + this.getDispatcher().dispatch({ action: 'join_room_error', err: err, }); From 1810c17d24f2165d268c7c35be96a35b1b009758 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 18:58:12 +0000 Subject: [PATCH 28/42] remove trace, add comment, ... --- src/components/structures/MatrixChat.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 3d3aa52e57..b67dc7b352 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -837,8 +837,7 @@ export default React.createClass({ // room name and avatar from an invite email) _viewRoom: function(roomInfo) { this.focusComposer = true; - console.log("!!! MatrixChat._viewRoom", roomInfo); - console.trace(); + console.log("!!! MatrixChat._viewRoom", roomInfo); const newState = { currentRoomId: roomInfo.room_id || null, @@ -887,6 +886,9 @@ export default React.createClass({ if (roomInfo.event_id && roomInfo.highlighted) { presentedId += "/" + roomInfo.event_id; } + + + // TODO: only emit this when we're not in grid mode? this.notifyNewScreen('room/' + presentedId); newState.ready = true; this.setState(newState); From 39289e57ac46b401a95bff3e53c7addfed3b761d Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Nov 2018 19:06:58 +0000 Subject: [PATCH 29/42] fix correct room being highlighted in left panel --- src/ActiveRoomObserver.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/ActiveRoomObserver.js b/src/ActiveRoomObserver.js index f3850dd87c..c276cccb5d 100644 --- a/src/ActiveRoomObserver.js +++ b/src/ActiveRoomObserver.js @@ -55,24 +55,23 @@ class ActiveRoomObserver { } } - _emit(roomId) { + _emit(roomId, newActiveRoomId) { if (!this._listeners[roomId]) return; for (const l of this._listeners[roomId]) { - l.call(); + l.call(l, newActiveRoomId); } } _onOpenRoomsStoreUpdate() { - // emit for the old room ID - if (this._activeRoomId) this._emit(this._activeRoomId); - const activeRoomStore = OpenRoomsStore.getActiveRoomStore(); + const newActiveRoomId = activeRoomStore && activeRoomStore.getRoomId(); + // emit for the old room ID + if (this._activeRoomId) this._emit(this._activeRoomId, newActiveRoomId); // update our cache - this._activeRoomId = activeRoomStore && activeRoomStore.getRoomId(); - + this._activeRoomId = newActiveRoomId; // and emit for the new one - if (this._activeRoomId) this._emit(this._activeRoomId); + if (this._activeRoomId) this._emit(this._activeRoomId, this._activeRoomId); } } From 7b6c8633772c0deff41e59f1d2b582ff5efeeb27 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 14 Dec 2018 15:53:52 +0100 Subject: [PATCH 30/42] fix lint --- src/components/structures/GroupGridView.js | 19 +++++++++++-------- src/stores/OpenRoomsStore.js | 7 ++++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index abfd343309..b80eeced0c 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -16,7 +16,6 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import OpenRoomsStore from '../../stores/OpenRoomsStore'; import dis from '../../dispatcher'; import RoomView from './RoomView'; @@ -114,13 +113,17 @@ export default class RoomGridView extends React.Component { "mx_GroupGridView_tile": true, "mx_GroupGridView_activeTile": isActive, }); - return (
{this._setActive(i)}} key={roomStore.getRoomId()} className={tileClasses}> - -
); + return (
{this._setActive(i);}} + key={roomStore.getRoomId()} + className={tileClasses} + > + +
); } else { return (
); } diff --git a/src/stores/OpenRoomsStore.js b/src/stores/OpenRoomsStore.js index 764f54d7c2..fabed60c9e 100644 --- a/src/stores/OpenRoomsStore.js +++ b/src/stores/OpenRoomsStore.js @@ -182,7 +182,7 @@ class OpenRoomsStore extends Store { auto_join: payload.auto_join, oob_data: payload.oob_data, }); - } catch(err) { + } catch (err) { this._forwardAction({ action: 'view_room_error', room_id: null, @@ -223,6 +223,7 @@ class OpenRoomsStore extends Store { } __onDispatch(payload) { + let proposedIndex; switch (payload.action) { // view_room: // - room_alias: '#somealias:matrix.org' @@ -253,10 +254,10 @@ class OpenRoomsStore extends Store { this._forwardingEvent = payload.event; break; case 'group_grid_set_active': - const proposedIndex = this._roomIndex(payload); + proposedIndex = this._roomIndex(payload); if (proposedIndex !== -1) { this._setState({ - currentIndex: proposedIndex + currentIndex: proposedIndex, }); } break; From b63bd5ea5453c08d05dd6002c5c6c6d704647b00 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 7 Jan 2019 14:59:00 +0100 Subject: [PATCH 31/42] allow right panel to be hidden (although container is still visible) --- src/components/structures/GroupGridView.js | 4 ++-- src/components/structures/LoggedInView.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index b80eeced0c..ece4e5fa23 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -97,8 +97,8 @@ export default class RoomGridView extends React.Component { if (activeRoomId) { rightPanel = (
-
- +
+ { !this.props.collapsedRhs ? : undefined }
); } diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 74274a5be2..67d7d41701 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -452,7 +452,7 @@ const LoggedInView = React.createClass({ />; break; case PageTypes.GroupGridView: - page_element = ; + page_element = ; break; case PageTypes.UserSettings: page_element = Date: Mon, 7 Jan 2019 15:20:39 +0100 Subject: [PATCH 32/42] clear width of right panel container when collapsed in grid view --- src/components/structures/GroupGridView.js | 2 +- src/components/structures/MainSplit.js | 15 +++++++++------ src/resizer/resizer.js | 10 +++++++++- src/resizer/sizer.js | 8 ++++++++ 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index ece4e5fa23..c8d5f59323 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -104,7 +104,7 @@ export default class RoomGridView extends React.Component { } return (
- +
{ roomStores.map((roomStore, i) => { if (roomStore) { diff --git a/src/components/structures/MainSplit.js b/src/components/structures/MainSplit.js index 0427130eea..aa27930ce0 100644 --- a/src/components/structures/MainSplit.js +++ b/src/components/structures/MainSplit.js @@ -71,14 +71,17 @@ export default class MainSplit extends React.Component { } componentDidUpdate(prevProps) { - const wasExpanded = !this.props.collapsedRhs && prevProps.collapsedRhs; - const wasCollapsed = this.props.collapsedRhs && !prevProps.collapsedRhs; - const wasPanelSet = this.props.panel && !prevProps.panel; - const wasPanelCleared = !this.props.panel && prevProps.panel; + const shouldAllowResizing = + !this.props.disableSizing && + !this.props.collapsedRhs && + this.props.panel; - if (wasExpanded || wasPanelSet) { + if (shouldAllowResizing && !this.resizer) { this._createResizer(); - } else if (wasCollapsed || wasPanelCleared) { + } else if (!shouldAllowResizing && this.resizer) { + if (this.props.disableSizing) { + this.resizer.clearItemSizes(); + } this.resizer.detach(); this.resizer = null; } diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index 0e113b3664..ff2120b341 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -43,6 +43,14 @@ export class Resizer { this._onMouseDown = this._onMouseDown.bind(this); } + clearItemSizes() { + const handles = this._getResizeHandles(); + handles.forEach((handle) => { + const {sizer, item} = this._createSizerAndDistributor(handle); + sizer.clearItemSize(item); + }); + } + setClassNames(classNames) { this.classNames = classNames; } @@ -134,7 +142,7 @@ export class Resizer { const distributor = new this.distributorCtor( sizer, item, id, this.distributorCfg, items, this.container); - return {sizer, distributor}; + return {sizer, distributor, item}; } _getResizableItems() { diff --git a/src/resizer/sizer.js b/src/resizer/sizer.js index 303214854b..0e2236814e 100644 --- a/src/resizer/sizer.js +++ b/src/resizer/sizer.js @@ -82,6 +82,14 @@ class Sizer { } } + clearItemSize(item, size) { + if (this.vertical) { + item.style.height = null; + } else { + item.style.width = null; + } + } + /** @param {MouseEvent} event the mouse event @return {number} the distance between the cursor and the edge of the container, From 8fa7ec0fac7df925de97cc400691999b7ecc1e65 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 7 Jan 2019 16:03:24 +0100 Subject: [PATCH 33/42] fix lint --- src/components/structures/GroupGridView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index c8d5f59323..4c488941d0 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -104,7 +104,7 @@ export default class RoomGridView extends React.Component { } return (
- +
{ roomStores.map((roomStore, i) => { if (roomStore) { From c2f6fc381cf63a63bc4c9fab093ecccacbb5bbd9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 7 Jan 2019 16:13:35 +0100 Subject: [PATCH 34/42] add feature flag for grid view --- .../views/context_menus/TagTileContextMenu.js | 23 +++++++++++-------- src/i18n/strings/en_EN.json | 3 ++- src/settings/Settings.js | 6 +++++ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/components/views/context_menus/TagTileContextMenu.js b/src/components/views/context_menus/TagTileContextMenu.js index 5cd5aea27a..ad93783485 100644 --- a/src/components/views/context_menus/TagTileContextMenu.js +++ b/src/components/views/context_menus/TagTileContextMenu.js @@ -21,6 +21,7 @@ import dis from '../../../dispatcher'; import TagOrderActions from '../../../actions/TagOrderActions'; import MatrixClientPeg from '../../../MatrixClientPeg'; import sdk from '../../../index'; +import SettingsStore from "../../../settings/SettingsStore"; export default class TagTileContextMenu extends React.Component { static propTypes = { @@ -64,6 +65,18 @@ export default class TagTileContextMenu extends React.Component { render() { const TintableSvg = sdk.getComponent("elements.TintableSvg"); + let gridViewOption; + if (SettingsStore.isFeatureEnabled("feature_gridview")) { + gridViewOption = (
+ + { _t('View as grid') } +
); + } return
{ _t('View Community') }
-
- - { _t('View as grid') } -
+ { gridViewOption }
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 8822bd6388..4fab9ec438 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1405,5 +1405,6 @@ "Failed to set direct chat tag": "Failed to set direct chat tag", "Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room", "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room", - "View as grid": "View as grid" + "View as grid": "View as grid", + "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu": "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu" } diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 14f4bdc6dd..8edec434bf 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -102,6 +102,12 @@ export const SETTINGS = { supportedLevels: LEVELS_FEATURE, default: false, }, + "feature_gridview": { + isFeature: true, + displayName: _td("Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu"), + supportedLevels: LEVELS_FEATURE, + default: false, + }, "MessageComposerInput.dontSuggestEmoji": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, displayName: _td('Disable Emoji suggestions while typing'), From aedc220b62a2414251c792fb111b9d421d7e17f6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 7 Jan 2019 16:33:23 +0100 Subject: [PATCH 35/42] fix (some) lint warnings --- src/components/structures/GroupGridView.js | 2 -- src/stores/OpenRoomsStore.js | 18 +++++++++--------- src/utils/Timer.js | 1 - 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index 4c488941d0..2eb3c357df 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -25,7 +25,6 @@ import RightPanel from './RightPanel'; import RoomHeaderButtons from '../views/right_panel/RoomHeaderButtons'; export default class RoomGridView extends React.Component { - constructor(props) { super(props); this.state = { @@ -132,5 +131,4 @@ export default class RoomGridView extends React.Component {
); } - } diff --git a/src/stores/OpenRoomsStore.js b/src/stores/OpenRoomsStore.js index fabed60c9e..21f02fe28d 100644 --- a/src/stores/OpenRoomsStore.js +++ b/src/stores/OpenRoomsStore.js @@ -98,18 +98,18 @@ class OpenRoomsStore extends Store { }); } - _createOpenRoom(room_id, room_alias) { + _createOpenRoom(roomId, roomAlias) { const dispatcher = new MatrixDispatcher(); // forward all actions coming from the room dispatcher // to the global one const dispatcherRef = dispatcher.register((payload) => { // block a view_room action for the same room because it will switch to // single room mode in MatrixChat - if (payload.action === 'view_room' && room_id === payload.room_id) { + if (payload.action === 'view_room' && roomId === payload.room_id) { return; } - payload.grid_src_room_id = room_id; - payload.grid_src_room_alias = room_alias; + payload.grid_src_room_id = roomId; + payload.grid_src_room_alias = roomAlias; this.getDispatcher().dispatch(payload); }); const openRoom = { @@ -120,8 +120,8 @@ class OpenRoomsStore extends Store { dispatcher.dispatch({ action: 'view_room', - room_id: room_id, - room_alias: room_alias, + room_id: roomId, + room_alias: roomAlias, }, true); return openRoom; @@ -134,16 +134,16 @@ class OpenRoomsStore extends Store { }); } - _setGroupOpenRooms(group_id) { + _setGroupOpenRooms(groupId) { this._cleanupOpenRooms(); // TODO: register to GroupStore updates - const rooms = GroupStore.getGroupRooms(group_id); + const rooms = GroupStore.getGroupRooms(groupId); const openRooms = rooms.map((room) => { return this._createOpenRoom(room.roomId); }); this._setState({ rooms: openRooms, - group_id: group_id, + group_id: groupId, currentIndex: 0, }); } diff --git a/src/utils/Timer.js b/src/utils/Timer.js index aeac0887c9..4953cf54f7 100644 --- a/src/utils/Timer.js +++ b/src/utils/Timer.js @@ -26,7 +26,6 @@ Once a timer is finished or aborted, it can't be started again a new one through `clone()` or `cloneIfRun()`. */ export default class Timer { - constructor(timeout) { this._timeout = timeout; this._onTimeout = this._onTimeout.bind(this); From c6952ba5b603a3d5285355f3f69b3e28ed9e717b Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 7 Jan 2019 16:56:35 +0100 Subject: [PATCH 36/42] fix some more lint warnings, as limit is 16 now --- src/components/views/right_panel/HeaderButtons.js | 1 - src/utils/Timer.js | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/views/right_panel/HeaderButtons.js b/src/components/views/right_panel/HeaderButtons.js index f0479eb8be..3f5f58121d 100644 --- a/src/components/views/right_panel/HeaderButtons.js +++ b/src/components/views/right_panel/HeaderButtons.js @@ -78,7 +78,6 @@ export default class HeaderButtons extends React.Component { // till show_right_panel, just without the fromHeader flag // as that would hide the right panel again dis.dispatch(Object.assign({}, payload, {fromHeader: false})); - } this.setState({ phase: payload.phase, diff --git a/src/utils/Timer.js b/src/utils/Timer.js index 4953cf54f7..ca06237fbf 100644 --- a/src/utils/Timer.js +++ b/src/utils/Timer.js @@ -69,6 +69,7 @@ export default class Timer { /** * if not started before, starts the timer. + * @returns {Timer} the same timer */ start() { if (!this.isRunning()) { @@ -80,6 +81,7 @@ export default class Timer { /** * (re)start the timer. If it's running, reset the timeout. If not, start it. + * @returns {Timer} the same timer */ restart() { if (this.isRunning()) { @@ -97,6 +99,7 @@ export default class Timer { /** * if the timer is running, abort it, * and reject the promise for this timer. + * @returns {Timer} the same timer */ abort() { if (this.isRunning()) { From c9272c48e0834f953743ccb01911743c0bfa663a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 8 Jan 2019 12:05:06 +0100 Subject: [PATCH 37/42] undo unneeded changes --- src/components/structures/MainSplit.js | 4 ---- src/resizer/resizer.js | 10 +--------- src/resizer/sizer.js | 8 -------- 3 files changed, 1 insertion(+), 21 deletions(-) diff --git a/src/components/structures/MainSplit.js b/src/components/structures/MainSplit.js index aa27930ce0..e1bbde1d97 100644 --- a/src/components/structures/MainSplit.js +++ b/src/components/structures/MainSplit.js @@ -72,16 +72,12 @@ export default class MainSplit extends React.Component { componentDidUpdate(prevProps) { const shouldAllowResizing = - !this.props.disableSizing && !this.props.collapsedRhs && this.props.panel; if (shouldAllowResizing && !this.resizer) { this._createResizer(); } else if (!shouldAllowResizing && this.resizer) { - if (this.props.disableSizing) { - this.resizer.clearItemSizes(); - } this.resizer.detach(); this.resizer = null; } diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index ff2120b341..0e113b3664 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -43,14 +43,6 @@ export class Resizer { this._onMouseDown = this._onMouseDown.bind(this); } - clearItemSizes() { - const handles = this._getResizeHandles(); - handles.forEach((handle) => { - const {sizer, item} = this._createSizerAndDistributor(handle); - sizer.clearItemSize(item); - }); - } - setClassNames(classNames) { this.classNames = classNames; } @@ -142,7 +134,7 @@ export class Resizer { const distributor = new this.distributorCtor( sizer, item, id, this.distributorCfg, items, this.container); - return {sizer, distributor, item}; + return {sizer, distributor}; } _getResizableItems() { diff --git a/src/resizer/sizer.js b/src/resizer/sizer.js index 0e2236814e..303214854b 100644 --- a/src/resizer/sizer.js +++ b/src/resizer/sizer.js @@ -82,14 +82,6 @@ class Sizer { } } - clearItemSize(item, size) { - if (this.vertical) { - item.style.height = null; - } else { - item.style.width = null; - } - } - /** @param {MouseEvent} event the mouse event @return {number} the distance between the cursor and the edge of the container, From 7227049c2a98db1b1c7fee33a342e7be7a86055b Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 8 Jan 2019 12:05:39 +0100 Subject: [PATCH 38/42] add right panel toggle button to room header when in grid --- res/img/feather-icons/toggle-right-panel.svg | 17 +++++++++++++++++ src/components/structures/GroupGridView.js | 7 ++++--- src/components/views/rooms/RoomHeader.js | 17 +++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 res/img/feather-icons/toggle-right-panel.svg diff --git a/res/img/feather-icons/toggle-right-panel.svg b/res/img/feather-icons/toggle-right-panel.svg new file mode 100644 index 0000000000..4cadf89564 --- /dev/null +++ b/res/img/feather-icons/toggle-right-panel.svg @@ -0,0 +1,17 @@ + + + + Group 2 + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index 2eb3c357df..b5e511db41 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -96,14 +96,14 @@ export default class RoomGridView extends React.Component { if (activeRoomId) { rightPanel = (
-
- { !this.props.collapsedRhs ? : undefined } +
+
); } return (
- +
{ roomStores.map((roomStore, i) => { if (roomStore) { @@ -118,6 +118,7 @@ export default class RoomGridView extends React.Component { className={tileClasses} > ; } + let toggleRightPanelButton; + if (this.props.isGrid) { + toggleRightPanelButton = + + ; + } + return (
@@ -420,6 +436,7 @@ module.exports = React.createClass({ { cancelButton } { rightRow } { !this.props.isGrid ? : undefined } + { toggleRightPanelButton }
); From 56726ba8e592bc9496f5f6c95ce3211ffd908478 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 8 Jan 2019 12:10:42 +0100 Subject: [PATCH 39/42] fix lint --- src/UserActivity.js | 1 + src/components/views/rooms/RoomHeader.js | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/UserActivity.js b/src/UserActivity.js index 4e3667274c..145b23e36e 100644 --- a/src/UserActivity.js +++ b/src/UserActivity.js @@ -44,6 +44,7 @@ class UserActivity { * Can be called multiple times with the same already running timer, which is a NO-OP. * Can be called before the user becomes active, in which case it is only started * later on when the user does become active. + * @param {Timer} timer the timer to use */ timeWhileActive(timer) { // important this happens first diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index 12258154ef..91ca73dd59 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -420,7 +420,11 @@ module.exports = React.createClass({ let toggleRightPanelButton; if (this.props.isGrid) { - toggleRightPanelButton = + toggleRightPanelButton = + ; } From 52c5610660c5dcec972fed536e02677aadf73324 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 8 Jan 2019 14:35:06 +0100 Subject: [PATCH 40/42] update copy --- src/components/views/context_menus/TagTileContextMenu.js | 2 +- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/context_menus/TagTileContextMenu.js b/src/components/views/context_menus/TagTileContextMenu.js index ad93783485..de20f42a7b 100644 --- a/src/components/views/context_menus/TagTileContextMenu.js +++ b/src/components/views/context_menus/TagTileContextMenu.js @@ -74,7 +74,7 @@ export default class TagTileContextMenu extends React.Component { width="15" height="15" /> - { _t('View as grid') } + { _t('View as Grid') }
); } return
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 4fab9ec438..8c544ee3b6 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1405,6 +1405,6 @@ "Failed to set direct chat tag": "Failed to set direct chat tag", "Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room", "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room", - "View as grid": "View as grid", + "View as Grid": "View as Grid", "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu": "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu" } From 9e67dbf0086c822062c80b8031717d87f40c9324 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 8 Jan 2019 14:35:26 +0100 Subject: [PATCH 41/42] change icon --- res/img/icons-gridview.svg | 103 ------------------ .../views/context_menus/TagTileContextMenu.js | 2 +- 2 files changed, 1 insertion(+), 104 deletions(-) delete mode 100644 res/img/icons-gridview.svg diff --git a/res/img/icons-gridview.svg b/res/img/icons-gridview.svg deleted file mode 100644 index 862ca63765..0000000000 --- a/res/img/icons-gridview.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/src/components/views/context_menus/TagTileContextMenu.js b/src/components/views/context_menus/TagTileContextMenu.js index de20f42a7b..8ce09bdb2c 100644 --- a/src/components/views/context_menus/TagTileContextMenu.js +++ b/src/components/views/context_menus/TagTileContextMenu.js @@ -70,7 +70,7 @@ export default class TagTileContextMenu extends React.Component { gridViewOption = (
From 254427461da694087279202f1f8781ef277a5166 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 9 Jan 2019 12:48:13 +0100 Subject: [PATCH 42/42] fix PR feedback --- res/css/structures/_GroupGridView.scss | 10 ++++------ res/themes/dark/css/_dark.scss | 4 ++++ res/themes/dharma/css/_dharma.scss | 3 +++ res/themes/light/css/_base.scss | 4 ++++ src/components/structures/GroupGridView.js | 12 ++---------- src/components/views/rooms/MessageComposerInput.js | 3 --- src/i18n/strings/en_EN.json | 3 ++- src/stores/RoomViewStore.js | 4 ++-- 8 files changed, 21 insertions(+), 22 deletions(-) diff --git a/res/css/structures/_GroupGridView.scss b/res/css/structures/_GroupGridView.scss index 9e51af25f9..3a1ff165f1 100644 --- a/res/css/structures/_GroupGridView.scss +++ b/res/css/structures/_GroupGridView.scss @@ -26,7 +26,6 @@ limitations under the License. flex: 1 1 0; } - .mx_GroupGridView_rightPanel { display: flex; flex-direction: column; @@ -55,11 +54,11 @@ limitations under the License. display: flex; } -.mx_GroupGridView_emptyTile::before { +.mx_GroupGridView_emptyTile { display: block; margin-top: 100px; text-align: center; - content: "no room in this tile yet"; + user-select: none; } .mx_GroupGridView_tile { @@ -85,17 +84,16 @@ limitations under the License. .mx_GroupGridView_activeTile:before { border-radius: 14px; - border: 8px solid rgba(134, 193, 165, 0.5); + border: 8px solid $gridview-focus-border-glow-color; margin: -8px; } .mx_GroupGridView_activeTile:after { border-radius: 8px; - border: 2px solid rgba(134, 193, 165, 1); + border: 2px solid $gridview-focus-border-color; margin: -2px; } - .mx_GroupGridView_tile > .mx_RoomView { height: 100%; } diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 636db5b39e..10d512d576 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -162,6 +162,10 @@ $lightbox-bg-color: #454545; $lightbox-fg-color: #ffffff; $lightbox-border-color: #ffffff; +/*** GroupGridView ***/ +$gridview-focus-border-glow-color: rgba(134, 193, 165, 0.5); +$gridview-focus-border-color: rgba(134, 193, 165, 1); + $imagebody-giflabel: rgba(1, 1, 1, 0.7); $imagebody-giflabel-border: rgba(1, 1, 1, 0.2); diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 08a287ad71..934e18b2a9 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -183,6 +183,9 @@ $lightbox-bg-color: #454545; $lightbox-fg-color: #ffffff; $lightbox-border-color: #ffffff; +/*** GroupGridView ***/ +$gridview-focus-border-glow-color: rgba(134, 193, 165, 0.5); +$gridview-focus-border-color: rgba(134, 193, 165, 1); // unused? $progressbar-color: #000; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 9fcb58d7f1..aaab5cd93a 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -175,6 +175,10 @@ $lightbox-bg-color: #454545; $lightbox-fg-color: #ffffff; $lightbox-border-color: #ffffff; +/*** GroupGridView ***/ +$gridview-focus-border-glow-color: rgba(134, 193, 165, 0.5); +$gridview-focus-border-color: rgba(134, 193, 165, 1); + $imagebody-giflabel: rgba(0, 0, 0, 0.7); $imagebody-giflabel-border: rgba(0, 0, 0, 0.2); diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js index b5e511db41..a1a9e1b183 100644 --- a/src/components/structures/GroupGridView.js +++ b/src/components/structures/GroupGridView.js @@ -18,6 +18,7 @@ limitations under the License. import React from 'react'; import OpenRoomsStore from '../../stores/OpenRoomsStore'; import dis from '../../dispatcher'; +import {_t} from '../../languageHandler'; import RoomView from './RoomView'; import classNames from 'classnames'; import MainSplit from './MainSplit'; @@ -48,7 +49,6 @@ export default class RoomGridView extends React.Component { componentWillMount() { this._unmounted = false; this._openRoomsStoreRegistration = OpenRoomsStore.addListener(this.onRoomsChanged); - this._dispatcherRef = dis.register(this._onAction); } componentWillUnmount() { @@ -56,7 +56,6 @@ export default class RoomGridView extends React.Component { if (this._openRoomsStoreRegistration) { this._openRoomsStoreRegistration.remove(); } - dis.unregister(this._dispatcherRef); } onRoomsChanged() { @@ -67,13 +66,6 @@ export default class RoomGridView extends React.Component { }); } - _onAction(payload) { - switch (payload.action) { - default: - break; - } - } - _setActive(i) { const store = OpenRoomsStore.getRoomStoreAt(i); if (store !== this.state.activeRoomStore) { @@ -125,7 +117,7 @@ export default class RoomGridView extends React.Component { />
); } else { - return (
); + return (
{_t("No room in this tile yet.")}
); } }) }
diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 0740667242..4e7b4d3bbf 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -356,9 +356,6 @@ export default class MessageComposerInput extends React.Component { componentWillMount() { this.dispatcherRef = this.props.roomViewStore.getDispatcher().register(this.onAction); if (this.props.isGrid) { - - - this.historyManager = new NoopHistoryManager(); } else { this.historyManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_'); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 8c544ee3b6..d6d70dfadd 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1406,5 +1406,6 @@ "Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room", "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room", "View as Grid": "View as Grid", - "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu": "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu" + "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu": "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu", + "No room in this tile yet.": "No room in this tile yet." } diff --git a/src/stores/RoomViewStore.js b/src/stores/RoomViewStore.js index 02c76d05d9..a0b831ad17 100644 --- a/src/stores/RoomViewStore.js +++ b/src/stores/RoomViewStore.js @@ -307,6 +307,6 @@ export class RoomViewStore extends Store { } const MatrixDispatcher = require("../matrix-dispatcher"); -const blubber = new RoomViewStore(new MatrixDispatcher()); +const backwardsCompatInstance = new RoomViewStore(new MatrixDispatcher()); -export default blubber; +export default backwardsCompatInstance;