aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Foiani <sotech117@Michaels-MacBook-Pro-5.local>2022-06-09 16:27:27 -0400
committerMichael Foiani <sotech117@Michaels-MacBook-Pro-5.local>2022-06-09 16:27:27 -0400
commit9024621c15962f3cdfccee6fc35294b44d4cf1ee (patch)
treeabb3a92981b8d224fca84e873a10c2681371d9a5 /src
parente9ae7c0482f1c9409d905bc6474bfd06abb01743 (diff)
fix undo, add disabled ui while recording, create expanding-segment to fill the space while recording
Diffstat (limited to 'src')
-rw-r--r--src/client/views/nodes/RecordingBox/ProgressBar.scss25
-rw-r--r--src/client/views/nodes/RecordingBox/ProgressBar.tsx158
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.tsx40
3 files changed, 122 insertions, 101 deletions
diff --git a/src/client/views/nodes/RecordingBox/ProgressBar.scss b/src/client/views/nodes/RecordingBox/ProgressBar.scss
index 3ed7cee3e..1cf60b82b 100644
--- a/src/client/views/nodes/RecordingBox/ProgressBar.scss
+++ b/src/client/views/nodes/RecordingBox/ProgressBar.scss
@@ -45,8 +45,31 @@
text-align: center;
}
-.no-transition {
+// .no-transition {
+// transition-duration: 0s;
+// }
+
+.segment-expanding {
+border-color: red;
+ background-color: white;
+ transition-duration: 0s;
+ opacity: .75;
+ pointer-events: none;
+}
+
+.segment-expanding:hover {
+ background-color: inherit;
+ cursor: not-allowed;
+}
+
+.segment-disabled {
+ pointer-events: none;
+ opacity: 0.5;
transition-duration: 0s;
+ /* Hide the text. */
+ text-indent: 100%;
+ white-space: nowrap;
+ overflow: hidden;
}
.segment-hide {
diff --git a/src/client/views/nodes/RecordingBox/ProgressBar.tsx b/src/client/views/nodes/RecordingBox/ProgressBar.tsx
index 54bfbc792..a00a4643d 100644
--- a/src/client/views/nodes/RecordingBox/ProgressBar.tsx
+++ b/src/client/views/nodes/RecordingBox/ProgressBar.tsx
@@ -1,8 +1,9 @@
+import { disable } from 'colors';
import { resolveTxt } from 'dns';
import { videointelligence } from 'googleapis/build/src/apis/videointelligence';
import { isInteger } from 'lodash';
import * as React from 'react';
-import { useEffect, useState, useCallback, useRef, useMemo } from "react"
+import { useEffect, useState, useCallback, useRef } from "react"
import "./ProgressBar.scss"
import { MediaSegment } from './RecordingView';
@@ -11,7 +12,8 @@ interface ProgressBarProps {
setVideos: React.Dispatch<React.SetStateAction<MediaSegment[]>>,
orderVideos: boolean,
progress: number,
- recording: boolean,
+ recording: boolean,
+ doUndo: boolean,
}
interface SegmentBox {
@@ -31,68 +33,73 @@ export function ProgressBar(props: ProgressBarProps) {
// array for the order of video segments
const [segments, setSegments] = useState<JSX.Element[]>([]);
- const [ordered, setOrdered] = useState<SegmentBox[]>([]);
+ const [ordered, setOrdered] = useState<SegmentBox[]>([]);
+
+ const [undoStack, setUndoStack] = useState<SegmentBox[]>([]);
const [dragged, setDragged] = useState<number>(-1);
- // total length of the video, in seconds*100
- // const [totalTime, setTotalTime] = useState<number>(0);
-
// length of the time removed from the video, in seconds*100
const [totalRemovedTime, setTotalRemovedTime] = useState<number>(0);
// this holds the index of the videoc segment to be removed
const [removed, setRemoved] = useState<number>(-1);
-
- // const totalTime = useMemo(() => props.progress*1000 - totalRemovedTime, [props.progress, totalRemovedTime]);
-
- // const totalTime = useMemo(() => props.videos.lastElement().endTime, [props.videos])
-
- // const totalTime = () => props.videos.lastElement().endTime
- // const memoTotal = useMemo(totalTime, [props.videos])
-
- // useEffect that updates total time based on progress
- // useEffect(() => {
- // console.log("useEffect progress", props.progress, 'totalRemovedTime', totalRemovedTime)
- // // setTotalTime(prev => {
- // // // progress is in seconds, prev is in deciseconds?
- // // const toAdd = props.progress * 10 - prev
- // // return prev + toAdd
- // // })
- // // setTotalTime(prev => props.progress * 10)
- // }, [props.progress])
+
+
+ // abstracted for other uses - brings back the most recently deleted segment
+ const handleUndo = () => {
+ // get the last element from the undo if it exists
+ if (undoStack.length === 0) return;
+ // get and remove the last element from the undo stack
+ const last = undoStack.lastElement();
+ setUndoStack(prevUndo => prevUndo.slice(0, -1));
+
+ // update the removed time and place element back into ordered
+ setTotalRemovedTime(prevRemoved => prevRemoved - (last.endTime - last.startTime));
+ setOrdered(prevOrdered => [...prevOrdered, last]);
+ }
+ useEffect(() => handleUndo(), [props.doUndo])
useEffect(() => {
- console.log("useEffect recording", props.recording)
- segments.forEach((seg, i) => {
- const htmlId = seg.props.id;
- const segmentHtml = document.getElementById(htmlId);
- segmentHtml?.classList.toggle('no-transition', props.recording);
- console.log(segmentHtml)
- });
+ console.log("useEffect recording", props.recording)
+ // get segments segment's html using it's id -> make them appeared disabled (or enabled)
+ segments.forEach((seg) => document.getElementById(seg.props.id)?.classList.toggle('segment-disabled', props.recording));
+
+ if (props.recording)
+ setSegments(prevSegments => [...prevSegments, <div key='segment-expanding' id='segment-expanding' className='segment segment-expanding' style={{ width: 'auto' }}>{props.videos.length + 1}</div>]);
}, [props.recording])
useEffect(() => {
- console.log('useEffect dragged, ordered')
const totalTime = props.progress * 1000 - totalRemovedTime;
const segmentsJSX = ordered.map((seg, i) =>
- <div id={`segment-${i.toString()}`} className={dragged === i ? 'segment-hide' : 'segment'} style={{ width: `${((seg.endTime - seg.startTime) / totalTime) * 100}%` }}>{seg.order}</div>);
+ <div key={`segment-${i}`} id={`segment-${i}`} className={dragged === i ? 'segment-hide' : 'segment'} style={{ width: `${((seg.endTime - seg.startTime) / totalTime) * 100}%` }}>{seg.order + 1}</div>);
setSegments(segmentsJSX)
}, [dragged, ordered]);
// to imporve performance, we only want to update the width, not re-render the whole thing
- useEffect(() => {
- // console.log('updating width on progress useEffect')
- const totalTime = props.progress * 1000 - totalRemovedTime;
- segments.forEach((seg, i) => {
- const htmlId = seg.props.id;
- const segmentHtml = document.getElementById(htmlId);
- segmentHtml?.style.width = `${((ordered[i].endTime - ordered[i].startTime) / totalTime) * 100}%`;
+ useEffect(() => {
+ if (!props.recording) return
+ const totalTime = props.progress * 1000 - totalRemovedTime;
+ let remainingTime = totalTime;
+ segments.forEach((seg, i) => {
+ // for the last segment, we need to set that directly
+ if (i === segments.length - 1) return;
+ // update remaining time
+ remainingTime -= (ordered[i].endTime - ordered[i].startTime);
+
+ // update the width for this segment
+ const htmlId = seg.props.id;
+ const segmentHtml = document.getElementById(htmlId);
+ if (segmentHtml) segmentHtml.style.width = `${((ordered[i].endTime - ordered[i].startTime) / totalTime) * 100}%`;
+ });
- // console.log('updating width on progress useEffect', htmlId, segmentHtml, segmentHtml?.style.width)
- });
+ // update the width of the expanding segment using the remaining time
+ const segExapandHtml = document.getElementById('segment-expanding');
+ if (segExapandHtml)
+ segExapandHtml.style.width = ordered.length === 0 ? '100%' : `${(remainingTime / totalTime) * 100}%`;
+
}, [props.progress]);
@@ -102,52 +109,36 @@ export function ProgressBar(props: ProgressBarProps) {
// in this case, do nothing.
if (props.orderVideos) return;
- const order = props.videos.length
- // in this case, a new video is added
- if (order && order > ordered.length) {
+ const order = props.videos.length - 1;
+ // in this case, a new video is added -> push it onto ordered
+ if (order >= ordered.length) {
const { endTime, startTime } = props.videos.lastElement();
- // update total time
- // setTotalTime(prevTime => prevTime + (endTime - startTime));
- // add the new segment to the ordered array
setOrdered(prevOrdered => {
return [...prevOrdered, { endTime, startTime , order }];
});
}
- // in this case, a segment is removed
+ // in this case, a video is removed
else if (order < ordered.length) {
- // update the total time
- // setTotalTime(prevTime => prevTime - (ordered[removed].endTime - ordered[removed].startTime));
-
- // update total removed time
- setTotalRemovedTime(prevRemoved => prevRemoved + (ordered[removed].endTime - ordered[removed].startTime));
-
- // remove the segment from the ordered array and decrement the order of the remaining segments
- // if they are greater than the removed segment's order
- const removedOrder = ordered[removed].order;
- setOrdered(prevOrdered =>
- prevOrdered.reduce((acc, seg, i) => {
- (i !== removed) && acc.push({ ...seg, order: seg.order > removedOrder ? seg.order - 1 : seg.order });
- return acc;
- },[] as SegmentBox[])
- );
- // reset to default/nullish state
- setRemoved(-1);
+ console.error('warning: video removed from parent');
}
}, [props.videos]);
useEffect(() => {
- props.setVideos(vids => ordered.map((seg) => vids[seg.order - 1]));
+ props.setVideos(vids => ordered.map((seg) => vids[seg.order]));
}, [props.orderVideos]);
useEffect(() => {
if (removed === -1) return;
-
- console.log('removed', removed)
-
- // update the videos array -> this will fire the useEffect above, where we update the orders & totalTime
- const index = ordered[removed].order - 1;
- props.setVideos(vids => vids.filter((vid, i) => i !== index));
+ // update total removed time
+ setTotalRemovedTime(prevRemoved => prevRemoved + (ordered[removed].endTime - ordered[removed].startTime));
+
+ // put the element on the undo stack
+ setUndoStack(prevUndo => [...prevUndo, ordered[removed]]);
+ // remove the segment from the array
+ setOrdered(prevOrdered => prevOrdered.filter((seg, i) => i !== removed));
+ // reset to default/nullish state
+ setRemoved(-1);
}, [removed]);
const updateLastHover = (segId: number): CurrentHover | null => {
@@ -163,7 +154,10 @@ export function ProgressBar(props: ProgressBarProps) {
const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
// don't move the videobox element
- e.stopPropagation()
+ e.stopPropagation()
+
+ // if recording, do nothing
+ if (props.recording) return;
// get the segment the user clicked on to be dragged
const clickedSegment = e.target as HTMLDivElement & EventTarget
@@ -177,10 +171,15 @@ export function ProgressBar(props: ProgressBarProps) {
// TODO: think of a way to accomodate touch -> maybe if poiuntermove isn't fired after x secs?
if (e.shiftKey) {
const segId = parseInt(clickedSegment.id.split('-')[1]);
- console.log('removing segment', segId)
setRemoved(segId);
return
}
+
+ if (e.ctrlKey) {
+ handleUndo();
+ return;
+ // todo: implement undo stack
+ }
const ptrId = e.pointerId;
progressBar.setPointerCapture(ptrId)
@@ -209,7 +208,6 @@ export function ProgressBar(props: ProgressBarProps) {
event.preventDefault();
// this fixes a bug where pointerup doesn't fire while cursor is upped while being dragged
- console.log('update cursor', progressBar.hasPointerCapture(ptrId), ptrId)
if (!progressBar.hasPointerCapture(ptrId)) {
placeSegmentandCleanup();
return;
@@ -269,9 +267,6 @@ export function ProgressBar(props: ProgressBarProps) {
dot.draggable = false;
document.body.append(dot)
}
- const cleanupDetachSegment = (dot: HTMLDivElement) => {
- dot.remove()
- }
const followCursor = (event: PointerEvent, dot: HTMLDivElement, rect: DOMRect): void => {
// event.stopPropagation()
// const { width, height } = dot.getBoundingClientRect()
@@ -283,11 +278,6 @@ export function ProgressBar(props: ProgressBarProps) {
return (
<div className="progressbar" id="progressbar" onPointerDown={onPointerDown} ref={progressBarRef}>
- {/* <div
- className="progressbar done"
- style={{ width: `${props.progress}%` }}
- // onClick={handleClick}
- ></div> */}
{segments}
</div>
)
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx
index 40117c41c..e131420c3 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx
@@ -31,7 +31,9 @@ export function RecordingView(props: IRecordingViewProps) {
const recordingTimerRef = useRef<number>(0);
const [recordingTimer, setRecordingTimer] = useState(0); // unit is 0.01 second
const [playing, setPlaying] = useState(false);
- const [progress, setProgress] = useState(0);
+ const [progress, setProgress] = useState(0);
+
+ const [doUndo, setDoUndo] = useState(false);
const [videos, setVideos] = useState<MediaSegment[]>([]);
const [orderVideos, setOrderVideos] = useState<boolean>(false);
@@ -225,11 +227,15 @@ export function RecordingView(props: IRecordingViewProps) {
}
}
- const clearPrevious = () => {
- const numVideos = videos.length
- setRecordingTimer(numVideos == 1 ? 0 : videos[numVideos - 2].endTime)
- setVideoProgressHelper(numVideos == 1 ? 0 : videos[numVideos - 2].endTime)
- setVideos(videos.filter((_, idx) => idx !== numVideos - 1));
+ const undoPrevious = (e: React.MouseEvent) => {
+ e.stopPropagation();
+ console.log('undo previous', doUndo)
+ setDoUndo(prev => !prev);
+ // const numVideos = videos.length
+ // setRecordingTimer(numVideos == 1 ? 0 : videos[numVideos - 2].endTime)
+ // setVideoProgressHelper(numVideos == 1 ? 0 : videos[numVideos - 2].endTime)
+ // setVideos(videos.filter((_, idx) => idx !== numVideos - 1));
+
}
const handleOnTimeUpdate = () => {
@@ -247,7 +253,8 @@ export function RecordingView(props: IRecordingViewProps) {
return toTwoDigit(minutes) + " : " + toTwoDigit(seconds);
}
- return (
+ // TODO: have the undo button only appear if there is something to undo
+ return (
<div className="recording-container">
<div className="video-wrapper">
<video id={`video-${props.id}`}
@@ -271,10 +278,10 @@ export function RecordingView(props: IRecordingViewProps) {
{!recording && (videos.length > 0 ?
- <div className="options-wrapper video-edit-wrapper">
- {/* <IconContext.Provider value={{ color: "grey", className: "video-edit-buttons" }}>
- <MdBackspace onClick={clearPrevious} />
- </IconContext.Provider> */}
+ <div className="options-wrapper video-edit-wrapper">
+ <IconContext.Provider value={{ color: "grey", className: "video-edit-buttons" }}>
+ <MdBackspace onClick={undoPrevious} />
+ </IconContext.Provider>
<IconContext.Provider value={{ color: "#cc1c08", className: "video-edit-buttons" }}>
<FaCheckCircle onClick={stop} />
</IconContext.Provider>
@@ -293,11 +300,12 @@ export function RecordingView(props: IRecordingViewProps) {
</div>
<ProgressBar
- videos={videos}
- setVideos={setVideos}
- orderVideos={orderVideos}
- progress={progress}
- recording={recording}
+ videos={videos}
+ setVideos={setVideos}
+ orderVideos={orderVideos}
+ progress={progress}
+ recording={recording}
+ doUndo={doUndo}
// playSegment={playSegment}
/>
</div>