Implement "seen by" functionality
This commit is contained in:
parent
e593b34326
commit
92ec6b0280
5 changed files with 139 additions and 2 deletions
|
|
@ -356,6 +356,40 @@ body {
|
|||
.quick-reaction-container .emoji {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.seen-by-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
height: 16px;
|
||||
.clickable {
|
||||
display: flex;
|
||||
height: 16px;
|
||||
}
|
||||
div {
|
||||
height: 16px;
|
||||
}
|
||||
margin-top: 3px;
|
||||
.more {
|
||||
margin-right: 10px;
|
||||
color: #444444;
|
||||
font-size: 12px;
|
||||
}
|
||||
.seen-by-user {
|
||||
width: 16px !important;
|
||||
height: 16px !important;
|
||||
margin-left: -5px !important;
|
||||
vertical-align: top;
|
||||
}
|
||||
.list-enter-active,
|
||||
.list-leave-active {
|
||||
transition: all 1s;
|
||||
}
|
||||
.list-enter, .list-leave-to /* .list-leave-active below version 2.1.8 */ {
|
||||
opacity: 0;
|
||||
transform: translateX(24px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.messageIn {
|
||||
|
|
|
|||
|
|
@ -88,7 +88,8 @@
|
|||
"outgoing_message_deleted_text": "You deleted this message.",
|
||||
"incoming_message_deleted_text": "This message was deleted.",
|
||||
"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"
|
||||
},
|
||||
"room": {
|
||||
"invitations": "You have no invitations | You have 1 invitation | You have {count} invitations",
|
||||
|
|
|
|||
|
|
@ -21,14 +21,17 @@
|
|||
</v-btn>
|
||||
</div>
|
||||
<QuickReactions :event="event" :timelineSet="timelineSet" v-on="$listeners"/>
|
||||
<SeenBy :room="room" :event="event"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SeenBy from "./SeenBy.vue";
|
||||
import messageMixin from "./messageMixin";
|
||||
|
||||
export default {
|
||||
mixins: [messageMixin],
|
||||
mixins: [messageMixin],
|
||||
components: { SeenBy }
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -25,14 +25,17 @@
|
|||
<span v-else class="white--text headline">{{ userAvatarLetter }}</span>
|
||||
</v-avatar>
|
||||
<QuickReactions :event="event" :timelineSet="timelineSet" v-on="$listeners"/>
|
||||
<SeenBy :room="room" :event="event"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SeenBy from "./SeenBy.vue";
|
||||
import messageMixin from "./messageMixin";
|
||||
|
||||
export default {
|
||||
mixins: [messageMixin],
|
||||
components: { SeenBy }
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
|
|
|||
96
src/components/messages/SeenBy.vue
Normal file
96
src/components/messages/SeenBy.vue
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
<template>
|
||||
<div class="seen-by-container">
|
||||
<v-tooltip top open-delay="500">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<div v-bind="attrs" v-on="on" class="clickable">
|
||||
<div class="more" v-if="seenBy.length > 0">{{ moreItems }}</div>
|
||||
<transition-group name="list" tag="div" v-if="seenBy.length > 0">
|
||||
<v-avatar v-for="(member, index) in seenBy" :key="member.userId" class="seen-by-user" size="16" color="grey"
|
||||
v-show="index < SHOW_LIMIT">
|
||||
<img v-if="memberAvatar(member)" :src="memberAvatar(member)" />
|
||||
<span v-else class="white--text headline">{{
|
||||
member.name.substring(0, 1).toUpperCase()
|
||||
}}</span>
|
||||
</v-avatar>
|
||||
</transition-group>
|
||||
</div>
|
||||
</template>
|
||||
<span>{{ $tc("message.seen_by", seenBy.length) }}</span>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
room: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return null;
|
||||
},
|
||||
},
|
||||
event: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
seenBy: [],
|
||||
SHOW_LIMIT: 5,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.update();
|
||||
if (this.room) {
|
||||
this.room.on("Room.receipt", this.onReceipt);
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.room) {
|
||||
this.room.off("Room.receipt", this.onReceipt);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
moreItems() {
|
||||
if (this.seenBy.length > this.SHOW_LIMIT) {
|
||||
return `+${this.seenBy.length - this.SHOW_LIMIT}`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onReceipt(ignoredevent) {
|
||||
this.update();
|
||||
},
|
||||
memberAvatar(member) {
|
||||
if (member) {
|
||||
return member.getAvatarUrl(
|
||||
this.$matrix.matrixClient.getHomeserverUrl(),
|
||||
16,
|
||||
16,
|
||||
"scale",
|
||||
true
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
update() {
|
||||
this.seenBy = ((this.room && this.event) ? this.room.getReceiptsForEvent(this.event) : [])
|
||||
.filter(receipt => receipt.type == 'm.read' && receipt.userId !== this.$matrix.currentUserId)
|
||||
.map(receipt => this.room.getMember(receipt.userId));
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
event() {
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "@/assets/css/chat.scss";
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue