Release v1.0.6: Background Timer Fix

This commit is contained in:
2025-11-23 13:15:45 +01:00
parent 9abdd10ada
commit 2f861c2fcb
9 changed files with 212 additions and 10 deletions

View File

@@ -37,6 +37,10 @@ export default class FocusTaskPlugin extends Plugin {
activeTaskId: string | null = null;
pomodoroCount: number = 0;
// Timestamp-based tracking for reliable background timing
private timerStartTimestamp: number = 0;
private pausedTimeRemaining: number = 0;
// Focus time tracking (in seconds for accuracy)
private focusSecondsToday: number = 0;
private secondsWorkedOnCurrentTask: number = 0;
@@ -46,10 +50,17 @@ export default class FocusTaskPlugin extends Plugin {
async onload() {
await this.loadAllData();
// Check and reset daily stats
this.checkDailyReset();
// Handle visibility changes to sync timer when app comes back to foreground
document.addEventListener('visibilitychange', () => {
if (!document.hidden && this.isTimerRunning) {
this.syncTimerFromTimestamp();
}
});
// Register the main view
this.registerView(
VIEW_TYPE_FOCUS_TASK,
@@ -251,6 +262,53 @@ export default class FocusTaskPlugin extends Plugin {
// ============ Timer Management ============
// Sync timer based on timestamp when app returns from background
syncTimerFromTimestamp() {
if (!this.isTimerRunning || this.timerStartTimestamp === 0) return;
const now = Date.now();
const elapsedMs = now - this.timerStartTimestamp;
const elapsedSeconds = Math.floor(elapsedMs / 1000);
if (this.isBreakMode) {
// Break mode: countdown timer
this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds);
if (this.currentTimerSeconds <= 0) {
this.handlePomodoroEnd();
}
} else {
// Work mode: check if it's pomodoro (countdown) or stopwatch (count up)
const task = this.data.tasks.find(t => t.id === this.activeTaskId);
if (!task) return;
if (this.pausedTimeRemaining > 0) {
// Pomodoro countdown mode
this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds);
// Update actual minutes worked
this.secondsWorkedOnCurrentTask += elapsedSeconds;
task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60);
this.focusSecondsToday += elapsedSeconds;
if (this.currentTimerSeconds <= 0) {
this.handlePomodoroEnd();
}
} else {
// Stopwatch count up mode
this.currentTimerSeconds += elapsedSeconds;
this.secondsWorkedOnCurrentTask += elapsedSeconds;
task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60);
this.focusSecondsToday += elapsedSeconds;
}
}
// Update displays
this.updateStatusBar();
this.updateTimerDisplay();
this.saveAllData();
}
startTimer(taskId: string) {
const task = this.data.tasks.find(t => t.id === taskId);
if (!task) return;
@@ -266,6 +324,10 @@ export default class FocusTaskPlugin extends Plugin {
this.isTimerRunning = true;
this.secondsWorkedOnCurrentTask = task.actualMinutes * 60;
// Set timestamp for background tracking (stopwatch mode)
this.timerStartTimestamp = Date.now();
this.pausedTimeRemaining = 0; // 0 indicates stopwatch mode
// Full refresh to show the active task card
this.refreshView();
this.updateStatusBar();
@@ -275,14 +337,14 @@ export default class FocusTaskPlugin extends Plugin {
this.currentTimerSeconds++;
this.secondsWorkedOnCurrentTask++;
task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60);
// Track focus time
this.focusSecondsToday++;
// Light update - only timer display, no full refresh
this.updateStatusBar();
this.updateTimerDisplay();
// Check if over estimate
if (this.currentTimerSeconds === task.estimatedMinutes * 60) {
if (this.settings.enableSounds) {
@@ -309,6 +371,10 @@ export default class FocusTaskPlugin extends Plugin {
// Initialize from existing actual time to preserve progress across breaks
this.secondsWorkedOnCurrentTask = task.actualMinutes * 60;
// Set timestamp for background tracking (pomodoro countdown mode)
this.timerStartTimestamp = Date.now();
this.pausedTimeRemaining = this.currentTimerSeconds;
// Full refresh to show the active task card
this.refreshView();
this.updateStatusBar();
@@ -384,6 +450,10 @@ export default class FocusTaskPlugin extends Plugin {
const isLongBreak = this.pomodoroCount % this.settings.longBreakInterval === 0;
this.currentTimerSeconds = (isLongBreak ? this.settings.longBreakMinutes : this.settings.pomodoroBreakMinutes) * 60;
// Set timestamp for background tracking (break countdown mode)
this.timerStartTimestamp = Date.now();
this.pausedTimeRemaining = this.currentTimerSeconds;
new Notice(isLongBreak ? '☕ Long break time!' : '☕ Short break time!');
// Full refresh to show break state
@@ -407,13 +477,15 @@ export default class FocusTaskPlugin extends Plugin {
toggleTimer() {
if (this.isTimerRunning && this.timerInterval) {
// Pause
// Pause - save current state
window.clearInterval(this.timerInterval);
this.timerInterval = null;
this.isTimerRunning = false;
this.pausedTimeRemaining = this.currentTimerSeconds;
} else if (this.activeTaskId) {
// Resume
// Resume - restart with new timestamp
this.isTimerRunning = true;
this.timerStartTimestamp = Date.now();
const task = this.data.tasks.find(t => t.id === this.activeTaskId);
this.timerInterval = window.setInterval(() => {
@@ -457,6 +529,8 @@ export default class FocusTaskPlugin extends Plugin {
this.isTimerRunning = false;
this.activeTaskId = null;
this.secondsWorkedOnCurrentTask = 0;
this.timerStartTimestamp = 0;
this.pausedTimeRemaining = 0;
this.updateStatusBar();
this.saveAllData();
this.refreshView();