Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/spreed.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormarco <marcoambrosini@pm.me>2021-09-09 10:32:04 +0300
committermarco <marcoambrosini@pm.me>2021-10-05 19:16:33 +0300
commit26d0214166498fa6569105d0a1b24b5bece9b390 (patch)
treecac6765117b1d3043d493795a2b0a380a059c195 /src
parent7d4e3c6877d697e3d0136fdfedd0462b709070bd (diff)
Create DeviceChecker component
Signed-off-by: marco <marcoambrosini@pm.me>
Diffstat (limited to 'src')
-rw-r--r--src/components/DeviceChecker/DeviceChecker.vue330
-rw-r--r--src/components/TopBar/CallButton.vue26
2 files changed, 355 insertions, 1 deletions
diff --git a/src/components/DeviceChecker/DeviceChecker.vue b/src/components/DeviceChecker/DeviceChecker.vue
new file mode 100644
index 000000000..be6ee6de6
--- /dev/null
+++ b/src/components/DeviceChecker/DeviceChecker.vue
@@ -0,0 +1,330 @@
+<!--
+ - @copyright Copyright (c) 2021 Marco Ambrosini <marcoambrosini@pm.me>
+ -
+ - @author Marco Ambrosini <marcoambrosini@pm.me>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<template>
+ <Modal v-if="modal"
+ class="talk-modal"
+ size="large"
+ @close="closeModal">
+ <div class="device-checker">
+ <h2 class="device-checker__title">
+ {{ t('spreed', 'Camera and microphone check') }}
+ </h2>
+ <!-- Preview -->
+ <div class="device-checker__preview">
+ <!-- eslint-disable-next-line -->
+ <video v-show="showVideo"
+ ref="video"
+ class="preview__video"
+ disable-picture-in-picture="true"
+ tabindex="-1" />
+ <div v-show="!showVideo"
+ class="preview__novideo">
+ <VideoBackground
+ :display-name="displayName"
+ :user="userId" />
+ <Avatar v-if="userId"
+ :size="128"
+ :disable-menu="true"
+ :disable-tooltip="true"
+ :show-user-status="false"
+ :user="userId"
+ :display-name="displayName" />
+ <div v-if="!userId"
+ class="avatar guest">
+ {{ firstLetterOfGuestName }}
+ </div>
+ </div>
+ </div>
+
+ <!--
+ Toggle audio and video on and off before starting or joining
+ a call.
+ -->
+ <div class="device-checker__call-preferences">
+ <!-- Audio toggle -->
+ <button
+ class="device-toggle"
+ :disabled="!audioPreviewAvailable"
+ @click="toggleAudio">
+ <span class="device-toggle__icon">
+ <Microphone
+ v-if="audioOn"
+ title=""
+ decorative
+ :size="20" />
+ <MicrophoneOff
+ v-if="!audioOn"
+ title=""
+ decorative
+ :size="20" />
+ </span>
+ </button>
+
+ <!-- Video toggle -->
+ <button
+ class="device-toggle"
+ :disabled="!videoPreviewAvailable"
+ @click="toggleVideo">
+ <span class="device-toggle__icon">
+ <Video
+ v-if="videoOn"
+ title=""
+ decorative
+ :size="20" />
+ <VideoOff
+ v-if="!videoOn"
+ title=""
+ decorative
+ :size="20" />
+ </span>
+ </button>
+ </div>
+
+ <!-- Device selection -->
+ <div class="device-checker__device-selection">
+ <button v-if="!showDeviceSelection"
+ class="select-devices"
+ @click="showDeviceSelection = true">
+ <span class="select-devices__icon">
+ <Cog
+ title=""
+ decorative
+ :size="20" />
+ </span>
+ <span> {{ t('spreed', 'Choose devices') }}</span>
+ </button>
+ <template v-if="showDeviceSelection">
+ <MediaDevicesSelector kind="audioinput"
+ :devices="devices"
+ :device-id="audioInputId"
+ @update:deviceId="audioInputId = $event" />
+ <MediaDevicesSelector kind="videoinput"
+ :devices="devices"
+ :device-id="videoInputId"
+ @update:deviceId="videoInputId = $event" />
+ </template>
+ </div>
+
+ <!-- Join call -->
+ <CallButton
+ class="call-button"
+ :force-join-call="true" />
+ </div>
+ </Modal>
+</template>
+
+<script>
+import Modal from '@nextcloud/vue/dist/Components/Modal'
+import { devices } from '../../mixins/devices'
+import MediaDevicesSelector from '../MediaDevicesSelector.vue'
+import VideoBackground from '../CallView/shared/VideoBackground.vue'
+import Avatar from '@nextcloud/vue/dist/Components/Avatar'
+import Cog from 'vue-material-design-icons/Cog.vue'
+import Microphone from 'vue-material-design-icons/Microphone'
+import MicrophoneOff from 'vue-material-design-icons/MicrophoneOff'
+import Video from 'vue-material-design-icons/Video'
+import VideoOff from 'vue-material-design-icons/VideoOff'
+import { localMediaModel } from '../../utils/webrtc/index'
+import CallButton from '../TopBar/CallButton.vue'
+import { subscribe, unsubscribe } from '@nextcloud/event-bus'
+
+export default {
+ name: 'DeviceChecker',
+
+ components: {
+ Modal,
+ MediaDevicesSelector,
+ VideoBackground,
+ Avatar,
+ Cog,
+ Microphone,
+ MicrophoneOff,
+ Video,
+ VideoOff,
+ CallButton,
+ },
+
+ mixins: [devices],
+
+ data() {
+ return {
+ model: localMediaModel,
+ modal: false,
+ showDeviceSelection: false,
+ audioOn: undefined,
+ videoOn: undefined,
+ }
+ },
+
+ computed: {
+ displayName() {
+ return this.$store.getters.getDisplayName()
+ },
+
+ userId() {
+ return this.$store.getters.getUserId()
+ },
+
+ token() {
+ return this.$store.getters.getToken()
+ },
+
+ showVideo() {
+ return this.videoPreviewAvailable && this.videoOn
+ },
+ },
+
+ mounted() {
+ subscribe('talk:device-checker:show', this.showModal)
+ subscribe('talk:device-checker:hide', this.closeModal)
+ this.audioOn = !localStorage.getItem('audioDisabled_' + this.token)
+ this.videoOn = !localStorage.getItem('videoDisabled_' + this.token)
+ },
+
+ beforeDestroy() {
+ unsubscribe('talk:device-checker:show', this.showModal)
+ unsubscribe('talk:device-checker:hide', this.closeModal)
+ },
+
+ methods: {
+ showModal() {
+ this.modal = true
+ },
+
+ closeModal() {
+ this.modal = false
+ this.showDeviceSelection = false
+ },
+
+ toggleAudio() {
+ if (!this.audioOn) {
+ localStorage.removeItem('audioDisabled_' + this.token)
+ this.audioOn = true
+ } else {
+ localStorage.setItem('audioDisabled_' + this.token, 'true')
+ this.audioOn = false
+ }
+ },
+
+ toggleVideo() {
+ if (!this.videoOn) {
+ localStorage.removeItem('videoDisabled_' + this.token)
+ this.videoOn = true
+ } else {
+ localStorage.setItem('videoDisabled_' + this.token, 'true')
+ this.videoOn = false
+ }
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../assets/variables.scss';
+@import '../../assets/avatar.scss';
+@include avatar-mixin(64px);
+@include avatar-mixin(128px);
+
+.device-checker {
+ width: 350px;
+ padding: 20px;
+ background-color: var(--color-main-background);
+ &__title {
+ text-align: center;
+ }
+ &__preview {
+ position: relative;
+ margin: 0 auto 12px auto;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+ border-radius: 12px;
+ height: 263px;
+ background-color: var(--color-loading-dark);
+ }
+
+ &__device-selection {
+ width: 100%;
+ }
+
+ &__call-preferences {
+ height: $clickable-area;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+}
+
+.preview {
+ &__video {
+ max-width: 100%;
+ object-fit: contain;
+ max-height: 100%;
+ }
+
+ &__novideo {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+ width: 100%;
+ }
+}
+
+.select-devices {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: none;
+ border: none;
+ padding: 0;
+ margin: auto;
+ &__icon {
+ margin-right: 4px;
+ }
+ opacity: 0.8;
+ &:hover,
+ &:focus {
+ opacity: 1;
+ }
+}
+
+.device-toggle {
+ background: none;
+ border: none;
+}
+
+.call-button {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-width: 150px;
+ margin: auto;
+}
+
+.checkbox {
+ display: flex;
+ justify-content: center;
+ margin: 14px;
+}
+</style>
diff --git a/src/components/TopBar/CallButton.vue b/src/components/TopBar/CallButton.vue
index d0ffee55e..35e1ac75d 100644
--- a/src/components/TopBar/CallButton.vue
+++ b/src/components/TopBar/CallButton.vue
@@ -31,7 +31,7 @@
:disabled="startCallButtonDisabled || loading || blockCalls"
class="top-bar__button"
:class="startCallButtonClasses"
- @click="joinCall">
+ @click="handleClick">
<span
class="icon"
:class="startCallIcon" />
@@ -55,6 +55,7 @@ import isInCall from '../../mixins/isInCall'
import participant from '../../mixins/participant'
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip'
import { emit } from '@nextcloud/event-bus'
+import BrowserStorage from '../../services/BrowserStorage'
export default {
name: 'CallButton',
@@ -69,6 +70,17 @@ export default {
participant,
],
+ props: {
+ /**
+ * Skips the device checker dialog and joins or starts the call
+ * upon clicking the button
+ */
+ forceJoinCall: {
+ type: Boolean,
+ default: false,
+ },
+ },
+
data() {
return {
loading: false,
@@ -211,6 +223,18 @@ export default {
})
this.loading = false
},
+
+ handleClick() {
+ const shouldShowDeviceCheckerScreen = (BrowserStorage.getItem('showDeviceChecker' + this.token) === null
+ || BrowserStorage.getItem('showDeviceChecker' + this.token) === 'true') && !this.forceJoinCall
+ console.debug(shouldShowDeviceCheckerScreen)
+ if (shouldShowDeviceCheckerScreen) {
+ emit('talk:device-checker:show')
+ } else {
+ emit('talk:device-checker:hide')
+ this.joinCall()
+ }
+ },
},
}
</script>