Merge branch 'espruino:master' into master
|
|
@ -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
|
||||
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 Dx = SegW/14, Dy = SegH/16;
|
||||
|
||||
const hColor = [1,1,1];
|
||||
const mColor = [0.3,0.3,1];
|
||||
const bColor = [0.2,0.2,0.2];
|
||||
switch(settings.ColorMinutes) {
|
||||
case "blue":
|
||||
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 = [
|
||||
[
|
||||
|
|
@ -114,16 +138,22 @@ const Font = [
|
|||
var dho = -1, eho = -1, dmo = -1, emo = -1;
|
||||
|
||||
|
||||
function drawHSeg(x1,y1,x2,y2,Num,dColor,Size) {
|
||||
g.setColor(0,0,0);
|
||||
function drawHSeg(x1,y1,x2,y2,Num,Color,Size) {
|
||||
|
||||
|
||||
g.setColor(g.theme.bg);
|
||||
g.fillRect(x1, y1, x2, y2);
|
||||
for (let i = 1; i < 8; i++) {
|
||||
for (let j = 1; j < 8; j++) {
|
||||
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);
|
||||
} else {
|
||||
g.setColor(bColor[0],bColor[1],bColor[2]);
|
||||
g.setColor(bColor[0],bColor[1],bColor[2]);
|
||||
g.fillCircle(x1+Dx+(i-1)*(x2-x1)/7,y1+Dy+(j-1)*(y2-y1)/7,1);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 j = 1; j < 8; j++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -143,25 +178,27 @@ function drawSSeg(x1,y1,x2,y2,Num,dColor,Size) {
|
|||
}
|
||||
|
||||
|
||||
function ShowSecons() {
|
||||
g.setColor(1,1,1);
|
||||
g.fillRect((Xe-Xs) / 2 - 14 + Xs -3,
|
||||
(Ye-Ys) / 2 - 7 + Ys -3,
|
||||
(Xe-Xs) / 2 + 14 + Xs +1,
|
||||
(Ye-Ys) / 2 + 7 + Ys +1);
|
||||
function ShowSeconds() {
|
||||
|
||||
g.setColor(sbColor[0],sbColor[1],sbColor[2]);
|
||||
|
||||
g.fillRect((Xe-Xs) / 2 - 14 + Xs -4,
|
||||
(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,
|
||||
(Ye-Ys) / 2 - 7 + Ys ,
|
||||
(Ye-Ys) / 2 - 7 + Ys +1,
|
||||
(Xe-Xs) / 2 + Xs -1,
|
||||
(Ye-Ys) / 2 + 7 + Ys,
|
||||
ds,mColor,1);
|
||||
(Ye-Ys) / 2 + 7 + Ys +1,
|
||||
ds,"fg",1);
|
||||
|
||||
drawSSeg( (Xe-Xs) / 2 + Xs +1,
|
||||
(Ye-Ys) / 2 - 7 + Ys,
|
||||
(Xe-Xs) / 2 + 14 + Xs +1,
|
||||
(Ye-Ys) / 2 + 7 + Ys,
|
||||
es,mColor,1);
|
||||
drawSSeg( (Xe-Xs) / 2 + Xs +2,
|
||||
(Ye-Ys) / 2 - 7 + Ys +1,
|
||||
(Xe-Xs) / 2 + 14 + Xs +2,
|
||||
(Ye-Ys) / 2 + 7 + Ys +1,
|
||||
es,"fg",1);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -185,29 +222,29 @@ function draw() {
|
|||
g.reset();
|
||||
if (dh != dho) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (eh != eho) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (dm != dmo) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (em != emo) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (!Bangle.isLocked()) ShowSecons();
|
||||
if (!Bangle.isLocked()) ShowSeconds();
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -278,7 +315,7 @@ function drawWidgeds() {
|
|||
|
||||
var x1M = 100;
|
||||
var y1M = y1B;
|
||||
var x2M = x1M + 30;
|
||||
var x2M = x1M + 25;
|
||||
var y2M = y2B;
|
||||
|
||||
if (messages.some(m=>m.new)) {
|
||||
|
|
@ -295,6 +332,7 @@ function drawWidgeds() {
|
|||
|
||||
print(strDow[dow] + ' ' + day + '.' + month + ' ' + year);
|
||||
|
||||
g.setColor(g.theme.fg);
|
||||
g.setFontAlign(-1, -1,0);
|
||||
g.setFont("Vector", 20);
|
||||
g.drawString(strDow[dow] + ' ' + day, 0, 0, true);
|
||||
|
|
|
|||
|
|
@ -1,21 +1,8 @@
|
|||
(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) {
|
||||
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) {
|
||||
var Apps = require("Storage").list(/\.info$/)
|
||||
.map(app => {var a=storage.readJSON(app, 1);return (
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
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
|
||||
* system widgeds ar not (yet) supported
|
||||
* 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
|
||||
* you can configure a app per swipe direction
|
||||
* when swiping the configured apps are launced
|
||||
* when screen is unlocked it shows additional info: bluetooth, battery, new message state, date and seconds
|
||||
* you can configure an app per swipe direction
|
||||
* when swiping the configured apps are launched
|
||||
* 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",
|
||||
"name": "7x7 Dots Clock",
|
||||
"shortName":"7x7 Dots Clock",
|
||||
"version":"0.01",
|
||||
"version":"0.02",
|
||||
"description": "A clock with a big 7x7 dots Font",
|
||||
"icon": "dotsfontclock.png",
|
||||
"tags": "clock",
|
||||
"type": "clock",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"allow_emulator": true,
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"7x7dotsclock.app.js","url":"7x7dotsclock.app.js"},
|
||||
{"name":"7x7dotsclock.settings.js","url":"7x7dotsclock.settings.js"},
|
||||
{"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
|
||||
0.13: Alarm widget state now updates when setting/resetting an alarm
|
||||
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' },
|
||||
/*LANG*/'< Back' : showMainMenu,
|
||||
/*LANG*/'Hours': {
|
||||
value: hrs,
|
||||
onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this'
|
||||
value: hrs, min : 0, max : 23, wrap : true,
|
||||
onchange: v => hrs=v
|
||||
},
|
||||
/*LANG*/'Minutes': {
|
||||
value: mins,
|
||||
onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this'
|
||||
value: mins, min : 0, max : 59, wrap : true,
|
||||
onchange: v => mins=v
|
||||
},
|
||||
/*LANG*/'Enabled': {
|
||||
value: en,
|
||||
|
|
@ -138,12 +138,12 @@ function editTimer(alarmIndex) {
|
|||
const menu = {
|
||||
'': { 'title': /*LANG*/'Timer' },
|
||||
/*LANG*/'Hours': {
|
||||
value: hrs,
|
||||
onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this'
|
||||
value: hrs, min : 0, max : 23, wrap : true,
|
||||
onchange: v => hrs=v
|
||||
},
|
||||
/*LANG*/'Minutes': {
|
||||
value: mins,
|
||||
onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this'
|
||||
value: mins, min : 0, max : 59, wrap : true,
|
||||
onchange: v => mins=v
|
||||
},
|
||||
/*LANG*/'Enabled': {
|
||||
value: en,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "alarm",
|
||||
"name": "Default Alarm & Timer",
|
||||
"shortName": "Alarms",
|
||||
"version": "0.14",
|
||||
"version": "0.15",
|
||||
"description": "Set and respond to alarms and timers",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,alarm,widget",
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
0.01: Add a number to match to turn off alarm
|
||||
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 = {
|
||||
'': { 'title': 'Alarms' },
|
||||
'Hours': {
|
||||
value: hrs,
|
||||
onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this'
|
||||
/*LANG*/'Hours': {
|
||||
value: hrs, min : 0, max : 23, wrap : true,
|
||||
onchange: v => hrs=v
|
||||
},
|
||||
'Minutes': {
|
||||
value: mins,
|
||||
onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this'
|
||||
/*LANG*/'Minutes': {
|
||||
value: mins, min : 0, max : 59, wrap : true,
|
||||
onchange: v => mins=v
|
||||
},
|
||||
'Enabled': {
|
||||
/*LANG*/'Enabled': {
|
||||
value: en,
|
||||
format: v=>v?"On":"Off",
|
||||
onchange: v=>en=v
|
||||
},
|
||||
'Repeat': {
|
||||
/*LANG*/'Repeat': {
|
||||
value: en,
|
||||
format: v=>v?"Yes":"No",
|
||||
onchange: v=>repeat=v
|
||||
},
|
||||
'Auto snooze': {
|
||||
/*LANG*/'Auto snooze': {
|
||||
value: as,
|
||||
format: v=>v?"Yes":"No",
|
||||
onchange: v=>as=v
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "hardalarm",
|
||||
"name": "Hard Alarm",
|
||||
"shortName": "HardAlarm",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "Make sure you wake up! Count to the right number to turn off the alarm",
|
||||
"icon": "app.png",
|
||||
"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 |
|
|
@ -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.21: Improve list readability on dark theme
|
||||
0.22: Add Home Assistant icon
|
||||
0.22: Allow repeat to be switched Off, so there is no buzzing repetition.
|
||||
Also gave the widget a pixel more room to the right
|
||||
Allow repeat to be switched Off, so there is no buzzing repetition.
|
||||
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.
|
||||
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.
|
||||
* `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
|
||||
|
||||
|
|
|
|||
|
|
@ -21,13 +21,11 @@
|
|||
*/
|
||||
|
||||
var Layout = require("Layout");
|
||||
var settings = require('Storage').readJSON("messages.settings.json", true) || {};
|
||||
var fontSmall = "6x8";
|
||||
var fontMedium = g.getFonts().includes("6x15")?"6x15":"6x8:2";
|
||||
var fontBig = g.getFonts().includes("12x20")?"12x20":"6x8:2";
|
||||
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
|
||||
try {
|
||||
g.setFont("6x8:2");
|
||||
|
|
@ -94,6 +92,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=="slack") return atob("GBiBAAAAAAAAAABAAAHvAAHvAADvAAAPAB/PMB/veD/veB/mcAAAABzH8B3v+B3v+B3n8AHgAAHuAAHvAAHvAADGAAAAAAAAAAAAAA==");
|
||||
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=="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==");
|
||||
|
|
@ -122,6 +121,7 @@ function getMessageImageCol(msg,def) {
|
|||
"outlook mail": "#0072c6",
|
||||
"skype": "#00aff0",
|
||||
"slack": "#e51670",
|
||||
"threema": "#000",
|
||||
"telegram": "#0088cc",
|
||||
"twitter": "#1da1f2",
|
||||
"whatsapp": "#4fce5d",
|
||||
|
|
@ -143,8 +143,8 @@ function showMapMessage(msg) {
|
|||
eta = m[2];
|
||||
} else target=msg.body;
|
||||
layout = new Layout({ type:"v", c: [
|
||||
{type:"txt", font:fontMedium, label:target, bgCol:colBg, fillx:1, pad:2 },
|
||||
{type:"h", bgCol:colBg, fillx:1, c: [
|
||||
{type:"txt", font:fontMedium, label:target, bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2 },
|
||||
{type:"h", bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, c: [
|
||||
{type:"txt", font:"6x8", label:"Towards" },
|
||||
{type:"txt", font:fontLarge, label:street }
|
||||
]},
|
||||
|
|
@ -168,27 +168,56 @@ function showMapMessage(msg) {
|
|||
}
|
||||
|
||||
function showMusicMessage(msg) {
|
||||
var updateLabelsInterval;
|
||||
var trackScrollOffset = 0;
|
||||
var artistScrollOffset = 0;
|
||||
var albumScrollOffset = 0;
|
||||
var trackName = '';
|
||||
var artistName = '';
|
||||
var albumName = '';
|
||||
|
||||
function fmtTime(s) {
|
||||
var m = Math.floor(s/60);
|
||||
s = (parseInt(s%60)).toString().padStart(2,0);
|
||||
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() {
|
||||
clearInterval(updateLabelsInterval);
|
||||
msg.new = false;
|
||||
saveMessages();
|
||||
layout = undefined;
|
||||
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: [
|
||||
{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:"v", fillx:1, c: [
|
||||
{ type:"txt", font:fontMedium, label:msg.artist, pad:2 },
|
||||
{ type:"txt", font:fontMedium, label:msg.album, pad:2 }
|
||||
{ type:"txt", font:fontMedium, bgCol:g.theme.bg2, label:artistName, pad:2, id:"artist" },
|
||||
{ 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: [
|
||||
{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
|
||||
|
|
@ -198,6 +227,14 @@ function showMusicMessage(msg) {
|
|||
]});
|
||||
g.clearRect(Bangle.appRect);
|
||||
layout.render();
|
||||
|
||||
updateLabelsInterval = setInterval(function() {
|
||||
updateLabels();
|
||||
layout.artist.label = artistName;
|
||||
layout.album.label = albumName;
|
||||
layout.track.label = trackName;
|
||||
layout.render();
|
||||
}, 400);
|
||||
}
|
||||
|
||||
function showMessageScroller(msg) {
|
||||
|
|
@ -214,7 +251,9 @@ function showMessageScroller(msg) {
|
|||
// a function to draw a menu item
|
||||
draw : function(idx, r) {
|
||||
// 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);
|
||||
}, select : function(idx) {
|
||||
if (idx>=lines.length-2)
|
||||
|
|
@ -270,13 +309,31 @@ function showMessage(msgid) {
|
|||
var title=msg.title, titleFont = fontLarge, lines;
|
||||
if (title) {
|
||||
var w = g.getWidth()-48;
|
||||
if (g.setFont(titleFont).stringWidth(title) > w)
|
||||
titleFont = fontMedium;
|
||||
if (g.setFont(titleFont).stringWidth(title) > w) {
|
||||
titleFont = fontBig;
|
||||
if (settings.fontSize!=1 && g.setFont(titleFont).stringWidth(title) > w)
|
||||
titleFont = fontMedium;
|
||||
}
|
||||
if (g.setFont(titleFont).stringWidth(title) > w) {
|
||||
lines = g.wrapString(title, w);
|
||||
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() {
|
||||
msg.new = false; saveMessages(); // read mail
|
||||
cancelReloadTimeout(); // don't auto-reload to clock now
|
||||
|
|
@ -303,27 +360,17 @@ function showMessage(msgid) {
|
|||
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: [
|
||||
{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:()=>{
|
||||
cancelReloadTimeout(); // don't auto-reload to clock now
|
||||
showMessageSettings(msg);
|
||||
}},
|
||||
{ type:"v", fillx:1, c: [
|
||||
{type:"txt", font:fontSmall, label:msg.src||/*LANG*/"Message", bgCol:colBg, fillx:1, pad:2, halign:1 },
|
||||
title?{type:"txt", font:titleFont, label:title, bgCol:colBg, fillx:1, pad:2 }:{},
|
||||
{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:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2 }:{},
|
||||
]},
|
||||
]},
|
||||
{type:"txt", font:bodyFont, label:body, fillx:1, filly:1, pad:2, cb:()=>{
|
||||
|
|
@ -374,9 +421,8 @@ function checkMessages(options) {
|
|||
c : Math.max(MESSAGES.length+1,3), // workaround for 2v10.219 firmware (min 3 not needed for 2v11)
|
||||
draw : function(idx, r) {"ram"
|
||||
var msg = MESSAGES[idx-1];
|
||||
if (msg && msg.new) g.setBgColor(colBg);
|
||||
else g.setBgColor((idx&1) ? colSBg1 : colSBg2);
|
||||
g.clearRect(r.x,r.y,r.x+r.w-1,r.y+r.h-1).setColor(g.theme.fg);
|
||||
if (msg && msg.new) g.setBgColor(g.theme.bgH).setColor(g.theme.fgH);
|
||||
else g.setColor(g.theme.fg);
|
||||
if (idx==0) msg = {id:"back", title:"< Back"};
|
||||
if (!msg) return;
|
||||
var x = r.x+2, title = msg.title, body = msg.body;
|
||||
|
|
@ -391,18 +437,20 @@ function checkMessages(options) {
|
|||
.setColor(fg); // only color the icon
|
||||
x += 50;
|
||||
}
|
||||
var m = msg.title+"\n"+msg.body;
|
||||
if (msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2);
|
||||
var m = msg.title+"\n"+msg.body, longBody=false;
|
||||
if (title) g.setFontAlign(-1,-1).setFont(fontBig).drawString(title, x,r.y+2);
|
||||
if (body) {
|
||||
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) {
|
||||
l = l.slice(0,3);
|
||||
l[l.length-1]+="...";
|
||||
}
|
||||
longBody = l.length>2;
|
||||
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 => {
|
||||
if (idx==0) load();
|
||||
|
|
@ -422,7 +470,7 @@ g.clear();
|
|||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
setTimeout(() => {
|
||||
var unreadTimeoutSecs = (require('Storage').readJSON("messages.settings.json", true) || {}).unreadTimeout;
|
||||
var unreadTimeoutSecs = settings.unreadTimeout;
|
||||
if (unreadTimeoutSecs===undefined) unreadTimeoutSecs=60;
|
||||
if (unreadTimeoutSecs)
|
||||
unreadTimeout = setTimeout(function() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "messages",
|
||||
"name": "Messages",
|
||||
"version": "0.22",
|
||||
"version": "0.24",
|
||||
"description": "App to display notifications from iOS and Gadgetbridge/Android",
|
||||
"icon": "app.png",
|
||||
"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",
|
||||
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);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ draw:function() {
|
|||
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);
|
||||
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 (c<120 && (Date.now()-this.l)>settings.repeat*1000) {
|
||||
this.l = Date.now();
|
||||
|
|
@ -47,4 +46,4 @@ want to buzz but should still show that there are unread messages. */
|
|||
if (global.MESSAGES===undefined) (function() {
|
||||
var messages = require("Storage").readJSON("messages.json",1)||[];
|
||||
if (messages.some(m=>m.new)) WIDGETS["messages"].show(true);
|
||||
})();
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@
|
|||
0.10: Improve the management of existing patterns: Draw the linked pattern on the left hand side of the app name within a scroller, similar to the default launcher. Slighlty clean up the code to make it less horrible.
|
||||
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.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;
|
||||
Bangle.setUI = function (mode, cb) {
|
||||
sui(mode, cb);
|
||||
if ("object"==typeof mode) mode = mode.mode;
|
||||
if (!mode) {
|
||||
Bangle.removeListener("drag", dragHandler);
|
||||
storedPatterns = {};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "ptlaunch",
|
||||
"name": "Pattern Launcher",
|
||||
"shortName": "Pattern Launcher",
|
||||
"version": "0.13",
|
||||
"version": "0.14",
|
||||
"description": "Directly launch apps from the clock screen with custom patterns.",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"manage_patterns_light.png"}],
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ function showThemeMenu() {
|
|||
/*LANG*/'Dark BW': ()=>{
|
||||
upd({
|
||||
fg:cl("#fff"), bg:cl("#000"),
|
||||
fg2:cl("#0ff"), bg2:cl("#000"),
|
||||
fg2:cl("#fff"), bg2:cl("#004"),
|
||||
fgH:cl("#fff"), bgH:cl("#00f"),
|
||||
dark:true
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
0.01: New App!
|
||||
0.01: New App!
|
||||
0.02: Update setUI to work with new Bangle.js 2v13 menu style
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
(function() {
|
||||
var sui = Bangle.setUI;
|
||||
Bangle.setUI = function(mode, cb) {
|
||||
if ("object"==typeof mode) mode = mode.mode;
|
||||
if (mode!="clock") return sui(mode,cb);
|
||||
return sui("clockupdown", (dir) => {
|
||||
let settings = require("Storage").readJSON("shortcuts.json", 1)||{};
|
||||
|
|
@ -12,4 +13,3 @@
|
|||
});
|
||||
};
|
||||
})();
|
||||
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "shortcuts",
|
||||
"name": "Shortcuts",
|
||||
"shortName": "Shortcuts",
|
||||
"version": "0.01",
|
||||
"version": "0.02",
|
||||
"description": "Quickly load your favourite apps from (almost) any watch face.",
|
||||
"icon": "app.png",
|
||||
"type": "bootloader",
|
||||
|
|
|
|||
|
|
@ -12,4 +12,4 @@
|
|||
1.10: Adds Kalman filter.
|
||||
1.14: Add VMG and coordinates screens
|
||||
1.43: Adds mirroring of the watch face to an Android device. See README.md
|
||||
1.48: Droidscript mirroring prog automatically uses last connection address. Auto connects when run.
|
||||
1.49: Droidscript mirroring prog automatically uses last connection address. Auto connects when run.
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
0.01: New App!
|
||||
0.02: Fix issue with mode being undefined
|
||||
0.03: Update setUI to work with new Bangle.js 2v13 menu style
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
Bangle.setUI = function(mode, cb) {
|
||||
sui(mode,cb);
|
||||
if(!mode) return;
|
||||
if ("object"==typeof mode) mode = mode.mode;
|
||||
if (!mode.startsWith("clock")) return;
|
||||
Bangle.swipeHandler = dir => { if (dir<0) Bangle.showLauncher(); };
|
||||
Bangle.on("swipe", Bangle.swipeHandler);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "swiperclocklaunch",
|
||||
"name": "Swiper Clock Launch",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "Navigate between clock and launcher with Swipe action",
|
||||
"icon": "swiperclocklaunch.png",
|
||||
"type": "bootloader",
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
0.01: New App!
|
||||
0.02: Fix settings wrapping code for new menu system
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "tabata",
|
||||
"name": "Tabata",
|
||||
"shortName": "Tabata - Control High-Intensity Interval Training",
|
||||
"version": "0.01",
|
||||
"version": "0.02",
|
||||
"description": "Control high-intensity interval training (according to tabata: https://en.wikipedia.org/wiki/Tabata_method).",
|
||||
"icon": "tabata.png",
|
||||
"tags": "workout,health",
|
||||
|
|
|
|||
|
|
@ -30,18 +30,17 @@ function showMainMenu() {
|
|||
},
|
||||
'Pause sec.': {
|
||||
value: settings.pause,
|
||||
onchange: function(v){
|
||||
if (v<0)v=MAX_SECONDS;
|
||||
if (v>MAX_SECONDS)v=0;
|
||||
min : 0, max : MAX_SECONDS, wrap : true,
|
||||
onchange: v => {
|
||||
settings.pause=v;
|
||||
this.value=v;
|
||||
saveSettingsDebounce();
|
||||
}
|
||||
},
|
||||
'Trainig sec.': {
|
||||
value: settings.training,
|
||||
onchange: function(v){if (v<0)v=MAX_SECONDS;if (v>MAX_SECONDS)v=0;settings.training=v;
|
||||
this.value=v;
|
||||
min : 0, max : MAX_SECONDS, wrap : true,
|
||||
onchange: v => {
|
||||
settings.training=v;
|
||||
saveSettingsDebounce();
|
||||
}
|
||||
},
|
||||
|
|
@ -61,8 +60,8 @@ function startTabata() {
|
|||
g.clear();
|
||||
Bangle.setLCDMode("doublebuffered");
|
||||
g.flip();
|
||||
var pause = settings.pause,
|
||||
training = settings.training,
|
||||
var pause = settings.pause,
|
||||
training = settings.training,
|
||||
round = 1,
|
||||
active = true,
|
||||
clearBtn1, clearBtn2, clearBtn3, timer;
|
||||
|
|
@ -86,7 +85,7 @@ function startTabata() {
|
|||
exitTraining();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (active) {
|
||||
drawCountDown(round, training, active);
|
||||
training--;
|
||||
|
|
@ -117,7 +116,7 @@ function drawCountDown(round, count, active) {
|
|||
|
||||
g.setFontAlign(0,0);
|
||||
g.setFont("6x8", 2);
|
||||
g.drawString("Round " + round + "/" + settings.rounds,120,6);
|
||||
g.drawString("Round " + round + "/" + settings.rounds,120,6);
|
||||
|
||||
g.setFont("6x8", 6);
|
||||
g.drawString("" + count,120,80);
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: First version
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 12.7 12.7"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
|
||||
sodipodi:docname="logo.svg"
|
||||
inkscape:export-filename="/home/klomp/Repositories/BangleApps/apps/widcw/widget.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:document-units="px"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
width="48px"
|
||||
inkscape:zoom="16.106622"
|
||||
inkscape:cx="29.242631"
|
||||
inkscape:cy="21.481848"
|
||||
inkscape:window-width="1061"
|
||||
inkscape:window-height="439"
|
||||
inkscape:window-x="2326"
|
||||
inkscape:window-y="806"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:bold;font-size:5.6446px;line-height:2.4ex;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:end;letter-spacing:0.21961px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:none;stroke:#000000;stroke-width:0.264591px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="11.591952"
|
||||
y="-4.2952275"
|
||||
id="text3356"
|
||||
inkscape:export-filename="/home/klomp/Repositories/BangleApps/apps/widcw/widget.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
transform="scale(0.99997031,-1.0000297)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3354"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:5.6446px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000000;stroke-width:0.264591px"
|
||||
x="11.811562"
|
||||
y="-4.2952275">CW</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"id": "widcw",
|
||||
"name": "Calendar Week Widget",
|
||||
"version": "0.01",
|
||||
"description": "Widget which shows the current calendar week",
|
||||
"icon": "widget.png",
|
||||
"type": "widget",
|
||||
"tags": "widget,calendar",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"widcw.wid.js","url":"widget.js"}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
(function() {
|
||||
var width = 22; // width of the widget
|
||||
|
||||
function draw() {
|
||||
const x = this.x, y = this.y, x2 = x+21, y2 = y+23;
|
||||
|
||||
var date = new Date();
|
||||
|
||||
// Calculate calendar week (https://stackoverflow.com/a/6117889)
|
||||
getCW= function(date){
|
||||
var d=new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
var dayNum = d.getDay() || 7;
|
||||
d.setDate(d.getDate() + 4 - dayNum);
|
||||
var yearStart = new Date(d.getFullYear(),0,1);
|
||||
return Math.ceil((((d - yearStart) / 86400000) + 1)/7);
|
||||
};
|
||||
|
||||
g.reset().setFontAlign(0, 0) // center all text
|
||||
// header
|
||||
.setBgColor("#f00").setColor("#fff")
|
||||
.clearRect(x, y, x2, y+8).setFont("4x6").drawString("CW", (x+x2)/2+1, y+5)
|
||||
// date
|
||||
.setBgColor("#fff").setColor("#000")
|
||||
.clearRect(x, y+9, x2, y2).setFont("Vector:16").drawString(getCW(date), (x+x2)/2+2, y+17);
|
||||
|
||||
if (!g.theme.dark) {
|
||||
// black border around date for light themes
|
||||
g.setColor("#000").drawPoly([
|
||||
x, y+9,
|
||||
x, y2,
|
||||
x2, y2,
|
||||
x2, y+9
|
||||
]);
|
||||
}
|
||||
|
||||
// redraw when date changes
|
||||
setTimeout(()=>WIDGETS["widcw"].draw(), (86401 - Math.floor(date/1000) % 86400)*1000);
|
||||
|
||||
}
|
||||
|
||||
// add your widget
|
||||
WIDGETS["widcw"]={
|
||||
area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right)
|
||||
width: width, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout
|
||||
draw:draw // called to draw the widget
|
||||
};
|
||||
|
||||
})();
|
||||
|
After Width: | Height: | Size: 884 B |
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 12.7 12.7"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
|
||||
sodipodi:docname="logo.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:document-units="px"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
width="48px"
|
||||
inkscape:zoom="16.106622"
|
||||
inkscape:cx="29.211588"
|
||||
inkscape:cy="21.450805"
|
||||
inkscape:window-width="1918"
|
||||
inkscape:window-height="1158"
|
||||
inkscape:window-x="1366"
|
||||
inkscape:window-y="20"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:bold;font-size:5.64444px;line-height:2.4ex;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:end;letter-spacing:0.219604px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="11.591612"
|
||||
y="8.4046535"
|
||||
id="text3356"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3354"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:5.64444px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000000;stroke-width:0.264583px"
|
||||
x="11.811215"
|
||||
y="8.4046535">CW</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
|
|
@ -2,3 +2,4 @@
|
|||
0.02: Don't break if running on 2v08 firmware (just don't display anything)
|
||||
0.03: Fix positioning
|
||||
0.04: Show GPS fix status
|
||||
0.05: Don't poll for GPS status, override setGPSPower handler (fix #1456)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "widgps",
|
||||
"name": "GPS Widget",
|
||||
"version": "0.04",
|
||||
"version": "0.05",
|
||||
"description": "Tiny widget to show the power and fix status of the GPS",
|
||||
"icon": "widget.png",
|
||||
"type": "widget",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
(function(){
|
||||
if (!Bangle.isGPSOn) return; // old firmware
|
||||
// override setGPSPower so we know if GPS is on or off
|
||||
var oldSetGPSPower = Bangle.setGPSPower;
|
||||
Bangle.setGPSPower = function(on,id) {
|
||||
var isGPSon = oldSetGPSPower(on,id);
|
||||
WIDGETS.gps.draw();
|
||||
return isGPSon;
|
||||
}
|
||||
|
||||
function draw() {
|
||||
WIDGETS.gps={area:"tr",width:24,draw:function() {
|
||||
g.reset();
|
||||
if (Bangle.isGPSOn()) {
|
||||
const gpsObject = Bangle.getGPSFix();
|
||||
|
|
@ -14,20 +20,5 @@
|
|||
g.setColor("#888"); // off = grey
|
||||
}
|
||||
g.drawImage(atob("GBiBAAAAAAAAAAAAAA//8B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+A//8AAAAAAAAAAAAA=="), this.x, 2+this.y);
|
||||
}
|
||||
|
||||
var timerInterval;
|
||||
Bangle.on('lcdPower', function(on) {
|
||||
if (on) {
|
||||
WIDGETS.gps.draw();
|
||||
if (!timerInterval) timerInterval = setInterval(()=>WIDGETS.gps.draw(), 2000);
|
||||
} else {
|
||||
if (timerInterval) {
|
||||
clearInterval(timerInterval);
|
||||
timerInterval = undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
WIDGETS.gps={area:"tr",width:24,draw:draw};
|
||||
}};
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -180,13 +180,6 @@ function Layout(layout, options) {
|
|||
if (l.id) ll[l.id] = l;
|
||||
// fix type up
|
||||
if (!l.type) l.type="";
|
||||
// FIXME ':'/fsz not needed in new firmwares - Font:12 is handled internally
|
||||
// fix fonts for pre-2v11 firmware
|
||||
if (l.font && l.font.includes(":")) {
|
||||
var f = l.font.split(":");
|
||||
l.font = f[0];
|
||||
l.fsz = f[1];
|
||||
}
|
||||
if (l.c) l.c.forEach(recurser);
|
||||
}
|
||||
recurser(this._l);
|
||||
|
|
@ -241,13 +234,13 @@ Layout.prototype.render = function (l) {
|
|||
"":function(){},
|
||||
"txt":function(l){
|
||||
if (l.wrap) {
|
||||
g.setFont(l.font,l.fsz).setFontAlign(0,-1);
|
||||
g.setFont(l.font).setFontAlign(0,-1);
|
||||
var lines = g.wrapString(l.label, l.w);
|
||||
var y = l.y+((l.h-g.getFontHeight()*lines.length)>>1);
|
||||
// TODO: on 2v11 we can just render in a single drawString call
|
||||
lines.forEach((line, i) => g.drawString(line, l.x+(l.w>>1), y+g.getFontHeight()*i));
|
||||
} else {
|
||||
g.setFont(l.font,l.fsz).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1));
|
||||
g.setFont(l.font).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1));
|
||||
}
|
||||
}, "btn":function(l){
|
||||
var x = l.x+(0|l.pad), y = l.y+(0|l.pad),
|
||||
|
|
@ -365,7 +358,7 @@ Layout.prototype.update = function() {
|
|||
if (l.wrap) {
|
||||
l._h = l._w = 0;
|
||||
} else {
|
||||
var m = g.setFont(l.font,l.fsz).stringMetrics(l.label);
|
||||
var m = g.setFont(l.font).stringMetrics(l.label);
|
||||
l._w = m.width; l._h = m.height;
|
||||
}
|
||||
}, "btn": function(l) {
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ Bangle.on("GPS", function(fix) {
|
|||
Bangle.on("step", function(steps) {
|
||||
if (!state.active) return;
|
||||
if (stats["step"]) stats["step"].emit("changed",stats["step"]);
|
||||
state.stepHistory[0] += steps-state.lastStepCount;
|
||||
state.lastStepCount = steps;
|
||||
});
|
||||
Bangle.on("HRM", function(h) {
|
||||
|
|
|
|||