Skip to content

Commit

Permalink
Add delete restore button to each segment of timeline
Browse files Browse the repository at this point in the history
  • Loading branch information
Dennis Benz committed Jul 4, 2023
1 parent a2bed50 commit 0354914
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 9 deletions.
6 changes: 5 additions & 1 deletion src/i18n/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,11 @@
"generateWaveform-text": "Generating Waveform",
"segment-tooltip": "Segment {{segment}}",
"scrubber-text-aria": "Timeline marker. {{currentTime}}. Active segment: {{segment}}. {{segmentStatus}}. Controls: {{moveLeft}} and {{moveRight}} to move the timeline marker. {{increase}} and {{decrease}} to increase/decrease the move delta.\n",
"segments-text-aria": "Segment {{index}}. {{segmentStatus}}. Start: {{start}}. End: {{end}}.\n"
"segments-text-aria": "Segment {{index}}. {{segmentStatus}}. Start: {{start}}. End: {{end}}.\n",
"segment-delete-tooltip": "Mark this segment as to be deleted",
"segment-delete-tooltip-aria": "Delete. Mark this segment as to be deleted",
"segment-restore-tooltip": "Unmark this segment as to be deleted",
"segment-restore-tooltip-aria": "Restore. Unmark this segment as to be deleted"
},

"workflowConfig": {
Expand Down
44 changes: 38 additions & 6 deletions src/main/Timeline.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useRef, useEffect } from 'react'
import React, { useState, useRef, useEffect, SyntheticEvent } from 'react'

import Draggable from 'react-draggable';

Expand All @@ -7,11 +7,11 @@ import { css } from '@emotion/react'
import { useSelector, useDispatch } from 'react-redux';
import { Segment, httpRequestState } from '../types'
import {
selectSegments, selectActiveSegmentIndex, selectDuration, selectVideoURL, selectWaveformImages, setWaveformImages
selectSegments, selectActiveSegmentIndex, selectDuration, selectVideoURL, selectWaveformImages, setWaveformImages, markAsDeletedOrAliveByIndex
} from '../redux/videoSlice'

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBars, faSpinner } from "@fortawesome/free-solid-svg-icons";
import { faBars, faSpinner, faTrash, faTrashRestore } from "@fortawesome/free-solid-svg-icons";

import useResizeObserver from "use-resize-observer";

Expand All @@ -23,8 +23,9 @@ import { scrubberKeyMap } from '../globalKeys';
import { useTranslation } from 'react-i18next';
import { ActionCreatorWithPayload } from '@reduxjs/toolkit';
import { RootState } from '../redux/store';
import { selectTheme } from '../redux/themeSlice';
import { selectTheme, Theme } from '../redux/themeSlice';
import { ThemedTooltip } from './Tooltip';
import { basicButtonStyle } from "../cssStyles";

/**
* A container for visualizing the cutting of the video, as well as for controlling
Expand Down Expand Up @@ -195,7 +196,7 @@ export const Scrubber: React.FC<{
height: timelineHeight - 10 + 'px', // TODO: CHECK IF height: '100%',
width: '1px',
position: 'absolute',
zIndex: 2,
zIndex: 1,
boxShadow: `${theme.boxShadow}`,
display: 'flex',
flexDirection: 'column',
Expand Down Expand Up @@ -293,12 +294,21 @@ export const SegmentsList: React.FC<{
}) => {

const { t } = useTranslation();
const theme = useSelector(selectTheme);

// Init redux variables
const dispatch = useDispatch()
const segments = useSelector(selectSegments)
const duration = useSelector(selectDuration)
const activeSegmentIndex = useSelector(selectActiveSegmentIndex)

const markAsDeletedOrAlive = (event: KeyboardEvent | SyntheticEvent, index: number) => {
event.preventDefault() // Prevent page scrolling due to Space bar press
event.stopPropagation() // Prevent video playback due to Space bar press

dispatch(markAsDeletedOrAliveByIndex(index));
}

/**
* Returns a background color based on whether the segment is to be deleted
* and whether the segment is currently active
Expand All @@ -325,6 +335,15 @@ export const SegmentsList: React.FC<{
}
}

const markAsDeletedButtonStyle = (theme: Theme) => css({
position: 'absolute',
right: '8px',
top: '8px',
padding: '5px',
background: `${theme.element_bg}`,
zIndex: 2,
});

// Render the individual segments
const renderedSegments = () => {
return (
Expand All @@ -338,6 +357,7 @@ export const SegmentsList: React.FC<{
end: convertMsToReadableString(segment.end) })}
tabIndex={tabable ? 0 : -1}
css={{
position: 'relative',
background: bgColor(segment.deleted, styleByActiveSegment ? activeSegmentIndex === index : false),
borderRadius: '5px',
borderStyle: styleByActiveSegment ? (activeSegmentIndex === index ? 'dashed' : 'solid') : 'solid',
Expand All @@ -346,8 +366,20 @@ export const SegmentsList: React.FC<{
boxSizing: 'border-box',
width: ((segment.end - segment.start) / duration) * 100 + '%',
height: timelineHeight - 20 + 'px', // CHECK IF 100%
zIndex: 1,
}}>
<ThemedTooltip title={segment.deleted ? t("timeline.segment-restore-tooltip") : t("timeline.segment-delete-tooltip")}>
<div css={[basicButtonStyle(theme), markAsDeletedButtonStyle(theme)]}
role='button' tabIndex={0}
aria-label={segment.deleted ? t("timeline.segment-restore-tooltip-aria") : t("timeline.segment-delete-tooltip-aria")}
onClick={(event: SyntheticEvent) => markAsDeletedOrAlive(event, index)}
onKeyDown={(event: React.KeyboardEvent<HTMLDivElement>) => { if (event.key === " " || event.key === "Enter") {
markAsDeletedOrAlive(event, index)
}}}
onMouseDown={(event) => event.stopPropagation() } // Prevent timeline jump
>
<FontAwesomeIcon icon={segment.deleted ? faTrashRestore : faTrash} size="1x" />
</div>
</ThemedTooltip>
</div>
</ThemedTooltip>
))
Expand Down
8 changes: 6 additions & 2 deletions src/redux/videoSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ const videoSlice = createSlice({
state.segments[state.activeSegmentIndex].deleted = !state.segments[state.activeSegmentIndex].deleted
state.hasChanges = true
},
markAsDeletedOrAliveByIndex: (state, action: PayloadAction<number>) => {
state.segments[action.payload].deleted = !state.segments[action.payload].deleted
state.hasChanges = true
},
markAllAsDeleted: state => {
state.segments.forEach((segment: Segment) => {
segment.deleted = true;
Expand Down Expand Up @@ -342,8 +346,8 @@ const setThumbnailHelper = (state: video, id: Track["id"], uri: Track["thumbnail

export const { setTrackEnabled, setIsPlaying, setIsPlayPreview, setCurrentlyAt, setCurrentlyAtInSeconds,
addSegment, setAspectRatio, setHasChanges, setWaveformImages, setThumbnails, setThumbnail, removeThumbnail,
cut, markAsDeletedOrAlive, markAllAsDeleted, setSelectedWorkflowIndex, mergeLeft, mergeRight, setPreviewTriggered,
setClickTriggered } = videoSlice.actions
cut, markAsDeletedOrAlive, markAsDeletedOrAliveByIndex, markAllAsDeleted, setSelectedWorkflowIndex, mergeLeft,
mergeRight, setPreviewTriggered, setClickTriggered } = videoSlice.actions

// Export selectors
// Selectors mainly pertaining to the video state
Expand Down

0 comments on commit 0354914

Please sign in to comment.