Merge pull request #1367 from matrix-org/dbkr/scroll_state_store
Introduce a RoomScrollStateStore
This commit is contained in:
commit
a012dbafce
3 changed files with 68 additions and 64 deletions
|
@ -47,6 +47,7 @@ import KeyCode from '../../KeyCode';
|
||||||
import UserProvider from '../../autocomplete/UserProvider';
|
import UserProvider from '../../autocomplete/UserProvider';
|
||||||
|
|
||||||
import RoomViewStore from '../../stores/RoomViewStore';
|
import RoomViewStore from '../../stores/RoomViewStore';
|
||||||
|
import RoomScrollStateStore from '../../stores/RoomScrollStateStore';
|
||||||
|
|
||||||
let DEBUG = false;
|
let DEBUG = false;
|
||||||
let debuglog = function() {};
|
let debuglog = function() {};
|
||||||
|
@ -163,7 +164,6 @@ module.exports = React.createClass({
|
||||||
roomLoadError: RoomViewStore.getRoomLoadError(),
|
roomLoadError: RoomViewStore.getRoomLoadError(),
|
||||||
joining: RoomViewStore.isJoining(),
|
joining: RoomViewStore.isJoining(),
|
||||||
initialEventId: RoomViewStore.getInitialEventId(),
|
initialEventId: RoomViewStore.getInitialEventId(),
|
||||||
initialEventPixelOffset: RoomViewStore.getInitialEventPixelOffset(),
|
|
||||||
isInitialEventHighlighted: RoomViewStore.isInitialEventHighlighted(),
|
isInitialEventHighlighted: RoomViewStore.isInitialEventHighlighted(),
|
||||||
forwardingEvent: RoomViewStore.getForwardingEvent(),
|
forwardingEvent: RoomViewStore.getForwardingEvent(),
|
||||||
shouldPeek: RoomViewStore.shouldPeek(),
|
shouldPeek: RoomViewStore.shouldPeek(),
|
||||||
|
@ -191,18 +191,26 @@ module.exports = React.createClass({
|
||||||
newState.room = MatrixClientPeg.get().getRoom(newState.roomId);
|
newState.room = MatrixClientPeg.get().getRoom(newState.roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.state.roomId === null && newState.roomId !== null) {
|
||||||
|
// Get the scroll state for the new room
|
||||||
|
|
||||||
|
// If an event ID wasn't specified, default to the one saved for this room
|
||||||
|
// in the scroll state store. Assume initialEventPixelOffset should be set.
|
||||||
|
if (!newState.initialEventId) {
|
||||||
|
const roomScrollState = RoomScrollStateStore.getScrollState(newState.roomId);
|
||||||
|
if (roomScrollState) {
|
||||||
|
newState.initialEventId = roomScrollState.focussedEvent;
|
||||||
|
newState.initialEventPixelOffset = roomScrollState.pixelOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clear the search results when clicking a search result (which changes the
|
// Clear the search results when clicking a search result (which changes the
|
||||||
// currently scrolled to event, this.state.initialEventId).
|
// currently scrolled to event, this.state.initialEventId).
|
||||||
if (this.state.initialEventId !== newState.initialEventId) {
|
if (this.state.initialEventId !== newState.initialEventId) {
|
||||||
newState.searchResults = null;
|
newState.searchResults = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the scroll state for the previous room so that we can return to this
|
|
||||||
// position when viewing this room in future.
|
|
||||||
if (this.state.roomId !== newState.roomId) {
|
|
||||||
this._updateScrollMap(this.state.roomId);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState(newState, () => {
|
this.setState(newState, () => {
|
||||||
// At this point, this.state.roomId could be null (e.g. the alias might not
|
// At this point, this.state.roomId could be null (e.g. the alias might not
|
||||||
// have been resolved yet) so anything called here must handle this case.
|
// have been resolved yet) so anything called here must handle this case.
|
||||||
|
@ -340,7 +348,9 @@ module.exports = React.createClass({
|
||||||
this.unmounted = true;
|
this.unmounted = true;
|
||||||
|
|
||||||
// update the scroll map before we get unmounted
|
// update the scroll map before we get unmounted
|
||||||
this._updateScrollMap(this.state.roomId);
|
if (this.state.roomId) {
|
||||||
|
RoomScrollStateStore.setScrollState(this.state.roomId, this._getScrollState());
|
||||||
|
}
|
||||||
|
|
||||||
if (this.refs.roomView) {
|
if (this.refs.roomView) {
|
||||||
// disconnect the D&D event listeners from the room view. This
|
// disconnect the D&D event listeners from the room view. This
|
||||||
|
@ -617,18 +627,6 @@ module.exports = React.createClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateScrollMap(roomId) {
|
|
||||||
// No point updating scroll state if the room ID hasn't been resolved yet
|
|
||||||
if (!roomId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'update_scroll_state',
|
|
||||||
room_id: roomId,
|
|
||||||
scroll_state: this._getScrollState(),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onRoom: function(room) {
|
onRoom: function(room) {
|
||||||
if (!room || room.roomId !== this.state.roomId) {
|
if (!room || room.roomId !== this.state.roomId) {
|
||||||
return;
|
return;
|
||||||
|
|
50
src/stores/RoomScrollStateStore.js
Normal file
50
src/stores/RoomScrollStateStore.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores where the user has scrolled to in each room
|
||||||
|
*/
|
||||||
|
class RoomScrollStateStore {
|
||||||
|
constructor() {
|
||||||
|
// A map from room id to scroll state.
|
||||||
|
//
|
||||||
|
// If there is no special scroll state (ie, we are following the live
|
||||||
|
// timeline), the scroll state is null. Otherwise, it is an object with
|
||||||
|
// the following properties:
|
||||||
|
//
|
||||||
|
// focussedEvent: the ID of the 'focussed' event. Typically this is
|
||||||
|
// the last event fully visible in the viewport, though if we
|
||||||
|
// have done an explicit scroll to an explicit event, it will be
|
||||||
|
// that event.
|
||||||
|
//
|
||||||
|
// pixelOffset: the number of pixels the window is scrolled down
|
||||||
|
// from the focussedEvent.
|
||||||
|
this._scrollStateMap = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
getScrollState(roomId) {
|
||||||
|
return this._scrollStateMap[roomId];
|
||||||
|
}
|
||||||
|
|
||||||
|
setScrollState(roomId, scrollState) {
|
||||||
|
this._scrollStateMap[roomId] = scrollState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (global.mx_RoomScrollStateStore === undefined) {
|
||||||
|
global.mx_RoomScrollStateStore = new RoomScrollStateStore();
|
||||||
|
}
|
||||||
|
export default global.mx_RoomScrollStateStore;
|
|
@ -30,8 +30,6 @@ const INITIAL_STATE = {
|
||||||
|
|
||||||
// The event to scroll to when the room is first viewed
|
// The event to scroll to when the room is first viewed
|
||||||
initialEventId: null,
|
initialEventId: null,
|
||||||
// The offset to display the initial event at (see scrollStateMap)
|
|
||||||
initialEventPixelOffset: null,
|
|
||||||
// Whether to highlight the initial event
|
// Whether to highlight the initial event
|
||||||
isInitialEventHighlighted: false,
|
isInitialEventHighlighted: false,
|
||||||
|
|
||||||
|
@ -41,20 +39,6 @@ const INITIAL_STATE = {
|
||||||
roomLoading: false,
|
roomLoading: false,
|
||||||
// Any error that has occurred during loading
|
// Any error that has occurred during loading
|
||||||
roomLoadError: null,
|
roomLoadError: null,
|
||||||
// A map from room id to scroll state.
|
|
||||||
//
|
|
||||||
// If there is no special scroll state (ie, we are following the live
|
|
||||||
// timeline), the scroll state is null. Otherwise, it is an object with
|
|
||||||
// the following properties:
|
|
||||||
//
|
|
||||||
// focussedEvent: the ID of the 'focussed' event. Typically this is
|
|
||||||
// the last event fully visible in the viewport, though if we
|
|
||||||
// have done an explicit scroll to an explicit event, it will be
|
|
||||||
// that event.
|
|
||||||
//
|
|
||||||
// pixelOffset: the number of pixels the window is scrolled down
|
|
||||||
// from the focussedEvent.
|
|
||||||
scrollStateMap: {},
|
|
||||||
|
|
||||||
forwardingEvent: null,
|
forwardingEvent: null,
|
||||||
};
|
};
|
||||||
|
@ -115,9 +99,6 @@ class RoomViewStore extends Store {
|
||||||
case 'on_logged_out':
|
case 'on_logged_out':
|
||||||
this.reset();
|
this.reset();
|
||||||
break;
|
break;
|
||||||
case 'update_scroll_state':
|
|
||||||
this._updateScrollState(payload);
|
|
||||||
break;
|
|
||||||
case 'forward_event':
|
case 'forward_event':
|
||||||
this._setState({
|
this._setState({
|
||||||
forwardingEvent: payload.event,
|
forwardingEvent: payload.event,
|
||||||
|
@ -132,7 +113,6 @@ class RoomViewStore extends Store {
|
||||||
roomId: payload.room_id,
|
roomId: payload.room_id,
|
||||||
roomAlias: payload.room_alias,
|
roomAlias: payload.room_alias,
|
||||||
initialEventId: payload.event_id,
|
initialEventId: payload.event_id,
|
||||||
initialEventPixelOffset: undefined,
|
|
||||||
isInitialEventHighlighted: payload.highlighted,
|
isInitialEventHighlighted: payload.highlighted,
|
||||||
forwardingEvent: null,
|
forwardingEvent: null,
|
||||||
roomLoading: false,
|
roomLoading: false,
|
||||||
|
@ -145,16 +125,6 @@ class RoomViewStore extends Store {
|
||||||
newState.joining = false;
|
newState.joining = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If an event ID wasn't specified, default to the one saved for this room
|
|
||||||
// via update_scroll_state. Assume initialEventPixelOffset should be set.
|
|
||||||
if (!newState.initialEventId) {
|
|
||||||
const roomScrollState = this._state.scrollStateMap[payload.room_id];
|
|
||||||
if (roomScrollState) {
|
|
||||||
newState.initialEventId = roomScrollState.focussedEvent;
|
|
||||||
newState.initialEventPixelOffset = roomScrollState.pixelOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._state.forwardingEvent) {
|
if (this._state.forwardingEvent) {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'send_event',
|
action: 'send_event',
|
||||||
|
@ -241,15 +211,6 @@ class RoomViewStore extends Store {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_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() {
|
reset() {
|
||||||
this._state = Object.assign({}, INITIAL_STATE);
|
this._state = Object.assign({}, INITIAL_STATE);
|
||||||
}
|
}
|
||||||
|
@ -264,11 +225,6 @@ class RoomViewStore extends Store {
|
||||||
return this._state.initialEventId;
|
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
|
// Whether to highlight the initial event
|
||||||
isInitialEventHighlighted() {
|
isInitialEventHighlighted() {
|
||||||
return this._state.isInitialEventHighlighted;
|
return this._state.isInitialEventHighlighted;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue