Merge branch 'master' of github.com:awkirk71/BangleApps into extended_sliding_clock
|
@ -11,3 +11,6 @@ tests/Layout/testresult.bmp
|
||||||
apps.local.json
|
apps.local.json
|
||||||
_site
|
_site
|
||||||
.jekyll-cache
|
.jekyll-cache
|
||||||
|
.owncloudsync.log
|
||||||
|
Desktop.ini
|
||||||
|
.sync_*.db*
|
||||||
|
|
|
@ -269,7 +269,7 @@ function actions(v){
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Messages status
|
// Get Messages status
|
||||||
var messages = require("Storage").readJSON("messages.json",1)||[];
|
var messages_installed = require("Storage").read("messages") !== undefined;
|
||||||
|
|
||||||
//var BTconnected = NRF.getSecurityStatus().connected;
|
//var BTconnected = NRF.getSecurityStatus().connected;
|
||||||
//NRF.on('connect',BTconnected = NRF.getSecurityStatus().connected);
|
//NRF.on('connect',BTconnected = NRF.getSecurityStatus().connected);
|
||||||
|
@ -318,7 +318,7 @@ function drawWidgeds() {
|
||||||
var x2M = x1M + 25;
|
var x2M = x1M + 25;
|
||||||
var y2M = y2B;
|
var y2M = y2B;
|
||||||
|
|
||||||
if (messages.some(m=>m.new)) {
|
if (messages_installed && require("messages").status() == "new") {
|
||||||
g.setColor(g.theme.fg);
|
g.setColor(g.theme.fg);
|
||||||
g.fillRect(x1M,y1M,x2M,y2M);
|
g.fillRect(x1M,y1M,x2M,y2M);
|
||||||
g.setColor(g.theme.bg);
|
g.setColor(g.theme.bg);
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
0.01: Initial version for upload
|
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",
|
{ "id": "7x7dotsclock",
|
||||||
"name": "7x7 Dots Clock",
|
"name": "7x7 Dots Clock",
|
||||||
"shortName":"7x7 Dots Clock",
|
"shortName":"7x7 Dots Clock",
|
||||||
"version":"0.02",
|
"version":"0.03",
|
||||||
"description": "A clock with a big 7x7 dots Font",
|
"description": "A clock with a big 7x7 dots Font",
|
||||||
"icon": "dotsfontclock.png",
|
"icon": "dotsfontclock.png",
|
||||||
"tags": "clock",
|
"tags": "clock",
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
0.01: New App!
|
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();
|
Bangle.loadWidgets();
|
||||||
|
|
||||||
// Clear the screen once, at startup
|
// 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",
|
"id": "90sclk",
|
||||||
"name": "90s Clock",
|
"name": "90s Clock",
|
||||||
"version": "0.02",
|
"version": "0.03",
|
||||||
"description": "A 90s style watch-face",
|
"description": "A 90s style watch-face",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"icon": "app.png",
|
"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.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.11: Bangle.js2: New pixels, btn1 to exit
|
||||||
0.12: Actual pixels as of 29th Nov 2021
|
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
|
// TODO: a nice little animation before
|
||||||
setTimeout(drawInfo, 1000);
|
setTimeout(drawInfo, 1000);
|
||||||
setWatch(_=>load(), BTN1);
|
Bangle.setUI({
|
||||||
|
mode : "custom",
|
||||||
|
back : load
|
||||||
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "about",
|
"id": "about",
|
||||||
"name": "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",
|
"description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"tags": "tool,system",
|
"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.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.07: Fix bug on the cutting edge firmware
|
||||||
0.08: Use default Bangle formatter for booleans
|
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 () {
|
(function () {
|
||||||
// load variable before defining functions cause it can trigger a ReferenceError
|
// load variable before defining functions cause it can trigger a ReferenceError
|
||||||
const activityreminder = require("activityreminder");
|
const activityreminder = require("activityreminder");
|
||||||
const storage = require("Storage");
|
|
||||||
const activityreminder_settings = activityreminder.loadSettings();
|
|
||||||
let activityreminder_data = activityreminder.loadData();
|
let activityreminder_data = activityreminder.loadData();
|
||||||
|
let W = g.getWidth();
|
||||||
|
// let H = g.getHeight();
|
||||||
|
|
||||||
function drawAlert() {
|
function getHoursMins(date){
|
||||||
E.showPrompt("Inactivity detected", {
|
var h = date.getHours();
|
||||||
title: "Activity reminder",
|
var m = date.getMinutes();
|
||||||
buttons: { "Ok": 1, "Dismiss": 2, "Pause": 3 }
|
return (""+h).substr(-2) + ":" + ("0"+m).substr(-2);
|
||||||
}).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:
|
function drawData(name, value, y){
|
||||||
if (!(storage.readJSON('setting.json', 1) || {}).quiet) {
|
g.drawString(name, 10, y);
|
||||||
Bangle.buzz(400);
|
g.drawString(value, 100, y);
|
||||||
}
|
}
|
||||||
setTimeout(load, 20000);
|
|
||||||
|
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() {
|
function run() {
|
||||||
if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) {
|
|
||||||
drawAlert();
|
|
||||||
} else {
|
|
||||||
eval(storage.read("activityreminder.settings.js"))(() => load());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g.clear();
|
g.clear();
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
|
drawInfo();
|
||||||
|
Bangle.setUI({
|
||||||
|
mode : "custom",
|
||||||
|
back : load
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
|
||||||
})();
|
})();
|
|
@ -27,8 +27,8 @@
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) {
|
if (mustAlert(now)) {
|
||||||
load('activityreminder.app.js');
|
load('activityreminder.alert.js');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 () {
|
Bangle.on('midnight', function () {
|
||||||
/*
|
/*
|
||||||
Usefull trick to have the app working smothly for people using it at night
|
Usefull trick to have the app working smothly for people using it at night
|
||||||
|
|
|
@ -31,26 +31,14 @@ exports.loadData = function () {
|
||||||
},
|
},
|
||||||
require("Storage").readJSON("activityreminder.data.json") || {});
|
require("Storage").readJSON("activityreminder.data.json") || {});
|
||||||
|
|
||||||
if(typeof(data.stepsDate) == "string")
|
if (typeof (data.stepsDate) == "string")
|
||||||
data.stepsDate = new Date(data.stepsDate);
|
data.stepsDate = new Date(data.stepsDate);
|
||||||
if(typeof(data.okDate) == "string")
|
if (typeof (data.okDate) == "string")
|
||||||
data.okDate = new Date(data.okDate);
|
data.okDate = new Date(data.okDate);
|
||||||
if(typeof(data.dismissDate) == "string")
|
if (typeof (data.dismissDate) == "string")
|
||||||
data.dismissDate = new Date(data.dismissDate);
|
data.dismissDate = new Date(data.dismissDate);
|
||||||
if(typeof(data.pauseDate) == "string")
|
if (typeof (data.pauseDate) == "string")
|
||||||
data.pauseDate = new Date(data.pauseDate);
|
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",
|
"name": "Activity Reminder",
|
||||||
"shortName":"Activity Reminder",
|
"shortName":"Activity Reminder",
|
||||||
"description": "A reminder to take short walks for the ones with a sedentary lifestyle",
|
"description": "A reminder to take short walks for the ones with a sedentary lifestyle",
|
||||||
"version":"0.08",
|
"version":"0.10",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"type": "app",
|
"type": "app",
|
||||||
"tags": "tool,activity",
|
"tags": "tool,activity",
|
||||||
|
@ -13,11 +13,12 @@
|
||||||
{"name": "activityreminder.app.js", "url":"app.js"},
|
{"name": "activityreminder.app.js", "url":"app.js"},
|
||||||
{"name": "activityreminder.boot.js", "url": "boot.js"},
|
{"name": "activityreminder.boot.js", "url": "boot.js"},
|
||||||
{"name": "activityreminder.settings.js", "url": "settings.js"},
|
{"name": "activityreminder.settings.js", "url": "settings.js"},
|
||||||
|
{"name": "activityreminder.alert.js", "url": "alert.js"},
|
||||||
{"name": "activityreminder", "url": "lib.js"},
|
{"name": "activityreminder", "url": "lib.js"},
|
||||||
{"name": "activityreminder.img", "url": "app-icon.js", "evaluate": true}
|
{"name": "activityreminder.img", "url": "app-icon.js", "evaluate": true}
|
||||||
],
|
],
|
||||||
"data": [
|
"data": [
|
||||||
{"name": "activityreminder.s.json"},
|
{"name": "activityreminder.s.json"},
|
||||||
{"name": "activityreminder.data.json"}
|
{"name": "activityreminder.data.json", "storageFile": true}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
const activityreminder = require("activityreminder");
|
const activityreminder = require("activityreminder");
|
||||||
let settings = activityreminder.loadSettings();
|
let settings = activityreminder.loadSettings();
|
||||||
|
|
||||||
// Show the menu
|
function getMainMenu(){
|
||||||
E.showMenu({
|
var mainMenu = {
|
||||||
"": { "title": "Activity Reminder" },
|
"": { "title": "Activity Reminder" },
|
||||||
"< Back": () => back(),
|
"< Back": () => back(),
|
||||||
'Enable': {
|
'Enable': {
|
||||||
|
@ -76,5 +76,11 @@
|
||||||
activityreminder.writeSettings(settings);
|
activityreminder.writeSettings(settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
return mainMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the menu
|
||||||
|
E.showMenu(getMainMenu());
|
||||||
})
|
})
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
0.01: AdvCasio first version
|
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');
|
const storage = require('Storage');
|
||||||
|
|
||||||
require("Font6x12").add(Graphics);
|
|
||||||
require("Font6x8").add(Graphics);
|
|
||||||
require("Font8x12").add(Graphics);
|
require("Font8x12").add(Graphics);
|
||||||
require("Font7x11Numeric7Seg").add(Graphics);
|
require("Font7x11Numeric7Seg").add(Graphics);
|
||||||
|
|
||||||
|
@ -257,7 +255,6 @@ function draw() {
|
||||||
|
|
||||||
|
|
||||||
g.setColor(0, 0, 0);
|
g.setColor(0, 0, 0);
|
||||||
g.setFont("6x12");
|
|
||||||
if(dataJson && dataJson.weather) drawWeather(dataJson.weather);
|
if(dataJson && dataJson.weather) drawWeather(dataJson.weather);
|
||||||
if(dataJson && dataJson.tasks) drawTasks(dataJson.tasks);
|
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
|
// Load widgets, but don't show them
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.setUI("clock");
|
|
||||||
|
|
||||||
g.reset();
|
g.reset();
|
||||||
g.clear();
|
g.clear();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ "id": "advcasio",
|
{ "id": "advcasio",
|
||||||
"name": "Advanced Casio Clock",
|
"name": "Advanced Casio Clock",
|
||||||
"shortName":"advcasio",
|
"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.",
|
"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",
|
"icon": "app.png",
|
||||||
"tags": "clock",
|
"tags": "clock",
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
0.01: Basic agenda with events from GB
|
0.01: Basic agenda with events from GB
|
||||||
0.02: Added settings page to force calendar sync
|
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
|
# 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,
|
title,
|
||||||
description,
|
description,
|
||||||
location,
|
location,
|
||||||
|
color:int,
|
||||||
|
calName,
|
||||||
allDay: bool,
|
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?)
|
//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 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) {
|
function getDate(timestamp) {
|
||||||
return new Date(timestamp*1000);
|
return new Date(timestamp*1000);
|
||||||
}
|
}
|
||||||
function formatDateLong(date, includeDay) {
|
function formatDateLong(date, includeDay, allDay) {
|
||||||
if(includeDay)
|
let shortTime = Locale.time(date,1)+Locale.meridian(date);
|
||||||
return Locale.date(date)+" "+Locale.time(date,1);
|
if(allDay) shortTime = "";
|
||||||
return Locale.time(date,1);
|
if(includeDay || allDay)
|
||||||
|
return Locale.date(date)+" "+shortTime;
|
||||||
|
return shortTime;
|
||||||
}
|
}
|
||||||
function formatDateShort(date) {
|
function formatDateShort(date, allDay) {
|
||||||
return Locale.date(date).replace(/\d\d\d\d/,"")+Locale.time(date,1);
|
return Locale.date(date).replace(/\d\d\d\d/,"")+(allDay?
|
||||||
|
"" : Locale.time(date,1)+Locale.meridian(date));
|
||||||
}
|
}
|
||||||
|
|
||||||
var lines = [];
|
var lines = [];
|
||||||
|
@ -45,7 +51,7 @@ function showEvent(ev) {
|
||||||
if(!ev) return;
|
if(!ev) return;
|
||||||
g.setFont(bodyFont);
|
g.setFont(bodyFont);
|
||||||
//var lines = [];
|
//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 titleCnt = lines.length;
|
||||||
var start = getDate(ev.timestamp);
|
var start = getDate(ev.timestamp);
|
||||||
var end = getDate((+ev.timestamp) + (+ev.durationInSeconds));
|
var end = getDate((+ev.timestamp) + (+ev.durationInSeconds));
|
||||||
|
@ -53,22 +59,24 @@ function showEvent(ev) {
|
||||||
if (titleCnt) lines.push(""); // add blank line after title
|
if (titleCnt) lines.push(""); // add blank line after title
|
||||||
if(start.getDay() == end.getDay() && start.getMonth() == end.getMonth())
|
if(start.getDay() == end.getDay() && start.getMonth() == end.getMonth())
|
||||||
includeDay = false;
|
includeDay = false;
|
||||||
if(includeDay) {
|
if(includeDay || ev.allDay) {
|
||||||
lines = lines.concat(
|
lines = lines.concat(
|
||||||
/*LANG*/"Start:",
|
/*LANG*/"Start:",
|
||||||
g.wrapString(formatDateLong(start, includeDay), g.getWidth()-10),
|
g.wrapString(formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10),
|
||||||
/*LANG*/"End:",
|
/*LANG*/"End:",
|
||||||
g.wrapString(formatDateLong(end, includeDay), g.getWidth()-10));
|
g.wrapString(formatDateLong(end, includeDay, ev.allDay), g.getWidth()-10));
|
||||||
} else {
|
} else {
|
||||||
lines = lines.concat(
|
lines = lines.concat(
|
||||||
g.wrapString(Locale.date(start), g.getWidth()-10),
|
g.wrapString(Locale.date(start), g.getWidth()-10),
|
||||||
g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay), g.getWidth()-10),
|
g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10),
|
||||||
g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay), g.getWidth()-10));
|
g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay, ev.allDay), g.getWidth()-10));
|
||||||
}
|
}
|
||||||
if(ev.location)
|
if(ev.location)
|
||||||
lines = lines.concat(/*LANG*/"Location"+": ", g.wrapString(ev.location, g.getWidth()-10));
|
lines = lines.concat(/*LANG*/"Location"+": ", g.wrapString(ev.location, g.getWidth()-10));
|
||||||
if(ev.description)
|
if(ev.description)
|
||||||
lines = lines.concat("",g.wrapString(ev.description, g.getWidth()-10));
|
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"]);
|
lines = lines.concat(["",/*LANG*/"< Back"]);
|
||||||
E.showScroller({
|
E.showScroller({
|
||||||
h : g.getFontHeight(), // height of each menu item in pixels
|
h : g.getFontHeight(), // height of each menu item in pixels
|
||||||
|
@ -89,6 +97,12 @@ function showEvent(ev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showList() {
|
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) {
|
if(CALENDAR.length == 0) {
|
||||||
E.showMessage("No events");
|
E.showMessage("No events");
|
||||||
return;
|
return;
|
||||||
|
@ -101,24 +115,21 @@ function showList() {
|
||||||
g.setColor(g.theme.fg);
|
g.setColor(g.theme.fg);
|
||||||
g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h);
|
g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h);
|
||||||
if (!ev) return;
|
if (!ev) return;
|
||||||
var isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000;
|
var isPast = false;
|
||||||
var x = r.x+2, title = ev.title;
|
var x = r.x+2, title = ev.title;
|
||||||
var body = formatDateShort(getDate(ev.timestamp))+"\n"+ev.location;
|
var body = formatDateShort(getDate(ev.timestamp),ev.allDay)+"\n"+(ev.location?ev.location:/*LANG*/"No location");
|
||||||
var m = ev.title+"\n"+ev.location, longBody=false;
|
if(settings.pastEvents) isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000;
|
||||||
if (title) g.setFontAlign(-1,-1).setFont(fontBig)
|
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) {
|
if (body) {
|
||||||
g.setFontAlign(-1,-1).setFont(fontMedium).setColor(isPast ? "#888" : g.theme.fg);
|
g.setFontAlign(-1,-1).setFont(fontMedium).setColor(isPast ? "#888" : g.theme.fg);
|
||||||
var l = g.wrapString(body, r.w-(x+14));
|
g.drawString(body, x+10,r.y+20);
|
||||||
if (l.length>3) {
|
|
||||||
l = l.slice(0,3);
|
|
||||||
l[l.length-1]+="...";
|
|
||||||
}
|
}
|
||||||
longBody = l.length>2;
|
|
||||||
g.drawString(l.join("\n"), x+10,r.y+20);
|
|
||||||
}
|
|
||||||
//if (!longBody && msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2);
|
|
||||||
g.setColor("#888").fillRect(r.x,r.y+r.h-1,r.x+r.w-1,r.y+r.h-1); // dividing line between items
|
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]),
|
select : idx => showEvent(CALENDAR[idx]),
|
||||||
back : () => load()
|
back : () => load()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "agenda",
|
"id": "agenda",
|
||||||
"name": "Agenda",
|
"name": "Agenda",
|
||||||
"version": "0.02",
|
"version": "0.06",
|
||||||
"description": "Simple agenda",
|
"description": "Simple agenda",
|
||||||
"icon": "agenda.png",
|
"icon": "agenda.png",
|
||||||
"screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}],
|
"screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}],
|
||||||
|
@ -12,6 +12,8 @@
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"agenda.app.js","url":"agenda.js"},
|
{"name":"agenda.app.js","url":"agenda.js"},
|
||||||
{"name":"agenda.settings.js","url":"settings.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}
|
{"name":"agenda.img","url":"agenda-icon.js","evaluate":true}
|
||||||
]
|
],
|
||||||
|
"data": [{"name":"agenda.settings.json"}]
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
Bluetooth.println("");
|
Bluetooth.println("");
|
||||||
Bluetooth.println(JSON.stringify(message));
|
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 CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[];
|
||||||
var mainmenu = {
|
var mainmenu = {
|
||||||
"" : { "title" : "Agenda" },
|
"" : { "title" : "Agenda" },
|
||||||
|
@ -32,6 +36,13 @@
|
||||||
E.showAlert(/*LANG*/"You are not connected").then(()=>E.showMenu(mainmenu));
|
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);
|
E.showMenu(mainmenu);
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{ "id": "agpsdata",
|
{ "id": "agpsdata",
|
||||||
"name": "A-GPS Data",
|
"name": "A-GPS Data Downloader App",
|
||||||
"shortName":"A-GPS Data",
|
"shortName":"A-GPS Data",
|
||||||
"icon": "agpsdata.png",
|
"icon": "agpsdata.png",
|
||||||
"version":"0.02",
|
"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",
|
"tags": "boot,tool,assisted,gps,agps,http",
|
||||||
"allow_emulator":true,
|
"allow_emulator":true,
|
||||||
"supports": ["BANGLEJS2"],
|
"supports": ["BANGLEJS2"],
|
||||||
|
|
|
@ -11,4 +11,5 @@
|
||||||
0.10: Fix SMS bug
|
0.10: Fix SMS bug
|
||||||
0.12: Use default Bangle formatter for booleans
|
0.12: Use default Bangle formatter for booleans
|
||||||
0.13: Added Bangle.http function (see Readme file for more info)
|
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
|
//send the request
|
||||||
var req = {t: "http", url:url, id:options.id};
|
var req = {t: "http", url:url, id:options.id};
|
||||||
if (options.xpath) req.xpath = options.xpath;
|
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);
|
gbSend(req);
|
||||||
//create the promise
|
//create the promise
|
||||||
var promise = new Promise(function(resolve,reject) {
|
var promise = new Promise(function(resolve,reject) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "android",
|
"id": "android",
|
||||||
"name": "Android Integration",
|
"name": "Android Integration",
|
||||||
"shortName": "Android",
|
"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.",
|
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"tags": "tool,system,messages,notifications,gadgetbridge",
|
"tags": "tool,system,messages,notifications,gadgetbridge",
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
0.02: Fix bug if image clock wasn't installed
|
0.02: Fix bug if image clock wasn't installed
|
||||||
0.03: Update to use setUI
|
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();
|
draw();
|
||||||
var secondInterval = setInterval(draw,100);
|
var secondInterval = setInterval(draw,100);
|
||||||
// load widgets
|
// load widgets
|
||||||
Bangle.loadWidgets();
|
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
// Stop when LCD goes off
|
// Stop when LCD goes off
|
||||||
Bangle.on('lcdPower',on=>{
|
Bangle.on('lcdPower',on=>{
|
||||||
|
@ -104,3 +103,5 @@ if (g.drawImages) {
|
||||||
}
|
}
|
||||||
// Show launcher when button pressed
|
// Show launcher when button pressed
|
||||||
Bangle.setUI("clock");
|
Bangle.setUI("clock");
|
||||||
|
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "animclk",
|
"id": "animclk",
|
||||||
"name": "Animated Clock",
|
"name": "Animated Clock",
|
||||||
"shortName": "Anim 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",
|
"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",
|
"icon": "app.png",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
|
|
|
@ -11,3 +11,4 @@
|
||||||
0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users)
|
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.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",
|
"id": "antonclk",
|
||||||
"name": "Anton Clock",
|
"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.",
|
"description": "A clock using the bold Anton font, optionally showing seconds and date in ISO-8601 format.",
|
||||||
"readme":"README.md",
|
"readme":"README.md",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
{
|
{
|
||||||
"id": "assistedgps",
|
"id": "assistedgps",
|
||||||
"name": "Assisted GPS Update (AGPS)",
|
"name": "Assisted GPS Updater (AGPS)",
|
||||||
"version": "0.03",
|
"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",
|
"icon": "app.png",
|
||||||
"type": "RAM",
|
"type": "RAM",
|
||||||
"tags": "tool,outdoors,agps",
|
"tags": "tool,outdoors,agps,gps,a-gps",
|
||||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||||
"custom": "custom.html",
|
"custom": "custom.html",
|
||||||
"customConnect": true,
|
"customConnect": true,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
0.01: Create astral clock app
|
0.01: Create astral clock app
|
||||||
0.02: Fixed Whirlpool galaxy RA/DA, larger compass display, fixed moonphase overlapping battery widget
|
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.03: Update to use Bangle.setUI instead of setWatch
|
||||||
|
0.04: Tell clock widgets to hide.
|
||||||
|
|
|
@ -767,6 +767,24 @@ function draw() {
|
||||||
g.clear();
|
g.clear();
|
||||||
current_moonphase = getMoonPhase();
|
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
|
// Load widgets
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
|
@ -799,23 +817,6 @@ Bangle.setGPSPower(1);
|
||||||
// Show launcher when button pressed
|
// Show launcher when button pressed
|
||||||
Bangle.setClockMode();
|
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 () {
|
setWatch(function () {
|
||||||
if (!astral_settings.astral_default) {
|
if (!astral_settings.astral_default) {
|
||||||
colours_switched = true;
|
colours_switched = true;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "astral",
|
"id": "astral",
|
||||||
"name": "Astral Clock",
|
"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.",
|
"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",
|
"icon": "app-icon.png",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
0.02: Add sit ups
|
0.02: Add sit ups
|
||||||
Add more feedback to the user about the exercises
|
Add more feedback to the user about the exercises
|
||||||
Clean up code
|
Clean up code
|
||||||
|
0.03: Add software back button on main menu
|
||||||
|
|
|
@ -71,7 +71,8 @@ function showMainMenu() {
|
||||||
let menu;
|
let menu;
|
||||||
menu = {
|
menu = {
|
||||||
"": {
|
"": {
|
||||||
title: "BanglExercise"
|
title: "BanglExercise",
|
||||||
|
back: load
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -381,4 +382,5 @@ Bangle.on('HRM', function(hrm) {
|
||||||
});
|
});
|
||||||
|
|
||||||
g.clear(1);
|
g.clear(1);
|
||||||
|
Bangle.loadWidgets();
|
||||||
showMainMenu();
|
showMainMenu();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ "id": "banglexercise",
|
{ "id": "banglexercise",
|
||||||
"name": "BanglExercise",
|
"name": "BanglExercise",
|
||||||
"shortName":"BanglExercise",
|
"shortName":"BanglExercise",
|
||||||
"version":"0.02",
|
"version":"0.03",
|
||||||
"description": "Can automatically track exercises while wearing the Bangle.js watch.",
|
"description": "Can automatically track exercises while wearing the Bangle.js watch.",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"screenshots": [{"url":"screenshot.png"}],
|
"screenshots": [{"url":"screenshot.png"}],
|
||||||
|
|
|
@ -7,3 +7,4 @@
|
||||||
0.07: Step count resets at midnight
|
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.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.09: NOW it really should reset daily (instead of every other day...)
|
||||||
|
0.10: Tell clock widgets to hide.
|
||||||
|
|
|
@ -416,9 +416,9 @@ var layout = new Layout( {
|
||||||
|
|
||||||
// Clear the screen once, at startup
|
// Clear the screen once, at startup
|
||||||
g.clear();
|
g.clear();
|
||||||
|
Bangle.setUI("clock");
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
Bangle.setUI("clock");
|
|
||||||
layout.render();
|
layout.render();
|
||||||
|
|
||||||
Bangle.on('lock', function(locked) {
|
Bangle.on('lock', function(locked) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "Barcode clock",
|
"name": "Barcode clock",
|
||||||
"shortName":"Barcode clock",
|
"shortName":"Barcode clock",
|
||||||
"icon": "barcode.icon.png",
|
"icon": "barcode.icon.png",
|
||||||
"version":"0.09",
|
"version":"0.10",
|
||||||
"description": "EAN-8 compatible barcode clock.",
|
"description": "EAN-8 compatible barcode clock.",
|
||||||
"tags": "barcode,ean,ean-8,watchface,clock,clockface",
|
"tags": "barcode,ean,ean-8,watchface,clock,clockface",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
0.01: App Created!
|
0.01: App Created!
|
||||||
0.02: Update to use Bangle.setUI instead of setWatch
|
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(0, 0.5, 0).drawImage(bg_crack);
|
||||||
g.setColor(1, 1, 1).drawImage(batman);
|
g.setColor(1, 1, 1).drawImage(batman);
|
||||||
|
|
||||||
|
// Show launcher when button pressed
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
|
|
||||||
|
@ -256,5 +259,3 @@ Bangle.drawWidgets();
|
||||||
timeInterval = setInterval(showTime, 1000);
|
timeInterval = setInterval(showTime, 1000);
|
||||||
showTime();
|
showTime();
|
||||||
|
|
||||||
// Show launcher when button pressed
|
|
||||||
Bangle.setUI("clock");
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "batclock",
|
"id": "batclock",
|
||||||
"name": "Bat Clock",
|
"name": "Bat Clock",
|
||||||
"shortName": "Bat Clock",
|
"shortName": "Bat Clock",
|
||||||
"version": "0.02",
|
"version": "0.03",
|
||||||
"description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.",
|
"description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.",
|
||||||
"icon": "bat-clock.png",
|
"icon": "bat-clock.png",
|
||||||
"screenshots": [{"url":"screenshot.png"}],
|
"screenshots": [{"url":"screenshot.png"}],
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
0.02: Modified for use with new bootloader and firmware
|
0.02: Modified for use with new bootloader and firmware
|
||||||
0.03: Update to use Bangle.setUI instead of setWatch
|
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();
|
if (on) drawClock();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Show launcher when button pressed
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
|
||||||
g.clear();
|
g.clear();
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
setInterval(() => { drawClock(); }, 1000);
|
setInterval(() => { drawClock(); }, 1000);
|
||||||
drawClock();
|
drawClock();
|
||||||
// Show launcher when button pressed
|
|
||||||
Bangle.setUI("clock");
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "bclock",
|
"id": "bclock",
|
||||||
"name": "Binary Clock",
|
"name": "Binary Clock",
|
||||||
"version": "0.03",
|
"version": "0.04",
|
||||||
"description": "A simple binary clock watch face",
|
"description": "A simple binary clock watch face",
|
||||||
"icon": "clock-binary.png",
|
"icon": "clock-binary.png",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
|
|
|
@ -3,3 +3,5 @@
|
||||||
0.03: Internationalisation; bug fix - battery icon responds promptly to charging state
|
0.03: Internationalisation; bug fix - battery icon responds promptly to charging state
|
||||||
0.04: bug fix
|
0.04: bug fix
|
||||||
0.05: proper fix for the race condition in queueDraw()
|
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 drawTimeout;
|
||||||
|
var lastBattCheck = 0;
|
||||||
|
var width = 0;
|
||||||
|
|
||||||
function queueDraw(millis_now) {
|
function queueDraw(millis_now) {
|
||||||
if (drawTimeout) clearTimeout(drawTimeout);
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
@ -24,12 +26,15 @@ function draw() {
|
||||||
var date = new Date();
|
var date = new Date();
|
||||||
var h = date.getHours(),
|
var h = date.getHours(),
|
||||||
m = date.getMinutes();
|
m = date.getMinutes();
|
||||||
var d = date.getDate(),
|
var d = date.getDate();
|
||||||
w = date.getDay(); // d=1..31; w=0..6
|
|
||||||
const level = E.getBattery();
|
|
||||||
const width = level + (level/2);
|
|
||||||
var is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"];
|
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.reset();
|
||||||
g.clear();
|
g.clear();
|
||||||
|
@ -47,24 +52,35 @@ function draw() {
|
||||||
g.drawString(d, g.getWidth() -6, 98);
|
g.drawString(d, g.getWidth() -6, 98);
|
||||||
g.setFont('Vector', 52);
|
g.setFont('Vector', 52);
|
||||||
g.setFontAlign(-1, -1);
|
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(9,159,166,171);
|
||||||
g.fillRect(167,163,170,167);
|
g.fillRect(167,163,170,167);
|
||||||
if (Bangle.isCharging()) {
|
if (Bangle.isCharging()) {
|
||||||
g.setColor(1,1,0);
|
g.setColor(1,1,0);
|
||||||
} else if (level > 40) {
|
g.fillRect(12,162,12+width,168);
|
||||||
g.setColor(0,1,0);
|
|
||||||
} else {
|
} else {
|
||||||
g.setColor(1,0,0);
|
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 (width < 150) {
|
||||||
if (level < 100) {
|
|
||||||
g.setColor(g.theme.bg);
|
g.setColor(g.theme.bg);
|
||||||
g.fillRect(12+width+1,162,162,168);
|
g.fillRect(12+width+1,162,162,168);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.setColor(0, 1, 0);
|
||||||
|
}
|
||||||
g.fillRect(0, 90, g.getWidth(), 94);
|
g.fillRect(0, 90, g.getWidth(), 94);
|
||||||
|
|
||||||
// widget redraw
|
// widget redraw
|
||||||
|
@ -85,7 +101,8 @@ Bangle.on('charging', (charging) => {
|
||||||
draw();
|
draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
draw();
|
draw();
|
||||||
|
|
||||||
Bangle.setUI("clock");
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ "id": "bigdclock",
|
{ "id": "bigdclock",
|
||||||
"name": "Big digit clock containing just the essentials",
|
"name": "Big digit clock containing just the essentials",
|
||||||
"shortName":"Big digit clk",
|
"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.",
|
"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",
|
"icon": "bigdclock.png",
|
||||||
"type": "clock",
|
"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.01: New App!
|
||||||
0.02: Fixed bug where screen didn't clear so incorrect time displayed.
|
0.02: Fixed bug where screen didn't clear so incorrect time displayed.
|
||||||
0.03: Update to use Bangle.setUI instead of setWatch
|
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
|
draw(); // draw immediately
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Load widgets
|
|
||||||
Bangle.loadWidgets();
|
|
||||||
Bangle.drawWidgets();
|
|
||||||
// Show launcher when button pressed
|
// Show launcher when button pressed
|
||||||
Bangle.setUI("clockupdown", btn=>{
|
Bangle.setUI("clockupdown", btn=>{
|
||||||
if (btn!=1) return;
|
if (btn!=1) return;
|
||||||
|
@ -176,3 +173,6 @@ Bangle.setUI("clockupdown", btn=>{
|
||||||
displayTime = 0;
|
displayTime = 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Load widgets
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "binclock",
|
"id": "binclock",
|
||||||
"name": "Binary Clock",
|
"name": "Binary Clock",
|
||||||
"shortName": "Binary Clock",
|
"shortName": "Binary Clock",
|
||||||
"version": "0.03",
|
"version": "0.04",
|
||||||
"description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.",
|
"description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
|
|
|
@ -2,3 +2,5 @@
|
||||||
0.02: first running version for BangleJs2
|
0.02: first running version for BangleJs2
|
||||||
0.03: corrected icon, added screen shot, extended description
|
0.03: corrected icon, added screen shot, extended description
|
||||||
0.04: corrected format of background image (raw binary)
|
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 hour = 0, minute = 1, second = 50;
|
||||||
var batVLevel = 20;
|
var batVLevel = 20;
|
||||||
|
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
|
@ -371,7 +372,6 @@ function draw() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show launcher when button pressed
|
// Show launcher when button pressed
|
||||||
Bangle.setUI("clock");
|
|
||||||
setRuntimeValues(g.getWidth());
|
setRuntimeValues(g.getWidth());
|
||||||
g.reset().clear();
|
g.reset().clear();
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"shortName":"BinWatch",
|
"shortName":"BinWatch",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"screenshots": [{"url":"screenshot.png"}],
|
"screenshots": [{"url":"screenshot.png"}],
|
||||||
"version":"0.04",
|
"version":"0.05",
|
||||||
"supports": ["BANGLEJS2"],
|
"supports": ["BANGLEJS2"],
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"allow_emulator":true,
|
"allow_emulator":true,
|
||||||
|
|
|
@ -5,3 +5,4 @@
|
||||||
0.04: Modified to account for changes in the behavior of Graphics.fillPoly
|
0.04: Modified to account for changes in the behavior of Graphics.fillPoly
|
||||||
0.05: Slight increase to draw speed after LCD on
|
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.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();
|
Bangle.drawWidgets();
|
||||||
intervalRef = setInterval(redraw,1000);
|
intervalRef = setInterval(redraw,1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show launcher when button pressed
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
startTimers();
|
startTimers();
|
||||||
Bangle.on('lcdPower',function(on) {
|
Bangle.on('lcdPower',function(on) {
|
||||||
|
@ -108,5 +112,3 @@ Bangle.on('lcdPower',function(on) {
|
||||||
clearTimers();
|
clearTimers();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Show launcher when button pressed
|
|
||||||
Bangle.setUI("clock");
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "blobclk",
|
"id": "blobclk",
|
||||||
"name": "Large Digit Blob Clock",
|
"name": "Large Digit Blob Clock",
|
||||||
"shortName": "Blob Clock",
|
"shortName": "Blob Clock",
|
||||||
"version": "0.06",
|
"version": "0.07",
|
||||||
"description": "A clock with big digits",
|
"description": "A clock with big digits",
|
||||||
"icon": "clock-blob.png",
|
"icon": "clock-blob.png",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
0.04: Work with themes, smaller screens
|
0.04: Work with themes, smaller screens
|
||||||
0.05: Adjust hand lengths to be within 'tick' points
|
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.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();
|
g.clear();
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
startTimers();
|
startTimers();
|
||||||
// Show launcher when button pressed
|
|
||||||
Bangle.setUI("clock");
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "boldclk",
|
"id": "boldclk",
|
||||||
"name": "Bold Clock",
|
"name": "Bold Clock",
|
||||||
"version": "0.06",
|
"version": "0.07",
|
||||||
"description": "Simple, readable and practical clock",
|
"description": "Simple, readable and practical clock",
|
||||||
"icon": "bold_clock.png",
|
"icon": "bold_clock.png",
|
||||||
"screenshots": [{"url":"screenshot_bold.png"}],
|
"screenshots": [{"url":"screenshot_bold.png"}],
|
||||||
|
|
|
@ -11,3 +11,13 @@
|
||||||
0.11: Performance improvements.
|
0.11: Performance improvements.
|
||||||
0.12: Implements a 2D menu.
|
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
|
# BW Clock
|
||||||
A very minimalistic clock with date and time in focus.
|
A very minimalistic clock.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Features
|
## 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.
|
- 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*
|
- Weather temperature as well as the wind speed can be shown. *Requirement: Weather app*
|
||||||
- HomeAssistant triggers can be executed directly. *Requirement: HomeAssistant 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.
|
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
|
## Settings
|
||||||
- Fullscreen on/off (widgets are still loaded).
|
- Screen: Normal (widgets shown), Dynamic (widgets shown if unlocked) or Full (widgets are hidden).
|
||||||
- Enable/disable lock icon in the settings. Useful if fullscreen is on.
|
- 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.
|
- 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
|
## 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
|
## Creator
|
||||||
[David Peer](https://github.com/peerdavid)
|
[David Peer](https://github.com/peerdavid)
|
||||||
|
|
|
@ -1,22 +1,25 @@
|
||||||
/************
|
/************************************************
|
||||||
* Includes
|
* Includes
|
||||||
*/
|
*/
|
||||||
const locale = require('locale');
|
const locale = require('locale');
|
||||||
const storage = require('Storage');
|
const storage = require('Storage');
|
||||||
|
const clock_info = require("clock_info");
|
||||||
|
|
||||||
/************
|
|
||||||
* Statics
|
/************************************************
|
||||||
|
* Globals
|
||||||
*/
|
*/
|
||||||
const SETTINGS_FILE = "bwclk.setting.json";
|
const SETTINGS_FILE = "bwclk.setting.json";
|
||||||
const TIMER_IDX = "bwclk";
|
|
||||||
const W = g.getWidth();
|
const W = g.getWidth();
|
||||||
const H = g.getHeight();
|
const H = g.getHeight();
|
||||||
|
var lock_input = false;
|
||||||
|
|
||||||
/************
|
|
||||||
|
/************************************************
|
||||||
* Settings
|
* Settings
|
||||||
*/
|
*/
|
||||||
let settings = {
|
let settings = {
|
||||||
fullscreen: false,
|
screen: "Normal",
|
||||||
showLock: true,
|
showLock: true,
|
||||||
hideColon: false,
|
hideColon: false,
|
||||||
menuPosX: 0,
|
menuPosX: 0,
|
||||||
|
@ -28,22 +31,10 @@ for (const key in saved_settings) {
|
||||||
settings[key] = saved_settings[key]
|
settings[key] = saved_settings[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************************************************
|
||||||
/************
|
|
||||||
* Assets
|
* Assets
|
||||||
*/
|
*/
|
||||||
// Manrope font
|
// 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) {
|
Graphics.prototype.setLargeFont = function(scale) {
|
||||||
// Actual height 47 (48 - 2)
|
// Actual height 47 (48 - 2)
|
||||||
this.setFontCustom(
|
this.setFontCustom(
|
||||||
|
@ -55,14 +46,12 @@ Graphics.prototype.setLargeFont = function(scale) {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Graphics.prototype.setMediumFont = function(scale) {
|
Graphics.prototype.setMediumFont = function(scale) {
|
||||||
// Actual height 41 (42 - 2)
|
// 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));
|
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;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Graphics.prototype.setSmallFont = function(scale) {
|
Graphics.prototype.setSmallFont = function(scale) {
|
||||||
// Actual height 28 (27 - 0)
|
// Actual height 28 (27 - 0)
|
||||||
this.setFontCustom(
|
this.setFontCustom(
|
||||||
|
@ -74,6 +63,16 @@ Graphics.prototype.setSmallFont = function(scale) {
|
||||||
return this;
|
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(){
|
function imgLock(){
|
||||||
return {
|
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 {
|
* Menu
|
||||||
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]]
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
var menu = [
|
// Custom bwItems menu - therefore, its added here and not in a clkinfo.js file.
|
||||||
[
|
var bwItems = {
|
||||||
function(){ return [ null, null ] },
|
name: null,
|
||||||
],
|
img: null,
|
||||||
[
|
items: [
|
||||||
function(){ return [ "Bangle", imgWatch() ] },
|
{ name: "WeekOfYear",
|
||||||
function(){ return [ E.getBattery() + "%", Bangle.isCharging() ? imgCharging() : imgBattery() ] },
|
get: () => ({ text: "Week " + weekOfYear(), img: null}),
|
||||||
function(){ return [ getSteps(), imgSteps() ] },
|
show: function() { bwItems.items[0].emit("redraw"); },
|
||||||
function(){ return [ Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", imgBpm()] },
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
function weekOfYear() {
|
||||||
* WEATHER MENU
|
var date = new Date();
|
||||||
*/
|
date.setHours(0, 0, 0, 0);
|
||||||
if(storage.readJSON('weather.json') !== undefined){
|
// Thursday in current week decides the year.
|
||||||
menu.push([
|
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
|
||||||
function(){ return [ "Weather", imgWeather() ] },
|
// January 4 is always in week 1.
|
||||||
function(){ return [ getWeather().temp, imgTemperature() ] },
|
var week1 = new Date(date.getFullYear(), 0, 4);
|
||||||
function(){ return [ getWeather().wind, imgWind() ] },
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
// Load menu
|
||||||
* HOME ASSISTANT MENU
|
var menu = clock_info.load();
|
||||||
*/
|
menu = menu.concat(bwItems);
|
||||||
try{
|
|
||||||
var triggers = require("ha.lib.js").getTriggers();
|
|
||||||
var haMenu = [
|
|
||||||
function(){ return [ "Home", imgHomeAssistant() ] },
|
|
||||||
];
|
|
||||||
|
|
||||||
triggers.forEach(trigger => {
|
|
||||||
haMenu.push(function(){
|
// Ensure that our settings are still in range (e.g. app uninstall). Otherwise reset the position it.
|
||||||
return [trigger.display, trigger.getIcon(), () => {}, () => {}, function(){
|
if(settings.menuPosX >= menu.length || settings.menuPosY > menu[settings.menuPosX].items.length ){
|
||||||
var ha = require("ha.lib.js");
|
settings.menuPosX = 0;
|
||||||
ha.sendTrigger("TRIGGER_BW");
|
settings.menuPosY = 0;
|
||||||
ha.sendTrigger(trigger.trigger);
|
}
|
||||||
}]
|
|
||||||
});
|
// 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(){
|
function canRunMenuItem(){
|
||||||
// In case the user removes HomeAssistant entries, showInfo
|
if(settings.menuPosY == 0){
|
||||||
// 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.
|
|
||||||
}
|
|
||||||
|
|
||||||
steps = Math.round(steps/100) / 10; // This ensures that we do not show e.g. 15.0k and 15k instead
|
|
||||||
return steps + "k";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
temp: " ? ",
|
|
||||||
hum: " ? ",
|
|
||||||
txt: " ? ",
|
|
||||||
wind: " ? ",
|
|
||||||
wdir: " ? ",
|
|
||||||
wrose: " ? "
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function isAlarmEnabled(){
|
|
||||||
try{
|
|
||||||
var alarm = require('sched');
|
|
||||||
var alarmObj = alarm.getAlarm(TIMER_IDX);
|
|
||||||
if(alarmObj===undefined || !alarmObj.on){
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
var menuEntry = menu[settings.menuPosX];
|
||||||
|
var item = menuEntry.items[settings.menuPosY-1];
|
||||||
} catch(ex){ }
|
return item.run !== undefined;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getAlarmMinutes(){
|
function runMenuItem(){
|
||||||
if(!isAlarmEnabled()){
|
if(settings.menuPosY == 0){
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var alarm = require('sched');
|
var menuEntry = menu[settings.menuPosX];
|
||||||
var alarmObj = alarm.getAlarm(TIMER_IDX);
|
var item = menuEntry.items[settings.menuPosY-1];
|
||||||
return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function increaseAlarm(){
|
|
||||||
try{
|
try{
|
||||||
var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0;
|
var ret = item.run();
|
||||||
var alarm = require('sched')
|
if(ret){
|
||||||
alarm.setAlarm(TIMER_IDX, {
|
Bangle.buzz(300, 0.6);
|
||||||
timer : (minutes+5)*60*1000,
|
}
|
||||||
});
|
} catch (ex) {
|
||||||
alarm.reload();
|
// Simply ignore it...
|
||||||
} 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() {
|
function draw() {
|
||||||
// Queue draw again
|
// Queue draw again
|
||||||
|
@ -363,7 +183,7 @@ function draw() {
|
||||||
|
|
||||||
// Draw clock
|
// Draw clock
|
||||||
drawDate();
|
drawDate();
|
||||||
drawTime();
|
drawMenuAndTime();
|
||||||
drawLock();
|
drawLock();
|
||||||
drawWidgets();
|
drawWidgets();
|
||||||
}
|
}
|
||||||
|
@ -371,12 +191,12 @@ function draw() {
|
||||||
|
|
||||||
function drawDate(){
|
function drawDate(){
|
||||||
// Draw background
|
// Draw background
|
||||||
var y = H/5*2;
|
var y = H/5*2 + (isFullscreen() ? 0 : 8);
|
||||||
g.reset().clearRect(0,0,W,W);
|
g.reset().clearRect(0,0,W,y);
|
||||||
|
|
||||||
// Draw date
|
// Draw date
|
||||||
y = parseInt(y/2)+4;
|
y = parseInt(y/2)+4;
|
||||||
y += settings.fullscreen ? 0 : 13;
|
y += isFullscreen() ? 0 : 8;
|
||||||
var date = new Date();
|
var date = new Date();
|
||||||
var dateStr = date.getDate();
|
var dateStr = date.getDate();
|
||||||
dateStr = ("0" + dateStr).substr(-2);
|
dateStr = ("0" + dateStr).substr(-2);
|
||||||
|
@ -395,15 +215,12 @@ function drawDate(){
|
||||||
|
|
||||||
g.setMediumFont();
|
g.setMediumFont();
|
||||||
g.setColor(g.theme.fg);
|
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
|
// 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();
|
var date = new Date();
|
||||||
|
|
||||||
// Draw time
|
// Draw time
|
||||||
|
@ -419,45 +236,65 @@ function drawTime(){
|
||||||
// Set y coordinates correctly
|
// Set y coordinates correctly
|
||||||
y += parseInt((H - y)/2) + 5;
|
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
|
// Show large or small time depending on info entry
|
||||||
if(menuName == null){
|
if(smallText){
|
||||||
if(settings.hideColon){
|
y -= 15;
|
||||||
g.setXLargeFont();
|
g.setMediumFont();
|
||||||
} else {
|
} else {
|
||||||
g.setLargeFont();
|
g.setLargeFont();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
y -= 15;
|
|
||||||
g.setMediumFont();
|
|
||||||
}
|
|
||||||
g.drawString(timeStr, W/2, y);
|
g.drawString(timeStr, W/2, y);
|
||||||
|
}
|
||||||
|
|
||||||
// Draw menu if set
|
function drawMenuItem(text, image){
|
||||||
if(menuName == null){
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
y += 35;
|
// Draw item if needed
|
||||||
g.setFontAlign(0,0);
|
lock_input = true;
|
||||||
g.setSmallFont();
|
var item = menuEntry.items[settings.menuPosY-1];
|
||||||
var imgWidth = 0;
|
item.show();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -470,7 +307,7 @@ function drawLock(){
|
||||||
|
|
||||||
|
|
||||||
function drawWidgets(){
|
function drawWidgets(){
|
||||||
if(settings.fullscreen){
|
if(isFullscreen()){
|
||||||
for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
|
for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
|
||||||
} else {
|
} else {
|
||||||
Bangle.drawWidgets();
|
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
|
// timeout used to update every minute
|
||||||
var drawTimeout;
|
var drawTimeout;
|
||||||
|
@ -508,6 +355,13 @@ Bangle.on('lcdPower',on=>{
|
||||||
Bangle.on('lock', function(isLocked) {
|
Bangle.on('lock', function(isLocked) {
|
||||||
if (drawTimeout) clearTimeout(drawTimeout);
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
drawTimeout = undefined;
|
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();
|
draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -516,13 +370,13 @@ Bangle.on('charging',function(charging) {
|
||||||
drawTimeout = undefined;
|
drawTimeout = undefined;
|
||||||
|
|
||||||
// Jump to battery
|
// Jump to battery
|
||||||
settings.menuPosX = 1;
|
settings.menuPosX = 0;
|
||||||
settings.menuPosY = 1;
|
settings.menuPosY = 1;
|
||||||
draw();
|
draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
Bangle.on('touch', function(btn, e){
|
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 left = parseInt(g.getWidth() * 0.22);
|
||||||
var right = g.getWidth() - left;
|
var right = g.getWidth() - left;
|
||||||
var upper = parseInt(g.getHeight() * 0.22) + widget_size;
|
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_right = e.x > right && !is_upper && !is_lower;
|
||||||
var is_center = !is_upper && !is_lower && !is_left && !is_right;
|
var is_center = !is_upper && !is_lower && !is_left && !is_right;
|
||||||
|
|
||||||
if(is_lower){
|
if(lock_input){
|
||||||
Bangle.buzz(40, 0.6);
|
return;
|
||||||
settings.menuPosY = (settings.menuPosY+1) % menu[settings.menuPosX].length;
|
|
||||||
|
|
||||||
// Handle custom menu entry function
|
|
||||||
var menuEntry = getMenuEntry();
|
|
||||||
if(menuEntry.length > 2){
|
|
||||||
menuEntry[2]();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drawTime();
|
if(is_lower){
|
||||||
|
Bangle.buzz(40, 0.6);
|
||||||
|
settings.menuPosY = (settings.menuPosY+1) % (menu[settings.menuPosX].items.length+1);
|
||||||
|
|
||||||
|
drawMenuAndTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_upper){
|
if(is_upper){
|
||||||
|
@ -554,22 +406,16 @@ Bangle.on('touch', function(btn, e){
|
||||||
|
|
||||||
Bangle.buzz(40, 0.6);
|
Bangle.buzz(40, 0.6);
|
||||||
settings.menuPosY = settings.menuPosY-1;
|
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
|
drawMenuAndTime();
|
||||||
var menuEntry = getMenuEntry();
|
|
||||||
if(menuEntry.length > 3){
|
|
||||||
menuEntry[3]();
|
|
||||||
}
|
|
||||||
|
|
||||||
drawTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_right){
|
if(is_right){
|
||||||
Bangle.buzz(40, 0.6);
|
Bangle.buzz(40, 0.6);
|
||||||
settings.menuPosX = (settings.menuPosX+1) % menu.length;
|
settings.menuPosX = (settings.menuPosX+1) % menu.length;
|
||||||
settings.menuPosY = 0;
|
settings.menuPosY = 0;
|
||||||
drawTime();
|
drawMenuAndTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_left){
|
if(is_left){
|
||||||
|
@ -577,23 +423,12 @@ Bangle.on('touch', function(btn, e){
|
||||||
settings.menuPosY = 0;
|
settings.menuPosY = 0;
|
||||||
settings.menuPosX = settings.menuPosX-1;
|
settings.menuPosX = settings.menuPosX-1;
|
||||||
settings.menuPosX = settings.menuPosX < 0 ? menu.length-1 : settings.menuPosX;
|
settings.menuPosX = settings.menuPosX < 0 ? menu.length-1 : settings.menuPosX;
|
||||||
drawTime();
|
drawMenuAndTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_center){
|
if(is_center){
|
||||||
var menuEntry = getMenuEntry();
|
if(canRunMenuItem()){
|
||||||
if(menuEntry.length > 4){
|
runMenuItem();
|
||||||
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.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -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
|
// 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
|
// is enabled. In order to draw the widgets correctly, we invert the
|
||||||
// dark/light theme as well as the colors.
|
// dark/light theme as well as the colors.
|
||||||
g.setTheme({bg:g.theme.fg,fg:g.theme.bg, dark:!g.theme.dark}).clear();
|
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
|
// Show launcher when middle button pressed
|
||||||
Bangle.setUI("clock");
|
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",
|
"id": "bwclk",
|
||||||
"name": "BW Clock",
|
"name": "BW Clock",
|
||||||
"version": "0.13",
|
"version": "0.23",
|
||||||
"description": "A very minimalistic clock with date and time in focus.",
|
"description": "A very minimalistic clock to mainly show date and time.",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}, {"url":"screenshot_4.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...
|
// initialize with default settings...
|
||||||
const storage = require('Storage')
|
const storage = require('Storage')
|
||||||
let settings = {
|
let settings = {
|
||||||
fullscreen: false,
|
screen: "Normal",
|
||||||
showLock: true,
|
showLock: true,
|
||||||
hideColon: false,
|
hideColon: false,
|
||||||
};
|
};
|
||||||
|
@ -17,15 +17,16 @@
|
||||||
storage.write(SETTINGS_FILE, settings)
|
storage.write(SETTINGS_FILE, settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var screenOptions = ["Normal", "Dynamic", "Full"];
|
||||||
E.showMenu({
|
E.showMenu({
|
||||||
'': { 'title': 'BW Clock' },
|
'': { 'title': 'BW Clock' },
|
||||||
'< Back': back,
|
'< Back': back,
|
||||||
'Fullscreen': {
|
'Screen': {
|
||||||
value: settings.fullscreen,
|
value: 0 | screenOptions.indexOf(settings.screen),
|
||||||
format: () => (settings.fullscreen ? 'Yes' : 'No'),
|
min: 0, max: 2,
|
||||||
onchange: () => {
|
format: v => screenOptions[v],
|
||||||
settings.fullscreen = !settings.fullscreen;
|
onchange: v => {
|
||||||
|
settings.screen = screenOptions[v];
|
||||||
save();
|
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 |
|
@ -9,3 +9,4 @@
|
||||||
0.8: Update Some Variable Scopes to not use memory until need
|
0.8: Update Some Variable Scopes to not use memory until need
|
||||||
0.9: Remove ESLint spaces
|
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,10 +165,10 @@ Bangle.on("lock", (locked) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
|
||||||
// Load widgets, but don't show them
|
// Load widgets, but don't show them
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.setUI("clock");
|
|
||||||
|
|
||||||
g.reset();
|
g.reset();
|
||||||
g.clear();
|
g.clear();
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"description": "Animated Clock with Space Cassio Watch Style",
|
"description": "Animated Clock with Space Cassio Watch Style",
|
||||||
"screenshots": [{ "url": "screens/screen_night.png" },{ "url": "screens/screen_day.png" }],
|
"screenshots": [{ "url": "screens/screen_night.png" },{ "url": "screens/screen_day.png" }],
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version": "0.10",
|
"version": "0.11",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
"tags": "clock, weather, cassio, retro",
|
"tags": "clock, weather, cassio, retro",
|
||||||
"supports": ["BANGLEJS2"],
|
"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.02: Added scrollable calendar and swipe gestures
|
||||||
0.03: Configurable drag gestures
|
0.03: Configurable drag gestures
|
||||||
0.04: Use default Bangle formatter for booleans
|
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();
|
Bangle.loadWidgets();
|
||||||
|
|
||||||
var s = Object.assign({
|
var s = Object.assign({
|
||||||
|
@ -123,7 +124,7 @@ function drawMinutes() {
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
var hours = s.MODE24 ? d.getHours().toString().padStart(2, ' ') : ((d.getHours() + 24) % 12 || 12).toString().padStart(2, ' ');
|
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 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 size = 50;
|
||||||
var clock_x = (w - 20) / 2;
|
var clock_x = (w - 20) / 2;
|
||||||
if (dimSeconds) {
|
if (dimSeconds) {
|
||||||
|
@ -307,4 +308,4 @@ NRF.on('disconnect', BTevent);
|
||||||
|
|
||||||
dimSeconds = Bangle.isLocked();
|
dimSeconds = Bangle.isLocked();
|
||||||
drawWatch();
|
drawWatch();
|
||||||
Bangle.setUI("clock");
|
|
||||||
|
|