Merge branch '584-roomDetails-add-dialog-to-members-list' into 'dev'

Room details: add dialog to member list

See merge request keanuapp/keanuapp-weblite!284
This commit is contained in:
N Pex 2024-03-11 14:14:05 +00:00
commit 459b797374
14 changed files with 347 additions and 202 deletions

View file

@ -922,8 +922,9 @@ body {
}
.room-info {
background-color: #e8e8e8;
background-color: #FDFBF9;
height: 100%;
.chat-header {
background-color: transparent;
border: none;
@ -978,6 +979,7 @@ body {
.v-card {
background-color: white;
border-radius: 20px;
box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.05) !important;
}
.member .user-name {
@ -994,6 +996,14 @@ body {
margin-left: 38px;
}
.member.v-list-item {
height: 56px;
&::before {
opacity: 0;
}
}
.show-all {
color: black;
font-size: 14 * $chat-text-size;
@ -1009,6 +1019,22 @@ body {
}
}
.member-action-dialog {
.user-name {
font-size: 18px;
font-weight: 700;
}
.v-list-item__title {
color:#074EE8;
font-size: 16px !important;
font-weight: 700 !important;
}
.v-list-item__subtitle {
color: rgba(0, 0, 0, 0.8);
font-size: 14px !important;
}
}
.with-right-label {
display: flex;
flex-wrap: nowrap;

View file

@ -0,0 +1,5 @@
<template>
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.455 1.15172C17.5599 0.837267 17.478 0.490627 17.2437 0.256285C17.0093 0.0219423 16.6627 -0.0598701 16.3483 0.0449199L0.598305 5.29492C0.247955 5.41168 0.00864239 5.7359 0.000224888 6.10512C-0.00811491 6.4744 0.216175 6.80909 0.560907 6.94171L7.78123 9.71878L10.5583 16.9391C10.6909 17.2838 11.0255 17.5081 11.3948 17.4997C11.764 17.4914 12.0883 17.2521 12.205 16.9016L17.455 1.15172Z" fill="#242424"/>
</svg>
</template>

View file

@ -0,0 +1,8 @@
<template>
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.89384 5.65641C6.55215 5.31471 5.9981 5.31471 5.65641 5.65641C5.31471 5.9981 5.31471 6.55215 5.65641 6.89384L10.6062 11.8436C10.9478 12.1853 11.5019 12.1853 11.8436 11.8436C12.1853 11.5019 12.1853 10.9478 11.8436 10.6062L6.89384 5.65641Z" fill="black"/>
<path d="M6.89384 5.65641C6.55215 5.31471 5.9981 5.31471 5.65641 5.65641C5.31471 5.9981 5.31471 6.55215 5.65641 6.89384L10.6062 11.8436C10.9478 12.1853 11.5019 12.1853 11.8436 11.8436C12.1853 11.5019 12.1853 10.9478 11.8436 10.6062L6.89384 5.65641Z" fill="black"/>
<path d="M5.65641 10.6062C5.31471 10.9479 5.31471 11.5019 5.65641 11.8436C5.9981 12.1853 6.55215 12.1853 6.89384 11.8436L11.8436 6.89386C12.1853 6.55216 12.1853 5.99811 11.8436 5.65642C11.5019 5.31472 10.9478 5.31472 10.6062 5.65642L5.65641 10.6062Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.75 0C3.91755 0 0 3.91755 0 8.75C0 13.5824 3.91755 17.5 8.75 17.5C13.5824 17.5 17.5 13.5824 17.5 8.75C17.5 3.91755 13.5824 0 8.75 0ZM1.75 8.75C1.75 4.88408 4.88408 1.75 8.75 1.75C12.6159 1.75 15.75 4.88408 15.75 8.75C15.75 12.6159 12.6159 15.75 8.75 15.75C4.88408 15.75 1.75 12.6159 1.75 8.75Z" fill="black"/>
</svg>
</template>

View file

@ -0,0 +1,7 @@
<template>
<svg width="21" height="18" viewBox="0 0 21 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.60303 0C8.39234 0 8.18549 0.0563288 8.00393 0.163173C7.82244 0.27002 7.67273 0.423416 7.5704 0.607586L5.39603 4.52146L1.661 2.8615C1.46003 2.77215 1.23813 2.74071 1.02028 2.77072C0.802418 2.80066 0.597196 2.89083 0.427813 3.0311C0.258487 3.17137 0.131608 3.35614 0.0615383 3.56457C-0.00852994 3.77306 -0.0189897 3.99694 0.0313228 4.21104L1.90995 12.2092L1.91022 12.2105C1.947 12.3656 2.01481 12.5117 2.10949 12.64C2.20431 12.7683 2.32401 12.876 2.46147 12.9568C2.59887 13.0376 2.75131 13.0898 2.90944 13.1101C3.06694 13.1304 3.22683 13.1188 3.37968 13.0759C6.7969 12.1327 10.4056 12.1323 13.823 13.0749C13.9758 13.1178 14.1357 13.1294 14.2931 13.1091C14.4512 13.0887 14.6035 13.0366 14.741 12.9558C14.8784 12.8751 14.9981 12.7674 15.0928 12.6392C15.1875 12.511 15.2554 12.3649 15.2922 12.2098L17.1744 4.21182C17.2247 3.99772 17.2143 3.77378 17.1443 3.56528C17.0743 3.35679 16.9475 3.17193 16.7781 3.0316C16.6087 2.89126 16.4035 2.80102 16.1856 2.77108C15.9677 2.74107 15.7457 2.77245 15.5447 2.86179L11.8102 4.52156L9.63586 0.607686C9.53353 0.423534 9.3839 0.270129 9.20234 0.163274C9.02077 0.0564274 8.81364 0 8.60303 0Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.0843 15.9802C17.2175 16.0455 17.3733 15.94 17.3478 15.8016L16.8547 13.1173L18.945 11.2169C19.0528 11.1189 18.9933 10.9481 18.8443 10.9279L15.9559 10.538L14.6628 8.09441C14.5962 7.96853 14.4038 7.96853 14.3371 8.09441L13.043 10.5366L10.1557 10.9279C10.0067 10.9481 9.94725 11.1189 10.055 11.2169L12.1459 13.1171L11.6522 15.8016C11.6268 15.94 11.7825 16.0455 11.9158 15.9802L14.5012 14.7124L17.0843 15.9802Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.4234 17.3267L14.5009 16.3831L12.5763 17.3269C11.9916 17.6137 11.3479 17.524 10.8831 17.209C10.4121 16.8899 10.0413 16.2684 10.177 15.5304L10.5198 13.6662L9.04619 12.3269C7.87843 11.2654 8.70182 9.61127 9.95426 9.44153C9.95423 9.44153 9.95429 9.44152 9.95426 9.44153L12.0783 9.15366L13.0113 7.39281C13.6416 6.20313 15.3588 6.20263 15.9887 7.39282L16.9209 9.15466L19.045 9.44143C20.2974 9.6111 21.1217 11.2651 19.954 12.3267C19.954 12.3267 19.9541 12.3267 19.954 12.3267L18.4807 13.6663L18.8231 15.5305C18.9587 16.2684 18.5879 16.8899 18.117 17.209C17.6522 17.524 17.0081 17.6135 16.4234 17.3267ZM16.8547 13.1173L18.945 11.2169C19.0528 11.1189 18.9933 10.9481 18.8443 10.9279L18.6597 10.903L15.9559 10.538L14.6628 8.09442C14.5962 7.96853 14.4038 7.96853 14.3371 8.09442L13.043 10.5366L10.1557 10.9279C10.0067 10.9481 9.94725 11.1189 10.055 11.2169L10.2145 11.3618L12.1459 13.1171L11.6522 15.8016C11.6268 15.94 11.7825 16.0455 11.9158 15.9802L12.1087 15.8856L14.5012 14.7124L16.8914 15.8855L17.0843 15.9802C17.2175 16.0455 17.3733 15.94 17.3478 15.8016L16.8547 13.1173Z" fill="white"/>
</svg>
</template>

View file

@ -0,0 +1,5 @@
<template>
<svg width="18" height="14" viewBox="0 0 18 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.60303 0C8.39234 0 8.18549 0.0563288 8.00393 0.163173C7.82244 0.27002 7.67273 0.423416 7.5704 0.607586L5.39603 4.52146L1.661 2.8615C1.46003 2.77215 1.23813 2.74071 1.02028 2.77072C0.802418 2.80066 0.597196 2.89083 0.427813 3.0311C0.258487 3.17137 0.131608 3.35614 0.0615383 3.56457C-0.00852994 3.77306 -0.0189897 3.99694 0.0313228 4.21104L1.90995 12.2092L1.91022 12.2105C1.947 12.3656 2.01481 12.5117 2.10949 12.64C2.20431 12.7683 2.32401 12.876 2.46147 12.9568C2.59887 13.0376 2.75131 13.0898 2.90944 13.1101C3.06694 13.1304 3.22683 13.1188 3.37968 13.0759C6.7969 12.1327 10.4056 12.1323 13.823 13.0749C13.9758 13.1178 14.1357 13.1294 14.2931 13.1091C14.4512 13.0887 14.6035 13.0366 14.741 12.9558C14.8784 12.8751 14.9981 12.7674 15.0928 12.6392C15.1875 12.511 15.2554 12.3649 15.2922 12.2098L17.1744 4.21182C17.2247 3.99772 17.2143 3.77378 17.1443 3.56528C17.0743 3.35679 16.9475 3.17193 16.7781 3.0316C16.6087 2.89126 16.4035 2.80102 16.1856 2.77108C15.9677 2.74107 15.7457 2.77245 15.5447 2.86179L11.8102 4.52156L9.63586 0.607686C9.53353 0.423534 9.3839 0.270129 9.20234 0.163274C9.02077 0.0564274 8.81364 0 8.60303 0Z" fill="black"/>
</svg>
</template>

View file

@ -0,0 +1,6 @@
<template>
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.25 7.875C4.76677 7.875 4.375 8.26677 4.375 8.75C4.375 9.23323 4.76677 9.625 5.25 9.625H12.25C12.7332 9.625 13.125 9.23323 13.125 8.75C13.125 8.26677 12.7332 7.875 12.25 7.875H5.25Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.75 0C3.91755 0 0 3.91755 0 8.75C0 13.5824 3.91755 17.5 8.75 17.5C13.5824 17.5 17.5 13.5824 17.5 8.75C17.5 3.91755 13.5824 0 8.75 0ZM1.75 8.75C1.75 4.88408 4.88408 1.75 8.75 1.75C12.6159 1.75 15.75 4.88408 15.75 8.75C15.75 12.6159 12.6159 15.75 8.75 15.75C4.88408 15.75 1.75 12.6159 1.75 8.75Z" fill="black"/>
</svg>
</template>

View file

@ -115,11 +115,9 @@
"ignore": "སྣང་མེད་ཐོངས།",
"join": "ཞུགས།",
"undo": "ཕྱིར་བསྡུ།",
"user_kick_and_ban": "སྤྱོད་མཁན་འདི་ཕྱིར་འབུད་དང་བཀག་སྡོམ་བྱོས།",
"user_make_admin": "འཛིན་སྐྱོང་པ་བཟོས།",
"user_make_moderator": "གཙོ་སྐྱོང་བ་བཟོས།",
"user_revoke_moderator": "གཙོ་སྐྱོང་བའི་དབང་ཚད་མེད་པར་བཟོས།",
"user_kick": "སྤྱོད་མཁན་འདི་སྒོར་ཕུད།"
"user_revoke_moderator": "གཙོ་སྐྱོང་བའི་དབང་ཚད་མེད་པར་བཟོས།"
},
"profile": {
"change_password": "གསང་ཚིག་རྗེས།",

View file

@ -23,7 +23,7 @@
},
"menu": {
"start_private_chat": "Direct Message with this user",
"actions": "actions",
"direct_chat": "Direct chat",
"reply": "Reply",
"edit": "Edit",
"delete": "Delete",
@ -41,9 +41,8 @@
"join": "Join",
"ignore": "Ignore",
"loading": "Loading {appName}",
"user_kick": "Kick this user",
"user_kick_and_ban": "Kick and ban this user",
"user_make_admin": "Make administrator",
"user_kick_and_ban": "Kick out",
"user_make_admin": "Make admin",
"user_make_moderator": "Make moderator",
"user_revoke_moderator": "Revoke moderator"
},
@ -164,7 +163,6 @@
"options": "Options"
},
"device_list": {
"title": "DEVICES",
"blocked": "Blocked",
"verified": "Verified",
"not_verified": "Not verified"

View file

@ -263,8 +263,6 @@
"loading": "Cargando {appName}",
"undo": "Deshacer",
"join": "Unirse",
"user_kick": "Expulsa a este usuario",
"user_kick_and_ban": "Expulsar y banear a este usuario",
"user_make_moderator": "Hacer moderador",
"user_make_admin": "Hacer administrador",
"user_revoke_moderator": "Revocar al moderador",

View file

@ -52,9 +52,7 @@
"join": "Entrar",
"ignore": "Ignore",
"loading": "Carregando {appName}",
"user_kick": "Expulsar este usuário",
"user_make_moderator": "Tornar moderador",
"user_kick_and_ban": "Expulsar e banir este usuário",
"user_make_admin": "Tornar administrador",
"user_revoke_moderator": "Revogar moderador",
"delete_now": "Excluir agora"

View file

@ -179,8 +179,6 @@
"ignore": "忽略",
"join": "加入",
"undo": "撤销",
"user_kick_and_ban": "移出并禁止该用户",
"user_kick": "移出该用户",
"user_make_admin": "设为管理员",
"user_make_moderator": "设为版主",
"user_revoke_moderator": "撤销版主身份"

View file

@ -0,0 +1,200 @@
<template>
<v-dialog
v-model="showDialog"
v-show="room"
class="ma-0 pa-0"
:width="$vuetify.breakpoint.smAndUp ? '688px' : '95%'"
>
<div class="dialog-content text-center member-action-dialog">
<div>
<v-avatar class="avatar" size="56" color="grey">
<img v-if="memberAvatar(activeMember)" :src="memberAvatar(activeMember)" />
<span v-else class="white--text headline">{{
activeMember.name.substring(0, 1).toUpperCase()
}}</span>
</v-avatar>
<div>
<span class="user-name">
{{
activeMember.userId == $matrix.currentUserId
? $t("room_info.user_you", {
user: activeMember.user ? activeMember.user.displayName : activeMember.name,
})
: $t("room_info.user", {
user: activeMember.user ? activeMember.user.displayName : activeMember.name,
})
}}
</span>
<span v-if="isAdmin(activeMember)" class="user-power">
{{ $t("room_info.user_admin") }}
</span>
<span v-else-if="isModerator(activeMember)" class="user-power">
{{ $t("room_info.user_moderator") }}
</span>
</div>
</div>
<DeviceList :member="activeMember" />
<div class="py-3" v-if="activeMember.userId != $matrix.currentUserId">
<v-btn text x-large block v-if="activeMember.userId != $matrix.currentUserId && !$matrix.isDirectRoomWith(room, activeMember.userId)" class="start-private-chat clickable d-block text-none justify-start" @click="startPrivateChat(activeMember.userId)">
<v-icon left>$vuetify.icons.direct_chat</v-icon> {{ $t("menu.direct_chat") }}
</v-btn>
<div v-if="canBanUser(activeMember)">
<v-btn text x-large block v-if="activeMember.userId != $matrix.currentUserId && canBanUser(activeMember)" class="start-private-chat clickable d-block text-none justify-start" @click="banUser(activeMember)">
<v-icon left>$vuetify.icons.kickout</v-icon> {{ $t("menu.user_kick_and_ban") }}
</v-btn>
</div>
<v-btn text x-large block v-if="activeMember.userId != $matrix.currentUserId && !isAdmin(activeMember) && canMakeAdmin(activeMember)" class="start-private-chat clickable d-block text-none justify-start" @click="makeAdmin(activeMember)">
<v-icon left>$vuetify.icons.make_admin</v-icon> {{ $t("menu.user_make_admin") }}
</v-btn>
<v-btn text x-large block v-if="activeMember.userId != $matrix.currentUserId && !isModerator(activeMember) && !isAdmin(activeMember) && canMakeModerator(activeMember)" class="start-private-chat clickable d-block text-none justify-start" @click="makeModerator(activeMember)">
<v-icon left>$vuetify.icons.make_moderator</v-icon> {{ $t("menu.user_make_moderator") }}
</v-btn>
<v-btn text x-large block v-if="activeMember.userId != $matrix.currentUserId && isModerator(activeMember) && canRevokeModerator(activeMember)" class="start-private-chat clickable d-block text-none justify-start" @click="revokeModerator(activeMember)">
<v-icon left>$vuetify.icons.revoke</v-icon> {{ $t("menu.user_revoke_moderator") }}
</v-btn>
</div>
</div>
</v-dialog>
</template>
<script>
import roomInfoMixin from "./roomInfoMixin";
import DeviceList from "../components/DeviceList";
import util from "../plugins/utils";
export default {
name: "MemberActionDialog",
mixins: [roomInfoMixin],
components: {
DeviceList
},
props: {
show: {
type: Boolean,
default: function () {
return false;
},
},
activeMember: {
type: Object
}
},
data() {
return {
showDialog: false
};
},
watch: {
show: {
handler(newVal, ignoredOldVal) {
this.showDialog = newVal;
}
},
showDialog() {
if (!this.showDialog) {
this.$emit("close");
}
},
},
methods: {
startPrivateChat(userId) {
this.$matrix
.getOrCreatePrivateChat(userId)
.then((room) => {
this.$nextTick(() => {
this.$navigation.push(
{
name: "Chat",
params: {
roomId: util.sanitizeRoomId(
room.getCanonicalAlias() || room.roomId
),
},
},
-1
);
});
})
.catch((err) => {
console.error(err);
})
.finally(() => {
this.showDialog = false;
});
},
canBanUser(member) {
if (this.room) {
const myUserId = this.$matrix.currentUserId;
const me = this.room.getMember(myUserId);
return me && me.powerLevelNorm > member.powerLevelNorm && this.room.currentState && this.room.currentState.hasSufficientPowerLevelFor("ban", me.powerLevel);
}
return false;
},
/**
* Return true if WE can make the member an admin
* @param member
*/
canMakeAdmin(ignoredmember) {
if (this.room) {
const myUserId = this.$matrix.currentUserId;
const me = this.room.getMember(myUserId);
return me && this.isAdmin(me);
}
return false;
},
/**
* Return true if WE can make the member a moderator
* @param member
*/
canMakeModerator(ignoredmember) {
if (this.room) {
const myUserId = this.$matrix.currentUserId;
const me = this.room.getMember(myUserId);
return me && this.isAdmin(me);
}
return false;
},
/**
* Return true if WE can "unmake" the member a moderator
* @param member
*/
canRevokeModerator(member) {
if (this.room) {
const myUserId = this.$matrix.currentUserId;
const me = this.room.getMember(myUserId);
return me && this.isAdmin(me) && me.powerLevel > member.powerLevel;
}
return false;
},
makeAdmin(member) {
if (this.room) {
this.$matrix.makeAdmin(this.room.roomId, member.userId)
this.showDialog = false;
}
},
makeModerator(member) {
if (this.room) {
this.$matrix.makeModerator(this.room.roomId, member.userId)
this.showDialog = false;
}
},
revokeModerator(member) {
if (this.room) {
this.$matrix.revokeModerator(this.room.roomId, member.userId)
this.showDialog = false;
}
},
banUser(member) {
if (this.room) {
this.$matrix.banUser(this.room.roomId, member.userId)
this.showDialog = false;
}
},
},
};
</script>
<style lang="scss">
@import "@/assets/css/chat.scss";
</style>

View file

@ -189,6 +189,14 @@
v-model="readOnlyRoom"
></v-switch>
</v-card-text>
<v-card-text class="with-right-label" style="align-items:center" v-if="canViewRetentionPolicy">
<div>
<div class="option-title">{{ $t('room_info.message_retention') }}</div>
<div class="option-text">{{ $t('room_info.message_retention_info') }}</div>
</div>
<div class="text-right">{{ messageRetention }}</div>
<v-btn v-on:click="showMessageRetentionDialog = true" v-if="canChangeRetentionPolicy" icon size="x-small"><v-icon color="black">edit</v-icon></v-btn>
</v-card-text>
</v-card>
<v-card class="members ma-3" flat>
@ -196,69 +204,48 @@
>{{ $t("room_info.members") }}<v-spacer></v-spacer>
<div>{{ members.length }}</div></v-card-title
>
<v-expansion-panels>
<v-expansion-panel v-for="(member, index) in members" :key="member.userId">
<v-expansion-panel-header
class="member"
v-show="showAllMembers || index < SHOW_MEMBER_LIMIT"
>
<div>
<v-avatar class="avatar" size="32" color="grey">
<img v-if="memberAvatar(member)" :src="memberAvatar(member)" />
<span v-else class="white--text headline">{{
member.name.substring(0, 1).toUpperCase()
}}</span>
</v-avatar>
<span class="user-name">
{{
member.userId == $matrix.currentUserId
? $t("room_info.user_you", {
user: member.user ? member.user.displayName : member.name,
})
: $t("room_info.user", {
user: member.user ? member.user.displayName : member.name,
})
}}
</span>
<span v-if="isAdmin(member)" class="user-power">
{{ $t("room_info.user_admin") }}
</span>
<span v-else-if="isModerator(member)" class="user-power">
{{ $t("room_info.user_moderator") }}
</span>
</div>
</v-expansion-panel-header>
<v-expansion-panel-content>
<v-tabs>
<v-tab v-if="member.userId != $matrix.currentUserId">{{ $t("menu.actions") }}</v-tab>
<v-tab>{{$t('device_list.title')}}</v-tab>
<!-- TODO: other rooms in common
<v-tab v-if="member.userId != $matrix.currentUserId">{{ $t("menu.common_room") }}</v-tab>
-->
<v-tab-item v-if="member.userId != $matrix.currentUserId">
<div class="py-3">
<v-btn text v-if="member.userId != $matrix.currentUserId && !$matrix.isDirectRoomWith(room, member.userId)" class="start-private-chat clickable d-block text-none" @click="startPrivateChat(member.userId)">{{ $t("menu.start_private_chat") }}</v-btn>
<div v-if="canKickUser(member) || canBanUser(member)">
<div v-if="member.userId != $matrix.currentUserId" class="mt-2">{{ String.fromCharCode(160) }}</div>
<v-btn text v-if="member.userId != $matrix.currentUserId && canKickUser(member)" class="start-private-chat clickable d-block text-none" @click="kickUser(member)">{{ $t("menu.user_kick") }}</v-btn>
<v-btn text v-if="member.userId != $matrix.currentUserId && canBanUser(member)" class="start-private-chat clickable d-block text-none" @click="banUser(member)">{{ $t("menu.user_kick_and_ban") }}</v-btn>
</div>
<div v-if="member.userId != $matrix.currentUserId" class="mt-2">{{ String.fromCharCode(160) }}</div>
<v-btn text v-if="member.userId != $matrix.currentUserId && !isAdmin(member) && canMakeAdmin(member)" class="start-private-chat clickable d-block text-none" @click="makeAdmin(member)">{{ $t("menu.user_make_admin") }}</v-btn>
<v-btn text v-if="member.userId != $matrix.currentUserId && !isModerator(member) && !isAdmin(member) && canMakeModerator(member)" class="start-private-chat clickable d-block text-none" @click="makeModerator(member)">{{ $t("menu.user_make_moderator") }}</v-btn>
<v-btn text v-if="member.userId != $matrix.currentUserId && isModerator(member) && canRevokeModerator(member)" class="start-private-chat clickable d-block text-none" @click="revokeModerator(member)">{{ $t("menu.user_revoke_moderator") }}</v-btn>
</div>
</v-tab-item>
<v-tab-item>
<DeviceList :member="member" />
</v-tab-item>
<!-- <v-tab-item v-if="member.userId != $matrix.currentUserId">
{{ "TODO" }}
</v-tab-item> -->
</v-tabs>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
<v-list>
<v-list-item-group>
<template v-for="(member, index) in members" >
<v-list-item
:key="member.userId"
class="member"
v-show="showAllMembers || index < SHOW_MEMBER_LIMIT"
@click="onListItemClick(member)"
>
<div>
<v-avatar class="avatar" size="32" color="grey">
<img v-if="memberAvatar(member)" :src="memberAvatar(member)" />
<span v-else class="white--text headline">{{
member.name.substring(0, 1).toUpperCase()
}}</span>
</v-avatar>
<span class="user-name">
{{
member.userId == $matrix.currentUserId
? $t("room_info.user_you", {
user: member.user ? member.user.displayName : member.name,
})
: $t("room_info.user", {
user: member.user ? member.user.displayName : member.name,
})
}}
</span>
<span v-if="isAdmin(member)" class="user-power">
{{ $t("room_info.user_admin") }}
</span>
<span v-else-if="isModerator(member)" class="user-power">
{{ $t("room_info.user_moderator") }}
</span>
</div>
</v-list-item>
<v-divider
v-if="(showAllMembers || index < SHOW_MEMBER_LIMIT) && index < members.length - 1"
:key="index"
></v-divider>
</template>
</v-list-item-group>
</v-list>
<div class="show-all p-2" @click="showAllMembers = !showAllMembers" v-if="members.length > SHOW_MEMBER_LIMIT">
{{ showAllMembers ? $t("room_info.hide_all") : $t("room_info.show_all") }}
</div>
@ -279,6 +266,13 @@
{{ $t("room_info.version_info", { version: buildVersion }) }}
</div>
<MemberActionDialog
:show="showMemberActionConfirmation"
:activeMember="activeMember || members[0]"
:room="room"
@close="showMemberActionConfirmation = false"
/>
<LeaveRoomDialog
:show="showLeaveConfirmation"
:room="room"
@ -306,11 +300,11 @@
import LeaveRoomDialog from "../components/LeaveRoomDialog";
import PurgeRoomDialog from "../components/PurgeRoomDialog";
import MessageRetentionDialog from "../components/MessageRetentionDialog";
import DeviceList from "../components/DeviceList";
import RoomExport from "../components/RoomExport";
import RoomAvatarPicker from "../components/RoomAvatarPicker";
import CopyLink from "../components/CopyLink.vue"
import RoomTypeSelector from "./RoomTypeSelector.vue";
import MemberActionDialog from "./MemberActionDialog.vue"
import roomInfoMixin from "./roomInfoMixin";
import roomTypeMixin from "./roomTypeMixin";
import util, { STATE_EVENT_ROOM_TYPE } from "../plugins/utils";
@ -322,7 +316,7 @@ export default {
LeaveRoomDialog,
PurgeRoomDialog,
MessageRetentionDialog,
DeviceList,
MemberActionDialog,
RoomExport,
RoomAvatarPicker,
RoomTypeSelector,
@ -333,6 +327,7 @@ export default {
members: [],
user: null,
showAllMembers: false,
showMemberActionConfirmation: false,
showLeaveConfirmation: false,
showPurgeConfirmation: false,
showMessageRetentionDialog: false,
@ -352,7 +347,8 @@ export default {
},
],
SHOW_MEMBER_LIMIT: 5,
exporting: false
exporting: false,
activeMember: null
};
},
mounted() {
@ -446,6 +442,10 @@ export default {
onMessageRetention(retention){
const retentionPeriodsFound = this.retentionPeriods.find(rp => rp.value===retention)
this.messageRetention = retentionPeriodsFound.text
},
onListItemClick(member) {
this.activeMember = member
this.showMemberActionConfirmation = true
},
onEvent(event) {
if (this.room && this.room.roomId == event.getRoomId()) {
@ -490,19 +490,6 @@ export default {
}
},
memberAvatar(member) {
if (member) {
return member.getAvatarUrl(
this.$matrix.matrixClient.getHomeserverUrl(),
40,
40,
"scale",
true
);
}
return null;
},
viewProfile() {
this.$navigation.push({ name: "Profile" }, 1);
},
@ -551,49 +538,11 @@ export default {
this.updatingJoinRule = false;
});
},
startPrivateChat(userId) {
this.$matrix
.getOrCreatePrivateChat(userId)
.then((room) => {
this.$nextTick(() => {
this.$navigation.push(
{
name: "Chat",
params: {
roomId: util.sanitizeRoomId(
room.getCanonicalAlias() || room.roomId
),
},
},
-1
);
});
})
.catch((err) => {
console.error(err);
});
},
exportRoom() {
if (this.room) {
this.exporting = true;
}
},
canKickUser(member) {
if (this.room) {
const myUserId = this.$matrix.currentUserId;
const me = this.room.getMember(myUserId);
return me && me.powerLevel > member.powerLevel && this.room.currentState && this.room.currentState.hasSufficientPowerLevelFor("kick", me.powerLevel);
}
return false;
},
canBanUser(member) {
if (this.room) {
const myUserId = this.$matrix.currentUserId;
const me = this.room.getMember(myUserId);
return me && me.powerLevelNorm > member.powerLevelNorm && this.room.currentState && this.room.currentState.hasSufficientPowerLevelFor("ban", me.powerLevel);
}
return false;
},
/**
* Return true if we can change power levels in the room, i.e. make read only room
*/
@ -610,76 +559,6 @@ export default {
}
return false;
},
// TODO - following power level comparisons assume that default power levels are used in the room!
isAdmin(member) {
return member.powerLevelNorm > 50;
},
isModerator(member) {
return member.powerLevelNorm > 0 && member.powerLevelNorm <= 50;
},
/**
* Return true if WE can make the member an admin
* @param member
*/
canMakeAdmin(ignoredmember) {
if (this.room) {
const myUserId = this.$matrix.currentUserId;
const me = this.room.getMember(myUserId);
return me && this.isAdmin(me);
}
return false;
},
/**
* Return true if WE can make the member a moderator
* @param member
*/
canMakeModerator(ignoredmember) {
if (this.room) {
const myUserId = this.$matrix.currentUserId;
const me = this.room.getMember(myUserId);
return me && this.isAdmin(me);
}
return false;
},
/**
* Return true if WE can "unmake" the member a moderator
* @param member
*/
canRevokeModerator(member) {
if (this.room) {
const myUserId = this.$matrix.currentUserId;
const me = this.room.getMember(myUserId);
return me && this.isAdmin(me) && me.powerLevel > member.powerLevel;
}
return false;
},
makeAdmin(member) {
if (this.room) {
this.$matrix.makeAdmin(this.room.roomId, member.userId)
}
},
makeModerator(member) {
if (this.room) {
this.$matrix.makeModerator(this.room.roomId, member.userId)
}
},
revokeModerator(member) {
if (this.room) {
this.$matrix.revokeModerator(this.room.roomId, member.userId)
}
},
kickUser(member) {
if (this.room) {
this.$matrix.kickUser(this.room.roomId, member.userId)
}
},
banUser(member) {
if (this.room) {
this.$matrix.banUser(this.room.roomId, member.userId)
}
},
/**
* Go back to previous page, or if none on the stack, go back to current room view.
*/

View file

@ -159,6 +159,25 @@ export default {
},
},
methods: {
memberAvatar(member) {
if (member) {
return member.getAvatarUrl(
this.$matrix.matrixClient.getHomeserverUrl(),
40,
40,
"scale",
true
);
}
return null;
},
// TODO - following power level comparisons assume that default power levels are used in the room!
isAdmin(member) {
return member.powerLevelNorm > 50;
},
isModerator(member) {
return member.powerLevelNorm > 0 && member.powerLevelNorm <= 50;
},
/**
* Get a string describing current room retention setting.
* Can be "None", "1 week", "1 hour" etc...