brandonsoto/pomodoro-timer

View on GitHub
src/pomodoro.js

Summary

Maintainability
A
0 mins
Test Coverage
const vscode = require('vscode');
const commands = require('./commands');
const MILLISECONDS_IN_SECOND = 1000;
const SECONDS_IN_MINUTE = 60;
const DEFAULT_TIMER_DURATION = 1500000; // 25 minutes in milliseconds
 
TODO found
// TODO: might want to put state data/logic into its own class
var TimerState = {
UNKNOWN: 0,
READY: 1,
RUNNING: 2,
PAUSED: 3,
FINISHED: 4,
DISPOSED: 5
}
exports.TimerState = TimerState;
 
const STARTABLE_STATES = new Set([TimerState.FINISHED, TimerState.READY, TimerState.PAUSED]);
exports.STARTABLE_STATES = STARTABLE_STATES;
 
const STOPPABLE_STATES = new Set([TimerState.RUNNING, TimerState.PAUSED]);
exports.STOPPABLE_STATES = STOPPABLE_STATES;
 
const PAUSEABLE_STATES = new Set([TimerState.RUNNING]);
exports.PAUSEABLE_STATES = PAUSEABLE_STATES;
 
const ALL_STATES = new Set([TimerState.UNKNOWN, TimerState.READY, TimerState.RUNNING, TimerState.PAUSED, TimerState.FINISHED, TimerState.DISPOSED]);
exports.ALL_STATES = ALL_STATES;
 
function stateToString(state) {
switch(state) {
case TimerState.UNKNOWN:
return "unknown";
case TimerState.READY:
return "ready";
case TimerState.RUNNING:
return "running";
case TimerState.PAUSED:
return "paused";
case TimerState.FINISHED:
return "finished";
case TimerState.DISPOSED:
return "disposed";
default:
return "unknown";
}
}
 
function millisecondsToMMSS (milliseconds) {
let totalSeconds = Math.round(milliseconds / MILLISECONDS_IN_SECOND);
let minutes = Math.floor(totalSeconds / SECONDS_IN_MINUTE);
let seconds = Math.floor(totalSeconds - (minutes * SECONDS_IN_MINUTE));
 
if (minutes < 10) {minutes = "0" + minutes; }
if (seconds < 10) {seconds = "0" + seconds; }
 
return minutes + ':' + seconds;
}
 
class PomodoroTimer {
constructor(interval=DEFAULT_TIMER_DURATION) {
this.name = "Pomodoro";
this.interval = interval === DEFAULT_TIMER_DURATION ? vscode.workspace.getConfiguration("pomodoro").get("interval", DEFAULT_TIMER_DURATION) * MILLISECONDS_IN_SECOND * SECONDS_IN_MINUTE : interval;
this.millisecondsRemaining = this.interval;
this.timeout = 0;
this.endDate = new Date();
this.secondInterval = 0;
this.state = TimerState.READY;
this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, Number.MIN_SAFE_INTEGER);
this.statusBarItem.command = commands.START_TIMER_CMD;
this.statusBarItem.show();
this.updateStatusBar();
}
 
updateStatusBar() {
const icon = TimerState.RUNNING === this.state ? "$(primitive-square)" : "$(triangle-right)";
this.statusBarItem.text = icon + " " + millisecondsToMMSS(this.millisecondsRemaining) + " (" + stateToString(this.state) + ")";
}
 
setState(state, statusBarCommand) {
this.state = state;
this.statusBarItem.command = statusBarCommand;
this.updateStatusBar();
}
 
isStartable() { return STARTABLE_STATES.has(this.state); }
 
isPauseable() { return PAUSEABLE_STATES.has(this.state); }
 
isStoppable() { return STOPPABLE_STATES.has(this.state); }
 
// starts/resumes the timer but does not reset it
start() {
if (!this.isStartable()) { return false; }
 
let onTimeout = () => {
this.reset();
vscode.window.showInformationMessage("Pomodoro has expired. Enjoy your break!", "Restart")
.then((value) => {
if ('Restart' === value) {
this.reset();
this.start();
}
});
};
 
let onSecondElapsed = () => {
this.millisecondsRemaining -= MILLISECONDS_IN_SECOND;
this.updateStatusBar();
};
 
this.endDate = new Date(Date.now().valueOf() + this.millisecondsRemaining);
this.timeout = setTimeout(onTimeout, this.millisecondsRemaining);
this.secondInterval = setInterval(onSecondElapsed, MILLISECONDS_IN_SECOND);
this.setState(TimerState.RUNNING, commands.PAUSE_TIMER_CMD);
 
return true;
}
 
// pauses the timer but does not reset it
pause() {
if (!this.isPauseable()) { return false; }
 
clearTimeout(this.timeout);
clearInterval(this.secondInterval);
 
this.setState(TimerState.PAUSED, commands.START_TIMER_CMD);
 
return true;
}
 
// stops the timer completely
stop() {
if (!this.isStoppable()) { return false; }
 
clearTimeout(this.timeout);
clearInterval(this.secondInterval);
 
this.timeout = 0;
this.secondInterval = 0;
this.millisecondsRemaining = 0;
this.setState(TimerState.FINISHED, commands.START_TIMER_CMD);
this.millisecondsRemaining = this.interval;
 
return true;
}
 
// stops and resets the timer but does not start it
reset() {
this.stop();
this.millisecondsRemaining = this.interval;
this.setState(TimerState.READY, commands.START_TIMER_CMD);
return true;
}
 
dispose() {
if (this.statusBarItem) {
this.statusBarItem.hide();
this.statusBarItem.dispose();
this.statusBarItem = null;
}
this.state = TimerState.DISPOSED;
}
};
exports.PomodoroTimer = PomodoroTimer;