Skip to content

Commit

Permalink
feat: pause timer when app enters background
Browse files Browse the repository at this point in the history
  • Loading branch information
gunnartorfis committed Sep 8, 2024
1 parent 3a45aae commit d6e04e7
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 1 deletion.
2 changes: 1 addition & 1 deletion example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const App: React.FC = () => {
<Toaster
position="top-center"
// offset={100}
duration={30000}
duration={5000}
swipToDismissDirection="up"
visibleToasts={4}
closeButton
Expand Down
39 changes: 39 additions & 0 deletions src/toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useToastContext } from './context';
import { ToastSwipeHandler } from './gestures';
import { cn } from './tailwind-utils';
import { isToastAction, type ToastProps } from './types';
import { useAppStateListener } from './use-app-state';
import { useColors } from './use-colors';

export const Toast: React.FC<ToastProps> = ({
Expand Down Expand Up @@ -59,8 +60,46 @@ export const Toast: React.FC<ToastProps> = ({
const isDragging = React.useRef(false);
const timer = React.useRef<NodeJS.Timeout>();
const timerStart = React.useRef<number | undefined>();
const timeLeftOnceBackgrounded = React.useRef<number | undefined>();
const isResolvingPromise = React.useRef(false);

const onBackground = React.useCallback(() => {
if (timer.current) {
timeLeftOnceBackgrounded.current =
duration - (Date.now() - timerStart.current!);
clearTimeout(timer.current);
timer.current = undefined;
timerStart.current = undefined;
}
}, [duration]);

const onForeground = React.useCallback(() => {
if (timeLeftOnceBackgrounded.current) {
if (timeLeftOnceBackgrounded.current > 0) {
timer.current = setTimeout(
() => {
if (!isDragging.current) {
onAutoClose?.(id);
}
},
Math.min(timeLeftOnceBackgrounded.current, 1000) // minimum 1 second to avoid weird behavior
);
} else {
onAutoClose?.(id);
}
}
}, [id, onAutoClose]);

useAppStateListener(
React.useMemo(
() => ({
onBackground,
onForeground,
}),
[onBackground, onForeground]
)
);

React.useEffect(() => {
if (isResolvingPromise.current) {
return;
Expand Down
31 changes: 31 additions & 0 deletions src/use-app-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import { AppState } from 'react-native';

export const useAppStateListener = ({
onBackground,
onForeground,
}: {
onBackground: () => void;
onForeground: () => void;
}) => {
const appState = React.useRef(AppState.currentState);

React.useEffect(() => {
const subscription = AppState.addEventListener('change', (nextAppState) => {
if (
appState.current.match(/inactive|background/) &&
nextAppState === 'active'
) {
onForeground();
} else {
onBackground();
}

appState.current = nextAppState;
});

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

0 comments on commit d6e04e7

Please sign in to comment.