call invite sounds (#6013)

Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>
This commit is contained in:
Vyacheslav Tumanov 2024-07-11 19:40:57 +05:00 committed by GitHub
parent 987b8a8068
commit 0031ede489
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 108 additions and 12 deletions

View File

@ -211,6 +211,16 @@ module.exports = [
} }
} }
}, },
{
test: /\.(wav|ogg)$/,
use: {
loader: 'file-loader',
options: {
'name': 'snd/[contenthash].[ext]',
esModule: false
}
}
},
{ {
test: /\.svg$/, test: /\.svg$/,
use: [ use: [

View File

@ -207,7 +207,8 @@ export function createModel (builder: Builder): void {
objectClass: love.class.JoinRequest, objectClass: love.class.JoinRequest,
providers: { providers: {
[notification.providers.PlatformNotification]: true, [notification.providers.PlatformNotification]: true,
[notification.providers.BrowserNotification]: true [notification.providers.BrowserNotification]: true,
[notification.providers.SoundNotification]: true
} }
}, },
love.ids.KnockNotification love.ids.KnockNotification

View File

@ -350,6 +350,15 @@ export function createModel (builder: Builder): void {
notification.providers.BrowserNotification notification.providers.BrowserNotification
) )
builder.createDoc(
notification.class.NotificationProvider,
core.space.Model,
{
label: notification.string.Sound
},
notification.providers.SoundNotification
)
builder.createDoc( builder.createDoc(
notification.class.NotificationProvider, notification.class.NotificationProvider,
core.space.Model, core.space.Model,

View File

@ -41,6 +41,7 @@
"dependencies": { "dependencies": {
"@hcengineering/platform": "^0.6.11", "@hcengineering/platform": "^0.6.11",
"@hcengineering/core": "^0.6.32", "@hcengineering/core": "^0.6.32",
"@hcengineering/notification": "^0.6.23",
"@hcengineering/analytics": "^0.6.0", "@hcengineering/analytics": "^0.6.0",
"@hcengineering/query": "^0.6.12", "@hcengineering/query": "^0.6.12",
"@hcengineering/ui": "^0.6.15", "@hcengineering/ui": "^0.6.15",

View File

@ -62,3 +62,4 @@ export * from './rules'
export * from './search' export * from './search'
export * from './image' export * from './image'
export * from './preview' export * from './preview'
export * from './sound'

View File

@ -0,0 +1,54 @@
import { type Class, type Doc, type Ref } from '@hcengineering/core'
import { type Asset, getMetadata } from '@hcengineering/platform'
import { getClient } from '.'
import notification from '@hcengineering/notification'
const sounds = new Map<Asset, AudioBufferSourceNode>()
const context = new AudioContext()
export async function prepareSound (key: string, _class?: Ref<Class<Doc>>, loop = false, play = false): Promise<void> {
const notificationType =
_class !== undefined
? getClient().getModel().findAllSync(notification.class.NotificationType, { objectClass: _class })
: undefined
const notAllowed = notificationType?.[0].providers[notification.providers.SoundNotification] === false
if (notificationType === undefined || notAllowed) {
return
}
try {
const soundUrl = getMetadata(key as Asset) as string
const audioBuffer = await fetch(soundUrl)
.then(async (res) => await res.arrayBuffer())
.then(async (ArrayBuffer) => await context.decodeAudioData(ArrayBuffer))
const audio = context.createBufferSource()
audio.buffer = audioBuffer
audio.loop = loop
sounds.set(key as Asset, audio)
if (play) {
playSound(key)
}
} catch (err) {
console.error('sound not found', key)
}
}
export function playSound (soundKey: string, _class?: Ref<Class<Doc>>, loop = false): void {
const sound = sounds.get(soundKey as Asset)
if (sound !== undefined) {
try {
sound.connect(context.destination)
sound.start()
} catch (err) {
console.error('error happened during sound play', soundKey, err)
}
} else {
void prepareSound(soundKey, _class, loop, true)
}
}
export function stopSound (soundKey: string): void {
const sound = sounds.get(soundKey as Asset)
if (sound !== undefined && sound?.context.state === 'running') {
sound.stop()
sound.disconnect(context.destination)
}
}

Binary file not shown.

View File

@ -38,3 +38,6 @@ loadMetadata(love.icon, {
ExitFullScreen: `${icons}#exitfullscreen`, ExitFullScreen: `${icons}#exitfullscreen`,
Invite: `${icons}#invite` Invite: `${icons}#invite`
}) })
loadMetadata(love.sound, {
Knock: require('../assets/knock.wav')
})

View File

@ -41,7 +41,6 @@
) )
await connectRoom(place.x, place.y, $myInfo, myPerson, room) await connectRoom(place.x, place.y, $myInfo, myPerson, room)
} }
async function decline (): Promise<void> { async function decline (): Promise<void> {
await client.update(invite, { status: RequestStatus.Rejected }) await client.update(invite, { status: RequestStatus.Rejected })
} }

