408b8c18ea
to keep the place we're scrolled to in rooms. This mainly eleimates the extra, superfluous onRoomViewStoreUpdate callback that happened when the previous room saved back its scroll state. Moving the scroll state to a separate store means we can have this not emit events because nothing needs to know when the scroll state changes.
287 lines
8.4 KiB
JavaScript
287 lines
8.4 KiB
JavaScript
/*
|
|
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.
|
|
*/
|
|
import dis from '../dispatcher';
|
|
import {Store} from 'flux/utils';
|
|
import MatrixClientPeg from '../MatrixClientPeg';
|
|
import sdk from '../index';
|
|
import Modal from '../Modal';
|
|
import { _t } from '../languageHandler';
|
|
|
|
const INITIAL_STATE = {
|
|
// Whether we're joining the currently viewed room
|
|
joining: false,
|
|
// Any error that has occurred during joining
|
|
joinError: null,
|
|
// The room ID of the room currently being viewed
|
|
roomId: null,
|
|
|
|
// The event to scroll to when the room is first viewed
|
|
initialEventId: null,
|
|
// Whether to highlight the initial event
|
|
isInitialEventHighlighted: false,
|
|
|
|
// The room alias of the room (or null if not originally specified in view_room)
|
|
roomAlias: null,
|
|
// Whether the current room is loading
|
|
roomLoading: false,
|
|
// Any error that has occurred during loading
|
|
roomLoadError: null,
|
|
|
|
forwardingEvent: null,
|
|
};
|
|
|
|
/**
|
|
* A class for storing application state for RoomView. This is the RoomView's interface
|
|
* with a subset of the js-sdk.
|
|
* ```
|
|
*/
|
|
class RoomViewStore extends Store {
|
|
constructor() {
|
|
super(dis);
|
|
|
|
// Initialise state
|
|
this._state = INITIAL_STATE;
|
|
}
|
|
|
|
_setState(newState) {
|
|
this._state = Object.assign(this._state, newState);
|
|
this.__emitChange();
|
|
}
|
|
|
|
__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':
|
|
this._viewRoom(payload);
|
|
break;
|
|
case 'view_room_error':
|
|
this._viewRoomError(payload);
|
|
break;
|
|
case 'will_join':
|
|
this._setState({
|
|
joining: true,
|
|
});
|
|
break;
|
|
case 'cancel_join':
|
|
this._setState({
|
|
joining: false,
|
|
});
|
|
break;
|
|
// join_room:
|
|
// - opts: options for joinRoom
|
|
case 'join_room':
|
|
this._joinRoom(payload);
|
|
break;
|
|
case 'joined_room':
|
|
this._joinedRoom(payload);
|
|
break;
|
|
case 'join_room_error':
|
|
this._joinRoomError(payload);
|
|
break;
|
|
case 'on_logged_out':
|
|
this.reset();
|
|
break;
|
|
case 'forward_event':
|
|
this._setState({
|
|
forwardingEvent: payload.event,
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
_viewRoom(payload) {
|
|
if (payload.room_id) {
|
|
const newState = {
|
|
roomId: payload.room_id,
|
|
roomAlias: payload.room_alias,
|
|
initialEventId: payload.event_id,
|
|
isInitialEventHighlighted: payload.highlighted,
|
|
forwardingEvent: null,
|
|
roomLoading: false,
|
|
roomLoadError: null,
|
|
// should peek by default
|
|
shouldPeek: payload.should_peek === undefined ? true : payload.should_peek,
|
|
};
|
|
|
|
if (payload.joined) {
|
|
newState.joining = false;
|
|
}
|
|
|
|
if (this._state.forwardingEvent) {
|
|
dis.dispatch({
|
|
action: 'send_event',
|
|
room_id: newState.roomId,
|
|
event: this._state.forwardingEvent,
|
|
});
|
|
}
|
|
|
|
this._setState(newState);
|
|
} 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,
|
|
initialEventPixelOffset: null,
|
|
isInitialEventHighlighted: null,
|
|
roomAlias: payload.room_alias,
|
|
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,
|
|
});
|
|
}, (err) => {
|
|
dis.dispatch({
|
|
action: 'view_room_error',
|
|
room_id: null,
|
|
room_alias: payload.room_alias,
|
|
err: err,
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
_viewRoomError(payload) {
|
|
this._setState({
|
|
roomId: payload.room_id,
|
|
roomAlias: payload.room_alias,
|
|
roomLoading: false,
|
|
roomLoadError: payload.err,
|
|
});
|
|
}
|
|
|
|
_joinRoom(payload) {
|
|
this._setState({
|
|
joining: true,
|
|
});
|
|
MatrixClientPeg.get().joinRoom(
|
|
this._state.roomAlias || this._state.roomId, payload.opts,
|
|
).done(() => {
|
|
dis.dispatch({
|
|
action: 'joined_room',
|
|
});
|
|
}, (err) => {
|
|
dis.dispatch({
|
|
action: 'join_room_error',
|
|
err: err,
|
|
});
|
|
const msg = err.message ? err.message : JSON.stringify(err);
|
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, {
|
|
title: _t("Failed to join room"),
|
|
description: msg,
|
|
});
|
|
});
|
|
}
|
|
|
|
_joinedRoom(payload) {
|
|
this._setState({
|
|
joining: false,
|
|
});
|
|
}
|
|
|
|
_joinRoomError(payload) {
|
|
this._setState({
|
|
joining: false,
|
|
joinError: payload.err,
|
|
});
|
|
}
|
|
|
|
_updateScrollState(payload) {
|
|
// Clobber existing scroll state for the given room ID
|
|
const newScrollStateMap = this._state.scrollStateMap;
|
|
newScrollStateMap[payload.room_id] = payload.scroll_state;
|
|
this._setState({
|
|
scrollStateMap: newScrollStateMap,
|
|
});
|
|
}
|
|
|
|
reset() {
|
|
this._state = Object.assign({}, INITIAL_STATE);
|
|
}
|
|
|
|
// The room ID of the room currently being viewed
|
|
getRoomId() {
|
|
return this._state.roomId;
|
|
}
|
|
|
|
// The event to scroll to when the room is first viewed
|
|
getInitialEventId() {
|
|
return this._state.initialEventId;
|
|
}
|
|
|
|
// The offset to display the initial event at (see scrollStateMap)
|
|
getInitialEventPixelOffset() {
|
|
return this._state.initialEventPixelOffset;
|
|
}
|
|
|
|
// Whether to highlight the initial event
|
|
isInitialEventHighlighted() {
|
|
return this._state.isInitialEventHighlighted;
|
|
}
|
|
|
|
// The room alias of the room (or null if not originally specified in view_room)
|
|
getRoomAlias() {
|
|
return this._state.roomAlias;
|
|
}
|
|
|
|
// Whether the current room is loading (true whilst resolving an alias)
|
|
isRoomLoading() {
|
|
return this._state.roomLoading;
|
|
}
|
|
|
|
// Any error that has occurred during loading
|
|
getRoomLoadError() {
|
|
return this._state.roomLoadError;
|
|
}
|
|
|
|
// Whether we're joining the currently viewed room
|
|
isJoining() {
|
|
return this._state.joining;
|
|
}
|
|
|
|
// Any error that has occurred during joining
|
|
getJoinError() {
|
|
return this._state.joinError;
|
|
}
|
|
|
|
// The mxEvent if one is about to be forwarded
|
|
getForwardingEvent() {
|
|
return this._state.forwardingEvent;
|
|
}
|
|
|
|
shouldPeek() {
|
|
return this._state.shouldPeek;
|
|
}
|
|
}
|
|
|
|
let singletonRoomViewStore = null;
|
|
if (!singletonRoomViewStore) {
|
|
singletonRoomViewStore = new RoomViewStore();
|
|
}
|
|
module.exports = singletonRoomViewStore;
|