mirror of
https://github.com/remvze/moodist.git
synced 2026-02-28 00:53:13 +08:00
feat: add alarm for pomodoro timer
This commit is contained in:
BIN
public/sounds/alarm.mp3
Normal file
BIN
public/sounds/alarm.mp3
Normal file
Binary file not shown.
@@ -9,6 +9,7 @@ import { Button } from './button';
|
||||
import { Setting } from './setting';
|
||||
|
||||
import { useLocalStorage } from '@/hooks/use-local-storage';
|
||||
import { useSoundEffect } from '@/hooks/use-sound-effect';
|
||||
import { usePomodoroStore } from '@/store';
|
||||
|
||||
import styles from './pomodoro.module.css';
|
||||
@@ -29,6 +30,8 @@ export function Pomodoro({ onClose, show }: PomodoroProps) {
|
||||
const [timer, setTimer] = useState(0);
|
||||
const interval = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
|
||||
const alarm = useSoundEffect('/sounds/alarm.mp3');
|
||||
|
||||
const defaultTimes = useMemo(
|
||||
() => ({
|
||||
long: 15 * 60,
|
||||
@@ -74,13 +77,15 @@ export function Pomodoro({ onClose, show }: PomodoroProps) {
|
||||
if (timer <= 0 && running) {
|
||||
if (interval.current) clearInterval(interval.current);
|
||||
|
||||
alarm.play();
|
||||
|
||||
setRunning(false);
|
||||
setCompletions(prev => ({
|
||||
...prev,
|
||||
[selectedTab]: prev[selectedTab] + 1,
|
||||
}));
|
||||
}
|
||||
}, [timer, selectedTab, running, setRunning]);
|
||||
}, [timer, selectedTab, running, setRunning, alarm]);
|
||||
|
||||
useEffect(() => {
|
||||
const time = times[selectedTab] || 10;
|
||||
|
||||
45
src/hooks/use-sound-effect.ts
Normal file
45
src/hooks/use-sound-effect.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { useMemo, useEffect, useCallback } from 'react';
|
||||
import { Howl } from 'howler';
|
||||
|
||||
import { useSSR } from './use-ssr';
|
||||
|
||||
export function useSoundEffect(src: string, volume: number = 1) {
|
||||
const { isBrowser } = useSSR();
|
||||
|
||||
const sound = useMemo<Howl | null>(() => {
|
||||
let sound: Howl | null = null;
|
||||
|
||||
if (isBrowser) {
|
||||
sound = new Howl({
|
||||
html5: true,
|
||||
src: src,
|
||||
});
|
||||
}
|
||||
|
||||
return sound;
|
||||
}, [src, isBrowser]);
|
||||
|
||||
useEffect(() => {
|
||||
if (sound) sound.volume(typeof volume === 'number' ? volume : 1);
|
||||
}, [sound, volume]);
|
||||
|
||||
const play = useCallback(() => {
|
||||
if (sound) {
|
||||
if (!sound.playing()) {
|
||||
sound.play();
|
||||
}
|
||||
}
|
||||
}, [sound]);
|
||||
|
||||
const stop = useCallback(() => {
|
||||
if (sound) sound.stop();
|
||||
}, [sound]);
|
||||
|
||||
const pause = useCallback(() => {
|
||||
if (sound) sound.pause();
|
||||
}, [sound]);
|
||||
|
||||
const control = useMemo(() => ({ pause, play, stop }), [play, stop, pause]);
|
||||
|
||||
return control;
|
||||
}
|
||||
Reference in New Issue
Block a user