View File

@ -16,12 +16,13 @@
import { PersonAccount, formatName } from '@hcengineering/contact' import { PersonAccount, formatName } from '@hcengineering/contact'
import { Avatar, personByIdStore } from '@hcengineering/contact-resources' import { Avatar, personByIdStore } from '@hcengineering/contact-resources'
import { getCurrentAccount } from '@hcengineering/core' import { getCurrentAccount } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation' import { getClient, playSound, stopSound } from '@hcengineering/presentation'
import { Button, Label } from '@hcengineering/ui' import { Button, Label } from '@hcengineering/ui'
import { JoinRequest, RequestStatus } from '@hcengineering/love' import { JoinRequest, RequestStatus } from '@hcengineering/love'
import love from '../plugin' import love from '../plugin'
import { myInfo, myOffice } from '../stores' import { myInfo, myOffice } from '../stores'
import { connectRoom, isConnected } from '../utils' import { connectRoom, isConnected } from '../utils'
import { onDestroy, onMount } from 'svelte'
export let request: JoinRequest export let request: JoinRequest
@ -42,6 +43,12 @@
async function decline (): Promise<void> { async function decline (): Promise<void> {
await client.update(request, { status: RequestStatus.Rejected }) await client.update(request, { status: RequestStatus.Rejected })
} }
onMount(() => {
playSound(love.sound.Knock, love.class.JoinRequest, true)
})
onDestroy(() => {
stopSound(love.sound.Knock)
})
</script> </script>
<div class="antiPopup flex-col-center"> <div class="antiPopup flex-col-center">

View File

@ -140,6 +140,9 @@ const love = plugin(loveId, {
ExitFullScreen: '' as Asset, ExitFullScreen: '' as Asset,
Invite: '' as Asset Invite: '' as Asset
}, },
sound: {
Knock: '' as Asset
},
metadata: { metadata: {
WebSocketURL: '' as Metadata<string>, WebSocketURL: '' as Metadata<string>,
ServiceEnpdoint: '' as Metadata<string> ServiceEnpdoint: '' as Metadata<string>

View File

@ -48,6 +48,7 @@
"Push": "Push", "Push": "Push",
"Unreads": "Unreads", "Unreads": "Unreads",
"EnablePush": "Enable push notifications", "EnablePush": "Enable push notifications",
"NotificationBlockedInBrowser": "Notifications are blocked in your browser. Please enable notifications in your browser settings" "NotificationBlockedInBrowser": "Notifications are blocked in your browser. Please enable notifications in your browser settings",
"Sound": "Sound"
} }
} }

View File

@ -47,6 +47,7 @@
"UnstarDocument": "Desmarcar documento", "UnstarDocument": "Desmarcar documento",
"Push": "Push", "Push": "Push",
"EnablePush": "Habilitar notificaciones push", "EnablePush": "Habilitar notificaciones push",
"NotificationBlockedInBrowser": "Las notificaciones están bloqueadas en tu navegador. Por favor, habilita las notificaciones en la configuración de tu navegador." "NotificationBlockedInBrowser": "Las notificaciones están bloqueadas en tu navegador. Por favor, habilita las notificaciones en la configuración de tu navegador.",
"Sound": "Sonido"
} }
} }

View File

