kopia lustrzana https://github.com/mifi/lossless-cut
rodzic
69a3b91926
commit
7f6e7ed6f7
18
src/App.jsx
18
src/App.jsx
|
@ -1,6 +1,6 @@
|
|||
import React, { memo, useEffect, useState, useCallback, useRef, useMemo } from 'react';
|
||||
import { unstable_batchedUpdates as batchedUpdates } from 'react-dom';
|
||||
import { FaAngleLeft, FaWindowClose, FaTimes, FaAngleRight, FaFile } from 'react-icons/fa';
|
||||
import { FaAngleLeft, FaWindowClose, FaTimes } from 'react-icons/fa';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import Lottie from 'react-lottie-player';
|
||||
import { SideSheet, Button, Position, ForkIcon, DisableIcon, Select, ThemeProvider } from 'evergreen-ui';
|
||||
|
@ -39,6 +39,8 @@ import ExportConfirm from './ExportConfirm';
|
|||
import ValueTuner from './components/ValueTuner';
|
||||
import VolumeControl from './components/VolumeControl';
|
||||
import SubtitleControl from './components/SubtitleControl';
|
||||
import BatchFile from './components/BatchFile';
|
||||
|
||||
import { loadMifiLink } from './mifi';
|
||||
import { primaryColor, controlsBackground, timelineBackground } from './colors';
|
||||
import allOutFormats from './outFormats';
|
||||
|
@ -2331,17 +2333,9 @@ const App = memo(() => {
|
|||
</div>
|
||||
|
||||
<div style={{ overflowX: 'hidden', overflowY: 'auto' }}>
|
||||
{batchFiles.map(({ path, name }) => {
|
||||
const isCurrent = path === filePath;
|
||||
return (
|
||||
<div role="button" style={{ background: isCurrent ? 'rgba(255,255,255,0.15)' : undefined, fontSize: 13, padding: '1px 3px', cursor: 'pointer', display: 'flex', alignItems: 'center', minHeight: 30, alignContent: 'flex-start' }} key={path} title={path} onClick={() => batchOpenSingleFile(path)}>
|
||||
<FaFile size={14} style={{ color: primaryColor, marginLeft: 3, marginRight: 4, flexShrink: 0 }} />
|
||||
<div style={{ wordBreak: 'break-all' }}>{name}</div>
|
||||
<div style={{ flexGrow: 1 }} />
|
||||
{isCurrent && <FaAngleRight size={14} style={{ color: 'white', marginRight: -3, flexShrink: 0 }} />}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{batchFiles.map(({ path, name }) => (
|
||||
<BatchFile key={path} path={path} name={name} filePath={filePath} onOpen={batchOpenSingleFile} onDelete={removeBatchFile} />
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
|
|
@ -25,33 +25,38 @@ const Segment = memo(({ seg, index, currentSegIndex, formatTimecode, getFrameCou
|
|||
|
||||
const ref = useRef();
|
||||
|
||||
useContextMenu(ref, invertCutSegments ? [] : [
|
||||
{ label: t('Jump to cut start'), click: jumpSegStart },
|
||||
{ label: t('Jump to cut end'), click: jumpSegEnd },
|
||||
const contextMenuTemplate = useMemo(() => {
|
||||
if (invertCutSegments) return [];
|
||||
return [
|
||||
{ label: t('Jump to cut start'), click: jumpSegStart },
|
||||
{ label: t('Jump to cut end'), click: jumpSegEnd },
|
||||
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator' },
|
||||
|
||||
{ label: t('Add segment'), click: addCutSegment },
|
||||
{ label: t('Label segment'), click: onLabelPress },
|
||||
{ label: t('Remove segment'), click: onRemovePress },
|
||||
{ label: t('Add segment'), click: addCutSegment },
|
||||
{ label: t('Label segment'), click: onLabelPress },
|
||||
{ label: t('Remove segment'), click: onRemovePress },
|
||||
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator' },
|
||||
|
||||
{ label: t('Change segment order'), click: onReorderPress },
|
||||
{ label: t('Increase segment order'), click: () => updateOrder(1) },
|
||||
{ label: t('Decrease segment order'), click: () => updateOrder(-1) },
|
||||
{ label: t('Change segment order'), click: onReorderPress },
|
||||
{ label: t('Increase segment order'), click: () => updateOrder(1) },
|
||||
{ label: t('Decrease segment order'), click: () => updateOrder(-1) },
|
||||
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator' },
|
||||
|
||||
{ label: t('Include ONLY this segment in export'), click: () => onExportSingleSegmentClick(seg) },
|
||||
{ label: enabled ? t('Exclude this segment from export') : t('Include this segment in export'), click: () => onExportSegmentEnabledToggle(seg) },
|
||||
{ label: t('Include all segments in export'), click: () => onExportSegmentEnableAll(seg) },
|
||||
{ label: t('Exclude all segments from export'), click: () => onExportSegmentDisableAll(seg) },
|
||||
{ label: t('Include ONLY this segment in export'), click: () => onExportSingleSegmentClick(seg) },
|
||||
{ label: enabled ? t('Exclude this segment from export') : t('Include this segment in export'), click: () => onExportSegmentEnabledToggle(seg) },
|
||||
{ label: t('Include all segments in export'), click: () => onExportSegmentEnableAll(seg) },
|
||||
{ label: t('Exclude all segments from export'), click: () => onExportSegmentDisableAll(seg) },
|
||||
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator' },
|
||||
|
||||
{ label: t('Segment tags'), click: () => onViewSegmentTagsPress(index) },
|
||||
]);
|
||||
{ label: t('Segment tags'), click: () => onViewSegmentTagsPress(index) },
|
||||
];
|
||||
}, [addCutSegment, enabled, index, invertCutSegments, jumpSegEnd, jumpSegStart, onExportSegmentDisableAll, onExportSegmentEnableAll, onExportSegmentEnabledToggle, onExportSingleSegmentClick, onLabelPress, onRemovePress, onReorderPress, onViewSegmentTagsPress, seg, t, updateOrder]);
|
||||
|
||||
useContextMenu(ref, contextMenuTemplate);
|
||||
|
||||
const duration = seg.end - seg.start;
|
||||
const durationMs = duration * 1000;
|
||||
|
|
|
@ -192,9 +192,11 @@ const Timeline = memo(({
|
|||
const onMouseMove = useCallback((e) => setHoveringTime(getMouseTimelinePos(e.nativeEvent)), [getMouseTimelinePos]);
|
||||
const onMouseOut = useCallback(() => setHoveringTime(), []);
|
||||
|
||||
useContextMenu(timelineScrollerRef, [
|
||||
const contextMenuTemplate = useMemo(() => [
|
||||
{ label: t('Seek to timecode'), click: goToTimecode },
|
||||
]);
|
||||
], [goToTimecode, t]);
|
||||
|
||||
useContextMenu(timelineScrollerRef, contextMenuTemplate);
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import React, { memo, useRef, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaAngleRight, FaFile } from 'react-icons/fa';
|
||||
|
||||
import useContextMenu from '../hooks/useContextMenu';
|
||||
import { primaryColor } from '../colors';
|
||||
|
||||
const BatchFile = memo(({ path, filePath, name, onOpen, onDelete }) => {
|
||||
const ref = useRef();
|
||||
|
||||
const { t } = useTranslation();
|
||||
const contextMenuTemplate = useMemo(() => [
|
||||
{ label: t('Remove'), click: () => onDelete(path) },
|
||||
], [t, onDelete, path]);
|
||||
|
||||
useContextMenu(ref, contextMenuTemplate);
|
||||
const isCurrent = path === filePath;
|
||||
|
||||
return (
|
||||
<div ref={ref} role="button" style={{ background: isCurrent ? 'rgba(255,255,255,0.15)' : undefined, fontSize: 13, padding: '1px 3px', cursor: 'pointer', display: 'flex', alignItems: 'center', minHeight: 30, alignContent: 'flex-start' }} title={path} onClick={() => onOpen(path)}>
|
||||
<FaFile size={14} style={{ color: primaryColor, marginLeft: 3, marginRight: 4, flexShrink: 0 }} />
|
||||
<div style={{ wordBreak: 'break-all' }}>{name}</div>
|
||||
<div style={{ flexGrow: 1 }} />
|
||||
{isCurrent && <FaAngleRight size={14} style={{ color: 'white', marginRight: -3, flexShrink: 0 }} />}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default BatchFile;
|
Ładowanie…
Reference in New Issue