Control currently viewied event via RoomViewStore

Fix for https://github.com/vector-im/riot-web/issues/4224

Due to the way `MatrixChat` does a state update when the `view_room` dispatch fires and a second update when `RoomViewStore` sends an update, the current event ID and room ID were becoming out of sync. The solution devised was to have the event ID managed by the `RoomViewStore` itself and do any defaulting there (for when we revisit a room that we saved scroll state for previously).

This required a few changes:
 - The addition of `update_scroll_state` in `RoomViewStore` allows the `RoomView` to save scroll state for a room before swapping to another one. Previously the caching of scroll state was done in `RoomView`.
 - The `view_room` dispatch now accepts an `event_id`, which dictates which event is supposed to be scrolled to in the `MessagePanel` when a new room is viewed. It also accepts `event_offset`, but currently, this isn't passed in by a dispatch in the app, but it is clobbered when loading the default position when an `event_id` isn't specified. Finally, `highlighted` was added to distinguish whether the initial event being scrolled to is also highlighted. This flag is also used by `viewRoom` in `MatrixChat` in order to decide whether to `notifyNewScreen` with the specified `event_id`.
This commit is contained in:
Luke Barnard 2017-06-08 14:17:49 +01:00
parent ea02d8841c
commit d3cf78ff5a
5 changed files with 109 additions and 78 deletions

View file

@ -27,12 +27,32 @@ const INITIAL_STATE = {
joinError: null,
// The room ID of the room
roomId: null,
// The event being viewed
eventId: null,
// The offset to display the event at (see scrollStateMap)
eventPixelOffset: null,
// Whether to highlight the event
isEventHighlighted: 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,
// 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: {},
};
/**
@ -56,8 +76,11 @@ class RoomViewStore extends Store {
__onDispatch(payload) {
switch (payload.action) {
// view_room:
// - room_alias: '#somealias:matrix.org'
// - room_id: '!roomid123:matrix.org'
// - 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;
@ -88,20 +111,39 @@ class RoomViewStore extends Store {
case 'on_logged_out':
this.reset();
break;
case 'update_scroll_state':
this._updateScrollState(payload);
break;
}
}
_viewRoom(payload) {
// Always set the room ID if present
if (payload.room_id) {
// If an event ID wasn't specified, default to the one saved for this room
// via update_scroll_state. Also assume event_offset should be set.
if (!payload.event_id) {
const roomScrollState = this._state.scrollStateMap[payload.room_id];
if (roomScrollState) {
payload.event_id = roomScrollState.focussedEvent;
payload.event_offset = roomScrollState.pixelOffset;
}
}
this._setState({
roomId: payload.room_id,
eventId: payload.event_id,
eventPixelOffset: payload.event_offset,
isEventHighlighted: payload.highlighted,
roomLoading: false,
roomLoadError: null,
});
} else if (payload.room_alias) {
// Resolve the alias and then do a second dispatch with the room ID acquired
this._setState({
roomId: null,
eventId: null,
eventPixelOffset: null,
isEventHighlighted: null,
roomAlias: payload.room_alias,
roomLoading: true,
roomLoadError: null,
@ -111,6 +153,8 @@ class RoomViewStore extends Store {
dis.dispatch({
action: 'view_room',
room_id: result.room_id,
event_id: payload.event_id,
highlighted: payload.highlighted,
room_alias: payload.room_alias,
});
}, (err) => {
@ -168,6 +212,15 @@ 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() {
this._state = Object.assign({}, INITIAL_STATE);
}
@ -176,6 +229,18 @@ class RoomViewStore extends Store {
return this._state.roomId;
}
getEventId() {
return this._state.eventId;
}
getEventPixelOffset() {
return this._state.eventPixelOffset;
}
isEventHighlighted() {
return this._state.isEventHighlighted;
}
getRoomAlias() {
return this._state.roomAlias;
}
@ -195,7 +260,6 @@ class RoomViewStore extends Store {
getJoinError() {
return this._state.joinError;
}
}
let singletonRoomViewStore = null;