import { ref, computed, type Ref } from 'vue';
import type { FileInfo, DirectoryNode } from '../types';
import type { useFileStore as useFileStoreType } from '../../store/modal/file';
import { openExistingFile as openExistingFileUtil, readFileContent, formatTimestamp } from '../fileUtils';
import { openPath, revealItemInDir } from '@tauri-apps/plugin-opener';
import { useContextMenu } from './useContextMenu';
import { WINDOW_EVENTS } from '../../constants/events';
import { notifyError, notifyInfo, notifySuccess } from '../../utils/notifications';
import { MESSAGES } from '../../constants/i18n';
const STORAGE_KEY_DIRECTORY_MANAGER_EXPANDED = 'cherry-markdown-directory-manager-expanded';
const DEFAULT_DIRECTORY_MANAGER_EXPANDED = true;
* 文件管理composable
*/
type FileStoreInstance = ReturnType<typeof useFileStoreType>;
export function useFileManager(fileStore: FileStoreInstance, folderManagerRef: Ref<any>) {
const sortedRecentFiles = computed(() => fileStore.sortedRecentFiles);
const currentFilePath = computed(() => fileStore.currentFilePath);
const lastOpenedFile = computed(() => fileStore.lastOpenedFile);
* 从localStorage加载目录管理展开状态
*/
const loadDirectoryManagerExpandedState = (): boolean => {
try {
const savedState = localStorage.getItem(STORAGE_KEY_DIRECTORY_MANAGER_EXPANDED);
if (savedState === null) {
return DEFAULT_DIRECTORY_MANAGER_EXPANDED;
}
const parsed = JSON.parse(savedState);
return typeof parsed === 'boolean' ? parsed : DEFAULT_DIRECTORY_MANAGER_EXPANDED;
} catch (error) {
console.warn('加载目录管理展开状态失败:', error);
return DEFAULT_DIRECTORY_MANAGER_EXPANDED;
}
};
* 保存目录管理展开状态到localStorage
*/
const saveDirectoryManagerExpandedState = (expanded: boolean): void => {
try {
localStorage.setItem(STORAGE_KEY_DIRECTORY_MANAGER_EXPANDED, JSON.stringify(expanded));
} catch (error) {
console.warn('保存目录管理展开状态失败:', error);
}
};
const recentFilesExpanded = ref(false);
const directoryManagerExpanded = ref(loadDirectoryManagerExpandedState());
const isLoading = ref(false);
const toggleDirectoryManager = (): void => {
directoryManagerExpanded.value = !directoryManagerExpanded.value;
saveDirectoryManagerExpandedState(directoryManagerExpanded.value);
if (directoryManagerExpanded.value) {
recentFilesExpanded.value = false;
}
};
const toggleSidebar = (): void => {
fileStore.toggleSidebar();
};
const openExistingFile = async (): Promise<void> => {
if (isLoading.value) return;
isLoading.value = true;
try {
const result = await openExistingFileUtil();
if (result.success && result.data) {
await openFile(result.data);
} else if (result.error) {
notifyError(`${MESSAGES.FILE.OPEN_FAILED}: ${result.error}`);
}
} finally {
isLoading.value = false;
}
};
const openDirectory = async (): Promise<void> => {
if (isLoading.value) return;
isLoading.value = true;
try {
if (folderManagerRef.value) {
await folderManagerRef.value.openDirectory();
}
} catch (error) {
notifyError(
`${MESSAGES.DIRECTORY.OPEN_FAILED}: ${error instanceof Error ? error.message : MESSAGES.UNKNOWN_ERROR}`,
);
} finally {
isLoading.value = false;
}
};
const openFile = async (
filePath: string,
fromDirectoryManager: boolean = false,
bumpRecent: boolean = true,
): Promise<void> => {
try {
const result = await readFileContent(filePath);
if (result.success && result.data) {
window.dispatchEvent(
new CustomEvent(WINDOW_EVENTS.OPEN_FILE_FROM_SIDEBAR, {
detail: { filePath, content: result.data },
}),
);
fileStore.setCurrentFilePath(filePath);
if (bumpRecent) {
fileStore.addRecentFile(filePath);
}
if (fromDirectoryManager) {
directoryManagerExpanded.value = true;
recentFilesExpanded.value = false;
saveDirectoryManagerExpandedState(true);
} else {
recentFilesExpanded.value = true;
directoryManagerExpanded.value = false;
saveDirectoryManagerExpandedState(false);
}
} else {
notifyError(`${MESSAGES.FILE.READ_FAILED}: ${result.error}`);
}
} catch (error) {
notifyError(`${MESSAGES.FILE.OPEN_FAILED}: ${error instanceof Error ? error.message : MESSAGES.UNKNOWN_ERROR}`);
}
};
const handleOpenFile = (filePath: string, fromDirectoryManager: boolean): void => {
openFile(filePath, fromDirectoryManager);
};
const refreshDirectories = async (): Promise<void> => {
if (folderManagerRef.value) {
await folderManagerRef.value.refreshDirectories();
}
};
const removeFromRecent = (filePath: string): void => {
try {
fileStore.removeRecentFile(filePath);
notifySuccess(MESSAGES.FILE_MANAGEMENT.REMOVE_SUCCESS);
void refreshDirectories();
} catch (error) {
notifyError(
`${MESSAGES.FILE_MANAGEMENT.REMOVE_FAILED}: ${error instanceof Error ? error.message : MESSAGES.UNKNOWN_ERROR}`,
);
}
};
const copyFilePath = async (filePath: string): Promise<void> => {
try {
await navigator.clipboard.writeText(filePath);
notifyInfo(MESSAGES.CLIPBOARD.COPY_PATH_SUCCESS);
hideContextMenu();
} catch (error) {
notifyError(
`${MESSAGES.CLIPBOARD.COPY_PATH_FAILED}: ${error instanceof Error ? error.message : MESSAGES.UNKNOWN_ERROR}`,
);
}
};
const openInExplorer = async (filePath: string): Promise<void> => {
try {
const directoryPath = filePath.replace(/\\/g, '/').replace(/\/[^\\/]*$/, '');
try {
await revealItemInDir(filePath);
hideContextMenu();
return;
} catch (_) {
}
await openPath(directoryPath);
hideContextMenu();
} catch (error) {
notifyError(
`${MESSAGES.EXPLORER.OPEN_FAILED}: ${error instanceof Error ? error.message : MESSAGES.UNKNOWN_ERROR}`,
);
try {
await navigator.clipboard.writeText(filePath);
notifyInfo(`${MESSAGES.CLIPBOARD.COPY_PATH_FALLBACK}: ${filePath}`);
} catch (clipboardError) {
notifyError(
`${MESSAGES.CLIPBOARD.COPY_PATH_FAILED}: ${clipboardError instanceof Error ? clipboardError.message : MESSAGES.UNKNOWN_ERROR}`,
);
}
}
};
const mapToFileInfo = (file: FileInfo | DirectoryNode): FileInfo => ({
path: file.path,
name: file.name,
lastAccessed: 'lastAccessed' in file && file.lastAccessed ? file.lastAccessed : Date.now(),
size: 'size' in file ? file.size : undefined,
type: 'type' in file ? file.type : undefined,
});
const { contextMenu, showContextMenu, hideContextMenu } = useContextMenu(mapToFileInfo);
const formatTime = (timestamp: number): string => {
return formatTimestamp(timestamp);
};
return {
sortedRecentFiles,
currentFilePath,
lastOpenedFile,
recentFilesExpanded,
directoryManagerExpanded,
contextMenu,
isLoading,
toggleDirectoryManager,
toggleSidebar,
openExistingFile,
openDirectory,
openFile,
handleOpenFile,
refreshDirectories,
removeFromRecent,
copyFilePath,
openInExplorer,
showContextMenu,
hideContextMenu,
formatTime,
};
}