Merge branch '482-show-list-of-seenBy' into 'dev'

Show member list of seen by

See merge request keanuapp/keanuapp-weblite!207
This commit is contained in:
N Pex 2023-06-26 12:22:35 +00:00
commit 791fa5936a
8 changed files with 91 additions and 43 deletions

View file

@ -208,7 +208,6 @@ body {
@media #{map-get($display-breakpoints, 'sm-and-down')} { @media #{map-get($display-breakpoints, 'sm-and-down')} {
margin-top: 72px; margin-top: 72px;
margin-bottom: 70px; margin-bottom: 70px;
z-index: 9;
} }
} }

View file

@ -96,7 +96,8 @@
"incoming_message_deleted_text": "This message was deleted.", "incoming_message_deleted_text": "This message was deleted.",
"not_allowed_to_send": "Only admins and moderators are allowed to send to the room", "not_allowed_to_send": "Only admins and moderators are allowed to send to the room",
"reaction_count_more": "{reactionCount} more", "reaction_count_more": "{reactionCount} more",
"seen_by": "Seen by no members | Seen by 1 member | Seen by {count} members", "seen_by_count": "Seen by no members | Seen by 1 member | Seen by {count} members",
"seen_by": "Seen by",
"file": "File", "file": "File",
"files": "Files", "files": "Files",
"images": "Images", "images": "Images",

View file

