kopia lustrzana https://github.com/mifi/lossless-cut
implement simple mode #546
rodzic
035dff2cc9
commit
1662adb1e3
|
@ -25,6 +25,7 @@ const defaults = {
|
|||
autoLoadTimecode: false,
|
||||
segmentsToChapters: false,
|
||||
preserveMetadataOnMerge: false,
|
||||
simpleMode: true,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
13
src/App.jsx
13
src/App.jsx
|
@ -207,6 +207,8 @@ const App = memo(() => {
|
|||
useEffect(() => safeSetConfig('segmentsToChapters', segmentsToChapters), [segmentsToChapters]);
|
||||
const [preserveMetadataOnMerge, setPreserveMetadataOnMerge] = useState(configStore.get('preserveMetadataOnMerge'));
|
||||
useEffect(() => safeSetConfig('preserveMetadataOnMerge', preserveMetadataOnMerge), [preserveMetadataOnMerge]);
|
||||
const [simpleMode, setSimpleMode] = useState(configStore.get('simpleMode'));
|
||||
useEffect(() => safeSetConfig('simpleMode', simpleMode), [simpleMode]);
|
||||
|
||||
useEffect(() => {
|
||||
i18n.changeLanguage(language || fallbackLng).catch(console.error);
|
||||
|
@ -668,6 +670,11 @@ const App = memo(() => {
|
|||
|
||||
const togglePreserveMovData = useCallback(() => setPreserveMovData((val) => !val), []);
|
||||
|
||||
const toggleSimpleMode = useCallback(() => setSimpleMode((v) => {
|
||||
if (!hideAllNotifications) toast.fire({ text: v ? i18n.t('Simple mode has been disabled. You will now see also non-essential buttons') : i18n.t('Simple mode enabled. You will now see only the most essential buttons') });
|
||||
return !v;
|
||||
}), [hideAllNotifications]);
|
||||
|
||||
const isCopyingStreamId = useCallback((path, streamId) => (
|
||||
!!(copyStreamIdsByFile[path] || {})[streamId]
|
||||
), [copyStreamIdsByFile]);
|
||||
|
@ -2008,7 +2015,7 @@ const App = memo(() => {
|
|||
/>
|
||||
</div>
|
||||
|
||||
{!isFileOpened && <NoFileLoaded topBarHeight={topBarHeight} bottomBarHeight={bottomBarHeight} mifiLink={mifiLink} toggleHelp={toggleHelp} currentCutSeg={currentCutSeg} />}
|
||||
{!isFileOpened && <NoFileLoaded topBarHeight={topBarHeight} bottomBarHeight={bottomBarHeight} mifiLink={mifiLink} toggleHelp={toggleHelp} currentCutSeg={currentCutSeg} simpleMode={simpleMode} toggleSimpleMode={toggleSimpleMode} />}
|
||||
|
||||
<AnimatePresence>
|
||||
{working && (
|
||||
|
@ -2192,6 +2199,7 @@ const App = memo(() => {
|
|||
hasVideo={hasVideo}
|
||||
keyframesEnabled={keyframesEnabled}
|
||||
toggleKeyframesEnabled={toggleKeyframesEnabled}
|
||||
simpleMode={simpleMode}
|
||||
/>
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
|
@ -2201,6 +2209,8 @@ const App = memo(() => {
|
|||
invertCutSegments={invertCutSegments}
|
||||
setInvertCutSegments={setInvertCutSegments}
|
||||
toggleComfortZoom={toggleComfortZoom}
|
||||
simpleMode={simpleMode}
|
||||
toggleSimpleMode={toggleSimpleMode}
|
||||
/>
|
||||
|
||||
<RightMenu
|
||||
|
@ -2217,6 +2227,7 @@ const App = memo(() => {
|
|||
outSegments={outSegments}
|
||||
exportConfirmEnabled={exportConfirmEnabled}
|
||||
toggleExportConfirmEnabled={toggleExportConfirmEnabled}
|
||||
simpleMode={simpleMode}
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
|
|
@ -4,10 +4,11 @@ import { motion } from 'framer-motion';
|
|||
import { FaYinYang } from 'react-icons/fa';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import SimpleModeButton from './components/SimpleModeButton';
|
||||
import { withBlur, toast } from './util';
|
||||
|
||||
|
||||
const LeftMenu = memo(({ zoom, setZoom, invertCutSegments, setInvertCutSegments, toggleComfortZoom }) => {
|
||||
const LeftMenu = memo(({ zoom, setZoom, invertCutSegments, setInvertCutSegments, toggleComfortZoom, simpleMode, toggleSimpleMode }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
function onYinYangClick() {
|
||||
|
@ -37,14 +38,20 @@ const LeftMenu = memo(({ zoom, setZoom, invertCutSegments, setInvertCutSegments,
|
|||
</motion.div>
|
||||
</div>
|
||||
|
||||
<div role="button" style={{ marginRight: 5, marginLeft: 10 }} title={t('Zoom')} onClick={toggleComfortZoom}>{Math.floor(zoom)}x</div>
|
||||
<SimpleModeButton simpleMode={simpleMode} toggleSimpleMode={toggleSimpleMode} style={{ padding: '0 10px' }} />
|
||||
|
||||
<Select height={20} style={{ width: 20 }} value={zoomOptions.includes(zoom) ? zoom.toString() : ''} title={t('Zoom')} onChange={withBlur(e => setZoom(parseInt(e.target.value, 10)))}>
|
||||
<option key="" value="" disabled>{t('Zoom')}</option>
|
||||
{zoomOptions.map(val => (
|
||||
<option key={val} value={String(val)}>{t('Zoom')} {val}x</option>
|
||||
))}
|
||||
</Select>
|
||||
{!simpleMode && (
|
||||
<>
|
||||
<div role="button" style={{ marginRight: 5, marginLeft: 10 }} title={t('Zoom')} onClick={toggleComfortZoom}>{Math.floor(zoom)}x</div>
|
||||
|
||||
<Select height={20} style={{ width: 70 }} value={zoomOptions.includes(zoom) ? zoom.toString() : ''} title={t('Zoom')} onChange={withBlur(e => setZoom(parseInt(e.target.value, 10)))}>
|
||||
<option key="" value="" disabled>{t('Zoom')}</option>
|
||||
{zoomOptions.map(val => (
|
||||
<option key={val} value={String(val)}>{t('Zoom')}</option>
|
||||
))}
|
||||
</Select>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -4,10 +4,11 @@ import { FaHandPointRight, FaHandPointLeft } from 'react-icons/fa';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import SetCutpointButton from './components/SetCutpointButton';
|
||||
import SimpleModeButton from './components/SimpleModeButton';
|
||||
|
||||
const electron = window.require('electron');
|
||||
|
||||
const NoFileLoaded = memo(({ topBarHeight, bottomBarHeight, mifiLink, toggleHelp, currentCutSeg }) => {
|
||||
const NoFileLoaded = memo(({ topBarHeight, bottomBarHeight, mifiLink, toggleHelp, currentCutSeg, simpleMode, toggleSimpleMode }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
|
@ -22,6 +23,11 @@ const NoFileLoaded = memo(({ topBarHeight, bottomBarHeight, mifiLink, toggleHelp
|
|||
<SetCutpointButton currentCutSeg={currentCutSeg} side="start" Icon={FaHandPointLeft} style={{ verticalAlign: 'middle' }} /> <SetCutpointButton currentCutSeg={currentCutSeg} side="end" Icon={FaHandPointRight} style={{ verticalAlign: 'middle' }} /> or <kbd>I</kbd> <kbd>O</kbd> to set cutpoints
|
||||
</div>
|
||||
|
||||
<div style={{ fontSize: '3vmin', color: '#ccc' }}>
|
||||
<SimpleModeButton simpleMode={simpleMode} toggleSimpleMode={toggleSimpleMode} style={{ verticalAlign: 'middle' }} size={16} /> to toggle simple mode
|
||||
</div>
|
||||
|
||||
|
||||
{mifiLink && mifiLink.loadUrl && (
|
||||
<div style={{ position: 'relative', margin: '3vmin', width: '60vmin', height: '20vmin' }}>
|
||||
<iframe src={mifiLink.loadUrl} title="iframe" style={{ background: 'rgba(0,0,0,0)', border: 'none', pointerEvents: 'none', width: '100%', height: '100%', position: 'absolute' }} />
|
||||
|
|
|
@ -13,6 +13,7 @@ import ToggleExportConfirm from './components/ToggleExportConfirm';
|
|||
const RightMenu = memo(({
|
||||
isRotationSet, rotation, areWeCutting, increaseRotation, deleteSource, renderCaptureFormatButton,
|
||||
capture, onExportPress, outSegments, hasVideo, autoMerge, exportConfirmEnabled, toggleExportConfirmEnabled,
|
||||
simpleMode,
|
||||
}) => {
|
||||
const rotationStr = `${rotation}°`;
|
||||
|
||||
|
@ -33,17 +34,19 @@ const RightMenu = memo(({
|
|||
</div>
|
||||
)}
|
||||
|
||||
<FaTrashAlt
|
||||
title={t('Delete source file')}
|
||||
style={{ padding: '5px 10px' }}
|
||||
size={16}
|
||||
onClick={deleteSource}
|
||||
role="button"
|
||||
/>
|
||||
{!simpleMode && (
|
||||
<FaTrashAlt
|
||||
title={t('Delete source file')}
|
||||
style={{ padding: '5px 10px' }}
|
||||
size={16}
|
||||
onClick={deleteSource}
|
||||
role="button"
|
||||
/>
|
||||
)}
|
||||
|
||||
{hasVideo && (
|
||||
<>
|
||||
{renderCaptureFormatButton({ height: 20 })}
|
||||
{!simpleMode && renderCaptureFormatButton({ height: 20 })}
|
||||
|
||||
<IoIosCamera
|
||||
style={{ paddingLeft: 5, paddingRight: 15 }}
|
||||
|
@ -54,7 +57,7 @@ const RightMenu = memo(({
|
|||
</>
|
||||
)}
|
||||
|
||||
<ToggleExportConfirm style={{ marginRight: 5 }} exportConfirmEnabled={exportConfirmEnabled} toggleExportConfirmEnabled={toggleExportConfirmEnabled} />
|
||||
{!simpleMode && <ToggleExportConfirm style={{ marginRight: 5 }} exportConfirmEnabled={exportConfirmEnabled} toggleExportConfirmEnabled={toggleExportConfirmEnabled} />}
|
||||
|
||||
<ExportButton outSegments={outSegments} areWeCutting={areWeCutting} autoMerge={autoMerge} onClick={onExportPress} />
|
||||
</div>
|
||||
|
|
|
@ -14,7 +14,7 @@ const TimelineControls = memo(({
|
|||
setCurrentSegIndex, cutStartTimeManual, setCutStartTimeManual, cutEndTimeManual, setCutEndTimeManual,
|
||||
duration, jumpCutEnd, jumpCutStart, startTimeOffset, setCutTime, currentApparentCutSeg,
|
||||
playing, shortStep, togglePlay, setTimelineMode, hasAudio, hasVideo, timelineMode,
|
||||
keyframesEnabled, toggleKeyframesEnabled, seekClosestKeyframe,
|
||||
keyframesEnabled, toggleKeyframesEnabled, seekClosestKeyframe, simpleMode,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
@ -56,7 +56,7 @@ const TimelineControls = memo(({
|
|||
const isCutTimeManualSet = () => cutTimeManual !== undefined;
|
||||
|
||||
const cutTimeInputStyle = {
|
||||
background: 'white', borderRadius: 5, color: 'rgba(0, 0, 0, 0.7)', fontSize: 13, textAlign: 'center', padding: '1px 5px', marginTop: 0, marginBottom: 0, marginLeft: isStart ? 3 : 5, marginRight: isStart ? 5 : 3, border: 'none', boxSizing: 'border-box', fontFamily: 'inherit', width: 90, outline: 'none',
|
||||
background: 'white', borderRadius: 5, color: 'rgba(0, 0, 0, 0.7)', fontSize: 13, textAlign: 'center', padding: '1px 5px', marginTop: 0, marginBottom: 0, marginLeft: isStart ? 0 : 5, marginRight: isStart ? 5 : 0, border: 'none', boxSizing: 'border-box', fontFamily: 'inherit', width: 90, outline: 'none',
|
||||
};
|
||||
|
||||
function parseAndSetCutTime(text) {
|
||||
|
@ -116,11 +116,12 @@ const TimelineControls = memo(({
|
|||
const PlayPause = playing ? FaPause : FaPlay;
|
||||
|
||||
const leftRightWidth = 100;
|
||||
const toolbarHeight = 24;
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', height: toolbarHeight }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', flexBasis: leftRightWidth }}>
|
||||
{hasAudio && (
|
||||
{hasAudio && !simpleMode && (
|
||||
<GiSoundWaves
|
||||
size={24}
|
||||
style={{ padding: '0 5px', color: timelineMode === 'waveform' ? primaryTextColor : undefined }}
|
||||
|
@ -129,7 +130,7 @@ const TimelineControls = memo(({
|
|||
onClick={() => setTimelineMode('waveform')}
|
||||
/>
|
||||
)}
|
||||
{hasVideo && (
|
||||
{hasVideo && !simpleMode && (
|
||||
<Fragment>
|
||||
<FaImages
|
||||
size={20}
|
||||
|
@ -152,64 +153,78 @@ const TimelineControls = memo(({
|
|||
|
||||
<div style={{ flexGrow: 1 }} />
|
||||
|
||||
<FaStepBackward
|
||||
size={16}
|
||||
title={t('Jump to start of video')}
|
||||
role="button"
|
||||
onClick={() => seekAbs(0)}
|
||||
/>
|
||||
{!simpleMode && (
|
||||
<FaStepBackward
|
||||
size={16}
|
||||
title={t('Jump to start of video')}
|
||||
role="button"
|
||||
onClick={() => seekAbs(0)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{renderJumpCutpointButton(-1)}
|
||||
{!simpleMode && renderJumpCutpointButton(-1)}
|
||||
|
||||
<SetCutpointButton currentCutSeg={currentCutSeg} side="start" Icon={FaStepBackward} onClick={jumpCutStart} title={t('Jump to cut start')} style={{ marginRight: 5 }} />
|
||||
<SetCutpointButton currentCutSeg={currentCutSeg} side="start" Icon={FaHandPointLeft} onClick={setCutStart} title={t('Set cut start to current position')} />
|
||||
{!simpleMode && <SetCutpointButton currentCutSeg={currentCutSeg} side="start" Icon={FaStepBackward} onClick={jumpCutStart} title={t('Jump to cut start')} style={{ marginRight: 5 }} />}
|
||||
<SetCutpointButton currentCutSeg={currentCutSeg} side="start" Icon={FaHandPointLeft} onClick={setCutStart} title={t('Set cut start to current position')} style={{ marginRight: 5 }} />
|
||||
|
||||
{renderCutTimeInput('start')}
|
||||
{!simpleMode && renderCutTimeInput('start')}
|
||||
|
||||
{!simpleMode && (
|
||||
<>
|
||||
<IoMdKey
|
||||
size={20}
|
||||
role="button"
|
||||
title={t('Seek previous keyframe')}
|
||||
style={{ transform: 'matrix(-1, 0, 0, 1, 0, 0)' }}
|
||||
onClick={() => seekClosestKeyframe(-1)}
|
||||
/>
|
||||
<FaCaretLeft
|
||||
size={20}
|
||||
role="button"
|
||||
title={t('One frame back')}
|
||||
onClick={() => shortStep(-1)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<IoMdKey
|
||||
size={20}
|
||||
role="button"
|
||||
title={t('Seek previous keyframe')}
|
||||
style={{ transform: 'matrix(-1, 0, 0, 1, 0, 0)' }}
|
||||
onClick={() => seekClosestKeyframe(-1)}
|
||||
/>
|
||||
<FaCaretLeft
|
||||
size={20}
|
||||
role="button"
|
||||
title={t('One frame back')}
|
||||
onClick={() => shortStep(-1)}
|
||||
/>
|
||||
<PlayPause
|
||||
size={16}
|
||||
role="button"
|
||||
onClick={togglePlay}
|
||||
/>
|
||||
<FaCaretRight
|
||||
size={20}
|
||||
role="button"
|
||||
title={t('One frame forward')}
|
||||
onClick={() => shortStep(1)}
|
||||
/>
|
||||
<IoMdKey
|
||||
size={20}
|
||||
role="button"
|
||||
title={t('Seek next keyframe')}
|
||||
onClick={() => seekClosestKeyframe(1)}
|
||||
/>
|
||||
|
||||
{renderCutTimeInput('end')}
|
||||
{!simpleMode && (
|
||||
<>
|
||||
<FaCaretRight
|
||||
size={20}
|
||||
role="button"
|
||||
title={t('One frame forward')}
|
||||
onClick={() => shortStep(1)}
|
||||
/>
|
||||
<IoMdKey
|
||||
size={20}
|
||||
role="button"
|
||||
title={t('Seek next keyframe')}
|
||||
onClick={() => seekClosestKeyframe(1)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<SetCutpointButton currentCutSeg={currentCutSeg} side="end" Icon={FaHandPointRight} onClick={setCutEnd} title={t('Set cut end to current position')} />
|
||||
<SetCutpointButton currentCutSeg={currentCutSeg} side="end" Icon={FaStepForward} onClick={jumpCutEnd} title={t('Jump to cut end')} style={{ marginLeft: 5 }} />
|
||||
{!simpleMode && renderCutTimeInput('end')}
|
||||
|
||||
{renderJumpCutpointButton(1)}
|
||||
<SetCutpointButton currentCutSeg={currentCutSeg} side="end" Icon={FaHandPointRight} onClick={setCutEnd} title={t('Set cut end to current position')} style={{ marginLeft: 5 }} />
|
||||
{!simpleMode && <SetCutpointButton currentCutSeg={currentCutSeg} side="end" Icon={FaStepForward} onClick={jumpCutEnd} title={t('Jump to cut end')} style={{ marginLeft: 5 }} />}
|
||||
|
||||
<FaStepForward
|
||||
size={16}
|
||||
title={t('Jump to end of video')}
|
||||
role="button"
|
||||
onClick={() => seekAbs(duration)}
|
||||
/>
|
||||
{!simpleMode && renderJumpCutpointButton(1)}
|
||||
|
||||
{!simpleMode && (
|
||||
<FaStepForward
|
||||
size={16}
|
||||
title={t('Jump to end of video')}
|
||||
role="button"
|
||||
onClick={() => seekAbs(duration)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div style={{ flexGrow: 1 }} />
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaBaby } from 'react-icons/fa';
|
||||
|
||||
import { primaryTextColor } from '../colors';
|
||||
|
||||
|
||||
const SimpleModeButton = memo(({ simpleMode, toggleSimpleMode, size = 20, style }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<FaBaby
|
||||
title={t('Simple mode')}
|
||||
size={size}
|
||||
style={{ color: simpleMode ? primaryTextColor : 'white', ...style }}
|
||||
onClick={toggleSimpleMode}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export default SimpleModeButton;
|
Ładowanie…
Reference in New Issue