open file

This commit is contained in:
pompurin404 2024-08-30 23:23:16 +08:00
parent c5c90caa1b
commit df41310237
No known key found for this signature in database
6 changed files with 77 additions and 36 deletions

View File

@ -1,9 +1,17 @@
import { exec, execFile, execSync } from 'child_process' import { exec, execFile, execSync } from 'child_process'
import { dialog, nativeTheme } from 'electron' import { dialog, nativeTheme, shell } from 'electron'
import { readFile } from 'fs/promises' import { readFile } from 'fs/promises'
import path from 'path' import path from 'path'
import { promisify } from 'util' import { promisify } from 'util'
import { exePath, mihomoCorePath, resourcesDir, resourcesFilesDir, taskDir } from '../utils/dirs' import {
exePath,
mihomoCorePath,
overridePath,
profilePath,
resourcesDir,
resourcesFilesDir,
taskDir
} from '../utils/dirs'
import { copyFileSync, writeFileSync } from 'fs' import { copyFileSync, writeFileSync } from 'fs'
export function getFilePath(ext: string[]): string[] | undefined { export function getFilePath(ext: string[]): string[] | undefined {
@ -18,6 +26,15 @@ export async function readTextFile(filePath: string): Promise<string> {
return await readFile(filePath, 'utf8') return await readFile(filePath, 'utf8')
} }
export function openFile(type: 'profile' | 'override', id: string, ext?: 'yaml' | 'js'): void {
if (type === 'profile') {
shell.openPath(profilePath(id))
}
if (type === 'override') {
shell.openPath(overridePath(id, ext || 'js'))
}
}
export async function openUWPTool(): Promise<void> { export async function openUWPTool(): Promise<void> {
const execFilePromise = promisify(execFile) const execFilePromise = promisify(execFile)
const uwpToolPath = path.join(resourcesDir(), 'files', 'enableLoopback.exe') const uwpToolPath = path.join(resourcesDir(), 'files', 'enableLoopback.exe')

View File

@ -49,7 +49,14 @@ import {
import { isEncryptionAvailable, manualGrantCorePermition, restartCore } from '../core/manager' import { isEncryptionAvailable, manualGrantCorePermition, restartCore } from '../core/manager'
import { triggerSysProxy } from '../sys/sysproxy' import { triggerSysProxy } from '../sys/sysproxy'
import { checkUpdate, downloadAndInstallUpdate } from '../resolve/autoUpdater' import { checkUpdate, downloadAndInstallUpdate } from '../resolve/autoUpdater'
import { getFilePath, openUWPTool, readTextFile, setNativeTheme, setupFirewall } from '../sys/misc' import {
getFilePath,
openFile,
openUWPTool,
readTextFile,
setNativeTheme,
setupFirewall
} from '../sys/misc'
import { getRuntimeConfig, getRuntimeConfigStr } from '../core/factory' import { getRuntimeConfig, getRuntimeConfigStr } from '../core/factory'
import { isPortable, setPortable } from './dirs' import { isPortable, setPortable } from './dirs'
import { listWebdavBackups, webdavBackup, webdavDelete, webdavRestore } from '../resolve/backup' import { listWebdavBackups, webdavBackup, webdavDelete, webdavRestore } from '../resolve/backup'
@ -171,6 +178,7 @@ export function registerIpcMainHandlers(): void {
ipcMain.handle('setNativeTheme', (_e, theme) => { ipcMain.handle('setNativeTheme', (_e, theme) => {
setNativeTheme(theme) setNativeTheme(theme)
}) })
ipcMain.handle('openFile', (_e, type, id, ext) => openFile(type, id, ext))
ipcMain.handle('copyEnv', ipcErrorWrapper(copyEnv)) ipcMain.handle('copyEnv', ipcErrorWrapper(copyEnv))
ipcMain.handle('alert', (_e, msg) => { ipcMain.handle('alert', (_e, msg) => {
dialog.showErrorBox('Mihomo Party', msg) dialog.showErrorBox('Mihomo Party', msg)

View File

@ -7,23 +7,7 @@ interface Props {
connection: IMihomoConnectionDetail connection: IMihomoConnectionDetail
onClose: () => void onClose: () => void
} }
// sourceIP: string
// destinationIP: string
// destinationGeoIP: string
// destinationIPASN: string
// sourcePort: string
// destinationPort: string
// inboundIP: string
// inboundPort: string
// inboundName: string
// inboundUser: string
// host: string
// dnsMode: string
// specialProxy: string
// specialRules: string
// remoteDestination: string
// dscp: number
// sniffHost: string
const ConnectionDetailModal: React.FC<Props> = (props) => { const ConnectionDetailModal: React.FC<Props> = (props) => {
const { connection, onClose } = props const { connection, onClose } = props
return ( return (

View File

@ -16,6 +16,7 @@ import EditInfoModal from './edit-info-modal'
import { useSortable } from '@dnd-kit/sortable' import { useSortable } from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities' import { CSS } from '@dnd-kit/utilities'
import ExecLogModal from './exec-log-modal' import ExecLogModal from './exec-log-modal'
import { openFile } from '@renderer/utils/ipc'
interface Props { interface Props {
info: IOverrideItem info: IOverrideItem
@ -48,6 +49,13 @@ const menuItems: MenuItem[] = [
color: 'default', color: 'default',
className: '' className: ''
} as MenuItem, } as MenuItem,
{
key: 'open-file',
label: '打开文件',
showDivider: false,
color: 'default',
className: ''
} as MenuItem,
{ {
key: 'exec-log', key: 'exec-log',
label: '执行日志', label: '执行日志',
@ -68,8 +76,8 @@ const OverrideItem: React.FC<Props> = (props) => {
const { info, addOverrideItem, removeOverrideItem, mutateOverrideConfig, updateOverrideItem } = const { info, addOverrideItem, removeOverrideItem, mutateOverrideConfig, updateOverrideItem } =
props props
const [updating, setUpdating] = useState(false) const [updating, setUpdating] = useState(false)
const [openInfo, setOpenInfo] = useState(false) const [openInfoEditor, setOpenInfoEditor] = useState(false)
const [openFile, setOpenFile] = useState(false) const [openFileEditor, setOpenFileEditor] = useState(false)
const [openLog, setOpenLog] = useState(false) const [openLog, setOpenLog] = useState(false)
const { const {
attributes, attributes,
@ -87,11 +95,15 @@ const OverrideItem: React.FC<Props> = (props) => {
const onMenuAction = (key: Key): void => { const onMenuAction = (key: Key): void => {
switch (key) { switch (key) {
case 'edit-info': { case 'edit-info': {
setOpenInfo(true) setOpenInfoEditor(true)
break break
} }
case 'edit-file': { case 'edit-file': {
setOpenFile(true) setOpenFileEditor(true)
break
}
case 'open-file': {
openFile('override', info.id, info.ext)
break break
} }
case 'exec-log': { case 'exec-log': {
@ -128,17 +140,17 @@ const OverrideItem: React.FC<Props> = (props) => {
zIndex: isDragging ? 'calc(infinity)' : undefined zIndex: isDragging ? 'calc(infinity)' : undefined
}} }}
> >
{openFile && ( {openFileEditor && (
<EditFileModal <EditFileModal
id={info.id} id={info.id}
language={info.ext === 'yaml' ? 'yaml' : 'javascript'} language={info.ext === 'yaml' ? 'yaml' : 'javascript'}
onClose={() => setOpenFile(false)} onClose={() => setOpenFileEditor(false)}
/> />
)} )}
{openInfo && ( {openInfoEditor && (
<EditInfoModal <EditInfoModal
item={info} item={info}
onClose={() => setOpenInfo(false)} onClose={() => setOpenInfoEditor(false)}
updateOverrideItem={updateOverrideItem} updateOverrideItem={updateOverrideItem}
/> />
)} )}
@ -148,7 +160,7 @@ const OverrideItem: React.FC<Props> = (props) => {
isPressable isPressable
onPress={() => { onPress={() => {
if (disableOpen) return if (disableOpen) return
setOpenFile(true) setOpenFileEditor(true)
}} }}
> >
<CardBody> <CardBody>

View File

@ -18,6 +18,7 @@ import EditFileModal from './edit-file-modal'
import EditInfoModal from './edit-info-modal' import EditInfoModal from './edit-info-modal'
import { useSortable } from '@dnd-kit/sortable' import { useSortable } from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities' import { CSS } from '@dnd-kit/utilities'
import { openFile } from '@renderer/utils/ipc'
interface Props { interface Props {
info: IProfileItem info: IProfileItem
@ -51,8 +52,8 @@ const ProfileItem: React.FC<Props> = (props) => {
const total = extra?.total ?? 0 const total = extra?.total ?? 0
const [updating, setUpdating] = useState(false) const [updating, setUpdating] = useState(false)
const [selecting, setSelecting] = useState(false) const [selecting, setSelecting] = useState(false)
const [openInfo, setOpenInfo] = useState(false) const [openInfoEditor, setOpenInfoEditor] = useState(false)
const [openFile, setOpenFile] = useState(false) const [openFileEditor, setOpenFileEditor] = useState(false)
const { const {
attributes, attributes,
listeners, listeners,
@ -78,6 +79,13 @@ const ProfileItem: React.FC<Props> = (props) => {
{ {
key: 'edit-file', key: 'edit-file',
label: '编辑文件', label: '编辑文件',
showDivider: false,
color: 'default',
className: ''
} as MenuItem,
{
key: 'open-file',
label: '打开文件',
showDivider: true, showDivider: true,
color: 'default', color: 'default',
className: '' className: ''
@ -105,11 +113,15 @@ const ProfileItem: React.FC<Props> = (props) => {
const onMenuAction = async (key: Key): Promise<void> => { const onMenuAction = async (key: Key): Promise<void> => {
switch (key) { switch (key) {
case 'edit-info': { case 'edit-info': {
setOpenInfo(true) setOpenInfoEditor(true)
break break
} }
case 'edit-file': { case 'edit-file': {
setOpenFile(true) setOpenFileEditor(true)
break
}
case 'open-file': {
openFile('profile', info.id)
break break
} }
case 'delete': { case 'delete': {
@ -147,11 +159,11 @@ const ProfileItem: React.FC<Props> = (props) => {
zIndex: isDragging ? 'calc(infinity)' : undefined zIndex: isDragging ? 'calc(infinity)' : undefined
}} }}
> >
{openFile && <EditFileModal id={info.id} onClose={() => setOpenFile(false)} />} {openFileEditor && <EditFileModal id={info.id} onClose={() => setOpenFileEditor(false)} />}
{openInfo && ( {openInfoEditor && (
<EditInfoModal <EditInfoModal
item={info} item={info}
onClose={() => setOpenInfo(false)} onClose={() => setOpenInfoEditor(false)}
updateProfileItem={updateProfileItem} updateProfileItem={updateProfileItem}
/> />
)} )}

View File

@ -297,6 +297,14 @@ export async function setNativeTheme(theme: 'system' | 'light' | 'dark'): Promis
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('setNativeTheme', theme)) return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('setNativeTheme', theme))
} }
export async function openFile(
type: 'profile' | 'override',
id: string,
ext?: 'yaml' | 'js'
): Promise<void> {
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('openFile', type, id, ext))
}
export async function registerShortcut( export async function registerShortcut(
oldShortcut: string, oldShortcut: string,
newShortcut: string, newShortcut: string,