Merge pull request #85 from matrix-org/read_marker_animate
Improve read markers so they show at appropriate times and animate away.pull/21833/head
commit
2eb724f1f0
|
@ -31,6 +31,11 @@ class UserActivity {
|
|||
start() {
|
||||
document.onmousemove = this._onUserActivity.bind(this);
|
||||
document.onkeypress = this._onUserActivity.bind(this);
|
||||
// can't use document.scroll here because that's only the document
|
||||
// itself being scrolled. Need to use addEventListener's useCapture.
|
||||
// also this needs to be the wheel event, not scroll, as scroll is
|
||||
// fired when the view scrolls down for a new message.
|
||||
window.addEventListener('wheel', this._onUserActivity.bind(this), true);
|
||||
this.lastActivityAtTs = new Date().getTime();
|
||||
this.lastDispatchAtTs = 0;
|
||||
}
|
||||
|
@ -41,10 +46,11 @@ class UserActivity {
|
|||
stop() {
|
||||
document.onmousemove = undefined;
|
||||
document.onkeypress = undefined;
|
||||
window.removeEventListener('wheel', this._onUserActivity.bind(this), true);
|
||||
}
|
||||
|
||||
_onUserActivity(event) {
|
||||
if (event.screenX) {
|
||||
if (event.screenX && event.type == "mousemove") {
|
||||
if (event.screenX === this.lastScreenX &&
|
||||
event.screenY === this.lastScreenY)
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@ var dis = require("../../dispatcher");
|
|||
|
||||
var PAGINATE_SIZE = 20;
|
||||
var INITIAL_SIZE = 20;
|
||||
var SEND_READ_RECEIPT_DELAY = 2000;
|
||||
|
||||
var DEBUG_SCROLL = false;
|
||||
|
||||
|
@ -74,6 +75,8 @@ module.exports = React.createClass({
|
|||
syncState: MatrixClientPeg.get().getSyncState(),
|
||||
hasUnsentMessages: this._hasUnsentMessages(room),
|
||||
callState: null,
|
||||
readMarkerEventId: room.getEventReadUpTo(MatrixClientPeg.get().credentials.userId),
|
||||
readMarkerGhostEventId: undefined,
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -261,7 +264,33 @@ module.exports = React.createClass({
|
|||
|
||||
onRoomReceipt: function(receiptEvent, room) {
|
||||
if (room.roomId == this.props.roomId) {
|
||||
this.forceUpdate();
|
||||
var readMarkerEventId = this.state.room.getEventReadUpTo(MatrixClientPeg.get().credentials.userId);
|
||||
var readMarkerGhostEventId = this.state.readMarkerGhostEventId;
|
||||
if (this.state.readMarkerEventId !== undefined && this.state.readMarkerEventId != readMarkerEventId) {
|
||||
readMarkerGhostEventId = this.state.readMarkerEventId;
|
||||
}
|
||||
|
||||
|
||||
// if the event after the one referenced in the read receipt if sent by us, do nothing since
|
||||
// this is a temporary period before the synthesized receipt for our own message arrives
|
||||
var readMarkerGhostEventIndex;
|
||||
for (var i = 0; i < room.timeline.length; ++i) {
|
||||
if (room.timeline[i].getId() == readMarkerGhostEventId) {
|
||||
readMarkerGhostEventIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (readMarkerGhostEventIndex + 1 < room.timeline.length) {
|
||||
var nextEvent = room.timeline[readMarkerGhostEventIndex + 1];
|
||||
if (nextEvent.sender && nextEvent.sender.userId == MatrixClientPeg.get().credentials.userId) {
|
||||
readMarkerGhostEventId = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
readMarkerEventId: readMarkerEventId,
|
||||
readMarkerGhostEventId: readMarkerGhostEventId,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -682,10 +711,10 @@ module.exports = React.createClass({
|
|||
|
||||
var EventTile = sdk.getComponent('rooms.EventTile');
|
||||
|
||||
|
||||
var prevEvent = null; // the last event we showed
|
||||
var readReceiptEventId = this.state.room.getEventReadUpTo(MatrixClientPeg.get().credentials.userId);
|
||||
var startIdx = Math.max(0, this.state.room.timeline.length - this.state.messageCap);
|
||||
var readMarkerIndex;
|
||||
var ghostIndex;
|
||||
for (var i = startIdx; i < this.state.room.timeline.length; i++) {
|
||||
var mxEv = this.state.room.timeline[i];
|
||||
|
||||
|
@ -699,6 +728,25 @@ module.exports = React.createClass({
|
|||
}
|
||||
}
|
||||
|
||||
// now we've decided whether or not to show this message,
|
||||
// add the read up to marker if appropriate
|
||||
// doing this here means we implicitly do not show the marker
|
||||
// if it's at the bottom
|
||||
// NB. it would be better to decide where the read marker was going
|
||||
// when the state changed rather than here in the render method, but
|
||||
// this is where we decide what messages we show so it's the only
|
||||
// place we know whether we're at the bottom or not.
|
||||
var self = this;
|
||||
var mxEvSender = mxEv.sender ? mxEv.sender.userId : null;
|
||||
if (prevEvent && prevEvent.getId() == this.state.readMarkerEventId && mxEvSender != MatrixClientPeg.get().credentials.userId) {
|
||||
var hr;
|
||||
hr = (<hr className="mx_RoomView_myReadMarker" style={{opacity: 1, width: '99%'}} ref={function(n) {
|
||||
self.readMarkerNode = n;
|
||||
}} />);
|
||||
readMarkerIndex = ret.length;
|
||||
ret.push(<li key="_readupto" className="mx_RoomView_myReadMarker_container">{hr}</li>);
|
||||
}
|
||||
|
||||
// is this a continuation of the previous message?
|
||||
var continuation = false;
|
||||
if (prevEvent !== null) {
|
||||
|
@ -735,13 +783,29 @@ module.exports = React.createClass({
|
|||
</li>
|
||||
);
|
||||
|
||||
if (eventId == readReceiptEventId) {
|
||||
ret.push(<hr className="mx_RoomView_myReadMarker" />);
|
||||
// A read up to marker has died and returned as a ghost!
|
||||
// Lives in the dom as the ghost of the previous one while it fades away
|
||||
if (eventId == this.state.readMarkerGhostEventId) {
|
||||
ghostIndex = ret.length;
|
||||
}
|
||||
|
||||
prevEvent = mxEv;
|
||||
}
|
||||
|
||||
// splice the read marker ghost in now that we know whether the read receipt
|
||||
// is the last element or not, because we only decide as we're going along.
|
||||
if (readMarkerIndex === undefined && ghostIndex && ghostIndex <= ret.length) {
|
||||
var hr;
|
||||
hr = (<hr className="mx_RoomView_myReadMarker" style={{opacity: 1, width: '85%'}} ref={function(n) {
|
||||
Velocity(n, {opacity: '0', width: '10%'}, {duration: 400, easing: 'easeInSine', delay: 1000, complete: function() {
|
||||
self.setState({readMarkerGhostEventId: undefined});
|
||||
}});
|
||||
}} />);
|
||||
ret.splice(ghostIndex, 0, (
|
||||
<li key="_readuptoghost" className="mx_RoomView_myReadMarker_container">{hr}</li>
|
||||
));
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in New Issue