feat: improved launch settings

This commit is contained in:
2025-07-07 06:56:30 +05:00
parent b14de1d15a
commit 1b50a7d4e4
8 changed files with 510 additions and 20 deletions

View File

@ -0,0 +1,205 @@
import { useState, useEffect } from 'react';
import {
Box,
Checkbox,
Typography,
List,
ListItem,
ListItemIcon,
ListItemText,
Collapse,
CircularProgress,
} from '@mui/material';
import FolderIcon from '@mui/icons-material/Folder';
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
interface FileNode {
name: string;
path: string;
isDirectory: boolean;
children: FileNode[];
}
interface FilesSelectorProps {
packName: string;
onSelectionChange: (selectedFiles: string[]) => void;
initialSelected?: string[]; // Добавляем этот параметр
}
export default function FilesSelector({
packName,
onSelectionChange,
initialSelected = [], // Значение по умолчанию
}: FilesSelectorProps) {
const [files, setFiles] = useState<FileNode[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// Используем initialSelected для начального состояния
const [selectedFiles, setSelectedFiles] = useState<string[]>(initialSelected);
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(
new Set(),
);
useEffect(() => {
const fetchFiles = async () => {
try {
setLoading(true);
const result = await window.electron.ipcRenderer.invoke(
'get-pack-files',
packName,
);
if (result.success) {
setFiles(result.files);
} else {
setError(result.error);
}
} catch (err) {
setError('Ошибка при загрузке файлов');
} finally {
setLoading(false);
}
};
fetchFiles();
}, [packName]);
// Обработка выбора файла/папки
const handleToggle = (
path: string,
isDirectory: boolean,
children: FileNode[],
) => {
let newSelected = [...selectedFiles];
if (isDirectory) {
if (selectedFiles.includes(path)) {
// Если папка выбрана, убираем ее и все вложенные файлы
newSelected = newSelected.filter((p) => !p.startsWith(path));
} else {
// Если папка не выбрана, добавляем ее и все вложенные файлы
newSelected.push(path);
const addChildPaths = (nodes: FileNode[]) => {
for (const node of nodes) {
newSelected.push(node.path);
if (node.isDirectory) {
addChildPaths(node.children);
}
}
};
addChildPaths(children);
}
} else {
// Для обычного файла просто переключаем состояние
if (selectedFiles.includes(path)) {
newSelected = newSelected.filter((p) => p !== path);
} else {
newSelected.push(path);
}
}
setSelectedFiles(newSelected);
onSelectionChange(newSelected);
};
// Переключение раскрытия папки
const toggleFolder = (path: string) => {
const newExpanded = new Set(expandedFolders);
if (expandedFolders.has(path)) {
newExpanded.delete(path);
} else {
newExpanded.add(path);
}
setExpandedFolders(newExpanded);
};
// Рекурсивный компонент для отображения файлов и папок
const renderFileTree = (nodes: FileNode[]) => {
// Сортировка: сначала папки, потом файлы
const sortedNodes = [...nodes].sort((a, b) => {
// Если у элементов разные типы (папка/файл)
if (a.isDirectory !== b.isDirectory) {
return a.isDirectory ? -1 : 1; // Папки идут первыми
}
// Если оба элемента одного типа, сортируем по алфавиту
return a.name.localeCompare(b.name);
});
return (
<List dense>
{sortedNodes.map((node) => (
<div key={node.path}>
<ListItem
sx={{
borderRadius: '3vw',
backgroundColor: '#FFFFFF1A',
marginBottom: '1vh',
}}
>
<ListItemIcon>
<Checkbox
edge="start"
checked={selectedFiles.includes(node.path)}
onChange={() =>
handleToggle(node.path, node.isDirectory, node.children)
}
tabIndex={-1}
sx={{ color: 'white' }}
/>
</ListItemIcon>
{node.isDirectory && (
<ListItemIcon onClick={() => toggleFolder(node.path)}>
{expandedFolders.has(node.path) ? (
<ExpandLessIcon sx={{ color: 'white' }} />
) : (
<ExpandMoreIcon sx={{ color: 'white' }} />
)}
</ListItemIcon>
)}
<ListItemIcon>
{node.isDirectory ? (
<FolderIcon sx={{ color: 'white' }} />
) : (
<InsertDriveFileIcon sx={{ color: 'white' }} />
)}
</ListItemIcon>
<ListItemText
primary={node.name}
sx={{ color: 'white', fontFamily: 'Benzin-Bold' }}
/>
</ListItem>
{node.isDirectory && node.children.length > 0 && (
<Collapse
in={expandedFolders.has(node.path)}
timeout="auto"
unmountOnExit
>
<Box sx={{ pl: 4 }}>{renderFileTree(node.children)}</Box>
</Collapse>
)}
</div>
))}
</List>
);
};
if (loading) {
return <CircularProgress />;
}
if (error) {
return <Typography color="error">{error}</Typography>;
}
return (
<Box sx={{ maxHeight: '300px', overflow: 'auto' }}>
{renderFileTree(files)}
</Box>
);
}