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