feat: 优化通知功能,增加icon小红点,增加提示音,优化通知场景

pull/64/head
moonrailgun 3 years ago
parent 338af097ca
commit 350371d6a3

@ -1,5 +1,10 @@
import { ChatConverseInfo, fetchConverseInfo } from '../model/converse';
import { findGroupInviteByCode, GroupInvite } from '../model/group';
import {
findGroupInviteByCode,
getGroupBasicInfo,
GroupBasicInfo,
GroupInvite,
} from '../model/group';
import {
fetchLocalStaticRegistryPlugins,
fetchRegistryPlugins,
@ -41,6 +46,19 @@ export async function getCachedConverseInfo(
return data;
}
/**
*
*/
export async function getCachedBaseGroupInfo(
groupId: string
): Promise<GroupBasicInfo | null> {
const data = await queryClient.fetchQuery(['baseGroupInfo', groupId], () =>
getGroupBasicInfo(groupId)
);
return data;
}
/**
*
*/

@ -9,6 +9,7 @@ export type { AppSocket } from './api/socket';
export {
getCachedUserInfo,
getCachedConverseInfo,
getCachedBaseGroupInfo,
getCachedGroupInviteInfo,
getCachedRegistryPlugins,
} from './cache/cache';

@ -3,5 +3,10 @@
"main": "src/index.tsx",
"version": "0.0.0",
"private": true,
"dependencies": {}
"dependencies": {
"tinycon": "^0.6.8"
},
"devDependencies": {
"@types/tinycon": "^0.6.3"
}
}

@ -0,0 +1,45 @@
import tinycon from 'tinycon';
/**
*
* @param num
*/
let bubbleNum = 0;
export function setBubble(num: number) {
bubbleNum = num;
if (num < 0) {
num = 0;
}
tinycon.setBubble(num >= 100 ? 99 : num);
}
/**
*
*/
export function incBubble() {
setBubble(bubbleNum + 1);
}
const hiddenProperty =
'hidden' in document
? 'hidden'
: 'webkitHidden' in document
? 'webkitHidden'
: 'mozHidden' in document
? 'mozHidden'
: null;
const visibilityChangeEvent = hiddenProperty?.replace(
/hidden/i,
'visibilitychange'
);
const onVisibilityChange = function () {
if (!document[hiddenProperty ?? '']) {
// 显示标签页时清空
tinycon.setBubble(0);
} else {
// 隐藏标签页
}
};
if (typeof visibilityChangeEvent === 'string') {
document.addEventListener(visibilityChangeEvent, onVisibilityChange);
}

@ -2,11 +2,16 @@ import {
regSocketEventListener,
getGlobalState,
getCachedUserInfo,
getCachedConverseInfo,
getCachedBaseGroupInfo,
getServiceWorkerRegistration,
navigate,
} from '@capital/common';
import { Translate } from './translate';
import { hasSilent } from './silent';
import { incBubble, setBubble } from './bubble';
const TAG = 'tailchat-message';
export function initNotify() {
if (Notification.permission === 'default') {
@ -15,7 +20,6 @@ export function initNotify() {
const registration: ServiceWorkerRegistration | null =
getServiceWorkerRegistration();
if (registration) {
registration.addEventListener('notificationclick', (e: any) => {
const tag = e.notification.tag;
@ -25,6 +29,13 @@ export function initNotify() {
});
}
let isBlur = false;
window.addEventListener('focus', () => {
setBubble(0); // 点击时清空
isBlur = false;
});
window.addEventListener('blur', () => (isBlur = true));
regSocketEventListener({
eventName: 'chat.message.add',
eventFn: (message) => {
@ -32,46 +43,59 @@ export function initNotify() {
const currentUserId = getGlobalState()?.user.info._id;
if (hasSilent(converseId)) {
// 免打扰
// 手动设置了当前会话免打扰
return;
}
if (currentUserId !== message.author) {
// 创建通知
if (currentUserId === message.author) {
// 忽略本人消息
return;
}
const hidden = window.document.hidden ?? false;
if (hidden || isBlur) {
// 如果当前不是活跃窗口或处于隐藏状态,则创建通知
// TODO: 需要增加所在群组
if (Notification.permission === 'granted') {
Promise.all([getCachedUserInfo(message.author)]).then(
([userInfo]) => {
const nickname = userInfo?.nickname ?? '';
const icon = userInfo?.avatar ?? undefined;
const content = message.content;
const title = `${Translate.from} ${nickname}`;
const options: NotificationOptions = {
body: content,
icon,
tag: 'tailchat-message',
renotify: true,
data: message,
};
// TODO: 需要增加显示所在群组
Promise.all([
getCachedUserInfo(message.author),
message.groupId
? getCachedBaseGroupInfo(message.groupId).then((d) => d.name)
: Promise.resolve(Translate.dm),
]).then(([userInfo, scopeName]) => {
const nickname = userInfo?.nickname ?? '';
const icon = userInfo?.avatar ?? undefined;
const content = message.content;
if (registration && registration.showNotification) {
registration.showNotification(title, options);
} else {
// fallback
const notification = new Notification(title, options);
notification.onclick = (e: any) => {
const tag = e.target.tag;
const data = e.target.data;
handleMessageNotifyClick(tag, data);
};
}
const title = `${Translate.from} [${scopeName}] ${nickname}`;
const options: NotificationOptions = {
body: content,
icon,
tag: TAG,
renotify: true,
data: message,
silent: true, // 因为有提示音了,所以禁音默认音
};
if (registration && registration.showNotification) {
registration.showNotification(title, options);
} else {
// fallback
const notification = new Notification(title, options);
notification.onclick = (e: any) => {
const tag = e.target.tag;
const data = e.target.data;
handleMessageNotifyClick(tag, data);
};
}
);
});
}
incBubble();
}
tryPlayNotificationSound(); // 不管当前是不是处于活跃状态,都发出提示音
},
});
}
@ -97,6 +121,18 @@ function handleMessageNotifyClick(tag, data) {
navigate(`/main/personal/converse/${converseId}`);
}
}
}
console.log(tag, data);
/**
*
*/
function tryPlayNotificationSound() {
try {
const audio = new Audio(
'/plugins/com.msgbyte.notify/assets/sounds_bing.mp3'
);
audio.play();
} catch (err) {
console.error(err);
}
}

@ -10,4 +10,8 @@ export const Translate = {
'zh-CN': '来自',
'en-US': 'From',
}),
dm: localTrans({
'zh-CN': '私信',
'en-US': 'DM',
}),
};

@ -1,6 +1,5 @@
{
"compilerOptions": {
"baseUrl": "./src",
"esModuleInterop": true,
"jsx": "react",
"paths": {

@ -37,6 +37,7 @@ export {
getServiceUrl,
getCachedUserInfo,
getCachedConverseInfo,
getCachedBaseGroupInfo,
localTrans,
getLanguage,
sharedEvent,

@ -644,7 +644,13 @@ importers:
miao-lang: 1.0.5
client/web/plugins/com.msgbyte.notify:
specifiers: {}
specifiers:
'@types/tinycon': ^0.6.3
tinycon: ^0.6.8
dependencies:
tinycon: 0.6.8
devDependencies:
'@types/tinycon': 0.6.3
client/web/plugins/com.msgbyte.openapi:
specifiers: {}
@ -11687,6 +11693,10 @@ packages:
dependencies:
'@types/node': 18.11.16
/@types/tinycon/0.6.3:
resolution: {integrity: sha512-TC42m8KAyp3AqyZKRXVkk5Qy+oIU8zo2U3362i16Qan0JgZNzLawO7oYnin4BJOy8FSZfOadYYvUWQnpaXoZwg==}
dev: true
/@types/trusted-types/2.0.2:
resolution: {integrity: sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==}
dev: true
@ -33655,6 +33665,10 @@ packages:
resolution: {integrity: sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==}
dev: false
/tinycon/0.6.8:
resolution: {integrity: sha512-bF8Lxm4JUXF6Cw0XlZdugJ44GV575OinZ0Pt8vQPr8ooNqd2yyNkoFdCHzmdpHlgoqfSLfcyk4HDP1EyllT+ug==}
dev: false
/title-case/2.1.1:
resolution: {integrity: sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==}
dependencies:

Loading…
Cancel
Save