diff --git a/res/css/views/rooms/_JumpToBottomButton.scss b/res/css/views/rooms/_JumpToBottomButton.scss index 6cb3b6bce9e..a8dc2ce11cd 100644 --- a/res/css/views/rooms/_JumpToBottomButton.scss +++ b/res/css/views/rooms/_JumpToBottomButton.scss @@ -52,6 +52,7 @@ limitations under the License. .mx_JumpToBottomButton_scrollDown { position: relative; + display: block; height: 38px; border-radius: 19px; box-sizing: border-box; diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index d1071a9e191..53a6d4d92bc 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -121,6 +121,9 @@ export default class MessagePanel extends React.Component { // callback which is called when the panel is scrolled. onScroll: PropTypes.func, + // callback which is called when the user interacts with the room timeline + onUserScroll: PropTypes.func, + // callback which is called when more content is needed. onFillRequest: PropTypes.func, @@ -885,6 +888,7 @@ export default class MessagePanel extends React.Component { ref={this._scrollPanel} className={className} onScroll={this.props.onScroll} + onUserScroll={this.props.onUserScroll} onResize={this.onResize} onFillRequest={this.props.onFillRequest} onUnfillRequest={this.props.onUnfillRequest} diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index bed54cc8df5..2dca8feea08 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -642,6 +642,17 @@ export default class RoomView extends React.Component { SettingsStore.unwatchSetting(this.layoutWatcherRef); } + private onUserScroll = () => { + if (this.state.initialEventId && this.state.isInitialEventHighlighted) { + dis.dispatch({ + action: 'view_room', + room_id: this.state.room.roomId, + event_id: this.state.initialEventId, + highlighted: false, + }); + } + } + private onLayoutChange = () => { this.setState({ layout: SettingsStore.getValue("layout"), @@ -1513,8 +1524,10 @@ export default class RoomView extends React.Component { // jump down to the bottom of this room, where new events are arriving private jumpToLiveTimeline = () => { - this.messagePanel.jumpToLiveTimeline(); - dis.fire(Action.FocusComposer); + dis.dispatch({ + action: 'view_room', + room_id: this.state.room.roomId, + }); }; // jump up to wherever our read marker is @@ -1985,6 +1998,7 @@ export default class RoomView extends React.Component { eventId={this.state.initialEventId} eventPixelOffset={this.state.initialEventPixelOffset} onScroll={this.onMessageListScroll} + onUserScroll={this.onUserScroll} onReadMarkerUpdated={this.updateTopUnreadMessagesBar} showUrlPreview = {this.state.showUrlPreview} className={messagePanelClassNames} @@ -2011,6 +2025,7 @@ export default class RoomView extends React.Component { highlight={this.state.room.getUnreadNotificationCount('highlight') > 0} numUnreadMessages={this.state.numUnreadMessages} onScrollToBottomClick={this.jumpToLiveTimeline} + roomId={this.state.roomId} />); } diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 5c5062633d8..f6e1530537f 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -133,6 +133,10 @@ export default class ScrollPanel extends React.Component { */ onScroll: PropTypes.func, + /* onUserScroll: callback which is called when the user interacts with the room timeline + */ + onUserScroll: PropTypes.func, + /* className: classnames to add to the top-level div */ className: PropTypes.string, @@ -535,21 +539,29 @@ export default class ScrollPanel extends React.Component { * @param {object} ev the keyboard event */ handleScrollKey = ev => { + let isScrolling = false; const roomAction = getKeyBindingsManager().getRoomAction(ev); switch (roomAction) { case RoomAction.ScrollUp: this.scrollRelative(-1); + isScrolling = true; break; case RoomAction.RoomScrollDown: this.scrollRelative(1); + isScrolling = true; break; case RoomAction.JumpToFirstMessage: this.scrollToTop(); + isScrolling = true; break; case RoomAction.JumpToLatestMessage: this.scrollToBottom(); + isScrolling = true; break; } + if (isScrolling && this.props.onUserScroll) { + this.props.onUserScroll(ev); + } }; /* Scroll the panel to bring the DOM node with the scroll token @@ -888,9 +900,8 @@ export default class ScrollPanel extends React.Component { + onWheel={this.props.onUserScroll} + className={`mx_ScrollPanel ${this.props.className}`} style={this.props.style}> { this.props.fixedChildren }
    diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index af20c31cb2a..c8261995339 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -94,6 +94,9 @@ class TimelinePanel extends React.Component { // callback which is called when the panel is scrolled. onScroll: PropTypes.func, + // callback which is called when the user interacts with the room timeline + onUserScroll: PropTypes.func, + // callback which is called when the read-up-to mark is updated. onReadMarkerUpdated: PropTypes.func, @@ -258,7 +261,9 @@ class TimelinePanel extends React.Component { console.warn("Replacing timelineSet on a TimelinePanel - confusion may ensue"); } - if (newProps.eventId != this.props.eventId) { + const differentEventId = newProps.eventId != this.props.eventId; + const differentHighlightedEventId = newProps.highlightedEventId != this.props.highlightedEventId; + if (differentEventId || differentHighlightedEventId) { console.log("TimelinePanel switching to eventId " + newProps.eventId + " (was " + this.props.eventId + ")"); return this._initTimeline(newProps); @@ -1456,6 +1461,7 @@ class TimelinePanel extends React.Component { ourUserId={MatrixClientPeg.get().credentials.userId} stickyBottom={stickyBottom} onScroll={this.onMessageListScroll} + onUserScroll={this.props.onUserScroll} onFillRequest={this.onMessageListFillRequest} onUnfillRequest={this.onMessageListUnfillRequest} isTwelveHour={this.state.isTwelveHour}