2023-09-16 11:35:50 +00:00
g . clear ( ) ;
2022-11-02 19:06:17 +00:00
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" ) ;
//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 ;
}
2024-08-23 22:19:49 +00:00
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 is used to adapt with the resolution of whatever device the app is running on.
const BUTTON _HEIGHT = 56 * SCALING ;
2022-11-02 19:06:17 +00:00
function drawButtons ( ) {
//Draw the backdrop
2024-08-23 22:19:49 +00:00
const BUTTON _TOP = H - BUTTON _HEIGHT ;
const IMG _SIZE = 24 ;
const IMG _ANCHOR _Y = BUTTON _TOP + BUTTON _HEIGHT / 2 - IMG _SIZE / 2 ;
g . setColor ( 0 , 0 , 1 )
. fillRect ( { x : 0 , y : BUTTON _TOP , x2 : W - 1 , y2 : H - 1 , r : 15 } )
2022-11-02 19:06:17 +00:00
. setColor ( 1 , 1 , 1 ) ;
if ( ! common . state . wasRunning ) { //If the timer was never started, only show a play button
2024-08-23 22:19:49 +00:00
g . drawImage ( common . BUTTON _ICONS . play , W / 2 - IMG _SIZE / 2 , IMG _ANCHOR _Y ) ;
2022-11-02 19:06:17 +00:00
} else {
2024-08-23 22:19:49 +00:00
g . setColor ( g . theme . bg )
. fillRect ( W / 2 - 2 , BUTTON _TOP , W / 2 + 2 , H )
. setColor ( 1 , 1 , 1 ) ;
2022-11-02 19:06:17 +00:00
if ( common . state . running ) {
2024-08-23 22:19:49 +00:00
g . drawImage ( common . BUTTON _ICONS . pause , W / 4 - IMG _SIZE / 2 , IMG _ANCHOR _Y )
. drawImage ( common . BUTTON _ICONS . skip , W * 3 / 4 - IMG _SIZE / 2 , IMG _ANCHOR _Y ) ;
2022-11-02 19:06:17 +00:00
} else {
2024-08-23 22:19:49 +00:00
g . drawImage ( common . BUTTON _ICONS . reset , W / 4 - IMG _SIZE / 2 , IMG _ANCHOR _Y )
. drawImage ( common . BUTTON _ICONS . play , W * 3 / 4 - IMG _SIZE / 2 , IMG _ANCHOR _Y ) ;
2022-11-02 19:06:17 +00:00
}
}
}
function drawTimerAndMessage ( ) {
2024-08-23 22:19:49 +00:00
const ANCHOR _X = W / 2 ;
const ANCHOR _Y = H * 3 / 8 ;
const TIME _SIZE = 48 * SCALING ;
const LABEL _SIZE = 18 * SCALING ;
2022-11-02 19:06:17 +00:00
g . reset ( )
. setFontAlign ( 0 , 0 )
2024-08-23 22:19:49 +00:00
. setFont ( "Vector" , TIME _SIZE )
. clearRect ( 0 , ANCHOR _Y - TIME _SIZE / 2 , W - 1 , ANCHOR _Y + TIME _SIZE / 2 + 1.2 * LABEL _SIZE )
2022-11-02 19:06:17 +00:00
//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 ) } ` ;
2024-08-23 22:19:49 +00:00
} ) ( ) , ANCHOR _X , ANCHOR _Y )
2022-11-02 19:06:17 +00:00
//Draw the phase label
2024-08-23 22:19:49 +00:00
. setFont ( "Vector" , LABEL _SIZE )
2022-11-02 19:06:17 +00:00
. 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 ) ,
2024-08-23 22:19:49 +00:00
ANCHOR _X , ANCHOR _Y + 2 * LABEL _SIZE ) ;
2022-11-02 19:06:17 +00:00
//Update phase with vibation if needed
if ( common . getTimeLeft ( ) <= 0 ) {
common . nextPhase ( true ) ;
}
}
drawButtons ( ) ;
Bangle . on ( "touch" , ( 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.
2024-08-23 22:19:49 +00:00
if ( xy !== undefined && xy . y <= g . getHeight ( ) - BUTTON _HEIGHT ) return ;
2022-11-02 19:06:17 +00:00
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 ( ) ;
2023-09-16 11:35:50 +00:00
if ( common . settings . showClock ) Bangle . showClock ( ) ;
2022-11-02 19:06:17 +00:00
} 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 ( ) ;
2023-09-16 11:35:50 +00:00
if ( common . settings . showClock ) Bangle . showClock ( ) ;
2022-11-02 19:06:17 +00:00
}
}
} ) ;
let timerInterval ;
function setupTimerInterval ( ) {
if ( timerInterval !== undefined ) {
clearInterval ( timerInterval ) ;
}
setTimeout ( ( ) => {
timerInterval = setInterval ( drawTimerAndMessage , 1000 ) ;
drawTimerAndMessage ( ) ;
} , common . timeLeft % 1000 ) ;
}
drawTimerAndMessage ( ) ;
if ( common . state . running ) {
setupTimerInterval ( ) ;
}
//Save our state when the app is closed
E . on ( 'kill' , ( ) => {
storage . writeJSON ( common . STATE _PATH , common . state ) ;
} ) ;
Bangle . loadWidgets ( ) ;
2023-09-16 11:35:50 +00:00
Bangle . drawWidgets ( ) ;