Removed Floating timer -> Status Bar

This commit is contained in:
2025-11-22 14:17:36 +01:00
parent a652a6ac04
commit 4303bfa2e6
8 changed files with 118 additions and 211 deletions

View File

@@ -36,8 +36,8 @@ export default class FocusTaskPlugin extends Plugin {
activeTaskId: string | null = null;
pomodoroCount: number = 0;
// Floating timer element
floatingTimerEl: HTMLElement | null = null;
// Status Bar element
statusBarEl: HTMLElement | null = null;
async onload() {
await this.loadAllData();
@@ -91,15 +91,13 @@ export default class FocusTaskPlugin extends Plugin {
this.addSettingTab(new FocusTaskSettingTab(this.app, this));
// Create floating timer if enabled
if (this.settings.showFloatingTimer) {
this.createFloatingTimer();
}
this.createStatusBar();
}
onunload() {
this.stopTimer();
this.removeFloatingTimer();
}
this.stopTimer();
}
async loadAllData() {
const loaded = await this.loadData();
@@ -272,7 +270,7 @@ export default class FocusTaskPlugin extends Plugin {
}, 1000);
this.saveAllData();
this.refreshView();
this.updateTimerDisplay();
this.updateFloatingTimer();
}
@@ -304,7 +302,7 @@ export default class FocusTaskPlugin extends Plugin {
}, 1000);
this.updateFloatingTimer();
this.refreshView();
this.updateTimerDisplay();
}
handlePomodoroEnd() {
@@ -357,7 +355,7 @@ export default class FocusTaskPlugin extends Plugin {
}
this.updateFloatingTimer();
this.refreshView();
this.updateTimerDisplay();
}
toggleTimer() {
@@ -388,7 +386,7 @@ export default class FocusTaskPlugin extends Plugin {
}
this.updateFloatingTimer();
this.refreshView();
this.updateTimerDisplay();
}
stopTimer() {
@@ -419,106 +417,38 @@ export default class FocusTaskPlugin extends Plugin {
}
}
// ============ Floating Timer ============
// ============ Status Bar Timer ============
createFloatingTimer() {
if (this.floatingTimerEl) return;
this.floatingTimerEl = document.body.createEl('div', {
cls: 'focus-task-floating-timer',
});
this.floatingTimerEl.innerHTML = `
<div class="focus-task-floating-inner">
<div class="focus-task-floating-task">No active task</div>
<div class="focus-task-floating-time">00:00</div>
<div class="focus-task-floating-controls">
<button class="focus-task-float-btn play-pause">▶</button>
<button class="focus-task-float-btn complete">✓</button>
</div>
</div>
`;
// Make draggable
this.makeDraggable(this.floatingTimerEl);
// Add event listeners
const playPauseBtn = this.floatingTimerEl.querySelector('.play-pause');
const completeBtn = this.floatingTimerEl.querySelector('.complete');
playPauseBtn?.addEventListener('click', () => this.toggleTimer());
completeBtn?.addEventListener('click', () => this.completeActiveTask());
createStatusBar() {
this.statusBarEl = this.addStatusBarItem();
this.statusBarEl.addClass('focus-task-status-bar');
this.updateStatusBar();
// Click to open panel
this.statusBarEl.addEventListener('click', () => {
this.activateView();
});
}
removeFloatingTimer() {
if (this.floatingTimerEl) {
this.floatingTimerEl.remove();
this.floatingTimerEl = null;
}
}
updateFloatingTimer() {
if (!this.floatingTimerEl) return;
const taskEl = this.floatingTimerEl.querySelector('.focus-task-floating-task');
const timeEl = this.floatingTimerEl.querySelector('.focus-task-floating-time');
const playPauseBtn = this.floatingTimerEl.querySelector('.play-pause');
updateStatusBar() {
if (!this.statusBarEl) return;
if (this.activeTaskId) {
const task = this.data.tasks.find(t => t.id === this.activeTaskId);
if (task && taskEl) {
taskEl.textContent = this.isBreakMode ? '☕ Break Time' : task.text;
}
} else if (taskEl) {
taskEl.textContent = 'No active task';
}
if (timeEl) {
timeEl.textContent = this.formatTime(this.currentTimerSeconds);
timeEl.classList.toggle('focus-task-overtime', this.currentTimerSeconds < 0);
}
if (playPauseBtn) {
playPauseBtn.textContent = this.isTimerRunning ? '⏸' : '▶';
}
// Update color based on state
this.floatingTimerEl.classList.toggle('focus-task-break-mode', this.isBreakMode);
this.floatingTimerEl.classList.toggle('focus-task-active', this.isTimerRunning);
}
makeDraggable(el: HTMLElement) {
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
el.onmousedown = dragMouseDown;
function dragMouseDown(e: MouseEvent) {
if ((e.target as HTMLElement).tagName === 'BUTTON') return;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e: MouseEvent) {
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
el.style.top = (el.offsetTop - pos2) + "px";
el.style.left = (el.offsetLeft - pos1) + "px";
el.style.right = 'auto';
el.style.bottom = 'auto';
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
const taskName = this.isBreakMode ? '☕ Break' : (task?.text.substring(0, 20) || 'Task');
const timeStr = this.formatTime(this.currentTimerSeconds);
const icon = this.isTimerRunning ? '▶' : '⏸';
this.statusBarEl.setText(`${icon} ${timeStr} - ${taskName}${task && task.text.length > 20 ? '...' : ''}`);
this.statusBarEl.addClass('focus-task-status-active');
} else {
this.statusBarEl.setText('⚡ Focus Task');
this.statusBarEl.removeClass('focus-task-status-active');
}
}
// ============ Sounds & Celebrations ============
showCelebration(task: FocusTask) {
@@ -612,6 +542,16 @@ export default class FocusTaskPlugin extends Plugin {
});
}
// Light refresh - only updates timer display without rebuilding DOM
updateTimerDisplay() {
const leaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_FOCUS_TASK);
leaves.forEach(leaf => {
if (leaf.view instanceof FocusTaskView) {
leaf.view.updateTimerDisplay();
}
});
}
getTasksByList(listId: string): FocusTask[] {
return this.data.tasks.filter(t => t.list === listId);
}
@@ -761,21 +701,7 @@ class FocusTaskSettingTab extends PluginSettingTab {
await this.plugin.saveAllData();
}));
new Setting(containerEl)
.setName('Show Floating Timer')
.setDesc('Display a draggable floating timer widget')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.showFloatingTimer)
.onChange(async value => {
this.plugin.settings.showFloatingTimer = value;
if (value) {
this.plugin.createFloatingTimer();
} else {
this.plugin.removeFloatingTimer();
}
await this.plugin.saveAllData();
}));
// Lists Management
containerEl.createEl('h2', { text: '📋 Lists' });

