diff --git a/README.md b/README.md index 24e010a..5e9d3dd 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A powerful task management and focus timer plugin for [Obsidian](https://obsidia ![Focus Task Banner](https://img.shields.io/badge/Obsidian-Plugin-7c3aed?style=for-the-badge&logo=obsidian&logoColor=white) ![License](https://img.shields.io/badge/License-MIT-green?style=for-the-badge) -![Version](https://img.shields.io/badge/Version-1.0.7-blue?style=for-the-badge) +![Version](https://img.shields.io/badge/Version-1.0.8-blue?style=for-the-badge) ## 🎯 Overview @@ -49,7 +49,7 @@ Focus Task brings the power of time-boxed task management directly into your Obs - **Daily Note Logging**: Automatically log completed tasks to your daily notes with timestamps and performance metrics ### 🎨 User Experience -- **Status Bar Timer**: timer that stays visible while you work +- **Status Bar Timer**: Timer that stays visible while you work - **Celebration Messages**: Fun, randomized messages when you complete tasks - **Sound Notifications**: Audio alerts for timer completion and task completion - **Keyboard Shortcuts**: Quick access to common actions diff --git a/main.js b/main.js index fae9149..e155c3b 100644 --- a/main.js +++ b/main.js @@ -714,42 +714,10 @@ var FocusTaskPlugin = class extends import_obsidian3.Plugin { // ============ Timer Management ============ // Sync timer based on timestamp when app returns from background syncTimerFromTimestamp() { - if (!this.isTimerRunning || this.timerStartTimestamp === 0) + if (!this.isTimerRunning) return; - const now = Date.now(); - const elapsedMs = now - this.timerStartTimestamp; - const elapsedSeconds = Math.floor(elapsedMs / 1e3); - if (elapsedSeconds < 1) - return; - if (this.isBreakMode) { - this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds); - if (this.currentTimerSeconds <= 0) { - this.handlePomodoroEnd(); - } - } else { - const task = this.data.tasks.find((t) => t.id === this.activeTaskId); - if (!task) - return; - if (this.pausedTimeRemaining > 0) { - this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds); - this.secondsWorkedOnCurrentTask += elapsedSeconds; - task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); - this.focusSecondsToday += elapsedSeconds; - if (this.currentTimerSeconds <= 0) { - this.handlePomodoroEnd(); - } - } else { - this.currentTimerSeconds += elapsedSeconds; - this.secondsWorkedOnCurrentTask += elapsedSeconds; - task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); - this.focusSecondsToday += elapsedSeconds; - } - } - this.timerStartTimestamp = now; - this.pausedTimeRemaining = this.currentTimerSeconds; this.updateStatusBar(); this.updateTimerDisplay(); - this.saveAllData(); } startTimer(taskId) { const task = this.data.tasks.find((t) => t.id === taskId); @@ -764,16 +732,23 @@ var FocusTaskPlugin = class extends import_obsidian3.Plugin { this.secondsWorkedOnCurrentTask = task.actualMinutes * 60; this.timerStartTimestamp = Date.now(); this.pausedTimeRemaining = 0; + const initialSecondsWorked = this.secondsWorkedOnCurrentTask; + let alertShown = false; this.refreshView(); this.updateStatusBar(); this.timerInterval = window.setInterval(() => { - this.currentTimerSeconds++; - this.secondsWorkedOnCurrentTask++; + const now = Date.now(); + const elapsedMs = now - this.timerStartTimestamp; + const elapsedSeconds = Math.floor(elapsedMs / 1e3); + this.currentTimerSeconds = elapsedSeconds; + this.secondsWorkedOnCurrentTask = initialSecondsWorked + elapsedSeconds; task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); - this.focusSecondsToday++; + const newFocusSeconds = Math.floor((this.data.totalFocusMinutesToday || 0) * 60) + elapsedSeconds; + this.focusSecondsToday = newFocusSeconds; this.updateStatusBar(); this.updateTimerDisplay(); - if (this.currentTimerSeconds === task.estimatedMinutes * 60) { + if (!alertShown && this.currentTimerSeconds >= task.estimatedMinutes * 60) { + alertShown = true; if (this.settings.enableSounds) { this.playAlertSound(); } @@ -795,17 +770,22 @@ var FocusTaskPlugin = class extends import_obsidian3.Plugin { this.secondsWorkedOnCurrentTask = Math.floor(task.actualMinutes * 60); this.timerStartTimestamp = Date.now(); this.pausedTimeRemaining = this.currentTimerSeconds; + const initialSecondsWorked = this.secondsWorkedOnCurrentTask; this.refreshView(); this.updateStatusBar(); this.timerInterval = window.setInterval(() => { - this.currentTimerSeconds--; + const now = Date.now(); + const elapsedMs = now - this.timerStartTimestamp; + const elapsedSeconds = Math.floor(elapsedMs / 1e3); + this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds); if (!this.isBreakMode) { - this.secondsWorkedOnCurrentTask++; + this.secondsWorkedOnCurrentTask = initialSecondsWorked + elapsedSeconds; const actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); if (task.actualMinutes !== actualMinutes) { task.actualMinutes = actualMinutes; } - this.focusSecondsToday++; + const newFocusSeconds = Math.floor((this.data.totalFocusMinutesToday || 0) * 60) + elapsedSeconds; + this.focusSecondsToday = newFocusSeconds; } this.updateStatusBar(); this.updateTimerDisplay(); @@ -855,7 +835,10 @@ var FocusTaskPlugin = class extends import_obsidian3.Plugin { this.refreshView(); if (!this.timerInterval) { this.timerInterval = window.setInterval(() => { - this.currentTimerSeconds--; + const now = Date.now(); + const elapsedMs = now - this.timerStartTimestamp; + const elapsedSeconds = Math.floor(elapsedMs / 1e3); + this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds); this.updateStatusBar(); this.updateTimerDisplay(); if (this.currentTimerSeconds <= 0) { @@ -875,12 +858,17 @@ var FocusTaskPlugin = class extends import_obsidian3.Plugin { this.isTimerRunning = true; this.timerStartTimestamp = Date.now(); const task = this.data.tasks.find((t) => t.id === this.activeTaskId); + const initialSecondsWorked = this.secondsWorkedOnCurrentTask; this.timerInterval = window.setInterval(() => { - this.currentTimerSeconds--; + const now = Date.now(); + const elapsedMs = now - this.timerStartTimestamp; + const elapsedSeconds = Math.floor(elapsedMs / 1e3); + this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds); if (task && !this.isBreakMode) { - this.secondsWorkedOnCurrentTask++; + this.secondsWorkedOnCurrentTask = initialSecondsWorked + elapsedSeconds; task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); - this.focusSecondsToday++; + const newFocusSeconds = Math.floor((this.data.totalFocusMinutesToday || 0) * 60) + elapsedSeconds; + this.focusSecondsToday = newFocusSeconds; } this.updateStatusBar(); this.updateTimerDisplay(); diff --git a/manifest.json b/manifest.json index 4eb6f3f..daaaa96 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "focus-task", "name": "Focus Task", - "version": "1.0.7", + "version": "1.0.8", "minAppVersion": "0.15.0", "description": "A Blitzit-inspired task management and focus timer plugin. Plan your day, track time with Pomodoro technique, and crush your tasks with satisfying checkoffs.", "author": "Crib", diff --git a/package.json b/package.json index 7788223..aa07a6d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "focus-task", - "version": "1.0.7", + "version": "1.0.8", "description": "A Blitzit-inspired task management and focus timer plugin for Obsidian", "main": "main.js", "scripts": { diff --git a/src/main.ts b/src/main.ts index 3c7cb1b..e24ffb4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -273,56 +273,14 @@ export default class FocusTaskPlugin extends Plugin { // Sync timer based on timestamp when app returns from background syncTimerFromTimestamp() { - if (!this.isTimerRunning || this.timerStartTimestamp === 0) return; + // Since all intervals now calculate from timestamps directly, + // we just need to trigger an update when coming back to foreground + if (!this.isTimerRunning) return; - const now = Date.now(); - const elapsedMs = now - this.timerStartTimestamp; - const elapsedSeconds = Math.floor(elapsedMs / 1000); - - // If less than 1 second elapsed, no need to sync - if (elapsedSeconds < 1) return; - - 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; - } - } - - // Reset timestamp to now to prevent double-counting on next sync - this.timerStartTimestamp = now; - this.pausedTimeRemaining = this.currentTimerSeconds; - - // Update displays + // The interval will automatically calculate correct values on next tick + // Just update the display immediately to show current state this.updateStatusBar(); this.updateTimerDisplay(); - this.saveAllData(); } startTimer(taskId: string) { @@ -344,25 +302,39 @@ export default class FocusTaskPlugin extends Plugin { this.timerStartTimestamp = Date.now(); this.pausedTimeRemaining = 0; // 0 indicates stopwatch mode + // Store initial values + const initialSecondsWorked = this.secondsWorkedOnCurrentTask; + let alertShown = false; + // Full refresh to show the active task card this.refreshView(); this.updateStatusBar(); // Start interval (count up mode - stopwatch) this.timerInterval = window.setInterval(() => { - this.currentTimerSeconds++; - this.secondsWorkedOnCurrentTask++; + // Calculate elapsed time from timestamp + const now = Date.now(); + const elapsedMs = now - this.timerStartTimestamp; + const elapsedSeconds = Math.floor(elapsedMs / 1000); + + // Update timer (count up) + this.currentTimerSeconds = elapsedSeconds; + + // Update actual time worked + this.secondsWorkedOnCurrentTask = initialSecondsWorked + elapsedSeconds; task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); - // Track focus time - this.focusSecondsToday++; + // Update focus time + const newFocusSeconds = Math.floor((this.data.totalFocusMinutesToday || 0) * 60) + elapsedSeconds; + this.focusSecondsToday = newFocusSeconds; // Light update - only timer display, no full refresh this.updateStatusBar(); this.updateTimerDisplay(); - // Check if over estimate - if (this.currentTimerSeconds === task.estimatedMinutes * 60) { + // Check if over estimate (only alert once) + if (!alertShown && this.currentTimerSeconds >= task.estimatedMinutes * 60) { + alertShown = true; if (this.settings.enableSounds) { this.playAlertSound(); } @@ -392,23 +364,34 @@ export default class FocusTaskPlugin extends Plugin { this.timerStartTimestamp = Date.now(); this.pausedTimeRemaining = this.currentTimerSeconds; + // Store the initial seconds worked to calculate delta + const initialSecondsWorked = this.secondsWorkedOnCurrentTask; + // Full refresh to show the active task card this.refreshView(); this.updateStatusBar(); this.timerInterval = window.setInterval(() => { - this.currentTimerSeconds--; + // Calculate elapsed time from timestamp (more accurate than counting ticks) + const now = Date.now(); + const elapsedMs = now - this.timerStartTimestamp; + const elapsedSeconds = Math.floor(elapsedMs / 1000); + + // Update countdown timer + this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds); if (!this.isBreakMode) { - this.secondsWorkedOnCurrentTask++; - // Calculate actual minutes from total seconds worked + // Update actual time worked based on real elapsed time + this.secondsWorkedOnCurrentTask = initialSecondsWorked + elapsedSeconds; const actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); - // Only update if changed to avoid unnecessary updates + if (task.actualMinutes !== actualMinutes) { task.actualMinutes = actualMinutes; } - // Increment focus time by 1 second - this.focusSecondsToday++; + + // Update focus time based on elapsed seconds + const newFocusSeconds = Math.floor((this.data.totalFocusMinutesToday || 0) * 60) + elapsedSeconds; + this.focusSecondsToday = newFocusSeconds; } // Light update - only timer display, no full refresh @@ -483,7 +466,14 @@ export default class FocusTaskPlugin extends Plugin { if (!this.timerInterval) { this.timerInterval = window.setInterval(() => { - this.currentTimerSeconds--; + // Calculate elapsed time from timestamp + const now = Date.now(); + const elapsedMs = now - this.timerStartTimestamp; + const elapsedSeconds = Math.floor(elapsedMs / 1000); + + // Update countdown timer + this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds); + // Light update - only timer display this.updateStatusBar(); this.updateTimerDisplay(); @@ -510,14 +500,28 @@ export default class FocusTaskPlugin extends Plugin { this.timerStartTimestamp = Date.now(); const task = this.data.tasks.find(t => t.id === this.activeTaskId); + // Store initial values for resume + const initialSecondsWorked = this.secondsWorkedOnCurrentTask; + this.timerInterval = window.setInterval(() => { - this.currentTimerSeconds--; + // Calculate elapsed time from timestamp + const now = Date.now(); + const elapsedMs = now - this.timerStartTimestamp; + const elapsedSeconds = Math.floor(elapsedMs / 1000); + + // Update timer (countdown from paused position) + this.currentTimerSeconds = Math.max(0, this.pausedTimeRemaining - elapsedSeconds); + if (task && !this.isBreakMode) { - this.secondsWorkedOnCurrentTask++; + // Update actual time worked + this.secondsWorkedOnCurrentTask = initialSecondsWorked + elapsedSeconds; task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); - // Track focus time - this.focusSecondsToday++; + + // Update focus time + const newFocusSeconds = Math.floor((this.data.totalFocusMinutesToday || 0) * 60) + elapsedSeconds; + this.focusSecondsToday = newFocusSeconds; } + // Light update - only timer display this.updateStatusBar(); this.updateTimerDisplay(); diff --git a/versions.json b/versions.json index 87c169d..cce5136 100644 --- a/versions.json +++ b/versions.json @@ -2,5 +2,6 @@ "1.0.4": "0.15.0", "1.0.5": "0.15.0", "1.0.6": "0.15.0", - "1.0.7": "0.15.0" + "1.0.7": "0.15.0", + "1.0.8": "0.15.0" }