Merge branch 'master' of github.com:awkirk71/BangleApps into extended_sliding_clock
|
@ -11,3 +11,6 @@ tests/Layout/testresult.bmp
|
|||
apps.local.json
|
||||
_site
|
||||
.jekyll-cache
|
||||
.owncloudsync.log
|
||||
Desktop.ini
|
||||
.sync_*.db*
|
||||
|
|
|
@ -149,11 +149,11 @@ function drawHSeg(x1,y1,x2,y2,Num,Color,Size) {
|
|||
if (Color == "fg") {
|
||||
g.setColor(g.theme.fg);
|
||||
} else {
|
||||
g.setColor(mColor[0],mColor[1],mColor[2]);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ function drawSSeg(x1,y1,x2,y2,Num,Color,Size) {
|
|||
for (let j = 1; j < 8; j++) {
|
||||
if (Font[Num][j-1][i-1] == 1) {
|
||||
if (Color == "fg") {
|
||||
g.setColor(sColor[0],sColor[1],sColor[2]);
|
||||
g.setColor(sColor[0],sColor[1],sColor[2]);
|
||||
} else {
|
||||
g.setColor(g.theme.fg);
|
||||
//g.setColor(0.7,0.7,0.7);
|
||||
|
@ -253,8 +253,8 @@ function actions(v){
|
|||
if(BTN1.read() === true) {
|
||||
print("BTN pressed");
|
||||
Bangle.showLauncher();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(v==-1){
|
||||
print("up swipe event");
|
||||
if(settings.swupApp != "") load(settings.swupApp);
|
||||
|
@ -269,7 +269,7 @@ function actions(v){
|
|||
}
|
||||
|
||||
// Get Messages status
|
||||
var messages = require("Storage").readJSON("messages.json",1)||[];
|
||||
var messages_installed = require("Storage").read("messages") !== undefined;
|
||||
|
||||
//var BTconnected = NRF.getSecurityStatus().connected;
|
||||
//NRF.on('connect',BTconnected = NRF.getSecurityStatus().connected);
|
||||
|
@ -289,27 +289,27 @@ function drawWidgeds() {
|
|||
g.setColor((g.getBPP()>8) ? "#07f" : (g.theme.dark ? "#0ff" : "#00f"));
|
||||
else
|
||||
g.setColor(g.theme.dark ? "#666" : "#999");
|
||||
g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="),x1Bt,y1Bt);
|
||||
g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="),x1Bt,y1Bt);
|
||||
|
||||
|
||||
|
||||
//Battery
|
||||
//print(E.getBattery());
|
||||
//print(Bangle.isCharging());
|
||||
|
||||
|
||||
var x1B = 130;
|
||||
var y1B = 2;
|
||||
var x2B = x1B + 20;
|
||||
var y2B = y1B + 15;
|
||||
|
||||
|
||||
g.setColor(g.theme.bg);
|
||||
g.clearRect(x1B,y1B,x2B,y2B);
|
||||
|
||||
|
||||
g.setColor(g.theme.fg);
|
||||
g.drawRect(x1B,y1B,x2B,y2B);
|
||||
g.fillRect(x1B,y1B,x1B+(E.getBattery()*(x2B-x1B)/100),y2B);
|
||||
g.fillRect(x2B,y1B+(y2B-y1B)/2-3,x2B+4,y1B+(y2B-y1B)/2+3);
|
||||
|
||||
|
||||
|
||||
|
||||
//Messages
|
||||
|
||||
|
@ -318,25 +318,25 @@ function drawWidgeds() {
|
|||
var x2M = x1M + 25;
|
||||
var y2M = y2B;
|
||||
|
||||
if (messages.some(m=>m.new)) {
|
||||
if (messages_installed && require("messages").status() == "new") {
|
||||
g.setColor(g.theme.fg);
|
||||
g.fillRect(x1M,y1M,x2M,y2M);
|
||||
g.setColor(g.theme.bg);
|
||||
g.drawLine(x1M,y1M,x1M+(x2M-x1M)/2,y1M+(y2M-y1M)/2);
|
||||
g.drawLine(x1M+(x2M-x1M)/2,y1M+(y2M-y1M)/2,x2M,y1M);
|
||||
}
|
||||
|
||||
|
||||
var strDow = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
|
||||
var d = new Date();
|
||||
var dow = d.getDay(),day = d.getDate(), month = d.getMonth() + 1, year = d.getFullYear();
|
||||
|
||||
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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -354,7 +354,7 @@ function SetFull(on) {
|
|||
} else {
|
||||
Ys = 30;
|
||||
Bangle.setUI("updown",actions);
|
||||
Bangle.on('swipe', function(direction) {
|
||||
Bangle.on('swipe', function(direction) {
|
||||
switch (direction) {
|
||||
case 1:
|
||||
print("swipe left event");
|
||||
|
@ -362,7 +362,7 @@ function SetFull(on) {
|
|||
print(settings.swleftApp);
|
||||
break;
|
||||
case -1:
|
||||
print("swipe right event");
|
||||
print("swipe right event");
|
||||
if(settings.swrightApp != "") load(settings.swrightApp);
|
||||
print(settings.swrightApp);
|
||||
break;
|
||||
|
@ -374,7 +374,7 @@ function SetFull(on) {
|
|||
|
||||
SegH = (Ye-Ys)/2;
|
||||
Dy = SegH/16;
|
||||
|
||||
|
||||
draw();
|
||||
|
||||
if (on != true) {
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: Initial version for upload
|
||||
0.02: better theme support, configurable colors, small improvements
|
||||
0.02: Better theme support, configurable colors, small improvements
|
||||
0.03: Use `messages` library to check for new messages
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "7x7dotsclock",
|
||||
"name": "7x7 Dots Clock",
|
||||
"shortName":"7x7 Dots Clock",
|
||||
"version":"0.02",
|
||||
"version":"0.03",
|
||||
"description": "A clock with a big 7x7 dots Font",
|
||||
"icon": "dotsfontclock.png",
|
||||
"tags": "clock",
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: New App!
|
||||
0.02: Fullscreen settings.
|
||||
0.02: Fullscreen settings.
|
||||
0.03: Tell clock widgets to hide.
|
||||
|
|
|
@ -115,6 +115,9 @@ function draw() {
|
|||
}
|
||||
}
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.loadWidgets();
|
||||
|
||||
// Clear the screen once, at startup
|
||||
|
@ -140,5 +143,3 @@ Bangle.on('lock', function(isLocked) {
|
|||
});
|
||||
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "90sclk",
|
||||
"name": "90s Clock",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "A 90s style watch-face",
|
||||
"readme": "README.md",
|
||||
"icon": "app.png",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: Initial version
|
|
@ -0,0 +1,13 @@
|
|||
# a_dndtoggle - Toggle Quiet Mode of the watch
|
||||
|
||||
When Quiet mode is off, just start this app to set quiet mode. Start it again to turn off quiet mode.
|
||||
Work in progress.
|
||||
|
||||
#ToDo
|
||||
Settings page, current status indicator.
|
||||
|
||||
## Creator
|
||||
|
||||
Hank - contact at http://forum.espruino.com
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
const modeNames = [/*LANG*/"Noisy", /*LANG*/"Alarms", /*LANG*/"Silent"];
|
||||
let bSettings = require('Storage').readJSON('setting.json',true)||{};
|
||||
let current = 0|bSettings.quiet;
|
||||
//0 off
|
||||
//1 alarms
|
||||
//2 silent
|
||||
|
||||
console.log("old: " + current);
|
||||
|
||||
switch (current) {
|
||||
case 0:
|
||||
bSettings.quiet = 2;
|
||||
Bangle.buzz();
|
||||
setTimeout('Bangle.buzz();',500);
|
||||
break;
|
||||
case 1:
|
||||
bSettings.quiet = 0;
|
||||
Bangle.buzz();
|
||||
break;
|
||||
case 2:
|
||||
bSettings.quiet = 0;
|
||||
Bangle.buzz();
|
||||
break;
|
||||
default:
|
||||
bSettings.quiet = 0;
|
||||
Bangle.buzz();
|
||||
}
|
||||
|
||||
console.log("new: " + bSettings.quiet);
|
||||
|
||||
E.showMessage(modeNames[current] + " -> " + modeNames[bSettings.quiet]);
|
||||
setTimeout('exitApp();', 2000);
|
||||
|
||||
|
||||
function exitApp(){
|
||||
|
||||
require("Storage").writeJSON("setting.json", bSettings);
|
||||
// reload clocks with new theme, otherwise just wait for user to switch apps
|
||||
|
||||
load()
|
||||
|
||||
}
|
After Width: | Height: | Size: 486 B |
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwJC/AAl/Agf/AAUAgIFDwEHAofgh/g/0Ag/wj+AnwVB/EegEfEIN4nkAh+AgE8vgVBAoV4Aoce/EAgfADQIFcjwpFHYIFCnxBFJopZBn5ZCMopxFPoqJFSowA/gA="))
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"id": "a_dndtoggle",
|
||||
"name": "a_dndtoggle - Toggle Quiet Mode of the watch",
|
||||
"shortName": "A_DND Toggle",
|
||||
"version": "0.01",
|
||||
"description": "Toggle Quiet Mode of the watch just by starting this app.",
|
||||
"icon": "a_dndtoggle.png",
|
||||
"type": "app",
|
||||
"tags": "tool",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"a_dndtoggle.app.js","url":"a_dndtoggle.app.js"},
|
||||
{"name":"a_dndtoggle.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"readme": "README.md"
|
||||
}
|
|
@ -10,3 +10,4 @@
|
|||
0.10: Added separate Bangle.js 2 file with Bangle.js 2 kickstarter pixels (as of 28 Oct 2021)
|
||||
0.11: Bangle.js2: New pixels, btn1 to exit
|
||||
0.12: Actual pixels as of 29th Nov 2021
|
||||
0.13: Bangle.js 2: Use setUI to add software back button
|
||||
|
|
|
@ -69,4 +69,7 @@ function drawImage() {
|
|||
|
||||
// TODO: a nice little animation before
|
||||
setTimeout(drawInfo, 1000);
|
||||
setWatch(_=>load(), BTN1);
|
||||
Bangle.setUI({
|
||||
mode : "custom",
|
||||
back : load
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "about",
|
||||
"name": "About",
|
||||
"version": "0.12",
|
||||
"version": "0.13",
|
||||
"description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,system",
|
||||
|
|
|
@ -6,3 +6,5 @@
|
|||
0.06: Add a temperature threshold to detect (and not alert) if the BJS isn't worn. Better support for the peoples using the app at night
|
||||
0.07: Fix bug on the cutting edge firmware
|
||||
0.08: Use default Bangle formatter for booleans
|
||||
0.09: New app screen (instead of showing settings or the alert) and some optimisations
|
||||
0.10: Add software back button via setUI
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
(function () {
|
||||
// load variable before defining functions cause it can trigger a ReferenceError
|
||||
const activityreminder = require("activityreminder");
|
||||
const storage = require("Storage");
|
||||
let activityreminder_data = activityreminder.loadData();
|
||||
|
||||
function run() {
|
||||
E.showPrompt("Inactivity detected", {
|
||||
title: "Activity reminder",
|
||||
buttons: { "Ok": 1, "Dismiss": 2, "Pause": 3 }
|
||||
}).then(function (v) {
|
||||
if (v == 1) {
|
||||
activityreminder_data.okDate = new Date();
|
||||
}
|
||||
if (v == 2) {
|
||||
activityreminder_data.dismissDate = new Date();
|
||||
}
|
||||
if (v == 3) {
|
||||
activityreminder_data.pauseDate = new Date();
|
||||
}
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
load();
|
||||
});
|
||||
|
||||
// Obey system quiet mode:
|
||||
if (!(storage.readJSON('setting.json', 1) || {}).quiet) {
|
||||
Bangle.buzz(400);
|
||||
}
|
||||
setTimeout(load, 20000);
|
||||
}
|
||||
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
run();
|
||||
|
||||
})();
|
|
@ -1,46 +1,58 @@
|
|||
(function () {
|
||||
// load variable before defining functions cause it can trigger a ReferenceError
|
||||
const activityreminder = require("activityreminder");
|
||||
const storage = require("Storage");
|
||||
const activityreminder_settings = activityreminder.loadSettings();
|
||||
let activityreminder_data = activityreminder.loadData();
|
||||
// load variable before defining functions cause it can trigger a ReferenceError
|
||||
const activityreminder = require("activityreminder");
|
||||
let activityreminder_data = activityreminder.loadData();
|
||||
let W = g.getWidth();
|
||||
// let H = g.getHeight();
|
||||
|
||||
function drawAlert() {
|
||||
E.showPrompt("Inactivity detected", {
|
||||
title: "Activity reminder",
|
||||
buttons: { "Ok": 1, "Dismiss": 2, "Pause": 3 }
|
||||
}).then(function (v) {
|
||||
if (v == 1) {
|
||||
activityreminder_data.okDate = new Date();
|
||||
}
|
||||
if (v == 2) {
|
||||
activityreminder_data.dismissDate = new Date();
|
||||
}
|
||||
if (v == 3) {
|
||||
activityreminder_data.pauseDate = new Date();
|
||||
}
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
load();
|
||||
});
|
||||
|
||||
// Obey system quiet mode:
|
||||
if (!(storage.readJSON('setting.json', 1) || {}).quiet) {
|
||||
Bangle.buzz(400);
|
||||
}
|
||||
setTimeout(load, 20000);
|
||||
}
|
||||
|
||||
function run() {
|
||||
if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) {
|
||||
drawAlert();
|
||||
} else {
|
||||
eval(storage.read("activityreminder.settings.js"))(() => load());
|
||||
}
|
||||
}
|
||||
function getHoursMins(date){
|
||||
var h = date.getHours();
|
||||
var m = date.getMinutes();
|
||||
return (""+h).substr(-2) + ":" + ("0"+m).substr(-2);
|
||||
}
|
||||
|
||||
function drawData(name, value, y){
|
||||
g.drawString(name, 10, y);
|
||||
g.drawString(value, 100, y);
|
||||
}
|
||||
|
||||
function drawInfo() {
|
||||
var h=18, y = h;
|
||||
g.setColor(g.theme.fg);
|
||||
g.setFont("Vector",h).setFontAlign(-1,-1);
|
||||
|
||||
// Header
|
||||
g.drawLine(0,25,W,25);
|
||||
g.drawLine(0,26,W,26);
|
||||
|
||||
g.drawString("Current Cycle", 10, y+=h);
|
||||
drawData("Start", getHoursMins(activityreminder_data.stepsDate), y+=h);
|
||||
drawData("Steps", getCurrentSteps(), y+=h);
|
||||
|
||||
/*
|
||||
g.drawString("Button Press", 10, y+=h*2);
|
||||
drawData("Ok", getHoursMins(activityreminder_data.okDate), y+=h);
|
||||
drawData("Dismiss", getHoursMins(activityreminder_data.dismissDate), y+=h);
|
||||
drawData("Pause", getHoursMins(activityreminder_data.pauseDate), y+=h);
|
||||
*/
|
||||
}
|
||||
|
||||
function getCurrentSteps(){
|
||||
let health = Bangle.getHealthStatus("day");
|
||||
return health.steps - activityreminder_data.stepsOnDate;
|
||||
}
|
||||
|
||||
function run() {
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
run();
|
||||
|
||||
})();
|
||||
drawInfo();
|
||||
Bangle.setUI({
|
||||
mode : "custom",
|
||||
back : load
|
||||
})
|
||||
}
|
||||
|
||||
run();
|
||||
|
||||
})();
|
||||
|
|
|
@ -1,70 +1,81 @@
|
|||
(function () {
|
||||
// load variable before defining functions cause it can trigger a ReferenceError
|
||||
const activityreminder = require("activityreminder");
|
||||
const activityreminder_settings = activityreminder.loadSettings();
|
||||
let activityreminder_data = activityreminder.loadData();
|
||||
|
||||
if (activityreminder_data.firstLoad) {
|
||||
activityreminder_data.firstLoad = false;
|
||||
// load variable before defining functions cause it can trigger a ReferenceError
|
||||
const activityreminder = require("activityreminder");
|
||||
const activityreminder_settings = activityreminder.loadSettings();
|
||||
let activityreminder_data = activityreminder.loadData();
|
||||
|
||||
if (activityreminder_data.firstLoad) {
|
||||
activityreminder_data.firstLoad = false;
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
}
|
||||
|
||||
function run() {
|
||||
if (isNotWorn()) return;
|
||||
let now = new Date();
|
||||
let h = now.getHours();
|
||||
|
||||
if (isDuringAlertHours(h)) {
|
||||
let health = Bangle.getHealthStatus("day");
|
||||
if (health.steps - activityreminder_data.stepsOnDate >= activityreminder_settings.minSteps // more steps made than needed
|
||||
|| health.steps < activityreminder_data.stepsOnDate) { // new day or reboot of the watch
|
||||
activityreminder_data.stepsOnDate = health.steps;
|
||||
activityreminder_data.stepsDate = now;
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
}
|
||||
|
||||
function run() {
|
||||
if (isNotWorn()) return;
|
||||
let now = new Date();
|
||||
let h = now.getHours();
|
||||
|
||||
if (isDuringAlertHours(h)) {
|
||||
let health = Bangle.getHealthStatus("day");
|
||||
if (health.steps - activityreminder_data.stepsOnDate >= activityreminder_settings.minSteps // more steps made than needed
|
||||
|| health.steps < activityreminder_data.stepsOnDate) { // new day or reboot of the watch
|
||||
activityreminder_data.stepsOnDate = health.steps;
|
||||
activityreminder_data.stepsDate = now;
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
/* todo in a futur release
|
||||
Add settimer to trigger like 30 secs after going in this part cause the person have been walking
|
||||
(pass some argument to run() to handle long walks and not triggering so often)
|
||||
*/
|
||||
}
|
||||
|
||||
if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) {
|
||||
load('activityreminder.app.js');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isNotWorn() {
|
||||
return (Bangle.isCharging() || activityreminder_settings.tempThreshold >= E.getTemperature());
|
||||
}
|
||||
|
||||
function isDuringAlertHours(h) {
|
||||
if (activityreminder_settings.startHour < activityreminder_settings.endHour) { // not passing through midnight
|
||||
return (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour);
|
||||
} else { // passing through midnight
|
||||
return (h >= activityreminder_settings.startHour || h < activityreminder_settings.endHour);
|
||||
}
|
||||
}
|
||||
|
||||
Bangle.on('midnight', function () {
|
||||
/*
|
||||
Usefull trick to have the app working smothly for people using it at night
|
||||
*/
|
||||
let now = new Date();
|
||||
let h = now.getHours();
|
||||
if (activityreminder_settings.enabled && isDuringAlertHours(h)) {
|
||||
// updating only the steps and keeping the original stepsDate on purpose
|
||||
activityreminder_data.stepsOnDate = 0;
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (activityreminder_settings.enabled) {
|
||||
setInterval(run, 60000);
|
||||
/* todo in a futur release
|
||||
increase setInterval time to something that is still sensible (5 mins ?)
|
||||
when we added a settimer
|
||||
Add settimer to trigger like 30 secs after going in this part cause the person have been walking
|
||||
(pass some argument to run() to handle long walks and not triggering so often)
|
||||
*/
|
||||
}
|
||||
|
||||
if (mustAlert(now)) {
|
||||
load('activityreminder.alert.js');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isNotWorn() {
|
||||
return (Bangle.isCharging() || activityreminder_settings.tempThreshold >= E.getTemperature());
|
||||
}
|
||||
|
||||
function isDuringAlertHours(h) {
|
||||
if (activityreminder_settings.startHour < activityreminder_settings.endHour) { // not passing through midnight
|
||||
return (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour);
|
||||
} else { // passing through midnight
|
||||
return (h >= activityreminder_settings.startHour || h < activityreminder_settings.endHour);
|
||||
}
|
||||
}
|
||||
|
||||
function mustAlert(now) {
|
||||
if ((now - activityreminder_data.stepsDate) / 60000 > activityreminder_settings.maxInnactivityMin) { // inactivity detected
|
||||
if ((now - activityreminder_data.okDate) / 60000 > 3 && // last alert anwsered with ok was more than 3 min ago
|
||||
(now - activityreminder_data.dismissDate) / 60000 > activityreminder_settings.dismissDelayMin && // last alert was more than dismissDelayMin ago
|
||||
(now - activityreminder_data.pauseDate) / 60000 > activityreminder_settings.pauseDelayMin) { // last alert was more than pauseDelayMin ago
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Bangle.on('midnight', function () {
|
||||
/*
|
||||
Usefull trick to have the app working smothly for people using it at night
|
||||
*/
|
||||
let now = new Date();
|
||||
let h = now.getHours();
|
||||
if (activityreminder_settings.enabled && isDuringAlertHours(h)) {
|
||||
// updating only the steps and keeping the original stepsDate on purpose
|
||||
activityreminder_data.stepsOnDate = 0;
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (activityreminder_settings.enabled) {
|
||||
setInterval(run, 60000);
|
||||
/* todo in a futur release
|
||||
increase setInterval time to something that is still sensible (5 mins ?)
|
||||
when we added a settimer
|
||||
*/
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -1,56 +1,44 @@
|
|||
exports.loadSettings = function () {
|
||||
return Object.assign({
|
||||
enabled: true,
|
||||
startHour: 9,
|
||||
endHour: 20,
|
||||
maxInnactivityMin: 30,
|
||||
dismissDelayMin: 15,
|
||||
pauseDelayMin: 120,
|
||||
minSteps: 50,
|
||||
tempThreshold: 27
|
||||
}, require("Storage").readJSON("activityreminder.s.json", true) || {});
|
||||
return Object.assign({
|
||||
enabled: true,
|
||||
startHour: 9,
|
||||
endHour: 20,
|
||||
maxInnactivityMin: 30,
|
||||
dismissDelayMin: 15,
|
||||
pauseDelayMin: 120,
|
||||
minSteps: 50,
|
||||
tempThreshold: 27
|
||||
}, require("Storage").readJSON("activityreminder.s.json", true) || {});
|
||||
};
|
||||
|
||||
exports.writeSettings = function (settings) {
|
||||
require("Storage").writeJSON("activityreminder.s.json", settings);
|
||||
require("Storage").writeJSON("activityreminder.s.json", settings);
|
||||
};
|
||||
|
||||
exports.saveData = function (data) {
|
||||
require("Storage").writeJSON("activityreminder.data.json", data);
|
||||
require("Storage").writeJSON("activityreminder.data.json", data);
|
||||
};
|
||||
|
||||
exports.loadData = function () {
|
||||
let health = Bangle.getHealthStatus("day");
|
||||
let data = Object.assign({
|
||||
firstLoad: true,
|
||||
stepsDate: new Date(),
|
||||
stepsOnDate: health.steps,
|
||||
okDate: new Date(1970),
|
||||
dismissDate: new Date(1970),
|
||||
pauseDate: new Date(1970),
|
||||
},
|
||||
let health = Bangle.getHealthStatus("day");
|
||||
let data = Object.assign({
|
||||
firstLoad: true,
|
||||
stepsDate: new Date(),
|
||||
stepsOnDate: health.steps,
|
||||
okDate: new Date(1970),
|
||||
dismissDate: new Date(1970),
|
||||
pauseDate: new Date(1970),
|
||||
},
|
||||
require("Storage").readJSON("activityreminder.data.json") || {});
|
||||
|
||||
if(typeof(data.stepsDate) == "string")
|
||||
data.stepsDate = new Date(data.stepsDate);
|
||||
if(typeof(data.okDate) == "string")
|
||||
data.okDate = new Date(data.okDate);
|
||||
if(typeof(data.dismissDate) == "string")
|
||||
data.dismissDate = new Date(data.dismissDate);
|
||||
if(typeof(data.pauseDate) == "string")
|
||||
data.pauseDate = new Date(data.pauseDate);
|
||||
if (typeof (data.stepsDate) == "string")
|
||||
data.stepsDate = new Date(data.stepsDate);
|
||||
if (typeof (data.okDate) == "string")
|
||||
data.okDate = new Date(data.okDate);
|
||||
if (typeof (data.dismissDate) == "string")
|
||||
data.dismissDate = new Date(data.dismissDate);
|
||||
if (typeof (data.pauseDate) == "string")
|
||||
data.pauseDate = new Date(data.pauseDate);
|
||||
|
||||
return data;
|
||||
return data;
|
||||
};
|
||||
|
||||
exports.mustAlert = function(activityreminder_data, activityreminder_settings) {
|
||||
let now = new Date();
|
||||
if ((now - activityreminder_data.stepsDate) / 60000 > activityreminder_settings.maxInnactivityMin) { // inactivity detected
|
||||
if ((now - activityreminder_data.okDate) / 60000 > 3 && // last alert anwsered with ok was more than 3 min ago
|
||||
(now - activityreminder_data.dismissDate) / 60000 > activityreminder_settings.dismissDelayMin && // last alert was more than dismissDelayMin ago
|
||||
(now - activityreminder_data.pauseDate) / 60000 > activityreminder_settings.pauseDelayMin) { // last alert was more than pauseDelayMin ago
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Activity Reminder",
|
||||
"shortName":"Activity Reminder",
|
||||
"description": "A reminder to take short walks for the ones with a sedentary lifestyle",
|
||||
"version":"0.08",
|
||||
"version":"0.10",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
"tags": "tool,activity",
|
||||
|
@ -13,11 +13,12 @@
|
|||
{"name": "activityreminder.app.js", "url":"app.js"},
|
||||
{"name": "activityreminder.boot.js", "url": "boot.js"},
|
||||
{"name": "activityreminder.settings.js", "url": "settings.js"},
|
||||
{"name": "activityreminder.alert.js", "url": "alert.js"},
|
||||
{"name": "activityreminder", "url": "lib.js"},
|
||||
{"name": "activityreminder.img", "url": "app-icon.js", "evaluate": true}
|
||||
],
|
||||
"data": [
|
||||
{"name": "activityreminder.s.json"},
|
||||
{"name": "activityreminder.data.json"}
|
||||
{"name": "activityreminder.data.json", "storageFile": true}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,80 +1,86 @@
|
|||
(function (back) {
|
||||
// Load settings
|
||||
const activityreminder = require("activityreminder");
|
||||
let settings = activityreminder.loadSettings();
|
||||
// Load settings
|
||||
const activityreminder = require("activityreminder");
|
||||
let settings = activityreminder.loadSettings();
|
||||
|
||||
// Show the menu
|
||||
E.showMenu({
|
||||
"": { "title": "Activity Reminder" },
|
||||
"< Back": () => back(),
|
||||
'Enable': {
|
||||
value: settings.enabled,
|
||||
onchange: v => {
|
||||
settings.enabled = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'Start hour': {
|
||||
value: settings.startHour,
|
||||
min: 0, max: 24,
|
||||
onchange: v => {
|
||||
settings.startHour = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'End hour': {
|
||||
value: settings.endHour,
|
||||
min: 0, max: 24,
|
||||
onchange: v => {
|
||||
settings.endHour = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'Max inactivity': {
|
||||
value: settings.maxInnactivityMin,
|
||||
min: 15, max: 120,
|
||||
onchange: v => {
|
||||
settings.maxInnactivityMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => x + "m"
|
||||
},
|
||||
'Dismiss delay': {
|
||||
value: settings.dismissDelayMin,
|
||||
min: 5, max: 60,
|
||||
onchange: v => {
|
||||
settings.dismissDelayMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => x + "m"
|
||||
},
|
||||
'Pause delay': {
|
||||
value: settings.pauseDelayMin,
|
||||
min: 30, max: 240, step: 5,
|
||||
onchange: v => {
|
||||
settings.pauseDelayMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => {
|
||||
return x + "m";
|
||||
}
|
||||
},
|
||||
'Min steps': {
|
||||
value: settings.minSteps,
|
||||
min: 10, max: 500, step: 10,
|
||||
onchange: v => {
|
||||
settings.minSteps = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'Temp Threshold': {
|
||||
value: settings.tempThreshold,
|
||||
min: 20, max: 40, step: 0.5,
|
||||
format: v => v + "°C",
|
||||
onchange: v => {
|
||||
settings.tempThreshold = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
function getMainMenu(){
|
||||
var mainMenu = {
|
||||
"": { "title": "Activity Reminder" },
|
||||
"< Back": () => back(),
|
||||
'Enable': {
|
||||
value: settings.enabled,
|
||||
onchange: v => {
|
||||
settings.enabled = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
});
|
||||
},
|
||||
'Start hour': {
|
||||
value: settings.startHour,
|
||||
min: 0, max: 24,
|
||||
onchange: v => {
|
||||
settings.startHour = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'End hour': {
|
||||
value: settings.endHour,
|
||||
min: 0, max: 24,
|
||||
onchange: v => {
|
||||
settings.endHour = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'Max inactivity': {
|
||||
value: settings.maxInnactivityMin,
|
||||
min: 15, max: 120,
|
||||
onchange: v => {
|
||||
settings.maxInnactivityMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => x + "m"
|
||||
},
|
||||
'Dismiss delay': {
|
||||
value: settings.dismissDelayMin,
|
||||
min: 5, max: 60,
|
||||
onchange: v => {
|
||||
settings.dismissDelayMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => x + "m"
|
||||
},
|
||||
'Pause delay': {
|
||||
value: settings.pauseDelayMin,
|
||||
min: 30, max: 240, step: 5,
|
||||
onchange: v => {
|
||||
settings.pauseDelayMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => {
|
||||
return x + "m";
|
||||
}
|
||||
},
|
||||
'Min steps': {
|
||||
value: settings.minSteps,
|
||||
min: 10, max: 500, step: 10,
|
||||
onchange: v => {
|
||||
settings.minSteps = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'Temp Threshold': {
|
||||
value: settings.tempThreshold,
|
||||
min: 20, max: 40, step: 0.5,
|
||||
format: v => v + "°C",
|
||||
onchange: v => {
|
||||
settings.tempThreshold = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return mainMenu;
|
||||
}
|
||||
|
||||
// Show the menu
|
||||
E.showMenu(getMainMenu());
|
||||
})
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
0.01: AdvCasio first version
|
||||
0.02: Remove un-needed fonts to improve memory usage
|
||||
0.03: Tell clock widgets to hide.
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
const storage = require('Storage');
|
||||
|
||||
require("Font6x12").add(Graphics);
|
||||
require("Font6x8").add(Graphics);
|
||||
require("Font8x12").add(Graphics);
|
||||
require("Font7x11Numeric7Seg").add(Graphics);
|
||||
|
||||
|
@ -257,7 +255,6 @@ function draw() {
|
|||
|
||||
|
||||
g.setColor(0, 0, 0);
|
||||
g.setFont("6x12");
|
||||
if(dataJson && dataJson.weather) drawWeather(dataJson.weather);
|
||||
if(dataJson && dataJson.tasks) drawTasks(dataJson.tasks);
|
||||
|
||||
|
@ -297,9 +294,10 @@ Bangle.on("lock", (locked) => {
|
|||
});
|
||||
|
||||
|
||||
Bangle.setUI("clock");
|
||||
|
||||
// Load widgets, but don't show them
|
||||
Bangle.loadWidgets();
|
||||
Bangle.setUI("clock");
|
||||
|
||||
g.reset();
|
||||
g.clear();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "advcasio",
|
||||
"name": "Advanced Casio Clock",
|
||||
"shortName":"advcasio",
|
||||
"version":"0.01",
|
||||
"version":"0.03",
|
||||
"description": "An over-engineered clock inspired by Casio watches. It has a 4 days weather, a timer using swipe and a scratchpad. Can be updated using a dedicated webapp.",
|
||||
"icon": "app.png",
|
||||
"tags": "clock",
|
||||
|
|
|
@ -1,2 +1,6 @@
|
|||
0.01: Basic agenda with events from GB
|
||||
0.02: Added settings page to force calendar sync
|
||||
0.03: Disable past events display from settings
|
||||
0.04: Added awareness of allDay field
|
||||
0.05: Displaying calendar colour and name
|
||||
0.06: Added clkinfo for clocks.
|
|
@ -1,3 +1,20 @@
|
|||
# Agenda
|
||||
|
||||
Basic agenda reading the events synchronised from GadgetBridge
|
||||
Basic agenda reading the events synchronised from GadgetBridge.
|
||||
|
||||
### Functionalities
|
||||
|
||||
* List all events in the next week (or whatever is synchronized)
|
||||
* Optionally view past events (until GB removes them)
|
||||
* Show start time and location of the events in the list
|
||||
* Show the colour of the calendar in the list
|
||||
* Display description, location and calendar name after tapping on events
|
||||
|
||||
### Report a bug
|
||||
|
||||
You can easily open an issue in the espruino repo, but I won't be notified and it might take time.
|
||||
If you want a (hopefully) quicker response, just report [on my fork](https://github.com/glemco/BangleApps).
|
||||
|
||||
### Known Problems
|
||||
|
||||
Any all-day event lasts just one day: that is a GB limitation that we will likely fix in the future.
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
(function() {
|
||||
var agendaItems = {
|
||||
name: "Agenda",
|
||||
img: atob("GBiBAf////////85z/AAAPAAAPgAAP////AAAPAAAPAAAPAAAOAAAeAAAeAAAcAAA8AAAoAABgAADP//+P//8PAAAPAAAPgAAf///w=="),
|
||||
items: []
|
||||
};
|
||||
|
||||
var now = new Date();
|
||||
var agenda = storage.readJSON("android.calendar.json")
|
||||
.filter(ev=>ev.timestamp + ev.durationInSeconds > now/1000)
|
||||
.sort((a,b)=>a.timestamp - b.timestamp);
|
||||
|
||||
agenda.forEach((entry, i) => {
|
||||
|
||||
var title = entry.title.slice(0,18);
|
||||
var date = new Date(entry.timestamp*1000);
|
||||
var dateStr = locale.date(date).replace(/\d\d\d\d/,"");
|
||||
dateStr += entry.durationInSeconds < 86400 ? "/ " + locale.time(date,1) : "";
|
||||
|
||||
agendaItems.items.push({
|
||||
name: "agendaEntry-" + i,
|
||||
get: () => ({ text: title + "\n" + dateStr, img: null}),
|
||||
show: function() { agendaItems.items[i].emit("redraw"); },
|
||||
hide: function () {}
|
||||
});
|
||||
});
|
||||
|
||||
return agendaItems;
|
||||
})
|
|
@ -6,6 +6,8 @@
|
|||
title,
|
||||
description,
|
||||
location,
|
||||
color:int,
|
||||
calName,
|
||||
allDay: bool,
|
||||
}
|
||||
*/
|
||||
|
@ -24,19 +26,23 @@ var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4";
|
|||
|
||||
//FIXME maybe write the end from GB already? Not durationInSeconds here (or do while receiving?)
|
||||
var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[];
|
||||
var settings = require("Storage").readJSON("agenda.settings.json",true)||{};
|
||||
|
||||
CALENDAR=CALENDAR.sort((a,b)=>a.timestamp - b.timestamp)
|
||||
CALENDAR=CALENDAR.sort((a,b)=>a.timestamp - b.timestamp);
|
||||
|
||||
function getDate(timestamp) {
|
||||
return new Date(timestamp*1000);
|
||||
}
|
||||
function formatDateLong(date, includeDay) {
|
||||
if(includeDay)
|
||||
return Locale.date(date)+" "+Locale.time(date,1);
|
||||
return Locale.time(date,1);
|
||||
function formatDateLong(date, includeDay, allDay) {
|
||||
let shortTime = Locale.time(date,1)+Locale.meridian(date);
|
||||
if(allDay) shortTime = "";
|
||||
if(includeDay || allDay)
|
||||
return Locale.date(date)+" "+shortTime;
|
||||
return shortTime;
|
||||
}
|
||||
function formatDateShort(date) {
|
||||
return Locale.date(date).replace(/\d\d\d\d/,"")+Locale.time(date,1);
|
||||
function formatDateShort(date, allDay) {
|
||||
return Locale.date(date).replace(/\d\d\d\d/,"")+(allDay?
|
||||
"" : Locale.time(date,1)+Locale.meridian(date));
|
||||
}
|
||||
|
||||
var lines = [];
|
||||
|
@ -45,7 +51,7 @@ function showEvent(ev) {
|
|||
if(!ev) return;
|
||||
g.setFont(bodyFont);
|
||||
//var lines = [];
|
||||
if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10)
|
||||
if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10);
|
||||
var titleCnt = lines.length;
|
||||
var start = getDate(ev.timestamp);
|
||||
var end = getDate((+ev.timestamp) + (+ev.durationInSeconds));
|
||||
|
@ -53,22 +59,24 @@ function showEvent(ev) {
|
|||
if (titleCnt) lines.push(""); // add blank line after title
|
||||
if(start.getDay() == end.getDay() && start.getMonth() == end.getMonth())
|
||||
includeDay = false;
|
||||
if(includeDay) {
|
||||
if(includeDay || ev.allDay) {
|
||||
lines = lines.concat(
|
||||
/*LANG*/"Start:",
|
||||
g.wrapString(formatDateLong(start, includeDay), g.getWidth()-10),
|
||||
g.wrapString(formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10),
|
||||
/*LANG*/"End:",
|
||||
g.wrapString(formatDateLong(end, includeDay), g.getWidth()-10));
|
||||
g.wrapString(formatDateLong(end, includeDay, ev.allDay), g.getWidth()-10));
|
||||
} else {
|
||||
lines = lines.concat(
|
||||
g.wrapString(Locale.date(start), g.getWidth()-10),
|
||||
g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay), g.getWidth()-10),
|
||||
g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay), g.getWidth()-10));
|
||||
g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10),
|
||||
g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay, ev.allDay), g.getWidth()-10));
|
||||
}
|
||||
if(ev.location)
|
||||
lines = lines.concat(/*LANG*/"Location"+": ", g.wrapString(ev.location, g.getWidth()-10));
|
||||
if(ev.description)
|
||||
lines = lines.concat("",g.wrapString(ev.description, g.getWidth()-10));
|
||||
if(ev.calName)
|
||||
lines = lines.concat(/*LANG*/"Calendar"+": ", g.wrapString(ev.calName, g.getWidth()-10));
|
||||
lines = lines.concat(["",/*LANG*/"< Back"]);
|
||||
E.showScroller({
|
||||
h : g.getFontHeight(), // height of each menu item in pixels
|
||||
|
@ -89,6 +97,12 @@ function showEvent(ev) {
|
|||
}
|
||||
|
||||
function showList() {
|
||||
//it might take time for GB to delete old events, decide whether to show them grayed out or hide entirely
|
||||
if(!settings.pastEvents) {
|
||||
let now = new Date();
|
||||
//TODO add threshold here?
|
||||
CALENDAR = CALENDAR.filter(ev=>ev.timestamp + ev.durationInSeconds > now/1000);
|
||||
}
|
||||
if(CALENDAR.length == 0) {
|
||||
E.showMessage("No events");
|
||||
return;
|
||||
|
@ -101,24 +115,21 @@ function showList() {
|
|||
g.setColor(g.theme.fg);
|
||||
g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h);
|
||||
if (!ev) return;
|
||||
var isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000;
|
||||
var isPast = false;
|
||||
var x = r.x+2, title = ev.title;
|
||||
var body = formatDateShort(getDate(ev.timestamp))+"\n"+ev.location;
|
||||
var m = ev.title+"\n"+ev.location, longBody=false;
|
||||
var body = formatDateShort(getDate(ev.timestamp),ev.allDay)+"\n"+(ev.location?ev.location:/*LANG*/"No location");
|
||||
if(settings.pastEvents) isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000;
|
||||
if (title) g.setFontAlign(-1,-1).setFont(fontBig)
|
||||
.setColor(isPast ? "#888" : g.theme.fg).drawString(title, x,r.y+2);
|
||||
.setColor(isPast ? "#888" : g.theme.fg).drawString(title, x+4,r.y+2);
|
||||
if (body) {
|
||||
g.setFontAlign(-1,-1).setFont(fontMedium).setColor(isPast ? "#888" : g.theme.fg);
|
||||
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);
|
||||
g.drawString(body, 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
|
||||
if(ev.color) {
|
||||
g.setColor("#"+(0x1000000+Number(ev.color)).toString(16).padStart(6,"0"));
|
||||
g.fillRect(r.x,r.y+4,r.x+3, r.y+r.h-4);
|
||||
}
|
||||
},
|
||||
select : idx => showEvent(CALENDAR[idx]),
|
||||
back : () => load()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "agenda",
|
||||
"name": "Agenda",
|
||||
"version": "0.02",
|
||||
"version": "0.06",
|
||||
"description": "Simple agenda",
|
||||
"icon": "agenda.png",
|
||||
"screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}],
|
||||
|
@ -12,6 +12,8 @@
|
|||
"storage": [
|
||||
{"name":"agenda.app.js","url":"agenda.js"},
|
||||
{"name":"agenda.settings.js","url":"settings.js"},
|
||||
{"name":"agenda.clkinfo.js","url":"agenda.clkinfo.js"},
|
||||
{"name":"agenda.img","url":"agenda-icon.js","evaluate":true}
|
||||
]
|
||||
],
|
||||
"data": [{"name":"agenda.settings.json"}]
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
Bluetooth.println("");
|
||||
Bluetooth.println(JSON.stringify(message));
|
||||
}
|
||||
var settings = require("Storage").readJSON("agenda.settings.json",1)||{};
|
||||
function updateSettings() {
|
||||
require("Storage").writeJSON("agenda.settings.json", settings);
|
||||
}
|
||||
var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[];
|
||||
var mainmenu = {
|
||||
"" : { "title" : "Agenda" },
|
||||
|
@ -32,6 +36,13 @@
|
|||
E.showAlert(/*LANG*/"You are not connected").then(()=>E.showMenu(mainmenu));
|
||||
}
|
||||
},
|
||||
/*LANG*/"Show past events" : {
|
||||
value : !!settings.pastEvents,
|
||||
onchange: v => {
|
||||
settings.pastEvents = v;
|
||||
updateSettings();
|
||||
}
|
||||
},
|
||||
};
|
||||
E.showMenu(mainmenu);
|
||||
})
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{ "id": "agpsdata",
|
||||
"name": "A-GPS Data",
|
||||
"name": "A-GPS Data Downloader App",
|
||||
"shortName":"A-GPS Data",
|
||||
"icon": "agpsdata.png",
|
||||
"version":"0.02",
|
||||
"description": "Download assisted GPS (A-GPS) data directly to your Bangle.js **using Gadgetbridge**",
|
||||
"description": "Once installed, this app allows you to download assisted GPS (A-GPS) data directly to your Bangle.js **via Gadgetbridge on an Android phone** when you run the app. If you just want to upload the latest AGPS data from this app loader, please use the `Assisted GPS Update (AGPS)` app.",
|
||||
"tags": "boot,tool,assisted,gps,agps,http",
|
||||
"allow_emulator":true,
|
||||
"supports": ["BANGLEJS2"],
|
||||
|
|
|
@ -11,4 +11,5 @@
|
|||
0.10: Fix SMS bug
|
||||
0.12: Use default Bangle formatter for booleans
|
||||
0.13: Added Bangle.http function (see Readme file for more info)
|
||||
0.14: Fix timeout of http function not beeing cleaned up
|
||||
0.14: Fix timeout of http function not being cleaned up
|
||||
0.15: Allow method/body/headers to be specified for `http` (needs Gadgetbridge 0.68.0b or later)
|
||||
|
|
|
@ -150,6 +150,9 @@
|
|||
//send the request
|
||||
var req = {t: "http", url:url, id:options.id};
|
||||
if (options.xpath) req.xpath = options.xpath;
|
||||
if (options.method) req.method = options.method;
|
||||
if (options.body) req.body = options.body;
|
||||
if (options.headers) req.headers = options.headers;
|
||||
gbSend(req);
|
||||
//create the promise
|
||||
var promise = new Promise(function(resolve,reject) {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "android",
|
||||
"name": "Android Integration",
|
||||
"shortName": "Android",
|
||||
"version": "0.14",
|
||||
"version": "0.15",
|
||||
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,system,messages,notifications,gadgetbridge",
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
0.01: New App!
|
||||
0.02: Fix bug if image clock wasn't installed
|
||||
0.03: Update to use setUI
|
||||
0.04: Tell clock widgets to hide. Move loadWidgets() so it only runs on
|
||||
startup and not on every draw.
|
||||
|
|
|
@ -87,7 +87,6 @@ if (g.drawImages) {
|
|||
draw();
|
||||
var secondInterval = setInterval(draw,100);
|
||||
// load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
// Stop when LCD goes off
|
||||
Bangle.on('lcdPower',on=>{
|
||||
|
@ -104,3 +103,5 @@ if (g.drawImages) {
|
|||
}
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.loadWidgets();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "animclk",
|
||||
"name": "Animated Clock",
|
||||
"shortName": "Anim Clock",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "An animated clock face using Mark Ferrari's amazing 8 bit game art and palette cycling: http://www.markferrari.com/art/8bit-game-art",
|
||||
"icon": "app.png",
|
||||
"type": "clock",
|
||||
|
|
|
@ -10,4 +10,5 @@
|
|||
week is buffered until date or timezone changes
|
||||
0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users)
|
||||
0.08: fixed calendar weeknumber not shortened to two digits
|
||||
0.09: Use default Bangle formatter for booleans
|
||||
0.09: Use default Bangle formatter for booleans
|
||||
0.10: Use Bangle.setUI({remove:...}) to allow loading the launcher without a full reset on 2v16
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "antonclk",
|
||||
"name": "Anton Clock",
|
||||
"version": "0.09",
|
||||
"version": "0.10",
|
||||
"description": "A clock using the bold Anton font, optionally showing seconds and date in ISO-8601 format.",
|
||||
"readme":"README.md",
|
||||
"icon": "app.png",
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
{
|
||||
"id": "assistedgps",
|
||||
"name": "Assisted GPS Update (AGPS)",
|
||||
"name": "Assisted GPS Updater (AGPS)",
|
||||
"version": "0.03",
|
||||
"description": "Downloads assisted GPS (AGPS) data to Bangle.js 1 or 2 for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.",
|
||||
"description": "Downloads assisted GPS (AGPS) data to Bangle.js for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.",
|
||||
"sortorder": -1,
|
||||
"icon": "app.png",
|
||||
"type": "RAM",
|
||||
"tags": "tool,outdoors,agps",
|
||||
"tags": "tool,outdoors,agps,gps,a-gps",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"custom": "custom.html",
|
||||
"customConnect": true,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
0.01: Create astral clock app
|
||||
0.02: Fixed Whirlpool galaxy RA/DA, larger compass display, fixed moonphase overlapping battery widget
|
||||
0.03: Update to use Bangle.setUI instead of setWatch
|
||||
0.04: Tell clock widgets to hide.
|
||||
|
|
|
@ -767,6 +767,24 @@ function draw() {
|
|||
g.clear();
|
||||
current_moonphase = getMoonPhase();
|
||||
|
||||
Bangle.setUI("clockupdown", btn => {
|
||||
if (btn==0) {
|
||||
if (!processing) {
|
||||
if (!modeswitch) {
|
||||
modeswitch = true;
|
||||
if (mode == "planetary") mode = "extras";
|
||||
else mode = "planetary";
|
||||
}
|
||||
else
|
||||
modeswitch = false;
|
||||
}
|
||||
} else {
|
||||
if (!processing)
|
||||
ready_to_compute = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
@ -799,23 +817,6 @@ Bangle.setGPSPower(1);
|
|||
// Show launcher when button pressed
|
||||
Bangle.setClockMode();
|
||||
|
||||
Bangle.setUI("clockupdown", btn => {
|
||||
if (btn==0) {
|
||||
if (!processing) {
|
||||
if (!modeswitch) {
|
||||
modeswitch = true;
|
||||
if (mode == "planetary") mode = "extras";
|
||||
else mode = "planetary";
|
||||
}
|
||||
else
|
||||
modeswitch = false;
|
||||
}
|
||||
} else {
|
||||
if (!processing)
|
||||
ready_to_compute = true;
|
||||
}
|
||||
});
|
||||
|
||||
setWatch(function () {
|
||||
if (!astral_settings.astral_default) {
|
||||
colours_switched = true;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "astral",
|
||||
"name": "Astral Clock",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "Clock that calculates and displays Alt Az positions of all planets, Sun as well as several other astronomy targets (customizable) and current Moon phase. Coordinates are calculated by GPS & time and onscreen compass assists orienting. See Readme before using.",
|
||||
"icon": "app-icon.png",
|
||||
"type": "clock",
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
0.02: Add sit ups
|
||||
Add more feedback to the user about the exercises
|
||||
Clean up code
|
||||
0.03: Add software back button on main menu
|
||||
|
|
|
@ -71,7 +71,8 @@ function showMainMenu() {
|
|||
let menu;
|
||||
menu = {
|
||||
"": {
|
||||
title: "BanglExercise"
|
||||
title: "BanglExercise",
|
||||
back: load
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -381,4 +382,5 @@ Bangle.on('HRM', function(hrm) {
|
|||
});
|
||||
|
||||
g.clear(1);
|
||||
Bangle.loadWidgets();
|
||||
showMainMenu();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "banglexercise",
|
||||
"name": "BanglExercise",
|
||||
"shortName":"BanglExercise",
|
||||
"version":"0.02",
|
||||
"version":"0.03",
|
||||
"description": "Can automatically track exercises while wearing the Bangle.js watch.",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
|
|
|
@ -7,3 +7,4 @@
|
|||
0.07: Step count resets at midnight
|
||||
0.08: Step count stored in memory to survive reloads. Now shows step count daily and since last reboot.
|
||||
0.09: NOW it really should reset daily (instead of every other day...)
|
||||
0.10: Tell clock widgets to hide.
|
||||
|
|
|
@ -416,13 +416,13 @@ var layout = new Layout( {
|
|||
|
||||
// Clear the screen once, at startup
|
||||
g.clear();
|
||||
Bangle.setUI("clock");
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
Bangle.setUI("clock");
|
||||
layout.render();
|
||||
|
||||
Bangle.on('lock', function(locked) {
|
||||
if(!locked) {
|
||||
layout.render();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "Barcode clock",
|
||||
"shortName":"Barcode clock",
|
||||
"icon": "barcode.icon.png",
|
||||
"version":"0.09",
|
||||
"version":"0.10",
|
||||
"description": "EAN-8 compatible barcode clock.",
|
||||
"tags": "barcode,ean,ean-8,watchface,clock,clockface",
|
||||
"type": "clock",
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.01: App Created!
|
||||
0.02: Update to use Bangle.setUI instead of setWatch
|
||||
0.03: Tell clock widgets to hide.
|
||||
|
|
|
@ -249,6 +249,9 @@ g.clear();
|
|||
g.setColor(0, 0.5, 0).drawImage(bg_crack);
|
||||
g.setColor(1, 1, 1).drawImage(batman);
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
|
@ -256,5 +259,3 @@ Bangle.drawWidgets();
|
|||
timeInterval = setInterval(showTime, 1000);
|
||||
showTime();
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "batclock",
|
||||
"name": "Bat Clock",
|
||||
"shortName": "Bat Clock",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.",
|
||||
"icon": "bat-clock.png",
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
0.02: Modified for use with new bootloader and firmware
|
||||
0.03: Update to use Bangle.setUI instead of setWatch
|
||||
0.04: Tell clock widgets to hide.
|
||||
|
|
|
@ -100,10 +100,12 @@ Bangle.on('lcdPower', on => {
|
|||
if (on) drawClock();
|
||||
});
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
setInterval(() => { drawClock(); }, 1000);
|
||||
drawClock();
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "bclock",
|
||||
"name": "Binary Clock",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "A simple binary clock watch face",
|
||||
"icon": "clock-binary.png",
|
||||
"type": "clock",
|
||||
|
|
|
@ -3,3 +3,5 @@
|
|||
0.03: Internationalisation; bug fix - battery icon responds promptly to charging state
|
||||
0.04: bug fix
|
||||
0.05: proper fix for the race condition in queueDraw()
|
||||
0.06: Tell clock widgets to hide.
|
||||
0.07: Better battery graphic - now has green, yellow and red sections; battery status reflected in the bar across the middle of the screen; current battery state checked only once every 15 minutes, leading to longer-lasting battery charge
|
||||
|
|
|
@ -11,6 +11,8 @@ Graphics.prototype.setFontOpenSans = function(scale) {
|
|||
};
|
||||
|
||||
var drawTimeout;
|
||||
var lastBattCheck = 0;
|
||||
var width = 0;
|
||||
|
||||
function queueDraw(millis_now) {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
|
@ -24,12 +26,15 @@ function draw() {
|
|||
var date = new Date();
|
||||
var h = date.getHours(),
|
||||
m = date.getMinutes();
|
||||
var d = date.getDate(),
|
||||
w = date.getDay(); // d=1..31; w=0..6
|
||||
const level = E.getBattery();
|
||||
const width = level + (level/2);
|
||||
var d = date.getDate();
|
||||
var is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"];
|
||||
var dows = require("date_utils").dows(0,1);
|
||||
var dow = require("date_utils").dows(0,1)[date.getDay()];
|
||||
|
||||
if ((date.getTime() >= lastBattCheck + 15*60000) || Bangle.isCharging()) {
|
||||
lastBattcheck = date.getTime();
|
||||
width = E.getBattery();
|
||||
width += width/2;
|
||||
}
|
||||
|
||||
g.reset();
|
||||
g.clear();
|
||||
|
@ -47,24 +52,35 @@ function draw() {
|
|||
g.drawString(d, g.getWidth() -6, 98);
|
||||
g.setFont('Vector', 52);
|
||||
g.setFontAlign(-1, -1);
|
||||
g.drawString(dows[w].slice(0,2).toUpperCase(), 6, 103);
|
||||
g.drawString(dow.slice(0,2).toUpperCase(), 6, 103);
|
||||
|
||||
g.fillRect(9,159,166,171);
|
||||
g.fillRect(167,163,170,167);
|
||||
if (Bangle.isCharging()) {
|
||||
g.setColor(1,1,0);
|
||||
} else if (level > 40) {
|
||||
g.setColor(0,1,0);
|
||||
g.fillRect(12,162,12+width,168);
|
||||
} else {
|
||||
g.setColor(1,0,0);
|
||||
g.fillRect(12,162,57,168);
|
||||
g.setColor(1,1,0);
|
||||
g.fillRect(58,162,72,168);
|
||||
g.setColor(0,1,0);
|
||||
g.fillRect(73,162,162,168);
|
||||
}
|
||||
g.fillRect(12,162,12+width,168);
|
||||
if (level < 100) {
|
||||
if (width < 150) {
|
||||
g.setColor(g.theme.bg);
|
||||
g.fillRect(12+width+1,162,162,168);
|
||||
}
|
||||
|
||||
g.setColor(0, 1, 0);
|
||||
if (Bangle.isCharging()) {
|
||||
g.setColor(1,1,0);
|
||||
} else if (width <= 45) {
|
||||
g.setColor(1,0,0);
|
||||
} else if (width <= 60) {
|
||||
g.setColor(1,1,0);
|
||||
} else {
|
||||
g.setColor(0, 1, 0);
|
||||
}
|
||||
g.fillRect(0, 90, g.getWidth(), 94);
|
||||
|
||||
// widget redraw
|
||||
|
@ -85,7 +101,8 @@ Bangle.on('charging', (charging) => {
|
|||
draw();
|
||||
});
|
||||
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.loadWidgets();
|
||||
draw();
|
||||
|
||||
Bangle.setUI("clock");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "bigdclock",
|
||||
"name": "Big digit clock containing just the essentials",
|
||||
"shortName":"Big digit clk",
|
||||
"version":"0.05",
|
||||
"version":"0.07",
|
||||
"description": "A clock containing just the essentials, made as easy to read as possible for those of us that need glasses. It contains the time, the day-of-week, the day-of-month, and the current battery state-of-charge.",
|
||||
"icon": "bigdclock.png",
|
||||
"type": "clock",
|
||||
|
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
@ -1,3 +1,4 @@
|
|||
0.01: New App!
|
||||
0.02: Fixed bug where screen didn't clear so incorrect time displayed.
|
||||
0.03: Update to use Bangle.setUI instead of setWatch
|
||||
0.04: Tell clock widgets to hide.
|
||||
|
|
|
@ -164,9 +164,6 @@ Bangle.on('lcdPower',on=>{
|
|||
draw(); // draw immediately
|
||||
}
|
||||
});
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clockupdown", btn=>{
|
||||
if (btn!=1) return;
|
||||
|
@ -176,3 +173,6 @@ Bangle.setUI("clockupdown", btn=>{
|
|||
displayTime = 0;
|
||||
}
|
||||
});
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "binclock",
|
||||
"name": "Binary Clock",
|
||||
"shortName": "Binary Clock",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.",
|
||||
"icon": "app.png",
|
||||
"type": "clock",
|
||||
|
|
|
@ -2,3 +2,5 @@
|
|||
0.02: first running version for BangleJs2
|
||||
0.03: corrected icon, added screen shot, extended description
|
||||
0.04: corrected format of background image (raw binary)
|
||||
0.05: move setUI() up before draw() as to not have a false positive 'sanity
|
||||
check' when building on github.
|
||||
|
|
|
@ -334,6 +334,7 @@ function setRuntimeValues(resolution) {
|
|||
var hour = 0, minute = 1, second = 50;
|
||||
var batVLevel = 20;
|
||||
|
||||
Bangle.setUI("clock");
|
||||
|
||||
function draw() {
|
||||
var d = new Date();
|
||||
|
@ -371,7 +372,6 @@ function draw() {
|
|||
}
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
setRuntimeValues(g.getWidth());
|
||||
g.reset().clear();
|
||||
Bangle.loadWidgets();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"shortName":"BinWatch",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
"version":"0.04",
|
||||
"version":"0.05",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator":true,
|
||||
|
|
|
@ -5,3 +5,4 @@
|
|||
0.04: Modified to account for changes in the behavior of Graphics.fillPoly
|
||||
0.05: Slight increase to draw speed after LCD on
|
||||
0.06: Update to use Bangle.setUI instead of setWatch, allow themes and different size screens
|
||||
0.07: Tell clock widgets to hide.
|
||||
|
|
|
@ -99,6 +99,10 @@ function startTimers() {
|
|||
Bangle.drawWidgets();
|
||||
intervalRef = setInterval(redraw,1000);
|
||||
}
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.loadWidgets();
|
||||
startTimers();
|
||||
Bangle.on('lcdPower',function(on) {
|
||||
|
@ -108,5 +112,3 @@ Bangle.on('lcdPower',function(on) {
|
|||
clearTimers();
|
||||
}
|
||||
});
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "blobclk",
|
||||
"name": "Large Digit Blob Clock",
|
||||
"shortName": "Blob Clock",
|
||||
"version": "0.06",
|
||||
"version": "0.07",
|
||||
"description": "A clock with big digits",
|
||||
"icon": "clock-blob.png",
|
||||
"type": "clock",
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
0.04: Work with themes, smaller screens
|
||||
0.05: Adjust hand lengths to be within 'tick' points
|
||||
0.06: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up".
|
||||
0.07: Tell clock widgets to hide.
|
||||
|
|
|
@ -130,9 +130,10 @@ Bangle.on('lcdPower', (on) => {
|
|||
}
|
||||
});
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
startTimers();
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "boldclk",
|
||||
"name": "Bold Clock",
|
||||
"version": "0.06",
|
||||
"version": "0.07",
|
||||
"description": "Simple, readable and practical clock",
|
||||
"icon": "bold_clock.png",
|
||||
"screenshots": [{"url":"screenshot_bold.png"}],
|
||||
|
|
|
@ -10,4 +10,14 @@
|
|||
0.10: HomeAssistant integration if HomeAssistant is installed.
|
||||
0.11: Performance improvements.
|
||||
0.12: Implements a 2D menu.
|
||||
0.13: Clicks < 24px are for widgets, if fullscreen mode is disabled.
|
||||
0.13: Clicks < 24px are for widgets, if fullscreen mode is disabled.
|
||||
0.14: Adds humidity to weather data.
|
||||
0.15: Added option for a dynamic mode to show widgets only if unlocked.
|
||||
0.16: You can now show your agenda if your calendar is synced with Gadgetbridge.
|
||||
0.17: Fix - Step count was no more shown in the menu.
|
||||
0.18: Set timer for an agenda entry by simply clicking in the middle of the screen. Only one timer can be set.
|
||||
0.19: Fix - Compatibility with "Digital clock widget"
|
||||
0.20: Better handling of async data such as getPressure.
|
||||
0.21: On the default menu the week of year can be shown.
|
||||
0.22: Use the new clkinfo module for the menu.
|
||||
0.23: Feedback of apps after run is now optional and decided by the corresponding clkinfo.
|
|
@ -1,46 +1,49 @@
|
|||
# BW Clock
|
||||
A very minimalistic clock with date and time in focus.
|
||||
A very minimalistic clock.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
The BW clock provides many features as well as 3rd party integrations:
|
||||
The BW clock implements features that are exposed by other apps through the `clkinfo` module.
|
||||
For example, if you install the HomeAssistant app, this menu item will be shown if you click right
|
||||
and additionally allows you to send triggers directly from the clock (select triggers via up/down and
|
||||
send via click center). Here are examples of other apps that are integrated:
|
||||
|
||||
- Bangle data such as steps, heart rate, battery or charging state.
|
||||
- A timer can be set directly. *Requirement: Scheduler library*
|
||||
- Show agenda entries. A timer for an agenda entry can also be set by simply clicking in the middle of the screen. This can be used to not forget a meeting etc. Note that only one agenda-timer can be set at a time. *Requirement: Gadgetbridge calendar sync enabled*
|
||||
- Weather temperature as well as the wind speed can be shown. *Requirement: Weather app*
|
||||
- HomeAssistant triggers can be executed directly. *Requirement: HomeAssistant app*
|
||||
|
||||
Note: If some apps are not installed (e.gt. weather app), then this menu item is hidden.
|
||||
|
||||
## Menu
|
||||
2D menu allows you to display lots of different data including data from 3rd party apps and it's also possible to control things e.g. to set a timer or send a HomeAssistant trigger.
|
||||
|
||||
Simply click left / right to go through the menu entries such as Bangle, Timer etc.
|
||||
and click up/down to move into this sub-menu. You can then click in the middle of the screen
|
||||
to e.g. send a trigger via HomeAssistant once you selected it.
|
||||
|
||||
```
|
||||
+5min
|
||||
|
|
||||
Bangle -- Timer[Optional] -- Weather[Optional] -- HomeAssistant [Optional]
|
||||
| | | |
|
||||
Bpm -5min Temperature Trigger1
|
||||
| | |
|
||||
Steps ... ...
|
||||
|
|
||||
Battery
|
||||
```
|
||||
|
||||
## Settings
|
||||
- Fullscreen on/off (widgets are still loaded).
|
||||
- Enable/disable lock icon in the settings. Useful if fullscreen is on.
|
||||
- Screen: Normal (widgets shown), Dynamic (widgets shown if unlocked) or Full (widgets are hidden).
|
||||
- Enable/disable lock icon in the settings. Useful if fullscreen mode is on.
|
||||
- The colon (e.g. 7:35 = 735) can be hidden in the settings for an even larger time font to improve readability further.
|
||||
- There are no design settings, as your bangle sys settings are used.
|
||||
- Your bangle uses the sys color settings so you can change the color too.
|
||||
|
||||
## Menu structure
|
||||
2D menu allows you to display lots of different data including data from 3rd party apps and it's also possible to control things e.g. to trigger HomeAssistant.
|
||||
|
||||
Simply click left / right to go through the menu entries such as Bangle, Weather etc.
|
||||
and click up/down to move into this sub-menu. You can then click in the middle of the screen
|
||||
to e.g. send a trigger via HomeAssistant once you selected it. The actions really depend
|
||||
on the app that provide this sub-menu through the `clkinfo` module.
|
||||
|
||||
```
|
||||
Bangle -- Agenda -- Weather -- HomeAssistant
|
||||
| | | |
|
||||
Battery Entry 1 Temperature Trigger1
|
||||
| | | |
|
||||
Steps ... ... ...
|
||||
|
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
## Thanks to
|
||||
<a href="https://www.flaticon.com/free-icons/" title="Icons">Icons created by Flaticon</a>
|
||||
|
||||
- Thanks to Gordon Williams not only for the great BangleJs, but specifically also for the implementation of `clkinfo` which simplified the BWClock a lot and moved complexety to the apps where it should be located.
|
||||
- <a href="https://www.flaticon.com/free-icons/" title="Icons">Icons created by Flaticon</a>
|
||||
|
||||
## Creator
|
||||
[David Peer](https://github.com/peerdavid)
|
||||
|
|
|
@ -1,22 +1,25 @@
|
|||
/************
|
||||
/************************************************
|
||||
* Includes
|
||||
*/
|
||||
const locale = require('locale');
|
||||
const storage = require('Storage');
|
||||
const clock_info = require("clock_info");
|
||||
|
||||
/************
|
||||
* Statics
|
||||
|
||||
/************************************************
|
||||
* Globals
|
||||
*/
|
||||
const SETTINGS_FILE = "bwclk.setting.json";
|
||||
const TIMER_IDX = "bwclk";
|
||||
const W = g.getWidth();
|
||||
const H = g.getHeight();
|
||||
var lock_input = false;
|
||||
|
||||
/************
|
||||
|
||||
/************************************************
|
||||
* Settings
|
||||
*/
|
||||
let settings = {
|
||||
fullscreen: false,
|
||||
screen: "Normal",
|
||||
showLock: true,
|
||||
hideColon: false,
|
||||
menuPosX: 0,
|
||||
|
@ -28,22 +31,10 @@ for (const key in saved_settings) {
|
|||
settings[key] = saved_settings[key]
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
/************************************************
|
||||
* Assets
|
||||
*/
|
||||
// Manrope font
|
||||
Graphics.prototype.setXLargeFont = function(scale) {
|
||||
// Actual height 53 (55 - 3)
|
||||
this.setFontCustom(
|
||||
E.toString(require('heatshrink').decompress(atob('AHM/8AIG/+AA4sD/wQGh/4EWQA/AC8YA40HNA0BRY8/RY0P/6LFgf//4iFA4IiFj4HBEQkHCAQiDHIIZGv4HCFQY5BDAo5CAAIpDDAfACA3wLYv//hsFKYxcCMgoiBOooiBQwwiBS40AHIgA/ACS/DLYjYCBAjQEBAYQDBAgHDUAbyDZQi3CegoHEVQQZFagUfW4Y0DaAgECaIJSEFYMPbIYNDv5ACGAIrBCgJ1EFYILCAAQWCj4zDGgILCegcDEQRNDHIIiCHgZ2BEQShFIqUDFYidCh5ODg4NCn40DAgd/AYR5BDILZEAAIMDAAYVCh7aHdYhKDbQg4Dv7rGBAihFCAwIDCAgA/AB3/eoa7GAAk/dgbVGDJrvCDK67DDIjaGdYpbCdYonCcQjjDEVUBEQ4A/AEMcAYV/NAUHcYUDawd/cYUPRYSmBBgaLBToP8BgYiBSgIiCj4iCg//EQSuDW4IMDVwYiCBgIiBBgrRDCATeBaIYqCv70DCgT4CEQMfIgQZBBoRnDv/3EQIvBDIffEQMHFwReBRYUfOgX/+IiDKIeHEQRRECwUHKwIuB8AiDIoJEBCwZFCv/4HIZaBIgPAEQS2CUYQiCD4SABEQcfOwIZBEQaHBO4RcEAAI/BEQQgBSIQiDTIRZBEQZuBVYQiDHoKWCEQQICFQIiDBAQeCEQQA/AANwA40BLIJ5BO4JWCBAUPAYR5En7RBUIQECN4SYCQQIiEh6CCEQk/BoQiBgYeCBoTrCAgT0CCgIfCFYQiBg4IBGgIiDj6rBg4rCBYLRDFYIiBbYIfBLgQiBIQYiD4JCCLgf/bQIWDBYV/EQV/BYXz/5FBgIiD5//IowZBD4M/NAX/BIPgDIJoC//5GgKUDn//4f/8KLE/wTBAAI8BEQPwj4HBVwYmBDgIZDN4QZCGYKJCHQP/JoSgCBATrCh5dBKITVDG4gICAAbvDAH5SCL4QADK4J5CCAiTCCAp1BCAqCDCAgiGCAIiFCAQiFeoIiFg6/FCAgiECAXnEQgQB/kfEQYQC4F/EQYQCgIiDfoIQBg4iDCAUAEQZUCcgIiDDIIQBEQhuBBoIiENoYiFDwQiECAQiFwEBPQQNCAQKDDEYMDDoMfRh4iGUwqvEESBiBaQ5oEbgr0FNAo+EEIwA+oAHGgJoFRAMHe4L0CAALNBBAT0BfwScDCAXweAL0DWgUPQYQiDwF/QYQiC/zTB+C0FBAL0CEQYIBGgMPCgIxBg4rCJIKsCh5IBBwTPCj4WBgYLBZ4V/MAIiBBQQrBEQYtCBYQiCO4QLFCwgiDIQIiGIoMHEQpFBn5FFD4JoENwRoGDgSUCAoKfBw//DgIiCT4auCFwN/T4RRET4TaCEQKoCDIQiCGgK/DAAQICdYQACHoIqCBAoQFEwIhFAH4AFQIROEj4IGXwIIGNwIACbgIhEBAiRCVwoqDTogHEW4QZFXgIZB/z9Cv49CF4MPBwI0Ca4LlB8ATCJoP4AoINDfQPAg7PBg4cBBwUfD4MfFYILCCwgOCf4QLEwEPCwILCgJaBn4WBBYQxCIQQiD+EDCYI5CBYRQBIo4fBMQIuBC4N/NAv8AoIcBSgU/FYIIBZIYrCW4hOCXIQZCgYUBv7jEh4uBZAscewZ8CgEgUYT0EEoQIBA4gICFQQIEHYQA+KQzdDAArdCAArpCEScHaIQiEvwiGe4QiFUwQiEbgIiFYIL0DEQTkBEQrJEEQc/cYYiCg4HBDIQiCfoRoEHQLaDEQQHBbQYiBCAT8Dn/BCAoXBJYP/OgZKC/6OEEARLCEQZLEEQZLEEQjKFEQI6EEQZLDEQbsGEQLjGYYYA/JIxzEg/AfgJSDAoPgfgiDC8COFAoPnaQj6CAAR+CW4TCFA4i6CDIqhCDIfwHoYHCYIN/GgKuBJ4JDBFYUf/C5CBYIZBv/Ag4ZBg4rBBYQTBAQIcBg4FBn5UBAQUfFwIfCEQeAgYfBAQUBFAKbCAQQiCGwIiE+A2BwBFNwE/AoM/EQJoIWwKCCh4cBFYKUERYV/W46uHFYIZGaJA0B/glBGYT0JIITiEMIJvCFQQAEHYQA/ABBlEOIhdGQAIRFSgQIBgQICn4IB8EAjiBCUYglCbQYeBEoQZCTwM/CYIZD/gEBUwIzBJ4UHYAU/EwIrBh4rCAoIXCn4rBCgUDAQN/FYMfBYIXBCYJnCBYXggf8HgQLCwEPEQQuBgJOECwILDCwgiLHIUHBYJFGD4IxBgYWCn4rBBwJoFDIYNBCgPADgKHBRYfDBQN/GAIrBToTLDVwYACDILiCWAb8DAAYzBYAjTCAAI9BAARNCBAoqCBAgQDFgbYCAH4AufgQACf4T8CAAT/CfgQACBwITCAAYOBCYQioh4iEAHQA=='))),
|
||||
46,
|
||||
atob("FR4uHyopKyksJSssGA=="),
|
||||
70+(scale<<8)+(1<<16)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Graphics.prototype.setLargeFont = function(scale) {
|
||||
// Actual height 47 (48 - 2)
|
||||
this.setFontCustom(
|
||||
|
@ -55,14 +46,12 @@ Graphics.prototype.setLargeFont = function(scale) {
|
|||
return this;
|
||||
};
|
||||
|
||||
|
||||
Graphics.prototype.setMediumFont = function(scale) {
|
||||
// Actual height 41 (42 - 2)
|
||||
this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAB/AAAAAAAP/AAAAAAD//AAAAAA///AAAAAP///AAAAB///8AAAAf///AAAAH///wAAAB///+AAAAH///gAAAAH//4AAAAAH/+AAAAAAH/wAAAAAAH8AAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAH////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gAAH+AAD+AAAD/AAH8AAAB/AAH4AAAA/gAH4AAAAfgAH4AAAAfgAPwAAAAfgAPwAAAAfgAPwAAAAfgAHwAAAAfgAH4AAAAfgAH4AAAA/gAH8AAAA/AAD+AAAD/AAD/gAAH/AAB/////+AAB/////8AAA/////4AAAf////wAAAH////gAAAB///+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAAAAfwAAAAAAA/gAAAAAAA/AAAAAAAB/AAAAAAAD+AAAAAAAD8AAAAAAAH8AAAAAAAH//////AAH//////AAH//////AAH//////AAH//////AAH//////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4AAA/AAAP4AAB/AAAf4AAD/AAA/4AAD/AAB/4AAH/AAD/4AAP/AAH/AAAf/AAH8AAA//AAH4AAB//AAP4AAD//AAPwAAH+/AAPwAAP8/AAPwAAf4/AAPwAA/4/AAPwAA/w/AAPwAB/g/AAPwAD/A/AAP4AH+A/AAH8AP8A/AAH/A/4A/AAD///wA/AAD///gA/AAB///AA/AAA//+AA/AAAP/8AA/AAAD/wAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAH4AAAHwAAH4AAAH4AAH4AAAH8AAH4AAAP+AAH4AAAH+AAH4A4AB/AAH4A+AA/AAH4B/AA/gAH4D/AAfgAH4H+AAfgAH4P+AAfgAH4f+AAfgAH4/+AAfgAH5/+AAfgAH5//AAfgAH7+/AA/gAH/8/gB/AAH/4f4H/AAH/wf//+AAH/gP//8AAH/AH//8AAH+AD//wAAH8AB//gAAD4AAf+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAAAAD/AAAAAAAP/AAAAAAB//AAAAAAH//AAAAAAf//AAAAAB///AAAAAH///AAAAAf/8/AAAAB//w/AAAAH/+A/AAAA//4A/AAAD//gA/AAAH/+AA/AAAH/4AA/AAAH/gAA/AAAH+AAA/AAAHwAAA/AAAHAAf///AAEAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAP/AHgAAH///AP4AAH///gP8AAH///gP8AAH///gP+AAH///gD/AAH/A/AB/AAH4A/AA/gAH4A+AAfgAH4B+AAfgAH4B+AAfgAH4B8AAfgAH4B8AAfgAH4B+AAfgAH4B+AAfgAH4B+AA/gAH4B/AA/AAH4A/gD/AAH4A/4H+AAH4Af//+AAH4AP//8AAH4AP//4AAHwAD//wAAAAAB//AAAAAAAf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAD////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gP4H+AAD/AfgD/AAH8A/AB/AAH8A/AA/gAH4B+AAfgAH4B+AAfgAPwB8AAfgAPwB8AAfgAPwB+AAfgAPwB+AAfgAH4B+AAfgAH4B/AA/gAH8B/AB/AAH+A/wD/AAD+A/8P+AAB8Af//+AAB4AP//8AAAwAH//4AAAAAD//gAAAAAA//AAAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAHAAPwAAAA/AAPwAAAD/AAPwAAAf/AAPwAAB//AAPwAAP//AAPwAA//8AAPwAH//wAAPwAf/+AAAPwB//4AAAPwP//AAAAPw//8AAAAP3//gAAAAP//+AAAAAP//wAAAAAP//AAAAAAP/4AAAAAAP/gAAAAAAP+AAAAAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAAAH+A//gAAAf/h//4AAA//z//8AAB/////+AAD/////+AAD///+H/AAH+H/4B/AAH8B/wA/gAH4A/gAfgAH4A/gAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAH4A/gAfgAH4A/gAfgAH8B/wA/gAH/H/4B/AAD///+H/AAD/////+AAB/////+AAA//z//8AAAf/h//4AAAH+A//gAAAAAAH+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAD/8AAAAAAP/+AAAAAAf//AAcAAA///gA8AAB///wB+AAD/x/4B/AAD+AP4B/AAH8AH8A/gAH4AH8A/gAH4AD8AfgAP4AD8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAH4AD8AfgAH4AD4A/gAH8AH4B/AAD+APwD/AAD/g/wP+AAB/////+AAA/////8AAAf////4AAAP////wAAAH////AAAAA///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DxcjFyAfISAiHCAiEg=="), 54+(scale<<8)+(1<<16));
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
Graphics.prototype.setSmallFont = function(scale) {
|
||||
// Actual height 28 (27 - 0)
|
||||
this.setFontCustom(
|
||||
|
@ -74,6 +63,16 @@ Graphics.prototype.setSmallFont = function(scale) {
|
|||
return this;
|
||||
};
|
||||
|
||||
Graphics.prototype.setMiniFont = function(scale) {
|
||||
// Actual height 16 (15 - 0)
|
||||
this.setFontCustom(
|
||||
atob('AAAAAAAAAAAAAP+w/5AAAAAA4ADgAOAA4AAAAAAAAAABgBmAGbAb8D+A+YDZ8B/wf4D5gJmAGQAQAAAAAAAeOD8cMwzxj/GPMYwc/Az4AAAAAHAA+DDIYMjA+YBzAAYADeA7MHMw4zDD4ADAAAAz4H/wzjDHMMMwwbBj4APgADAAAAAA4ADgAAAAAAAAAAfwH/54B+ABAAAAAOABeAcf/gfwAAAAACAAaAD4APgAOABgAAAAAAACAAIAAgA/wAMAAgACAAAAAAAAPAA4AAAAAAIAAgACAAIAAgAAAAAAADAAMAAAAAAAcAfwf4D4AIAAAAA/wH/gwDDAMMAwwDB/4D/AAAAAAGAAwAD/8P/wAAAAAHAw8HDA8MHww7DnMH4wGBAAAMBgyHDcMPww/DDv4MfAAAAAAAHgD+A+YPhgwGAH8AfwAEAAAAAA/GD8cMwwzDDMMM5wx+ABgAAAP8B/4MwwzDDMMMwwx+ADwAAAgADAAMBwwfDPgP4A8ADAAAAAe+D/8M4wxjDGMP5wf+ABwAAAfAB+cMYwwjDCMMYwf+A/wAAAAAAAAAxgBCAAAAAAAAAYPBA4AAAAAAAAAgAHAA+AHMAYYAAAAAAAAAAAAAAJAAkACQAJAAkACQAJAAkAAAAAAAAAAAAAABhgHMAPgAcAAgAAAAAAAABgAOAAwbDDsMYA/AA4AAAAAAAD4A/wGBgxzDPsMyQjJDPkM+wYIBxgD+AAAAAAABAA8A/gf8DwwODA/sAfwAHwADAAAP/w//DGMMYwxjDOMP9we+ABwA8AP8Bw4MAwwDDAMMAwwDDgcHDgMMAAAAAA//D/8MAwwDDAMMAw4HB/4D/AAAAAAP/w//DGMMYwxjDGMMQwgBAAAP/w//DDAMMAwwDDAMAADwA/wHDgwDDAMMAwwDDCMOJwc+ADwAAA//D/8AMAAwADAAMAAwD/8P/wAAAAAP/w//AAAABgAHAAMAAwAHD/4P+AAAAAAP/w//AOAB+AOcBw4MBwgDAAEAAA//D/8AAwADAAMAAwADAAAP/w//A8AA8AA+AA8AHwB8AeAHgA//D/8AAAAAD/8P/wcAAcAA8AA4AB4P/w//AAAA8AP8Bw4MAwwDDAMMAwwDDgcH/gP8AAAAAA//D/8MMAwwDDAMYA7gB8ABgADwA/wHDgwDDAMMAwwDDA8ODwf/A/8AAAAAD/8P/wwwDDAMMAx4Dv4HxwEBAAAHjg/HDMMMYwxjDGMONwc+ABwMAAwADAAMAA//D/8MAAwADAAIAAAAD/wP/gAHAAMAAwADAAMAHg/8AAAMAA+AA/AAfgAPAA8AfgPwD4AMAAwAD4AD+AA/AA8A/g/gDwAP4AH8AB8APwH8D8AMAAgBDAMPDgO8APAB8AOcDw8MAwgBCAAOAAeAAeAAfwH/B4AOAAwAAAAMAwwPDB8Mew3jD4MPAwwDAAAAAAAAB//3//QABAAAAAAADgAP4AH+AB8AAQAABAAEAAf/9//wAAAAAAAAAAGAAwAGAAwABgADAAGAAAAAAAAAQABAAEAAQABAAEAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAAAAAQA3wHbAZMBswGzAf4A/wAAAAAP/w//AYMBgwGDAYMA/gB8AAAAEAD+Ae8BgwGDAYMBgwDGAAAAMAD+Ae8BgwGDAYMBhw//D/8AAAAYAP4B/wGTAZMBkwGTAP4AcAEAAYAP/w//CQAJAAAwAP4hz3GDMQMxAzGHcf/h/8AAAAAP/w//AYABgAGAAYAA/wB/AAAAAA3/Df8AAAAAOf/9//AAAAAP/w//ADgAfADGAYMBAQAAD/8P/wAAAAAB/wH/AYABgAGAAf8A/wGAAYABgAH/AP8AAAAAAf8B/wGAAYABgAGAAP8AfwAAADAA/gHvAYMBgwGDAYMA/gB8AAAAAAH/8f/xgwGDAYMBgwD+AHwAAAAwAP4B7wGDAYMBgwGHAf/x//AAAAAB/wH/AYABgAEAAAAA5gHzAbMBkwGbAd8AzgEAAYAP/wf/AQMBAwAAAAAB/gH/AAMAAwADAAcB/wH/AAABAAHgAPwAHwAPAH4B8AGAAQAB8AB+AA8APwHwAeAA/AAPAD8B+AHAAQEBgwHOAHwAOAD+AccBAwAAAQAB4AD4EB/wB8A/APgBwAAAAAEBgwGPAZ8B8wHjAcMBAQAAAAAABgf/9/n2AAAAAAAP/w//AAAEAAYAB/nz//AGAAAAAAAAAAAAcABgAGAAcAAwAHAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'),
|
||||
32,
|
||||
atob("AwUHDwoOCwQHBwcJBAcEBgoGCQkKCQoICQoFBQoMCgkPCgoMCwkICwsECAoIDgsMCgwKCgoLCg8KCQoHBgcLCwgJCgkKCQYKCgQECAQOCgoKCgYIBwoIDAkJCAcEBwsQ"),
|
||||
16+(scale<<8)+(1<<16)
|
||||
);
|
||||
return this;
|
||||
};
|
||||
|
||||
function imgLock(){
|
||||
return {
|
||||
|
@ -83,279 +82,100 @@ function imgLock(){
|
|||
}
|
||||
}
|
||||
|
||||
function imgSteps(){
|
||||
return {
|
||||
width : 24, height : 24, bpp : 1,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("/H///wv4CBn4CD8ACCj4IBj8f+Eeh/wjgCBngCCg/4nEH//4h/+jEP/gRBAQX+jkf/wgB//8GwP4FoICDHgICCBwIA=="))
|
||||
}
|
||||
}
|
||||
|
||||
function imgBattery(){
|
||||
return {
|
||||
width : 24, height : 24, bpp : 1,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("/4AN4EAg4TBgd///9oEAAQv8ARQRDDQQgCEwQ4OA"))
|
||||
}
|
||||
}
|
||||
|
||||
function imgCharging() {
|
||||
return {
|
||||
width : 24, height : 24, bpp : 1,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("//+v///k///4AQPwBANgBoMxBoMb/P+h/w/kH8H4gfB+EBwfggHH4EAt4CBn4CBj4CBh4FCCIO/8EB//Agf/wEH/8Gh//x////fAQIA="))
|
||||
}
|
||||
}
|
||||
|
||||
function imgBpm() {
|
||||
return {
|
||||
width : 24, height : 24, bpp : 1,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("/4AOn4CD/wCCjgCCv/8jF/wGYgOA5MB//BC4PDAQnjAQPnAQgANA"))
|
||||
}
|
||||
}
|
||||
|
||||
function imgTemperature() {
|
||||
return {
|
||||
width : 24, height : 24, bpp : 1,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("//D///wICBjACBngCNkgCP/0kv/+s1//nDn/8wICEBAIOC/08v//IYJECA=="))
|
||||
}
|
||||
}
|
||||
|
||||
function imgWeather(){
|
||||
return {
|
||||
width : 24, height : 24, bpp : 1,
|
||||
transparent : 0,
|
||||
buffer : require("heatshrink").decompress(atob("AAcYAQ0MgEwAQUAngLB/8AgP/wACCgf/4Fz//OAQQICCIoaCEAQpGHA4ACA="))
|
||||
}
|
||||
}
|
||||
|
||||
function imgWind () {
|
||||
return {
|
||||
width : 24, height : 24, bpp : 1,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("/0f//8h///Pn//zAQXzwf/88B//mvGAh18gEevn/DIICB/PwgEBAQMHBAIADFwM/wEAGAP/54CD84CE+eP//wIQU/A=="))
|
||||
}
|
||||
}
|
||||
|
||||
function imgTimer() {
|
||||
return {
|
||||
width : 24, height : 24, bpp : 1,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("/+B/4CD84CEBAPygFP+F+h/x/+P+fz5/n+HnAQNn5/wuYCBmYCC5kAAQfOgFz80As/ngHn+fD54mC/F+j/+gF/HAQA=="))
|
||||
}
|
||||
}
|
||||
|
||||
function imgWatch() {
|
||||
return {
|
||||
width : 24, height : 24, bpp : 1,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("/8B//+ARANB/l4//5/1/+f/n/n5+fAQnf9/P44CC8/n7/n+YOB/+fDQQgCEwQsCHBBEC"))
|
||||
}
|
||||
}
|
||||
|
||||
function imgHomeAssistant() {
|
||||
return {
|
||||
width : 48, height : 48, bpp : 1,
|
||||
transparent : 0,
|
||||
buffer : require("heatshrink").decompress(atob("AD8BwAFDg/gAocP+AFDj4FEn/8Aod//wFD/1+FAf4j+8AoMD+EPDAUH+OPAoUP+fPAoUfBYk/C4l/EYIwC//8n//FwIFEgYFD4EH+E8nkP8BdBAonjjk44/wj/nzk58/4gAFDF4PgCIMHAoPwhkwh4FB/EEkEfIIWAHwIFC4A+BAoXgg4FDL4IFDL4IFDLIYFkAEQA=="))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
* 2D MENU with entries of:
|
||||
* [name, icon, opt[customDownFun], opt[customUpFun], opt[customCenterFun]]
|
||||
*
|
||||
/************************************************
|
||||
* Menu
|
||||
*/
|
||||
var menu = [
|
||||
[
|
||||
function(){ return [ null, null ] },
|
||||
],
|
||||
[
|
||||
function(){ return [ "Bangle", imgWatch() ] },
|
||||
function(){ return [ E.getBattery() + "%", Bangle.isCharging() ? imgCharging() : imgBattery() ] },
|
||||
function(){ return [ getSteps(), imgSteps() ] },
|
||||
function(){ return [ Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", imgBpm()] },
|
||||
// Custom bwItems menu - therefore, its added here and not in a clkinfo.js file.
|
||||
var bwItems = {
|
||||
name: null,
|
||||
img: null,
|
||||
items: [
|
||||
{ name: "WeekOfYear",
|
||||
get: () => ({ text: "Week " + weekOfYear(), img: null}),
|
||||
show: function() { bwItems.items[0].emit("redraw"); },
|
||||
hide: function () {}
|
||||
},
|
||||
]
|
||||
]
|
||||
};
|
||||
|
||||
/*
|
||||
* Timer Menu
|
||||
*/
|
||||
try{
|
||||
require('sched');
|
||||
menu.push([
|
||||
function(){
|
||||
var text = isAlarmEnabled() ? getAlarmMinutes() + " min." : "Timer";
|
||||
return [text, imgTimer(), () => decreaseAlarm(), () => increaseAlarm(), null ]
|
||||
},
|
||||
]);
|
||||
} catch(ex) {
|
||||
// If sched is not installed, we hide this menu item
|
||||
}
|
||||
|
||||
/*
|
||||
* WEATHER MENU
|
||||
*/
|
||||
if(storage.readJSON('weather.json') !== undefined){
|
||||
menu.push([
|
||||
function(){ return [ "Weather", imgWeather() ] },
|
||||
function(){ return [ getWeather().temp, imgTemperature() ] },
|
||||
function(){ return [ getWeather().wind, imgWind() ] },
|
||||
]);
|
||||
function weekOfYear() {
|
||||
var date = new Date();
|
||||
date.setHours(0, 0, 0, 0);
|
||||
// Thursday in current week decides the year.
|
||||
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
|
||||
// January 4 is always in week 1.
|
||||
var week1 = new Date(date.getFullYear(), 0, 4);
|
||||
// Adjust to Thursday in week 1 and count number of weeks from date to week1.
|
||||
return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000
|
||||
- 3 + (week1.getDay() + 6) % 7) / 7);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* HOME ASSISTANT MENU
|
||||
*/
|
||||
try{
|
||||
var triggers = require("ha.lib.js").getTriggers();
|
||||
var haMenu = [
|
||||
function(){ return [ "Home", imgHomeAssistant() ] },
|
||||
];
|
||||
// Load menu
|
||||
var menu = clock_info.load();
|
||||
menu = menu.concat(bwItems);
|
||||
|
||||
triggers.forEach(trigger => {
|
||||
haMenu.push(function(){
|
||||
return [trigger.display, trigger.getIcon(), () => {}, () => {}, function(){
|
||||
var ha = require("ha.lib.js");
|
||||
ha.sendTrigger("TRIGGER_BW");
|
||||
ha.sendTrigger(trigger.trigger);
|
||||
}]
|
||||
});
|
||||
|
||||
// Ensure that our settings are still in range (e.g. app uninstall). Otherwise reset the position it.
|
||||
if(settings.menuPosX >= menu.length || settings.menuPosY > menu[settings.menuPosX].items.length ){
|
||||
settings.menuPosX = 0;
|
||||
settings.menuPosY = 0;
|
||||
}
|
||||
|
||||
// Set draw functions for each item
|
||||
menu.forEach((menuItm, x) => {
|
||||
menuItm.items.forEach((item, y) => {
|
||||
function drawItem() {
|
||||
// For the clock, we have a special case, as we don't wanna redraw
|
||||
// immediately when something changes. Instead, we update data each minute
|
||||
// to save some battery etc. Therefore, we hide (and disable the listener)
|
||||
// immedeately after redraw...
|
||||
item.hide();
|
||||
|
||||
// After drawing the item, we enable inputs again...
|
||||
lock_input = false;
|
||||
|
||||
var info = item.get();
|
||||
drawMenuItem(info.text, info.img);
|
||||
}
|
||||
|
||||
item.on('redraw', drawItem);
|
||||
})
|
||||
menu.push(haMenu);
|
||||
} catch(ex){
|
||||
// If HomeAssistant is not installed, we hide this item
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function getMenuEntry(){
|
||||
// In case the user removes HomeAssistant entries, showInfo
|
||||
// could be larger than infoArray.length...
|
||||
settings.menuPosX = settings.menuPosX % menu.length;
|
||||
settings.menuPosY = settings.menuPosY % menu[settings.menuPosX].length;
|
||||
return menu[settings.menuPosX][settings.menuPosY]();
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
* Helper
|
||||
*/
|
||||
function getSteps() {
|
||||
var steps = 0;
|
||||
try{
|
||||
if (WIDGETS.wpedom !== undefined) {
|
||||
steps = WIDGETS.wpedom.getSteps();
|
||||
} else if (WIDGETS.activepedom !== undefined) {
|
||||
steps = WIDGETS.activepedom.getSteps();
|
||||
} else {
|
||||
steps = Bangle.getHealthStatus("day").steps;
|
||||
}
|
||||
} catch(ex) {
|
||||
// In case we failed, we can only show 0 steps.
|
||||
function canRunMenuItem(){
|
||||
if(settings.menuPosY == 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
steps = Math.round(steps/100) / 10; // This ensures that we do not show e.g. 15.0k and 15k instead
|
||||
return steps + "k";
|
||||
var menuEntry = menu[settings.menuPosX];
|
||||
var item = menuEntry.items[settings.menuPosY-1];
|
||||
return item.run !== undefined;
|
||||
}
|
||||
|
||||
|
||||
function getWeather(){
|
||||
var weatherJson;
|
||||
|
||||
try {
|
||||
weatherJson = storage.readJSON('weather.json');
|
||||
var weather = weatherJson.weather;
|
||||
|
||||
// Temperature
|
||||
weather.temp = locale.temp(weather.temp-273.15);
|
||||
|
||||
// Humidity
|
||||
weather.hum = weather.hum + "%";
|
||||
|
||||
// Wind
|
||||
const wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/);
|
||||
weather.wind = Math.round(wind[1]) + "kph";
|
||||
|
||||
return weather
|
||||
|
||||
} catch(ex) {
|
||||
// Return default
|
||||
function runMenuItem(){
|
||||
if(settings.menuPosY == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
temp: " ? ",
|
||||
hum: " ? ",
|
||||
txt: " ? ",
|
||||
wind: " ? ",
|
||||
wdir: " ? ",
|
||||
wrose: " ? "
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function isAlarmEnabled(){
|
||||
var menuEntry = menu[settings.menuPosX];
|
||||
var item = menuEntry.items[settings.menuPosY-1];
|
||||
try{
|
||||
var alarm = require('sched');
|
||||
var alarmObj = alarm.getAlarm(TIMER_IDX);
|
||||
if(alarmObj===undefined || !alarmObj.on){
|
||||
return false;
|
||||
var ret = item.run();
|
||||
if(ret){
|
||||
Bangle.buzz(300, 0.6);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch(ex){ }
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function getAlarmMinutes(){
|
||||
if(!isAlarmEnabled()){
|
||||
return -1;
|
||||
} catch (ex) {
|
||||
// Simply ignore it...
|
||||
}
|
||||
|
||||
var alarm = require('sched');
|
||||
var alarmObj = alarm.getAlarm(TIMER_IDX);
|
||||
return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
|
||||
}
|
||||
|
||||
|
||||
function increaseAlarm(){
|
||||
try{
|
||||
var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0;
|
||||
var alarm = require('sched')
|
||||
alarm.setAlarm(TIMER_IDX, {
|
||||
timer : (minutes+5)*60*1000,
|
||||
});
|
||||
alarm.reload();
|
||||
} catch(ex){ }
|
||||
}
|
||||
|
||||
|
||||
function decreaseAlarm(){
|
||||
try{
|
||||
var minutes = getAlarmMinutes();
|
||||
minutes -= 5;
|
||||
|
||||
var alarm = require('sched')
|
||||
alarm.setAlarm(TIMER_IDX, undefined);
|
||||
|
||||
if(minutes > 0){
|
||||
alarm.setAlarm(TIMER_IDX, {
|
||||
timer : minutes*60*1000,
|
||||
});
|
||||
}
|
||||
|
||||
alarm.reload();
|
||||
} catch(ex){ }
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
* DRAW
|
||||
/************************************************
|
||||
* Draw
|
||||
*/
|
||||
function draw() {
|
||||
// Queue draw again
|
||||
|
@ -363,7 +183,7 @@ function draw() {
|
|||
|
||||
// Draw clock
|
||||
drawDate();
|
||||
drawTime();
|
||||
drawMenuAndTime();
|
||||
drawLock();
|
||||
drawWidgets();
|
||||
}
|
||||
|
@ -371,12 +191,12 @@ function draw() {
|
|||
|
||||
function drawDate(){
|
||||
// Draw background
|
||||
var y = H/5*2;
|
||||
g.reset().clearRect(0,0,W,W);
|
||||
var y = H/5*2 + (isFullscreen() ? 0 : 8);
|
||||
g.reset().clearRect(0,0,W,y);
|
||||
|
||||
// Draw date
|
||||
y = parseInt(y/2)+4;
|
||||
y += settings.fullscreen ? 0 : 13;
|
||||
y += isFullscreen() ? 0 : 8;
|
||||
var date = new Date();
|
||||
var dateStr = date.getDate();
|
||||
dateStr = ("0" + dateStr).substr(-2);
|
||||
|
@ -395,15 +215,12 @@ function drawDate(){
|
|||
|
||||
g.setMediumFont();
|
||||
g.setColor(g.theme.fg);
|
||||
g.drawString(dateStr, W/2 - fullDateW / 2, y+1);
|
||||
g.drawString(dateStr, W/2 - fullDateW / 2, y+2);
|
||||
}
|
||||
|
||||
|
||||
function drawTime(){
|
||||
function drawTime(y, smallText){
|
||||
// Draw background
|
||||
var y = H/5*2 + (settings.fullscreen ? 0 : 8);
|
||||
g.setColor(g.theme.fg);
|
||||
g.fillRect(0,y,W,H);
|
||||
var date = new Date();
|
||||
|
||||
// Draw time
|
||||
|
@ -419,45 +236,65 @@ function drawTime(){
|
|||
// Set y coordinates correctly
|
||||
y += parseInt((H - y)/2) + 5;
|
||||
|
||||
var menuEntry = getMenuEntry();
|
||||
var menuName = menuEntry[0];
|
||||
var menuImg = menuEntry[1];
|
||||
var printImgLeft = settings.menuPosY != 0;
|
||||
|
||||
// Show large or small time depending on info entry
|
||||
if(menuName == null){
|
||||
if(settings.hideColon){
|
||||
g.setXLargeFont();
|
||||
} else {
|
||||
g.setLargeFont();
|
||||
}
|
||||
} else {
|
||||
if(smallText){
|
||||
y -= 15;
|
||||
g.setMediumFont();
|
||||
} else {
|
||||
g.setLargeFont();
|
||||
}
|
||||
g.drawString(timeStr, W/2, y);
|
||||
}
|
||||
|
||||
// Draw menu if set
|
||||
if(menuName == null){
|
||||
function drawMenuItem(text, image){
|
||||
// First clear the time region
|
||||
var y = H/5*2 + (isFullscreen() ? 0 : 8);
|
||||
|
||||
g.setColor(g.theme.fg);
|
||||
g.fillRect(0,y,W,H);
|
||||
|
||||
// Draw menu text
|
||||
var hasText = (text != null && text != "");
|
||||
if(hasText){
|
||||
g.setFontAlign(0,0);
|
||||
|
||||
// For multiline text we show an even smaller font...
|
||||
text = String(text);
|
||||
if(text.split('\n').length > 1){
|
||||
g.setMiniFont();
|
||||
} else {
|
||||
g.setSmallFont();
|
||||
}
|
||||
|
||||
var imgWidth = image == null ? 0 : 24;
|
||||
var strWidth = g.stringWidth(text);
|
||||
g.setColor(g.theme.fg).fillRect(0, 149-14, W, H);
|
||||
g.setColor(g.theme.bg).drawString(text, W/2 + imgWidth/2 + 2, 149+3);
|
||||
|
||||
if(image != null){
|
||||
var scale = imgWidth / image.width;
|
||||
g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 149 - parseInt(imgWidth/2), {scale: scale});
|
||||
}
|
||||
}
|
||||
|
||||
// Draw time
|
||||
drawTime(y, hasText);
|
||||
}
|
||||
|
||||
|
||||
function drawMenuAndTime(){
|
||||
var menuEntry = menu[settings.menuPosX];
|
||||
|
||||
// The first entry is the overview...
|
||||
if(settings.menuPosY == 0){
|
||||
drawMenuItem(menuEntry.name, menuEntry.img);
|
||||
return;
|
||||
}
|
||||
|
||||
y += 35;
|
||||
g.setFontAlign(0,0);
|
||||
g.setSmallFont();
|
||||
var imgWidth = 0;
|
||||
if(menuImg !== undefined){
|
||||
imgWidth = 24.0;
|
||||
var strWidth = g.stringWidth(menuName);
|
||||
var scale = imgWidth / menuImg.width;
|
||||
g.drawImage(
|
||||
menuImg,
|
||||
W/2 + (printImgLeft ? -strWidth/2-2 : strWidth/2+2) - parseInt(imgWidth/2),
|
||||
y - parseInt(imgWidth/2),
|
||||
{ scale: scale }
|
||||
);
|
||||
}
|
||||
g.drawString(menuName, printImgLeft ? W/2 + imgWidth/2 + 2 : W/2 - imgWidth/2 - 2, y+3);
|
||||
// Draw item if needed
|
||||
lock_input = true;
|
||||
var item = menuEntry.items[settings.menuPosY-1];
|
||||
item.show();
|
||||
}
|
||||
|
||||
|
||||
|
@ -470,7 +307,7 @@ function drawLock(){
|
|||
|
||||
|
||||
function drawWidgets(){
|
||||
if(settings.fullscreen){
|
||||
if(isFullscreen()){
|
||||
for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
|
||||
} else {
|
||||
Bangle.drawWidgets();
|
||||
|
@ -478,9 +315,19 @@ function drawWidgets(){
|
|||
}
|
||||
|
||||
|
||||
function isFullscreen(){
|
||||
var s = settings.screen.toLowerCase();
|
||||
if(s == "dynamic"){
|
||||
return Bangle.isLocked()
|
||||
} else {
|
||||
return s == "full"
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw timeout
|
||||
|
||||
|
||||
/************************************************
|
||||
* Listener
|
||||
*/
|
||||
// timeout used to update every minute
|
||||
var drawTimeout;
|
||||
|
@ -508,6 +355,13 @@ Bangle.on('lcdPower',on=>{
|
|||
Bangle.on('lock', function(isLocked) {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
|
||||
if(!isLocked && settings.screen.toLowerCase() == "dynamic"){
|
||||
// If we have to show the widgets again, we load it from our
|
||||
// cache and not through Bangle.loadWidgets as its much faster!
|
||||
for (let wd of WIDGETS) {wd.draw=wd._draw;wd.area=wd._area;}
|
||||
}
|
||||
|
||||
draw();
|
||||
});
|
||||
|
||||
|
@ -516,13 +370,13 @@ Bangle.on('charging',function(charging) {
|
|||
drawTimeout = undefined;
|
||||
|
||||
// Jump to battery
|
||||
settings.menuPosX = 1;
|
||||
settings.menuPosX = 0;
|
||||
settings.menuPosY = 1;
|
||||
draw();
|
||||
});
|
||||
|
||||
Bangle.on('touch', function(btn, e){
|
||||
var widget_size = settings.fullscreen ? 0 : 20; // Its not exactly 24px -- empirically it seems that 20 worked better...
|
||||
var widget_size = isFullscreen() ? 0 : 20; // Its not exactly 24px -- empirically it seems that 20 worked better...
|
||||
var left = parseInt(g.getWidth() * 0.22);
|
||||
var right = g.getWidth() - left;
|
||||
var upper = parseInt(g.getHeight() * 0.22) + widget_size;
|
||||
|
@ -534,17 +388,15 @@ Bangle.on('touch', function(btn, e){
|
|||
var is_right = e.x > right && !is_upper && !is_lower;
|
||||
var is_center = !is_upper && !is_lower && !is_left && !is_right;
|
||||
|
||||
if(lock_input){
|
||||
return;
|
||||
}
|
||||
|
||||
if(is_lower){
|
||||
Bangle.buzz(40, 0.6);
|
||||
settings.menuPosY = (settings.menuPosY+1) % menu[settings.menuPosX].length;
|
||||
settings.menuPosY = (settings.menuPosY+1) % (menu[settings.menuPosX].items.length+1);
|
||||
|
||||
// Handle custom menu entry function
|
||||
var menuEntry = getMenuEntry();
|
||||
if(menuEntry.length > 2){
|
||||
menuEntry[2]();
|
||||
}
|
||||
|
||||
drawTime();
|
||||
drawMenuAndTime();
|
||||
}
|
||||
|
||||
if(is_upper){
|
||||
|
@ -554,22 +406,16 @@ Bangle.on('touch', function(btn, e){
|
|||
|
||||
Bangle.buzz(40, 0.6);
|
||||
settings.menuPosY = settings.menuPosY-1;
|
||||
settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].length-1 : settings.menuPosY;
|
||||
settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].items.length : settings.menuPosY;
|
||||
|
||||
// Handle custom menu entry function
|
||||
var menuEntry = getMenuEntry();
|
||||
if(menuEntry.length > 3){
|
||||
menuEntry[3]();
|
||||
}
|
||||
|
||||
drawTime();
|
||||
drawMenuAndTime();
|
||||
}
|
||||
|
||||
if(is_right){
|
||||
Bangle.buzz(40, 0.6);
|
||||
settings.menuPosX = (settings.menuPosX+1) % menu.length;
|
||||
settings.menuPosY = 0;
|
||||
drawTime();
|
||||
drawMenuAndTime();
|
||||
}
|
||||
|
||||
if(is_left){
|
||||
|
@ -577,23 +423,12 @@ Bangle.on('touch', function(btn, e){
|
|||
settings.menuPosY = 0;
|
||||
settings.menuPosX = settings.menuPosX-1;
|
||||
settings.menuPosX = settings.menuPosX < 0 ? menu.length-1 : settings.menuPosX;
|
||||
drawTime();
|
||||
drawMenuAndTime();
|
||||
}
|
||||
|
||||
if(is_center){
|
||||
var menuEntry = getMenuEntry();
|
||||
if(menuEntry.length > 4){
|
||||
Bangle.buzz(80, 0.6).then(()=>{
|
||||
try{
|
||||
menuEntry[4]();
|
||||
setTimeout(()=>{
|
||||
Bangle.buzz(80, 0.6);
|
||||
}, 250);
|
||||
} catch(ex){
|
||||
// In case it fails, we simply ignore it.
|
||||
}
|
||||
}
|
||||
);
|
||||
if(canRunMenuItem()){
|
||||
runMenuItem();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -608,17 +443,24 @@ E.on("kill", function(){
|
|||
});
|
||||
|
||||
|
||||
/*
|
||||
* Draw clock the first time
|
||||
/************************************************
|
||||
* Startup Clock
|
||||
*/
|
||||
|
||||
// The upper part is inverse i.e. light if dark and dark if light theme
|
||||
// is enabled. In order to draw the widgets correctly, we invert the
|
||||
// dark/light theme as well as the colors.
|
||||
g.setTheme({bg:g.theme.fg,fg:g.theme.bg, dark:!g.theme.dark}).clear();
|
||||
|
||||
// Load widgets and draw clock the first time
|
||||
Bangle.loadWidgets();
|
||||
draw();
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
// Load widgets and draw clock the first time
|
||||
Bangle.loadWidgets();
|
||||
|
||||
// Cache draw function for dynamic screen to hide / show widgets
|
||||
// Bangle.loadWidgets() could also be called later on but its much slower!
|
||||
for (let wd of WIDGETS) {wd._draw=wd.draw; wd._area=wd.area;}
|
||||
|
||||
// Draw first time
|
||||
draw();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"id": "bwclk",
|
||||
"name": "BW Clock",
|
||||
"version": "0.13",
|
||||
"description": "A very minimalistic clock with date and time in focus.",
|
||||
"version": "0.23",
|
||||
"description": "A very minimalistic clock to mainly show date and time.",
|
||||
"readme": "README.md",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}, {"url":"screenshot_4.png"}],
|
||||
|
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.4 KiB |
|
@ -4,7 +4,7 @@
|
|||
// initialize with default settings...
|
||||
const storage = require('Storage')
|
||||
let settings = {
|
||||
fullscreen: false,
|
||||
screen: "Normal",
|
||||
showLock: true,
|
||||
hideColon: false,
|
||||
};
|
||||
|
@ -17,15 +17,16 @@
|
|||
storage.write(SETTINGS_FILE, settings)
|
||||
}
|
||||
|
||||
|
||||
var screenOptions = ["Normal", "Dynamic", "Full"];
|
||||
E.showMenu({
|
||||
'': { 'title': 'BW Clock' },
|
||||
'< Back': back,
|
||||
'Fullscreen': {
|
||||
value: settings.fullscreen,
|
||||
format: () => (settings.fullscreen ? 'Yes' : 'No'),
|
||||
onchange: () => {
|
||||
settings.fullscreen = !settings.fullscreen;
|
||||
'Screen': {
|
||||
value: 0 | screenOptions.indexOf(settings.screen),
|
||||
min: 0, max: 2,
|
||||
format: v => screenOptions[v],
|
||||
onchange: v => {
|
||||
settings.screen = screenOptions[v];
|
||||
save();
|
||||
},
|
||||
},
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
0.01: Initial version
|
||||
0.02: More compact rendering & app icon
|
||||
0.03: Tell clock widgets to hide.
|
|
@ -0,0 +1,9 @@
|
|||
# Calendar Clock - Your day at a glance
|
||||
|
||||
This clock shows a chronological view of your current and future events.
|
||||
It uses events synced from Gadgetbridge to achieve this.
|
||||
|
||||
The current time and date is highlighted in cyan.
|
||||
|
||||
## Screenshot
|
||||

|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwgpm5gAB4AVRhgWCAAQWWDCARC/4ACJR4uB54WDAAP8DBotFGIgXLFwv4GAouQC4gwMLooXF/gXJOowXGJBIXBCIgXQxgXLMAIXXMAmIC5OIx4XJhH/wAXIxnIC78IxGIHoIABI44MBC4wQBEQIDB5gXGPAJgEC6IxBC5oABC4wwDa4YTCxAWD5nPDAzvGFYgAB5AXWJBK+GcAq5CGBIuBC5X4GBIJBdoQXB/GIx4CDPJAuEC5JoCDAgWBFwYXJxCBIFwYXKYwoACCwZ3IPQoWIC5YABGYIABCwpHKAQYMBCwwX/C5QAMC8R3/R/4XNhAXNwAXHgGIABgWIAFwA=="))
|
|
@ -0,0 +1,119 @@
|
|||
var calendar = [];
|
||||
var current = [];
|
||||
var next = [];
|
||||
|
||||
function updateCalendar() {
|
||||
calendar = require("Storage").readJSON("android.calendar.json",true)||[];
|
||||
calendar = calendar.filter(e => isActive(e) || getTime() <= e.timestamp);
|
||||
calendar.sort((a,b) => a.timestamp - b.timestamp);
|
||||
|
||||
current = calendar.filter(isActive);
|
||||
next = calendar.filter(e=>!isActive(e));
|
||||
}
|
||||
|
||||
function isActive(event) {
|
||||
var timeActive = getTime() - event.timestamp;
|
||||
return timeActive >= 0 && timeActive <= event.durationInSeconds;
|
||||
}
|
||||
function zp(str) {
|
||||
return ("0"+str).substr(-2);
|
||||
}
|
||||
|
||||
function drawEventHeader(event, y) {
|
||||
g.setFont("Vector", 24);
|
||||
|
||||
var time = isActive(event) ? new Date() : new Date(event.timestamp * 1000);
|
||||
var timeStr = zp(time.getHours()) + ":" + zp(time.getMinutes());
|
||||
g.drawString(timeStr, 5, y);
|
||||
y += 24;
|
||||
|
||||
g.setFont("12x20", 1);
|
||||
if (isActive(event)) {
|
||||
g.drawString(zp(time.getDate())+". " + require("locale").month(time,1),15*timeStr.length,y-21);
|
||||
} else {
|
||||
var offset = 0-time.getTimezoneOffset()/1440;
|
||||
var days = Math.floor((time.getTime()/1000)/86400+offset)-Math.floor(getTime()/86400+offset);
|
||||
if(days > 0) {
|
||||
var daysStr = days===1?/*LANG*/"tomorrow":/*LANG*/"in "+days+/*LANG*/" days";
|
||||
g.drawString(daysStr,15*timeStr.length,y-21);
|
||||
}
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
function drawEventBody(event, y) {
|
||||
g.setFont("12x20", 1);
|
||||
var lines = g.wrapString(event.title, g.getWidth()-10);
|
||||
if (lines.length > 2) {
|
||||
lines = lines.slice(0,2);
|
||||
lines[1] = lines[1].slice(0,-3)+"...";
|
||||
}
|
||||
g.drawString(lines.join('\n'), 5, y);
|
||||
y+=20 * lines.length;
|
||||
if(event.location) {
|
||||
g.drawImage(atob("DBSBAA8D/H/nDuB+B+B+B3Dn/j/B+A8A8AYAYAYAAAAAAA=="),5,y);
|
||||
g.drawString(event.location, 20, y);
|
||||
y+=20;
|
||||
}
|
||||
y+=5;
|
||||
return y;
|
||||
}
|
||||
|
||||
function drawEvent(event, y) {
|
||||
y = drawEventHeader(event, y);
|
||||
y = drawEventBody(event, y);
|
||||
return y;
|
||||
}
|
||||
|
||||
var curEventHeight = 0;
|
||||
|
||||
function drawCurrentEvents(y) {
|
||||
g.setColor("#0ff");
|
||||
g.clearRect(5, y, g.getWidth() - 5, y + curEventHeight);
|
||||
curEventHeight = y;
|
||||
|
||||
if(current.length === 0) {
|
||||
y = drawEvent({timestamp: getTime(), durationInSeconds: 100}, y);
|
||||
} else {
|
||||
y = drawEventHeader(current[0], y);
|
||||
for (var e of current) {
|
||||
y = drawEventBody(e, y);
|
||||
}
|
||||
}
|
||||
curEventHeight = y - curEventHeight;
|
||||
return y;
|
||||
}
|
||||
|
||||
function drawFutureEvents(y) {
|
||||
g.setColor(g.theme.fg);
|
||||
for (var e of next) {
|
||||
y = drawEvent(e, y);
|
||||
if(y>g.getHeight())break;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
function fullRedraw() {
|
||||
g.clearRect(5,24,g.getWidth()-5,g.getHeight());
|
||||
updateCalendar();
|
||||
var y = 30;
|
||||
y = drawCurrentEvents(y);
|
||||
drawFutureEvents(y);
|
||||
}
|
||||
|
||||
function redraw() {
|
||||
g.reset();
|
||||
if (current.find(e=>!isActive(e)) || next.find(isActive)) {
|
||||
fullRedraw();
|
||||
} else {
|
||||
drawCurrentEvents(30);
|
||||
}
|
||||
}
|
||||
|
||||
g.clear();
|
||||
fullRedraw();
|
||||
var minuteInterval = setInterval(redraw, 60 * 1000);
|
||||
|
||||
Bangle.setUI("clock");
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 692 B |
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"id": "calclock",
|
||||
"name": "Calendar Clock",
|
||||
"shortName": "CalClock",
|
||||
"version": "0.03",
|
||||
"description": "Show the current and upcoming events synchronized from Gadgetbridge",
|
||||
"icon": "calclock.png",
|
||||
"type": "clock",
|
||||
"tags": "clock agenda",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"calclock.app.js","url":"calclock.js"},
|
||||
{"name":"calclock.img","url":"calclock-icon.js","evaluate":true}
|
||||
],
|
||||
"screenshots": [{"url":"screenshot.png"}]
|
||||
}
|
After Width: | Height: | Size: 2.9 KiB |
|
@ -8,4 +8,5 @@
|
|||
0.7: Update Rocket Sequences Scope to not use memory all time
|
||||
0.8: Update Some Variable Scopes to not use memory until need
|
||||
0.9: Remove ESLint spaces
|
||||
0.10: Show daily steps, heartrate and the temperature if weather information is available.
|
||||
0.10: Show daily steps, heartrate and the temperature if weather information is available.
|
||||
0.11: Tell clock widgets to hide.
|
||||
|
|
|
@ -165,11 +165,11 @@ Bangle.on("lock", (locked) => {
|
|||
}
|
||||
});
|
||||
|
||||
Bangle.setUI("clock");
|
||||
|
||||
// Load widgets, but don't show them
|
||||
Bangle.loadWidgets();
|
||||
Bangle.setUI("clock");
|
||||
|
||||
g.reset();
|
||||
g.clear();
|
||||
draw();
|
||||
draw();
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"description": "Animated Clock with Space Cassio Watch Style",
|
||||
"screenshots": [{ "url": "screens/screen_night.png" },{ "url": "screens/screen_day.png" }],
|
||||
"icon": "app.png",
|
||||
"version": "0.10",
|
||||
"version": "0.11",
|
||||
"type": "clock",
|
||||
"tags": "clock, weather, cassio, retro",
|
||||
"supports": ["BANGLEJS2"],
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
0.01: Initial Creation
|
||||
0.02: Fixed some sleep bugs. Added a sleep mode toggle
|
|
@ -0,0 +1,11 @@
|
|||
# Chimer - For the BangleJS
|
||||
|
||||
A fork of [Hour Chime](https://github.com/espruino/BangleApps/tree/master/apps/widchime) that adds extra features such as:
|
||||
|
||||
- Buzz or beep on every 60, 30 or 15 minutes.
|
||||
- Repeat Chime up to 3 times
|
||||
- Set hours to disable chime
|
||||
|
||||
Setting the hours you don't want your watch to chime for is done by setting the hour you want it to stop, and the hour you want it to start.
|
||||
|
||||
Hours range from 0 - 23.
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
widget.png: "https://icons8.com/icon/114436/alarm"
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"id": "chimer",
|
||||
"name": "Chimer",
|
||||
"version": "0.02",
|
||||
"description": "A fork of Hour Chime that adds extra features such as: \n - Buzz or beep on every 60, 30 or 15 minutes. \n - Reapeat Chime up to 3 times \n - Set hours to disable chime",
|
||||
"icon": "widget.png",
|
||||
"type": "widget",
|
||||
"tags": "widget",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"readme": "README.MD",
|
||||
"storage": [
|
||||
{ "name": "chimer.wid.js", "url": "widget.js" },
|
||||
{ "name": "chimer.settings.js", "url": "settings.js" }
|
||||
],
|
||||
"data": [{ "name": "chimer.json" }]
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* @param {function} back Use back() to return to settings menu
|
||||
*/
|
||||
|
||||
(function (back) {
|
||||
// default to buzzing
|
||||
var FILE = "chimer.json";
|
||||
var settings = {};
|
||||
const chimes = ["Off", "Buzz", "Beep", "Both"];
|
||||
const frequency = ["60 min", "30 min", "15 min", "1 min"];
|
||||
|
||||
var showMainMenu = () => {
|
||||
E.showMenu({
|
||||
"": { title: "Chimer" },
|
||||
"< Back": () => back(),
|
||||
"Chime Type": {
|
||||
value: settings.type,
|
||||
min: 0,
|
||||
max: 2, // both is just silly
|
||||
format: (v) => chimes[v],
|
||||
onchange: (v) => {
|
||||
settings.type = v;
|
||||
writeSettings(settings);
|
||||
},
|
||||
},
|
||||
Frequency: {
|
||||
value: settings.freq,
|
||||
min: 0,
|
||||
max: 2,
|
||||
format: (v) => frequency[v],
|
||||
onchange: (v) => {
|
||||
settings.freq = v;
|
||||
writeSettings(settings);
|
||||
},
|
||||
},
|
||||
Repetition: {
|
||||
value: settings.repeat,
|
||||
min: 1,
|
||||
max: 5,
|
||||
format: (v) => v,
|
||||
onchange: (v) => {
|
||||
settings.repeat = v;
|
||||
writeSettings(settings);
|
||||
},
|
||||
},
|
||||
"Sleep Mode": {
|
||||
value: !!settings.sleep,
|
||||
onchange: (v) => {
|
||||
settings.sleep = v;
|
||||
writeSettings(settings);
|
||||
},
|
||||
},
|
||||
"Sleep Start": {
|
||||
value: settings.start,
|
||||
min: 0,
|
||||
max: 23,
|
||||
format: (v) => v,
|
||||
onchange: (v) => {
|
||||
settings.start = v;
|
||||
writeSettings(settings);
|
||||
},
|
||||
},
|
||||
"Sleep End": {
|
||||
value: settings.end,
|
||||
min: 0,
|
||||
max: 23,
|
||||
format: (v) => v,
|
||||
onchange: (v) => {
|
||||
settings.end = v;
|
||||
writeSettings(settings);
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
var readSettings = () => {
|
||||
var settings = require("Storage").readJSON(FILE, 1) || {
|
||||
type: 1,
|
||||
freq: 0,
|
||||
repeat: 1,
|
||||
sleep: true,
|
||||
start: 6,
|
||||
end: 22,
|
||||
};
|
||||
return settings;
|
||||
};
|
||||
|
||||
var writeSettings = (settings) => {
|
||||
require("Storage").writeJSON(FILE, settings);
|
||||
};
|
||||
|
||||
settings = readSettings();
|
||||
showMainMenu();
|
||||
});
|
|
@ -0,0 +1,134 @@
|
|||
(function () {
|
||||
// 0: off, 1: buzz, 2: beep, 3: both
|
||||
var FILE = "chimer.json";
|
||||
|
||||
var readSettings = () => {
|
||||
var settings = require("Storage").readJSON(FILE, 1) || {
|
||||
type: 1,
|
||||
freq: 0,
|
||||
repeat: 1,
|
||||
sleep: true,
|
||||
start: 6,
|
||||
end: 22,
|
||||
};
|
||||
return settings;
|
||||
};
|
||||
|
||||
var settings = readSettings();
|
||||
|
||||
function sleep(milliseconds) {
|
||||
const date = Date.now();
|
||||
let currentDate = null;
|
||||
do {
|
||||
currentDate = Date.now();
|
||||
} while (currentDate - date < milliseconds);
|
||||
}
|
||||
|
||||
function chime() {
|
||||
for (var i = 0; i < settings.repeat; i++) {
|
||||
if (settings.type === 1) {
|
||||
Bangle.buzz(100);
|
||||
} else if (settings.type === 2) {
|
||||
Bangle.beep();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
sleep(150);
|
||||
}
|
||||
}
|
||||
|
||||
let lastHour = new Date().getHours();
|
||||
let lastMinute = new Date().getMinutes(); // don't chime when (re)loaded at a whole hour
|
||||
function check() {
|
||||
const now = new Date(),
|
||||
h = now.getHours(),
|
||||
m = now.getMinutes(),
|
||||
s = now.getSeconds(),
|
||||
ms = now.getMilliseconds();
|
||||
if (
|
||||
(settings.sleep && h > settings.end) ||
|
||||
(settings.sleep && h >= settings.end && m !== 0) ||
|
||||
(settings.sleep && h < settings.start)
|
||||
) {
|
||||
var mLeft = 60 - m,
|
||||
sLeft = mLeft * 60 - s,
|
||||
msLeft = sLeft * 1000 - ms;
|
||||
setTimeout(check, msLeft);
|
||||
return;
|
||||
}
|
||||
if (settings.freq === 1) {
|
||||
if ((m !== lastMinute && m === 0) || (m !== lastMinute && m === 30))
|
||||
chime();
|
||||
lastHour = h;
|
||||
lastMinute = m;
|
||||
// check again in 30 minutes
|
||||
switch (true) {
|
||||
case m / 30 >= 1:
|
||||
var mLeft = 30 - (m - 30),
|
||||
sLeft = mLeft * 60 - s,
|
||||
msLeft = sLeft * 1000 - ms;
|
||||
break;
|
||||
case m / 30 < 1:
|
||||
var mLeft = 30 - m,
|
||||
sLeft = mLeft * 60 - s,
|
||||
msLeft = sLeft * 1000 - ms;
|
||||
break;
|
||||
}
|
||||
setTimeout(check, msLeft);
|
||||
} else if (settings.freq === 2) {
|
||||
if (
|
||||
(m !== lastMinute && m === 0) ||
|
||||
(m !== lastMinute && m === 15) ||
|
||||
(m !== lastMinute && m === 30) ||
|
||||
(m !== lastMinute && m === 45)
|
||||
)
|
||||
chime();
|
||||
lastHour = h;
|
||||
lastMinute = m;
|
||||
// check again in 15 minutes
|
||||
switch (true) {
|
||||
case m / 15 >= 3:
|
||||
var mLeft = 15 - (m - 45),
|
||||
sLeft = mLeft * 60 - s,
|
||||
msLeft = sLeft * 1000 - ms;
|
||||
break;
|
||||
case m / 15 >= 2:
|
||||
var mLeft = 15 - (m - 30),
|
||||
sLeft = mLeft * 60 - s,
|
||||
msLeft = sLeft * 1000 - ms;
|
||||
break;
|
||||
case m / 15 >= 1:
|
||||
var mLeft = 15 - (m - 15),
|
||||
sLeft = mLeft * 60 - s,
|
||||
msLeft = sLeft * 1000 - ms;
|
||||
break;
|
||||
case m / 15 < 1:
|
||||
var mLeft = 15 - m,
|
||||
sLeft = mLeft * 60 - s,
|
||||
msLeft = sLeft * 1000 - ms;
|
||||
break;
|
||||
}
|
||||
setTimeout(check, msLeft);
|
||||
} else if (settings.freq === 3) {
|
||||
if (m !== lastMinute) chime();
|
||||
lastHour = h;
|
||||
lastMinute = m;
|
||||
// check again in 1 minute
|
||||
|
||||
var mLeft = 1,
|
||||
sLeft = mLeft * 60 - s,
|
||||
msLeft = sLeft * 1000 - ms;
|
||||
setTimeout(check, msLeft);
|
||||
} else {
|
||||
if (h !== lastHour && m === 0) chime();
|
||||
lastHour = h;
|
||||
// check again in 60 minutes
|
||||
var mLeft = 60 - m,
|
||||
sLeft = mLeft * 60 - s,
|
||||
msLeft = sLeft * 1000 - ms;
|
||||
setTimeout(check, msLeft);
|
||||
}
|
||||
}
|
||||
|
||||
check();
|
||||
})();
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -2,3 +2,5 @@
|
|||
0.02: Added scrollable calendar and swipe gestures
|
||||
0.03: Configurable drag gestures
|
||||
0.04: Use default Bangle formatter for booleans
|
||||
0.05: Improved colors (connected vs disconnected)
|
||||
0.06: Tell clock widgets to hide.
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
Bangle.setUI("clock");
|
||||
Bangle.loadWidgets();
|
||||
|
||||
var s = Object.assign({
|
||||
|
@ -123,7 +124,7 @@ function drawMinutes() {
|
|||
var d = new Date();
|
||||
var hours = s.MODE24 ? d.getHours().toString().padStart(2, ' ') : ((d.getHours() + 24) % 12 || 12).toString().padStart(2, ' ');
|
||||
var minutes = d.getMinutes().toString().padStart(2, '0');
|
||||
var textColor = NRF.getSecurityStatus().connected ? '#fff' : '#f00';
|
||||
var textColor = NRF.getSecurityStatus().connected ? '#99f' : '#fff';
|
||||
var size = 50;
|
||||
var clock_x = (w - 20) / 2;
|
||||
if (dimSeconds) {
|
||||
|
@ -307,4 +308,4 @@ NRF.on('disconnect', BTevent);
|
|||
|
||||
dimSeconds = Bangle.isLocked();
|
||||
drawWatch();
|
||||
Bangle.setUI("clock");
|
||||
|
||||
|
|