mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-25 11:43:17 +01:00
improve export confirm #1798
This commit is contained in:
parent
b7cf87a0e2
commit
ae8f6d4be1
@ -29,9 +29,9 @@ const boxStyle = { margin: '15px 15px 50px 15px', borderRadius: 10, padding: '10
|
||||
|
||||
const outDirStyle = { ...highlightedTextStyle, wordBreak: 'break-all', cursor: 'pointer' };
|
||||
|
||||
const warningStyle = { color: 'var(--red11)', fontSize: '80%' };
|
||||
const warningStyle = { color: 'var(--red11)', fontSize: '80%', marginBottom: '.5em' };
|
||||
|
||||
const HelpIcon = ({ onClick, style }) => <IoIosHelpCircle size={20} role="button" onClick={withBlur(onClick)} style={{ cursor: 'pointer', color: primaryTextColor, verticalAlign: 'middle', marginLeft: 5, ...style }} />;
|
||||
const HelpIcon = ({ onClick, style }) => <IoIosHelpCircle size={20} role="button" onClick={withBlur(onClick)} style={{ cursor: 'pointer', color: primaryTextColor, verticalAlign: 'middle', ...style }} />;
|
||||
|
||||
const ExportConfirm = memo(({
|
||||
areWeCutting, selectedSegments, segmentsToExport, willMerge, visible, onClosePress, onExportConfirm,
|
||||
@ -41,7 +41,7 @@ const ExportConfirm = memo(({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { changeOutDir, keyframeCut, toggleKeyframeCut, preserveMovData, movFastStart, avoidNegativeTs, setAvoidNegativeTs, autoDeleteMergedSegments, exportConfirmEnabled, toggleExportConfirmEnabled, segmentsToChapters, toggleSegmentsToChapters, preserveMetadataOnMerge, togglePreserveMetadataOnMerge, enableSmartCut, setEnableSmartCut, effectiveExportMode, enableOverwriteOutput, setEnableOverwriteOutput } = useUserSettings();
|
||||
const { changeOutDir, keyframeCut, toggleKeyframeCut, preserveMovData, movFastStart, avoidNegativeTs, setAvoidNegativeTs, autoDeleteMergedSegments, exportConfirmEnabled, toggleExportConfirmEnabled, segmentsToChapters, toggleSegmentsToChapters, preserveMetadataOnMerge, togglePreserveMetadataOnMerge, enableSmartCut, setEnableSmartCut, effectiveExportMode, enableOverwriteOutput, setEnableOverwriteOutput, ffmpegExperimental, setFfmpegExperimental } = useUserSettings();
|
||||
|
||||
const isMov = ffmpegIsMov(outFormat);
|
||||
const isIpod = outFormat === 'ipod';
|
||||
@ -109,6 +109,10 @@ const ExportConfirm = memo(({
|
||||
toast.fire({ icon: 'info', timer: 10000, text: `${avoidNegativeTs}: ${texts[avoidNegativeTs]}` });
|
||||
}, [avoidNegativeTs]);
|
||||
|
||||
const onFfmpegExperimentalHelpPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: t('Enable experimental ffmpeg features flag?') });
|
||||
}, [t]);
|
||||
|
||||
const canEditTemplate = !willMerge || !autoDeleteMergedSegments;
|
||||
|
||||
// https://stackoverflow.com/questions/33454533/cant-scroll-to-top-of-flex-item-that-is-overflowing-container
|
||||
@ -148,10 +152,14 @@ const ExportConfirm = memo(({
|
||||
<ExportModeButton selectedSegments={selectedSegments} />
|
||||
</td>
|
||||
<td>
|
||||
{effectiveExportMode === 'sesgments_to_chapters' && <WarningSignIcon verticalAlign="middle" color="warning" marginLeft=".3em" title={i18n.t('Segments to chapters mode is active, this means that the file will not be cut. Instead chapters will be created from the segments.')} />}
|
||||
<HelpIcon onClick={onExportModeHelpPress} />
|
||||
{effectiveExportMode === 'sesgments_to_chapters' ? (
|
||||
<WarningSignIcon verticalAlign="middle" color="warning" title={i18n.t('Segments to chapters mode is active, this means that the file will not be cut. Instead chapters will be created from the segments.')} />
|
||||
) : (
|
||||
<HelpIcon onClick={onExportModeHelpPress} />
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
{t('Output container format:')}
|
||||
@ -163,6 +171,7 @@ const ExportConfirm = memo(({
|
||||
<HelpIcon onClick={onOutFmtHelpPress} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<Trans>Input has {{ numStreamsTotal }} tracks</Trans>
|
||||
@ -174,10 +183,14 @@ const ExportConfirm = memo(({
|
||||
<HighlightedText style={{ cursor: 'pointer' }} onClick={onShowStreamsSelectorClick}><Trans>Keeping {{ numStreamsToCopy }} tracks</Trans></HighlightedText>
|
||||
</td>
|
||||
<td>
|
||||
{areWeCuttingProblematicStreams && <WarningSignIcon verticalAlign="middle" color="warning" marginLeft=".3em" />}
|
||||
<HelpIcon onClick={onTracksHelpPress} />
|
||||
{areWeCuttingProblematicStreams ? (
|
||||
<WarningSignIcon verticalAlign="middle" color="warning" />
|
||||
) : (
|
||||
<HelpIcon onClick={onTracksHelpPress} />
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
{t('Save output to path:')}
|
||||
@ -226,6 +239,7 @@ const ExportConfirm = memo(({
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3 style={{ marginBottom: '.5em' }}>{t('Advanced options')}</h3>
|
||||
|
||||
<table className={styles.options}>
|
||||
@ -243,6 +257,7 @@ const ExportConfirm = memo(({
|
||||
<HelpIcon onClick={onSegmentsToChaptersHelpPress} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
{t('Preserve original metadata when merging? (slow)')}
|
||||
@ -274,10 +289,14 @@ const ExportConfirm = memo(({
|
||||
<Switch checked={enableSmartCut} onCheckedChange={() => setEnableSmartCut((v) => !v)} />
|
||||
</td>
|
||||
<td>
|
||||
{needSmartCut && <WarningSignIcon verticalAlign="middle" color="warning" marginLeft=".3em" title={i18n.t('Experimental functionality has been activated!')} />}
|
||||
<HelpIcon onClick={onSmartCutHelpPress} />
|
||||
{needSmartCut ? (
|
||||
<WarningSignIcon verticalAlign="middle" color="warning" title={i18n.t('Experimental functionality has been activated!')} />
|
||||
) : (
|
||||
<HelpIcon onClick={onSmartCutHelpPress} />
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{!needSmartCut && (
|
||||
<tr>
|
||||
<td>
|
||||
@ -288,8 +307,11 @@ const ExportConfirm = memo(({
|
||||
<Switch checked={keyframeCut} onCheckedChange={() => toggleKeyframeCut()} />
|
||||
</td>
|
||||
<td>
|
||||
{!keyframeCut && <WarningSignIcon verticalAlign="middle" color="warning" marginLeft=".3em" />}
|
||||
<HelpIcon onClick={onKeyframeCutHelpPress} />
|
||||
{!keyframeCut ? (
|
||||
<WarningSignIcon verticalAlign="middle" color="warning" />
|
||||
) : (
|
||||
<HelpIcon onClick={onKeyframeCutHelpPress} />
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
@ -304,11 +326,17 @@ const ExportConfirm = memo(({
|
||||
</td>
|
||||
<td>
|
||||
<MovFastStartButton />
|
||||
{isIpod && !movFastStart && <div style={warningStyle}>{t('For the ipod format, it is recommended to activate this option')}</div>}
|
||||
</td>
|
||||
<td>
|
||||
<HelpIcon onClick={onMovFastStartHelpPress} /> {isIpod && !movFastStart && <span style={warningStyle}>{t('For the ipod format, it is recommended to activate this option')}</span>}
|
||||
{isIpod && !movFastStart ? (
|
||||
<WarningSignIcon verticalAlign="middle" color="warning" />
|
||||
) : (
|
||||
<HelpIcon onClick={onMovFastStartHelpPress} />
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
{t('Preserve all MP4/MOV metadata?')}
|
||||
@ -318,8 +346,11 @@ const ExportConfirm = memo(({
|
||||
<PreserveMovDataButton />
|
||||
</td>
|
||||
<td>
|
||||
{isIpod && preserveMovData && <WarningSignIcon verticalAlign="middle" color="warning" marginLeft=".3em" />}
|
||||
<HelpIcon onClick={onPreserveMovDataHelpPress} />
|
||||
{isIpod && preserveMovData ? (
|
||||
<WarningSignIcon verticalAlign="middle" color="warning" />
|
||||
) : (
|
||||
<HelpIcon onClick={onPreserveMovDataHelpPress} />
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
</>
|
||||
@ -340,11 +371,26 @@ const ExportConfirm = memo(({
|
||||
</Select>
|
||||
</td>
|
||||
<td>
|
||||
{!['make_zero', 'auto'].includes(avoidNegativeTs) && <WarningSignIcon verticalAlign="middle" color="warning" marginLeft=".3em" />}
|
||||
<HelpIcon onClick={onAvoidNegativeTsHelpPress} />
|
||||
{!['make_zero', 'auto'].includes(avoidNegativeTs) ? (
|
||||
<WarningSignIcon verticalAlign="middle" color="warning" />
|
||||
) : (
|
||||
<HelpIcon onClick={onAvoidNegativeTsHelpPress} />
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
{t('"ffmpeg" experimental flag')}
|
||||
</td>
|
||||
<td>
|
||||
<Switch checked={ffmpegExperimental} onCheckedChange={setFfmpegExperimental} />
|
||||
</td>
|
||||
<td>
|
||||
<HelpIcon onClick={onFfmpegExperimentalHelpPress} />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@ -357,7 +403,7 @@ const ExportConfirm = memo(({
|
||||
animate={{ opacity: 1, translateX: 0 }}
|
||||
exit={{ opacity: 0, translateX: 50 }}
|
||||
transition={{ duration: 0.4, easings: ['easeOut'] }}
|
||||
style={{ display: 'flex', alignItems: 'flex-end' }}
|
||||
style={{ display: 'flex', alignItems: 'flex-end', background: 'rgba(0,0,0,0.5)' }}
|
||||
>
|
||||
<ToggleExportConfirm size={25} />
|
||||
<div style={{ fontSize: 13, marginLeft: 3, marginRight: 7, maxWidth: 120, lineHeight: '100%', color: exportConfirmEnabled ? 'var(--gray12)' : 'var(--gray11)', cursor: 'pointer' }} role="button" onClick={toggleExportConfirmEnabled}>{t('Show this page before exporting?')}</div>
|
||||
|
@ -28,14 +28,15 @@ table.options {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.options td:last-child {
|
||||
text-align: right;
|
||||
width: 3em;
|
||||
}
|
||||
table.options td:nth-child(2) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
table.options td:last-child {
|
||||
text-align: center;
|
||||
width: 1.7em;
|
||||
}
|
||||
|
||||
table.options td {
|
||||
vertical-align: top;
|
||||
}
|
@ -120,7 +120,7 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate
|
||||
{outSegFileNames != null && <Button height={20} onClick={onAllSegmentsPreviewPress} marginLeft={5}>{t('Preview')}</Button>}
|
||||
|
||||
<IconButton title={t('Reset')} icon={ResetIcon} height={20} onClick={reset} marginLeft={5} intent="danger" />
|
||||
<IconButton title={t('Close')} icon={TickIcon} height={20} onClick={onHideClick} marginLeft={5} intent="success" />
|
||||
<IconButton title={t('Close')} icon={TickIcon} height={20} onClick={onHideClick} marginLeft={5} intent="success" appearance="primary" />
|
||||
</div>
|
||||
|
||||
<div style={{ fontSize: '.8em', color: 'var(--gray11)', display: 'flex', gap: '.3em', flexWrap: 'wrap', alignItems: 'center', marginBottom: '.7em' }}>
|
||||
@ -134,11 +134,16 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate
|
||||
|
||||
{error != null && <div style={{ marginBottom: '1em' }}><ErrorIcon color="var(--red9)" size={14} verticalAlign="baseline" /> {i18n.t('There is an error in the file name template:')} {error}</div>}
|
||||
|
||||
{isMissingExtension && <div style={{ marginBottom: '1em' }}><WarningSignIcon color="var(--amber9)" /> {i18n.t('The file name template is missing {{ext}} and will result in a file without the suggested extension. This may result in an unplayable output file.', { ext: extVar })}</div>}
|
||||
{isMissingExtension && (
|
||||
<div style={{ marginBottom: '1em' }}>
|
||||
<WarningSignIcon verticalAlign="middle" color="var(--amber9)" />{' '}
|
||||
{i18n.t('The file name template is missing {{ext}} and will result in a file without the suggested extension. This may result in an unplayable output file.', { ext: extVar })}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{hasTextNumericPaddedValue && (
|
||||
<div style={{ marginBottom: '.3em' }}>
|
||||
<Select value={outputFileNameMinZeroPadding} onChange={(e) => setOutputFileNameMinZeroPadding(parseInt(e.target.value, 10))} style={{ marginRight: '1em' }}>
|
||||
<Select value={outputFileNameMinZeroPadding} onChange={(e) => setOutputFileNameMinZeroPadding(parseInt(e.target.value, 10))} style={{ marginRight: '1em', fontSize: '1em' }}>
|
||||
{Array.from({ length: 10 }).map((v, i) => i + 1).map((v) => <option key={v} value={v}>{v}</option>)}
|
||||
</Select>
|
||||
Minimum numeric padded length
|
||||
@ -149,7 +154,7 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate
|
||||
<Switch checked={safeOutputFileName} onCheckedChange={toggleSafeOutputFileName} style={{ verticalAlign: 'middle', marginRight: '.5em' }} />
|
||||
<span>{t('Sanitize file names')}</span>
|
||||
|
||||
{!safeOutputFileName && <WarningSignIcon color="var(--amber9)" style={{ marginLeft: '.5em' }} />}
|
||||
{!safeOutputFileName && <WarningSignIcon color="var(--amber9)" style={{ marginLeft: '.5em', verticalAlign: 'middle' }} />}
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
@ -49,7 +49,7 @@ const Settings = memo(({
|
||||
const { t } = useTranslation();
|
||||
const [showAdvanced, setShowAdvanced] = useState(!simpleMode);
|
||||
|
||||
const { customOutDir, changeOutDir, keyframeCut, toggleKeyframeCut, timecodeFormat, setTimecodeFormat, invertCutSegments, setInvertCutSegments, askBeforeClose, setAskBeforeClose, enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction, autoSaveProjectFile, setAutoSaveProjectFile, invertTimelineScroll, setInvertTimelineScroll, language, setLanguage, ffmpegExperimental, setFfmpegExperimental, hideNotifications, setHideNotifications, autoLoadTimecode, setAutoLoadTimecode, enableAutoHtml5ify, setEnableAutoHtml5ify, customFfPath, setCustomFfPath, storeProjectInWorkingDir, mouseWheelZoomModifierKey, setMouseWheelZoomModifierKey, captureFrameMethod, setCaptureFrameMethod, captureFrameQuality, setCaptureFrameQuality, captureFrameFileNameFormat, setCaptureFrameFileNameFormat, enableNativeHevc, setEnableNativeHevc, enableUpdateCheck, setEnableUpdateCheck, allowMultipleInstances, setAllowMultipleInstances, preferStrongColors, setPreferStrongColors, treatInputFileModifiedTimeAsStart, setTreatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart, setTreatOutputFileModifiedTimeAsStart, exportConfirmEnabled, toggleExportConfirmEnabled } = useUserSettings();
|
||||
const { customOutDir, changeOutDir, keyframeCut, toggleKeyframeCut, timecodeFormat, setTimecodeFormat, invertCutSegments, setInvertCutSegments, askBeforeClose, setAskBeforeClose, enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction, autoSaveProjectFile, setAutoSaveProjectFile, invertTimelineScroll, setInvertTimelineScroll, language, setLanguage, hideNotifications, setHideNotifications, autoLoadTimecode, setAutoLoadTimecode, enableAutoHtml5ify, setEnableAutoHtml5ify, customFfPath, setCustomFfPath, storeProjectInWorkingDir, mouseWheelZoomModifierKey, setMouseWheelZoomModifierKey, captureFrameMethod, setCaptureFrameMethod, captureFrameQuality, setCaptureFrameQuality, captureFrameFileNameFormat, setCaptureFrameFileNameFormat, enableNativeHevc, setEnableNativeHevc, enableUpdateCheck, setEnableUpdateCheck, allowMultipleInstances, setAllowMultipleInstances, preferStrongColors, setPreferStrongColors, treatInputFileModifiedTimeAsStart, setTreatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart, setTreatOutputFileModifiedTimeAsStart, exportConfirmEnabled, toggleExportConfirmEnabled } = useUserSettings();
|
||||
|
||||
const onLangChange = useCallback((e) => {
|
||||
const { value } = e.target;
|
||||
@ -252,15 +252,6 @@ const Settings = memo(({
|
||||
</td>
|
||||
</Row>
|
||||
|
||||
{showAdvanced && (
|
||||
<Row>
|
||||
<KeyCell>{t('Enable experimental ffmpeg features flag?')}</KeyCell>
|
||||
<td>
|
||||
<Switch checked={ffmpegExperimental} onCheckedChange={setFfmpegExperimental} />
|
||||
</td>
|
||||
</Row>
|
||||
)}
|
||||
|
||||
{showAdvanced && (
|
||||
<Row>
|
||||
<KeyCell>
|
||||
|
@ -144,7 +144,7 @@ export function filenamify(name) {
|
||||
export function withBlur(cb) {
|
||||
return (e) => {
|
||||
cb(e);
|
||||
e.target.blur();
|
||||
e.target?.blur();
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user