Merge pull request #2451 from matrix-org/bwindels/revertgridview

Revert "Tiled room UI"
pull/21833/head
Bruno Windels 2019-01-17 12:09:37 +00:00 committed by GitHub
commit e7359ff115
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 187 additions and 842 deletions

View File

@ -5,7 +5,6 @@
@import "./structures/_ContextualMenu.scss"; @import "./structures/_ContextualMenu.scss";
@import "./structures/_CreateRoom.scss"; @import "./structures/_CreateRoom.scss";
@import "./structures/_FilePanel.scss"; @import "./structures/_FilePanel.scss";
@import "./structures/_GroupGridView.scss";
@import "./structures/_GroupView.scss"; @import "./structures/_GroupView.scss";
@import "./structures/_HomePage.scss"; @import "./structures/_HomePage.scss";
@import "./structures/_LeftPanel.scss"; @import "./structures/_LeftPanel.scss";

View File

@ -1,130 +0,0 @@
/*
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: flex;
flex-direction: column;
}
.mx_GroupGridView_rooms {
display: grid;
grid-template-columns: repeat(3, calc(100% / 3));
grid-template-rows: repeat(2, calc(100% / 2));
flex: 1 1 0;
min-width: 0;
}
.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;
}
.mx_GroupGridView_emptyTile {
display: block;
margin-top: 100px;
text-align: center;
user-select: none;
}
.mx_GroupGridView_tile {
border-right: 1px solid $panel-divider-color;
border-bottom: 1px solid $panel-divider-color;
}
.mx_GroupGridView_activeTile {
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: 3500;
}
.mx_GroupGridView_activeTile:before {
border-radius: 14px;
border: 8px solid $gridview-focus-border-glow-color;
margin: -8px;
}
.mx_GroupGridView_activeTile:after {
border-radius: 8px;
border: 2px solid $gridview-focus-border-color;
margin: -2px;
}
.mx_GroupGridView_tile > .mx_RoomView {
height: 100%;
}
.mx_GroupGridView_rooms > *:nth-child(1) {
grid-column: 1;
grid-row: 1;
}
.mx_GroupGridView_rooms > *:nth-child(2) {
grid-column: 2;
grid-row: 1;
}
.mx_GroupGridView_rooms > *:nth-child(3) {
grid-column: 3;
grid-row: 1;
}
.mx_GroupGridView_rooms > *:nth-child(4) {
grid-column: 1;
grid-row: 2;
}
.mx_GroupGridView_rooms > *:nth-child(5) {
grid-column: 2;
grid-row: 2;
}
.mx_GroupGridView_rooms > *:nth-child(6) {
grid-column: 3;
grid-row: 2;
}

View File

@ -81,8 +81,7 @@ limitations under the License.
Empirically this stops the MessagePanel's width exploding outwards when Empirically this stops the MessagePanel's width exploding outwards when
gemini is in 'prevented' mode gemini is in 'prevented' mode
*/ */
// disabling this for now as it clips the active room rect on the grid view overflow-x: auto;
// overflow-x: auto;
/* To fix https://github.com/vector-im/riot-web/issues/3298 where Safari /* 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 needed height 100% all the way down to the HomePage. Height does not

View File

@ -53,10 +53,6 @@ limitations under the License.
.mx_MemberList_query, .mx_MemberList_query,
.mx_GroupMemberList_query, .mx_GroupMemberList_query,
.mx_GroupRoomList_query { .mx_GroupRoomList_query {
flex: 0 0 auto;
}
.mx_MemberList .gm-scrollbar-container {
flex: 1 1 0; flex: 1 1 0;
} }

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="14px" viewBox="0 0 22 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
<title>Group 2</title>
<desc>Created with Sketch.</desc>
<g id="Experiments" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
<g id="multi-room-test-copy-8" transform="translate(-826.000000, -15.000000)" stroke="#929EB4" stroke-width="1.6">
<g id="Group-4" transform="translate(341.000000, 7.000000)">
<g id="Group-2" transform="translate(486.000000, 8.000000)">
<path d="M20,1 L2.30926389e-14,1" id="Line-10"></path>
<path d="M20,7 L3,7" id="Line-10-Copy"></path>
<path d="M20,13 L6,13" id="Line-10-Copy-2"></path>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 995 B

View File

@ -162,10 +162,6 @@ $lightbox-bg-color: #454545;
$lightbox-fg-color: #ffffff; $lightbox-fg-color: #ffffff;
$lightbox-border-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: rgba(1, 1, 1, 0.7);
$imagebody-giflabel-border: rgba(1, 1, 1, 0.2); $imagebody-giflabel-border: rgba(1, 1, 1, 0.2);
$imagebody-giflabel-color: rgba(0, 0, 0, 1); $imagebody-giflabel-color: rgba(0, 0, 0, 1);

View File

@ -184,9 +184,6 @@ $lightbox-bg-color: #454545;
$lightbox-fg-color: #ffffff; $lightbox-fg-color: #ffffff;
$lightbox-border-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? // unused?
$progressbar-color: #000; $progressbar-color: #000;

View File

@ -175,10 +175,6 @@ $lightbox-bg-color: #454545;
$lightbox-fg-color: #ffffff; $lightbox-fg-color: #ffffff;
$lightbox-border-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: rgba(0, 0, 0, 0.7);
$imagebody-giflabel-border: rgba(0, 0, 0, 0.2); $imagebody-giflabel-border: rgba(0, 0, 0, 0.2);
$imagebody-giflabel-color: rgba(255, 255, 255, 1); $imagebody-giflabel-color: rgba(255, 255, 255, 1);

View File

@ -14,10 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import OpenRoomsStore from './stores/OpenRoomsStore'; import RoomViewStore from './stores/RoomViewStore';
/** /**
* Consumes changes from the OpenRoomsStore and notifies specific things * Consumes changes from the RoomViewStore and notifies specific things
* about when the active room changes. Unlike listening for RoomViewStore * about when the active room changes. Unlike listening for RoomViewStore
* changes, you can subscribe to only changes relevant to a particular * changes, you can subscribe to only changes relevant to a particular
* room. * room.
@ -28,15 +28,11 @@ import OpenRoomsStore from './stores/OpenRoomsStore';
class ActiveRoomObserver { class ActiveRoomObserver {
constructor() { constructor() {
this._listeners = {}; this._listeners = {};
const roomStore = OpenRoomsStore.getActiveRoomStore();
this._activeRoomId = roomStore && roomStore.getRoomId(); this._activeRoomId = RoomViewStore.getRoomId();
// TODO: We could self-destruct when the last listener goes away, or at least // TODO: We could self-destruct when the last listener goes away, or at least
// stop listening. // stop listening.
this._roomStoreToken = OpenRoomsStore.addListener(this._onOpenRoomsStoreUpdate.bind(this)); this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate.bind(this));
}
getActiveRoomId() {
return this._activeRoomId;
} }
addListener(roomId, listener) { addListener(roomId, listener) {
@ -55,23 +51,23 @@ class ActiveRoomObserver {
} }
} }
_emit(roomId, newActiveRoomId) { _emit(roomId) {
if (!this._listeners[roomId]) return; if (!this._listeners[roomId]) return;
for (const l of this._listeners[roomId]) { for (const l of this._listeners[roomId]) {
l.call(l, newActiveRoomId); l.call();
} }
} }
_onOpenRoomsStoreUpdate() { _onRoomViewStoreUpdate() {
const activeRoomStore = OpenRoomsStore.getActiveRoomStore();
const newActiveRoomId = activeRoomStore && activeRoomStore.getRoomId();
// emit for the old room ID // emit for the old room ID
if (this._activeRoomId) this._emit(this._activeRoomId, newActiveRoomId); if (this._activeRoomId) this._emit(this._activeRoomId);
// update our cache // update our cache
this._activeRoomId = newActiveRoomId; this._activeRoomId = RoomViewStore.getRoomId();
// and emit for the new one // and emit for the new one
if (this._activeRoomId) this._emit(this._activeRoomId, this._activeRoomId); if (this._activeRoomId) this._emit(this._activeRoomId);
} }
} }

View File

@ -19,7 +19,6 @@ limitations under the License.
export default { export default {
HomePage: "home_page", HomePage: "home_page",
RoomView: "room_view", RoomView: "room_view",
GroupGridView: "group_grid_view",
UserSettings: "user_settings", UserSettings: "user_settings",
RoomDirectory: "room_directory", RoomDirectory: "room_directory",
UserView: "user_view", UserView: "user_view",

View File

@ -1,127 +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 OpenRoomsStore from '../../stores/OpenRoomsStore';
import dis from '../../dispatcher';
import {_t} from '../../languageHandler';
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 {
constructor(props) {
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);
}
componentWillUnmount() {
this._unmounted = true;
if (this._openRoomsStoreRegistration) {
this._openRoomsStoreRegistration.remove();
}
}
onRoomsChanged() {
if (this._unmounted) return;
this.setState({
roomStores: OpenRoomsStore.getRoomStores(),
activeRoomStore: OpenRoomsStore.getActiveRoomStore(),
});
}
_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;
if (emptyCount) {
const emptyTiles = Array.from({length: emptyCount}, () => null);
roomStores = roomStores.concat(emptyTiles);
}
const activeRoomId = this.state.activeRoomStore && this.state.activeRoomStore.getRoomId();
let rightPanel;
if (activeRoomId) {
rightPanel = (
<div className="mx_GroupGridView_rightPanel">
<div className="mx_GroupGridView_tabs"><RoomHeaderButtons /></div>
<RightPanel roomId={activeRoomId} />
</div>
);
}
return (<main className="mx_GroupGridView">
<MainSplit panel={rightPanel} collapsedRhs={this.props.collapsedRhs} >
<div className="mx_GroupGridView_rooms">
{ roomStores.map((roomStore, i) => {
if (roomStore) {
const isActive = roomStore === this.state.activeRoomStore;
const tileClasses = classNames({
"mx_GroupGridView_tile": true,
"mx_GroupGridView_activeTile": isActive,
});
return (<section
onClick={() => {this._setActive(i);}}
key={roomStore.getRoomId()}
className={tileClasses}
>
<RoomView
collapsedRhs={this.props.collapsedRhs}
isGrid={true}
roomViewStore={roomStore}
isActive={isActive}
/>
</section>);
} else {
return (<section className={"mx_GroupGridView_emptyTile"} key={`empty-${i}`}>{_t("No room in this tile yet.")}</section>);
}
}) }
</div>
</MainSplit>
</main>);
}
}

View File

@ -31,7 +31,6 @@ import sessionStore from '../../stores/SessionStore';
import MatrixClientPeg from '../../MatrixClientPeg'; import MatrixClientPeg from '../../MatrixClientPeg';
import SettingsStore from "../../settings/SettingsStore"; import SettingsStore from "../../settings/SettingsStore";
import RoomListStore from "../../stores/RoomListStore"; import RoomListStore from "../../stores/RoomListStore";
import OpenRoomsStore from "../../stores/OpenRoomsStore";
import TagOrderActions from '../../actions/TagOrderActions'; import TagOrderActions from '../../actions/TagOrderActions';
import RoomListActions from '../../actions/RoomListActions'; import RoomListActions from '../../actions/RoomListActions';
@ -417,7 +416,6 @@ const LoggedInView = React.createClass({
const RoomDirectory = sdk.getComponent('structures.RoomDirectory'); const RoomDirectory = sdk.getComponent('structures.RoomDirectory');
const HomePage = sdk.getComponent('structures.HomePage'); const HomePage = sdk.getComponent('structures.HomePage');
const GroupView = sdk.getComponent('structures.GroupView'); const GroupView = sdk.getComponent('structures.GroupView');
const GroupGridView = sdk.getComponent('structures.GroupGridView');
const MyGroups = sdk.getComponent('structures.MyGroups'); const MyGroups = sdk.getComponent('structures.MyGroups');
const MatrixToolbar = sdk.getComponent('globals.MatrixToolbar'); const MatrixToolbar = sdk.getComponent('globals.MatrixToolbar');
const CookieBar = sdk.getComponent('globals.CookieBar'); const CookieBar = sdk.getComponent('globals.CookieBar');
@ -430,14 +428,7 @@ const LoggedInView = React.createClass({
switch (this.props.page_type) { switch (this.props.page_type) {
case PageTypes.RoomView: case PageTypes.RoomView:
if (!OpenRoomsStore.getActiveRoomStore()) {
console.warn(`LoggedInView: getCurrentRoomStore not set!`);
}
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 = <RoomView page_element = <RoomView
roomViewStore={OpenRoomsStore.getActiveRoomStore()}
ref='roomView' ref='roomView'
autoJoin={this.props.autoJoin} autoJoin={this.props.autoJoin}
onRegistered={this.props.onRegistered} onRegistered={this.props.onRegistered}
@ -451,9 +442,7 @@ const LoggedInView = React.createClass({
ConferenceHandler={this.props.ConferenceHandler} ConferenceHandler={this.props.ConferenceHandler}
/>; />;
break; break;
case PageTypes.GroupGridView:
page_element = <GroupGridView collapsedRhs={this.props.collapsedRhs} />;
break;
case PageTypes.UserSettings: case PageTypes.UserSettings:
page_element = <UserSettings page_element = <UserSettings
onClose={this.props.onCloseAllSettings} onClose={this.props.onCloseAllSettings}

View File

@ -71,13 +71,14 @@ export default class MainSplit extends React.Component {
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
const shouldAllowResizing = const wasExpanded = !this.props.collapsedRhs && prevProps.collapsedRhs;
!this.props.collapsedRhs && const wasCollapsed = this.props.collapsedRhs && !prevProps.collapsedRhs;
this.props.panel; const wasPanelSet = this.props.panel && !prevProps.panel;
const wasPanelCleared = !this.props.panel && prevProps.panel;
if (shouldAllowResizing && !this.resizer) { if (wasExpanded || wasPanelSet) {
this._createResizer(); this._createResizer();
} else if (!shouldAllowResizing && this.resizer) { } else if (wasCollapsed || wasPanelCleared) {
this.resizer.detach(); this.resizer.detach();
this.resizer = null; this.resizer = null;
} }

View File

@ -651,9 +651,6 @@ export default React.createClass({
case 'view_group': case 'view_group':
this._viewGroup(payload); this._viewGroup(payload);
break; break;
case 'group_grid_view':
this._viewGroupGrid(payload);
break;
case 'view_home_page': case 'view_home_page':
this._viewHome(); this._viewHome();
break; break;
@ -865,7 +862,6 @@ export default React.createClass({
// room name and avatar from an invite email) // room name and avatar from an invite email)
_viewRoom: function(roomInfo) { _viewRoom: function(roomInfo) {
this.focusComposer = true; this.focusComposer = true;
console.log("!!! MatrixChat._viewRoom", roomInfo);
const newState = { const newState = {
currentRoomId: roomInfo.room_id || null, currentRoomId: roomInfo.room_id || null,
@ -914,9 +910,6 @@ export default React.createClass({
if (roomInfo.event_id && roomInfo.highlighted) { if (roomInfo.event_id && roomInfo.highlighted) {
presentedId += "/" + roomInfo.event_id; presentedId += "/" + roomInfo.event_id;
} }
// TODO: only emit this when we're not in grid mode?
this.notifyNewScreen('room/' + presentedId); this.notifyNewScreen('room/' + presentedId);
newState.ready = true; newState.ready = true;
this.setState(newState); this.setState(newState);
@ -933,11 +926,6 @@ export default React.createClass({
this.notifyNewScreen('group/' + groupId); this.notifyNewScreen('group/' + groupId);
}, },
_viewGroupGrid: function(payload) {
this._setPage(PageTypes.GroupGridView);
// this.notifyNewScreen('grid/' + payload.group_id);
},
_viewHome: function() { _viewHome: function() {
// The home page requires the "logged in" view, so we'll set that. // The home page requires the "logged in" view, so we'll set that.
this.setStateForNewView({ this.setStateForNewView({

View File

@ -165,7 +165,7 @@ export default class RightPanel extends React.Component {
} else if (this.state.phase === RightPanel.Phase.GroupRoomList) { } else if (this.state.phase === RightPanel.Phase.GroupRoomList) {
panel = <GroupRoomList groupId={this.props.groupId} key={this.props.groupId} />; panel = <GroupRoomList groupId={this.props.groupId} key={this.props.groupId} />;
} else if (this.state.phase === RightPanel.Phase.RoomMemberInfo) { } else if (this.state.phase === RightPanel.Phase.RoomMemberInfo) {
panel = <MemberInfo roomId={this.props.roomId} member={this.state.member} key={this.props.roomId || this.state.member.userId} />; panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.state.member.userId} />;
} else if (this.state.phase === RightPanel.Phase.GroupMemberInfo) { } else if (this.state.phase === RightPanel.Phase.GroupMemberInfo) {
panel = <GroupMemberInfo panel = <GroupMemberInfo
groupMember={this.state.member} groupMember={this.state.member}

View File

@ -36,6 +36,7 @@ const ContentMessages = require("../../ContentMessages");
const Modal = require("../../Modal"); const Modal = require("../../Modal");
const sdk = require('../../index'); const sdk = require('../../index');
const CallHandler = require('../../CallHandler'); const CallHandler = require('../../CallHandler');
const dis = require("../../dispatcher");
const Tinter = require("../../Tinter"); const Tinter = require("../../Tinter");
const rate_limited_func = require('../../ratelimitedfunc'); const rate_limited_func = require('../../ratelimitedfunc');
const ObjectUtils = require('../../ObjectUtils'); const ObjectUtils = require('../../ObjectUtils');
@ -45,6 +46,7 @@ import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard';
import MainSplit from './MainSplit'; import MainSplit from './MainSplit';
import RightPanel from './RightPanel'; import RightPanel from './RightPanel';
import RoomViewStore from '../../stores/RoomViewStore';
import RoomScrollStateStore from '../../stores/RoomScrollStateStore'; import RoomScrollStateStore from '../../stores/RoomScrollStateStore';
import WidgetEchoStore from '../../stores/WidgetEchoStore'; import WidgetEchoStore from '../../stores/WidgetEchoStore';
import SettingsStore, {SettingLevel} from "../../settings/SettingsStore"; import SettingsStore, {SettingLevel} from "../../settings/SettingsStore";
@ -92,8 +94,6 @@ module.exports = React.createClass({
// Servers the RoomView can use to try and assist joins // Servers the RoomView can use to try and assist joins
viaServers: PropTypes.arrayOf(PropTypes.string), viaServers: PropTypes.arrayOf(PropTypes.string),
// the store for this room view
roomViewStore: PropTypes.object.isRequired,
}, },
getInitialState: function() { getInitialState: function() {
@ -155,7 +155,7 @@ module.exports = React.createClass({
}, },
componentWillMount: function() { componentWillMount: function() {
this.dispatcherRef = this.props.roomViewStore.getDispatcher().register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
MatrixClientPeg.get().on("Room", this.onRoom); MatrixClientPeg.get().on("Room", this.onRoom);
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline); MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
MatrixClientPeg.get().on("Room.name", this.onRoomName); MatrixClientPeg.get().on("Room.name", this.onRoomName);
@ -166,7 +166,7 @@ module.exports = React.createClass({
MatrixClientPeg.get().on("crypto.keyBackupStatus", this.onKeyBackupStatus); MatrixClientPeg.get().on("crypto.keyBackupStatus", this.onKeyBackupStatus);
this._fetchMediaConfig(); this._fetchMediaConfig();
// Start listening for RoomViewStore updates // Start listening for RoomViewStore updates
this._roomStoreToken = this.props.roomViewStore.addListener(this._onRoomViewStoreUpdate); this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
this._onRoomViewStoreUpdate(true); this._onRoomViewStoreUpdate(true);
WidgetEchoStore.on('update', this._onWidgetEchoStoreUpdate); WidgetEchoStore.on('update', this._onWidgetEchoStoreUpdate);
@ -197,8 +197,8 @@ module.exports = React.createClass({
if (this.unmounted) { if (this.unmounted) {
return; return;
} }
const store = this.props.roomViewStore;
if (!initial && this.state.roomId !== store.getRoomId()) { if (!initial && this.state.roomId !== RoomViewStore.getRoomId()) {
// RoomView explicitly does not support changing what room // RoomView explicitly does not support changing what room
// is being viewed: instead it should just be re-mounted when // is being viewed: instead it should just be re-mounted when
// switching rooms. Therefore, if the room ID changes, we // switching rooms. Therefore, if the room ID changes, we
@ -212,21 +212,22 @@ module.exports = React.createClass({
// it was, it means we're about to be unmounted. // it was, it means we're about to be unmounted.
return; return;
} }
const newState = { const newState = {
roomId: store.getRoomId(), roomId: RoomViewStore.getRoomId(),
roomAlias: store.getRoomAlias(), roomAlias: RoomViewStore.getRoomAlias(),
roomLoading: store.isRoomLoading(), roomLoading: RoomViewStore.isRoomLoading(),
roomLoadError: store.getRoomLoadError(), roomLoadError: RoomViewStore.getRoomLoadError(),
joining: store.isJoining(), joining: RoomViewStore.isJoining(),
initialEventId: store.getInitialEventId(), initialEventId: RoomViewStore.getInitialEventId(),
isInitialEventHighlighted: store.isInitialEventHighlighted(), isInitialEventHighlighted: RoomViewStore.isInitialEventHighlighted(),
forwardingEvent: store.getForwardingEvent(), forwardingEvent: RoomViewStore.getForwardingEvent(),
shouldPeek: store.shouldPeek(), shouldPeek: RoomViewStore.shouldPeek(),
showingPinned: SettingsStore.getValue("PinnedEvents.isOpen", store.getRoomId()), showingPinned: SettingsStore.getValue("PinnedEvents.isOpen", RoomViewStore.getRoomId()),
editingRoomSettings: store.isEditingSettings(), editingRoomSettings: RoomViewStore.isEditingSettings(),
}; };
if (this.state.editingRoomSettings && !newState.editingRoomSettings) this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'}); if (this.state.editingRoomSettings && !newState.editingRoomSettings) dis.dispatch({action: 'focus_composer'});
// Temporary logging to diagnose https://github.com/vector-im/riot-web/issues/4307 // Temporary logging to diagnose https://github.com/vector-im/riot-web/issues/4307
console.log( console.log(
@ -388,7 +389,7 @@ module.exports = React.createClass({
// XXX: EVIL HACK to autofocus inviting on empty rooms. // XXX: EVIL HACK to autofocus inviting on empty rooms.
// We use the setTimeout to avoid racing with focus_composer. // We use the setTimeout to avoid racing with focus_composer.
if (this.props.isActive !== false && this.state.room && if (this.state.room &&
this.state.room.getJoinedMemberCount() == 1 && this.state.room.getJoinedMemberCount() == 1 &&
this.state.room.getLiveTimeline() && this.state.room.getLiveTimeline() &&
this.state.room.getLiveTimeline().getEvents() && this.state.room.getLiveTimeline().getEvents() &&
@ -442,7 +443,7 @@ module.exports = React.createClass({
roomView.removeEventListener('dragleave', this.onDragLeaveOrEnd); roomView.removeEventListener('dragleave', this.onDragLeaveOrEnd);
roomView.removeEventListener('dragend', this.onDragLeaveOrEnd); roomView.removeEventListener('dragend', this.onDragLeaveOrEnd);
} }
this.props.roomViewStore.getDispatcher().unregister(this.dispatcherRef); dis.unregister(this.dispatcherRef);
if (MatrixClientPeg.get()) { if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("Room", this.onRoom); MatrixClientPeg.get().removeListener("Room", this.onRoom);
MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline); MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
@ -834,7 +835,7 @@ module.exports = React.createClass({
}, },
onSearchResultsResize: function() { onSearchResultsResize: function() {
this.props.roomViewStore.getDispatcher().dispatch({ action: 'timeline_resize' }, true); dis.dispatch({ action: 'timeline_resize' }, true);
}, },
onSearchResultsFillRequest: function(backwards) { onSearchResultsFillRequest: function(backwards) {
@ -855,7 +856,7 @@ module.exports = React.createClass({
onInviteButtonClick: function() { onInviteButtonClick: function() {
// call AddressPickerDialog // call AddressPickerDialog
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'view_invite', action: 'view_invite',
roomId: this.state.room.roomId, roomId: this.state.room.roomId,
}); });
@ -877,7 +878,7 @@ module.exports = React.createClass({
// Join this room once the user has registered and logged in // Join this room once the user has registered and logged in
const signUrl = this.props.thirdPartyInvite ? const signUrl = this.props.thirdPartyInvite ?
this.props.thirdPartyInvite.inviteSignUrl : undefined; this.props.thirdPartyInvite.inviteSignUrl : undefined;
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'do_after_sync_prepared', action: 'do_after_sync_prepared',
deferred_action: { deferred_action: {
action: 'join_room', action: 'join_room',
@ -887,7 +888,7 @@ module.exports = React.createClass({
// Don't peek whilst registering otherwise getPendingEventList complains // Don't peek whilst registering otherwise getPendingEventList complains
// Do this by indicating our intention to join // Do this by indicating our intention to join
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'will_join', action: 'will_join',
}); });
@ -898,20 +899,20 @@ module.exports = React.createClass({
if (submitted) { if (submitted) {
this.props.onRegistered(credentials); this.props.onRegistered(credentials);
} else { } else {
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'cancel_after_sync_prepared', action: 'cancel_after_sync_prepared',
}); });
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'cancel_join', action: 'cancel_join',
}); });
} }
}, },
onDifferentServerClicked: (ev) => { onDifferentServerClicked: (ev) => {
this.props.roomViewStore.getDispatcher().dispatch({action: 'start_registration'}); dis.dispatch({action: 'start_registration'});
close(); close();
}, },
onLoginClick: (ev) => { onLoginClick: (ev) => {
this.props.roomViewStore.getDispatcher().dispatch({action: 'start_login'}); dis.dispatch({action: 'start_login'});
close(); close();
}, },
}).close; }).close;
@ -921,7 +922,7 @@ module.exports = React.createClass({
Promise.resolve().then(() => { Promise.resolve().then(() => {
const signUrl = this.props.thirdPartyInvite ? const signUrl = this.props.thirdPartyInvite ?
this.props.thirdPartyInvite.inviteSignUrl : undefined; this.props.thirdPartyInvite.inviteSignUrl : undefined;
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'join_room', action: 'join_room',
opts: { inviteSignUrl: signUrl, viaServers: this.props.viaServers }, opts: { inviteSignUrl: signUrl, viaServers: this.props.viaServers },
}); });
@ -986,10 +987,10 @@ module.exports = React.createClass({
}, },
uploadFile: async function(file) { uploadFile: async function(file) {
this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'}); dis.dispatch({action: 'focus_composer'});
if (MatrixClientPeg.get().isGuest()) { if (MatrixClientPeg.get().isGuest()) {
this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'}); dis.dispatch({action: 'require_registration'});
return; return;
} }
@ -1013,14 +1014,14 @@ module.exports = React.createClass({
} }
// Send message_sent callback, for things like _checkIfAlone because after all a file is still a message. // Send message_sent callback, for things like _checkIfAlone because after all a file is still a message.
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'message_sent', action: 'message_sent',
}); });
}, },
injectSticker: function(url, info, text) { injectSticker: function(url, info, text) {
if (MatrixClientPeg.get().isGuest()) { if (MatrixClientPeg.get().isGuest()) {
this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'}); dis.dispatch({action: 'require_registration'});
return; return;
} }
@ -1221,7 +1222,7 @@ module.exports = React.createClass({
}, },
onSettingsClick: function() { onSettingsClick: function() {
this.props.roomViewStore.getDispatcher().dispatch({ action: 'open_room_settings' }); dis.dispatch({ action: 'open_room_settings' });
}, },
onSettingsSaveClick: function() { onSettingsSaveClick: function() {
@ -1254,31 +1255,31 @@ module.exports = React.createClass({
}); });
// still editing room settings // still editing room settings
} else { } else {
this.props.roomViewStore.getDispatcher().dispatch({ action: 'close_settings' }); dis.dispatch({ action: 'close_settings' });
} }
}).finally(() => { }).finally(() => {
this.setState({ this.setState({
uploadingRoomSettings: false, uploadingRoomSettings: false,
}); });
this.props.roomViewStore.getDispatcher().dispatch({ action: 'close_settings' }); dis.dispatch({ action: 'close_settings' });
}).done(); }).done();
}, },
onCancelClick: function() { onCancelClick: function() {
console.log("updateTint from onCancelClick"); console.log("updateTint from onCancelClick");
this.updateTint(); this.updateTint();
this.props.roomViewStore.getDispatcher().dispatch({ action: 'close_settings' }); dis.dispatch({ action: 'close_settings' });
if (this.state.forwardingEvent) { if (this.state.forwardingEvent) {
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'forward_event', action: 'forward_event',
event: null, event: null,
}); });
} }
this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'}); dis.dispatch({action: 'focus_composer'});
}, },
onLeaveClick: function() { onLeaveClick: function() {
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'leave_room', action: 'leave_room',
room_id: this.state.room.roomId, room_id: this.state.room.roomId,
}); });
@ -1286,7 +1287,7 @@ module.exports = React.createClass({
onForgetClick: function() { onForgetClick: function() {
MatrixClientPeg.get().forget(this.state.room.roomId).done(function() { MatrixClientPeg.get().forget(this.state.room.roomId).done(function() {
this.props.roomViewStore.getDispatcher().dispatch({ action: 'view_next_room' }); dis.dispatch({ action: 'view_next_room' });
}, function(err) { }, function(err) {
const errCode = err.errcode || _t("unknown error code"); const errCode = err.errcode || _t("unknown error code");
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
@ -1303,7 +1304,7 @@ module.exports = React.createClass({
rejecting: true, rejecting: true,
}); });
MatrixClientPeg.get().leave(this.state.roomId).done(function() { MatrixClientPeg.get().leave(this.state.roomId).done(function() {
this.props.roomViewStore.getDispatcher().dispatch({ action: 'view_next_room' }); dis.dispatch({ action: 'view_next_room' });
self.setState({ self.setState({
rejecting: false, rejecting: false,
}); });
@ -1329,7 +1330,7 @@ module.exports = React.createClass({
// using /leave rather than /join. In the short term though, we // using /leave rather than /join. In the short term though, we
// just ignore them. // just ignore them.
// https://github.com/vector-im/vector-web/issues/1134 // https://github.com/vector-im/vector-web/issues/1134
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'view_room_directory', action: 'view_room_directory',
}); });
}, },
@ -1348,7 +1349,7 @@ module.exports = React.createClass({
// jump down to the bottom of this room, where new events are arriving // jump down to the bottom of this room, where new events are arriving
jumpToLiveTimeline: function() { jumpToLiveTimeline: function() {
this.refs.messagePanel.jumpToLiveTimeline(); this.refs.messagePanel.jumpToLiveTimeline();
this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'}); dis.dispatch({action: 'focus_composer'});
}, },
// jump up to wherever our read marker is // jump up to wherever our read marker is
@ -1438,7 +1439,7 @@ module.exports = React.createClass({
}, },
onFullscreenClick: function() { onFullscreenClick: function() {
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'video_fullscreen', action: 'video_fullscreen',
fullscreen: true, fullscreen: true,
}, true); }, true);
@ -1563,7 +1564,6 @@ module.exports = React.createClass({
<RoomHeader ref="header" <RoomHeader ref="header"
room={this.state.room} room={this.state.room}
oobData={this.props.oobData} oobData={this.props.oobData}
isGrid={this.props.isGrid}
collapsedRhs={this.props.collapsedRhs} collapsedRhs={this.props.collapsedRhs}
/> />
<div className="mx_RoomView_body"> <div className="mx_RoomView_body">
@ -1610,7 +1610,6 @@ module.exports = React.createClass({
<div className="mx_RoomView"> <div className="mx_RoomView">
<RoomHeader <RoomHeader
ref="header" ref="header"
isGrid={this.props.isGrid}
room={this.state.room} room={this.state.room}
collapsedRhs={this.props.collapsedRhs} collapsedRhs={this.props.collapsedRhs}
/> />
@ -1752,9 +1751,7 @@ module.exports = React.createClass({
if (canSpeak) { if (canSpeak) {
messageComposer = messageComposer =
<MessageComposer <MessageComposer
roomViewStore={this.props.roomViewStore}
room={this.state.room} room={this.state.room}
isGrid={this.props.isGrid}
onResize={this.onChildResize} onResize={this.onChildResize}
uploadFile={this.uploadFile} uploadFile={this.uploadFile}
callState={this.state.callState} callState={this.state.callState}
@ -1881,14 +1878,11 @@ module.exports = React.createClass({
}, },
); );
const rightPanel = this.state.room && !this.props.isGrid ? const rightPanel = this.state.room ? <RightPanel roomId={this.state.room.roomId} /> : undefined;
<RightPanel roomId={this.state.room.roomId} /> :
undefined;
return ( return (
<main className={"mx_RoomView" + (inCall ? " mx_RoomView_inCall" : "")} ref="roomView"> <main className={"mx_RoomView" + (inCall ? " mx_RoomView_inCall" : "")} ref="roomView">
<RoomHeader ref="header" room={this.state.room} searchInfo={searchInfo} <RoomHeader ref="header" room={this.state.room} searchInfo={searchInfo}
isGrid={this.props.isGrid}
oobData={this.props.oobData} oobData={this.props.oobData}
editing={this.state.editingRoomSettings} editing={this.state.editingRoomSettings}
saving={this.state.uploadingRoomSettings} saving={this.state.uploadingRoomSettings}

View File

@ -21,7 +21,6 @@ import dis from '../../../dispatcher';
import TagOrderActions from '../../../actions/TagOrderActions'; import TagOrderActions from '../../../actions/TagOrderActions';
import MatrixClientPeg from '../../../MatrixClientPeg'; import MatrixClientPeg from '../../../MatrixClientPeg';
import sdk from '../../../index'; import sdk from '../../../index';
import SettingsStore from "../../../settings/SettingsStore";
export default class TagTileContextMenu extends React.Component { export default class TagTileContextMenu extends React.Component {
static propTypes = { static propTypes = {
@ -35,7 +34,6 @@ export default class TagTileContextMenu extends React.Component {
this._onViewCommunityClick = this._onViewCommunityClick.bind(this); this._onViewCommunityClick = this._onViewCommunityClick.bind(this);
this._onRemoveClick = this._onRemoveClick.bind(this); this._onRemoveClick = this._onRemoveClick.bind(this);
this._onViewAsGridClick = this._onViewAsGridClick.bind(this);
} }
_onViewCommunityClick() { _onViewCommunityClick() {
@ -55,28 +53,8 @@ export default class TagTileContextMenu extends React.Component {
this.props.onFinished(); this.props.onFinished();
} }
_onViewAsGridClick() {
dis.dispatch({
action: 'group_grid_view',
group_id: this.props.tag,
});
this.props.onFinished();
}
render() { render() {
const TintableSvg = sdk.getComponent("elements.TintableSvg"); const TintableSvg = sdk.getComponent("elements.TintableSvg");
let gridViewOption;
if (SettingsStore.isFeatureEnabled("feature_gridview")) {
gridViewOption = (<div className="mx_TagTileContextMenu_item" onClick={this._onViewAsGridClick} >
<TintableSvg
className="mx_TagTileContextMenu_item_icon"
src="img/feather-icons/grid.svg"
width="15"
height="15"
/>
{ _t('View as Grid') }
</div>);
}
return <div> return <div>
<div className="mx_TagTileContextMenu_item" onClick={this._onViewCommunityClick} > <div className="mx_TagTileContextMenu_item" onClick={this._onViewCommunityClick} >
<TintableSvg <TintableSvg
@ -87,7 +65,6 @@ export default class TagTileContextMenu extends React.Component {
/> />
{ _t('View Community') } { _t('View Community') }
</div> </div>
{ gridViewOption }
<hr className="mx_TagTileContextMenu_separator" /> <hr className="mx_TagTileContextMenu_separator" />
<div className="mx_TagTileContextMenu_item" onClick={this._onRemoveClick} > <div className="mx_TagTileContextMenu_item" onClick={this._onRemoveClick} >
<img className="mx_TagTileContextMenu_item_icon" src="img/icon_context_delete.svg" width="15" height="15" /> <img className="mx_TagTileContextMenu_item_icon" src="img/icon_context_delete.svg" width="15" height="15" />

View File

@ -78,6 +78,7 @@ export default class HeaderButtons extends React.Component {
// till show_right_panel, just without the fromHeader flag // till show_right_panel, just without the fromHeader flag
// as that would hide the right panel again // as that would hide the right panel again
dis.dispatch(Object.assign({}, payload, {fromHeader: false})); dis.dispatch(Object.assign({}, payload, {fromHeader: false}));
} }
this.setState({ this.setState({
phase: payload.phase, phase: payload.phase,

View File

@ -39,6 +39,7 @@ import Unread from '../../../Unread';
import { findReadReceiptFromUserId } from '../../../utils/Receipt'; import { findReadReceiptFromUserId } from '../../../utils/Receipt';
import withMatrixClient from '../../../wrappers/withMatrixClient'; import withMatrixClient from '../../../wrappers/withMatrixClient';
import AccessibleButton from '../elements/AccessibleButton'; import AccessibleButton from '../elements/AccessibleButton';
import RoomViewStore from '../../../stores/RoomViewStore';
import SdkConfig from '../../../SdkConfig'; import SdkConfig from '../../../SdkConfig';
import MultiInviter from "../../../utils/MultiInviter"; import MultiInviter from "../../../utils/MultiInviter";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
@ -49,7 +50,6 @@ module.exports = withMatrixClient(React.createClass({
propTypes: { propTypes: {
matrixClient: PropTypes.object.isRequired, matrixClient: PropTypes.object.isRequired,
member: PropTypes.object.isRequired, member: PropTypes.object.isRequired,
roomId: PropTypes.string,
}, },
getInitialState: function() { getInitialState: function() {
@ -713,7 +713,7 @@ module.exports = withMatrixClient(React.createClass({
} }
if (!member || !member.membership || member.membership === 'leave') { if (!member || !member.membership || member.membership === 'leave') {
const roomId = member && member.roomId ? member.roomId : this.props.roomId; const roomId = member && member.roomId ? member.roomId : RoomViewStore.getRoomId();
const onInviteUserButton = async () => { const onInviteUserButton = async () => {
try { try {
// We use a MultiInviter to re-use the invite logic, even though // We use a MultiInviter to re-use the invite logic, even though

View File

@ -22,6 +22,7 @@ import MatrixClientPeg from '../../../MatrixClientPeg';
import Modal from '../../../Modal'; import Modal from '../../../Modal';
import sdk from '../../../index'; import sdk from '../../../index';
import dis from '../../../dispatcher'; import dis from '../../../dispatcher';
import RoomViewStore from '../../../stores/RoomViewStore';
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
import Stickerpicker from './Stickerpicker'; import Stickerpicker from './Stickerpicker';
import { makeRoomPermalink } from '../../../matrix-to'; import { makeRoomPermalink } from '../../../matrix-to';
@ -62,7 +63,7 @@ export default class MessageComposer extends React.Component {
isRichTextEnabled: SettingsStore.getValue('MessageComposerInput.isRichTextEnabled'), isRichTextEnabled: SettingsStore.getValue('MessageComposerInput.isRichTextEnabled'),
}, },
showFormatting: SettingsStore.getValue('MessageComposer.showFormatting'), showFormatting: SettingsStore.getValue('MessageComposer.showFormatting'),
isQuoting: Boolean(this.props.roomViewStore.getQuotingEvent()), isQuoting: Boolean(RoomViewStore.getQuotingEvent()),
tombstone: this._getRoomTombstone(), tombstone: this._getRoomTombstone(),
}; };
} }
@ -74,7 +75,7 @@ export default class MessageComposer extends React.Component {
// XXX: fragile as all hell - fixme somehow, perhaps with a dedicated Room.encryption event or something. // 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("event", this.onEvent);
MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents); MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents);
this._roomStoreToken = this.props.roomViewStore.addListener(this._onRoomViewStoreUpdate); this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
this._waitForOwnMember(); this._waitForOwnMember();
} }
@ -123,14 +124,14 @@ export default class MessageComposer extends React.Component {
} }
_onRoomViewStoreUpdate() { _onRoomViewStoreUpdate() {
const isQuoting = Boolean(this.props.roomViewStore.getQuotingEvent()); const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
if (this.state.isQuoting === isQuoting) return; if (this.state.isQuoting === isQuoting) return;
this.setState({ isQuoting }); this.setState({ isQuoting });
} }
onUploadClick(ev) { onUploadClick(ev) {
if (MatrixClientPeg.get().isGuest()) { if (MatrixClientPeg.get().isGuest()) {
this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'}); dis.dispatch({action: 'require_registration'});
return; return;
} }
@ -164,7 +165,7 @@ export default class MessageComposer extends React.Component {
} }
} }
const isQuoting = Boolean(this.props.roomViewStore.getQuotingEvent()); const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
let replyToWarning = null; let replyToWarning = null;
if (isQuoting) { if (isQuoting) {
replyToWarning = <p>{ replyToWarning = <p>{
@ -228,7 +229,7 @@ export default class MessageComposer extends React.Component {
if (!call) { if (!call) {
return; return;
} }
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'hangup', action: 'hangup',
// hangup the call for this room, which may not be the room in props // 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) // (e.g. conferences which will hangup the 1:1 room instead)
@ -237,7 +238,7 @@ export default class MessageComposer extends React.Component {
} }
onCallClick(ev) { onCallClick(ev) {
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'place_call', action: 'place_call',
type: ev.shiftKey ? "screensharing" : "video", type: ev.shiftKey ? "screensharing" : "video",
room_id: this.props.room.roomId, room_id: this.props.room.roomId,
@ -245,7 +246,7 @@ export default class MessageComposer extends React.Component {
} }
onVoiceCallClick(ev) { onVoiceCallClick(ev) {
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'place_call', action: 'place_call',
type: "voice", type: "voice",
room_id: this.props.room.roomId, room_id: this.props.room.roomId,
@ -287,8 +288,7 @@ export default class MessageComposer extends React.Component {
const createEvent = replacementRoom.currentState.getStateEvents('m.room.create', ''); const createEvent = replacementRoom.currentState.getStateEvents('m.room.create', '');
if (createEvent && createEvent.getId()) createEventId = createEvent.getId(); if (createEvent && createEvent.getId()) createEventId = createEvent.getId();
} }
dis.dispatch({
this.props.roomViewStore.getDispatcher().dispatch({
action: 'view_room', action: 'view_room',
highlighted: true, highlighted: true,
event_id: createEventId, event_id: createEventId,
@ -432,10 +432,8 @@ export default class MessageComposer extends React.Component {
controls.push( controls.push(
<MessageComposerInput <MessageComposerInput
roomViewStore={this.props.roomViewStore}
ref={(c) => this.messageComposerInput = c} ref={(c) => this.messageComposerInput = c}
key="controls_input" key="controls_input"
isGrid={this.props.isGrid}
onResize={this.props.onResize} onResize={this.props.onResize}
room={this.props.room} room={this.props.room}
placeholder={placeholderText} placeholder={placeholderText}
@ -542,6 +540,5 @@ MessageComposer.propTypes = {
uploadAllowed: PropTypes.func.isRequired, uploadAllowed: PropTypes.func.isRequired,
// string representing the current room app drawer state // string representing the current room app drawer state
showApps: PropTypes.bool, showApps: PropTypes.bool
roomViewStore: PropTypes.object.isRequired,
}; };

View File

@ -38,6 +38,8 @@ import sdk from '../../../index';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import Analytics from '../../../Analytics'; import Analytics from '../../../Analytics';
import dis from '../../../dispatcher';
import * as RichText from '../../../RichText'; import * as RichText from '../../../RichText';
import * as HtmlUtils from '../../../HtmlUtils'; import * as HtmlUtils from '../../../HtmlUtils';
import Autocomplete from './Autocomplete'; import Autocomplete from './Autocomplete';
@ -55,6 +57,7 @@ import {
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
import {makeUserPermalink} from "../../../matrix-to"; import {makeUserPermalink} from "../../../matrix-to";
import ReplyPreview from "./ReplyPreview"; import ReplyPreview from "./ReplyPreview";
import RoomViewStore from '../../../stores/RoomViewStore';
import ReplyThread from "../elements/ReplyThread"; import ReplyThread from "../elements/ReplyThread";
import {ContentHelpers} from 'matrix-js-sdk'; import {ContentHelpers} from 'matrix-js-sdk';
@ -108,6 +111,15 @@ const SLATE_SCHEMA = {
}, },
}; };
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({
action: 'message_send_failed',
});
}
function rangeEquals(a: Range, b: Range): boolean { function rangeEquals(a: Range, b: Range): boolean {
return (a.anchor.key === b.anchor.key return (a.anchor.key === b.anchor.key
&& a.anchor.offset === b.anchorOffset && a.anchor.offset === b.anchorOffset
@ -117,18 +129,6 @@ function rangeEquals(a: Range, b: Range): boolean {
&& a.isBackward === b.isBackward); && 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 * The textInput part of the MessageComposer
*/ */
@ -144,7 +144,6 @@ export default class MessageComposerInput extends React.Component {
onFilesPasted: PropTypes.func, onFilesPasted: PropTypes.func,
onInputStateChanged: PropTypes.func, onInputStateChanged: PropTypes.func,
roomViewStore: PropTypes.object.isRequired,
}; };
client: MatrixClient; client: MatrixClient;
@ -339,31 +338,18 @@ export default class MessageComposerInput extends React.Component {
} }
componentWillMount() { componentWillMount() {
this.dispatcherRef = this.props.roomViewStore.getDispatcher().register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
if (this.props.isGrid) { this.historyManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_');
this.historyManager = new NoopHistoryManager();
} else {
this.historyManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_');
}
} }
componentWillUnmount() { componentWillUnmount() {
this.props.roomViewStore.getDispatcher().unregister(this.dispatcherRef); dis.unregister(this.dispatcherRef);
} }
_collectEditor = (e) => { _collectEditor = (e) => {
this._editor = e; this._editor = e;
} }
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+')');
this.props.roomViewStore.getDispatcher().dispatch({
action: 'message_send_failed',
});
}
onAction = (payload) => { onAction = (payload) => {
const editorState = this.state.editorState; const editorState = this.state.editorState;
@ -1129,7 +1115,7 @@ export default class MessageComposerInput extends React.Component {
return true; return true;
} }
const replyingToEv = this.props.roomViewStore.getQuotingEvent(); const replyingToEv = RoomViewStore.getQuotingEvent();
const mustSendHTML = Boolean(replyingToEv); const mustSendHTML = Boolean(replyingToEv);
if (this.state.isRichTextEnabled) { if (this.state.isRichTextEnabled) {
@ -1217,18 +1203,18 @@ export default class MessageComposerInput extends React.Component {
// Clear reply_to_event as we put the message into the queue // Clear reply_to_event as we put the message into the queue
// if the send fails, retry will handle resending. // if the send fails, retry will handle resending.
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'reply_to_event', action: 'reply_to_event',
event: null, event: null,
}); });
} }
this.client.sendMessage(this.props.room.roomId, content).then((res) => { this.client.sendMessage(this.props.room.roomId, content).then((res) => {
this.props.roomViewStore.getDispatcher().dispatch({ dis.dispatch({
action: 'message_sent', action: 'message_sent',
}); });
}).catch((e) => { }).catch((e) => {
this.onSendMessageFailed(e, this.props.room); onSendMessageFailed(e, this.props.room);
}); });
this.setState({ this.setState({
@ -1599,7 +1585,7 @@ export default class MessageComposerInput extends React.Component {
return ( return (
<div className="mx_MessageComposer_input_wrapper" onClick={this.focusComposer}> <div className="mx_MessageComposer_input_wrapper" onClick={this.focusComposer}>
<div className="mx_MessageComposer_autocomplete_wrapper"> <div className="mx_MessageComposer_autocomplete_wrapper">
<ReplyPreview roomViewStore={this.props.roomViewStore} /> <ReplyPreview />
<Autocomplete <Autocomplete
ref={(e) => this.autocomplete = e} ref={(e) => this.autocomplete = e}
room={this.props.room} room={this.props.room}

View File

@ -18,6 +18,7 @@ import React from 'react';
import dis from '../../../dispatcher'; import dis from '../../../dispatcher';
import sdk from '../../../index'; import sdk from '../../../index';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import RoomViewStore from '../../../stores/RoomViewStore';
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
function cancelQuoting() { function cancelQuoting() {
@ -37,7 +38,7 @@ export default class ReplyPreview extends React.Component {
this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this); this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this);
this._roomStoreToken = this.props.roomViewStore.addListener(this._onRoomViewStoreUpdate); this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
this._onRoomViewStoreUpdate(); this._onRoomViewStoreUpdate();
} }
@ -49,7 +50,7 @@ export default class ReplyPreview extends React.Component {
} }
_onRoomViewStoreUpdate() { _onRoomViewStoreUpdate() {
const event = this.props.roomViewStore.getQuotingEvent(); const event = RoomViewStore.getQuotingEvent();
if (this.state.event !== event) { if (this.state.event !== event) {
this.setState({ event }); this.setState({ event });
} }

View File

@ -24,7 +24,6 @@ import { _t } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg'; import MatrixClientPeg from '../../../MatrixClientPeg';
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import RateLimitedFunc from '../../../ratelimitedfunc'; import RateLimitedFunc from '../../../ratelimitedfunc';
import dis from '../../../dispatcher';
import * as linkify from 'linkifyjs'; import * as linkify from 'linkifyjs';
import linkifyElement from 'linkifyjs/element'; import linkifyElement from 'linkifyjs/element';
@ -153,14 +152,6 @@ module.exports = React.createClass({
}); });
}, },
onToggleRightPanelClick: function(ev) {
if (this.props.collapsedRhs) {
dis.dispatch({action: "show_right_panel"});
} else {
dis.dispatch({action: "hide_right_panel"});
}
},
_hasUnreadPins: function() { _hasUnreadPins: function() {
const currentPinEvent = this.props.room.currentState.getStateEvents("m.room.pinned_events", ''); const currentPinEvent = this.props.room.currentState.getStateEvents("m.room.pinned_events", '');
if (!currentPinEvent) return false; if (!currentPinEvent) return false;
@ -418,17 +409,6 @@ module.exports = React.createClass({
</div>; </div>;
} }
let toggleRightPanelButton;
if (this.props.isGrid) {
toggleRightPanelButton =
<AccessibleButton
className="mx_RoomHeader_button"
onClick={this.onToggleRightPanelClick}
title={_t('Toggle right panel')}>
<TintableSvg src="img/feather-icons/toggle-right-panel.svg" width="20" height="20" />
</AccessibleButton>;
}
return ( return (
<div className={"mx_RoomHeader light-panel " + (this.props.editing ? "mx_RoomHeader_editing" : "")}> <div className={"mx_RoomHeader light-panel " + (this.props.editing ? "mx_RoomHeader_editing" : "")}>
<div className="mx_RoomHeader_wrapper"> <div className="mx_RoomHeader_wrapper">
@ -439,8 +419,7 @@ module.exports = React.createClass({
{ saveButton } { saveButton }
{ cancelButton } { cancelButton }
{ rightRow } { rightRow }
{ !this.props.isGrid ? <RoomHeaderButtons collapsedRhs={this.props.collapsedRhs} /> : undefined } <RoomHeaderButtons collapsedRhs={this.props.collapsedRhs} />
{ toggleRightPanelButton }
</div> </div>
</div> </div>
); );

View File

@ -29,6 +29,7 @@ import * as RoomNotifs from '../../../RoomNotifs';
import * as FormattingUtils from '../../../utils/FormattingUtils'; import * as FormattingUtils from '../../../utils/FormattingUtils';
import AccessibleButton from '../elements/AccessibleButton'; import AccessibleButton from '../elements/AccessibleButton';
import ActiveRoomObserver from '../../../ActiveRoomObserver'; import ActiveRoomObserver from '../../../ActiveRoomObserver';
import RoomViewStore from '../../../stores/RoomViewStore';
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
module.exports = React.createClass({ module.exports = React.createClass({
@ -61,7 +62,7 @@ module.exports = React.createClass({
roomName: this.props.room.name, roomName: this.props.room.name,
notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId), notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
notificationCount: this.props.room.getUnreadNotificationCount(), notificationCount: this.props.room.getUnreadNotificationCount(),
selected: this.props.room.roomId === ActiveRoomObserver.getActiveRoomId(), selected: this.props.room.roomId === RoomViewStore.getRoomId(),
statusMessage: this._getStatusMessage(), statusMessage: this._getStatusMessage(),
}); });
}, },
@ -150,9 +151,9 @@ module.exports = React.createClass({
} }
}, },
_onActiveRoomChange: function(activeRoomId) { _onActiveRoomChange: function() {
this.setState({ this.setState({
selected: this.props.room.roomId === activeRoomId, selected: this.props.room.roomId === RoomViewStore.getRoomId(),
}); });
}, },

View File

@ -17,10 +17,42 @@ limitations under the License.
'use strict'; 'use strict';
import MatrixDispatcher from "./matrix-dispatcher"; 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);
}
}
}
if (global.mxDispatcher === undefined) { if (global.mxDispatcher === undefined) {
global.mxDispatcher = new MatrixDispatcher(); global.mxDispatcher = new MatrixDispatcher();
} }
module.exports = global.mxDispatcher; module.exports = global.mxDispatcher;

