mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-16 14:20:53 +08:00
* refactor(ipc): generate bindings with Specta * fix(profile): project IPC inputs to consumed fields * fix(events): remove unused refresh payloads * fix(webdav): return only consumed backup metadata * fix(network): trim unused interface metadata * fix(sysinfo): return only displayed system fields * chore(knip): check generated runtime exports * fix(proxy): confirm runtime chain updates before UI changes * fix(clipboard): propagate proxy environment copy failures * refactor(dns): remove ignored runtime patch * refactor(core): trim unused upgrade response fields * refactor(ipc): avoid redundant response copies * refactor(proxy): clarify automatic proxy query naming * chore(tests): remove added IPC regression tests * refactor(ipc): enforce typed command boundaries * chore(contract): check generated bindings before push * refactor(ipc): remove unused proxy liveness payloads
290 lines
9.4 KiB
TypeScript
290 lines
9.4 KiB
TypeScript
import { ContentCopyRounded } from '@mui/icons-material'
|
|
import { Button, Input, MenuItem, Select } from '@mui/material'
|
|
import { open } from '@tauri-apps/plugin-dialog'
|
|
import { useCallback, useRef } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
|
|
import { DialogRef, TooltipIcon } from '@/components/base'
|
|
import { useVerge } from '@/hooks/use-verge'
|
|
import { navigationItems } from '@/pages/_navigation-meta'
|
|
import { copyClashEnv } from '@/services/cmds'
|
|
import { supportedLanguages } from '@/services/i18n'
|
|
import { mutate } from '@/services/mutate'
|
|
import { showNotice } from '@/services/notice-service'
|
|
import getSystem from '@/utils/get-system'
|
|
|
|
import { BackupViewer } from './mods/backup-viewer'
|
|
import { ConfigViewer } from './mods/config-viewer'
|
|
import { GuardState } from './mods/guard-state'
|
|
import { HotkeyViewer } from './mods/hotkey-viewer'
|
|
import { LayoutViewer } from './mods/layout-viewer'
|
|
import { MiscViewer } from './mods/misc-viewer'
|
|
import { SettingItem, SettingList } from './mods/setting-comp'
|
|
import { ThemeModeSwitch } from './mods/theme-mode-switch'
|
|
import { ThemeViewer } from './mods/theme-viewer'
|
|
import { UpdateViewer } from './mods/update-viewer'
|
|
|
|
interface Props {
|
|
onError?: (err: Error) => void
|
|
}
|
|
|
|
const OS = getSystem()
|
|
|
|
const languageOptions = supportedLanguages.map((code) => {
|
|
const labels: { [key: string]: string } = {
|
|
en: 'English',
|
|
ru: 'Русский',
|
|
zh: '简体中文',
|
|
fa: 'فارسی',
|
|
tt: 'Татар',
|
|
id: 'Bahasa Indonesia',
|
|
ar: 'العربية',
|
|
ko: '한국어',
|
|
tr: 'Türkçe',
|
|
de: 'Deutsch',
|
|
es: 'Español',
|
|
jp: '日本語',
|
|
zhtw: '繁體中文',
|
|
pt: 'Português',
|
|
}
|
|
const label = labels[code] || code
|
|
return { code, label }
|
|
})
|
|
|
|
const SettingVergeBasic = ({ onError }: Props) => {
|
|
const { t } = useTranslation()
|
|
|
|
const { verge, patchVerge, mutateVerge } = useVerge()
|
|
const {
|
|
theme_mode,
|
|
language,
|
|
tray_event,
|
|
env_type,
|
|
startup_script,
|
|
start_page,
|
|
} = verge ?? {}
|
|
const configRef = useRef<DialogRef>(null)
|
|
const hotkeyRef = useRef<DialogRef>(null)
|
|
const miscRef = useRef<DialogRef>(null)
|
|
const themeRef = useRef<DialogRef>(null)
|
|
const layoutRef = useRef<DialogRef>(null)
|
|
const updateRef = useRef<DialogRef>(null)
|
|
const backupRef = useRef<DialogRef>(null)
|
|
|
|
const onChangeData = (patch: any) => {
|
|
mutateVerge({ ...verge, ...patch }, false)
|
|
}
|
|
|
|
const onCopyClashEnv = useCallback(async () => {
|
|
try {
|
|
await mutate(copyClashEnv, {
|
|
id: 'copy-clash-env',
|
|
onFulfilled: () =>
|
|
showNotice.success(
|
|
'shared.feedback.notifications.common.copySuccess',
|
|
1000,
|
|
),
|
|
})
|
|
} catch {
|
|
// The shared mutation boundary reports the failure.
|
|
}
|
|
}, [])
|
|
|
|
return (
|
|
<SettingList title={t('settings.components.verge.basic.title')}>
|
|
<ThemeViewer ref={themeRef} />
|
|
<ConfigViewer ref={configRef} />
|
|
<HotkeyViewer ref={hotkeyRef} />
|
|
<MiscViewer ref={miscRef} />
|
|
<LayoutViewer ref={layoutRef} />
|
|
<UpdateViewer ref={updateRef} />
|
|
<BackupViewer ref={backupRef} />
|
|
|
|
<SettingItem label={t('settings.components.verge.basic.fields.language')}>
|
|
<GuardState
|
|
value={language ?? 'en'}
|
|
onCatch={onError}
|
|
onFormat={(e: any) => e.target.value}
|
|
onChange={(e) => onChangeData({ language: e })}
|
|
onGuard={(e) => patchVerge({ language: e })}
|
|
>
|
|
<Select size="small" sx={{ width: 110, '> div': { py: '7.5px' } }}>
|
|
{languageOptions.map(({ code, label }) => (
|
|
<MenuItem key={code} value={code}>
|
|
{label}
|
|
</MenuItem>
|
|
))}
|
|
</Select>
|
|
</GuardState>
|
|
</SettingItem>
|
|
|
|
<SettingItem
|
|
label={t('settings.components.verge.basic.fields.themeMode')}
|
|
>
|
|
<GuardState
|
|
value={theme_mode}
|
|
onCatch={onError}
|
|
onChange={(e) => onChangeData({ theme_mode: e })}
|
|
onGuard={(e) => patchVerge({ theme_mode: e })}
|
|
>
|
|
<ThemeModeSwitch />
|
|
</GuardState>
|
|
</SettingItem>
|
|
|
|
{OS !== 'linux' && (
|
|
<SettingItem
|
|
label={t('settings.components.verge.basic.fields.trayClickEvent')}
|
|
>
|
|
<GuardState
|
|
value={tray_event ?? 'main_window'}
|
|
onCatch={onError}
|
|
onFormat={(e: any) => e.target.value}
|
|
onChange={(e) => onChangeData({ tray_event: e })}
|
|
onGuard={(e) => patchVerge({ tray_event: e })}
|
|
>
|
|
<Select size="small" sx={{ width: 140, '> div': { py: '7.5px' } }}>
|
|
<MenuItem value="main_window">
|
|
{t(
|
|
'settings.components.verge.basic.trayOptions.showMainWindow',
|
|
)}
|
|
</MenuItem>
|
|
<MenuItem value="tray_menu">
|
|
{t('settings.components.verge.basic.trayOptions.showTrayMenu')}
|
|
</MenuItem>
|
|
<MenuItem value="system_proxy">
|
|
{t('settings.sections.system.toggles.systemProxy')}
|
|
</MenuItem>
|
|
<MenuItem value="tun_mode">
|
|
{t('settings.sections.system.toggles.tunMode')}
|
|
</MenuItem>
|
|
<MenuItem value="disable">
|
|
{t('settings.components.verge.basic.trayOptions.disable')}
|
|
</MenuItem>
|
|
</Select>
|
|
</GuardState>
|
|
</SettingItem>
|
|
)}
|
|
|
|
<SettingItem
|
|
label={t('settings.components.verge.basic.fields.copyEnvType')}
|
|
extra={
|
|
<TooltipIcon icon={ContentCopyRounded} onClick={onCopyClashEnv} />
|
|
}
|
|
>
|
|
<GuardState
|
|
value={env_type ?? (OS === 'windows' ? 'powershell' : 'bash')}
|
|
onCatch={onError}
|
|
onFormat={(e: any) => e.target.value}
|
|
onChange={(e) => onChangeData({ env_type: e })}
|
|
onGuard={(e) => patchVerge({ env_type: e })}
|
|
>
|
|
<Select size="small" sx={{ width: 140, '> div': { py: '7.5px' } }}>
|
|
<MenuItem value="bash">Bash</MenuItem>
|
|
<MenuItem value="fish">Fish</MenuItem>
|
|
<MenuItem value="nushell">Nushell</MenuItem>
|
|
<MenuItem value="cmd">CMD</MenuItem>
|
|
<MenuItem value="powershell">PowerShell</MenuItem>
|
|
</Select>
|
|
</GuardState>
|
|
</SettingItem>
|
|
|
|
<SettingItem
|
|
label={t('settings.components.verge.basic.fields.startPage')}
|
|
>
|
|
<GuardState
|
|
value={start_page ?? '/'}
|
|
onCatch={onError}
|
|
onFormat={(e: any) => e.target.value}
|
|
onChange={(e) => onChangeData({ start_page: e })}
|
|
onGuard={(e) => patchVerge({ start_page: e })}
|
|
>
|
|
<Select size="small" sx={{ width: 140, '> div': { py: '7.5px' } }}>
|
|
{Object.values(navigationItems).map((page) => {
|
|
return (
|
|
<MenuItem key={page.path} value={page.path}>
|
|
{t(page.label)}
|
|
</MenuItem>
|
|
)
|
|
})}
|
|
</Select>
|
|
</GuardState>
|
|
</SettingItem>
|
|
|
|
<SettingItem
|
|
label={t('settings.components.verge.basic.fields.startupScript')}
|
|
>
|
|
<GuardState
|
|
value={startup_script ?? ''}
|
|
onCatch={onError}
|
|
onFormat={(e: any) => e.target.value}
|
|
onChange={(e) => onChangeData({ startup_script: e })}
|
|
onGuard={(e) => patchVerge({ startup_script: e })}
|
|
>
|
|
<Input
|
|
value={startup_script}
|
|
disabled
|
|
disableUnderline
|
|
sx={{ width: 230 }}
|
|
endAdornment={
|
|
<>
|
|
<Button
|
|
onClick={async () => {
|
|
const selected = await open({
|
|
directory: false,
|
|
multiple: false,
|
|
filters: [
|
|
{
|
|
name: 'Shell Script',
|
|
extensions: ['sh', 'bat', 'ps1'],
|
|
},
|
|
],
|
|
})
|
|
if (selected) {
|
|
onChangeData({ startup_script: `${selected}` })
|
|
patchVerge({ startup_script: `${selected}` })
|
|
}
|
|
}}
|
|
>
|
|
{t('settings.components.verge.basic.actions.browse')}
|
|
</Button>
|
|
{startup_script && (
|
|
<Button
|
|
onClick={async () => {
|
|
onChangeData({ startup_script: '' })
|
|
patchVerge({ startup_script: '' })
|
|
}}
|
|
>
|
|
{t('shared.actions.clear')}
|
|
</Button>
|
|
)}
|
|
</>
|
|
}
|
|
></Input>
|
|
</GuardState>
|
|
</SettingItem>
|
|
|
|
<SettingItem
|
|
onClick={() => themeRef.current?.open()}
|
|
label={t('settings.components.verge.basic.fields.themeSetting')}
|
|
/>
|
|
|
|
<SettingItem
|
|
onClick={() => layoutRef.current?.open()}
|
|
label={t('settings.components.verge.basic.fields.layoutSetting')}
|
|
/>
|
|
|
|
<SettingItem
|
|
onClick={() => miscRef.current?.open()}
|
|
label={t('settings.components.verge.basic.fields.misc')}
|
|
/>
|
|
|
|
<SettingItem
|
|
onClick={() => hotkeyRef.current?.open()}
|
|
label={t('settings.components.verge.basic.fields.hotkeySetting')}
|
|
/>
|
|
</SettingList>
|
|
)
|
|
}
|
|
|
|
export default SettingVergeBasic
|