import { useState, useEffect, useCallback } from 'react'; import AsyncStorage from '@react-native-async-storage/async-storage'; import * as FileSystem from 'expo-file-system'; import { DATA_DIRECTORY_URI_KEY } from '@/constants/Settings'; import { StorageAccessFramework } from 'expo-file-system'; interface FileEntry { name: string; uri: string; datetime: Date; size: number; } interface PrettyNameOptions { pathContext?: 'full' | 'short'; } interface FileInfoWithSize { uri: string; exists: boolean; isDirectory: boolean | null; modificationTime: number | null; size: number; } function datetimeFromFilename(filename: string): Date { const match = filename.match(/(\d+)\.md$/); if (match) { const datePart = parseInt(match[1]) * 1000; // Convert seconds to milliseconds const date = new Date(datePart); if (!isNaN(date.getTime())) { return date; } } return new Date(); } export function prettyName(uri: string | null, options: PrettyNameOptions = {}) { if (!uri) return null; const { pathContext = 'short' } = options; var returnString = ""; if (pathContext === 'full') { returnString = "/"; } const decodedUri = decodeURIComponent(uri); const match = decodedUri.match(/.*\/primary:(.+)/); if (match) { if (pathContext === 'short') { const filename = match[1].split('/').pop() || "Unknown"; returnString = returnString.concat(filename); } else { returnString = returnString.concat(match[1]); } } else { // Fallback to your original logic returnString = returnString.concat(uri.split('%3A').pop() || "Unknown"); } return returnString; } export function useFileSystem() { const [dataDirectoryUri, setDataDirectoryUri] = useState(null); const [isLoading, setIsLoading] = useState(true); const [files, setFiles] = useState([]); const [directorySize, setDirectorySize] = useState(0); // Load saved directory URI useEffect(() => { const loadDirectoryUri = async () => { try { const savedUri = await AsyncStorage.getItem(DATA_DIRECTORY_URI_KEY); if (savedUri) { setDataDirectoryUri(savedUri); } } catch (error) { console.error('Error loading directory URI:', error); } finally { setIsLoading(false); } }; loadDirectoryUri(); }, []); // Load files when directory changes const loadFiles = useCallback(async () => { if (!dataDirectoryUri) return; try { const dirContents = await StorageAccessFramework.readDirectoryAsync(dataDirectoryUri); const markdownFiles = []; let totalSize = 0; for (const fileName of dirContents.filter(name => name.endsWith('.md'))) { try { const fileInfo = await FileSystem.getInfoAsync(fileName) as FileInfoWithSize; const fileEntry = { name: prettyName(fileName) ?? "", uri: fileInfo.uri, datetime: datetimeFromFilename(fileName), size: fileInfo.size, }; markdownFiles.push(fileEntry); totalSize += fileEntry.size; } catch (error) { console.warn(`Error getting info for file ${fileName}:`, error); } } markdownFiles.sort((a, b) => b.datetime.getTime() - a.datetime.getTime()); // Sort by datetime descending setFiles(markdownFiles); setDirectorySize(totalSize); } catch (error) { console.error('Error loading files:', error); } }, [dataDirectoryUri]); useEffect(() => { loadFiles(); }, [loadFiles]); const writeFile = useCallback(async (filename: string, content: string) => { if (!dataDirectoryUri) throw new Error('No directory selected'); const fileUri = `${dataDirectoryUri}/${filename}`; await FileSystem.writeAsStringAsync(fileUri, content); await loadFiles(); // Refresh file list }, [dataDirectoryUri, loadFiles]); const readFile = useCallback(async (filename: string): Promise => { if (!dataDirectoryUri) throw new Error('No directory selected'); const fileUri = `${dataDirectoryUri}/${filename}`; return await FileSystem.readAsStringAsync(fileUri); }, [dataDirectoryUri]); const saveDataDirectoryUri = useCallback(async (uri: string | null) => { try { if (uri) { await AsyncStorage.setItem(DATA_DIRECTORY_URI_KEY, uri); } else { await AsyncStorage.removeItem(DATA_DIRECTORY_URI_KEY); } setDataDirectoryUri(uri); // Refresh files when directory changes if (uri) { await loadFiles(); } else { setFiles([]); } } catch (error) { console.error('Error updating directory URI:', error); } }, [loadFiles]); return { dataDirectoryUri, saveDataDirectoryUri, isLoading, files, writeFile, readFile, loadFiles, hasDirectory: !!dataDirectoryUri, directorySize, }; }