View File

@ -1,53 +0,0 @@
/*
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);
}
}
}

View File

@ -110,12 +110,6 @@ export const SETTINGS = {
supportedLevels: LEVELS_FEATURE, supportedLevels: LEVELS_FEATURE,
default: false, 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": { "MessageComposerInput.dontSuggestEmoji": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS, supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Disable Emoji suggestions while typing'), displayName: _td('Disable Emoji suggestions while typing'),

View File

@ -1,277 +0,0 @@
/*
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 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.
*/
class OpenRoomsStore extends Store {
constructor() {
super(dis);
// Initialise state
this._state = {
rooms: [],
currentIndex: null,
group_id: null,
};
this._forwardingEvent = null;
}
getRoomStores() {
return this._state.rooms.map((r) => r.store);
}
getActiveRoomStore() {
const openRoom = this._getActiveOpenRoom();
if (openRoom) {
return openRoom.store;
}
}
getRoomStoreAt(index) {
if (index >= 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) {
return this._state.rooms[index];
}
}
_setState(newState) {
this._state = Object.assign(this._state, newState);
this.__emitChange();
}
_hasRoom(payload) {
return this._roomIndex(payload) !== -1;
}
_roomIndex(payload) {
return this._state.rooms.findIndex((r) => matchesRoom(payload, r.store));
}
_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,
});
}
_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' && roomId === payload.room_id) {
return;
}
payload.grid_src_room_id = roomId;
payload.grid_src_room_alias = roomAlias;
this.getDispatcher().dispatch(payload);
});
const openRoom = {
store: new RoomViewStore(dispatcher),
dispatcher,
dispatcherRef,
};
dispatcher.dispatch({
action: 'view_room',
room_id: roomId,
room_alias: roomAlias,
}, true);
return openRoom;
}
_setSingleOpenRoom(payload) {
this._setState({
rooms: [this._createOpenRoom(payload.room_id, payload.room_alias)],
currentIndex: 0,
});
}
_setGroupOpenRooms(groupId) {
this._cleanupOpenRooms();
// TODO: register to GroupStore updates
const rooms = GroupStore.getGroupRooms(groupId);
const openRooms = rooms.map((room) => {
return this._createOpenRoom(room.roomId);
});
this._setState({
rooms: openRooms,
group_id: groupId,
currentIndex: 0,
});
}
_forwardAction(payload) {
// 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);
}
}
async _resolveRoomAlias(payload) {
try {
const result = await MatrixClientPeg.get()
.getRoomIdForAlias(payload.room_alias);
this.getDispatcher().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,
});
}
}
_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) {
let proposedIndex;
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':
this._viewRoom(payload);
break;
case 'view_my_groups':
case 'view_group':
this._forwardAction(payload);
this._cleanupOpenRooms();
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':
case 'focus_composer':
this._forwardAction(payload);
break;
case 'forward_event':
this._forwardingEvent = payload.event;
break;
case 'group_grid_set_active':
proposedIndex = this._roomIndex(payload);
if (proposedIndex !== -1) {
this._setState({
currentIndex: proposedIndex,
});
}
break;
case 'group_grid_view':
if (payload.group_id !== this._state.group_id) {
this._setGroupOpenRooms(payload.group_id);
}
break;
}
}
}
let singletonOpenRoomsStore = null;
if (!singletonOpenRoomsStore) {
singletonOpenRoomsStore = new OpenRoomsStore();
}
module.exports = singletonOpenRoomsStore;