@ -182,7 +182,7 @@ export default {
bottom: 0; bottom: 0;
overflow-x: hidden; overflow-x: hidden;
overflow-y: hidden; overflow-y: hidden;
z-index: 10; z-index: 20;
} }
.bottom-sheet-bg { .bottom-sheet-bg {

View file

@ -4,7 +4,7 @@
<div v-if="showSenderAndTime" class="senderAndTime"> <div v-if="showSenderAndTime" class="senderAndTime">
<div class="sender">{{ eventSenderDisplayName(event) }}</div> <div class="sender">{{ eventSenderDisplayName(event) }}</div>
<div class="time"> <div class="time">
{{ formatTime(event.event.origin_server_ts) }} {{ utils.formatTime(event.event.origin_server_ts) }}
</div> </div>
</div> </div>
<v-avatar class="avatar" ref="avatar" size="32" color="#ededed" @click.stop="otherAvatarClicked($refs.avatar.$el)"> <v-avatar class="avatar" ref="avatar" size="32" color="#ededed" @click.stop="otherAvatarClicked($refs.avatar.$el)">

View file

@ -3,7 +3,7 @@
<div class="messageOut"> <div class="messageOut">
<div class="senderAndTime"> <div class="senderAndTime">
<div class="time"> <div class="time">
{{ formatTime(event.event.origin_server_ts) }} {{ utils.formatTime(event.event.origin_server_ts) }}
</div> </div>
<div class="status">{{ event.status }}</div> <div class="status">{{ event.status }}</div>
</div> </div>

View file

@ -1,27 +1,57 @@
<template> <template>
<div class="seen-by-container"> <div>
<v-tooltip top open-delay="500" v-if="seenBy.length > 0"> <div class="seen-by-container">
<template v-slot:activator="{ on, attrs }"> <v-tooltip top open-delay="500" v-if="seenBy.length > 0">
<div v-bind="attrs" v-on="on" class="clickable"> <template v-slot:activator="{ on, attrs }">
<div class="more" v-if="seenBy.length > 0">{{ moreItems }}</div> <div v-bind="attrs" v-on="on" class="clickable">
<transition-group name="list" tag="div" v-if="seenBy.length > 0"> <div class="more" v-if="seenBy.length > 0">{{ moreItems }}</div>
<v-avatar v-for="(member, index) in seenBy" :key="member.userId" class="seen-by-user" size="16" color="grey" <transition-group name="list" tag="div" v-if="seenBy.length > 0">
v-show="index < SHOW_LIMIT"> <v-avatar v-for="(member, index) in seenBy" :key="member.roomMember.userId" class="seen-by-user" size="16" color="grey"
<img v-if="memberAvatar(member)" :src="memberAvatar(member)" /> v-show="index < SHOW_LIMIT" @click="open">
<img v-if="memberAvatar(member.roomMember)" :src="memberAvatar(member.roomMember)" />
<span v-else class="white--text headline">{{
member.roomMember.name.substring(0, 1).toUpperCase()
}}</span>
</v-avatar>
</transition-group>
</div>
</template>
<span>{{ $tc("message.seen_by_count", seenBy.length) }}</span>
</v-tooltip>
</div>
<BottomSheet
:halfY="0.12"
ref="seenByListBottomSheet"
>
<v-list>
<v-subheader class="text-uppercase"> {{ $tc("message.seen_by") }}</v-subheader>
<v-list-item v-for="(member, index) in seenBy" :key="index">
<v-list-item-icon>
<v-avatar size="40" color="grey">
<img v-if="memberAvatar(member.roomMember)" :src="memberAvatar(member.roomMember)" />
<span v-else class="white--text headline">{{ <span v-else class="white--text headline">{{
member.name.substring(0, 1).toUpperCase() member.roomMember.name.substring(0, 1).toUpperCase()
}}</span> }}</span>
</v-avatar> </v-avatar>
</transition-group> </v-list-item-icon>
</div> <v-list-item-content class="text-left">
</template> <v-list-item-title>{{member.roomMember.name}}</v-list-item-title>
<span>{{ $tc("message.seen_by", seenBy.length) }}</span> <v-list-item-subtitle>{{ seenByTimeStamp(member.readTimestamp) }}</v-list-item-subtitle>
</v-tooltip> </v-list-item-content>
</v-list-item>
</v-list>
</BottomSheet>
</div> </div>
</template> </template>
<script> <script>
import BottomSheet from "../BottomSheet.vue"
import utils from "../../plugins/utils.js";
export default { export default {
components: {
BottomSheet
},
props: { props: {
room: { room: {
type: Object, type: Object,
@ -40,6 +70,7 @@ export default {
return { return {
seenBy: [], seenBy: [],
SHOW_LIMIT: 5, SHOW_LIMIT: 5,
utils
} }
}, },
mounted() { mounted() {
@ -62,6 +93,17 @@ export default {
} }
}, },
methods: { methods: {
seenByTimeStamp(timestamp) {
let dayDiff = utils.dayDiffToday(timestamp);
if (dayDiff < 3) {
return this.$tc("message.time_ago", dayDiff) + ' '+utils.formatTime(timestamp);
} else {
return utils.formatTime(timestamp);
}
},
open() {
this.$refs.seenByListBottomSheet.open();
},
onReceipt(ignoredevent) { onReceipt(ignoredevent) {
this.update(); this.update();
}, },
@ -80,7 +122,10 @@ export default {
update() { update() {
this.seenBy = ((this.room && this.event) ? this.room.getReceiptsForEvent(this.event) : []) this.seenBy = ((this.room && this.event) ? this.room.getReceiptsForEvent(this.event) : [])
.filter(receipt => receipt.type == 'm.read' && receipt.userId !== this.$matrix.currentUserId) .filter(receipt => receipt.type == 'm.read' && receipt.userId !== this.$matrix.currentUserId)
.map(receipt => this.room.getMember(receipt.userId)); .map(receipt => {
return { readTimestamp: receipt.data.ts, roomMember: this.room.getMember(receipt.userId) }
}
);
}, },
}, },
watch: { watch: {

View file

@ -1,6 +1,8 @@
import QuickReactions from "./QuickReactions.vue"; import QuickReactions from "./QuickReactions.vue";
import * as linkify from 'linkifyjs'; import * as linkify from 'linkifyjs';
import linkifyHtml from 'linkify-html'; import linkifyHtml from 'linkify-html';
import utils from "../../plugins/utils"
linkify.options.defaults.className = "link"; linkify.options.defaults.className = "link";
linkify.options.defaults.target = { url: "_blank" }; linkify.options.defaults.target = { url: "_blank" };
@ -39,6 +41,7 @@ export default {
event: {}, event: {},
inReplyToEvent: null, inReplyToEvent: null,
inReplyToSender: null, inReplyToSender: null,
utils
}; };
}, },
mounted() { mounted() {
@ -231,22 +234,6 @@ export default {
return false; return false;
}, },
formatTime(time) {
const date = new Date();
date.setTime(time);
const today = new Date();
if (
date.getDate() == today.getDate() &&
date.getMonth() == today.getMonth() &&
date.getFullYear() == today.getFullYear()
) {
// For today, skip the date part
return date.toLocaleTimeString();
}
return date.toLocaleString();
},
formatTimeAgo(time) { formatTimeAgo(time) {
const date = new Date(); const date = new Date();
date.setTime(time); date.setTime(time);

View file

@ -779,6 +779,22 @@ class Util {
return then.format('L'); return then.format('L');
} }
formatTime(time) {
const date = new Date();
date.setTime(time);
const today = new Date();
if (
date.getDate() == today.getDate() &&
date.getMonth() == today.getMonth() &&
date.getFullYear() == today.getFullYear()
) {
// For today, skip the date part
return date.toLocaleTimeString();
}
return date.toLocaleString();
}
formatRecordDuration(ms) { formatRecordDuration(ms) {
return dayjs.duration(ms).format("HH:mm:ss"); return dayjs.duration(ms).format("HH:mm:ss");
} }