import { Button, List, ListItem, ListItemText, Stack, Typography, } from '@mui/material' import { open as openDialog } from '@tauri-apps/plugin-dialog' import { useLockFn } from 'ahooks' import type { ReactNode, Ref } from 'react' import { useCallback, useImperativeHandle, useState } from 'react' import { useTranslation } from 'react-i18next' import { BaseDialog, DialogRef } from '@/components/base' import { useVerge } from '@/hooks/use-verge' import { createLocalBackup, createWebdavBackup, importLocalBackup, } from '@/services/cmds' import { mutate } from '@/services/mutate' import { errorDetail, showNotice } from '@/services/notice-service' import { buildWebdavSignature, setWebdavStatus } from '@/services/webdav-status' import { AutoBackupSettings } from './auto-backup-settings' import { BackupHistoryViewer } from './backup-history-viewer' import { BackupWebdavDialog } from './backup-webdav-dialog' type BackupSource = 'local' | 'webdav' export function BackupViewer({ ref }: { ref?: Ref }) { const { t } = useTranslation() const { verge } = useVerge() const [open, setOpen] = useState(false) const [busyAction, setBusyAction] = useState(null) const [localImporting, setLocalImporting] = useState(false) const [historyOpen, setHistoryOpen] = useState(false) const [historySource, setHistorySource] = useState('local') const [historyPage, setHistoryPage] = useState(0) const [webdavDialogOpen, setWebdavDialogOpen] = useState(false) const webdavSignature = buildWebdavSignature(verge) useImperativeHandle(ref, () => ({ open: () => setOpen(true), close: () => setOpen(false), })) const openHistory = (target: BackupSource) => { setHistorySource(target) setHistoryPage(0) setHistoryOpen(true) } const handleBackup = useLockFn(async (target: BackupSource) => { try { setBusyAction(target) if (target === 'local') { await mutate(() => createLocalBackup(), { id: 'create-local-backup', errorNotice: false, successNotice: 'settings.modals.backup.messages.localBackupCreated', }) } else { await mutate(() => createWebdavBackup(), { id: 'create-webdav-backup', errorNotice: false, successNotice: 'settings.modals.backup.messages.backupCreated', onFulfilled: () => setWebdavStatus(webdavSignature, 'ready'), }) } } catch (error) { console.error(error) showNotice.error( target === 'local' ? 'settings.modals.backup.messages.localBackupFailed' : 'settings.modals.backup.messages.backupFailed', target === 'local' ? undefined : { error: errorDetail(error) }, ) if (target === 'webdav') { setWebdavStatus(webdavSignature, 'failed') } } finally { setBusyAction(null) } }) const handleImport = useLockFn(async () => { const selected = await openDialog({ multiple: false, filters: [{ name: 'Backup File', extensions: ['zip'] }], }) if (!selected || Array.isArray(selected)) return try { setLocalImporting(true) await mutate(() => importLocalBackup(selected), { id: 'import-local-backup', errorNotice: false, successNotice: 'settings.modals.backup.messages.localBackupImported', }) openHistory('local') } catch (error) { console.error(error) showNotice.error( 'settings.modals.backup.messages.localBackupImportFailed', { error: errorDetail(error) }, ) } finally { setLocalImporting(false) } }) const setWebdavBusy = useCallback( (loading: boolean) => { setBusyAction(loading ? 'webdav' : null) }, [setBusyAction], ) const isLocalBusy = busyAction === 'local' || localImporting return ( setOpen(false)} onClose={() => setOpen(false)} > `1px solid ${theme.palette.divider}`, borderRadius: 2, p: 2, }} > {t('settings.modals.backup.auto.title')} `1px solid ${theme.palette.divider}`, borderRadius: 2, p: 2, }} > {t('settings.modals.backup.manual.title')} {( [ { key: 'local' as BackupSource, title: t('settings.modals.backup.tabs.local'), description: t('settings.modals.backup.manual.local'), actions: [ , , , ], }, { key: 'webdav' as BackupSource, title: t('settings.modals.backup.tabs.webdav'), description: t('settings.modals.backup.manual.webdav'), actions: [ , , , ], }, ] satisfies Array<{ key: BackupSource title: string description: string actions: ReactNode[] }> ).map((item, idx) => ( {item.actions} ))} setHistoryOpen(false)} /> setWebdavDialogOpen(false)} onBackupSuccess={() => openHistory('webdav')} setBusy={setWebdavBusy} /> ) }