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

How to save current duration after reopening app #192

Closed mattpilleul closed 2 years ago

mattpilleul commented 2 years ago

Hello !

I wanted to know how to save the remaining time and displaying it back when launching app again.

Here is my current code :

<CountdownCircleTimer
            isPlaying={true}
            duration={duration}
            size={280}
            strokeWidth={20}
            trailColor="#FFEEF6"
            rotation="counterclockwise"
            trailStrokeWidth={20}
            initialRemainingTime={remainingTimeRef}
            colors={'#EB589A'}
            children={({remainingTime}) => {
              const hours = Math.floor(remainingTime / 3600);
              const minutes = Math.floor((remainingTime % 3600) / 60);
              const seconds = remainingTime % 60;
              remainingTimeRef.current = remainingTime;
              return (
                <Text
                  style={{
                    fontStyle: 'normal',
                    fontWeight: '500',
                    fontSize: 24,
                    textAlign: 'center',
                    letterSpacing: 2,
                    lineHeight: 32,
                  }}>
                  {hours}:{minutes}:{seconds}
                </Text>
              );
            }}
            onComplete={() => ({shouldRepeat: false}, setEndTitle(true))}

If anyone as a solution, it will help me !

vydimitrov commented 2 years ago

Hey @mattpilleul, I do not see the whole implantation but it seems you have a error here initialRemainingTime={remainingTimeRef} it should be initialRemainingTime={remainingTimeRef.current}. Otherwise you can use onUpdate to get the remaining time and save it somewhere. Later when the App is launched again just use it for the initialRemainingTime. In case the component is not unmounted then you will need to pass a new key prop to the component so it can start over.

mattpilleul commented 2 years ago

Hi ! Thanks for your quick answer, I've been passing remainingTimeRef.current but not working.

Do you have a simple example with onUpdate props ?

How could i save remainingTime and display it on app launching ? I'm a little confused..

vydimitrov commented 2 years ago

Hey you will need to listen for App state change, like shown here - https://reactnative.dev/docs/appstate

When the app becomes active again/second time, you will need to pass a new key prop the timer component and the remaining time you saved, something like this one:

import React, { useRef, useState, useEffect } from "react";
import { AppState, StyleSheet, Text, View } from "react-native";

const AppStateExample = () => {
  const [key, setKey] = useState(0)
  const appState = useRef(AppState.currentState);
  const [appStateVisible, setAppStateVisible] = useState(appState.current);

  useEffect(() => {
    const subscription = AppState.addEventListener("change", nextAppState => {
      if (
        appState.current.match(/inactive|background/) &&
        nextAppState === "active"
      ) {
        console.log("App has come to the foreground!");
       // Here the App is active again so now we change the "key" so the countdown will rerender and
     // take the remaining time you saved and pass to it
      setKey(prev => prev+1)
      }

      appState.current = nextAppState;
      setAppStateVisible(appState.current);
      console.log("AppState", appState.current);
    });

    return () => {
      subscription.remove();
    };
  }, []);

<Countedown
  key={key}
   initialRemainingTime={remainingTimeRef.current}.
/>
mattpilleul commented 2 years ago

Thanks for rapid reply ! Just tested your method, every is working great in background but when i kill the app and launch it again same problem, the duration uses default useState value. I don't understand what I'm missing here...

mattpilleul commented 2 years ago

Thanks for rapid reply ! Just tested your method, every is working great in background but when i kill the app and launch it again same problem, the duration uses default useState value. I don't understand what I'm missing here...

My bad, even in background mode the countdown seems to stop :(

vydimitrov commented 2 years ago

When you kill the app then all local component state is gone. You will need to save the remaining time in some persistent place, like on the Web is local storage or DB.

The countdown should reflect the time passed while it was on the background and continue from where there but not the place where the countdown when in the background. If you want to keep the same time as the one when it went in the background you can simply pause it when going to background and start in again when active.

mattpilleul commented 2 years ago

Ok sounds good. I will try saving it somewhere ! Thanks for you time and advice

mattpilleul commented 2 years ago

Hi ! Could you help me on this current problem ?

I've been thinking about a solution but nothing seems working...

vydimitrov commented 2 years ago

Hey, can you create ExpoSnack with the code you have and we can try to work it together there?

mattpilleul commented 2 years ago

Hey, can you create ExpoSnack with the code you have and we can try to work it together there?

So ! I'm currently facing issues on Expo Snack with babel runtime, could i share you the project, in private ?

vydimitrov commented 2 years ago

Sure, you can add me as a contributor, I just need to look around and see what you are trying to achieve.

mattpilleul commented 2 years ago

Done ! Just check Screens/Home.js

vydimitrov commented 2 years ago

@mattpilleul, did you manage to get it working?