Add timed message retention feature

This commit is contained in:
N Pex 2024-02-06 10:22:35 +00:00
parent f8e67afa31
commit 3313da0cb8
5 changed files with 404 additions and 47 deletions

View file

@ -483,6 +483,11 @@ export default {
Places: this.$t("emoji.categories.places")
}
},
/**
* A timer to handle message retention/auto deletion
*/
retentionTimer: null
};
},
@ -511,6 +516,10 @@ export default {
this.$root.$off('audio-playback-ended', this.audioPlaybackEnded);
this.$audioPlayer.pause();
this.stopRRTimer();
if (this.retentionTimer) {
clearInterval(this.retentionTimer);
this.retentionTimer = null;
}
},
destroyed() {
@ -774,6 +783,12 @@ export default {
this.events.filter(event => (event.threadRootId && !event.parentThread)).forEach(event => this.setParentThread(event));
this.events.filter(event => (event.replyEventId && !event.replyEvent)).forEach(event => this.setReplyToEvent(event));
console.log("Loading finished!");
this.updateRetentionTimer();
} else if (!value) {
if (this.retentionTimer) {
clearInterval(this.retentionTimer);
this.retentionTimer = null;
}
}
}
},
@ -871,6 +886,52 @@ export default {
this.initialLoadDone = true;
console.log("Loading finished!");
},
/**
* Set events to display. At the same time, filter out messages that are past rentention period etc.
*/
setEvents(events) {
this.events = this.removeTimedOutEvents(events);
},
updateRetentionTimer(maybeEvent) {
const retentionEvent = maybeEvent || (this.room && this.room.currentState.getStateEvents("m.room.retention", ""));
if (retentionEvent) {
const maxLifetime = parseInt(retentionEvent.getContent().max_lifetime);
if (maxLifetime) {
if (!this.retentionTimer) {
this.retentionTimer = setInterval(this.onRetentionTimer, 60000);
}
return;
}
}
if (this.retentionTimer) {
clearInterval(this.retentionTimer);
this.retentionTimer = null;
}
},
removeTimedOutEvents(events) {
const retentionEvent = this.room && this.room.currentState.getStateEvents("m.room.retention", "");
let maxLifetime = 0;
if (retentionEvent) {
maxLifetime = parseInt(retentionEvent.getContent().max_lifetime);
}
return events.filter((e) => {
if (maxLifetime > 0 && !e.isState()) { // Keep all state events
return e.getLocalAge() < maxLifetime;
}
return true;
});
},
onRetentionTimer() {
const events = this.removeTimedOutEvents(this.events);
if (events.length != this.events.length) {
this.events = events; // Changed
}
},
onRoomJoined(initialEventId) {
// Listen to events
this.$matrix.on("Room.timeline", this.onEvent);
@ -885,7 +946,7 @@ export default {
this.timelineWindow
.load(initialEventId, 20)
.then(() => {
self.events = self.timelineWindow.getEvents();
self.setEvents(self.timelineWindow.getEvents());
const getMoreIfNeeded = function _getMoreIfNeeded() {
const container = self.$refs.chatContainer;
@ -896,7 +957,7 @@ export default {
self.timelineWindow.canPaginate(EventTimeline.BACKWARDS)
) {
return self.timelineWindow.paginate(EventTimeline.BACKWARDS, 10, true, 5).then((success) => {
self.events = self.timelineWindow.getEvents();
self.setEvents(self.timelineWindow.getEvents());
if (success) {
return _getMoreIfNeeded.call(self);
} else {
@ -943,7 +1004,7 @@ export default {
this.onRoomJoined(null);
} else {
// Error. Done loading.
this.events = this.timelineWindow.getEvents();
this.setEvents(this.timelineWindow.getEvents());
this.setInitialLoadDone();
}
})
@ -976,7 +1037,7 @@ export default {
.then(() => {
self.timelineSet = timelineSet;
self.timelineWindow = timelineWindow;
self.events = self.timelineWindow.getEvents();
self.setEvents(self.timelineWindow.getEvents());
})
.finally(() => {
this.loading = false;
@ -1090,7 +1151,7 @@ export default {
if (tl) {
const parentEvent = tl.getEvents().find((e) => e.getId() === event.threadRootId);
if (parentEvent) {
this.events = this.timelineWindow.getEvents();
this.setEvents(this.timelineWindow.getEvents());
const fn = () => {
Vue.set(parentEvent, "isMxThread", true);
Vue.set(event, "parentThread", parentEvent);
@ -1123,7 +1184,7 @@ export default {
if (tl) {
const parentEvent = tl.getEvents().find((e) => e.getId() === event.replyEventId);
if (parentEvent) {
this.events = this.timelineWindow.getEvents();
this.setEvents(this.timelineWindow.getEvents());
const fn = () => {Vue.set(event, "replyEvent", parentEvent);};
if (this.initialLoadDone) {
const sel = "[eventId=\"" + parentEvent.getId() + "\"]";
@ -1162,7 +1223,7 @@ export default {
this.paginateBackIfNeeded();
}
if (loadingDone && event.forwardLooking && (!event.isRelation() || event.isMxThread || event.threadRootId || event.parentThread )) {
if (loadingDone && event.forwardLooking && (!event.isRelation() || event.isMxThread || event.threadRootId || event.parentThread)) {
// If we are at bottom, scroll to see new events...
var scrollToSeeNew = event.getSender() == this.$matrix.currentUserId; // When we sent, scroll
const container = this.chatContainer;
@ -1179,13 +1240,17 @@ export default {
(event.getPrevContent() || {}).membership == "join" &&
(
(event.getContent().membership == "leave" && event.getSender() != this.currentUserId) ||
(event.getContent().membership == "ban" ))
) {
this.$store.commit("setCurrentRoomId", null);
const wasPurged = event.getContent().reason == "Room Deleted";
this.$navigation.push({ name: "Goodbye", params: { roomWasPurged: wasPurged } }, -1);
}
(event.getContent().membership == "ban"))
) {
this.$store.commit("setCurrentRoomId", null);
const wasPurged = event.getContent().reason == "Room Deleted";
this.$navigation.push({ name: "Goodbye", params: { roomWasPurged: wasPurged } }, -1);
}
else if (event.getType() === "m.room.retention") {
this.updateRetentionTimer(event);
}
}
},
onUserTyping(event, member) {
@ -1404,7 +1469,7 @@ export default {
.then((success) => {
if (success && this.scrollPosition) {
this.scrollPosition.prepareFor("up");
this.events = this.timelineWindow.getEvents();
this.setEvents(this.timelineWindow.getEvents());
this.$nextTick(() => {
// restore scroll position!
console.log("Restore scroll!");
@ -1429,7 +1494,7 @@ export default {
.paginate(EventTimeline.FORWARDS, 10, true)
.then((success) => {
if (success) {
this.events = this.timelineWindow.getEvents();
this.setEvents(this.timelineWindow.getEvents());
if (!this.useVoiceMode && this.scrollPosition) {
this.scrollPosition.prepareFor("down");
this.$nextTick(() => {