From f07219c3daf9529c5f0d0b7daa313320ef5d39eb Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Sun, 15 Sep 2024 16:38:00 +0200 Subject: [PATCH 1/2] fix: migrate fullscreen store and related functions/listeners to composable Signed-off-by: Maksim Sukharev --- src/components/TopBar/TopBar.vue | 15 ------ src/components/TopBar/TopBarMenu.vue | 42 +++------------ src/composables/useDocumentFullscreen.ts | 67 ++++++++++++++++++++++++ src/composables/useViewer.js | 7 +-- src/env.d.ts | 11 ++++ src/store/storeConfig.js | 2 - src/store/uiModeStore.js | 5 +- src/store/windowVisibilityStore.js | 41 --------------- 8 files changed, 94 insertions(+), 96 deletions(-) create mode 100644 src/composables/useDocumentFullscreen.ts delete mode 100644 src/store/windowVisibilityStore.js diff --git a/src/components/TopBar/TopBar.vue b/src/components/TopBar/TopBar.vue index 680d7d0a12e..63c109ce7f4 100644 --- a/src/components/TopBar/TopBar.vue +++ b/src/components/TopBar/TopBar.vue @@ -328,17 +328,9 @@ export default { mounted() { document.body.classList.add('has-topbar') - document.addEventListener('fullscreenchange', this.fullScreenChanged, false) - document.addEventListener('mozfullscreenchange', this.fullScreenChanged, false) - document.addEventListener('MSFullscreenChange', this.fullScreenChanged, false) - document.addEventListener('webkitfullscreenchange', this.fullScreenChanged, false) }, beforeDestroy() { - document.removeEventListener('fullscreenchange', this.fullScreenChanged, false) - document.removeEventListener('mozfullscreenchange', this.fullScreenChanged, false) - document.removeEventListener('MSFullscreenChange', this.fullScreenChanged, false) - document.removeEventListener('webkitfullscreenchange', this.fullScreenChanged, false) document.body.classList.remove('has-topbar') }, @@ -349,13 +341,6 @@ export default { this.sidebarStore.showSidebar({ activeTab }) }, - fullScreenChanged() { - this.$store.dispatch( - 'setIsFullscreen', - document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement - ) - }, - openConversationSettings() { emit('show-conversation-settings', { token: this.token }) }, diff --git a/src/components/TopBar/TopBarMenu.vue b/src/components/TopBar/TopBarMenu.vue index 20d542a5340..b330099d595 100644 --- a/src/components/TopBar/TopBarMenu.vue +++ b/src/components/TopBar/TopBarMenu.vue @@ -174,6 +174,11 @@ import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js' import TransitionExpand from '../MediaSettings/TransitionExpand.vue' +import { + useDocumentFullscreen, + enableFullscreen, + disableFullscreen, +} from '../../composables/useDocumentFullscreen.ts' import { useIsInCall } from '../../composables/useIsInCall.js' import { CALL, CONVERSATION, PARTICIPANT } from '../../constants.js' import { getTalkConfig } from '../../services/CapabilitiesManager.ts' @@ -251,6 +256,7 @@ export default { setup() { return { isInCall: useIsInCall(), + isFullscreen: useDocumentFullscreen(), breakoutRoomsStore: useBreakoutRoomsStore(), } }, @@ -269,10 +275,6 @@ export default { return this.$store.getters.conversation(this.token) || this.$store.getters.dummyConversation }, - isFullscreen() { - return this.$store.getters.isFullscreen() - }, - labelFullscreen() { return this.isFullscreen ? t('spreed', 'Exit full screen (F)') @@ -435,38 +437,10 @@ export default { } if (this.isFullscreen) { - this.disableFullscreen() - this.$store.dispatch('setIsFullscreen', false) + disableFullscreen() } else { - this.enableFullscreen() emit('toggle-navigation', { open: false }) - this.$store.dispatch('setIsFullscreen', true) - } - }, - - enableFullscreen() { - const fullscreenElem = document.getElementById('content-vue') - - if (fullscreenElem.requestFullscreen) { - fullscreenElem.requestFullscreen() - } else if (fullscreenElem.webkitRequestFullscreen) { - fullscreenElem.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT) - } else if (fullscreenElem.mozRequestFullScreen) { - fullscreenElem.mozRequestFullScreen() - } else if (fullscreenElem.msRequestFullscreen) { - fullscreenElem.msRequestFullscreen() - } - }, - - disableFullscreen() { - if (document.exitFullscreen) { - document.exitFullscreen() - } else if (document.webkitExitFullscreen) { - document.webkitExitFullscreen() - } else if (document.mozCancelFullScreen) { - document.mozCancelFullScreen() - } else if (document.msExitFullscreen) { - document.msExitFullscreen() + enableFullscreen() } }, diff --git a/src/composables/useDocumentFullscreen.ts b/src/composables/useDocumentFullscreen.ts new file mode 100644 index 00000000000..9cafd85410f --- /dev/null +++ b/src/composables/useDocumentFullscreen.ts @@ -0,0 +1,67 @@ +/* + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { createSharedComposable } from '@vueuse/core' +import { readonly, ref, onBeforeMount, onBeforeUnmount } from 'vue' +import type { Ref, DeepReadonly } from 'vue' + +interface WebkitElement extends Element { + ALLOW_KEYBOARD_INPUT: FullscreenOptions; +} + +/** + * Composable to check whether the page is displayed at fullscreen + * @return {DeepReadonly>} - computed boolean whether the page is displayed at fullscreen + */ +function useDocumentFullscreenComposable() { + const isFullscreen = ref(document.fullscreenElement !== null) + + const changeIsFullscreen = () => { + isFullscreen.value = document.fullscreenElement !== null + } + + document.addEventListener('fullscreenchange', changeIsFullscreen) + document.addEventListener('webkitfullscreenchange', changeIsFullscreen) + + onBeforeUnmount(() => { + document.removeEventListener('fullscreenchange', changeIsFullscreen) + document.removeEventListener('webkitfullscreenchange', changeIsFullscreen) + }) + + return readonly(isFullscreen) +} + +/** + * Enable a fullscreen with Fullscreen API + */ +export async function enableFullscreen() { + const element = document.getElementById('content-vue') + if (!element) { + return + } + + if (element.requestFullscreen) { + await element.requestFullscreen() + } else if (element.webkitRequestFullscreen) { + await element.webkitRequestFullscreen((Element as unknown as WebkitElement).ALLOW_KEYBOARD_INPUT) + } +} + +/** + * Disable a fullscreen + */ +export async function disableFullscreen() { + if (document.exitFullscreen) { + await document.exitFullscreen() + } else if (document.webkitExitFullscreen) { + await document.webkitExitFullscreen() + } +} + +/** + * Shared composable to check whether the page is displayed at fullscreen + * @return {DeepReadonly>} - computed boolean whether the page is displayed at fullscreen + */ +export const useDocumentFullscreen = createSharedComposable(useDocumentFullscreenComposable) diff --git a/src/composables/useViewer.js b/src/composables/useViewer.js index 92d018cdffb..6099c28c510 100644 --- a/src/composables/useViewer.js +++ b/src/composables/useViewer.js @@ -3,8 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { computed, nextTick, ref, watch } from 'vue' +import { nextTick, ref, watch } from 'vue' +import { useDocumentFullscreen } from './useDocumentFullscreen.ts' import { useIsInCall } from './useIsInCall.js' import { useStore } from './useStore.js' import { useSidebarStore } from '../stores/sidebar.js' @@ -74,7 +75,7 @@ function reparentViewer(isFullscreen) { if (isFullscreen) { // When changed to the fullscreen mode, Viewer should be moved to the talk app - document.getElementById('content-vue').appendChild(viewerElement) + document.getElementById('content-vue')?.appendChild(viewerElement) } else { // In normal mode if it was in fullscreen before, move back to body // Otherwise it will be overlapped by web-page's header @@ -98,7 +99,7 @@ const isViewerOpen = ref(false) export function useViewer(fileAPI) { const store = useStore() const isInCall = useIsInCall() - const isFullscreen = computed(() => store.getters.isFullscreen()) + const isFullscreen = useDocumentFullscreen() const sidebarStore = useSidebarStore() watch(isFullscreen, () => { diff --git a/src/env.d.ts b/src/env.d.ts index 4d9841cd308..3acd12645ce 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -3,7 +3,18 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +type ExitFullscreen = typeof document.exitFullscreen +type RequestFullscreen = typeof document.documentElement.requestFullscreen + declare global { + interface Document { + webkitExitFullscreen: ExitFullscreen; + } + + interface HTMLElement { + webkitRequestFullscreen: RequestFullscreen; + } + // @nextcloud/webpack-vue-config build globals const appName: string const appVersion: string diff --git a/src/store/storeConfig.js b/src/store/storeConfig.js index ba77b609aff..8c35643e669 100644 --- a/src/store/storeConfig.js +++ b/src/store/storeConfig.js @@ -13,7 +13,6 @@ import participantsStore from './participantsStore.js' import soundsStore from './soundsStore.js' import tokenStore from './tokenStore.js' import uiModeStore from './uiModeStore.js' -import windowVisibilityStore from './windowVisibilityStore.js' export default { modules: { @@ -27,7 +26,6 @@ export default { soundsStore, tokenStore, uiModeStore, - windowVisibilityStore, }, mutations: {}, diff --git a/src/store/uiModeStore.js b/src/store/uiModeStore.js index 75f308d7648..f79faf88ca4 100644 --- a/src/store/uiModeStore.js +++ b/src/store/uiModeStore.js @@ -3,6 +3,8 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +import { useDocumentFullscreen } from '../composables/useDocumentFullscreen.ts' + /** * This store handles the values that need to be customized depending on the * current UI mode of Talk (main UI, embedded in Files sidebar, video @@ -15,7 +17,8 @@ const state = { const getters = { getMainContainerSelector: (state, getters, rootState, rootGetters) => () => { - return rootGetters.isFullscreen() ? state.mainContainerSelector : 'body' + const isFullscreen = useDocumentFullscreen() + return isFullscreen.value ? state.mainContainerSelector : 'body' }, } diff --git a/src/store/windowVisibilityStore.js b/src/store/windowVisibilityStore.js deleted file mode 100644 index f8af1239da5..00000000000 --- a/src/store/windowVisibilityStore.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -const state = { - fullscreen: false, -} - -const getters = { - isFullscreen: (state) => () => { - return state.fullscreen - }, -} - -const mutations = { - /** - * Sets the fullscreen state - * - * @param {object} state current store state; - * @param {boolean} value the value; - */ - setIsFullscreen(state, value) { - state.fullscreen = value - }, -} - -const actions = { - /** - * Sets the fullscreen state - * - * @param {object} context the context object; - * @param {boolean} value the value; - */ - setIsFullscreen(context, value) { - context.commit('setIsFullscreen', value) - }, - -} - -export default { state, mutations, getters, actions } From a8c7e587732d571e5d6ea600daf5cd2180cc9532 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Mon, 16 Sep 2024 17:16:53 +0200 Subject: [PATCH 2/2] fix: remove unsupported argument (remove since Chrome 70+) Signed-off-by: Maksim Sukharev --- src/composables/useDocumentFullscreen.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/composables/useDocumentFullscreen.ts b/src/composables/useDocumentFullscreen.ts index 9cafd85410f..0abd203c9ed 100644 --- a/src/composables/useDocumentFullscreen.ts +++ b/src/composables/useDocumentFullscreen.ts @@ -7,10 +7,6 @@ import { createSharedComposable } from '@vueuse/core' import { readonly, ref, onBeforeMount, onBeforeUnmount } from 'vue' import type { Ref, DeepReadonly } from 'vue' -interface WebkitElement extends Element { - ALLOW_KEYBOARD_INPUT: FullscreenOptions; -} - /** * Composable to check whether the page is displayed at fullscreen * @return {DeepReadonly>} - computed boolean whether the page is displayed at fullscreen @@ -45,7 +41,7 @@ export async function enableFullscreen() { if (element.requestFullscreen) { await element.requestFullscreen() } else if (element.webkitRequestFullscreen) { - await element.webkitRequestFullscreen((Element as unknown as WebkitElement).ALLOW_KEYBOARD_INPUT) + await element.webkitRequestFullscreen() } }