Merge branch 'espruino:master' into master
35
apps.json
|
|
@ -2857,10 +2857,10 @@
|
|||
"name": "Test User Input",
|
||||
"shortName":"Test User Input",
|
||||
"icon": "app.png",
|
||||
"version":"0.05",
|
||||
"description": "Basic app to test the bangle.js input interface. It displays the user action in text, an option round element or an on/off switch image for swipe movements.",
|
||||
"version":"0.06",
|
||||
"description": "App to test the bangle.js input interface. It displays the user action in text, circle buttons or on/off switch UI elements.",
|
||||
"readme": "README.md",
|
||||
"tags": "input,interface,buttons,touch",
|
||||
"tags": "input,interface,buttons,touch,UI",
|
||||
"storage": [
|
||||
{"name":"testuserinput.app.js","url":"app.js"},
|
||||
{"name":"testuserinput.img","url":"app-icon.js","evaluate":true}
|
||||
|
|
@ -3044,7 +3044,7 @@
|
|||
"name": "Gadgetbridge Music Controls",
|
||||
"shortName":"Music Controls",
|
||||
"icon": "icon.png",
|
||||
"version":"0.03",
|
||||
"version":"0.05",
|
||||
"description": "Control the music on your Gadgetbridge-connected phone",
|
||||
"tags": "tools,bluetooth,gadgetbridge,music",
|
||||
"type":"app",
|
||||
|
|
@ -3085,8 +3085,8 @@
|
|||
{ "id": "kitchen",
|
||||
"name": "Kitchen Combo",
|
||||
"icon": "kitchen.png",
|
||||
"version":"0.06",
|
||||
"description": "Combination of the stepo, walkersclock, arrow and waypointer apps into a multiclock format. 'Everything but the kitchen sink'. Requires firmware v2.08.167 or later",
|
||||
"version":"0.10",
|
||||
"description": "Combination of the Stepo, Walkersclock, Arrow and Waypointer apps into a multiclock format. 'Everything but the kitchen sink'. Requires firmware v2.08.167 or later",
|
||||
"tags": "tool,outdoors,gps",
|
||||
"type":"clock",
|
||||
"readme": "README.md",
|
||||
|
|
@ -3096,10 +3096,13 @@
|
|||
{"name":"stepo.kit.js","url":"stepo.kit.js"},
|
||||
{"name":"gps.kit.js","url":"gps.kit.js"},
|
||||
{"name":"digi.kit.js","url":"digi.kit.js"},
|
||||
{"name":"heart.kit.js","url":"heart.kit.js"},
|
||||
{"name":"swatch.kit.js","url":"swatch.kit.js"},
|
||||
{"name":"compass.kit.js","url":"compass.kit.js"},
|
||||
{"name":"waypoints.json","url":"waypoints.json","evaluate":false},
|
||||
{"name":"kitchen.img","url":"kitchen.icon.js","evaluate":true}
|
||||
],
|
||||
"data": [
|
||||
{"name":"waypoints.json","url":"waypoints.json"}
|
||||
]
|
||||
},
|
||||
{ "id": "qmsched",
|
||||
|
|
@ -3152,7 +3155,7 @@
|
|||
"id": "omnitrix",
|
||||
"name":"Omnitrix",
|
||||
"icon":"omnitrix.png",
|
||||
"version": "1.0",
|
||||
"version": "0.01",
|
||||
"readme": "README.md",
|
||||
"description": "An Omnitrix Showpiece",
|
||||
"tags": "game",
|
||||
|
|
@ -3166,7 +3169,7 @@
|
|||
"name": "Bat Clock",
|
||||
"shortName":"Bat Clock",
|
||||
"icon": "bat-clock.png",
|
||||
"version":"1.0",
|
||||
"version":"0.01",
|
||||
"description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.",
|
||||
"tags": "clock",
|
||||
"type": "clock",
|
||||
|
|
@ -3175,5 +3178,19 @@
|
|||
{"name":"batclock.app.js","url":"bat-clock.app.js"},
|
||||
{"name":"batclock.img","url":"bat-clock.icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id":"doztime",
|
||||
"name":"Dozenal Time",
|
||||
"shortName":"Dozenal Time",
|
||||
"icon":"app.png",
|
||||
"version":"0.01",
|
||||
"description":"A dozenal Holocene calendar and dozenal diurnal clock",
|
||||
"tags":"clock",
|
||||
"type":"clock",
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"doztime.app.js","url":"app.js"},
|
||||
{"name":"doztime.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
Dozenal Time
|
||||
============
|
||||
|
||||
A dozenal Holocene calendar and a dozenal diurnal clock. For information about them, go to https://dozenal.ae-web.ca/pdf/dozenal-calendar.pdf and https://dozenal.ae-web.ca/pdf/about-short.pdf. They've been in use for some years.
|
||||
|
||||
In the dozenal number base, ten and eleven are single digits, and 10 is a dozen. The clock simply divides the day by successive powers of a dozen. The day or parts of it may be divided easily into halves, thirds, quarters, sixths, or twelfths (dozenths). There is no conglomeration of bases two, ten, twelve, and sixty, as in the current system of time measurement.
|
||||
|
||||
The annual calendar has a dozen months of 5 weeks each, each week having 6 days. The 5 or 6 days beyond 360 (dozenal 260) are added where they keep the season beginnings the most accurate.
|
||||
|
||||
The year itself begins on the December solstice. Because that always happens, there is no need of a leap-year rule to keep the seasons from drifting.
|
||||
|
||||
The epoch (year numbering) begins in the last year when the perihelion coincided with the June solstice, near the beginning of the Holocene era. That astronomical basis makes the calendar free from politics, religion, or geography.
|
||||
|
||||
While the year number remains cardinal, BTN5 toggles between cardinal and ordinal for the rest of the calendar segments. BTN4 adds or removes a quickly changing digit to or from the clock.
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("lEowggdkUiCKIADCJcCkUjmYACmUikAlKB4ImDAoQSJkYhBFAQECAQI5HBQU//4AC+YUCHowzBCQfzAYYKCEw8vEgYqD+QoGgQbBHAYADCwIoBCYkiEwhPEBAIoBHgY6BExHyHwQhBFAQ6BkYTHDgcyHgcCHRZlDCYQsBTYg6GDAJQDPoI6LAAIPBCYRiHHQhkDCYRiHHQhkCCYKKBCYzzBA4yMBCYTVEGYITEBYITZHY5PHUAJjITIJjHRZINBIYoTDWZAoFWYbbJFALbHgUyX4oPDXIcjMQITBmZkHFYszCYZkJMQoTCKAQ8IHQZOCHgYoKkQ6DHgYoEcIgmBHQg8CFAIPCCYfzBQQSEFAbrFCQImHFAQUCkczmYECAQISGHoYzBAAQFCCRA9BEwYoDHI4pFAAgRLCooRPABg="))
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
// Positioning values for graphics buffers
|
||||
const g_height = 80; // total graphics height
|
||||
const g_x_off = 16; // position from left
|
||||
const g_y_off = (240 - g_height)/2; // vertical center for graphics region
|
||||
const g_width = 240 - 2 * g_x_off; // total graphics width
|
||||
const g_height_d = 32; // height of date region
|
||||
const g_y_off_d = 0; // y position of date region within graphics region
|
||||
const spacing = 0; // space between date and time in graphics region
|
||||
const g_y_off_t = g_y_off_d + g_height_d + spacing; // y position of time within graphics region
|
||||
const g_height_t = 48; // height of time region
|
||||
|
||||
// Other vars
|
||||
const A1 = [30,30,30,30,31,31,31,31,31,31,30,30];
|
||||
const B1 = [30,30,30,30,30,31,31,31,31,31,30,30];
|
||||
const B2 = [30,30,30,30,31,31,31,31,31,30,30,30];
|
||||
const timeColour = "#f2f2f2";
|
||||
const dateColours = ["#ff0000","#ffa500","#ffff00","#00b800","#0000ff","#ff00ff","#ff0080"];
|
||||
const calen10 = {"size":32,"pt0":[32-g_x_off,16],"step":[20,0],"dx":-4.5,"dy":-4.5}; // positioning for usual calendar line
|
||||
const calen7 = {"size":32,"pt0":[62-g_x_off,16],"step":[20,0],"dx":-4.5,"dy":-4.5}; // positioning for S-day calendar line
|
||||
const time5 = {"size":48,"pt0":[64-g_x_off,24],"step":[30,0],"dx":-6.5,"dy":-6.5}; // positioning for lull time line; was 64
|
||||
const time6 = {"size":48,"pt0":[48-g_x_off,24],"step":[30,0],"dx":-6.5,"dy":-6.5}; // positioning for twinkling time line
|
||||
const baseYear = 11584;
|
||||
const baseDate = Date(2020,11,21); // month values run from 0 to 11
|
||||
let accum = new Date(baseDate.getTime());
|
||||
let sequence = [];
|
||||
let timeActiveUntil;
|
||||
let addTimeDigit = false;
|
||||
let dateFormat = false;
|
||||
let lastX = 999999999;
|
||||
let res = {};
|
||||
//var last_time_log = 0;
|
||||
|
||||
// Date and time graphics buffers
|
||||
var dateColour = "#ffffff"; // override later
|
||||
var g_d = Graphics.createArrayBuffer(g_width,g_height_d,1,{'msb':true});
|
||||
var g_t = Graphics.createArrayBuffer(g_width,g_height_t,1,{'msb':true});
|
||||
// Set screen mode and function to write graphics buffers
|
||||
Bangle.setLCDMode();
|
||||
g.clear(); // start with blank screen
|
||||
g.flip = function()
|
||||
{
|
||||
g.setColor(dateColour);
|
||||
g.drawImage(
|
||||
{
|
||||
width:g_width,
|
||||
height:g_height_d,
|
||||
buffer:g_d.buffer
|
||||
}, g_x_off, g_y_off + g_y_off_d);
|
||||
g.setColor(timeColour);
|
||||
g.drawImage(
|
||||
{
|
||||
width:g_width,
|
||||
height:g_height_t,
|
||||
buffer:g_t.buffer
|
||||
}, g_x_off, g_y_off + g_y_off_t);
|
||||
};
|
||||
|
||||
setWatch(function(){ modeTime(); }, BTN1, {repeat:true} );
|
||||
setWatch(function(){ Bangle.showLauncher(); }, BTN2, { repeat: false, edge: "falling" });
|
||||
setWatch(function(){ modeWeather(); }, BTN3, {repeat:true});
|
||||
setWatch(function(){ toggleTimeDigits(); }, BTN4, {repeat:true});
|
||||
setWatch(function(){ toggleDateFormat(); }, BTN5, {repeat:true});
|
||||
|
||||
function buildSequence(targ){
|
||||
for(let i=0;i<targ.length;++i){
|
||||
sequence.push(new Date(accum.getTime()));
|
||||
accum.setDate(accum.getDate()+targ[i]);
|
||||
}
|
||||
}
|
||||
buildSequence(B2);
|
||||
buildSequence(B2);
|
||||
buildSequence(A1);
|
||||
buildSequence(B1);
|
||||
buildSequence(B2);
|
||||
buildSequence(B2);
|
||||
buildSequence(A1);
|
||||
buildSequence(B1);
|
||||
buildSequence(B2);
|
||||
buildSequence(B2);
|
||||
buildSequence(A1);
|
||||
buildSequence(B1);
|
||||
buildSequence(B2);
|
||||
|
||||
function getDate(dt){
|
||||
let index = sequence.findIndex(n => n > dt)-1;
|
||||
let year = baseYear+parseInt(index/12);
|
||||
let month = index % 12;
|
||||
let day = parseInt((dt-sequence[index])/86400000);
|
||||
let colour = dateColours[day % 6];
|
||||
if(day==30){ colour=dateColours[6]; }
|
||||
return({"year":year,"month":month,"day":day,"colour":colour});
|
||||
}
|
||||
function toggleTimeDigits(){
|
||||
addTimeDigit = !addTimeDigit;
|
||||
modeTime();
|
||||
}
|
||||
function toggleDateFormat(){
|
||||
dateFormat = !dateFormat;
|
||||
modeTime();
|
||||
}
|
||||
function formatDate(res,dateFormat){
|
||||
let yyyy = res.year.toString(12);
|
||||
calenDef = calen10;
|
||||
if(!dateFormat){ //ordinal format
|
||||
let mm = ("0"+(res.month+1).toString(12)).substr(-2);
|
||||
let dd = ("0"+(res.day+1).toString(12)).substr(-2);
|
||||
if(res.day==30){
|
||||
calenDef = calen7;
|
||||
let m = ((res.month+1).toString(12)).substr(-2);
|
||||
return(yyyy+"-"+"S"+m); // ordinal format
|
||||
}
|
||||
return(yyyy+"-"+mm+"-"+dd);
|
||||
}
|
||||
let m = res.month.toString(12); // cardinal format
|
||||
let w = parseInt(res.day/6);
|
||||
let d = res.day%6;
|
||||
//return(yyyy+"-"+res.month+"-"+w+"-"+d);
|
||||
return(yyyy+"-"+m+"-"+w+"-"+d);
|
||||
}
|
||||
|
||||
function writeDozTime(text,def,colour){
|
||||
let pts = def.pts;
|
||||
let x=def.pt0[0];
|
||||
let y=def.pt0[1];
|
||||
g_t.clear();
|
||||
g_t.setFont("Vector",def.size);
|
||||
for(let i in text){
|
||||
if(text[i]=="a"){ g_t.setFontAlign(0,0,2); g_t.drawString("2",x+def.dx,y+def.dy); }
|
||||
else if(text[i]=="b"){ g_t.setFontAlign(0,0,2); g_t.drawString("3",x+def.dx,y+def.dy); }
|
||||
else{ g_t.setFontAlign(0,0,0); g_t.drawString(text[i],x,y); }
|
||||
x = x+def.step[0];
|
||||
y = y+def.step[1];
|
||||
}
|
||||
}
|
||||
function writeDozDate(text,def,colour){
|
||||
dateColour = colour;
|
||||
let pts = def.pts;
|
||||
let x=def.pt0[0];
|
||||
let y=def.pt0[1];
|
||||
g_d.clear();
|
||||
g_d.setFont("Vector",def.size);
|
||||
for(let i in text){
|
||||
if(text[i]=="a"){ g_d.setFontAlign(0,0,2); g_d.drawString("2",x+def.dx,y+def.dy); }
|
||||
else if(text[i]=="b"){ g_d.setFontAlign(0,0,2); g_d.drawString("3",x+def.dx,y+def.dy); }
|
||||
else{ g_d.setFontAlign(0,0,0); g_d.drawString(text[i],x,y); }
|
||||
x = x+def.step[0];
|
||||
y = y+def.step[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Functions for time mode
|
||||
function drawTime()
|
||||
{
|
||||
let dt = new Date();
|
||||
let date = "";
|
||||
let timeDef;
|
||||
let x = 0;
|
||||
dt.setDate(dt.getDate());
|
||||
if(addTimeDigit){
|
||||
x =
|
||||
10368*dt.getHours()+172.8*dt.getMinutes()+2.88*dt.getSeconds()+0.00288*dt.getMilliseconds();
|
||||
let msg = "00000"+Math.floor(x).toString(12);
|
||||
let time = msg.substr(-5,3)+"."+msg.substr(-2);
|
||||
let wait = 347*(1-(x%1));
|
||||
timeDef = time6;
|
||||
} else {
|
||||
x =
|
||||
864*dt.getHours()+14.4*dt.getMinutes()+0.24*dt.getSeconds()+0.00024*dt.getMilliseconds();
|
||||
let msg = "0000"+Math.floor(x).toString(12);
|
||||
let time = msg.substr(-4,3)+"."+msg.substr(-1);
|
||||
let wait = 4167*(1-(x%1));
|
||||
timeDef = time5;
|
||||
}
|
||||
if(lastX > x){ res = getDate(dt); } // calculate date once at start-up and once when turning over to a new day
|
||||
date = formatDate(res,dateFormat);
|
||||
if(dt<timeActiveUntil)
|
||||
{
|
||||
// Write to background buffers, then display on screen
|
||||
writeDozDate(date,calenDef,res.colour);
|
||||
writeDozTime(time,timeDef,timeColour);
|
||||
g.flip();
|
||||
// Ready next interval
|
||||
setTimeout(drawTime,wait);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear screen
|
||||
g_d.clear();
|
||||
g_t.clear();
|
||||
g.flip();
|
||||
}
|
||||
lastX = x;
|
||||
}
|
||||
function modeTime()
|
||||
{
|
||||
timeActiveUntil = new Date();
|
||||
timeActiveUntil.setDate(timeActiveUntil.getDate());
|
||||
timeActiveUntil.setSeconds(timeActiveUntil.getSeconds()+15);
|
||||
//Bangle.setLCDPower(true);
|
||||
clearTimeout();
|
||||
drawTime();
|
||||
}
|
||||
|
||||
// Time-logging function
|
||||
/*function logTime(label)
|
||||
{
|
||||
var d = new Date();
|
||||
var t = d.getTime();
|
||||
var diff_test = t - last_time_log;
|
||||
last_time_log = t;
|
||||
console.log(label + " at time: " + t + ", since last: " + diff_test);
|
||||
}*/
|
||||
|
||||
// Functions for weather mode - TODO
|
||||
function drawWeather() {}
|
||||
function modeWeather() {}
|
||||
|
||||
// Start time on twist
|
||||
Bangle.on('twist', function() {
|
||||
modeTime();
|
||||
});
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
|
|
@ -1,3 +1,5 @@
|
|||
0.01: Initial version
|
||||
0.02: Increase text brightness, improve controls, (try to) reduce memory usage
|
||||
0.03: Only auto-start if active app is a clock, auto close after 1 hour of inactivity
|
||||
0.04: Setting to disable touch controls, minor bugfix
|
||||
0.05: Setting to disable double/triple press control, remove touch controls setting, reduce fadeout flicker
|
||||
|
|
@ -16,10 +16,16 @@ Download the [latest Gadgetbridge for Android here](https://f-droid.org/packages
|
|||
|
||||
## Settings
|
||||
|
||||
The app can automatically load when you play music and close when the music stops.
|
||||
You can change this under `Settings`->`App/Widget Settings`->`Music Controls`.
|
||||
You can change these under `Settings`->`App/Widget Settings`->`Music Controls`.
|
||||
|
||||
**Auto start**:
|
||||
Automatically load the app when you play music and close when the music stops.
|
||||
(If the app opened automatically, it closes after music has been paused for 5 minutes.)
|
||||
|
||||
**Simple button**:
|
||||
Disable double/triple pressing Button 2: always simply toggle play/pause.
|
||||
(For music players which handle multiple button presses themselves.)
|
||||
|
||||
## Controls
|
||||
|
||||
### Buttons
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ function fadeOut() {
|
|||
if (!Bangle.isLCDOn() || !fade) {
|
||||
return;
|
||||
}
|
||||
drawMusic();
|
||||
drawMusic(false); // don't clear: draw over existing text to prevent flicker
|
||||
setTimeout(fadeOut, 500);
|
||||
}
|
||||
function brightness() {
|
||||
|
|
@ -127,7 +127,7 @@ function f2hex(f) {
|
|||
return ("00"+(Math.round(f*255)).toString(16)).substr(-2);
|
||||
}
|
||||
/**
|
||||
* @param name
|
||||
* @param {string} name - musicinfo property "num"/"artist"/"album"/"track"
|
||||
* @return {string} Semi-random color to use for given info
|
||||
*/
|
||||
function infoColor(name) {
|
||||
|
|
@ -138,16 +138,13 @@ function infoColor(name) {
|
|||
s = 0;
|
||||
} else {
|
||||
// make color depend deterministically on info
|
||||
let code = 0;
|
||||
let code = textCode(info[name]);
|
||||
switch(name) {
|
||||
case "track":
|
||||
code += textCode(info.track);
|
||||
// fallthrough: also use album+artist
|
||||
case "album":
|
||||
case "track": // also use album
|
||||
code += textCode(info.album);
|
||||
// fallthrough: also use artist
|
||||
default:
|
||||
code += textCode(info[name]);
|
||||
// fallthrough
|
||||
case "album": // also use artist
|
||||
code += textCode(info.artist);
|
||||
}
|
||||
h = code%360;
|
||||
s = 0.7;
|
||||
|
|
@ -173,7 +170,6 @@ function trackColor() {
|
|||
////////////////////
|
||||
/**
|
||||
* Draw date and time
|
||||
* @return {*}
|
||||
*/
|
||||
function drawDateTime() {
|
||||
const now = new Date;
|
||||
|
|
@ -208,8 +204,9 @@ function drawDateTime() {
|
|||
|
||||
/**
|
||||
* Draw track number and total count
|
||||
* @param {boolean} clr - Clear area before redrawing?
|
||||
*/
|
||||
function drawNum() {
|
||||
function drawNum(clr) {
|
||||
let num = "";
|
||||
if ("n" in info && info.n>0) {
|
||||
num = "#"+info.n;
|
||||
|
|
@ -219,9 +216,11 @@ function drawNum() {
|
|||
}
|
||||
g.reset();
|
||||
g.setFont("Vector", 30)
|
||||
.setFontAlign(1, -1) // top right
|
||||
.clearRect(225, 30, 120, 60)
|
||||
.drawString(num, 225, 30);
|
||||
.setFontAlign(1, -1); // top right
|
||||
if (clr) {
|
||||
g.clearRect(225, 30, 120, 60);
|
||||
}
|
||||
g.drawString(num, 225, 30);
|
||||
}
|
||||
/**
|
||||
* Clear rectangle used by track title
|
||||
|
|
@ -231,8 +230,9 @@ function clearTrack() {
|
|||
}
|
||||
/**
|
||||
* Draw track title
|
||||
* @param {boolean} clr - Clear area before redrawing?
|
||||
*/
|
||||
function drawTrack() {
|
||||
function drawTrack(clr) {
|
||||
let size = fitText(info.track);
|
||||
if (size<25) {
|
||||
// the title is too long: start the scroller
|
||||
|
|
@ -249,7 +249,9 @@ function drawTrack() {
|
|||
g.setFont("Vector", size)
|
||||
.setFontAlign(0, 1) // center bottom
|
||||
.setColor(trackColor());
|
||||
if (clr) {
|
||||
clearTrack();
|
||||
}
|
||||
g.drawString(info.track, 119, 109);
|
||||
}
|
||||
/**
|
||||
|
|
@ -269,8 +271,9 @@ function drawScroller() {
|
|||
|
||||
/**
|
||||
* Draw track artist and album
|
||||
* @param {boolean} clr - Clear area before redrawing?
|
||||
*/
|
||||
function drawArtistAlbum() {
|
||||
function drawArtistAlbum(clr) {
|
||||
// we just use small enough fonts to make these always fit
|
||||
// calculate stuff before clear+redraw
|
||||
const aCol = infoColor("artist");
|
||||
|
|
@ -284,7 +287,9 @@ function drawArtistAlbum() {
|
|||
bSiz = 20;
|
||||
}
|
||||
g.reset();
|
||||
if (clr) {
|
||||
g.clearRect(0, 120, 240, 189);
|
||||
}
|
||||
let top = 124;
|
||||
if (info.artist) {
|
||||
g.setFont("Vector", aSiz)
|
||||
|
|
@ -377,10 +382,14 @@ function drawControls() {
|
|||
controlState = stat;
|
||||
}
|
||||
|
||||
function drawMusic() {
|
||||
drawNum();
|
||||
drawTrack();
|
||||
drawArtistAlbum();
|
||||
/**
|
||||
* @param {boolean} [clr=true] Clear area before redrawing?
|
||||
*/
|
||||
function drawMusic(clr) {
|
||||
clr = !(clr===false); // undefined means yes
|
||||
drawNum(clr);
|
||||
drawTrack(clr);
|
||||
drawArtistAlbum(clr);
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
|
|
@ -388,7 +397,7 @@ function drawMusic() {
|
|||
///////////////////////
|
||||
/**
|
||||
* Update music info
|
||||
* @param e
|
||||
* @param {Object} e - Gadgetbridge musicinfo event
|
||||
*/
|
||||
function musicInfo(e) {
|
||||
info = e;
|
||||
|
|
@ -408,7 +417,11 @@ function musicInfo(e) {
|
|||
}
|
||||
}
|
||||
|
||||
let tPxt, tIxt;
|
||||
let tPxt, tIxt; // Timeouts to eXiT when Paused/Inactive for too long
|
||||
/**
|
||||
* Update music state
|
||||
* @param {Object} e - Gadgetbridge musicstate event
|
||||
*/
|
||||
function musicState(e) {
|
||||
stat = e.state;
|
||||
// if paused for five minutes, load the clock
|
||||
|
|
@ -444,6 +457,7 @@ function musicState(e) {
|
|||
}
|
||||
}
|
||||
if (Bangle.isLCDOn()) {
|
||||
drawMusic(false); // redraw in case we were fading out but resumed play
|
||||
drawControls();
|
||||
}
|
||||
}
|
||||
|
|
@ -471,11 +485,19 @@ function startButtonWatches() {
|
|||
tPress = setTimeout(() => {Bangle.showLauncher();}, 3000);
|
||||
}
|
||||
}, BTN2, {repeat: true, edge: "rising"});
|
||||
const s = require("Storage").readJSON("gbmusic.json", 1) || {};
|
||||
if (s.simpleButton) {
|
||||
setWatch(() => {
|
||||
clearTimeout(tPress);
|
||||
togglePlay();
|
||||
}, BTN2, {repeat: true, edge: "falling"});
|
||||
} else {
|
||||
setWatch(() => {
|
||||
nPress++;
|
||||
clearTimeout(tPress);
|
||||
tPress = setTimeout(handleButton2Press, 500);
|
||||
}, BTN2, {repeat: true, edge: "falling"});
|
||||
}
|
||||
}
|
||||
function handleButton2Press() {
|
||||
tPress = null;
|
||||
|
|
@ -498,7 +520,7 @@ function handleButton2Press() {
|
|||
let tCommand = {};
|
||||
/**
|
||||
* Send command and highlight corresponding control
|
||||
* @param command "play/pause/next/previous/volumeup/volumedown"
|
||||
* @param {string} command - "play"/"pause"/"next"/"previous"/"volumeup"/"volumedown"
|
||||
*/
|
||||
function sendCommand(command) {
|
||||
Bluetooth.println(JSON.stringify({t: "music", n: command}));
|
||||
|
|
@ -519,6 +541,7 @@ function togglePlay() {
|
|||
}
|
||||
function startTouchWatches() {
|
||||
Bangle.on("touch", side => {
|
||||
if (!Bangle.isLCDOn()) {return;} // for <2v10 firmware
|
||||
switch(side) {
|
||||
case 1:
|
||||
sendCommand(stat==="play" ? "pause" : "previous");
|
||||
|
|
@ -531,6 +554,7 @@ function startTouchWatches() {
|
|||
}
|
||||
});
|
||||
Bangle.on("swipe", dir => {
|
||||
if (!Bangle.isLCDOn()) {return;} // for <2v10 firmware
|
||||
sendCommand(dir===1 ? "previous" : "next");
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,35 +4,42 @@
|
|||
(function(back) {
|
||||
const SETTINGS_FILE = "gbmusic.json",
|
||||
storage = require("Storage"),
|
||||
translate = require("locale").translate
|
||||
translate = require("locale").translate;
|
||||
|
||||
// initialize with default settings...
|
||||
let s = {
|
||||
autoStart: true,
|
||||
}
|
||||
simpleButton: false,
|
||||
};
|
||||
// ...and overwrite them with any saved values
|
||||
// This way saved values are preserved if a new version adds more settings
|
||||
const saved = storage.readJSON(SETTINGS_FILE, 1) || {}
|
||||
const saved = storage.readJSON(SETTINGS_FILE, 1) || {};
|
||||
for(const key in saved) {
|
||||
s[key] = saved[key]
|
||||
s[key] = saved[key];
|
||||
}
|
||||
|
||||
// creates a function to safe a specific setting, e.g. save('autoStart')(true)
|
||||
function save(key) {
|
||||
return function(value) {
|
||||
s[key] = value
|
||||
storage.write(SETTINGS_FILE, s)
|
||||
return function (value) {
|
||||
s[key] = value;
|
||||
storage.write(SETTINGS_FILE, s);
|
||||
}
|
||||
}
|
||||
|
||||
const menu = {
|
||||
const yesNo = (v) => translate(v ? "Yes" : "No");
|
||||
let menu = {
|
||||
"": {"title": "Music Control"},
|
||||
"< Back": back,
|
||||
"Auto start": {
|
||||
value: s.autoStart,
|
||||
format: v => translate(v ? "Yes" : "No"),
|
||||
};
|
||||
menu[translate("< Back")] = back;
|
||||
menu[translate("Auto start")] = {
|
||||
value: !!s.autoStart,
|
||||
format: yesNo,
|
||||
onchange: save("autoStart"),
|
||||
}
|
||||
}
|
||||
E.showMenu(menu)
|
||||
})
|
||||
};
|
||||
menu[translate("Simple button")] = {
|
||||
value: !!s.simpleButton,
|
||||
format: yesNo,
|
||||
onchange: save("simpleButton"),
|
||||
};
|
||||
|
||||
E.showMenu(menu);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,3 +4,7 @@
|
|||
0.04: Added stopwatch face
|
||||
0.05: Stopwatch, hide hours if 0, fixed flicker when stopped, updated README issues
|
||||
0.06: Reduced memory footprint of compass, used direct screen access rather than arrayBuffer
|
||||
0.07: Added error codes if dependancies are missing
|
||||
0.08: Improved error handling for missing firmware features, added template app.kit.js
|
||||
0.09: Added heart rate monitor app
|
||||
0.10: Converted Stepo to use direct screen writes, added a Trip Counter feature to stepo
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
# Kitchen Combo - a multiclock format of the waypointer, walksersclock, stepo and arrow apps.
|
||||
# Kitchen Combo - a multiclock format of the waypointer, walkersclock, stepo, stopwatch, heartrate and arrow apps.
|
||||
|
||||

|
||||
|
||||
*...everything but the kitchen sink..*
|
||||
|
||||
NOTE: This app require Bangle firmware 2.08.187 or later.
|
||||
NOTE: This app requires Bangle firmware 2.08.187 or later.
|
||||
|
||||
The app is aimed at navigation whilst walking. Please note that it
|
||||
would be foolish in the extreme to rely on this as your only
|
||||
|
|
@ -44,13 +44,16 @@ The following buttons depend on which face is currently in use
|
|||
## Stepo
|
||||

|
||||
|
||||
- Requires one of the pedominter widgets to be installed
|
||||
- Displays the time in large font
|
||||
- Display current step count in a doughnut gauge
|
||||
- Show step count in the middle of the doughnut gauge
|
||||
- The gauge show percentage of steps out of a goal of 10000 steps
|
||||
- When the battery is less than 25% the doughnut turns red
|
||||
- Use BTN1 to switch to the Trip Counter, use long press to reset Trip Counter
|
||||
- Use BTN3 to switch to the next app
|
||||
|
||||
|
||||
## GPS
|
||||

|
||||
- Use BTN1 long press to switch the GPS on or off
|
||||
|
|
@ -65,10 +68,16 @@ The following buttons depend on which face is currently in use
|
|||
- Use BTN3 to switch to the next app.
|
||||
|
||||
## Swatch
|
||||

|
||||
- A simple stopwatch
|
||||
- BTN1 - start, stop
|
||||
- BTN2 - lap if the timer is running, reset if the timer is stopped
|
||||
|
||||
## Heart
|
||||

|
||||
- A simple heart rate monitor, at present the app is just showing the raw value from HRM.bpm
|
||||
- BTN1, long press, turn heart rate monitor on / off
|
||||
|
||||
## Waypointer
|
||||
- Use BTN1 to select previous waypoint (when GPS is on)
|
||||
- Use BTN2 to select the next waypoint (when GPS is on)
|
||||
|
|
@ -217,12 +226,31 @@ I have settled on directly writing to the screen using the Graphics
|
|||
object (g.) for the compass App. This creates a bit of flicker when
|
||||
the arrow moves but is more reliable than using the ArrayBuffer.
|
||||
|
||||
v0.09: Since adding the heart rate monitor I have noticed that I can
|
||||
sometimes can a memory error when switch through the Apps back to the
|
||||
Stepo App. I think this can be cured by statically allocating the
|
||||
ArrayBuffer for stepo rather than using new everytime you switch back
|
||||
into the stepo watch face. The problem is that the bangle memory
|
||||
management / defragmentation is quite slow to run.
|
||||
|
||||
### Issues
|
||||
v0.10: Revisited having a display buffer for the stepo part of the App.
|
||||
Now use direct screen writing as it means less memory allocation and
|
||||
reduces chance of getting a memory error on switching watch faces.
|
||||
|
||||
### Error Codes
|
||||
|
||||
The following error codes will be displayed if one of the dependancies is not met.
|
||||
|
||||
* E-STEPS - no pedomintor widget has been installed, please install the widpedom or the activepedom widgets
|
||||
* E-CALIB - no compass calibration data was found, see 'Compass Calibration'
|
||||
* E-FW - require firmware 2v08.187 or later to detect gps and compass power status
|
||||
|
||||
### Issues / Future enhancements
|
||||
|
||||
* GPS time display shows GMT and not BST, needs localising
|
||||
* Occassional buzzing after 2-3 days of use, seems to disappear after
|
||||
a reset to the launcher menu. Needs investigation
|
||||
* Need to gracefully handle incorrect firmware
|
||||
* Need to gracefully handle missing compass calibration data
|
||||
* Need to gracefully handle missing steps widget
|
||||
* Automatically switch the GPS power setting from Super-E to PSMOO 10
|
||||
seconds after the LCD goes off. At present I just rely on using
|
||||
the GPSSetup app and set the GPS power mode that I want.
|
||||
* Add a small graph to the heart rate monitor app
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
// simple template
|
||||
(() => {
|
||||
function getFace(){
|
||||
var intervalRefSec;
|
||||
var prevTime;
|
||||
|
||||
const Y_TIME = 30;
|
||||
const Y_ACTIVITY = 116;
|
||||
|
||||
function init(gps,sw) {
|
||||
prevTime = "";
|
||||
g.clear();
|
||||
}
|
||||
|
||||
function freeResources() {
|
||||
prevTime = undefined;
|
||||
}
|
||||
|
||||
function startTimer() {
|
||||
draw();
|
||||
intervalRefSec = setInterval(draw, 5000);
|
||||
}
|
||||
|
||||
function stopTimer() {
|
||||
if (intervalRefSec) { intervalRefSec = clearInterval(intervalRefSec); }
|
||||
}
|
||||
|
||||
function onButtonShort(btn) {}
|
||||
function onButtonLong(btn) {}
|
||||
|
||||
function draw() {
|
||||
var d = new Date();
|
||||
var da = d.toString().split(" ");
|
||||
var time = da[4].substr(0,5);
|
||||
|
||||
if (time !== prevTime) {
|
||||
prevTime = time;
|
||||
g.setColor(0);
|
||||
g.fillRect(0, Y_TIME, 239, Y_ACTIVITY -1);
|
||||
g.setColor(1,1,1);
|
||||
g.setFont("Vector",80);
|
||||
g.setFontAlign(0,-1);
|
||||
g.drawString(time, 120, Y_TIME);
|
||||
|
||||
g.setFont("Vector",26);
|
||||
g.drawString("Hello World", 120, Y_ACTIVITY);
|
||||
}
|
||||
}
|
||||
|
||||
return {init:init, freeResources:freeResources, startTimer:startTimer, stopTimer:stopTimer,
|
||||
onButtonShort:onButtonShort, onButtonLong:onButtonLong};
|
||||
}
|
||||
|
||||
return getFace;
|
||||
})();
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
//console.log(o);
|
||||
}
|
||||
|
||||
function init(gps,sw) {
|
||||
function init(gps,sw, hrm) {
|
||||
showMem("compass init() START");
|
||||
gpsObject = gps;
|
||||
intervalRefSec = undefined;
|
||||
|
|
@ -49,13 +49,13 @@
|
|||
loc = undefined;
|
||||
CALIBDATA = undefined;
|
||||
wp = undefined;
|
||||
if (Bangle.isCompassOn()) Bangle.setCompassPower(0);
|
||||
if (Bangle.isCompassOn !== undefined && Bangle.isCompassOn()) Bangle.setCompassPower(0);
|
||||
showMem("compass freeResources() END");
|
||||
}
|
||||
|
||||
function startTimer() {
|
||||
log_debug("startTimer()");
|
||||
if (!Bangle.isCompassOn()) Bangle.setCompassPower(1);
|
||||
if (Bangle.isCompassOn !== undefined && !Bangle.isCompassOn()) Bangle.setCompassPower(1);
|
||||
resetPrevious();
|
||||
draw();
|
||||
intervalRefSec = setInterval(draw, 500);
|
||||
|
|
@ -63,8 +63,8 @@
|
|||
|
||||
function stopTimer() {
|
||||
log_debug("stopTimer()");
|
||||
if(intervalRefSec) {intervalRefSec=clearInterval(intervalRefSec);}
|
||||
if (Bangle.isCompassOn()) Bangle.setCompassPower(0);
|
||||
if (intervalRefSec) {intervalRefSec=clearInterval(intervalRefSec);}
|
||||
if (Bangle.isCompassOn !== undefined && Bangle.isCompassOn()) Bangle.setCompassPower(0);
|
||||
}
|
||||
|
||||
function showMem(msg) {
|
||||
|
|
@ -175,7 +175,22 @@
|
|||
}
|
||||
|
||||
function draw() {
|
||||
//log_debug("draw()");
|
||||
log_debug("draw()");
|
||||
|
||||
g.setFontAlign(0,0);
|
||||
g.setColor(1,1,1);
|
||||
g.setFont("Vector", 24);
|
||||
|
||||
if (Bangle.isCompassOn === undefined) {
|
||||
g.drawString("E-FW", 120, 120);
|
||||
return
|
||||
}
|
||||
|
||||
if (CALIBDATA === undefined || CALIBDATA === null) {
|
||||
g.drawString("E-CALIB", 120, 120);
|
||||
return
|
||||
}
|
||||
|
||||
var d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale);
|
||||
heading = newHeading(d,heading);
|
||||
// sets bearing to waypoint bearing if GPS on else sets to 0 (north)
|
||||
|
|
|
|||
|
|
@ -11,11 +11,12 @@
|
|||
const INFO_NONE = 0;
|
||||
const INFO_BATT = 1;
|
||||
const INFO_MEM = 2;
|
||||
const INFO_FW = 3;
|
||||
const Y_TIME = 30;
|
||||
const Y_ACTIVITY = 116;
|
||||
const Y_MODELINE = 200;
|
||||
|
||||
function init(gps,sw) {
|
||||
function init(gps,sw,hrm) {
|
||||
showMem("digi init 1");
|
||||
days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday","Friday", "Saturday"];
|
||||
prevInfo = "";
|
||||
|
|
@ -98,6 +99,9 @@
|
|||
infoMode = INFO_MEM
|
||||
break;
|
||||
case INFO_MEM:
|
||||
infoMode = INFO_FW
|
||||
break;
|
||||
case INFO_FW:
|
||||
default:
|
||||
infoMode = INFO_NONE;
|
||||
break;
|
||||
|
|
@ -111,17 +115,21 @@
|
|||
let col = 0x07FF; // cyan
|
||||
|
||||
switch(infoMode) {
|
||||
case INFO_NONE:
|
||||
col = 0x0000;
|
||||
str = "";
|
||||
break;
|
||||
case INFO_MEM:
|
||||
val = process.memory();
|
||||
str = "Memory: " + Math.round(val.usage*100/val.total) + "%";
|
||||
break;
|
||||
case INFO_BATT:
|
||||
default:
|
||||
str = "Battery: " + E.getBattery() + "%";
|
||||
break;
|
||||
case INFO_FW:
|
||||
str = "Fw: " + process.env.VERSION;
|
||||
break;
|
||||
case INFO_NONE:
|
||||
default:
|
||||
col = 0x0000;
|
||||
str = "";
|
||||
break;
|
||||
}
|
||||
|
||||
// check if we need to draw, avoid flicker
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
//console.log(o);
|
||||
}
|
||||
|
||||
function init(gps, sw) {
|
||||
function init(gps, sw, hrm) {
|
||||
log_debug("gps init");
|
||||
//log_debug(gps);
|
||||
gpsObject = gps;
|
||||
|
|
@ -79,6 +79,12 @@
|
|||
g.setColor(0xFFC0);
|
||||
g.setFontAlign(0, -1);
|
||||
|
||||
if (Bangle.isGPSOn === undefined) {
|
||||
g.setColor(1,1,1);
|
||||
g.drawString("E-FW", 120, Y_ACTIVITY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gpsObject.getState() === gpsObject.GPS_OFF) {
|
||||
g.drawString("GPS off", 120, Y_ACTIVITY);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
(() => {
|
||||
function getFace(){
|
||||
const Y_TIME = 30;
|
||||
const Y_ACTIVITY = 116;
|
||||
let prevTime;
|
||||
let prevBpm;
|
||||
let toggle = 1;
|
||||
let redrawHrmPower = true;
|
||||
let intervalRefSec;
|
||||
let img;
|
||||
let hrmObject;
|
||||
|
||||
function log_debug(o) {
|
||||
//console.log(o);
|
||||
}
|
||||
|
||||
function init(gps, sw, hrm) {
|
||||
img = require("heatshrink").decompress(atob("mEwwRC/ABf/+ADBh//BQgGB//AgYDBCAQWCA4QPCDAYSC//8n4EC4AiEAAo1EBZIeDAAn8BZoKHJAYL7L64LLTa6/DAAi/CKhDjGBZBIGIwQ8IHQQ8IHQYwHBQgwFFwgwGFwgwGFwowFBQwwDFwwwEFwwwEFw4wDBRAkBERAkCERIA/AAYA="));
|
||||
prevTime = "-";
|
||||
prevBpm = "-";
|
||||
toggle = 1;
|
||||
redrawHrmPower = true;
|
||||
hrmObject = hrm;
|
||||
intervalRefSec;
|
||||
g.clear();
|
||||
}
|
||||
|
||||
function freeResources() {
|
||||
prevTime = undefined;
|
||||
img = undefined;
|
||||
}
|
||||
|
||||
function startTimer() {
|
||||
draw();
|
||||
intervalRefSec = setInterval(draw, 1000);
|
||||
}
|
||||
|
||||
function stopTimer() {
|
||||
if (intervalRefSec) { intervalRefSec = clearInterval(intervalRefSec); }
|
||||
}
|
||||
|
||||
function onButtonShort(btn) {}
|
||||
|
||||
function onButtonLong(btn) {
|
||||
log_debug("toggleHRM");
|
||||
if (btn !== 1) return;
|
||||
if (!Bangle.isHRMOn) return; // old firmware
|
||||
hrmObject.toggleHRMPower();
|
||||
prevBpm = '-';
|
||||
toggle = 1; // ensure we draw the heart first
|
||||
redrawHrmPower = true;
|
||||
}
|
||||
|
||||
function draw() {
|
||||
let d = new Date();
|
||||
let da = d.toString().split(" ");
|
||||
let time = da[4].substr(0,5);
|
||||
|
||||
if (time !== prevTime) {
|
||||
prevTime = time;
|
||||
g.setColor(0);
|
||||
g.fillRect(0, Y_TIME, 239, Y_ACTIVITY -1);
|
||||
g.setColor(1,1,1);
|
||||
g.setFont("Vector",80);
|
||||
g.setFontAlign(0,-1);
|
||||
g.drawString(time, 120, Y_TIME);
|
||||
}
|
||||
|
||||
let bpm = hrmObject.getBpm();
|
||||
|
||||
if (!Bangle.isHRMOn()) {
|
||||
if (!redrawHrmPower) return;
|
||||
redrawHrmPower = false;
|
||||
g.setColor(0);
|
||||
g.drawImage(img, 12, 132, {scale:2});
|
||||
g.fillRect(120,120,239,239);
|
||||
g.setColor(255,0,0);
|
||||
//g.setColor(0xFFC0); // yellow
|
||||
g.drawImage(img, 12, 132, {scale:2});
|
||||
|
||||
g.setFont("Vector",40);
|
||||
g.setFontAlign(0,0);
|
||||
g.setColor(1,1,1);
|
||||
g.drawString("OFF", 180, 180);
|
||||
return;
|
||||
}
|
||||
|
||||
// draw the heart
|
||||
if (++toggle % 2 === 0) {
|
||||
g.setColor(0);
|
||||
g.fillRect(12, 132, 108, 228);
|
||||
} else {
|
||||
g.setColor(255,0,0);
|
||||
//g.setColor(0xFFC0); // yellow
|
||||
g.drawImage(img, 12, 132, {scale:2});
|
||||
}
|
||||
|
||||
// draw the bpm
|
||||
if (bpm !== prevBpm) {
|
||||
prevBpm = bpm;
|
||||
g.setColor(0);
|
||||
g.fillRect(120, 120, 239, 239);
|
||||
g.setColor(1,1,1);
|
||||
//g.setColor(0xFFC0); // yellow
|
||||
g.setFont("Vector",52);
|
||||
g.setFontAlign(0,0);
|
||||
g.drawString(bpm, 180, 180);
|
||||
}
|
||||
}
|
||||
|
||||
return {init:init, freeResources:freeResources, startTimer:startTimer, stopTimer:stopTimer,
|
||||
onButtonShort:onButtonShort, onButtonLong:onButtonLong};
|
||||
}
|
||||
|
||||
return getFace;
|
||||
})();
|
||||
|
|
@ -26,15 +26,17 @@ function nextFace(){
|
|||
|
||||
g.clear();
|
||||
g.reset();
|
||||
face.init(gpsObj, swObj);
|
||||
face.init(gpsObj, swObj, hrmObj, tripObject);
|
||||
startdraw();
|
||||
}
|
||||
|
||||
// when you feel the buzzer you know you have done a long press
|
||||
function longPressCheck() {
|
||||
Bangle.buzz();
|
||||
debug_log("long PressCheck() buzz");
|
||||
if (pressTimer) {
|
||||
clearInterval(pressTimer);
|
||||
debug_log("clear pressTimer 2");
|
||||
pressTimer = undefined;
|
||||
}
|
||||
}
|
||||
|
|
@ -45,6 +47,11 @@ function buttonPressed(btn) {
|
|||
nextFace();
|
||||
} else {
|
||||
firstPress = getTime();
|
||||
if (pressTimer) {
|
||||
debug_log("clear pressTimer 1");
|
||||
clearInterval(pressTimer);
|
||||
}
|
||||
debug_log("set pressTimer 1");
|
||||
pressTimer = setInterval(longPressCheck, 1500);
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +60,7 @@ function buttonPressed(btn) {
|
|||
function buttonReleased(btn) {
|
||||
var dur = getTime() - firstPress;
|
||||
if (pressTimer) {
|
||||
debug_log("clear pressTimer 3");
|
||||
clearInterval(pressTimer);
|
||||
pressTimer = undefined;
|
||||
}
|
||||
|
|
@ -180,7 +188,7 @@ GPS.prototype.determineGPSState = function() {
|
|||
}
|
||||
} else {
|
||||
if (this.listenerCount > 0) {
|
||||
Bangle.removeListener("GPS", this.processFix);
|
||||
Bangle.removeListener("GPS", processFix);
|
||||
this.listenerCount--;
|
||||
this.log_debug("listener removed " + this.listenerCount);
|
||||
}
|
||||
|
|
@ -248,6 +256,7 @@ GPS.prototype.processFix = function(fix) {
|
|||
this.gpsState = this.GPS_RUNNING;
|
||||
if (!this.last_fix.fix && !(require("Storage").readJSON("setting.json", 1) || {}).quiet) {
|
||||
Bangle.buzz(); // buzz on first position
|
||||
debug_log("GPS fix buzz");
|
||||
}
|
||||
this.last_fix = fix;
|
||||
}
|
||||
|
|
@ -651,6 +660,122 @@ function stopwatchDraw() {
|
|||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
Heart Rate Monitor
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
function HRM() {
|
||||
this.bpm = 0;
|
||||
this.confidence = 0;
|
||||
}
|
||||
|
||||
HRM.prototype.log_debug = function(o) {
|
||||
//console.log(o);
|
||||
}
|
||||
|
||||
HRM.prototype.toggleHRMPower = function() {
|
||||
this.log_debug("HRM.toggleHRMPower()");
|
||||
if (!Bangle.isHRMOn) return; // old firmware
|
||||
|
||||
if (!Bangle.isHRMOn()) {
|
||||
this.log_debug("HRM.toggleHRMPower(powerOn)");
|
||||
Bangle.removeListener('HRM', onHRM);
|
||||
Bangle.setHRMPower(1);
|
||||
Bangle.on('HRM', onHRM);
|
||||
} else {
|
||||
this.log_debug("HRM.toggleHRMPower(powerOff)");
|
||||
Bangle.removeListener('HRM', onHRM);
|
||||
Bangle.setHRMPower(0);
|
||||
}
|
||||
|
||||
// poke the hrt widget indicator to change
|
||||
if (WIDGETS.widhrt !== undefined) {
|
||||
WIDGETS.widhrt.draw();
|
||||
}
|
||||
}
|
||||
|
||||
HRM.prototype.getBpm = function() {
|
||||
return this.bpm;
|
||||
}
|
||||
|
||||
HRM.prototype.getConfidence = function() {
|
||||
return this.confidence;
|
||||
}
|
||||
|
||||
HRM.prototype.onHRM = function(hrm) {
|
||||
this.bpm = hrm.bpm;
|
||||
this.confidence = hrm.confidence;
|
||||
this.log_debug("onHRM:(bpm)" + this.bpm);
|
||||
this.log_debug("onHRM:(conf) " + this.confidence);
|
||||
}
|
||||
|
||||
let hrmObj = new HRM();
|
||||
|
||||
function onHRM(hrm) {
|
||||
hrmObj.onHRM(hrm);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
Trip Counter
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
function TRIP() {
|
||||
this.showTrip = false;
|
||||
this.tripStart = 0;
|
||||
}
|
||||
|
||||
TRIP.prototype.resetTrip = function(steps) {
|
||||
this.tripStart = (0 + steps);
|
||||
console.log("resetTrip starting=" + this.tripStart);
|
||||
}
|
||||
|
||||
TRIP.prototype.getTrip = function(steps) {
|
||||
let tripSteps = (0 + steps) - this.tripStart;
|
||||
console.log("getTrip steps=" + steps);
|
||||
console.log("getTrip tripStart=" + this.tripStart);
|
||||
console.log("getTrip=" + tripSteps);
|
||||
return tripSteps;
|
||||
}
|
||||
|
||||
TRIP.prototype.getTripState = function() {
|
||||
return this.showTrip;
|
||||
}
|
||||
|
||||
TRIP.prototype.setTripState = function(t) {
|
||||
this.showTrip = t;
|
||||
}
|
||||
|
||||
let tripObject = new TRIP();
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
Debug Object
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
function DEBUG() {
|
||||
this.logfile = require("Storage").open("debug.log","a");
|
||||
}
|
||||
|
||||
DEBUG.prototype.log = function(msg) {
|
||||
let timestamp = new Date().toString().split(" ")[4];
|
||||
let line = timestamp + ", " + msg + "\n";
|
||||
this.logfile.write(line);
|
||||
}
|
||||
|
||||
debugObj = new DEBUG();
|
||||
*/
|
||||
|
||||
function debug_log(m) {
|
||||
//debugObj.log(m);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
Start App
|
||||
|
|
@ -659,6 +784,6 @@ Start App
|
|||
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
face.init(gpsObj,swObj);
|
||||
face.init(gpsObj,swObj, hrmObj, tripObject);
|
||||
startdraw();
|
||||
setButtons();
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
|
@ -1,45 +1,29 @@
|
|||
(() => {
|
||||
function getFace(){
|
||||
var pal4color;
|
||||
var pal4red;
|
||||
var buf;
|
||||
var intervalRefSec;
|
||||
var trip;
|
||||
var prevSteps;
|
||||
|
||||
function init(g,sw) {
|
||||
showMem("stepo init 1");
|
||||
pal4color = new Uint16Array([0x0000,0xFFFF,0x7BEF,0xAFE5],0,2); // b,w,grey,greenyellow
|
||||
pal4red = new Uint16Array([0x0000,0xFFFF,0xF800,0xAFE5],0,2); // b,w,red,greenyellow
|
||||
buf = Graphics.createArrayBuffer(120,120,2,{msb:true});
|
||||
showMem("stepo init 2");
|
||||
function init(g,sw,hrm,tr) {
|
||||
trip = tr;
|
||||
}
|
||||
|
||||
function freeResources() {
|
||||
showMem("stepo free 1");
|
||||
pal4color = undefined;
|
||||
pal4red = undefined;
|
||||
buf = undefined;
|
||||
showMem("stepo free 2");
|
||||
trip = undefined;
|
||||
prevSteps = -1;
|
||||
}
|
||||
|
||||
function showMem(msg) {
|
||||
var val = process.memory();
|
||||
var str = msg + " " + Math.round(val.usage*100/val.total) + "%";
|
||||
//console.log(str);
|
||||
function onButtonShort(btn) {
|
||||
trip.setTripState(!trip.getTripState());
|
||||
drawStepText();
|
||||
}
|
||||
|
||||
function flip(x,y) {
|
||||
g.drawImage({width:120,height:120,bpp:2,buffer:buf.buffer, palette:pal4color}, x, y);
|
||||
buf.clear();
|
||||
function onButtonLong(btn) {
|
||||
trip.resetTrip(getSteps());
|
||||
trip.setTripState(true);
|
||||
drawStepText();
|
||||
}
|
||||
|
||||
function flip_red(x,y) {
|
||||
g.drawImage({width:120,height:120,bpp:2,buffer:buf.buffer, palette:pal4red}, x, y);
|
||||
buf.clear();
|
||||
}
|
||||
|
||||
function onButtonShort(btn) {}
|
||||
function onButtonLong(btn) {}
|
||||
|
||||
function radians(a) {
|
||||
return a*Math.PI/180;
|
||||
}
|
||||
|
|
@ -55,10 +39,16 @@
|
|||
|
||||
function drawSteps() {
|
||||
var i = 0;
|
||||
var cx = 60;
|
||||
var cy = 60;
|
||||
var cx = 60 + 60;
|
||||
var cy = 60 + 115;
|
||||
var r = 56;
|
||||
var steps = getSteps();
|
||||
|
||||
if (prevSteps == steps)
|
||||
return;
|
||||
|
||||
prevSteps = steps;
|
||||
|
||||
var percent = steps / 10000;
|
||||
|
||||
if (percent > 1) percent = 1;
|
||||
|
|
@ -67,35 +57,57 @@
|
|||
var midrot = -180 - (360 * percent);
|
||||
var endrot = -360 - 180;
|
||||
|
||||
buf.setColor(3); // green-yellow
|
||||
g.setColor(0xAFE5); // greenyellow
|
||||
|
||||
// draw guauge
|
||||
for (i = startrot; i > midrot; i -= 4) {
|
||||
x = cx + r * Math.sin(radians(i));
|
||||
y = cy + r * Math.cos(radians(i));
|
||||
buf.fillCircle(x,y,4);
|
||||
g.fillCircle(x,y,4);
|
||||
}
|
||||
|
||||
buf.setColor(2); // grey
|
||||
|
||||
// draw remainder of guage in grey
|
||||
for (i = midrot; i > endrot; i -= 4) {
|
||||
x = cx + r * Math.sin(radians(i));
|
||||
y = cy + r * Math.cos(radians(i));
|
||||
buf.fillCircle(x,y,4);
|
||||
}
|
||||
|
||||
// draw steps
|
||||
buf.setColor(1); // white
|
||||
buf.setFont("Vector", 24);
|
||||
buf.setFontAlign(0,0);
|
||||
buf.drawString(steps, cx, cy);
|
||||
|
||||
// change the remaining color to RED if battery is below 25%
|
||||
if (E.getBattery() > 25)
|
||||
flip(60,115);
|
||||
g.setColor(0x7BEF); // grey
|
||||
else
|
||||
flip_red(60,115);
|
||||
g.setColor(0xF800); // red
|
||||
|
||||
// draw remainder of guage in grey or red
|
||||
for (i = midrot; i > endrot; i -= 4) {
|
||||
x = cx + r * Math.sin(radians(i));
|
||||
y = cy + r * Math.cos(radians(i));
|
||||
g.fillCircle(x,y,4);
|
||||
}
|
||||
}
|
||||
|
||||
function drawStepText() {
|
||||
var cx = 60 + 60;
|
||||
var cy = 60 + 115;
|
||||
var r = 56;
|
||||
var steps = getSteps();
|
||||
|
||||
/*
|
||||
* if our trip count is greater than todays steps then we have
|
||||
* rolled over to the next day so we should reset the trip counter
|
||||
*/
|
||||
if (trip.getTrip(steps) < 0)
|
||||
trip.resetTrip(steps);
|
||||
|
||||
// show trip count or total steps today
|
||||
g.setFontAlign(0,0);
|
||||
g.setFont("Vector", 24);
|
||||
|
||||
// clear the space for the text
|
||||
g.clearRect(cx - (r - 12), cy - 16, cx + (r - 12), cy + 16);
|
||||
|
||||
if (trip.getTripState() == true) {
|
||||
g.setColor(0x7BEF); // grey
|
||||
//g.setColor(1,0,0); // red
|
||||
g.drawString(trip.getTrip(steps), cx, cy);
|
||||
} else {
|
||||
g.setColor(1,1,1); // white
|
||||
g.drawString(steps, cx, cy);
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
|
|
@ -110,12 +122,13 @@
|
|||
g.drawString(time, 120, 30, true);
|
||||
|
||||
drawSteps();
|
||||
drawStepText();
|
||||
}
|
||||
|
||||
function getSteps() {
|
||||
if (stepsWidget() !== undefined)
|
||||
return stepsWidget().getSteps();
|
||||
return "-";
|
||||
return "E-STEPS";
|
||||
}
|
||||
|
||||
function stepsWidget() {
|
||||
|
|
@ -132,5 +145,4 @@
|
|||
}
|
||||
|
||||
return getFace;
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
function getFace(){
|
||||
let swObject = undefined;
|
||||
|
||||
function init(gps, sw) {
|
||||
function init(gps, sw, hrm) {
|
||||
swObject = sw;
|
||||
g.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
0.01: New App!
|
||||
0.02: Tweaks for app loader
|
||||
0.03: Fix app icon, add change of colors
|
||||
0.04: Improvements and new round check option elements
|
||||
0.04: Improvements and new radio button option elements
|
||||
0.05: ...
|
||||
0.06: Improvements, multiple rows with radio buttons
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
# Test User Input
|
||||
|
||||
This very basic app, allows to *test the bangle.js input interface*, and displays the result in text or a switch on/off image.
|
||||
This basic app, allows to **test the bangle.js input interface** trough every types of finger interaction.
|
||||
Interactrion type is displayed in text or a switch on/off image for swipe screen.
|
||||
|
||||
Besides the basics, the UI also includes multiple rows with radio buttons
|
||||
|
||||
|
||||
## Captures
|
||||
|
||||
(Following images can be outdated)
|
||||
|
||||
Launcher icon
|
||||
|
||||
|
|
@ -31,14 +38,14 @@ Colours, font, user input, image, load widgets
|
|||
|
||||
|
||||
## Controls
|
||||
Press left area - Prints Touch1
|
||||
Press righ area - Prints Touch2
|
||||
Press center area - Prints Touch3
|
||||
Swipe Left - Displays Switch OFF image
|
||||
Swipe Right - Displays Switch ON image
|
||||
BTN1 - Prints Button1
|
||||
BTN2 - Prints Button2
|
||||
BTN3 - Quit to Launcher
|
||||
- Press left area - Prints Touch1
|
||||
- Press righ area - Prints Touch2
|
||||
- Press center area - Prints Touch3
|
||||
- Swipe Left - Displays Switch OFF image
|
||||
- Swipe Right - Displays Switch ON image
|
||||
- BTN1 - Prints Button1
|
||||
- BTN2 - Prints Button2
|
||||
- BTN3 - Quit to Launcher
|
||||
|
||||
|
||||
## Support
|
||||
|
|
|
|||
|
|
@ -1,35 +1,71 @@
|
|||
/* Test bangle.js input interface */
|
||||
var v_mode_debug=0; //1=yes, 0=no (to disable console msg)
|
||||
if (v_mode_debug==1) console.log("Debug mode enabled");
|
||||
else console.log("Debug mode disabled");
|
||||
var v_model=process.env.BOARD;
|
||||
if (v_mode_debug==1) console.log("device="+v_model);
|
||||
|
||||
var v_str_version='v0.06'; //testing purpose
|
||||
|
||||
var x_max_screen=g.getWidth();//240;
|
||||
var y_max_screen=g.getHeight(); //240;
|
||||
var y_wg_bottom=g.getHeight()-25;
|
||||
var y_wg_top=25;
|
||||
if (v_model=='BANGLEJS') {
|
||||
var x_btn_area=215;
|
||||
var x_max_usable_area=x_btn_area;//Pend! only for bangle.js
|
||||
var y_btn2=124; //harcoded for bangle.js cuz it is not the half of
|
||||
} else x_max_usable_area=240;
|
||||
var x_mid_screen=x_max_screen/2;
|
||||
|
||||
var colbackg='#111111';//black
|
||||
var colorange='#e56e06'; //RGB format rrggbb
|
||||
var v_color_lines=0xFFFF; //White hex format
|
||||
var v_color_b_area=colbackg;
|
||||
var v_font1size='16';
|
||||
var v_clicks='0';
|
||||
console.log("*** Test input interface ***");
|
||||
var v_color_b_area=colbackg; //for banner area
|
||||
var v_color_text='#FB0E01';
|
||||
//var v_font1size=16;
|
||||
var v_font1size=11; //out of quotes
|
||||
var v_font2size=18;
|
||||
var v_font3size=14;
|
||||
|
||||
var v_clicks=0;
|
||||
var v_selected_row=1; //used by round option
|
||||
var v_total_rows=2;//used by round option
|
||||
var array_r_option=[];
|
||||
|
||||
var v_y_optionrow1=80;
|
||||
var v_y_optionrow2=110;
|
||||
var v_y_optionrow3=140;
|
||||
|
||||
|
||||
function ClearActiveArea(){
|
||||
if (v_mode_debug==1) console.log("*** Test input interface ***");
|
||||
|
||||
//the biggest usable area, button area not included
|
||||
function ClearActiveArea(x1,y1,x2,y2){
|
||||
g.setColor(colbackg);
|
||||
g.fillRect(0,32,239,239); //fill all screen except widget area
|
||||
//FOR BANGLE.JS (0,y_wg_top,x_max_usable_area,y_wg_bottom);
|
||||
//fill all screen except widget area
|
||||
g.fillRect(x1,y1,x2,y2);
|
||||
g.flip();
|
||||
}
|
||||
|
||||
function PrintHelp(){
|
||||
console.log("********************************");
|
||||
console.log("Log: *** Print help in screen");
|
||||
ClearActiveArea();
|
||||
if (v_mode_debug==1) console.log("Log: *** Print help in screen");
|
||||
ClearActiveArea(0,y_wg_top,x_max_usable_area,y_wg_bottom);
|
||||
g.setColor(colorange);
|
||||
g.setFontVector(18).drawString("To test the input, try :",25,90);
|
||||
/* PRINT FROM widget BOTTOM */
|
||||
g.setFontVector(v_font2size).drawString("To test the UI, try:",5,y_wg_bottom-(10*v_font3size));
|
||||
g.flip();
|
||||
g.setColor(0,1,0); //green
|
||||
g.setFontVector(v_font1size).drawString("Swipe right -->", 30, 115);
|
||||
g.setFontVector(v_font1size).drawString("Swipe left <--", 30, 130);
|
||||
g.setFontVector(v_font1size).drawString("Click Left area", 30, 145);
|
||||
g.setFontVector(v_font1size).drawString("Click Right area", 30,160);
|
||||
g.setFontVector(v_font1size).drawString("Click Middle area", 30,175);
|
||||
g.setFontVector(v_font1size).drawString("Press Button1 ", 30,190);
|
||||
g.setFontVector(v_font1size).drawString("Press Button2 for colors", 30,205);
|
||||
g.setFontVector(v_font1size).drawString("Press Button3 to Quit", 30,220);
|
||||
g.setFontVector(v_font3size);
|
||||
g.drawString("Swipe right -->", 30, y_wg_bottom-(8*v_font3size));
|
||||
g.drawString("Swipe left <--", 30, y_wg_bottom-(7*v_font3size));
|
||||
g.drawString("Click Left area", 30, y_wg_bottom-(6*v_font3size));
|
||||
g.drawString("Click Right area", 30,y_wg_bottom-(5*v_font3size));
|
||||
g.drawString("Click Middle area", 30,y_wg_bottom-(4*v_font3size));
|
||||
g.drawString("Press Button1", 30,y_wg_bottom-(3*v_font3size));
|
||||
g.drawString("Press Button2: Colour", 30,y_wg_bottom-(2*v_font3size));
|
||||
g.drawString("Press Button3: Quit", 30,y_wg_bottom-v_font3size);
|
||||
g.flip();
|
||||
}
|
||||
|
||||
|
|
@ -48,8 +84,8 @@ function ClearBannerArea(){
|
|||
g.fillRect(55,32,185,78);
|
||||
g.flip();
|
||||
}
|
||||
|
||||
function DrawRoundOption(area){
|
||||
//arg input area Touch1=left Touch2=right
|
||||
function DrawRoundOption(x_obj1,y_obj1,x_obj2,y_obj2,i_area){
|
||||
//draw a img from an Image object
|
||||
var img_obj_check = {
|
||||
width : 30, height : 30, bpp : 4,
|
||||
|
|
@ -63,21 +99,26 @@ function ClearBannerArea(){
|
|||
palette : new Uint16Array([65535,63422,9532,13789,59197,57084,34266,28220,63390,65503,61310,61277,57116,55003,61309,40604]),
|
||||
buffer : E.toArrayBuffer(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMzMwAAAAAAAAAAADMzf//3MzMAAAAAAAAAAzPxmZkRrzMwAAAAAAAAM3mZmZmRiKczAAAAAAADP5mZmZmRiKpjMAAAAAAzeZmZmZkRiKq3MwAAAAAzGZmZmZkRiKq8MwAAAAM/mZmZmZkYiKtE8iAAAAMxmZmZmZEYiqtEUiAAAAN5mZmZmRGIiqtExyAAAAPxmZmZkRiIqrRMViAAAAPxEREREYiKq7RMViAAAAP4ERERiIiqq0TFViAAAAP4iIiIiIqqtETFViAAAAN6iIiIiqq7RExV1yAAAAM0qqqqqru0RMVd0iAAAAM/uqqru7RETFXdYiAAAAAzS7u7RERMxV3dIgAAAAAzdEREREzFVd3XIgAAAAADNkREzMVVXd1iIAAAAAAAM3VVVVVd3dciAAAAAAAAAzNtVd3d1iIgAAAAAAAAADMidmZnIiIAAAAAAAAAAAAiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))
|
||||
};
|
||||
if (area=='Touch 1') {
|
||||
g.drawImage(img_obj_check,20,80);
|
||||
console.log("Draw option check left");
|
||||
if (i_area=='none') {
|
||||
g.drawImage(img_obj_uncheck,x_obj1,y_obj1);
|
||||
g.drawImage(img_obj_uncheck,x_obj2,y_obj2);
|
||||
}
|
||||
else g.drawImage(img_obj_uncheck,20,80);
|
||||
if (area=='Touch 2') {
|
||||
g.drawImage(img_obj_check,190,80);
|
||||
console.log("Draw option check right");
|
||||
else if (i_area=='Touch 1') {
|
||||
g.drawImage(img_obj_check,x_obj1,y_obj1);
|
||||
g.drawImage(img_obj_uncheck,x_obj2,y_obj2);
|
||||
if (v_mode_debug==1) console.log("Draw option check left");
|
||||
}
|
||||
else g.drawImage(img_obj_uncheck,190,80);
|
||||
else if (i_area=='Touch 2') {
|
||||
g.drawImage(img_obj_uncheck,x_obj1,y_obj1);
|
||||
g.drawImage(img_obj_check,x_obj2,y_obj2);
|
||||
if (v_mode_debug==1) console.log("Draw option check right");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function DrawSwitch(swipedir){
|
||||
if (swipedir==' <---') {
|
||||
console.log("Draw switch <--");
|
||||
if (v_mode_debug==1) console.log("Draw switch <--");
|
||||
var img_off = {
|
||||
width : 48, height : 48, bpp : 2,
|
||||
transparent : 0,
|
||||
|
|
@ -87,7 +128,7 @@ if (swipedir==' <---') {
|
|||
g.drawImage(img_off,99,33);
|
||||
}
|
||||
else if (swipedir==' --->') {
|
||||
console.log("Draw switch -->");
|
||||
if (v_mode_debug==1) console.log("Draw switch -->");
|
||||
var img_on = {
|
||||
width : 48, height : 48, bpp : 2,
|
||||
transparent : 0,
|
||||
|
|
@ -100,70 +141,154 @@ if (swipedir==' <---') {
|
|||
|
||||
|
||||
function PrintUserInput(boton){
|
||||
console.log("Pressed touch/BTN",boton);
|
||||
if (v_clicks=='0') {
|
||||
if (v_mode_debug==1) console.log("Pressed touch/BTN",boton);
|
||||
if (v_clicks==0) {
|
||||
PrintAreas();
|
||||
v_clicks=1;
|
||||
v_clicks++;
|
||||
}
|
||||
ClearBannerArea();
|
||||
|
||||
if (boton==' <---') DrawSwitch(boton);
|
||||
else if (boton==' --->') DrawSwitch(boton);
|
||||
else
|
||||
{ //a BUTTON or AREA AND NO swipe /slide
|
||||
if (boton=='Touch 1'||boton=='Touch 2') DrawRoundOption(boton);
|
||||
//all input but not swipe
|
||||
else {
|
||||
g.setColor(colorange);
|
||||
//Call info banner
|
||||
g.setFontVector(30).drawString(boton, 63, 55);
|
||||
if ((boton=='Touch 1')||(boton=='Touch 2')){
|
||||
if (v_selected_row==1) v_y_opt=v_y_optionrow1;
|
||||
else if (v_selected_row==2) v_y_opt=v_y_optionrow2;
|
||||
DrawRoundOption(20,v_y_opt,190,v_y_opt,boton);
|
||||
//set the option value in an array
|
||||
array_r_option[v_selected_row]=boton;
|
||||
if (v_mode_debug==1) console.log("array["+v_selected_row+"]="+array_r_option[v_selected_row]);
|
||||
}
|
||||
}
|
||||
|
||||
g.flip();
|
||||
}
|
||||
|
||||
function PrintBtn1(boton){
|
||||
console.log("Pressed BTN1");
|
||||
if (v_clicks=='0'){
|
||||
PrintAreas();
|
||||
v_clicks=1;
|
||||
function Btn1Clkd(boton){
|
||||
if (v_mode_debug==1) console.log("Pressed BTN1");
|
||||
if (v_clicks==0){
|
||||
PrintAreas(); //only 1st time
|
||||
//v_selected_row=1;
|
||||
v_clicks++;
|
||||
}
|
||||
|
||||
|
||||
else if ((v_clicks>0)&&(v_selected_row!=v_total_rows)){
|
||||
v_selected_row++;
|
||||
//Params: row_arrow, row_clear_area
|
||||
if (v_mode_debug==1) console.log("row :"+v_selected_row);
|
||||
DrawRowSelArrow(v_selected_row,v_selected_row-1);
|
||||
v_clicks++;
|
||||
}
|
||||
else if ((v_clicks>0)&&(v_selected_row==v_total_rows)){
|
||||
|
||||
DrawRowSelArrow(1,v_selected_row);
|
||||
if (v_mode_debug==1) console.log("last row :"+v_selected_row);
|
||||
v_selected_row=1;
|
||||
v_clicks++;
|
||||
}
|
||||
PrintUserInput("Button1");
|
||||
|
||||
}
|
||||
|
||||
function PrintBtn2(boton){
|
||||
console.log("Pressed BTN2");
|
||||
function Btn2Clkd(boton){
|
||||
if (v_mode_debug==1) console.log("Pressed BTN2");
|
||||
v_color_b_area=ChangeColorBannerArea(v_color_b_area);
|
||||
if (v_clicks=='0'){
|
||||
PrintAreas();
|
||||
v_clicks=1;
|
||||
if (v_clicks==0){
|
||||
PrintAreas();//only 1st time
|
||||
v_clicks++;
|
||||
}
|
||||
PrintUserInput("Button2");
|
||||
}
|
||||
|
||||
function DrawBangleButtons(){
|
||||
|
||||
/*Button name */
|
||||
g.setColor(v_color_text); //green
|
||||
g.setFontVector(v_font3size);
|
||||
g.drawString("B1", x_max_screen-g.stringWidth("B1"),y_wg_top);
|
||||
g.drawString("B2", x_max_screen-g.stringWidth("B2"),y_btn2);
|
||||
//y y_wg_bottom-v_font3size ?
|
||||
g.drawString("B3",x_max_screen-g.stringWidth("B3"),y_wg_bottom);
|
||||
|
||||
/*Button area description */
|
||||
g.setFontVector(v_font1size);
|
||||
g.setColor(v_color_lines);
|
||||
//y_wg_bottom-(2*v_font1size)
|
||||
g.drawString("Quit", x_max_screen-g.stringWidth("Quit"),y_wg_bottom-v_font1size-2);
|
||||
|
||||
|
||||
//Print version
|
||||
if (v_mode_debug==1){
|
||||
g.setColor(0,1,0); //green
|
||||
//y_wg_bottom-(2*v_font1size)
|
||||
g.drawString(v_str_version, x_max_screen-g.stringWidth(v_str_version),y_wg_bottom-(v_font1size*3));
|
||||
}
|
||||
|
||||
//under btn2, left top 90grades
|
||||
g.setFontAlign(-1,-1,1);
|
||||
g.drawString("Color", x_max_screen-v_font1size,y_btn2+v_font3size);
|
||||
//g.drawString("Color", x_max_screen-g.stringWidth("Color"),y_btn2+v_font1size);
|
||||
|
||||
|
||||
g.setColor(0,1,0); //green
|
||||
g.drawString("Up", x_max_screen-v_font1size,y_wg_top+v_font3size);
|
||||
g.setColor(v_color_lines);
|
||||
g.drawString("Down", x_max_screen-2*v_font1size,y_wg_top+v_font3size);
|
||||
g.flip();
|
||||
//back to standard /horizontal
|
||||
g.setFontAlign(-1,-1,0);
|
||||
}
|
||||
|
||||
function DrawRowSelArrow(v_drawRow, v_clearRow){
|
||||
//Params: row_arrow, row_clear_area
|
||||
//for clear previous draw arrow
|
||||
if (v_clearRow!== undefined) {
|
||||
g.setColor(colbackg);
|
||||
if (v_clearRow==1) v_y_arrow=v_y_optionrow1+14;
|
||||
else if (v_clearRow==2) v_y_arrow=v_y_optionrow2+14;
|
||||
else if (v_clearRow==3) v_y_arrow=v_y_optionrow3+14;
|
||||
g.fillRect(5,v_y_arrow-5,13,v_y_arrow+5);
|
||||
g.flip();
|
||||
}
|
||||
//draw an arrow to select a row
|
||||
if (v_drawRow!== undefined) {
|
||||
if (v_drawRow==1) v_y_arrow=v_y_optionrow1+14;
|
||||
else if (v_drawRow==2) v_y_arrow=v_y_optionrow2+14;
|
||||
else if (v_drawRow==3) v_y_arrow=v_y_optionrow3+14;
|
||||
|
||||
g.setColor(v_color_lines);
|
||||
g.drawLine(5, v_y_arrow, 13, v_y_arrow);//horizontal
|
||||
g.drawLine(13, v_y_arrow, 10, v_y_arrow-5);//over diag
|
||||
g.drawLine(13, v_y_arrow, 10, v_y_arrow+5);//under diag
|
||||
g.flip();
|
||||
}
|
||||
else console.log("Error: Param row nbr missing");
|
||||
}
|
||||
|
||||
function PrintAreas(){
|
||||
console.log("********************************");
|
||||
console.log("Log: *** Print Areas in screen");
|
||||
ClearActiveArea();
|
||||
if (v_mode_debug==1) console.log("Log: *** Print Areas in screen");
|
||||
ClearActiveArea(0,y_wg_top,x_max_usable_area,y_wg_bottom);
|
||||
g.setColor(v_color_lines);
|
||||
g.drawLine(1, 140, 1, 200);//vline left border
|
||||
g.drawLine(239, 140, 239, 200);//vlide right border
|
||||
g.drawLine(120, 100, 120, 135);//vline middle separation top
|
||||
g.drawLine(120, 170, 120, 200);//vline middle separation bottom
|
||||
|
||||
//BTN1
|
||||
g.setFontVector(v_font1size).drawString("Color<-", 130,125);
|
||||
//BTN13
|
||||
g.setFontVector(v_font1size).drawString("Quit<-", 135,225);
|
||||
g.flip();
|
||||
g.setColor(0,1,0); //green
|
||||
g.setFontVector(v_font1size).drawString("BTN1", 195,45);
|
||||
DrawRowSelArrow(1);
|
||||
DrawRoundOption(20,v_y_optionrow1,190,v_y_optionrow1,'none');
|
||||
DrawRoundOption(20,v_y_optionrow2,190,v_y_optionrow2,'none');
|
||||
|
||||
g.setFontVector(v_font1size).drawString("BTN2", 195,125);
|
||||
g.drawLine(x_max_screen-1, 50, x_max_screen-1, 65);//vlide right border
|
||||
g.drawLine(x_mid_screen, 80, x_mid_screen, 105);//vline middle separation part1 up
|
||||
g.drawLine(x_mid_screen, 140, x_mid_screen, 180);//vline middle separation part2 down
|
||||
|
||||
g.setFontVector(v_font1size).drawString("BTN3", 195,225);
|
||||
g.setFontVector(v_font1size).drawString("Middle area", 80,155);
|
||||
g.setFontVector(v_font1size).drawString("Left area", 15, 185);
|
||||
g.setFontVector(v_font1size).drawString("Right area", 140,185);
|
||||
g.flip();
|
||||
|
||||
g.setFontVector(v_font3size);
|
||||
g.drawString("Middle area", 80,155);
|
||||
g.drawString("Left area", 15, 185);
|
||||
g.drawString("Right area", 140,185);
|
||||
|
||||
if (v_model=='BANGLEJS') DrawBangleButtons();
|
||||
}
|
||||
|
||||
function UserInput(){
|
||||
|
|
@ -181,23 +306,26 @@ function UserInput(){
|
|||
}
|
||||
});
|
||||
//only the name of the function
|
||||
setWatch(PrintBtn1, BTN1, { repeat: true });
|
||||
setWatch(PrintBtn2, BTN2, { repeat: true });
|
||||
setWatch(Btn1Clkd, BTN1, { repeat: true });
|
||||
setWatch(Btn2Clkd, BTN2, { repeat: true });
|
||||
setWatch(Bangle.showLauncher, BTN3, { repeat: true });
|
||||
Bangle.on('swipe', dir => {
|
||||
if(dir == 1) PrintUserInput(" --->");
|
||||
else PrintUserInput(" <---");
|
||||
});
|
||||
console.log("Log: Input conditions loaded");
|
||||
if (v_mode_debug==1) console.log("Log: Input conditions loaded");
|
||||
} //end of UserInput
|
||||
|
||||
//Main code
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
//optional line below widgets area
|
||||
|
||||
g.setColor(v_color_lines);
|
||||
g.drawLine(60, 30, 180, 30);
|
||||
g.flip();
|
||||
//optional line below widgets area
|
||||
//g.drawLine(60, 30, 180, 30);
|
||||
//g.flip();
|
||||
//end optional
|
||||
PrintHelp();
|
||||
|
||||
UserInput();
|
||||
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 112 KiB |