@ -48,6 +48,7 @@
"Push": "Push", "Push": "Push",
"Unreads": "Non lus", "Unreads": "Non lus",
"EnablePush": "Activer les notifications push", "EnablePush": "Activer les notifications push",
"NotificationBlockedInBrowser": "Les notifications sont bloquées dans votre navigateur. Veuillez activer les notifications dans les paramètres de votre navigateur" "NotificationBlockedInBrowser": "Les notifications sont bloquées dans votre navigateur. Veuillez activer les notifications dans les paramètres de votre navigateur",
"Sound": "Son"
} }
} }

View File

@ -47,6 +47,7 @@
"UnstarDocument": "Desmarcar documento", "UnstarDocument": "Desmarcar documento",
"Push": "Push", "Push": "Push",
"EnablePush": "Ativar notificações push", "EnablePush": "Ativar notificações push",
"NotificationBlockedInBrowser": "Notificações bloqueadas no navegador. Por favor habilite las notificaciones en la configuración de su navegador." "NotificationBlockedInBrowser": "Notificações bloqueadas no navegador. Por favor habilite las notificaciones en la configuración de su navegador.",
"Sound": "Som"
} }
} }

View File

@ -48,6 +48,7 @@
"Push": "Push", "Push": "Push",
"Unreads": "Непрочитанные", "Unreads": "Непрочитанные",
"EnablePush": "Включить Push-уведомления", "EnablePush": "Включить Push-уведомления",
"NotificationBlockedInBrowser": "Уведомления заблокированы в вашем браузере. Пожалуйста, включите уведомления в настройках браузера" "NotificationBlockedInBrowser": "Уведомления заблокированы в вашем браузере. Пожалуйста, включите уведомления в настройках браузера",
"Sound": "Звук"
} }
} }

View File

@ -48,6 +48,7 @@
"Push": "推送", "Push": "推送",
"Unreads": "未读", "Unreads": "未读",
"EnablePush": "启用推送通知", "EnablePush": "启用推送通知",
"NotificationBlockedInBrowser": "通知在您的浏览器中被阻止。请在浏览器设置中启用通知" "NotificationBlockedInBrowser": "通知在您的浏览器中被阻止。请在浏览器设置中启用通知",
"Sound": "声音"
} }
} }

View File

@ -352,7 +352,8 @@ const notification = plugin(notificationId, {
providers: { providers: {
PlatformNotification: '' as Ref<NotificationProvider>, PlatformNotification: '' as Ref<NotificationProvider>,
BrowserNotification: '' as Ref<NotificationProvider>, BrowserNotification: '' as Ref<NotificationProvider>,
EmailNotification: '' as Ref<NotificationProvider> EmailNotification: '' as Ref<NotificationProvider>,
SoundNotification: '' as Ref<NotificationProvider>
}, },
integrationType: { integrationType: {
MobileApp: '' as Ref<IntegrationType> MobileApp: '' as Ref<IntegrationType>
@ -400,7 +401,8 @@ const notification = plugin(notificationId, {
ArchiveAllConfirmationMessage: '' as IntlString, ArchiveAllConfirmationMessage: '' as IntlString,
YouAddedCollaborators: '' as IntlString, YouAddedCollaborators: '' as IntlString,
YouRemovedCollaborators: '' as IntlString, YouRemovedCollaborators: '' as IntlString,
Push: '' as IntlString Push: '' as IntlString,
Sound: '' as IntlString
}, },
function: { function: {
Notify: '' as Resource<NotifyFunc>, Notify: '' as Resource<NotifyFunc>,

View File

@ -36,7 +36,7 @@ export class NotificationsPage {
documents = (): Locator => this.page.getByRole('button', { name: 'Documents' }) documents = (): Locator => this.page.getByRole('button', { name: 'Documents' })
requests = (): Locator => this.page.getByRole('button', { name: 'Requests' }) requests = (): Locator => this.page.getByRole('button', { name: 'Requests' })
todos = (): Locator => this.page.getByRole('button', { name: "Todo's" }) todos = (): Locator => this.page.getByRole('button', { name: "Todo's" })
chatMessageToggle = (): Locator => this.page.locator('div:nth-child(6) > .flex-between > .toggle > .toggle-switch') chatMessageToggle = (): Locator => this.page.locator('div:nth-child(7) > .flex-between > .toggle > .toggle-switch')
constructor (page: Page) { constructor (page: Page) {
this.page = page this.page = page