Merge branch 'master' into messages-load-function
|
|
@ -11,3 +11,6 @@ tests/Layout/testresult.bmp
|
|||
apps.local.json
|
||||
_site
|
||||
.jekyll-cache
|
||||
.owncloudsync.log
|
||||
Desktop.ini
|
||||
.sync_*.db*
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
0.01: New App!
|
||||
0.02: Fullscreen settings.
|
||||
0.02: Fullscreen settings.
|
||||
0.03: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -115,6 +115,9 @@ function draw() {
|
|||
}
|
||||
}
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.loadWidgets();
|
||||
|
||||
// Clear the screen once, at startup
|
||||
|
|
@ -140,5 +143,3 @@ Bangle.on('lock', function(isLocked) {
|
|||
});
|
||||
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "90sclk",
|
||||
"name": "90s Clock",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "A 90s style watch-face",
|
||||
"readme": "README.md",
|
||||
"icon": "app.png",
|
||||
|
|
|
|||
|
|
@ -6,3 +6,4 @@
|
|||
0.06: Add a temperature threshold to detect (and not alert) if the BJS isn't worn. Better support for the peoples using the app at night
|
||||
0.07: Fix bug on the cutting edge firmware
|
||||
0.08: Use default Bangle formatter for booleans
|
||||
0.09: New app screen (instead of showing settings or the alert) and some optimisations
|
||||
|
|
@ -0,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,54 @@
|
|||
(function () {
|
||||
// load variable before defining functions cause it can trigger a ReferenceError
|
||||
const activityreminder = require("activityreminder");
|
||||
const storage = require("Storage");
|
||||
const activityreminder_settings = activityreminder.loadSettings();
|
||||
let activityreminder_data = activityreminder.loadData();
|
||||
// load variable before defining functions cause it can trigger a ReferenceError
|
||||
const activityreminder = require("activityreminder");
|
||||
let activityreminder_data = activityreminder.loadData();
|
||||
let W = g.getWidth();
|
||||
// let H = g.getHeight();
|
||||
|
||||
function drawAlert() {
|
||||
E.showPrompt("Inactivity detected", {
|
||||
title: "Activity reminder",
|
||||
buttons: { "Ok": 1, "Dismiss": 2, "Pause": 3 }
|
||||
}).then(function (v) {
|
||||
if (v == 1) {
|
||||
activityreminder_data.okDate = new Date();
|
||||
}
|
||||
if (v == 2) {
|
||||
activityreminder_data.dismissDate = new Date();
|
||||
}
|
||||
if (v == 3) {
|
||||
activityreminder_data.pauseDate = new Date();
|
||||
}
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
load();
|
||||
});
|
||||
|
||||
// Obey system quiet mode:
|
||||
if (!(storage.readJSON('setting.json', 1) || {}).quiet) {
|
||||
Bangle.buzz(400);
|
||||
}
|
||||
setTimeout(load, 20000);
|
||||
}
|
||||
|
||||
function run() {
|
||||
if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) {
|
||||
drawAlert();
|
||||
} else {
|
||||
eval(storage.read("activityreminder.settings.js"))(() => load());
|
||||
}
|
||||
}
|
||||
function getHoursMins(date){
|
||||
var h = date.getHours();
|
||||
var m = date.getMinutes();
|
||||
return (""+h).substr(-2) + ":" + ("0"+m).substr(-2);
|
||||
}
|
||||
|
||||
function drawData(name, value, y){
|
||||
g.drawString(name, 10, y);
|
||||
g.drawString(value, 100, y);
|
||||
}
|
||||
|
||||
function drawInfo() {
|
||||
var h=18, y = h;
|
||||
g.setColor(g.theme.fg);
|
||||
g.setFont("Vector",h).setFontAlign(-1,-1);
|
||||
|
||||
// Header
|
||||
g.drawLine(0,25,W,25);
|
||||
g.drawLine(0,26,W,26);
|
||||
|
||||
g.drawString("Current Cycle", 10, y+=h);
|
||||
drawData("Start", getHoursMins(activityreminder_data.stepsDate), y+=h);
|
||||
drawData("Steps", getCurrentSteps(), y+=h);
|
||||
|
||||
/*
|
||||
g.drawString("Button Press", 10, y+=h*2);
|
||||
drawData("Ok", getHoursMins(activityreminder_data.okDate), y+=h);
|
||||
drawData("Dismiss", getHoursMins(activityreminder_data.dismissDate), y+=h);
|
||||
drawData("Pause", getHoursMins(activityreminder_data.pauseDate), y+=h);
|
||||
*/
|
||||
}
|
||||
|
||||
function getCurrentSteps(){
|
||||
let health = Bangle.getHealthStatus("day");
|
||||
return health.steps - activityreminder_data.stepsOnDate;
|
||||
}
|
||||
|
||||
function run() {
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
run();
|
||||
|
||||
drawInfo();
|
||||
}
|
||||
|
||||
run();
|
||||
|
||||
})();
|
||||
|
|
@ -1,70 +1,81 @@
|
|||
(function () {
|
||||
// load variable before defining functions cause it can trigger a ReferenceError
|
||||
const activityreminder = require("activityreminder");
|
||||
const activityreminder_settings = activityreminder.loadSettings();
|
||||
let activityreminder_data = activityreminder.loadData();
|
||||
|
||||
if (activityreminder_data.firstLoad) {
|
||||
activityreminder_data.firstLoad = false;
|
||||
// load variable before defining functions cause it can trigger a ReferenceError
|
||||
const activityreminder = require("activityreminder");
|
||||
const activityreminder_settings = activityreminder.loadSettings();
|
||||
let activityreminder_data = activityreminder.loadData();
|
||||
|
||||
if (activityreminder_data.firstLoad) {
|
||||
activityreminder_data.firstLoad = false;
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
}
|
||||
|
||||
function run() {
|
||||
if (isNotWorn()) return;
|
||||
let now = new Date();
|
||||
let h = now.getHours();
|
||||
|
||||
if (isDuringAlertHours(h)) {
|
||||
let health = Bangle.getHealthStatus("day");
|
||||
if (health.steps - activityreminder_data.stepsOnDate >= activityreminder_settings.minSteps // more steps made than needed
|
||||
|| health.steps < activityreminder_data.stepsOnDate) { // new day or reboot of the watch
|
||||
activityreminder_data.stepsOnDate = health.steps;
|
||||
activityreminder_data.stepsDate = now;
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
}
|
||||
|
||||
function run() {
|
||||
if (isNotWorn()) return;
|
||||
let now = new Date();
|
||||
let h = now.getHours();
|
||||
|
||||
if (isDuringAlertHours(h)) {
|
||||
let health = Bangle.getHealthStatus("day");
|
||||
if (health.steps - activityreminder_data.stepsOnDate >= activityreminder_settings.minSteps // more steps made than needed
|
||||
|| health.steps < activityreminder_data.stepsOnDate) { // new day or reboot of the watch
|
||||
activityreminder_data.stepsOnDate = health.steps;
|
||||
activityreminder_data.stepsDate = now;
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
/* todo in a futur release
|
||||
Add settimer to trigger like 30 secs after going in this part cause the person have been walking
|
||||
(pass some argument to run() to handle long walks and not triggering so often)
|
||||
*/
|
||||
}
|
||||
|
||||
if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) {
|
||||
load('activityreminder.app.js');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isNotWorn() {
|
||||
return (Bangle.isCharging() || activityreminder_settings.tempThreshold >= E.getTemperature());
|
||||
}
|
||||
|
||||
function isDuringAlertHours(h) {
|
||||
if (activityreminder_settings.startHour < activityreminder_settings.endHour) { // not passing through midnight
|
||||
return (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour);
|
||||
} else { // passing through midnight
|
||||
return (h >= activityreminder_settings.startHour || h < activityreminder_settings.endHour);
|
||||
}
|
||||
}
|
||||
|
||||
Bangle.on('midnight', function () {
|
||||
/*
|
||||
Usefull trick to have the app working smothly for people using it at night
|
||||
*/
|
||||
let now = new Date();
|
||||
let h = now.getHours();
|
||||
if (activityreminder_settings.enabled && isDuringAlertHours(h)) {
|
||||
// updating only the steps and keeping the original stepsDate on purpose
|
||||
activityreminder_data.stepsOnDate = 0;
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (activityreminder_settings.enabled) {
|
||||
setInterval(run, 60000);
|
||||
/* todo in a futur release
|
||||
increase setInterval time to something that is still sensible (5 mins ?)
|
||||
when we added a settimer
|
||||
Add settimer to trigger like 30 secs after going in this part cause the person have been walking
|
||||
(pass some argument to run() to handle long walks and not triggering so often)
|
||||
*/
|
||||
}
|
||||
|
||||
if (mustAlert(now)) {
|
||||
load('activityreminder.alert.js');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isNotWorn() {
|
||||
return (Bangle.isCharging() || activityreminder_settings.tempThreshold >= E.getTemperature());
|
||||
}
|
||||
|
||||
function isDuringAlertHours(h) {
|
||||
if (activityreminder_settings.startHour < activityreminder_settings.endHour) { // not passing through midnight
|
||||
return (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour);
|
||||
} else { // passing through midnight
|
||||
return (h >= activityreminder_settings.startHour || h < activityreminder_settings.endHour);
|
||||
}
|
||||
}
|
||||
|
||||
function mustAlert(now) {
|
||||
if ((now - activityreminder_data.stepsDate) / 60000 > activityreminder_settings.maxInnactivityMin) { // inactivity detected
|
||||
if ((now - activityreminder_data.okDate) / 60000 > 3 && // last alert anwsered with ok was more than 3 min ago
|
||||
(now - activityreminder_data.dismissDate) / 60000 > activityreminder_settings.dismissDelayMin && // last alert was more than dismissDelayMin ago
|
||||
(now - activityreminder_data.pauseDate) / 60000 > activityreminder_settings.pauseDelayMin) { // last alert was more than pauseDelayMin ago
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Bangle.on('midnight', function () {
|
||||
/*
|
||||
Usefull trick to have the app working smothly for people using it at night
|
||||
*/
|
||||
let now = new Date();
|
||||
let h = now.getHours();
|
||||
if (activityreminder_settings.enabled && isDuringAlertHours(h)) {
|
||||
// updating only the steps and keeping the original stepsDate on purpose
|
||||
activityreminder_data.stepsOnDate = 0;
|
||||
activityreminder.saveData(activityreminder_data);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (activityreminder_settings.enabled) {
|
||||
setInterval(run, 60000);
|
||||
/* todo in a futur release
|
||||
increase setInterval time to something that is still sensible (5 mins ?)
|
||||
when we added a settimer
|
||||
*/
|
||||
}
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -1,56 +1,44 @@
|
|||
exports.loadSettings = function () {
|
||||
return Object.assign({
|
||||
enabled: true,
|
||||
startHour: 9,
|
||||
endHour: 20,
|
||||
maxInnactivityMin: 30,
|
||||
dismissDelayMin: 15,
|
||||
pauseDelayMin: 120,
|
||||
minSteps: 50,
|
||||
tempThreshold: 27
|
||||
}, require("Storage").readJSON("activityreminder.s.json", true) || {});
|
||||
return Object.assign({
|
||||
enabled: true,
|
||||
startHour: 9,
|
||||
endHour: 20,
|
||||
maxInnactivityMin: 30,
|
||||
dismissDelayMin: 15,
|
||||
pauseDelayMin: 120,
|
||||
minSteps: 50,
|
||||
tempThreshold: 27
|
||||
}, require("Storage").readJSON("activityreminder.s.json", true) || {});
|
||||
};
|
||||
|
||||
exports.writeSettings = function (settings) {
|
||||
require("Storage").writeJSON("activityreminder.s.json", settings);
|
||||
require("Storage").writeJSON("activityreminder.s.json", settings);
|
||||
};
|
||||
|
||||
exports.saveData = function (data) {
|
||||
require("Storage").writeJSON("activityreminder.data.json", data);
|
||||
require("Storage").writeJSON("activityreminder.data.json", data);
|
||||
};
|
||||
|
||||
exports.loadData = function () {
|
||||
let health = Bangle.getHealthStatus("day");
|
||||
let data = Object.assign({
|
||||
firstLoad: true,
|
||||
stepsDate: new Date(),
|
||||
stepsOnDate: health.steps,
|
||||
okDate: new Date(1970),
|
||||
dismissDate: new Date(1970),
|
||||
pauseDate: new Date(1970),
|
||||
},
|
||||
let health = Bangle.getHealthStatus("day");
|
||||
let data = Object.assign({
|
||||
firstLoad: true,
|
||||
stepsDate: new Date(),
|
||||
stepsOnDate: health.steps,
|
||||
okDate: new Date(1970),
|
||||
dismissDate: new Date(1970),
|
||||
pauseDate: new Date(1970),
|
||||
},
|
||||
require("Storage").readJSON("activityreminder.data.json") || {});
|
||||
|
||||
if(typeof(data.stepsDate) == "string")
|
||||
data.stepsDate = new Date(data.stepsDate);
|
||||
if(typeof(data.okDate) == "string")
|
||||
data.okDate = new Date(data.okDate);
|
||||
if(typeof(data.dismissDate) == "string")
|
||||
data.dismissDate = new Date(data.dismissDate);
|
||||
if(typeof(data.pauseDate) == "string")
|
||||
data.pauseDate = new Date(data.pauseDate);
|
||||
if (typeof (data.stepsDate) == "string")
|
||||
data.stepsDate = new Date(data.stepsDate);
|
||||
if (typeof (data.okDate) == "string")
|
||||
data.okDate = new Date(data.okDate);
|
||||
if (typeof (data.dismissDate) == "string")
|
||||
data.dismissDate = new Date(data.dismissDate);
|
||||
if (typeof (data.pauseDate) == "string")
|
||||
data.pauseDate = new Date(data.pauseDate);
|
||||
|
||||
return data;
|
||||
return data;
|
||||
};
|
||||
|
||||
exports.mustAlert = function(activityreminder_data, activityreminder_settings) {
|
||||
let now = new Date();
|
||||
if ((now - activityreminder_data.stepsDate) / 60000 > activityreminder_settings.maxInnactivityMin) { // inactivity detected
|
||||
if ((now - activityreminder_data.okDate) / 60000 > 3 && // last alert anwsered with ok was more than 3 min ago
|
||||
(now - activityreminder_data.dismissDate) / 60000 > activityreminder_settings.dismissDelayMin && // last alert was more than dismissDelayMin ago
|
||||
(now - activityreminder_data.pauseDate) / 60000 > activityreminder_settings.pauseDelayMin) { // last alert was more than pauseDelayMin ago
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Activity Reminder",
|
||||
"shortName":"Activity Reminder",
|
||||
"description": "A reminder to take short walks for the ones with a sedentary lifestyle",
|
||||
"version":"0.08",
|
||||
"version":"0.09",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
"tags": "tool,activity",
|
||||
|
|
@ -13,11 +13,12 @@
|
|||
{"name": "activityreminder.app.js", "url":"app.js"},
|
||||
{"name": "activityreminder.boot.js", "url": "boot.js"},
|
||||
{"name": "activityreminder.settings.js", "url": "settings.js"},
|
||||
{"name": "activityreminder.alert.js", "url": "alert.js"},
|
||||
{"name": "activityreminder", "url": "lib.js"},
|
||||
{"name": "activityreminder.img", "url": "app-icon.js", "evaluate": true}
|
||||
],
|
||||
"data": [
|
||||
{"name": "activityreminder.s.json"},
|
||||
{"name": "activityreminder.data.json"}
|
||||
{"name": "activityreminder.data.json", "storageFile": true}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,80 +1,86 @@
|
|||
(function (back) {
|
||||
// Load settings
|
||||
const activityreminder = require("activityreminder");
|
||||
let settings = activityreminder.loadSettings();
|
||||
// Load settings
|
||||
const activityreminder = require("activityreminder");
|
||||
let settings = activityreminder.loadSettings();
|
||||
|
||||
// Show the menu
|
||||
E.showMenu({
|
||||
"": { "title": "Activity Reminder" },
|
||||
"< Back": () => back(),
|
||||
'Enable': {
|
||||
value: settings.enabled,
|
||||
onchange: v => {
|
||||
settings.enabled = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'Start hour': {
|
||||
value: settings.startHour,
|
||||
min: 0, max: 24,
|
||||
onchange: v => {
|
||||
settings.startHour = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'End hour': {
|
||||
value: settings.endHour,
|
||||
min: 0, max: 24,
|
||||
onchange: v => {
|
||||
settings.endHour = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'Max inactivity': {
|
||||
value: settings.maxInnactivityMin,
|
||||
min: 15, max: 120,
|
||||
onchange: v => {
|
||||
settings.maxInnactivityMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => x + "m"
|
||||
},
|
||||
'Dismiss delay': {
|
||||
value: settings.dismissDelayMin,
|
||||
min: 5, max: 60,
|
||||
onchange: v => {
|
||||
settings.dismissDelayMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => x + "m"
|
||||
},
|
||||
'Pause delay': {
|
||||
value: settings.pauseDelayMin,
|
||||
min: 30, max: 240, step: 5,
|
||||
onchange: v => {
|
||||
settings.pauseDelayMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => {
|
||||
return x + "m";
|
||||
}
|
||||
},
|
||||
'Min steps': {
|
||||
value: settings.minSteps,
|
||||
min: 10, max: 500, step: 10,
|
||||
onchange: v => {
|
||||
settings.minSteps = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'Temp Threshold': {
|
||||
value: settings.tempThreshold,
|
||||
min: 20, max: 40, step: 0.5,
|
||||
format: v => v + "°C",
|
||||
onchange: v => {
|
||||
settings.tempThreshold = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
function getMainMenu(){
|
||||
var mainMenu = {
|
||||
"": { "title": "Activity Reminder" },
|
||||
"< Back": () => back(),
|
||||
'Enable': {
|
||||
value: settings.enabled,
|
||||
onchange: v => {
|
||||
settings.enabled = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
});
|
||||
},
|
||||
'Start hour': {
|
||||
value: settings.startHour,
|
||||
min: 0, max: 24,
|
||||
onchange: v => {
|
||||
settings.startHour = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'End hour': {
|
||||
value: settings.endHour,
|
||||
min: 0, max: 24,
|
||||
onchange: v => {
|
||||
settings.endHour = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'Max inactivity': {
|
||||
value: settings.maxInnactivityMin,
|
||||
min: 15, max: 120,
|
||||
onchange: v => {
|
||||
settings.maxInnactivityMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => x + "m"
|
||||
},
|
||||
'Dismiss delay': {
|
||||
value: settings.dismissDelayMin,
|
||||
min: 5, max: 60,
|
||||
onchange: v => {
|
||||
settings.dismissDelayMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => x + "m"
|
||||
},
|
||||
'Pause delay': {
|
||||
value: settings.pauseDelayMin,
|
||||
min: 30, max: 240, step: 5,
|
||||
onchange: v => {
|
||||
settings.pauseDelayMin = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
},
|
||||
format: x => {
|
||||
return x + "m";
|
||||
}
|
||||
},
|
||||
'Min steps': {
|
||||
value: settings.minSteps,
|
||||
min: 10, max: 500, step: 10,
|
||||
onchange: v => {
|
||||
settings.minSteps = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
},
|
||||
'Temp Threshold': {
|
||||
value: settings.tempThreshold,
|
||||
min: 20, max: 40, step: 0.5,
|
||||
format: v => v + "°C",
|
||||
onchange: v => {
|
||||
settings.tempThreshold = v;
|
||||
activityreminder.writeSettings(settings);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return mainMenu;
|
||||
}
|
||||
|
||||
// Show the menu
|
||||
E.showMenu(getMainMenu());
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
0.01: AdvCasio first version
|
||||
0.02: Remove un-needed fonts to improve memory usage
|
||||
0.03: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -294,9 +294,10 @@ Bangle.on("lock", (locked) => {
|
|||
});
|
||||
|
||||
|
||||
Bangle.setUI("clock");
|
||||
|
||||
// Load widgets, but don't show them
|
||||
Bangle.loadWidgets();
|
||||
Bangle.setUI("clock");
|
||||
|
||||
g.reset();
|
||||
g.clear();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "advcasio",
|
||||
"name": "Advanced Casio Clock",
|
||||
"shortName":"advcasio",
|
||||
"version":"0.02",
|
||||
"version":"0.03",
|
||||
"description": "An over-engineered clock inspired by Casio watches. It has a 4 days weather, a timer using swipe and a scratchpad. Can be updated using a dedicated webapp.",
|
||||
"icon": "app.png",
|
||||
"tags": "clock",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
0.01: Basic agenda with events from GB
|
||||
0.02: Added settings page to force calendar sync
|
||||
0.03: Disable past events display from settings
|
||||
0.04: Added awareness of allDay field
|
||||
|
|
|
|||
|
|
@ -26,18 +26,21 @@ var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4";
|
|||
var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[];
|
||||
var settings = require("Storage").readJSON("agenda.settings.json",true)||{};
|
||||
|
||||
CALENDAR=CALENDAR.sort((a,b)=>a.timestamp - b.timestamp)
|
||||
CALENDAR=CALENDAR.sort((a,b)=>a.timestamp - b.timestamp);
|
||||
|
||||
function getDate(timestamp) {
|
||||
return new Date(timestamp*1000);
|
||||
}
|
||||
function formatDateLong(date, includeDay) {
|
||||
if(includeDay)
|
||||
return Locale.date(date)+" "+Locale.time(date,1);
|
||||
return Locale.time(date,1);
|
||||
function formatDateLong(date, includeDay, allDay) {
|
||||
let shortTime = Locale.time(date,1)+Locale.meridian(date);
|
||||
if(allDay) shortTime = "";
|
||||
if(includeDay || allDay)
|
||||
return Locale.date(date)+" "+shortTime;
|
||||
return shortTime;
|
||||
}
|
||||
function formatDateShort(date) {
|
||||
return Locale.date(date).replace(/\d\d\d\d/,"")+Locale.time(date,1);
|
||||
function formatDateShort(date, allDay) {
|
||||
return Locale.date(date).replace(/\d\d\d\d/,"")+(allDay?
|
||||
"" : Locale.time(date,1)+Locale.meridian(date));
|
||||
}
|
||||
|
||||
var lines = [];
|
||||
|
|
@ -46,7 +49,7 @@ function showEvent(ev) {
|
|||
if(!ev) return;
|
||||
g.setFont(bodyFont);
|
||||
//var lines = [];
|
||||
if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10)
|
||||
if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10);
|
||||
var titleCnt = lines.length;
|
||||
var start = getDate(ev.timestamp);
|
||||
var end = getDate((+ev.timestamp) + (+ev.durationInSeconds));
|
||||
|
|
@ -54,17 +57,17 @@ function showEvent(ev) {
|
|||
if (titleCnt) lines.push(""); // add blank line after title
|
||||
if(start.getDay() == end.getDay() && start.getMonth() == end.getMonth())
|
||||
includeDay = false;
|
||||
if(includeDay) {
|
||||
if(includeDay || ev.allDay) {
|
||||
lines = lines.concat(
|
||||
/*LANG*/"Start:",
|
||||
g.wrapString(formatDateLong(start, includeDay), g.getWidth()-10),
|
||||
g.wrapString(formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10),
|
||||
/*LANG*/"End:",
|
||||
g.wrapString(formatDateLong(end, includeDay), g.getWidth()-10));
|
||||
g.wrapString(formatDateLong(end, includeDay, ev.allDay), g.getWidth()-10));
|
||||
} else {
|
||||
lines = lines.concat(
|
||||
g.wrapString(Locale.date(start), g.getWidth()-10),
|
||||
g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay), g.getWidth()-10),
|
||||
g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay), g.getWidth()-10));
|
||||
g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10),
|
||||
g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay, ev.allDay), g.getWidth()-10));
|
||||
}
|
||||
if(ev.location)
|
||||
lines = lines.concat(/*LANG*/"Location"+": ", g.wrapString(ev.location, g.getWidth()-10));
|
||||
|
|
@ -110,7 +113,7 @@ function showList() {
|
|||
if (!ev) return;
|
||||
var isPast = false;
|
||||
var x = r.x+2, title = ev.title;
|
||||
var body = formatDateShort(getDate(ev.timestamp))+"\n"+(ev.location?ev.location:/*LANG*/"No location");
|
||||
var body = formatDateShort(getDate(ev.timestamp),ev.allDay)+"\n"+(ev.location?ev.location:/*LANG*/"No location");
|
||||
if(settings.pastEvents) isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000;
|
||||
if (title) g.setFontAlign(-1,-1).setFont(fontBig)
|
||||
.setColor(isPast ? "#888" : g.theme.fg).drawString(title, x,r.y+2);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "agenda",
|
||||
"name": "Agenda",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "Simple agenda",
|
||||
"icon": "agenda.png",
|
||||
"screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}],
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
0.01: New App!
|
||||
0.02: Fix bug if image clock wasn't installed
|
||||
0.03: Update to use setUI
|
||||
0.04: Tell clock widgets to hide. Move loadWidgets() so it only runs on
|
||||
startup and not on every draw.
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ if (g.drawImages) {
|
|||
draw();
|
||||
var secondInterval = setInterval(draw,100);
|
||||
// load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
// Stop when LCD goes off
|
||||
Bangle.on('lcdPower',on=>{
|
||||
|
|
@ -104,3 +103,5 @@ if (g.drawImages) {
|
|||
}
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.loadWidgets();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "animclk",
|
||||
"name": "Animated Clock",
|
||||
"shortName": "Anim Clock",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "An animated clock face using Mark Ferrari's amazing 8 bit game art and palette cycling: http://www.markferrari.com/art/8bit-game-art",
|
||||
"icon": "app.png",
|
||||
"type": "clock",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
0.01: Create astral clock app
|
||||
0.02: Fixed Whirlpool galaxy RA/DA, larger compass display, fixed moonphase overlapping battery widget
|
||||
0.03: Update to use Bangle.setUI instead of setWatch
|
||||
0.04: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -767,6 +767,24 @@ function draw() {
|
|||
g.clear();
|
||||
current_moonphase = getMoonPhase();
|
||||
|
||||
Bangle.setUI("clockupdown", btn => {
|
||||
if (btn==0) {
|
||||
if (!processing) {
|
||||
if (!modeswitch) {
|
||||
modeswitch = true;
|
||||
if (mode == "planetary") mode = "extras";
|
||||
else mode = "planetary";
|
||||
}
|
||||
else
|
||||
modeswitch = false;
|
||||
}
|
||||
} else {
|
||||
if (!processing)
|
||||
ready_to_compute = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
|
@ -799,23 +817,6 @@ Bangle.setGPSPower(1);
|
|||
// Show launcher when button pressed
|
||||
Bangle.setClockMode();
|
||||
|
||||
Bangle.setUI("clockupdown", btn => {
|
||||
if (btn==0) {
|
||||
if (!processing) {
|
||||
if (!modeswitch) {
|
||||
modeswitch = true;
|
||||
if (mode == "planetary") mode = "extras";
|
||||
else mode = "planetary";
|
||||
}
|
||||
else
|
||||
modeswitch = false;
|
||||
}
|
||||
} else {
|
||||
if (!processing)
|
||||
ready_to_compute = true;
|
||||
}
|
||||
});
|
||||
|
||||
setWatch(function () {
|
||||
if (!astral_settings.astral_default) {
|
||||
colours_switched = true;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "astral",
|
||||
"name": "Astral Clock",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "Clock that calculates and displays Alt Az positions of all planets, Sun as well as several other astronomy targets (customizable) and current Moon phase. Coordinates are calculated by GPS & time and onscreen compass assists orienting. See Readme before using.",
|
||||
"icon": "app-icon.png",
|
||||
"type": "clock",
|
||||
|
|
|
|||
|
|
@ -7,3 +7,4 @@
|
|||
0.07: Step count resets at midnight
|
||||
0.08: Step count stored in memory to survive reloads. Now shows step count daily and since last reboot.
|
||||
0.09: NOW it really should reset daily (instead of every other day...)
|
||||
0.10: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -416,13 +416,13 @@ var layout = new Layout( {
|
|||
|
||||
// Clear the screen once, at startup
|
||||
g.clear();
|
||||
Bangle.setUI("clock");
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
Bangle.setUI("clock");
|
||||
layout.render();
|
||||
|
||||
Bangle.on('lock', function(locked) {
|
||||
if(!locked) {
|
||||
layout.render();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "Barcode clock",
|
||||
"shortName":"Barcode clock",
|
||||
"icon": "barcode.icon.png",
|
||||
"version":"0.09",
|
||||
"version":"0.10",
|
||||
"description": "EAN-8 compatible barcode clock.",
|
||||
"tags": "barcode,ean,ean-8,watchface,clock,clockface",
|
||||
"type": "clock",
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
0.01: App Created!
|
||||
0.02: Update to use Bangle.setUI instead of setWatch
|
||||
0.03: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -249,6 +249,9 @@ g.clear();
|
|||
g.setColor(0, 0.5, 0).drawImage(bg_crack);
|
||||
g.setColor(1, 1, 1).drawImage(batman);
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
|
|
@ -256,5 +259,3 @@ Bangle.drawWidgets();
|
|||
timeInterval = setInterval(showTime, 1000);
|
||||
showTime();
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "batclock",
|
||||
"name": "Bat Clock",
|
||||
"shortName": "Bat Clock",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.",
|
||||
"icon": "bat-clock.png",
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
0.02: Modified for use with new bootloader and firmware
|
||||
0.03: Update to use Bangle.setUI instead of setWatch
|
||||
0.04: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -100,10 +100,12 @@ Bangle.on('lcdPower', on => {
|
|||
if (on) drawClock();
|
||||
});
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
setInterval(() => { drawClock(); }, 1000);
|
||||
drawClock();
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "bclock",
|
||||
"name": "Binary Clock",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "A simple binary clock watch face",
|
||||
"icon": "clock-binary.png",
|
||||
"type": "clock",
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@
|
|||
0.03: Internationalisation; bug fix - battery icon responds promptly to charging state
|
||||
0.04: bug fix
|
||||
0.05: proper fix for the race condition in queueDraw()
|
||||
0.06: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@ Bangle.on('charging', (charging) => {
|
|||
draw();
|
||||
});
|
||||
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.loadWidgets();
|
||||
draw();
|
||||
|
||||
Bangle.setUI("clock");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "bigdclock",
|
||||
"name": "Big digit clock containing just the essentials",
|
||||
"shortName":"Big digit clk",
|
||||
"version":"0.05",
|
||||
"version":"0.06",
|
||||
"description": "A clock containing just the essentials, made as easy to read as possible for those of us that need glasses. It contains the time, the day-of-week, the day-of-month, and the current battery state-of-charge.",
|
||||
"icon": "bigdclock.png",
|
||||
"type": "clock",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
0.01: New App!
|
||||
0.02: Fixed bug where screen didn't clear so incorrect time displayed.
|
||||
0.03: Update to use Bangle.setUI instead of setWatch
|
||||
0.04: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -164,9 +164,6 @@ Bangle.on('lcdPower',on=>{
|
|||
draw(); // draw immediately
|
||||
}
|
||||
});
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clockupdown", btn=>{
|
||||
if (btn!=1) return;
|
||||
|
|
@ -176,3 +173,6 @@ Bangle.setUI("clockupdown", btn=>{
|
|||
displayTime = 0;
|
||||
}
|
||||
});
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "binclock",
|
||||
"name": "Binary Clock",
|
||||
"shortName": "Binary Clock",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.",
|
||||
"icon": "app.png",
|
||||
"type": "clock",
|
||||
|
|
|
|||
|
|
@ -2,3 +2,5 @@
|
|||
0.02: first running version for BangleJs2
|
||||
0.03: corrected icon, added screen shot, extended description
|
||||
0.04: corrected format of background image (raw binary)
|
||||
0.05: move setUI() up before draw() as to not have a false positive 'sanity
|
||||
check' when building on github.
|
||||
|
|
|
|||
|
|
@ -334,6 +334,7 @@ function setRuntimeValues(resolution) {
|
|||
var hour = 0, minute = 1, second = 50;
|
||||
var batVLevel = 20;
|
||||
|
||||
Bangle.setUI("clock");
|
||||
|
||||
function draw() {
|
||||
var d = new Date();
|
||||
|
|
@ -371,7 +372,6 @@ function draw() {
|
|||
}
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
setRuntimeValues(g.getWidth());
|
||||
g.reset().clear();
|
||||
Bangle.loadWidgets();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"shortName":"BinWatch",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
"version":"0.04",
|
||||
"version":"0.05",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator":true,
|
||||
|
|
|
|||
|
|
@ -5,3 +5,4 @@
|
|||
0.04: Modified to account for changes in the behavior of Graphics.fillPoly
|
||||
0.05: Slight increase to draw speed after LCD on
|
||||
0.06: Update to use Bangle.setUI instead of setWatch, allow themes and different size screens
|
||||
0.07: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -99,6 +99,10 @@ function startTimers() {
|
|||
Bangle.drawWidgets();
|
||||
intervalRef = setInterval(redraw,1000);
|
||||
}
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.loadWidgets();
|
||||
startTimers();
|
||||
Bangle.on('lcdPower',function(on) {
|
||||
|
|
@ -108,5 +112,3 @@ Bangle.on('lcdPower',function(on) {
|
|||
clearTimers();
|
||||
}
|
||||
});
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "blobclk",
|
||||
"name": "Large Digit Blob Clock",
|
||||
"shortName": "Blob Clock",
|
||||
"version": "0.06",
|
||||
"version": "0.07",
|
||||
"description": "A clock with big digits",
|
||||
"icon": "clock-blob.png",
|
||||
"type": "clock",
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@
|
|||
0.04: Work with themes, smaller screens
|
||||
0.05: Adjust hand lengths to be within 'tick' points
|
||||
0.06: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up".
|
||||
0.07: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -130,9 +130,10 @@ Bangle.on('lcdPower', (on) => {
|
|||
}
|
||||
});
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
startTimers();
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "boldclk",
|
||||
"name": "Bold Clock",
|
||||
"version": "0.06",
|
||||
"version": "0.07",
|
||||
"description": "Simple, readable and practical clock",
|
||||
"icon": "bold_clock.png",
|
||||
"screenshots": [{"url":"screenshot_bold.png"}],
|
||||
|
|
|
|||
|
|
@ -11,4 +11,10 @@
|
|||
0.11: Performance improvements.
|
||||
0.12: Implements a 2D menu.
|
||||
0.13: Clicks < 24px are for widgets, if fullscreen mode is disabled.
|
||||
0.14: Adds humidity to weather data.
|
||||
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.
|
||||
|
|
@ -4,15 +4,22 @@ A very minimalistic clock to mainly show date and time.
|
|||

|
||||
|
||||
## Features
|
||||
The BW clock provides many features as well as 3rd party integrations:
|
||||
The BW clock provides many features and also 3rd party integrations:
|
||||
- Bangle data such as steps, heart rate, battery or charging state.
|
||||
- A timer can be set directly. *Requirement: Scheduler library*
|
||||
- Show agenda entries. A timer for an agenda entry can also be set by simply clicking in the middle of the screen. This can be used to not forget a meeting etc. Note that only one agenda-timer can be set at a time. *Requirement: Gadgetbridge calendar sync enabled*
|
||||
- Weather temperature as well as the wind speed can be shown. *Requirement: Weather app*
|
||||
- HomeAssistant triggers can be executed directly. *Requirement: HomeAssistant app*
|
||||
|
||||
Note: If some apps are not installed (e.gt. weather app), then this menu item is hidden.
|
||||
|
||||
## Menu
|
||||
## Settings
|
||||
- Screen: Normal (widgets shown), Dynamic (widgets shown if unlocked) or Full (widgets are hidden).
|
||||
- Enable/disable lock icon in the settings. Useful if fullscreen mode is on.
|
||||
- The colon (e.g. 7:35 = 735) can be hidden in the settings for an even larger time font to improve readability further.
|
||||
- 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 set a timer or send a HomeAssistant trigger.
|
||||
|
||||
Simply click left / right to go through the menu entries such as Bangle, Timer etc.
|
||||
|
|
@ -22,25 +29,18 @@ 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 ... ...
|
||||
Bangle -- Timer[Optional] -- Agenda 1[Optional] -- Weather[Optional] -- HomeAssistant [Optional]
|
||||
| | | | |
|
||||
Bpm -5min Agenda 2 Temperature Trigger1
|
||||
| | | |
|
||||
Steps ... ... ...
|
||||
|
|
||||
Battery
|
||||
```
|
||||
|
||||
## Settings
|
||||
- Fullscreen on/off (widgets are still loaded).
|
||||
- Enable/disable lock icon in the settings. Useful if fullscreen is on.
|
||||
- The colon (e.g. 7:35 = 735) can be hidden in the settings for an even larger time font to improve readability further.
|
||||
- There are no design settings, as your bangle sys settings are used.
|
||||
|
||||
|
||||
## Thanks to
|
||||
<a href="https://www.flaticon.com/free-icons/" title="Icons">Icons created by Flaticon</a>
|
||||
|
||||
|
||||
## Creator
|
||||
[David Peer](https://github.com/peerdavid)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ const storage = require('Storage');
|
|||
* Statics
|
||||
*/
|
||||
const SETTINGS_FILE = "bwclk.setting.json";
|
||||
const TIMER_IDX = "bwclk";
|
||||
const TIMER_IDX = "bwclk_timer";
|
||||
const TIMER_AGENDA_IDX = "bwclk_agenda";
|
||||
const W = g.getWidth();
|
||||
const H = g.getHeight();
|
||||
|
||||
|
|
@ -16,7 +17,7 @@ const H = g.getHeight();
|
|||
* Settings
|
||||
*/
|
||||
let settings = {
|
||||
fullscreen: false,
|
||||
screen: "Normal",
|
||||
showLock: true,
|
||||
hideColon: false,
|
||||
menuPosX: 0,
|
||||
|
|
@ -33,17 +34,6 @@ for (const key in saved_settings) {
|
|||
* Assets
|
||||
*/
|
||||
// Manrope font
|
||||
Graphics.prototype.setXLargeFont = function(scale) {
|
||||
// Actual height 53 (55 - 3)
|
||||
this.setFontCustom(
|
||||
E.toString(require('heatshrink').decompress(atob('AHM/8AIG/+AA4sD/wQGh/4EWQA/AC8YA40HNA0BRY8/RY0P/6LFgf//4iFA4IiFj4HBEQkHCAQiDHIIZGv4HCFQY5BDAo5CAAIpDDAfACA3wLYv//hsFKYxcCMgoiBOooiBQwwiBS40AHIgA/ACS/DLYjYCBAjQEBAYQDBAgHDUAbyDZQi3CegoHEVQQZFagUfW4Y0DaAgECaIJSEFYMPbIYNDv5ACGAIrBCgJ1EFYILCAAQWCj4zDGgILCegcDEQRNDHIIiCHgZ2BEQShFIqUDFYidCh5ODg4NCn40DAgd/AYR5BDILZEAAIMDAAYVCh7aHdYhKDbQg4Dv7rGBAihFCAwIDCAgA/AB3/eoa7GAAk/dgbVGDJrvCDK67DDIjaGdYpbCdYonCcQjjDEVUBEQ4A/AEMcAYV/NAUHcYUDawd/cYUPRYSmBBgaLBToP8BgYiBSgIiCj4iCg//EQSuDW4IMDVwYiCBgIiBBgrRDCATeBaIYqCv70DCgT4CEQMfIgQZBBoRnDv/3EQIvBDIffEQMHFwReBRYUfOgX/+IiDKIeHEQRRECwUHKwIuB8AiDIoJEBCwZFCv/4HIZaBIgPAEQS2CUYQiCD4SABEQcfOwIZBEQaHBO4RcEAAI/BEQQgBSIQiDTIRZBEQZuBVYQiDHoKWCEQQICFQIiDBAQeCEQQA/AANwA40BLIJ5BO4JWCBAUPAYR5En7RBUIQECN4SYCQQIiEh6CCEQk/BoQiBgYeCBoTrCAgT0CCgIfCFYQiBg4IBGgIiDj6rBg4rCBYLRDFYIiBbYIfBLgQiBIQYiD4JCCLgf/bQIWDBYV/EQV/BYXz/5FBgIiD5//IowZBD4M/NAX/BIPgDIJoC//5GgKUDn//4f/8KLE/wTBAAI8BEQPwj4HBVwYmBDgIZDN4QZCGYKJCHQP/JoSgCBATrCh5dBKITVDG4gICAAbvDAH5SCL4QADK4J5CCAiTCCAp1BCAqCDCAgiGCAIiFCAQiFeoIiFg6/FCAgiECAXnEQgQB/kfEQYQC4F/EQYQCgIiDfoIQBg4iDCAUAEQZUCcgIiDDIIQBEQhuBBoIiENoYiFDwQiECAQiFwEBPQQNCAQKDDEYMDDoMfRh4iGUwqvEESBiBaQ5oEbgr0FNAo+EEIwA+oAHGgJoFRAMHe4L0CAALNBBAT0BfwScDCAXweAL0DWgUPQYQiDwF/QYQiC/zTB+C0FBAL0CEQYIBGgMPCgIxBg4rCJIKsCh5IBBwTPCj4WBgYLBZ4V/MAIiBBQQrBEQYtCBYQiCO4QLFCwgiDIQIiGIoMHEQpFBn5FFD4JoENwRoGDgSUCAoKfBw//DgIiCT4auCFwN/T4RRET4TaCEQKoCDIQiCGgK/DAAQICdYQACHoIqCBAoQFEwIhFAH4AFQIROEj4IGXwIIGNwIACbgIhEBAiRCVwoqDTogHEW4QZFXgIZB/z9Cv49CF4MPBwI0Ca4LlB8ATCJoP4AoINDfQPAg7PBg4cBBwUfD4MfFYILCCwgOCf4QLEwEPCwILCgJaBn4WBBYQxCIQQiD+EDCYI5CBYRQBIo4fBMQIuBC4N/NAv8AoIcBSgU/FYIIBZIYrCW4hOCXIQZCgYUBv7jEh4uBZAscewZ8CgEgUYT0EEoQIBA4gICFQQIEHYQA+KQzdDAArdCAArpCEScHaIQiEvwiGe4QiFUwQiEbgIiFYIL0DEQTkBEQrJEEQc/cYYiCg4HBDIQiCfoRoEHQLaDEQQHBbQYiBCAT8Dn/BCAoXBJYP/OgZKC/6OEEARLCEQZLEEQZLEEQjKFEQI6EEQZLDEQbsGEQLjGYYYA/JIxzEg/AfgJSDAoPgfgiDC8COFAoPnaQj6CAAR+CW4TCFA4i6CDIqhCDIfwHoYHCYIN/GgKuBJ4JDBFYUf/C5CBYIZBv/Ag4ZBg4rBBYQTBAQIcBg4FBn5UBAQUfFwIfCEQeAgYfBAQUBFAKbCAQQiCGwIiE+A2BwBFNwE/AoM/EQJoIWwKCCh4cBFYKUERYV/W46uHFYIZGaJA0B/glBGYT0JIITiEMIJvCFQQAEHYQA/ABBlEOIhdGQAIRFSgQIBgQICn4IB8EAjiBCUYglCbQYeBEoQZCTwM/CYIZD/gEBUwIzBJ4UHYAU/EwIrBh4rCAoIXCn4rBCgUDAQN/FYMfBYIXBCYJnCBYXggf8HgQLCwEPEQQuBgJOECwILDCwgiLHIUHBYJFGD4IxBgYWCn4rBBwJoFDIYNBCgPADgKHBRYfDBQN/GAIrBToTLDVwYACDILiCWAb8DAAYzBYAjTCAAI9BAARNCBAoqCBAgQDFgbYCAH4AufgQACf4T8CAAT/CfgQACBwITCAAYOBCYQioh4iEAHQA=='))),
|
||||
46,
|
||||
atob("FR4uHyopKyksJSssGA=="),
|
||||
70+(scale<<8)+(1<<16)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Graphics.prototype.setLargeFont = function(scale) {
|
||||
// Actual height 47 (48 - 2)
|
||||
this.setFontCustom(
|
||||
|
|
@ -75,6 +65,19 @@ Graphics.prototype.setSmallFont = function(scale) {
|
|||
};
|
||||
|
||||
|
||||
Graphics.prototype.setMiniFont = function(scale) {
|
||||
// Actual height 16 (15 - 0)
|
||||
this.setFontCustom(
|
||||
atob('AAAAAAAAAAAAAP+w/5AAAAAA4ADgAOAA4AAAAAAAAAABgBmAGbAb8D+A+YDZ8B/wf4D5gJmAGQAQAAAAAAAeOD8cMwzxj/GPMYwc/Az4AAAAAHAA+DDIYMjA+YBzAAYADeA7MHMw4zDD4ADAAAAz4H/wzjDHMMMwwbBj4APgADAAAAAA4ADgAAAAAAAAAAfwH/54B+ABAAAAAOABeAcf/gfwAAAAACAAaAD4APgAOABgAAAAAAACAAIAAgA/wAMAAgACAAAAAAAAPAA4AAAAAAIAAgACAAIAAgAAAAAAADAAMAAAAAAAcAfwf4D4AIAAAAA/wH/gwDDAMMAwwDB/4D/AAAAAAGAAwAD/8P/wAAAAAHAw8HDA8MHww7DnMH4wGBAAAMBgyHDcMPww/DDv4MfAAAAAAAHgD+A+YPhgwGAH8AfwAEAAAAAA/GD8cMwwzDDMMM5wx+ABgAAAP8B/4MwwzDDMMMwwx+ADwAAAgADAAMBwwfDPgP4A8ADAAAAAe+D/8M4wxjDGMP5wf+ABwAAAfAB+cMYwwjDCMMYwf+A/wAAAAAAAAAxgBCAAAAAAAAAYPBA4AAAAAAAAAgAHAA+AHMAYYAAAAAAAAAAAAAAJAAkACQAJAAkACQAJAAkAAAAAAAAAAAAAABhgHMAPgAcAAgAAAAAAAABgAOAAwbDDsMYA/AA4AAAAAAAD4A/wGBgxzDPsMyQjJDPkM+wYIBxgD+AAAAAAABAA8A/gf8DwwODA/sAfwAHwADAAAP/w//DGMMYwxjDOMP9we+ABwA8AP8Bw4MAwwDDAMMAwwDDgcHDgMMAAAAAA//D/8MAwwDDAMMAw4HB/4D/AAAAAAP/w//DGMMYwxjDGMMQwgBAAAP/w//DDAMMAwwDDAMAADwA/wHDgwDDAMMAwwDDCMOJwc+ADwAAA//D/8AMAAwADAAMAAwD/8P/wAAAAAP/w//AAAABgAHAAMAAwAHD/4P+AAAAAAP/w//AOAB+AOcBw4MBwgDAAEAAA//D/8AAwADAAMAAwADAAAP/w//A8AA8AA+AA8AHwB8AeAHgA//D/8AAAAAD/8P/wcAAcAA8AA4AB4P/w//AAAA8AP8Bw4MAwwDDAMMAwwDDgcH/gP8AAAAAA//D/8MMAwwDDAMYA7gB8ABgADwA/wHDgwDDAMMAwwDDA8ODwf/A/8AAAAAD/8P/wwwDDAMMAx4Dv4HxwEBAAAHjg/HDMMMYwxjDGMONwc+ABwMAAwADAAMAA//D/8MAAwADAAIAAAAD/wP/gAHAAMAAwADAAMAHg/8AAAMAA+AA/AAfgAPAA8AfgPwD4AMAAwAD4AD+AA/AA8A/g/gDwAP4AH8AB8APwH8D8AMAAgBDAMPDgO8APAB8AOcDw8MAwgBCAAOAAeAAeAAfwH/B4AOAAwAAAAMAwwPDB8Mew3jD4MPAwwDAAAAAAAAB//3//QABAAAAAAADgAP4AH+AB8AAQAABAAEAAf/9//wAAAAAAAAAAGAAwAGAAwABgADAAGAAAAAAAAAQABAAEAAQABAAEAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAAAAAQA3wHbAZMBswGzAf4A/wAAAAAP/w//AYMBgwGDAYMA/gB8AAAAEAD+Ae8BgwGDAYMBgwDGAAAAMAD+Ae8BgwGDAYMBhw//D/8AAAAYAP4B/wGTAZMBkwGTAP4AcAEAAYAP/w//CQAJAAAwAP4hz3GDMQMxAzGHcf/h/8AAAAAP/w//AYABgAGAAYAA/wB/AAAAAA3/Df8AAAAAOf/9//AAAAAP/w//ADgAfADGAYMBAQAAD/8P/wAAAAAB/wH/AYABgAGAAf8A/wGAAYABgAH/AP8AAAAAAf8B/wGAAYABgAGAAP8AfwAAADAA/gHvAYMBgwGDAYMA/gB8AAAAAAH/8f/xgwGDAYMBgwD+AHwAAAAwAP4B7wGDAYMBgwGHAf/x//AAAAAB/wH/AYABgAEAAAAA5gHzAbMBkwGbAd8AzgEAAYAP/wf/AQMBAwAAAAAB/gH/AAMAAwADAAcB/wH/AAABAAHgAPwAHwAPAH4B8AGAAQAB8AB+AA8APwHwAeAA/AAPAD8B+AHAAQEBgwHOAHwAOAD+AccBAwAAAQAB4AD4EB/wB8A/APgBwAAAAAEBgwGPAZ8B8wHjAcMBAQAAAAAABgf/9/n2AAAAAAAP/w//AAAEAAYAB/nz//AGAAAAAAAAAAAAcABgAGAAcAAwAHAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'),
|
||||
32,
|
||||
atob("AwUHDwoOCwQHBwcJBAcEBgoGCQkKCQoICQoFBQoMCgkPCgoMCwkICwsECAoIDgsMCgwKCgoLCg8KCQoHBgcLCwgJCgkKCQYKCgQECAQOCgoKCgYIBwoIDAkJCAcEBwsQ"),
|
||||
16+(scale<<8)+(1<<16)
|
||||
);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
|
||||
function imgLock(){
|
||||
return {
|
||||
width : 16, height : 16, bpp : 1,
|
||||
|
|
@ -165,12 +168,27 @@ function imgWatch() {
|
|||
|
||||
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=="))
|
||||
width : 24, height : 24, bpp : 1,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("/4AF84CB4YCBwICBCAP+jFH/k8g/4kkH+AFB8ACB4cY4eHzPhgmZkHnzPn8fb4/gvwUD8EYARhAC"))
|
||||
}
|
||||
}
|
||||
|
||||
function imgAgenda() {
|
||||
return {
|
||||
width : 24, height : 24, bpp : 1,
|
||||
transparent : 1,
|
||||
buffer : require("heatshrink").decompress(atob("/4AFnPP+ALBAQX4CIgLFAQvggEBAQvAgEDAQMCwEAgwTBhgiB/AlCGQ8BGQQ"))
|
||||
}
|
||||
}
|
||||
|
||||
function imgMountain() {
|
||||
return {
|
||||
width : 24, height : 24, bpp : 1,
|
||||
transparent : 1,
|
||||
buffer : atob("//////////////////////3///n///D//uZ//E8//A+/+Z+f8//P5//n7//3z//zn//5AAAAAAAA////////////////////")
|
||||
}
|
||||
}
|
||||
|
||||
/************
|
||||
* 2D MENU with entries of:
|
||||
|
|
@ -186,6 +204,7 @@ var menu = [
|
|||
function(){ return [ E.getBattery() + "%", Bangle.isCharging() ? imgCharging() : imgBattery() ] },
|
||||
function(){ return [ getSteps(), imgSteps() ] },
|
||||
function(){ return [ Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", imgBpm()] },
|
||||
function(){ return [ measureAltitude, imgMountain() ]},
|
||||
]
|
||||
]
|
||||
|
||||
|
|
@ -196,14 +215,90 @@ try{
|
|||
require('sched');
|
||||
menu.push([
|
||||
function(){
|
||||
var text = isAlarmEnabled() ? getAlarmMinutes() + " min." : "Timer";
|
||||
return [text, imgTimer(), () => decreaseAlarm(), () => increaseAlarm(), null ]
|
||||
var text = isAlarmEnabled(TIMER_IDX) ? getAlarmMinutes(TIMER_IDX) + " min." : "Timer";
|
||||
return [text, imgTimer(), () => decreaseAlarm(TIMER_IDX), () => increaseAlarm(TIMER_IDX), null ]
|
||||
},
|
||||
]);
|
||||
} catch(ex) {
|
||||
// If sched is not installed, we hide this menu item
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AGENDA MENU
|
||||
* Note that we handle the agenda differently in order to hide old entries...
|
||||
*/
|
||||
var agendaIdx = 0;
|
||||
var agendaTimerIdx = 0;
|
||||
if(storage.readJSON("android.calendar.json") !== undefined){
|
||||
function nextAgendaEntry(){
|
||||
agendaIdx += 1;
|
||||
}
|
||||
|
||||
function previousAgendaEntry(){
|
||||
agendaIdx -= 1;
|
||||
}
|
||||
|
||||
menu.push([
|
||||
function(){
|
||||
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);
|
||||
|
||||
if(agenda.length <= 0){
|
||||
return ["All done", imgAgenda()]
|
||||
}
|
||||
|
||||
agendaIdx = agendaIdx < 0 ? 0 : agendaIdx;
|
||||
agendaIdx = agendaIdx >= agenda.length ? agendaIdx -1 : agendaIdx;
|
||||
|
||||
var entry = agenda[agendaIdx];
|
||||
var title = entry.title.slice(0,14);
|
||||
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) : "";
|
||||
|
||||
function dynImgAgenda(){
|
||||
if(isAlarmEnabled(TIMER_AGENDA_IDX) && agendaTimerIdx == agendaIdx){
|
||||
return imgTimer();
|
||||
} else {
|
||||
return imgAgenda();
|
||||
}
|
||||
}
|
||||
|
||||
return [title + "\n" + dateStr, dynImgAgenda(), () => nextAgendaEntry(), () => previousAgendaEntry(), function(){
|
||||
try{
|
||||
var alarm = require('sched')
|
||||
|
||||
// If other time, we disable the old one and enable this one.
|
||||
if(agendaIdx != agendaTimerIdx){
|
||||
agendaTimerIdx = -1;
|
||||
alarm.setAlarm(TIMER_AGENDA_IDX, undefined);
|
||||
}
|
||||
|
||||
// Disable alarm if enabled
|
||||
if(isAlarmEnabled(TIMER_AGENDA_IDX)){
|
||||
agendaTimerIdx = -1;
|
||||
alarm.setAlarm(TIMER_AGENDA_IDX, undefined);
|
||||
alarm.reload();
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, set alarm for given event
|
||||
agendaTimerIdx = agendaIdx;
|
||||
alarm.setAlarm(TIMER_AGENDA_IDX, {
|
||||
msg: title,
|
||||
timer : parseInt((date - now)),
|
||||
});
|
||||
alarm.reload();
|
||||
} catch(ex){ }
|
||||
}]
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* WEATHER MENU
|
||||
*/
|
||||
|
|
@ -246,13 +341,37 @@ function getMenuEntry(){
|
|||
// 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]();
|
||||
var menuEntry = menu[settings.menuPosX][settings.menuPosY]();
|
||||
|
||||
if(menuEntry[0] == null){
|
||||
return menuEntry;
|
||||
}
|
||||
|
||||
// For the first entry we always convert it into a callback function
|
||||
// such that the menu is compatible with async functions such as
|
||||
// measuring the pressure, altitude or sending http requests...
|
||||
if(typeof menuEntry[0] !== 'function'){
|
||||
var value = menuEntry[0];
|
||||
menuEntry[0] = function(callbackFun){
|
||||
callbackFun(String(value), settings.menuPosX, settings.menuPosY);
|
||||
}
|
||||
}
|
||||
return menuEntry;
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
* Helper
|
||||
*/
|
||||
function isFullscreen(){
|
||||
var s = settings.screen.toLowerCase();
|
||||
if(s == "dynamic"){
|
||||
return Bangle.isLocked()
|
||||
} else {
|
||||
return s == "full"
|
||||
}
|
||||
}
|
||||
|
||||
function getSteps() {
|
||||
var steps = 0;
|
||||
try{
|
||||
|
|
@ -267,8 +386,7 @@ function getSteps() {
|
|||
// 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";
|
||||
return steps;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -306,10 +424,10 @@ function getWeather(){
|
|||
}
|
||||
|
||||
|
||||
function isAlarmEnabled(){
|
||||
function isAlarmEnabled(idx){
|
||||
try{
|
||||
var alarm = require('sched');
|
||||
var alarmObj = alarm.getAlarm(TIMER_IDX);
|
||||
var alarmObj = alarm.getAlarm(idx);
|
||||
if(alarmObj===undefined || !alarmObj.on){
|
||||
return false;
|
||||
}
|
||||
|
|
@ -321,22 +439,22 @@ function isAlarmEnabled(){
|
|||
}
|
||||
|
||||
|
||||
function getAlarmMinutes(){
|
||||
if(!isAlarmEnabled()){
|
||||
function getAlarmMinutes(idx){
|
||||
if(!isAlarmEnabled(idx)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
var alarm = require('sched');
|
||||
var alarmObj = alarm.getAlarm(TIMER_IDX);
|
||||
var alarmObj = alarm.getAlarm(idx);
|
||||
return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
|
||||
}
|
||||
|
||||
|
||||
function increaseAlarm(){
|
||||
function increaseAlarm(idx){
|
||||
try{
|
||||
var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0;
|
||||
var alarm = require('sched')
|
||||
alarm.setAlarm(TIMER_IDX, {
|
||||
var minutes = isAlarmEnabled(idx) ? getAlarmMinutes(idx) : 0;
|
||||
var alarm = require('sched');
|
||||
alarm.setAlarm(idx, {
|
||||
timer : (minutes+5)*60*1000,
|
||||
});
|
||||
alarm.reload();
|
||||
|
|
@ -344,16 +462,16 @@ function increaseAlarm(){
|
|||
}
|
||||
|
||||
|
||||
function decreaseAlarm(){
|
||||
function decreaseAlarm(idx){
|
||||
try{
|
||||
var minutes = getAlarmMinutes();
|
||||
var minutes = getAlarmMinutes(idx);
|
||||
minutes -= 5;
|
||||
|
||||
var alarm = require('sched')
|
||||
alarm.setAlarm(TIMER_IDX, undefined);
|
||||
alarm.setAlarm(idx, undefined);
|
||||
|
||||
if(minutes > 0){
|
||||
alarm.setAlarm(TIMER_IDX, {
|
||||
alarm.setAlarm(idx, {
|
||||
timer : minutes*60*1000,
|
||||
});
|
||||
}
|
||||
|
|
@ -363,6 +481,23 @@ function decreaseAlarm(){
|
|||
}
|
||||
|
||||
|
||||
function measureAltitude(callbackFun){
|
||||
var oldX = settings.menuPosX;
|
||||
var oldY = settings.menuPosY;
|
||||
try{
|
||||
Bangle.getPressure().then(data=>{
|
||||
if(data && data.altitude && data.altitude > -100){
|
||||
callbackFun(Math.round(data.altitude) + "m", oldX, oldY);
|
||||
} else {
|
||||
callbackFun("???", oldX, oldY);
|
||||
}
|
||||
});
|
||||
}catch(ex){
|
||||
callbackFun("err", oldX, oldY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
* DRAW
|
||||
*/
|
||||
|
|
@ -385,7 +520,7 @@ function drawDate(){
|
|||
|
||||
// Draw date
|
||||
y = parseInt(y/2)+4;
|
||||
y += settings.fullscreen ? 0 : 13;
|
||||
y += isFullscreen() ? 0 : 13;
|
||||
var date = new Date();
|
||||
var dateStr = date.getDate();
|
||||
dateStr = ("0" + dateStr).substr(-2);
|
||||
|
|
@ -410,7 +545,7 @@ function drawDate(){
|
|||
|
||||
function drawTime(){
|
||||
// Draw background
|
||||
var y = H/5*2 + (settings.fullscreen ? 0 : 8);
|
||||
var y = H/5*2 + (isFullscreen() ? 0 : 8);
|
||||
g.setColor(g.theme.fg);
|
||||
g.fillRect(0,y,W,H);
|
||||
var date = new Date();
|
||||
|
|
@ -429,44 +564,55 @@ function drawTime(){
|
|||
y += parseInt((H - y)/2) + 5;
|
||||
|
||||
var menuEntry = getMenuEntry();
|
||||
var menuName = menuEntry[0];
|
||||
var menuTextFun = menuEntry[0];
|
||||
var menuImg = menuEntry[1];
|
||||
var printImgLeft = settings.menuPosY != 0;
|
||||
|
||||
// Show large or small time depending on info entry
|
||||
if(menuName == null){
|
||||
if(settings.hideColon){
|
||||
g.setXLargeFont();
|
||||
} else {
|
||||
g.setLargeFont();
|
||||
}
|
||||
if(menuTextFun == null){
|
||||
g.setLargeFont();
|
||||
g.drawString(timeStr, W/2, y);
|
||||
return;
|
||||
} else {
|
||||
y -= 15;
|
||||
g.setMediumFont();
|
||||
}
|
||||
g.drawString(timeStr, W/2, y);
|
||||
|
||||
// Draw menu if set
|
||||
if(menuName == null){
|
||||
return;
|
||||
g.drawString(timeStr, W/2, y);
|
||||
}
|
||||
|
||||
y += 35;
|
||||
g.setFontAlign(0,0);
|
||||
g.setSmallFont();
|
||||
var imgWidth = 0;
|
||||
if(menuImg !== undefined){
|
||||
imgWidth = 24.0;
|
||||
var strWidth = g.stringWidth(menuName);
|
||||
var scale = imgWidth / menuImg.width;
|
||||
g.drawImage(
|
||||
menuImg,
|
||||
W/2 + (printImgLeft ? -strWidth/2-2 : strWidth/2+2) - parseInt(imgWidth/2),
|
||||
y - parseInt(imgWidth/2),
|
||||
{ scale: scale }
|
||||
);
|
||||
}
|
||||
g.drawString(menuName, printImgLeft ? W/2 + imgWidth/2 + 2 : W/2 - imgWidth/2 - 2, y+3);
|
||||
// Async set the menu (could be that some data is async fetched)
|
||||
menuTextFun((menuText, oldX, oldY) => {
|
||||
|
||||
// We display the text IFF the user did not change the menu
|
||||
if(settings.menuPosX != oldX || settings.menuPosY != oldY){
|
||||
return;
|
||||
}
|
||||
|
||||
// As its a callback, we have to ensure that the color
|
||||
// font etc. is still correct...
|
||||
g.setColor(g.theme.bg);
|
||||
g.setFontAlign(0,0);
|
||||
y += 35;
|
||||
|
||||
if(menuText.split('\n').length > 1){
|
||||
g.setMiniFont();
|
||||
} else {
|
||||
g.setSmallFont();
|
||||
}
|
||||
|
||||
var imgWidth = 0;
|
||||
if(menuImg !== undefined){
|
||||
imgWidth = 24.0;
|
||||
var strWidth = g.stringWidth(menuText);
|
||||
var scale = imgWidth / menuImg.width;
|
||||
g.drawImage(
|
||||
menuImg,
|
||||
W/2 + (printImgLeft ? -strWidth/2-4 : strWidth/2+4) - parseInt(imgWidth/2),
|
||||
y - parseInt(imgWidth/2),
|
||||
{ scale: scale }
|
||||
);
|
||||
}
|
||||
g.drawString(menuText, printImgLeft ? W/2 + imgWidth/2 + 2 : W/2 - imgWidth/2 - 2, y+3);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -479,7 +625,7 @@ function drawLock(){
|
|||
|
||||
|
||||
function drawWidgets(){
|
||||
if(settings.fullscreen){
|
||||
if(isFullscreen()){
|
||||
for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
|
||||
} else {
|
||||
Bangle.drawWidgets();
|
||||
|
|
@ -517,6 +663,13 @@ Bangle.on('lcdPower',on=>{
|
|||
Bangle.on('lock', function(isLocked) {
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
|
||||
if(!isLocked && settings.screen.toLowerCase() == "dynamic"){
|
||||
// If we have to show the widgets again, we load it from our
|
||||
// cache and not through Bangle.loadWidgets as its much faster!
|
||||
for (let wd of WIDGETS) {wd.draw=wd._draw;wd.area=wd._area;}
|
||||
}
|
||||
|
||||
draw();
|
||||
});
|
||||
|
||||
|
|
@ -531,7 +684,7 @@ Bangle.on('charging',function(charging) {
|
|||
});
|
||||
|
||||
Bangle.on('touch', function(btn, e){
|
||||
var widget_size = settings.fullscreen ? 0 : 20; // Its not exactly 24px -- empirically it seems that 20 worked better...
|
||||
var widget_size = isFullscreen() ? 0 : 20; // Its not exactly 24px -- empirically it seems that 20 worked better...
|
||||
var left = parseInt(g.getWidth() * 0.22);
|
||||
var right = g.getWidth() - left;
|
||||
var upper = parseInt(g.getHeight() * 0.22) + widget_size;
|
||||
|
|
@ -575,6 +728,9 @@ Bangle.on('touch', function(btn, e){
|
|||
}
|
||||
|
||||
if(is_right){
|
||||
// A bit hacky but we ensure that always the first agenda entry is shown...
|
||||
agendaIdx = 0;
|
||||
|
||||
Bangle.buzz(40, 0.6);
|
||||
settings.menuPosX = (settings.menuPosX+1) % menu.length;
|
||||
settings.menuPosY = 0;
|
||||
|
|
@ -582,6 +738,9 @@ Bangle.on('touch', function(btn, e){
|
|||
}
|
||||
|
||||
if(is_left){
|
||||
// A bit hacky but we ensure that always the first agenda entry is shown...
|
||||
agendaIdx = 0;
|
||||
|
||||
Bangle.buzz(40, 0.6);
|
||||
settings.menuPosY = 0;
|
||||
settings.menuPosX = settings.menuPosX-1;
|
||||
|
|
@ -591,12 +750,13 @@ Bangle.on('touch', function(btn, e){
|
|||
|
||||
if(is_center){
|
||||
var menuEntry = getMenuEntry();
|
||||
if(menuEntry.length > 4){
|
||||
if(menuEntry.length > 4 && menuEntry[4] != null){
|
||||
Bangle.buzz(80, 0.6).then(()=>{
|
||||
try{
|
||||
menuEntry[4]();
|
||||
setTimeout(()=>{
|
||||
Bangle.buzz(80, 0.6);
|
||||
drawTime();
|
||||
}, 250);
|
||||
} catch(ex){
|
||||
// In case it fails, we simply ignore it.
|
||||
|
|
@ -625,9 +785,15 @@ E.on("kill", function(){
|
|||
// dark/light theme as well as the colors.
|
||||
g.setTheme({bg:g.theme.fg,fg:g.theme.bg, dark:!g.theme.dark}).clear();
|
||||
|
||||
// Load widgets and draw clock the first time
|
||||
Bangle.loadWidgets();
|
||||
draw();
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
// Load widgets and draw clock the first time
|
||||
Bangle.loadWidgets();
|
||||
|
||||
// Cache draw function for dynamic screen to hide / show widgets
|
||||
// Bangle.loadWidgets() could also be called later on but its much slower!
|
||||
for (let wd of WIDGETS) {wd._draw=wd.draw; wd._area=wd.area;}
|
||||
|
||||
// Draw first time
|
||||
draw();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "bwclk",
|
||||
"name": "BW Clock",
|
||||
"version": "0.14",
|
||||
"version": "0.20",
|
||||
"description": "A very minimalistic clock to mainly show date and time.",
|
||||
"readme": "README.md",
|
||||
"icon": "app.png",
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.4 KiB |
|
|
@ -4,7 +4,7 @@
|
|||
// initialize with default settings...
|
||||
const storage = require('Storage')
|
||||
let settings = {
|
||||
fullscreen: false,
|
||||
screen: "Normal",
|
||||
showLock: true,
|
||||
hideColon: false,
|
||||
};
|
||||
|
|
@ -17,15 +17,16 @@
|
|||
storage.write(SETTINGS_FILE, settings)
|
||||
}
|
||||
|
||||
|
||||
var screenOptions = ["Normal", "Dynamic", "Full"];
|
||||
E.showMenu({
|
||||
'': { 'title': 'BW Clock' },
|
||||
'< Back': back,
|
||||
'Fullscreen': {
|
||||
value: settings.fullscreen,
|
||||
format: () => (settings.fullscreen ? 'Yes' : 'No'),
|
||||
onchange: () => {
|
||||
settings.fullscreen = !settings.fullscreen;
|
||||
'Screen': {
|
||||
value: 0 | screenOptions.indexOf(settings.screen),
|
||||
min: 0, max: 2,
|
||||
format: v => screenOptions[v],
|
||||
onchange: v => {
|
||||
settings.screen = screenOptions[v];
|
||||
save();
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
0.01: Initial version
|
||||
0.02: More compact rendering & app icon
|
||||
0.03: Tell clock widgets to hide.
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# Calendar Clock - Your day at a glance
|
||||
|
||||
This clock shows a chronological view of your current and future events.
|
||||
It uses events synced from Gadgetbridge to achieve this.
|
||||
|
||||
The current time and date is highlighted in cyan.
|
||||
|
||||
## Screenshot
|
||||

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

|
||||
|
||||
## Features
|
||||
|
||||
Has a dark mode
|
||||
|
||||
## Requests
|
||||
|
||||
If you have any issues or would like to suggest a feature, click here to send a message -> [here](https://github.com/elykittytee/BangleApps/issues/new?title=Poketch%20Clock%20Bug).
|
||||
|
||||
## Creator
|
||||
|
||||
Eleanor Tayam
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("j0ewkBiIAxHIQMJiBJEIxAaCAIQfHDgIUFDwwNCHYgVFiAVBHYgIDEghKCCIQGCFYoaDAYgORGIJ2DBwYIBHgQOPgAOIPIYOGAgQOFFgh7DHZQeDBwhoFQgh3JEAgOFFoqkHYRzgOfx4bCJ4gNGSIaJEABA7EAGA"))
|
||||
|
After Width: | Height: | Size: 660 B |
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"id": "distortclk",
|
||||
"name": "Distort Clock",
|
||||
"shortName":"Distort Clock",
|
||||
"version": "0.01",
|
||||
"description": "A clockface",
|
||||
"icon": "app.png",
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"allow_emulator": true,
|
||||
"readme":"README.md",
|
||||
"storage": [
|
||||
{"name":"distortclk.app.js","url":"app.js"},
|
||||
{"name":"distortclk.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
|
|
@ -1,2 +1,3 @@
|
|||
0.01: First published version of app
|
||||
0.02: Move to Bangle.setUI to launcher support
|
||||
0.03: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -173,6 +173,9 @@ const drawHR = function () {
|
|||
}
|
||||
};
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
// clean app screen
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
|
|
@ -198,6 +201,3 @@ Bangle.on('HRM', function (d) {
|
|||
|
||||
// draw now
|
||||
drawClock();
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "fclock",
|
||||
"name": "fclock",
|
||||
"shortName": "F Clock",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "Simple design of a digital clock",
|
||||
"icon": "app.png",
|
||||
"type": "clock",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
0.01: first release
|
||||
0.02: RAM efficient version of `fourTwentyTz.js` (as suggested by @gfwilliams).
|
||||
0.03: `mkFourTwentyTz.js` now handles new timezonedb.com CSV format
|
||||
0.04: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ function draw() {
|
|||
|
||||
// Clear the screen once, at startup
|
||||
g.clear();
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI("clock");
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
|
@ -47,5 +49,4 @@ Bangle.on('lcdPower',on=>{
|
|||
drawTimeout = undefined;
|
||||
}
|
||||
});
|
||||
// Show launcher when middle button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "ftclock",
|
||||
"name": "Four Twenty Clock",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"description": "A clock that tells when and where it's going to be 4:20 next",
|
||||
"icon": "app.png",
|
||||
"screenshots": [{"url":"screenshot.png"}, {"url":"screenshot1.png"}],
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ function onInit(device) {
|
|||
if (crc==3508163280 || crc==1418074094) version = "2v12";
|
||||
if (crc==4056371285) version = "2v13";
|
||||
if (crc==1038322422) version = "2v14";
|
||||
if (crc==2560806221) version = "2v15";
|
||||
if (!ok) {
|
||||
version += `(⚠ update required)`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
0.01: First released version
|
||||
0.02: Changed setWatch to Bangle.setUI
|
||||
0.03: Tell clock widgets to hide.
|
||||
|
|
|
|||
|
|
@ -238,10 +238,12 @@ Bangle.on('lcdPower', (on) => {
|
|||
}
|
||||
});
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
g.clear();
|
||||
startTimers();
|
||||
Bangle.loadWidgets();
|
||||
drawAll();
|
||||
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"id": "gallifr",
|
||||
"name": "Time Traveller's Chronometer",
|
||||
"shortName": "Time Travel Clock",
|
||||
"version": "0.02",
|
||||
"version": "0.03",
|
||||
"description": "A clock for time travellers. The light pie segment shows the minutes, the black circle, the hour. The dial itself reads 'time' just in case you forget.",
|
||||
"icon": "gallifr.png",
|
||||
"screenshots": [{"url":"screenshot_time.png"}],
|
||||
|
|
|
|||