diff --git a/shared/hooks/model/useUserSettings.ts b/shared/hooks/model/useUserSettings.ts new file mode 100644 index 00000000..50749ee5 --- /dev/null +++ b/shared/hooks/model/useUserSettings.ts @@ -0,0 +1,55 @@ +import { useQuery, useQueryClient } from 'react-query'; +import { + getUserSettings, + setUserSettings, + UserSettings, +} from '../../model/user'; +import { useAsyncRequest } from '../useAsyncRequest'; + +/** + * 用户设置hooks + */ +export function useUserSettings() { + const client = useQueryClient(); + const { data: settings, isLoading } = useQuery( + ['useUserSettings'], + () => getUserSettings(), + { + staleTime: 1 * 60 * 1000, // 缓存1分钟 + } + ); + + const [{ loading: saveLoading }, setSettings] = useAsyncRequest( + async (settings: UserSettings) => { + const newSettings = await setUserSettings(settings); + + client.setQueryData(['useUserSettings'], () => newSettings); + }, + [client] + ); + + return { + settings: settings ?? {}, + setSettings, + loading: isLoading || saveLoading, + }; +} + +/** + * 单个用户设置 + */ +export function useSingleUserSetting( + name: keyof UserSettings, + defaultValue?: T +) { + const { settings, setSettings, loading } = useUserSettings(); + + return { + value: settings[name] ?? defaultValue, + setValue: async (newVal: T) => + setSettings({ + [name]: newVal, + }), + loading, + }; +} diff --git a/shared/i18n/langs/en-US/translation.json b/shared/i18n/langs/en-US/translation.json index 429516af..0b9c190c 100644 --- a/shared/i18n/langs/en-US/translation.json +++ b/shared/i18n/langs/en-US/translation.json @@ -11,6 +11,7 @@ "k1885734a": "Effective after refreshing the page", "k18c716ce": "Password cannot be less than 6 digits", "k19885be1": "Panel name is too long", + "k1a377364": "Message List Virtualization", "k1b38bb5c": "Register Now", "k1bd56481": "Close independent window", "k1cbe2507": "Confirm", diff --git a/shared/i18n/langs/zh-CN/translation.json b/shared/i18n/langs/zh-CN/translation.json index 333b1c95..ba46502b 100644 --- a/shared/i18n/langs/zh-CN/translation.json +++ b/shared/i18n/langs/zh-CN/translation.json @@ -11,6 +11,7 @@ "k1885734a": "刷新页面后生效", "k18c716ce": "密码不能低于6位", "k19885be1": "面板名过长", + "k1a377364": "聊天列表虚拟化", "k1b38bb5c": "立即注册", "k1bd56481": "关闭独立窗口", "k1cbe2507": "确认", diff --git a/shared/index.tsx b/shared/index.tsx index 13c1c425..167896ce 100644 --- a/shared/index.tsx +++ b/shared/index.tsx @@ -66,6 +66,10 @@ export { useLanguage } from './i18n/language'; // hooks export { useAvailableServices } from './hooks/model/useAvailableServices'; export { useUsernames } from './hooks/model/useUsernames'; +export { + useUserSettings, + useSingleUserSetting, +} from './hooks/model/useUserSettings'; export { useAsync } from './hooks/useAsync'; export { useAsyncFn } from './hooks/useAsyncFn'; export { useAsyncRefresh } from './hooks/useAsyncRefresh'; @@ -135,7 +139,7 @@ export type { SendMessagePayloadMeta, } from './model/message'; export type { PluginManifest } from './model/plugin'; -export type { UserBaseInfo, UserLoginInfo } from './model/user'; +export type { UserBaseInfo, UserLoginInfo, UserSettings } from './model/user'; export { loginWithEmail, loginWithToken, diff --git a/shared/model/user.ts b/shared/model/user.ts index db07ee89..3d690673 100644 --- a/shared/model/user.ts +++ b/shared/model/user.ts @@ -16,6 +16,13 @@ export interface UserLoginInfo extends UserBaseInfo { createdAt: string; } +export interface UserSettings { + /** + * 消息列表虚拟化 + */ + messageListVirtualization?: boolean; +} + // 内置用户信息 const builtinUserInfo: Record = { [SYSTEM_USERID]: { @@ -237,6 +244,28 @@ export async function modifyUserField( return data; } +/** + * 获取用户设置 + */ +export async function getUserSettings(): Promise { + const { data } = await request.get('/api/user/getUserSettings'); + + return data; +} + +/** + * 设置用户设置 + */ +export async function setUserSettings( + settings: UserSettings +): Promise { + const { data } = await request.post('/api/user/setUserSettings', { + settings, + }); + + return data; +} + /** * 检查Token是否可用 */ diff --git a/web/src/components/ChatBox/ChatMessageList/index.tsx b/web/src/components/ChatBox/ChatMessageList/index.tsx index 9d86017c..c3134ca7 100644 --- a/web/src/components/ChatBox/ChatMessageList/index.tsx +++ b/web/src/components/ChatBox/ChatMessageList/index.tsx @@ -1,12 +1,21 @@ +import { LoadingSpinner } from '@/components/LoadingSpinner'; import React from 'react'; +import { useSingleUserSetting } from 'tailchat-shared'; import { NormalMessageList } from './NormalList'; import type { MessageListProps } from './types'; import { VirtualizedMessageList } from './VirtualizedList'; -const useVirtualizedList = true; // 是否使用虚拟化列表 - export const ChatMessageList: React.FC = React.memo( (props) => { + const { value: useVirtualizedList, loading } = useSingleUserSetting( + 'messageListVirtualization', + false + ); + + if (loading) { + return ; + } + return useVirtualizedList ? (
diff --git a/web/src/components/modals/SettingsView/System.tsx b/web/src/components/modals/SettingsView/System.tsx index 3a322c1a..f158bbdc 100644 --- a/web/src/components/modals/SettingsView/System.tsx +++ b/web/src/components/modals/SettingsView/System.tsx @@ -1,13 +1,23 @@ import { FullModalField } from '@/components/FullModal/Field'; import { pluginColorScheme } from '@/plugin/common'; -import { Select } from 'antd'; +import { Select, Switch } from 'antd'; import React, { useCallback } from 'react'; -import { showToasts, t, useColorScheme } from 'tailchat-shared'; +import { + showToasts, + t, + useColorScheme, + useSingleUserSetting, +} from 'tailchat-shared'; import { useLanguage } from 'tailchat-shared'; export const SettingsSystem: React.FC = React.memo(() => { const { language, setLanguage } = useLanguage(); const { colorScheme, setColorScheme } = useColorScheme(); + const { + value: messageListVirtualization, + setValue: setMessageListVirtualization, + loading, + } = useSingleUserSetting('messageListVirtualization', false); const handleChangeLanguage = useCallback( (newLang: string) => { @@ -54,6 +64,17 @@ export const SettingsSystem: React.FC = React.memo(() => { } /> + + setMessageListVirtualization(checked)} + /> + } + />
); });