mirror of https://github.com/espruino/BangleApps
218 lines
6.5 KiB
JavaScript
218 lines
6.5 KiB
JavaScript
g.clear();
|
|
|
|
Bangle.POMOPLUS_ACTIVE = true; //Prevent the boot code from running. To avoid having to reload on every interaction, we'll control the vibrations from here when the user is in the app.
|
|
|
|
const storage = require("Storage");
|
|
const common = require("pomoplus-com.js");
|
|
const wu = require("widget_utils");
|
|
|
|
//Expire the state if necessary
|
|
if (
|
|
common.settings.pausedTimerExpireTime != 0 &&
|
|
!common.state.running &&
|
|
(new Date()).getTime() - common.state.pausedTime > common.settings.pausedTimerExpireTime
|
|
) {
|
|
common.state = common.STATE_DEFAULT;
|
|
}
|
|
|
|
const W = g.getWidth();
|
|
const H = g.getHeight();
|
|
const SCALING = W/176; // The UI was tweaked to look good on a Bangle.js 2 (176x176 px). SCALING automatically adapts so elements have the same proportions relative to the screen size on devices with other resolutions.
|
|
const BUTTON_HEIGHT = 56 * SCALING;
|
|
const BUTTON_TOP = H - BUTTON_HEIGHT;
|
|
|
|
function drawButtons() {
|
|
//Draw the backdrop
|
|
const ICONS_SIZE = 24;
|
|
const ICONS_ANCHOR_Y = BUTTON_TOP + BUTTON_HEIGHT / 2 - ICONS_SIZE / 2;
|
|
g.setColor(0, 0, 1)
|
|
.fillRect({x:0, y:BUTTON_TOP, x2:W-1, y2:H-1,r:15*SCALING})
|
|
.setColor(1, 1, 1);
|
|
|
|
if (!common.state.wasRunning) { //If the timer was never started, only show a play button
|
|
g.drawImage(common.BUTTON_ICONS.play, W / 2 - ICONS_SIZE / 2, ICONS_ANCHOR_Y);
|
|
} else {
|
|
g.setColor(g.theme.bg)
|
|
.fillRect(W / 2 - 2, BUTTON_TOP, W / 2 + 2, H)
|
|
.setColor(1,1,1);
|
|
if (common.state.running) {
|
|
g.drawImage(common.BUTTON_ICONS.pause, W / 4 - ICONS_SIZE / 2, ICONS_ANCHOR_Y)
|
|
.drawImage(common.BUTTON_ICONS.skip, W * 3 / 4 - ICONS_SIZE / 2, ICONS_ANCHOR_Y);
|
|
} else {
|
|
g.drawImage(common.BUTTON_ICONS.reset, W / 4 - ICONS_SIZE / 2, ICONS_ANCHOR_Y)
|
|
.drawImage(common.BUTTON_ICONS.play, W * 3 / 4 - ICONS_SIZE / 2, ICONS_ANCHOR_Y);
|
|
}
|
|
}
|
|
}
|
|
|
|
function drawTimerAndMessage() {
|
|
const ANCHOR_X = W / 2;
|
|
const ANCHOR_Y = H * 3 / 8;
|
|
const TIME_SIZE = 48 * SCALING;
|
|
const LABEL_SIZE = 18 * SCALING;
|
|
g.reset()
|
|
.setFontAlign(0, 0)
|
|
.setFont("Vector", TIME_SIZE)
|
|
.clearRect(0, ANCHOR_Y - TIME_SIZE / 2, W-1, ANCHOR_Y + TIME_SIZE / 2 + 1.2 * LABEL_SIZE)
|
|
|
|
//Draw the timer
|
|
.drawString((() => {
|
|
let timeLeft = common.getTimeLeft();
|
|
let hours = timeLeft / 3600000;
|
|
let minutes = (timeLeft % 3600000) / 60000;
|
|
let seconds = (timeLeft % 60000) / 1000;
|
|
|
|
function pad(number) {
|
|
return ('00' + parseInt(number)).slice(-2);
|
|
}
|
|
|
|
if (hours >= 1) return `${parseInt(hours)}:${pad(minutes)}:${pad(seconds)}`;
|
|
else return `${parseInt(minutes)}:${pad(seconds)}`;
|
|
})(), ANCHOR_X, ANCHOR_Y)
|
|
|
|
//Draw the phase label
|
|
.setFont("Vector", LABEL_SIZE)
|
|
.drawString(((currentPhase, numShortBreaks) => {
|
|
if (!common.state.wasRunning) return "Not started";
|
|
else if (currentPhase == common.PHASE_WORKING) return `Work ${numShortBreaks + 1}/${common.settings.numShortBreaks + 1}`
|
|
else if (currentPhase == common.PHASE_SHORT_BREAK) return `Short break ${numShortBreaks + 1}/${common.settings.numShortBreaks}`;
|
|
else return "Long break!";
|
|
})(common.state.phase, common.state.numShortBreaks),
|
|
ANCHOR_X, ANCHOR_Y + 2*LABEL_SIZE);
|
|
|
|
//Update phase with vibation if needed
|
|
if (common.getTimeLeft() <= 0) {
|
|
common.nextPhase(true);
|
|
}
|
|
}
|
|
|
|
if (!Bangle.isLocked()) drawButtons();
|
|
|
|
let hideButtons = ()=>{
|
|
g.clearRect(0,BUTTON_TOP,W-1,H-1);
|
|
}
|
|
|
|
let graphicState = 0; // 0 - all is visible, 1 - widgets are hidden, 2 - widgets and buttons are hidden.
|
|
let onButtonSwitchGraphics = (n)=>{
|
|
if (process.env.HWVERSION == 2) n=2; // Translate Bangle.js 2 button to Bangle.js 1 middle button.
|
|
if (n == 2) {
|
|
if (graphicState == 0) {
|
|
wu.hide();
|
|
}
|
|
if (graphicState == 1) {
|
|
hideButtons();
|
|
}
|
|
if (graphicState == 2) {
|
|
wu.show();
|
|
drawButtons();
|
|
}
|
|
graphicState = (graphicState+1) % 3;
|
|
}
|
|
}
|
|
|
|
let onTouchSoftwareButtons = (button, xy) => {
|
|
//If we support full touch and we're not touching the keys, ignore.
|
|
//If we don't support full touch, we can't tell so just assume we are.
|
|
let isOutsideButtonArea = xy !== undefined && xy.y <= g.getHeight() - BUTTON_HEIGHT;
|
|
if (isOutsideButtonArea || graphicState == 2) return;
|
|
|
|
if (!common.state.wasRunning) {
|
|
//If we were never running, there is only one button: the start button
|
|
let now = (new Date()).getTime();
|
|
common.state = {
|
|
wasRunning: true,
|
|
running: true,
|
|
startTime: now,
|
|
pausedTime: now,
|
|
elapsedTime: 0,
|
|
phase: common.PHASE_WORKING,
|
|
numShortBreaks: 0
|
|
};
|
|
setupTimerInterval();
|
|
drawButtons();
|
|
if (common.settings.showClock) Bangle.showClock();
|
|
|
|
} else if (common.state.running) {
|
|
//If we are running, there are two buttons: pause and skip
|
|
if (button == 1) {
|
|
//Record the exact moment that we paused
|
|
let now = (new Date()).getTime();
|
|
common.state.pausedTime = now;
|
|
|
|
//Stop the timer
|
|
common.state.running = false;
|
|
clearInterval(timerInterval);
|
|
timerInterval = undefined;
|
|
drawTimerAndMessage();
|
|
drawButtons();
|
|
|
|
} else {
|
|
common.nextPhase(false);
|
|
}
|
|
|
|
} else {
|
|
//If we are stopped, there are two buttons: Reset and continue
|
|
if (button == 1) {
|
|
//Reset the timer
|
|
common.state = common.STATE_DEFAULT;
|
|
drawTimerAndMessage();
|
|
drawButtons();
|
|
|
|
} else {
|
|
//Start the timer and record old elapsed time and when we started
|
|
let now = (new Date()).getTime();
|
|
common.state.elapsedTime += common.state.pausedTime - common.state.startTime;
|
|
common.state.startTime = now;
|
|
common.state.running = true;
|
|
drawTimerAndMessage();
|
|
setupTimerInterval();
|
|
drawButtons();
|
|
if (common.settings.showClock) Bangle.showClock();
|
|
}
|
|
}
|
|
};
|
|
|
|
Bangle.setUI({
|
|
mode: "custom",
|
|
touch: onTouchSoftwareButtons,
|
|
btn: onButtonSwitchGraphics
|
|
})
|
|
|
|
let timerInterval;
|
|
|
|
function setupTimerInterval() {
|
|
if (timerInterval !== undefined) {
|
|
clearInterval(timerInterval);
|
|
}
|
|
setTimeout(() => {
|
|
timerInterval = setInterval(drawTimerAndMessage, 1000);
|
|
drawTimerAndMessage();
|
|
}, common.timeLeft % 1000);
|
|
}
|
|
|
|
drawTimerAndMessage();
|
|
if (common.state.running) {
|
|
setupTimerInterval();
|
|
}
|
|
|
|
Bangle.on('lock', (on, reason) => {
|
|
if (graphicState==2) return;
|
|
if (on) {
|
|
hideButtons();
|
|
wu.hide();
|
|
}
|
|
if (!on) {
|
|
drawButtons();
|
|
if (graphicState==0) wu.show();
|
|
}
|
|
});
|
|
|
|
//Save our state when the app is closed
|
|
E.on('kill', () => {
|
|
storage.writeJSON(common.STATE_PATH, common.state);
|
|
});
|
|
|
|
Bangle.loadWidgets();
|
|
Bangle.drawWidgets();
|
|
if (Bangle.isLocked()) wu.hide();
|