mirror of https://github.com/espruino/BangleApps
Merge branch 'master' of github.com:espruino/BangleApps
commit
72265bebff
|
@ -9,4 +9,6 @@
|
|||
0.09: fix battery icon size
|
||||
0.10: Tell clock widgets to hide.
|
||||
0.11: fix issue https://github.com/espruino/BangleApps/issues/2128 (#2128) ( settings undefined )
|
||||
0.12: implemented widget_utils
|
||||
0.12: implemented widget_utils
|
||||
0.13: convert var/function into let
|
||||
0.14: cleanup code and fix fastload issue
|
|
@ -2,7 +2,7 @@
|
|||
"id": "rebble",
|
||||
"name": "Rebble Clock",
|
||||
"shortName": "Rebble",
|
||||
"version": "0.12",
|
||||
"version": "0.14",
|
||||
"description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion",
|
||||
"readme": "README.md",
|
||||
"icon": "rebble.png",
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
var SunCalc = require("suncalc");
|
||||
const SETTINGS_FILE = "rebble.json";
|
||||
const LOCATION_FILE = "mylocation.json";
|
||||
const GLOBAL_SETTINGS = "setting.json";
|
||||
let settings;
|
||||
let location;
|
||||
let is12Hour;
|
||||
|
||||
Graphics.prototype.setFontKdamThmor = function(scale) {
|
||||
// Actual height 70 (69 - 0)
|
||||
this.setFontCustom(
|
||||
|
@ -17,312 +9,349 @@ Graphics.prototype.setFontKdamThmor = function(scale) {
|
|||
return this;
|
||||
}
|
||||
|
||||
var boot_img = require("heatshrink").decompress(atob("oFAwkEogA/AH4A/AH4A/AH4A/AE8AAAoeXoAfeDQUBmcyD7A+Dh///8QD649CiAfaHwUvD4sEHy0DDYIfEICg+Cn4fHICY+DD4nxcgojOHwgfEIAYfRCIQaDD4ZAFD5r7DH4//kAfRCIZ/GAAnwD5p9DX44fTHgYSBf4ofVDAQEBl4fFUAgfOXoQzBgIfFBAIfPP4RAEAoYAB+cRiK/SG4h/WIBAfXIA7CBAAswD55AHn6fUIBMCD65AHl4gCmcziAfQQJqfQQJpiDgk0IDXxQLRAEECaBM+QgRYRYgUIA0CD4ggSQJiDCiAKBICszAAswD55AHABKBVD7BAFABIqBD5pAFABPxD55AOD6BADiIAJQAyxLABwf/gaAPAH4A/AH4ARA=="));
|
||||
var sunrise_img = require("heatshrink").decompress(atob("oFAwkEogA/AH4A/AH4A/AH4ACp5A/AH4A/AH4AIoEAggfcgAABD/4f/D/4f/CiNPmgfUoYIHoEAggfSoEQgYJGmAUJD5QJBgQ/IIBBKJChiVSCYR1LBZAzTICQyNICAxOICAwPD40xA4UTc5xAFiAuDiAWCAAMBc5hgHDxAgFeCKEDh//AAPwdiKDHh9PD4X0EAX0DyQ+BHoYgFh4+UDwofB/68OAAlBHw6CEQKITBDxAABMCReHUQhgSLxRgDDx9CD4g8DD4sUbqEUH5SABUB4fBDxYfKkQAFkEAiQJGAAcjgECBQ6qBAH4A9Y5wA/AH4Aw"));
|
||||
var sunset_img = require("heatshrink").decompress(atob("oFAwkEogA/AH4A/AH4A/AH4A/AH4A/AH4AMoEAggfcgAABD/4f/D/4f/CqU0D6lDBA9AgEED6VAiEDBI0wChIfKBIMCH5BAIJRIUMSqQTCOpYLIGaZASGRpAQGJxAQGB4fGmIHCibnOIAsQFwcQCwQABgLnMMA4eIEArwRQgY0DAwwARC44gC+geSORJ8PHw4KTABFBGhRAT+AzLgEPLzZgUKRhgBDx9CD50UbqARMUCBROD5MiAAsggESBIwADkcAgQKHVQIA/AHrHOAH4A/AGA"));
|
||||
|
||||
var drawCount = 0;
|
||||
var sideBar = 0;
|
||||
var sunRise = "00:00";
|
||||
var sunSet = "00:00";
|
||||
|
||||
function log_debug(o) {
|
||||
//console.log(o);
|
||||
|
||||
}
|
||||
|
||||
// requires the myLocation app
|
||||
function loadLocation() {
|
||||
location = require("Storage").readJSON(LOCATION_FILE,1)||{"lat":51.5072,"lon":0.1276,"location":"London"};
|
||||
}
|
||||
|
||||
function loadSettings() {
|
||||
settings = {'bg': '#0f0', 'color': 'Green', 'autoCycle': true,'sideTap':0};
|
||||
//sideTap 0 = on | 1 = sidebar1...
|
||||
|
||||
let tmp = require('Storage').readJSON(SETTINGS_FILE, 1) || settings;
|
||||
for (const key in tmp) {
|
||||
settings[key] = tmp[key]
|
||||
}
|
||||
|
||||
if(settings.sideTap!=0)
|
||||
sideBar=parseInt(settings.sideTap)-1; //tab to show
|
||||
is12Hour = (require("Storage").readJSON(GLOBAL_SETTINGS, 1) || {})["12hour"] || false;
|
||||
}
|
||||
|
||||
const zeroPad = (num, places) => String(num).padStart(places, '0')
|
||||
|
||||
function formatHours(h) {
|
||||
if (is12Hour) {
|
||||
if (h == 0) {
|
||||
h = 12;
|
||||
} else if (h > 12) {
|
||||
h -= 12;
|
||||
}
|
||||
}
|
||||
return zeroPad(h, 2);
|
||||
}
|
||||
|
||||
function extractTime(d){
|
||||
var h = d.getHours(), m = d.getMinutes();
|
||||
return(formatHours(h) + ":" + zeroPad(m, 2));
|
||||
}
|
||||
|
||||
function updateSunRiseSunSet(lat, lon){
|
||||
// get today's sunlight times for lat/lon
|
||||
var times = SunCalc.getTimes(new Date(), lat, lon);
|
||||
|
||||
// format sunrise time from the Date object
|
||||
sunRise = extractTime(times.sunrise);
|
||||
sunSet = extractTime(times.sunset);
|
||||
}
|
||||
|
||||
// wrapper, makes it easier if we want to switch to a different font later
|
||||
function setSmallFont() {
|
||||
g.setFont('Vector', 20);
|
||||
}
|
||||
|
||||
// set the text color of the sidebar elements that dont change with the Theme
|
||||
function setTextColor() {
|
||||
// day and steps
|
||||
if (settings.color == 'Blue' || settings.color == 'Red') {
|
||||
g.setColor('#fff'); // white on blue or red best contrast
|
||||
} else {
|
||||
g.setColor('#000'); // otherwise black regardless of theme
|
||||
}
|
||||
}
|
||||
|
||||
const h = g.getHeight();
|
||||
const w = g.getWidth();
|
||||
const ha = 2*h/5 - 8;
|
||||
const h2 = 3*h/5 - 10;
|
||||
const h3 = 7*h/8;
|
||||
const w2 = 9*w/14;
|
||||
const w3 = w2 + ((w - w2)/2); // centre line of the sidebar
|
||||
const ws = w - w2; // sidebar width
|
||||
const wb = 40; // battery width
|
||||
|
||||
function draw() {
|
||||
log_debug("draw()");
|
||||
let date = new Date();
|
||||
let hh = date.getHours();
|
||||
let mm = date.getMinutes();
|
||||
|
||||
hh = formatHours(hh);
|
||||
mm = zeroPad(mm,2);
|
||||
|
||||
//const t = 6;
|
||||
|
||||
if (drawCount % 60 == 0)
|
||||
updateSunRiseSunSet(location.lat, location.lon);
|
||||
|
||||
g.reset();
|
||||
g.setColor(g.theme.bg);
|
||||
g.fillRect(0, 0, w2, h);
|
||||
g.setColor(settings.bg);
|
||||
g.fillRect(w2, 0, w, h);
|
||||
|
||||
// time
|
||||
g.setColor(g.theme.fg);
|
||||
g.setFontKdamThmor();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(hh, w2/2, 10 + 0);
|
||||
g.drawString(mm, w2/2, 10 + h/2);
|
||||
|
||||
switch(sideBar) {
|
||||
case 0:
|
||||
drawSideBar1();
|
||||
break;
|
||||
case 1:
|
||||
drawSideBar2();
|
||||
break;
|
||||
case 2:
|
||||
drawSideBar3();
|
||||
break;
|
||||
}
|
||||
|
||||
drawCount++;
|
||||
queueDraw();
|
||||
}
|
||||
|
||||
function drawSideBar1() {
|
||||
let date = new Date();
|
||||
let dy=require("date_utils").dow(date.getDay(),1).toUpperCase();
|
||||
let dd=date.getDate();
|
||||
let mm=require("date_utils").month(date.getMonth()+1,1).toUpperCase();
|
||||
|
||||
|
||||
drawBattery(w2 + (w-w2-wb)/2, h/10, wb, 17);
|
||||
|
||||
setTextColor();
|
||||
g.setFont('Vector', 20);
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(E.getBattery() + '%', w3, (h/10) + 17 + 7);
|
||||
|
||||
drawDateAndCalendar(w3, h/2, dy, dd, mm);
|
||||
}
|
||||
|
||||
function drawSideBar2() {
|
||||
drawBattery(w2 + (w-w2-wb)/2, h/10, wb, 17);
|
||||
|
||||
setTextColor();
|
||||
g.setFont('Vector', 20);
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(E.getBattery() + '%', w3, (h/10) + 17 + 7);
|
||||
|
||||
// steps
|
||||
g.drawImage(boot_img, w2 + (ws - 64)/2, h/2, { scale: 1 });
|
||||
setSmallFont();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(formatSteps(), w3, 7*h/8);
|
||||
}
|
||||
|
||||
// sunrise, sunset times
|
||||
function drawSideBar3() {
|
||||
g.setColor('#fff'); // sunrise white
|
||||
g.drawImage(sunrise_img, w2 + (ws - 64)/2, 0, { scale: 1 });
|
||||
setTextColor();
|
||||
setSmallFont();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(sunRise, w3, 64);
|
||||
|
||||
g.setColor('#000'); // sunset black
|
||||
g.drawImage(sunset_img, w2 + (ws - 64)/2, h/2, { scale: 1 });
|
||||
setTextColor();
|
||||
setSmallFont();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(sunSet, w3, (h/2) + 64);
|
||||
}
|
||||
|
||||
function drawDateAndCalendar(x,y,dy,dd,mm) {
|
||||
// day
|
||||
setTextColor();
|
||||
setSmallFont();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(dy.toUpperCase(), x, y);
|
||||
|
||||
drawCalendar(x - (w/10), y + 28, w/5, 3, dd);
|
||||
|
||||
// month
|
||||
setTextColor();
|
||||
setSmallFont();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(mm.toUpperCase(), x, y + 70);
|
||||
}
|
||||
|
||||
// at x,y width:wi thicknes:th
|
||||
function drawCalendar(x,y,wi,th,str) {
|
||||
g.setColor(g.theme.fg);
|
||||
g.fillRect(x, y, x + wi, y + wi);
|
||||
g.setColor(g.theme.bg);
|
||||
g.fillRect(x + th, y + th, x + wi - th, y + wi - th);
|
||||
g.setColor(g.theme.fg);
|
||||
|
||||
let hook_t = 6;
|
||||
// first calendar hook, one third in
|
||||
g.fillRect(x + (wi/3) - (th/2), y - hook_t, x + wi/3 + th - (th/2), y + hook_t);
|
||||
// second calendar hook, two thirds in
|
||||
g.fillRect(x + (2*wi/3) -(th/2), y - hook_t, x + 2*wi/3 + th - (th/2), y + hook_t);
|
||||
|
||||
setSmallFont();
|
||||
g.setFontAlign(0, 0);
|
||||
g.drawString(str, x + wi/2 + th/2, y + wi/2 + th/2);
|
||||
}
|
||||
|
||||
function drawBattery(x,y,wi,hi) {
|
||||
g.reset();
|
||||
g.setColor(g.theme.fg);
|
||||
g.fillRect(x,y+2,x+wi-4,y+2+hi); // outer
|
||||
g.clearRect(x+2,y+2+2,x+wi-4-2,y+2+hi-2); // centre
|
||||
g.setColor(g.theme.fg);
|
||||
g.fillRect(x+wi-3,y+2+(((hi - 1)/2)-1),x+wi-2,y+2+(((hi - 1)/2)-1)+4); // contact
|
||||
g.fillRect(x+3, y+5, x +3 + E.getBattery()*(wi-10)/100, y+hi-1); // the level
|
||||
|
||||
if( Bangle.isCharging() )
|
||||
{
|
||||
g.setBgColor(settings.bg);
|
||||
image = ()=> { return require("heatshrink").decompress(atob("j8OwMB/4AD94DC44DCwP//n/gH//EOgE/+AdBh/gAYMH4EAvkDAYP/+/AFAX+FgfzGAnAA=="));}
|
||||
g.drawImage(image(),x+3,y+4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// format steps so they fit in the place
|
||||
function formatSteps() {
|
||||
var s = Bangle.getHealthStatus("day").steps;
|
||||
|
||||
if (s < 1000) {
|
||||
return s + '';
|
||||
} else if (s < 10000) {
|
||||
return '' + (s/1000).toFixed(1) + 'K';
|
||||
}
|
||||
return Math.floor(s / 1000) + 'K';
|
||||
}
|
||||
|
||||
function nextSidebar() {
|
||||
|
||||
if (++sideBar > 2) sideBar = 0;
|
||||
log_debug("next: " + sideBar);
|
||||
|
||||
}
|
||||
|
||||
function prevSidebar() {
|
||||
|
||||
if (--sideBar < 0) sideBar = 2;
|
||||
log_debug("prev: " + sideBar);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// timeout used to update every minute
|
||||
var drawTimeout;
|
||||
|
||||
// schedule a draw for the next minute
|
||||
function queueDraw() {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = setTimeout(function() {
|
||||
drawTimeout = undefined;
|
||||
if (settings.autoCycle) {
|
||||
nextSidebar();
|
||||
}
|
||||
draw();
|
||||
}, 60000 - (Date.now() % 60000));
|
||||
}
|
||||
|
||||
|
||||
log_debug("starting..");
|
||||
loadSettings();
|
||||
loadLocation();
|
||||
|
||||
|
||||
if(settings.autoCycle || settings.sideTap==0)
|
||||
{
|
||||
Bangle.setUI("clockupdown", btn=> {
|
||||
if (btn<0) prevSidebar();
|
||||
if (btn>0) nextSidebar();
|
||||
draw();
|
||||
});
|
||||
}
|
||||
else{
|
||||
Bangle.setUI("clock");
|
||||
}
|
||||
|
||||
|
||||
Bangle.loadWidgets();
|
||||
require("widget_utils").hide();
|
||||
let SunCalc = require("suncalc");
|
||||
const SETTINGS_FILE = "rebble.json";
|
||||
const LOCATION_FILE = "mylocation.json";
|
||||
const GLOBAL_SETTINGS = "setting.json";
|
||||
let settings;
|
||||
let location;
|
||||
let is12Hour;
|
||||
|
||||
|
||||
|
||||
draw(); // queues the next draw for a minutes time
|
||||
Bangle.on('charging', function(charging) {
|
||||
//redraw the sidebar ( with the battery )
|
||||
switch(sideBar) {
|
||||
let boot_img = require("heatshrink").decompress(atob("oFAwkEogA/AH4A/AH4A/AH4A/AE8AAAoeXoAfeDQUBmcyD7A+Dh///8QD649CiAfaHwUvD4sEHy0DDYIfEICg+Cn4fHICY+DD4nxcgojOHwgfEIAYfRCIQaDD4ZAFD5r7DH4//kAfRCIZ/GAAnwD5p9DX44fTHgYSBf4ofVDAQEBl4fFUAgfOXoQzBgIfFBAIfPP4RAEAoYAB+cRiK/SG4h/WIBAfXIA7CBAAswD55AHn6fUIBMCD65AHl4gCmcziAfQQJqfQQJpiDgk0IDXxQLRAEECaBM+QgRYRYgUIA0CD4ggSQJiDCiAKBICszAAswD55AHABKBVD7BAFABIqBD5pAFABPxD55AOD6BADiIAJQAyxLABwf/gaAPAH4A/AH4ARA=="));
|
||||
let sunrise_img = require("heatshrink").decompress(atob("oFAwkEogA/AH4A/AH4A/AH4ACp5A/AH4A/AH4AIoEAggfcgAABD/4f/D/4f/CiNPmgfUoYIHoEAggfSoEQgYJGmAUJD5QJBgQ/IIBBKJChiVSCYR1LBZAzTICQyNICAxOICAwPD40xA4UTc5xAFiAuDiAWCAAMBc5hgHDxAgFeCKEDh//AAPwdiKDHh9PD4X0EAX0DyQ+BHoYgFh4+UDwofB/68OAAlBHw6CEQKITBDxAABMCReHUQhgSLxRgDDx9CD4g8DD4sUbqEUH5SABUB4fBDxYfKkQAFkEAiQJGAAcjgECBQ6qBAH4A9Y5wA/AH4Aw"));
|
||||
let sunset_img = require("heatshrink").decompress(atob("oFAwkEogA/AH4A/AH4A/AH4A/AH4A/AH4AMoEAggfcgAABD/4f/D/4f/CqU0D6lDBA9AgEED6VAiEDBI0wChIfKBIMCH5BAIJRIUMSqQTCOpYLIGaZASGRpAQGJxAQGB4fGmIHCibnOIAsQFwcQCwQABgLnMMA4eIEArwRQgY0DAwwARC44gC+geSORJ8PHw4KTABFBGhRAT+AzLgEPLzZgUKRhgBDx9CD50UbqARMUCBROD5MiAAsggESBIwADkcAgQKHVQIA/AHrHOAH4A/AGA"));
|
||||
|
||||
let drawCount = 0;
|
||||
let sideBar = 0;
|
||||
let sunRise = "00:00";
|
||||
let sunSet = "00:00";
|
||||
|
||||
let log_debug= function(o) {
|
||||
//console.log(o);
|
||||
}
|
||||
|
||||
// requires the myLocation app
|
||||
let loadLocation= function() {
|
||||
location = require("Storage").readJSON(LOCATION_FILE,1)||{"lat":51.5072,"lon":0.1276,"location":"London"};
|
||||
}
|
||||
|
||||
let loadSettings=function() {
|
||||
settings = {'bg': '#0f0', 'color': 'Green', 'autoCycle': true,'sideTap':0};
|
||||
//sideTap 0 = on | 1 = sidebar1...
|
||||
|
||||
let tmp = require('Storage').readJSON(SETTINGS_FILE, 1) || settings;
|
||||
for (const key in tmp) {
|
||||
settings[key] = tmp[key]
|
||||
}
|
||||
|
||||
if(settings.sideTap!=0)
|
||||
sideBar=parseInt(settings.sideTap)-1; //tab to
|
||||
is12Hour = (require("Storage").readJSON(GLOBAL_SETTINGS, 1) || {})["12hour"] || false;
|
||||
}
|
||||
|
||||
const zeroPad = (num, places) => String(num).padStart(places, '0')
|
||||
|
||||
let formatHours=function(h) {
|
||||
if (is12Hour) {
|
||||
if (h == 0) {
|
||||
h = 12;
|
||||
} else if (h > 12) {
|
||||
h -= 12;
|
||||
}
|
||||
}
|
||||
return zeroPad(h, 2);
|
||||
}
|
||||
|
||||
let extractTime=function(d){
|
||||
let h = d.getHours(), m = d.getMinutes();
|
||||
return(formatHours(h) + ":" + zeroPad(m, 2));
|
||||
}
|
||||
|
||||
let updateSunRiseSunSet=function(lat, lon){
|
||||
// get today's sunlight times for lat/lon
|
||||
let times = SunCalc.getTimes(new Date(), lat, lon);
|
||||
|
||||
// format sunrise time from the Date object
|
||||
sunRise = extractTime(times.sunrise);
|
||||
sunSet = extractTime(times.sunset);
|
||||
}
|
||||
|
||||
// wrapper, makes it easier if we want to switch to a different font later
|
||||
let setSmallFont=function() {
|
||||
g.setFont('Vector', 20);
|
||||
}
|
||||
|
||||
// set the text color of the sidebar elements that dont change with the Theme
|
||||
let setTextColor=function() {
|
||||
// day and steps
|
||||
if (settings.color == 'Blue' || settings.color == 'Red') {
|
||||
g.setColor('#fff'); // white on blue or red best contrast
|
||||
} else {
|
||||
g.setColor('#000'); // otherwise black regardless of theme
|
||||
}
|
||||
}
|
||||
|
||||
const h = g.getHeight();
|
||||
const w = g.getWidth();
|
||||
/*const ha = 2*h/5 - 8;
|
||||
const h2 = 3*h/5 - 10;
|
||||
const h3 = 7*h/8;*/
|
||||
const w2 = 9*w/14;
|
||||
const w3 = w2 + ((w - w2)/2); // centre line of the sidebar
|
||||
const ws = w - w2; // sidebar width
|
||||
const wb = 40; // battery width
|
||||
|
||||
let draw=function() {
|
||||
log_debug("draw()");
|
||||
let date = new Date();
|
||||
let hh = date.getHours();
|
||||
let mm = date.getMinutes();
|
||||
|
||||
hh = formatHours(hh);
|
||||
mm = zeroPad(mm,2);
|
||||
|
||||
//const t = 6;
|
||||
|
||||
if (drawCount % 60 == 0)
|
||||
updateSunRiseSunSet(location.lat, location.lon);
|
||||
|
||||
g.reset();
|
||||
g.setColor(g.theme.bg);
|
||||
g.fillRect(0, 0, w2, h);
|
||||
g.setColor(settings.bg);
|
||||
g.fillRect(w2, 0, w, h);
|
||||
|
||||
// time
|
||||
g.setColor(g.theme.fg);
|
||||
g.setFontKdamThmor();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(hh, w2/2, 10 + 0);
|
||||
g.drawString(mm, w2/2, 10 + h/2);
|
||||
|
||||
switch(sideBar) {
|
||||
case 0:
|
||||
drawSideBar1();
|
||||
break;
|
||||
case 1:
|
||||
drawSideBar2();
|
||||
break;
|
||||
case 2:
|
||||
drawSideBar3();
|
||||
break;
|
||||
}
|
||||
|
||||
drawCount++;
|
||||
queueDraw();
|
||||
}
|
||||
});
|
||||
|
||||
let drawSideBar1=function() {
|
||||
let date = new Date();
|
||||
let dy=require("date_utils").dow(date.getDay(),1).toUpperCase();
|
||||
let dd=date.getDate();
|
||||
let mm=require("date_utils").month(date.getMonth()+1,1).toUpperCase();
|
||||
|
||||
|
||||
drawBattery(w2 + (w-w2-wb)/2, h/10, wb, 17);
|
||||
|
||||
setTextColor();
|
||||
g.setFont('Vector', 20);
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(E.getBattery() + '%', w3, (h/10) + 17 + 7);
|
||||
|
||||
drawDateAndCalendar(w3, h/2, dy, dd, mm);
|
||||
}
|
||||
|
||||
let drawSideBar2=function() {
|
||||
drawBattery(w2 + (w-w2-wb)/2, h/10, wb, 17);
|
||||
|
||||
setTextColor();
|
||||
g.setFont('Vector', 20);
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(E.getBattery() + '%', w3, (h/10) + 17 + 7);
|
||||
|
||||
// steps
|
||||
g.drawImage(boot_img, w2 + (ws - 64)/2, h/2, { scale: 1 });
|
||||
setSmallFont();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(formatSteps(), w3, 7*h/8);
|
||||
}
|
||||
|
||||
// sunrise, sunset times
|
||||
let drawSideBar3=function() {
|
||||
g.setColor('#fff'); // sunrise white
|
||||
g.drawImage(sunrise_img, w2 + (ws - 64)/2, 0, { scale: 1 });
|
||||
setTextColor();
|
||||
setSmallFont();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(sunRise, w3, 64);
|
||||
|
||||
g.setColor('#000'); // sunset black
|
||||
g.drawImage(sunset_img, w2 + (ws - 64)/2, h/2, { scale: 1 });
|
||||
setTextColor();
|
||||
setSmallFont();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(sunSet, w3, (h/2) + 64);
|
||||
}
|
||||
|
||||
let drawDateAndCalendar=function(x,y,dy,dd,mm) {
|
||||
// day
|
||||
setTextColor();
|
||||
setSmallFont();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(dy.toUpperCase(), x, y);
|
||||
|
||||
drawCalendar(x - (w/10), y + 28, w/5, 3, dd);
|
||||
|
||||
// month
|
||||
setTextColor();
|
||||
setSmallFont();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(mm.toUpperCase(), x, y + 70);
|
||||
}
|
||||
|
||||
// at x,y width:wi thicknes:th
|
||||
let drawCalendar=function(x,y,wi,th,str) {
|
||||
g.setColor(g.theme.fg);
|
||||
g.fillRect(x, y, x + wi, y + wi);
|
||||
g.setColor(g.theme.bg);
|
||||
g.fillRect(x + th, y + th, x + wi - th, y + wi - th);
|
||||
g.setColor(g.theme.fg);
|
||||
|
||||
let hook_t = 6;
|
||||
// first calendar hook, one third in
|
||||
g.fillRect(x + (wi/3) - (th/2), y - hook_t, x + wi/3 + th - (th/2), y + hook_t);
|
||||
// second calendar hook, two thirds in
|
||||
g.fillRect(x + (2*wi/3) -(th/2), y - hook_t, x + 2*wi/3 + th - (th/2), y + hook_t);
|
||||
|
||||
setSmallFont();
|
||||
g.setFontAlign(0, 0);
|
||||
g.drawString(str, x + wi/2 + th/2, y + wi/2 + th/2);
|
||||
}
|
||||
|
||||
let drawBattery=function(x,y,wi,hi) {
|
||||
g.reset();
|
||||
g.setColor(g.theme.fg);
|
||||
g.fillRect(x,y+2,x+wi-4,y+2+hi); // outer
|
||||
g.clearRect(x+2,y+2+2,x+wi-4-2,y+2+hi-2); // centre
|
||||
g.setColor(g.theme.fg);
|
||||
g.fillRect(x+wi-3,y+2+(((hi - 1)/2)-1),x+wi-2,y+2+(((hi - 1)/2)-1)+4); // contact
|
||||
g.fillRect(x+3, y+5, x +3 + E.getBattery()*(wi-10)/100, y+hi-1); // the level
|
||||
|
||||
log_debug("Charging "+Bangle.isCharging());
|
||||
if( Bangle.isCharging() )
|
||||
{
|
||||
g.setBgColor(settings.bg);
|
||||
image = ()=> { return require("heatshrink").decompress(atob("j8OwMB/4AD94DC44DCwP//n/gH//EOgE/+AdBh/gAYMH4EAvkDAYP/+/AFAX+FgfzGAnAA=="));}
|
||||
g.drawImage(image(),x+3,y+4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// format steps so they fit in the place
|
||||
let formatSteps=function() {
|
||||
let s = Bangle.getHealthStatus("day").steps;
|
||||
|
||||
if (s < 1000) {
|
||||
return s + '';
|
||||
} else if (s < 10000) {
|
||||
return '' + (s/1000).toFixed(1) + 'K';
|
||||
}
|
||||
return Math.floor(s / 1000) + 'K';
|
||||
}
|
||||
|
||||
let nextSidebar=function() {
|
||||
if (++sideBar > 2) sideBar = 0;
|
||||
log_debug("next: " + sideBar);
|
||||
}
|
||||
|
||||
let prevSidebar=function() {
|
||||
if (--sideBar < 0) sideBar = 2;
|
||||
log_debug("prev: " + sideBar);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// timeout used to update every minute
|
||||
let drawTimeout;
|
||||
|
||||
// schedule a draw for the next minute
|
||||
let queueDraw=function() {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = setTimeout(function() {
|
||||
drawTimeout = undefined;
|
||||
if (settings.autoCycle) {
|
||||
nextSidebar();
|
||||
}
|
||||
draw();
|
||||
}, 60000 - (Date.now() % 60000));
|
||||
}
|
||||
|
||||
|
||||
|
||||
let chargingListener= function(charging) {
|
||||
|
||||
//redraw the sidebar ( with the battery )
|
||||
switch(sideBar) {
|
||||
case 0:
|
||||
drawSideBar1();
|
||||
break;
|
||||
case 1:
|
||||
drawSideBar2();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let deleteAll=function()
|
||||
{
|
||||
// Called to unload all of the clock app
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
delete Graphics.prototype.setFontKdamThmor;
|
||||
Bangle.removeListener('charging',chargingListener);
|
||||
}
|
||||
|
||||
let main=function(){
|
||||
|
||||
|
||||
log_debug("starting..");
|
||||
loadSettings();
|
||||
loadLocation();
|
||||
|
||||
if(settings.autoCycle || settings.sideTap==0)
|
||||
{
|
||||
Bangle.setUI({
|
||||
mode : "clockupdown",
|
||||
remove : deleteAll
|
||||
},
|
||||
btn=> {
|
||||
if (btn<0) prevSidebar();
|
||||
if (btn>0) nextSidebar();
|
||||
draw();
|
||||
});
|
||||
|
||||
}
|
||||
else{
|
||||
Bangle.setUI({
|
||||
mode : "clock",
|
||||
remove : deleteAll
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
Bangle.on('charging',chargingListener);
|
||||
|
||||
|
||||
Bangle.loadWidgets();
|
||||
draw();
|
||||
require("widget_utils").hide();
|
||||
|
||||
}
|
||||
|
||||
|
||||
main();
|
||||
}
|
|
@ -15,13 +15,13 @@
|
|||
localSettings[key] = saved[key]
|
||||
}
|
||||
|
||||
function save() {
|
||||
let save=function() {
|
||||
settings = localSettings
|
||||
storage.write(SETTINGS_FILE, settings)
|
||||
}
|
||||
|
||||
var color_options = ['Green','Orange','Cyan','Purple','Red','Blue'];
|
||||
var bg_code = ['#0f0','#ff0','#0ff','#f0f','#f00','#00f'];
|
||||
let color_options = ['Green','Orange','Cyan','Purple','Red','Blue'];
|
||||
let bg_code = ['#0f0','#ff0','#0ff','#f0f','#f00','#00f'];
|
||||
|
||||
function showMenu()
|
||||
{
|
||||
|
@ -66,7 +66,7 @@
|
|||
E.showMenu(menu);
|
||||
}
|
||||
|
||||
function NumberToSideTap(Number)
|
||||
let NumberToSideTap=function(Number)
|
||||
{
|
||||
if(Number==0)
|
||||
return 'on';
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: New app!
|
|
@ -0,0 +1,19 @@
|
|||
Do a seven minute workout - or three!
|
||||
|
||||
Touch the screen to start the workout and follow the instructions.
|
||||
|
||||
Once the workout is finished the screen can be touched to go again - but get a minute or two of rest inbetween!
|
||||
|
||||
Search the web if you want further instructions, videos are helpful!
|
||||
|
||||
TODO:
|
||||
- Add visible countdowns
|
||||
- Add tracking of excercises, number of repetitions done etc. (Integration with BanglExercise app?)
|
||||
- Add tracking of workouts over time.
|
||||
- Move the whole app into BangleExercise app?
|
||||
-
|
||||
|
||||
Creator:
|
||||
Thyttan
|
||||
|
||||
<a target="_blank" href="https://icons8.com/icon/19961/jump">Jump</a> icon by <a target="_blank" href="https://icons8.com">Icons8</a>
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwhC/AFfd7oWUhoXB6AuVGCoX/CQZwDO4wGBRJ4uESpYLCBg4KKLQw+EBBAYK6Wq1UtPaAPC7QXB1qSRLAMqC4OiLZQYIC4YWRAAIWBAALvTC/7DLCySoBAASPSCgPc5owSFwXM5gwSFwQXBGCQuC4EMGARGSAoJIRIwXAAoMMJB4uFGCIuFGCIuGGAhGM7gKHGAJIKC4IMIBRRHDAYUzAAQKGABUDCwYABmDvPC4IFDC6IAYJAhGSAAwZNCwQQEA44WJBQ4YMgYLWAH4AaA=="))
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
'Jumping jacks',
|
||||
'Wall sit',
|
||||
'Pushups',
|
||||
'Crunches',
|
||||
'Step-up onto chair, alternating legs',
|
||||
'Squats',
|
||||
'Triceps dips, using a chair or bench',
|
||||
'Forearm plank',
|
||||
'High-knees or running in place',
|
||||
'Lunges, alternating legs',
|
||||
'Pushups with rotation, alternating sides',
|
||||
'Side plank',
|
||||
|
||||
Once you've completed all 12 exercises, take a break for 1–2 minutes and repeat the circuit another 2–3 times.
|
||||
|
||||
*/
|
||||
{
|
||||
|
||||
let R = Bangle.appRect;
|
||||
let instructions = ['Rest\n\nNext up:\n\n',
|
||||
'Tap to start!',
|
||||
'Get ready!\nFirst up:\n',
|
||||
'Jumping jacks',
|
||||
'Wall sit',
|
||||
'Pushups',
|
||||
'Crunches',
|
||||
'Step-up onto\nchair,\nalternating legs',
|
||||
'Squats',
|
||||
'Triceps dips,\n using\ a\nchair or bench',
|
||||
'Forearm plank',
|
||||
'High-knees or\nrunning in place',
|
||||
'Lunges,\nalternating legs',
|
||||
'Pushups with\nrotation,\nalternating sides',
|
||||
'Side plank',
|
||||
'Workout done!'
|
||||
];
|
||||
|
||||
Bangle.setLCDTimeout(0);
|
||||
Bangle.setLocked(false);
|
||||
|
||||
let draw = function(instruction) {
|
||||
g.reset();
|
||||
g.clearRect(R);
|
||||
|
||||
g.setFont12x20();
|
||||
g.setFontAlign(0,0,0);
|
||||
g.drawString(instruction, R.w/2, R.h/2);
|
||||
};
|
||||
|
||||
let endWorkout = function(interval) {
|
||||
draw(instructions[instructions.length-1]);
|
||||
clearInterval(interval);
|
||||
ongoing = false;
|
||||
};
|
||||
|
||||
let cycle = 40; // standard cycle is 40 seconds
|
||||
let scaling = cycle/40; // scaling if changing cycle length
|
||||
let ongoing = false;
|
||||
let touchHandler = function() {
|
||||
if (!ongoing) {
|
||||
Bangle.buzz();
|
||||
ongoing = true;
|
||||
// Get ready!
|
||||
draw(instructions[2]+instructions[3]);
|
||||
let i = 3;
|
||||
// buzzes before start
|
||||
setTimeout(()=>{let j = 0; let buzzes = setInterval(()=>{Bangle.buzz(200*scaling); j++; if (j==5) clearInterval(buzzes);}, 1*1000*scaling);}, 4*1000*scaling);
|
||||
// timeout till first excercise
|
||||
let timeout = setTimeout(()=>{draw(instructions[i]);i++;}, 10*1000*scaling);
|
||||
// buzzes before first rest
|
||||
setTimeout(()=>{let j = 0; let buzzes = setInterval(()=>{Bangle.buzz(200*scaling); j++; if (j==5) clearInterval(buzzes);}, 1*1000*scaling);}, 34*1000*scaling);
|
||||
// interval containing rest and excercises 10+30=40
|
||||
let interval = setInterval(()=>{
|
||||
if (i==instructions.length-1) {
|
||||
endWorkout(interval);
|
||||
} else {
|
||||
// draw pause message
|
||||
draw(instructions[0]+instructions[i]);
|
||||
// buzzes before next excercise
|
||||
setTimeout(()=>{let j = 0; let buzzes = setInterval(()=>{Bangle.buzz(200*scaling); j++; if (j==5) clearInterval(buzzes);}, 1*1000*scaling);}, 4*1000*scaling);
|
||||
// timeout till next excercise
|
||||
setTimeout(()=>{draw(instructions[i]);i++;}, 10*1000*scaling);
|
||||
// buzzes before next rest
|
||||
setTimeout(()=>{let j = 0; let buzzes = setInterval(()=>{Bangle.buzz(200*scaling); j++; if (j==5) clearInterval(buzzes);}, 1*1000*scaling);}, 34*1000*scaling);
|
||||
}
|
||||
}, 40*1000*scaling);
|
||||
}
|
||||
};
|
||||
|
||||
let swipeHandler = function() {
|
||||
|
||||
};
|
||||
|
||||
let uiMode = {
|
||||
mode : 'custom',
|
||||
back : load,
|
||||
touch : touchHandler,
|
||||
//swipe : swipeHandler
|
||||
};
|
||||
Bangle.setUI(uiMode);
|
||||
|
||||
Bangle.loadWidgets();
|
||||
// Tap to start!
|
||||
draw(instructions[1]);
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,16 @@
|
|||
{ "id": "sevenmin",
|
||||
"name": "Seven minute workout",
|
||||
"shortName": "7 min wo",
|
||||
"version": "0.01",
|
||||
"description": "A basic implementation of the famous consice workout",
|
||||
"icon": "icon.png",
|
||||
"type":"app",
|
||||
"tags": "Training, Workout",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator":true,
|
||||
"storage": [
|
||||
{"name":"sevenmin.app.js", "url":"app.js"},
|
||||
{"name":"sevenmin.img", "url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue