diff --git a/main.js b/main.js index bb7a89d..4f68a0e 100644 --- a/main.js +++ b/main.js @@ -43,7 +43,7 @@ var DEFAULT_SETTINGS = { { id: "personal", name: "Personal", color: "#22c55e", icon: "\u{1F3E0}" }, { id: "learning", name: "Learning", color: "#f59e0b", icon: "\u{1F4DA}" } ], - autoStartBreak: false, + autoStartBreak: true, tickSoundEnabled: false, // Daily note logging logToDaily: false @@ -319,9 +319,11 @@ var FocusTaskView = class extends import_obsidian2.ItemView { const activeCard = activeSection.createEl("div", { cls: "focus-task-active-card" }); if (this.plugin.isBreakMode) { activeCard.addClass("focus-task-break-card"); - activeCard.createEl("div", { cls: "focus-task-active-label", text: "\u2615 BREAK TIME" }); + const breakLabel = this.plugin.currentTimerSeconds > 0 ? "\u2615 BREAK TIME" : "\u2728 BREAK COMPLETE"; + activeCard.createEl("div", { cls: "focus-task-active-label", text: breakLabel }); } else { - activeCard.createEl("div", { cls: "focus-task-active-label", text: "\u{1F3AF} FOCUSING ON" }); + const workLabel = this.plugin.currentTimerSeconds > 0 ? "\u{1F3AF} FOCUSING ON" : "\u{1F345} POMODORO COMPLETE"; + activeCard.createEl("div", { cls: "focus-task-active-label", text: workLabel }); } activeCard.createEl("div", { cls: "focus-task-active-task-name", text: task.text }); const timerDisplay = activeCard.createEl("div", { cls: "focus-task-timer-display" }); @@ -348,25 +350,62 @@ var FocusTaskView = class extends import_obsidian2.ItemView { this.actualTimeEl = timeInfo.createEl("span", { text: `Actual: ${this.plugin.formatTimeHuman(task.actualMinutes)}` }); } const controls = activeCard.createEl("div", { cls: "focus-task-active-controls" }); - this.pauseBtnEl = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-secondary" }); - this.pauseBtnEl.innerHTML = this.plugin.isTimerRunning ? "\u23F8 Pause" : "\u25B6 Resume"; - this.pauseBtnEl.addEventListener("click", () => this.plugin.toggleTimer()); - if (!this.plugin.isBreakMode) { - const completeBtn = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-success" }); - completeBtn.innerHTML = "\u2713 Complete"; - completeBtn.addEventListener("click", () => this.plugin.completeTask(task.id)); - } - const stopBtn = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-danger" }); - stopBtn.innerHTML = "\u2715 Stop"; - stopBtn.addEventListener("click", () => this.plugin.stopTimer()); if (this.plugin.isBreakMode) { - const skipBreakBtn = controls.createEl("button", { cls: "focus-task-btn" }); - skipBreakBtn.innerHTML = "\u23ED Skip Break"; - skipBreakBtn.addEventListener("click", () => { - this.plugin.isBreakMode = false; - this.plugin.stopTimer(); - this.refresh(); - }); + if (this.plugin.currentTimerSeconds > 0) { + this.pauseBtnEl = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-secondary" }); + this.pauseBtnEl.innerHTML = this.plugin.isTimerRunning ? "\u23F8 Pause" : "\u25B6 Resume"; + this.pauseBtnEl.addEventListener("click", () => this.plugin.toggleTimer()); + const skipBreakBtn = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-primary" }); + skipBreakBtn.innerHTML = "\u23ED Skip Break"; + skipBreakBtn.addEventListener("click", () => { + this.plugin.isBreakMode = false; + this.plugin.startPomodoro(task.id); + }); + const stopBtn = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-danger" }); + stopBtn.innerHTML = "\u2715 Stop"; + stopBtn.addEventListener("click", () => { + this.plugin.isBreakMode = false; + this.plugin.stopTimer(); + }); + } else { + const resumeWorkBtn = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-success" }); + resumeWorkBtn.innerHTML = "\u25B6 Resume Work"; + resumeWorkBtn.addEventListener("click", () => { + this.plugin.isBreakMode = false; + this.plugin.startPomodoro(task.id); + }); + const stopBtn = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-danger" }); + stopBtn.innerHTML = "\u2715 Stop"; + stopBtn.addEventListener("click", () => { + this.plugin.isBreakMode = false; + this.plugin.stopTimer(); + }); + } + } else { + if (this.plugin.currentTimerSeconds > 0) { + this.pauseBtnEl = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-secondary" }); + this.pauseBtnEl.innerHTML = this.plugin.isTimerRunning ? "\u23F8 Pause" : "\u25B6 Resume"; + this.pauseBtnEl.addEventListener("click", () => this.plugin.toggleTimer()); + const completeBtn = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-success" }); + completeBtn.innerHTML = "\u2713 Complete"; + completeBtn.addEventListener("click", () => this.plugin.completeTask(task.id)); + const stopBtn = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-danger" }); + stopBtn.innerHTML = "\u2715 Stop"; + stopBtn.addEventListener("click", () => this.plugin.stopTimer()); + } else { + const startBreakBtn = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-secondary" }); + startBreakBtn.innerHTML = "\u2615 Start Break"; + startBreakBtn.addEventListener("click", () => this.plugin.startBreak()); + const continueBtn = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-primary" }); + continueBtn.innerHTML = "\u25B6 Continue Working"; + continueBtn.addEventListener("click", () => this.plugin.startPomodoro(task.id)); + const completeBtn = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-success" }); + completeBtn.innerHTML = "\u2713 Complete"; + completeBtn.addEventListener("click", () => this.plugin.completeTask(task.id)); + const stopBtn = controls.createEl("button", { cls: "focus-task-btn focus-task-btn-danger" }); + stopBtn.innerHTML = "\u2715 Stop"; + stopBtn.addEventListener("click", () => this.plugin.stopTimer()); + } } } } else { @@ -499,6 +538,7 @@ var FocusTaskPlugin = class extends import_obsidian3.Plugin { this.pomodoroCount = 0; // Focus time tracking (in seconds for accuracy) this.focusSecondsToday = 0; + this.secondsWorkedOnCurrentTask = 0; // Status bar element this.statusBarEl = null; } @@ -671,11 +711,13 @@ var FocusTaskPlugin = class extends import_obsidian3.Plugin { this.isBreakMode = false; this.currentTimerSeconds = 0; this.isTimerRunning = true; + this.secondsWorkedOnCurrentTask = task.actualMinutes * 60; this.refreshView(); this.updateStatusBar(); this.timerInterval = window.setInterval(() => { this.currentTimerSeconds++; - task.actualMinutes = Math.floor(this.currentTimerSeconds / 60); + this.secondsWorkedOnCurrentTask++; + task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); this.focusSecondsToday++; this.updateStatusBar(); this.updateTimerDisplay(); @@ -698,14 +740,14 @@ var FocusTaskPlugin = class extends import_obsidian3.Plugin { this.isBreakMode = false; this.currentTimerSeconds = this.settings.pomodoroWorkMinutes * 60; this.isTimerRunning = true; + this.secondsWorkedOnCurrentTask = task.actualMinutes * 60; this.refreshView(); this.updateStatusBar(); - let secondsWorked = 0; this.timerInterval = window.setInterval(() => { this.currentTimerSeconds--; if (!this.isBreakMode) { - secondsWorked++; - task.actualMinutes = Math.floor(secondsWorked / 60); + this.secondsWorkedOnCurrentTask++; + task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); this.focusSecondsToday++; } this.updateStatusBar(); @@ -716,6 +758,14 @@ var FocusTaskPlugin = class extends import_obsidian3.Plugin { }, 1e3); } handlePomodoroEnd() { + if (this.timerInterval) { + window.clearInterval(this.timerInterval); + this.timerInterval = null; + } + this.currentTimerSeconds = 0; + this.isTimerRunning = false; + this.updateStatusBar(); + this.updateTimerDisplay(); if (!this.isBreakMode) { this.pomodoroCount++; this.data.pomodorosCompleted++; @@ -726,20 +776,20 @@ var FocusTaskPlugin = class extends import_obsidian3.Plugin { if (this.settings.autoStartBreak) { this.startBreak(); } else { - this.stopTimer(); + this.refreshView(); } } else { if (this.settings.enableSounds) { this.playAlertSound(); } new import_obsidian3.Notice("\u26A1 Break over! Ready to focus?"); - this.isBreakMode = false; - this.stopTimer(); + this.refreshView(); } this.saveAllData(); } startBreak() { this.isBreakMode = true; + this.isTimerRunning = true; const isLongBreak = this.pomodoroCount % this.settings.longBreakInterval === 0; this.currentTimerSeconds = (isLongBreak ? this.settings.longBreakMinutes : this.settings.pomodoroBreakMinutes) * 60; new import_obsidian3.Notice(isLongBreak ? "\u2615 Long break time!" : "\u2615 Short break time!"); @@ -767,7 +817,8 @@ var FocusTaskPlugin = class extends import_obsidian3.Plugin { this.timerInterval = window.setInterval(() => { this.currentTimerSeconds--; if (task && !this.isBreakMode) { - task.actualMinutes = Math.floor((this.settings.pomodoroWorkMinutes * 60 - this.currentTimerSeconds) / 60); + this.secondsWorkedOnCurrentTask++; + task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); this.focusSecondsToday++; } this.updateStatusBar(); @@ -795,6 +846,7 @@ var FocusTaskPlugin = class extends import_obsidian3.Plugin { } this.isTimerRunning = false; this.activeTaskId = null; + this.secondsWorkedOnCurrentTask = 0; this.updateStatusBar(); this.saveAllData(); this.refreshView(); diff --git a/src/main.ts b/src/main.ts index 7a41eaa..74381d6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -36,9 +36,10 @@ export default class FocusTaskPlugin extends Plugin { isBreakMode: boolean = false; activeTaskId: string | null = null; pomodoroCount: number = 0; - + // Focus time tracking (in seconds for accuracy) private focusSecondsToday: number = 0; + private secondsWorkedOnCurrentTask: number = 0; // Status bar element statusBarEl: HTMLElement | null = null; @@ -263,6 +264,7 @@ export default class FocusTaskPlugin extends Plugin { this.isBreakMode = false; this.currentTimerSeconds = 0; this.isTimerRunning = true; + this.secondsWorkedOnCurrentTask = task.actualMinutes * 60; // Full refresh to show the active task card this.refreshView(); @@ -271,7 +273,8 @@ export default class FocusTaskPlugin extends Plugin { // Start interval (count up mode - stopwatch) this.timerInterval = window.setInterval(() => { this.currentTimerSeconds++; - task.actualMinutes = Math.floor(this.currentTimerSeconds / 60); + this.secondsWorkedOnCurrentTask++; + task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); // Track focus time this.focusSecondsToday++; @@ -303,23 +306,23 @@ export default class FocusTaskPlugin extends Plugin { this.currentTimerSeconds = this.settings.pomodoroWorkMinutes * 60; this.isTimerRunning = true; + // Initialize from existing actual time to preserve progress across breaks + this.secondsWorkedOnCurrentTask = task.actualMinutes * 60; + // Full refresh to show the active task card this.refreshView(); this.updateStatusBar(); - // Track seconds worked for accurate focus time - let secondsWorked = 0; - this.timerInterval = window.setInterval(() => { this.currentTimerSeconds--; - + if (!this.isBreakMode) { - secondsWorked++; - task.actualMinutes = Math.floor(secondsWorked / 60); + this.secondsWorkedOnCurrentTask++; + task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); // Increment focus time by 1 second this.focusSecondsToday++; } - + // Light update - only timer display, no full refresh this.updateStatusBar(); this.updateTimerDisplay(); @@ -331,45 +334,61 @@ export default class FocusTaskPlugin extends Plugin { } handlePomodoroEnd() { + // Stop the timer interval to prevent going into negative + if (this.timerInterval) { + window.clearInterval(this.timerInterval); + this.timerInterval = null; + } + + // Set timer to 0 to ensure it doesn't show negative + this.currentTimerSeconds = 0; + this.isTimerRunning = false; + + // Update displays immediately + this.updateStatusBar(); + this.updateTimerDisplay(); + if (!this.isBreakMode) { // Work session ended this.pomodoroCount++; this.data.pomodorosCompleted++; - + if (this.settings.enableSounds) { this.playAlertSound(); } - + new Notice('🍅 Pomodoro complete! Time for a break.'); - + if (this.settings.autoStartBreak) { this.startBreak(); } else { - this.stopTimer(); + this.refreshView(); } } else { - // Break ended + // Break ended - keep timer at 0 until user resumes if (this.settings.enableSounds) { this.playAlertSound(); } new Notice('⚡ Break over! Ready to focus?'); - this.isBreakMode = false; - this.stopTimer(); + + // Keep the break card visible with timer at 0:00 + this.refreshView(); } - + this.saveAllData(); } startBreak() { this.isBreakMode = true; + this.isTimerRunning = true; const isLongBreak = this.pomodoroCount % this.settings.longBreakInterval === 0; this.currentTimerSeconds = (isLongBreak ? this.settings.longBreakMinutes : this.settings.pomodoroBreakMinutes) * 60; - + new Notice(isLongBreak ? '☕ Long break time!' : '☕ Short break time!'); - + // Full refresh to show break state this.refreshView(); - + if (!this.timerInterval) { this.timerInterval = window.setInterval(() => { this.currentTimerSeconds--; @@ -382,7 +401,7 @@ export default class FocusTaskPlugin extends Plugin { } }, 1000); } - + this.updateStatusBar(); } @@ -396,11 +415,12 @@ export default class FocusTaskPlugin extends Plugin { // Resume this.isTimerRunning = true; const task = this.data.tasks.find(t => t.id === this.activeTaskId); - + this.timerInterval = window.setInterval(() => { this.currentTimerSeconds--; if (task && !this.isBreakMode) { - task.actualMinutes = Math.floor((this.settings.pomodoroWorkMinutes * 60 - this.currentTimerSeconds) / 60); + this.secondsWorkedOnCurrentTask++; + task.actualMinutes = Math.floor(this.secondsWorkedOnCurrentTask / 60); // Track focus time this.focusSecondsToday++; } @@ -415,7 +435,7 @@ export default class FocusTaskPlugin extends Plugin { } else { new Notice('No active task. Select a task first.'); } - + // Full refresh to update pause/resume button state this.updateStatusBar(); this.refreshView(); @@ -426,16 +446,17 @@ export default class FocusTaskPlugin extends Plugin { window.clearInterval(this.timerInterval); this.timerInterval = null; } - + if (this.activeTaskId) { const task = this.data.tasks.find(t => t.id === this.activeTaskId); if (task) { task.isActive = false; } } - + this.isTimerRunning = false; this.activeTaskId = null; + this.secondsWorkedOnCurrentTask = 0; this.updateStatusBar(); this.saveAllData(); this.refreshView(); diff --git a/src/types.ts b/src/types.ts index 06a6903..771066b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -58,7 +58,7 @@ export const DEFAULT_SETTINGS: FocusTaskSettings = { { id: 'personal', name: 'Personal', color: '#22c55e', icon: '🏠' }, { id: 'learning', name: 'Learning', color: '#f59e0b', icon: '📚' }, ], - autoStartBreak: false, + autoStartBreak: true, tickSoundEnabled: false, // Daily note logging logToDaily: false, diff --git a/src/view.ts b/src/view.ts index 29ef077..6308357 100644 --- a/src/view.ts +++ b/src/view.ts @@ -145,9 +145,11 @@ export class FocusTaskView extends ItemView { if (this.plugin.isBreakMode) { activeCard.addClass('focus-task-break-card'); - activeCard.createEl('div', { cls: 'focus-task-active-label', text: '☕ BREAK TIME' }); + const breakLabel = this.plugin.currentTimerSeconds > 0 ? '☕ BREAK TIME' : '✨ BREAK COMPLETE'; + activeCard.createEl('div', { cls: 'focus-task-active-label', text: breakLabel }); } else { - activeCard.createEl('div', { cls: 'focus-task-active-label', text: '🎯 FOCUSING ON' }); + const workLabel = this.plugin.currentTimerSeconds > 0 ? '🎯 FOCUSING ON' : '🍅 POMODORO COMPLETE'; + activeCard.createEl('div', { cls: 'focus-task-active-label', text: workLabel }); } activeCard.createEl('div', { cls: 'focus-task-active-task-name', text: task.text }); @@ -186,29 +188,77 @@ export class FocusTaskView extends ItemView { // Controls const controls = activeCard.createEl('div', { cls: 'focus-task-active-controls' }); - - this.pauseBtnEl = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-secondary' }); - this.pauseBtnEl.innerHTML = this.plugin.isTimerRunning ? '⏸ Pause' : '▶ Resume'; - this.pauseBtnEl.addEventListener('click', () => this.plugin.toggleTimer()); - - if (!this.plugin.isBreakMode) { - const completeBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-success' }); - completeBtn.innerHTML = '✓ Complete'; - completeBtn.addEventListener('click', () => this.plugin.completeTask(task.id)); - } - - const stopBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-danger' }); - stopBtn.innerHTML = '✕ Stop'; - stopBtn.addEventListener('click', () => this.plugin.stopTimer()); - + if (this.plugin.isBreakMode) { - const skipBreakBtn = controls.createEl('button', { cls: 'focus-task-btn' }); - skipBreakBtn.innerHTML = '⏭ Skip Break'; - skipBreakBtn.addEventListener('click', () => { - this.plugin.isBreakMode = false; - this.plugin.stopTimer(); - this.refresh(); - }); + // Break mode controls + if (this.plugin.currentTimerSeconds > 0) { + // Break is still counting down + this.pauseBtnEl = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-secondary' }); + this.pauseBtnEl.innerHTML = this.plugin.isTimerRunning ? '⏸ Pause' : '▶ Resume'; + this.pauseBtnEl.addEventListener('click', () => this.plugin.toggleTimer()); + + const skipBreakBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-primary' }); + skipBreakBtn.innerHTML = '⏭ Skip Break'; + skipBreakBtn.addEventListener('click', () => { + this.plugin.isBreakMode = false; + this.plugin.startPomodoro(task.id); + }); + + const stopBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-danger' }); + stopBtn.innerHTML = '✕ Stop'; + stopBtn.addEventListener('click', () => { + this.plugin.isBreakMode = false; + this.plugin.stopTimer(); + }); + } else { + // Break timer finished - show resume button + const resumeWorkBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-success' }); + resumeWorkBtn.innerHTML = '▶ Resume Work'; + resumeWorkBtn.addEventListener('click', () => { + this.plugin.isBreakMode = false; + this.plugin.startPomodoro(task.id); + }); + + const stopBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-danger' }); + stopBtn.innerHTML = '✕ Stop'; + stopBtn.addEventListener('click', () => { + this.plugin.isBreakMode = false; + this.plugin.stopTimer(); + }); + } + } else { + // Work mode controls + if (this.plugin.currentTimerSeconds > 0) { + // Work session still running + this.pauseBtnEl = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-secondary' }); + this.pauseBtnEl.innerHTML = this.plugin.isTimerRunning ? '⏸ Pause' : '▶ Resume'; + this.pauseBtnEl.addEventListener('click', () => this.plugin.toggleTimer()); + + const completeBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-success' }); + completeBtn.innerHTML = '✓ Complete'; + completeBtn.addEventListener('click', () => this.plugin.completeTask(task.id)); + + const stopBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-danger' }); + stopBtn.innerHTML = '✕ Stop'; + stopBtn.addEventListener('click', () => this.plugin.stopTimer()); + } else { + // Work session finished - show break and completion options + const startBreakBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-secondary' }); + startBreakBtn.innerHTML = '☕ Start Break'; + startBreakBtn.addEventListener('click', () => this.plugin.startBreak()); + + const continueBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-primary' }); + continueBtn.innerHTML = '▶ Continue Working'; + continueBtn.addEventListener('click', () => this.plugin.startPomodoro(task.id)); + + const completeBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-success' }); + completeBtn.innerHTML = '✓ Complete'; + completeBtn.addEventListener('click', () => this.plugin.completeTask(task.id)); + + const stopBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-danger' }); + stopBtn.innerHTML = '✕ Stop'; + stopBtn.addEventListener('click', () => this.plugin.stopTimer()); + } } } } else {