convert cleanup dialog to radix

pull/2575/head
Mikael Finstad 8 months ago
parent 251106dd6d
commit 25110600bc
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26

@ -78,7 +78,7 @@ import {
import getSwal, { errorToast, showPlaybackFailedMessage } from './swal';
import { adjustRate } from './util/rate-calculator';
import { askExtractFramesAsImages } from './dialogs/extractFrames';
import { askForOutDir, askForImportChapters, askForFileOpenAction, showCleanupFilesDialog, showDiskFull, showExportFailedDialog, showConcatFailedDialog, openYouTubeChaptersDialog, showRefuseToOverwrite, showOpenDialog, showMuxNotSupported, promptDownloadMediaUrl, CleanupChoicesType, showOutputNotWritable, deleteFiles, mustDisallowVob, toastError } from './dialogs';
import { askForOutDir, askForImportChapters, askForFileOpenAction, showDiskFull, showExportFailedDialog, showConcatFailedDialog, openYouTubeChaptersDialog, showRefuseToOverwrite, showOpenDialog, showMuxNotSupported, promptDownloadMediaUrl, CleanupChoicesType, showOutputNotWritable, deleteFiles, mustDisallowVob, toastError } from './dialogs';
import { openSendReportDialog } from './reporting';
import { fallbackLng } from './i18n';
import { sortSegments, convertSegmentsToChaptersWithGaps, hasAnySegmentOverlap, isDurationValid, getPlaybackAction, getSegmentTags, filterNonMarkers } from './segments';
@ -178,7 +178,7 @@ function App() {
const { withErrorHandling, handleError, genericError, setGenericError } = useErrorHandling();
const { showGenericDialog, genericDialog, closeGenericDialog, confirmDialog, openExportFinishedDialog, openCutFinishedDialog, openConcatFinishedDialog } = useDialog();
const { showGenericDialog, genericDialog, closeGenericDialog, confirmDialog, openExportFinishedDialog, openCutFinishedDialog, openConcatFinishedDialog, openCleanupFilesDialog } = useDialog();
// Note that each action may be multiple key bindings and this will only be the first binding for each action
const keyBindingByAction = useMemo(() => Object.fromEntries(keyBindings.map((binding) => [binding.action, binding])), [keyBindings]);
@ -995,13 +995,12 @@ function App() {
}, (err) => i18n.t('Unable to delete file: {{message}}', { message: err instanceof Error ? err.message : String(err) }));
}, [batchListRemoveFile, clearSegments, filePath, previewFilePath, projectFileSavePath, resetState, setWorking, withErrorHandling]);
// todo convert to Dialog component
const askForCleanupChoices = useCallback(async () => {
const trashResponse = await showCleanupFilesDialog(cleanupChoices);
const trashResponse = await openCleanupFilesDialog(cleanupChoices);
if (!trashResponse) return undefined; // Canceled
setCleanupChoices(trashResponse); // Store for next time
return trashResponse;
}, [cleanupChoices, setCleanupChoices]);
}, [cleanupChoices, openCleanupFilesDialog, setCleanupChoices]);
const cleanupFilesWithDialog = useCallback(async () => {
let response: CleanupChoicesType | undefined = cleanupChoices;

@ -7,7 +7,8 @@ import * as Dialog from './Dialog';
import * as AlertDialog from './AlertDialog';
import { DialogButton } from './Button';
import { showItemInFolder } from '../util';
import { ListItem, Notices, OutputIncorrectSeeHelpMenu, UnorderedList, Warnings } from '../dialogs';
import { CleanupChoice, CleanupChoicesType, ListItem, Notices, OutputIncorrectSeeHelpMenu, UnorderedList, Warnings } from '../dialogs';
import Checkbox from './Checkbox';
export interface GenericDialogParams {
@ -201,6 +202,79 @@ export function useDialog() {
});
}, [openExportFinishedDialog, t]);
async function openCleanupFilesDialog(cleanupChoicesInitial: CleanupChoicesType) {
return new Promise<CleanupChoicesType | undefined>((resolve) => {
function CleanupChoices() {
const [choices, setChoices] = useState(cleanupChoicesInitial);
const getVal = (key: CleanupChoice) => !!choices[key];
const onChange = (key: CleanupChoice, val: boolean | string) => setChoices((oldChoices) => {
const newChoices = { ...oldChoices, [key]: Boolean(val) };
if ((newChoices.trashSourceFile || newChoices.trashTmpFiles) && !newChoices.closeFile) {
newChoices.closeFile = true;
}
return newChoices;
});
const trashTmpFiles = getVal('trashTmpFiles');
const trashSourceFile = getVal('trashSourceFile');
const trashProjectFile = getVal('trashProjectFile');
const deleteIfTrashFails = getVal('deleteIfTrashFails');
const closeFile = getVal('closeFile');
const askForCleanup = getVal('askForCleanup');
const cleanupAfterExport = getVal('cleanupAfterExport');
const { onOpenChange } = useGenericDialogContext();
const handleOkClick = useCallback(() => {
resolve(choices);
onOpenChange(false);
}, [choices, onOpenChange]);
return (
<AlertDialog.Content aria-describedby={undefined} style={{ width: '80vw' }}>
<AlertDialog.Title>
{t('Cleanup files?')}
</AlertDialog.Title>
<AlertDialog.Description>
{t('What do you want to do after exporting a file or when pressing the "delete source file" button?')}
</AlertDialog.Description>
<Checkbox label={t('Close currently opened file')} checked={closeFile} disabled={trashSourceFile || trashTmpFiles} onCheckedChange={(checked) => onChange('closeFile', checked)} />
<div style={{ marginBottom: '2em' }}>
<Checkbox label={t('Trash auto-generated files')} checked={trashTmpFiles} onCheckedChange={(checked) => onChange('trashTmpFiles', checked)} />
<Checkbox label={t('Trash original source file')} checked={trashSourceFile} onCheckedChange={(checked) => onChange('trashSourceFile', checked)} />
<Checkbox label={t('Trash project LLC file')} checked={trashProjectFile} onCheckedChange={(checked) => onChange('trashProjectFile', checked)} />
<Checkbox label={t('Permanently delete the files if trash fails?')} disabled={!(trashTmpFiles || trashProjectFile || trashSourceFile)} checked={deleteIfTrashFails} onCheckedChange={(checked) => onChange('deleteIfTrashFails', checked)} />
</div>
<div style={{ marginBottom: '2em' }}>
<Checkbox label={t('Show this dialog every time?')} checked={askForCleanup} onCheckedChange={(checked) => onChange('askForCleanup', checked)} />
<Checkbox label={t('Do all of this automatically after exporting a file?')} checked={cleanupAfterExport} onCheckedChange={(checked) => onChange('cleanupAfterExport', checked)} />
</div>
<Dialog.ButtonRow>
<AlertDialog.Cancel asChild>
<DialogButton>{t('Cancel')}</DialogButton>
</AlertDialog.Cancel>
<DialogButton onClick={handleOkClick} primary>{t('Confirm')}</DialogButton>
</Dialog.ButtonRow>
</AlertDialog.Content>
);
}
showGenericDialog({
isAlert: true,
content: <CleanupChoices />,
onClose: () => resolve(undefined),
});
});
}
return {
genericDialog,
closeGenericDialog,
@ -209,5 +283,6 @@ export function useDialog() {
openExportFinishedDialog,
openCutFinishedDialog,
openConcatFinishedDialog,
openCleanupFilesDialog,
};
}

