feat(file):增加修改文件名称的功能。
This commit is contained in:
parent
65943e33b9
commit
0eb69d777d
|
@ -1,4 +1,7 @@
|
||||||
use std::{fs::DirEntry, path::Path};
|
use std::{
|
||||||
|
fs::{self, DirEntry},
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
use mountpoints::mountinfos;
|
use mountpoints::mountinfos;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
@ -193,3 +196,17 @@ pub async fn scan_for_child_dirs<R: Runtime>(
|
||||||
child_dirs.sort_by(|a, b| a.dirname.partial_cmp(&b.dirname).unwrap());
|
child_dirs.sort_by(|a, b| a.dirname.partial_cmp(&b.dirname).unwrap());
|
||||||
Ok(child_dirs)
|
Ok(child_dirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn rename_file<R: Runtime>(
|
||||||
|
_app: tauri::AppHandle<R>,
|
||||||
|
_window: tauri::Window<R>,
|
||||||
|
store_path: String,
|
||||||
|
origin_name: String,
|
||||||
|
new_name: String,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let origin_file = PathBuf::from(store_path.clone()).join(origin_name);
|
||||||
|
let new_file = PathBuf::from(store_path).join(new_name);
|
||||||
|
fs::rename(origin_file, new_file).map_err(|e| format!("重命名问文件失败,{}", e))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@ fn main() {
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
commands::prelude::scan_directory,
|
commands::prelude::scan_directory,
|
||||||
commands::prelude::show_drives,
|
commands::prelude::show_drives,
|
||||||
commands::prelude::scan_for_child_dirs
|
commands::prelude::scan_for_child_dirs,
|
||||||
|
commands::prelude::rename_file
|
||||||
])
|
])
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
let main_window = app.get_window("main").unwrap();
|
let main_window = app.get_window("main").unwrap();
|
||||||
|
|
|
@ -123,6 +123,7 @@ export const DirTree: FC = () => {
|
||||||
const roots = useDirTreeStore(currentRootsSelector());
|
const roots = useDirTreeStore(currentRootsSelector());
|
||||||
const { focused, focus, unfocus, selected, foldDir } = useDirTreeStore();
|
const { focused, focus, unfocus, selected, foldDir } = useDirTreeStore();
|
||||||
const [viewRef, { width }] = useMeasure();
|
const [viewRef, { width }] = useMeasure();
|
||||||
|
const storeFiles = useFileListStore.use.updateFiles();
|
||||||
const ebus = useContext<EventEmitter>(EventBusContext);
|
const ebus = useContext<EventEmitter>(EventBusContext);
|
||||||
|
|
||||||
const handleFocusAction = useCallback(() => {
|
const handleFocusAction = useCallback(() => {
|
||||||
|
|
|
@ -1,18 +1,34 @@
|
||||||
//@ts-nocheck
|
//@ts-nocheck
|
||||||
import { Box, Center, Text, Tooltip } from '@mantine/core';
|
import { Box, Center, Group, Text, TextInput, Tooltip } from '@mantine/core';
|
||||||
|
import { notifications } from '@mantine/notifications';
|
||||||
|
import { invoke } from '@tauri-apps/api';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
import { head, includes, indexOf, isEmpty, length, not, pluck } from 'ramda';
|
import { equals, find, head, includes, indexOf, isEmpty, length, not, pluck, propEq } from 'ramda';
|
||||||
import { FC, useCallback, useContext, useLayoutEffect, useMemo, useRef } from 'react';
|
import {
|
||||||
|
FC,
|
||||||
|
KeyboardEvent,
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useLayoutEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState
|
||||||
|
} from 'react';
|
||||||
import { useMeasure } from 'react-use';
|
import { useMeasure } from 'react-use';
|
||||||
import { Virtuoso, VirtuosoHandle } from 'react-virtuoso';
|
import { Virtuoso, VirtuosoHandle } from 'react-virtuoso';
|
||||||
import { EventBusContext } from '../EventBus';
|
import { EventBusContext } from '../EventBus';
|
||||||
|
import { useDirTreeStore } from '../states/dirs';
|
||||||
import { sortedFilesSelector, useFileListStore } from '../states/files';
|
import { sortedFilesSelector, useFileListStore } from '../states/files';
|
||||||
|
|
||||||
export const FileList: FC = () => {
|
export const FileList: FC = () => {
|
||||||
const files = useFileListStore(sortedFilesSelector());
|
const files = useFileListStore(sortedFilesSelector());
|
||||||
|
const storeFiles = useFileListStore.use.updateFiles();
|
||||||
const activeFiles = useFileListStore.use.actives();
|
const activeFiles = useFileListStore.use.actives();
|
||||||
|
const cwd = useDirTreeStore.use.selected();
|
||||||
|
const directories = useDirTreeStore.use.directories();
|
||||||
const ebus = useContext<EventEmitter>(EventBusContext);
|
const ebus = useContext<EventEmitter>(EventBusContext);
|
||||||
const filesCount = useMemo(() => length(files), [files]);
|
const filesCount = useMemo(() => length(files), [files]);
|
||||||
|
const [editingFile, setEditing] = useState<string | null>(null);
|
||||||
const [parentRef, { height: parentHeight }] = useMeasure();
|
const [parentRef, { height: parentHeight }] = useMeasure();
|
||||||
const listRef = useRef<VirtuosoHandle | null>(null);
|
const listRef = useRef<VirtuosoHandle | null>(null);
|
||||||
const handleFileSelectAction = useCallback(
|
const handleFileSelectAction = useCallback(
|
||||||
|
@ -21,6 +37,30 @@ export const FileList: FC = () => {
|
||||||
},
|
},
|
||||||
[ebus]
|
[ebus]
|
||||||
);
|
);
|
||||||
|
const handleFileRenameAction = useCallback(
|
||||||
|
async (fileId: string, event: KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
if (equals(event.key, 'Enter')) {
|
||||||
|
const newFileName = event.target.value;
|
||||||
|
const originalFile = find(propEq('id', fileId), files);
|
||||||
|
const storeDirectory = find(propEq('id', cwd), directories);
|
||||||
|
try {
|
||||||
|
await invoke('rename_file', {
|
||||||
|
storePath: storeDirectory?.path,
|
||||||
|
originName: originalFile?.filename,
|
||||||
|
newName: newFileName
|
||||||
|
});
|
||||||
|
const refreshedFiles = await invoke('scan_directory', { target: storeDirectory?.path });
|
||||||
|
storeFiles(refreshedFiles);
|
||||||
|
ebus.emit('reset_views');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[debug]重命名文件:', e);
|
||||||
|
notifications.show({ message: `重命名文件失败,${e}`, color: 'red' });
|
||||||
|
}
|
||||||
|
setEditing(null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[files, cwd, directories]
|
||||||
|
);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
let firstActived = head(activeFiles);
|
let firstActived = head(activeFiles);
|
||||||
|
@ -51,6 +91,7 @@ export const FileList: FC = () => {
|
||||||
px={4}
|
px={4}
|
||||||
py={2}
|
py={2}
|
||||||
onClick={() => handleFileSelectAction(files[index].filename)}
|
onClick={() => handleFileSelectAction(files[index].filename)}
|
||||||
|
onDoubleClick={() => setEditing(files[index].id)}
|
||||||
sx={theme => ({
|
sx={theme => ({
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
|
@ -59,7 +100,18 @@ export const FileList: FC = () => {
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Tooltip label={files[index].filename} zIndex={999}>
|
<Tooltip label={files[index].filename} zIndex={999}>
|
||||||
|
{propEq('id', editingFile)(files[index]) ? (
|
||||||
|
<Group>
|
||||||
|
<TextInput
|
||||||
|
defaultValue={files[index].filename}
|
||||||
|
size="xs"
|
||||||
|
variant="unstyled"
|
||||||
|
onKeyDown={event => handleFileRenameAction(files[index].id, event)}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
) : (
|
||||||
<Text truncate>{files[index].filename}</Text>
|
<Text truncate>{files[index].filename}</Text>
|
||||||
|
)}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user