diff options
author | Dorra <dorra.jaoued7@gmail.com> | 2024-03-14 11:02:31 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-14 11:02:31 +0100 |
commit | d206d551618df7d30997068d5c59f03776928839 (patch) | |
tree | e5e49a7a5581ca890fda2ab1ce7247c9098656ac | |
parent | 891ede4d46e9f5b139c5928b3734415f47bb8ba1 (diff) | |
parent | 9e15ea3897f2b2750d371b46b76b43b165132029 (diff) |
Merge pull request #11701 from nextcloud/feat/noid/draggable-presenter-overlay
feat(PresenterOverlay): make the overlay draggable.
-rw-r--r-- | package-lock.json | 19 | ||||
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | src/components/CallView/CallView.vue | 35 | ||||
-rw-r--r-- | src/components/CallView/shared/VideoVue.vue | 42 |
4 files changed, 75 insertions, 22 deletions
diff --git a/package-lock.json b/package-lock.json index 9b9d74bf4..764700362 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,7 @@ "util": "^0.12.5", "vue": "^2.7.16", "vue-cropperjs": "^4.2.0", + "vue-draggable-resizable": "^1.7.5", "vue-frag": "^1.4.3", "vue-material-design-icons": "^5.3.0", "vue-observe-visibility": "^1.0.0", @@ -19806,6 +19807,18 @@ "cropperjs": "^1.5.6" } }, + "node_modules/vue-draggable-resizable": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/vue-draggable-resizable/-/vue-draggable-resizable-1.7.5.tgz", + "integrity": "sha512-+L0tqbZYuskfSpKlk1EfsB9OOuy7NNFPaIry4nZ7g+Sr4JaL5xQ6pEaE5IavkV9M/riX/1pr6uAPc9pLxcqfLg==", + "engines": { + "node": ">= 4.0.0", + "npm": ">= 3.0.0" + }, + "peerDependencies": { + "vue": "^2.3.0" + } + }, "node_modules/vue-eslint-parser": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz", @@ -35491,6 +35504,12 @@ "cropperjs": "^1.5.6" } }, + "vue-draggable-resizable": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/vue-draggable-resizable/-/vue-draggable-resizable-1.7.5.tgz", + "integrity": "sha512-+L0tqbZYuskfSpKlk1EfsB9OOuy7NNFPaIry4nZ7g+Sr4JaL5xQ6pEaE5IavkV9M/riX/1pr6uAPc9pLxcqfLg==", + "requires": {} + }, "vue-eslint-parser": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz", diff --git a/package.json b/package.json index 83d606920..a745e3a21 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "util": "^0.12.5", "vue": "^2.7.16", "vue-cropperjs": "^4.2.0", + "vue-draggable-resizable": "^1.7.5", "vue-frag": "^1.4.3", "vue-material-design-icons": "^5.3.0", "vue-observe-visibility": "^1.0.0", diff --git a/src/components/CallView/CallView.vue b/src/components/CallView/CallView.vue index 3641e747c..e278f0544 100644 --- a/src/components/CallView/CallView.vue +++ b/src/components/CallView/CallView.vue @@ -75,8 +75,14 @@ :shared-data="sharedDatas[shownRemoteScreenPeerId]" is-big /> <!-- presenter overlay --> - <TransitionWrapper v-if="shouldShowPresenterOverlay" - name="slide-down"> + <VueDraggableResizable v-if="shouldShowPresenterOverlay" + :key="presenterOverlaySize" + parent + :resizable="false" + :h="presenterOverlaySize" + :w="presenterOverlaySize" + :x="10" + :y="10"> <VideoVue class="presenter-overlay__video" :token="token" :model="shownRemoteScreenCallParticipantModel" @@ -84,8 +90,8 @@ is-presenter-overlay un-selectable hide-bottom-bar - @click-video="toggleShowPresenterOverlay" /> - </TransitionWrapper> + @click-presenter="toggleShowPresenterOverlay" /> + </VueDraggableResizable> <!-- presenter button when presenter overlay is collapsed --> <NcButton v-else-if="isPresenterCollapsed" :aria-label="t('spreed', 'Show presenter')" @@ -153,6 +159,7 @@ <script> import debounce from 'debounce' +import VueDraggableResizable from 'vue-draggable-resizable' import AccountBox from 'vue-material-design-icons/AccountBoxOutline.vue' @@ -169,7 +176,6 @@ import ReactionToaster from './shared/ReactionToaster.vue' import Screen from './shared/Screen.vue' import VideoVue from './shared/VideoVue.vue' import ViewerOverlayCallView from './shared/ViewerOverlayCallView.vue' -import TransitionWrapper from '../TransitionWrapper.vue' import { SIMULCAST } from '../../constants.js' import BrowserStorage from '../../services/BrowserStorage.js' @@ -187,13 +193,13 @@ export default { AccountBox, EmptyCallView, ViewerOverlayCallView, + VueDraggableResizable, Grid, LocalVideo, NcButton, ReactionToaster, Screen, VideoVue, - TransitionWrapper, }, props: { @@ -236,6 +242,7 @@ export default { isBackgroundBlurred: true, showPresenterOverlay: true, debounceFetchPeers: () => {}, + presenterOverlaySize: 128, } }, computed: { @@ -372,7 +379,6 @@ export default { presenterVideoBlockerEnabled() { return this.sharedDatas[this.shownRemoteScreenPeerId]?.remoteVideoBlocker?.isVideoEnabled() }, - }, watch: { 'localCallParticipantModel.attributes.peerId'(newValue, previousValue) { @@ -470,6 +476,8 @@ export default { subscribe('switch-screen-to-id', this._switchScreenToId) subscribe('set-background-blurred', this.setBackgroundBlurred) + + window.addEventListener('resize', this.updateSize) }, beforeDestroy() { this.debounceFetchPeers.clear?.() @@ -479,6 +487,8 @@ export default { unsubscribe('switch-screen-to-id', this._switchScreenToId) unsubscribe('set-background-blurred', this.setBackgroundBlurred) + + window.removeEventListener('resize', this.updateSize) }, methods: { /** @@ -758,6 +768,10 @@ export default { this.showPresenterOverlay = !this.showPresenterOverlay } }, + + updateSize() { + this.presenterOverlaySize = Math.min(Math.max(window.innerWidth * 0.1, 100), 242) + }, }, } </script> @@ -783,14 +797,15 @@ export default { } .presenter-overlay__video { - position: absolute; - bottom: 48px; - right: 8px; + position: relative; --max-size: 242px; + --min-size: 100px; width: 10vw; height: 10vw; max-width: var(--max-size); max-height: var(--max-size); + min-width: var(--min-size); + min-height: var(--min-size); z-index: 10; } diff --git a/src/components/CallView/shared/VideoVue.vue b/src/components/CallView/shared/VideoVue.vue index 918debb1b..075481de9 100644 --- a/src/components/CallView/shared/VideoVue.vue +++ b/src/components/CallView/shared/VideoVue.vue @@ -37,6 +37,12 @@ :class="fitVideo ? 'video--fit' : 'video--fill'" class="video" @playing="updateVideoAspectRatio" /> + <AccountOff v-if="isPresenterOverlay && mouseover" + class="presenter-icon__hide" + :aria-label="t('spreed', 'Hide presenter video')" + :title="t('spreed', 'Hide presenter video')" + :size="32" + @click="$emit('click-presenter')" /> </div> </TransitionWrapper> <TransitionWrapper name="fade"> @@ -78,7 +84,6 @@ :has-shadow="hasVideo" :participant-name="participantName" /> </slot> - <AccountOff v-if="isPresenterOverlay && mouseover" class="presenter-icon__hide" :size="30" /> </div> </template> @@ -191,7 +196,7 @@ export default { }, }, - emits: ['click-video'], + emits: ['click-video', 'click-presenter'], setup() { const guestNameStore = useGuestNameStore() @@ -304,12 +309,14 @@ export default { 'video-container-grid': this.isGrid, 'video-container-big': this.isBig, 'one-to-one': this.isOneToOne, + 'presenter-overlay': this.isPresenterOverlay } }, videoWrapperClass() { return { 'icon-loading': this.isLoading, + 'presenter-overlay': this.isPresenterOverlay } }, @@ -660,6 +667,10 @@ export default { border-radius: calc(var(--default-clickable-area) / 2); } +.videoWrapper.presenter-overlay > video { + border-radius: 50%; +} + .videoWrapper.icon-loading:after { height: 60px; width: 60px; @@ -703,6 +714,10 @@ export default { border-radius: calc(var(--default-clickable-area) / 2); } +.video-container.presenter-overlay::after { + border-radius: 50%; +} + .video-container.speaking::after { content: ''; box-shadow: inset 0 0 0 2px white; @@ -715,18 +730,21 @@ export default { } .presenter-icon__hide { - position: absolute; - height: 100%; - width: 100%; - top: 0; - left: 0; + position: relative; color: white; -} - -.video-container.presenter::after { - content: ''; + left: 50%; + transform: translate(-50%, -52px); + opacity: 0.7; background-color: rgba(0, 0, 0, 0.5); - cursor: pointer; + border-radius: 50%; + padding: 6px; + width: 44px; + + &:hover { + cursor: pointer; + opacity: 0.9; + } + } </style> |