View File

@ -14,6 +14,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import dis from '../dispatcher';
import {Store} from 'flux/utils'; import {Store} from 'flux/utils';
import MatrixClientPeg from '../MatrixClientPeg'; import MatrixClientPeg from '../MatrixClientPeg';
import sdk from '../index'; import sdk from '../index';
@ -52,12 +53,12 @@ const INITIAL_STATE = {
* with a subset of the js-sdk. * with a subset of the js-sdk.
* ``` * ```
*/ */
export class RoomViewStore extends Store { class RoomViewStore extends Store {
constructor(dispatcher) { constructor() {
super(dispatcher); super(dis);
// Initialise state // Initialise state
this._state = Object.assign({}, INITIAL_STATE); this._state = INITIAL_STATE;
} }
_setState(newState) { _setState(newState) {
@ -84,8 +85,6 @@ export class RoomViewStore extends Store {
}); });
break; break;
case 'view_room_error': case 'view_room_error':
// should not go over dispatcher anymore
// but be internal to RoomViewStore
this._viewRoomError(payload); this._viewRoomError(payload);
break; break;
case 'will_join': case 'will_join':
@ -151,11 +150,22 @@ export class RoomViewStore extends Store {
// pull the user out of Room Settings // pull the user out of Room Settings
isEditingSettings: false, isEditingSettings: false,
}; };
if (this._state.forwardingEvent) {
dis.dispatch({
action: 'send_event',
room_id: newState.roomId,
event: this._state.forwardingEvent,
});
}
this._setState(newState); this._setState(newState);
if (payload.auto_join) { if (payload.auto_join) {
this._joinRoom(payload); this._joinRoom(payload);
} }
} else if (payload.room_alias) { } else if (payload.room_alias) {
// Resolve the alias and then do a second dispatch with the room ID acquired
this._setState({ this._setState({
roomId: null, roomId: null,
initialEventId: null, initialEventId: null,
@ -165,6 +175,25 @@ export class RoomViewStore extends Store {
roomLoading: true, roomLoading: true,
roomLoadError: null, 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,
});
});
} }
} }
@ -190,7 +219,7 @@ export class RoomViewStore extends Store {
// stream yet, and that's the point at which we'd consider // stream yet, and that's the point at which we'd consider
// the user joined to the room. // the user joined to the room.
}, (err) => { }, (err) => {
this.getDispatcher().dispatch({ dis.dispatch({
action: 'join_room_error', action: 'join_room_error',
err: err, err: err,
}); });
@ -306,7 +335,8 @@ export class RoomViewStore extends Store {
} }
} }
const MatrixDispatcher = require("../matrix-dispatcher"); let singletonRoomViewStore = null;
const backwardsCompatInstance = new RoomViewStore(new MatrixDispatcher()); if (!singletonRoomViewStore) {
singletonRoomViewStore = new RoomViewStore();
export default backwardsCompatInstance; }
module.exports = singletonRoomViewStore;

View File

@ -26,6 +26,7 @@ Once a timer is finished or aborted, it can't be started again
a new one through `clone()` or `cloneIfRun()`. a new one through `clone()` or `cloneIfRun()`.
*/ */
export default class Timer { export default class Timer {
constructor(timeout) { constructor(timeout) {
this._timeout = timeout; this._timeout = timeout;
this._onTimeout = this._onTimeout.bind(this); this._onTimeout = this._onTimeout.bind(this);