255 lines
No EOL
7.7 KiB
Vue
255 lines
No EOL
7.7 KiB
Vue
<template>
|
|
<v-container fluid v-if="room">
|
|
<v-row class="chat-header-row flex-nowrap">
|
|
<v-col class="chat-header-name ma-0 pa-0 flex-shrink-1 flex-nowrap" @click.stop="onHeaderClicked">
|
|
<div class="room-title-row">
|
|
<div class="room-name-inline text-truncate" :title="room.name">
|
|
{{ room.name }}
|
|
</div>
|
|
<v-icon class="icon-dropdown" size="11">$vuetify.icons.ic_dropdown</v-icon>
|
|
<div :class="{ 'notification-alert': true, 'popup-open': showMissedItemsInfo }" v-if="notifications">
|
|
<!-- MISSED ITEMS POPUP -->
|
|
<div class="missed-items-popup-background" v-if="showMissedItemsInfo" @click.stop=""></div>
|
|
<div class="missed-items-popup" v-if="showMissedItemsInfo">
|
|
<div class="text">{{ notificationsText }}</div>
|
|
<div class="button clickable" @click.stop="$store.commit('setHasShownMissedItemsHint', true)">{{$t('menu.ok')}}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="num-members">{{ $tc("room.members", memberCount) }}</div>
|
|
</v-col>
|
|
<v-col cols="auto" class="text-end ma-0 pa-0 ms-1">
|
|
<v-avatar :class="{ 'avatar-32': true, 'clickable': true, 'popup-open': showProfileInfo }" size="26"
|
|
color="#e0e0e0" @click.stop="showProfileInfo = true">
|
|
<img v-if="userAvatar" :src="userAvatar" />
|
|
<span v-else class="white--text">{{ userAvatarLetter }}</span>
|
|
</v-avatar>
|
|
</v-col>
|
|
<v-col cols="auto" class="text-end ma-0 pa-0 ms-1">
|
|
<v-btn id="btn-purge-room" v-if="userCanPurgeRoom" class="mx-2 box-shadow-none" fab dark small color="red"
|
|
@click.stop="showPurgeConfirmation = true">
|
|
<v-icon light>$vuetify.icons.ic_moderator-delete</v-icon>
|
|
</v-btn>
|
|
<v-btn id="btn-leave-room" class="mx-2 box-shadow-none" fab dark small color="red" @click.stop="leaveRoom" v-else>
|
|
<v-icon color="white">$vuetify.icons.ic_member-leave</v-icon>
|
|
</v-btn>
|
|
</v-col>
|
|
<v-col cols="auto" class="text-end ma-0 pa-0 ms-1 clickable">
|
|
<div :class="{ 'popup-open': showMoreMenu }">
|
|
<v-btn class="mx-2 box-shadow-none" fab dark small color="transparent" @click.stop="showMoreMenu = true">
|
|
<v-icon size="15" color="black">$vuetify.icons.ic_more</v-icon>
|
|
</v-btn>
|
|
</div>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- "REALLY LEAVE?" dialog -->
|
|
<LeaveRoomDialog :show="showLeaveConfirmation" :room="room" @close="showLeaveConfirmation = false" />
|
|
|
|
<!-- PROFILE INFO POPUP -->
|
|
<ProfileInfoPopup :show="showProfileInfo" @close="showProfileInfo = false" />
|
|
|
|
<!-- MORE MENU POPUP -->
|
|
<MoreMenuPopup :show="showMoreMenu" :menuItems="moreMenuItems" @close="showMoreMenu = false"
|
|
v-on:leave="showLeaveConfirmation = true" />
|
|
|
|
<!-- PURGE ROOM POPUP -->
|
|
<PurgeRoomDialog :show="showPurgeConfirmation" :room="room" @close="showPurgeConfirmation = false" />
|
|
|
|
<RoomExport :room="room" v-if="downloadingChat" v-on:close="downloadingChat = false" />
|
|
|
|
</v-container>
|
|
</template>
|
|
|
|
<script>
|
|
import LeaveRoomDialog from "../components/LeaveRoomDialog";
|
|
import ProfileInfoPopup from "../components/ProfileInfoPopup";
|
|
import MoreMenuPopup from "../components/MoreMenuPopup";
|
|
import profileInfoMixin from "../components/profileInfoMixin";
|
|
import PurgeRoomDialog from "../components/PurgeRoomDialog";
|
|
import RoomExport from "../components/RoomExport";
|
|
|
|
import roomInfoMixin from "./roomInfoMixin";
|
|
|
|
export default {
|
|
name: "ChatHeader",
|
|
mixins: [profileInfoMixin, roomInfoMixin],
|
|
components: {
|
|
LeaveRoomDialog,
|
|
ProfileInfoPopup,
|
|
MoreMenuPopup,
|
|
PurgeRoomDialog,
|
|
RoomExport
|
|
},
|
|
data() {
|
|
return {
|
|
memberCount: null,
|
|
showLeaveConfirmation: false,
|
|
showProfileInfo: false,
|
|
showPurgeConfirmation: false,
|
|
showMoreMenu: false,
|
|
downloadingChat: false,
|
|
};
|
|
},
|
|
mounted() {
|
|
this.$matrix.on("Room.timeline", this.onEvent);
|
|
this.updateMemberCount();
|
|
},
|
|
|
|
destroyed() {
|
|
this.$matrix.off("Room.timeline", this.onEvent);
|
|
},
|
|
|
|
computed: {
|
|
room() {
|
|
return this.$matrix.currentRoom;
|
|
},
|
|
memberAvatar() {
|
|
let roomMember;
|
|
if (this.room) {
|
|
this.room.getMembers().forEach(member => {
|
|
if (this.room.name === member.name) {
|
|
roomMember = member;
|
|
}
|
|
});
|
|
if (roomMember) {
|
|
return roomMember.getAvatarUrl(
|
|
this.$matrix.matrixClient.getHomeserverUrl(),
|
|
40,
|
|
40,
|
|
"scale",
|
|
true
|
|
);
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
notifications() {
|
|
return this.$matrix.joinedRooms.some(room => room.roomId !== this.$matrix.currentRoomId && room.getUnreadNotificationCount("total") > 0) ||
|
|
this.$matrix.invites.length > 0;
|
|
},
|
|
notificationsText() {
|
|
const invitationCount = this.$matrix.invites.length
|
|
if (invitationCount > 0) {
|
|
return this.$tc('room.invitations', invitationCount);
|
|
}
|
|
const missedMessagesCount = this.$matrix.joinedRooms.reduce((value, room) => (room.roomId !== this.$matrix.currentRoomId ? (value + room.getUnreadNotificationCount("total")) : value), 0);
|
|
if (missedMessagesCount > 0) {
|
|
return this.$tc('room.unseen_messages', missedMessagesCount);
|
|
}
|
|
return "";
|
|
},
|
|
moreMenuItems() {
|
|
let items = [];
|
|
const roomLink = this.publicRoomLink;
|
|
if (roomLink) {
|
|
items.push({
|
|
icon: '$vuetify.icons.ic_link', text: this.$t('room_info.copy_link'), handler: () => {
|
|
this.$copyText(this.publicRoomLink);
|
|
}
|
|
});
|
|
}
|
|
if (this.userCanExportChat) {
|
|
items.push({
|
|
icon: '$vuetify.icons.ic_download', text: this.$t('room_info.download_chat'), handler: () => {
|
|
this.downloadingChat = true;
|
|
}
|
|
});
|
|
}
|
|
items.push({
|
|
icon: '$vuetify.icons.ic_info', text: this.$t('room_info.title'), handler: () => {
|
|
this.$emit("view-room-details", { event: this.event });
|
|
}
|
|
});
|
|
items.push({
|
|
icon: '$vuetify.icons.ic_member-leave', text: this.$t('leave.leave'), handler: () => {
|
|
this.leaveRoom();
|
|
}
|
|
});
|
|
return items;
|
|
},
|
|
showMissedItemsInfo: {
|
|
get() {
|
|
return this.notifications && (this.$store.state.hasShownMissedItemsHint !== true);
|
|
},
|
|
set(newValue) {
|
|
console.log("Ignore", newValue);
|
|
}
|
|
},
|
|
},
|
|
watch: {
|
|
room: {
|
|
handler(newVal, ignoredOldVal) {
|
|
if (newVal) {
|
|
this.memberCount = newVal.getJoinedMemberCount();
|
|
} else {
|
|
this.memberCount = null;
|
|
}
|
|
},
|
|
},
|
|
},
|
|
|
|
methods: {
|
|
onEvent(event) {
|
|
if (!this.room || event.getRoomId() !== this.room.roomId) {
|
|
return; // Not for this room
|
|
}
|
|
if (event.getType() == "m.room.member") {
|
|
this.updateMemberCount();
|
|
}
|
|
},
|
|
|
|
onHeaderClicked() {
|
|
this.$emit("header-click", { event: this.event });
|
|
},
|
|
|
|
updateMemberCount() {
|
|
if (!this.room) {
|
|
this.memberCount = 0;
|
|
} else {
|
|
this.memberCount = this.room.getJoinedMemberCount();
|
|
}
|
|
},
|
|
|
|
leaveRoom() {
|
|
this.showLeaveConfirmation = true;
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
@import "@/assets/css/chat.scss";
|
|
|
|
.popup-open {
|
|
position: relative;
|
|
overflow: visible;
|
|
}
|
|
|
|
.popup-open::after {
|
|
position: absolute;
|
|
left: 50%;
|
|
content: "▲";
|
|
top: 30px;
|
|
margin-left: -10px;
|
|
font-size: 20px;
|
|
color: #ffffff;
|
|
z-index: 400;
|
|
pointer-events: none;
|
|
animation-duration: 0.3s;
|
|
animation-delay: 0.2s;
|
|
animation-fill-mode: both;
|
|
animation-name: fadein;
|
|
animation-iteration-count: 1;
|
|
}
|
|
|
|
@keyframes fadein {
|
|
from {
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
</style> |