mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-26 11:44:28 +08:00
feat(preferences): update preferences structure and enhance shortcut management
- Updated the preferences configuration with new shortcut definitions and types for better management. - Introduced a method to get and subscribe to preference changes in the PreferenceService, improving reactivity. - Refactored SelectionService to utilize the new preference management system, enhancing code clarity and maintainability. - Updated SelectionAssistantSettings to use the new preference hooks for managing selection settings. - Adjusted the generated preferences file to reflect the latest configuration changes.
This commit is contained in:
parent
30e6883333
commit
e15005d1cf
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Auto-generated preferences configuration
|
||||
* Generated at: 2025-08-10T12:46:51.544Z
|
||||
* Generated at: 2025-08-15T03:23:46.568Z
|
||||
*
|
||||
* This file is automatically generated from classification.json
|
||||
* To update this file, modify classification.json and run:
|
||||
@ -301,7 +301,7 @@ export interface PreferencesType {
|
||||
// redux/selectionStore/selectionEnabled
|
||||
'feature.selection.enabled': boolean
|
||||
// redux/selectionStore/filterList
|
||||
'feature.selection.filter_list': unknown[]
|
||||
'feature.selection.filter_list': string[]
|
||||
// redux/selectionStore/filterMode
|
||||
'feature.selection.filter_mode': string
|
||||
// redux/selectionStore/isFollowToolbar
|
||||
@ -310,6 +310,34 @@ export interface PreferencesType {
|
||||
'feature.selection.remember_win_size': boolean
|
||||
// redux/selectionStore/triggerMode
|
||||
'feature.selection.trigger_mode': string
|
||||
// redux/shortcuts/shortcuts.clear_topic
|
||||
'shortcut.chat.clear': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.copy_last_message
|
||||
'shortcut.chat.copy_last_message': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.search_message_in_chat
|
||||
'shortcut.chat.search_message': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.toggle_new_context
|
||||
'shortcut.chat.toggle_new_context': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.exit_fullscreen
|
||||
'shortcut.exit_fullscreen': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.search_message
|
||||
'shortcut.global.search_message': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.show_app
|
||||
'shortcut.main_window.show': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.mini_window
|
||||
'shortcut.mini_window.show': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.show_settings
|
||||
'shortcut.show_settings': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.toggle_show_assistants
|
||||
'shortcut.toggle_show_assistants': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.new_topic
|
||||
'shortcut.topic.new': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.zoom_in
|
||||
'shortcut.zoom_in': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.zoom_out
|
||||
'shortcut.zoom_out': Record<string, unknown>
|
||||
// redux/shortcuts/shortcuts.zoom_reset
|
||||
'shortcut.zoom_reset': Record<string, unknown>
|
||||
// redux/settings/enableTopicNaming
|
||||
'topic.naming.enabled': boolean
|
||||
// redux/settings/topicNamingPrompt
|
||||
@ -481,6 +509,35 @@ export const DefaultPreferences: PreferencesType = {
|
||||
'feature.selection.follow_toolbar': true,
|
||||
'feature.selection.remember_win_size': false,
|
||||
'feature.selection.trigger_mode': 'selected',
|
||||
'shortcut.chat.clear': { editable: true, enabled: true, key: ['CommandOrControl', 'L'], system: false },
|
||||
'shortcut.chat.copy_last_message': {
|
||||
editable: true,
|
||||
enabled: false,
|
||||
key: ['CommandOrControl', 'Shift', 'C'],
|
||||
system: false
|
||||
},
|
||||
'shortcut.chat.search_message': { editable: true, enabled: true, key: ['CommandOrControl', 'F'], system: false },
|
||||
'shortcut.chat.toggle_new_context': {
|
||||
editable: true,
|
||||
enabled: true,
|
||||
key: ['CommandOrControl', 'K'],
|
||||
system: false
|
||||
},
|
||||
'shortcut.exit_fullscreen': { editable: false, enabled: true, key: ['Escape'], system: true },
|
||||
'shortcut.global.search_message': {
|
||||
editable: true,
|
||||
enabled: true,
|
||||
key: ['CommandOrControl', 'Shift', 'F'],
|
||||
system: false
|
||||
},
|
||||
'shortcut.main_window.show': { editable: true, enabled: true, key: [], system: true },
|
||||
'shortcut.mini_window.show': { editable: true, enabled: false, key: ['CommandOrControl', 'E'], system: true },
|
||||
'shortcut.show_settings': { editable: false, enabled: true, key: ['CommandOrControl', ','], system: true },
|
||||
'shortcut.toggle_show_assistants': { editable: true, enabled: true, key: ['CommandOrControl', '['], system: false },
|
||||
'shortcut.topic.new': { editable: true, enabled: true, key: ['CommandOrControl', 'N'], system: false },
|
||||
'shortcut.zoom_in': { editable: false, enabled: true, key: ['CommandOrControl', '='], system: true },
|
||||
'shortcut.zoom_out': { editable: false, enabled: true, key: ['CommandOrControl', '-'], system: true },
|
||||
'shortcut.zoom_reset': { editable: false, enabled: true, key: ['CommandOrControl', '0'], system: true },
|
||||
'topic.naming.enabled': true,
|
||||
'topic.naming.prompt': '',
|
||||
'topic.pin_to_top': false,
|
||||
@ -497,8 +554,8 @@ export const DefaultPreferences: PreferencesType = {
|
||||
|
||||
/**
|
||||
* 生成统计:
|
||||
* - 总配置项: 156
|
||||
* - 总配置项: 170
|
||||
* - electronStore项: 2
|
||||
* - redux项: 154
|
||||
* - redux项: 168
|
||||
* - localStorage项: 0
|
||||
*/
|
||||
|
||||
7
packages/shared/data/types.d.ts
vendored
7
packages/shared/data/types.d.ts
vendored
@ -2,3 +2,10 @@ import { PreferencesType } from './preferences'
|
||||
|
||||
export type PreferenceDefaultScopeType = PreferencesType['default']
|
||||
export type PreferenceKeyType = keyof PreferenceDefaultScopeType
|
||||
|
||||
export type PreferenceShortcutType = {
|
||||
key: string[]
|
||||
editable: boolean
|
||||
enabled: boolean
|
||||
system: boolean
|
||||
}
|
||||
|
||||
@ -94,6 +94,20 @@ export class PreferenceService {
|
||||
return this.cache[key] ?? DefaultPreferences.default[key]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single preference value from memory cache and subscribe to changes
|
||||
* @param key - The preference key to get
|
||||
* @param callback - The callback function to call when the preference changes
|
||||
* @returns The current value of the preference
|
||||
*/
|
||||
public getAndSubscribeChange<K extends PreferenceKeyType>(
|
||||
key: K,
|
||||
callback: (newValue: PreferenceDefaultScopeType[K], oldValue?: PreferenceDefaultScopeType[K]) => void
|
||||
): PreferenceDefaultScopeType[K] {
|
||||
const value = this.get(key)
|
||||
this.subscribeChange(key, callback)
|
||||
return value
|
||||
}
|
||||
/**
|
||||
* Set a single preference value
|
||||
* Updates both database and memory cache, then broadcasts changes to all listeners
|
||||
@ -261,11 +275,11 @@ export class PreferenceService {
|
||||
*/
|
||||
public subscribeChange<K extends PreferenceKeyType>(
|
||||
key: K,
|
||||
callback: (newValue: PreferenceDefaultScopeType[K], oldValue: PreferenceDefaultScopeType[K]) => void
|
||||
callback: (newValue: PreferenceDefaultScopeType[K], oldValue?: PreferenceDefaultScopeType[K]) => void
|
||||
): () => void {
|
||||
const listener = (changedKey: string, newValue: any, oldValue: any) => {
|
||||
if (changedKey === key) {
|
||||
callback(newValue, oldValue)
|
||||
callback(newValue as PreferenceDefaultScopeType[K], oldValue as PreferenceDefaultScopeType[K])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { preferenceService } from '@data/PreferenceService'
|
||||
import { loggerService } from '@logger'
|
||||
import { SELECTION_FINETUNED_LIST, SELECTION_PREDEFINED_BLACKLIST } from '@main/configs/SelectionConfig'
|
||||
import { isDev, isMac, isWin } from '@main/constant'
|
||||
@ -13,8 +14,6 @@ import type {
|
||||
} from 'selection-hook'
|
||||
|
||||
import type { ActionItem } from '../../renderer/src/types/selectionTypes'
|
||||
import { ConfigKeys, configManager } from './ConfigManager'
|
||||
import storeSyncService from './StoreSyncService'
|
||||
|
||||
const logger = loggerService.withContext('SelectionService')
|
||||
|
||||
@ -144,12 +143,13 @@ export class SelectionService {
|
||||
* Ensures UI elements scale properly with system DPI settings
|
||||
*/
|
||||
private initZoomFactor(): void {
|
||||
const zoomFactor = configManager.getZoomFactor()
|
||||
const zoomFactor = preferenceService.getAndSubscribeChange('app.zoom_factor', (zoomFactor: number) => {
|
||||
this.setZoomFactor(zoomFactor)
|
||||
})
|
||||
|
||||
if (zoomFactor) {
|
||||
this.setZoomFactor(zoomFactor)
|
||||
}
|
||||
|
||||
configManager.subscribe('ZoomFactor', this.setZoomFactor)
|
||||
}
|
||||
|
||||
public setZoomFactor = (zoomFactor: number) => {
|
||||
@ -157,51 +157,53 @@ export class SelectionService {
|
||||
}
|
||||
|
||||
private initConfig(): void {
|
||||
this.triggerMode = configManager.getSelectionAssistantTriggerMode() as TriggerMode
|
||||
this.isFollowToolbar = configManager.getSelectionAssistantFollowToolbar()
|
||||
this.isRemeberWinSize = configManager.getSelectionAssistantRemeberWinSize()
|
||||
this.filterMode = configManager.getSelectionAssistantFilterMode()
|
||||
this.filterList = configManager.getSelectionAssistantFilterList()
|
||||
this.triggerMode = preferenceService.getAndSubscribeChange(
|
||||
'feature.selection.trigger_mode',
|
||||
(triggerMode: string) => {
|
||||
const oldTriggerMode = this.triggerMode as TriggerMode
|
||||
|
||||
this.setHookGlobalFilterMode(this.filterMode, this.filterList)
|
||||
this.setHookFineTunedList()
|
||||
this.triggerMode = triggerMode as TriggerMode
|
||||
this.processTriggerMode()
|
||||
|
||||
configManager.subscribe(ConfigKeys.SelectionAssistantTriggerMode, (triggerMode: TriggerMode) => {
|
||||
const oldTriggerMode = this.triggerMode
|
||||
|
||||
this.triggerMode = triggerMode
|
||||
this.processTriggerMode()
|
||||
|
||||
//trigger mode changed, need to update the filter list
|
||||
if (oldTriggerMode !== triggerMode) {
|
||||
this.setHookGlobalFilterMode(this.filterMode, this.filterList)
|
||||
}
|
||||
})
|
||||
|
||||
configManager.subscribe(ConfigKeys.SelectionAssistantFollowToolbar, (isFollowToolbar: boolean) => {
|
||||
this.isFollowToolbar = isFollowToolbar
|
||||
})
|
||||
|
||||
configManager.subscribe(ConfigKeys.SelectionAssistantRemeberWinSize, (isRemeberWinSize: boolean) => {
|
||||
this.isRemeberWinSize = isRemeberWinSize
|
||||
//when off, reset the last action window size to default
|
||||
if (!this.isRemeberWinSize) {
|
||||
this.lastActionWindowSize = {
|
||||
width: this.ACTION_WINDOW_WIDTH,
|
||||
height: this.ACTION_WINDOW_HEIGHT
|
||||
//trigger mode changed, need to update the filter list
|
||||
if (oldTriggerMode !== triggerMode) {
|
||||
this.setHookGlobalFilterMode(this.filterMode, this.filterList)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
configManager.subscribe(ConfigKeys.SelectionAssistantFilterMode, (filterMode: string) => {
|
||||
) as TriggerMode
|
||||
this.isFollowToolbar = preferenceService.getAndSubscribeChange(
|
||||
'feature.selection.follow_toolbar',
|
||||
(followToolbar: boolean) => {
|
||||
this.isFollowToolbar = followToolbar
|
||||
}
|
||||
)
|
||||
this.isRemeberWinSize = preferenceService.getAndSubscribeChange(
|
||||
'feature.selection.remember_win_size',
|
||||
(rememberWinSize: boolean) => {
|
||||
this.isRemeberWinSize = rememberWinSize
|
||||
//when off, reset the last action window size to default
|
||||
if (!this.isRemeberWinSize) {
|
||||
this.lastActionWindowSize = {
|
||||
width: this.ACTION_WINDOW_WIDTH,
|
||||
height: this.ACTION_WINDOW_HEIGHT
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
this.filterMode = preferenceService.getAndSubscribeChange('feature.selection.filter_mode', (filterMode: string) => {
|
||||
this.filterMode = filterMode
|
||||
this.setHookGlobalFilterMode(this.filterMode, this.filterList)
|
||||
})
|
||||
this.filterList = preferenceService.getAndSubscribeChange(
|
||||
'feature.selection.filter_list',
|
||||
(filterList: string[]) => {
|
||||
this.filterList = filterList
|
||||
this.setHookGlobalFilterMode(this.filterMode, this.filterList)
|
||||
}
|
||||
)
|
||||
|
||||
configManager.subscribe(ConfigKeys.SelectionAssistantFilterList, (filterList: string[]) => {
|
||||
this.filterList = filterList
|
||||
this.setHookGlobalFilterMode(this.filterMode, this.filterList)
|
||||
})
|
||||
this.setHookGlobalFilterMode(this.filterMode, this.filterList)
|
||||
this.setHookFineTunedList()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -381,12 +383,9 @@ export class SelectionService {
|
||||
public toggleEnabled(enabled: boolean | undefined = undefined): void {
|
||||
if (!this.selectionHook) return
|
||||
|
||||
const newEnabled = enabled === undefined ? !configManager.getSelectionAssistantEnabled() : enabled
|
||||
const newEnabled = enabled === undefined ? !preferenceService.get('feature.selection.enabled') : enabled
|
||||
|
||||
configManager.setSelectionAssistantEnabled(newEnabled)
|
||||
|
||||
//sync the new enabled state to all renderer windows
|
||||
storeSyncService.syncToRenderer('selectionStore/setSelectionEnabled', newEnabled)
|
||||
preferenceService.set('feature.selection.enabled', newEnabled)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1462,27 +1461,27 @@ export class SelectionService {
|
||||
})
|
||||
|
||||
ipcMain.handle(IpcChannel.Selection_SetEnabled, (_, enabled: boolean) => {
|
||||
configManager.setSelectionAssistantEnabled(enabled)
|
||||
preferenceService.set('feature.selection.enabled', enabled)
|
||||
})
|
||||
|
||||
ipcMain.handle(IpcChannel.Selection_SetTriggerMode, (_, triggerMode: string) => {
|
||||
configManager.setSelectionAssistantTriggerMode(triggerMode)
|
||||
preferenceService.set('feature.selection.trigger_mode', triggerMode)
|
||||
})
|
||||
|
||||
ipcMain.handle(IpcChannel.Selection_SetFollowToolbar, (_, isFollowToolbar: boolean) => {
|
||||
configManager.setSelectionAssistantFollowToolbar(isFollowToolbar)
|
||||
preferenceService.set('feature.selection.follow_toolbar', isFollowToolbar)
|
||||
})
|
||||
|
||||
ipcMain.handle(IpcChannel.Selection_SetRemeberWinSize, (_, isRemeberWinSize: boolean) => {
|
||||
configManager.setSelectionAssistantRemeberWinSize(isRemeberWinSize)
|
||||
preferenceService.set('feature.selection.remember_win_size', isRemeberWinSize)
|
||||
})
|
||||
|
||||
ipcMain.handle(IpcChannel.Selection_SetFilterMode, (_, filterMode: string) => {
|
||||
configManager.setSelectionAssistantFilterMode(filterMode)
|
||||
preferenceService.set('feature.selection.filter_mode', filterMode)
|
||||
})
|
||||
|
||||
ipcMain.handle(IpcChannel.Selection_SetFilterList, (_, filterList: string[]) => {
|
||||
configManager.setSelectionAssistantFilterList(filterList)
|
||||
preferenceService.set('feature.selection.filter_list', filterList)
|
||||
})
|
||||
|
||||
// [macOS] only macOS has the available isFullscreen mode
|
||||
@ -1533,7 +1532,7 @@ export class SelectionService {
|
||||
export function initSelectionService(): boolean {
|
||||
if (!isSupportedOS) return false
|
||||
|
||||
configManager.subscribe(ConfigKeys.SelectionAssistantEnabled, (enabled: boolean): void => {
|
||||
const enabled = preferenceService.getAndSubscribeChange('feature.selection.enabled', (enabled: boolean): void => {
|
||||
//avoid closure
|
||||
const ss = SelectionService.getInstance()
|
||||
if (!ss) {
|
||||
@ -1548,7 +1547,7 @@ export function initSelectionService(): boolean {
|
||||
}
|
||||
})
|
||||
|
||||
if (!configManager.getSelectionAssistantEnabled()) return false
|
||||
if (!enabled) return false
|
||||
|
||||
const ss = SelectionService.getInstance()
|
||||
if (!ss) {
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { usePreference } from '@data/hooks/usePreference'
|
||||
import { isMac, isWin } from '@renderer/config/constant'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
import { useSelectionAssistant } from '@renderer/hooks/useSelectionAssistant'
|
||||
import { getSelectionDescriptionLabel } from '@renderer/i18n/label'
|
||||
import { FilterMode, TriggerMode } from '@renderer/types/selectionTypes'
|
||||
import { ActionItem } from '@renderer/types/selectionTypes'
|
||||
import SelectionToolbar from '@renderer/windows/selection/toolbar/SelectionToolbar'
|
||||
import { Button, Radio, Row, Slider, Switch, Tooltip } from 'antd'
|
||||
import { CircleHelp, Edit2 } from 'lucide-react'
|
||||
@ -27,30 +28,42 @@ import SelectionFilterListModal from './components/SelectionFilterListModal'
|
||||
const SelectionAssistantSettings: FC = () => {
|
||||
const { theme } = useTheme()
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
selectionEnabled,
|
||||
triggerMode,
|
||||
isCompact,
|
||||
isAutoClose,
|
||||
isAutoPin,
|
||||
isFollowToolbar,
|
||||
isRemeberWinSize,
|
||||
actionItems,
|
||||
actionWindowOpacity,
|
||||
filterMode,
|
||||
filterList,
|
||||
setSelectionEnabled,
|
||||
setTriggerMode,
|
||||
setIsCompact,
|
||||
setIsAutoClose,
|
||||
setIsAutoPin,
|
||||
setIsFollowToolbar,
|
||||
setIsRemeberWinSize,
|
||||
setActionWindowOpacity,
|
||||
setActionItems,
|
||||
setFilterMode,
|
||||
setFilterList
|
||||
} = useSelectionAssistant()
|
||||
// const {
|
||||
// selectionEnabled,
|
||||
// triggerMode,
|
||||
// isCompact,
|
||||
// isAutoClose,
|
||||
// isAutoPin,
|
||||
// isFollowToolbar,
|
||||
// isRemeberWinSize,
|
||||
// actionItems,
|
||||
// actionWindowOpacity,
|
||||
// filterMode,
|
||||
// filterList,
|
||||
// setSelectionEnabled,
|
||||
// setTriggerMode,
|
||||
// setIsCompact,
|
||||
// setIsAutoClose,
|
||||
// setIsAutoPin,
|
||||
// setIsFollowToolbar,
|
||||
// setIsRemeberWinSize,
|
||||
// setActionWindowOpacity,
|
||||
// setActionItems,
|
||||
// setFilterMode,
|
||||
// setFilterList
|
||||
// } = useSelectionAssistant()
|
||||
|
||||
const [selectionEnabled, setSelectionEnabled] = usePreference('feature.selection.enabled')
|
||||
const [triggerMode, setTriggerMode] = usePreference('feature.selection.trigger_mode')
|
||||
const [isCompact, setIsCompact] = usePreference('feature.selection.compact')
|
||||
const [isAutoClose, setIsAutoClose] = usePreference('feature.selection.auto_close')
|
||||
const [isAutoPin, setIsAutoPin] = usePreference('feature.selection.auto_pin')
|
||||
const [isFollowToolbar, setIsFollowToolbar] = usePreference('feature.selection.follow_toolbar')
|
||||
const [isRemeberWinSize, setIsRemeberWinSize] = usePreference('feature.selection.remember_win_size')
|
||||
const [actionWindowOpacity, setActionWindowOpacity] = usePreference('feature.selection.action_window_opacity')
|
||||
const [filterMode, setFilterMode] = usePreference('feature.selection.filter_mode')
|
||||
const [filterList, setFilterList] = usePreference('feature.selection.filter_list')
|
||||
const [actionItems, setActionItems] = usePreference('feature.selection.action_items')
|
||||
|
||||
const isSupportedOS = isWin || isMac
|
||||
|
||||
@ -229,7 +242,7 @@ const SelectionAssistantSettings: FC = () => {
|
||||
</SettingRow>
|
||||
</SettingGroup>
|
||||
|
||||
<SelectionActionsList actionItems={actionItems} setActionItems={setActionItems} />
|
||||
<SelectionActionsList actionItems={actionItems as ActionItem[]} setActionItems={setActionItems} />
|
||||
|
||||
<SettingGroup theme={theme}>
|
||||
<SettingTitle>{t('selection.settings.advanced.title')}</SettingTitle>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user