diff --git a/src/components/CallView/CallView.vue b/src/components/CallView/CallView.vue index 3cac3e1018a..2ae089ebd8d 100644 --- a/src/components/CallView/CallView.vue +++ b/src/components/CallView/CallView.vue @@ -16,7 +16,9 @@
-
+
- + + + + +
+ + +
import debounce from 'debounce' +import { provide, ref } from 'vue' import { showMessage } from '@nextcloud/dialogs' import { subscribe, unsubscribe } from '@nextcloud/event-bus' @@ -131,9 +145,11 @@ import LocalVideo from './shared/LocalVideo.vue' import PresenterOverlay from './shared/PresenterOverlay.vue' import ReactionToaster from './shared/ReactionToaster.vue' import Screen from './shared/Screen.vue' +import VideoBottomBar from './shared/VideoBottomBar.vue' import VideoVue from './shared/VideoVue.vue' import ViewerOverlayCallView from './shared/ViewerOverlayCallView.vue' +import { placeholderImage, placeholderModel, placeholderName, placeholderSharedData } from './Grid/gridPlaceholders.ts' import { SIMULCAST } from '../../constants.js' import { fetchPeers } from '../../services/callsService.js' import { getTalkConfig } from '../../services/CapabilitiesManager.ts' @@ -147,13 +163,14 @@ export default { components: { EmptyCallView, - ViewerOverlayCallView, Grid, LocalVideo, PresenterOverlay, ReactionToaster, Screen, + VideoBottomBar, VideoVue, + ViewerOverlayCallView, }, props: { @@ -174,6 +191,12 @@ export default { }, setup() { + // For debug and screenshot purposes. Set to true to enable + const devMode = ref(false) + provide('CallView:devModeEnabled', devMode) + const screenshotMode = ref(false) + provide('CallView:screenshotModeEnabled', screenshotMode) + const settingsStore = useSettingsStore() const startWithoutMediaEnabled = settingsStore.startWithoutMedia if (startWithoutMediaEnabled) { @@ -184,6 +207,7 @@ export default { localMediaModel, localCallParticipantModel, callParticipantCollection, + devMode, } }, @@ -327,8 +351,19 @@ export default { }, shouldShowPresenterOverlay() { - return this.shownRemoteScreenCallParticipantModel?.attributes.videoAvailable || this.isModelWithVideo(this.shownRemoteScreenCallParticipantModel) + return (this.showLocalScreen && this.hasLocalVideo) + || ((this.showRemoteScreen || this.showSelectedScreen) + && (this.shownRemoteScreenCallParticipantModel?.attributes.videoAvailable || this.isModelWithVideo(this.shownRemoteScreenCallParticipantModel))) + + }, + + presenterModel() { + // Prioritize local screen over remote screen, if both are available (as in DOM order) + return this.showLocalScreen ? this.localCallParticipantModel : this.shownRemoteScreenCallParticipantModel + }, + presenterSharedData() { + return this.showLocalScreen ? this.localSharedData : this.sharedDatas[this.shownRemoteScreenPeerId] }, presenterVideoBlockerEnabled() { @@ -336,7 +371,7 @@ export default { }, showEmptyCallView() { - return !this.callParticipantModels.length && !this.screenSharingActive + return !this.callParticipantModels.length && !this.screenSharingActive && !this.devMode }, supportedReactions() { @@ -447,6 +482,11 @@ export default { methods: { t, + // Placeholder data for devMode and screenshotMode + placeholderImage, + placeholderName, + placeholderModel, + placeholderSharedData, /** * Updates data properties that depend on the CallParticipantModels. * @@ -707,13 +747,16 @@ export default { }, isModelWithVideo(callParticipantModel) { + if (!callParticipantModel) { + return false + } return callParticipantModel.attributes.videoAvailable && this.sharedDatas[callParticipantModel.attributes.peerId].remoteVideoBlocker.isVideoEnabled() && (typeof callParticipantModel.attributes.stream === 'object') }, toggleShowPresenterOverlay() { - if (!this.presenterVideoBlockerEnabled) { + if (!this.showLocalScreen && !this.presenterVideoBlockerEnabled) { this.sharedDatas[this.shownRemoteScreenPeerId].remoteVideoBlocker.setVideoEnabled(true) } else { this.showPresenterOverlay = !this.showPresenterOverlay @@ -759,6 +802,22 @@ export default { // doesn't affect screen shares, as it's a different MediaStream position: static; } + + .dev-mode-video--promoted { + position: absolute; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + } + + .dev-mode-video--promoted img { + position: absolute; + height: 100%; + aspect-ratio: 4 / 3; + object-fit: cover; + border-radius: var(--border-radius-element, calc(var(--default-clickable-area) / 2)); + } } .local-video { diff --git a/src/components/CallView/Grid/Grid.vue b/src/components/CallView/Grid/Grid.vue index 1e8058ea8a3..ac641edaea5 100644 --- a/src/components/CallView/Grid/Grid.vue +++ b/src/components/CallView/Grid/Grid.vue @@ -59,11 +59,11 @@ -
- -
-

GRID INFO

-

Videos (total): {{ videosCount }}

-

Displayed videos n: {{ displayedVideos.length }}

-

Max per page: ~{{ videosCap }}

-

Grid width: {{ gridWidth }}

-

Grid height: {{ gridHeight }}

-

Min video width: {{ minWidth }}

-

Min video Height: {{ minHeight }}

-

Grid aspect ratio: {{ gridAspectRatio }}

-

Number of pages: {{ numberOfPages }}

-

Current page: {{ currentPage }}

-
+
@@ -128,6 +142,7 @@