feat(extension): adicionar lembrete inteligente para iniciar tarefa ao codar sem task ativa

This commit is contained in:
Gabriel Menezes 2026-11-05 15:11:53 -04:00
parent c613c71f1e
commit e7703f34e7
4 changed files with 106 additions and 9 deletions

View file

@ -8,6 +8,7 @@ Extensão oficial do **BeeTask** para o Visual Studio Code. Gerencie suas demand
- **⏱️ Cronômetro em Tempo Real:** Acompanhe o tempo trabalhado na tarefa ativa direto na Barra de Status (rodapé do VS Code). - **⏱️ Cronômetro em Tempo Real:** Acompanhe o tempo trabalhado na tarefa ativa direto na Barra de Status (rodapé do VS Code).
- **🛑 Pausa Automática por Inatividade (10min):** Se você se ausentar do VS Code por mais de 10 minutos com uma tarefa rodando, a extensão pausa o cronômetro automaticamente e pergunta se você ainda está trabalhando nela ao retornar. - **🛑 Pausa Automática por Inatividade (10min):** Se você se ausentar do VS Code por mais de 10 minutos com uma tarefa rodando, a extensão pausa o cronômetro automaticamente e pergunta se você ainda está trabalhando nela ao retornar.
- **💡 Lembrete de Início de Tarefa:** Se você começar a editar código sem nenhuma tarefa ativa, a extensão lembra de forma sutil e pergunta qual tarefa você vai trabalhar.
- **📋 Painel de Tarefas na Barra Lateral:** Visualize rapidamente suas tarefas pendentes, em execução e concluídas na aba BeeTask. - **📋 Painel de Tarefas na Barra Lateral:** Visualize rapidamente suas tarefas pendentes, em execução e concluídas na aba BeeTask.
- **▶️ Play / ⏸️ Pause com 1 Clique:** Inicie e pause o cronômetro das suas tarefas direto do VS Code. - **▶️ Play / ⏸️ Pause com 1 Clique:** Inicie e pause o cronômetro das suas tarefas direto do VS Code.
- **➕ Criação Rápida de Tarefas:** Crie novas tarefas associadas a projetos e categorias sem sair do editor. - **➕ Criação Rápida de Tarefas:** Crie novas tarefas associadas a projetos e categorias sem sair do editor.
@ -81,3 +82,5 @@ Acesse `Configurações` (`Ctrl+,`) e busque por `BeeTask`:
- `beetask.refreshIntervalSeconds`: Intervalo de sincronização automática em segundos (Padrão: `30`). - `beetask.refreshIntervalSeconds`: Intervalo de sincronização automática em segundos (Padrão: `30`).
- `beetask.enableIdleDetection`: Ativar pausa automática da tarefa por inatividade (Padrão: `true`). - `beetask.enableIdleDetection`: Ativar pausa automática da tarefa por inatividade (Padrão: `true`).
- `beetask.idleTimeoutMinutes`: Tempo limite de inatividade em minutos (Padrão: `10`). - `beetask.idleTimeoutMinutes`: Tempo limite de inatividade em minutos (Padrão: `10`).
- `beetask.enableNoActiveTaskPrompt`: Lembrar de iniciar tarefa ao começar a codar (Padrão: `true`).
- `beetask.noActiveTaskCooldownMinutes`: Intervalo mínimo entre lembretes em minutos (Padrão: `15`).

View file

@ -2,7 +2,7 @@
"name": "beetask-vscode", "name": "beetask-vscode",
"displayName": "BeeTask", "displayName": "BeeTask",
"description": "Gerenciamento e rastreamento de tarefas com cronômetro integrado ao VS Code", "description": "Gerenciamento e rastreamento de tarefas com cronômetro integrado ao VS Code",
"version": "1.1.0", "version": "1.2.0",
"publisher": "beetech", "publisher": "beetech",
"icon": "media/icon.png", "icon": "media/icon.png",
"repository": { "repository": {
@ -163,6 +163,16 @@
"type": "number", "type": "number",
"default": 10, "default": 10,
"description": "Tempo limite de inatividade em minutos para pausar a tarefa ativa (padrão: 10 minutos)" "description": "Tempo limite de inatividade em minutos para pausar a tarefa ativa (padrão: 10 minutos)"
},
"beetask.enableNoActiveTaskPrompt": {
"type": "boolean",
"default": true,
"description": "Lembrar de iniciar uma tarefa ao começar a codar sem nenhuma tarefa ativa"
},
"beetask.noActiveTaskCooldownMinutes": {
"type": "number",
"default": 15,
"description": "Intervalo mínimo em minutos entre lembretes de início de tarefa (padrão: 15 minutos)"
} }
} }
} }

View file

