From cb7ccf8c774a8c8ab877ddd65667af1db03cc488 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Thu, 31 Mar 2022 00:10:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E8=99=9A=E6=8B=9F=E5=8C=96=E4=B8=8E=E4=B8=AA=E4=BA=BA=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shared/hooks/model/useUserSettings.ts | 55 +++++++++++++++++++ shared/i18n/langs/en-US/translation.json | 1 + shared/i18n/langs/zh-CN/translation.json | 1 + shared/index.tsx | 6 +- shared/model/user.ts | 29 ++++++++++ .../ChatBox/ChatMessageList/index.tsx | 13 ++++- .../components/modals/SettingsView/System.tsx | 25 ++++++++- 7 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 shared/hooks/model/useUserSettings.ts 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)} + /> + } + />
); });