mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-10 09:22:23 +00:00
Add browser notifications sound (#8515)
Signed-off-by: Anton Alexeyev <alexeyev.anton@gmail.com>
This commit is contained in:
parent
601fabd712
commit
afbaf26078
@ -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,
|
||||
|
@ -106,6 +106,7 @@ export class TBrowserNotification extends TDoc implements BrowserNotification {
|
||||
messageClass?: Ref<Class<ActivityMessage>>
|
||||
objectId!: Ref<Doc>
|
||||
objectClass!: Ref<Class<Doc>>
|
||||
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 (
|
||||
|
@ -6,21 +6,20 @@ import notification from '@hcengineering/notification'
|
||||
const sounds = new Map<Asset, AudioBuffer>()
|
||||
const context = new AudioContext()
|
||||
|
||||
export async function prepareSound (key: string, _class?: Ref<Class<Doc>>): Promise<void> {
|
||||
if (_class === undefined) return
|
||||
|
||||
export async function isNotificationAllowed (_class?: Ref<Class<Doc>>): Promise<boolean> {
|
||||
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<void> {
|
||||
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<Class<Doc>>): Prom
|
||||
}
|
||||
}
|
||||
|
||||
export async function playSound (
|
||||
soundKey: string,
|
||||
_class?: Ref<Class<Doc>>,
|
||||
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<Class<Doc>>,
|
||||
loop = false
|
||||
): Promise<(() => void) | null> {
|
||||
const allowed = await isNotificationAllowed(_class)
|
||||
if (!allowed) return null
|
||||
return await playSound(soundKey, loop)
|
||||
}
|
||||
|
@ -15,18 +15,20 @@
|
||||
<script lang="ts">
|
||||
import { formatName } from '@hcengineering/contact'
|
||||
import { Avatar, personByIdStore } from '@hcengineering/contact-resources'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { getClient, playNotificationSound } from '@hcengineering/presentation'
|
||||
import { Button, Label } from '@hcengineering/ui'
|
||||
import { Invite, RequestStatus, getFreeRoomPlace } from '@hcengineering/love'
|
||||
import love from '../plugin'
|
||||
import { infos, myInfo, rooms } from '../stores'
|
||||
import { connectRoom } from '../utils'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
|
||||
export let invite: Invite
|
||||
|
||||
$: person = $personByIdStore.get(invite.from)
|
||||
|
||||
const client = getClient()
|
||||
let stopSound: (() => void) | null = null
|
||||
|
||||
async function accept (): Promise<void> {
|
||||
const room = $rooms.find((p) => p._id === invite.room)
|
||||
@ -45,6 +47,14 @@
|
||||
async function decline (): Promise<void> {
|
||||
await client.update(invite, { status: RequestStatus.Rejected })
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
stopSound = await playNotificationSound(love.sound.Knock, love.class.Invite, true)
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
stopSound?.()
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="antiPopup flex-col-center">
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { formatName, getCurrentEmployee } from '@hcengineering/contact'
|
||||
import { Avatar, personByIdStore } from '@hcengineering/contact-resources'
|
||||
import { getClient, playSound } from '@hcengineering/presentation'
|
||||
import { getClient, playNotificationSound } from '@hcengineering/presentation'
|
||||
import { Button, Label } from '@hcengineering/ui'
|
||||
import { JoinRequest, RequestStatus } from '@hcengineering/love'
|
||||
import love from '../plugin'
|
||||
@ -45,7 +45,7 @@
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
stopSound = await playSound(love.sound.Knock, love.class.JoinRequest, true)
|
||||
stopSound = await playNotificationSound(love.sound.Knock, love.class.JoinRequest, true)
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
|
BIN
plugins/notification-assets/assets/inbox-notification.wav
Normal file
BIN
plugins/notification-assets/assets/inbox-notification.wav
Normal file
Binary file not shown.
@ -22,3 +22,6 @@ loadMetadata(notification.icon, {
|
||||
Inbox: `${icons}#inbox`,
|
||||
BellCrossed: `${icons}#bell-crossed`
|
||||
})
|
||||
loadMetadata(notification.sound, {
|
||||
InboxNotification: require('../assets/inbox-notification.wav')
|
||||
})
|
||||
|
@ -7,10 +7,10 @@
|
||||
import chunter, { ThreadMessage } from '@hcengineering/chunter'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import activity, { ActivityMessage } from '@hcengineering/activity'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
|
||||
import { getClient, playSound } from '@hcengineering/presentation'
|
||||
import { pushAvailable, subscribePush } from '../utils'
|
||||
import plugin from '../plugin'
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
export let notification: PlatformNotification
|
||||
export let onRemove: () => void
|
||||
@ -54,6 +54,11 @@
|
||||
const fn = await getResource(chunter.function.OpenChannelInSidebar)
|
||||
await fn(_id, _class, undefined, thread, true, selectedMessageId)
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
if (!value.soundAlert) return
|
||||
await playSound(plugin.sound.InboxNotification)
|
||||
})
|
||||
</script>
|
||||
|
||||
<NotificationToast title={notification.title} severity={notification.severity} onClose={onRemove}>
|
||||
|
@ -62,6 +62,7 @@ export interface BrowserNotification extends Doc {
|
||||
messageClass?: Ref<Class<ActivityMessage>>
|
||||
objectId: Ref<Doc>
|
||||
objectClass: Ref<Class<Doc>>
|
||||
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,
|
||||
|
@ -54,6 +54,7 @@ async function createPushFromInbox (
|
||||
control: TriggerControl,
|
||||
n: InboxNotification,
|
||||
receiver: AccountUuid,
|
||||
soundAlert: boolean,
|
||||
receiverSpace: Ref<PersonSpace>,
|
||||
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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user