Skip to content
Open
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
61 changes: 43 additions & 18 deletions src/app/AppConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,27 +78,19 @@ export type AppConfig = {

/**
* Whether to play a sound when a chat notification is received.
* Same as notifications.sound_notification initial state.
* - 'always': always play sound
* - 'respect-dnd': play sound only if user status is not Do-Not-Disturb [default]
* - 'never': disable notification sound
* Default: true, but ignored on Do-Not-Disturb.
*/
playSoundChat: 'always' | 'respect-dnd' | 'never'
playSoundChat: boolean
/**
* Whether to play a sound when a call notification is received.
* Same as notifications.sound_talk initial state.
* - 'always': always play sound
* - 'respect-dnd': play sound only if user status is not Do-Not-Disturb [default]
* - 'never': disable notification sound
* Default: true, but ignored on Do-Not-Disturb.
*/
playSoundCall: 'always' | 'respect-dnd' | 'never'
playSoundCall: boolean
/**
* Whether to show a popup when a call notification is received.
* - 'always': always show the popup
* - 'respect-dnd': show the popup only if user status is not Do-Not-Disturb [default]
* - 'never': disable the call popup
* Default: true, but ignored on Do-Not-Disturb.
*/
enableCallbox: 'always' | 'respect-dnd' | 'never'
enableCallbox: boolean
/**
* Whether to play ring sound on secondary speaker when a call notification is received.
*/
Expand All @@ -120,9 +112,9 @@ const defaultAppConfig: AppConfig = {
systemTitleBar: isLinux,
monochromeTrayIcon: isMac,
zoomFactor: 1,
playSoundChat: 'respect-dnd',
playSoundCall: 'respect-dnd',
enableCallbox: 'respect-dnd',
playSoundChat: true,
playSoundCall: true,
enableCallbox: true,
secondarySpeaker: false,
secondarySpeakerDevice: null,
}
Expand Down Expand Up @@ -167,11 +159,44 @@ async function writeAppConfigFile(config: Partial<AppConfig>) {
}
}

/**
* Validate the application config by removing unknown properties and properties with invalid values
* @param config - Config to validate
*/
function validateAppConfig(config: unknown): Partial<AppConfig> {
if (typeof config !== 'object' || config === null) {
return {}
}
// Remove unknown keys
for (const key in config) {
if (!(key in defaultAppConfig)) {
delete config[key as keyof typeof config]
}
}
// Validate values
const booleanProperties: AppConfigKey[] = ['launchAtStartup', 'systemTitleBar', 'monochromeTrayIcon', 'playSoundChat', 'playSoundCall', 'enableCallbox', 'secondarySpeaker']
for (const key of booleanProperties) {
if (typeof config[key as keyof typeof config] !== 'boolean') {
delete config[key as keyof typeof config]
}
}
if ('zoomFactor' in config && typeof config.zoomFactor !== 'number') {
delete config.zoomFactor
}
if ('theme' in config && !['default', 'dark', 'light'].includes(config.theme as AppConfig['theme'])) {
delete config.theme
}
if ('secondarySpeakerDevice' in config && typeof config.secondarySpeakerDevice !== 'string' && config.secondarySpeakerDevice !== null) {
delete config.secondarySpeakerDevice
}
return config
}

/**
* Load the application config into the application memory
*/
export async function loadAppConfig() {
const config = await readAppConfigFile()
const config = validateAppConfig(await readAppConfigFile())
Object.assign(appConfig, config)
initialized = true
}
Expand Down
5 changes: 2 additions & 3 deletions src/talk/renderer/Settings/DesktopSettingsSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,8 @@ const zoomHint = t('talk_desktop', 'Zoom can be also changed by {key} or mouse w
}, undefined, { escape: false })

const generalNotificationOptions = [
{ label: t('talk_desktop', 'Always'), value: 'always' } as const,
{ label: t('talk_desktop', 'When not in "Do not disturb"'), value: 'respect-dnd' } as const,
{ label: t('talk_desktop', 'Never'), value: 'never' } as const,
{ label: t('talk_desktop', 'When not in "Do not disturb"'), value: true } as const,
{ label: t('talk_desktop', 'Never'), value: false } as const,
]

const playSoundChat = useAppConfigValue('playSoundChat')
Expand Down
8 changes: 2 additions & 6 deletions src/talk/renderer/Settings/appConfig.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,8 @@ export const useAppConfigStore = defineStore('appConfig', () => {

const userStatusStore = useUserStatusStore()
watchEffect(() => {
const playSoundChat = appConfig.value.playSoundChat === 'respect-dnd'
? userStatusStore.userStatus?.status !== 'dnd'
: appConfig.value.playSoundChat === 'always'
const playSoundCall = appConfig.value.playSoundCall === 'respect-dnd'
? userStatusStore.userStatus?.status !== 'dnd'
: appConfig.value.playSoundCall === 'always'
const playSoundChat = appConfig.value.playSoundChat && userStatusStore.userStatus?.status !== 'dnd'
const playSoundCall = appConfig.value.playSoundCall && userStatusStore.userStatus?.status !== 'dnd'
setInitialState('notifications', 'sound_notification', playSoundChat)
setInitialState('notifications', 'sound_talk', playSoundCall)
})
Expand Down
1 change: 1 addition & 0 deletions src/talk/renderer/TitleBar/components/DevMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import IconMessageBadgeOutline from 'vue-material-design-icons/MessageBadgeOutli
import IconConsole from 'vue-material-design-icons/Console.vue'
import { appData } from '../../../../app/AppData.js'

// @ts-expect-error appData is not typed yet
const supportsTestAdminNotification = appData.capabilities?.notifications?.['admin-notifications']?.includes('ocs') && appData.userMetadata?.groups.includes('admin')
const supportsTestPushNotification = appData.capabilities?.notifications?.['ocs-endpoints']?.includes('test-push')
const supportsTestNotification = supportsTestPushNotification || supportsTestAdminNotification
Expand Down
12 changes: 7 additions & 5 deletions src/talk/renderer/notifications/notifications.store.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,14 @@ export function createNotificationStore() {
return
}

const isNotificationFromPendingCall = notification.objectType === 'call'
&& await checkCurrentUserHasPendingCall(notification.objectId)

const enableCallboxConfig = getAppConfigValue('enableCallbox')
const shouldShowCallPopup = isNotificationFromPendingCall
&& (enableCallboxConfig === 'always' || (enableCallboxConfig === 'respect-dnd' && !userStatusStore.isDnd))
const callboxEnabled = enableCallboxConfig && !userStatusStore.isDnd
const isCallNotification = notification.objectType === 'call'

// Check for pending call only as the last check to avoid unnecessary requests
const shouldShowCallPopup = isCallNotification
&& callboxEnabled
&& await checkCurrentUserHasPendingCall(notification.objectId)

if (shouldShowCallPopup) {
const params = {
Expand Down
3 changes: 1 addition & 2 deletions src/talk/renderer/talk.main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import 'regenerator-runtime' // TODO: Why isn't it added on bundling
import { setupWebPage } from '../../shared/setupWebPage.js'
import { createTalkDesktopApp } from './TalkDesktop.app.ts'

// Initially open the Welcome page, if not specified
await setupWebPage({ routeHash: '#/apps/spreed' })
await setupWebPage()

await createTalkDesktopApp()