1
0
Fork 0

Move changes to smpltmr

master
sir-indy 2022-05-01 18:02:15 +01:00
parent f60d0f22a2
commit 2e8744ca22
13 changed files with 159 additions and 335 deletions

View File

@ -1 +1,2 @@
0.01: Release
0.01: Release
0.02: Rewrite with new interface

View File

@ -1,21 +1,12 @@
# Simple Timer
A simple app to set a timer quickly. Simply tab on top/bottom/left/right
to select the minutes and tab in the middle of the screen to start/stop
the timer. Note that this timer depends on qalarm.
# Overview
If you open the app, you can simply control the timer
by clicking on top, bottom, left or right of the screen.
If you tab at the middle of the screen, the timer is
started / stopped.
![](description.png)
A simple app to set a timer quickly. Drag or tap on the up and down buttons over the hour, minute or second to set the time.
This app uses the `sched` library, which allows the timer to continue to run in the background when this app is closed.
# Creator
[David Peer](https://github.com/peerdavid)
[Sir Indy](https://github.com/sir-indy)
# Thanks to...
Time icon created by <a href="https://www.flaticon.com/free-icons/time" title="time icons">CreativeCons - Flaticon</a>

View File

@ -1,124 +1,173 @@
/*
* SIMPLE TIMER
*
* Creator: David Peer
* Date: 02/2022
*/
const secondsToTime = (s) => new Object({h:Math.floor((s/3600) % 24), m:Math.floor((s/60) % 60), s:Math.floor(s % 60)});
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
function formatTime(s) {
var t = secondsToTime(s);
if (t.h) {
return t.h + ':' + ("0" + t.m).substr(-2) + ':' + ("0" + t.s).substr(-2);
} else {
return t.m + ':' + ("0" + t.s).substr(-2);
}
}
const timerID = "simpletimer";
Bangle.loadWidgets();
Bangle.drawWidgets();
var Layout = require("Layout");
var seconds = 5 * 60; // Default to 5 minutes
var drawTimeout;
var imgArrow = Graphics.createImage(`
x
xxx
xxx
xxxxx
xxxxx
xxx xxx
xxx xxx
xxx xxx
xxx xxx
`);
const alarm = require("sched");
const imgPause = atob("GBiBAP+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B/w==");
const imgPlay = atob("GBiBAIAAAOAAAPgAAP4AAP+AAP/gAP/4AP/+AP//gP//4P//+P///v///v//+P//4P//gP/+AP/4AP/gAP+AAP4AAPgAAOAAAIAAAA==");
const TIMER_IDX = "smpltmr";
const screenWidth = g.getWidth();
const screenHeight = g.getHeight();
const cx = parseInt(screenWidth/2);
const cy = parseInt(screenHeight/2)-12;
var minutes = 5;
var interval; //used for the 1 second interval timer
function isTimerEnabled(){
var alarmObj = alarm.getAlarm(TIMER_IDX);
if(alarmObj===undefined || !alarmObj.on){
return false;
function onDrag(event) {
Bangle.buzz(20, 0.3);
var diff = -Math.round(event.dy/5);
if (event.x < timePickerLayout.hours.w) {
diff *= 3600;
} else if (event.x > timePickerLayout.mins.x && event.x < timePickerLayout.secs.x) {
diff *= 60;
}
return true;
updateTimePicker(diff);
}
function getTimerMin(){
var alarmObj = alarm.getAlarm(TIMER_IDX);
return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
}
function setTimer(minutes){
alarm.setAlarm(TIMER_IDX, {
// msg : "Simple Timer",
timer : minutes*60*1000,
});
alarm.reload();
}
function deleteTimer(){
alarm.setAlarm(TIMER_IDX, undefined);
alarm.reload();
}
setWatch(_=>load(), BTN1);
function draw(){
g.clear(1);
Bangle.drawWidgets();
if (interval) {
clearInterval(interval);
function onTouch(button, xy) {
var touchMidpoint = timePickerLayout.hours.y + timePickerLayout.hours.h/2;
var diff = 0;
if (xy.y > 24 && xy.y < touchMidpoint - 10) {
Bangle.buzz(40, 0.3);
diff = 1;
} else if (xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) {
Bangle.buzz(40, 0.3);
diff = -1;
} else if (xy.y > timePickerLayout.btnStart.y) {
Bangle.buzz(40, 0.6);
runTimer();
return;
}
interval = undefined;
// Write time
g.setFontAlign(0, 0, 0);
g.setFont("Vector", 32).setFontAlign(0,-1);
var started = isTimerEnabled();
var text = minutes + " min.";
if(started){
var min = getTimerMin();
text = min + " min.";
if (xy.x < timePickerLayout.hours.w) {
diff *= 3600;
} else if (xy.x > timePickerLayout.mins.x && xy.x < timePickerLayout.secs.x) {
diff *= 60;
}
updateTimePicker(diff);
}
var rectWidth = parseInt(g.stringWidth(text) / 2);
if(started){
interval = setInterval(draw, 1000);
g.setColor("#ff0000");
function onButton() {
var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID));
g.clearRect(Bangle.appRect);
if (timeToNext != undefined) {
runTimer();
} else {
g.setColor(g.theme.fg);
runTimePicker();
}
g.fillRect(cx-rectWidth-5, cy-5, cx+rectWidth, cy+30);
g.setColor(g.theme.bg);
g.drawString(text, cx, cy);
}
function updateTimePicker(diff) {
seconds = clamp(seconds + (diff || 0), 0, 24 * 3600 - 1);
var set_time = secondsToTime(seconds);
updateLayoutField(timePickerLayout, 'hours', set_time.h);
updateLayoutField(timePickerLayout, 'mins', set_time.m);
updateLayoutField(timePickerLayout, 'secs', set_time.s);
}
Bangle.on('touch', function(btn, e){
var left = parseInt(g.getWidth() * 0.25);
var right = g.getWidth() - left;
var upper = parseInt(g.getHeight() * 0.25);
var lower = g.getHeight() - upper;
function updateLayoutField(layout, field, value) {
layout.clear(layout[field]);
layout[field].label = value;
layout.render(layout[field]);
}
var isLeft = e.x < left;
var isRight = e.x > right;
var isUpper = e.y < upper;
var isLower = e.y > lower;
var isMiddle = !isLeft && !isRight && !isUpper && !isLower;
var started = isTimerEnabled();
function updateTimer() {
var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID));
updateLayoutField(timerLayout, 'timer', formatTime(timeToNext / 1000));
queueDraw(1000);
}
if(isRight && !started){
minutes += 1;
Bangle.buzz(40, 0.3);
} else if(isLeft && !started){
minutes -= 1;
Bangle.buzz(40, 0.3);
} else if(isUpper && !started){
minutes += 5;
Bangle.buzz(40, 0.3);
} else if(isLower && !started){
minutes -= 5;
Bangle.buzz(40, 0.3);
} else if(isMiddle) {
if(!started){
setTimer(minutes);
} else {
deleteTimer();
}
Bangle.buzz(80, 0.6);
}
minutes = Math.max(0, minutes);
function queueDraw(millisecs) {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
updateTimer();
}, millisecs - (Date.now() % millisecs));
}
draw();
function timerStop() {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined;
seconds = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)) / 1000;
require("sched").setAlarm(timerID, undefined);
require("sched").reload();
runTimePicker();
}
function runTimePicker() {
g.clearRect(Bangle.appRect);
Bangle.setUI({
mode : "custom",
touch : function(n,e) {onTouch(n,e);},
drag : function(e) {onDrag(e);},
btn : function(n) {onButton();},
});
timePickerLayout.render();
updateTimePicker();
//timePickerLayout.debug();
}
function runTimer() {
require("sched").setAlarm(timerID, {
vibrate : ".-.-",
hidden: true,
timer : seconds * 1000
});
require("sched").reload();
g.clearRect(Bangle.appRect);
timerLayout.render();
updateTimer();
}
var timePickerLayout = new Layout({
type:"v", c: [
{type:undefined, height:2},
{type:"h", c: [
{type:"v", width:g.getWidth()/3, c: [
{type:"txt", font:"6x8", label:/*LANG*/"Hours", col:g.theme.fg2},
{type:"img", pad:8, src:imgArrow, col:g.theme.fg2},
{type:"txt", font:"20%", label:"00", id:"hours", filly:1, fillx:1},
{type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2}
]},
{type:"v", width:g.getWidth()/3, c: [
{type:"txt", font:"6x8", label:/*LANG*/"Minutes", col:g.theme.fg2},
{type:"img", pad:8, src:imgArrow, col:g.theme.fg2},
{type:"txt", font:"20%", label:"00", id:"mins", filly:1, fillx:1},
{type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2}
]},
{type:"v", width:g.getWidth()/3, c: [
{type:"txt", font:"6x8", label:/*LANG*/"Seconds", col:g.theme.fg2},
{type:"img", pad:8, src:imgArrow, col:g.theme.fg2},
{type:"txt", font:"20%", label:"00", id:"secs", filly:1, fillx:1},
{type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2}
]},
]},
{type:"btn", src:imgPlay, id:"btnStart", fillx:1 }
], filly:1
});
g.reset();
draw();
var timerLayout = new Layout({
type:"v", c: [
{type:"txt", font:"22%", label:"0:00", id:"timer", fillx:1, filly:1 },
{type:"btn", src:imgPause, cb: l=>timerStop(), fillx:1 }
], filly:1
});
onButton();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -2,10 +2,10 @@
"id": "smpltmr",
"name": "Simple Timer",
"shortName": "Simple Timer",
"version": "0.01",
"version": "0.02",
"description": "A very simple app to start a timer.",
"icon": "app.png",
"tags": "tool",
"tags": "tool,alarm,timer",
"dependencies": {"scheduler":"type"},
"supports": ["BANGLEJS2"],
"screenshots": [{"url":"screenshot.png"}, {"url": "screenshot_2.png"}],

View File

@ -1 +0,0 @@
0.01: First release

View File

@ -1,12 +0,0 @@
# Simple Timer
TESTING - DO NOT INSTALL, MAY BE BROKEN
Does one thing well. Set a time in hours, minutes and seconds, and alerts you when time is up. Opening the app while the timer is running (or just leaving the app open) shows how much time is left on the timer. This is the part I felt was missing from the Alarms and Timer app.
Drag or tap on the up and down buttons over the hour, minute or second to set the time.
![](timersimple-scr1.png)
![](timersimple-scr2.png)
Written by: [Sir Indy](https://github.com/sir-indy) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,18 +0,0 @@
{
"id":"timersimple",
"name":"Timer Simple",
"shortName": "Timer Simple",
"version": "0.01",
"description": "Sets a single timer, and tells you how long left.",
"readme": "README.md",
"icon":"icons8-time-span-48.png",
"screenshots": [{"url":"timersimple-scr1.png"},{"url":"timersimple-scr2.png"}],
"tags": "tool,alarm,timer",
"supports": ["BANGLEJS2"],
"dependencies": {"scheduler":"type"},
"allow_emulator": true,
"storage": [
{"name":"timersimple.app.js","url":"timersimple.app.js"},
{"name":"timersimple.img","url":"timersimple.icon.js","evaluate":true}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,185 +0,0 @@
const secondsToTime = (s) => new Object({h:Math.floor((s/3600) % 24), m:Math.floor((s/60) % 60), s:Math.floor(s % 60)});
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
function formatTime(s) {
var t = secondsToTime(s);
if (t.h) {
return t.h + ':' + ("0" + t.m).substr(-2) + ':' + ("0" + t.s).substr(-2);
} else {
return t.m + ':' + ("0" + t.s).substr(-2);
}
}
const timerID = "simpletimer";
Bangle.loadWidgets();
Bangle.drawWidgets();
var Layout = require("Layout");
var seconds = 5 * 60; // Default to 5 minutes
var drawTimeout;
var timerLayout;
var timePickerLayout;
var imgArrow = Graphics.createImage(`
x
xxx
xxx
xxxxx
xxxxx
xxx xxx
xxx xxx
xxx xxx
xxx xxx
`);
const imgPause = atob("GBiBAP+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B//+B/w==");
const imgPlay = atob("GBiBAIAAAOAAAPgAAP4AAP+AAP/gAP/4AP/+AP//gP//4P//+P///v///v//+P//4P//gP/+AP/4AP/gAP+AAP4AAPgAAOAAAIAAAA==");
function onDrag(event) {
Bangle.buzz(20, 0.3);
var diff = -Math.round(event.dy/5);
if (event.x < timePickerLayout.hours.w) {
diff *= 3600;
} else if (event.x > timePickerLayout.mins.x && event.x < timePickerLayout.secs.x) {
diff *= 60;
}
updateTimePicker(diff);
}
function onTouch(button, xy) {
var touchMidpoint = timePickerLayout.hours.y + timePickerLayout.hours.h/2;
var diff = 0;
if (xy.y > 24 && xy.y < touchMidpoint - 10) {
Bangle.buzz(40, 0.3);
diff = 1;
} else if (xy.y > touchMidpoint + 10 && xy.y < timePickerLayout.btnStart.y) {
Bangle.buzz(40, 0.3);
diff = -1;
} else if (xy.y > timePickerLayout.btnStart.y) {
Bangle.buzz(40, 0.6);
runTimer();
return;
}
if (xy.x < timePickerLayout.hours.w) {
diff *= 3600;
} else if (xy.x > timePickerLayout.mins.x && xy.x < timePickerLayout.secs.x) {
diff *= 60;
}
updateTimePicker(diff);
}
function updateTimePicker(diff) {
seconds = clamp(seconds + (diff || 0), 0, 24 * 3600 - 1);
var set_time = secondsToTime(seconds);
updateLayoutField(timePickerLayout, 'hours', set_time.h);
updateLayoutField(timePickerLayout, 'mins', set_time.m);
updateLayoutField(timePickerLayout, 'secs', set_time.s);
}
function updateLayoutField(layout, field, value) {
layout.clear(layout[field]);
layout[field].label = value;
layout.render(layout[field]);
}
function updateTimer() {
var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID));
updateLayoutField(timerLayout, 'timer', formatTime(timeToNext / 1000));
//var d = new Date();
//updateLayoutField(timerLayout, 'time', require("locale").time(d,1));
queueDraw(1000);
}
function queueDraw(millisecs) {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
updateTimer();
}, millisecs - (Date.now() % millisecs));
}
function timerStop() {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined;
seconds = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID)) / 1000;
require("sched").setAlarm(timerID, undefined);
require("sched").reload();
runTimePicker();
}
var timePickerLayoutCode = {
type:"v", c: [
{type:undefined, height:2},
//{type:"txt", font:"15%", label:"TIMER", id:"title"},
{type:"h", c: [
{type:"v", width:g.getWidth()/3, c: [
{type:"txt", font:"6x8", label:/*LANG*/"Hours", col:g.theme.fg2},
{type:"img", pad:8, src:imgArrow, col:g.theme.fg2},
{type:"txt", font:"20%", label:"00", id:"hours", filly:1, fillx:1},
{type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2}
]},
{type:"v", width:g.getWidth()/3, c: [
{type:"txt", font:"6x8", label:/*LANG*/"Minutes", col:g.theme.fg2},
{type:"img", pad:8, src:imgArrow, col:g.theme.fg2},
{type:"txt", font:"20%", label:"00", id:"mins", filly:1, fillx:1},
{type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2}
]},
{type:"v", width:g.getWidth()/3, c: [
{type:"txt", font:"6x8", label:/*LANG*/"Seconds", col:g.theme.fg2},
{type:"img", pad:8, src:imgArrow, col:g.theme.fg2},
{type:"txt", font:"20%", label:"00", id:"secs", filly:1, fillx:1},
{type:"img", pad:8, src:imgArrow, col:g.theme.fg2, r:2}
]},
]},
{type:"btn", src:imgPlay, id:"btnStart", fillx:1 }
//{type:"btn", label:'Start', font:"20%", id:"btnStart", fillx:0 }
], filly:1
};
var timerLayoutCode = {
type:"v", c: [
{type:undefined, height:8},
//{type:"txt", font:"6x8", label:/*LANG*/"Timer", id:"title", col:g.theme.fg2},
{type:"txt", font:"22%", label:"0:00", id:"timer", fillx:1, filly:1 },
//{type:"h", c: [
// {type:"txt", font:"6x8", pad:8, label:/*LANG*/"Time Now:", halign:-1, col:g.theme.fg2},
// {type:"txt", font:"6x8", label:"00:00", id:"time", halign:1, col:g.theme.fg2},
//]},
{type:"btn", src:imgPause, cb: l=>timerStop(), fillx:1 }
], filly:1
};
function runTimePicker() {
g.clearRect(Bangle.appRect);
timePickerLayout = new Layout(timePickerLayoutCode);
Bangle.setUI({
mode : "custom",
touch : function(n,e) {onTouch(n,e);},
drag : function(e) {onDrag(e);},
btn : function(n) {runTimer();},
});
timePickerLayout.render();
updateTimePicker();
//timePickerLayout.debug();
}
function runTimer() {
require("sched").setAlarm(timerID, {
vibrate : ".-.-",
hidden: true,
timer : seconds * 1000
});
require("sched").reload();
g.clearRect(Bangle.appRect);
timerLayout = new Layout(timerLayoutCode);
timerLayout.render();
updateTimer();
}
var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm(timerID));
if (timeToNext != undefined) {
g.clearRect(Bangle.appRect);
timerLayout = new Layout(timerLayoutCode);
timerLayout.render();
updateTimer();
} else {
runTimePicker();
}

View File

@ -1 +0,0 @@
require("heatshrink").decompress(atob("mEwwcBkmSpIC/ARf//9JkQRMCAIRBAwIRKv4RFpARIz4QCCIdJiREJAAgJCCI0nCI3+BgOJCIs/CI3/9MkyJoIAAxuGp4RJ8gRQ/mSogRDu4RJNwKSEqXfCJPSCImSrYRJ+SkEyVfCJP6CIo1B4wRHUgIREA4MAj4SHCIeUCIP//EAt4RHkQRF//ggIDB+EHCJf/wEAAAQRM/0CoAmCCJf/4VDI5pcCNwoRKNZ4RMUIQRLYowAIYozpRrYRJ+QREqVLCJPSpGSCIdJv5GIyQREpVJfA///mSogRDpNJloRH8mSBwQRDku/CIwMBCIspkmXCAvpkmRCIslAYKkETwMkxIRFkmkyVLNwYJCBwgCDAwyeEAQqSBAwiMEAQwGFBxACDygDBkQOKAX4CD"))