vydimitrov / react-countdown-circle-timer

Lightweight React/React Native countdown timer component with color and progress animation based on SVG
MIT License
692 stars 87 forks source link

Feature request: more precision #191

Closed hirbod closed 2 years ago

hirbod commented 2 years ago

Hi, lovely lib and nice rewrite. The onUpdate callback is also nice, but I need a bit more precision. I am using the timer to show time left to record a video. The video record can be done in segments and the timer will recreate itself always based on remaining time etc.

I am working with ffprobe to get the exact duration of my recorded videos and the user is not allowed to exceed the max duration, and it is important that onComplete does trigger with the exact duration. But you're rounding with Math.ceil, which breaks it for me, as every "stop" on my recording sessions will round my numbers, return a wrong onUpdate remainingTime value etc.

Could you add a prop like preciseTimes and just accept that I am going to pass stuff like 9.487000 and also return the same precision back in all callbacks? I really don't want to fork this project because something small like this :D

Thanks in advance.

vydimitrov commented 2 years ago

Hey @Hirbod, that is an interesting idea. I think you can achieve most of it with the current API. The timer duration is always precise, so you pass 9.487000, it will be over at that time. You can check the code here. There is no rounding for the duration. The only thing that I am rounding is the remainingTime but there you can use the elapsedTime that the children function takes, like so:

const duration =  9.487000
const children = ({ elapsedTIme }) => {
  return duration - elaspedTime
}

This will give you the precision you want. The only thing that I can't see working for now is the onUpdate, but you can anyhow hook your logic from the children function to get your precision.

Does this help?

hirbod commented 2 years ago

Hi @vydimitrov, I was just referring to the remainingTime, sorry. I have following durations:

30 seconds 60 seconds 120 seconds

Once selected, the duration is set. The user starts recording (I trigger a state update for isPlaying)

            <CountdownCircleTimer
              isPlaying={isRecording}
              key={(recordDuration + '' + remainingRecordingTime).toString()}
              initialRemainingTime={remainingRecordingTime == null ? recordDuration : remainingRecordingTime}

Your component automatically starts running now. The recording can be stopped or will forcefully be stopped, once onComplete() triggers. Once the video record is done, I run ffprobe to get the exact duration + a little reduce function to get the sum of all recorded clips.

    const recordedTime = recordedClips.reduce((accumulator, current) => accumulator + current.duration, 0);
    if (recordedTime != null) {
      const remainingTime = Math.max(recordDuration - recordedTime, 0);
      setRemainingRecordingTime(remainingTime);
    }

My issue is, that onComplete triggers a bit to early based on my calculated value (most of the times, there is 0.0031234 ish left), which will be shown as 1 though.

I need to somehow get the real recorded duration and the remainingTime somehow perfectly synced.

hirbod commented 2 years ago

Hi @vydimitrov, thanks for rubberducking with me. I got a solution now :D

vydimitrov commented 2 years ago

Yup, you can use the elapsedTime to display the remaining time, which has the full precision you need. Check it here:

https://codesandbox.io/s/flamboyant-cartwright-1vz3q?file=/src/index.js

Is this what you need?

hirbod commented 2 years ago

My issue was, that onComplete triggered setRemainingRecordingTime(0), but once recordedClips effect triggered (and ffprobe runs async`, I will have a different total duration (because ffprobe is counting based on video frames).

And my reduce function will most likely be off. I just added a check that once onComplete triggered the value(0), that I am not updating the remainingTime again.

Awesome library, love it!