refactor: enhance preference management and update mappings

- Updated preferences to utilize the new SendMessageShortcut type for better type safety.
- Refactored components to use the usePreference hook instead of useSettings for improved preference handling.
- Added new preferences for target language and send message shortcut in various components.
- Cleaned up unused code and comments related to settings for better maintainability.
- Updated auto-generated preference mappings to reflect recent changes in preference structure.
This commit is contained in:
fullex 2025-09-02 13:24:41 +08:00
parent 5cc7390bb6
commit 0a67ab4103
16 changed files with 184 additions and 139 deletions

View File

@ -38,3 +38,5 @@ export enum ThemeMode {
export type LanguageVarious = 'zh-CN' | 'zh-TW' | 'el-GR' | 'en-US' | 'es-ES' | 'fr-FR' | 'ja-JP' | 'pt-PT' | 'ru-RU' export type LanguageVarious = 'zh-CN' | 'zh-TW' | 'el-GR' | 'en-US' | 'es-ES' | 'fr-FR' | 'ja-JP' | 'pt-PT' | 'ru-RU'
export type WindowStyle = 'transparent' | 'opaque' export type WindowStyle = 'transparent' | 'opaque'
export type SendMessageShortcut = 'Enter' | 'Shift+Enter' | 'Ctrl+Enter' | 'Command+Enter' | 'Alt+Enter'

View File

@ -1,6 +1,6 @@
/** /**
* Auto-generated preferences configuration * Auto-generated preferences configuration
* Generated at: 2025-09-02T02:45:09.198Z * Generated at: 2025-09-02T04:48:55.916Z
* *
* This file is automatically generated from classification.json * This file is automatically generated from classification.json
* To update this file, modify classification.json and run: * To update this file, modify classification.json and run:
@ -14,6 +14,7 @@ import type {
SelectionActionItem, SelectionActionItem,
SelectionFilterMode, SelectionFilterMode,
SelectionTriggerMode, SelectionTriggerMode,
SendMessageShortcut,
WindowStyle WindowStyle
} from '@shared/data/preferenceTypes' } from '@shared/data/preferenceTypes'
import { LanguageVarious, ThemeMode } from '@shared/data/preferenceTypes' import { LanguageVarious, ThemeMode } from '@shared/data/preferenceTypes'
@ -116,7 +117,7 @@ export interface PreferencesType {
// redux/settings/enableQuickPanelTriggers // redux/settings/enableQuickPanelTriggers
'chat.input.quick_panel.triggers_enabled': boolean 'chat.input.quick_panel.triggers_enabled': boolean
// redux/settings/sendMessageShortcut // redux/settings/sendMessageShortcut
'chat.input.send_message_shortcut': string 'chat.input.send_message_shortcut': SendMessageShortcut
// redux/settings/showInputEstimatedTokens // redux/settings/showInputEstimatedTokens
'chat.input.show_estimated_tokens': boolean 'chat.input.show_estimated_tokens': boolean
// redux/settings/autoTranslateWithSpace // redux/settings/autoTranslateWithSpace
@ -143,8 +144,6 @@ export interface PreferencesType {
'chat.message.show_divider': boolean 'chat.message.show_divider': boolean
// redux/settings/showPrompt // redux/settings/showPrompt
'chat.message.show_prompt': boolean 'chat.message.show_prompt': boolean
// redux/settings/showTokens
'chat.message.show_tokens': boolean
// redux/settings/messageStyle // redux/settings/messageStyle
'chat.message.style': string 'chat.message.style': string
// redux/settings/thoughtAutoCollapse // redux/settings/thoughtAutoCollapse
@ -321,6 +320,8 @@ export interface PreferencesType {
'feature.selection.trigger_mode': SelectionTriggerMode 'feature.selection.trigger_mode': SelectionTriggerMode
// redux/settings/translateModelPrompt // redux/settings/translateModelPrompt
'feature.translate.model_prompt': string 'feature.translate.model_prompt': string
// redux/settings/targetLanguage
'feature.translate.target_language': string
// redux/shortcuts/shortcuts.exit_fullscreen // redux/shortcuts/shortcuts.exit_fullscreen
'shortcut.app.exit_fullscreen': Record<string, unknown> 'shortcut.app.exit_fullscreen': Record<string, unknown>
// redux/shortcuts/shortcuts.search_message // redux/shortcuts/shortcuts.search_message
@ -436,7 +437,6 @@ export const DefaultPreferences: PreferencesType = {
'chat.message.navigation_mode': 'none', 'chat.message.navigation_mode': 'none',
'chat.message.show_divider': true, 'chat.message.show_divider': true,
'chat.message.show_prompt': true, 'chat.message.show_prompt': true,
'chat.message.show_tokens': true,
'chat.message.style': 'plain', 'chat.message.style': 'plain',
'chat.message.thought.auto_collapse': true, 'chat.message.thought.auto_collapse': true,
'chat.narrow_mode': false, 'chat.narrow_mode': false,
@ -552,6 +552,7 @@ export const DefaultPreferences: PreferencesType = {
'feature.selection.remember_win_size': false, 'feature.selection.remember_win_size': false,
'feature.selection.trigger_mode': 'selected', 'feature.selection.trigger_mode': 'selected',
'feature.translate.model_prompt': TRANSLATE_PROMPT, 'feature.translate.model_prompt': TRANSLATE_PROMPT,
'feature.translate.target_language': 'en-us',
'shortcut.app.exit_fullscreen': { editable: false, enabled: true, key: ['Escape'], system: true }, 'shortcut.app.exit_fullscreen': { editable: false, enabled: true, key: ['Escape'], system: true },
'shortcut.app.search_message': { 'shortcut.app.search_message': {
editable: true, editable: true,

View File

@ -1,6 +1,6 @@
/** /**
* Auto-generated preference mappings from classification.json * Auto-generated preference mappings from classification.json
* Generated at: 2025-09-01T14:38:08.063Z * Generated at: 2025-09-02T05:21:08.374Z
* *
* This file contains pure mapping relationships without default values. * This file contains pure mapping relationships without default values.
* Default values are managed in packages/shared/data/preferences.ts * Default values are managed in packages/shared/data/preferences.ts
@ -14,10 +14,6 @@
* ElectronStore没有嵌套originalKey直接对应configManager.get(key) * ElectronStore没有嵌套originalKey直接对应configManager.get(key)
*/ */
export const ELECTRON_STORE_MAPPINGS = [ export const ELECTRON_STORE_MAPPINGS = [
{
originalKey: 'Language',
targetKey: 'app.language'
},
{ {
originalKey: 'ZoomFactor', originalKey: 'ZoomFactor',
targetKey: 'app.zoom_factor' targetKey: 'app.zoom_factor'
@ -58,6 +54,10 @@ export const REDUX_STORE_MAPPINGS = {
originalKey: 'enableQuickAssistant', originalKey: 'enableQuickAssistant',
targetKey: 'feature.quick_assistant.enabled' targetKey: 'feature.quick_assistant.enabled'
}, },
{
originalKey: 'language',
targetKey: 'app.language'
},
{ {
originalKey: 'launchToTray', originalKey: 'launchToTray',
targetKey: 'app.tray.on_launch' targetKey: 'app.tray.on_launch'
@ -86,6 +86,10 @@ export const REDUX_STORE_MAPPINGS = {
originalKey: 'sendMessageShortcut', originalKey: 'sendMessageShortcut',
targetKey: 'chat.input.send_message_shortcut' targetKey: 'chat.input.send_message_shortcut'
}, },
{
originalKey: 'targetLanguage',
targetKey: 'feature.translate.target_language'
},
{ {
originalKey: 'proxyMode', originalKey: 'proxyMode',
targetKey: 'app.proxy.mode' targetKey: 'app.proxy.mode'
@ -110,10 +114,6 @@ export const REDUX_STORE_MAPPINGS = {
originalKey: 'showPrompt', originalKey: 'showPrompt',
targetKey: 'chat.message.show_prompt' targetKey: 'chat.message.show_prompt'
}, },
{
originalKey: 'showTokens',
targetKey: 'chat.message.show_tokens'
},
{ {
originalKey: 'showMessageDivider', originalKey: 'showMessageDivider',
targetKey: 'chat.message.show_divider' targetKey: 'chat.message.show_divider'
@ -180,7 +180,7 @@ export const REDUX_STORE_MAPPINGS = {
}, },
{ {
originalKey: 'codeEditor.enabled', originalKey: 'codeEditor.enabled',
targetKey: 'chat.code.editor.highlight_active_line' targetKey: 'chat.code.editor.enabled'
}, },
{ {
originalKey: 'codeEditor.themeLight', originalKey: 'codeEditor.themeLight',
@ -190,6 +190,10 @@ export const REDUX_STORE_MAPPINGS = {
originalKey: 'codeEditor.themeDark', originalKey: 'codeEditor.themeDark',
targetKey: 'chat.code.editor.theme_dark' targetKey: 'chat.code.editor.theme_dark'
}, },
{
originalKey: 'codeEditor.highlightActiveLine',
targetKey: 'chat.code.editor.highlight_active_line'
},
{ {
originalKey: 'codeEditor.foldGutter', originalKey: 'codeEditor.foldGutter',
targetKey: 'chat.code.editor.fold_gutter' targetKey: 'chat.code.editor.fold_gutter'
@ -298,6 +302,10 @@ export const REDUX_STORE_MAPPINGS = {
originalKey: 'webdavDisableStream', originalKey: 'webdavDisableStream',
targetKey: 'data.backup.webdav.disable_stream' targetKey: 'data.backup.webdav.disable_stream'
}, },
{
originalKey: 'translateModelPrompt',
targetKey: 'feature.translate.model_prompt'
},
{ {
originalKey: 'autoTranslateWithSpace', originalKey: 'autoTranslateWithSpace',
targetKey: 'chat.input.translate.auto_translate_with_space' targetKey: 'chat.input.translate.auto_translate_with_space'
@ -723,10 +731,10 @@ export const REDUX_STORE_MAPPINGS = {
/** /**
* : * :
* - ElectronStore项: 2 * - ElectronStore项: 1
* - Redux Store项: 169 * - Redux Store项: 172
* - Redux分类: settings, selectionStore, nutstore, shortcuts * - Redux分类: settings, selectionStore, nutstore, shortcuts
* - 总配置项: 171 * - 总配置项: 173
* *
* 使: * 使:
* 1. ElectronStore读取: configManager.get(mapping.originalKey) * 1. ElectronStore读取: configManager.get(mapping.originalKey)

View File

@ -1,3 +1,4 @@
import { usePreference } from '@data/hooks/usePreference'
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { ActionTool } from '@renderer/components/ActionTools' import { ActionTool } from '@renderer/components/ActionTools'
import CodeEditor, { CodeEditorHandles } from '@renderer/components/CodeEditor' import CodeEditor, { CodeEditorHandles } from '@renderer/components/CodeEditor'
@ -16,7 +17,6 @@ import CodeViewer from '@renderer/components/CodeViewer'
import ImageViewer from '@renderer/components/ImageViewer' import ImageViewer from '@renderer/components/ImageViewer'
import { BasicPreviewHandles } from '@renderer/components/Preview' import { BasicPreviewHandles } from '@renderer/components/Preview'
import { MAX_COLLAPSED_CODE_HEIGHT } from '@renderer/config/constant' import { MAX_COLLAPSED_CODE_HEIGHT } from '@renderer/config/constant'
import { useSettings } from '@renderer/hooks/useSettings'
import { pyodideService } from '@renderer/services/PyodideService' import { pyodideService } from '@renderer/services/PyodideService'
import { getExtensionByLanguage } from '@renderer/utils/code-language' import { getExtensionByLanguage } from '@renderer/utils/code-language'
import { extractHtmlTitle } from '@renderer/utils/formats' import { extractHtmlTitle } from '@renderer/utils/formats'
@ -28,7 +28,6 @@ import styled, { css } from 'styled-components'
import { SPECIAL_VIEW_COMPONENTS, SPECIAL_VIEWS } from './constants' import { SPECIAL_VIEW_COMPONENTS, SPECIAL_VIEWS } from './constants'
import StatusBar from './StatusBar' import StatusBar from './StatusBar'
import { ViewMode } from './types' import { ViewMode } from './types'
const logger = loggerService.withContext('CodeBlockView') const logger = loggerService.withContext('CodeBlockView')
interface Props { interface Props {
@ -55,7 +54,13 @@ interface Props {
*/ */
export const CodeBlockView: React.FC<Props> = memo(({ children, language, onSave }) => { export const CodeBlockView: React.FC<Props> = memo(({ children, language, onSave }) => {
const { t } = useTranslation() const { t } = useTranslation()
const { codeEditor, codeExecution, codeImageTools, codeCollapsible, codeWrappable } = useSettings()
const [codeEditorEnabled] = usePreference('chat.code.editor.enabled')
const [codeExecutionEnabled] = usePreference('chat.code.execution.enabled')
const [codeExecutionTimeoutMinutes] = usePreference('chat.code.execution.timeout_minutes')
const [codeCollapsible] = usePreference('chat.code.collapsible')
const [codeWrappable] = usePreference('chat.code.wrappable')
const [codeImageTools] = usePreference('chat.code.image_tools')
const [viewState, setViewState] = useState({ const [viewState, setViewState] = useState({
mode: 'special' as ViewMode, mode: 'special' as ViewMode,
@ -87,8 +92,8 @@ export const CodeBlockView: React.FC<Props> = memo(({ children, language, onSave
const [tools, setTools] = useState<ActionTool[]>([]) const [tools, setTools] = useState<ActionTool[]>([])
const isExecutable = useMemo(() => { const isExecutable = useMemo(() => {
return codeExecution.enabled && language === 'python' return codeExecutionEnabled && language === 'python'
}, [codeExecution.enabled, language]) }, [codeExecutionEnabled, language])
const sourceViewRef = useRef<CodeEditorHandles>(null) const sourceViewRef = useRef<CodeEditorHandles>(null)
const specialViewRef = useRef<BasicPreviewHandles>(null) const specialViewRef = useRef<BasicPreviewHandles>(null)
@ -153,7 +158,7 @@ export const CodeBlockView: React.FC<Props> = memo(({ children, language, onSave
setExecutionResult(null) setExecutionResult(null)
pyodideService pyodideService
.runScript(children, {}, codeExecution.timeoutMinutes * 60000) .runScript(children, {}, codeExecutionTimeoutMinutes * 60000)
.then((result) => { .then((result) => {
setExecutionResult(result) setExecutionResult(result)
}) })
@ -166,7 +171,7 @@ export const CodeBlockView: React.FC<Props> = memo(({ children, language, onSave
.finally(() => { .finally(() => {
setIsRunning(false) setIsRunning(false)
}) })
}, [children, codeExecution.timeoutMinutes]) }, [children, codeExecutionTimeoutMinutes])
const showPreviewTools = useMemo(() => { const showPreviewTools = useMemo(() => {
return viewMode !== 'source' && hasSpecialView return viewMode !== 'source' && hasSpecialView
@ -191,7 +196,7 @@ export const CodeBlockView: React.FC<Props> = memo(({ children, language, onSave
// 特殊视图的编辑/查看源码按钮,在分屏模式下不可用 // 特殊视图的编辑/查看源码按钮,在分屏模式下不可用
useViewSourceTool({ useViewSourceTool({
enabled: hasSpecialView, enabled: hasSpecialView,
editable: codeEditor.enabled, editable: codeEditorEnabled,
viewMode, viewMode,
onViewModeChange: setViewMode, onViewModeChange: setViewMode,
setTools setTools
@ -233,7 +238,7 @@ export const CodeBlockView: React.FC<Props> = memo(({ children, language, onSave
// 代码编辑器的保存按钮 // 代码编辑器的保存按钮
useSaveTool({ useSaveTool({
enabled: codeEditor.enabled && !isInSpecialView, enabled: codeEditorEnabled && !isInSpecialView,
sourceViewRef, sourceViewRef,
setTools setTools
}) })
@ -241,7 +246,7 @@ export const CodeBlockView: React.FC<Props> = memo(({ children, language, onSave
// 源代码视图组件 // 源代码视图组件
const sourceView = useMemo( const sourceView = useMemo(
() => () =>
codeEditor.enabled ? ( codeEditorEnabled ? (
<CodeEditor <CodeEditor
className="source-view" className="source-view"
ref={sourceViewRef} ref={sourceViewRef}
@ -264,7 +269,7 @@ export const CodeBlockView: React.FC<Props> = memo(({ children, language, onSave
{children} {children}
</CodeViewer> </CodeViewer>
), ),
[children, codeEditor.enabled, handleHeightChange, language, onSave, shouldExpand, shouldWrap] [children, codeEditorEnabled, handleHeightChange, language, onSave, shouldExpand, shouldWrap]
) )
// 特殊视图组件映射 // 特殊视图组件映射

View File

@ -1,5 +1,5 @@
import { useMultiplePreferences, usePreference } from '@data/hooks/usePreference'
import { useCodeStyle } from '@renderer/context/CodeStyleProvider' import { useCodeStyle } from '@renderer/context/CodeStyleProvider'
import { useSettings } from '@renderer/hooks/useSettings'
import CodeMirror, { Annotation, BasicSetupOptions, EditorView, Extension } from '@uiw/react-codemirror' import CodeMirror, { Annotation, BasicSetupOptions, EditorView, Extension } from '@uiw/react-codemirror'
import diff from 'fast-diff' import diff from 'fast-diff'
import { useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react' import { useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react'
@ -117,7 +117,17 @@ const CodeEditor = ({
expanded = true, expanded = true,
wrapped = true wrapped = true
}: CodeEditorProps) => { }: CodeEditorProps) => {
const { fontSize: _fontSize, codeShowLineNumbers: _lineNumbers, codeEditor } = useSettings() const [_fontSize] = usePreference('chat.message.font_size')
const [_lineNumbers] = usePreference('chat.code.show_line_numbers')
const [codeEditor] = useMultiplePreferences({
autocompletion: 'chat.code.editor.autocompletion',
foldGutter: 'chat.code.editor.fold_gutter',
highlightActiveLine: 'chat.code.editor.highlight_active_line',
keymap: 'chat.code.editor.keymap',
themeLight: 'chat.code.editor.theme_light',
themeDark: 'chat.code.editor.theme_dark'
})
const enableKeymap = useMemo(() => options?.keymap ?? codeEditor.keymap, [options?.keymap, codeEditor.keymap]) const enableKeymap = useMemo(() => options?.keymap ?? codeEditor.keymap, [options?.keymap, codeEditor.keymap])
// 合并 codeEditor 和 options 的 basicSetupoptions 优先 // 合并 codeEditor 和 options 的 basicSetupoptions 优先

View File

@ -1,7 +1,7 @@
import { usePreference } from '@data/hooks/usePreference'
import { MAX_COLLAPSED_CODE_HEIGHT } from '@renderer/config/constant' import { MAX_COLLAPSED_CODE_HEIGHT } from '@renderer/config/constant'
import { useCodeStyle } from '@renderer/context/CodeStyleProvider' import { useCodeStyle } from '@renderer/context/CodeStyleProvider'
import { useCodeHighlight } from '@renderer/hooks/useCodeHighlight' import { useCodeHighlight } from '@renderer/hooks/useCodeHighlight'
import { useSettings } from '@renderer/hooks/useSettings'
import { uuid } from '@renderer/utils' import { uuid } from '@renderer/utils'
import { getReactStyleFromToken } from '@renderer/utils/shiki' import { getReactStyleFromToken } from '@renderer/utils/shiki'
import { useVirtualizer } from '@tanstack/react-virtual' import { useVirtualizer } from '@tanstack/react-virtual'
@ -27,7 +27,8 @@ interface CodeViewerProps {
* - * -
*/ */
const CodeViewer = ({ children, language, expanded, wrapped, onHeightChange, className, height }: CodeViewerProps) => { const CodeViewer = ({ children, language, expanded, wrapped, onHeightChange, className, height }: CodeViewerProps) => {
const { codeShowLineNumbers, fontSize } = useSettings() const [codeShowLineNumbers] = usePreference('chat.code.show_line_numbers')
const [fontSize] = usePreference('chat.message.font_size')
const { getShikiPreProperties, isShikiThemeDark } = useCodeStyle() const { getShikiPreProperties, isShikiThemeDark } = useCodeStyle()
const shikiThemeRef = useRef<HTMLDivElement>(null) const shikiThemeRef = useRef<HTMLDivElement>(null)
const scrollerRef = useRef<HTMLDivElement>(null) const scrollerRef = useRef<HTMLDivElement>(null)

View File

@ -1,6 +1,6 @@
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import { usePreference } from '@data/hooks/usePreference'
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { useSettings } from '@renderer/hooks/useSettings'
import useTranslate from '@renderer/hooks/useTranslate' import useTranslate from '@renderer/hooks/useTranslate'
import { translateText } from '@renderer/services/TranslateService' import { translateText } from '@renderer/services/TranslateService'
import { Modal, ModalProps } from 'antd' import { Modal, ModalProps } from 'antd'
@ -42,7 +42,8 @@ const PopupContainer: React.FC<Props> = ({
const [textValue, setTextValue] = useState(text) const [textValue, setTextValue] = useState(text)
const [isTranslating, setIsTranslating] = useState(false) const [isTranslating, setIsTranslating] = useState(false)
const textareaRef = useRef<TextAreaRef>(null) const textareaRef = useRef<TextAreaRef>(null)
const { targetLanguage, showTranslateConfirm } = useSettings() const [targetLanguage] = usePreference('feature.translate.target_language')
const [showTranslateConfirm] = usePreference('chat.input.translate.show_confirm')
const isMounted = useRef(true) const isMounted = useRef(true)
useEffect(() => { useEffect(() => {

View File

@ -1,6 +1,6 @@
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import { usePreference } from '@data/hooks/usePreference'
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { useSettings } from '@renderer/hooks/useSettings'
import useTranslate from '@renderer/hooks/useTranslate' import useTranslate from '@renderer/hooks/useTranslate'
import { translateText } from '@renderer/services/TranslateService' import { translateText } from '@renderer/services/TranslateService'
import { Button, Tooltip } from 'antd' import { Button, Tooltip } from 'antd'
@ -22,7 +22,8 @@ const logger = loggerService.withContext('TranslateButton')
const TranslateButton: FC<Props> = ({ text, onTranslated, disabled, style, isLoading }) => { const TranslateButton: FC<Props> = ({ text, onTranslated, disabled, style, isLoading }) => {
const { t } = useTranslation() const { t } = useTranslation()
const [isTranslating, setIsTranslating] = useState(false) const [isTranslating, setIsTranslating] = useState(false)
const { targetLanguage, showTranslateConfirm } = useSettings() const [targetLanguage] = usePreference('feature.translate.target_language')
const [showTranslateConfirm] = usePreference('chat.input.translate.show_confirm')
const { getLanguageByLangcode } = useTranslate() const { getLanguageByLangcode } = useTranslate()
const translateConfirm = () => { const translateConfirm = () => {

View File

@ -30,13 +30,14 @@ export function useAppInit() {
const { const {
proxyUrl, proxyUrl,
proxyBypassRules, proxyBypassRules,
language, // language,
// windowStyle, // windowStyle,
autoCheckUpdate, autoCheckUpdate,
proxyMode, proxyMode,
// customCss, // customCss,
enableDataCollection enableDataCollection
} = useSettings() } = useSettings()
const [language] = usePreference('app.language')
const [windowStyle] = usePreference('app.theme.window_style') const [windowStyle] = usePreference('app.theme.window_style')
const [customCss] = usePreference('ui.custom_css') const [customCss] = usePreference('ui.custom_css')

View File

@ -1,7 +1,6 @@
import store, { useAppDispatch, useAppSelector } from '@renderer/store' import store, { useAppDispatch, useAppSelector } from '@renderer/store'
import { import {
AssistantIconType, AssistantIconType,
SendMessageShortcut,
setAssistantIconType, setAssistantIconType,
setAutoCheckUpdate as _setAutoCheckUpdate, setAutoCheckUpdate as _setAutoCheckUpdate,
// setDisableHardwareAcceleration, // setDisableHardwareAcceleration,
@ -22,6 +21,7 @@ import {
} from '@renderer/store/settings' } from '@renderer/store/settings'
import { SidebarIcon, TranslateLanguageCode } from '@renderer/types' import { SidebarIcon, TranslateLanguageCode } from '@renderer/types'
import { UpgradeChannel } from '@shared/config/constant' import { UpgradeChannel } from '@shared/config/constant'
import type { SendMessageShortcut } from '@shared/data/preferenceTypes'
export function useSettings() { export function useSettings() {
const settings = useAppSelector((state) => state.settings) const settings = useAppSelector((state) => state.settings)

View File

@ -1,4 +1,5 @@
import { HolderOutlined } from '@ant-design/icons' import { HolderOutlined } from '@ant-design/icons'
import { usePreference } from '@data/hooks/usePreference'
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { QuickPanelView, useQuickPanel } from '@renderer/components/QuickPanel' import { QuickPanelView, useQuickPanel } from '@renderer/components/QuickPanel'
import TranslateButton from '@renderer/components/TranslateButton' import TranslateButton from '@renderer/components/TranslateButton'
@ -18,7 +19,6 @@ import { useAssistant } from '@renderer/hooks/useAssistant'
import { useKnowledgeBases } from '@renderer/hooks/useKnowledge' import { useKnowledgeBases } from '@renderer/hooks/useKnowledge'
import { useMessageOperations, useTopicLoading } from '@renderer/hooks/useMessageOperations' import { useMessageOperations, useTopicLoading } from '@renderer/hooks/useMessageOperations'
import { modelGenerating, useRuntime } from '@renderer/hooks/useRuntime' import { modelGenerating, useRuntime } from '@renderer/hooks/useRuntime'
import { useSettings } from '@renderer/hooks/useSettings'
import { useShortcut, useShortcutDisplay } from '@renderer/hooks/useShortcuts' import { useShortcut, useShortcutDisplay } from '@renderer/hooks/useShortcuts'
import { useSidebarIconShow } from '@renderer/hooks/useSidebarIcon' import { useSidebarIconShow } from '@renderer/hooks/useSidebarIcon'
import { useTimer } from '@renderer/hooks/useTimer' import { useTimer } from '@renderer/hooks/useTimer'
@ -75,20 +75,20 @@ let _text = ''
let _files: FileType[] = [] let _files: FileType[] = []
const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) => { const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) => {
const [targetLanguage] = usePreference('feature.translate.target_language')
const [sendMessageShortcut] = usePreference('chat.input.send_message_shortcut')
const [pasteLongTextAsFile] = usePreference('chat.input.paste_long_text_as_file')
const [pasteLongTextThreshold] = usePreference('chat.input.paste_long_text_threshold')
const [showInputEstimatedTokens] = usePreference('chat.input.show_estimated_tokens')
const [autoTranslateWithSpace] = usePreference('chat.input.translate.auto_translate_with_space')
const [enableQuickPanelTriggers] = usePreference('chat.input.quick_panel.triggers_enabled')
const [enableSpellCheck] = usePreference('app.spell_check.enabled')
const [fontSize] = usePreference('chat.message.font_size')
const [text, setText] = useState(_text) const [text, setText] = useState(_text)
const [inputFocus, setInputFocus] = useState(false) const [inputFocus, setInputFocus] = useState(false)
const { assistant, addTopic, model, setModel, updateAssistant } = useAssistant(_assistant.id) const { assistant, addTopic, model, setModel, updateAssistant } = useAssistant(_assistant.id)
const {
targetLanguage,
sendMessageShortcut,
fontSize,
pasteLongTextAsFile,
pasteLongTextThreshold,
showInputEstimatedTokens,
autoTranslateWithSpace,
enableQuickPanelTriggers,
enableSpellCheck
} = useSettings()
const [expanded, setExpand] = useState(false) const [expanded, setExpand] = useState(false)
const [estimateTokenCount, setEstimateTokenCount] = useState(0) const [estimateTokenCount, setEstimateTokenCount] = useState(0)
const [contextCount, setContextCount] = useState({ current: 0, max: 0 }) const [contextCount, setContextCount] = useState({ current: 0, max: 0 })

View File

@ -17,7 +17,6 @@ import { CollapsibleSettingGroup } from '@renderer/pages/settings/SettingGroup'
import { getDefaultModel } from '@renderer/services/AssistantService' import { getDefaultModel } from '@renderer/services/AssistantService'
import { useAppDispatch } from '@renderer/store' import { useAppDispatch } from '@renderer/store'
import { import {
SendMessageShortcut,
setAutoTranslateWithSpace, setAutoTranslateWithSpace,
setCodeCollapsible, setCodeCollapsible,
setCodeEditor, setCodeEditor,
@ -48,6 +47,7 @@ import {
import { Assistant, AssistantSettings, CodeStyleVarious, MathEngine } from '@renderer/types' import { Assistant, AssistantSettings, CodeStyleVarious, MathEngine } from '@renderer/types'
import { modalConfirm } from '@renderer/utils' import { modalConfirm } from '@renderer/utils'
import { getSendMessageShortcutLabel } from '@renderer/utils/input' import { getSendMessageShortcutLabel } from '@renderer/utils/input'
import type { SendMessageShortcut } from '@shared/data/preferenceTypes'
import { ThemeMode } from '@shared/data/preferenceTypes' import { ThemeMode } from '@shared/data/preferenceTypes'
import { Button, Col, InputNumber, Row, Slider, Switch, Tooltip } from 'antd' import { Button, Col, InputNumber, Row, Slider, Switch, Tooltip } from 'antd'
import { CircleHelp, Settings2 } from 'lucide-react' import { CircleHelp, Settings2 } from 'lucide-react'

View File

@ -1,89 +1,103 @@
// import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { createSlice, PayloadAction } from '@reduxjs/toolkit'
// import { SelectionActionItem, FilterMode, SelectionState, TriggerMode } from '@shared/data/preferenceTypes' import type { SelectionActionItem, SelectionFilterMode, SelectionTriggerMode } from '@shared/data/preferenceTypes'
// export const defaultActionItems: ActionItem[] = [ interface SelectionState {
// { id: 'translate', name: 'selection.action.builtin.translate', enabled: true, isBuiltIn: true, icon: 'languages' }, selectionEnabled: boolean
// { id: 'explain', name: 'selection.action.builtin.explain', enabled: true, isBuiltIn: true, icon: 'file-question' }, triggerMode: SelectionTriggerMode
// { id: 'summary', name: 'selection.action.builtin.summary', enabled: true, isBuiltIn: true, icon: 'scan-text' }, isCompact: boolean
// { isAutoClose: boolean
// id: 'search', isAutoPin: boolean
// name: 'selection.action.builtin.search', isFollowToolbar: boolean
// enabled: true, isRemeberWinSize: boolean
// isBuiltIn: true, filterMode: SelectionFilterMode
// icon: 'search', filterList: string[]
// searchEngine: 'Google|https://www.google.com/search?q={{queryString}}' actionWindowOpacity: number
// }, actionItems: SelectionActionItem[]
// { id: 'copy', name: 'selection.action.builtin.copy', enabled: true, isBuiltIn: true, icon: 'clipboard-copy' }, }
// { id: 'refine', name: 'selection.action.builtin.refine', enabled: false, isBuiltIn: true, icon: 'wand-sparkles' },
// { id: 'quote', name: 'selection.action.builtin.quote', enabled: false, isBuiltIn: true, icon: 'quote' }
// ]
// export const initialState: SelectionState = { export const defaultActionItems: SelectionActionItem[] = [
// selectionEnabled: false, { id: 'translate', name: 'selection.action.builtin.translate', enabled: true, isBuiltIn: true, icon: 'languages' },
// triggerMode: 'selected', { id: 'explain', name: 'selection.action.builtin.explain', enabled: true, isBuiltIn: true, icon: 'file-question' },
// isCompact: false, { id: 'summary', name: 'selection.action.builtin.summary', enabled: true, isBuiltIn: true, icon: 'scan-text' },
// isAutoClose: false, {
// isAutoPin: false, id: 'search',
// isFollowToolbar: true, name: 'selection.action.builtin.search',
// isRemeberWinSize: false, enabled: true,
// filterMode: 'default', isBuiltIn: true,
// filterList: [], icon: 'search',
// actionWindowOpacity: 100, searchEngine: 'Google|https://www.google.com/search?q={{queryString}}'
// actionItems: defaultActionItems },
// } { id: 'copy', name: 'selection.action.builtin.copy', enabled: true, isBuiltIn: true, icon: 'clipboard-copy' },
{ id: 'refine', name: 'selection.action.builtin.refine', enabled: false, isBuiltIn: true, icon: 'wand-sparkles' },
{ id: 'quote', name: 'selection.action.builtin.quote', enabled: false, isBuiltIn: true, icon: 'quote' }
]
// const selectionSlice = createSlice({ export const initialState: SelectionState = {
// name: 'selectionStore', selectionEnabled: false,
// initialState, triggerMode: 'selected',
// reducers: { isCompact: false,
// setSelectionEnabled: (state, action: PayloadAction<boolean>) => { isAutoClose: false,
// state.selectionEnabled = action.payload isAutoPin: false,
// }, isFollowToolbar: true,
// setTriggerMode: (state, action: PayloadAction<TriggerMode>) => { isRemeberWinSize: false,
// state.triggerMode = action.payload filterMode: 'default',
// }, filterList: [],
// setIsCompact: (state, action: PayloadAction<boolean>) => { actionWindowOpacity: 100,
// state.isCompact = action.payload actionItems: defaultActionItems
// }, }
// setIsAutoClose: (state, action: PayloadAction<boolean>) => {
// state.isAutoClose = action.payload
// },
// setIsAutoPin: (state, action: PayloadAction<boolean>) => {
// state.isAutoPin = action.payload
// },
// setIsFollowToolbar: (state, action: PayloadAction<boolean>) => {
// state.isFollowToolbar = action.payload
// },
// setIsRemeberWinSize: (state, action: PayloadAction<boolean>) => {
// state.isRemeberWinSize = action.payload
// },
// setFilterMode: (state, action: PayloadAction<FilterMode>) => {
// state.filterMode = action.payload
// },
// setFilterList: (state, action: PayloadAction<string[]>) => {
// state.filterList = action.payload
// },
// setActionWindowOpacity: (state, action: PayloadAction<number>) => {
// state.actionWindowOpacity = action.payload
// },
// setActionItems: (state, action: PayloadAction<ActionItem[]>) => {
// state.actionItems = action.payload
// }
// }
// })
// export const { const selectionSlice = createSlice({
// setSelectionEnabled, name: 'selectionStore',
// setTriggerMode, initialState,
// setIsCompact, reducers: {
// setIsAutoClose, setSelectionEnabled: (state, action: PayloadAction<boolean>) => {
// setIsAutoPin, state.selectionEnabled = action.payload
// setIsFollowToolbar, },
// setIsRemeberWinSize, setTriggerMode: (state, action: PayloadAction<SelectionTriggerMode>) => {
// setFilterMode, state.triggerMode = action.payload
// setFilterList, },
// setActionWindowOpacity, setIsCompact: (state, action: PayloadAction<boolean>) => {
// setActionItems state.isCompact = action.payload
// } = selectionSlice.actions },
setIsAutoClose: (state, action: PayloadAction<boolean>) => {
state.isAutoClose = action.payload
},
setIsAutoPin: (state, action: PayloadAction<boolean>) => {
state.isAutoPin = action.payload
},
setIsFollowToolbar: (state, action: PayloadAction<boolean>) => {
state.isFollowToolbar = action.payload
},
setIsRemeberWinSize: (state, action: PayloadAction<boolean>) => {
state.isRemeberWinSize = action.payload
},
setFilterMode: (state, action: PayloadAction<SelectionFilterMode>) => {
state.filterMode = action.payload
},
setFilterList: (state, action: PayloadAction<string[]>) => {
state.filterList = action.payload
},
setActionWindowOpacity: (state, action: PayloadAction<number>) => {
state.actionWindowOpacity = action.payload
},
setActionItems: (state, action: PayloadAction<SelectionActionItem[]>) => {
state.actionItems = action.payload
}
}
})
// export default selectionSlice.reducer export const {
setSelectionEnabled,
setTriggerMode,
setIsCompact,
setIsAutoClose,
setIsAutoPin,
setIsFollowToolbar,
setIsRemeberWinSize,
setFilterMode,
setFilterList,
setActionWindowOpacity,
setActionItems
} = selectionSlice.actions
export default selectionSlice.reducer

View File

@ -16,12 +16,13 @@ import {
import { uuid } from '@renderer/utils' import { uuid } from '@renderer/utils'
import { UpgradeChannel } from '@shared/config/constant' import { UpgradeChannel } from '@shared/config/constant'
import { TRANSLATE_PROMPT } from '@shared/config/prompts' import { TRANSLATE_PROMPT } from '@shared/config/prompts'
import type { SendMessageShortcut } from '@shared/data/preferenceTypes'
import { LanguageVarious, ThemeMode } from '@shared/data/preferenceTypes' import { LanguageVarious, ThemeMode } from '@shared/data/preferenceTypes'
import { OpenAIVerbosity } from '@types' import { OpenAIVerbosity } from '@types'
import { RemoteSyncState } from './backup' import { RemoteSyncState } from './backup'
export type SendMessageShortcut = 'Enter' | 'Shift+Enter' | 'Ctrl+Enter' | 'Command+Enter' | 'Alt+Enter' // export type SendMessageShortcut = 'Enter' | 'Shift+Enter' | 'Ctrl+Enter' | 'Command+Enter' | 'Alt+Enter'
// Re-export for backward compatibility // Re-export for backward compatibility
export { DEFAULT_SIDEBAR_ICONS } export { DEFAULT_SIDEBAR_ICONS }

View File

@ -1,4 +1,4 @@
import type { SendMessageShortcut } from '@renderer/store/settings' import type { SendMessageShortcut } from '@shared/data/preferenceTypes'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { getFilesFromDropEvent, getSendMessageShortcutLabel, isSendMessageKeyPressed } from '../input' import { getFilesFromDropEvent, getSendMessageShortcutLabel, isSendMessageKeyPressed } from '../input'

View File

@ -1,7 +1,7 @@
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { isMac, isWin } from '@renderer/config/constant' import { isMac, isWin } from '@renderer/config/constant'
import type { SendMessageShortcut } from '@renderer/store/settings'
import { FileMetadata } from '@renderer/types' import { FileMetadata } from '@renderer/types'
import type { SendMessageShortcut } from '@shared/data/preferenceTypes'
const logger = loggerService.withContext('Utils:Input') const logger = loggerService.withContext('Utils:Input')