@ -1,4 +1,4 @@
import { CSSProperties, ReactNode, useState } from 'react';
import { CSSProperties, ReactNode } from 'react';
import i18n from 'i18next';
import { Trans } from 'react-i18next';
import invariant from 'tiny-invariant';
@ -9,7 +9,6 @@ import pMap from 'p-map';
import { formatDuration } from '../util/duration';
import { parseYouTube } from '../edlFormats';
import CopyClipboardButton from '../components/CopyClipboardButton';
import Checkbox from '../components/Checkbox';
import { appPath, isMac, isMasBuild, isWindows, isWindowsStoreBuild, testFailFsOperation, trashFile, unlinkWithRetry } from '../util';
import { ParseTimecode } from '../types';
import { FindKeyframeMode } from '../ffmpeg';
@ -355,66 +354,6 @@ export interface CleanupChoicesType {
}
export type CleanupChoice = keyof CleanupChoicesType;
const CleanupChoices = ({ cleanupChoicesInitial, onChange: onChangeProp }: { cleanupChoicesInitial: CleanupChoicesType, onChange: (v: CleanupChoicesType) => void }) => {
const [choices, setChoices] = useState(cleanupChoicesInitial);
const getVal = (key: CleanupChoice) => !!choices[key];
const onChange = (key: CleanupChoice, val: boolean | string) => setChoices((oldChoices) => {
const newChoices = { ...oldChoices, [key]: Boolean(val) };
if ((newChoices.trashSourceFile || newChoices.trashTmpFiles) && !newChoices.closeFile) {
newChoices.closeFile = true;
}
onChangeProp(newChoices);
return newChoices;
});
const trashTmpFiles = getVal('trashTmpFiles');
const trashSourceFile = getVal('trashSourceFile');
const trashProjectFile = getVal('trashProjectFile');
const deleteIfTrashFails = getVal('deleteIfTrashFails');
const closeFile = getVal('closeFile');
const askForCleanup = getVal('askForCleanup');
const cleanupAfterExport = getVal('cleanupAfterExport');
return (
<div style={{ textAlign: 'left' }}>
<p>{i18n.t('What do you want to do after exporting a file or when pressing the "delete source file" button?')}</p>
<Checkbox label={i18n.t('Close currently opened file')} checked={closeFile} disabled={trashSourceFile || trashTmpFiles} onCheckedChange={(checked) => onChange('closeFile', checked)} />
<div style={{ marginTop: 25 }}>
<Checkbox label={i18n.t('Trash auto-generated files')} checked={trashTmpFiles} onCheckedChange={(checked) => onChange('trashTmpFiles', checked)} />
<Checkbox label={i18n.t('Trash original source file')} checked={trashSourceFile} onCheckedChange={(checked) => onChange('trashSourceFile', checked)} />
<Checkbox label={i18n.t('Trash project LLC file')} checked={trashProjectFile} onCheckedChange={(checked) => onChange('trashProjectFile', checked)} />
<Checkbox label={i18n.t('Permanently delete the files if trash fails?')} disabled={!(trashTmpFiles || trashProjectFile || trashSourceFile)} checked={deleteIfTrashFails} onCheckedChange={(checked) => onChange('deleteIfTrashFails', checked)} />
</div>
<div style={{ marginTop: 25 }}>
<Checkbox label={i18n.t('Show this dialog every time?')} checked={askForCleanup} onCheckedChange={(checked) => onChange('askForCleanup', checked)} />
<Checkbox label={i18n.t('Do all of this automatically after exporting a file?')} checked={cleanupAfterExport} onCheckedChange={(checked) => onChange('cleanupAfterExport', checked)} />
</div>
</div>
);
};
export async function showCleanupFilesDialog(cleanupChoicesIn: CleanupChoicesType) {
let cleanupChoices = cleanupChoicesIn;
const { value } = await getSwal().ReactSwal.fire<string>({
title: i18n.t('Cleanup files?'),
html: <CleanupChoices cleanupChoicesInitial={cleanupChoices} onChange={(newChoices) => { cleanupChoices = newChoices; }} />,
confirmButtonText: i18n.t('Confirm'),
confirmButtonColor: '#d33',
showCancelButton: true,
cancelButtonText: i18n.t('Cancel'),
});
if (value) return cleanupChoices;
return undefined;
}
function parseBytesHuman(str: string) {
const match = str.replaceAll(/\s/g, '').match(/^(\d+)([gkmt]?)b$/i);
if (!match) return undefined;

Loading…
Cancel
Save