Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add extra logic to keep track of time accurately in the background #664

Merged
merged 1 commit into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 48 additions & 15 deletions app/renderer/src/contexts/CounterContext.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useState, useEffect, useCallback } from "react";
import React, { useCallback, useEffect, useState } from "react";
import useStayAwake from "use-stay-awake";
import { setRound, setTimerType, setPlay } from "store";
import { setPlay, setRound, setTimerType } from "store";
import { useNotification } from "hooks";
import { padNum, isEqualToOne } from "utils";
import { isEqualToOne, padNum } from "utils";

import notificationIcon from "assets/logos/notification-dark.png";

Expand Down Expand Up @@ -51,12 +51,24 @@ const CounterProvider: React.FC = ({ children }) => {
const [shouldFullscreen, setShouldFullscreen] = useState(false);

const [count, setCount] = useState(config.stayFocus * 60);
const [lastCountTime, setLastCountTime] = useState(Date.now());
const [hasNotified30Seconds, setHasNotified30Seconds] =
useState(false);
const [hasNotified60Seconds, setHasNotified60Seconds] =
useState(false);
const [hasNotifiedBreak, setHasNotifiedBreak] = useState(false);

const [duration, setDuration] = useState(config.stayFocus * 60);

const setTimerDuration = useCallback((time: number) => {
setDuration(time * 60);
setCount(time * 60);
setLastCountTime(Date.now());
setHasNotified30Seconds(false);
if (time > 1) {
setHasNotified60Seconds(false);
}
setHasNotifiedBreak(false);
}, []);

const resetTimerAction = useCallback(() => {
Expand All @@ -71,8 +83,7 @@ const CounterProvider: React.FC = ({ children }) => {
setTimerDuration(config.longBreak);
break;
case TimerStatus.SPECIAL_BREAK:
setDuration(duration);
setCount(duration);
setTimerDuration(duration / 60);
break;
}
}, [
Expand All @@ -81,10 +92,15 @@ const CounterProvider: React.FC = ({ children }) => {
config.shortBreak,
timer.timerType,
duration,
setDuration,
setTimerDuration,
]);

useEffect(() => {
if (timer.playing) {
setLastCountTime(Date.now());
}
}, [timer.playing]);

useEffect(() => {
if (timer.playing && timer.timerType !== TimerStatus.STAY_FOCUS) {
preventSleeping();
Expand Down Expand Up @@ -212,21 +228,28 @@ const CounterProvider: React.FC = ({ children }) => {
useEffect(() => {
let timerInterval: NodeJS.Timeout;

// calculate how far off a full second the countdown timer is and adjust the countdown timer accordingly
const offset = count % 1;
if (timer.playing) {
timerInterval = setInterval(() => {
setCount((prevState) => {
let remaining = prevState - 1;
return remaining;
// Calculate time passed since last count
const now = Date.now();
const timePassed = now - lastCountTime;

setLastCountTime(Date.now());
return prevState - timePassed / 1000;
});
}, 1000);
}, offset * 1000);
}

return () => clearInterval(timerInterval);
}, [timer.playing]);
}, [timer.playing, lastCountTime, count]);

useEffect(() => {
if (settings.notificationType === "extra") {
if (count === 61) {
if (count <= 60 && count > 0 && !hasNotified60Seconds) {
setHasNotified60Seconds(true);
if (timer.timerType === TimerStatus.SHORT_BREAK) {
notification(
"60 seconds left.",
Expand All @@ -247,9 +270,12 @@ const CounterProvider: React.FC = ({ children }) => {
);
}
} else if (
count === 31 &&
timer.timerType === TimerStatus.STAY_FOCUS
count <= 30 &&
count > 0 &&
timer.timerType === TimerStatus.STAY_FOCUS &&
!hasNotified30Seconds
) {
setHasNotified30Seconds(true);
notification(
"30 seconds left.",
{ body: "Pause all media playing if there's one." },
Expand All @@ -258,7 +284,8 @@ const CounterProvider: React.FC = ({ children }) => {
}
}

if (count === 0) {
if (count <= 0 && !hasNotifiedBreak) {
setHasNotifiedBreak(true);
switch (timer.timerType) {
case TimerStatus.STAY_FOCUS:
if (timer.round < config.sessionRounds) {
Expand Down Expand Up @@ -379,6 +406,12 @@ const CounterProvider: React.FC = ({ children }) => {
settings.notificationType,
settings.autoStartWorkTime,
settings.enableVoiceAssistance,
hasNotified60Seconds,
hasNotified60Seconds,
hasNotifiedBreak,
setHasNotified30Seconds,
setHasNotified60Seconds,
setHasNotifiedBreak,
]);

useEffect(() => {
Expand All @@ -394,7 +427,7 @@ const CounterProvider: React.FC = ({ children }) => {
return (
<CounterContext.Provider
value={{
count,
count: Math.ceil(count),
duration,
resetTimerAction,
shouldFullscreen,
Expand Down
2 changes: 1 addition & 1 deletion app/tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "pomatez"
# In the current version of release please, unless the toml file is in the root of the project it cannot be updated.
# https://github.com/googleapis/release-please/issues/1724
# util/cargo-version-updater.js will run to keep this value up to date before rust builds.
version = "1.6.4"
version = "1.7.0"
description = "Attractive pomodoro timer for Windows, Mac, and Linux."
authors = ["Roldan Montilla Jr"]
license = "MIT"
Expand Down
Loading
Loading