83 lines
2.3 KiB
TypeScript
83 lines
2.3 KiB
TypeScript
import { isXaigenStudio } from '~/utils/videoModels'
|
|
|
|
const PREF_KEY = 'aigen-notify-complete'
|
|
const TAG = 'aigen-generation-complete'
|
|
|
|
function appName() {
|
|
try {
|
|
const pub = useRuntimeConfig().public as { instanceName?: string; studio?: string }
|
|
return String(pub.instanceName || (isXaigenStudio(pub) ? 'xAIGen' : 'AIGen'))
|
|
} catch {
|
|
return 'AIGen'
|
|
}
|
|
}
|
|
|
|
function appIcon() {
|
|
try {
|
|
const pub = useRuntimeConfig().public as { instanceName?: string; studio?: string }
|
|
return isXaigenStudio(pub) ? '/favicon.svg' : '/favicon-aigen.svg'
|
|
} catch {
|
|
return '/favicon-aigen.svg'
|
|
}
|
|
}
|
|
|
|
export function generationNotifySupported() {
|
|
return typeof window !== 'undefined' && 'Notification' in window
|
|
}
|
|
|
|
export function generationNotifyPref() {
|
|
if (typeof window === 'undefined') return true
|
|
try {
|
|
return localStorage.getItem(PREF_KEY) !== '0'
|
|
} catch {
|
|
return true
|
|
}
|
|
}
|
|
|
|
export function setGenerationNotifyPref(on: boolean) {
|
|
try {
|
|
localStorage.setItem(PREF_KEY, on ? '1' : '0')
|
|
} catch { /* ignore */ }
|
|
}
|
|
|
|
export async function ensureGenerationNotifyPermission() {
|
|
if (!generationNotifySupported() || !generationNotifyPref()) return false
|
|
if (Notification.permission === 'granted') return true
|
|
if (Notification.permission === 'denied') return false
|
|
try {
|
|
const result = await Notification.requestPermission()
|
|
return result === 'granted'
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
export async function notifyGenerationComplete(kind: 'video' | 'image' = 'video') {
|
|
if (!generationNotifySupported() || !generationNotifyPref()) return
|
|
if (Notification.permission !== 'granted') return
|
|
if (typeof document !== 'undefined' && !document.hidden && document.hasFocus()) return
|
|
const title = appName()
|
|
const body = kind === 'image' ? 'Image generation is complete.' : 'Generation is complete.'
|
|
const options: NotificationOptions = {
|
|
body,
|
|
icon: appIcon(),
|
|
tag: TAG,
|
|
renotify: true,
|
|
silent: false
|
|
}
|
|
try {
|
|
const registration = await navigator.serviceWorker?.ready
|
|
if (registration?.showNotification) {
|
|
await registration.showNotification(title, options)
|
|
return
|
|
}
|
|
} catch { /* fall through */ }
|
|
try {
|
|
const note = new Notification(title, options)
|
|
note.onclick = () => {
|
|
window.focus()
|
|
note.close()
|
|
}
|
|
} catch { /* ignore */ }
|
|
}
|