View File

@@ -30,7 +30,7 @@ export interface FocusTaskSettings {
enableCelebrations: boolean;
defaultEstimateMinutes: number;
lists: TaskList[];
showFloatingTimer: boolean;
showFloatingTimer: true;
autoStartBreak: boolean;
tickSoundEnabled: boolean;
}

View File

@@ -12,6 +12,12 @@ import FocusTaskPlugin from './main';
export class FocusTaskView extends ItemView {
plugin: FocusTaskPlugin;
currentFilter: string = 'all';
// References to elements that need frequent updates
private timerTimeEl: HTMLElement | null = null;
private progressBarEl: HTMLElement | null = null;
private actualTimeEl: HTMLElement | null = null;
private pauseBtnEl: HTMLElement | null = null;
constructor(leaf: WorkspaceLeaf, plugin: FocusTaskPlugin) {
super(leaf);
@@ -34,10 +40,47 @@ export class FocusTaskView extends ItemView {
this.refresh();
}
// Light update - only updates timer display without rebuilding DOM
updateTimerDisplay() {
if (!this.timerTimeEl) return;
// Update timer text
this.timerTimeEl.textContent = this.plugin.formatTime(this.plugin.currentTimerSeconds);
// Update progress bar
if (this.progressBarEl) {
let progressPercent = 0;
if (this.plugin.isBreakMode) {
const breakDuration = this.plugin.pomodoroCount % this.plugin.settings.longBreakInterval === 0
? this.plugin.settings.longBreakMinutes * 60
: this.plugin.settings.pomodoroBreakMinutes * 60;
progressPercent = ((breakDuration - this.plugin.currentTimerSeconds) / breakDuration) * 100;
} else {
const workDuration = this.plugin.settings.pomodoroWorkMinutes * 60;
progressPercent = ((workDuration - this.plugin.currentTimerSeconds) / workDuration) * 100;
}
this.progressBarEl.style.width = `${Math.min(Math.max(progressPercent, 0), 100)}%`;
}
// Update actual time display
if (this.actualTimeEl && this.plugin.activeTaskId) {
const task = this.plugin.data.tasks.find(t => t.id === this.plugin.activeTaskId);
if (task) {
this.actualTimeEl.textContent = `Actual: ${this.plugin.formatTimeHuman(task.actualMinutes)}`;
}
}
}
refresh() {
const container = this.containerEl.children[1];
container.empty();
container.addClass('focus-task-container');
// Reset element references
this.timerTimeEl = null;
this.progressBarEl = null;
this.actualTimeEl = null;
this.pauseBtnEl = null;
// Header
this.renderHeader(container);
@@ -109,16 +152,16 @@ export class FocusTaskView extends ItemView {
activeCard.createEl('div', { cls: 'focus-task-active-task-name', text: task.text });
// Timer display
// Timer display - store reference for updates
const timerDisplay = activeCard.createEl('div', { cls: 'focus-task-timer-display' });
timerDisplay.createEl('span', {
this.timerTimeEl = timerDisplay.createEl('span', {
cls: 'focus-task-timer-time',
text: this.plugin.formatTime(this.plugin.currentTimerSeconds)
});
// Progress bar
// Progress bar - store reference for updates
const progressWrap = activeCard.createEl('div', { cls: 'focus-task-progress-wrap' });
const progress = progressWrap.createEl('div', { cls: 'focus-task-progress-bar' });
this.progressBarEl = progressWrap.createEl('div', { cls: 'focus-task-progress-bar' });
let progressPercent = 0;
if (this.plugin.isBreakMode) {
@@ -131,22 +174,22 @@ export class FocusTaskView extends ItemView {
progressPercent = ((workDuration - this.plugin.currentTimerSeconds) / workDuration) * 100;
}
progress.style.width = `${Math.min(Math.max(progressPercent, 0), 100)}%`;
if (progressPercent >= 100) progress.addClass('focus-task-overtime');
this.progressBarEl.style.width = `${Math.min(Math.max(progressPercent, 0), 100)}%`;
if (progressPercent >= 100) this.progressBarEl.addClass('focus-task-overtime');
// Time info
// Time info - store reference for actual time updates
if (!this.plugin.isBreakMode) {
const timeInfo = activeCard.createEl('div', { cls: 'focus-task-time-info' });
timeInfo.createEl('span', { text: `Est: ${this.plugin.formatTimeHuman(task.estimatedMinutes)}` });
timeInfo.createEl('span', { text: `Actual: ${this.plugin.formatTimeHuman(task.actualMinutes)}` });
this.actualTimeEl = timeInfo.createEl('span', { text: `Actual: ${this.plugin.formatTimeHuman(task.actualMinutes)}` });
}
// Controls
const controls = activeCard.createEl('div', { cls: 'focus-task-active-controls' });
const pauseBtn = controls.createEl('button', { cls: 'focus-task-btn focus-task-btn-secondary' });
pauseBtn.innerHTML = this.plugin.isTimerRunning ? '⏸ Pause' : '▶ Resume';
pauseBtn.addEventListener('click', () => this.plugin.toggleTimer());
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' });
@@ -316,4 +359,4 @@ export class FocusTaskView extends ItemView {
this.plugin.deleteTask(task.id);
});
}
}
}