@ -11,6 +11,11 @@ export class IdleDetector implements vscode.Disposable {
private isPrompting: boolean = false; private isPrompting: boolean = false;
private disposables: vscode.Disposable[] = []; private disposables: vscode.Disposable[] = [];
// Lembrete de codar sem tarefa ativa
private lastNoActivePromptTime: number = 0;
private isPromptingNoActive: boolean = false;
private pendingActivityTimer: NodeJS.Timeout | null = null;
private api: BeeTaskApiClient; private api: BeeTaskApiClient;
private authManager: AuthManager; private authManager: AuthManager;
private statusBar: StatusBarManager; private statusBar: StatusBarManager;
@ -31,46 +36,121 @@ export class IdleDetector implements vscode.Disposable {
this.startPeriodicCheck(); this.startPeriodicCheck();
} }
public recordActivity(): void { public recordActivity(isCodeEdit: boolean = false): void {
this.lastActivityTime = Date.now(); this.lastActivityTime = Date.now();
if (isCodeEdit) {
this.scheduleNoActiveTaskCheck();
}
} }
private registerActivityListeners(): void { private registerActivityListeners(): void {
// 1. Digitação ou alteração de código // 1. Digitação ou alteração de código (edição real de código)
this.disposables.push( this.disposables.push(
vscode.workspace.onDidChangeTextDocument(() => this.recordActivity()) vscode.workspace.onDidChangeTextDocument((e) => {
// Ignora alterações em esquemas que não sejam arquivos reais (ex: output, git, etc)
if (e.document.uri.scheme === 'file') {
this.recordActivity(true);
} else {
this.recordActivity(false);
}
})
); );
// 2. Movimentação de cursor ou seleção de texto // 2. Movimentação de cursor ou seleção de texto
this.disposables.push( this.disposables.push(
vscode.window.onDidChangeTextEditorSelection(() => this.recordActivity()) vscode.window.onDidChangeTextEditorSelection(() => this.recordActivity(false))
); );
// 3. Troca de arquivo / aba ativa // 3. Troca de arquivo / aba ativa
this.disposables.push( this.disposables.push(
vscode.window.onDidChangeActiveTextEditor(() => this.recordActivity()) vscode.window.onDidChangeActiveTextEditor(() => this.recordActivity(false))
); );
// 4. Rolagem da página (scroll) // 4. Rolagem da página (scroll)
this.disposables.push( this.disposables.push(
vscode.window.onDidChangeTextEditorVisibleRanges(() => this.recordActivity()) vscode.window.onDidChangeTextEditorVisibleRanges(() => this.recordActivity(false))
); );
// 5. Salvamento de arquivo // 5. Salvamento de arquivo
this.disposables.push( this.disposables.push(
vscode.workspace.onDidSaveTextDocument(() => this.recordActivity()) vscode.workspace.onDidSaveTextDocument((doc) => {
if (doc.uri.scheme === 'file') {
this.recordActivity(true);
} else {
this.recordActivity(false);
}
})
); );
// 6. Janela do VS Code ganhou foco // 6. Janela do VS Code ganhou foco
this.disposables.push( this.disposables.push(
vscode.window.onDidChangeWindowState((state) => { vscode.window.onDidChangeWindowState((state) => {
if (state.focused) { if (state.focused) {
this.recordActivity(); this.recordActivity(false);
} }
}) })
); );
} }
private scheduleNoActiveTaskCheck(): void {
if (this.pendingActivityTimer) return;
// Aguarda 3 segundos de digitação contínua para exibir o lembrete de forma suave
this.pendingActivityTimer = setTimeout(async () => {
this.pendingActivityTimer = null;
await this.checkNoActiveTask();
}, 3000);
}
private async checkNoActiveTask(): Promise<void> {
const config = vscode.workspace.getConfiguration('beetask');
const enabled = config.get<boolean>('enableNoActiveTaskPrompt', true);
const cooldownMinutes = config.get<number>('noActiveTaskCooldownMinutes', 15);
if (!enabled || this.isPromptingNoActive || this.isPrompting) {
return;
}
const isAuth = await this.authManager.isAuthenticated();
if (!isAuth) {
return;
}
const activeTask = this.statusBar.getActiveTask();
if (activeTask) {
// Já está com uma tarefa rodando, nada a fazer
return;
}
const now = Date.now();
if (now - this.lastNoActivePromptTime < cooldownMinutes * 60000) {
return; // Ainda dentro do período de cooldown
}
this.isPromptingNoActive = true;
this.lastNoActivePromptTime = now;
try {
const choice = await vscode.window.showInformationMessage(
'🐝 BeeTask: Você começou a mexer no código sem nenhuma tarefa ativa. Qual demanda você está trabalhando?',
'Selecionar Tarefa',
'Criar Nova Tarefa',
'Lembrar mais tarde'
);
if (choice === 'Selecionar Tarefa') {
await vscode.commands.executeCommand('beetask.startTask');
} else if (choice === 'Criar Nova Tarefa') {
await vscode.commands.executeCommand('beetask.createTask');
}
} catch (err: any) {
console.error('[BeeTask] Erro ao exibir lembrete de tarefa ativa:', err);
} finally {
this.isPromptingNoActive = false;
}
}
private startPeriodicCheck(): void { private startPeriodicCheck(): void {
// Checa a cada 15 segundos // Checa a cada 15 segundos
this.checkInterval = setInterval(async () => { this.checkInterval = setInterval(async () => {
@ -158,6 +238,10 @@ export class IdleDetector implements vscode.Disposable {
} }
public dispose(): void { public dispose(): void {
if (this.pendingActivityTimer) {
clearTimeout(this.pendingActivityTimer);
this.pendingActivityTimer = null;
}
if (this.checkInterval) { if (this.checkInterval) {
clearInterval(this.checkInterval); clearInterval(this.checkInterval);
this.checkInterval = null; this.checkInterval = null;