Experimental "read only" room support
This commit is contained in:
parent
f34721c930
commit
76ca3f8e70
8 changed files with 169 additions and 17 deletions
|
|
@ -40,5 +40,6 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"experimental_voice_mode": true
|
||||
"experimental_voice_mode": true,
|
||||
"experimental_read_only_room": true
|
||||
}
|
||||
|
|
@ -295,6 +295,19 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.input-area-read-only {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(white, 0.8);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 40;
|
||||
}
|
||||
|
||||
@media #{map-get($display-breakpoints, 'sm-and-down')} {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
|
|
@ -1466,6 +1479,21 @@ body {
|
|||
.mic-button {
|
||||
z-index: 0;
|
||||
}
|
||||
.mic-button.dimmed {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.toast-read-only {
|
||||
position: fixed;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
background-color: rgba(black, 0.7);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 40;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.audio-layout.voice-recorder {
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@
|
|||
"reply_poll": "Poll",
|
||||
"time_ago": "Today | Yesterday | {count} days ago",
|
||||
"outgoing_message_deleted_text": "You deleted this message.",
|
||||
"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"
|
||||
},
|
||||
"room": {
|
||||
"invitations": "You have no invitations | You have 1 invitation | You have {count} invitations",
|
||||
|
|
@ -249,7 +250,9 @@
|
|||
"experimental_features": "Experimental Features",
|
||||
"voice_mode": "Voice mode",
|
||||
"voice_mode_info": "Switches the chat interface to a 'listen and record' mode",
|
||||
"download_chat": "Download chat"
|
||||
"download_chat": "Download chat",
|
||||
"read_only_room": "Read only room",
|
||||
"read_only_room_info": "Only admins and moderators are allowed to send to the room"
|
||||
},
|
||||
"room_info_sheet": {
|
||||
"this_room": "This room",
|
||||
|
|
|
|||
|
|
@ -56,12 +56,14 @@
|
|||
</div>
|
||||
|
||||
<div class="load-later">
|
||||
<v-btn v-if="canRecordAudio" class="mic-button" ref="mic_button" fab small elevation="0" v-blur
|
||||
@click.stop="$emit('start-recording')">
|
||||
<v-btn :class="{'mic-button': true, 'dimmed': !canRecordAudio}" ref="mic_button" fab small elevation="0" v-blur
|
||||
@click.stop="micButtonClicked()">
|
||||
<v-icon color="white">mic</v-icon>
|
||||
</v-btn>
|
||||
<v-icon class="clickable" @click="loadNext" color="white" size="28">expand_more</v-icon>
|
||||
</div>
|
||||
|
||||
<div v-if="showReadOnlyToast" class="toast-read-only">{{ $t("message.not_allowed_to_send") }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -111,6 +113,7 @@ export default {
|
|||
playing: false,
|
||||
analyzer: null,
|
||||
analyzerDataArray: null,
|
||||
showReadOnlyToast: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -162,12 +165,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
canRecordAudio() {
|
||||
if (this.room) {
|
||||
const myUserId = this.$matrix.currentUserId;
|
||||
const me = this.room.getMember(myUserId);
|
||||
return me && me.powerLevelNorm > 0 && util.browserCanRecordAudio();
|
||||
}
|
||||
return false;
|
||||
return !this.$matrix.currentRoomIsReadOnlyForUser && util.browserCanRecordAudio();
|
||||
},
|
||||
currentTime() {
|
||||
return util.formatDuration(this.playTime);
|
||||
|
|
@ -448,6 +446,17 @@ export default {
|
|||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
micButtonClicked() {
|
||||
if (this.$matrix.currentRoomIsReadOnlyForUser) {
|
||||
this.showReadOnlyToast = true;
|
||||
setTimeout(() => {
|
||||
this.showReadOnlyToast = false;
|
||||
}, 3000);
|
||||
} else {
|
||||
this.$emit('start-recording');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
:timelineSet="timelineSet"
|
||||
:readMarker="readMarker"
|
||||
:recordingMembers="typingMembers"
|
||||
v-on:start-recording="showRecorder = true"
|
||||
v-on:start-recording="setShowRecorder()"
|
||||
v-on:loadnext="handleScrolledToBottom(false)"
|
||||
v-on:loadprevious="handleScrolledToTop()"
|
||||
v-on:mark-read="sendRR"
|
||||
|
|
@ -177,6 +177,7 @@
|
|||
<VoiceRecorder :micButtonRef="$refs.mic_button" :ptt="showRecorderPTT" :show="showRecorder"
|
||||
v-on:close="showRecorder = false" v-on:file="onVoiceRecording" />
|
||||
</div>
|
||||
<div v-if="!useVoiceMode && room && $matrix.currentRoomIsReadOnlyForUser" class="input-area-read-only">{{ $t("message.not_allowed_to_send") }}</div>
|
||||
</v-container>
|
||||
|
||||
<input ref="attachment" type="file" name="attachment" @change="handlePickedAttachment($event)"
|
||||
|
|
@ -1450,7 +1451,15 @@ export default {
|
|||
setTimeout(() => {
|
||||
this.chatContainer.parentElement.removeChild(div);
|
||||
}, 3000);
|
||||
},
|
||||
setShowRecorder() {
|
||||
if (this.canRecordAudio) {
|
||||
this.showRecorder = true;
|
||||
} else {
|
||||
this.showNoRecordingAvailableDialog = true;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -43,13 +43,13 @@
|
|||
v-on:keyup.enter="$refs.create.focus()" :disabled="step > steps.INITIAL" solo></v-text-field>
|
||||
|
||||
<!-- Our only option right now is voice mode, so if not enabled, hide the 'options' drop down as well -->
|
||||
<template v-if="$config.experimental_voice_mode">
|
||||
<template v-if="$config.experimental_voice_mode || $config.experimental_read_only_room">
|
||||
<div @click.stop="showOptions = !showOptions" v-show="roomName.length > 0" class="options clickable">
|
||||
<div>{{ $t("new_room.options") }}</div>
|
||||
<v-icon v-if="!showOptions">expand_more</v-icon>
|
||||
<v-icon v-else>expand_less</v-icon>
|
||||
</div>
|
||||
<v-card v-show="showOptions" class="account ma-3" flat>
|
||||
<v-card v-if="$config.experimental_voice_mode" v-show="showOptions" class="account ma-3" flat>
|
||||
<v-card-text class="with-right-label">
|
||||
<div>
|
||||
<div class="option-title">{{ $t('room_info.voice_mode') }}</div>
|
||||
|
|
@ -58,6 +58,15 @@
|
|||
<v-switch v-model="useVoiceMode"></v-switch>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<v-card v-if="$config.experimental_read_only_room" v-show="showOptions" class="account ma-3" flat>
|
||||
<v-card-text class="with-right-label">
|
||||
<div>
|
||||
<div class="option-title">{{ $t('room_info.read_only_room') }}</div>
|
||||
<div class="option-text">{{ $t('room_info.read_only_room_info') }}</div>
|
||||
</div>
|
||||
<v-switch v-model="readOnlyRoom"></v-switch>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<div class="error--text" v-if="roomCreationErrorMsg"> {{ roomCreationErrorMsg }}</div>
|
||||
|
|
@ -259,6 +268,7 @@ export default {
|
|||
roomCreationErrorMsg: "",
|
||||
showOptions: false,
|
||||
useVoiceMode: false,
|
||||
readOnlyRoom: false,
|
||||
};
|
||||
},
|
||||
|
||||
|
|
@ -401,7 +411,7 @@ export default {
|
|||
content: {
|
||||
history_visibility: "joined"
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
|
|
@ -516,6 +526,20 @@ export default {
|
|||
}
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
// Set power level event. Need to do that here, because we might not have the userId when the options object is created.
|
||||
const powerLevels = {};
|
||||
powerLevels[this.$matrix.currentUserId] = 100;
|
||||
createRoomOptions.initial_state.push(
|
||||
{
|
||||
type: "m.room.power_levels",
|
||||
state_key: "",
|
||||
content: {
|
||||
users: powerLevels,
|
||||
events_default: this.readOnlyRoom ? 50 : 0
|
||||
}
|
||||
});
|
||||
|
||||
return this.$matrix.matrixClient
|
||||
.createRoom(createRoomOptions)
|
||||
.then(({ room_id, room_alias }) => {
|
||||
|
|
|
|||
|
|
@ -165,9 +165,9 @@
|
|||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-card class="account ma-3" flat v-if="$config.experimental_voice_mode">
|
||||
<v-card class="account ma-3" flat v-if="$config.experimental_voice_mode || canChangeReadOnly()">
|
||||
<v-card-title class="h2 with-right-label"><div>{{ $t("room_info.experimental_features") }}</div><div></div></v-card-title>
|
||||
<v-card-text class="with-right-label">
|
||||
<v-card-text class="with-right-label" v-if="$config.experimental_voice_mode">
|
||||
<div>
|
||||
<div class="option-title">{{ $t('room_info.voice_mode') }}</div>
|
||||
<div class="option-text">{{ $t('room_info.voice_mode_info') }}</div>
|
||||
|
|
@ -176,6 +176,15 @@
|
|||
v-model="useVoiceMode"
|
||||
></v-switch>
|
||||
</v-card-text>
|
||||
<v-card-text class="with-right-label" v-if="canChangeReadOnly()">
|
||||
<div>
|
||||
<div class="option-title">{{ $t('room_info.read_only_room') }}</div>
|
||||
<div class="option-text">{{ $t('room_info.read_only_room_info') }}</div>
|
||||
</div>
|
||||
<v-switch
|
||||
v-model="readOnlyRoom"
|
||||
></v-switch>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-card class="members ma-3" flat>
|
||||
|
|
@ -389,6 +398,14 @@ export default {
|
|||
this.$matrix.matrixClient.setRoomTag(this.room.roomId, "ui_options", options);
|
||||
}
|
||||
},
|
||||
},
|
||||
readOnlyRoom: {
|
||||
get: function () {
|
||||
return this.$matrix.isReadOnlyRoom(this.room.roomId);
|
||||
},
|
||||
set: function (readOnly) {
|
||||
this.$matrix.setReadOnlyRoom(this.room.roomId, readOnly);
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -591,6 +608,16 @@ export default {
|
|||
}
|
||||
return false;
|
||||
},
|
||||
/**
|
||||
* Return true if we can change power levels in the room, i.e. make read only room
|
||||
*/
|
||||
canChangeReadOnly() {
|
||||
if (!this.$config.experimental_read_only_room) { return false; }
|
||||
if (this.room) {
|
||||
return this.room.currentState && this.room.currentState.maySendStateEvent("m.room.power_levels", this.$matrix.currentUserId);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// TODO - following power level comparisons assume that default power levels are used in the room!
|
||||
isAdmin(member) {
|
||||
return member.powerLevelNorm > 50;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ export default {
|
|||
userDisplayName: null,
|
||||
userAvatar: null,
|
||||
currentRoom: null,
|
||||
currentRoomIsReadOnlyForUser: false,
|
||||
currentRoomBeingPurged: false,
|
||||
notificationCount: 0,
|
||||
};
|
||||
|
|
@ -93,6 +94,7 @@ export default {
|
|||
immediate: true,
|
||||
handler(roomId) {
|
||||
this.currentRoom = this.getRoom(roomId);
|
||||
this.currentRoomIsReadOnlyForUser = this.isReadOnlyRoomForUser(roomId, this.currentUserId);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -355,6 +357,14 @@ export default {
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "m.room.power_levels":
|
||||
{
|
||||
if (this.currentRoom && event.getRoomId() == this.currentRoom.roomId) {
|
||||
this.currentRoomIsReadOnlyForUser = this.isReadOnlyRoomForUser(event.getRoomId(), this.currentUserId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
this.updateNotificationCount();
|
||||
},
|
||||
|
|
@ -550,6 +560,47 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
isReadOnlyRoom(roomId) {
|
||||
if (this.matrixClient && roomId) {
|
||||
const room = this.getRoom(roomId);
|
||||
if (room && room.currentState) {
|
||||
const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", "");
|
||||
if (powerLevelEvent) {
|
||||
return powerLevelEvent.getContent().events_default > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
isReadOnlyRoomForUser(roomId, userId) {
|
||||
if (this.matrixClient && roomId && userId) {
|
||||
const room = this.getRoom(roomId);
|
||||
if (room && room.currentState) {
|
||||
return !room.currentState.maySendMessage(userId)
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
setReadOnlyRoom(roomId, readOnly) {
|
||||
if (this.matrixClient && roomId) {
|
||||
const room = this.getRoom(roomId);
|
||||
if (room && room.currentState) {
|
||||
const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", "");
|
||||
if (powerLevelEvent) {
|
||||
let content = powerLevelEvent.getContent();
|
||||
content.events_default = readOnly ? 50 : 0;
|
||||
this.matrixClient.sendStateEvent(
|
||||
room.roomId,
|
||||
"m.room.power_levels",
|
||||
content
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Purge the room with the given id! This means:
|
||||
* - Make room invite only
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue