mirror of https://github.com/msgbyte/tailchat
feat: 增加群组消息通知免打扰功能
parent
0050f233a2
commit
27e9969796
@ -0,0 +1,12 @@
|
|||||||
|
import { DependencyList, useLayoutEffect } from 'react';
|
||||||
|
import { useMemoizedFn } from './useMemoizedFn';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听变更并触发回调
|
||||||
|
*/
|
||||||
|
export function useWatch(deps: DependencyList, cb: () => void) {
|
||||||
|
const memoizedFn = useMemoizedFn(cb);
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
memoizedFn();
|
||||||
|
}, deps);
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
import { initNotify } from './notify';
|
|
||||||
|
|
||||||
if ('Notification' in window) {
|
|
||||||
initNotify();
|
|
||||||
} else {
|
|
||||||
console.warn('浏览器不支持 Notification');
|
|
||||||
}
|
|
@ -0,0 +1,39 @@
|
|||||||
|
import {
|
||||||
|
regGroupPanelBadge,
|
||||||
|
regPluginGroupTextPanelExtraMenu,
|
||||||
|
sharedEvent,
|
||||||
|
} from '@capital/common';
|
||||||
|
import { Icon } from '@capital/component';
|
||||||
|
import React from 'react';
|
||||||
|
import { appendSilent, hasSilent, removeSilent } from './silent';
|
||||||
|
import { initNotify } from './notify';
|
||||||
|
|
||||||
|
const PLUGIN_NAME = 'com.msgbyte.notify';
|
||||||
|
|
||||||
|
if ('Notification' in window) {
|
||||||
|
initNotify();
|
||||||
|
} else {
|
||||||
|
console.warn('浏览器不支持 Notification');
|
||||||
|
}
|
||||||
|
|
||||||
|
regPluginGroupTextPanelExtraMenu({
|
||||||
|
name: `${PLUGIN_NAME}/grouppanelmenu`,
|
||||||
|
label: '免打扰',
|
||||||
|
icon: 'mdi:bell-off-outline',
|
||||||
|
onClick: (panelInfo) => {
|
||||||
|
if (hasSilent(panelInfo.id)) {
|
||||||
|
removeSilent(panelInfo.id);
|
||||||
|
} else {
|
||||||
|
appendSilent(panelInfo.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedEvent.emit('groupPanelBadgeUpdate');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
regGroupPanelBadge({
|
||||||
|
name: `${PLUGIN_NAME}/grouppanelbadge`,
|
||||||
|
render: (groupId: string, panelId: string) => {
|
||||||
|
return hasSilent(panelId) ? <Icon icon="mdi:bell-off-outline" /> : null;
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* 免打扰
|
||||||
|
*/
|
||||||
|
|
||||||
|
const KEY = 'plugin:com.msgbyte.notify/slientStorage';
|
||||||
|
|
||||||
|
const silentSet = new Set<string>(loadFromLocalstorage());
|
||||||
|
|
||||||
|
export function appendSilent(converseId: string) {
|
||||||
|
silentSet.add(converseId);
|
||||||
|
saveToLocalstorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeSilent(converseId: string) {
|
||||||
|
silentSet.delete(converseId);
|
||||||
|
saveToLocalstorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasSilent(converseId: string): boolean {
|
||||||
|
return silentSet.has(converseId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveToLocalstorage() {
|
||||||
|
localStorage.setItem(KEY, JSON.stringify(Array.from(silentSet)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadFromLocalstorage(): string[] {
|
||||||
|
try {
|
||||||
|
const arr = JSON.parse(localStorage.getItem(KEY));
|
||||||
|
if (Array.isArray(arr)) {
|
||||||
|
return arr;
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
import { useParams } from 'react-router';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取群组面板的参数
|
|
||||||
*/
|
|
||||||
export function useGroupPanelParams(): {
|
|
||||||
groupId: string;
|
|
||||||
panelId: string;
|
|
||||||
} {
|
|
||||||
const { groupId = '', panelId = '' } = useParams<{
|
|
||||||
groupId: string;
|
|
||||||
panelId: string;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
return { groupId, panelId };
|
|
||||||
}
|
|
@ -0,0 +1,84 @@
|
|||||||
|
import {
|
||||||
|
pluginGroupPanelBadges,
|
||||||
|
pluginGroupTextPanelExtraMenus,
|
||||||
|
} from '@/plugin/common';
|
||||||
|
import { findPluginPanelInfoByName } from '@/utils/plugin-helper';
|
||||||
|
import type { ItemType } from 'antd/lib/menu/hooks/useItems';
|
||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { useParams } from 'react-router';
|
||||||
|
import { Icon } from 'tailchat-design';
|
||||||
|
import {
|
||||||
|
GroupPanel,
|
||||||
|
GroupPanelType,
|
||||||
|
isValidStr,
|
||||||
|
useSharedEventHandler,
|
||||||
|
} from 'tailchat-shared';
|
||||||
|
import { useUpdate } from 'ahooks';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群组面板的参数
|
||||||
|
*/
|
||||||
|
export function useGroupPanelParams(): {
|
||||||
|
groupId: string;
|
||||||
|
panelId: string;
|
||||||
|
} {
|
||||||
|
const { groupId = '', panelId = '' } = useParams<{
|
||||||
|
groupId: string;
|
||||||
|
panelId: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
return { groupId, panelId };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取来自插件的菜单项
|
||||||
|
*/
|
||||||
|
export function useExtraMenuItems(panel: GroupPanel): ItemType[] {
|
||||||
|
const extraMenuItems = useMemo(() => {
|
||||||
|
if (panel.type === GroupPanelType.TEXT) {
|
||||||
|
return pluginGroupTextPanelExtraMenus;
|
||||||
|
} else {
|
||||||
|
return isValidStr(panel.pluginPanelName)
|
||||||
|
? findPluginPanelInfoByName(panel.pluginPanelName)?.menus ?? []
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
}, [panel.type, panel.pluginPanelName]);
|
||||||
|
|
||||||
|
if (Array.isArray(extraMenuItems) && extraMenuItems.length > 0) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
},
|
||||||
|
...extraMenuItems.map((item) => ({
|
||||||
|
key: item.name,
|
||||||
|
label: item.label,
|
||||||
|
icon: item.icon ? <Icon icon={item.icon} /> : undefined,
|
||||||
|
onClick: () => item.onClick(panel),
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群组面板额外badge
|
||||||
|
*/
|
||||||
|
export function useGroupPanelExtraBadge(
|
||||||
|
groupId: string,
|
||||||
|
panelId: string
|
||||||
|
): React.ReactNode[] {
|
||||||
|
const update = useUpdate();
|
||||||
|
|
||||||
|
useSharedEventHandler('groupPanelBadgeUpdate', () => {
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
|
||||||
|
const extraBadge = pluginGroupPanelBadges.map((item) => (
|
||||||
|
<React.Fragment key={panelId + item.name}>
|
||||||
|
{item.render(groupId, panelId)}
|
||||||
|
</React.Fragment>
|
||||||
|
));
|
||||||
|
|
||||||
|
return extraBadge;
|
||||||
|
}
|
Loading…
Reference in New Issue