alantoa / react-native-awesome-slider

🚀 An anwesome <Slider/> that supports various features haptic, lottie, animation, ballon, etc.
MIT License
263 stars 30 forks source link

Gap between track and thumb with disableTrackFollow prop while seeking ends #19

Closed efstathiosntonas closed 2 years ago

efstathiosntonas commented 2 years ago

Hi @alantoa, thanks for this awesome library.

When I use disableTrackFollow there's a gap between the track and the thumb after seeking is complete on both iOS and Android. No expensive calculations or re-renders are taking place, only the parent which holds the player controls. I'm passing the progress directly to the slider from parent.

See attached video, I've made the thumb transparent for testing purposes:

https://user-images.githubusercontent.com/717975/174292503-8fe06f5c-082f-4015-a4db-3ece72afe91f.mov

Parent:


  const progress = useSharedValue(0);

const playAudio = useCallback(async () => {
    await startPlayer(currentMessage?.audio?.url, (res: any) => {
      const { status } = res;
      switch (status) {
        case AUDIO_STATUS.begin: {
          setPlaying(true);
          break;
        }
        case AUDIO_STATUS.play: {
          const { currentPosition } = res.data;
          progress.value = currentPosition;  <---- setting progress here
          setPlayTime(msToHMS(currentPosition)); <-- setting current position to display mm:ss
          break;
        }
  .....
}, [])

return (
  <TrackPlayerProgress
              disabled={!playing}
              duration={currentMessage?.audio?.secs}
              messagePosition={position}
              onSeekComplete={seekPlayer}
              progress={progress}
            />
)

and the TrackPlayerProgress:

interface IProps {
  disabled: boolean;
  duration: number | undefined;
  messagePosition: string;
  onSeekComplete: (position: number) => Promise<void>;
  progress: Animated.SharedValue<number>;
  themeContext: any;
}

const TrackPlayerProgress = ({
  disabled,
  duration,
  messagePosition,
  progress,
  themeContext
}: IProps) => {
  const isScrubbing = useSharedValue(false);
  const minValue = useSharedValue(0);

  const maxValue = useDerivedValue(() => {
    return duration;
  }, [duration]);

  const pauseAudio = useCallback(async () => {
    breadcrumb("User Paused Audio Message");
    await pausePlayer();
  }, []);

  const onSlidingStart = useCallback(async () => {
    await pauseAudio();
  }, [pauseAudio]);

  const onSlidingComplete = (slideValue: number) => {
    seekPlayer(slideValue).then(() => {
      isScrubbing.value = false;
    });
  };

  const theme = useMemo(
    () => ({
      minimumTrackTintColor:
        messagePosition === "right"
          ? themeContext.chatScreen.audioPlayer.right.minimumTrack
          : themeContext.chatScreen.audioPlayer.left.minimumTrack,
      maximumTrackTintColor:
        messagePosition === "right"
          ? themeContext.chatScreen.audioPlayer.right.track
          : themeContext.chatScreen.audioPlayer.left.track,
      bubbleBackgroundColor: themeContext.chatScreen.audioPlayer.timeBubble,
      bubbleTextColor: themeContext.chatScreen.audioPlayer.timeBubbleText
    }),
    [messagePosition, themeContext]
  );

  console.count("rendering track component");

  return (
    <View style={styles.container}>
      <View style={styles.sliderInnerContainer}>
        <Slider
          bubble={msToHMS}
          disableTrackFollow
          bubbleTranslateY={Platform.OS === "ios" ? -20 : -30}
          containerStyle={styles.sliderContainer}
          disable={disabled}
          isScrubbing={isScrubbing}
          // @ts-ignore
          maximumValue={maxValue}
          minimumValue={minValue}
          onSlidingComplete={onSlidingComplete}
          onSlidingStart={onSlidingStart}
          progress={progress}
          sliderHeight={5}
          style={styles.slider}
          thumbWidth={20}
          theme={theme}
        />
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    alignItems: "center",
    marginLeft: 5,
    marginRight: 15
  },
  sliderInnerContainer: {
    maxWidth: 500,
    position: "relative",
    width: "100%"
  },
  sliderContainer: {
    borderRadius: 50
  },
  slider: {
    borderRadius: 12,
    marginBottom: 14,
    marginTop: 16
  }
});

export default React.memo(TrackPlayerProgress, isEqual);

I believe there's a miscalculation between the thumbSize and the min track position/width after the seek. Tried to debug it a bit and what fixes it somehow is to remove - thumbWidth from this function:

  const progressToValue = (value: number) => {
    'worklet';
    if (sliderTotalValue() === 0) {
      return 0;
    }
    return (value / sliderTotalValue()) * (width.value - thumbWidth);
  };

After removing the - thumbWidth it works fine but the thumb reaches the end and the audio is still playing.

efstathiosntonas commented 2 years ago

Just found out that this happens with all audio messages, not only after seek, see video:

https://user-images.githubusercontent.com/717975/174294469-f1c58fb7-e977-489f-83da-d10cc163389d.mov

This video has disableTrackFollow disabled at start and then disabled at 0:22, without it the track stays always in the middle of the thumb while when enabled the track starts "loosing" it and it stays progressively behind the thumb as the time pass by:

https://user-images.githubusercontent.com/717975/174297188-d55da1f6-1de6-4c52-9164-d6ae0401f42b.mov

alantoa commented 2 years ago

hey @efstathiosntonas! thanks for looking into this! 🙏 I remember that I have dealt with this issue before, maybe it reappeared in a PR. I'll find time to look at it over the weekend or next week! this lib is not complicated, if you have solved this issue, welcome free commit PR, I can review and test it!

efstathiosntonas commented 2 years ago

Thanks @alantoa, trying to debug it, if I manage to fix it I'll create a PR.

efstathiosntonas commented 2 years ago

@alantoa found the bug, will create a PR

alantoa commented 2 years ago

hi, @efstathiosntonas, thank you! published in v2.0.8!

efstathiosntonas commented 2 years ago

Thanks @alantoa, keep it up, this is a great library and trust me, I’ve used every single slider out there, this one handles seeking way better than the rest.

alantoa commented 2 years ago

this one handles seeking way better than the rest.

thank you, LFG! I'm glad to help if you have any issues!