From 9024621c15962f3cdfccee6fc35294b44d4cf1ee Mon Sep 17 00:00:00 2001
From: Michael Foiani <sotech117@Michaels-MacBook-Pro-5.local>
Date: Thu, 9 Jun 2022 16:27:27 -0400
Subject: fix undo, add disabled ui while recording, create expanding-segment
 to fill the space while recording

---
 .../views/nodes/RecordingBox/ProgressBar.tsx       | 158 ++++++++++-----------
 1 file changed, 74 insertions(+), 84 deletions(-)

(limited to 'src/client/views/nodes/RecordingBox/ProgressBar.tsx')

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>
       )
-- 
cgit v1.2.3-70-g09d2

