Merge pull request #1979 from matrix-org/t3chguy/max_continuation_interval

split continuation if there is a gap in conversation
This commit is contained in:
David Baker 2018-06-18 11:22:51 +01:00 committed by GitHub
commit a32ffa83ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2016 OpenMarket Ltd Copyright 2016 OpenMarket Ltd
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -25,6 +26,9 @@ import sdk from '../../index';
import MatrixClientPeg from '../../MatrixClientPeg'; import MatrixClientPeg from '../../MatrixClientPeg';
const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes
const continuedTypes = ['m.sticker', 'm.room.message'];
/* (almost) stateless UI component which builds the event tiles in the room timeline. /* (almost) stateless UI component which builds the event tiles in the room timeline.
*/ */
module.exports = React.createClass({ module.exports = React.createClass({
@ -189,7 +193,7 @@ module.exports = React.createClass({
/** /**
* Page up/down. * Page up/down.
* *
* mult: -1 to page up, +1 to page down * @param {number} mult: -1 to page up, +1 to page down
*/ */
scrollRelative: function(mult) { scrollRelative: function(mult) {
if (this.refs.scrollPanel) { if (this.refs.scrollPanel) {
@ -199,6 +203,8 @@ module.exports = React.createClass({
/** /**
* Scroll up/down in response to a scroll key * Scroll up/down in response to a scroll key
*
* @param {KeyboardEvent} ev: the keyboard event to handle
*/ */
handleScrollKey: function(ev) { handleScrollKey: function(ev) {
if (this.refs.scrollPanel) { if (this.refs.scrollPanel) {
@ -257,6 +263,7 @@ module.exports = React.createClass({
this.eventNodes = {}; this.eventNodes = {};
let visible = false;
let i; let i;
// first figure out which is the last event in the list which we're // first figure out which is the last event in the list which we're
@ -297,7 +304,7 @@ module.exports = React.createClass({
// if the readmarker has moved, cancel any active ghost. // if the readmarker has moved, cancel any active ghost.
if (this.currentReadMarkerEventId && this.props.readMarkerEventId && if (this.currentReadMarkerEventId && this.props.readMarkerEventId &&
this.props.readMarkerVisible && this.props.readMarkerVisible &&
this.currentReadMarkerEventId != this.props.readMarkerEventId) { this.currentReadMarkerEventId !== this.props.readMarkerEventId) {
this.currentGhostEventId = null; this.currentGhostEventId = null;
} }
@ -404,8 +411,8 @@ module.exports = React.createClass({
let isVisibleReadMarker = false; let isVisibleReadMarker = false;
if (eventId == this.props.readMarkerEventId) { if (eventId === this.props.readMarkerEventId) {
var visible = this.props.readMarkerVisible; visible = this.props.readMarkerVisible;
// if the read marker comes at the end of the timeline (except // if the read marker comes at the end of the timeline (except
// for local echoes, which are excluded from RMs, because they // for local echoes, which are excluded from RMs, because they
@ -423,11 +430,11 @@ module.exports = React.createClass({
// XXX: there should be no need for a ghost tile - we should just use a // XXX: there should be no need for a ghost tile - we should just use a
// a dispatch (user_activity_end) to start the RM animation. // a dispatch (user_activity_end) to start the RM animation.
if (eventId == this.currentGhostEventId) { if (eventId === this.currentGhostEventId) {
// if we're showing an animation, continue to show it. // if we're showing an animation, continue to show it.
ret.push(this._getReadMarkerGhostTile()); ret.push(this._getReadMarkerGhostTile());
} else if (!isVisibleReadMarker && } else if (!isVisibleReadMarker &&
eventId == this.currentReadMarkerEventId) { eventId === this.currentReadMarkerEventId) {
// there is currently a read-up-to marker at this point, but no // there is currently a read-up-to marker at this point, but no
// more. Show an animation of it disappearing. // more. Show an animation of it disappearing.
ret.push(this._getReadMarkerGhostTile()); ret.push(this._getReadMarkerGhostTile());
@ -449,16 +456,17 @@ module.exports = React.createClass({
// Some events should appear as continuations from previous events of // Some events should appear as continuations from previous events of
// different types. // different types.
const continuedTypes = ['m.sticker', 'm.room.message'];
const eventTypeContinues = const eventTypeContinues =
prevEvent !== null && prevEvent !== null &&
continuedTypes.includes(mxEv.getType()) && continuedTypes.includes(mxEv.getType()) &&
continuedTypes.includes(prevEvent.getType()); continuedTypes.includes(prevEvent.getType());
if (prevEvent !== null // if there is a previous event and it has the same sender as this event
&& prevEvent.sender && mxEv.sender // and the types are the same/is in continuedTypes and the time between them is <= CONTINUATION_MAX_INTERVAL
&& mxEv.sender.userId === prevEvent.sender.userId if (prevEvent !== null && prevEvent.sender && mxEv.sender && mxEv.sender.userId === prevEvent.sender.userId &&
&& (mxEv.getType() == prevEvent.getType() || eventTypeContinues)) { (mxEv.getType() === prevEvent.getType() || eventTypeContinues) &&
(mxEv.getTs() - prevEvent.getTs() <= CONTINUATION_MAX_INTERVAL)) {
continuation = true; continuation = true;
} }
@ -493,7 +501,7 @@ module.exports = React.createClass({
} }
const eventId = mxEv.getId(); const eventId = mxEv.getId();
const highlight = (eventId == this.props.highlightedEventId); const highlight = (eventId === this.props.highlightedEventId);
// we can't use local echoes as scroll tokens, because their event IDs change. // we can't use local echoes as scroll tokens, because their event IDs change.
// Local echos have a send "status". // Local echos have a send "status".
@ -632,7 +640,8 @@ module.exports = React.createClass({
render: function() { render: function() {
const ScrollPanel = sdk.getComponent("structures.ScrollPanel"); const ScrollPanel = sdk.getComponent("structures.ScrollPanel");
const Spinner = sdk.getComponent("elements.Spinner"); const Spinner = sdk.getComponent("elements.Spinner");
let topSpinner, bottomSpinner; let topSpinner;
let bottomSpinner;
if (this.props.backPaginating) { if (this.props.backPaginating) {
topSpinner = <li key="_topSpinner"><Spinner /></li>; topSpinner = <li key="_topSpinner"><Spinner /></li>;
} }