Work on read markers

Don't update read marker for outgoing events (they might be local echoes etc).
This commit is contained in:
N-Pex 2021-03-03 12:29:55 +01:00
parent ae09d3a78a
commit 7cf9d5b949
3 changed files with 107 additions and 25 deletions

View file

@ -149,7 +149,7 @@
<v-col <v-col
class="input-area-button text-center flex-grow-0 flex-shrink-1" class="input-area-button text-center flex-grow-0 flex-shrink-1"
v-if="!currentInput || currentInput.length == 0" v-if="!currentInput || currentInput.length == 0"
> >
<v-btn <v-btn
ref="mic_button" ref="mic_button"
@ -158,7 +158,7 @@
elevation="0" elevation="0"
color="transparent" color="transparent"
v-blur v-blur
style="z-index:10" style="z-index: 10"
@touchstart.native.stop="startRecording" @touchstart.native.stop="startRecording"
@mousedown.native.stop="startRecording" @mousedown.native.stop="startRecording"
> >
@ -166,8 +166,9 @@
</v-btn> </v-btn>
</v-col> </v-col>
<v-col class="input-area-button text-center flex-grow-0 flex-shrink-1" <v-col
v-else class="input-area-button text-center flex-grow-0 flex-shrink-1"
v-else
> >
<v-btn <v-btn
fab fab
@ -204,9 +205,13 @@
/> />
</label> </label>
</v-col> </v-col>
</v-row> </v-row>
<VoiceRecorder :micButtonRef="$refs.mic_button" :show="showRecorder" v-on:close="showRecorder = false" v-on:file="onVoiceRecording" /> <VoiceRecorder
:micButtonRef="$refs.mic_button"
:show="showRecorder"
v-on:close="showRecorder = false"
v-on:file="onVoiceRecording"
/>
</v-container> </v-container>
<div v-if="currentImageInput"> <div v-if="currentImageInput">
@ -264,7 +269,12 @@
</v-dialog> </v-dialog>
<!-- Loading indicator --> <!-- Loading indicator -->
<v-container fluid fill-height style="position: absolute" v-if="!initialLoadDone"> <v-container
fluid
fill-height
style="position: absolute"
v-if="!initialLoadDone"
>
<v-row align="center" justify="center"> <v-row align="center" justify="center">
<v-col class="text-center"> <v-col class="text-center">
<v-progress-circular <v-progress-circular
@ -291,6 +301,7 @@ import ContactInvited from "./messages/ContactInvited.vue";
import RoomNameChanged from "./messages/RoomNameChanged.vue"; import RoomNameChanged from "./messages/RoomNameChanged.vue";
import RoomTopicChanged from "./messages/RoomTopicChanged.vue"; import RoomTopicChanged from "./messages/RoomTopicChanged.vue";
import RoomAvatarChanged from "./messages/RoomAvatarChanged.vue"; import RoomAvatarChanged from "./messages/RoomAvatarChanged.vue";
import RoomHistoryVisibility from "./messages/RoomHistoryVisibility.vue";
import DebugEvent from "./messages/DebugEvent.vue"; import DebugEvent from "./messages/DebugEvent.vue";
import util from "../plugins/utils"; import util from "../plugins/utils";
import MessageOperations from "./messages/MessageOperations.vue"; import MessageOperations from "./messages/MessageOperations.vue";
@ -343,6 +354,7 @@ export default {
RoomNameChanged, RoomNameChanged,
RoomTopicChanged, RoomTopicChanged,
RoomAvatarChanged, RoomAvatarChanged,
RoomHistoryVisibility,
DebugEvent, DebugEvent,
MessageOperations, MessageOperations,
VoiceRecorder VoiceRecorder
@ -533,7 +545,7 @@ export default {
onRoomJoined(initialEventId) { onRoomJoined(initialEventId) {
console.log("Read up to " + initialEventId); console.log("Read up to " + initialEventId);
//initialEventId = null; initialEventId = null;
this.timelineWindow = new TimelineWindow( this.timelineWindow = new TimelineWindow(
this.$matrix.matrixClient, this.$matrix.matrixClient,
@ -554,10 +566,10 @@ export default {
self.timelineWindow.canPaginate(EventTimeline.BACKWARDS) self.timelineWindow.canPaginate(EventTimeline.BACKWARDS)
) { ) {
return self.timelineWindow return self.timelineWindow
.paginate(EventTimeline.BACKWARDS, 10, true) .paginate(EventTimeline.BACKWARDS, 10, true, 5)
.then((success) => { .then((success) => {
self.events = self.timelineWindow.getEvents();
if (success) { if (success) {
self.events = self.timelineWindow.getEvents();
return _getMoreIfNeeded.call(self); return _getMoreIfNeeded.call(self);
} else { } else {
return Promise.reject("Failed to paginate"); return Promise.reject("Failed to paginate");
@ -587,6 +599,7 @@ export default {
this.onRoomJoined(null); this.onRoomJoined(null);
} else { } else {
// Error. Done loading. // Error. Done loading.
this.events = this.timelineWindow.getEvents();
this.initialLoadDone = true; this.initialLoadDone = true;
} }
}) })
@ -700,6 +713,9 @@ export default {
case "m.room.avatar": case "m.room.avatar":
return RoomAvatarChanged; return RoomAvatarChanged;
case "m.room.history_visibility":
return RoomHistoryVisibility;
} }
return DebugEvent; return DebugEvent;
}, },
@ -1039,7 +1055,7 @@ export default {
/** Stop Read Receipt timer */ /** Stop Read Receipt timer */
stopRRTimer() { stopRRTimer() {
if (this.rrTimer) { if (this.rrTimer) {
clearInterval(this.rrTimer); clearTimeout(this.rrTimer);
this.rrTimer = null; this.rrTimer = null;
} }
}, },
@ -1049,32 +1065,48 @@ export default {
*/ */
restartRRTimer() { restartRRTimer() {
this.stopRRTimer(); this.stopRRTimer();
this.rrTimer = setInterval(this.rrTimerElapsed, READ_RECEIPT_TIMEOUT); this.rrTimer = setTimeout(this.rrTimerElapsed, READ_RECEIPT_TIMEOUT);
}, },
rrTimerElapsed() { rrTimerElapsed() {
const container = this.$refs.chatContainer; this.rrTimer = null;
const el = util.getLastVisibleElement(container);
if (el) {
const eventId = el.getAttribute("eventId");
if (eventId && this.room) {
const event = this.room.findEventById(eventId);
if (event && (!this.lastRR || event.getTs() > this.lastRR.getTs())) {
// Disable timer while we are sending
clearInterval(this.rrTimer);
this.rrTimer = null;
// Send read receipt const container = this.$refs.chatContainer;
const elFirst = util.getFirstVisibleElement(container);
const elLast = util.getLastVisibleElement(container);
if (elFirst && elLast) {
const eventIdFirst = elFirst.getAttribute("eventId");
const eventIdLast = elLast.getAttribute("eventId");
if (eventIdLast && this.room) {
var event = this.room.findEventById(eventIdLast);
const index = this.events.indexOf(event);
// Walk backwards through visible events to the first one that is incoming
//
var lastTimestamp = 0;
if (this.lastRR) {
lastTimestamp = this.lastRR.getTs();
}
for (var i = index; i >= 0; i--) {
event = this.events[i];
if (event == this.lastRR || event.getTs() <= lastTimestamp) {
// Already sent this or too old...
break;
}
// Is it an incoming event?
if (event.getSender() !== this.$matrix.currentUserId) {
// Send read receipt
this.$matrix.matrixClient this.$matrix.matrixClient
.sendReadReceipt(event) .sendReadReceipt(event)
.then(() => { .then(() => {
this.$matrix.matrixClient.setRoomReadMarkers( this.$matrix.matrixClient.setRoomReadMarkers(
this.room.roomId, this.room.roomId,
eventId event.getId()
); );
}) })
.then(() => { .then(() => {
console.log("RR sent for event: " + eventId); console.log("RR sent for event: " + event.getId());
this.lastRR = event; this.lastRR = event;
}) })
.catch((err) => { .catch((err) => {
@ -1083,9 +1115,17 @@ export default {
.finally(() => { .finally(() => {
this.restartRRTimer(); this.restartRRTimer();
}); });
return; // Bail out here
}
// Stop iterating at first visible
if (event.getId() == eventIdFirst) {
break;
}
} }
} }
} }
this.restartRRTimer();
}, },
showDayMarkerBeforeEvent(event) { showDayMarkerBeforeEvent(event) {

View file

@ -0,0 +1,34 @@
<template>
<!-- ROOM AVATAR CHANGED -->
<div class="statusEvent">
{{ stateEventDisplayName(event) }} made room history {{ history(event) }}
</div>
</template>
<script>
import messageMixin from "./messageMixin";
export default {
mixins: [messageMixin],
methods: {
history(event) {
const visibility = event.getContent().history_visibility;
switch (visibility) {
case "world_readable":
return "readable by anyone";
case "shared":
return "readable to all members in the room";
case "invited":
return "readable to members from when they were invited";
case "joined":
return "readable to members from when they joined";
}
return visibility;
}
}
};
</script>
<style lang="scss">
@import "@/assets/css/chat.scss";
</style>

View file

@ -348,9 +348,17 @@ class Util {
return null; return null;
} }
getFirstVisibleElement(parentNode) {
const y = parentNode.scrollTop;
return this.getElementAtY(parentNode, y);
}
getLastVisibleElement(parentNode) { getLastVisibleElement(parentNode) {
const y = parentNode.scrollTop + parentNode.clientHeight; const y = parentNode.scrollTop + parentNode.clientHeight;
return this.getElementAtY(parentNode, y);
}
getElementAtY(parentNode, y) {
let start = 0; let start = 0;
let end = parentNode.children.length - 1; let end = parentNode.children.length - 1;