diff --git a/models/chunter/src/notifications.ts b/models/chunter/src/notifications.ts index cefebd1c50..bc9b8c696b 100644 --- a/models/chunter/src/notifications.ts +++ b/models/chunter/src/notifications.ts @@ -159,6 +159,17 @@ export function defineNotifications (builder: Builder): void { ] }) + builder.createDoc(notification.class.NotificationProviderDefaults, core.space.Model, { + provider: notification.providers.SoundNotificationProvider, + ignoredTypes: [], + enabledTypes: [ + chunter.ids.DMNotification, + chunter.ids.ChannelNotification, + chunter.ids.ThreadNotification, + chunter.ids.JoinChannelNotification + ] + }) + builder.createDoc(notification.class.ActivityNotificationViewlet, core.space.Model, { messageMatch: { _class: activity.class.DocUpdateMessage, diff --git a/models/notification/src/index.ts b/models/notification/src/index.ts index c76d58e71b..d8b2bc8717 100644 --- a/models/notification/src/index.ts +++ b/models/notification/src/index.ts @@ -106,6 +106,7 @@ export class TBrowserNotification extends TDoc implements BrowserNotification { messageClass?: Ref> objectId!: Ref objectClass!: Ref> + soundAlert!: boolean } @Model(notification.class.PushSubscription, core.class.Doc, DOMAIN_USER_NOTIFY) @@ -776,7 +777,6 @@ export function createModel (builder: Builder): void { depends: notification.providers.PushNotificationProvider, defaultEnabled: true, canDisable: true, - ignoreAll: true, order: 250 }, notification.providers.SoundNotificationProvider @@ -787,6 +787,12 @@ export function createModel (builder: Builder): void { ignoredTypes: [notification.ids.CollaboratoAddNotification], enabledTypes: [] }) + + builder.createDoc(notification.class.NotificationProviderDefaults, core.space.Model, { + provider: notification.providers.SoundNotificationProvider, + ignoredTypes: [notification.ids.CollaboratoAddNotification], + enabledTypes: [] + }) } export function generateClassNotificationTypes ( diff --git a/packages/presentation/src/sound.ts b/packages/presentation/src/sound.ts index eff939be10..6aa8ec906f 100644 --- a/packages/presentation/src/sound.ts +++ b/packages/presentation/src/sound.ts @@ -6,21 +6,20 @@ import notification from '@hcengineering/notification' const sounds = new Map() const context = new AudioContext() -export async function prepareSound (key: string, _class?: Ref>): Promise { - if (_class === undefined) return - +export async function isNotificationAllowed (_class?: Ref>): Promise { + if (_class === undefined) return false const client = getClient() const notificationType = client .getModel() .findAllSync(notification.class.NotificationType, { objectClass: _class })[0] - if (notificationType === undefined) return + if (notificationType === undefined) return false const isAllowedFn = await getResource(notification.function.IsNotificationAllowed) - const allowed: boolean = isAllowedFn(notificationType, notification.providers.SoundNotificationProvider) - - if (!allowed) return + return isAllowedFn(notificationType, notification.providers.SoundNotificationProvider) +} +export async function prepareSound (key: string): Promise { try { const soundUrl = getMetadata(key as Asset) as string const rawAudio = await fetch(soundUrl) @@ -33,14 +32,11 @@ export async function prepareSound (key: string, _class?: Ref>): Prom } } -export async function playSound ( - soundKey: string, - _class?: Ref>, - loop = false -): Promise<(() => void) | null> { +export async function playSound (soundKey: string, loop = false): Promise<(() => void) | null> { const soundAssetKey = soundKey as Asset + if (!sounds.has(soundAssetKey)) { - await prepareSound(soundKey, _class) + await prepareSound(soundKey) } const sound = sounds.get(soundKey as Asset) @@ -65,3 +61,13 @@ export async function playSound ( return null } } + +export async function playNotificationSound ( + soundKey: string, + _class?: Ref>, + loop = false +): Promise<(() => void) | null> { + const allowed = await isNotificationAllowed(_class) + if (!allowed) return null + return await playSound(soundKey, loop) +} diff --git a/plugins/love-resources/src/components/InvitePopup.svelte b/plugins/love-resources/src/components/InvitePopup.svelte index b41e9f1a55..484819c7ba 100644 --- a/plugins/love-resources/src/components/InvitePopup.svelte +++ b/plugins/love-resources/src/components/InvitePopup.svelte @@ -15,18 +15,20 @@
diff --git a/plugins/love-resources/src/components/RequestPopup.svelte b/plugins/love-resources/src/components/RequestPopup.svelte index 66d12028c0..83d7ee411d 100644 --- a/plugins/love-resources/src/components/RequestPopup.svelte +++ b/plugins/love-resources/src/components/RequestPopup.svelte @@ -15,7 +15,7 @@ diff --git a/plugins/notification/src/index.ts b/plugins/notification/src/index.ts index 6e9bafa301..e6fb984280 100644 --- a/plugins/notification/src/index.ts +++ b/plugins/notification/src/index.ts @@ -62,6 +62,7 @@ export interface BrowserNotification extends Doc { messageClass?: Ref> objectId: Ref objectClass: Ref> + soundAlert: boolean } export interface PushData { @@ -405,6 +406,9 @@ const notification = plugin(notificationId, { Inbox: '' as Asset, BellCrossed: '' as Asset }, + sound: { + InboxNotification: '' as Asset + }, string: { Notification: '' as IntlString, Notifications: '' as IntlString, diff --git a/server-plugins/notification-resources/src/push.ts b/server-plugins/notification-resources/src/push.ts index 85baedff3b..7c52242733 100644 --- a/server-plugins/notification-resources/src/push.ts +++ b/server-plugins/notification-resources/src/push.ts @@ -54,6 +54,7 @@ async function createPushFromInbox ( control: TriggerControl, n: InboxNotification, receiver: AccountUuid, + soundAlert: boolean, receiverSpace: Ref, subscriptions: PushSubscription[], senderPerson?: Person @@ -87,7 +88,10 @@ async function createPushFromInbox ( } const path = [workbenchId, control.workspace.url, notificationId, encodeObjectURI(id, n.objectClass)] - await createPushNotification(control, receiver, title, body, n._id, subscriptions, senderPerson, path) + + if (subscriptions.length > 0) { + await createPushNotification(control, receiver, title, body, n._id, subscriptions, senderPerson, path) + } const messageInfo = getMessageInfo(n, control.hierarchy) return control.txFactory.createTxCreateDoc(notification.class.BrowserNotification, receiverSpace, { @@ -102,7 +106,8 @@ async function createPushFromInbox ( messageClass: messageInfo._class, onClickLocation: { path - } + }, + soundAlert }) } @@ -246,23 +251,23 @@ export async function PushNotificationsHandler ( receivers.has(it.user) ) - if (subscriptions.length === 0) { - return [] - } - const res: Tx[] = [] for (const inboxNotification of all) { const { user } = inboxNotification const userSubscriptions = subscriptions.filter((it) => it.user === user) - if (userSubscriptions.length === 0) continue const senderSocialString = inboxNotification.createdBy ?? inboxNotification.modifiedBy const senderPerson = await getPerson(control, senderSocialString) + const soundAlert = + availableProviders + .get(inboxNotification._id) + ?.find((p) => p === notification.providers.SoundNotificationProvider) !== undefined const tx = await createPushFromInbox( control, inboxNotification, user, + soundAlert, inboxNotification.space, userSubscriptions, senderPerson diff --git a/tests/sanity/tests/model/profile/notifications-page.ts b/tests/sanity/tests/model/profile/notifications-page.ts index a6e9d30342..7c3e5373ce 100644 --- a/tests/sanity/tests/model/profile/notifications-page.ts +++ b/tests/sanity/tests/model/profile/notifications-page.ts @@ -36,7 +36,7 @@ export class NotificationsPage { documents = (): Locator => this.page.getByRole('button', { name: 'Documents' }) requests = (): Locator => this.page.getByRole('button', { name: 'Requests' }) todos = (): Locator => this.page.getByRole('button', { name: "Todo's" }) - chatMessageToggle = (): Locator => this.page.locator('.grid > div:nth-child(6)') + chatMessageToggle = (): Locator => this.page.locator('.grid > div:nth-child(7)') constructor (page: Page) { this.page = page