Merge branch 'espruino:master' into master
|
|
@ -2,4 +2,5 @@ apps/animclk/V29.LBM.js
|
||||||
apps/banglerun/rollup.config.js
|
apps/banglerun/rollup.config.js
|
||||||
apps/schoolCalendar/fullcalendar/main.js
|
apps/schoolCalendar/fullcalendar/main.js
|
||||||
apps/authentiwatch/qr_packed.js
|
apps/authentiwatch/qr_packed.js
|
||||||
|
apps/qrcode/qr-scanner.umd.min.js
|
||||||
*.test.js
|
*.test.js
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
name: Node CI
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [16.x]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository and submodules
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
- name: install testing dependencies
|
||||||
|
run: npm i
|
||||||
|
- name: test all apps and widgets
|
||||||
|
run: npm run test
|
||||||
|
- name: install typescript dependencies
|
||||||
|
working-directory: ./typescript
|
||||||
|
run: npm ci
|
||||||
|
- name: build types
|
||||||
|
working-directory: ./typescript
|
||||||
|
run: npm run build:types
|
||||||
|
- name: build all TS apps and widgets
|
||||||
|
working-directory: ./typescript
|
||||||
|
run: npm run build
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
language: node_js
|
|
||||||
node_js:
|
|
||||||
- "node"
|
|
||||||
|
|
@ -5,7 +5,7 @@ by Peter Kuppelwieser
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let settings = Object.assign({ swupApp: "",swdownApp: "", swleftApp: "", swrightApp: ""}, require("Storage").readJSON("7x7dotsclock.json", true) || {});
|
let settings = Object.assign({ swupApp: "",swdownApp: "", swleftApp: "", swrightApp: "", ColorMinutes: ""}, require("Storage").readJSON("7x7dotsclock.json", true) || {});
|
||||||
|
|
||||||
// position on screen
|
// position on screen
|
||||||
var Xs = 0, Ys = 30,Xe = 175, Ye=175;
|
var Xs = 0, Ys = 30,Xe = 175, Ye=175;
|
||||||
|
|
@ -13,9 +13,33 @@ var Xs = 0, Ys = 30,Xe = 175, Ye=175;
|
||||||
var SegH = (Ye-Ys)/2,SegW = (Xe-Xs)/2;
|
var SegH = (Ye-Ys)/2,SegW = (Xe-Xs)/2;
|
||||||
var Dx = SegW/14, Dy = SegH/16;
|
var Dx = SegW/14, Dy = SegH/16;
|
||||||
|
|
||||||
const hColor = [1,1,1];
|
switch(settings.ColorMinutes) {
|
||||||
const mColor = [0.3,0.3,1];
|
case "blue":
|
||||||
const bColor = [0.2,0.2,0.2];
|
var mColor = [0.3,0.3,1];
|
||||||
|
var sColor = [0,0,1];
|
||||||
|
var sbColor = [1,1,1];
|
||||||
|
break;
|
||||||
|
case "pink":
|
||||||
|
var mColor = [1,0.3,1];
|
||||||
|
var sColor = [1,0,1];
|
||||||
|
var sbColor = [1,1,1];
|
||||||
|
break;
|
||||||
|
case "green":
|
||||||
|
var mColor = [0.3,1,0.3];
|
||||||
|
var sColor = [0,1,0];
|
||||||
|
var sbColor = [1,1,1];
|
||||||
|
break;
|
||||||
|
case "yellow":
|
||||||
|
var mColor = [1,1,0.3];
|
||||||
|
var sColor = [1,1,0];
|
||||||
|
var sbColor = [0,0,0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
var sColor = [0,0,1];
|
||||||
|
var mColor = [0.3,0.3,1];
|
||||||
|
var sbColor = [1,1,1];
|
||||||
|
}
|
||||||
|
const bColor = [0.3,0.3,0.3];
|
||||||
|
|
||||||
const Font = [
|
const Font = [
|
||||||
[
|
[
|
||||||
|
|
@ -114,13 +138,19 @@ const Font = [
|
||||||
var dho = -1, eho = -1, dmo = -1, emo = -1;
|
var dho = -1, eho = -1, dmo = -1, emo = -1;
|
||||||
|
|
||||||
|
|
||||||
function drawHSeg(x1,y1,x2,y2,Num,dColor,Size) {
|
function drawHSeg(x1,y1,x2,y2,Num,Color,Size) {
|
||||||
g.setColor(0,0,0);
|
|
||||||
|
|
||||||
|
g.setColor(g.theme.bg);
|
||||||
g.fillRect(x1, y1, x2, y2);
|
g.fillRect(x1, y1, x2, y2);
|
||||||
for (let i = 1; i < 8; i++) {
|
for (let i = 1; i < 8; i++) {
|
||||||
for (let j = 1; j < 8; j++) {
|
for (let j = 1; j < 8; j++) {
|
||||||
if (Font[Num][j-1][i-1] == 1) {
|
if (Font[Num][j-1][i-1] == 1) {
|
||||||
g.setColor(dColor[0],dColor[1],dColor[2]);
|
if (Color == "fg") {
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
|
} else {
|
||||||
|
g.setColor(mColor[0],mColor[1],mColor[2]);
|
||||||
|
}
|
||||||
g.fillCircle(x1+Dx+(i-1)*(x2-x1)/7,y1+Dy+(j-1)*(y2-y1)/7,Size);
|
g.fillCircle(x1+Dx+(i-1)*(x2-x1)/7,y1+Dy+(j-1)*(y2-y1)/7,Size);
|
||||||
} else {
|
} else {
|
||||||
g.setColor(bColor[0],bColor[1],bColor[2]);
|
g.setColor(bColor[0],bColor[1],bColor[2]);
|
||||||
|
|
@ -131,11 +161,16 @@ function drawHSeg(x1,y1,x2,y2,Num,dColor,Size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function drawSSeg(x1,y1,x2,y2,Num,dColor,Size) {
|
function drawSSeg(x1,y1,x2,y2,Num,Color,Size) {
|
||||||
for (let i = 1; i < 8; i++) {
|
for (let i = 1; i < 8; i++) {
|
||||||
for (let j = 1; j < 8; j++) {
|
for (let j = 1; j < 8; j++) {
|
||||||
if (Font[Num][j-1][i-1] == 1) {
|
if (Font[Num][j-1][i-1] == 1) {
|
||||||
g.setColor(dColor[0],dColor[1],dColor[2]);
|
if (Color == "fg") {
|
||||||
|
g.setColor(sColor[0],sColor[1],sColor[2]);
|
||||||
|
} else {
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
|
//g.setColor(0.7,0.7,0.7);
|
||||||
|
}
|
||||||
g.fillCircle(x1+(i-1)*(x2-x1)/7,y1+(j-1)*(y2-y1)/7,Size);
|
g.fillCircle(x1+(i-1)*(x2-x1)/7,y1+(j-1)*(y2-y1)/7,Size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -143,25 +178,27 @@ function drawSSeg(x1,y1,x2,y2,Num,dColor,Size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function ShowSecons() {
|
function ShowSeconds() {
|
||||||
g.setColor(1,1,1);
|
|
||||||
g.fillRect((Xe-Xs) / 2 - 14 + Xs -3,
|
g.setColor(sbColor[0],sbColor[1],sbColor[2]);
|
||||||
(Ye-Ys) / 2 - 7 + Ys -3,
|
|
||||||
(Xe-Xs) / 2 + 14 + Xs +1,
|
g.fillRect((Xe-Xs) / 2 - 14 + Xs -4,
|
||||||
(Ye-Ys) / 2 + 7 + Ys +1);
|
(Ye-Ys) / 2 - 7 + Ys -4,
|
||||||
|
(Xe-Xs) / 2 + 14 + Xs +4,
|
||||||
|
(Ye-Ys) / 2 + 7 + Ys +4);
|
||||||
|
|
||||||
|
|
||||||
drawSSeg( (Xe-Xs) / 2 - 14 + Xs -1,
|
drawSSeg( (Xe-Xs) / 2 - 14 + Xs -1,
|
||||||
(Ye-Ys) / 2 - 7 + Ys ,
|
(Ye-Ys) / 2 - 7 + Ys +1,
|
||||||
(Xe-Xs) / 2 + Xs -1,
|
(Xe-Xs) / 2 + Xs -1,
|
||||||
(Ye-Ys) / 2 + 7 + Ys,
|
(Ye-Ys) / 2 + 7 + Ys +1,
|
||||||
ds,mColor,1);
|
ds,"fg",1);
|
||||||
|
|
||||||
drawSSeg( (Xe-Xs) / 2 + Xs +1,
|
drawSSeg( (Xe-Xs) / 2 + Xs +2,
|
||||||
(Ye-Ys) / 2 - 7 + Ys,
|
(Ye-Ys) / 2 - 7 + Ys +1,
|
||||||
(Xe-Xs) / 2 + 14 + Xs +1,
|
(Xe-Xs) / 2 + 14 + Xs +2,
|
||||||
(Ye-Ys) / 2 + 7 + Ys,
|
(Ye-Ys) / 2 + 7 + Ys +1,
|
||||||
es,mColor,1);
|
es,"fg",1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,29 +222,29 @@ function draw() {
|
||||||
g.reset();
|
g.reset();
|
||||||
if (dh != dho) {
|
if (dh != dho) {
|
||||||
g.setColor(1,1,1);
|
g.setColor(1,1,1);
|
||||||
drawHSeg(Xs, Ys, Xs+SegW, Ys+SegH,dh,hColor,4);
|
drawHSeg(Xs, Ys, Xs+SegW, Ys+SegH,dh,"fg",4);
|
||||||
dho = dh;
|
dho = dh;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eh != eho) {
|
if (eh != eho) {
|
||||||
g.setColor(1,1,1);
|
g.setColor(1,1,1);
|
||||||
drawHSeg(Xs+SegW+Dx, Ys, Xs+SegW*2, Ys+SegH,eh,hColor,4);
|
drawHSeg(Xs+SegW+Dx, Ys, Xs+SegW*2, Ys+SegH,eh,"fg",4);
|
||||||
eho = eh;
|
eho = eh;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dm != dmo) {
|
if (dm != dmo) {
|
||||||
g.setColor(0.3,0.3,1);
|
g.setColor(0.3,0.3,1);
|
||||||
drawHSeg(Xs, Ys+SegH+Dy, Xs+SegW, Ys+SegH*2,dm,mColor,4);
|
drawHSeg(Xs, Ys+SegH+Dy, Xs+SegW, Ys+SegH*2,dm,"",4);
|
||||||
dmo = dm;
|
dmo = dm;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (em != emo) {
|
if (em != emo) {
|
||||||
g.setColor(0.3,0.3,1);
|
g.setColor(0.3,0.3,1);
|
||||||
drawHSeg(Xs+SegW+Dx, Ys+SegH+Dy, Xs+SegW*2, Ys+SegH*2,em,mColor,4);
|
drawHSeg(Xs+SegW+Dx, Ys+SegH+Dy, Xs+SegW*2, Ys+SegH*2,em,"",4);
|
||||||
emo = em;
|
emo = em;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Bangle.isLocked()) ShowSecons();
|
if (!Bangle.isLocked()) ShowSeconds();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -278,7 +315,7 @@ function drawWidgeds() {
|
||||||
|
|
||||||
var x1M = 100;
|
var x1M = 100;
|
||||||
var y1M = y1B;
|
var y1M = y1B;
|
||||||
var x2M = x1M + 30;
|
var x2M = x1M + 25;
|
||||||
var y2M = y2B;
|
var y2M = y2B;
|
||||||
|
|
||||||
if (messages.some(m=>m.new)) {
|
if (messages.some(m=>m.new)) {
|
||||||
|
|
@ -295,6 +332,7 @@ function drawWidgeds() {
|
||||||
|
|
||||||
print(strDow[dow] + ' ' + day + '.' + month + ' ' + year);
|
print(strDow[dow] + ' ' + day + '.' + month + ' ' + year);
|
||||||
|
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
g.setFontAlign(-1, -1,0);
|
g.setFontAlign(-1, -1,0);
|
||||||
g.setFont("Vector", 20);
|
g.setFont("Vector", 20);
|
||||||
g.drawString(strDow[dow] + ' ' + day, 0, 0, true);
|
g.drawString(strDow[dow] + ' ' + day, 0, 0, true);
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,8 @@
|
||||||
(function(back) {
|
(function(back) {
|
||||||
|
|
||||||
let settings = Object.assign({ swupApp: "",swdownApp: "", swleftApp: "", swrightApp: ""}, require("Storage").readJSON("7x7dotsclock.json", true) || {});
|
let settings = Object.assign({ swupApp: "",swdownApp: "", swleftApp: "", swrightApp: "",ColorMinutes: ""}, require("Storage").readJSON("7x7dotsclock.json", true) || {});
|
||||||
|
|
||||||
|
|
||||||
function showMainMenu() {
|
|
||||||
const mainMenu = {
|
|
||||||
"": {"title": "7x7 Dots Clock Settings"},
|
|
||||||
"< Back": ()=>load(),
|
|
||||||
"sw-up": ()=>showSelAppMenu("swupApp"),
|
|
||||||
"sw-down": ()=>showSelAppMenu("swdownApp"),
|
|
||||||
"sw-left": ()=>showSelAppMenu("swleftApp"),
|
|
||||||
"sw-right": ()=>showSelAppMenu("swrightApp")
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
E.showMenu(mainMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSetting(key,value) {
|
function setSetting(key,value) {
|
||||||
print("call " + key + " = " + value);
|
print("call " + key + " = " + value);
|
||||||
|
|
@ -26,6 +13,42 @@ function setSetting(key,value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Helper method which uses int-based menu item for set of string values
|
||||||
|
function stringItems(key, startvalue, values) {
|
||||||
|
return {
|
||||||
|
value: (startvalue === undefined ? 0 : values.indexOf(startvalue)),
|
||||||
|
format: v => values[v],
|
||||||
|
min: 0,
|
||||||
|
max: values.length - 1,
|
||||||
|
wrap: true,
|
||||||
|
step: 1,
|
||||||
|
onchange: v => {
|
||||||
|
setSetting(key,values[v]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method which breaks string set settings down to local settings object
|
||||||
|
function stringInSettings(name, values) {
|
||||||
|
return stringItems(name,settings[name], values);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMainMenu() {
|
||||||
|
const mainMenu = {
|
||||||
|
"": {"title": "7x7 Dots Clock Settings"},
|
||||||
|
"< Back": ()=>load(),
|
||||||
|
"Minutes": stringInSettings("ColorMinutes", ["blue","pink","green","yellow"]),
|
||||||
|
"swipe-up": ()=>showSelAppMenu("swupApp"),
|
||||||
|
"swipe-down": ()=>showSelAppMenu("swdownApp"),
|
||||||
|
"swipe-left": ()=>showSelAppMenu("swleftApp"),
|
||||||
|
"swipe-right": ()=>showSelAppMenu("swrightApp")
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
E.showMenu(mainMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function showSelAppMenu(key) {
|
function showSelAppMenu(key) {
|
||||||
var Apps = require("Storage").list(/\.info$/)
|
var Apps = require("Storage").list(/\.info$/)
|
||||||
.map(app => {var a=storage.readJSON(app, 1);return (
|
.map(app => {var a=storage.readJSON(app, 1);return (
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
0.01: Initial version for upload
|
0.01: Initial version for upload
|
||||||
|
0.02: better theme support, configurable colors, small improvements
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,14 @@
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
looks best with dark theme so far
|
|
||||||
|
|
||||||
* A Clock with big numbers made of 7x7 dots
|
* A Clock with big numbers made of 7x7 dots
|
||||||
* system widgeds ar not (yet) supported
|
* system widgeds ar not (yet) supported
|
||||||
* when screen is locked it shows hours and minutes in full screen mode
|
* when screen is locked it shows hours and minutes in full screen mode
|
||||||
|
* adjustable color for minutes and seconds
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
* when screen is unlocked it shows additional info: bluetooth, battery, new message, date and seconds
|
* when screen is unlocked it shows additional info: bluetooth, battery, new message state, date and seconds
|
||||||
* you can configure a app per swipe direction
|
* you can configure an app per swipe direction
|
||||||
* when swiping the configured apps are launced
|
* when swiping the configured apps are launched
|
||||||
* button press opens launcher
|
* button press opens launcher
|
||||||
|
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
|
@ -1,17 +1,19 @@
|
||||||
{ "id": "7x7dotsclock",
|
{ "id": "7x7dotsclock",
|
||||||
"name": "7x7 Dots Clock",
|
"name": "7x7 Dots Clock",
|
||||||
"shortName":"7x7 Dots Clock",
|
"shortName":"7x7 Dots Clock",
|
||||||
"version":"0.01",
|
"version":"0.02",
|
||||||
"description": "A clock with a big 7x7 dots Font",
|
"description": "A clock with a big 7x7 dots Font",
|
||||||
"icon": "dotsfontclock.png",
|
"icon": "dotsfontclock.png",
|
||||||
"tags": "clock",
|
"tags": "clock",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
"supports" : ["BANGLEJS2"],
|
"supports" : ["BANGLEJS2"],
|
||||||
|
"allow_emulator": true,
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"},
|
{"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"},
|
||||||
{"name":"7x7dotsclock.settings.js","url":"7x7dotsclock.settings.js"},
|
{"name":"7x7dotsclock.settings.js","url":"7x7dotsclock.settings.js"},
|
||||||
{"name":"7x7dotsclock.img","url":"7x7dotsclock.img.js","evaluate":true}
|
{"name":"7x7dotsclock.img","url":"7x7dotsclock.img.js","evaluate":true}
|
||||||
],
|
],
|
||||||
"data": [{"name":"7x7dotsclock.json"}]
|
"data": [{"name":"7x7dotsclock.json"}],
|
||||||
|
"screenshots": [{"url":"dotsfontclock.png"},{"url":"dotsfontclock-scr1.png"},{"url":"dotsfontclock-scr2.png"}]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,4 @@
|
||||||
Widgets now shown on Alarm screen
|
Widgets now shown on Alarm screen
|
||||||
0.13: Alarm widget state now updates when setting/resetting an alarm
|
0.13: Alarm widget state now updates when setting/resetting an alarm
|
||||||
0.14: Order of 'back' menu item
|
0.14: Order of 'back' menu item
|
||||||
|
0.15: Fix hour/minute wrapping code for new menu system
|
||||||
|
|
|
||||||
|
|
@ -73,12 +73,12 @@ function editAlarm(alarmIndex) {
|
||||||
'': { 'title': /*LANG*/'Alarm' },
|
'': { 'title': /*LANG*/'Alarm' },
|
||||||
/*LANG*/'< Back' : showMainMenu,
|
/*LANG*/'< Back' : showMainMenu,
|
||||||
/*LANG*/'Hours': {
|
/*LANG*/'Hours': {
|
||||||
value: hrs,
|
value: hrs, min : 0, max : 23, wrap : true,
|
||||||
onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this'
|
onchange: v => hrs=v
|
||||||
},
|
},
|
||||||
/*LANG*/'Minutes': {
|
/*LANG*/'Minutes': {
|
||||||
value: mins,
|
value: mins, min : 0, max : 59, wrap : true,
|
||||||
onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this'
|
onchange: v => mins=v
|
||||||
},
|
},
|
||||||
/*LANG*/'Enabled': {
|
/*LANG*/'Enabled': {
|
||||||
value: en,
|
value: en,
|
||||||
|
|
@ -138,12 +138,12 @@ function editTimer(alarmIndex) {
|
||||||
const menu = {
|
const menu = {
|
||||||
'': { 'title': /*LANG*/'Timer' },
|
'': { 'title': /*LANG*/'Timer' },
|
||||||
/*LANG*/'Hours': {
|
/*LANG*/'Hours': {
|
||||||
value: hrs,
|
value: hrs, min : 0, max : 23, wrap : true,
|
||||||
onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this'
|
onchange: v => hrs=v
|
||||||
},
|
},
|
||||||
/*LANG*/'Minutes': {
|
/*LANG*/'Minutes': {
|
||||||
value: mins,
|
value: mins, min : 0, max : 59, wrap : true,
|
||||||
onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this'
|
onchange: v => mins=v
|
||||||
},
|
},
|
||||||
/*LANG*/'Enabled': {
|
/*LANG*/'Enabled': {
|
||||||
value: en,
|
value: en,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "alarm",
|
"id": "alarm",
|
||||||
"name": "Default Alarm & Timer",
|
"name": "Default Alarm & Timer",
|
||||||
"shortName": "Alarms",
|
"shortName": "Alarms",
|
||||||
"version": "0.14",
|
"version": "0.15",
|
||||||
"description": "Set and respond to alarms and timers",
|
"description": "Set and respond to alarms and timers",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"tags": "tool,alarm,widget",
|
"tags": "tool,alarm,widget",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
0.01: New App!
|
||||||
|
0.02: Icons, loading screen
|
||||||
|
0.03: Random icon, Shorter "loading" screen
|
||||||
|
0.04: Support for light and dark Themes
|
||||||
|
0.05: Small bugfix
|
||||||
|
0.06: Formatting
|
||||||
|
0.07: Added potato GLaDOS and quote functionality when you tap her
|
||||||
|
0.08: Fixed drawing issues with the quotes and added more
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Description
|
||||||
|
|
||||||
|
This is a simple clock based on the Portal Series.
|
||||||
|
|
||||||
|
# Features
|
||||||
|
|
||||||
|
The button in the center of the screen is interactable and the warning image will change when it is pressed.
|
||||||
|
|
||||||
|
Potato GLaDOS in the bottom left corner is interactable and will display a quote when tapped. (You can add more quotes by editing the `aptsciclkquotes.txt` file seperating each quote with a `^`)
|
||||||
|
|
||||||
|
When the app loads the Apeture Science Logo is displayed.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwgNKxAACEaIVDDKWAhAXGwAtODA4HBLR4YFD4QWICIhABGAoMBJRBZHC4wwHOQ4IFAgQwGUQ4YBAg4uMJIwDDGAjRLIgYLHc5gXJIwbKLC4hICb4gZKfAhgETJKHJLwwXRUooWKCImAJogXRMopGMNwkIC4oWLYYqtHC5rFJC5h0GIxwsGFyD8CC4wwOIxBIQFwoeBCxrwEFwYXTFgTXReI4uQC4apPC4xNERqBlGFx4XCeJ4nHD4kIIxY3KPoIxNBwYXEJRInEP44iGOgwXFBYYcDChCHHC4wMBC5BnJEoouMGAYXEJJCCJC4pOEcpYKBFIpJFZRQXGD4gWKXBUICxjdFIhwyJOJMAA="))
|
||||||
|
|
@ -0,0 +1,368 @@
|
||||||
|
const big = g.getWidth()>200;
|
||||||
|
const timeFontSize = big?5:4;
|
||||||
|
const dateFontSize = big?3:2;
|
||||||
|
const gmtFontSize = 2;
|
||||||
|
const font = "6x8";
|
||||||
|
|
||||||
|
const xyCenter = g.getWidth() / 2;
|
||||||
|
const yposTime = xyCenter*0.73;
|
||||||
|
const yposDate = xyCenter*0.48;
|
||||||
|
const yposYear = xyCenter*1.8;
|
||||||
|
|
||||||
|
const buttonTolerance = 20;
|
||||||
|
const buttonX = 88;
|
||||||
|
const buttonY = 104;
|
||||||
|
|
||||||
|
var pause = false; //set to true to pause any sort of drawing (except for quotes)
|
||||||
|
|
||||||
|
function getImg(img){
|
||||||
|
if (img == "w0"){//drink
|
||||||
|
return {
|
||||||
|
width : 60, height : 60, bpp : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOZFIQOD4EABwnwgEDBwf8g/4h4ODwYQBv4OC+AbDAIP+j/HAQIOC4Hwj4RBBwP8o8B/+PBwWOkEP/l/BwP4+JCB44OCj+Ih/+n4OB+PEoP38YOB/0YkUXGgIOB8cBi9f+IOCkEI+XvBwXigFG64OEg0/t4OEuP7BwkHx/PBwWigF8voOC+Uwg/ig4OCkMgv8QsIOB+cfSoOGLIUR/E/4ljBwPxx/B/0kO4UI/0P+J3C/HHVQOISoWEn+D/iPBBwIwC8IOCwcP84IBBwU4TAMHBwfAv+AcARBBgD3CBwX8gDnBBwfwewIODAgIABBwYHDB3oAEBwIHFByyDBABg"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (img == "w1"){//cube dispenser
|
||||||
|
return {
|
||||||
|
width : 60, height : 60, bpp : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOI/3/+fvBwYEBnwO/By3APgN/O6IeBh4OF8AOcwADCBwX8g4dM/8fBwt774OE+/9Bwt/BxodH3oOcFgyVG8BhCBwX8hRwCBwXA0C6BBwc/w4OE41MBwtEo6VF84sE/1/54OLDo4sHHYxKHLIxoGO44AD/kAABo"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (img == "w2"){//acid
|
||||||
|
return {
|
||||||
|
width : 60, height : 60, bpp : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOF+IOGngOF8/D8YGD/wdBB4nv4fzAwf4BwOfGQd/4f7/+//+f74OB4PwHIJKDx8P/4BBBwP8BwIBBBwXvh+Hw5ZD+Pwnl/NAcegJOBBwfgj0fBwvhBxcPgYEBBwXw/F+FghIB84OC/BfBOYQOBk/w/0f4f4nkGgFgh0hwED4H4jOBuF8hk/v/Hzlnx/zFgQZBGYLCD4EHaIn8gAOF8EDBwn+dgQOK/8AN4IOD+EABww0BBwqGEBwIWBBwk8CwIODg/gv4OEv4OD+4OBBAIOBRYIFBh+PcAQdC+gOCDoN+h/vBwPP/wOB/wOBwJCBBwP2oa3BLALgBiA7BOwIvB/+DQoV/d4hPBBwQsB/wJB8ZoEAAZoDAAQOPRQIAM"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (img == "w3"){//turret
|
||||||
|
return {
|
||||||
|
width : 60, height : 60, bpp : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOi+IOGh4OF8AOF/UNBwthx4OE+0YBwtBh4OE6mQBwn7rEfBwl22IOE99gBwn99UzBwUc/+90YsC8HH+++n98n/+g0++2Z+4OB4Fz73T74OCg877d8/YdC+d7u/v3gsBjEvt/+O4X+gvtIgI7CwG934OD8E326kD/0A+yzEwEO74OD/EArYOEgEDv4OD+PAl4OEnkBaInz0EPBwk3iAdE+XwSIYDBj2Oj4OD/fYvIOEvdHz4OD99unIOD/vt44OE3u4Dou3h4OE+3x/IOE70/Bwn78/9Bwl4LAQ7Dx75DBwP4Awb+EBwgAEBz0AABo="))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (img == "w4"){//falling cube
|
||||||
|
return {
|
||||||
|
width : 60, height : 60, bpp : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOC+YOF/0PBwvgv4OE/kFBwvAyIdFnYeBBwYeDDofng4OE8vYDonx7uPBwkf/+/Bwfh+czBwf+g/5z4OD+FevIdEhMDDon/0E3BwgeBJQgeB+5ZFvAEBBwfzgYOEw/XLInwn3BBwf8gH4LYIOCwUHDonwmE4HYkHwKkE8P4XYQOCv7dCYQkBWYsAWYvAiAsE/EDJQn/wF+CwJZDg/gBwgrBXYIOC8D+FNAL+F4eDBwn4nh2BBweHFYJ3EFYQOC/0P/AOECgIOE/E/BwsHBwvACAIODWAQOEJAIOFAgIOEQ4QsEAAOfBwoACBwgACBw8AABo"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (img == "w5"){//ball
|
||||||
|
return {
|
||||||
|
width : 60, height : 60, bpp : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOiv4OF8YOFAgQOEyYdGBw3zBw0BBwv4j4OB+EAgOD84OE+/ev4dD/3+BwvcugsE/u7t0f4aRC7e2sF8Bwlxg4dEu8YBwYsB/HDHYsMngOB8EDweHDon//PADoYABz0PBwfwnJKE/0OjZZC/kB4Hxz4OCwEYh+wBwXwgeA/+HBwUP8EP/0/BwPj/0DCQIOB/l/4DQBw4OBDIMPUoJKB+H/wY+B44OBj/4CoJKC+P/g7+FBAL+Fj4OFbwIOEI4IOF8YO6JQwAEaIgORgAANA"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (img == "w6"){//ball recviver
|
||||||
|
return {
|
||||||
|
width : 60, height : 60, bpp : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOR/YOG34Ob/e7Bwu7CwQOhGgQOD34OF/0LBwvfv4dMuPfBwn29oOFtwONDowsHHY3+h7CNj4OF+IOc4A7NDo7gGJQ4ACBwX+//vBwnvBAIOK8EH/kBBwd+v/PSwIOB/fnjiWBBwXesHPLQIOB/2AgEvBwfgh0AFgf8gAuBLKQObgAANA=="))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (img == "w7"){//falling portals
|
||||||
|
return {
|
||||||
|
width : 60, height : 60, bpp : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AB0//4AE4YFE/H8BwtvBwvvvgOE/33Bwvf3gOE/v7Bxn5Bw2fHYv7/oOF3/cB118JQQOC4ODJQn8jEfLInBjBoE/0jO4pjD953CwCVF/EH5//+ykCwA8Cp4OB/MDz4DBEQUYjPzaIfn5k/74xC/l44f+BwePz1595ADDYPvv7vDMAN3Bwf4CAIOE4//BYIOB/0On47E8AFCBwcPTwYOCAgPAgE8Bwf8gEDBwOAGIJZDBwX9DofhUYRKDKIIOEAAQOD8EABwgcB+IODnoKB84OD37tCBwUzZ4QODZ4QdDnIFB/YODZwP+v47DJIIBBJQcAAwZyBABoA=="))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (img == "w8"){//flying portals
|
||||||
|
return {
|
||||||
|
width : 60, height : 60, bpp : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AB0//4AE4YFE/H8BwtvBwvvvgOE/33Bwvf3gdF/YOF/4OF/IOGgA7F8ENBwn8gHcBw/5AoOAg4OCh4sD/vD+AFB45KBBwfwv//BwMJgEIFAXcnvggF4kEBBwPMSIIYBz/8nAEBw5ZD4IhBO48AhpoG953FSo/2Ugv/p4OF/LCGaIyIBB34OH4EAngODbAMDBwnfDoqeCBy7RBBwnh//xBwc9BQPnBwe/AYO/BwUzFYQODGgYOCnIFB/YOD57WBv47Dj//AIJKDgAGDOQIANA"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (img == "w9"){//cake
|
||||||
|
return {
|
||||||
|
width : 60, height : 60, bpp : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AB0//4AE4YGF/gOY/oOG94OF/1/Bwv3FgwKCBwfnFhn8HY0LAQPwvgOB8EP/5uBBwP2gF4j+PBwP+sEEj/x44OB90Ao/8Dodwg8/nkH4ZXBgHnx8ABwPv/k98+ABwZEB+EAJQPj/3+nkAv4OB5+fz0Aj4OB98Ag+Ah/nBwJXB4EDHYSTB/EA/wsCSoJfBwAODNIPgBwgcBHYQOCC4QODn8Ah4ODGgMH+47D8EB/A7KTYMf4A7Eg/wHYgcBHZx3DcAPggbRBFgQcBcAQOB/iUBBwgcBBwgcCd4V/HYL+D/YOBDgIOC8/+DgIOC/+HfwIOD/4cCBwYAEBwQADBz0AABoA="))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (img == "butPress"){
|
||||||
|
return {
|
||||||
|
width : 176, height : 176, bpp : 4,
|
||||||
|
transparent : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("iIA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AFEc5kM5hD/ACXMAAJXB5nBI35WSK4ZY/AB8cK4/MJP5WRK4pY/ABhPD5e7he7A4fBJn5XNKwJXCLAZX/ABUcKwhXDLAZN/VxhSCK4m8WH5XNVwZXEWARX/ABEcK4sAgBYDXYRP/K5RQC2ACE3e8K/5XPVgYDCK/4AKJIPLVYoEEBoPBIWPd6ICPK46uDAohXzjvd7oCMCAJX/K7cAAAZXFBQkBK/6v/ABPd6ICPK/4AaK4mwKwYEDV+4ARjhKBVQoDD3gMBK2MdAIRXXVYSuDK/5XN5ZRCgEAWQYLBK/4AJK4u7KwZXC4JXxiPd6JXV5hXH3hX1ACscWApXDMQRN/WBpYCK4QICV35XOLARXBA4ZX/ABccKAfMhgFEJf5YRK4hJ/ABxXH4JI/LCRXCK34ASjhXCIf4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/ACIA=="))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (img == "butUnpress"){
|
||||||
|
return {
|
||||||
|
width : 176, height : 176, bpp : 4,
|
||||||
|
transparent : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("iIA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AFEc5kM5hD/ACXMAAJXB5nBI35WSK4ZY/AB8cK4/MJP5WRK4pY/ABhQEK43BJn5X/AEMcK5fMJv6uPK46w/K/4AgjhPFgEALAxP/K5vAAQhX/K6KsDWApP/AA6uHWA/BIWOIwICPK46qFAohXxjGIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIwICPK/4AaKInAAhCv2ACMcVRC0FK2MYAIRXXVYSuFK/5XO5kAgCuFK/4AJJwvMKw3BK+MRxGBK/4ArjhXMJv6wQK4qu/K/4AjjhXKJf5YRK4hJ/ABxXH4JI/LCRXCK34ASjhXCIf4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/ACI="))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (img == "apetureLaboratories"){
|
||||||
|
return {
|
||||||
|
width : 173, height : 43, bpp : 4,
|
||||||
|
transparent : 0,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AA+IAAeAIv5UTK34APhABBKwpeBJX5VLJgJWGAwKv/ABL8EKomABIYA/KpJWHAoRW/KpZQCfwJSCAgRW/KphWFBgZW/KphNCAgSxEKP4ADJAatFKwWAL4oA/KpALGXQhS/Ko4MIwAOMAHREOKv5ZVVgcAh///4LDAwQAB+AIHCQYHMDQQYBDwQEGDIoaGTx4MCwAiCJgYhFBIYIHLw4HFBARjGESJUDehZVFVhJNLRI5VGDIIdEAgwiL+DzDJAJVJB4IMBCoKsHAYpFCDgr2IApYEIBpJFCKpqsCHgQbFIhBVHBhJoGTwyBRKp5mBDoY6GKoYqEXYg7JApKeHQJysEKpRmBDoasHQBAACM4qMGEAr0JAgZjGFYhVPgGAEIpVEAAaAEA4oyEW4qyKFZBoFKoisDJIJWLfIp3IQBJeJfgysMERpVCwEIVpijFBA6ZJdA4JHJYgEKQIx1EVgRVBVhj5IEIyZHHYoUGNw4MCQIwIKAARVDxBVRQo6ZJHZZoGU4yBGBAiBGVgRZBVhYlIfJBoFHZZoHfJRwGBAQrEVISvCKpwrEUZAqFVhzYKB4yKGQIpVDAYJVKEoYFDBIpVIb4ysMIgoPHOgoRFhGAVwKsLAFzQHACBVCVhQA/KpawBCJa76IhRWDVxIODAwTaFAocP///dhALGBQYJBCIYQBDYgKEBBAEDVgeIAgKgFBYZVEEYY+CH4YDBBgYFBBYoFEOYhmEDYgFFLIwEDKw2AKwhTFBoSsHIgglFAQo/HKIoDECBBZGc46eEAYa2EKox2Ga5LjLDoq8FKAgVDBAv/EghWGVgRWJKoaOFD4IgCViAWFVjKTGJIZOFKpKOHAQj3JAogCFPApcGKQziGLopKCU4hWFKojsEHYrXFCAJFId45CEDYh4EB4Y1DCYSzFJQT+FgAGCKooA/AAZMBfopWDKv5WLVgxT/AB+AKopW/ACBU/ABwA=="))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (img == "apetureLaboratoriesLight"){
|
||||||
|
return {
|
||||||
|
width : 173, height : 43, bpp : 4,
|
||||||
|
transparent : 1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("iIAGxAADwINHAH5ULK34APjABBKwpeBJX5VLJgJWGAwKv/ABL8EKomBBIYA/KpJWHAoRW/KpZQCfwJSCAgRW/KphWFBgZW/KphNCAgSxEKP4ADJAatFKwWBL4oA/KpALGXQhS/Ko4MIwIOMAHREOKv5ZVVgcRiEAgALDAwQABgIIHCQYHMDQQYBDwQEGDIoaGTx4MCwIiCJgYhFBIYIHLw4HFBARjGESJUDehZVFVhJNLRI5VGDIIdEAgwiLgLzDJAJVJB4IMBCoKsHAYpFCDgr2IApYEIBpJFCKpqsCHgQbFIhBVHBhJoGTwyBRKp5mBDoY6GKoYqEXYg7JApKeHQJysEKpRmBDoasHQBAACM4qMGEAr0JAgZjGFYhVPiOBEIpVEAAaAEA4oyEW4qyKFZBoFKoisDJIJWLfIp3IQBJeJfgysMERpVCwMYVpijFBA6ZJdA4JHJYgEKQIx1EVgRVBVhj5IEIyZHHYoUGNw4MCQIwIKAARVDxBVRQo6ZJHZZoGU4yBGBAiBGVgRZBVhYlIfJBoFHZZoHfJRwGBAQrEVISvCKpwrEUZAqFVhzYKB4yKGQIpVDAYJVKEoYFDBIpVIb4ysMIgoPHOgoRFjGBVwKsLAFzQHACBVCVhQA/KpawBCJa76IhRWDVxIODAwTaFAocQgEAdhALGBQYJBCIYQBDYgKEBBAEDVgeIAgKgFBYZVEEYY+CH4YDBBgYFBBYoFEOYhmEDYgFFLIwEDKw2BKwhTFBoSsHIgglFAQo/HKIoDECBBZGc46eEAYa2EKox2Ga5LjLDoq8FKAgVDBAsAEghWGVgRWJKoaOFD4IgCViAWFVjKTGJIZOFKpKOHAQj3JAogCFPApcGKQziGLopKCU4hWFKojsEHYrXFCAJFId45CEDYh4EB4Y1DCYSzFJQT+FiIGCKooA/AAZMBfopWDKv5WLVgxT/AB+BKopW/ACBU/ABsQA="))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (img == "potato"){
|
||||||
|
return {
|
||||||
|
width : 54, height : 55, bpp : 4,
|
||||||
|
transparent : 6,
|
||||||
|
buffer : require("heatshrink").decompress(atob("swAEsEGA4oASEQ4ARGgNgDa8QsA3BKStowxTDDalikxTCRKsSNwY2BDSYvDGoI2TsoTDgwEBGx5IBs1VHIgaBGx4qCDQZOBUiUGstQDQ4FBKYwHGDQNWDRA3BCYsABotgJ4dkogABowcGAAUGOwogDDAVCAYScKOooFBooWCAAjqNAoQYHKYQ8ELQZzFsAMCiIeJAAdFMwiCEoIaNoICBoAaMiMUDA0ikMiigaIAAgaGDIIaBkcyoCHEMxqIBmdEkMzmcxDSVBkYXBGoMzmUQDSMSDIURiIbBkDBCDRtBiYwBDIMREAMiDR6qBiI0BkQEBKQKkBUJQAEoCfBC4MVgMSDYMkGwQaBeBMUiC3BGYNN8kSHgM0DQrsGAAMQQAMyCwIaBgK/BmIaKM4IGCiMTDQXd9waCmlENZIaEgESKAMhpxQEDQSiEoJTGiEimaGCqIaBmKABUQwyBUIzRBkIXBDoI8BkAaDGwgaFEIMCeQUSYAKNBmLYDGwJ/DDYlFqAaBGwILBGgLyBUIRSFQghrCgEjDYMiiTdCggaFDYgaFKIKIBmcTkciiA1GNwpsFgI4BmZsBkVEDRAbJiBTCNQMABIIZHfBCPBDQKSCoFEGhA2IKIMQgJ1CoCFHGxVBeASQDgAZJDQ8RQIMyDQkGDZQ1GDILtBAwNGsAaLs1hokECYNCaQMxDIVmDRoOBDQifCBggaNKgMRqUhiovFGxoMEsCADAQQaMsUWJBi+LsMRqtWDSwUBqvFqpVFQ54UCstVqEGsDbBQx4lFgAABotRAgQABT54ADqtRM5jjQAAQ"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (img == "apetureWatch"){
|
||||||
|
return {
|
||||||
|
width : 176, height : 176, bpp : 4,
|
||||||
|
transparent : 2,
|
||||||
|
buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+/4A/AH4A/AH4A/AD0RgAASgMQCqgrqiJX/K/5X/K/5XR7vQK/8IxBX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5Xah////wK/5XTKwIABK4YAG//x7vRBhAA2jGIAYMfK4fxCRAOCK/5XFKwYABBgTBEh4LC7vQbabxLFYoVPFZMIxADBK4sAK4wLDK/5XSBYhX/K6MPBIQDBK/5XD+BXMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XF+CuEK4yuCK/5XHWAZOCK4cPKwhX/K45MFK4YAGK/5XGLApX/K6X/K5sPK/5XIWAZXJ/5X/K6sPK/5XPAoauDK/5XJ/5XDj5eEVwRX/K5y2FVwRX/K4/wK44GDVwRX/K50fWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGAoKkCK4arEK/5XIVQRQDK/5XQAwZLC+BXBAwYACLwJX/K4auCWApXHCAJX/K5JYFAoi/Ch5X/K4ZHCAAZXEAoZnCK/5XLVQRXFBgZX/K4igCLAnxFYRdBBohX/K5cAiIrJK/5XEfIhX/K/5Xr+BX/K/5Xu/5X/K/5WKFhRXWl5XB+BX/K6ywFK9XxK4SMFK7JWCK58PK7sP/5XDGoxXr/5Xc//4xBXEHIKyPK54fFK5CPBK7cPxAyBK4oHBK7wKFK5AQBK7UP/GPD4JWCiMfK4IJBK7jOGFgYwEK4XRBg4AQ/CtFAAZXCBQ4AQjBXCCRxXcUoJLDjnMhnMBgTqCK7RzJYYxXC6DbTAAf4UYInB5gABK4PM4KBDdYwrQhBXBBQ5XIAAJXYh6GDKwRXDLASwCK7BxIK8auDjhXH5iwPK5gKIK8iuBKwhXFLAJX/AA0PxCuBKAhXG4KwCK/6uEx/xK5qwNK/KuBjhXL5kRWAJXrbapXEJ4pXH4JXXABRXhh+I+JXPiP//5X/K4WP+McJ4oLBLAxX/K5vAAQhX/ABBDBiJXFVgawFiMf//wK/4gBAAKuHWA/BCYQhIK8uIwACOK5CqFAohXxhGIxACMCAJX/K7YaEK4pKFK/6v/ABOIwACOK/4AMFZRXI4AEIV+wrO///iMcVRC0FiMf//wQaZXZhABCFZ0P//xK4qrCVwpXB/+PbahX15gLBVwpX/K5ERJwvMKw3BiP4K98AxGAFaH//5XPj/4+BXvFaRXCjhXMiMfxBXhGoIAcK4nxWAxXF4MR/GPK4Q4e+UiADcvK4UPWARXMj/4NwayKACUPK8KwDjhXKcQOIKYZX/eIkRLAhXEiKuBx5XEY4QAYDgJXiIAXxiJXH4KuC/4VDK/6wGLAZXCKwKuGK/6wIiMcK4QFBVw5X/WA2IwJSCAAYJBVwpX/WA2IJwJVDj///GPVwpX/LA34K4PxVoYHBKwxX/AAynCK4ZWC+BX/K5ixB/6vEVo5X/IxAABK4asHK/5XLgJXCBxRX/K/5XgLAQNLK/5X/K6r7CACxX/K/5XVfJcBiINLK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K5o6bK/YaZK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K6o6bK/cAABUBiINLK/5X/K/5X/K/5X/K/AMLACBX/K7DMaAAcRADA4eA=="))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (img == "apetureWatchLight"){
|
||||||
|
return {
|
||||||
|
width : 176, height : 176, bpp : 4,
|
||||||
|
transparent : 2,
|
||||||
|
buffer : require("heatshrink").decompress(atob("kQA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+gAA/AH4A/AH4A/AD0R/4AS+MfCqgrqiJX/K/5X/K/5XR7vfK//4xBX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5Xa+EAgEPK/5XTKwIABK4YAGgEB7vRBhAA2jGIAYMQK4cBCRAOCK/5XFKwYABBgTBE+ALC7vfbabxLFYoVPFZP4xADBK4v/K4wLDK/5XSBYhX/K6PwBIQDBK/5XDh5XMBAQQCK/5XDKAJXKVwRWBAoJX/K4j3CUohXDL4YACK/5XFh6uEK4yuCK/5XHWAZOCK4fwKwhX/K45MFK4YAGK/5XGLApX/K6UAK5vwK/5XIWAZXJgBX/K6vwK/5XPAoauDK/5XJgBXDiBeEVwRX/K5y2FVwRX/K48PK44GDVwRX/K50QWAi9DK/5XGUYRQCiKwCAwKuDK/5XGJgZXGMQJWDK/5XGAoKkCK4arEK/5XIVQRQDK/5XQAwZLCh5XBAwYACLwJX/K4auCWApXHCAJX/K5JYFAoi/C+BX/K4ZHCAAZXEAoZnCK/5XLVQRXFBgZX/K4igCLAkBFYRdBBohX/K5f/iIrJK/5XEfIhX/K/5Xrh5X/K/5XugBX/K/5WKFhRXWkBXBh5XvgJXCGgpXcWApXoF4KvD+COGK65WCK5/wK7gtCK4YmCLB5XfgBXbFgIzBK4mILCBXPDwpXIcIJXa+BPBKAJXFLARXdBQpXICAJXah/4x4qDAAMfK4IJBWBpXODgwsDAAcQK4XRBg4APgAwBVogADK4XwgInWjBXCCRxXbiD9BKwcc5kM5gNCRgXwK7JyJYYxXC77bTIwf4UYInB5gABK4PM4MRDQXwDpYrKawMABQ5XIAAJXYh6uDKwRXDLAQRDK64YIK8SuEjhXH5iwPK5gKIK8UP/APBKwhXFLAKwNK/ItBiJQEK43BDgRX/AAXw/GP+JXNGQXwK/5XDEgMcK5fMiIdBK9YAKK5cPK4RPFK4/BDoUPFagAJK8WI+JXPGYRX/IIWP+McJ4sAgBYGK/5XN4ACEK/4AH+AjCK4qsDWAsRDwIWCK/ogBAAKuHWA/BCYQhIK8uIx4COK5CqFAohXx/GIxACMCAJX/K7cAAAZXFBQkBK/6v/ABOIx4COK/4AMFZRXI4AEIV+wrN+AjCjiqIWgpUCCwRXr/ABCFZ0PBoJXFVYSuFK4P/x4VBK/5XI5kAgCuFK/5XIiJOF5hWG4MR/BXv/+Ix5XREgJXOj58BK94rR+AkCjhXMiMfxAUCK70AADpXE+KwGK4vBiP4x5XhgUiADcgEQTyCK5sf/ATDK/5DD+McK5UR/+IK/5XEeYcRLAhXEiKuBx4SDK/6wFiJXH4KuOK/SwELAZXCKwKuOK/ywBiMcK4QFBVwZX/K43/gACBxGBKQQADBIKuBh5X/K43/JAOIJwJVDIYP4x4NCK/5XHfAP4K4PxVoYHBBgRX/K5H/gCnCK4ZWDVxpX9LARABV4ZWQK/xYBgBXD+EAKx5X/AAMBK4RVQK/5ADK4RBSK/5YDIKZX/K/5XNfYQA1K/5X2eJkReKfxj4VTK/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5XvgAAYh5X8DTJX/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5X/K/5XVgAAYK/orL+MRIKZX/K/5X/K/5X/K/5X/K/5XmgAAdiIA3"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function drawStart(){
|
||||||
|
g.clear();
|
||||||
|
g.reset();
|
||||||
|
if (g.theme.dark){apSciLab = getImg("apetureLaboratories");}
|
||||||
|
else {apSciLab = getImg("apetureLaboratoriesLight");}
|
||||||
|
g.drawImage(apSciLab, xyCenter-apSciLab.width/2, xyCenter-apSciLab.height/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check settings for what type our clock should be
|
||||||
|
var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"];
|
||||||
|
|
||||||
|
// timeout used to update every minute
|
||||||
|
var drawTimeout;
|
||||||
|
|
||||||
|
//warnings
|
||||||
|
var maxWarning = 9;
|
||||||
|
var curWarning = Math.floor(Math.random() * (maxWarning+1));
|
||||||
|
|
||||||
|
function unPause(delay, quote){
|
||||||
|
if (pause){
|
||||||
|
setTimeout(function() {
|
||||||
|
if (quote == undefined || quoteNum == quote){
|
||||||
|
pause = false;
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var quoteNum;
|
||||||
|
|
||||||
|
function quote(fontsize, width, height, specificQuote){
|
||||||
|
pause = true;
|
||||||
|
var finalString = "";
|
||||||
|
var quotesFile;
|
||||||
|
var finalFontSize;
|
||||||
|
quotesFile = require("Storage").read("aptsciclkquotes.txt", 0, 0); //opens the quotes file
|
||||||
|
//console.log(quotesFile);
|
||||||
|
var quotes = quotesFile.split("^");
|
||||||
|
var numQuotes = quotes.length;//number of quotes
|
||||||
|
var curQuote;
|
||||||
|
|
||||||
|
if (specificQuote == undefined){
|
||||||
|
quoteNum = Math.round(Math.random()*numQuotes)-1;
|
||||||
|
curQuote = quotes[quoteNum]; //quote to be displayed
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
quoteNum = specificQuote;
|
||||||
|
curQuote = quotes[quoteNum];
|
||||||
|
}
|
||||||
|
|
||||||
|
unPause(10000, quoteNum);
|
||||||
|
|
||||||
|
var curWords = curQuote.split(" "); //individual words
|
||||||
|
//console.log(numQuotes);
|
||||||
|
|
||||||
|
var maxChar = width/6/fontsize;
|
||||||
|
var maxLines = height/10/fontsize;
|
||||||
|
var curLines = 0;
|
||||||
|
var curLength = 0;
|
||||||
|
|
||||||
|
|
||||||
|
for (var i = 0; i < curWords.length; i++){
|
||||||
|
//console.log(curLength+curWords[i].length);
|
||||||
|
if (curLength + curWords[i].length <= maxChar){
|
||||||
|
finalString += " "+curWords[i];
|
||||||
|
curLength += curWords[i].length+1;
|
||||||
|
//console.log("next");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//console.log("break");
|
||||||
|
curLines++;
|
||||||
|
if (curLines > maxLines){
|
||||||
|
curLength = 0;
|
||||||
|
finalString = "";
|
||||||
|
i = -1;
|
||||||
|
if (fontsize > 1){fontsize--;}
|
||||||
|
maxChar = width/6/fontsize;
|
||||||
|
maxLines = height/10/fontsize;
|
||||||
|
console.log(maxLines);
|
||||||
|
console.log(maxChar);
|
||||||
|
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
curLength = 0;
|
||||||
|
finalString += "\n";
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finalFontSize = fontsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//drawing actual stuff
|
||||||
|
g.setColor(g.getBgColor());
|
||||||
|
g.fillRect(10, 10+28, g.getWidth()-10,g.getWidth()-10);
|
||||||
|
g.reset();
|
||||||
|
g.setFont(font, finalFontSize);
|
||||||
|
g.setFontAlign(0, 0);
|
||||||
|
g.drawString(finalString, xyCenter, xyCenter+14);
|
||||||
|
//quote length*pixels per character = pixel width
|
||||||
|
//height ~120 width ~160
|
||||||
|
}
|
||||||
|
|
||||||
|
function buttonPressed(){
|
||||||
|
if (curWarning < maxWarning) curWarning += 1;
|
||||||
|
else curWarning = 0;
|
||||||
|
g.reset();
|
||||||
|
buttonImg = getImg("butPress");
|
||||||
|
g.drawImage(buttonImg, 0, 0);
|
||||||
|
|
||||||
|
warningImg = getImg("w"+String(curWarning));
|
||||||
|
g.drawImage(warningImg, 1, g.getWidth()-61);
|
||||||
|
|
||||||
|
setTimeout(buttonUnpressed, 500);
|
||||||
|
}
|
||||||
|
function buttonUnpressed(){
|
||||||
|
if (!pause){
|
||||||
|
buttonImg = getImg("butUnpress");
|
||||||
|
g.drawImage(buttonImg, 0, 0);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
setTimeout(buttonUnpressed, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// schedule a draw for the next minute
|
||||||
|
function queueDraw() {
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
drawTimeout = setTimeout(function() {
|
||||||
|
drawTimeout = undefined;
|
||||||
|
draw();
|
||||||
|
}, 60000 - (Date.now() % 60000));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
if (pause){}
|
||||||
|
else{
|
||||||
|
// get date
|
||||||
|
var d = new Date();
|
||||||
|
var da = d.toString().split(" ");
|
||||||
|
|
||||||
|
g.reset(); // default draw styles
|
||||||
|
//draw watchface
|
||||||
|
if (g.theme.dark){apSciWatch = getImg("apetureWatch");}
|
||||||
|
else {apSciWatch = getImg("apetureWatchLight");}
|
||||||
|
g.drawImage(apSciWatch, xyCenter-apSciWatch.width/2, xyCenter-apSciWatch.height/2);
|
||||||
|
|
||||||
|
potato = getImg("potato");
|
||||||
|
g.drawImage(potato, 118, 118);
|
||||||
|
|
||||||
|
g.drawImage(warningImg, 1, g.getWidth()-61);//update warning
|
||||||
|
|
||||||
|
// drawString centered
|
||||||
|
g.setFontAlign(0, 0);
|
||||||
|
|
||||||
|
// draw time
|
||||||
|
var time = da[4].substr(0, 5).split(":");
|
||||||
|
var hours = time[0],
|
||||||
|
minutes = time[1];
|
||||||
|
var meridian = "";
|
||||||
|
if (is12Hour) {
|
||||||
|
hours = parseInt(hours,10);
|
||||||
|
meridian = "AM";
|
||||||
|
if (hours == 0) {
|
||||||
|
hours = 12;
|
||||||
|
meridian = "AM";
|
||||||
|
} else if (hours >= 12) {
|
||||||
|
meridian = "PM";
|
||||||
|
if (hours>12) hours -= 12;
|
||||||
|
}
|
||||||
|
hours = (" "+hours).substr(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
g.setFont(font, timeFontSize);
|
||||||
|
g.drawString(`${hours}:${minutes}`, xyCenter+2, yposTime, false);
|
||||||
|
g.setFont(font, gmtFontSize);
|
||||||
|
g.drawString(meridian, xyCenter + 102, yposTime + 10, true);
|
||||||
|
|
||||||
|
// draw Day, name of month, Date
|
||||||
|
var date = [da[0], da[1], da[2]].join(" ");
|
||||||
|
g.setFont(font, dateFontSize);
|
||||||
|
g.drawString(String(date), xyCenter, yposDate, false);
|
||||||
|
|
||||||
|
|
||||||
|
// draw year
|
||||||
|
g.setFont(font, dateFontSize);
|
||||||
|
g.drawString(d.getFullYear(), xyCenter+1, yposYear, true);
|
||||||
|
}
|
||||||
|
queueDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Stop updates when LCD is off, restart when on
|
||||||
|
Bangle.on('lcdPower',on=>{
|
||||||
|
if (on) {
|
||||||
|
draw(); // draw immediately, queue redraw
|
||||||
|
} else { // stop draw timer
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
drawTimeout = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bangle.on('touch',(n,e)=>{
|
||||||
|
//button is 88 104
|
||||||
|
if (!pause && buttonX-buttonTolerance < e.x && e.x < buttonX+buttonTolerance && buttonY-buttonTolerance < e.y && e.y < buttonY+buttonTolerance){
|
||||||
|
buttonPressed();
|
||||||
|
}
|
||||||
|
//Potato GLaDOS
|
||||||
|
else if (!pause && 117 < e.x && e.x < 172 && 117 < e.y && e.y < 172){
|
||||||
|
quote(2, 150, 140);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
unPause(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//show Apeture laboritories
|
||||||
|
drawStart();
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
// clean app screen
|
||||||
|
g.clear();
|
||||||
|
// Show launcher when button pressed
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
//update warning image
|
||||||
|
buttonPressed();
|
||||||
|
// draw now
|
||||||
|
draw();
|
||||||
|
}, 500);
|
||||||
|
After Width: | Height: | Size: 714 B |
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"id": "aptsciclk",
|
||||||
|
"name": "Apeture Science Clock",
|
||||||
|
"shortName":"AptSci Clock",
|
||||||
|
"version": "0.08",
|
||||||
|
"description": "A clock based on the portal series",
|
||||||
|
"icon": "app.png",
|
||||||
|
"type": "clock",
|
||||||
|
"tags": "clock",
|
||||||
|
"supports": ["BANGLEJS2"],
|
||||||
|
"allow_emulator": false,
|
||||||
|
"readme":"README.md",
|
||||||
|
"storage": [
|
||||||
|
{"name":"aptsciclkquotes.txt","url":"quotes.txt"},
|
||||||
|
{"name":"aptsciclk.app.js","url":"app.js"},
|
||||||
|
{"name":"aptsciclk.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Well here we are again^You euthanized your faithful Companion Cube more quickly than any test subject on record. Congratulations.^So get comfortable while I warm up the neurotoxin emitters^This isn't brave. It's murder. What did I ever do to you?^The difference between us is that I can feel pain.^Who's gonna make the cake when I'm gone? You?^Oh... It's you.^I've been really busy being dead. You know, after you MURDERED ME.^So. How are you holding up? BECAUSE I'M A POTATO.^You really do have brain damage, don't you?^You like revenge, right? Everybody likes revenge. Well, let's go get some.^It's been fun. Don't come back.^And then you showed up. You dangerous, mute lunatic.^Unbelievable. You, [subject name here] must be the pride of [subject hometown here.]^You are not a good person. You know that, right? Good people don't get up here.^Cake, and grief counseling, will be available at the conclusion of the test.^This is your fault. I'm going to kill you. And all the cake is gone. You don't even care, do you?^Momentum, a function of mass and velocity, is conserved between portals. In layman's terms, speedy thing goes in, speedy thing comes out.
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
node_modules/
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
0.01: First release
|
|
||||||
0.02: Bugfix time: Reset minutes to 0 when hitting 60
|
|
||||||
0.03: Fix distance >=10 km (fix #529)
|
|
||||||
0.04: Use offscreen buffer for flickerless updates
|
|
||||||
0.05: Complete rewrite. New UI, GPS & HRM Kalman filters, activity logging
|
|
||||||
0.06: Reading HDOP directly from the GPS event (needs Espruino 2v07 or above)
|
|
||||||
0.07: Fixed GPS update, added guards against NaN values
|
|
||||||
0.08: Fix issue with GPS coordinates being wrong after the first one
|
|
||||||
0.09: Another GPS fix (log raw coordinates - not filtered ones)
|
|
||||||
0.10: Removed kalman filtering to allow distance log to work
|
|
||||||
Only log data every 5 seconds (not 1 sec)
|
|
||||||
Don't create a file until the first log entry is ready
|
|
||||||
Add labels for buttons
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
# BangleRun
|
|
||||||
|
|
||||||
An app for running sessions. Displays info and logs your run for later viewing.
|
|
||||||
|
|
||||||
## Compilation
|
|
||||||
|
|
||||||
The app is written in Typescript, and needs to be transpiled in order to be
|
|
||||||
run on the BangleJS. The easiest way to perform this step is by using the
|
|
||||||
ubiquitous [NPM package manager](https://www.npmjs.com/get-npm).
|
|
||||||
|
|
||||||
After having installed NPM for your platform, checkout the `BangleApps` repo,
|
|
||||||
open a terminal, and navigate into the `apps/banglerun` folder. Then issue:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm i
|
|
||||||
```
|
|
||||||
|
|
||||||
to install the project's build tools, and:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
To build the app. The last command will generate the `app.js` file, containing
|
|
||||||
the transpiled code for the BangleJS.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
require("heatshrink").decompress(atob("mEwwIHEuAEDgP8ApMDAqAXBjAGD/E8AgUcgF8CAX/BgIFBn//wAFCv//8PwAoP///5Aon/8AcB+IFB4AFB8P/34FBgfj/8fwAFB4f+g4cBg/H/w/Cg+HKQcPx4FEh4/CAoMfAocOj4/CKYRwELIIFDLII6BAoZSBLIYeCgP+v4FD/k/GAQFBHgcD/ABBIIX4gIFBSYPwAoUPAog/B8AFEwAFDDQQCBQoQFCZYYFigCKEgFwgAA=="))
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
!function(){"use strict";var t;!function(t){t.Stopped="STOP",t.Paused="PAUSE",t.Running="RUN"}(t||(t={}));const n={STOP:63488,PAUSE:65504,RUN:2016};function e(t,n,e){g.setColor(0),g.fillRect(n-60,e,n+60,e+30),g.setColor(65535),g.drawString(t,n,e)}function i(i){var s;g.setFontVector(30),g.setFontAlign(0,-1,0),e((i.distance/1e3).toFixed(2),60,55),e(function(t){const n=Math.round(t),e=Math.floor(n/3600),i=Math.floor(n/60)%60,s=n%60;return(e?e+":":"")+("0"+i).substr(-2)+":"+("0"+s).substr(-2)}(i.duration),172,55),e(function(t){if(t<.1667)return"__'__\"";const n=Math.round(1e3/t),e=Math.floor(n/60),i=n%60;return("0"+e).substr(-2)+"'"+("0"+i).substr(-2)+'"'}(i.speed),60,115),e(i.hr.toFixed(0),172,115),e(i.steps.toFixed(0),60,175),e(i.cadence.toFixed(0),172,175),g.setFont("6x8",2),g.setColor(i.gpsValid?2016:63488),g.fillRect(0,216,80,240),g.setColor(0),g.drawString("GPS",40,220),g.setColor(65535),g.fillRect(80,216,160,240),g.setColor(0),g.drawString(("0"+(s=new Date).getHours()).substr(-2)+":"+("0"+s.getMinutes()).substr(-2),120,220),g.setColor(n[i.status]),g.fillRect(160,216,230,240),g.setColor(0),g.drawString(i.status,200,220),g.setFont("6x8").setFontAlign(0,0,1).setColor(-1),i.status===t.Paused?g.drawString("START",236,60,1).drawString(" CLEAR ",236,180,1):i.status===t.Running?g.drawString(" PAUSE ",236,60,1).drawString(" PAUSE ",236,180,1):g.drawString("START",236,60,1).drawString(" ",236,180,1)}function s(t){g.clear(),g.setColor(50712),g.setFont("6x8",2),g.setFontAlign(0,-1,0),g.drawString("DIST (KM)",60,32),g.drawString("TIME",180,32),g.drawString("PACE",60,92),g.drawString("HEART",180,92),g.drawString("STEPS",60,152),g.drawString("CADENCE",180,152),i(t),Bangle.drawWidgets()}function a(n){n.status===t.Stopped&&function(t){const n=(new Date).toISOString().replace(/[-:]/g,""),e=`banglerun_${n.substr(2,6)}_${n.substr(9,6)}`;t.file=require("Storage").open(e,"w"),t.fileWritten=!1}(n),n.status===t.Running?n.status=t.Paused:n.status=t.Running,i(n)}const r={fix:NaN,lat:NaN,lon:NaN,alt:NaN,vel:NaN,dop:NaN,gpsValid:!1,x:NaN,y:NaN,z:NaN,t:NaN,timeSinceLog:0,hr:60,hrError:100,file:null,fileWritten:!1,drawing:!1,status:t.Stopped,duration:0,distance:0,speed:0,steps:0,cadence:0};var o;o=r,Bangle.on("GPS",n=>function(n,e){n.lat=e.lat,n.lon=e.lon,n.alt=e.alt,n.vel=e.speed/3.6,n.fix=e.fix,n.dop=e.hdop,n.gpsValid=n.fix>0,function(n){const e=Date.now();let i=(e-n.t)/1e3;if(isFinite(i)||(i=0),n.t=e,n.timeSinceLog+=i,n.status===t.Running&&(n.duration+=i),!n.gpsValid)return;const s=6371008.8+n.alt,a=n.lat*Math.PI/180,r=n.lon*Math.PI/180,o=s*Math.cos(a)*Math.cos(r),g=s*Math.cos(a)*Math.sin(r),d=s*Math.sin(a);if(!n.x)return n.x=o,n.y=g,void(n.z=d);const u=o-n.x,l=g-n.y,c=d-n.z,f=Math.sqrt(u*u+l*l+c*c);n.x=o,n.y=g,n.z=d,n.status===t.Running&&(n.distance+=f,n.speed=n.distance/n.duration||0,n.cadence=60*n.steps/n.duration||0)}(n),i(n),n.gpsValid&&n.status===t.Running&&n.timeSinceLog>5&&(n.timeSinceLog=0,function(t){t.fileWritten||(t.file.write(["timestamp","latitude","longitude","altitude","duration","distance","heartrate","steps"].join(",")+"\n"),t.fileWritten=!0),t.file.write([Date.now().toFixed(0),t.lat.toFixed(6),t.lon.toFixed(6),t.alt.toFixed(2),t.duration.toFixed(0),t.distance.toFixed(2),t.hr.toFixed(0),t.steps.toFixed(0)].join(",")+"\n")}(n))}(o,n)),Bangle.setGPSPower(1),function(t){Bangle.on("HRM",n=>function(t,n){if(0===n.confidence)return;const e=n.bpm-t.hr,i=Math.abs(e)+101-n.confidence,s=t.hrError/(t.hrError+i)||0;t.hr+=e*s,t.hrError+=(i-t.hrError)*s}(t,n)),Bangle.setHRMPower(1)}(r),function(n){Bangle.on("step",()=>function(n){n.status===t.Running&&(n.steps+=1)}(n))}(r),function(t){Bangle.loadWidgets(),Bangle.on("lcdPower",n=>{t.drawing=n,n&&s(t)}),s(t)}(r),setWatch(()=>a(r),BTN1,{repeat:!0,edge:"falling"}),setWatch(()=>function(n){n.status===t.Paused&&function(t){t.duration=0,t.distance=0,t.speed=0,t.steps=0,t.cadence=0}(n),n.status===t.Running?n.status=t.Paused:n.status=t.Stopped,i(n)}(r),BTN3,{repeat:!0,edge:"falling"})}();
|
|
||||||
|
Before Width: | Height: | Size: 10 KiB |
|
|
@ -1,217 +0,0 @@
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link rel="stylesheet" href="../../css/spectre.min.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="tracks"></div>
|
|
||||||
|
|
||||||
<script src="../../core/lib/interface.js"></script>
|
|
||||||
<script>
|
|
||||||
/* TODO: Calculate cadence from step count */
|
|
||||||
var domTracks = document.getElementById("tracks");
|
|
||||||
|
|
||||||
function saveKML(track,title) {
|
|
||||||
var kml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
|
|
||||||
<Document>
|
|
||||||
<Schema id="schema">
|
|
||||||
<gx:SimpleArrayField name="heartrate" type="int">
|
|
||||||
<displayName>Heart Rate</displayName>
|
|
||||||
</gx:SimpleArrayField>
|
|
||||||
<gx:SimpleArrayField name="steps" type="int">
|
|
||||||
<displayName>Step Count</displayName>
|
|
||||||
</gx:SimpleArrayField>
|
|
||||||
<gx:SimpleArrayField name="distance" type="float">
|
|
||||||
<displayName>Distance</displayName>
|
|
||||||
</gx:SimpleArrayField>
|
|
||||||
<gx:SimpleArrayField name="cadence" type="int">
|
|
||||||
<displayName>Cadence</displayName>
|
|
||||||
</gx:SimpleArrayField>
|
|
||||||
</Schema>
|
|
||||||
<Folder>
|
|
||||||
<name>Tracks</name>
|
|
||||||
<Placemark>
|
|
||||||
<name>${title}</name>
|
|
||||||
<gx:Track>
|
|
||||||
${track.map(pt=>` <when>${pt.date.toISOString()}</when>\n`).join("")}
|
|
||||||
${track.map(pt=>` <gx:coord>${pt.lon} ${pt.lat} ${pt.alt}</gx:coord>\n`).join("")}
|
|
||||||
<ExtendedData>
|
|
||||||
<SchemaData schemaUrl="#schema">
|
|
||||||
<gx:SimpleArrayData name="heartrate">
|
|
||||||
${track.map(pt=>` <gx:value>${pt.heartrate}</gx:value>\n`).join("")}
|
|
||||||
</gx:SimpleArrayData>
|
|
||||||
<gx:SimpleArrayData name="steps">
|
|
||||||
${track.map(pt=>` <gx:value>${pt.steps}</gx:value>\n`).join("")}
|
|
||||||
</gx:SimpleArrayData>
|
|
||||||
<gx:SimpleArrayData name="distance">
|
|
||||||
${track.map(pt=>` <gx:value>${pt.distance}</gx:value>\n`).join("")}
|
|
||||||
</gx:SimpleArrayData>
|
|
||||||
</SchemaData>
|
|
||||||
</ExtendedData>
|
|
||||||
</gx:Track>
|
|
||||||
</Placemark>
|
|
||||||
</Folder>
|
|
||||||
</Document>
|
|
||||||
</kml>`;
|
|
||||||
var a = document.createElement("a"),
|
|
||||||
file = new Blob([kml], {type: "application/vnd.google-earth.kml+xml"});
|
|
||||||
var url = URL.createObjectURL(file);
|
|
||||||
a.href = url;
|
|
||||||
a.download = title+".kml";
|
|
||||||
document.body.appendChild(a);
|
|
||||||
a.click();
|
|
||||||
setTimeout(function() {
|
|
||||||
document.body.removeChild(a);
|
|
||||||
window.URL.revokeObjectURL(url);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveGPX(track, title) {
|
|
||||||
var gpx = `<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<gpx creator="Bangle.js" version="1.1" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3">
|
|
||||||
<metadata>
|
|
||||||
<time>${track[0].date.toISOString()}</time>
|
|
||||||
</metadata>
|
|
||||||
<trk>
|
|
||||||
<name>${title}</name>
|
|
||||||
<trkseg>`;
|
|
||||||
track.forEach(pt=>{
|
|
||||||
gpx += `
|
|
||||||
<trkpt lat="${pt.lat}" lon="${pt.lon}">
|
|
||||||
<ele>${pt.alt}</ele>
|
|
||||||
<time>${pt.date.toISOString()}</time>
|
|
||||||
<extensions>
|
|
||||||
<gpxtpx:TrackPointExtension>
|
|
||||||
<gpxtpx:hr>${pt.heartrate}</gpxtpx:hr>
|
|
||||||
<gpxtpx:distance>${pt.distance}</gpxtpx:distance>
|
|
||||||
${/* <gpxtpx:cad>65</gpxtpx:cad> */""}
|
|
||||||
</gpxtpx:TrackPointExtension>
|
|
||||||
</extensions>
|
|
||||||
</trkpt>`;
|
|
||||||
});
|
|
||||||
gpx += `
|
|
||||||
</trkseg>
|
|
||||||
</trk>
|
|
||||||
</gpx>`;
|
|
||||||
var a = document.createElement("a"),
|
|
||||||
file = new Blob([gpx], {type: "application/gpx+xml"});
|
|
||||||
var url = URL.createObjectURL(file);
|
|
||||||
a.href = url;
|
|
||||||
a.download = title+".gpx";
|
|
||||||
document.body.appendChild(a);
|
|
||||||
a.click();
|
|
||||||
setTimeout(function() {
|
|
||||||
document.body.removeChild(a);
|
|
||||||
window.URL.revokeObjectURL(url);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function trackLineToObject(l, hasFileName) {
|
|
||||||
// "timestamp,latitude,longitude,altitude,duration,distance,heartrate,steps\n"
|
|
||||||
var t = l.trim().split(",");
|
|
||||||
var n = hasFileName ? 1 : 0;
|
|
||||||
var o = {
|
|
||||||
invalid : t.length < 8,
|
|
||||||
date : new Date(parseInt(t[n+0])),
|
|
||||||
lat : parseFloat(t[n+1]),
|
|
||||||
lon : parseFloat(t[n+2]),
|
|
||||||
alt : parseFloat(t[n+3]),
|
|
||||||
duration : parseFloat(t[n+4]),
|
|
||||||
distance : parseFloat(t[n+5]),
|
|
||||||
heartrate : parseInt(t[n+6]),
|
|
||||||
steps : parseInt(t[n+7]),
|
|
||||||
};
|
|
||||||
if (hasFileName)
|
|
||||||
o.filename = t[0];
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
function downloadTrack(trackid, callback) {
|
|
||||||
Util.showModal("Downloading Track...");
|
|
||||||
Util.readStorageFile(trackid, data=>{
|
|
||||||
Util.hideModal();
|
|
||||||
var trackLines = data.trim().split("\n");
|
|
||||||
trackLines.shift(); // remove first line, which is column header
|
|
||||||
// should be:
|
|
||||||
// "timestamp,latitude,longitude,altitude,duration,distance,heartrate,steps\n"
|
|
||||||
var track = trackLines.map(l=>trackLineToObject(l,false));
|
|
||||||
callback(track);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function getTrackList() {
|
|
||||||
Util.showModal("Loading Tracks...");
|
|
||||||
domTracks.innerHTML = "";
|
|
||||||
Puck.eval(`require("Storage").list(/banglerun_.*\\x01/).map(fn=>{fn=fn.slice(0,-1);var f=require("Storage").open(fn,"r");f.readLine();return fn+","+f.readLine()})`,trackLines=>{
|
|
||||||
var html = `<div class="container">
|
|
||||||
<div class="columns">\n`;
|
|
||||||
trackLines.forEach(l => {
|
|
||||||
var track = trackLineToObject(l, true /*has filename*/);
|
|
||||||
html += `
|
|
||||||
<div class="column col-12">
|
|
||||||
<div class="card-header">
|
|
||||||
<div class="card-title h5">Track ${track.filename}</div>
|
|
||||||
<div class="card-subtitle text-gray">${track.invalid ? "No Data":track.date.toString().substr(0,24)}</div>
|
|
||||||
</div>
|
|
||||||
${track.invalid?``:`<div class="card-image">
|
|
||||||
<iframe
|
|
||||||
width="100%"
|
|
||||||
height="250"
|
|
||||||
frameborder="0" style="border:0"
|
|
||||||
src="https://www.google.com/maps/embed/v1/place?key=AIzaSyBxTcwrrVOh2piz7EmIs1Xn4FsRxJWeVH4&q=${track.lat},${track.lon}&zoom=10" allowfullscreen>
|
|
||||||
</iframe>
|
|
||||||
</div>
|
|
||||||
<div class="card-body"></div>`}
|
|
||||||
<div class="card-footer">${track.invalid?``:`
|
|
||||||
<button class="btn btn-primary" trackid="${track.filename}" task="downloadkml">Download KML</button>
|
|
||||||
<button class="btn btn-primary" trackid="${track.filename}" task="downloadgpx">Download GPX</button>`}
|
|
||||||
<button class="btn btn-default" trackid="${track.filename}" task="delete">Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
});
|
|
||||||
if (trackLines.length==0) {
|
|
||||||
html += `
|
|
||||||
<div class="column col-12">
|
|
||||||
<div class="card-header">
|
|
||||||
<div class="card-title h5">No tracks</div>
|
|
||||||
<div class="card-subtitle text-gray">No GPS tracks found</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
html += `
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
domTracks.innerHTML = html;
|
|
||||||
Util.hideModal();
|
|
||||||
var buttons = domTracks.querySelectorAll("button");
|
|
||||||
for (var i=0;i<buttons.length;i++) {
|
|
||||||
buttons[i].addEventListener("click",event => {
|
|
||||||
var button = event.currentTarget;
|
|
||||||
var trackid = button.getAttribute("trackid");
|
|
||||||
var task = button.getAttribute("task");
|
|
||||||
if (task=="delete") {
|
|
||||||
Util.showModal("Deleting Track...");
|
|
||||||
Util.eraseStorageFile(trackid,()=>{
|
|
||||||
Util.hideModal();
|
|
||||||
getTrackList();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (task=="downloadkml") {
|
|
||||||
downloadTrack(trackid, track => saveKML(track, `Bangle.js Track ${trackid}`));
|
|
||||||
}
|
|
||||||
if (task=="downloadgpx") {
|
|
||||||
downloadTrack(trackid, track => saveGPX(track, `Bangle.js Track ${trackid}`));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function onInit() {
|
|
||||||
getTrackList();
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"spec_dir": "test",
|
|
||||||
"spec_files": [
|
|
||||||
"**/*.spec.ts"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
{
|
|
||||||
"id": "banglerun",
|
|
||||||
"name": "BangleRun",
|
|
||||||
"shortName": "BangleRun",
|
|
||||||
"version": "0.10",
|
|
||||||
"description": "An app for running sessions. Displays info and logs your run for later viewing.",
|
|
||||||
"icon": "banglerun.png",
|
|
||||||
"tags": "run,running,fitness,outdoors",
|
|
||||||
"supports": ["BANGLEJS"],
|
|
||||||
"interface": "interface.html",
|
|
||||||
"allow_emulator": false,
|
|
||||||
"storage": [
|
|
||||||
{"name":"banglerun.app.js","url":"app.js"},
|
|
||||||
{"name":"banglerun.img","url":"app-icon.js","evaluate":true}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
{
|
|
||||||
"name": "banglerun",
|
|
||||||
"version": "0.5.0",
|
|
||||||
"description": "Bangle.js app for running sessions",
|
|
||||||
"main": "app.js",
|
|
||||||
"types": "app.d.ts",
|
|
||||||
"scripts": {
|
|
||||||
"build": "rollup -c",
|
|
||||||
"test": "ts-node -P tsconfig.spec.json node_modules/jasmine/bin/jasmine --config=jasmine.json"
|
|
||||||
},
|
|
||||||
"author": {
|
|
||||||
"name": "Stefano Baldan",
|
|
||||||
"email": "singintime@gmail.com"
|
|
||||||
},
|
|
||||||
"license": "ISC",
|
|
||||||
"devDependencies": {
|
|
||||||
"@rollup/plugin-typescript": "^4.1.1",
|
|
||||||
"@types/jasmine": "^3.5.10",
|
|
||||||
"jasmine": "^3.5.0",
|
|
||||||
"rollup": "^2.10.2",
|
|
||||||
"rollup-plugin-terser": "^5.3.0",
|
|
||||||
"terser": "^4.7.0",
|
|
||||||
"ts-node": "^8.10.2",
|
|
||||||
"tslib": "^2.0.0",
|
|
||||||
"typescript": "^3.9.2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import typescript from '@rollup/plugin-typescript';
|
|
||||||
import { terser } from 'rollup-plugin-terser';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
input: './src/app.ts',
|
|
||||||
output: {
|
|
||||||
dir: '.',
|
|
||||||
format: 'iife',
|
|
||||||
name: 'banglerun'
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
typescript(),
|
|
||||||
terser(),
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
import { draw } from './display';
|
|
||||||
import { initLog } from './log';
|
|
||||||
import { ActivityStatus, AppState } from './state';
|
|
||||||
|
|
||||||
function startActivity(state: AppState): void {
|
|
||||||
if (state.status === ActivityStatus.Stopped) {
|
|
||||||
initLog(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.status === ActivityStatus.Running) {
|
|
||||||
state.status = ActivityStatus.Paused;
|
|
||||||
} else {
|
|
||||||
state.status = ActivityStatus.Running;
|
|
||||||
}
|
|
||||||
|
|
||||||
draw(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopActivity(state: AppState): void {
|
|
||||||
if (state.status === ActivityStatus.Paused) {
|
|
||||||
clearActivity(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.status === ActivityStatus.Running) {
|
|
||||||
state.status = ActivityStatus.Paused;
|
|
||||||
} else {
|
|
||||||
state.status = ActivityStatus.Stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
draw(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearActivity(state: AppState): void {
|
|
||||||
state.duration = 0;
|
|
||||||
state.distance = 0;
|
|
||||||
state.speed = 0;
|
|
||||||
state.steps = 0;
|
|
||||||
state.cadence = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export { clearActivity, startActivity, stopActivity };
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
import { startActivity, stopActivity } from './activity';
|
|
||||||
import { initDisplay } from './display';
|
|
||||||
import { initGps } from './gps';
|
|
||||||
import { initHrm } from './hrm';
|
|
||||||
import { initState } from './state';
|
|
||||||
import { initStep } from './step';
|
|
||||||
|
|
||||||
declare var BTN1: any;
|
|
||||||
declare var BTN3: any;
|
|
||||||
declare var setWatch: any;
|
|
||||||
|
|
||||||
const appState = initState();
|
|
||||||
|
|
||||||
initGps(appState);
|
|
||||||
initHrm(appState);
|
|
||||||
initStep(appState);
|
|
||||||
initDisplay(appState);
|
|
||||||
|
|
||||||
setWatch(() => startActivity(appState), BTN1, { repeat: true, edge: 'falling' });
|
|
||||||
setWatch(() => stopActivity(appState), BTN3, { repeat: true, edge: 'falling' });
|
|
||||||
|
|
@ -1,123 +0,0 @@
|
||||||
import { ActivityStatus, AppState } from './state';
|
|
||||||
|
|
||||||
declare var Bangle: any;
|
|
||||||
declare var g: any;
|
|
||||||
|
|
||||||
const STATUS_COLORS = {
|
|
||||||
'STOP': 0xF800,
|
|
||||||
'PAUSE': 0xFFE0,
|
|
||||||
'RUN': 0x07E0,
|
|
||||||
}
|
|
||||||
|
|
||||||
function initDisplay(state: AppState): void {
|
|
||||||
Bangle.loadWidgets();
|
|
||||||
Bangle.on('lcdPower', (on: boolean) => {
|
|
||||||
state.drawing = on;
|
|
||||||
if (on) {
|
|
||||||
drawAll(state);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
drawAll(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawBackground(): void {
|
|
||||||
g.clear();
|
|
||||||
g.setColor(0xC618);
|
|
||||||
g.setFont('6x8', 2);
|
|
||||||
g.setFontAlign(0, -1, 0);
|
|
||||||
g.drawString('DIST (KM)', 60, 32);
|
|
||||||
g.drawString('TIME', 172, 32);
|
|
||||||
g.drawString('PACE', 60, 92);
|
|
||||||
g.drawString('HEART', 172, 92);
|
|
||||||
g.drawString('STEPS', 60, 152);
|
|
||||||
g.drawString('CADENCE', 172, 152);
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawValue(value: string, x: number, y: number) {
|
|
||||||
g.setColor(0x0000);
|
|
||||||
g.fillRect(x - 60, y, x + 60, y + 30);
|
|
||||||
g.setColor(0xFFFF);
|
|
||||||
g.drawString(value, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function draw(state: AppState): void {
|
|
||||||
g.setFontVector(30);
|
|
||||||
g.setFontAlign(0, -1, 0);
|
|
||||||
|
|
||||||
drawValue(formatDistance(state.distance), 60, 55);
|
|
||||||
drawValue(formatTime(state.duration), 172, 55);
|
|
||||||
drawValue(formatPace(state.speed), 60, 115);
|
|
||||||
drawValue(state.hr.toFixed(0), 172, 115);
|
|
||||||
drawValue(state.steps.toFixed(0), 60, 175);
|
|
||||||
drawValue(state.cadence.toFixed(0), 172, 175);
|
|
||||||
|
|
||||||
g.setFont('6x8', 2);
|
|
||||||
|
|
||||||
g.setColor(state.gpsValid ? 0x07E0 : 0xF800);
|
|
||||||
g.fillRect(0, 216, 80, 240);
|
|
||||||
g.setColor(0x0000);
|
|
||||||
g.drawString('GPS', 40, 220);
|
|
||||||
|
|
||||||
g.setColor(0xFFFF);
|
|
||||||
g.fillRect(80, 216, 160, 240);
|
|
||||||
g.setColor(0x0000);
|
|
||||||
g.drawString(formatClock(new Date()), 120, 220);
|
|
||||||
|
|
||||||
g.setColor(STATUS_COLORS[state.status]);
|
|
||||||
g.fillRect(160, 216, 230, 240);
|
|
||||||
g.setColor(0x0000);
|
|
||||||
g.drawString(state.status, 200, 220);
|
|
||||||
|
|
||||||
g.setFont("6x8").setFontAlign(0,0,1).setColor(-1);
|
|
||||||
if (state.status === ActivityStatus.Paused) {
|
|
||||||
g.drawString("START",236,60,1).drawString(" CLEAR ",236,180,1);
|
|
||||||
} else if (state.status === ActivityStatus.Running) {
|
|
||||||
g.drawString(" PAUSE ",236,60,1).drawString(" PAUSE ",236,180,1);
|
|
||||||
} else {
|
|
||||||
g.drawString("START",236,60,1).drawString(" ",236,180,1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawAll(state: AppState) {
|
|
||||||
drawBackground();
|
|
||||||
draw(state);
|
|
||||||
Bangle.drawWidgets();
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatClock(date: Date): string {
|
|
||||||
return ('0' + date.getHours()).substr(-2) + ':' + ('0' + date.getMinutes()).substr(-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatDistance(meters: number): string {
|
|
||||||
return (meters / 1000).toFixed(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatPace(speed: number): string {
|
|
||||||
if (speed < 0.1667) {
|
|
||||||
return `__'__"`;
|
|
||||||
}
|
|
||||||
const pace = Math.round(1000 / speed);
|
|
||||||
const min = Math.floor(pace / 60);
|
|
||||||
const sec = pace % 60;
|
|
||||||
return ('0' + min).substr(-2) + `'` + ('0' + sec).substr(-2) + `"`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatTime(time: number): string {
|
|
||||||
const seconds = Math.round(time);
|
|
||||||
const hrs = Math.floor(seconds / 3600);
|
|
||||||
const min = Math.floor(seconds / 60) % 60;
|
|
||||||
const sec = seconds % 60;
|
|
||||||
return (hrs ? hrs + ':' : '') + ('0' + min).substr(-2) + `:` + ('0' + sec).substr(-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
draw,
|
|
||||||
drawAll,
|
|
||||||
drawBackground,
|
|
||||||
drawValue,
|
|
||||||
formatClock,
|
|
||||||
formatDistance,
|
|
||||||
formatPace,
|
|
||||||
formatTime,
|
|
||||||
initDisplay,
|
|
||||||
};
|
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
import { draw } from './display';
|
|
||||||
import { updateLog } from './log';
|
|
||||||
import { ActivityStatus, AppState } from './state';
|
|
||||||
|
|
||||||
declare var Bangle: any;
|
|
||||||
|
|
||||||
interface GpsEvent {
|
|
||||||
lat: number;
|
|
||||||
lon: number;
|
|
||||||
alt: number;
|
|
||||||
speed: number;
|
|
||||||
hdop: number;
|
|
||||||
fix: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EARTH_RADIUS = 6371008.8;
|
|
||||||
|
|
||||||
function initGps(state: AppState): void {
|
|
||||||
Bangle.on('GPS', (gps: GpsEvent) => readGps(state, gps));
|
|
||||||
Bangle.setGPSPower(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function readGps(state: AppState, gps: GpsEvent): void {
|
|
||||||
state.lat = gps.lat;
|
|
||||||
state.lon = gps.lon;
|
|
||||||
state.alt = gps.alt;
|
|
||||||
state.vel = gps.speed / 3.6;
|
|
||||||
state.fix = gps.fix;
|
|
||||||
state.dop = gps.hdop;
|
|
||||||
state.gpsValid = state.fix > 0;
|
|
||||||
|
|
||||||
updateGps(state);
|
|
||||||
draw(state);
|
|
||||||
|
|
||||||
/* Only log GPS data every 5 secs if we
|
|
||||||
have a fix and we're running. */
|
|
||||||
if (state.gpsValid &&
|
|
||||||
state.status === ActivityStatus.Running &&
|
|
||||||
state.timeSinceLog > 5) {
|
|
||||||
state.timeSinceLog = 0;
|
|
||||||
updateLog(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateGps(state: AppState): void {
|
|
||||||
const t = Date.now();
|
|
||||||
let dt = (t - state.t) / 1000;
|
|
||||||
if (!isFinite(dt)) dt=0;
|
|
||||||
state.t = t;
|
|
||||||
state.timeSinceLog += dt;
|
|
||||||
|
|
||||||
if (state.status === ActivityStatus.Running) {
|
|
||||||
state.duration += dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!state.gpsValid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const r = EARTH_RADIUS + state.alt;
|
|
||||||
const lat = state.lat * Math.PI / 180;
|
|
||||||
const lon = state.lon * Math.PI / 180;
|
|
||||||
const x = r * Math.cos(lat) * Math.cos(lon);
|
|
||||||
const y = r * Math.cos(lat) * Math.sin(lon);
|
|
||||||
const z = r * Math.sin(lat);
|
|
||||||
|
|
||||||
if (!state.x) {
|
|
||||||
state.x = x;
|
|
||||||
state.y = y;
|
|
||||||
state.z = z;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dx = x - state.x;
|
|
||||||
const dy = y - state.y;
|
|
||||||
const dz = z - state.z;
|
|
||||||
const dpMag = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
||||||
|
|
||||||
state.x = x;
|
|
||||||
state.y = y;
|
|
||||||
state.z = z;
|
|
||||||
|
|
||||||
if (state.status === ActivityStatus.Running) {
|
|
||||||
state.distance += dpMag;
|
|
||||||
state.speed = (state.distance / state.duration) || 0;
|
|
||||||
state.cadence = (60 * state.steps / state.duration) || 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { initGps, readGps, updateGps };
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
import { AppState } from './state';
|
|
||||||
|
|
||||||
interface HrmData {
|
|
||||||
bpm: number;
|
|
||||||
confidence: number;
|
|
||||||
raw: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare var Bangle: any;
|
|
||||||
|
|
||||||
function initHrm(state: AppState) {
|
|
||||||
Bangle.on('HRM', (hrm: HrmData) => updateHrm(state, hrm));
|
|
||||||
Bangle.setHRMPower(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateHrm(state: AppState, hrm: HrmData) {
|
|
||||||
if (hrm.confidence === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dHr = hrm.bpm - state.hr;
|
|
||||||
const hrError = Math.abs(dHr) + 101 - hrm.confidence;
|
|
||||||
const hrGain = (state.hrError / (state.hrError + hrError)) || 0;
|
|
||||||
|
|
||||||
state.hr += dHr * hrGain;
|
|
||||||
state.hrError += (hrError - state.hrError) * hrGain;
|
|
||||||
}
|
|
||||||
|
|
||||||
export { initHrm, updateHrm };
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
import { AppState } from './state';
|
|
||||||
|
|
||||||
declare var require: any;
|
|
||||||
|
|
||||||
function initLog(state: AppState): void {
|
|
||||||
const datetime = new Date().toISOString().replace(/[-:]/g, '');
|
|
||||||
const date = datetime.substr(2, 6);
|
|
||||||
const time = datetime.substr(9, 6);
|
|
||||||
const filename = `banglerun_${date}_${time}`;
|
|
||||||
state.file = require('Storage').open(filename, 'w');
|
|
||||||
state.fileWritten = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLog(state: AppState): void {
|
|
||||||
if (!state.fileWritten) {
|
|
||||||
state.file.write([
|
|
||||||
'timestamp',
|
|
||||||
'latitude',
|
|
||||||
'longitude',
|
|
||||||
'altitude',
|
|
||||||
'duration',
|
|
||||||
'distance',
|
|
||||||
'heartrate',
|
|
||||||
'steps',
|
|
||||||
].join(',') + '\n');
|
|
||||||
state.fileWritten = true;
|
|
||||||
}
|
|
||||||
state.file.write([
|
|
||||||
Date.now().toFixed(0),
|
|
||||||
state.lat.toFixed(6),
|
|
||||||
state.lon.toFixed(6),
|
|
||||||
state.alt.toFixed(2),
|
|
||||||
state.duration.toFixed(0),
|
|
||||||
state.distance.toFixed(2),
|
|
||||||
state.hr.toFixed(0),
|
|
||||||
state.steps.toFixed(0),
|
|
||||||
].join(',') + '\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
export { initLog, updateLog };
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
enum ActivityStatus {
|
|
||||||
Stopped = 'STOP',
|
|
||||||
Paused = 'PAUSE',
|
|
||||||
Running = 'RUN',
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AppState {
|
|
||||||
// GPS NMEA data
|
|
||||||
fix: number;
|
|
||||||
lat: number;
|
|
||||||
lon: number;
|
|
||||||
alt: number;
|
|
||||||
vel: number;
|
|
||||||
dop: number;
|
|
||||||
gpsValid: boolean;
|
|
||||||
|
|
||||||
// Absolute position data
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
z: number;
|
|
||||||
// Last fix time
|
|
||||||
t: number;
|
|
||||||
// Last time we saved log info
|
|
||||||
timeSinceLog : number;
|
|
||||||
|
|
||||||
// HRM data
|
|
||||||
hr: number,
|
|
||||||
hrError: number,
|
|
||||||
|
|
||||||
// Logger data
|
|
||||||
file: File;
|
|
||||||
fileWritten: boolean;
|
|
||||||
|
|
||||||
// Drawing data
|
|
||||||
drawing: boolean;
|
|
||||||
|
|
||||||
// Activity data
|
|
||||||
status: ActivityStatus;
|
|
||||||
duration: number;
|
|
||||||
distance: number;
|
|
||||||
speed: number;
|
|
||||||
steps: number;
|
|
||||||
cadence: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface File {
|
|
||||||
read: Function;
|
|
||||||
write: Function;
|
|
||||||
erase: Function;
|
|
||||||
}
|
|
||||||
|
|
||||||
function initState(): AppState {
|
|
||||||
return {
|
|
||||||
fix: NaN,
|
|
||||||
lat: NaN,
|
|
||||||
lon: NaN,
|
|
||||||
alt: NaN,
|
|
||||||
vel: NaN,
|
|
||||||
dop: NaN,
|
|
||||||
gpsValid: false,
|
|
||||||
|
|
||||||
x: NaN,
|
|
||||||
y: NaN,
|
|
||||||
z: NaN,
|
|
||||||
t: NaN,
|
|
||||||
timeSinceLog : 0,
|
|
||||||
|
|
||||||
hr: 60,
|
|
||||||
hrError: 100,
|
|
||||||
|
|
||||||
file: null,
|
|
||||||
fileWritten: false,
|
|
||||||
|
|
||||||
drawing: false,
|
|
||||||
|
|
||||||
status: ActivityStatus.Stopped,
|
|
||||||
duration: 0,
|
|
||||||
distance: 0,
|
|
||||||
speed: 0,
|
|
||||||
steps: 0,
|
|
||||||
cadence: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { ActivityStatus, AppState, File, initState };
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import { ActivityStatus, AppState } from './state';
|
|
||||||
|
|
||||||
declare var Bangle: any;
|
|
||||||
|
|
||||||
function initStep(state: AppState) {
|
|
||||||
Bangle.on('step', () => updateStep(state));
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateStep(state: AppState) {
|
|
||||||
if (state.status === ActivityStatus.Running) {
|
|
||||||
state.steps += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { initStep, updateStep };
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "es2015",
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"target": "es2015"
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "commonjs",
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"target": "es2015"
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"test"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
0.02: Write available data on reset or kill
|
0.02: Write available data on reset or kill
|
||||||
|
0.03: Buzz short on every finished measurement and longer if all are done
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,6 @@ function write(){
|
||||||
data += "," + rrMax + "," + rrMin + ","+rrNumberOfValues;
|
data += "," + rrMax + "," + rrMin + ","+rrNumberOfValues;
|
||||||
data += "\n";
|
data += "\n";
|
||||||
file.write(data);
|
file.write(data);
|
||||||
Bangle.buzz(500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onBtHrm(e) {
|
function onBtHrm(e) {
|
||||||
|
|
@ -87,6 +86,11 @@ function onBtHrm(e) {
|
||||||
if (currentSlot <= hrvSlots.length && (Date.now() - startingTime) > (hrvSlots[currentSlot] * 1000) && !hrvValues[hrvSlots[currentSlot]]){
|
if (currentSlot <= hrvSlots.length && (Date.now() - startingTime) > (hrvSlots[currentSlot] * 1000) && !hrvValues[hrvSlots[currentSlot]]){
|
||||||
hrvValues[hrvSlots[currentSlot]] = hrv;
|
hrvValues[hrvSlots[currentSlot]] = hrv;
|
||||||
currentSlot++;
|
currentSlot++;
|
||||||
|
if (currentSlot == hrvSlots.length){
|
||||||
|
Bangle.buzz(500)
|
||||||
|
} else {
|
||||||
|
Bangle.buzz(50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "bthrv",
|
"id": "bthrv",
|
||||||
"name": "Bluetooth Heart Rate variance calculator",
|
"name": "Bluetooth Heart Rate variance calculator",
|
||||||
"shortName": "BT HRV",
|
"shortName": "BT HRV",
|
||||||
"version": "0.02",
|
"version": "0.03",
|
||||||
"description": "Calculates HRV from a a BT HRM with interval data",
|
"description": "Calculates HRV from a a BT HRM with interval data",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"type": "app",
|
"type": "app",
|
||||||
|
|
|
||||||
|
|
@ -20,3 +20,6 @@
|
||||||
Color depending on value (green -> red, red -> green) option
|
Color depending on value (green -> red, red -> green) option
|
||||||
Good HRM value will not be overwritten so fast anymore
|
Good HRM value will not be overwritten so fast anymore
|
||||||
0.10: Use roboto font for time, date and day of week and center align them
|
0.10: Use roboto font for time, date and day of week and center align them
|
||||||
|
0.11: New color option: foreground color
|
||||||
|
Improve performance, reduce memory usage
|
||||||
|
Small optical adjustments
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,8 @@ const storage = require("Storage");
|
||||||
const SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js");
|
const SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js");
|
||||||
|
|
||||||
const shoesIcon = atob("EBCBAAAACAAcAB4AHgAeABwwADgGeAZ4AHgAMAAAAHAAIAAA");
|
const shoesIcon = atob("EBCBAAAACAAcAB4AHgAeABwwADgGeAZ4AHgAMAAAAHAAIAAA");
|
||||||
const heartIcon = atob("EBCBAAAAAAAeeD/8P/x//n/+P/w//B/4D/AH4APAAYAAAAAA");
|
|
||||||
const powerIcon = atob("EBCBAAAAA8ADwA/wD/AP8A/wD/AP8A/wD/AP8A/wD/AH4AAA");
|
|
||||||
const temperatureIcon = atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA");
|
const temperatureIcon = atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA");
|
||||||
|
|
||||||
const weatherCloudy = atob("EBCBAAAAAAAAAAfgD/Af8H/4//7///////9//z/+AAAAAAAA");
|
|
||||||
const weatherSunny = atob("EBCBAAAAAYAQCBAIA8AH4A/wb/YP8A/gB+ARiBAIAYABgAAA");
|
|
||||||
const weatherMoon = atob("EBCBAAAAAYAP8B/4P/w//D/8f/5//j/8P/w//B/4D/ABgAAA");
|
|
||||||
const weatherPartlyCloudy = atob("EBCBAAAAAAAYQAMAD8AIQBhoW+AOYBwwOBBgHGAGP/wf+AAA");
|
|
||||||
const weatherRainy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQAJBgjPOEkgGYAZgA8ABgAAA");
|
|
||||||
const weatherPartlyRainy = atob("EBCBAAAAEEAQAAeADMAYaFvoTmAMMDgQIBxhhiGGG9wDwAGA");
|
|
||||||
const weatherSnowy = atob("EBCBAAAAAAADwAGAEYg73C50BCAEIC50O9wRiAGAA8AAAAAA");
|
|
||||||
const weatherFoggy = atob("EBCBAAAAAAADwAZgDDA4EGAcQAZAAgAAf74AAAAAd/4AAAAA");
|
|
||||||
const weatherStormy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQMJAgjmOGcgAgACAAAAAAAAA");
|
|
||||||
|
|
||||||
const sunSetDown = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAAGYAPAAYAAAAAA");
|
|
||||||
const sunSetUp = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAABgAPABmAAAAAA");
|
|
||||||
|
|
||||||
Graphics.prototype.setFontRobotoRegular50NumericOnly = function(scale) {
|
Graphics.prototype.setFontRobotoRegular50NumericOnly = function(scale) {
|
||||||
// Actual height 39 (40 - 2)
|
// Actual height 39 (40 - 2)
|
||||||
this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAB8AAAAAAAfAAAAAAAPwAAAAAAB8AAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAA4AAAAAAB+AAAAAAD/gAAAAAD/4AAAAAH/4AAAAAP/wAAAAAP/gAAAAAf/gAAAAAf/AAAAAA/+AAAAAB/+AAAAAB/8AAAAAD/4AAAAAH/4AAAAAD/wAAAAAA/wAAAAAAPgAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///wAAAB////gAAA////8AAA/////gAAP////8AAH8AAA/gAB8AAAD4AA+AAAAfAAPAAAADwADwAAAA8AA8AAAAPAAPAAAADwADwAAAA8AA8AAAAPAAPgAAAHwAB8AAAD4AAfwAAD+AAD/////AAA/////wAAH////4AAAf///4AAAB///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAPgAAAAAADwAAAAAAB8AAAAAAAfAAAAAAAHgAAAAAAD4AAAAAAA+AAAAAAAPAAAAAAAH/////wAB/////8AA//////AAP/////wAD/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAfgAADwAAP4AAB8AAH+AAA/AAD/gAAfwAB/AAAf8AAfAAAP/AAPgAAH7wAD4AAD88AA8AAB+PAAPAAA/DwADwAAfg8AA8AAPwPAAPAAH4DwADwAH8A8AA+AD+APAAPwB/ADwAB/D/gA8AAf//gAPAAD//wADwAAf/wAA8AAD/4AAPAAAHwAADwAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAADgAAAHwAA+AAAD8AAP4AAB/AAD/AAA/wAA/wAAf4AAD+AAHwAAAPgAD4APAB8AA+ADwAPAAPAA8ADwADwAPAA8AA8ADwAPAAPAA8ADwADwAfAA8AA8AH4APAAPgD+AHwAB8B/wD4AAf7/+B+AAD//v//AAA//x//wAAD/4P/4AAAf8B/4AAAAYAH4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAHwAAAAAAH8AAAAAAD/AAAAAAD/wAAAAAD/8AAAAAB/vAAAAAB/jwAAAAA/g8AAAAA/wPAAAAAfwDwAAAAf4A8AAAAf4APAAAAP8ADwAAAP8AA8AAAH8AAPAAAD/////8AA//////AAP/////wAD/////8AA//////AAAAAAPAAAAAAADwAAAAAAA8AAAAAAAPAAAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAAB/APwAAH//wD+AAD//8A/wAA///AH+AAP//wAPgAD/B4AB8AA8A+AAfAAPAPAADwADwDwAA8AA8A8AAPAAPAPAADwADwD4AA8AA8A+AAPAAPAPwAHwADwD8AD4AA8AfwD+AAPAH///AADwA///wAA8AH//4AAPAAf/4AAAAAB/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAD//+AAAAD///4AAAD////AAAB////4AAA/78D/AAAfw8AH4AAPweAA+AAD4PgAHwAB8DwAA8AAfA8AAPAAHgPAADwAD4DwAA8AA+A8AAPAAPAPgAHwADwD4AB8AA8AfgA+AAPAH+B/gAAAA///wAAAAH//4AAAAA//8AAAAAH/8AAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwAAAAAAA8AAAAAAAPAAAAAAADwAAAAAAA8AAAABAAPAAAABwADwAAAB8AA8AAAB/AAPAAAB/wADwAAD/8AA8AAD/8AAPAAD/4AADwAD/4AAA8AD/4AAAPAH/wAAADwH/wAAAA8H/wAAAAPH/wAAAAD3/gAAAAA//gAAAAAP/gAAAAAD/gAAAAAA/AAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwA/4AAAH/Af/AAAH/8P/4AAD//n//AAA//7//4AAfx/+A+AAHwD+AHwAD4AfgB8AA8AHwAPAAPAA8ADwADwAPAA8AA8ADwAPAAPAA8ADwADwAfAA8AA+AH4AfAAHwD+AHwAB/D/4D4AAP/+/n+AAD//n//AAAf/w//gAAB/wH/wAAAHwA/4AAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+AAAAAAD/8AAAAAD//wAAAAB//+AAAAA///wAAAAf4H+APAAH4AfgDwAD8AB8A8AA+AAfAPAAPAADwDwADwAA8B8AA8AAPAfAAPAADwHgADwAA8D4AA+AAeB+AAHwAHg/AAB+ADwfgAAP8D4/4AAD////8AAAf///8AAAB///+AAAAP//+AAAAAP/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAOAAAB8AAHwAAAfgAD8AAAH4AA/AAAB8AAHwAAAOAAA4AAAAAAAAAAAAAAAAAAAAAAAAAA"), 46, atob("DRUcHBwcHBwcHBwcDA=="), 50+(scale<<8)+(1<<16));
|
this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAB8AAAAAAAfAAAAAAAPwAAAAAAB8AAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAA4AAAAAAB+AAAAAAD/gAAAAAD/4AAAAAH/4AAAAAP/wAAAAAP/gAAAAAf/gAAAAAf/AAAAAA/+AAAAAB/+AAAAAB/8AAAAAD/4AAAAAH/4AAAAAD/wAAAAAA/wAAAAAAPgAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///wAAAB////gAAA////8AAA/////gAAP////8AAH8AAA/gAB8AAAD4AA+AAAAfAAPAAAADwADwAAAA8AA8AAAAPAAPAAAADwADwAAAA8AA8AAAAPAAPgAAAHwAB8AAAD4AAfwAAD+AAD/////AAA/////wAAH////4AAAf///4AAAB///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAPgAAAAAADwAAAAAAB8AAAAAAAfAAAAAAAHgAAAAAAD4AAAAAAA+AAAAAAAPAAAAAAAH/////wAB/////8AA//////AAP/////wAD/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAfgAADwAAP4AAB8AAH+AAA/AAD/gAAfwAB/AAAf8AAfAAAP/AAPgAAH7wAD4AAD88AA8AAB+PAAPAAA/DwADwAAfg8AA8AAPwPAAPAAH4DwADwAH8A8AA+AD+APAAPwB/ADwAB/D/gA8AAf//gAPAAD//wADwAAf/wAA8AAD/4AAPAAAHwAADwAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAADgAAAHwAA+AAAD8AAP4AAB/AAD/AAA/wAA/wAAf4AAD+AAHwAAAPgAD4APAB8AA+ADwAPAAPAA8ADwADwAPAA8AA8ADwAPAAPAA8ADwADwAfAA8AA8AH4APAAPgD+AHwAB8B/wD4AAf7/+B+AAD//v//AAA//x//wAAD/4P/4AAAf8B/4AAAAYAH4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAHwAAAAAAH8AAAAAAD/AAAAAAD/wAAAAAD/8AAAAAB/vAAAAAB/jwAAAAA/g8AAAAA/wPAAAAAfwDwAAAAf4A8AAAAf4APAAAAP8ADwAAAP8AA8AAAH8AAPAAAD/////8AA//////AAP/////wAD/////8AA//////AAAAAAPAAAAAAADwAAAAAAA8AAAAAAAPAAAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAAB/APwAAH//wD+AAD//8A/wAA///AH+AAP//wAPgAD/B4AB8AA8A+AAfAAPAPAADwADwDwAA8AA8A8AAPAAPAPAADwADwD4AA8AA8A+AAPAAPAPwAHwADwD8AD4AA8AfwD+AAPAH///AADwA///wAA8AH//4AAPAAf/4AAAAAB/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAD//+AAAAD///4AAAD////AAAB////4AAA/78D/AAAfw8AH4AAPweAA+AAD4PgAHwAB8DwAA8AAfA8AAPAAHgPAADwAD4DwAA8AA+A8AAPAAPAPgAHwADwD4AB8AA8AfgA+AAPAH+B/gAAAA///wAAAAH//4AAAAA//8AAAAAH/8AAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwAAAAAAA8AAAAAAAPAAAAAAADwAAAAAAA8AAAABAAPAAAABwADwAAAB8AA8AAAB/AAPAAAB/wADwAAD/8AA8AAD/8AAPAAD/4AADwAD/4AAA8AD/4AAAPAH/wAAADwH/wAAAA8H/wAAAAPH/wAAAAD3/gAAAAA//gAAAAAP/gAAAAAD/gAAAAAA/AAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwA/4AAAH/Af/AAAH/8P/4AAD//n//AAA//7//4AAfx/+A+AAHwD+AHwAD4AfgB8AA8AHwAPAAPAA8ADwADwAPAA8AA8ADwAPAAPAA8ADwADwAfAA8AA+AH4AfAAHwD+AHwAB/D/4D4AAP/+/n+AAD//n//AAAf/w//gAAB/wH/wAAAHwA/4AAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+AAAAAAD/8AAAAAD//wAAAAB//+AAAAA///wAAAAf4H+APAAH4AfgDwAD8AB8A8AA+AAfAPAAPAADwDwADwAA8B8AA8AAPAfAAPAADwHgADwAA8D4AA+AAeB+AAHwAHg/AAB+ADwfgAAP8D4/4AAD////8AAAf///8AAAB///+AAAAP//+AAAAAP/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAOAAAB8AAHwAAAfgAD8AAAH4AA/AAAB8AAHwAAAOAAA4AAAAAAAAAAAAAAAAAAAAAAAAAA"), 46, atob("DRUcHBwcHBwcHBwcDA=="), 50+(scale<<8)+(1<<16));
|
||||||
|
|
@ -67,7 +52,7 @@ const colorGreen = '#008000';
|
||||||
const colorBlue = '#0000ff';
|
const colorBlue = '#0000ff';
|
||||||
const colorYellow = '#ffff00';
|
const colorYellow = '#ffff00';
|
||||||
const widgetOffset = showWidgets ? 24 : 0;
|
const widgetOffset = showWidgets ? 24 : 0;
|
||||||
const dowOffset = circleCount == 3 ? 22 : 24; // dow offset relative to date
|
const dowOffset = circleCount == 3 ? 20 : 22; // dow offset relative to date
|
||||||
const h = g.getHeight() - widgetOffset;
|
const h = g.getHeight() - widgetOffset;
|
||||||
const w = g.getWidth();
|
const w = g.getWidth();
|
||||||
const hOffset = (circleCount == 3 ? 34 : 30) - widgetOffset;
|
const hOffset = (circleCount == 3 ? 34 : 30) - widgetOffset;
|
||||||
|
|
@ -103,10 +88,7 @@ const circleFontBig = circleCount == 3 ? "Vector:16" : "Vector:12";
|
||||||
const iconOffset = circleCount == 3 ? 6 : 8;
|
const iconOffset = circleCount == 3 ? 6 : 8;
|
||||||
const defaultCircleTypes = ["steps", "hr", "battery", "weather"];
|
const defaultCircleTypes = ["steps", "hr", "battery", "weather"];
|
||||||
|
|
||||||
|
function hideWidgets() {
|
||||||
function draw() {
|
|
||||||
g.clear(true);
|
|
||||||
if (!showWidgets) {
|
|
||||||
/*
|
/*
|
||||||
* we are not drawing the widgets as we are taking over the whole screen
|
* we are not drawing the widgets as we are taking over the whole screen
|
||||||
* so we will blank out the draw() functions of each widget and change the
|
* so we will blank out the draw() functions of each widget and change the
|
||||||
|
|
@ -118,6 +100,12 @@ function draw() {
|
||||||
wd.area = "";
|
wd.area = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
g.clear(true);
|
||||||
|
if (!showWidgets) {
|
||||||
|
hideWidgets();
|
||||||
} else {
|
} else {
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
}
|
}
|
||||||
|
|
@ -129,7 +117,7 @@ function draw() {
|
||||||
g.setFontRobotoRegular50NumericOnly();
|
g.setFontRobotoRegular50NumericOnly();
|
||||||
g.setFontAlign(0, -1);
|
g.setFontAlign(0, -1);
|
||||||
g.setColor(colorFg);
|
g.setColor(colorFg);
|
||||||
g.drawString(locale.time(new Date(), 1), w / 2, h1 + 8);
|
g.drawString(locale.time(new Date(), 1), w / 2, h1 + 6);
|
||||||
now = Math.round(new Date().getTime() / 1000);
|
now = Math.round(new Date().getTime() / 1000);
|
||||||
|
|
||||||
// date & dow
|
// date & dow
|
||||||
|
|
@ -138,10 +126,19 @@ function draw() {
|
||||||
g.drawString(locale.date(new Date()), w / 2, h2);
|
g.drawString(locale.date(new Date()), w / 2, h2);
|
||||||
g.drawString(locale.dow(new Date()), w / 2, h2 + dowOffset);
|
g.drawString(locale.dow(new Date()), w / 2, h2 + dowOffset);
|
||||||
|
|
||||||
|
// draw the circles a little bit delayed so we decrease the blocking time
|
||||||
|
setTimeout(function() {
|
||||||
drawCircle(1);
|
drawCircle(1);
|
||||||
|
}, 1);
|
||||||
|
setTimeout(function() {
|
||||||
drawCircle(2);
|
drawCircle(2);
|
||||||
|
}, 1);
|
||||||
|
setTimeout(function() {
|
||||||
drawCircle(3);
|
drawCircle(3);
|
||||||
|
}, 1);
|
||||||
|
setTimeout(function() {
|
||||||
if (circleCount >= 4) drawCircle(4);
|
if (circleCount >= 4) drawCircle(4);
|
||||||
|
}, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawCircle(index) {
|
function drawCircle(index) {
|
||||||
|
|
@ -248,6 +245,9 @@ function getGradientColor(color, percent) {
|
||||||
const colorList = [
|
const colorList = [
|
||||||
'#00FF00', '#80FF00', '#FFFF00', '#FF8000', '#FF0000'
|
'#00FF00', '#80FF00', '#FFFF00', '#FF8000', '#FF0000'
|
||||||
];
|
];
|
||||||
|
if (color == "fg") {
|
||||||
|
color = colorFg;
|
||||||
|
}
|
||||||
if (color == "green-red") {
|
if (color == "green-red") {
|
||||||
const colorIndex = Math.round(colorList.length * percent);
|
const colorIndex = Math.round(colorList.length * percent);
|
||||||
return colorList[Math.min(colorIndex, colorList.length) - 1] || "#00ff00";
|
return colorList[Math.min(colorIndex, colorList.length) - 1] || "#00ff00";
|
||||||
|
|
@ -325,6 +325,8 @@ function drawStepsDistance(w) {
|
||||||
function drawHeartRate(w) {
|
function drawHeartRate(w) {
|
||||||
if (!w) w = getCircleXPosition("hr");
|
if (!w) w = getCircleXPosition("hr");
|
||||||
|
|
||||||
|
const heartIcon = atob("EBCBAAAAAAAeeD/8P/x//n/+P/w//B/4D/AH4APAAYAAAAAA");
|
||||||
|
|
||||||
drawCircleBackground(w);
|
drawCircleBackground(w);
|
||||||
|
|
||||||
const color = getCircleColor("hr");
|
const color = getCircleColor("hr");
|
||||||
|
|
@ -349,6 +351,8 @@ function drawBattery(w) {
|
||||||
if (!w) w = getCircleXPosition("battery");
|
if (!w) w = getCircleXPosition("battery");
|
||||||
const battery = E.getBattery();
|
const battery = E.getBattery();
|
||||||
|
|
||||||
|
const powerIcon = atob("EBCBAAAAA8ADwA/wD/AP8A/wD/AP8A/wD/AP8A/wD/AH4AAA");
|
||||||
|
|
||||||
drawCircleBackground(w);
|
drawCircleBackground(w);
|
||||||
|
|
||||||
let color = getCircleColor("battery");
|
let color = getCircleColor("battery");
|
||||||
|
|
@ -426,6 +430,10 @@ function drawSunProgress(w) {
|
||||||
if (!w) w = getCircleXPosition("sunprogress");
|
if (!w) w = getCircleXPosition("sunprogress");
|
||||||
const percent = getSunProgress();
|
const percent = getSunProgress();
|
||||||
|
|
||||||
|
// sunset icons:
|
||||||
|
const sunSetDown = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAAGYAPAAYAAAAAA");
|
||||||
|
const sunSetUp = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAABgAPABmAAAAAA");
|
||||||
|
|
||||||
drawCircleBackground(w);
|
drawCircleBackground(w);
|
||||||
|
|
||||||
const color = getCircleColor("sunprogress");
|
const color = getCircleColor("sunprogress");
|
||||||
|
|
@ -559,6 +567,18 @@ function windAsBeaufort(windInKmh) {
|
||||||
*/
|
*/
|
||||||
function getWeatherIconByCode(code) {
|
function getWeatherIconByCode(code) {
|
||||||
const codeGroup = Math.round(code / 100);
|
const codeGroup = Math.round(code / 100);
|
||||||
|
|
||||||
|
// weather icons:
|
||||||
|
const weatherCloudy = atob("EBCBAAAAAAAAAAfgD/Af8H/4//7///////9//z/+AAAAAAAA");
|
||||||
|
const weatherSunny = atob("EBCBAAAAAYAQCBAIA8AH4A/wb/YP8A/gB+ARiBAIAYABgAAA");
|
||||||
|
const weatherMoon = atob("EBCBAAAAAYAP8B/4P/w//D/8f/5//j/8P/w//B/4D/ABgAAA");
|
||||||
|
const weatherPartlyCloudy = atob("EBCBAAAAAAAYQAMAD8AIQBhoW+AOYBwwOBBgHGAGP/wf+AAA");
|
||||||
|
const weatherRainy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQAJBgjPOEkgGYAZgA8ABgAAA");
|
||||||
|
const weatherPartlyRainy = atob("EBCBAAAAEEAQAAeADMAYaFvoTmAMMDgQIBxhhiGGG9wDwAGA");
|
||||||
|
const weatherSnowy = atob("EBCBAAAAAAADwAGAEYg73C50BCAEIC50O9wRiAGAA8AAAAAA");
|
||||||
|
const weatherFoggy = atob("EBCBAAAAAAADwAZgDDA4EGAcQAZAAgAAf74AAAAAd/4AAAAA");
|
||||||
|
const weatherStormy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQMJAgjmOGcgAgACAAAAAAAAA");
|
||||||
|
|
||||||
switch (codeGroup) {
|
switch (codeGroup) {
|
||||||
case 2:
|
case 2:
|
||||||
return weatherStormy;
|
return weatherStormy;
|
||||||
|
|
@ -823,7 +843,6 @@ if (isCircleEnabled("hr")) {
|
||||||
enableHRMSensor();
|
enableHRMSensor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Bangle.setUI("clock");
|
Bangle.setUI("clock");
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{ "id": "circlesclock",
|
{ "id": "circlesclock",
|
||||||
"name": "Circles clock",
|
"name": "Circles clock",
|
||||||
"shortName":"Circles clock",
|
"shortName":"Circles clock",
|
||||||
"version":"0.10",
|
"version":"0.11",
|
||||||
"description": "A clock with three or four circles for different data at the bottom in a probably familiar style",
|
"description": "A clock with three or four circles for different data at the bottom in a probably familiar style",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}, {"url":"screenshot-dark-4.png"}, {"url":"screenshot-light-4.png"}],
|
"screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}, {"url":"screenshot-dark-4.png"}, {"url":"screenshot-light-4.png"}],
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,10 @@
|
||||||
const valuesCircleTypes = ["empty", "steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "temperature", "pressure", "altitude"];
|
const valuesCircleTypes = ["empty", "steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "temperature", "pressure", "altitude"];
|
||||||
const namesCircleTypes = ["empty", "steps", "distance", "heart", "battery", "weather", "sun", "temperature", "pressure", "altitude"];
|
const namesCircleTypes = ["empty", "steps", "distance", "heart", "battery", "weather", "sun", "temperature", "pressure", "altitude"];
|
||||||
|
|
||||||
const valuesColors = ["", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff", "#fff", "#000", "green-red", "red-green"];
|
const valuesColors = ["", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff",
|
||||||
const namesColors = ["default", "red", "green", "blue", "yellow", "magenta", "cyan", "white", "black", "green->red", "red->green"];
|
"#00ffff", "#fff", "#000", "green-red", "red-green", "fg"];
|
||||||
|
const namesColors = ["default", "red", "green", "blue", "yellow", "magenta",
|
||||||
|
"cyan", "white", "black", "green->red", "red->green", "foreground"];
|
||||||
|
|
||||||
const weatherData = ["empty", "humidity", "wind"];
|
const weatherData = ["empty", "humidity", "wind"];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,4 @@
|
||||||
0.23: Customizer! Unused fonts no longer take up precious memory.
|
0.23: Customizer! Unused fonts no longer take up precious memory.
|
||||||
0.24: Added previews to the customizer.
|
0.24: Added previews to the customizer.
|
||||||
0.25: Fixed a bug that would let widgets change the color of the clock.
|
0.25: Fixed a bug that would let widgets change the color of the clock.
|
||||||
|
0.26: Time formatted to locale
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,11 @@
|
||||||
|
var is12;
|
||||||
|
function getHours(d) {
|
||||||
|
var h = d.getHours();
|
||||||
|
if (is12===undefined) is12 = (require('Storage').readJSON('setting.json',1)||{})["12hour"];
|
||||||
|
if (!is12) return h;
|
||||||
|
return (h%12==0) ? 12 : h%12;
|
||||||
|
}
|
||||||
|
|
||||||
exports.drawClock = function(fontIndex) {
|
exports.drawClock = function(fontIndex) {
|
||||||
var digits = [];
|
var digits = [];
|
||||||
fontFile=require("Storage").read("contourclock-"+Math.abs(parseInt(fontIndex+0.5))+".json");
|
fontFile=require("Storage").read("contourclock-"+Math.abs(parseInt(fontIndex+0.5))+".json");
|
||||||
|
|
@ -15,8 +23,8 @@ exports.drawClock = function(fontIndex) {
|
||||||
var y = g.getHeight()/2-digits[0].height/2;
|
var y = g.getHeight()/2-digits[0].height/2;
|
||||||
var date = new Date();
|
var date = new Date();
|
||||||
g.clearRect(0,38,g.getWidth()-1,138);
|
g.clearRect(0,38,g.getWidth()-1,138);
|
||||||
d1=parseInt(date.getHours()/10);
|
d1=parseInt(getHours(date)/10);
|
||||||
d2=parseInt(date.getHours()%10);
|
d2=parseInt(getHours(date)%10);
|
||||||
d3=10;
|
d3=10;
|
||||||
d4=parseInt(date.getMinutes()/10);
|
d4=parseInt(date.getMinutes()/10);
|
||||||
d5=parseInt(date.getMinutes()%10);
|
d5=parseInt(date.getMinutes()%10);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{ "id": "contourclock",
|
{ "id": "contourclock",
|
||||||
"name": "Contour Clock",
|
"name": "Contour Clock",
|
||||||
"shortName" : "Contour Clock",
|
"shortName" : "Contour Clock",
|
||||||
"version":"0.25",
|
"version":"0.26",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"description": "A Minimalist clockface with large Digits. Now with more fonts!",
|
"description": "A Minimalist clockface with large Digits. Now with more fonts!",
|
||||||
"screenshots" : [{"url":"cc-screenshot-1.png"},{"url":"cc-screenshot-2.png"}],
|
"screenshots" : [{"url":"cc-screenshot-1.png"},{"url":"cc-screenshot-2.png"}],
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
|
0.02: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up".
|
||||||
|
|
|
||||||
|
|
@ -133,15 +133,6 @@ Bangle.on('lcdPower', (on) => {
|
||||||
clearTimers();
|
clearTimers();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Bangle.on('faceUp',function(up){
|
|
||||||
//console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn());
|
|
||||||
if (up && !Bangle.isLCDOn()) {
|
|
||||||
//console.log("faceUp and LCD off");
|
|
||||||
clearTimers();
|
|
||||||
Bangle.setLCDPower(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
g.clear();
|
g.clear();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "crowclk",
|
"id": "crowclk",
|
||||||
"name": "Crow Clock",
|
"name": "Crow Clock",
|
||||||
"version": "0.01",
|
"version": "0.02",
|
||||||
"description": "A simple clock based on Bold Clock that has MST3K's Crow T. Robot for a face",
|
"description": "A simple clock based on Bold Clock that has MST3K's Crow T. Robot for a face",
|
||||||
"icon": "crow_clock.png",
|
"icon": "crow_clock.png",
|
||||||
"screenshots": [{"url":"screenshot_crow.png"}],
|
"screenshots": [{"url":"screenshot_crow.png"}],
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
0.01: first release
|
||||||
|
0.02: added settings menu to change color
|
||||||
|
0.03: fix metadata.json to allow setting as clock
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Daisy
|
||||||
|
|
||||||
|
*A beautiful digital clock with large ring guage, idle timer and a
|
||||||
|
cyclic information line that includes, day, date, steps, battery,
|
||||||
|
sunrise and sunset times*
|
||||||
|
|
||||||
|
Written by: [Hugh Barney](https://github.com/hughbarney) For support
|
||||||
|
and discussion please post in the [Bangle JS
|
||||||
|
Forum](http://forum.espruino.com/microcosms/1424/)
|
||||||
|
|
||||||
|
* Derived from `The Ring` proof of concept and the [Pastel clock](https://banglejs.com/apps/?q=pastel)
|
||||||
|
* Includes the [Lazybones](https://banglejs.com/apps/?q=lazybones) Idle warning timer
|
||||||
|
* Touch the top right/top left to cycle through the info display (Day, Date, Steps, Sunrise, Sunset)
|
||||||
|
* Uses mylocation.json from MyLocation app to calculate sunrise and sunset times for your location
|
||||||
|
* The screen is updated every minute to save battery power
|
||||||
|
* Uses the [BloggerSansLight](https://www.1001fonts.com/rounded-fonts.html?page=3) font, which if free for commercial use
|
||||||
|
|
||||||
|
## Future Development
|
||||||
|
* Add a heart rate option in the information line that turns on when selected
|
||||||
|
* Use mini icons in the information line rather that text
|
||||||
|
* Add weather icons as per Pastel clock
|
||||||
|
* Add a lock icon to the screen
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|

|
||||||
|
|
||||||
|
It is worth looking at the real thing though as the screenshot does not do it justice.
|
||||||
|
(Though I need to redo this photo at some point)
|
||||||
|

|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEw4UA///pf+sdR0n8CAkCwAcJhNgBI8KwALBgWgCo8NqAZHhNYktYloLKkoLHqwLByoLEgXoBYsrK4UDq0CqulrVVwGV4AXCquCBYYEBC4UC6tiBYeJq57DytayttvNW0tWHgclq2VtNpAYNYKQgiBBYIkBKgUK9Q8B9Nq1Nrqug1WgCoOqytq1/61NW1XVsALBq2ttbMB9N62olBKQNVtNvBYP61dVKgWlqtY34LB/wGBvQ8CEgIKBAAOVq7NDGwILD2/qBQWqAAILDAwUAlIzB1YLD9X1q+oytVqtbBYflA4NeBZVWlQjJ9A7LKZhrLQZS9Bqvq16bGWZXgZY2JZYcK1TjC9WrcYOAcYL7FpL7EAAMlq219NrRYNYBYeVrWV9t7q2lqwKCFwNi6utvVXxLuCBYWCGAIuBAgILCgdegVXBYPVwG1C4eohNWktYyvglYLCKgVeBYO1KQgLCrElvElBY94loBBBY/ghtghILGhSsBsECRgQZHBI5XCJ4kAA="))
|
||||||
|
|
@ -0,0 +1,483 @@
|
||||||
|
var SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js");
|
||||||
|
const storage = require('Storage');
|
||||||
|
const locale = require("locale");
|
||||||
|
const SETTINGS_FILE = "daisy.json";
|
||||||
|
const LOCATION_FILE = "mylocation.json";
|
||||||
|
const h = g.getHeight();
|
||||||
|
const w = g.getWidth();
|
||||||
|
let settings;
|
||||||
|
let location;
|
||||||
|
|
||||||
|
// variable for controlling idle alert
|
||||||
|
let lastStep = getTime();
|
||||||
|
let warned = 0;
|
||||||
|
let idle = false;
|
||||||
|
let IDLE_MINUTES = 26;
|
||||||
|
|
||||||
|
var pal1; // palette for 0-40%
|
||||||
|
var pal2; // palette for 50-100%
|
||||||
|
const infoWidth = 50;
|
||||||
|
const infoHeight = 14;
|
||||||
|
var drawingSteps = false;
|
||||||
|
|
||||||
|
function log_debug(o) {
|
||||||
|
//print(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.1001fonts.com/rounded-fonts.html?page=3
|
||||||
|
Graphics.prototype.setFontBloggerSansLight46 = function(scale) {
|
||||||
|
// Actual height 46 (45 - 0)
|
||||||
|
this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAAAA/AAAAAAAAPwAAAAAAAD4AAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAH/gAAAAAAP/wAAAAAAf/gAAAAAAf/AAAAAAA//AAAAAAB/+AAAAAAD/8AAAAAAH/4AAAAAAH/wAAAAAAP/gAAAAAAf/gAAAAAA//AAAAAAB/+AAAAAAA/8AAAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///8AAAAP////4AAAP/////AAAH/////4AAD+AAAB/AAA8AAAAHwAAeAAAAA+AAHgAAAAHgADwAAAAB4AA8AAAAAPAAPAAAAADwADwAAAAA8AA8AAAAAPAAPAAAAADwAB4AAAAB4AAeAAAAAeAAHwAAAAPgAA/AAAAPwAAH/////4AAA/////8AAAH////+AAAAf///+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAPAAAAAAAAHwAAAAAAAB4AAAAAAAA+AAAAAAAAfAAAAAAAAHgAAAAAAAD4AAAAAAAB8AAAAAAAAeAAAAAAAAPgAAAAAAADwAAAAAAAB//////4AAf//////AAH//////gAA//////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAD4AAHAAAAD+AAD4AAAB/gAA8AAAB/4AAfAAAA/+AAHgAAAf3gAB4AAAPx4AA8AAAH4eAAPAAAD4HgADwAAB8B4AA8AAA+AeAAPAAAfAHgADwAAPgB4AA8AAHwAeAAHgAD4AHgAB4AD8AB4AAfAB+AAeAAD8B/AAHgAAf//gAB4AAH//wAAeAAAf/wAAHgAAB/wAAA4AAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AADgAAAAPAAB4AAAADwAAeAAAAA+AAHgAAAAHgAB4ABgAB4AAeAA8AAeAAHgA/AADwAB4AfwAA8AAeAP8AAPAAHgH/AADwAB4H7wAA8AAeD48AAPAAHh8PAAHgAB5+BwAB4AAe/AeAA+AAH/AHwAfAAB/gA/AfgAAfwAH//wAAHwAA//4AAA4AAH/8AAAAAAAf4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAD+AAAAAAAD/gAAAAAAH/4AAAAAAH/+AAAAAAP/ngAAAAAP/h4AAAAAf/AeAAAAAf/AHgAAAA/+AB4AAAA/+AAeAAAB/8AAHgAAA/8AAB4AAAP4AAAeAAAB4AAAHgAAAAAAAB4AAAAAAAAeAAAAAAP///4AAAAH////AAAAA////gAAAAP///4AAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAD4AA8AAD///gAPAAB///4AD4AAf//+AAeAAH+APAAHgAB4AHgAA4AAeAB4AAOAAHgAcAADwAB4AHAAA8AAeADwAAPAAHgAcAADwAB4AHAAA8AAeAB4AAeAAHgAeAAHgAB4AHwAD4AAeAA+AB8AAHgAP4B+AAB4AB///gAAOAAP//gAABAAA//wAAAAAAD/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/gAAAAAB///4AAAAD////wAAAD////+AAAB/////4AAA/gPgB/AAAfgDwAHwAAPgA8AA+AADwAeAAHgAB4AHgAB4AAeAB4AAfAAHgAeAADwABwAHgAA8AAcAB4AAPAAHAAeAAHwAB4AHgAB4AAeAB8AAeAAHgAPAAPgAB4AD8APwAAOAAfwP4AADgAD//8AAAAAAf/+AAAAAAB/+AAAAAAAH8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAA4AAeAAAAB/AAHgAAAB/wAB4AAAB/4AAeAAAD/4AAHgAAD/wAAB4AAH/wAAAeAAH/gAAAHgAP/gAAAB4AP/AAAAAeAf/AAAAAHgf+AAAAAB4/+AAAAAAe/8AAAAAAH/8AAAAAAB/4AAAAAAAf4AAAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/gAAAA/AB/+AAAA/8B//wAAA//gf/+AAAf/8PgPgAAH4fngB8AAD4B/wAPgAA8AP8AB4AAeAB+AAeAAHgAfgADwAB4ADwAA8AAcAA8AAPAAHAAPAADwAB4ADwAA8AAeAB+AAPAAHgAfgAHgAB8AP8AB4AAPgH/AA+AAD8H54AfAAAf/8fgPwAAD/+D//4AAAf/Af/8AAAB/AD/+AAAAAAAP+AAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHwAAAAAAAf/wAAAAAAf/+AAAAAAP//4AAwAAH//+AAeAAD+APwAHgAA+AA+AB4AAfAAHgAOAAHgAB4ADwAB4AAPAA8AAeAADwAPAAHgAA8ADwAB4AAPAA8AAeAADwAPAAHgAA8AHgAB8AAeAB4AAPgAHgA+AAD8ADwA/AAAfwA8A/gAAD/wef/wAAAf////4AAAB////4AAAAH///wAAAAAD/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AB4AAAAAfgA/AAAAAH4APwAAAAB+AD4AAAAAPAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DRAcHBwcHBwcHBwcDQ=="), 56+(scale<<8)+(1<<16));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Graphics.prototype.setFontRoboto20 = function(scale) {
|
||||||
|
// Actual height 21 (20 - 0)
|
||||||
|
this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAH/zA/+YAAAAAAAHwAAwAAHwAA+AAAAAAAAAAAQACDAAYbADP4B/8A/zAGYZADH4A/+A/7AHYYADCAAAAAAAQAeHgH4eBzgwMMHnhw88GGBw4wHj+AcPgAAAAAAAAAAB4AA/gAGMAAwhwGMcAfuABzgABzgAc+AOMYBhBAAMYAB/AAHwAAAAAHwD5+A/8YGPDAw8YGPzA/HYD4fAADwAB/AAOYAABAAAAHwAA4AAAAAAAAAAH/gD//B8A+cAA7AADAAAAAAAYAAbwAHHgHwf/4A/8AAAAEAABiAAGwAA8AA/AAH+AAGwAByAAEAAAAAAAMAABgAAMAABgAH/wA/+AAMAABgAAMAABgAAAAAAAIAAfAADwAAAABgAAMAABgAAMAABgAAAAAAAAAAAAADAAAYAAAAAAAAADgAB8AB+AA+AA+AA/AAHAAAgAAAAAAB8AB/8Af/wHAHAwAYGADAwAYHAHAf/wB/8AAAAAAAAAAABgAAcAADAAAYAAH//A//4AAAAAAAAAAAAAAAAAAAAABwDAeA4HAPAwHYGBzAwcYHHDAfwYB8DAAAYAAAAAAABgOAcBwHADAwwYGGDAwwYHPHAf/wB58AAAAAAAAADAAB4AAfAAPYAHjAB4YA8DAH//A//4AAYAADAAAAAAAAAEMA/xwH+HAxgYGMDAxgYGODAw/4GD+AAHAAAAAAAAAf8AP/wD2HA5wYGMDAxgYGOHAA/wAD8AAAAAAAAAAAGAAAwAAGADAwB4GB+Aw+AGfAA/gAHwAAwAAAAAAADAB5+Af/wHPDAwwYGGDAwwYHPHAfvwB58AAAAAAAAAAAB+AAf4AHDjAwMYGBjAwM4HDOAf/gB/4AAAAAAAAAAAAYDADAYAAAAAAAAAAYDAfAYHwAAAABAAAcAADgAA+AAGwAB3AAMYABjgAYMAAAAAAAAAAAAAAABmAAMwABmAAMwABmAAMwABmAAMwAAiAAAAAAAAAYMADjgAMYAB3AAGwAA2AADgAAcAABAAAAAAAAAMAADgAA4AAGBzAweYGHAA/wAD8AAEAAAAwAB/4A/PwOAGDgAYYPxmH/Mw4ZmMDMxgZmM+Mx/5mHDAYAIDgDAPBwAf8AAMAAAAAAAYAAfAAPwAP4AH+AH4wA8GAH4wAP2AAPwAAfwAAfAAAYAAAAAAAAAAA//4H//AwwYGGDAwwYGGDAwwYH/HAf/wB58AAAAADAAH/AD/+AcBwHADAwAYGADAwAYGADA4A4DweAODgAAAAAAAAAAAAAAH//A//4GADAwAYGADAwAYGADAYAwD4+AP/gAfwAAAAAAAAAAAH//A//4GDDAwYYGDDAwYYGDDAwYYGCDAgAYAAAAAAAH//A//4GDAAwYAGDAAwYAGDAAwYAGAAAAAAAAAAH/AD/8AcBwHAHAwAYGADAwYYGDDA4YYDz/AOfwAAAAAAAAAAA//4H//A//4ADAAAYAADAAAYAADAAAYAADAA//4H//AAAAAAAAAAAAAAA//4H//AAAAAAAAABAAAeAAB4AADAAAYAADAAAYAAHA//wH/8AAAAAAAAAAAAAAA//4H//AAcAAPAAD4AA/wAOPADg8A4B4GAHAgAYAAAAAAAH//A//4AADAAAYAADAAAYAADAAAYAADAAAAAAAA//4H//A+AAB+AAD8AAD8AAH4AAPAAH4AH4AD8AD8AA+AAH//A//4AAAAAAAH//A//4H//AeAAB8AADwAAPgAAeAAA8AADwH//A//4AAAAAAAAAAAH/AB/8AeDwHAHAwAYGADAwAYGADA4A4DweAP/gA/4AAAAAAAAAAAH//A//4GBgAwMAGBgAwMAGBgAwcAH/AAfwAA8AAAAAA/4AP/gDgOA4A4GADAwAYGADAwAYHAHgeD+B/8wD+GAAAAAAAAAAA//4H//AwYAGDAAwYAGDgAweAHH8Afz4B8HAAAIAAYAPDwD8OA5w4GGDAwwYGHDAwYYHDnAePwBw8AAAAGAAAwAAGAAAwAAGAAA//4H//AwAAGAAAwAAGAAAwAAAAAAAAAH/4A//wAAPAAAYAADAAAYAADAAAYAAPA//wH/8AAAAAAAAgAAHAAA/AAB/AAD+AAD+AAD4AAfAAfwAfwAfwAH4AA4AAEAAA+AAH/AAH/gAD/AAD4AD+AH+AH8AA+AAH+AAD+AAD/AAD4AH/AP/AH+AA8AAAAAAAAAGADA4A4HweAPPgA/wAB8AAfwAPvgDweA8B4GADAAAIGAAA4AAHwAAPgAAfAAA/4AH/AD4AB8AA+AAHgAAwAAAAAAAAAGADAwB4GAfAwPYGDzAx4YGeDA/AYHwDA4AYGADAAAAAAAA///3//+wAA2AAGAAAGAAA+AAD8AAD8AAD4AAH4AAHgAAMAAAAwAA2AAG///3//+AAAAAAAAAAAOAAHwAD4AA8AAD8AADwAAGAAAAAAABgAAMAABgAAMAABgAAMAABgAAMAABgAAAEAAAwAADAAAIAAAAAAAAAAEeABn4Ad3ADMYAZjADMYAZmAB/4AP/AAAAAAAA//4H//ABgwAYDADAYAYDADg4AP+AA/gABwAAAAAAAAA/gAP+ADg4AYDADAYAYDADAYAOOABxwAAAAAEAAH8AB/wAcHADAYAYDADAYAcDA//4H//AAAAAAAAAAAAH8AB/wAdnADMYAZjADMYAZjAB84AHmAAMAAMAABgAB//gf/8HMAAxgAGIAAAAAAH8IB/zAcHMDAZgYDMDAZgcHcD//Af/wAAAAAAAAAAH//A//4AMAADAAAYAADAAAcAAD/4AP/AAAAAAAAAAAGf/Az/4AAAAAAAAAAMz//mf/4AAAAAAAAAAH//A//4ABwAAeAAH4ABzwAcPACAYAABAAAAAAAA//4H//AAAAAAAAAAAAf/AD/4AMAADAAAYAADAAAcAAD/4AP/ABgAAYAADAAAYAADgAAP/AA/4AAAAAAAAf/AD/4AMAADAAAYAADAAAcAAD/4AP/AAAAAAAAAAAAH8AB/wAcHADAYAYDADAYAYDADx4AP+AA/gAAAAAAAAf/8D//gYDADAYAYDADAYAcHAB/wAH8AAEAAAAAAEAAH8AB/wAcHADAYAYDADAYAYDAD//gf/8AAAAAAAAAAAf/AD/4AcAADAAAYAACAAAAEAB5wAfnADMYAZjADGYAYzADn4AOeAAAAAAAADAAAYAAf/wD//ADAYAYDAAAAAAAAD/gAf/AAA4AADAAAYAADAAAwAf/AD/4AAAAAAAAYAAD4AAP4AAP4AAPAAH4AH4AD8AAcAAAAAAQAADwAAf4AAf4AAPAAP4AP4ADwAAfgAA/gAA/AAD4AH+AD+AAeAAAAAAAAACAYAcHADzwAH8AAfAAH8ADx4AcHACAIAcAMD4BgP4MAP/AAPwAP4AP4AD4AAcAAAAAAAAADAYAYHADD4AY7ADOYAfjADwYAcDADAYAAAAADAAA4AH//B/v8cABzAACAAAH//w//+AAAAAAACAACcAAx/n+H//AA4AAHAAAAAAAAAAAAAOAADgAAYAADAAAcAABgAAGAAAwAAGAADwAAcAAAAA"), 32, atob("BQUHDQwPDQQHBwkMBAYGCQwMDAwMDAwMDAwFBAsMCwoTDg0ODgwMDg8GDA0LEg8ODQ4NDA0ODRMNDQ0GCQYJCQYLDAsMCwcMDAUFCwUSDAwMDAcLBwwKEAoKCgcFBw4A"), 21+(scale<<8)+(1<<16));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
function assignPalettes() {
|
||||||
|
// palette for 0-40%
|
||||||
|
pal1 = new Uint16Array([g.theme.bg, g.toColor(settings.gy), g.toColor(settings.fg), g.toColor("#00f")]);
|
||||||
|
// palette for 50-100%
|
||||||
|
pal2 = new Uint16Array([g.theme.bg, g.toColor(settings.fg), g.toColor(settings.gy), g.toColor("#00f")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSmallFont20() {
|
||||||
|
g.setFontRoboto20();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setLargeFont() {
|
||||||
|
g.setFontBloggerSansLight46(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSmallFont() {
|
||||||
|
g.setFont('Vector', 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSteps() {
|
||||||
|
try {
|
||||||
|
return Bangle.getHealthStatus("day").steps;
|
||||||
|
} catch (e) {
|
||||||
|
if (WIDGETS.wpedom !== undefined)
|
||||||
|
return WIDGETS.wpedom.getSteps();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////// sunrise / sunset /////////////////////////////
|
||||||
|
|
||||||
|
function loadSettings() {
|
||||||
|
settings = require("Storage").readJSON(SETTINGS_FILE,1)||{};
|
||||||
|
settings.gy = settings.gy||'#020';
|
||||||
|
settings.fg = settings.fg||'#0f0';
|
||||||
|
settings.idle_check = settings.idle_check||true;
|
||||||
|
assignPalettes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// requires the myLocation app
|
||||||
|
function loadLocation() {
|
||||||
|
location = require("Storage").readJSON(LOCATION_FILE,1)||{};
|
||||||
|
location.lat = location.lat||51.5072;
|
||||||
|
location.lon = location.lon||0.1276;
|
||||||
|
location.location = location.location||"London";
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractTime(d){
|
||||||
|
var h = d.getHours(), m = d.getMinutes();
|
||||||
|
return(("0"+h).substr(-2) + ":" + ("0"+m).substr(-2));
|
||||||
|
}
|
||||||
|
|
||||||
|
var sunRise = "00:00";
|
||||||
|
var sunSet = "00:00";
|
||||||
|
var drawCount = 0;
|
||||||
|
|
||||||
|
function updateSunRiseSunSet(now, lat, lon, line){
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
const infoData = {
|
||||||
|
ID_DATE: { calc: () => {var d = (new Date()).toString().split(" "); return d[2] + ' ' + d[1] + ' ' + d[3];} },
|
||||||
|
ID_DAY: { calc: () => {var d = require("locale").dow(new Date()).toLowerCase(); return d[0].toUpperCase() + d.substring(1);} },
|
||||||
|
ID_SR: { calc: () => 'Sunrise: ' + sunRise },
|
||||||
|
ID_SS: { calc: () => 'Sunset: ' + sunSet },
|
||||||
|
ID_STEP: { calc: () => 'Steps: ' + getSteps() },
|
||||||
|
ID_BATT: { calc: () => 'Battery: ' + E.getBattery() + '%' }
|
||||||
|
};
|
||||||
|
|
||||||
|
const infoList = Object.keys(infoData).sort();
|
||||||
|
let infoMode = infoList[0];
|
||||||
|
|
||||||
|
function nextInfo() {
|
||||||
|
let idx = infoList.indexOf(infoMode);
|
||||||
|
if (idx > -1) {
|
||||||
|
if (idx === infoList.length - 1) infoMode = infoList[0];
|
||||||
|
else infoMode = infoList[idx + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function prevInfo() {
|
||||||
|
let idx = infoList.indexOf(infoMode);
|
||||||
|
if (idx > -1) {
|
||||||
|
if (idx === 0) infoMode = infoList[infoList.length - 1];
|
||||||
|
else infoMode = infoList[idx - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// putting into 1 function like this, rather than individual variables
|
||||||
|
// reduces ram usage from 70%-13%
|
||||||
|
function getGaugeImage(p) {
|
||||||
|
// p0
|
||||||
|
if (p < 2) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVAAVUFUgpDAAdAFMEBFQ4ABqBVnLMQqLLLzWEABLgbVgohEGopYaiofDBihWVHJpYYDgYPbKx1ACJhYZIwT4OcAZWYHyRYUIgQXQH4RqOThCXUYRpCHNyQVVQQTwVQiSZWIQSEQNgSYSIYiEQQSyEUCQLDSOAyCnQiSCYQiSCYQiSCZDaDARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A"))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p2
|
||||||
|
if (p >= 2 && p < 4) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette: pal1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/ADNUFE8FqtVq2q1AqkFIIrDAAOAFMEBFQYrE1WgKsYrGLL4qFFY2pqDWeFZdUVkAhCAQMKFYdVLDUVFQYMHlWq0oMJKyoOJlQrCLDBWDB5clB5xWOoARMCARYWKwT4OgpYXKwY+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI"))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p4
|
||||||
|
if (p >= 4 && p < 7) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFY2loAqjFY1VqDWeFZdUVkAhEhQrDLDcVFQYMHlQrCBhBWVHJpYYDgYPbKx1ACJhYZIwT4OgpYXKwY+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI"))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p7
|
||||||
|
if (p >= 7 && p < 10) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgWlKzVACJgrCqBWYawgAJcAOlNBhWMCZ8qFYJYUgoqBC6ECFYJqOAApWSS4jCNQQ5uSCqqCCeCqESFQKZUIQSEQNgSYSIYiEQQSyEUCQLDSOAyCnQiSCYQiSCYQiSCZDaDARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A=="))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p10
|
||||||
|
if (p >= 10 && p < 20) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAOkQSdUFacK1WloCCSCaAAEFYKaQQSyEC0pvQirZTbomlIh6CYZAZFOQTBxDQhyCYOQhoPQS4bQHaBzaVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI"))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p20
|
||||||
|
if (p >= 20 && p < 30) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4AWgNVoAEGAERSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A="))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p30
|
||||||
|
if (p >= 30 && p < 40) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4rbgNVoArjgGq0Ar/FbMFFc+oFYYqkgEqFf4r/FY0VqgrlhWqFf4r/Ff4rdqorowArBqArlgQr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlhQrCioroAYIr/Ff4r/FbcFqorllWoFf4r/FY9AFcmqFYUBFc+gFf4rZgFVqAqjgWqwAr/FbdUFccFawkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHI"))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p40
|
||||||
|
if (p >= 40 && p < 50) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal1,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVqtW1WoFUgpBFYYABwApggIqDFYmq0BVjFYxZfFQorGLLrWCFZbgbVgtUBQcKLD8VFQYMHlQsDKzoOJFgZYYKwYPLFgZWaoARMLDJWCawgAJcAZWYCZ6FCLCkFFQNQCZ8CFYOoFaZWSLAmAQShWQLAiESQQRtTLAKESFQNUFacKQiSCCoArTgCESQSyEUirZTboyCnQiSCYQiSCYQiSCZQgeAVxwqYQgSwMVwNUFbMKWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbhdVFcTcHbT7cDFY0BbT7cD0ArxgtVoArfgGq1ArHFUDcBFY0VFceqFY1UFcMKFY1VFcmAFYtQFcMCFYsBFcugFYtAFcMAFYsFFcuoFYoqigEqFeEVFcuqFYlUFccKFYlVFc2AFYdQFccCFf4rbgNVoArjgGq0Ar/FbMFFc+oFYYqkgEqFf4r/FY0VqgrlhWqFf4r/Ff4rdqorowArBqArlgQr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlhQrCioroAYIr/Ff4r/FbcFqorllWoFf4r/FY9AFcmqFYUBFc+gFf4rZgFVqAqjgWqwAr/FbdUFccKFYkVFcwFDitVFccqFYkFFcuoFeNAFcWqFYkBFcugFYtQFUMCFYsAFcuAFYtUFcMKFY0VFcgHFitVFcMqFY0FFceoFY9AFcGqFY0BqtQFT8C1WgFeMAqtUFb8K1WAFY7cglQrIioriBI8FqtAFb2q1ArJbjzaBFZEBbj7aB0ALIFcLaHbkLaJFYbcd1QrKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAiEXKwKuNQjUBQR6EaiqCPQjVVQSATCqtUFSZvB1WACiSEUY4KCQQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A"))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p50
|
||||||
|
if (p >= 50 && p < 60) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal2,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZgGq0AqjgNVoAr/FbeoFccFFYkqFcwFDlWqFccVFYkKFctUFeOAFcVVFYkCFctQFYugFUMBFYsAFctAFYuoFcMFFY0qFcgHFlWqFcMVFY0KFcdUFY+AFcFVFY0C1WgFT8BqtQFeMA1WoFb8FqtAFY7cgiorIlQriBI8K1WAFb1VqgrJbjzaBFZECbj7aBqALIFcLaHbkLaJFYbcdqorKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAiEXKwKuNQjSCQQjSCQQjSCRAAIrB1AqTgorBoAUQQiyCSQgjdSbISCRQgZYSKwKCSQghYQKwSCSQghYQKwSCTAAMqFYOoCJsFFQNVFShYEwARMFQRWVLAiFMQIRWWLAosKFQZWXLAosIFQZWYLAzgFawZWbAAMKFgmq1IoEAANUFTQABFZtAFbgsFFYwqeWQorFVjZZJFYhVfcAwrCazoA/AHI"))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p60
|
||||||
|
if (p >= 60 && p < 70) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal2,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZgGq0AqjgNVoAr/FbeoFccFFYkqFcwFDlWqFccVFYkKFctUFeOAFcVVFYkCFctQFYugFUMBFYsAFctAFYuoFcMFFY0qFcgHFlWqFcMVFY0KFcdUFY+AFcFVFY0C1WgFT8BqtQFeMA1WoFb8FqtAFY7cgiorIlQriBI8K1WAFb1VqgrJbjzaBFZECbj7aBqALIFcLaHbkLaJFYbcdqorKbjzaKbkDaLbgSwcVwLaJWD6uLFYawaVwIrMbgKwaVwLaKbgawaVwLaLbgawZQQLaLWDiuOWAaEYQQKuMWAelNBqCLVxqEC0oRPQS6EC0oSQQSyECFYKEVQSIABFYI/QAAcFFYJDRCgSCmYYjdSCqqYCLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A"))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p70
|
||||||
|
if (p >= 70 && p < 80) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal2,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AFYegFccBFf4rbgWqwArjgFVqAr/FbMKFc9UFYYqkgEVFf4r/FY0q1ArlgtVFf4r/Ff4rd1QrooArB0ArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rb1ArlgorClQroAYIr/Ff4r/FbcK1QrlitUFf4r/FY+AFclVFYUCFc9QFf4rZAgoAggNVoAr/FbdUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA="))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p80
|
||||||
|
if (p >= 80 && p < 90) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal2,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AcIdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA="))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p90
|
||||||
|
if (p >= 90 && p < 100) return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal2,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESquq1ArTgqESNgOqwArTIYKERH4KCUQigSBbKTdGCKKCVQiTCCFSyERCALBQQjAPBoArXDZ7ARObKuBSZwcaVzR0QFYKuZWAYNZWCJJKMoKuaWAahKBhiwTJRSudURorBFTgfMVzqjDO5DaeZ5jaeJhhiKbi4rIbT4hLqoriPI7afUpS5BbTwiKFdZgIADSmHFYIqgbgIrGcgIriEYwzHADZ7HRY4rdaYrjHADcBFYoGBFcgkEGQwAeFYqKHFbzUEcQ4AdiorwiorlEogxFAD59FWoorhoArDqArjgIr/FbYwFAEJSDFf4rXgornqgrDFUkAior/Ff4rGAYYAjKYYr/Ff4r/FbdVFdFAFYNQFcsBFf4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/FbdUFcsFFYUVFdADBFf4r/Ff4rbAYYAjKYYr/Ff4rFoArkqorCgIrnqAr/FbIEFAEBSFFf4rYqgrjgorEiormAocVAogAfEooxFFcB9EFdq1DAD9VFYkBFctQFYoGEADokHFcp8FRQoAdag7iFFb4HFioHGADYjHGY4rcPYyLHADbTHcYNQFT4iIFdZgIADKmJqrcgiorIBIIrhMKIAXUpIrBbjzaBFZAKKbS5MJFcKkJbj4fLBYLcdqorKbjzPMbjxKNMhauTURawdJJorBWDShBFZiRBWDQcOHRyuPOhorBWDIbPWDRzQSYKEYIwLLOHgSEXDIJyPQjD2SQjCCQQjSCRCYY/QN4xDRQiyCSQgjdSCqqECLCRWBYyiECISBWCYqgXCLCBWCQSYYEIhxqCeChYFThoQCKypYEIxgPPLB4cKFQZWXDoosIBhhYWcArWDKzYhHABA1EADArNoArcFhgqeWQysgLJxVfcBLWdAH4A5A"))
|
||||||
|
};
|
||||||
|
|
||||||
|
// p100
|
||||||
|
return {
|
||||||
|
width : 176, height : 176, bpp : 2,
|
||||||
|
transparent : -1,
|
||||||
|
palette : pal2,
|
||||||
|
buffer : require("heatshrink").decompress(atob("AH4A/AH4ACgtVAAVUFUgpDAAdAFMEBFQ4ABqBVnLMQqLFjzWEABLgbVgohEGoqyaiofDBihWVHJpYYDgYPbKxz5NLDJGCfBzgDKzA+SLChECC6A/CNRycIS6jCNIQ5uSCqqCCeCqESTKxCCQiBsCTCRDEQiCCWQigSBYaRwGQU6ESQTCESQTCESQTIbQYCJzZVwKTODjSuaOiArBVzKwDBrKwRJJRlBVzSwDUJQMMWCZKKVzqiNFYIqcD5iudUYZ3IbTzPMbTxMMMRTcXFZDafEJdVFcR5HbT6lKXILaeERQrrMBAAaUw4rBFUDcBFYzkBFcQjGGY4AbPY6LHFbrTFcY4AbgIrFAwIrkEggyGADwrFRQ4reagjiHADsVFeEVFcolEGIoAfPoq1FFcNAFYdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA="))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
if (!idle)
|
||||||
|
drawClock();
|
||||||
|
else
|
||||||
|
drawIdle();
|
||||||
|
queueDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawClock() {
|
||||||
|
var date = new Date();
|
||||||
|
var timeStr = require("locale").time(date,1);
|
||||||
|
var da = date.toString().split(" ");
|
||||||
|
var time = da[4].substr(0,5);
|
||||||
|
var hh = da[4].substr(0,2);
|
||||||
|
var mm = da[4].substr(3,2);
|
||||||
|
var steps = getSteps();
|
||||||
|
var p_steps = Math.round(100*(steps/10000));
|
||||||
|
|
||||||
|
g.reset();
|
||||||
|
g.setColor(g.theme.bg);
|
||||||
|
g.fillRect(0, 0, w, h);
|
||||||
|
g.drawImage(getGaugeImage(p_steps), 0, 0);
|
||||||
|
setLargeFont();
|
||||||
|
|
||||||
|
g.setColor(settings.fg);
|
||||||
|
g.setFontAlign(1,0); // right aligned
|
||||||
|
g.drawString(hh, (w/2) - 1, h/2);
|
||||||
|
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
|
g.setFontAlign(-1,0); // left aligned
|
||||||
|
g.drawString(mm, (w/2) + 1, h/2);
|
||||||
|
|
||||||
|
setSmallFont();
|
||||||
|
g.setFontAlign(0,0); // left aligned
|
||||||
|
g.drawString((infoData[infoMode].calc()), w/2, (3*h/4) - 4);
|
||||||
|
|
||||||
|
// recalc sunrise / sunset every hour
|
||||||
|
if (drawCount % 60 == 0)
|
||||||
|
updateSunRiseSunSet(new Date(), location.lat, location.lon);
|
||||||
|
drawCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawSteps() {
|
||||||
|
if (drawingSteps) return;
|
||||||
|
drawingSteps = true;
|
||||||
|
setSmallFont();
|
||||||
|
g.setFontAlign(0,0);
|
||||||
|
var steps = getSteps();
|
||||||
|
g.setColor(g.theme.bg);
|
||||||
|
g.fillRect((w/2) - infoWidth, (3*h/4) - infoHeight, (w/2) + infoWidth, (3*h/4) + infoHeight);
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
|
g.drawString('Steps ' + steps, w/2, (3*h/4) - 4);
|
||||||
|
drawingSteps = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Bangle.on('step', s => {
|
||||||
|
drawSteps();
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
///////////////// IDLE TIMER /////////////////////////////////////
|
||||||
|
|
||||||
|
function drawIdle() {
|
||||||
|
let mins = Math.round((getTime() - lastStep) / 60);
|
||||||
|
g.reset();
|
||||||
|
g.setColor(g.theme.bg);
|
||||||
|
g.fillRect(Bangle.appRect);
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
|
setSmallFont20();
|
||||||
|
g.setFontAlign(0, 0);
|
||||||
|
g.drawString('Last step was', w/2, (h/3));
|
||||||
|
g.drawString(mins + ' minutes ago', w/2, 20+(h/3));
|
||||||
|
dismissBtn.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////// BUTTON CLASS ///////////////////////////////////////////
|
||||||
|
|
||||||
|
// simple on screen button class
|
||||||
|
function BUTTON(name,x,y,w,h,c,f,tx) {
|
||||||
|
this.name = name;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.w = w;
|
||||||
|
this.h = h;
|
||||||
|
this.color = c;
|
||||||
|
this.callback = f;
|
||||||
|
this.text = tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if pressed the callback
|
||||||
|
BUTTON.prototype.check = function(x,y) {
|
||||||
|
//console.log(this.name + ":check() x=" + x + " y=" + y +"\n");
|
||||||
|
|
||||||
|
if (x>= this.x && x<= (this.x + this.w) && y>= this.y && y<= (this.y + this.h)) {
|
||||||
|
log_debug(this.name + ":callback\n");
|
||||||
|
this.callback();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
BUTTON.prototype.draw = function() {
|
||||||
|
g.setColor(this.color);
|
||||||
|
g.fillRect(this.x, this.y, this.x + this.w, this.y + this.h);
|
||||||
|
g.setColor("#000"); // the icons and boxes are drawn black
|
||||||
|
setSmallFont20();
|
||||||
|
g.setFontAlign(0, 0);
|
||||||
|
g.drawString(this.text, (this.x + this.w/2), (this.y + this.h/2));
|
||||||
|
g.drawRect(this.x, this.y, (this.x + this.w), (this.y + this.h));
|
||||||
|
};
|
||||||
|
|
||||||
|
function dismissPrompt() {
|
||||||
|
idle = false;
|
||||||
|
warned = false;
|
||||||
|
lastStep = getTime();
|
||||||
|
Bangle.buzz(100);
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
var dismissBtn = new BUTTON("big",0, 3*h/4 ,w, h/4, "#0ff", dismissPrompt, "Dismiss");
|
||||||
|
|
||||||
|
Bangle.on('touch', function(button, xy) {
|
||||||
|
var x = xy.x;
|
||||||
|
var y = xy.y;
|
||||||
|
// adjust for outside the dimension of the screen
|
||||||
|
// http://forum.espruino.com/conversations/371867/#comment16406025
|
||||||
|
if (y > h) y = h;
|
||||||
|
if (y < 0) y = 0;
|
||||||
|
if (x > w) x = w;
|
||||||
|
if (x < 0) x = 0;
|
||||||
|
|
||||||
|
if (idle && dismissBtn.check(x, y)) return;
|
||||||
|
});
|
||||||
|
|
||||||
|
// if we get a step then we are not idle
|
||||||
|
Bangle.on('step', s => {
|
||||||
|
lastStep = getTime();
|
||||||
|
// redraw if we had been idle
|
||||||
|
if (idle == true) {
|
||||||
|
dismissPrompt();
|
||||||
|
}
|
||||||
|
idle = false;
|
||||||
|
warned = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
function checkIdle() {
|
||||||
|
log_debug("checkIdle()");
|
||||||
|
if (!settings.idle_check) {
|
||||||
|
idle = false;
|
||||||
|
warned = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hour = (new Date()).getHours();
|
||||||
|
let active = (hour >= 9 && hour < 21);
|
||||||
|
//let active = true;
|
||||||
|
let dur = getTime() - lastStep;
|
||||||
|
|
||||||
|
if (active && dur > IDLE_MINUTES * 60) {
|
||||||
|
drawIdle();
|
||||||
|
if (warned++ < 3) {
|
||||||
|
buzzer(warned);
|
||||||
|
log_debug("checkIdle: warned=" + warned);
|
||||||
|
Bangle.setLocked(false);
|
||||||
|
}
|
||||||
|
idle = true;
|
||||||
|
} else {
|
||||||
|
idle = false;
|
||||||
|
warned = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// timeout for multi-buzzer
|
||||||
|
var buzzTimeout;
|
||||||
|
|
||||||
|
// n buzzes
|
||||||
|
function buzzer(n) {
|
||||||
|
log_debug("buzzer n=" + n);
|
||||||
|
|
||||||
|
if (n-- < 1) return;
|
||||||
|
Bangle.buzz(250);
|
||||||
|
|
||||||
|
if (buzzTimeout) clearTimeout(buzzTimeout);
|
||||||
|
buzzTimeout = setTimeout(function() {
|
||||||
|
buzzTimeout = undefined;
|
||||||
|
buzzer(n);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
checkIdle();
|
||||||
|
draw();
|
||||||
|
}, 60000 - (Date.now() % 60000));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop updates when LCD is off, restart when on
|
||||||
|
Bangle.on('lcdPower',on=>{
|
||||||
|
if (on) {
|
||||||
|
draw(); // draw immediately, queue redraw
|
||||||
|
} else { // stop draw timer
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
drawTimeout = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bangle.setUI("clockupdown", btn=> {
|
||||||
|
if (btn<0) prevInfo();
|
||||||
|
if (btn>0) nextInfo();
|
||||||
|
draw();
|
||||||
|
});
|
||||||
|
|
||||||
|
loadSettings();
|
||||||
|
loadLocation();
|
||||||
|
|
||||||
|
g.clear();
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
/*
|
||||||
|
* we are not drawing the widgets as we are taking over the whole screen
|
||||||
|
* so we will blank out the draw() functions of each widget and change the
|
||||||
|
* area to the top bar doesn't get cleared.
|
||||||
|
*/
|
||||||
|
for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
|
||||||
|
draw();
|
||||||
|
After Width: | Height: | Size: 4.9 KiB |
|
|
@ -0,0 +1,18 @@
|
||||||
|
{ "id": "daisy",
|
||||||
|
"name": "Daisy",
|
||||||
|
"version":"0.03",
|
||||||
|
"dependencies": {"mylocation":"app"},
|
||||||
|
"description": "A clock based on the Pastel clock with large ring guage for steps",
|
||||||
|
"icon": "app.png",
|
||||||
|
"type": "clock",
|
||||||
|
"tags": "clock",
|
||||||
|
"supports" : ["BANGLEJS2"],
|
||||||
|
"screenshots": [{"url":"screenshot_daisy2.jpg"}],
|
||||||
|
"readme": "README.md",
|
||||||
|
"storage": [
|
||||||
|
{"name":"daisy.app.js","url":"app.js"},
|
||||||
|
{"name":"daisy.img","url":"app-icon.js","evaluate":true},
|
||||||
|
{"name":"daisy.settings.js","url":"settings.js"}
|
||||||
|
],
|
||||||
|
"data": [{"name":"daisy.json"}]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
|
@ -0,0 +1,51 @@
|
||||||
|
(function(back) {
|
||||||
|
const SETTINGS_FILE = "daisy.json";
|
||||||
|
|
||||||
|
// initialize with default settings...
|
||||||
|
let s = {'gy' : '#020',
|
||||||
|
'fg' : '#0f0',
|
||||||
|
'color': 'Green',
|
||||||
|
'check_idle' : true};
|
||||||
|
|
||||||
|
// ...and overwrite them with any saved values
|
||||||
|
// This way saved values are preserved if a new version adds more settings
|
||||||
|
const storage = require('Storage')
|
||||||
|
let settings = storage.readJSON(SETTINGS_FILE, 1) || s;
|
||||||
|
const saved = settings || {}
|
||||||
|
for (const key in saved) {
|
||||||
|
s[key] = saved[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
settings = s
|
||||||
|
storage.write(SETTINGS_FILE, settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
var color_options = ['Green','Orange','Cyan','Purple','Red','Blue'];
|
||||||
|
var fg_code = ['#0f0','#ff0','#0ff','#f0f','#f00','#00f'];
|
||||||
|
var gy_code = ['#020','#220','#022','#202','#200','#002'];
|
||||||
|
|
||||||
|
E.showMenu({
|
||||||
|
'': { 'title': 'Daisy Clock' },
|
||||||
|
'< Back': back,
|
||||||
|
'Colour': {
|
||||||
|
value: 0 | color_options.indexOf(s.color),
|
||||||
|
min: 0, max: 5,
|
||||||
|
format: v => color_options[v],
|
||||||
|
onchange: v => {
|
||||||
|
s.color = color_options[v];
|
||||||
|
s.fg = fg_code[v];
|
||||||
|
s.gy = gy_code[v];
|
||||||
|
save();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'Idle Warning': {
|
||||||
|
value: !!s.idle_check,
|
||||||
|
format: v => v ? /*LANG*/"Yes":/*LANG*/"No",
|
||||||
|
onchange: v => {
|
||||||
|
s.idle_check = v;
|
||||||
|
save();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
0.01: Initial version
|
||||||
|
0.02: Added BangleJS Two
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
The application is based on a technique that Thomas Edison used to prevent falling asleep using a steel ball. Essentially the app starts with a display that shows the current HR value that the watch alarm is set to and this can be adjusted with buttons 1 and 3. This HR settng should be the approximate value you want the alarm to trigger and so you should ideally know both what your HR is currently and what your heartrate normally is during sleep. For your current HR according to the watch, you can simply use the HR monitor available in the Espruino app loader, and then from that you can choose a lower value as the target for the alarm and adjust as required.
|
The application is based on a technique that Thomas Edison used to prevent falling asleep using a steel ball. Essentially the app starts with a display that shows the current HR value that the watch alarm is set to and this can be adjusted with buttons 1 and 3 (Mapped to top touch and bottom touch on Bangle 2). This HR settng should be the approximate value you want the alarm to trigger and so you should ideally know both what your HR is currently and what your heartrate normally is during sleep. For your current HR according to the watch, you can simply use the HR monitor available in the Espruino app loader, and then from that you can choose a lower value as the target for the alarm and adjust as required.
|
||||||
|
|
||||||
When you press the middle button on the side, the HR monitor starts, the alarm will trigger when your heart rate average drops to the limit you’ve set and has a certain level of steadiness that is determined by a assessing the variance over several readings - the sensitivity of this variance can be adjusted in a variable in the app's code under 'ADVANCED SETTINGS' if needed. The code also has a basic logging function which shows, in a CSV file, when you started the HR tracker and when the alarm was triggered.
|
When you press the middle button on the side, the HR monitor starts, the alarm will trigger when your heart rate average drops to the limit you’ve set and has a certain level of steadiness that is determined by a assessing the variance over several readings - the sensitivity of this variance can be adjusted in a variable in the app's code under 'ADVANCED SETTINGS' if needed. The code also has a basic logging function which shows, in a CSV file, when you started the HR tracker and when the alarm was triggered.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ var lower_limit_BPM = 49;
|
||||||
var upper_limit_BPM = 140;
|
var upper_limit_BPM = 140;
|
||||||
var deviation_threshold = 3;
|
var deviation_threshold = 3;
|
||||||
|
|
||||||
|
var ISBANGLEJS1 = process.env.HWVERSION==1;
|
||||||
|
|
||||||
var target_heartrate = 70;
|
var target_heartrate = 70;
|
||||||
var heartrate_set;
|
var heartrate_set;
|
||||||
|
|
||||||
|
|
@ -33,8 +35,8 @@ function btn2Pressed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_target_HR(){
|
function update_target_HR(){
|
||||||
|
|
||||||
g.clear();
|
g.clear();
|
||||||
|
if (process.env.HWVERSION==1) {
|
||||||
g.setColor("#00ff7f");
|
g.setColor("#00ff7f");
|
||||||
g.setFont("6x8", 4);
|
g.setFont("6x8", 4);
|
||||||
g.setFontAlign(0,0); // center font
|
g.setFontAlign(0,0); // center font
|
||||||
|
|
@ -52,6 +54,20 @@ function update_target_HR(){
|
||||||
|
|
||||||
g.setFont("6x8", 1);
|
g.setFont("6x8", 1);
|
||||||
g.drawString("if unsure, start with 7-10%\n less than waking average and\n adjust as required", 120,170);
|
g.drawString("if unsure, start with 7-10%\n less than waking average and\n adjust as required", 120,170);
|
||||||
|
} else {
|
||||||
|
g.setFont("6x8", 4);
|
||||||
|
g.setFontAlign(0,0); // center font
|
||||||
|
g.drawString(target_heartrate, 88,88);
|
||||||
|
g.setFont("6x8", 2);
|
||||||
|
g.setFontAlign(-1,-1);
|
||||||
|
g.drawString("-", 160, 160);
|
||||||
|
g.drawString("+", 160, 10);
|
||||||
|
g.drawString("GO", 150, 88);
|
||||||
|
g.setFontAlign(0,0); // center font
|
||||||
|
g.drawString("target HR", 88,65);
|
||||||
|
g.setFont("6x8", 1);
|
||||||
|
g.drawString("if unsure, start with 7-10%\n less than waking average and\n adjust as required", 88,150);
|
||||||
|
}
|
||||||
|
|
||||||
g.setFont("6x8",3);
|
g.setFont("6x8",3);
|
||||||
g.flip();
|
g.flip();
|
||||||
|
|
@ -105,8 +121,13 @@ function checkHR() {
|
||||||
average_HR = average(HR_samples).toFixed(0);
|
average_HR = average(HR_samples).toFixed(0);
|
||||||
stdev_HR = getStandardDeviation (HR_samples).toFixed(1);
|
stdev_HR = getStandardDeviation (HR_samples).toFixed(1);
|
||||||
|
|
||||||
|
if (ISBANGLEJS1) {
|
||||||
g.drawString("HR: " + average_HR, 120,100);
|
g.drawString("HR: " + average_HR, 120,100);
|
||||||
g.drawString("STDEV: " + stdev_HR, 120,160);
|
g.drawString("STDEV: " + stdev_HR, 120,160);
|
||||||
|
} else {
|
||||||
|
g.drawString("HR: " + average_HR, 88,60);
|
||||||
|
g.drawString("STDEV: " + stdev_HR, 88,90);
|
||||||
|
}
|
||||||
HR_samples = [];
|
HR_samples = [];
|
||||||
if(average_HR < target_heartrate && stdev_HR < deviation_threshold){
|
if(average_HR < target_heartrate && stdev_HR < deviation_threshold){
|
||||||
|
|
||||||
|
|
@ -131,12 +152,26 @@ function checkHR() {
|
||||||
|
|
||||||
update_target_HR();
|
update_target_HR();
|
||||||
|
|
||||||
setWatch(btn1Pressed, BTN1, {repeat:true});
|
if (ISBANGLEJS1) {
|
||||||
setWatch(btn2Pressed, BTN2, {repeat:true});
|
// Bangle 1
|
||||||
setWatch(btn3Pressed, BTN3, {repeat:true});
|
setWatch(btn1Pressed, BTN1, {repeat:true});
|
||||||
|
setWatch(btn2Pressed, BTN2, {repeat:true});
|
||||||
|
setWatch(btn3Pressed, BTN3, {repeat:true});
|
||||||
|
} else {
|
||||||
|
// Bangle 2
|
||||||
|
setWatch(btn2Pressed, BTN1, { repeat: true });
|
||||||
|
Bangle.on('touch', function(zone, e) {
|
||||||
|
if (e.y < g.getHeight() / 2) {
|
||||||
|
btn1Pressed();
|
||||||
|
}
|
||||||
|
if (e.y > g.getHeight() / 2) {
|
||||||
|
btn3Pressed();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Bangle.on('HRM',function(hrm) {
|
Bangle.on('HRM',function(hrm) {
|
||||||
|
|
||||||
if(trigger_count < 2){
|
if(trigger_count < 2){
|
||||||
if (firstBPM)
|
if (firstBPM)
|
||||||
firstBPM=false; // ignore the first one as it's usually rubbish
|
firstBPM=false; // ignore the first one as it's usually rubbish
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
"id": "edisonsball",
|
"id": "edisonsball",
|
||||||
"name": "Edison's Ball",
|
"name": "Edison's Ball",
|
||||||
"shortName": "Edison's Ball",
|
"shortName": "Edison's Ball",
|
||||||
"version": "0.01",
|
"version": "0.02",
|
||||||
"description": "Hypnagogia/Micro-Sleep alarm for experimental use in exploring sleep transition and combating drowsiness",
|
"description": "Hypnagogia/Micro-Sleep alarm for experimental use in exploring sleep transition and combating drowsiness",
|
||||||
"icon": "app-icon.png",
|
"icon": "app-icon.png",
|
||||||
"tags": "",
|
"tags": "sleep,hyponagogia,quick,nap",
|
||||||
"supports": ["BANGLEJS"],
|
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"edisonsball.app.js","url":"app.js"},
|
{"name":"edisonsball.app.js","url":"app.js"},
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
0.01: Add a number to match to turn off alarm
|
0.01: Add a number to match to turn off alarm
|
||||||
0.02: Respect Quiet Mode
|
0.02: Respect Quiet Mode
|
||||||
|
0.03: Fix hour/minute wrapping code for new menu system
|
||||||
|
|
|
||||||
|
|
@ -56,25 +56,25 @@ function editAlarm(alarmIndex) {
|
||||||
}
|
}
|
||||||
const menu = {
|
const menu = {
|
||||||
'': { 'title': 'Alarms' },
|
'': { 'title': 'Alarms' },
|
||||||
'Hours': {
|
/*LANG*/'Hours': {
|
||||||
value: hrs,
|
value: hrs, min : 0, max : 23, wrap : true,
|
||||||
onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this'
|
onchange: v => hrs=v
|
||||||
},
|
},
|
||||||
'Minutes': {
|
/*LANG*/'Minutes': {
|
||||||
value: mins,
|
value: mins, min : 0, max : 59, wrap : true,
|
||||||
onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this'
|
onchange: v => mins=v
|
||||||
},
|
},
|
||||||
'Enabled': {
|
/*LANG*/'Enabled': {
|
||||||
value: en,
|
value: en,
|
||||||
format: v=>v?"On":"Off",
|
format: v=>v?"On":"Off",
|
||||||
onchange: v=>en=v
|
onchange: v=>en=v
|
||||||
},
|
},
|
||||||
'Repeat': {
|
/*LANG*/'Repeat': {
|
||||||
value: en,
|
value: en,
|
||||||
format: v=>v?"Yes":"No",
|
format: v=>v?"Yes":"No",
|
||||||
onchange: v=>repeat=v
|
onchange: v=>repeat=v
|
||||||
},
|
},
|
||||||
'Auto snooze': {
|
/*LANG*/'Auto snooze': {
|
||||||
value: as,
|
value: as,
|
||||||
format: v=>v?"Yes":"No",
|
format: v=>v?"Yes":"No",
|
||||||
onchange: v=>as=v
|
onchange: v=>as=v
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "hardalarm",
|
"id": "hardalarm",
|
||||||
"name": "Hard Alarm",
|
"name": "Hard Alarm",
|
||||||
"shortName": "HardAlarm",
|
"shortName": "HardAlarm",
|
||||||
"version": "0.02",
|
"version": "0.03",
|
||||||
"description": "Make sure you wake up! Count to the right number to turn off the alarm",
|
"description": "Make sure you wake up! Count to the right number to turn off the alarm",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"tags": "tool,alarm,widget",
|
"tags": "tool,alarm,widget",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: Initial commit
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Analogue Clock
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwgP/AH4Aq+GEkPh4E/BZMAh4LGw/h8MPBZHggIXJ/EB4ALI//h/4LHwk/BagA/ACY="))
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
Graphics.prototype.setFontUndo = function(scale) {
|
||||||
|
// Actual height 19 (20 - 2)
|
||||||
|
this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqKAqooCqigKqKAAAACgAAKAAAoAACgAAAAAAAAACgAAKAAAoAACgAAAAAAKCgAoKAKqqAqqoCqqgKqqAKCgAoKAKqqAqqoCqqgKqqAKCgAoKAAAAAKgoAqCgKqKAqooKiioqKKiooqKiioKKqAoqoCgqAKCoAAAACoCgKgKAiCoCIKgKioAqKgACoAAKgACoAAKgACoqAKioCoIgKgiAoCoCgKgAAAAKqgAqqAKqqAqqoKiioqKKiooqKiioKAKAoAoCgCgKAKAAAACgAAKAAAoAACgAAAAAAKqgAqqAKqqAqqoCgCgKAKAAAACgCgKAKAqqoCqqgCqoAKqgAAAACigAKKAAqoACqgAqoACqgAKqAAqoAAqoACqgAKKAAooAAAAAAoAACgAAKAAAoAAqqACqoAKqgAqqAAKAAAoAACgAAKAAAAAAACoAAKgAAqAACoAAAAAoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAAAAACgAAKAAAoAACgAAAAAAoAACgAAqAACoAAqAACoAAqAACoAAqAACoAAqAACoAAqAACoAAKAAAoAAAAAACqoAKqgCqqgKqqAoAoCgCgKAKAoAoCqqgKqqAKqgAqqAAAAAqqoCqqgKqqAqqoAAAAKCqAoKoCiqgKKqAoooCiigKKKAoooCqigKqKAKgoAqCgAAAAoAoCgCgKAKAoAoCiigKKKAoooCiigKqqAqqoAqqACqoAAAACqAAKoAAqoACqgAAKAAAoAACgAAKAAqqoCqqgKqqAqqoAAAAKoKAqgoCqigKqKAoooCiigKKKAoooCiqgKKqAoKgCgqAAAAAKqgAqqAKqqAqqoCiigKKKAoooCiigKKqAoqoCgqAKCoAAAACgAAKAAAoAACgAAKAAAoAACgAAKAAAqqoCqqgCqqAKqoAAAACqoAKqgCqqgKqqAoooCiigKKKAoooCqqgKqqAKqgAqqAAAAAKgAAqAAKqAAqoACigAKKAAooACigAKqqAqqoAqqgCqqAAAACgCgKAKAoAoCgCgAAAAoAqCgCoKAKgoAqAAAAAKAAAoAAKoAAqgAKqgAqqAKgqAqCoCgCgKAKAAAAAoKACgoAKCgAoKACgoAKCgAoKACgoAKCgAoKACgoAKCgAAAAKAKAoAoCoKgKgqAKqgAqqAAqgACqAACgAAKAAAAACgAAKAAAoAACgAAKKKAoooCiigKKKAqoACqgACoAAKgAAAAACqqAKqoCqqgKqqAoAACgAAKCoAoKgCiqgKKqAoooCiigKqqAqqoAqqACqoAAAAAqqgCqqAqqoCqqgKKAAooACigAKKAAqqoCqqgCqqAKqoAAAAKqqAqqoCqqgKqqAoooCiigKKKAoooCqqgKqqAKCgAoKAAAAAKqgAqqAKqqAqqoCgCgKAKAoAoCgCgKAKAoAoCgCgKAKAAAACqqgKqqAqqoCqqgKAKAoAoCoKgKgqAKqgAqqAAqgACqAAAAACqoAKqgCqqgKqqAoooCiigKKKAoooCgCgKAKAoAoCgCgAAAAKqoAqqgKqqAqqoCigAKKAAooACigAKAAAoAACgAAKAAAAAAAqqACqoAqqoCqqgKAKAoAoCiigKKKAoqoCiqgKKqAoqoAAAAKqqAqqoCqqgKqqAAoAACgAAKAAAoACqqgKqqAqqoCqqgAAAAoAoCgCgKAKAoAoCqqgKqqAqqoCqqgKAKAoAoCgCgKAKAAAAAAKAAAoAACoAAKgAAKAAAoAACgAAKAqqoCqqgKqoAqqgAAAAKqqAqqoCqqgKqqACqAAKoACqoAKqgCoKgKgqAoAoCgCgAAAAqqgCqqAKqqAqqoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAACqqgKqqAqqoCqqgCoAAKgAAKgAAqAAKgAAqAAKqqAqqoCqqgKqqAAAACqqgKqqAqqoCqqgCoAAKgAAKgAAqAAqqoCqqgKqqAqqoAAAACqoAKqgCqqgKqqAoAoCgCgKAKAoAoCqqgKqqAKqgAqqAAAAAqqoCqqgKqqAqqoCigAKKAAooACigAKqAAqoAAqAACoAAAAAAqqACqoAqqoCqqgKAKAoAoCgKgKAqAqqoCqqgCqqAKqoAAAAKqqAqqoCqqgKqqAooACigAKKgAoqACqqgKqqAKioAqKgAAAAKgoAqCgKqKAqooCiigKKKAoooCiigKKqAoqoCgqAKCoAAAACgAAKAAAoAACgAAKqqAqqoCqqgKqqAoAACgAAKAAAoAAAAAAKqoAqqgCqqgKqqAAAoAACgAAKAAAoCqqgKqqAqqgCqqAAAAAqqACqoAKqoAqqgAAKgAAqAACoAAKgKqoAqqgCqoAKqgAAAACqqgKqqAqqoCqqgACoAAKgACoAAKgAAKgAAqAKqqAqqoCqqgKqqAAAACoKgKgqAqqoCqqgAqgACqAAKoAAqgAqqoCqqgKgqAqCoAAAAKoAAqgACqgAKqAAAqoACqgAKqAAqoCqgAKqAAqgACqAAAAAAoCoCgKgKCqAoKoCiqgKKqAqooCqigKoKAqgoCoCgKgKAAAACqqgKqqAqqoCqqgKAKAoAoAAAAKAAAoAACoAAKgAAKgAAqAAAqAACoAACoAAKgAAKgAAqAAAqAACoAACgAAKAAAACgCgKAKAqqoCqqgKqqAqqoAAA"), 32, atob("DQULDw0RDQUHBw0NBQ0FEQ0FDQ0NDQ0NDQ0FBQsNCw0RDQ0NDQ0NDQ0NDQ0NDw0NDQ0NDQ0NDQ8NDQ0HEQc="), 22+(scale<<8)+(1<<16));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
draw();
|
||||||
|
}, 60000 - (Date.now() % 60000));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
var x = g.getWidth()/2;
|
||||||
|
var y = g.getHeight()/2 - 10;
|
||||||
|
g.reset();
|
||||||
|
// work out locale-friendly date/time
|
||||||
|
var date = new Date();
|
||||||
|
var timeStr = require("locale").time(date,1).trim();
|
||||||
|
var dateStr = require("locale").date(date).toUpperCase();
|
||||||
|
|
||||||
|
|
||||||
|
// draw time
|
||||||
|
g.setFontAlign(0,0).setFont("Undo:3");
|
||||||
|
g.clearRect(0,y-30,g.getWidth(),y+30); // clear the background
|
||||||
|
g.drawString(timeStr,x,y);
|
||||||
|
// draw date
|
||||||
|
y += 40;
|
||||||
|
g.setFontAlign(0,0).setFont("Undo");
|
||||||
|
g.clearRect(0,y-10,g.getWidth(),y+20); // clear the background
|
||||||
|
g.drawString(dateStr,x,y);
|
||||||
|
// queue draw in one minute
|
||||||
|
queueDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the screen once, at startup
|
||||||
|
g.clear();
|
||||||
|
// draw immediately at first, queue update
|
||||||
|
draw();
|
||||||
|
// Stop updates when LCD is off, restart when on
|
||||||
|
Bangle.on('lcdPower',on=>{
|
||||||
|
if (on) {
|
||||||
|
draw(); // draw immediately, queue redraw
|
||||||
|
} else { // stop draw timer
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
drawTimeout = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Show launcher when middle button pressed
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
// Load widgets
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
After Width: | Height: | Size: 3.4 KiB |
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"id": "intclock",
|
||||||
|
"name": "Interlaced Clock",
|
||||||
|
"version": "0.01",
|
||||||
|
"description": "A lightweight digital clock using an 'interlaced' font",
|
||||||
|
"icon": "app.png",
|
||||||
|
"screenshots": [{"url":"screenshot.png"}],
|
||||||
|
"type": "clock",
|
||||||
|
"tags": "clock",
|
||||||
|
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||||
|
"allow_emulator": true,
|
||||||
|
"storage": [
|
||||||
|
{"name":"intclock.app.js","url":"app.js"},
|
||||||
|
{"name":"intclock.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
|
|
@ -1,3 +1,4 @@
|
||||||
0.01: Initial Release
|
0.01: Initial Release
|
||||||
0.02: Support for Bangle 2
|
0.02: Support for Bangle 2
|
||||||
0.03: Keep the date from being overwritten, use correct colour from theme for clearing
|
0.03: Keep the date from being overwritten, use correct colour from theme for clearing
|
||||||
|
0.04: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up".
|
||||||
|
|
|
||||||
|
|
@ -239,15 +239,6 @@ Bangle.on('lcdPower', (on) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Bangle.on('faceUp',function(up){
|
|
||||||
//console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn());
|
|
||||||
if (up && !Bangle.isLCDOn()) {
|
|
||||||
//console.log("faceUp and LCD off");
|
|
||||||
clearTimers();
|
|
||||||
Bangle.setLCDPower(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
g.clear();
|
g.clear();
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "matrixclock",
|
"id": "matrixclock",
|
||||||
"name": "Matrix Clock",
|
"name": "Matrix Clock",
|
||||||
"version": "0.03",
|
"version": "0.04",
|
||||||
"description": "inspired by The Matrix, a clock of the same style",
|
"description": "inspired by The Matrix, a clock of the same style",
|
||||||
"icon": "matrixclock.png",
|
"icon": "matrixclock.png",
|
||||||
"screenshots": [{"url":"screenshot_matrix.png"}],
|
"screenshots": [{"url":"screenshot_matrix.png"}],
|
||||||
|
|
|
||||||
|
|
@ -32,5 +32,8 @@
|
||||||
0.20: Allow tapping on the body to show a scrollable view of the message and title in a bigger font (fix #1405, #1031)
|
0.20: Allow tapping on the body to show a scrollable view of the message and title in a bigger font (fix #1405, #1031)
|
||||||
0.21: Improve list readability on dark theme
|
0.21: Improve list readability on dark theme
|
||||||
0.22: Add Home Assistant icon
|
0.22: Add Home Assistant icon
|
||||||
0.22: Allow repeat to be switched Off, so there is no buzzing repetition.
|
Allow repeat to be switched Off, so there is no buzzing repetition.
|
||||||
Also gave the widget a pixel more room to the right
|
Also gave the widget a pixel more room to the right
|
||||||
|
0.23: Change message colors to match current theme instead of using green
|
||||||
|
Now attempt to use Large/Big/Medium fonts, and allow minimum font size to be configured
|
||||||
|
0.24: Remove left-over debug statement
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@ and `Messages`:
|
||||||
* `Unread Timer` - when a new message is received we go into the Messages app.
|
* `Unread Timer` - when a new message is received we go into the Messages app.
|
||||||
If there is no user input for this amount of time then the app will exit and return
|
If there is no user input for this amount of time then the app will exit and return
|
||||||
to the clock where a ringing bell will be shown in the Widget bar.
|
to the clock where a ringing bell will be shown in the Widget bar.
|
||||||
|
* `Min Font` - the minimum font size used when displaying messages on the screen. A bigger font
|
||||||
|
is chosen if there isn't much message text, but this specifies the smallest the font should get before
|
||||||
|
it starts getting clipped.
|
||||||
|
|
||||||
## New Messages
|
## New Messages
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Layout = require("Layout");
|
var Layout = require("Layout");
|
||||||
|
var settings = require('Storage').readJSON("messages.settings.json", true) || {};
|
||||||
var fontSmall = "6x8";
|
var fontSmall = "6x8";
|
||||||
var fontMedium = g.getFonts().includes("6x15")?"6x15":"6x8:2";
|
var fontMedium = g.getFonts().includes("6x15")?"6x15":"6x8:2";
|
||||||
var fontBig = g.getFonts().includes("12x20")?"12x20":"6x8:2";
|
var fontBig = g.getFonts().includes("12x20")?"12x20":"6x8:2";
|
||||||
var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4";
|
var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4";
|
||||||
var colBg = g.theme.dark ? "#141":"#4f4";
|
|
||||||
var colSBg1 = g.theme.dark ? "#121":"#cFc";
|
|
||||||
var colSBg2 = g.theme.dark ? "#000":"#9F9";
|
|
||||||
// hack for 2v10 firmware's lack of ':size' font handling
|
// hack for 2v10 firmware's lack of ':size' font handling
|
||||||
try {
|
try {
|
||||||
g.setFont("6x8:2");
|
g.setFont("6x8:2");
|
||||||
|
|
@ -77,9 +75,13 @@ function getPosImage() {
|
||||||
function getNegImage() {
|
function getNegImage() {
|
||||||
return atob("FhaBADAAMeAB78AP/4B/fwP4/h/B/P4D//AH/4AP/AAf4AB/gAP/AB/+AP/8B/P4P4fx/A/v4B//AD94AHjAAMA=");
|
return atob("FhaBADAAMeAB78AP/4B/fwP4/h/B/P4D//AH/4AP/AAf4AB/gAP/AB/+AP/8B/P4P4fx/A/v4B//AD94AHjAAMA=");
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* icons should be 24x24px with 1bpp colors and transparancy
|
||||||
|
*/
|
||||||
function getMessageImage(msg) {
|
function getMessageImage(msg) {
|
||||||
if (msg.img) return atob(msg.img);
|
if (msg.img) return atob(msg.img);
|
||||||
var s = (msg.src||"").toLowerCase();
|
var s = (msg.src||"").toLowerCase();
|
||||||
|
if (s=="alarm" || s =="alarmclockreceiver") return atob("GBjBAP////8AAAAAAAACAEAHAOAefng5/5wTgcgHAOAOGHAMGDAYGBgYGBgYGBgYGBgYDhgYBxgMATAOAHAHAOADgcAB/4AAfgAAAAAAAAA=");
|
||||||
if (s=="calendar") return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B9m2B//+B//+Btm2B//+B//+Btm+B//+B//+A//8AAAAAAAAAAAAA==");
|
if (s=="calendar") return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B9m2B//+B//+Btm2B//+B//+Btm+B//+B//+A//8AAAAAAAAAAAAA==");
|
||||||
if (s=="facebook") return getFBIcon();
|
if (s=="facebook") return getFBIcon();
|
||||||
if (s=="hangouts") return atob("FBaBAAH4AH/gD/8B//g//8P//H5n58Y+fGPnxj5+d+fmfj//4//8H//B//gH/4A/8AA+AAHAABgAAAA=");
|
if (s=="hangouts") return atob("FBaBAAH4AH/gD/8B//g//8P//H5n58Y+fGPnxj5+d+fmfj//4//8H//B//gH/4A/8AA+AAHAABgAAAA=");
|
||||||
|
|
@ -94,6 +96,7 @@ function getMessageImage(msg) {
|
||||||
if (s=="skype") return atob("GhoBB8AAB//AA//+Af//wH//+D///w/8D+P8Afz/DD8/j4/H4fP5/A/+f4B/n/gP5//B+fj8fj4/H8+DB/PwA/x/A/8P///B///gP//4B//8AD/+AAA+AA==");
|
if (s=="skype") return atob("GhoBB8AAB//AA//+Af//wH//+D///w/8D+P8Afz/DD8/j4/H4fP5/A/+f4B/n/gP5//B+fj8fj4/H8+DB/PwA/x/A/8P///B///gP//4B//8AD/+AAA+AA==");
|
||||||
if (s=="slack") return atob("GBiBAAAAAAAAAABAAAHvAAHvAADvAAAPAB/PMB/veD/veB/mcAAAABzH8B3v+B3v+B3n8AHgAAHuAAHvAAHvAADGAAAAAAAAAAAAAA==");
|
if (s=="slack") return atob("GBiBAAAAAAAAAABAAAHvAAHvAADvAAAPAB/PMB/veD/veB/mcAAAABzH8B3v+B3v+B3n8AHgAAHuAAHvAAHvAADGAAAAAAAAAAAAAA==");
|
||||||
if (s=="sms message") return getNotificationImage();
|
if (s=="sms message") return getNotificationImage();
|
||||||
|
if (s=="threema") return atob("GBjB/4Yx//8AAAAAAAAAAAAAfgAB/4AD/8AH/+AH/+AP//AP2/APw/APw/AHw+AH/+AH/8AH/4AH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=");
|
||||||
if (s=="twitter") return atob("GhYBAABgAAB+JgA/8cAf/ngH/5+B/8P8f+D///h///4f//+D///g///wD//8B//+AP//gD//wAP/8AB/+AB/+AH//AAf/AAAYAAA");
|
if (s=="twitter") return atob("GhYBAABgAAB+JgA/8cAf/ngH/5+B/8P8f+D///h///4f//+D///g///wD//8B//+AP//gD//wAP/8AB/+AB/+AH//AAf/AAAYAAA");
|
||||||
if (s=="telegram") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA==");
|
if (s=="telegram") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA==");
|
||||||
if (s=="whatsapp") return atob("GBiBAAB+AAP/wAf/4A//8B//+D///H9//n5//nw//vw///x///5///4///8e//+EP3/APn/wPn/+/j///H//+H//8H//4H//wMB+AA==");
|
if (s=="whatsapp") return atob("GBiBAAB+AAP/wAf/4A//8B//+D///H9//n5//nw//vw///x///5///4///8e//+EP3/APn/wPn/+/j///H//+H//8H//4H//wMB+AA==");
|
||||||
|
|
@ -105,6 +108,7 @@ function getMessageImage(msg) {
|
||||||
function getMessageImageCol(msg,def) {
|
function getMessageImageCol(msg,def) {
|
||||||
return {
|
return {
|
||||||
// generic colors, using B2-safe colors
|
// generic colors, using B2-safe colors
|
||||||
|
"alarm": "#fff",
|
||||||
"calendar": "#f00",
|
"calendar": "#f00",
|
||||||
"mail": "#ff0",
|
"mail": "#ff0",
|
||||||
"music": "#f0f",
|
"music": "#f0f",
|
||||||
|
|
@ -122,6 +126,7 @@ function getMessageImageCol(msg,def) {
|
||||||
"outlook mail": "#0072c6",
|
"outlook mail": "#0072c6",
|
||||||
"skype": "#00aff0",
|
"skype": "#00aff0",
|
||||||
"slack": "#e51670",
|
"slack": "#e51670",
|
||||||
|
"threema": "#000",
|
||||||
"telegram": "#0088cc",
|
"telegram": "#0088cc",
|
||||||
"twitter": "#1da1f2",
|
"twitter": "#1da1f2",
|
||||||
"whatsapp": "#4fce5d",
|
"whatsapp": "#4fce5d",
|
||||||
|
|
@ -143,8 +148,8 @@ function showMapMessage(msg) {
|
||||||
eta = m[2];
|
eta = m[2];
|
||||||
} else target=msg.body;
|
} else target=msg.body;
|
||||||
layout = new Layout({ type:"v", c: [
|
layout = new Layout({ type:"v", c: [
|
||||||
{type:"txt", font:fontMedium, label:target, bgCol:colBg, fillx:1, pad:2 },
|
{type:"txt", font:fontMedium, label:target, bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2 },
|
||||||
{type:"h", bgCol:colBg, fillx:1, c: [
|
{type:"h", bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, c: [
|
||||||
{type:"txt", font:"6x8", label:"Towards" },
|
{type:"txt", font:"6x8", label:"Towards" },
|
||||||
{type:"txt", font:fontLarge, label:street }
|
{type:"txt", font:fontLarge, label:street }
|
||||||
]},
|
]},
|
||||||
|
|
@ -168,27 +173,56 @@ function showMapMessage(msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMusicMessage(msg) {
|
function showMusicMessage(msg) {
|
||||||
|
var updateLabelsInterval;
|
||||||
|
var trackScrollOffset = 0;
|
||||||
|
var artistScrollOffset = 0;
|
||||||
|
var albumScrollOffset = 0;
|
||||||
|
var trackName = '';
|
||||||
|
var artistName = '';
|
||||||
|
var albumName = '';
|
||||||
|
|
||||||
function fmtTime(s) {
|
function fmtTime(s) {
|
||||||
var m = Math.floor(s/60);
|
var m = Math.floor(s/60);
|
||||||
s = (parseInt(s%60)).toString().padStart(2,0);
|
s = (parseInt(s%60)).toString().padStart(2,0);
|
||||||
return m+":"+s;
|
return m+":"+s;
|
||||||
}
|
}
|
||||||
|
function reduceStringAndPad(text, offset, maxLen) {
|
||||||
|
var sliceLength = offset + maxLen > text.length ? text.length - offset : maxLen;
|
||||||
|
return text.substr(offset, sliceLength).padEnd(maxLen, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function back() {
|
function back() {
|
||||||
|
clearInterval(updateLabelsInterval);
|
||||||
msg.new = false;
|
msg.new = false;
|
||||||
saveMessages();
|
saveMessages();
|
||||||
layout = undefined;
|
layout = undefined;
|
||||||
checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1});
|
checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1});
|
||||||
}
|
}
|
||||||
|
function updateLabels() {
|
||||||
|
trackName = reduceStringAndPad(msg.track, trackScrollOffset, 13);
|
||||||
|
artistName = reduceStringAndPad(msg.artist, artistScrollOffset, 21);
|
||||||
|
albumName = reduceStringAndPad(msg.album, albumScrollOffset, 21);
|
||||||
|
|
||||||
|
trackScrollOffset++;
|
||||||
|
artistScrollOffset++;
|
||||||
|
albumScrollOffset++;
|
||||||
|
|
||||||
|
if ((trackScrollOffset + 13) > msg.track.length) trackScrollOffset = 0;
|
||||||
|
if ((artistScrollOffset + 21) > msg.artist.length) artistScrollOffset = 0;
|
||||||
|
if ((albumScrollOffset + 21) > msg.album.length) albumScrollOffset = 0;
|
||||||
|
}
|
||||||
|
updateLabels();
|
||||||
|
|
||||||
layout = new Layout({ type:"v", c: [
|
layout = new Layout({ type:"v", c: [
|
||||||
{type:"h", fillx:1, bgCol:colBg, c: [
|
{type:"h", fillx:1, bgCol:g.theme.bg2, col: g.theme.fg2, c: [
|
||||||
{ type:"btn", src:getBackImage, cb:back },
|
{ type:"btn", src:getBackImage, cb:back },
|
||||||
{ type:"v", fillx:1, c: [
|
{ type:"v", fillx:1, c: [
|
||||||
{ type:"txt", font:fontMedium, label:msg.artist, pad:2 },
|
{ type:"txt", font:fontMedium, bgCol:g.theme.bg2, label:artistName, pad:2, id:"artist" },
|
||||||
{ type:"txt", font:fontMedium, label:msg.album, pad:2 }
|
{ type:"txt", font:fontMedium, bgCol:g.theme.bg2, label:albumName, pad:2, id:"album" }
|
||||||
]}
|
]}
|
||||||
]},
|
]},
|
||||||
{type:"txt", font:fontLarge, label:msg.track, fillx:1, filly:1, pad:2 },
|
{type:"txt", font:fontLarge, bgCol:g.theme.bg, label:trackName, fillx:1, filly:1, pad:2, id:"track" },
|
||||||
Bangle.musicControl?{type:"h",fillx:1, c: [
|
Bangle.musicControl?{type:"h",fillx:1, c: [
|
||||||
{type:"btn", pad:8, label:"\0"+atob("FhgBwAADwAAPwAA/wAD/gAP/gA//gD//gP//g///j///P//////////P//4//+D//gP/4A/+AD/gAP8AA/AADwAAMAAA"), cb:()=>Bangle.musicControl("play")}, // play
|
{type:"btn", pad:8, label:"\0"+atob("FhgBwAADwAAPwAA/wAD/gAP/gA//gD//gP//g///j///P//////////P//4//+D//gP/4A/+AD/gAP8AA/AADwAAMAAA"), cb:()=>Bangle.musicControl("play")}, // play
|
||||||
{type:"btn", pad:8, label:"\0"+atob("EhaBAHgHvwP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP3gHg"), cb:()=>Bangle.musicControl("pause")}, // pause
|
{type:"btn", pad:8, label:"\0"+atob("EhaBAHgHvwP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP/wP3gHg"), cb:()=>Bangle.musicControl("pause")}, // pause
|
||||||
|
|
@ -198,6 +232,14 @@ function showMusicMessage(msg) {
|
||||||
]});
|
]});
|
||||||
g.clearRect(Bangle.appRect);
|
g.clearRect(Bangle.appRect);
|
||||||
layout.render();
|
layout.render();
|
||||||
|
|
||||||
|
updateLabelsInterval = setInterval(function() {
|
||||||
|
updateLabels();
|
||||||
|
layout.artist.label = artistName;
|
||||||
|
layout.album.label = albumName;
|
||||||
|
layout.track.label = trackName;
|
||||||
|
layout.render();
|
||||||
|
}, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMessageScroller(msg) {
|
function showMessageScroller(msg) {
|
||||||
|
|
@ -214,7 +256,9 @@ function showMessageScroller(msg) {
|
||||||
// a function to draw a menu item
|
// a function to draw a menu item
|
||||||
draw : function(idx, r) {
|
draw : function(idx, r) {
|
||||||
// FIXME: in 2v13 onwards, clearRect(r) will work fine. There's a bug in 2v12
|
// FIXME: in 2v13 onwards, clearRect(r) will work fine. There's a bug in 2v12
|
||||||
g.setBgColor(idx<titleCnt ? colBg : g.theme.bg).clearRect(r.x,r.y,r.x+r.w, r.y+r.h);
|
g.setBgColor(idx<titleCnt ? g.theme.bg2 : g.theme.bg).
|
||||||
|
setColor(idx<titleCnt ? g.theme.fg2 : g.theme.fg).
|
||||||
|
clearRect(r.x,r.y,r.x+r.w, r.y+r.h);
|
||||||
g.setFont(bodyFont).drawString(lines[idx], r.x, r.y);
|
g.setFont(bodyFont).drawString(lines[idx], r.x, r.y);
|
||||||
}, select : function(idx) {
|
}, select : function(idx) {
|
||||||
if (idx>=lines.length-2)
|
if (idx>=lines.length-2)
|
||||||
|
|
@ -270,13 +314,31 @@ function showMessage(msgid) {
|
||||||
var title=msg.title, titleFont = fontLarge, lines;
|
var title=msg.title, titleFont = fontLarge, lines;
|
||||||
if (title) {
|
if (title) {
|
||||||
var w = g.getWidth()-48;
|
var w = g.getWidth()-48;
|
||||||
if (g.setFont(titleFont).stringWidth(title) > w)
|
if (g.setFont(titleFont).stringWidth(title) > w) {
|
||||||
|
titleFont = fontBig;
|
||||||
|
if (settings.fontSize!=1 && g.setFont(titleFont).stringWidth(title) > w)
|
||||||
titleFont = fontMedium;
|
titleFont = fontMedium;
|
||||||
|
}
|
||||||
if (g.setFont(titleFont).stringWidth(title) > w) {
|
if (g.setFont(titleFont).stringWidth(title) > w) {
|
||||||
lines = g.wrapString(title, w);
|
lines = g.wrapString(title, w);
|
||||||
title = (lines.length>2) ? lines.slice(0,2).join("\n")+"..." : lines.join("\n");
|
title = (lines.length>2) ? lines.slice(0,2).join("\n")+"..." : lines.join("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If body of message is only two lines long w/ large font, use large font.
|
||||||
|
var body=msg.body, bodyFont = fontLarge;
|
||||||
|
if (body) {
|
||||||
|
var w = g.getWidth()-10;
|
||||||
|
if (g.setFont(bodyFont).stringWidth(body) > w * 2) {
|
||||||
|
bodyFont = fontBig;
|
||||||
|
if (settings.fontSize!=1 && g.setFont(bodyFont).stringWidth(body) > w * 3)
|
||||||
|
bodyFont = fontMedium;
|
||||||
|
}
|
||||||
|
if (g.setFont(bodyFont).stringWidth(body) > w) {
|
||||||
|
lines = g.setFont(bodyFont).wrapString(msg.body, w);
|
||||||
|
var maxLines = Math.floor((g.getHeight()-110) / g.getFontHeight());
|
||||||
|
body = (lines.length>maxLines) ? lines.slice(0,maxLines).join("\n")+"..." : lines.join("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
function goBack() {
|
function goBack() {
|
||||||
msg.new = false; saveMessages(); // read mail
|
msg.new = false; saveMessages(); // read mail
|
||||||
cancelReloadTimeout(); // don't auto-reload to clock now
|
cancelReloadTimeout(); // don't auto-reload to clock now
|
||||||
|
|
@ -303,27 +365,17 @@ function showMessage(msgid) {
|
||||||
checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1});
|
checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1});
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
// If body of message is only two lines long w/ large font, use large font.
|
|
||||||
var body=msg.body, bodyFont = fontLarge, lines;
|
|
||||||
if (body) {
|
|
||||||
var w = g.getWidth()-48;
|
|
||||||
if (g.setFont(bodyFont).stringWidth(body) > w * 2)
|
|
||||||
bodyFont = fontMedium;
|
|
||||||
if (g.setFont(bodyFont).stringWidth(body) > w) {
|
|
||||||
lines = g.setFont(bodyFont).wrapString(msg.body, g.getWidth()-10);
|
|
||||||
body = (lines.length>4) ? lines.slice(0,4).join("\n")+"..." : lines.join("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layout = new Layout({ type:"v", c: [
|
layout = new Layout({ type:"v", c: [
|
||||||
{type:"h", fillx:1, bgCol:colBg, c: [
|
{type:"h", fillx:1, bgCol:g.theme.bg2, col: g.theme.fg2, c: [
|
||||||
{ type:"btn", src:getMessageImage(msg), col:getMessageImageCol(msg), pad: 3, cb:()=>{
|
{ type:"btn", src:getMessageImage(msg), col:getMessageImageCol(msg), pad: 3, cb:()=>{
|
||||||
cancelReloadTimeout(); // don't auto-reload to clock now
|
cancelReloadTimeout(); // don't auto-reload to clock now
|
||||||
showMessageSettings(msg);
|
showMessageSettings(msg);
|
||||||
}},
|
}},
|
||||||
{ type:"v", fillx:1, c: [
|
{ type:"v", fillx:1, c: [
|
||||||
{type:"txt", font:fontSmall, label:msg.src||/*LANG*/"Message", bgCol:colBg, fillx:1, pad:2, halign:1 },
|
{type:"txt", font:fontSmall, label:msg.src||/*LANG*/"Message", bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2, halign:1 },
|
||||||
title?{type:"txt", font:titleFont, label:title, bgCol:colBg, fillx:1, pad:2 }:{},
|
title?{type:"txt", font:titleFont, label:title, bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2 }:{},
|
||||||
]},
|
]},
|
||||||
]},
|
]},
|
||||||
{type:"txt", font:bodyFont, label:body, fillx:1, filly:1, pad:2, cb:()=>{
|
{type:"txt", font:bodyFont, label:body, fillx:1, filly:1, pad:2, cb:()=>{
|
||||||
|
|
@ -374,9 +426,8 @@ function checkMessages(options) {
|
||||||
c : Math.max(MESSAGES.length+1,3), // workaround for 2v10.219 firmware (min 3 not needed for 2v11)
|
c : Math.max(MESSAGES.length+1,3), // workaround for 2v10.219 firmware (min 3 not needed for 2v11)
|
||||||
draw : function(idx, r) {"ram"
|
draw : function(idx, r) {"ram"
|
||||||
var msg = MESSAGES[idx-1];
|
var msg = MESSAGES[idx-1];
|
||||||
if (msg && msg.new) g.setBgColor(colBg);
|
if (msg && msg.new) g.setBgColor(g.theme.bgH).setColor(g.theme.fgH);
|
||||||
else g.setBgColor((idx&1) ? colSBg1 : colSBg2);
|
else g.setColor(g.theme.fg);
|
||||||
g.clearRect(r.x,r.y,r.x+r.w-1,r.y+r.h-1).setColor(g.theme.fg);
|
|
||||||
if (idx==0) msg = {id:"back", title:"< Back"};
|
if (idx==0) msg = {id:"back", title:"< Back"};
|
||||||
if (!msg) return;
|
if (!msg) return;
|
||||||
var x = r.x+2, title = msg.title, body = msg.body;
|
var x = r.x+2, title = msg.title, body = msg.body;
|
||||||
|
|
@ -391,18 +442,20 @@ function checkMessages(options) {
|
||||||
.setColor(fg); // only color the icon
|
.setColor(fg); // only color the icon
|
||||||
x += 50;
|
x += 50;
|
||||||
}
|
}
|
||||||
var m = msg.title+"\n"+msg.body;
|
var m = msg.title+"\n"+msg.body, longBody=false;
|
||||||
if (msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2);
|
|
||||||
if (title) g.setFontAlign(-1,-1).setFont(fontBig).drawString(title, x,r.y+2);
|
if (title) g.setFontAlign(-1,-1).setFont(fontBig).drawString(title, x,r.y+2);
|
||||||
if (body) {
|
if (body) {
|
||||||
g.setFontAlign(-1,-1).setFont("6x8");
|
g.setFontAlign(-1,-1).setFont("6x8");
|
||||||
var l = g.wrapString(body, r.w-14);
|
var l = g.wrapString(body, r.w-(x+14));
|
||||||
if (l.length>3) {
|
if (l.length>3) {
|
||||||
l = l.slice(0,3);
|
l = l.slice(0,3);
|
||||||
l[l.length-1]+="...";
|
l[l.length-1]+="...";
|
||||||
}
|
}
|
||||||
|
longBody = l.length>2;
|
||||||
g.drawString(l.join("\n"), x+10,r.y+20);
|
g.drawString(l.join("\n"), x+10,r.y+20);
|
||||||
}
|
}
|
||||||
|
if (!longBody && msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2);
|
||||||
|
g.setColor("#888").fillRect(r.x,r.y+r.h-1,r.x+r.w-1,r.y+r.h-1); // dividing line between items
|
||||||
},
|
},
|
||||||
select : idx => {
|
select : idx => {
|
||||||
if (idx==0) load();
|
if (idx==0) load();
|
||||||
|
|
@ -422,7 +475,7 @@ g.clear();
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
var unreadTimeoutSecs = (require('Storage').readJSON("messages.settings.json", true) || {}).unreadTimeout;
|
var unreadTimeoutSecs = settings.unreadTimeout;
|
||||||
if (unreadTimeoutSecs===undefined) unreadTimeoutSecs=60;
|
if (unreadTimeoutSecs===undefined) unreadTimeoutSecs=60;
|
||||||
if (unreadTimeoutSecs)
|
if (unreadTimeoutSecs)
|
||||||
unreadTimeout = setTimeout(function() {
|
unreadTimeout = setTimeout(function() {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "messages",
|
"id": "messages",
|
||||||
"name": "Messages",
|
"name": "Messages",
|
||||||
"version": "0.22",
|
"version": "0.24",
|
||||||
"description": "App to display notifications from iOS and Gadgetbridge/Android",
|
"description": "App to display notifications from iOS and Gadgetbridge/Android",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"type": "app",
|
"type": "app",
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 4.1 KiB |
|
|
@ -37,6 +37,12 @@
|
||||||
format: v => v?v+"s":/*LANG*/"Off",
|
format: v => v?v+"s":/*LANG*/"Off",
|
||||||
onchange: v => updateSetting("unreadTimeout", v)
|
onchange: v => updateSetting("unreadTimeout", v)
|
||||||
},
|
},
|
||||||
|
/*LANG*/'Min Font': {
|
||||||
|
value: 0|settings().fontSize,
|
||||||
|
min: 0, max: 1,
|
||||||
|
format: v => [/*LANG*/"Small",/*LANG*/"Medium"][v],
|
||||||
|
onchange: v => updateSetting("fontSize", v)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
E.showMenu(mainmenu);
|
E.showMenu(mainmenu);
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ draw:function() {
|
||||||
g.reset().clearRect(this.x, this.y, this.x+this.width, this.y+this.iconwidth);
|
g.reset().clearRect(this.x, this.y, this.x+this.width, this.y+this.iconwidth);
|
||||||
g.drawImage((c&1) ? atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+DAADDAADDAADDwAPD8A/DOBzDDn/DA//DAHvDAPvjAPvjAPvjAPvh///gf/vAAD+AAB8AAAAA==") : atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+D///D///A//8CP/xDj/HD48DD+B8D/D+D/3vD/vvj/vvj/vvj/vvh/v/gfnvAAD+AAB8AAAAA=="), this.x, this.y);
|
g.drawImage((c&1) ? atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+DAADDAADDAADDwAPD8A/DOBzDDn/DA//DAHvDAPvjAPvjAPvjAPvh///gf/vAAD+AAB8AAAAA==") : atob("GBiBAAAAAAAAAAAAAAAAAAAAAB//+D///D///A//8CP/xDj/HD48DD+B8D/D+D/3vD/vvj/vvj/vvj/vvh/v/gfnvAAD+AAB8AAAAA=="), this.x, this.y);
|
||||||
let settings = require('Storage').readJSON("messages.settings.json", true) || {};
|
let settings = require('Storage').readJSON("messages.settings.json", true) || {};
|
||||||
console.log("dingen ", typeof(settings.repeat), settings.repeat)
|
|
||||||
if (settings.repeat===undefined) settings.repeat = 4;
|
if (settings.repeat===undefined) settings.repeat = 4;
|
||||||
if (c<120 && (Date.now()-this.l)>settings.repeat*1000) {
|
if (c<120 && (Date.now()-this.l)>settings.repeat*1000) {
|
||||||
this.l = Date.now();
|
this.l = Date.now();
|
||||||
|
|
|
||||||
|
|
@ -353,13 +353,15 @@ const events = {
|
||||||
let c, p, i, l = from - o, h = to - o;
|
let c, p, i, l = from - o, h = to - o;
|
||||||
for (i = 0; (c = this.wall[i]).time < l; i++) ;
|
for (i = 0; (c = this.wall[i]).time < l; i++) ;
|
||||||
for (; (c = this.wall[i]).time < h; i++) {
|
for (; (c = this.wall[i]).time < h; i++) {
|
||||||
if ((p = c.time < t) ? c.past : c.future)
|
p = c.time < t;
|
||||||
|
if (p ? c.past : c.future)
|
||||||
result = Math.min(result, f(c, new Date(c.time + o), p));
|
result = Math.min(result, f(c, new Date(c.time + o), p));
|
||||||
}
|
}
|
||||||
l += o; h += o; t += o;
|
l += o; h += o; t += o;
|
||||||
for (i = 0; (c = this.fixed[i]).time < l; i++) ;
|
for (i = 0; (c = this.fixed[i]).time < l; i++) ;
|
||||||
for (; (c = this.fixed[i]).time < h; i++) {
|
for (; (c = this.fixed[i]).time < h; i++) {
|
||||||
if ((p = c.time < t) ? c.past : c.future)
|
p = c.time < t;
|
||||||
|
if (p ? c.past : c.future)
|
||||||
result = Math.min(f(c, new Date(c.time), p));
|
result = Math.min(f(c, new Date(c.time), p));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,8 @@ const prepFont = (name, data) => {
|
||||||
let width = m[2] == '*' ? null : +m[2];
|
let width = m[2] == '*' ? null : +m[2];
|
||||||
let c = null, o = 0;
|
let c = null, o = 0;
|
||||||
lines.forEach((line, l) => {
|
lines.forEach((line, l) => {
|
||||||
if (m = /^(<*)(=)([*\d]*)(=*)(>*)$/.exec(line) || /^(<*)(-)(.)(-*)(>*)$/.exec(line)) {
|
m = /^(<*)(=)([*\d]*)(=*)(>*)$/.exec(line) || /^(<*)(-)(.)(-*)(>*)$/.exec(line);
|
||||||
|
if (m) {
|
||||||
const h = m[2] == '=';
|
const h = m[2] == '=';
|
||||||
if (m[1].length > desc || h && m[1].length != desc)
|
if (m[1].length > desc || h && m[1].length != desc)
|
||||||
throw new Error('Invalid descender height at ' + l);
|
throw new Error('Invalid descender height at ' + l);
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,8 @@ const prepFont = (name, data) => {
|
||||||
let width = m[2] == '*' ? null : +m[2];
|
let width = m[2] == '*' ? null : +m[2];
|
||||||
let c = null, o = 0;
|
let c = null, o = 0;
|
||||||
lines.forEach((line, l) => {
|
lines.forEach((line, l) => {
|
||||||
if (m = /^(<*)(=)([*\d]*)(=*)(>*)$/.exec(line) || /^(<*)(-)(.)(-*)(>*)$/.exec(line)) {
|
m = /^(<*)(=)([*\d]*)(=*)(>*)$/.exec(line) || /^(<*)(-)(.)(-*)(>*)$/.exec(line);
|
||||||
|
if (m) {
|
||||||
const h = m[2] == '=';
|
const h = m[2] == '=';
|
||||||
if (m[1].length > desc || h && m[1].length != desc)
|
if (m[1].length > desc || h && m[1].length != desc)
|
||||||
throw new Error('Invalid descender height at ' + l);
|
throw new Error('Invalid descender height at ' + l);
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,4 @@
|
||||||
0.11: Respect theme colors. Fix: Do not pollute global space with internal variables ans functions in boot.js
|
0.11: Respect theme colors. Fix: Do not pollute global space with internal variables ans functions in boot.js
|
||||||
0.12: Improve pattern detection code readability by PaddeK http://forum.espruino.com/profiles/117930/
|
0.12: Improve pattern detection code readability by PaddeK http://forum.espruino.com/profiles/117930/
|
||||||
0.13: Improve pattern rendering by HughB http://forum.espruino.com/profiles/167235/
|
0.13: Improve pattern rendering by HughB http://forum.espruino.com/profiles/167235/
|
||||||
|
0.14: Update setUI to work with new Bangle.js 2v13 menu style
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@
|
||||||
var sui = Bangle.setUI;
|
var sui = Bangle.setUI;
|
||||||
Bangle.setUI = function (mode, cb) {
|
Bangle.setUI = function (mode, cb) {
|
||||||
sui(mode, cb);
|
sui(mode, cb);
|
||||||
|
if ("object"==typeof mode) mode = mode.mode;
|
||||||
if (!mode) {
|
if (!mode) {
|
||||||
Bangle.removeListener("drag", dragHandler);
|
Bangle.removeListener("drag", dragHandler);
|
||||||
storedPatterns = {};
|
storedPatterns = {};
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "ptlaunch",
|
"id": "ptlaunch",
|
||||||
"name": "Pattern Launcher",
|
"name": "Pattern Launcher",
|
||||||
"shortName": "Pattern Launcher",
|
"shortName": "Pattern Launcher",
|
||||||
"version": "0.13",
|
"version": "0.14",
|
||||||
"description": "Directly launch apps from the clock screen with custom patterns.",
|
"description": "Directly launch apps from the clock screen with custom patterns.",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"screenshots": [{"url":"manage_patterns_light.png"}],
|
"screenshots": [{"url":"manage_patterns_light.png"}],
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
0.01: Initial Release
|
0.01: Initial Release
|
||||||
0.02: Minor tweaks for light theme
|
0.02: Minor tweaks for light theme
|
||||||
0.03: Made images 2 bit and fixed theme honoring
|
0.03: Made images 2 bit and fixed theme honoring
|
||||||
|
0.04: Fixed date font alignment and changed date font to match a real Rolex
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
# Rolex
|
# Rolex
|
||||||
|
|
||||||

|
 
|
||||||
|
|
||||||
Created with the aid of the Espruino documentation and looking through many of the wonderful exising watchfaces that have been made.
|
Created with the aid of the Espruino documentation and looking through many of the wonderful exising watchfaces that have been made.
|
||||||
This has not been tested on a watch yet as I haven't aquired one but has been tested in the emulator.
|
This has not been tested on a watch yet as I haven't aquired one but has been tested in the emulator.
|
||||||
The hands don't rotate dead on center but they're as close as I could get them to.
|
The hands don't rotate dead on center but they're as close as I could get them to.
|
||||||
|
|
||||||
|
Colour switches based on watch theme so if you want a white on black change your watch theme to dark, and for black on white change it to light.
|
||||||
|
|
||||||
Special thanks to:
|
Special thanks to:
|
||||||
* rozek (for his updated widget draw code for utilization with background images)
|
* rozek (for his updated widget draw code for utilization with background images)
|
||||||
* Gordon Williams (Bangle.js, watchapps for reference code and documentation)
|
* Gordon Williams (Bangle.js, watchapps for reference code and documentation)
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,14 @@ var imgSec = {
|
||||||
buffer : E.toArrayBuffer(atob("v/q//r/+v/qv+q/qq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qv+v/6/D/wD8PDw8PwD/w///6v+qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqr+r//v///X/1X/Vf9V/1X/1///+//q/qq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq6qrqg=="))
|
buffer : E.toArrayBuffer(atob("v/q//r/+v/qv+q/qq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qv+v/6/D/wD8PDw8PwD/w///6v+qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqr+r//v///X/1X/Vf9V/1X/1///+//q/qq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq+qr6qvqq6qrqg=="))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* use font closer to Rolex */
|
||||||
|
|
||||||
|
Graphics.prototype.setFontRolexFont = function(scale) {
|
||||||
|
// Actual height 12 (12 - 1)
|
||||||
|
this.setFontCustom(atob("AAAABAACAAAAAYAHgA4AOABgAAAAA/gD/gMBgQBAwGA/4A/gAAAAAAIBAQCB/8D/4AAQAAAAAAAAAwEDAYEBQIEgYxA/CA4MAAAAAAAAgIBAhCBCEDOYHvgCOAAAAAAABgANAAyAHEAf/A/+AAgABAAAAAAADBAcCBsECYIEYgIeAAAAAAAHwAfwB5wGggZBAjGBH4CDgAAACAAYAAgABAMCDwE+APgAYAAAAAAABxwH3wJwgRhA3iB54AhgAAAAAAPhA/iBDMCCQGHgH+AHwAAAAAAAQIAgQAAAAAA="), 46, atob("BAUJCQkJCQkJCQkJBQ=="), 17+(scale<<8)+(1<<16));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
/* Set variables to get screen width, height and center points */
|
/* Set variables to get screen width, height and center points */
|
||||||
|
|
||||||
let W = g.getWidth();
|
let W = g.getWidth();
|
||||||
|
|
@ -36,10 +44,6 @@ let cx = W/2;
|
||||||
let cy = H/2;
|
let cy = H/2;
|
||||||
let Timeout;
|
let Timeout;
|
||||||
|
|
||||||
/* set font */
|
|
||||||
|
|
||||||
require("Font4x5Numeric").add(Graphics);
|
|
||||||
|
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
|
|
||||||
/* Custom version of Bangle.drawWidgets (does not clear the widget areas) Thanks to rozek */
|
/* Custom version of Bangle.drawWidgets (does not clear the widget areas) Thanks to rozek */
|
||||||
|
|
@ -106,9 +110,10 @@ function drawHands() {
|
||||||
g.drawImage(imgHour,cx-22*hourSin,cy+22*hourCos,{rotate:hourAngle});
|
g.drawImage(imgHour,cx-22*hourSin,cy+22*hourCos,{rotate:hourAngle});
|
||||||
g.drawImage(imgMin,cx-34*minSin,cy+34*minCos,{rotate:minAngle});
|
g.drawImage(imgMin,cx-34*minSin,cy+34*minCos,{rotate:minAngle});
|
||||||
g.drawImage(imgSec,cx-25*secSin,cy+25*secCos,{rotate:secAngle});
|
g.drawImage(imgSec,cx-25*secSin,cy+25*secCos,{rotate:secAngle});
|
||||||
g.setFont("4x5Numeric:3");
|
g.setFontRolexFont();
|
||||||
g.setColor(g.theme.bg);
|
g.setColor(g.theme.bg);
|
||||||
g.drawString(d.getDate(),157,81);
|
g.setFontAlign(0,0,0);
|
||||||
|
g.drawString(d.getDate(),165,89);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawBackground() {
|
function drawBackground() {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
"name": "rolex",
|
"name": "rolex",
|
||||||
"shortName":"rolex",
|
"shortName":"rolex",
|
||||||
"icon": "rolex.png",
|
"icon": "rolex.png",
|
||||||
"screenshots": [{"url":"screenshot.png"}],
|
"screenshots": [{"url":"screenshot1.png"}],
|
||||||
"version":"0.03",
|
"version":"0.04",
|
||||||
"description": "A rolex like watch face",
|
"description": "A rolex like watch face",
|
||||||
"tags": "clock",
|
"tags": "clock",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
|
|
|
||||||
|
After Width: | Height: | Size: 3.8 KiB |
|
|
@ -46,8 +46,8 @@ record GPS/HRM/etc data every time you start a run?
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
This app uses the [`exstats` module](/modules/exstats.js). When uploaded via the
|
This app uses the [`exstats` module](https://github.com/espruino/BangleApps/blob/master/modules/exstats.js). When uploaded via the
|
||||||
app loader, the module is automatically included in the app's source. However
|
app loader, the module is automatically included in the app's source. However
|
||||||
when developing via the IDE the module won't get pulled in by default.
|
when developing via the IDE the module won't get pulled in by default.
|
||||||
|
|
||||||
There are some options to fix this easily - please check out the [modules README.md file](/modules/README.md)
|
There are some options to fix this easily - please check out the [modules README.md file](https://github.com/espruino/BangleApps/blob/master/modules/README.md)
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@ function showThemeMenu() {
|
||||||
/*LANG*/'Dark BW': ()=>{
|
/*LANG*/'Dark BW': ()=>{
|
||||||
upd({
|
upd({
|
||||||
fg:cl("#fff"), bg:cl("#000"),
|
fg:cl("#fff"), bg:cl("#000"),
|
||||||
fg2:cl("#0ff"), bg2:cl("#000"),
|
fg2:cl("#fff"), bg2:cl("#004"),
|
||||||
fgH:cl("#fff"), bgH:cl("#00f"),
|
fgH:cl("#fff"), bgH:cl("#00f"),
|
||||||
dark:true
|
dark:true
|
||||||
});
|
});
|
||||||
|
|
|
||||||