New room list and chat header design
This commit is contained in:
parent
7396fbc959
commit
baf0120eee
23 changed files with 651 additions and 287 deletions
|
|
@ -6,7 +6,7 @@
|
|||
v-on="$listeners"
|
||||
>
|
||||
<v-col cols="auto" class="me-2">
|
||||
<v-icon size="22">{{ icon }}</v-icon>
|
||||
<v-icon :size="iconSize">{{ icon }}</v-icon>
|
||||
</v-col>
|
||||
<v-col>{{ text }}</v-col>
|
||||
</v-row>
|
||||
|
|
@ -22,6 +22,12 @@ export default {
|
|||
return null;
|
||||
},
|
||||
},
|
||||
iconSize: {
|
||||
type: Number,
|
||||
default: function() {
|
||||
return 22;
|
||||
}
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: function () {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
color="black"
|
||||
@click.stop="onBackgroundClick"
|
||||
class="bottom-sheet-close"
|
||||
v-if="showCloseButton"
|
||||
>
|
||||
<v-icon color="white" >cancel</v-icon>
|
||||
</v-btn>
|
||||
|
|
@ -40,6 +41,10 @@ import Hammer from "hammerjs";
|
|||
|
||||
export default {
|
||||
props: {
|
||||
showCloseButton: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
openY: {
|
||||
type: Number,
|
||||
default: 0.1,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
<template>
|
||||
<div class="chat-root fill-height d-flex flex-column">
|
||||
<div class="chat-room-invitations clickable" v-if="invitationCount > 0" @click.stop="onInvitationsClick">
|
||||
{{ $tc("room.invitations", invitationCount) }}
|
||||
</div>
|
||||
<ChatHeader class="chat-header flex-grow-0 flex-shrink-0" v-on:header-click="onHeaderClick" />
|
||||
<ChatHeader class="chat-header flex-grow-0 flex-shrink-0" v-on:header-click="onHeaderClick" v-on:view-room-details="viewRoomDetails" />
|
||||
<AudioLayout ref="chatContainer" class="auto-audio-player-root" v-if="useVoiceMode" :room="room"
|
||||
:events="events" :autoplay="!showRecorder"
|
||||
:timelineSet="timelineSet"
|
||||
|
|
@ -513,9 +510,6 @@ export default {
|
|||
debugging() {
|
||||
return false; //(window.location.host || "").startsWith("localhost");
|
||||
},
|
||||
invitationCount() {
|
||||
return this.$matrix.invites.length;
|
||||
},
|
||||
canCreatePoll() {
|
||||
// We say that if you can redact events, you are allowed to create polls.
|
||||
const me = this.room && this.room.getMember(this.$matrix.currentUserId);
|
||||
|
|
@ -1436,16 +1430,17 @@ export default {
|
|||
},
|
||||
|
||||
onHeaderClick() {
|
||||
const invitations = this.$matrix.invites.length;
|
||||
const joinedRooms = this.$matrix.joinedRooms;
|
||||
if (joinedRooms && joinedRooms.length == 1 && joinedRooms[0].roomId == this.room.roomId) {
|
||||
if (invitations == 0 && joinedRooms && joinedRooms.length == 1 && joinedRooms[0].roomId == this.room.roomId) {
|
||||
// Only joined to this room, go directly to room details!
|
||||
this.$navigation.push({ name: "RoomInfo" });
|
||||
return;
|
||||
}
|
||||
this.$refs.roomInfoSheet.open();
|
||||
},
|
||||
onInvitationsClick() {
|
||||
this.$navigation.push({ name: "Home" }, -1);
|
||||
viewRoomDetails() {
|
||||
this.$navigation.push({ name: "RoomInfo" });
|
||||
},
|
||||
pollWasClosed(ignoredE) {
|
||||
let div = document.createElement("div");
|
||||
|
|
|
|||
|
|
@ -1,92 +1,73 @@
|
|||
<template>
|
||||
<v-container fluid v-if="room">
|
||||
<v-row class="chat-header-row flex-nowrap">
|
||||
<v-col
|
||||
cols="auto"
|
||||
class="chat-header-members text-start ma-0 pa-0"
|
||||
@click.stop="onHeaderClicked"
|
||||
>
|
||||
<v-avatar size="40" class="me-2">
|
||||
<v-img v-if="room.avatar || memberAvatar" :src="room.avatar || memberAvatar" />
|
||||
</v-avatar>
|
||||
</v-col>
|
||||
|
||||
<v-col
|
||||
class="chat-header-name ma-0 pa-0 flex-shrink-1 flex-nowrap"
|
||||
@click.stop="onHeaderClicked"
|
||||
>
|
||||
<div class="room-name-inline text-truncate" :title="room.name">
|
||||
{{ room.name }}<v-icon class="icon-dropdown" size="11">$vuetify.icons.ic_dropdown</v-icon><div class="notification-alert" v-if="notifications"></div>
|
||||
|
||||
<!--<v-icon>expand_more</v-icon>-->
|
||||
<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">
|
||||
<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>$vuetify.icons.ic_member-leave</v-icon>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col cols="auto" class="text-end ma-0 pa-0 ms-2">
|
||||
<v-avatar
|
||||
class="avatar-32 clickable"
|
||||
size="40"
|
||||
color="#e0e0e0"
|
||||
@click.stop="showProfileInfo = true"
|
||||
>
|
||||
<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"
|
||||
/>
|
||||
<LeaveRoomDialog :show="showLeaveConfirmation" :room="room" @close="showLeaveConfirmation = false" />
|
||||
|
||||
<!-- PROFILE INFO POPUP -->
|
||||
<ProfileInfoPopup
|
||||
:show="showProfileInfo"
|
||||
@close="showProfileInfo = false"
|
||||
/>
|
||||
<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"
|
||||
/>
|
||||
<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";
|
||||
|
||||
|
|
@ -96,14 +77,18 @@ export default {
|
|||
components: {
|
||||
LeaveRoomDialog,
|
||||
ProfileInfoPopup,
|
||||
PurgeRoomDialog
|
||||
MoreMenuPopup,
|
||||
PurgeRoomDialog,
|
||||
RoomExport
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
memberCount: null,
|
||||
showLeaveConfirmation: false,
|
||||
showProfileInfo: false,
|
||||
showPurgeConfirmation: false
|
||||
showPurgeConfirmation: false,
|
||||
showMoreMenu: false,
|
||||
downloadingChat: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -123,8 +108,8 @@ export default {
|
|||
let roomMember;
|
||||
if (this.room) {
|
||||
this.room.getMembers().forEach(member => {
|
||||
if(this.room.name === member.name) {
|
||||
roomMember = member;
|
||||
if (this.room.name === member.name) {
|
||||
roomMember = member;
|
||||
}
|
||||
});
|
||||
if (roomMember) {
|
||||
|
|
@ -140,8 +125,57 @@ export default {
|
|||
return null;
|
||||
},
|
||||
notifications() {
|
||||
return this.$matrix.joinedRooms.some(room => room.roomId !== this.$matrix.currentRoomId && room.getUnreadNotificationCount("total") > 0);
|
||||
}
|
||||
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: {
|
||||
|
|
@ -186,4 +220,36 @@ export default {
|
|||
|
||||
<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>
|
||||
|
|
@ -15,8 +15,6 @@
|
|||
<RoomList
|
||||
showInvites
|
||||
showCreate
|
||||
title=""
|
||||
:invitesTitle="$t('room.room_list_invites')"
|
||||
v-on:newroom="createRoom"
|
||||
/>
|
||||
</v-card-text>
|
||||
|
|
|
|||
169
src/components/MoreMenuPopup.vue
Normal file
169
src/components/MoreMenuPopup.vue
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
<template>
|
||||
<v-dialog v-model="showDialog" content-class="more-menu-popup" class="ma-0 pa-0">
|
||||
<div class="popup-wrapper">
|
||||
<v-card flat>
|
||||
<v-card-text>
|
||||
|
||||
<v-container class="mt-0 pa-0 action-row-container-no-dividers">
|
||||
<ActionRow v-for="item in menuItems" :key="item.name" :icon="item.icon" :iconSize="16" :text="item.text" @click="$emit('close');item.handler()" />
|
||||
|
||||
<v-row class="profile-row clickable" @click="viewProfile" no-gutters align-content="center">
|
||||
<v-col cols="auto" class="me-2">
|
||||
<v-avatar class="avatar-32" size="32" color="#e0e0e0" @click.stop="viewProfile">
|
||||
<img v-if="userAvatar" :src="userAvatar" />
|
||||
<span v-else class="white--text">{{ userAvatarLetter }}</span>
|
||||
</v-avatar>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<div class="profile-label">{{ $t('profile.title') }}</div>
|
||||
<div class="display-name">{{ displayName }}</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</v-dialog>
|
||||
</template>
|
||||
<script>
|
||||
import profileInfoMixin from "./profileInfoMixin";
|
||||
import ActionRow from "./ActionRow.vue";
|
||||
|
||||
export default {
|
||||
name: "MoreMenuPopup",
|
||||
mixins: [profileInfoMixin],
|
||||
components: { ActionRow },
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: function () {
|
||||
return false;
|
||||
},
|
||||
},
|
||||
menuItems: {
|
||||
type: Array,
|
||||
default: function() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
show: {
|
||||
immediate: true,
|
||||
handler(newVal, ignoredOldVal) {
|
||||
this.showDialog = newVal;
|
||||
},
|
||||
},
|
||||
showDialog() {
|
||||
if (!this.showDialog) {
|
||||
this.$emit("close");
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
viewProfile() {
|
||||
this.showDialog = false;
|
||||
this.$navigation.push({ name: "Profile" }, 1);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "@/assets/css/chat.scss";
|
||||
@import '~vuetify/src/styles/settings/_variables.scss';
|
||||
|
||||
.popup-wrapper {
|
||||
width: fit-content;
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.15);
|
||||
border-radius: 18px;
|
||||
pointer-events: initial;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.more-menu-popup {
|
||||
font-family: "Inter", sans-serif !important;
|
||||
font-size: 16px;
|
||||
line-height: 117%;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.4px;
|
||||
position: fixed;
|
||||
margin: 0px;
|
||||
top: 70px;
|
||||
right: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
box-shadow: none;
|
||||
pointer-events: none;
|
||||
.v-card__text {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.action-row {
|
||||
height: 40px;
|
||||
padding: 4px 20px !important;
|
||||
font-size: 16px;
|
||||
color: #000B16;
|
||||
}
|
||||
|
||||
.profile-row {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||
padding: 20px 20px !important;
|
||||
}
|
||||
|
||||
.action-row:after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.profile-label {
|
||||
letter-spacing: 0.4px;
|
||||
color: #000B16;
|
||||
}
|
||||
|
||||
.display-name {
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.4px;
|
||||
color: #000B16;
|
||||
}
|
||||
|
||||
[dir="rtl"] & {
|
||||
right: inherit;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
//border-radius: 40px;
|
||||
width: 95%;
|
||||
|
||||
@media #{map-get($display-breakpoints, 'sm-and-up')} {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
@media #{map-get($display-breakpoints, 'lg-and-up')} {
|
||||
overflow: unset;
|
||||
width: $main-desktop-width;
|
||||
;
|
||||
position: absolute;
|
||||
top: 70px;
|
||||
right: unset;
|
||||
width: $dialog-desktop-width;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: -18px;
|
||||
right: 40px;
|
||||
}
|
||||
|
||||
// .v-card {
|
||||
// border-radius: 20px;
|
||||
// }
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,51 +1,38 @@
|
|||
<template>
|
||||
<v-dialog
|
||||
v-model="showDialog"
|
||||
content-class="profile-info-popup"
|
||||
class="ma-0 pa-0"
|
||||
>
|
||||
<v-dialog v-model="showDialog" content-class="profile-info-popup" class="ma-0 pa-0">
|
||||
<v-card flat>
|
||||
<v-card-text>
|
||||
<div class="you-are">{{ $t("profile_info_popup.you_are") }}</div>
|
||||
<v-container fluid>
|
||||
<v-row>
|
||||
<v-col :class="['username',{'editable': editDisplayName }]" cols="pa-2" ref="username">
|
||||
<v-col :class="['username', { 'editable': editDisplayName }]" cols="pa-2" ref="username">
|
||||
<div v-if="$matrix.currentUser.is_guest">
|
||||
<i18n path="profile_info_popup.identity_temporary" tag="span">
|
||||
<template v-slot:displayName>
|
||||
<input
|
||||
v-model="displayName"
|
||||
@blur="
|
||||
updateDisplayName($event.target.value);
|
||||
editDisplayName = !editDisplayName;
|
||||
"
|
||||
@focus="editDisplayName = !editDisplayName"
|
||||
/>
|
||||
<input v-model="displayName"
|
||||
@keyup.enter="$event => $event.target.blur()"
|
||||
@blur="
|
||||
updateDisplayName($event.target.value);
|
||||
editDisplayName = !editDisplayName;
|
||||
" @focus="editDisplayName = !editDisplayName" />
|
||||
</template>
|
||||
</i18n>
|
||||
</div>
|
||||
<div v-else>
|
||||
<i18n path="profile_info_popup.identity" tag="span">
|
||||
<template v-slot:displayName>
|
||||
<input
|
||||
<input
|
||||
v-model="displayName"
|
||||
@blur="
|
||||
updateDisplayName($event.target.value);
|
||||
editDisplayName = !editDisplayName;
|
||||
"
|
||||
@focus="editDisplayName = !editDisplayName"
|
||||
/>
|
||||
@keyup.enter="$event => $event.target.blur()"
|
||||
@blur="updateDisplayName($event.target.value);editDisplayName = !editDisplayName;"
|
||||
@focus="editDisplayName = !editDisplayName"
|
||||
/>
|
||||
</template>
|
||||
</i18n>
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col cols="auto" class="pa-2">
|
||||
<v-avatar
|
||||
class="avatar-32"
|
||||
size="32"
|
||||
color="#e0e0e0"
|
||||
@click.stop="viewProfile"
|
||||
>
|
||||
<v-avatar class="avatar-32" size="32" color="#e0e0e0" @click.stop="viewProfile">
|
||||
<img v-if="userAvatar" :src="userAvatar" />
|
||||
<span v-else class="white--text">{{ userAvatarLetter }}</span>
|
||||
</v-avatar>
|
||||
|
|
@ -53,24 +40,6 @@
|
|||
</v-row>
|
||||
</v-container>
|
||||
|
||||
<v-container class="mt-4 pa-0">
|
||||
<ActionRow
|
||||
@click="viewProfile"
|
||||
:icon="'account_circle'"
|
||||
:text="$t('profile_info_popup.edit_profile')"
|
||||
/>
|
||||
<ActionRow
|
||||
@click.stop="showLogoutPopup=true"
|
||||
:icon="'logout'"
|
||||
:text="$t('profile_info_popup.logout')"
|
||||
/>
|
||||
<LogoutRoomDialog
|
||||
:showLogoutPopup="showLogoutPopup"
|
||||
@onOutsideLogoutPopupClicked="showLogoutPopup=false"
|
||||
@onCancelLogoutClicked="showLogoutPopup=false"
|
||||
/>
|
||||
</v-container>
|
||||
|
||||
<div class="more-container">
|
||||
<div class="want_more">
|
||||
🙌 {{ $t("profile_info_popup.want_more") }}
|
||||
|
|
@ -78,7 +47,7 @@
|
|||
<i18n path="profile_info_popup.powered_by" tag="div">
|
||||
<template v-slot:product>{{ product }}</template>
|
||||
<template v-slot:productLink>
|
||||
<a :href="'//'+productLink">{{ productLink }}</a>
|
||||
<a :href="'//' + productLink">{{ productLink }}</a>
|
||||
</template>
|
||||
</i18n>
|
||||
<div class="text-end">
|
||||
|
|
@ -93,16 +62,10 @@
|
|||
</template>
|
||||
<script>
|
||||
import profileInfoMixin from "./profileInfoMixin";
|
||||
import ActionRow from "./ActionRow.vue";
|
||||
import LogoutRoomDialog from './LogoutRoomDialog.vue';
|
||||
|
||||
export default {
|
||||
name: "ProfileInfoPopup",
|
||||
mixins: [profileInfoMixin],
|
||||
components: {
|
||||
ActionRow,
|
||||
LogoutRoomDialog
|
||||
},
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
|
|
@ -115,7 +78,6 @@ export default {
|
|||
return {
|
||||
showDialog: false,
|
||||
editDisplayName: false,
|
||||
showLogoutPopup: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -163,28 +125,20 @@ export default {
|
|||
margin: 0px;
|
||||
top: 70px;
|
||||
right: 10px;
|
||||
|
||||
[dir="rtl"] & {
|
||||
right: inherit;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
border-radius: 40px;
|
||||
width: 95%;
|
||||
|
||||
&::before {
|
||||
content: "▲";
|
||||
position: fixed;
|
||||
top: 57px;
|
||||
right: 22px;
|
||||
[dir="rtl"] & {
|
||||
left: 22px;
|
||||
right: inherit;
|
||||
}
|
||||
color: white;
|
||||
}
|
||||
.you-are {
|
||||
padding-top: 20px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.username {
|
||||
border-radius: 4px;
|
||||
background-color: #f5f5f5;
|
||||
|
|
@ -202,19 +156,45 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.more-container {
|
||||
border-radius: 10px;
|
||||
background-color: #f5f5f5;
|
||||
padding: 20px;
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 14 * $chat-text-size;
|
||||
line-height: 117%;
|
||||
letter-spacing: 0.4px;
|
||||
color: #000B16;
|
||||
margin-top: 18px;
|
||||
a {
|
||||
color: #000B16 !important;
|
||||
}
|
||||
.want_more {
|
||||
font-family: "Poppins", sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 13 * $chat-text-size;
|
||||
color: #0e252d;
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
|
||||
.new_room {
|
||||
margin-top: 16px;
|
||||
height: 27px;
|
||||
border-radius: 13.5px;
|
||||
border: 1px solid #000000;
|
||||
}
|
||||
.new_room .v-btn__content {
|
||||
font-family: "Poppins", sans-serif !important;
|
||||
font-weight: 700 !important;
|
||||
font-size: 13 * $chat-text-size !important;
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-size: 10 * $chat-text-size !important;
|
||||
line-height: 133%;
|
||||
letter-spacing: 0.34px;
|
||||
text-transform: uppercase;
|
||||
color: #181719;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +204,8 @@ export default {
|
|||
|
||||
@media #{map-get($display-breakpoints, 'lg-and-up')} {
|
||||
overflow: unset;
|
||||
width: $main-desktop-width;;
|
||||
width: $main-desktop-width;
|
||||
;
|
||||
position: absolute;
|
||||
top: 70px;
|
||||
right: unset;
|
||||
|
|
|
|||
|
|
@ -4,12 +4,6 @@
|
|||
<!-- Header-->
|
||||
<v-container fluid class="chat-header flex-grow-0 flex-shrink-0">
|
||||
<v-row class="chat-header-row flex-nowrap">
|
||||
<v-col cols="auto" class="chat-header-members text-start ma-0 pa-0" @click.stop="onHeaderClicked">
|
||||
<v-avatar size="40" class="me-2">
|
||||
<v-img v-if="room.avatar" :src="room.avatar" />
|
||||
</v-avatar>
|
||||
</v-col>
|
||||
|
||||
<v-col class="chat-header-name ma-0 pa-0 flex-shrink-1 flex-nowrap">
|
||||
<div class="room-name-inline text-truncate" :title="room.name">
|
||||
{{ room.name }}
|
||||
|
|
|
|||
|
|
@ -3,52 +3,16 @@
|
|||
class="room-info-bottom-sheet"
|
||||
:halfY="0.12"
|
||||
ref="sheet"
|
||||
:showCloseButton="false"
|
||||
>
|
||||
<div class="room-info-sheet" ref="roomInfoSheetContent">
|
||||
<div class="text-center current-room">
|
||||
<room-avatar-picker />
|
||||
<div class="h4">{{$t('room_info_sheet.this_room')}}</div>
|
||||
<div
|
||||
class="h2"
|
||||
v-if="!isRoomNameEditMode"
|
||||
@click="onRoomNameClicked()"
|
||||
>
|
||||
{{ roomName }}
|
||||
</div>
|
||||
<v-text-field
|
||||
v-model="editedRoomName"
|
||||
ref="editedRoomName"
|
||||
:rules="[(v) => !!v || $t('room.room_name_required')]"
|
||||
:error="roomNameErrorMessage != null"
|
||||
:error-messages="roomNameErrorMessage"
|
||||
required
|
||||
color="black"
|
||||
counter="50"
|
||||
background-color="white"
|
||||
autofocus
|
||||
v-if="isRoomNameEditMode"
|
||||
maxlength="50"
|
||||
@blur="updateRoomName()"
|
||||
@keyup.enter="updateRoomName()"
|
||||
solo
|
||||
></v-text-field>
|
||||
<v-btn
|
||||
id="btn-room-details"
|
||||
height="20px"
|
||||
color="black"
|
||||
class="filled-button"
|
||||
@click.stop="showDetails"
|
||||
>{{$t('room_info_sheet.view_details')}}</v-btn
|
||||
>
|
||||
</div>
|
||||
<room-list :title="'Other rooms'" v-on:close="close" v-on:newroom="createRoom" :showCreate="true" />
|
||||
<room-list v-on:close="close" v-on:newroom="createRoom" :showCreate="true" />
|
||||
</div>
|
||||
</BottomSheet>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BottomSheet from "./BottomSheet";
|
||||
import RoomAvatarPicker from "./RoomAvatarPicker";
|
||||
import RoomList from "./RoomList";
|
||||
import roomInfoMixin from "./roomInfoMixin";
|
||||
|
||||
|
|
@ -58,7 +22,6 @@ export default {
|
|||
components: {
|
||||
BottomSheet,
|
||||
RoomList,
|
||||
RoomAvatarPicker,
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
|
|
|
|||
|
|
@ -1,70 +1,59 @@
|
|||
<template>
|
||||
<v-list dense class="room-list">
|
||||
<div class="h4">{{ title }}</div>
|
||||
<v-list-item-group v-model="currentRoomId" color="primary">
|
||||
<v-list-item v-if="showCreate" @click.stop="$emit('newroom')">
|
||||
|
||||
<v-list-item v-if="showCreate" @click.stop="$emit('newroom')" class="room-list-room">
|
||||
<v-list-item-avatar class="round" size="42" color="#d9d9d9">
|
||||
<v-icon size="11">$vuetify.icons.ic_new_room</v-icon>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="new-room">{{
|
||||
<v-list-item-title class="room-list-new-room">{{
|
||||
$t("menu.new_room")
|
||||
}}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<!-- invites -->
|
||||
<v-list-item
|
||||
:disabled="roomsProcessing[room.roomId]"
|
||||
v-for="room in invitedRooms"
|
||||
:key="room.roomId"
|
||||
:value="room.roomId"
|
||||
>
|
||||
<v-list-item-avatar size="40" color="#e0e0e0">
|
||||
<v-img v-if="room.avatar" :src="room.avatar" />
|
||||
<v-list-item :disabled="roomsProcessing[room.roomId]" v-for="room in invitedRooms" :key="room.roomId"
|
||||
:value="room.roomId" class="room-list-room">
|
||||
<v-list-item-avatar size="42" color="#d9d9d9">
|
||||
<v-img v-if="roomAvatar(room)" :src="roomAvatar(room)" />
|
||||
<span v-else class="white--text headline">{{
|
||||
room.name.substring(0, 1).toUpperCase()
|
||||
}}</span>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{ room.name }}</v-list-item-title>
|
||||
<v-list-item-title class="room-list-name">{{ room.name }}</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ room.topic }}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-btn
|
||||
id="btn-accept"
|
||||
class="filled-button"
|
||||
depressed
|
||||
color="black"
|
||||
@click.stop="acceptInvitation(room)"
|
||||
>{{ $t("menu.join") }}</v-btn
|
||||
>
|
||||
<v-btn
|
||||
id="btn-reject"
|
||||
class="filled-button"
|
||||
color="black"
|
||||
@click.stop="rejectInvitation(room)"
|
||||
text
|
||||
>{{ $t("menu.ignore") }}</v-btn
|
||||
>
|
||||
<v-btn id="btn-accept" class="filled-button" depressed color="black" @click.stop="acceptInvitation(room)">{{
|
||||
$t("menu.join") }}</v-btn>
|
||||
<v-btn id="btn-reject" class="filled-button" color="black" @click.stop="rejectInvitation(room)" text>{{
|
||||
$t("menu.ignore") }}</v-btn>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item
|
||||
v-for="room in joinedRooms"
|
||||
:key="room.roomId"
|
||||
:value="room.roomId"
|
||||
>
|
||||
<v-list-item-avatar size="40" color="#e0e0e0">
|
||||
<v-img v-if="room.avatar" :src="room.avatar" />
|
||||
<v-list-item v-for="room in joinedRooms" :key="room.roomId" :value="room.roomId" class="room-list-room"
|
||||
#default="{ active }">
|
||||
<v-list-item-avatar size="42" color="#d9d9d9">
|
||||
<v-img v-if="roomAvatar(room)" :src="roomAvatar(room)" />
|
||||
<span v-else class="white--text headline">{{
|
||||
room.name.substring(0, 1).toUpperCase()
|
||||
}}</span>
|
||||
</v-list-item-avatar>
|
||||
<div class="room-list-notification-count" v-if="notificationCount(room) > 0">
|
||||
{{ notificationCount(room) }}
|
||||
</div>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{ room.name }}</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ room.topic }}</v-list-item-subtitle>
|
||||
<v-list-item-title class="room-list-name">{{ room.name }}
|
||||
<v-icon class="ml-2 mb-1" size="10" v-if="isPublic(room)">$vuetify.icons.ic_public</v-icon>
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle class="room-list-new-messages" v-if="notificationCount(room) > 0">
|
||||
{{ $t("room.room_list_new_messages", { count: notificationCount(room) }) }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-icon size="16" v-if="active">$vuetify.icons.ic_circle_filled</v-icon>
|
||||
<v-icon size="16" v-else>$vuetify.icons.ic_circle</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
|
|
@ -108,6 +97,26 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
roomAvatar(room) {
|
||||
if (this.isDirect(room)) {
|
||||
if (room.avatar) {
|
||||
return room.avatar;
|
||||
}
|
||||
const membersNotMe = room.getMembers().filter(m => m.userId != this.$matrix.currentUserId);
|
||||
if (membersNotMe && membersNotMe.length == 1) {
|
||||
return membersNotMe[0].getAvatarUrl(
|
||||
this.$matrix.matrixClient.getHomeserverUrl(),
|
||||
42,
|
||||
42,
|
||||
"scale",
|
||||
true
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return room.avatar;
|
||||
}
|
||||
},
|
||||
|
||||
sortItemsOnName(items) {
|
||||
if (items == null) {
|
||||
return [];
|
||||
|
|
@ -166,6 +175,14 @@ export default {
|
|||
Vue.delete(this.roomsProcessing, room.roomId);
|
||||
});
|
||||
},
|
||||
|
||||
isPublic(room) {
|
||||
return this.$matrix.getRoomJoinRule(room) === "public"
|
||||
},
|
||||
|
||||
isDirect(room) {
|
||||
return this.$matrix.isDirectRoom(room);
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue