Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: handle background blur in Talk if server doesn't support it #13507

Merged
merged 2 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion src/components/CallView/CallView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
-->

<template>
<div id="call-container">
<div id="call-container" :class="callContainerClass">
<ViewerOverlayCallView v-if="isViewerOverlay"
:token="token"
:model="promotedParticipantModel"
Expand Down Expand Up @@ -137,6 +137,7 @@ import { provide, ref } from 'vue'

import { showMessage } from '@nextcloud/dialogs'
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'

import Grid from './Grid/Grid.vue'
Expand All @@ -151,14 +152,19 @@ import ViewerOverlayCallView from './shared/ViewerOverlayCallView.vue'

import { placeholderImage, placeholderModel, placeholderName, placeholderSharedData } from './Grid/gridPlaceholders.ts'
import { SIMULCAST } from '../../constants.js'
import BrowserStorage from '../../services/BrowserStorage.js'
import { fetchPeers } from '../../services/callsService.js'
import { getTalkConfig } from '../../services/CapabilitiesManager.ts'
import { EventBus } from '../../services/EventBus.js'
import { useCallViewStore } from '../../stores/callView.js'
import { useSettingsStore } from '../../stores/settings.js'
import { satisfyVersion } from '../../utils/satisfyVersion.ts'
import { localMediaModel, localCallParticipantModel, callParticipantCollection } from '../../utils/webrtc/index.js'
import RemoteVideoBlocker from '../../utils/webrtc/RemoteVideoBlocker.js'

const serverVersion = loadState('core', 'config', {}).version ?? '29.0.0.0'
const serverSupportsBackgroundBlurred = satisfyVersion(serverVersion, '29.0.4.0')

export default {
name: 'CallView',

Expand Down Expand Up @@ -204,12 +210,16 @@ export default {
localMediaModel.disableVideo()
}

// Fallback ref for versions before v29.0.4
const isBackgroundBlurred = ref(BrowserStorage.getItem('background-blurred') !== 'false')

return {
localMediaModel,
localCallParticipantModel,
callParticipantCollection,
devMode,
callViewStore: useCallViewStore(),
isBackgroundBlurred,
}
},

Expand Down Expand Up @@ -379,6 +389,17 @@ export default {
supportedReactions() {
return getTalkConfig(this.token, 'call', 'supported-reactions')
},

/**
* Fallback style for versions before v29.0.4
*/
callContainerClass() {
if (serverSupportsBackgroundBlurred) {
return
}

return this.isBackgroundBlurred ? 'call-container__blurred' : 'call-container__non-blurred'
}
},

watch: {
Expand Down Expand Up @@ -470,6 +491,7 @@ export default {
callParticipantCollection.on('remove', this._lowerHandWhenParticipantLeaves)

subscribe('switch-screen-to-id', this._switchScreenToId)
subscribe('set-background-blurred', this.setBackgroundBlurred)
},

beforeDestroy() {
Expand All @@ -480,6 +502,7 @@ export default {
callParticipantCollection.off('remove', this._lowerHandWhenParticipantLeaves)

unsubscribe('switch-screen-to-id', this._switchScreenToId)
unsubscribe('set-background-blurred', this.setBackgroundBlurred)
},

methods: {
Expand Down Expand Up @@ -748,6 +771,14 @@ export default {
}
},

/**
* Fallback method for versions before v29.0.4
* @param {boolean} value whether background should be blurred
*/
setBackgroundBlurred(value) {
this.isBackgroundBlurred = value
Antreesy marked this conversation as resolved.
Show resolved Hide resolved
},

isModelWithVideo(callParticipantModel) {
if (!callParticipantModel) {
return false
Expand Down Expand Up @@ -776,8 +807,16 @@ export default {
width: 100%;
height: 100%;
background-color: $color-call-background;
// Default value has changed since v29.0.4: 'blur(25px)' => 'none'
backdrop-filter: var(--filter-background-blur);
--grid-gap: calc(var(--default-grid-baseline) * 2);

&.call-container__blurred {
backdrop-filter: blur(25px);
}
&.call-container__non-blurred {
backdrop-filter: none;
}
}

#videos {
Expand Down
70 changes: 53 additions & 17 deletions src/components/SettingsDialog/SettingsDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,30 @@
<NcAppSettingsSection id="performance"
:name="t('spreed', 'Performance')"
class="app-settings-section">
<NcCheckboxRadioSwitch id="blur-call-background"
:checked="isBackgroundBlurred === 'yes'"
:indeterminate="isBackgroundBlurred === ''"
type="checkbox"
<template v-if="serverSupportsBackgroundBlurred">
<NcCheckboxRadioSwitch id="blur-call-background"
:checked="isBackgroundBlurred === 'yes'"
:indeterminate="isBackgroundBlurred === ''"
type="checkbox"
class="checkbox"
disabled>
{{ t('spreed', 'Blur background image in the call (may increase GPU load)') }}
</NcCheckboxRadioSwitch>
<a :href="themingUrl"
target="_blank"
rel="noreferrer nofollow"
class="external">
{{ t('spreed', 'Background blur for Nextcloud instance can be adjusted in the theming settings.') }} ↗
</a>
</template>
<NcCheckboxRadioSwitch v-else
id="blur-call-background"
:checked="isBackgroundBlurred !== 'false'"
type="switch"
class="checkbox"
disabled>
@update:checked="toggleBackgroundBlurred">
{{ t('spreed', 'Blur background image in the call (may increase GPU load)') }}
</NcCheckboxRadioSwitch>
<a :href="themingUrl"
target="_blank"
rel="noreferrer nofollow"
class="external">
{{ t('spreed', 'Background blur for Nextcloud instance can be adjusted in the theming settings.') }} ↗
</a>
</NcAppSettingsSection>
<NcAppSettingsSection v-if="!disableKeyboardShortcuts"
id="shortcuts"
Expand Down Expand Up @@ -185,10 +195,12 @@
</template>

<script>
import { ref } from 'vue'

import axios from '@nextcloud/axios'
import { showError, showSuccess } from '@nextcloud/dialogs'
import { FilePickerVue } from '@nextcloud/dialogs/filepicker.js'
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import { generateOcsUrl, generateUrl } from '@nextcloud/router'
Expand All @@ -207,8 +219,14 @@ import { useCustomSettings } from '../../services/SettingsAPI.ts'
import { setUserConfig } from '../../services/settingsService.js'
import { useSettingsStore } from '../../stores/settings.js'
import { useSoundsStore } from '../../stores/sounds.js'
import { satisfyVersion } from '../../utils/satisfyVersion.ts'

const serverVersion = loadState('core', 'config', {}).version ?? '29.0.0.0'
const serverSupportsBackgroundBlurred = satisfyVersion(serverVersion, '29.0.4.0')

const isBackgroundBlurred = loadState('spreed', 'force_enable_blur_filter', '')
const isBackgroundBlurredState = serverSupportsBackgroundBlurred
? loadState('spreed', 'force_enable_blur_filter', '') // 'yes', 'no', ''
: BrowserStorage.getItem('background-blurred') // 'true', 'false', null
const supportTypingStatus = getTalkConfig('local', 'chat', 'typing-privacy') !== undefined

export default {
Expand All @@ -227,12 +245,14 @@ export default {
const settingsStore = useSettingsStore()
const soundsStore = useSoundsStore()
const { customSettingsSections } = useCustomSettings()
const isBackgroundBlurred = ref(isBackgroundBlurredState)

return {
settingsStore,
soundsStore,
supportTypingStatus,
isBackgroundBlurred,
serverSupportsBackgroundBlurred,
customSettingsSections,
}
},
Expand Down Expand Up @@ -300,11 +320,17 @@ export default {

async created() {
const blurred = BrowserStorage.getItem('background-blurred')
if (blurred === 'false' && isBackgroundBlurred === '') {
console.debug('Blur was disabled intentionally, propagating last choice to server')
await setUserConfig('theming', 'force_enable_blur_filter', 'no')
if (serverSupportsBackgroundBlurred) {
// Blur is handled by theming app, migrating
if (blurred === 'false' && isBackgroundBlurredState === '') {
console.debug('Blur was disabled intentionally, propagating last choice to server')
await setUserConfig('theming', 'force_enable_blur_filter', 'no')
}
BrowserStorage.removeItem('background-blurred')
} else if (blurred === null) {
// Fallback to BrowserStorage
BrowserStorage.setItem('background-blurred', 'true')
}
BrowserStorage.removeItem('background-blurred')
},

mounted() {
Expand Down Expand Up @@ -360,6 +386,16 @@ export default {
this.privacyLoading = false
},

/**
* Fallback method for versions before v29.0.4
* @param {boolean} value whether background should be blurred
*/
toggleBackgroundBlurred(value) {
this.isBackgroundBlurred = value.toString()
BrowserStorage.setItem('background-blurred', this.isBackgroundBlurred)
emit('set-background-blurred', value)
},

async togglePlaySounds() {
this.playSoundsLoading = true
try {
Expand Down
39 changes: 39 additions & 0 deletions src/utils/__tests__/satisfyVersion.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { satisfyVersion } from '../satisfyVersion.ts'

describe('satisfyVersion', () => {
const testCases = [
// Before required
['29.1.4.3', '28.2.5.4', true],
['29.1.4.3', '29.0.15.3', true],
['29.1.4.3', '29.1.1.3', true],
['29.1.4.3', '29.1.4.0', true],
Antreesy marked this conversation as resolved.
Show resolved Hide resolved
['29.1.4.3', '29.1.4', true],
['29.1.4.3', '29.1', true],
['29.1.4.3', '29', true],
['29.1.4', '29.1.3.9', true],
['29.1', '29.0.9.1', true],
['29', '28.1.5.6', true],
// Exact match
['29.1.4.3', '29.1.4.3', true],
['29', '29.0.0.0', true],
// After required
['29.1.4.3', '29.1.4.4', false],
['29.1.4.3', '29.1.5.0', false],
['29.1.4.3', '29.2.0.0', false],
['29.1.4.3', '30.0.0.0', false],
Antreesy marked this conversation as resolved.
Show resolved Hide resolved
['29.1.4.3', '29.1.5', false],
['29.1.4.3', '29.2', false],
['29.1.4.3', '30', false],
['29.1.4', '29.1.4.3', false],
['29.1', '29.1.4.3', false],
['29', '29.1.4.3', false],
]

it.each(testCases)('check if %s should satisfy requirement %s returns %s', (a, b, c) => {
expect(satisfyVersion(a, b)).toBe(c)
})
})
26 changes: 26 additions & 0 deletions src/utils/satisfyVersion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

/**
* Checks if given version satisfy requirements (newer than)
* Versions are expected to have format like '29.1.4.3'
* @param version given version
* @param requirement version to compare against
*/
function satisfyVersion(version: string, requirement: string): boolean {
const versionMap = version.split('.').map(Number)
const requirementMap = requirement.split('.').map(Number)
ShGKme marked this conversation as resolved.
Show resolved Hide resolved

for (let i = 0; i < Math.max(versionMap.length, requirementMap.length); i++) {
if ((versionMap[i] ?? 0) !== (requirementMap[i] ?? 0)) {
return (versionMap[i] ?? 0) > (requirementMap[i] ?? 0)
}
}
return true
}

export {
satisfyVersion,
}
Loading