import { useState, useEffect, useCallback, useRef } from 'react'; import { Typography, Box, Checkbox, Alert, Divider, Container, Stack, Switch, Grid, } from '@mui/material'; import WarningIcon from '@mui/icons-material/Warning'; import StorageIcon from '@mui/icons-material/Storage'; import Button from '@/components/Button'; import GlobalSnackbar, { useSnackbar } from '@/components/GlobalSnackbar'; import StorageCleanerConfirm from '@/components/StorageCleanerConfirm'; import { storageUtil } from '@/utils/chromeStorage'; import type { StorageCleanerOptions, CleaningResult, StorageCleanerPreferences, } from '@/types/storage'; import { getCurrentTab, isRestrictedUrl, clearStorage, formatCleaningResult, getCookieSize, getLocalStorageSize, getSessionStorageSize, getIndexedDBSize, getCacheStorageSize, getServiceWorkerCount, formatSize, } from '@/utils/storageCleaner'; const DEFAULT_OPTIONS: StorageCleanerOptions = { localStorage: true, sessionStorage: true, indexedDB: true, cookies: true, cacheStorage: true, serviceWorkers: true, }; const DEFAULT_PREFERENCES: StorageCleanerPreferences = { autoRefresh: true, selectedTypes: DEFAULT_OPTIONS, }; export default function StorageCleanerPage() { const [domain, setDomain] = useState(''); const [error, setError] = useState(''); const [options, setOptions] = useState(DEFAULT_OPTIONS); const [sizes, setSizes] = useState>({}); const [autoRefresh, setAutoRefresh] = useState(true); const [loading, setLoading] = useState(false); const [result, setResult] = useState(null); const [showConfirm, setShowConfirm] = useState(false); const { snackbarProps, showMessage } = useSnackbar(); const reloadTimeoutRef = useRef(null); useEffect(() => { return () => { if (reloadTimeoutRef.current) clearTimeout(reloadTimeoutRef.current); }; }, []); const loadInfo = async () => { const tab = await getCurrentTab(); if (!tab || !tab.url) { setError('无法获取当前标签页'); return; } if (isRestrictedUrl(tab.url)) { setError('存储清理功能不支持此页面'); return; } const url = tab.url; const tabId = tab.id!; setDomain(new URL(url).hostname); const [savedPrefs, cSize, lsSize, ssSize, idbSize, cacheCount, swCount] = await Promise.all([ storageUtil.get('storageCleaner/preferences', DEFAULT_PREFERENCES), getCookieSize(url), getLocalStorageSize(tabId), getSessionStorageSize(tabId), getIndexedDBSize(tabId), getCacheStorageSize(tabId), getServiceWorkerCount(tabId), ]); setAutoRefresh(savedPrefs?.autoRefresh ?? DEFAULT_PREFERENCES.autoRefresh); setOptions(savedPrefs?.selectedTypes ?? DEFAULT_PREFERENCES.selectedTypes); setSizes({ cookies: cSize, localStorage: lsSize, sessionStorage: ssSize, indexedDB: idbSize, cacheStorage: cacheCount, serviceWorkers: swCount, }); }; useEffect(() => { loadInfo(); }, []); const handleAutoRefreshChange = useCallback( async (checked: boolean) => { setAutoRefresh(checked); await storageUtil.set('storageCleaner/preferences', { autoRefresh: checked, selectedTypes: options, }); }, [options], ); const handleOptionChange = useCallback( async (key: keyof StorageCleanerOptions) => { setOptions((prev) => { const newOptions = { ...prev, [key]: !prev[key] }; storageUtil.set('storageCleaner/preferences', { autoRefresh, selectedTypes: newOptions, }); return newOptions; }); }, [autoRefresh], ); const allSelected = Object.values(options).every(Boolean); const someSelected = Object.values(options).some(Boolean) && !allSelected; const handleSelectAll = useCallback( async (checked: boolean) => { const newOptions = { localStorage: checked, sessionStorage: checked, indexedDB: checked, cookies: checked, cacheStorage: checked, serviceWorkers: checked, }; setOptions(newOptions); await storageUtil.set('storageCleaner/preferences', { autoRefresh, selectedTypes: newOptions, }); }, [autoRefresh], ); const handleClean = useCallback(async () => { const tab = await getCurrentTab(); if (!tab || !tab.id || !tab.url) { showMessage('无法获取当前标签页'); return; } setLoading(true); try { const cleaningResult = await clearStorage(tab.id, tab.url, options); setResult(cleaningResult); if (autoRefresh && cleaningResult.success && tab.id !== undefined) { showMessage('清理成功,即将刷新页面'); reloadTimeoutRef.current = setTimeout(() => { chrome.tabs.reload(tab.id!); }, 1500); } else { loadInfo(); } } catch (err) { showMessage(`清理失败: ${String(err)}`, { severity: 'error' }); } finally { setLoading(false); setShowConfirm(false); } }, [options, autoRefresh, showMessage]); if (error) { return ( } sx={{ borderRadius: 3 }}> {error} ); } // 这里的总大小仅包含以字节计算的项 const totalSize = (sizes.cookies || 0) + (sizes.localStorage || 0) + (sizes.sessionStorage || 0) + (sizes.indexedDB || 0); const OptionItem = ({ label, checked, size, isCount = false, onChange, }: { label: string; checked: boolean; size?: number; isCount?: boolean; onChange: () => void; }) => ( {label} {size !== undefined && size > 0 ? ( {isCount ? `${size} 个` : formatSize(size)} ) : ( 无数据 )} ); return ( {/* Domain Header */} 存储清理 {totalSize > 0 && ( 已占用 {formatSize(totalSize)} )} {domain || '加载中...'} {/* Storage Options Grid */} handleOptionChange('localStorage')} /> handleOptionChange('sessionStorage')} /> handleOptionChange('indexedDB')} /> handleOptionChange('cookies')} /> handleOptionChange('cacheStorage')} /> handleOptionChange('serviceWorkers')} /> 全选所有项 handleSelectAll(e.target.checked)} color="warning" sx={{ p: 0.5 }} /> {/* Auto Refresh Toggle */} 清理后自动刷新页面 handleAutoRefreshChange(e.target.checked)} color="warning" /> {/* Primary Action */} {/* Result & Refresh Secondary Action */} {result && ( {result.success ? formatCleaningResult(result) : result.error || '清理失败'} )} setShowConfirm(false)} onConfirm={handleClean} options={options} /> ); }