I'm developing a workout application with Ionic 7 (ReactTS) using Capacitor. I would like to display a notification with the remaining rest time before the next set to the user. The displayed remaining rest time should be updated every second.
What I've tried:
- LocalNotifications.schedule with the same ID but it's just canceling the notification and creating a new one. The sound and visual effects are triggered again.
- LocalNotifications.removeAllDeliveredNotifications and then LocalNotifications.schedule with the same ID but it's just canceling the notification and creating a new one. The sound and visual effects are triggered again.
If anyone knows of a plugin or has a solution, I would greatly appreciate it.
Here is my component "CountDown.tsx" :
import React, { useEffect } from 'react';
// Assets
import BoxingBellSound from '../../assets/sounds/boxingBell.mp3';
// Components
import { CountdownCircleTimer } from 'react-countdown-circle-timer';
// Libraries
import {
LocalNotifications,
LocalNotificationSchema,
} from '@capacitor/local-notifications';
import { App, AppState } from '@capacitor/app';
// Styles
import './CountDown.css';
interface Props {
value: number;
title: string;
}
const CountDown: React.FC<Props> = ({ title, value }) => {
let remainingTime: number = value;
const sendNotification = async () => {
const notification: LocalNotificationSchema = {
id: 1,
title,
body: `${remainingTime}`,
smallIcon: 'res://icon.png',
};
await LocalNotifications.schedule({
notifications: [notification],
});
};
const renderChildren = (remainingTime: number) => {
const minutes: number = Math.floor(remainingTime / 60);
const seconds: number = remainingTime % 60;
const formattedMinutes: string =
minutes >= 10 ? minutes.toString() : `0${minutes}`;
const formattedSeconds: string =
seconds >= 10 ? seconds.toString() : `0${seconds}`;
return `${formattedMinutes}:${formattedSeconds}`;
};
useEffect(() => {
const intervalId = setInterval(() => {
if (remainingTime > 0) {
remainingTime -= 1;
sendNotification();
} else {
new Audio(BoxingBellSound).play();
clearInterval(intervalId);
}
}, 1000);
return () => clearInterval(intervalId);
}, []);
return (
<CountdownCircleTimer
isPlaying
duration={value}
colors={['#004777', '#F7B801', '#A30000', '#A30000']}
colorsTime={[7, 5, 2, 0]}
size={80}
>
{({ remainingTime }) => renderChildren(remainingTime)}
</CountdownCircleTimer>
);
};
export default CountDown;